diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ba3fd..b200284 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2012 Fidelity Information Services, Inc # +# Copyright 2012, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -15,11 +15,63 @@ cmake_minimum_required(VERSION 2.8.5) project(GTM C ASM) -set(version V5.5-000) -if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4) - set(arch "x86") +# Max optimization level is -O2 +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + get_property(flags CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE) + if("${flags}" MATCHES "-O[3-9]") + string(REGEX REPLACE "-O[3-9]" "-O2" flags "${flags}") + set_property(CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE "${flags}") + endif() +endforeach() + +# Defaults +set(version V6.0-003) +if("${version}" STREQUAL "") + set(version V9.9-0) +endif() + +# If CMAKE_BUILD_TYPE is not defined make it a Release build +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) +endif() + +# If it's a debug build make sure GT.M uses all of its debug options +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") + +set(install_permissions_script + OWNER_READ OWNER_EXECUTE OWNER_WRITE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + ) + +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) + +# Only IA64 and x86_64 architectures use this option +set(gen_xfer_desc 0) + +# Platform specific libs +set(gtm_osarch_libs "") + +# Define these ahead of establishing platforms +set(gt_src_list) +set(sources_used "") +set(extralibs "") +set(is_encryption_supported 1) +set(libmumpsrestoreregex "") +message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}") +# Establish platform +# Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true +if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + include(sr_linux/platform.cmake) +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "HP-UX") + include(sr_hpux/platform.cmake) +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "AIX") + include(sr_aix/platform.cmake) +elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS") + include(sr_sun/platform.cmake) else() - set(arch "x86_64") + message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}") endif() # Choose where to get bootstrap sources. @@ -45,41 +97,6 @@ if(NOT GTM_INSTALL_DIR) set(GTM_INSTALL_DIR .) endif() -# Max optimization level is -O2 -get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach(lang ${languages}) - get_property(flags CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE) - if("${flags}" MATCHES "-O[3-9]") - string(REGEX REPLACE "-O[3-9]" "-O2" flags "${flags}") - set_property(CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE "${flags}") - endif() -endforeach() - -if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) -endif() - -set(install_permissions_script - OWNER_READ OWNER_EXECUTE OWNER_WRITE - GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE - ) - -set(CMAKE_INCLUDE_FLAG_ASM "-Wa,-I") # gcc -I does not make it to "as" -set(CMAKE_C_FLAGS - # TODO: Use CMake 2.8.9 POSITION_INDEPENDENT_CODE abstraction for -fPIC in static libs - "${CMAKE_C_FLAGS} -ansi -fsigned-char -fPIC -Wmissing-prototypes") -set(CMAKE_C_FLAGS_RELEASE - "${CMAKE_C_FLAGS_RELEASE} -fno-defer-pop -fno-strict-aliasing -ffloat-store") -add_definitions( - #-DNOLIBGTMSHR #gt_cc_option_DBTABLD=-DNOLIBGTMSHR - -D_GNU_SOURCE - -D_FILE_OFFSET_BITS=64 - -D_XOPEN_SOURCE=600 - -D_LARGEFILE64_SOURCE - ) -set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) - #----------------------------------------------------------------------------- # Source files are organized into subdirectories named by platform. @@ -88,17 +105,6 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) # appear in multiple directories but only the instance found earliest # in the search path will be used. Later instances of the same source # file name will be ignored. -set(gt_src_list) -set(gen_xfer_desc 0) -if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") - list(APPEND gt_src_list sr_linux) - if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4) - list(APPEND gt_src_list sr_i386 sr_x86_regs sr_unix_nsb) - else() - list(APPEND gt_src_list sr_x86_64 sr_x86_regs) - set(gen_xfer_desc 1) - endif() -endif() list(APPEND gt_src_list sr_unix_gnp sr_unix_cm @@ -113,7 +119,7 @@ list(APPEND gt_src_list foreach(d ${gt_src_list}) set(source_dir_${d} ${GTM_SOURCE_DIR}/${d}) file(GLOB sources_${d} RELATIVE ${source_dir_${d}} - ${d}/*.c ${d}/*.s ${d}/*.si) + ${d}/*.c ${d}/*.s ${d}/*.si) endforeach() if(gen_bootstrap) # Prefer generated sources over all other locations. @@ -153,15 +159,20 @@ endfunction() # Macro to search directories ordered by 'gt_src_list' for a given # list of source file names, assign them to a target, and exclude the # source file names from inclusion in libmumps. -set(sources_used "") macro(set_source_list target) foreach(name ${ARGN}) set(src "") foreach(d ${gt_src_list}) if(";${sources_${d}};" MATCHES ";(${name}\\.(c|s|si));") - set(src ${d}/${CMAKE_MATCH_1}) - set("source_used_${CMAKE_MATCH_1}" 1) - list(APPEND sources_used ${source_dir_${d}}/${CMAKE_MATCH_1}) + set(fname ${CMAKE_MATCH_1}) + set(src ${d}/${fname}) + set("source_used_${fname}" 1) + list(APPEND sources_used ${source_dir_${d}}/${fname}) + if(NOT "${libmumpsrestoreregex}" STREQUAL "") + if(";${name};" MATCHES ";(${libmumpsrestoreregex});") + set("source_used_${fname}" 0) + endif() + endif() break() endif() endforeach() @@ -192,6 +203,9 @@ load_source_list(libgtcm sr_unix_cm/libgtcm.list) load_source_list(liblke sr_unix/liblke.list) load_source_list(libmupip sr_unix/libmupip.list) load_source_list(libstub sr_unix/libstub.list) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") + load_source_list(libgtmrpc sr_sun/libgtmrpc.list) +endif() # Assign sources to executables. set_source_list(gtm_threadgbl_deftypes gtm_threadgbl_deftypes) @@ -213,6 +227,9 @@ set_source_list(maskpass maskpass) set_source_list(mumps gtm) set_source_list(mupip mupip mupip_cmd) set_source_list(semstat2 semstat2) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") + set_source_list(gtm_svc gtm_svc gtm_rpc_init gtm_dal_svc) +endif() #----------------------------------------------------------------------------- # libmumps gets leftover sources, so compute the remaining list. @@ -240,14 +257,14 @@ foreach(m chk2lev.m chkop.m gendash.m genout.m loadop.m loadvx.m msg.m tttgen.m ) endforeach() -set(mumps_ttt_args -run tttgen - ${GTM_SOURCE_DIR}/sr_unix/ttt.txt - ${GTM_SOURCE_DIR}/sr_port/opcode_def.h - ${GTM_SOURCE_DIR}/sr_port/vxi.h - ) +foreach(f ttt.txt opcode_def.h vxi.h) + select_file(src ${f}) + list(APPEND tttfiles ${src}) +endforeach() +set(mumps_ttt_args -run tttgen ${tttfiles}) add_custom_command( OUTPUT gen/ttt.c - DEPENDS ${GTM_SOURCE_DIR}/sr_unix/ttt.txt + DEPENDS ${tttfiles} gen/chk2lev.m gen/chkop.m gen/gendash.m gen/genout.m gen/loadop.m gen/loadvx.m gen/tttgen.m gen/tttscan.m ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake ${gen_bootstrap_depend} @@ -307,6 +324,7 @@ if(gen_xfer_desc) ${GTM_BINARY_DIR}/sources.list COMMAND ${CMAKE_COMMAND} -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -D "arch=${arch}" -D "includes=${includes}" -P ${GTM_SOURCE_DIR}/sr_unix/gen_xfer_desc.cmake VERBATIM @@ -357,6 +375,7 @@ foreach(lib mupip stub mumps + ${extralibs} ) add_library(lib${lib} STATIC ${lib${lib}_SOURCES}) set_property(TARGET lib${lib} PROPERTY OUTPUT_NAME ${lib}) @@ -364,61 +383,72 @@ foreach(lib endforeach() # TODO: find_package or find_library for system libs? -target_link_libraries(libmumps -lelf -lncurses -lm -ldl -lpthread -lrt) +include_directories ("/usr/local/include") +target_link_libraries(libmumps ${libmumpslibs}) -add_executable(mumps ${mumps_SOURCES}) -target_link_libraries(mumps libmumps) +add_executable(mumps ${mumps_SOURCES}) +target_link_libraries(mumps libmumps) -add_executable(dse ${dse_SOURCES}) -target_link_libraries(dse libdse libmumps libstub) +add_executable(dse ${dse_SOURCES}) +target_link_libraries(dse libdse libmumps libstub) list(APPEND with_export dse) -add_executable(dbcertify ${dbcertify_SOURCES}) -target_link_libraries(dbcertify libdbcertify libmupip libmumps libstub) +add_executable(dbcertify ${dbcertify_SOURCES}) +target_link_libraries(dbcertify libdbcertify libmupip libmumps libstub) -add_executable(geteuid ${geteuid_SOURCES}) +add_executable(geteuid ${geteuid_SOURCES}) -add_executable(gtmsecshr ${gtmsecshr_SOURCES}) -add_dependencies(gtmsecshr gen_gtm_threadgbl_deftypes) +add_executable(gtmsecshr ${gtmsecshr_SOURCES}) +add_dependencies(gtmsecshr gen_gtm_threadgbl_deftypes) -add_executable(gtmsecshr_real ${gtmsecshr_real_SOURCES}) +add_executable(gtmsecshr_real ${gtmsecshr_real_SOURCES}) target_link_libraries(gtmsecshr_real libmumps) set_target_properties(gtmsecshr_real PROPERTIES OUTPUT_NAME gtmsecshr RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/gtmsecshrdir ) -add_dependencies(gtmsecshr_real gen_gtm_threadgbl_deftypes) +add_dependencies(gtmsecshr_real gen_gtm_threadgbl_deftypes) -add_executable(mupip ${mupip_SOURCES}) -target_link_libraries(mupip libmupip libmumps libstub) +add_executable(mupip ${mupip_SOURCES}) +target_link_libraries(mupip libmupip libmumps libstub) list(APPEND with_export mupip) -add_executable(lke ${lke_SOURCES}) -target_link_libraries(lke liblke libmumps libgnpclient libmumps libgnpclient libcmisockettcp) +add_executable(lke ${lke_SOURCES}) +target_link_libraries(lke liblke libmumps libgnpclient libmumps libgnpclient libcmisockettcp) +list(APPEND with_export lke) -add_executable(gtcm_server ${gtcm_server_SOURCES}) -target_link_libraries(gtcm_server libgtcm libmumps libstub) + +add_executable(gtcm_server ${gtcm_server_SOURCES}) +target_link_libraries(gtcm_server libgtcm libmumps libstub) list(APPEND with_export gtcm_server) -add_executable(gtcm_gnp_server ${gtcm_gnp_server_SOURCES}) -target_link_libraries(gtcm_gnp_server libgnpserver liblke libmumps libcmisockettcp libstub) + +add_executable(gtcm_gnp_server ${gtcm_gnp_server_SOURCES}) +target_link_libraries(gtcm_gnp_server libgnpserver liblke libmumps libcmisockettcp libstub) list(APPEND with_export gtcm_gnp_server) -add_executable(gtcm_play ${gtcm_play_SOURCES}) -target_link_libraries(gtcm_play libgtcm libmumps libstub) +add_executable(gtcm_play ${gtcm_play_SOURCES}) +target_link_libraries(gtcm_play libgtcm libmumps libstub) list(APPEND with_export gtcm_play) -add_executable(gtcm_pkdisp ${gtcm_pkdisp_SOURCES}) -target_link_libraries(gtcm_pkdisp libgtcm libmumps libstub) -add_executable(gtcm_shmclean ${gtcm_shmclean_SOURCES}) -target_link_libraries(gtcm_shmclean libgtcm libmumps libstub) -add_executable(semstat2 ${semstat2_SOURCES}) -add_executable(ftok ${ftok_SOURCES}) -target_link_libraries(ftok libmumps libstub) +add_executable(gtcm_pkdisp ${gtcm_pkdisp_SOURCES}) +target_link_libraries(gtcm_pkdisp libgtcm libmumps libstub) +add_executable(gtcm_shmclean ${gtcm_shmclean_SOURCES}) +target_link_libraries(gtcm_shmclean libgtcm libmumps libstub) + +add_executable(semstat2 ${semstat2_SOURCES}) + +add_executable(ftok ${ftok_SOURCES}) +target_link_libraries(ftok libmumps libstub) + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") + add_executable(gtm_svc ${gtm_svc_SOURCES}) + target_link_libraries(gtm_svc libmumps libgnpclient libcmisockettcp libgtmrpc) +endif() foreach(t ${with_export}) set_target_properties(${t} PROPERTIES - LINK_FLAGS "-Wl,-u,gtm_filename_to_id -Wl,-u,gtm_zstatus -Wl,--version-script,\"${GTM_BINARY_DIR}/gtmexe_symbols.export\"" - LINK_DEPENDS "${GTM_BINARY_DIR}/gtmexe_symbols.export" + LINK_FLAGS "${gtm_link}" + LINK_DEPENDS "${gtm_dep}" ) add_dependencies(${t} gen_export) endforeach() @@ -427,68 +457,81 @@ add_library(libgtmshr MODULE ${libgtmshr_SOURCES}) set_property(TARGET libgtmshr PROPERTY OUTPUT_NAME gtmshr) target_link_libraries(libgtmshr libmumps libgnpclient libcmisockettcp) set_target_properties(libgtmshr PROPERTIES - LINK_FLAGS "-Wl,-u,gtm_ci -Wl,-u,gtm_filename_to_id -Wl,--version-script,\"${GTM_BINARY_DIR}/gtmshr_symbols.export\"" - LINK_DEPENDS "${GTM_BINARY_DIR}/gtmshr_symbols.export" + LINK_FLAGS "${libgtmshr_link}" + LINK_DEPENDS "${libgtmshr_dep}" ) add_dependencies(libgtmshr gen_export) add_dependencies(mumps libgtmshr) -add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES}) -set_target_properties(libgtmcrypt PROPERTIES - OUTPUT_NAME gtmcrypt - COMPILE_DEFINITIONS USE_GCRYPT - LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin - ) -target_link_libraries(libgtmcrypt gpg-error gpgme gcrypt) -install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin) +if(is_encryption_supported) + # Iterate over the list of GPG related libraries + foreach(gpglib gpg-error gpgme gcrypt) + # For each library, we need a new CMake variable, hence GPGLIB_${gpglib} + find_library(GPGLIB_${gpglib} NAME ${gpglib} PATHS ${CMAKE_LIBRARY_PATH}) + # Append the found library to the list + set(GPG_LIBRARIES ${GPG_LIBRARIES} ${GPGLIB_${gpglib}}) + endforeach() -add_executable(maskpass ${maskpass_SOURCES}) -target_link_libraries(maskpass gpg-error gpgme gcrypt) -set_target_properties(maskpass PROPERTIES - COMPILE_DEFINITIONS USE_GCRYPT - RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt - ) -install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt) + add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES}) + set_target_properties(libgtmcrypt PROPERTIES + OUTPUT_NAME gtmcrypt + COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB" + LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin + ) + target_link_libraries(libgtmcrypt ${GPG_LIBRARIES}) + install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin) -foreach(f - add_db_key.sh - build.sh - encrypt_sign_db_key.sh - gen_keypair.sh - gen_sym_hash.sh - gen_sym_key.sh - gtmcrypt.tab - gtmcrypt_dbk_ref.c - gtmcrypt_dbk_ref.h - gtmcrypt_interface.h - gtmcrypt_pk_ref.c - gtmcrypt_pk_ref.h - gtmcrypt_ref.c - gtmcrypt_ref.h - gtmcrypt_sym_ref.h - gtmxc_types.h - import_and_sign_key.sh - install.sh - maskpass.c - pinentry-gtm.sh - pinentry.m - pinentry.m + add_executable(maskpass ${maskpass_SOURCES}) + target_link_libraries(maskpass ${GPG_LIBRARIES}) + set_target_properties(maskpass PROPERTIES + COMPILE_DEFINITIONS USE_GCRYPT + RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt ) - set(f_in "${GTM_SOURCE_DIR}/sr_unix/${f}") - set(f_out "${GTM_BINARY_DIR}/plugin/gtmcrypt/${f}") - add_custom_command( - OUTPUT "${f_out}" - DEPENDS "${f_in}" - COMMAND ${CMAKE_COMMAND} -E copy "${f_in}" "${f_out}" - ) - if("${f}" MATCHES "\\.sh$") - set(permissions PERMISSIONS ${install_permissions_script}) - else() - set(permissions "") - endif() - install(FILES "${f_out}" DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt ${permissions}) - list(APPEND files_to_place "${f_out}") -endforeach() + install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt) + + foreach(f + add_db_key.sh + build.sh + encrypt_sign_db_key.sh + gen_keypair.sh + gen_sym_hash.sh + gen_sym_key.sh + gtmcrypt.tab + gtmcrypt_dbk_ref.c + gtmcrypt_dbk_ref.h + gtmcrypt_interface.h + gtmcrypt_pk_ref.c + gtmcrypt_pk_ref.h + gtmcrypt_dbk_ref.c + gtmcrypt_dbk_ref.h + gtmcrypt_ref.c + gtmcrypt_ref.h + gtmcrypt_sym_ref.h + gtmxc_types.h + import_and_sign_key.sh + install.sh + maskpass.c + pinentry-gtm.sh + pinentry.m + pinentry.m + show_install_config.sh + ) + set(f_in "${GTM_SOURCE_DIR}/sr_unix/${f}") + set(f_out "${GTM_BINARY_DIR}/plugin/gtmcrypt/${f}") + add_custom_command( + OUTPUT "${f_out}" + DEPENDS "${f_in}" + COMMAND ${CMAKE_COMMAND} -E copy "${f_in}" "${f_out}" + ) + if("${f}" MATCHES "\\.sh$") + set(permissions PERMISSIONS ${install_permissions_script}) + else() + set(permissions "") + endif() + install(FILES "${f_out}" DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt ${permissions}) + list(APPEND files_to_place "${f_out}") + endforeach() +endif() install(TARGETS mumps @@ -603,6 +646,7 @@ foreach(f lke.hlp mumps.hlp mupip.hlp + custom_errors_sample.txt ) select_file(src ${f}) list(APPEND files ${src}) @@ -673,7 +717,10 @@ endforeach() #----------------------------------------------------------------------------- set(gtm_hlp mumps.hlp) set(gde_hlp gde.hlp) -foreach(help gtm gde) +set(mupip_hlp mupip.hlp) +set(dse_hlp dse.hlp) +set(lke_hlp lke.hlp) +foreach(help gtm gde mupip dse lke) set(CMAKE_CONFIGURABLE_FILE_CONTENT "Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${help}help.dat Change -region DEFAULT -record=1020 -key=255 @@ -736,6 +783,6 @@ install(FILES sr_unix/lowerc_cp.sh DESTINATION ${GTM_INSTALL_DIR} ) install(FILES COPYING DESTINATION ${GTM_INSTALL_DIR}) -install(FILES sr_port/README.txt DESTINATION ${GTM_INSTALL_DIR}) add_custom_target(place_files ALL DEPENDS ${files_to_place}) + diff --git a/README b/README index f8e6b64..c7a9d51 100755 --- a/README +++ b/README @@ -1,115 +1,90 @@ -All software in this package is part of FIS GT.M (http://fis-gtm.com) -which is Copyright 2012 Fidelity Information Services, Inc., and -provided to you under the terms of a license. If there is a COPYING +All software in this package is part of FIS GT.M (http://fis-gtm.com) +which is Copyright 2013 Fidelity Information Services, Inc., and +provided to you under the terms of a license. If there is a COPYING file included in this package, it contains the terms of the license under which the package is provided to you. If there is not a COPYING file in the package, you must ensure that your use of FIS GT.M complies with the license under which it is provided. If you are unsure as to the terms of -your license, please consult with the entity that provided you with the package. +your license, please consult with the entity that provided you with the +package. -The make file enclosed (sr_unix/comlist.mk) will build GT.M from source. -The prerequisites are GNU make, GT.M binary installation (which you can -download from http://sourceforge.net/projects/fis-gtm/), Linux x86, tcsh, -Unicode and GPG include files. Unicode include files are automatically -installed if ICU is installed. GPG include files require installing the -GNUPG and related library development packages. GNU make 3.81, -Ubuntu 10.04 LTS and RHEL 5.0 were used to do the test builds for this -distribution. The default ICU and GPG packages were taken from the OS -vendors' repositories. +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. -To build a production version GT.M for linux do the following steps: -1. Fulfill the pre-requisites. - Download and install GT.M binary distribution from SourceForge if you - do not have GT.M installed already. The build procedure needs an - existing GT.M mumps installed on the machine. +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. + + 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. + + [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.0-003 is /opt/fis-gtm/V6.0-003_i686 or + /opt/fis-gtm/V6.0-003_x8664. These instrcutions are written using x8664, please + use i686 as necessary. + + $ tar xfz gtm_V60003_linux_x8664_pro.tar.gz + + # Note down the installation path for use with cmake below - 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 - V54002 is /opt/lsb-gtm/V5.4-002_i686 or /opt/lsb-gtm/V5.4-002_x8664. - $ tar xfz gtm_V54002_linux_i686_src.tar.gz $ sudo sh ./configure 2. Unpack the GT.M sources - Change directory in the directory that you will place the GT.M source, - here after referred to as . - $ mkdir - $ cd - $ tar xfz gtm_V54002_linux_i686_src.tar.gz + The GT.M source tarball extracts to a directory with the version number in + the name, fis-gtm-V6.0-003 + $ tar xfz fis-gtm-V6.0-003.tar.gz + $ cd fis-gtm-V6.0-003 - You should find this README, COPYING file and sr_* source directroies. + You should find this README, LICENSE, COPYING and CMakeLists.txt file and + sr_* source directories. -3. Define environment variables needed to build GT.M - You will need to use tcsh to build GT.M. GT.M uses several csh script - files the define environment variables used in the build process. You - will need to define several variables prior to intiating your GT.M build. +3. Building GT.M - + can be a sub directory of the source directory, + fis-gtm-V6.0-003, or any other valid path. - - Define 'gtm_curpro' and 'gtm_exe' so that you can compile M programs. - This is the directory in which you installed the GT.M binaries from - SourceForge. - $ setenv gtm_curpro - $ setenv gtm_exe $gtm_curpro - $ setenv HOSTOS `uname -s` + $ mkdir + $ cd - - Define 'gtm_tools' and 'gtm_inc' - $ setenv gtm_tools $PWD/sr_linux - $ setenv gtm_inc $PWD/sr_linux + # [optional] If you installed GT.M, provide the directory path to cmake + # -D GTM_DIST:PATH=$gtm_dist + # + # By default the build produces release versions of GT.M. To build a debug + # version of GT.M supply the following parameter to cmake + # -D CMAKE_BUILD_TYPE=DEBUG + # + # Note that the cmake install does not create the final installed GT.M. + # Instead, it stages GT.M for distribution. Change the CMAKE_INSTALL_PREFIX + # to place the staged files in a local directory. To install GT.M, you must + # cd to that installed directory and execute the configure script. + # + # -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package + # + $ cmake /fis-gtm-V6.0-003 -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package - - [OPTIONAL] Ubuntu users must define 'distro' - $ setenv distro ubuntu + $ make - - [OPTIONAL] By default the build procedure will build 64 bit version of - GT.M on a x86_64 bit machine. - If you intend to build 32 bit version of GT.M on a x86_64 bit machine you - have to explicitly set the environment variable 'OBJECT_MODE' to '32' - $ setenv OBJECT_MODE 32 + $ make install - - Specify which ICU version is installed. - ICU version needs to be of the form #.# If the result of running - "icu-config --version" has the form #.#.#, just use the first two - parts. For example, if "icu-config --version" returns 3.8.1, use - 3.8 in the "setenv" step. - $ icu-config --version - $ setenv gtm_icu_version + $ cd package/lib/fis-gtm/V6.0-003_x86_64 - - Define 'gtm_version_change' and execute gtm_env.csh - $ setenv gtm_version_change 1 - $ source sr_unix/gtm_env.csh + # Now you are ready to install GT.M. Answer a few questions and install it. + # The recommended installation path is /opt/fis-gtm/V6.0-003_x86_64 -4. Building GT.M - + $ sudo ./configure -By default, the gmake will build a production version GT.M. The build type -of GT.M can be controlled by a parameter "buildtypes" - dbg (debug), -bta (beta), and pro (production). Passing a subset of dbg, bta, or pro in -"buildtypes" from the environment or the command line will build that subset. -For example: - - gmake -f sr_unix/comlist.mk -I./sr_unix -I./sr_linux buildtypes=dbg gtm_ver=$PWD - -will build just a debuggable GT.M release. - -You can clean your builds by appending 'clean' to the make line. -For example: - gmake -f sr_unix/comlist.mk -I./sr_unix -I./sr_linux buildtypes=dbg gtm_ver=$PWD clean - -5. Packaging GT.M - - -Once the required builds have been done the object distribution can be -tar'ed by doing: - - gmake -f sr_unix/comlist.mk -I./sr_unix -I./sr_linux gtm_ver=$PWD package - -Again, buildtypes can be used to package just a subset. For example: - - gmake -f sr_unix/comlist.mk -I./sr_unix -I./sr_linux buildtypes=pro gtm_ver=$PWD package - -Appendix: Known warnings and errors - - "cc1: note: obsolete option -I- used, please use -iquote instead" - You can safely ignore this warning - - - "chk2lev.mdep:2: *** missing separator. Stop." - tcsh is using the builtin echo, you need to set the environment variable - 'distro' to 'ubuntu' and clean your build. - $ setenv distro ubuntu + $ make clean +4. Packaging GT.M - + Create a tar file from the installed directory diff --git a/sr_i386/auto_zlink.c b/sr_i386/auto_zlink.c index cacfcc7..8f7350e 100644 --- a/sr_i386/auto_zlink.c +++ b/sr_i386/auto_zlink.c @@ -15,7 +15,7 @@ #include "i386.h" #include "urx.h" -#include "rtnhdr.h" +#include #include "op.h" #include diff --git a/sr_i386/cmerrors_ctl.c b/sr_i386/cmerrors_ctl.c index 94db2b9..0d89e8f 100644 --- a/sr_i386/cmerrors_ctl.c +++ b/sr_i386/cmerrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * diff --git a/sr_i386/cmierrors_ctl.c b/sr_i386/cmierrors_ctl.c index dbb0d2a..d8493c8 100644 --- a/sr_i386/cmierrors_ctl.c +++ b/sr_i386/cmierrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * diff --git a/sr_i386/emit_code.c b/sr_i386/emit_code.c index 657ec3b..66256ce 100644 --- a/sr_i386/emit_code.c +++ b/sr_i386/emit_code.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include "compiler.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "opcode.h" #include "xfer_enum.h" @@ -87,6 +87,9 @@ GBLDEF uint4 txtrel_cnt; /* count of text relocation records */ /* its referenced in ind_code.c */ GBLDEF int calculated_code_size, generated_code_size; +error_def(ERR_UNIMPLOP); +error_def(ERR_MAXARGCNT); + void trip_gen(triple *ct) { oprtype **sopr, *opr; /* triple operand */ @@ -99,8 +102,6 @@ void trip_gen(triple *ct) oprtype *irep_opr; short *repl, repcnt; /* temp irep ptr */ int4 off; - error_def (ERR_UNIMPLOP); - error_def (ERR_MAXARGCNT); tp = ttt[ct->opcode]; if (tp <= 0) @@ -125,8 +126,8 @@ void trip_gen(triple *ct) continue; } *sopr++ = opr; - if (sopr >= ARRAYTOP(saved_opr)) - rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS); + if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); } opr++; } @@ -752,8 +753,6 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r int4 offset, literal; triple *ct; - error_def (ERR_UNIMPLOP); - if (opr->oprclass == TRIP_REF) { ct = opr->oprval.tref; @@ -790,7 +789,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r temp_reg = I386_REG_ECX; break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } pc_value_idx = code_idx + 5; @@ -832,7 +831,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r code_idx += 1 + SIZEOF(int4); break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; @@ -940,7 +939,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r emit_base_offset(use_reg, base_reg, offset); break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; @@ -970,7 +969,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r temp_reg = I386_REG_ECX; break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } code_buf[code_idx++] = I386_INS_CALL_Jv; @@ -1032,7 +1031,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r } break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; @@ -1146,7 +1145,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r emit_base_offset(use_reg, base_reg, offset); break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; @@ -1175,9 +1174,6 @@ void emit_xfer(short xfer) void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_reg) { - - error_def (ERR_UNIMPLOP); - switch (op) { case CLEAR: @@ -1221,7 +1217,7 @@ void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_re code_buf[code_idx++] = 0; break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } } @@ -1271,8 +1267,6 @@ void emit_base_offset (short reg_opcode, short base_reg, int4 offset) void emit_op_alit (generic_op op, unsigned char use_reg) { - error_def (ERR_UNIMPLOP); - switch (op) { case LOAD_ADDRESS: @@ -1289,7 +1283,7 @@ void emit_op_alit (generic_op op, unsigned char use_reg) code_buf[code_idx++] = I386_INS_PUSH_Iv; break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } } diff --git a/sr_i386/error.si b/sr_i386/error.si index 97a3b83..0325ac4 100644 --- a/sr_i386/error.si +++ b/sr_i386/error.si @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2007 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -36,16 +36,13 @@ chnd_jmp = 12 .else # setjmp is really __sigsetjmp(env,0) .extern __sigsetjmp +.extern gtm_asm_establish .endif .sbttl error.si ESTABLISH .macro ESTABLISH x, label - addl $chnd_size,ctxt # ctxt++ + call gtm_asm_establish # Bulk of ESTABLISH macro movl ctxt,%eax - movl active_ch,%edx # ctxt->save_active_ch = active_ch - movl %edx,chnd_save_active(%eax) - movl $0,chnd_ch_active(%eax) # ctxt->ch_active = FALSE - movl %eax,active_ch # active_ch = ctxt movl $\x,chnd_ch(%eax) # ctxt->ch = x addl $chnd_jmp,%eax # setjmp(ctxt->jmp) .ifndef cygwin diff --git a/sr_i386/find_line_call.c b/sr_i386/find_line_call.c index 312dc2c..be5af91 100644 --- a/sr_i386/find_line_call.c +++ b/sr_i386/find_line_call.c @@ -12,7 +12,7 @@ #include "mdef.h" #include "xfer_enum.h" #include "i386.h" -#include "rtnhdr.h" /* Needed by zbreak.h */ +#include /* Needed by zbreak.h */ #include "zbreak.h" zb_code *find_line_call(void *addr) diff --git a/sr_i386/gdeerrors_ctl.c b/sr_i386/gdeerrors_ctl.c index d1253a8..90dc1b3 100644 --- a/sr_i386/gdeerrors_ctl.c +++ b/sr_i386/gdeerrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,6 +70,7 @@ LITDEF err_msg gdeerrors[] = { "NONASCII", "!AD is illegal for a !AD as it contains non-ASCII characters", 4, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "JNLALLOCGROW", "Increased Journal ALLOCATION from [!AD blocks] to [!AD blocks] to match AUTOSWITCHLIMIT for !AD !AD", 8, + "KEYFORBLK", "But block size !AD can only support key size !AD", 4, }; LITDEF int GDE_BLKSIZ512 = 150503435; @@ -129,9 +130,10 @@ LITDEF int GDE_WRITEERROR = 150503859; LITDEF int GDE_NONASCII = 150503866; LITDEF int GDE_CRYPTNOMM = 150503874; LITDEF int GDE_JNLALLOCGROW = 150503883; +LITDEF int GDE_KEYFORBLK = 150503891; GBLDEF err_ctl gdeerrors_ctl = { 248, "GDE", &gdeerrors[0], - 57}; + 58}; diff --git a/sr_i386/incr_link.c b/sr_i386/incr_link.c index 2bd6f98..5ad8c02 100644 --- a/sr_i386/incr_link.c +++ b/sr_i386/incr_link.c @@ -16,7 +16,7 @@ #include "gtm_string.h" #include -#include "rtnhdr.h" +#include #include "compiler.h" #include "urx.h" #include "objlabel.h" /* needed for masscomp.h */ diff --git a/sr_i386/make_cimode.c b/sr_i386/make_cimode.c index e91a472..e744f1e 100644 --- a/sr_i386/make_cimode.c +++ b/sr_i386/make_cimode.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "error.h" -#include "rtnhdr.h" +#include #include "op.h" #include "i386.h" #include "inst_flush.h" diff --git a/sr_i386/make_dmode.c b/sr_i386/make_dmode.c index 8523abc..92e5902 100644 --- a/sr_i386/make_dmode.c +++ b/sr_i386/make_dmode.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "error.h" -#include "rtnhdr.h" +#include #include "op.h" #include "i386.h" #include "inst_flush.h" diff --git a/sr_i386/merrors_ctl.c b/sr_i386/merrors_ctl.c index 8db8b9d..a409df6 100644 --- a/sr_i386/merrors_ctl.c +++ b/sr_i386/merrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -67,7 +67,7 @@ LITDEF err_msg merrors[] = { "NUMUNXEOR", "!_!AD!/!_!_!_unexpected end of record in numeric subscript", 2, "EXPR", "Expression expected but not found", 0, "STRUNXEOR", "!_!AD!/!_!_!_unexpected end of record in string subscript", 2, - "JNLEXTEND", "Journal file extension error. Journal file !AD closed.", 2, + "JNLEXTEND", "Journal file extension error for file !AD", 2, "FCHARMAXARGS", "Argument count of $CHAR function exceeded the maximum of 255", 0, "FCNSVNEXPECTED", "Function or special variable expected in this context", 0, "FNARGINC", "Format specifiers to $FNUMBER are incompatible: \"!AD\"", 2, @@ -95,7 +95,7 @@ LITDEF err_msg merrors[] = { "GVUNDEF", "Global variable undefined: !AD", 2, "TRANSNEST", "Maximum transaction nesting levels exceeded", 0, "INDEXTRACHARS", "Indirection string contains extra trailing characters", 0, - "INDMAXNEST", "Maximum nesting of indirection expressions exceeded", 0, + "UNUSEDMSG260", "INDMAXNEST Last used in V6.0-000", 0, "INDRMAXLEN", "Maximum length !UL of an indirection argument was exceeded", 1, "INSFFBCNT", "Insufficient byte count quota left for requested operation", 0, "INTEGERRS", "Database integrity errors", 0, @@ -195,7 +195,7 @@ LITDEF err_msg merrors[] = { "TEXTARG", "Invalid argument to $TEXT function", 0, "TMPSTOREMAX", "Maximum space for temporary values exceeded", 0, "VIEWCMD", "View parameter is not valid with VIEW command", 0, - "TXTNEGLIN", "A line prior to line number zero was referenced in $TEXT", 0, + "JNI", "!AD", 2, "TXTSRCFMT", "$TEXT encountered an invalid source program file format", 0, "UIDMSG", "Unidentified message received", 0, "UIDSND", "Unidentified sender PID", 0, @@ -204,9 +204,9 @@ LITDEF err_msg merrors[] = { "VAREXPECTED", "Variable expected in this context", 0, "VARRECBLKSZ", "Blocksize must be at least record size + 4 bytes", 0, "MAXARGCNT", "Maximum number of arguments !UL exceeded", 1, - "WCFAIL", "The database cache is corrupt", 0, + "GTMSECSHRSEMGET", "semget error errno = !UL", 1, "VIEWARGCNT", "View parameter !AD has inappropriate number of subparameters", 2, - "XKILLCNTEXC", "Maximum number of arguments (!UL) to exclusive kill exceeded", 1, + "GTMSECSHRDMNSTARTED", "gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", 5, "ZATTACHERR", "Error attaching to \"!AD\"", 2, "ZDATEFMT", "$ZDATE format string contains invalid character", 0, "ZEDFILSPEC", "Illegal ZEDIT file specification: !AD", 2, @@ -273,14 +273,14 @@ LITDEF err_msg merrors[] = { "MULTFORMPARM", "This formal parameter is multiply defined", 0, "QUITARGUSE", "Quit cannot take an argument in this context", 0, "NAMEEXPECTED", "A local variable name is expected in this context", 0, - "UNUSEDMSG438", "ACTLSTEXP: Last used in V5.4-002B", 0, + "FALLINTOFLST", "Fall-through to a label with formallist is not allowed", 0, "NOTEXTRINSIC", "Quit does not return to an extrinsic function: argument not allowed", 0, - "UNUSEDMSG440", "FMLLSTPRESENT: Last used in V5.4-002B", 0, + "GTMSECSHRREMSEMFAIL", "error removing semaphore errno = !UL", 1, "FMLLSTMISSING", "The formal list is absent from a label called with an actual list: !AD", 2, "ACTLSTTOOLONG", "More actual parameters than formal parameters: !AD", 2, "ACTOFFSET", "Actuallist not allowed with offset", 0, "MAXACTARG", "Maximum number of actual arguments exceeded", 0, - "GTMDUMPFAIL", "Could not create DUMP FILE", 0, + "GTMSECSHRREMSEM", "[client pid !UL] Semaphore (!UL) removed", 2, "JNLTMQUAL2", "Time qualifier LOOKBACK_TIME=\"!AZ\" is later than SINCE_TIME=\"!AZ\"", 2, "GDINVALID", "Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD", 6, "ASSERT", "Assert failed in !AD line !UL for expression (!AD)", 5, @@ -305,8 +305,8 @@ LITDEF err_msg merrors[] = { "DBBLEVMN", "!AD Block level less than zero", 2, "DBBSIZMN", "!AD Block too small", 2, "DBBSIZMX", "!AD Block larger than file block size", 2, - "DBRSIZMN", "!AD Record too small", 2, - "DBRSIZMX", "!AD Record too large", 2, + "DBRSIZMN", "!AD Physical record too small", 2, + "DBRSIZMX", "!AD Physical record too large", 2, "DBCMPNZRO", "!AD First record of block has nonzero compression count", 2, "DBSTARSIZ", "!AD Star record has wrong size", 2, "DBSTARCMP", "!AD Star record has nonzero compression count", 2, @@ -424,13 +424,13 @@ LITDEF err_msg merrors[] = { "BEGINST", "Beginning LOAD at record number: !UL", 1, "INVMVXSZ", "Invalid block size for GOQ load format", 0, "JNLWRTNOWWRTR", "Journal writer attempting another write", 0, - "MUPGDERR", "Command aborted due to global directory errors", 0, + "GTMSECSHRSHMCONCPROC", "More than one process attached to Shared memory segment (!UL) not removed (!UL)", 2, "JNLINVALLOC", "Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.", 3, "JNLINVEXT", "Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2, "MUPCLIERR", "Action not taken due to CLI errors", 0, "JNLTMQUAL4", "Time qualifier BEFORE_TIME=\"!AZ\" is less than AFTER_TIME=\"!AZ\"", 2, - "JNLBUFFTOOLG", "Journal file buffer !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2, - "JNLBUFFTOOSM", "Journal file buffer !UL is less than minimum of database block size in 512 byte pages + 1 (!UL)", 2, + "GTMSECSHRREMSHM", "[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", 3, + "GTMSECSHRREMFILE", "[client pid !UL] File (!AD) removed", 3, "MUNODBNAME", "A database name or the region qualifier must be specified", 0, "FILECREATE", "!AD file !AD created", 4, "FILENOTCREATE", "!AD file !AD not created", 4, @@ -452,7 +452,7 @@ LITDEF err_msg merrors[] = { "WCWRNNOTCHG", "Not all specified database files were changed", 0, "ZCWRONGDESC", "A string longer than 65535 is passed via 32-bit descriptor", 0, "MUTNWARN", "Database file !AD has 0x!16@XQ more transactions to go before reaching the transaction number limit (0x!16@XQ). Renew database with MUPIP INTEG TN_RESET", 4, - "JNLNAMLEN", "Journal file name !AD: for database file !AD exceeds maximum length of !UL", 5, + "GTMSECSHRUPDDBHDR", "[client pid !UL] database fileheader (!AD) updated !AD", 5, "LCKSTIMOUT", "DAL timed lock request expired", 0, "CTLMNEMAXLEN", "The maximum length of a control mnemonic has been exceeded", 0, "CTLMNEXPECTED", "Control mnemonic is expected in this context", 0, @@ -505,7 +505,7 @@ LITDEF err_msg merrors[] = { "CENOINDIR", "Indirection type information not available for compiler escape feature", 0, "COLLATIONUNDEF", "Collation type !UL is not defined", 1, "RBWRNNOTCHG", "Not all specified database files were changed", 0, - "GTMSECSHRSRVF", "!AD - !UL : Attempt to service request failed", 3, + "GTMSECSHRSRVF", "!AD - !UL : Attempt to service request failed (retry = !UL)", 4, "FREEZECTRL", "Control Y or control C encountered during attempt to freeze the database. Aborting freeze.", 0, "JNLFLUSH", "Error flushing journal buffers to journal file !AD", 2, "CCPSIGDMP", "CCP non fatal dump, continuing operation. Report to your GT.M Support Channel.", 0, @@ -542,7 +542,7 @@ LITDEF err_msg merrors[] = { "MUSTANDALONE", "Could not get exclusive access to !AD", 2, "MUNOACTION", "MUPIP unable to perform requested action", 0, "RMBIGSHARE", "File with BIGRECORD specified may only be shared if READONLY", 0, - "TPRESTART", "Database !AD; code: !AD; blk: 0x!XL in glbl: ^!AD; pvtmods: !UL, blkmods: !UL, blklvl: !UL, type: !UL, readset: !UL, writeset: !UL, local_tn: !16@XQ", 14, + "TPRESTART", "Database !AD; code: !AD; blk: 0x!XL in glbl: ^!AD; pvtmods: !UL, blkmods: !UL, blklvl: !UL, type: !UL, readset: !UL, writeset: !UL, local_tn: 0x!16@XQ", 14, "SOCKWRITE", "Write to a TCP/IP socket failed", 0, "DBCNTRLERR", "Database file !AD: control error suspected but not found", 2, "NOTERMENV", "Environment variable TERM not set. Assuming \"unknown.\"", 0, @@ -576,26 +576,26 @@ LITDEF err_msg merrors[] = { "ZCPREALLNUMEX", "Pre-allocation value should be a decimal number", 0, "ZCPREALLVALPAR", "Pre-allocation allowed only for variables passed by reference", 0, "VERMISMATCH", "Attempt to access !AD with version !AD, while already using !AD", 6, - "JNLCNTRL", "Journal control unsynchronized. Journaling closed for !AD.", 2, + "JNLCNTRL", "Journal control unsynchronized for !AD.", 2, "TRIGNAMBAD", "Trigger initialization failed. Error while processing ^#t(\"!AD\",!AD)", 4, "BUFRDTIMEOUT", "Pid [0x!XL] timed out waiting for buffered read of blk [0x!XL] into cr [0x!XL] by process [0x!XL] to complete in database file !AD", 6, "INVALIDRIP", "Invalid read-in-progress field in Cache Record. Resetting and continuing. Region: !AD.", 2, "BLKSIZ512", "Block size !UL rounds to !UL", 2, "MUTEXERR", "Mutual Exclusion subsystem failure", 0, "JNLVSIZE", "Journal File !AD has incorrect virtual_filesize !UL. Allocation : !UL, Extension : !UL, Filesize : !UL, File system block size : !UL", 7, - "MUTEXLCKALERT", "Mutual Exclusion subsystem ALERT - lock attempt threshold crossed for region !AD. Process !UL is in crit.", 3, + "MUTEXLCKALERT", "Mutual Exclusion subsystem ALERT - lock attempt threshold crossed for region !AD. Process !UL is in crit cycle !UL.", 4, "MUTEXFRCDTERM", "Mutual Exclusion subsystem detected forced termination of process !UL. Crit salvaged from region !AD.", 3, "GTMSECSHR", "!UL : Error during gtmsecshr operation", 1, - "GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL.", 6, - "GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD.", 7, - "SOCKACTNA", "Action not appropriate for current socket", 0, + "GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL", 6, + "GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD", 7, + "FREEBLKSLOW", "Only !UL free blocks left out of !UL total blocks for !AD", 4, "PROTNOTSUP", "Protocol !AD not supported", 2, "DELIMSIZNA", "Delimiter size is not appropriate", 0, "INVCTLMNE", "Invalid control mnemonics", 0, "SOCKLISTEN", "Error listening on a socket", 0, "LQLENGTHNA", "Listening queue length !UL not appropriate. Must be between 1 and 5.", 1, "ADDRTOOLONG", "Socket address !AD of length !UL is longer than the maximum permissible length !UL", 4, - "UNUSEDMSG760", "LSNCONNOTCMP Last used in V5.4-002A", 0, + "GTMSECSHRGETSEMFAIL", "error getting semaphore errno = !UL", 1, "CPBEYALLOC", "Attempt to copy beyond the allocated buffer", 0, "DBRDONLY", "Database file !AD read only", 2, "DUPTN", "Duplicate transaction found [TN = 0x!16@XQ] at offset 0x!XL in journal file !AD", 4, @@ -616,7 +616,7 @@ LITDEF err_msg merrors[] = { "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, "JNLMINALIGN", "Journal Record Alignment !UL is less than the minimum value of !UL", 2, - "JNLDSKALIGN", "Journal Record Alignment !UL is not a multiple of 512", 1, + "UNUSEDMSG781", "JNLDSKALIGN : Last used in V4.3-000", 0, "JNLPOOLSETUP", "Journal Pool setup error", 0, "JNLSTATEOFF", "ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON", 2, "RECVPOOLSETUP", "Receive Pool setup error", 0, @@ -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, - "GTMSECSHRLOGF", "!AD - !UL : Error while creating gtmsecshr log file", 3, + "UNUSEDMSG809", "GTMSECSHRLOGF last used in V5.5-000", 0, "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, @@ -679,7 +679,7 @@ LITDEF err_msg merrors[] = { "BUFFLUFAILED", "Error flushing buffers from !AD for database file !AD", 4, "MUQUALINCOMP", "Incompatible qualifiers - FILE and REGION", 0, "DISTPATHMAX", "$gtm_dist path is greater than maximum (!UL)", 1, - "MAXTRACEHEIGHT", "The maximum trace tree height (!UL) has been exceeded. The trace information will be incomplete.", 1, + "UNUSEDMSG844", "MAXTRACEHEIGHT last used in V5.4-002", 0, "IMAGENAME", "The executing module name should be !AD instead of !AD", 4, "GTMSECSHRPERM", "The gtmsecshr module in $gtm_dist does not have the correct permission and uid", 0, "GTMDISTUNDEF", "Environment variable $gtm_dist is not defined", 0, @@ -733,8 +733,8 @@ 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, - "GTMSECSHRLOGSWH", "Error switching gtmsecshr log file gtmsecshr log -- !AD original log -- !AD error phase -- !AD process id -- !UL", 7, - "GTMSECSHRDEFLOG", "$gtm_log is either undefined or not defined to an absolute path, thus gtm_log is set to its default !AD", 2, + "UNUSEDMSG898", "GTMSECSHRLOGSWH last used in V5.5-000", 0, + "UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0, "DBBADNSUB", "!AD Bad numeric subscript", 2, "DBBADKYNM", "!AD Bad key name", 2, "DBBADPNTR", "!AD Bad pointer value in directory", 2, @@ -785,7 +785,7 @@ LITDEF err_msg merrors[] = { "DBMBPFRINT", "!AD Master bit map shows this map has space, agreeing with MUPIP INTEG", 2, "DBMAXKEYEXC", "!AD Maximum key size for database exceeds design maximum", 2, "DBMXRSEXCMIN", "!AD Maximum record size for database is less than the design minimum", 2, - "DBMAXRSEXBL", "!AD Maximum record size for database exceeds what the block size can support", 2, + "UNUSEDMSG950", "DBMAXRSEXBL : Last used in V5.5-000", 0, "DBREADBM", "!AD Read error on bitmap", 2, "DBCOMPTOOLRG", "!AD Record has too large compression count", 2, "DBVERPERFWARN2", "Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance", 2, @@ -807,14 +807,14 @@ LITDEF err_msg merrors[] = { "SEMWT2LONG", "Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL", 7, "REPLINSTOPEN", "Error opening replication instance file !AD", 2, "REPLINSTCLOSE", "Error closing replication instance file !AD", 2, - "JNLNOTFOUND", "File !AD does not exist -- possibly moved or deleted", 2, + "UNUSEDMSG972", "JNLNOTFOUND : Last used in V4.4-000", 0, "DBCRERR8", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16@XQ, expecting 0x!16@XQ -- called from module !AD at line !UL", 11, "NUMPROCESSORS", "Could not determine number of processors", 0, "DBADDRANGE8", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16@XQ was outside !AD range 0x!16@XQ to 0x!16@XQ", 9, "RNDWNSEMFAIL", "Attempting to acquire gds_rundown semaphore when it is already owned", 0, "GTMSECSHRSHUTDN", "gtmsecshr process has received a shutdown request -- shutting down", 0, - "NOSPACECRE", "Not enough space to create database file !AD. !UL blocks are needed, only !UL available.", 4, - "LOWSPACECRE", "Disk space for database file !AD is not enough for !UL future extensions. !UL !UL-byte blocks are needed, only !UL available.", 6, + "NOSPACECRE", "Not enough space to create database file !AD. !@ZQ blocks are needed, only !@ZQ available.", 4, + "LOWSPACECRE", "Disk space for database file !AD is not enough for !UL future extensions. !@ZQ !UL-byte blocks are needed, only !@ZQ available.", 6, "WAITDSKSPACE", "Process 0x!XL will wait !UL seconds for necessary disk space to become available for !AD ", 4, "OUTOFSPACE", "Database file !AD ran out of disk space. Detected by process !UL. !/Exit without clearing shared memory due to the disk space constraints. !/Make space and then perform mupip rundown to ensure database integrity.", 3, "JNLPVTINFO", "Pid 0x!XL!/ cycle 0x!XL fd_mismatch 0x!XL channel 0x!XL sync_io 0x!XL!/ pini_addr 0x!XL qio_active 0x!XL old_channel 0x!XL", 8, @@ -824,16 +824,16 @@ LITDEF err_msg merrors[] = { "RENAMEFAIL", "Rename of file !AD to !AD failed", 4, "FILERENAME", "File !AD is renamed to !AD", 4, "JNLBUFINFO", "Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL", 16, - "JNLQIOLOCKED", "Error obtaining io_in_prog lock on jnl-file !AD", 2, - "JNLEOFPREZERO", "Error while zeroing jnl-file !AD", 2, + "UNUSEDMSG989", "JNLQIOLOCKED : Last used in V4.4-000", 0, + "UNUSEDMSG990", "JNLEOFPREZERO : Last used in V4.4-000", 0, "TPNOTACID", "!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD", 8, "JNLSETDATA2LONG", "SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.", 2, "JNLNEWREC", "Target system cannot recognize journal record of type !UL, last recognized type is !UL", 2, "REPLFTOKSEM", "Error with replication semaphores for instance file !AD", 2, - "GETCWD", "Error getting current working directory for file !AD", 2, + "UNUSEDMSG995", "GETCWD : Last used before V4.0-001E", 0, "EXTRIOERR", "Error writing extract file !AD", 2, "EXTRCLOSEERR", "Error closing extract file !AD", 2, - "TRUNCATE", "Error while truncating jnl-file !AD to length !UL", 3, + "UNUSEDMSG998", "TRUNCATE : Last used in V4.3-001F", 0, "REPLEXITERR", "Replication process encountered an error while exiting", 0, "MUDESTROYSUC", "Global section (!AD) corresponding to file !AD successfully destroyed", 4, "DBRNDWN", "Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.", 2, @@ -846,7 +846,7 @@ LITDEF err_msg merrors[] = { "TCSETATTR", "Error while setting terminal attributes on file descriptor !UL", 1, "IOWRITERR", "IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.", 5, "REPLINSTWRITE", "Error writing [0x!XL] bytes at offset [0x!16@XQ] in replication instance file !AD", 4, - "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL is incorrect, should be 0x!XL. Auto-corrected.", 4, + "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.", 4, "REQ2RESUME", "Request to resume suspended processing received from process !UL owned by userid !UL", 2, "TIMERHANDLER", "Incorrect SIGALRM handler (0x!XJ) found by !AD", 3, "FREEMEMORY", "Error occurred freeing memory from 0x!XJ", 1, @@ -860,7 +860,7 @@ LITDEF err_msg merrors[] = { "REPLACCSEM", "Error with replication access semaphore (id = !UL) for instance file !AD", 3, "JNLFLUSHNOPROG", "No progress while attempting to flush journal file !AD", 2, "REPLINSTCREATE", "Error creating replication instance file !AD", 2, - "SUSPENDING", "Suspending processing on user request or attempt to do terminal I/O while running in the background", 0, + "SUSPENDING", "Process Received Signal !UL. Suspending processing on user request or attempt to do terminal I/O while running in the background", 1, "SOCKBFNOTEMPTY", "Socket buffer size cannot be set to 0x!XL due to 0x!XL bytes of buffered data. Read first.", 2, "ILLESOCKBFSIZE", "The specified socket buffer size is 0x!XL, which is either 0 or too big", 1, "NOSOCKETINDEV", "There is no socket in the current socket device", 0, @@ -914,7 +914,7 @@ LITDEF err_msg merrors[] = { "SYSTEMVALUE", "Invalid value for $SYSTEM (!AD)", 2, "SIZENOTVALID4", "Size (in bytes) must be either 1, 2, or 4", 0, "STRNOTVALID", "Error: cannot convert !AD value to valid value", 2, - "RECNOCREJNL", "Recover could not create new journal file !AD", 2, + "UNUSEDMSG1079", "RECNOCREJNL : Last used in V4.3-001F", 0, "ERRWETRAP", "Error while processing $ETRAP", 0, "TRACINGON", "Tracing already turned on", 0, "CITABENV", "Environment variable for call-in table !AD not set", 2, @@ -942,9 +942,9 @@ LITDEF err_msg merrors[] = { "ZDIROUTOFSYNC", "$ZDIRECTORY !AD is not the same as its cached value !AD", 4, "GBLNOEXIST", "Global !AD no longer exists", 2, "MAXBTLEVEL", "Global !AD reached maximum level", 2, - "JNLSTRESTFL", "Failed to restore journaling state for database !AD", 2, + "UNUSEDMSG1107", "JNLSTRESTFL : found no evidence it ever was used in a production release", 0, "JNLALIGNSZCHG", "Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)", 1, - "MAXTRACELEVEL", "The maximum traceable level of !UL has been exceeded. The frame information will not be maintained.", 1, + "UNUSEDMSG1109", "MAXTRACELEVEL : last used in V5.4-002B", 0, "GVFAILCORE", "A core file is being created for later analysis if necessary", 0, "DBCDBNOCERTIFY", "Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN", 2, "DBFRZRESETSUC", "Freeze released successfully on database file !AD", 2, @@ -966,7 +966,7 @@ LITDEF err_msg merrors[] = { "PREVJNLLINKCUT", "Previous journal file name link set to NULL in new journal file !AD created for database file !AD", 4, "PREVJNLLINKSET", "Previous generation journal file name is changed from !AD to !AD", 4, "FILENAMETOOLONG", "File name too long", 0, - "UNUSEDMSG1131", "JNLCREATERR Last used in V5.4-001", 0, + "REQRECOV", "Error accessing database !AD. Must be recovered on cluster node !AD.", 4, "JNLTRANS2BIG", "Transaction needs an estimated [!UL blocks] in journal file !AD which exceeds the AUTOSWITCHLIMIT of !UL blocks", 4, "JNLSWITCHTOOSM", "Journal AUTOSWITCHLIMIT [!UL blocks] is less than Journal ALLOCATION [!UL blocks] for database file !AD", 4, "JNLSWITCHSZCHG", "Journal AUTOSWITCHLIMIT [!UL blocks] is rounded down to [!UL blocks] to equal the sum of Journal ALLOCATION [!UL blocks] and a multiple of Journal EXTENSION [!UL blocks] for database file !AD", 6, @@ -1090,7 +1090,7 @@ LITDEF err_msg merrors[] = { "REPLINSTSEQORD", "!AD has seqno [0x!16@XQ] which is less than last record seqno [0x!16@XQ] in replication instance file !AD", 6, "REPLINSTSTNDALN", "Could not get exclusive access to replication instance file !AD", 2, "REPLREQROLLBACK", "Replication instance file !AD indicates abnormal shutdown or an incomplete ROLLBACK. Run MUPIP JOURNAL ROLLBACK first", 2, - "UNUSEDMSG1255", "REPLUPGRADEPRI : Last used in V5.4-002B", 0, + "REQROLLBACK", "Error accessing database !AD. Run MUPIP JOURNAL ROLLBACK on cluster node !AD.", 4, "UNUSEDMSG1256", "REPLUPGRADESEC : Last used in V5.4-002B", 0, "SRCSRVEXISTS", "Source server for secondary instance !AD is already running with pid !UL", 3, "SRCSRVNOTEXIST", "Source server for secondary instance !AD is not alive", 2, @@ -1132,7 +1132,7 @@ LITDEF err_msg merrors[] = { "COMMITWAITPID", "Pid !UL waited !UL minute(s) for pid !UL to finish commits to block 0x!XL in database file !AD", 6, "UPDREPLSTATEOFF", "Error replicating global ^!AD as it maps to database !AD which has replication turned OFF", 4, "LITNONGRAPH", "M standard requires graphics in string literals", 0, - "DBFHEADERR8", "Database file !AD: control problem: !AD was 0x!XJ expecting 0x!XJ", 6, + "DBFHEADERR8", "Database file !AD: control problem: !AD was 0x!16@XQ expecting 0x!16@XQ", 6, "MMBEFOREJNL", "BEFORE image journaling cannot be set with MM access method in database file !AD", 2, "MMNOBFORRPL", "Replication cannot be used in database file !AD which uses MM access method and NOBEFORE image journaling", 2, "KILLABANDONED", "Abandoned kills counter is greater than zero for file !AD, !AD", 4, @@ -1145,15 +1145,15 @@ LITDEF err_msg merrors[] = { "DZWRNOALIAS", "$ZWRTAC cannot be aliased", 0, "FREEZEERR", "Error while trying to !AD region !AD", 4, "CLOSEFAIL", "Error while closing file descriptor !SL", 1, - "CRYPTINIT", "Error initializing encryption library. !AD", 2, - "CRYPTOPFAILED", "Encrypt/Decrypt operation failed. !AD", 2, - "CRYPTDLNOOPEN", "Error loading encryption library. !AD", 2, + "CRYPTINIT", "Could not initialize encryption library while opening encrypted file !AD. !AD", 4, + "CRYPTOPFAILED", "Encrypt/Decrypt operation failed for file !AD. !AD", 4, + "CRYPTDLNOOPEN", "Could not load encryption library while opening encrypted file !AD. !AD", 4, "CRYPTNOV4", "!AD is an encrypted database. Cannot downgrade(to V4) with Encryption option enabled.", 2, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "CRYPTJNLWRONGHASH", "Encryption key hash mismatch between journal file !AD and corresponding database file !AD", 4, - "CRYPTKEYFETCHFAILED", "Cannot obtain encryption key for !AD. !AD", 4, - "CRYPTKEYFETCHFAILEDNF", "Cannot obtain encryption key. !AD", 2, - "CRYPTHASHGENFAILED", "Error generating encryption hash. !AD", 2, + "CRYPTKEYFETCHFAILED", "Could not retrieve encryption key corresponding to file !AD. !AD", 4, + "CRYPTKEYFETCHFAILEDNF", "Could not retrieve encryption key during !AD operation key. !AD", 4, + "CRYPTHASHGENFAILED", "Could not generate cryptographic hash for symmetric key corresponding to file !AD. !AD", 4, "CRYPTNOPSWDINTP", "Cannot prompt for password inside a TP transaction.", 0, "BADTAG", "Unable to use file !AD (CCSID !UL) with CCSID !UL", 4, "ICUVERLT36", "!AD !UL.!UL. ICU version greater than or equal to 3.6 should be used", 4, @@ -1189,7 +1189,7 @@ LITDEF err_msg merrors[] = { "TRIGTLVLCHNG", "Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started", 2, "TRIGNAMEUNIQ", "Unable to make trigger name !AD unique beyond !UL versions already loaded", 3, "ZTRIGINVACT", "Missing or invalid parameter in position !UL given to $ZTRIGGER()", 1, - "UNUSEDMSG1354", "ZTRIGNOTP : Last used in V5.4-001", 0, + "INDRCOMPFAIL", "Compilation of indirection failed", 0, "QUITALSINV", "QUIT * return when the extrinsic was not invoked with SET *", 0, "PROCTERM", "!AD process termination due to !AD (return code !UL) from !AD", 7, "SRCLNNTDSP", "Source lines exceeding !UL character width are not displayed", 1, @@ -1202,10 +1202,10 @@ 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@XQ", 7, "TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0, - "TPLOCKRESTMAX", "Transaction restarts due to unavailability of locks not allowed in a final TP retry more than !UL times", 1, + "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0, "GBLEXPECTED", "Global variable reference expected in this context", 0, "GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2, - "UNUSEDMSG1370", "ONLYLDTRIG: Last used in V5.4-001", 0, + "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@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, @@ -1217,7 +1217,7 @@ LITDEF err_msg merrors[] = { "REPLXENDIANFAIL", "!AD side encountered error while doing endian conversion at journal sequence number 0x!16@XQ", 3, "ZGOTOINVLVL2", "ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)", 0, "GTMSECSHRCHDIRF", "gtmsecshr unable to chdir to its temporary directory (!AD)", 2, - "UNUSEDMSG1382", "FORCTRLINDX: Only used in V5.4-002", 0, + "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@XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1, @@ -1248,12 +1248,12 @@ LITDEF err_msg merrors[] = { "NORESYNCUPDATERONLY", "NORESYNC qualifier only allowed on a Supplementary Instance which allows local updates", 0, "NOSUPPLSUPPL", "Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD", 4, "REPL2OLD", "Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD", 4, - "RCVR2MANY", "The instance already has the maximum supportable number of receiver servers [!UL] active", 1, - "RLBKCONFIGBNDRY", "Rollback encountered journal records indicating current source !AD replaced old source !AD; cannot rollback past sequence number 0x!16@XQ", 5, + "EXTRFILEXISTS", "Error opening output file: !AD -- File exists", 2, + "MUUSERECOV", "Abnormal shutdown of journaled database !AD detected", 2, "SECNOTSUPPLEMENTARY", "!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD ", 4, "SUPRCVRNEEDSSUPSRC", "Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD", 4, - "SYNCTOSAMETYPE", "Source instance !AD and receiver instance !AD must either be both supplementary or both non-supplementary for them to synchronize their state", 4, - "TARGINSRUNNING", "Cannot change the instance definition of instance !AD while it is running", 2, + "UNUSEDMSG1417", "SYNCTOSAMETYPE: Never used before so slot free for reuse", 0, + "UNUSEDMSG1418", "TARGINSRUNNING: Never used before so slot free for reuse", 0, "UPDSYNC2MTINS", "Can only UPDATERESYNC with an empty instance file", 0, "UPDSYNCINSTFILE", "Error with instance file name specified in UPDATERESYNC qualifier", 0, "REUSEINSTNAME", "Error with instance name specified in REUSE qualifier", 0, @@ -1272,7 +1272,7 @@ LITDEF err_msg merrors[] = { "ORLBKNOV4BLK", "Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue", 4, "DBROLLEDBACK", "Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid", 0, "DSEWCREINIT", "Database cache reinitialized by DSE for region !AD", 2, - "RNDWNSKIPCNT", "A total of !UL process(es) skipped database rundown due to a concurrent ONLINE ROLLBACK", 1, + "MURNDWNOVRD", "OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD", 2, "REPLONLNRLBK", "ONLINE ROLLBACK detected. Starting afresh", 0, "SRVLCKWT2LNG", "PID !UL is holding the source server lock. Waited for !UL minute(s). Now exiting", 2, "IGNBMPMRKFREE", "Ignoring bitmap free-up operation for region !AD (!AD) due to concurrent ONLINE ROLLBACK", 4, @@ -1295,6 +1295,74 @@ LITDEF err_msg merrors[] = { "STRMSEQMISMTCH", "Unable to play update on Stream !2UL with seqno [0x!16@XQ] as receiving instance has a different stream seqno [0x!16@XQ]", 3, "LOCKSPACEINFO", "Region: !AD: processes on queue: !UL/!UL; LOCK slots in use: !UL/!UL; name space!ADfull", 8, "JRTNULLFAIL", "Applying NULL journal record failed. Failure code: !AD.", 2, + "LOCKSUB2LONG", "Following subscript is !UL bytes long which exceeds 255 byte limit.", 1, + "RESRCWAIT", "Waiting briefly for the !AD semaphore for region !AD (!AD) was held by PID !UL (Sem. ID: !UL).", 8, + "RESRCINTRLCKBYPAS", "!AD with PID !UL bypassing the !AD semaphore for region !AD (!AD) was held by PID !UL.", 10, + "DBFHEADERRANY", "Database file !AD: control problem: !AD was 0x!XJ expecting 0x!XJ", 6, + "REPLINSTFROZEN", "Instance !AZ is now Frozen", 1, + "REPLINSTFREEZECOMMENT", "Freeze Comment: !AZ", 1, + "REPLINSTUNFROZEN", "Instance !AZ is now Unfrozen", 1, + "DSKNOSPCAVAIL", "Attempted write to file !AD failed due to lack of disk space. Retrying indefinitely.", 2, + "DSKNOSPCBLOCKED", "Retry of write to file !AD suspended due to new instance freeze. Waiting for instance to be unfrozen.", 2, + "DSKSPCAVAILABLE", "Write to file !AD succeeded after out-of-space condition cleared", 2, + "ENOSPCQIODEFER", "Write to file !AD deferred due to lack of disk space", 2, + "CUSTOMFILOPERR", "Error while doing !AD operation on file !AD", 4, + "CUSTERRNOTFND", "Error mnemonic !AD specified in custom errors file is not valid for this version of GT.M", 2, + "CUSTERRSYNTAX", "Syntax error in file !AD at line number !UL", 3, + "ORLBKINPROG", "Online ROLLBACK in progress by PID !UL in region !AD", 3, + "DBSPANGLOINCMP", "!AD Spanning node is missing. Block no !UL of spanning node is missing", 3, + "DBSPANCHUNKORD", "!AD Chunk of !UL blocks is out of order", 3, + "DBDATAMX", "!AD Record too large", 2, + "DBIOERR", "Error while doing write operation on region !AD (!AD)", 4, + "INITORRESUME", "UPDATERESYNC on a Supplementary Instance must additionally specify INITIALIZE or RESUME", 0, + "GTMSECSHRNOARG0", "gtmsecshr cannot identify its origin - argv[0] is null", 0, + "GTMSECSHRISNOT", "gtmsecshr is not running as gtmsecshr but !AD - must be gtmsecshr", 2, + "GTMSECSHRBADDIR", "gtmsecshr is not running from $gtm_dist/gtmsecshrdir or $gtm_dist cannot be determined", 0, + "JNLBUFFREGUPD", "Journal file buffer size for region !AD has been adjusted from !UL to !UL.", 4, + "JNLBUFFDBUPD", "Journal file buffer size for database file !AD has been adjusted from !UL to !UL.", 4, + "LOCKINCR2HIGH", "Attempt to increment a LOCK more than !UL times", 1, + "LOCKIS", "!_!_Resource name: !AD", 2, + "LDSPANGLOINCMP", "Incomplete spanning node found during load", 0, + "MUFILRNDWNFL2", "Database section (id = !UL) belonging to database file !AD rundown failed", 3, + "MUINSTFROZEN", "!AD : Instance !AZ is frozen. Waiting for instance to be unfrozen before proceeding with writes to database file !AD", 5, + "MUINSTUNFROZEN", "!AD : Instance !AZ is now Unfrozen. Continuing with writes to database file !AD", 5, + "GTMEISDIR", "!AD : Is a directory", 2, + "SPCLZMSG", "The following error message cannot be driven through ZMESSAGE", 0, + "MUNOTALLINTEG", "At least one region skipped. See the earlier messages", 0, + "BKUPRUNNING", "Process !UL is currently backing up region !AD. Cannot start another backup.", 3, + "MUSIZEINVARG", "MUPIP SIZE : Invalid parameter value for: !AD", 2, + "MUSIZEFAIL", "MUPIP SIZE : failed. Failure code: !AD.", 2, + "SIDEEFFECTEVAL", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in actuallist, function arguments, non-Boolean binary operands or subscripts", 0, + "CRYPTINIT2", "Could not initialize encryption library !AD. !AD", 4, + "CRYPTDLNOOPEN2", "Could not load encryption library !AD. !AD", 4, + "CRYPTBADCONFIG", "Could not retrieve data from encrypted file !AD due to bad encryption configuration. !AD", 4, + "DBCOLLREQ", "JOURNAL EXTRACT proceeding without collation information for globals in database. !AD !AD", 4, + "SETEXTRENV", "Database files are missing or Instance is frozen; supply the database files, wait for the freeze to lift or define gtm_extract_nocol to extract possibly incorrect collation", 0, + "NOTALLDBRNDWN", "Not all regions were successfully rundown", 0, + "TPRESTNESTERR", "TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this", 0, + "JNLFILRDOPN", "Error opening journal file !AD for read for database file !AD", 4, + "SEQNUMSEARCHTIMEOUT", "Timed out trying to find sequence number !@ZQ [0x!16@XQ] in Journal File(s). See above messages for details. Source server exiting", 2, + "FTOKKEY", "FTOK key 0x!XL", 1, + "SEMID", "Semaphore id !UL", 1, + "JNLQIOSALVAGE", "Journal IO lock salvaged", 0, + "FAKENOSPCLEARED", "DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago", 1, + "MMFILETOOLARGE", "Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform", 4, + "BADZPEEKARG", "Missing, invalid or surplus !AD parameter for $ZPEEK()", 2, + "BADZPEEKRANGE", "Access exception raised in memory range given to $ZPEEK()", 0, + "BADZPEEKFMT", "$ZPEEK() value length inappropriate for selected format", 0, + "DBMBMINCFREFIXED", "Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected", 1, + "NULLENTRYREF", "JOB command did not specify entryref", 0, + "ZPEEKNORPLINFO", "$ZPEEK() unable to access requested replication structure", 0, + "MMREGNOACCESS", "Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs", 4, + "MALLOCMAXUNIX", "Exceeded maximum allocation defined by $gtm_max_storalloc", 0, + "MALLOCMAXVMS", "Exceeded maximum allocation defined by GTM_MAX_STORALLOC", 0, + "HOSTCONFLICT", "Host !AD could not open database file !AD because it is marked as already open on node !AD", 6, + "GETADDRINFO", "Error in getting address info", 0, + "GETNAMEINFO", "Error in getting name info", 0, + "SOCKBIND", "Error in binding TCP socket", 0, + "INSTFRZDEFER", "Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict", 4, + "REGOPENRETRY", "Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...", 4, + "REGOPENFAIL", "Failed to open region !AD (!AD) due to conflicting database shutdown activity", 4, }; LITDEF int ERR_ACK = 150372361; @@ -1379,11 +1447,11 @@ LITDEF int ERR_GVSUBOFLOW = 150372986; LITDEF int ERR_GVUNDEF = 150372994; LITDEF int ERR_TRANSNEST = 150373002; LITDEF int ERR_INDEXTRACHARS = 150373010; -LITDEF int ERR_INDMAXNEST = 150373018; +LITDEF int ERR_UNUSEDMSG260 = 150373018; LITDEF int ERR_INDRMAXLEN = 150373026; LITDEF int ERR_INSFFBCNT = 150373034; LITDEF int ERR_INTEGERRS = 150373042; -LITDEF int ERR_INVCMD = 150373050; +LITDEF int ERR_INVCMD = 150373048; LITDEF int ERR_INVFCN = 150373058; LITDEF int ERR_INVOBJ = 150373066; LITDEF int ERR_INVSVN = 150373074; @@ -1479,7 +1547,7 @@ LITDEF int ERR_TERMASTQUOTA = 150373786; LITDEF int ERR_TEXTARG = 150373794; LITDEF int ERR_TMPSTOREMAX = 150373802; LITDEF int ERR_VIEWCMD = 150373810; -LITDEF int ERR_TXTNEGLIN = 150373818; +LITDEF int ERR_JNI = 150373818; LITDEF int ERR_TXTSRCFMT = 150373826; LITDEF int ERR_UIDMSG = 150373834; LITDEF int ERR_UIDSND = 150373842; @@ -1488,9 +1556,9 @@ LITDEF int ERR_UNIMPLOP = 150373858; LITDEF int ERR_VAREXPECTED = 150373866; LITDEF int ERR_VARRECBLKSZ = 150373874; LITDEF int ERR_MAXARGCNT = 150373882; -LITDEF int ERR_WCFAIL = 150373890; +LITDEF int ERR_GTMSECSHRSEMGET = 150373890; LITDEF int ERR_VIEWARGCNT = 150373898; -LITDEF int ERR_XKILLCNTEXC = 150373906; +LITDEF int ERR_GTMSECSHRDMNSTARTED = 150373907; LITDEF int ERR_ZATTACHERR = 150373914; LITDEF int ERR_ZDATEFMT = 150373922; LITDEF int ERR_ZEDFILSPEC = 150373930; @@ -1545,7 +1613,7 @@ LITDEF int ERR_GVRUNDOWN = 150374314; LITDEF int ERR_LKRUNDOWN = 150374322; LITDEF int ERR_IORUNDOWN = 150374330; LITDEF int ERR_FILENOTFND = 150374338; -LITDEF int ERR_MUFILRNDWNFL = 150374347; +LITDEF int ERR_MUFILRNDWNFL = 150374346; LITDEF int ERR_JNLTMQUAL1 = 150374354; LITDEF int ERR_FORCEDHALT = 150374364; LITDEF int ERR_LOADEOF = 150374370; @@ -1557,14 +1625,14 @@ LITDEF int ERR_GVZPREVFAIL = 150374410; LITDEF int ERR_MULTFORMPARM = 150374418; LITDEF int ERR_QUITARGUSE = 150374426; LITDEF int ERR_NAMEEXPECTED = 150374434; -LITDEF int ERR_UNUSEDMSG438 = 150374442; +LITDEF int ERR_FALLINTOFLST = 150374442; LITDEF int ERR_NOTEXTRINSIC = 150374450; -LITDEF int ERR_UNUSEDMSG440 = 150374458; +LITDEF int ERR_GTMSECSHRREMSEMFAIL = 150374458; LITDEF int ERR_FMLLSTMISSING = 150374466; LITDEF int ERR_ACTLSTTOOLONG = 150374474; LITDEF int ERR_ACTOFFSET = 150374482; LITDEF int ERR_MAXACTARG = 150374490; -LITDEF int ERR_GTMDUMPFAIL = 150374498; +LITDEF int ERR_GTMSECSHRREMSEM = 150374498; LITDEF int ERR_JNLTMQUAL2 = 150374506; LITDEF int ERR_GDINVALID = 150374514; LITDEF int ERR_ASSERT = 150374524; @@ -1708,17 +1776,17 @@ LITDEF int ERR_LDGOQFMT = 150375618; LITDEF int ERR_BEGINST = 150375627; LITDEF int ERR_INVMVXSZ = 150375636; LITDEF int ERR_JNLWRTNOWWRTR = 150375642; -LITDEF int ERR_MUPGDERR = 150375650; +LITDEF int ERR_GTMSECSHRSHMCONCPROC = 150375650; LITDEF int ERR_JNLINVALLOC = 150375656; LITDEF int ERR_JNLINVEXT = 150375664; LITDEF int ERR_MUPCLIERR = 150375674; LITDEF int ERR_JNLTMQUAL4 = 150375682; -LITDEF int ERR_JNLBUFFTOOLG = 150375688; -LITDEF int ERR_JNLBUFFTOOSM = 150375696; +LITDEF int ERR_GTMSECSHRREMSHM = 150375691; +LITDEF int ERR_GTMSECSHRREMFILE = 150375699; LITDEF int ERR_MUNODBNAME = 150375706; LITDEF int ERR_FILECREATE = 150375715; LITDEF int ERR_FILENOTCREATE = 150375723; -LITDEF int ERR_JNLPROCSTUCK = 150375731; +LITDEF int ERR_JNLPROCSTUCK = 150375728; LITDEF int ERR_INVGLOBALQUAL = 150375738; LITDEF int ERR_COLLARGLONG = 150375746; LITDEF int ERR_NOPINI = 150375754; @@ -1736,7 +1804,7 @@ LITDEF int ERR_WCERRNOTCHG = 150375842; LITDEF int ERR_WCWRNNOTCHG = 150375848; LITDEF int ERR_ZCWRONGDESC = 150375858; LITDEF int ERR_MUTNWARN = 150375864; -LITDEF int ERR_JNLNAMLEN = 150375874; +LITDEF int ERR_GTMSECSHRUPDDBHDR = 150375875; LITDEF int ERR_LCKSTIMOUT = 150375880; LITDEF int ERR_CTLMNEMAXLEN = 150375890; LITDEF int ERR_CTLMNEXPECTED = 150375898; @@ -1872,14 +1940,14 @@ LITDEF int ERR_MUTEXFRCDTERM = 150376928; LITDEF int ERR_GTMSECSHR = 150376938; LITDEF int ERR_GTMSECSHRSRVFID = 150376944; LITDEF int ERR_GTMSECSHRSRVFIL = 150376952; -LITDEF int ERR_SOCKACTNA = 150376962; +LITDEF int ERR_FREEBLKSLOW = 150376960; LITDEF int ERR_PROTNOTSUP = 150376970; LITDEF int ERR_DELIMSIZNA = 150376978; LITDEF int ERR_INVCTLMNE = 150376986; LITDEF int ERR_SOCKLISTEN = 150376994; LITDEF int ERR_LQLENGTHNA = 150377002; LITDEF int ERR_ADDRTOOLONG = 150377010; -LITDEF int ERR_UNUSEDMSG760 = 150377018; +LITDEF int ERR_GTMSECSHRGETSEMFAIL = 150377018; LITDEF int ERR_CPBEYALLOC = 150377026; LITDEF int ERR_DBRDONLY = 150377034; LITDEF int ERR_DUPTN = 150377040; @@ -1900,7 +1968,7 @@ LITDEF int ERR_BCKUPBUFLUSH = 150377154; LITDEF int ERR_NOFORKCORE = 150377160; LITDEF int ERR_JNLREAD = 150377170; LITDEF int ERR_JNLMINALIGN = 150377176; -LITDEF int ERR_JNLDSKALIGN = 150377184; +LITDEF int ERR_UNUSEDMSG781 = 150377186; LITDEF int ERR_JNLPOOLSETUP = 150377194; LITDEF int ERR_JNLSTATEOFF = 150377202; LITDEF int ERR_RECVPOOLSETUP = 150377210; @@ -1928,7 +1996,7 @@ LITDEF int ERR_MUKILLIP = 150377376; LITDEF int ERR_JNLRDONLY = 150377386; LITDEF int ERR_ANCOMPTINC = 150377394; LITDEF int ERR_ABNCOMPTINC = 150377402; -LITDEF int ERR_GTMSECSHRLOGF = 150377410; +LITDEF int ERR_UNUSEDMSG809 = 150377410; LITDEF int ERR_SOCKNOTFND = 150377418; LITDEF int ERR_CURRSOCKOFR = 150377426; LITDEF int ERR_SOCKETEXIST = 150377434; @@ -1963,7 +2031,7 @@ LITDEF int ERR_RECSIZENOTEVEN = 150377658; LITDEF int ERR_BUFFLUFAILED = 150377666; LITDEF int ERR_MUQUALINCOMP = 150377674; LITDEF int ERR_DISTPATHMAX = 150377682; -LITDEF int ERR_MAXTRACEHEIGHT = 150377691; +LITDEF int ERR_UNUSEDMSG844 = 150377690; LITDEF int ERR_IMAGENAME = 150377698; LITDEF int ERR_GTMSECSHRPERM = 150377706; LITDEF int ERR_GTMDISTUNDEF = 150377714; @@ -2017,8 +2085,8 @@ LITDEF int ERR_SECONDAHEAD = 150378090; LITDEF int ERR_SCNDDBNOUPD = 150378098; LITDEF int ERR_MUINFOUINT4 = 150378107; LITDEF int ERR_NLMISMATCHCALC = 150378114; -LITDEF int ERR_GTMSECSHRLOGSWH = 150378122; -LITDEF int ERR_GTMSECSHRDEFLOG = 150378131; +LITDEF int ERR_UNUSEDMSG898 = 150378122; +LITDEF int ERR_UNUSEDMSG899 = 150378131; LITDEF int ERR_DBBADNSUB = 150378138; LITDEF int ERR_DBBADKYNM = 150378146; LITDEF int ERR_DBBADPNTR = 150378154; @@ -2069,7 +2137,7 @@ LITDEF int ERR_DBMBPFRDLBM = 150378504; LITDEF int ERR_DBMBPFRINT = 150378512; LITDEF int ERR_DBMAXKEYEXC = 150378522; LITDEF int ERR_DBMXRSEXCMIN = 150378530; -LITDEF int ERR_DBMAXRSEXBL = 150378538; +LITDEF int ERR_UNUSEDMSG950 = 150378538; LITDEF int ERR_DBREADBM = 150378546; LITDEF int ERR_DBCOMPTOOLRG = 150378554; LITDEF int ERR_DBVERPERFWARN2 = 150378560; @@ -2091,7 +2159,7 @@ LITDEF int ERR_MUTEXRSRCCLNUP = 150378683; LITDEF int ERR_SEMWT2LONG = 150378690; LITDEF int ERR_REPLINSTOPEN = 150378698; LITDEF int ERR_REPLINSTCLOSE = 150378706; -LITDEF int ERR_JNLNOTFOUND = 150378715; +LITDEF int ERR_UNUSEDMSG972 = 150378714; LITDEF int ERR_DBCRERR8 = 150378723; LITDEF int ERR_NUMPROCESSORS = 150378728; LITDEF int ERR_DBADDRANGE8 = 150378739; @@ -2108,16 +2176,16 @@ LITDEF int ERR_REPLJNLCLOSED = 150378818; LITDEF int ERR_RENAMEFAIL = 150378824; LITDEF int ERR_FILERENAME = 150378835; LITDEF int ERR_JNLBUFINFO = 150378843; -LITDEF int ERR_JNLQIOLOCKED = 150378850; -LITDEF int ERR_JNLEOFPREZERO = 150378858; +LITDEF int ERR_UNUSEDMSG989 = 150378850; +LITDEF int ERR_UNUSEDMSG990 = 150378858; LITDEF int ERR_TPNOTACID = 150378867; LITDEF int ERR_JNLSETDATA2LONG = 150378874; LITDEF int ERR_JNLNEWREC = 150378882; LITDEF int ERR_REPLFTOKSEM = 150378890; -LITDEF int ERR_GETCWD = 150378898; +LITDEF int ERR_UNUSEDMSG995 = 150378898; LITDEF int ERR_EXTRIOERR = 150378906; LITDEF int ERR_EXTRCLOSEERR = 150378914; -LITDEF int ERR_TRUNCATE = 150378922; +LITDEF int ERR_UNUSEDMSG998 = 150378922; LITDEF int ERR_REPLEXITERR = 150378930; LITDEF int ERR_MUDESTROYSUC = 150378939; LITDEF int ERR_DBRNDWN = 150378946; @@ -2130,7 +2198,7 @@ LITDEF int ERR_TCGETATTR = 150378994; LITDEF int ERR_TCSETATTR = 150379002; LITDEF int ERR_IOWRITERR = 150379010; LITDEF int ERR_REPLINSTWRITE = 150379018; -LITDEF int ERR_DBBADFREEBLKCTR = 150379027; +LITDEF int ERR_DBBADFREEBLKCTR = 150379024; LITDEF int ERR_REQ2RESUME = 150379035; LITDEF int ERR_TIMERHANDLER = 150379040; LITDEF int ERR_FREEMEMORY = 150379050; @@ -2138,11 +2206,11 @@ LITDEF int ERR_MUREPLSECDEL = 150379059; LITDEF int ERR_MUREPLSECNOTDEL = 150379067; LITDEF int ERR_MUJPOOLRNDWNSUC = 150379075; LITDEF int ERR_MURPOOLRNDWNSUC = 150379083; -LITDEF int ERR_MUJPOOLRNDWNFL = 150379091; -LITDEF int ERR_MURPOOLRNDWNFL = 150379099; +LITDEF int ERR_MUJPOOLRNDWNFL = 150379090; +LITDEF int ERR_MURPOOLRNDWNFL = 150379098; LITDEF int ERR_MUREPLPOOL = 150379107; LITDEF int ERR_REPLACCSEM = 150379114; -LITDEF int ERR_JNLFLUSHNOPROG = 150379122; +LITDEF int ERR_JNLFLUSHNOPROG = 150379120; LITDEF int ERR_REPLINSTCREATE = 150379130; LITDEF int ERR_SUSPENDING = 150379139; LITDEF int ERR_SOCKBFNOTEMPTY = 150379146; @@ -2198,7 +2266,7 @@ LITDEF int ERR_NOSUBSCRIPT = 150379538; LITDEF int ERR_SYSTEMVALUE = 150379546; LITDEF int ERR_SIZENOTVALID4 = 150379554; LITDEF int ERR_STRNOTVALID = 150379562; -LITDEF int ERR_RECNOCREJNL = 150379571; +LITDEF int ERR_UNUSEDMSG1079 = 150379570; LITDEF int ERR_ERRWETRAP = 150379578; LITDEF int ERR_TRACINGON = 150379587; LITDEF int ERR_CITABENV = 150379594; @@ -2216,7 +2284,7 @@ LITDEF int ERR_SETZDIR = 150379682; LITDEF int ERR_JOBACTREF = 150379690; LITDEF int ERR_ECLOSTMID = 150379696; LITDEF int ERR_ZFF2MANY = 150379706; -LITDEF int ERR_JNLFSYNCLSTCK = 150379715; +LITDEF int ERR_JNLFSYNCLSTCK = 150379712; LITDEF int ERR_DELIMWIDTH = 150379722; LITDEF int ERR_DBBMLCORRUPT = 150379730; LITDEF int ERR_DLCKAVOIDANCE = 150379738; @@ -2226,9 +2294,9 @@ LITDEF int ERR_INVZDIRFORM = 150379762; LITDEF int ERR_ZDIROUTOFSYNC = 150379768; LITDEF int ERR_GBLNOEXIST = 150379779; LITDEF int ERR_MAXBTLEVEL = 150379786; -LITDEF int ERR_JNLSTRESTFL = 150379794; +LITDEF int ERR_UNUSEDMSG1107 = 150379794; LITDEF int ERR_JNLALIGNSZCHG = 150379803; -LITDEF int ERR_MAXTRACELEVEL = 150379811; +LITDEF int ERR_UNUSEDMSG1109 = 150379810; LITDEF int ERR_GVFAILCORE = 150379818; LITDEF int ERR_DBCDBNOCERTIFY = 150379826; LITDEF int ERR_DBFRZRESETSUC = 150379835; @@ -2250,7 +2318,7 @@ LITDEF int ERR_JNLFNF = 150379955; LITDEF int ERR_PREVJNLLINKCUT = 150379963; LITDEF int ERR_PREVJNLLINKSET = 150379971; LITDEF int ERR_FILENAMETOOLONG = 150379978; -LITDEF int ERR_UNUSEDMSG1131 = 150379986; +LITDEF int ERR_REQRECOV = 150379986; LITDEF int ERR_JNLTRANS2BIG = 150379994; LITDEF int ERR_JNLSWITCHTOOSM = 150380002; LITDEF int ERR_JNLSWITCHSZCHG = 150380011; @@ -2374,7 +2442,7 @@ LITDEF int ERR_REPLINSTSECUNDF = 150380946; LITDEF int ERR_REPLINSTSEQORD = 150380954; LITDEF int ERR_REPLINSTSTNDALN = 150380962; LITDEF int ERR_REPLREQROLLBACK = 150380970; -LITDEF int ERR_UNUSEDMSG1255 = 150380978; +LITDEF int ERR_REQROLLBACK = 150380978; LITDEF int ERR_UNUSEDMSG1256 = 150380986; LITDEF int ERR_SRCSRVEXISTS = 150380994; LITDEF int ERR_SRCSRVNOTEXIST = 150381002; @@ -2473,7 +2541,7 @@ LITDEF int ERR_TRIGTCOMMIT = 150381738; LITDEF int ERR_TRIGTLVLCHNG = 150381746; LITDEF int ERR_TRIGNAMEUNIQ = 150381754; LITDEF int ERR_ZTRIGINVACT = 150381762; -LITDEF int ERR_UNUSEDMSG1354 = 150381770; +LITDEF int ERR_INDRCOMPFAIL = 150381770; LITDEF int ERR_QUITALSINV = 150381778; LITDEF int ERR_PROCTERM = 150381784; LITDEF int ERR_SRCLNNTDSP = 150381795; @@ -2486,10 +2554,10 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842; LITDEF int ERR_SSATTACHSHM = 150381850; LITDEF int ERR_TRIGDEFNOSYNC = 150381856; LITDEF int ERR_TRESTMAX = 150381866; -LITDEF int ERR_TPLOCKRESTMAX = 150381874; +LITDEF int ERR_UNUSEDMSG1367 = 150381874; LITDEF int ERR_GBLEXPECTED = 150381882; LITDEF int ERR_GVZTRIGFAIL = 150381890; -LITDEF int ERR_UNUSEDMSG1370 = 150381898; +LITDEF int ERR_MUUSERLBK = 150381898; LITDEF int ERR_SETINSETTRIGONLY = 150381906; LITDEF int ERR_DZTRIGINTRIG = 150381914; LITDEF int ERR_SECNODZTRIGINTP = 150381922; @@ -2501,7 +2569,7 @@ LITDEF int ERR_REPLNOXENDIAN = 150381962; LITDEF int ERR_REPLXENDIANFAIL = 150381970; LITDEF int ERR_ZGOTOINVLVL2 = 150381978; LITDEF int ERR_GTMSECSHRCHDIRF = 150381986; -LITDEF int ERR_UNUSEDMSG1382 = 150381994; +LITDEF int ERR_JNLORDBFLU = 150381994; LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002; LITDEF int ERR_ZCINVALIDKEYWORD = 150382010; LITDEF int ERR_REPLNOMULTILINETRG = 150382018; @@ -2532,12 +2600,12 @@ LITDEF int ERR_NORESYNCSUPPLONLY = 150382210; LITDEF int ERR_NORESYNCUPDATERONLY = 150382218; LITDEF int ERR_NOSUPPLSUPPL = 150382226; LITDEF int ERR_REPL2OLD = 150382234; -LITDEF int ERR_RCVR2MANY = 150382242; -LITDEF int ERR_RLBKCONFIGBNDRY = 150382250; +LITDEF int ERR_EXTRFILEXISTS = 150382242; +LITDEF int ERR_MUUSERECOV = 150382250; LITDEF int ERR_SECNOTSUPPLEMENTARY = 150382258; LITDEF int ERR_SUPRCVRNEEDSSUPSRC = 150382266; -LITDEF int ERR_SYNCTOSAMETYPE = 150382274; -LITDEF int ERR_TARGINSRUNNING = 150382282; +LITDEF int ERR_UNUSEDMSG1417 = 150382275; +LITDEF int ERR_UNUSEDMSG1418 = 150382283; LITDEF int ERR_UPDSYNC2MTINS = 150382290; LITDEF int ERR_UPDSYNCINSTFILE = 150382298; LITDEF int ERR_REUSEINSTNAME = 150382306; @@ -2556,7 +2624,7 @@ LITDEF int ERR_ORLBKFRZOVER = 150382403; LITDEF int ERR_ORLBKNOV4BLK = 150382410; LITDEF int ERR_DBROLLEDBACK = 150382418; LITDEF int ERR_DSEWCREINIT = 150382427; -LITDEF int ERR_RNDWNSKIPCNT = 150382435; +LITDEF int ERR_MURNDWNOVRD = 150382435; LITDEF int ERR_REPLONLNRLBK = 150382442; LITDEF int ERR_SRVLCKWT2LNG = 150382450; LITDEF int ERR_IGNBMPMRKFREE = 150382459; @@ -2579,9 +2647,77 @@ LITDEF int ERR_STRMNUMMISMTCH2 = 150382586; LITDEF int ERR_STRMSEQMISMTCH = 150382594; LITDEF int ERR_LOCKSPACEINFO = 150382603; LITDEF int ERR_JRTNULLFAIL = 150382610; +LITDEF int ERR_LOCKSUB2LONG = 150382618; +LITDEF int ERR_RESRCWAIT = 150382627; +LITDEF int ERR_RESRCINTRLCKBYPAS = 150382635; +LITDEF int ERR_DBFHEADERRANY = 150382643; +LITDEF int ERR_REPLINSTFROZEN = 150382650; +LITDEF int ERR_REPLINSTFREEZECOMMENT = 150382659; +LITDEF int ERR_REPLINSTUNFROZEN = 150382667; +LITDEF int ERR_DSKNOSPCAVAIL = 150382675; +LITDEF int ERR_DSKNOSPCBLOCKED = 150382682; +LITDEF int ERR_DSKSPCAVAILABLE = 150382691; +LITDEF int ERR_ENOSPCQIODEFER = 150382699; +LITDEF int ERR_CUSTOMFILOPERR = 150382706; +LITDEF int ERR_CUSTERRNOTFND = 150382714; +LITDEF int ERR_CUSTERRSYNTAX = 150382722; +LITDEF int ERR_ORLBKINPROG = 150382731; +LITDEF int ERR_DBSPANGLOINCMP = 150382738; +LITDEF int ERR_DBSPANCHUNKORD = 150382746; +LITDEF int ERR_DBDATAMX = 150382754; +LITDEF int ERR_DBIOERR = 150382762; +LITDEF int ERR_INITORRESUME = 150382770; +LITDEF int ERR_GTMSECSHRNOARG0 = 150382778; +LITDEF int ERR_GTMSECSHRISNOT = 150382786; +LITDEF int ERR_GTMSECSHRBADDIR = 150382794; +LITDEF int ERR_JNLBUFFREGUPD = 150382800; +LITDEF int ERR_JNLBUFFDBUPD = 150382808; +LITDEF int ERR_LOCKINCR2HIGH = 150382818; +LITDEF int ERR_LOCKIS = 150382827; +LITDEF int ERR_LDSPANGLOINCMP = 150382834; +LITDEF int ERR_MUFILRNDWNFL2 = 150382842; +LITDEF int ERR_MUINSTFROZEN = 150382851; +LITDEF int ERR_MUINSTUNFROZEN = 150382859; +LITDEF int ERR_GTMEISDIR = 150382866; +LITDEF int ERR_SPCLZMSG = 150382874; +LITDEF int ERR_MUNOTALLINTEG = 150382880; +LITDEF int ERR_BKUPRUNNING = 150382890; +LITDEF int ERR_MUSIZEINVARG = 150382898; +LITDEF int ERR_MUSIZEFAIL = 150382906; +LITDEF int ERR_SIDEEFFECTEVAL = 150382912; +LITDEF int ERR_CRYPTINIT2 = 150382922; +LITDEF int ERR_CRYPTDLNOOPEN2 = 150382930; +LITDEF int ERR_CRYPTBADCONFIG = 150382938; +LITDEF int ERR_DBCOLLREQ = 150382944; +LITDEF int ERR_SETEXTRENV = 150382954; +LITDEF int ERR_NOTALLDBRNDWN = 150382962; +LITDEF int ERR_TPRESTNESTERR = 150382970; +LITDEF int ERR_JNLFILRDOPN = 150382978; +LITDEF int ERR_SEQNUMSEARCHTIMEOUT = 150382986; +LITDEF int ERR_FTOKKEY = 150382995; +LITDEF int ERR_SEMID = 150383003; +LITDEF int ERR_JNLQIOSALVAGE = 150383011; +LITDEF int ERR_FAKENOSPCLEARED = 150383019; +LITDEF int ERR_MMFILETOOLARGE = 150383026; +LITDEF int ERR_BADZPEEKARG = 150383034; +LITDEF int ERR_BADZPEEKRANGE = 150383042; +LITDEF int ERR_BADZPEEKFMT = 150383050; +LITDEF int ERR_DBMBMINCFREFIXED = 150383056; +LITDEF int ERR_NULLENTRYREF = 150383066; +LITDEF int ERR_ZPEEKNORPLINFO = 150383074; +LITDEF int ERR_MMREGNOACCESS = 150383082; +LITDEF int ERR_MALLOCMAXUNIX = 150383090; +LITDEF int ERR_MALLOCMAXVMS = 150383098; +LITDEF int ERR_HOSTCONFLICT = 150383106; +LITDEF int ERR_GETADDRINFO = 150383114; +LITDEF int ERR_GETNAMEINFO = 150383122; +LITDEF int ERR_SOCKBIND = 150383130; +LITDEF int ERR_INSTFRZDEFER = 150383139; +LITDEF int ERR_REGOPENRETRY = 150383147; +LITDEF int ERR_REGOPENFAIL = 150383154; GBLDEF err_ctl merrors_ctl = { 246, "GTM", &merrors[0], - 1282}; + 1350}; diff --git a/sr_i386/mval_def.si b/sr_i386/mval_def.si index 96841c3..df6ce60 100644 --- a/sr_i386/mval_def.si +++ b/sr_i386/mval_def.si @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2011 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -95,6 +95,19 @@ top = 8 addl $4,%esp movl %eax, \mval \label: +.endm + + .sbttl mval_def.si mv_force_defined_strict +# --------------------------------------- +# mv_force_defined_strict(mval, label) +# --------------------------------------- +.macro mv_force_defined_strict mval, label + testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) + jne \label + pushl \mval + call underr_strict + addl $4,%esp +\label: .endm .sbttl mval_def.si mv_force_str diff --git a/sr_i386/obj_file.c b/sr_i386/obj_file.c index da40b0e..3ff8953 100644 --- a/sr_i386/obj_file.c +++ b/sr_i386/obj_file.c @@ -16,7 +16,7 @@ #include #include "compiler.h" -#include "rtnhdr.h" +#include #include "obj_gen.h" #include "cgp.h" #include "mdq.h" diff --git a/sr_i386/op_forloop.s b/sr_i386/op_forloop.s index e664c74..db3c17e 100644 --- a/sr_i386/op_forloop.s +++ b/sr_i386/op_forloop.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2008 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -53,7 +53,7 @@ ENTRY op_forloop pushl %esi pushl %ebx movl indx(%ebp),%esi - mv_force_defined %esi, l0 + mv_force_defined_strict %esi, l0 # disregard NOUNDEF movl %esi, indx(%ebp) mv_force_num %esi, l1 movl indx(%ebp),%esi diff --git a/sr_i386/opp_iretmval.s b/sr_i386/opp_iretmval.s index 99d92aa..08087c3 100644 --- a/sr_i386/opp_iretmval.s +++ b/sr_i386/opp_iretmval.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2007 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -29,9 +29,9 @@ # PUBLIC opp_iretmval ENTRY opp_iretmval # /* PROC */ putframe - addl $4,%esp + addl $4,%esp # /* burn return pc */ call op_iretmval - addl $4,%esp + addl $8,%esp # /* burn two passed-in args */ getframe ret # opp_iretmval ENDP diff --git a/sr_i386/ttt.c b/sr_i386/ttt.c index 1f4e010..fc23248 100644 --- a/sr_i386/ttt.c +++ b/sr_i386/ttt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,651 +13,681 @@ #include "vxi.h" #include "vxt.h" #include "xfer_enum.h" -LITDEF short ttt[4053] = { +LITDEF short ttt[4229] = { -/* 0 */ 0,0,0,0,306,3386,2829,530, -/* 8 */ 2202,2814,2844,1892,384,3336,2004,2960, -/* 16 */ 2081,2072,3569,3606,2045,2054,2120,2066, -/* 24 */ 2111,2090,2027,730,757,745,784,796, -/* 32 */ 808,826,868,886,904,919,948,984, -/* 40 */ 999,1014,1029,1047,1059,2930,2945,1131, -/* 48 */ 1164,1197,1236,1299,1350,1626,1641,1656, -/* 56 */ 1686,1725,1737,1761,1788,1809,1824,3401, -/* 64 */ 3423,0,0,0,0,545,0,486, -/* 72 */ 0,1878,0,2916,0,0,0,0, -/* 80 */ 0,0,338,396,2180,2186,2606,2633, -/* 88 */ 2651,2754,2692,2683,2769,3475,3559,2865, -/* 96 */ 0,2895,3026,2989,2974,3004,3350,3202, -/* 104 */ 3268,3481,3493,3508,3532,3541,3526,3517, -/* 112 */ 3301,3602,3615,3637,3674,3686,3707,3731, -/* 120 */ 3797,0,0,2802,2162,3078,4002,618, -/* 128 */ 4005,672,2663,3044,500,506,4008,2278, -/* 136 */ 2360,2252,453,2301,2380,2036,2323,2390, -/* 144 */ 4011,2147,2138,4015,1368,1386,4016,334, -/* 152 */ 330,3292,408,4020,4023,4026,2881,4029, -/* 160 */ 4032,4035,4038,4041,4044,3372,0,2778, -/* 168 */ 2446,2427,1605,2418,2198,2018,2729,1913, -/* 176 */ 697,2719,0,0,2217,3550,3578,1581, -/* 184 */ 3502,2313,1906,515,3698,1773,2129,1284, -/* 192 */ 321,3030,584,650,568,628,3662,1179, -/* 200 */ 1218,3630,2858,2156,2793,2872,600,1071, -/* 208 */ 2733,4047,2370,3749,3767,3782,477,2748, -/* 216 */ 3022,1851,3818,3809,1422,3364,559,1671, -/* 224 */ 1713,2335,4050,3435,2406,706,844,3061, -/* 232 */ 3590,3459,3445,3452,3441,682,933,2265, -/* 240 */ 2288,1113,2239,1101,2099,1086,1146,2347, -/* 248 */ 1551,1494,1479,1533,1449,1461,1506,1434, -/* 256 */ 1518,1566,0,3322,0,960,969,3181, -/* 264 */ 3247,1800,3160,3226,2226,3854,3824,3830, -/* 272 */ 3842,3864,1323,1335,1257,1269,1311,3413, -/* 280 */ 1701,1836,3878,3893,3929,3911,3088,3100, -/* 288 */ 3112,3124,2642,2657,1593,417,772,1404, -/* 296 */ 609,3136,3148,3941,3947,3956,3973,3987, -/* 304 */ 3993,3653,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2, -/* 312 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_add, -/* 320 */ VXT_END, -/* 321 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm, -/* 329 */ VXT_END, -/* 330 */ VXI_INCL,VXT_VAL,1,VXT_END, -/* 334 */ VXI_CLRL,VXT_VAL,0,VXT_END, -/* 338 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END, -/* 342 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,1,VXT_END, -/* 349 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,1,VXT_END, -/* 356 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,1,VXT_END, -/* 363 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,1,VXT_END, -/* 370 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,1,VXT_END, -/* 377 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,1,VXT_END, -/* 384 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 392 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END, -/* 396 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 404 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END, -/* 408 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false, -/* 416 */ VXT_END, -/* 417 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars, -/* 425 */ VXT_END, -/* 426 */ VXI_TSTL,VXT_VAL,1,VXT_END, -/* 430 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool, -/* 438 */ VXT_END, -/* 439 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint, -/* 447 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END, -/* 453 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 461 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END, -/* 463 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1, -/* 471 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END, -/* 477 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num, -/* 485 */ VXT_END, -/* 486 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 494 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END, -/* 500 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END, -/* 506 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn, -/* 514 */ VXT_END, -/* 515 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 523 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END, -/* 530 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 538 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END, -/* 545 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, -/* 553 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END, -/* 559 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul, -/* 567 */ VXT_END, -/* 568 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 576 */ 2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, -/* 584 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 592 */ 2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, -/* 600 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret, -/* 608 */ VXT_END, -/* 609 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals, -/* 617 */ VXT_END, -/* 618 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 626 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END, -/* 628 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 636 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 644 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, -/* 650 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 658 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 666 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, -/* 672 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 680 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END, -/* 682 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 690 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END, -/* 697 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch, -/* 705 */ VXT_END, -/* 706 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, -/* 714 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL, -/* 722 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, -/* 730 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 738 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END, -/* 745 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 753 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END, -/* 757 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 765 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END, -/* 772 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 780 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END, -/* 784 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 792 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END, -/* 796 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 804 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END, -/* 808 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 816 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 824 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END, +/* 0 */ 0,0,0,0,324,3399,2842,548, +/* 8 */ 2220,2827,2857,1910,402,3349,2022,2973, +/* 16 */ 2099,2090,3582,3619,2063,2072,2138,2084, +/* 24 */ 2129,2108,2045,748,775,763,802,814, +/* 32 */ 826,844,886,904,922,943,972,1002, +/* 40 */ 1017,1032,1047,1065,1077,2943,2958,1149, +/* 48 */ 1182,1215,1254,1317,1368,1644,1659,1674, +/* 56 */ 1704,1743,1755,1779,1806,1827,1842,3414, +/* 64 */ 3436,0,0,0,0,563,0,504, +/* 72 */ 0,1896,0,2929,0,0,0,0, +/* 80 */ 0,0,356,414,2198,2204,2619,2646, +/* 88 */ 2664,2767,2705,2696,2782,3488,3572,2878, +/* 96 */ 0,2908,3039,3002,2987,3017,3363,3215, +/* 104 */ 3281,3494,3506,3521,3545,3554,3539,3530, +/* 112 */ 3314,3615,3628,3650,3687,3699,3720,3744, +/* 120 */ 3810,0,0,2815,2180,3091,4178,636, +/* 128 */ 4181,690,2676,3057,518,524,4184,2283, +/* 136 */ 2370,2270,471,2306,2390,2054,2328,2400, +/* 144 */ 4187,2165,2156,4191,1386,1404,4192,352, +/* 152 */ 348,3305,426,4196,4199,4202,2894,4205, +/* 160 */ 4208,4211,4214,4217,4220,3385,0,2791, +/* 168 */ 2459,2437,1623,2428,2216,2036,2742,1931, +/* 176 */ 715,2732,0,0,2235,3563,3591,1599, +/* 184 */ 3515,2318,1924,533,3711,1791,2147,1302, +/* 192 */ 339,3043,602,668,586,646,3675,1197, +/* 200 */ 1236,3643,2871,2174,2806,2885,618,1089, +/* 208 */ 2746,4223,2380,3762,3780,3795,495,2761, +/* 216 */ 3035,1869,3831,3822,1440,3377,577,1689, +/* 224 */ 1731,2343,4226,3448,2416,724,862,3074, +/* 232 */ 3603,3472,3458,3465,3454,700,957,2293, +/* 240 */ 1131,2257,1119,2117,1104,1164,2355,1569, +/* 248 */ 1512,1497,1551,1467,1479,1524,1452,1536, +/* 256 */ 1584,0,3335,0,981,990,3194,3260, +/* 264 */ 1818,3173,3239,2244,3867,3837,3843,3855, +/* 272 */ 3877,1341,1353,1275,1287,1329,3426,1719, +/* 280 */ 1854,3891,3906,3942,3969,3924,3101,3113, +/* 288 */ 3125,3137,2655,2670,1611,435,790,1422, +/* 296 */ 627,3149,3161,3954,3960,0,0,0, +/* 304 */ 0,3666,3981,3992,4004,4013,4027,4040, +/* 312 */ 4050,4067,4076,4085,4097,4109,4121,4136, +/* 320 */ 4148,0,0,4157,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB, +/* 328 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3, +/* 336 */ VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END, +/* 339 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm, +/* 347 */ VXT_END, +/* 348 */ VXI_INCL,VXT_VAL,1,VXT_END, +/* 352 */ VXI_CLRL,VXT_VAL,0,VXT_END, +/* 356 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END, +/* 360 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,1,VXT_END, +/* 367 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,1,VXT_END, +/* 374 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,1,VXT_END, +/* 381 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,1,VXT_END, +/* 388 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,1,VXT_END, +/* 395 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,1,VXT_END, +/* 402 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 410 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END, +/* 414 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END, +/* 426 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false, +/* 434 */ VXT_END, +/* 435 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars, +/* 443 */ VXT_END, +/* 444 */ VXI_TSTL,VXT_VAL,1,VXT_END, +/* 448 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool, +/* 456 */ VXT_END, +/* 457 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint, +/* 465 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END, +/* 471 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 479 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END, +/* 481 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1, +/* 489 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END, +/* 495 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num, +/* 503 */ VXT_END, +/* 504 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 512 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END, +/* 518 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END, +/* 524 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn, +/* 532 */ VXT_END, +/* 533 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 541 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END, +/* 548 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 556 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END, +/* 563 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, +/* 571 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END, +/* 577 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul, +/* 585 */ VXT_END, +/* 586 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 594 */ 2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, +/* 602 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 610 */ 2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, +/* 618 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret, +/* 626 */ VXT_END, +/* 627 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals, +/* 635 */ VXT_END, +/* 636 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 644 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END, +/* 646 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 654 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 662 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, +/* 668 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 676 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 684 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, +/* 690 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 698 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END, +/* 700 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 708 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END, +/* 715 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch, +/* 723 */ VXT_END, +/* 724 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, +/* 732 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL, +/* 740 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, +/* 748 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 756 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END, +/* 763 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 771 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END, +/* 775 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 783 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END, +/* 790 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 798 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END, +/* 802 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 810 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END, +/* 814 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 822 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END, /* 826 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 834 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 842 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END, -/* 844 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, -/* 852 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 860 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, -/* 868 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 876 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 884 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END, +/* 842 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END, +/* 844 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 852 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 860 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END, +/* 862 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, +/* 870 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 878 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, /* 886 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 894 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 902 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END, -/* 904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 912 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END, -/* 919 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, -/* 927 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END, -/* 933 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 941 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END, -/* 948 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 956 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,VXT_END, -/* 960 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1, -/* 968 */ VXT_END, -/* 969 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 977 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget2,VXT_END, -/* 984 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 992 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END, -/* 999 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1007 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END, -/* 1014 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1022 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END, -/* 1029 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1037 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1045 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END, -/* 1047 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1055 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END, -/* 1059 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1067 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END, -/* 1071 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1079 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END, -/* 1086 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, -/* 1094 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END, -/* 1101 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1109 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END, -/* 1113 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 1121 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER, -/* 1129 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END, -/* 1131 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1139 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END, -/* 1146 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, -/* 1154 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1162 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END, -/* 1164 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1172 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END, -/* 1179 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1187 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1195 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END, -/* 1197 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 1205 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1213 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END, -/* 1218 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1226 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1234 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END, -/* 1236 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 1244 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1252 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END, -/* 1257 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1265 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END, -/* 1269 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1277 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END, -/* 1284 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1292 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END, -/* 1299 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1307 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END, -/* 1311 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1319 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END, -/* 1323 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1331 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END, -/* 1335 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1343 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END, -/* 1350 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1358 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1366 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END, -/* 1368 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 902 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END, +/* 904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 912 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 920 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END, +/* 922 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 930 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 938 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END, +/* 943 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, +/* 951 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END, +/* 957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 965 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END, +/* 972 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget, +/* 980 */ VXT_END, +/* 981 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1, +/* 989 */ VXT_END, +/* 990 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 998 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END, +/* 1002 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1010 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END, +/* 1017 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1025 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END, +/* 1032 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1040 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END, +/* 1047 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 1055 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1063 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END, +/* 1065 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1073 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END, +/* 1077 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1085 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END, +/* 1089 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1097 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END, +/* 1104 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, +/* 1112 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END, +/* 1119 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END, +/* 1131 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 1139 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER, +/* 1147 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END, +/* 1149 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1157 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END, +/* 1164 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, +/* 1172 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1180 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END, +/* 1182 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1190 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END, +/* 1197 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 1205 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1213 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END, +/* 1215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 1223 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1231 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END, +/* 1236 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 1244 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1252 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END, +/* 1254 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 1262 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1270 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END, +/* 1275 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1283 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END, +/* 1287 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1295 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END, +/* 1302 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1310 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END, +/* 1317 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1325 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END, +/* 1329 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1337 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END, +/* 1341 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1349 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END, +/* 1353 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1361 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END, +/* 1368 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1376 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1384 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END, +/* 1384 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END, /* 1386 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1394 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1402 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END, +/* 1402 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END, /* 1404 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1412 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1420 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END, -/* 1422 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 1430 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END, -/* 1434 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1442 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END, -/* 1449 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1457 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END, -/* 1461 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1469 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1477 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END, -/* 1479 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1487 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END, -/* 1494 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1502 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END, -/* 1506 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1514 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END, -/* 1518 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1526 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END, -/* 1533 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1541 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1549 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END, -/* 1551 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1559 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END, -/* 1566 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1574 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END, -/* 1581 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 1589 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END, -/* 1593 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1601 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END, -/* 1605 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, -/* 1613 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1621 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END, -/* 1626 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1634 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END, -/* 1641 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1649 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END, -/* 1656 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1664 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END, -/* 1671 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1679 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END, -/* 1686 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1694 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END, -/* 1701 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1709 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END, -/* 1713 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1721 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END, -/* 1725 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1733 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END, -/* 1737 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, -/* 1745 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 1753 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END, -/* 1761 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1769 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END, -/* 1773 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1781 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END, -/* 1788 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1796 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END, -/* 1800 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod, -/* 1808 */ VXT_END, -/* 1809 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1817 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END, -/* 1824 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1832 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END, -/* 1836 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1844 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END, -/* 1851 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL, -/* 1859 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB, -/* 1867 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7, -/* 1875 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END, -/* 1878 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 1886 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END, -/* 1892 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, -/* 1900 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END, -/* 1906 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END, -/* 1913 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1921 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END, -/* 1926 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,1,VXT_END, -/* 1933 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,1,VXT_END, -/* 1940 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,1,VXT_END, -/* 1947 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 1955 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 1963 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 1966 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 1974 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 1982 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 1985 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 1993 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 2001 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 2004 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx, -/* 2012 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 2018 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth, -/* 2026 */ VXT_END, -/* 2027 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata, -/* 2035 */ VXT_END, -/* 2036 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam, +/* 1420 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END, +/* 1422 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1430 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1438 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END, +/* 1440 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 1448 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END, +/* 1452 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1460 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END, +/* 1467 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1475 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END, +/* 1479 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1487 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1495 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END, +/* 1497 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1505 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END, +/* 1512 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1520 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END, +/* 1524 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1532 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END, +/* 1536 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1544 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END, +/* 1551 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1559 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1567 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END, +/* 1569 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1577 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END, +/* 1584 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1592 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END, +/* 1599 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 1607 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END, +/* 1611 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1619 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END, +/* 1623 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, +/* 1631 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1639 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END, +/* 1644 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1652 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END, +/* 1659 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1667 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END, +/* 1674 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1682 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END, +/* 1689 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1697 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END, +/* 1704 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1712 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END, +/* 1719 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1727 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END, +/* 1731 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1739 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END, +/* 1743 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1751 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END, +/* 1755 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, +/* 1763 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 1771 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END, +/* 1779 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1787 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END, +/* 1791 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1799 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END, +/* 1806 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1814 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END, +/* 1818 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod, +/* 1826 */ VXT_END, +/* 1827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END, +/* 1842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1850 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END, +/* 1854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1862 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END, +/* 1869 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL, +/* 1877 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB, +/* 1885 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7, +/* 1893 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END, +/* 1896 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 1904 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END, +/* 1910 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, +/* 1918 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END, +/* 1924 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END, +/* 1931 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1939 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END, +/* 1944 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,1,VXT_END, +/* 1951 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,1,VXT_END, +/* 1958 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,1,VXT_END, +/* 1965 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 1973 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 1981 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 1984 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 1992 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 2000 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 2003 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 2011 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 2019 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 2022 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx, +/* 2030 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 2036 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth, /* 2044 */ VXT_END, -/* 2045 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget, +/* 2045 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata, /* 2053 */ VXT_END, -/* 2054 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 2062 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END, -/* 2066 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END, -/* 2072 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked, -/* 2080 */ VXT_END, -/* 2081 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname, -/* 2089 */ VXT_END, -/* 2090 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext, +/* 2054 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam, +/* 2062 */ VXT_END, +/* 2063 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget, +/* 2071 */ VXT_END, +/* 2072 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 2080 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END, +/* 2084 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END, +/* 2090 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked, /* 2098 */ VXT_END, -/* 2099 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 2107 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END, -/* 2111 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder, -/* 2119 */ VXT_END, -/* 2120 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput, -/* 2128 */ VXT_END, -/* 2129 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery, +/* 2099 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname, +/* 2107 */ VXT_END, +/* 2108 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext, +/* 2116 */ VXT_END, +/* 2117 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 2125 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END, +/* 2129 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder, /* 2137 */ VXT_END, -/* 2138 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg, +/* 2138 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput, /* 2146 */ VXT_END, -/* 2147 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg, +/* 2147 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery, /* 2155 */ VXT_END, -/* 2156 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END, -/* 2162 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 2170 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER, -/* 2178 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END, -/* 2180 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END, -/* 2186 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 2194 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END, -/* 2198 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END, -/* 2202 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2210 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END, -/* 2217 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc, -/* 2225 */ VXT_END, -/* 2226 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2234 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END, -/* 2239 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2247 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END, -/* 2252 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2260 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END, -/* 2265 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2273 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indget,VXT_END, -/* 2278 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2286 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END, -/* 2288 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2296 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END, -/* 2301 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG, -/* 2309 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2313 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2321 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END, -/* 2323 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 2331 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END, -/* 2335 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG, -/* 2343 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2347 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2355 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END, -/* 2360 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2368 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END, -/* 2370 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2378 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END, +/* 2156 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg, +/* 2164 */ VXT_END, +/* 2165 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg, +/* 2173 */ VXT_END, +/* 2174 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END, +/* 2180 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 2188 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER, +/* 2196 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END, +/* 2198 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END, +/* 2204 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 2212 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END, +/* 2216 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END, +/* 2220 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2228 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END, +/* 2235 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc, +/* 2243 */ VXT_END, +/* 2244 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2252 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END, +/* 2257 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2265 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END, +/* 2270 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2278 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END, +/* 2283 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2291 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END, +/* 2293 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2301 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END, +/* 2306 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG, +/* 2314 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2318 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2326 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END, +/* 2328 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2336 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END, +/* 2343 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG, +/* 2351 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2355 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2363 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END, +/* 2370 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2378 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END, /* 2380 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2388 */ SIZEOF(char *) * (short int)xf_indset,VXT_END, -/* 2390 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2398 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END, -/* 2406 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 2414 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END, -/* 2418 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad, -/* 2426 */ VXT_END, -/* 2427 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmval,VXT_END, -/* 2434 */ VXI_BRB,VXT_JMP,1,VXT_END, -/* 2438 */ VXI_JMP,VXT_JMP,1,VXT_END, -/* 2442 */ VXI_BRW,VXT_JMP,1,VXT_END, -/* 2446 */ VXI_JMP,VXT_VAL,1,VXT_END, -/* 2450 */ VXI_BEQL,VXT_JMP,1,VXT_END, -/* 2454 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2461 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2468 */ VXI_BGEQ,VXT_JMP,1,VXT_END, -/* 2472 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2479 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2486 */ VXI_BGTR,VXT_JMP,1,VXT_END, -/* 2490 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2497 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2504 */ VXI_BLEQ,VXT_JMP,1,VXT_END, -/* 2508 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2515 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2522 */ VXI_BLSS,VXT_JMP,1,VXT_END, -/* 2526 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2533 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2540 */ VXI_BNEQ,VXT_JMP,1,VXT_END, -/* 2544 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2551 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2558 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END, -/* 2564 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, -/* 2572 */ VXT_END, -/* 2573 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, -/* 2581 */ VXT_END, -/* 2582 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END, -/* 2588 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, -/* 2596 */ VXT_END, -/* 2597 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, -/* 2605 */ VXT_END, -/* 2606 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL, -/* 2614 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL, -/* 2622 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1, -/* 2630 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END, -/* 2633 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill, -/* 2641 */ VXT_END, -/* 2642 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias, -/* 2650 */ VXT_END, -/* 2651 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END, -/* 2657 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END, -/* 2663 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2671 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG, -/* 2679 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2683 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr, -/* 2691 */ VXT_END, -/* 2692 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr, -/* 2700 */ VXT_END, -/* 2701 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2707 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2713 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2719 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2727 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END, -/* 2729 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END, -/* 2733 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 2741 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, -/* 2748 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END, -/* 2754 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2762 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, -/* 2769 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock, -/* 2777 */ VXT_END, -/* 2778 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2786 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END, -/* 2793 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw, -/* 2801 */ VXT_END, -/* 2802 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 2810 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END, -/* 2814 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2822 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END, -/* 2829 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2837 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END, -/* 2844 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, -/* 2852 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END, -/* 2858 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END, -/* 2865 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END, -/* 2872 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp, -/* 2880 */ VXT_END, -/* 2881 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 2889 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END, -/* 2895 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 2903 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 2911 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END, -/* 2916 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 2924 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END, -/* 2930 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2938 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END, -/* 2945 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2953 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END, -/* 2960 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx, -/* 2968 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 2974 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2982 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END, -/* 2989 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2997 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END, -/* 3004 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 3012 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3020 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END, -/* 3022 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END, -/* 3026 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END, -/* 3030 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2, -/* 3038 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END, -/* 3044 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3052 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 3060 */ VXT_END, -/* 3061 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3069 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 3077 */ VXT_END, -/* 3078 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3086 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END, -/* 3088 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3096 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END, -/* 3100 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3108 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END, -/* 3112 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3120 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END, -/* 3124 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3132 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END, -/* 3136 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3144 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END, -/* 3148 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3156 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END, -/* 3160 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3168 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3176 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END, -/* 3181 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3189 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3197 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END, -/* 3202 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3210 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3218 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END, -/* 3226 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3234 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3242 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END, -/* 3247 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3255 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3263 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END, -/* 3268 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3276 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3284 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END, -/* 3292 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true, -/* 3300 */ VXT_END, -/* 3301 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3309 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS, -/* 3317 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END, -/* 3322 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 3330 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END, -/* 3336 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx, -/* 3344 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 3350 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, -/* 3358 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, -/* 3364 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END, -/* 3372 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, -/* 3380 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, -/* 3386 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3394 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END, -/* 3401 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3409 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END, -/* 3413 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3421 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END, -/* 3423 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3431 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END, -/* 3435 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END, -/* 3441 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END, -/* 3445 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END, -/* 3452 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END, -/* 3459 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3467 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END, -/* 3475 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END, -/* 3481 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3489 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END, -/* 3493 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view, -/* 3501 */ VXT_END, -/* 3502 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END, -/* 3508 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write, -/* 3516 */ VXT_END, -/* 3517 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol, -/* 3525 */ VXT_END, -/* 3526 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END, -/* 3532 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone, -/* 3540 */ VXT_END, -/* 3541 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab, -/* 3549 */ VXT_END, -/* 3550 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill, -/* 3558 */ VXT_END, -/* 3559 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3567 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END, -/* 3569 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate, -/* 3577 */ VXT_END, -/* 3578 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3586 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END, -/* 3590 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3598 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END, -/* 3602 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3606 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate, -/* 3614 */ VXT_END, -/* 3615 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3623 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END, -/* 3630 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END, -/* 3637 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, -/* 3645 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END, -/* 3653 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt, -/* 3661 */ VXT_END, -/* 3662 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3670 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END, -/* 3674 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3682 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END, -/* 3686 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 3694 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END, -/* 3698 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious, -/* 3706 */ VXT_END, -/* 3707 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, -/* 3715 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3723 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END, -/* 3731 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL, -/* 3739 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3747 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, -/* 3749 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3757 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3765 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, -/* 3767 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3775 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3782 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3790 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3797 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3805 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END, -/* 3809 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit, -/* 3817 */ VXT_END, -/* 3818 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END, -/* 3824 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END, -/* 3830 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3838 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, -/* 3842 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3850 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, -/* 3854 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER, -/* 3862 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END, -/* 3864 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx, -/* 3872 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 3878 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3886 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END, -/* 3893 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3901 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 3909 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END, -/* 3911 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3919 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 3927 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END, -/* 3929 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3937 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END, -/* 3941 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END, -/* 3947 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn, -/* 3955 */ VXT_END, -/* 3956 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3964 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshindx,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 3972 */ VXT_END, -/* 3973 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savputindx, -/* 3981 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 3987 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_forfreeindx,VXT_END, -/* 3993 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fornestlvl, -/* 4001 */ VXT_END, -/* 4002 */ 342,356,349,2434,2442,2438,2701,2713, -/* 4010 */ 2707,0,0,0,463,439,430,0, -/* 4018 */ 0,426,1947,1985,1966,2582,2597,2588, -/* 4026 */ 2558,2573,2564,2450,2461,2454,2540,2551, -/* 4034 */ 2544,2486,2497,2490,2504,2515,2508,2522, -/* 4042 */ 2533,2526,2468,2479,2472,1926,1940,1933, -/* 4050 */ 363,377,370}; +/* 2388 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END, +/* 2390 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2398 */ SIZEOF(char *) * (short int)xf_indset,VXT_END, +/* 2400 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2408 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END, +/* 2416 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 2424 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END, +/* 2428 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad, +/* 2436 */ VXT_END, +/* 2437 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2445 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END, +/* 2447 */ VXI_BRB,VXT_JMP,1,VXT_END, +/* 2451 */ VXI_JMP,VXT_JMP,1,VXT_END, +/* 2455 */ VXI_BRW,VXT_JMP,1,VXT_END, +/* 2459 */ VXI_JMP,VXT_VAL,1,VXT_END, +/* 2463 */ VXI_BEQL,VXT_JMP,1,VXT_END, +/* 2467 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2474 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2481 */ VXI_BGEQ,VXT_JMP,1,VXT_END, +/* 2485 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2492 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2499 */ VXI_BGTR,VXT_JMP,1,VXT_END, +/* 2503 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2510 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2517 */ VXI_BLEQ,VXT_JMP,1,VXT_END, +/* 2521 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2528 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2535 */ VXI_BLSS,VXT_JMP,1,VXT_END, +/* 2539 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2546 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2553 */ VXI_BNEQ,VXT_JMP,1,VXT_END, +/* 2557 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2564 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2571 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END, +/* 2577 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, +/* 2585 */ VXT_END, +/* 2586 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, +/* 2594 */ VXT_END, +/* 2595 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END, +/* 2601 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, +/* 2609 */ VXT_END, +/* 2610 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, +/* 2618 */ VXT_END, +/* 2619 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL, +/* 2627 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL, +/* 2635 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1, +/* 2643 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END, +/* 2646 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill, +/* 2654 */ VXT_END, +/* 2655 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias, +/* 2663 */ VXT_END, +/* 2664 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END, +/* 2670 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END, +/* 2676 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2684 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG, +/* 2692 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2696 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr, +/* 2704 */ VXT_END, +/* 2705 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr, +/* 2713 */ VXT_END, +/* 2714 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2720 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2726 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2732 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2740 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END, +/* 2742 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END, +/* 2746 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 2754 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, +/* 2761 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END, +/* 2767 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2775 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, +/* 2782 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock, +/* 2790 */ VXT_END, +/* 2791 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2799 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END, +/* 2806 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw, +/* 2814 */ VXT_END, +/* 2815 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 2823 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END, +/* 2827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END, +/* 2842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2850 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END, +/* 2857 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, +/* 2865 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END, +/* 2871 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END, +/* 2878 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END, +/* 2885 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp, +/* 2893 */ VXT_END, +/* 2894 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 2902 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END, +/* 2908 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 2916 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 2924 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END, +/* 2929 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 2937 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END, +/* 2943 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2951 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END, +/* 2958 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2966 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END, +/* 2973 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx, +/* 2981 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 2987 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2995 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END, +/* 3002 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 3010 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END, +/* 3017 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 3025 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3033 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END, +/* 3035 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END, +/* 3039 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END, +/* 3043 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2, +/* 3051 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END, +/* 3057 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3065 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 3073 */ VXT_END, +/* 3074 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3082 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 3090 */ VXT_END, +/* 3091 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3099 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END, +/* 3101 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3109 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END, +/* 3113 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3121 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END, +/* 3125 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3133 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END, +/* 3137 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3145 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END, +/* 3149 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3157 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END, +/* 3161 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3169 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END, +/* 3173 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3181 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3189 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END, +/* 3194 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3202 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3210 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END, +/* 3215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3223 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3231 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END, +/* 3239 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3247 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3255 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END, +/* 3260 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3268 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3276 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END, +/* 3281 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3289 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3297 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END, +/* 3305 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true, +/* 3313 */ VXT_END, +/* 3314 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3322 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS, +/* 3330 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END, +/* 3335 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 3343 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END, +/* 3349 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx, +/* 3357 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 3363 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, +/* 3371 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, +/* 3377 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END, +/* 3385 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, +/* 3393 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, +/* 3399 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3407 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END, +/* 3414 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END, +/* 3426 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3434 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END, +/* 3436 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3444 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END, +/* 3448 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END, +/* 3454 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END, +/* 3458 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END, +/* 3465 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END, +/* 3472 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3480 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END, +/* 3488 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END, +/* 3494 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3502 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END, +/* 3506 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view, +/* 3514 */ VXT_END, +/* 3515 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END, +/* 3521 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write, +/* 3529 */ VXT_END, +/* 3530 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol, +/* 3538 */ VXT_END, +/* 3539 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END, +/* 3545 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone, +/* 3553 */ VXT_END, +/* 3554 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab, +/* 3562 */ VXT_END, +/* 3563 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill, +/* 3571 */ VXT_END, +/* 3572 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3580 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END, +/* 3582 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate, +/* 3590 */ VXT_END, +/* 3591 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3599 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END, +/* 3603 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3611 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END, +/* 3615 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3619 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate, +/* 3627 */ VXT_END, +/* 3628 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3636 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END, +/* 3643 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END, +/* 3650 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, +/* 3658 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END, +/* 3666 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt, +/* 3674 */ VXT_END, +/* 3675 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3683 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END, +/* 3687 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3695 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END, +/* 3699 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 3707 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END, +/* 3711 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious, +/* 3719 */ VXT_END, +/* 3720 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, +/* 3728 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3736 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END, +/* 3744 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL, +/* 3752 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3760 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, +/* 3762 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3770 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3778 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, +/* 3780 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3788 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3795 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3803 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3810 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3818 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END, +/* 3822 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit, +/* 3830 */ VXT_END, +/* 3831 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END, +/* 3837 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END, +/* 3843 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3851 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, +/* 3855 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3863 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, +/* 3867 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER, +/* 3875 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END, +/* 3877 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx, +/* 3885 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 3891 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3899 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END, +/* 3906 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3914 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 3922 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END, +/* 3924 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3932 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 3940 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END, +/* 3942 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3950 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END, +/* 3954 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END, +/* 3960 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn, +/* 3968 */ VXT_END, +/* 3969 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3977 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END, +/* 3981 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50, +/* 3989 */ VXT_ADDR,0,VXT_END, +/* 3992 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4000 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END, +/* 4004 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop, +/* 4012 */ VXT_END, +/* 4013 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot, +/* 4021 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 4027 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 4035 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END, +/* 4040 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 4048 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END, +/* 4050 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4058 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 4066 */ VXT_END, +/* 4067 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn, +/* 4075 */ VXT_END, +/* 4076 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn, +/* 4084 */ VXT_END, +/* 4085 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4093 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END, +/* 4097 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4105 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END, +/* 4109 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4117 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END, +/* 4121 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 4129 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END, +/* 4136 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 4144 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END, +/* 4148 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2, +/* 4156 */ VXT_END, +/* 4157 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 4165 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 4173 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpeek,VXT_END, +/* 4178 */ 360,374,367,2447,2455,2451,2714,2726, +/* 4186 */ 2720,0,0,0,481,457,448,0, +/* 4194 */ 0,444,1965,2003,1984,2595,2610,2601, +/* 4202 */ 2571,2586,2577,2463,2474,2467,2553,2564, +/* 4210 */ 2557,2499,2510,2503,2517,2528,2521,2535, +/* 4218 */ 2546,2539,2481,2492,2485,1944,1958,1951, +/* 4226 */ 381,395,388}; diff --git a/sr_linux/gtm_env_sp.csh b/sr_linux/gtm_env_sp.csh index 3980e58..eff718d 100644 --- a/sr_linux/gtm_env_sp.csh +++ b/sr_linux/gtm_env_sp.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2012 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -182,11 +182,12 @@ if ( $?gtm_version_change == "1" ) then # -fno-defer-pop to prevent problems with assembly/generated code with optimization # -fno-strict-aliasing since we don't comply with the rules # -ffloat-store for consistent results avoiding rounding differences + # -fno-omit-frame-pointer so %rbp always gets set up (required by caller_id()). Default changed in gcc 4.6. if ( "ia64" != $mach_type ) then setenv gt_cc_option_optimize "-O2 -fno-defer-pop -fno-strict-aliasing -ffloat-store" if ( "32" == $gt_build_type ) then # applies to 32bit x86_64, ia32 and cygwin - setenv gt_cc_option_optimize "$gt_cc_option_optimize -march=i686" + setenv gt_cc_option_optimize "$gt_cc_option_optimize -fno-omit-frame-pointer -march=i686" endif endif # -g generate debugging information for dbx (no longer overrides -O) diff --git a/sr_linux/gtm_env_sp.mk b/sr_linux/gtm_env_sp.mk index 79c5514..81fd6c1 100644 --- a/sr_linux/gtm_env_sp.mk +++ b/sr_linux/gtm_env_sp.mk @@ -65,25 +65,10 @@ gt_cc_option_nooptimize= gt_cc_option_optimize=-O2 -fno-defer-pop -fno-strict-aliasing -ffloat-store gt_cc_options_common+= -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=600 -fsigned-char -ifeq ($(gt_build_type),32) -gt_cc_option_I=-I- -endif - ifeq ($(gt_machine_type), x86_64) ifeq ($(gt_build_type),32) -# Do not lookup the source directory before include directories specified by -I. -# gcc complains about -I- being obsolete, but using -iquote cause build errors for gcc and as - ABS 2008.12.09 -# -# The -I- option is only needed for 32 bit builds on x86_64. It provides a feature that is not present in -# -iquote - namely -I- disables the ability to search the current directory for include files. This is needed -# when compiling something in sr_port which includes a file that is in both sr_port and the architecture specific -# sr_386. We don't want the sr_port version. An example is sr_port/code_gen.c which includes emit_code.h. -# emit_code.h is found in both sr_port and sr_i386. Using -I- will find the sr_i386 version, but without it the -# sr_port version is used. SLJ 2010.03.31 - # The /emul/ia32-linux/... directory doesn't exist on most machines, but when it's there we need it. No problem # with always includeing it. - gt_cc_option_I+= -I/emul/ia32-linux/usr/include/ else gt_cc_option_I= diff --git a/sr_linux/release_name.h b/sr_linux/release_name.h index d810239..e2eb210 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 V5.5-000A CYGWIN x86" +#define GTM_RELEASE_NAME "GT.M V6.0-003 CYGWIN x86" #elif defined(__ia64) -#define GTM_RELEASE_NAME "GT.M V5.5-000A Linux IA64" +#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux IA64" #elif defined(__x86_64__) -#define GTM_RELEASE_NAME "GT.M V5.5-000A Linux x86_64" +#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86_64" #elif defined(__s390__) -#define GTM_RELEASE_NAME "GT.M V5.5-000A Linux S390X" +#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux S390X" #else -#define GTM_RELEASE_NAME "GT.M V5.5-000A Linux x86" +#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86" #endif #define GTM_PRODUCT "GT.M" -#define GTM_VERSION "V5.5" +#define GTM_VERSION "V6.0" diff --git a/sr_port/act_in_gvt.c b/sr_port/act_in_gvt.c index 578e6b3..c4b6bb7 100644 --- a/sr_port/act_in_gvt.c +++ b/sr_port/act_in_gvt.c @@ -19,7 +19,7 @@ #include "collseq.h" #include "spec_type.h" #ifdef GTM_TRIGGER -#include "rtnhdr.h" +#include #include "gv_trigger.h" #endif diff --git a/sr_port/actuallist.c b/sr_port/actuallist.c index d29c33c..cc8c3d0 100644 --- a/sr_port/actuallist.c +++ b/sr_port/actuallist.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,15 +13,22 @@ #include "compiler.h" #include "opcode.h" #include "toktyp.h" +#include "mdq.h" +#include "fullbool.h" #include "advancewindow.h" +#include "show_source_line.h" -error_def (ERR_MAXACTARG); -error_def (ERR_NAMEEXPECTED); -error_def (ERR_COMMAORRPAREXP); +GBLREF boolean_t run_time; + +error_def(ERR_COMMAORRPAREXP); +error_def(ERR_MAXACTARG); +error_def(ERR_NAMEEXPECTED); +error_def(ERR_SIDEEFFECTEVAL); int actuallist (oprtype *opr) { - int mask, parmcount; + boolean_t se_warn; + int i, j, mask, parmcount; oprtype ot; triple *counttrip, *masktrip, *ref0, *ref1, *ref2; DCL_THREADGBL_ACCESS; @@ -96,6 +103,29 @@ error_def (ERR_COMMAORRPAREXP); } ref0 = ref1; } + if ((1 < parmcount) && (TREF(side_effect_base))[TREF(expr_depth)]) + { /* at least two arguments and at least one side effect - look for lvns needing protection */ + assert(OLD_SE != TREF(side_effect_handling)); + se_warn = (!run_time && (SE_WARN == TREF(side_effect_handling))); + for (i = 0, j = parmcount, ref0 = counttrip->operand[1].oprval.tref; --j; + ref0 = ref0->operand[1].oprval.tref) + { /* no need to do the last argument - can't have a side effect after it */ + assert(OC_PARAMETER == ref0->opcode); + assert((TRIP_REF == ref0->operand[0].oprclass) && (TRIP_REF == ref0->operand[1].oprclass)); + if (!((1 << i++) & mask) && (OC_VAR == ref0->operand[0].oprval.tref->opcode)) + { /* can only protect pass-by-value (not pass-by-reference) */ + ref1 = maketriple(OC_STOTEMP); + ref1->operand[0] = put_tref(ref0->operand[0].oprval.tref); + ref0->operand[0].oprval.tref = ref1; + dqins(ref0, exorder, ref1); /* NOTE:this violates information hiding */ + if (se_warn) + ISSUE_SIDEEFFECTEVAL_WARNING(ref0->src.column); + } + } + /* the following asserts check we're getting only TRIP_REF or empty operands */ + assert((NO_REF == ref0->operand[0].oprclass) || (TRIP_REF == ref0->operand[0].oprclass)); + assert(((NO_REF == ref0->operand[0].oprclass) ? TRIP_REF : NO_REF) == ref0->operand[1].oprclass); + } } advancewindow(); masktrip->operand[0] = put_ilit(mask); diff --git a/sr_port/adjust_frames.c b/sr_port/adjust_frames.c index b736978..9124d8c 100644 --- a/sr_port/adjust_frames.c +++ b/sr_port/adjust_frames.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" GBLREF stack_frame *frame_pointer; diff --git a/sr_port/advancewindow.c b/sr_port/advancewindow.c index 37ae786..6329e7c 100644 --- a/sr_port/advancewindow.c +++ b/sr_port/advancewindow.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -52,7 +52,7 @@ static readonly unsigned char apos_ok[] = void advancewindow(void) { unsigned char *cp1, *cp2, *cp3, x; - char *tmp, source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)]; + char *tmp; int y, charlen; # ifdef UNICODE_SUPPORTED uint4 ch; @@ -96,7 +96,7 @@ void advancewindow(void) } if (!run_time) { - show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE); + show_source_line(TRUE); dec_err(VARLSTCNT(1) ERR_LITNONGRAPH); } } @@ -151,7 +151,7 @@ void advancewindow(void) { if (cp2 < cp3) *cp2++ = x; - y = ctypetab[x = *++lexical_ptr]; + y = ctypetab[x = *++lexical_ptr]; /* note assignment */ if ((TK_UPPER != y) && (TK_DIGIT != y) && (TK_LOWER != y)) break; } @@ -159,7 +159,7 @@ void advancewindow(void) TREF(director_token) = TK_IDENT; return; case TK_PERIOD: - if (ctypetab[x = *(lexical_ptr + 1)] != TK_DIGIT) + if (ctypetab[x = *(lexical_ptr + 1)] != TK_DIGIT) /* note assignment */ break; case TK_DIGIT: (TREF(director_mval)).str.addr = lexical_ptr; @@ -186,14 +186,14 @@ void advancewindow(void) } return; case TK_APOSTROPHE: - if (( x = *++lexical_ptr) >= 32) + if (32 <= (x = *++lexical_ptr)) /* note assignment */ { x -= 32; - if (x < SIZEOF(apos_ok) / SIZEOF(unsigned char)) + if (x < ARRAYSIZE(apos_ok)) { if (y = apos_ok[x]) { - if (DEL < (x = *++lexical_ptr)) + if (DEL < (x = *++lexical_ptr)) /* note assignment */ { TREF(director_token) = TK_ERROR; return; @@ -210,6 +210,14 @@ void advancewindow(void) } TREF(director_token) = TK_APOSTROPHE; return; + case TK_GREATER: + case TK_LESS: + if (TK_EQUAL == ctypetab[*(lexical_ptr + 1)]) + { + ++lexical_ptr; + y = ((TK_LESS == y) ? TK_NGREATER : TK_NLESS); + } + break; case TK_SEMICOLON: while (*++lexical_ptr) ; @@ -217,7 +225,7 @@ void advancewindow(void) TREF(director_token) = TK_EOL; return; /* if next character is terminator, avoid incrementing past it */ case TK_ASTERISK: - if (DEL < (x = *(lexical_ptr + 1))) + if (DEL < (x = *(lexical_ptr + 1))) /* note assignment */ { TREF(director_token) = TK_ERROR; return; @@ -229,7 +237,7 @@ void advancewindow(void) } break; case TK_RBRACKET: - if ((x = *(lexical_ptr + 1)) > DEL) + if ((x = *(lexical_ptr + 1)) > DEL) /* note assignment */ { TREF(director_token) = TK_ERROR; return; @@ -240,6 +248,17 @@ void advancewindow(void) y = TK_SORTS_AFTER; } break; + case TK_ATSIGN: + if (DEL < (x = *(lexical_ptr + 1))) /* note assignment */ + { + TREF(director_token) = TK_ERROR; + return; + } + if (TK_HASH == ctypetab[x]) + { + lexical_ptr++; + y = TK_ATHASH; + } default: ; } diff --git a/sr_port/alias_funcs.c b/sr_port/alias_funcs.c index 48c9dfa..a0f5c0d 100644 --- a/sr_port/alias_funcs.c +++ b/sr_port/alias_funcs.c @@ -16,7 +16,7 @@ #include -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "stp_parms.h" diff --git a/sr_port/alloc_reg.c b/sr_port/alloc_reg.c index 2cdae9c..d25d2b4 100644 --- a/sr_port/alloc_reg.c +++ b/sr_port/alloc_reg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,8 +23,6 @@ #include "alloc_reg.h" #include "cdbg_dump.h" -#define MAX_TEMP_COUNT 128 - GBLDEF int4 sa_temps[VALUED_REF_TYPES]; GBLDEF int4 sa_temps_offset[VALUED_REF_TYPES]; @@ -44,8 +42,12 @@ LITDEF int4 sa_class_sizes[VALUED_REF_TYPES] = }; LITREF octabstruct oc_tab[]; +#define MAX_TEMP_COUNT 1024 + error_def(ERR_TMPSTOREMAX); +STATICFNDCL void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT]); + void alloc_reg(void) { triple *x, *y, *ref; @@ -94,14 +96,22 @@ void alloc_reg(void) COMPDBG(PRINTF(" ** Converting triple to NOOP (rsn 2) **\n");); continue; /* continue, because 'normal' NOOP continues from this switch */ } +# ifndef DEBUG break; +# endif case OC_LINEFETCH: +# ifdef DEBUG + for (c = temphigh[TVAL_REF]; 0 <= c; c--) + assert(0 == tempcont[TVAL_REF][c]); /* check against leaking TVAL temps */ + if (OC_LINESTART == opc) + break; +# endif case OC_FETCH: assert((TRIP_REF == x->operand[0].oprclass) && (OC_ILIT == x->operand[0].oprval.tref->opcode)); if (x->operand[0].oprval.tref->operand[0].oprval.ilit == mvmax) { x->operand[0].oprval.tref->operand[0].oprval.ilit = 0; - x->operand[1].oprclass = 0; + x->operand[1].oprclass = NO_REF; } break; case OC_STO: @@ -121,50 +131,24 @@ void alloc_reg(void) && (0 == x->operand[0].oprval.tref->operand[0].oprval.mlit->v.str.len)) { x->operand[0] = x->operand[1]; - x->operand[1].oprclass = 0; + x->operand[1].oprclass = NO_REF; opc = x->opcode = OC_EQUNUL; } else if ((TRIP_REF == x->operand[1].oprclass) && (OC_LIT == x->operand[1].oprval.tref->opcode) && (0 == x->operand[1].oprval.tref->operand[0].oprval.mlit->v.str.len)) { - x->operand[1].oprclass = 0; + x->operand[1].oprclass = NO_REF; opc = x->opcode = OC_EQUNUL; } break; } - for (j = x->operand, y = x; j < ARRAYTOP(y->operand); ) - { - if (TRIP_REF == j->oprclass) - { - ref = j->oprval.tref; - if (OC_PARAMETER == ref->opcode) - { - y = ref; - j = y->operand; - continue; - } - if (r = ref->destination.oprclass) /* Note assignment */ - { - dqloop(&ref->backptr, que, b) - { - if (b->bpt == y) - { - dqdel(b, que); - break; - } - } - if ((ref->backptr.que.fl == &ref->backptr) && (TVAR_REF != r)) - tempcont[r][j->oprval.tref->destination.oprval.temp] = 0; - } - } - j++; - } if (OC_PASSTHRU == x->opcode) { COMPDBG(PRINTF(" *** OC_PASSTHRU opcode being NOOP'd\n");); + remove_backptr(x, &x->operand[0], tempcont); x->opcode = OC_NOOP; continue; } - if (!(dest_type = x->destination.oprclass)) /* Note assignment */ + if (NO_REF == (dest_type = x->destination.oprclass)) /* Note assignment */ { oct = oc_tab[opc].octype; if ((oct & OCT_VALUE) && (x->backptr.que.fl != &x->backptr) && !(oct & OCT_CGSKIP)) @@ -175,7 +159,7 @@ void alloc_reg(void) { x->destination = y->operand[0]; y->opcode = OC_NOOP; - y->operand[0].oprclass = y->operand[1].oprclass = 0; + y->operand[0].oprclass = y->operand[1].oprclass = NO_REF; } else { oct &= OCT_VALUE | OCT_MVADDR; @@ -186,7 +170,7 @@ void alloc_reg(void) for (c = 0; tempcont[r][c] && (MAX_TEMP_COUNT > c); c++) ; if (MAX_TEMP_COUNT <= c) - rts_error(VARLSTCNT(1) ERR_TMPSTOREMAX); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TMPSTOREMAX); tempcont[r][c] = 1; x->destination.oprclass = r; x->destination.oprval.temp = c; @@ -201,6 +185,27 @@ void alloc_reg(void) assert(x->destination.oprval.tref->destination.oprclass); x->destination = x->destination.oprval.tref->destination; } + for (j = x->operand, y = x; j < ARRAYTOP(y->operand); ) + { /* Loop through all the parameters of the current opcode. For each parameter that requires an intermediate + * temporary, decrement (this is what remove_backptr does) the "reference count" -- opcodes yet to be + * processed that still need the intermediate result -- and if that number is zero, mark the temporary + * available. We can then reuse the temp to hold the results of subsequent opcodes. Note that remove_backptr + * is essentially the resolve_tref() in resolve_ref.c. resolve_tref increments the "reference count", + * while remove_backptr decrements it. + */ + if (TRIP_REF == j->oprclass) + { + ref = j->oprval.tref; + if (OC_PARAMETER == ref->opcode) + { + y = ref; + j = y->operand; + continue; + } + remove_backptr(y, j, tempcont); + } + j++; + } } for (r = 0; VALUED_REF_TYPES > r; r++) sa_temps[r] = temphigh[r] + 1; @@ -208,10 +213,40 @@ void alloc_reg(void) size = sa_temps[TVAL_REF] * sa_class_sizes[TVAL_REF]; sa_temps_offset[TVAL_REF] = size; /* Since we need to align the temp region to the largest types, align even int temps to SIZEOF(char*) */ - size += ROUND_UP2(sa_temps[TINT_REF] * sa_class_sizes[TINT_REF], SIZEOF(char *)); + size += ROUND_UP2(sa_temps[TINT_REF] *sa_class_sizes[TINT_REF], SIZEOF(char *)); sa_temps_offset[TINT_REF] = size; size += sa_temps[TVAD_REF] * sa_class_sizes[TVAD_REF]; sa_temps_offset[TVAD_REF] = size; size += sa_temps[TCAD_REF] * sa_class_sizes[TCAD_REF]; sa_temps_offset[TCAD_REF] = size; } + +void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT]) +{ + triple *ref; + tbp *b; + int r; + + assert(TRIP_REF == opnd->oprclass); + ref = opnd->oprval.tref; + while (OC_PASSTHRU == opnd->oprval.tref->opcode) + { + ref = ref->operand[0].oprval.tref; + opnd = &ref->operand[0]; + assert(TRIP_REF == opnd->oprclass); + } + r = ref->destination.oprclass; + if (NO_REF != r) + { + dqloop(&ref->backptr, que, b) + { + if (b->bpt == curtrip) + { + dqdel(b, que); + break; + } + } + if ((ref->backptr.que.fl == &ref->backptr) && (TVAR_REF != r)) + tempcont[r][ref->destination.oprval.temp] = 0; + } +} diff --git a/sr_port/asc_hex2i.c b/sr_port/asc_hex2i.c index 23577db..6710073 100644 --- a/sr_port/asc_hex2i.c +++ b/sr_port/asc_hex2i.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,24 +11,53 @@ #include "mdef.h" -unsigned int asc_hex2i(p,len) -char *p; -int len; +LITREF unsigned char lower_to_upper_table[]; + +unsigned int asc_hex2i(uchar_ptr_t p, int len) { - char *c; - int ret; + uchar_ptr_t c; + unsigned char ch; + int ret; ret = 0; for (c = p + len; c > p; p++) { - if (*p >= '0' && *p <= '9') - ret = ret * 16 + *p - '0'; - else if (*p >= 'a' && *p <= 'f') - ret = ret * 16 + *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'F') - ret = ret * 16 + *p - 'A' + 10; + if (('0' <= *p) && ('9' >= *p)) + ret = (ret << 4) + (*p - '0'); else - return (uint4)-1; + { + ch = lower_to_upper_table[*p]; + if (('A' <= ch) && ('F' >= ch)) + ret = (ret << 4) + ch - 'A' + 10; + else + return (unsigned int)-1; + } } return ret; } + +#ifndef VMS +/* Routine identical to asc_hex2i() but with 8 byte accumulator and return type */ +gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len) +{ + uchar_ptr_t c; + unsigned char ch; + gtm_uint64_t ret; + + ret = 0; + for (c = p + len; c > p; p++) + { + if (('0' <= *p) && ('9' >= *p)) + ret = (ret << 4) + (*p - '0'); + else + { + ch = lower_to_upper_table[*p]; + if (('A' <= ch) && ('F' >= ch)) + ret = (ret << 4) + ch - 'A' + 10; + else + return (gtm_uint64_t)-1; + } + } + return ret; +} +#endif diff --git a/sr_port/base_frame.c b/sr_port/base_frame.c index 9f1bd21..919d058 100644 --- a/sr_port/base_frame.c +++ b/sr_port/base_frame.c @@ -13,7 +13,8 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include "error.h" /* For DBGEHND() */ +#include #include "stack_frame.h" GBLREF unsigned char *stacktop, *stackwarn, *msp; @@ -61,4 +62,5 @@ void base_frame(rhdtyp *base_address) fp->type = SFT_COUNT; fp->ret_value = NULL; fp->dollar_test = -1; + DBGEHND((stderr, "base_frame: New base frame allocated at 0x"lvaddr"\n", fp)); } diff --git a/sr_port/bm_getfree.c b/sr_port/bm_getfree.c index a872d11..6faf3e1 100644 --- a/sr_port/bm_getfree.c +++ b/sr_port/bm_getfree.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -67,6 +67,9 @@ GBLREF uint4 dollar_tlevel; GBLREF uint4 update_array_size, cumul_update_array_size; GBLREF unsigned int t_tries; +error_def(ERR_DBBADFREEBLKCTR); +error_def(ERR_DBMBMINCFREFIXED); + block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_work, cw_set_element *cs, int *cw_depth_ptr) { cw_set_element *cs1; @@ -81,18 +84,7 @@ block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_wor uint4 status; srch_blk_status blkhist; -# ifdef GTM_TRUNCATE - if (dba_mm == cs_data->acc_meth) - { - total_blks = cs_addrs->total_blks; - } else - { - total_blks = cs_addrs->ti->total_blks; - cs_addrs->total_blks = MAX(cs_addrs->total_blks, total_blks); - } -# else total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; -# endif if (orig_hint >= total_blks) /* for TP, hint can be > total_blks */ orig_hint = 1; hint = orig_hint; @@ -110,16 +102,12 @@ block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_wor hint = 1; continue; } - if (SS_NORMAL != (status = gdsfilext(cs_data->extension_size, total_blks))) + if (SS_NORMAL != (status = GDSFILEXT(cs_data->extension_size, total_blks, TRANS_IN_PROG_TRUE))) return (status); if (dba_mm == cs_data->acc_meth) return (FILE_EXTENDED); hint = total_blks; total_blks = cs_addrs->ti->total_blks; -# ifdef GTM_TRUNCATE - assert(dba_mm != cs_data->acc_meth); - cs_addrs->total_blks = MAX(cs_addrs->total_blks, total_blks); -# endif hint_cycled = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP); local_maps = hint_cycled + 2; /* for (up to) 2 wraps */ /* @@ -214,14 +202,21 @@ block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_wor if (hint_cycled) hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0; } - if ((0 == depth) && (FALSE != cs_addrs->now_crit)) /* if it's from the cw_set, its state is murky */ - bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data)); /* if crit, repair master map error */ + if ((0 == depth) && cs_addrs->now_crit) /* if it's from the cw_set, its state is murky */ + { + assert(FALSE); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_DBMBMINCFREFIXED, 1, bml); + bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data)); /* repair master map error */ + } } - /* If not in the final retry, it is possible that free_bit is >= map_size (e.g. if bitmap block gets recycled). */ - if (map_size <= (uint4)free_bit && CDB_STAGNATE <= t_tries) - { /* bad free bit */ + /* If not in the final retry, it is possible that free_bit is >= map_size, e.g., if the buffer holding the bitmap block + * gets recycled with a non-bitmap block in which case the bit that bm_find_blk returns could be greater than map_size. + * But, this should never happen in final retry. + */ + if ((map_size <= (uint4)free_bit) && (CDB_STAGNATE <= t_tries)) + { /* Bad free bit. */ assert((NO_FREE_SPACE == free_bit) && (lcnt > local_maps)); /* All maps full, should have extended */ - GTMASSERT; + assertpro(FALSE); } if (0 != depth) { @@ -263,8 +258,6 @@ boolean_t is_free_blks_ctr_ok(void) sm_uc_ptr_t bmp; unsigned int local_maps, total_blks, free_blocks; - error_def(ERR_DBBADFREEBLKCTR); - assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data && cs_addrs->now_crit); total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; local_maps = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP); @@ -296,7 +289,8 @@ boolean_t is_free_blks_ctr_ok(void) assert(cs_addrs->ti->free_blocks == free_blocks); if (cs_addrs->ti->free_blocks != free_blocks) { - send_msg(VARLSTCNT(6) ERR_DBBADFREEBLKCTR, 4, DB_LEN_STR(gv_cur_region), cs_addrs->ti->free_blocks, free_blocks); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_DBBADFREEBLKCTR, 4, DB_LEN_STR(gv_cur_region), + cs_addrs->ti->free_blocks, free_blocks); cs_addrs->ti->free_blocks = free_blocks; return FALSE; } diff --git a/sr_port/bm_setmap.c b/sr_port/bm_setmap.c index 9d61b9b..e575bf2 100644 --- a/sr_port/bm_setmap.c +++ b/sr_port/bm_setmap.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,13 +35,13 @@ #include "gvcst_map_build.h" #include "mm_read.h" -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF sgmnt_data_ptr_t cs_data; -GBLREF char *update_array, *update_array_ptr; -GBLREF cw_set_element cw_set[]; -GBLREF unsigned char rdfail_detail; -GBLREF unsigned char *non_tp_jfb_buff_ptr; +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data_ptr_t cs_data; +GBLREF char *update_array, *update_array_ptr; +GBLREF cw_set_element cw_set[]; +GBLREF unsigned char rdfail_detail; +GBLREF jnl_format_buffer *non_tp_jfb_ptr; void bm_setmap(block_id bml, block_id blk, int4 busy) { @@ -96,8 +96,8 @@ void bm_setmap(block_id bml, block_id blk, int4 busy) if (JNL_ENABLED(cs_data)) { cse = (cw_set_element *)(&cw_set[0]); - cse->new_buff = non_tp_jfb_buff_ptr; - memcpy(non_tp_jfb_buff_ptr, bmp, ((blk_hdr_ptr_t)bmp)->bsiz); + cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; + memcpy(cse->new_buff, bmp, ((blk_hdr_ptr_t)bmp)->bsiz); gvcst_map_build((uint4 *)cse->upd_addr, (uchar_ptr_t)cse->new_buff, cse, cs_addrs->ti->curr_tn); cse->done = TRUE; } diff --git a/sr_port/bool_expr.c b/sr_port/bool_expr.c index 68e3d73..d4b2845 100644 --- a/sr_port/bool_expr.c +++ b/sr_port/bool_expr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,6 +10,7 @@ ****************************************************************/ #include "mdef.h" +#include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" @@ -19,17 +20,15 @@ int bool_expr(boolean_t op, oprtype *addr) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (!(TREF(expr_depth))++) - TREF(expr_start) = TREF(expr_start_orig) = NULL; + INCREMENT_EXPR_DEPTH; if (!eval_expr(&x)) { - TREF(expr_depth) = 0; + DECREMENT_EXPR_DEPTH; return FALSE; } assert(TRIP_REF == x.oprclass); coerce(&x, OCT_BOOL); bx_tail(x.oprval.tref, op, addr); - if (!(--(TREF(expr_depth)))) - TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE; + DECREMENT_EXPR_DEPTH; return TRUE; } diff --git a/sr_port/bt_get.c b/sr_port/bt_get.c index f956870..ec9b8a5 100644 --- a/sr_port/bt_get.c +++ b/sr_port/bt_get.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,7 +40,7 @@ bt_rec_ptr_t bt_get(int4 block) /* block = block # to get */ if (bt->blk == BT_QUEHEAD) return NULL; } - SET_TRACEABLE_VAR(csa->hdr->wc_blocked, TRUE); + SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_bt_get); return NULL; /* actually should return BT_INVALID or some such value but callers check only for NULL */ } diff --git a/sr_port/bt_init.c b/sr_port/bt_init.c index d86ea85..2eb0b1e 100644 --- a/sr_port/bt_init.c +++ b/sr_port/bt_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,14 +16,17 @@ #include "gdsbt.h" #include "gdsfhead.h" -void bt_init(sgmnt_addrs *cs) +void bt_init(sgmnt_addrs *csa) { - sgmnt_data_ptr_t base; + sgmnt_data_ptr_t csd; - base = cs->hdr; - cs->ti = &base->trans_hist; - cs->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->bt_header_off); - cs->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->bt_base_off); - cs->th_base = (th_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->th_base_off); + csd = csa->hdr; + csa->ti = &csd->trans_hist; + if (dba_mm != csd->acc_meth) + { /* BT structures are NOT maintained for MM */ + csa->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_header_off); + csa->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_base_off); + csa->th_base = (th_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->th_base_off); + } return; } diff --git a/sr_port/bt_put.c b/sr_port/bt_put.c index 235f7a8..c1c7a2d 100644 --- a/sr_port/bt_put.c +++ b/sr_port/bt_put.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,6 +35,9 @@ GBLREF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover" */ GBLREF uint4 process_id; GBLREF jnl_gbls_t jgbl; +error_def(ERR_BTFAIL); +error_def(ERR_WCBLOCKED); + bt_rec_ptr_t bt_put(gd_region *reg, int4 block) { bt_rec_ptr_t bt, q0, q1, hdr; @@ -45,10 +48,6 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block) trans_num lcl_tn; uint4 lcnt; - error_def(ERR_BTFAIL); - error_def(ERR_WCFAIL); - error_def(ERR_WCBLOCKED); - csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs; csd = csa->hdr; assert(csa->now_crit || csd->clustered); @@ -72,7 +71,7 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block) BG_TRACE_PRO_ANY(csa, bt_put_flush_dirty); if (FALSE == wcs_get_space(reg, 0, cr)) { - assert(csd->wc_blocked); /* only reason we currently know + assert(csa->nl->wc_blocked); /* only reason we currently know * why wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO_ANY(csa, wcb_bt_put); @@ -92,8 +91,7 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block) bt->killtn = lcl_tn; insqt((que_ent_ptr_t)bt, (que_ent_ptr_t)hdr); th = (th_rec_ptr_t)remqh((que_ent_ptr_t)csa->th_base); - if (EMPTY_QUEUE == (sm_long_t)th) - GTMASSERT; + assertpro(EMPTY_QUEUE != (sm_long_t)th); break; } if (bt->blk == block) @@ -114,8 +112,7 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block) assert(in_wcs_recover || (bt->tn < lcl_tn) || (jgbl.forw_phase_recovery && !JNL_ENABLED(csa))); q0 = (bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->tnque.fl); th = (th_rec_ptr_t)remqt((que_ent_ptr_t)((sm_uc_ptr_t)q0 + SIZEOF(th->tnque))); - if (EMPTY_QUEUE == (sm_long_t)th) - GTMASSERT; + assertpro(EMPTY_QUEUE != (sm_long_t)th); break; } if (0 == bt->blkque.fl) diff --git a/sr_port/bt_refresh.c b/sr_port/bt_refresh.c index 87b8dd0..5c7d858 100644 --- a/sr_port/bt_refresh.c +++ b/sr_port/bt_refresh.c @@ -46,7 +46,7 @@ void bt_refresh(sgmnt_addrs *csa, boolean_t init) insqt((que_ent_ptr_t)((sm_uc_ptr_t)ptr + (2 * SIZEOF(sm_off_t))), (que_ent_ptr_t)csa->th_base); } } - ((th_rec *)((uchar_ptr_t)csa->th_base + csa->th_base->tnque.fl))->tn = csa->ti->curr_tn - 1; + SET_OLDEST_HIST_TN(csa, csa->ti->curr_tn - 1); csa->ti->mm_tn = 0; return; } diff --git a/sr_port/bx_boolop.c b/sr_port/bx_boolop.c index 778a2b2..a1455b3 100644 --- a/sr_port/bx_boolop.c +++ b/sr_port/bx_boolop.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,6 +10,7 @@ ****************************************************************/ #include "mdef.h" +#include "cmd_qlf.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" @@ -19,11 +20,48 @@ LITREF octabstruct oc_tab[]; +GBLREF boolean_t run_time; +GBLREF command_qualifier cmd_qlf; + +#define STOTEMP_IF_NEEDED(REF0, I, T1, OPND) \ +{ /* Input: \ + * --- REF0: a boolean triple, which may have either 1 input (OC_COBOOL) or 2 (other opcodes). \ + * --- I: whichever operand of REF0 we are STOTEMPing \ + * --- T1: STOTEMP triple. NOOPed if not needed \ + * --- OPND: operand referring to value we need need to pass as input into boolean operation \ + * If OPND refers to a variable (OC_VAR), we need to STOTEMP it to protect it from subsequent side effects. \ + * If it refers to a literal, and dynamic literals are enabled, we need to insert an OC_LITC anyway. Doing it \ + * here in bx_boolop is convenient and ensures the OC_LITC is not skipped at run time. \ + */ \ + assert(TRIP_REF == OPND.oprclass); \ + switch (OPND.oprval.tref->opcode) \ + { \ + case OC_VAR: \ + T1->opcode = OC_STOTEMP; \ + T1->operand[0] = OPND; \ + REF0->operand[I] = put_tref(T1); \ + break; \ + case OC_LIT: \ + if (!run_time && (cmd_qlf.qlf & CQ_DYNAMIC_LITERALS)) \ + { \ + T1->opcode = OC_LITC; \ + T1->operand[0] = OPND; \ + REF0->operand[I] = put_tref(T1); \ + break; \ + } \ + default: \ + T1->opcode = OC_NOOP; \ + T1->operand[0].oprclass = NO_REF; \ + REF0->operand[I] = put_tref(OPND.oprval.tref); \ + } \ +} + void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr) { boolean_t expr_fini; - oprtype *i, *p; - triple *ref0, *ref1, *t0, *t1; + oprtype *adj_addr, *i, *p; + tbp *tripbp; + triple *ref0, *ref1, *ref2, *t0, *t1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -35,77 +73,93 @@ void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean *p = put_tjmp(t); } else p = addr; - if (GTM_BOOL == TREF(gtm_fullbool) || !TREF(saw_side_effect)) + if (!TREF(saw_side_effect) || ((OLD_SE == TREF(side_effect_handling)) && (GTM_BOOL == TREF(gtm_fullbool)))) { /* nice simple short circuit */ assert(NULL == TREF(boolchain_ptr)); bx_tail(t->operand[0].oprval.tref, jmp_type_one, p); bx_tail(t->operand[1].oprval.tref, sense, addr); - } else - { /* got a side effect and don't want them short circuited - this violates info hiding big-time - * This code relies on the original technique of setting up a jump ladder - * then it changes the jumps into stotemps and creates a new ladder using the saved evaluations - * for the relocated jumps to work with - * The most interesting part is getting the addresses for the new jump operands (targets) - * In theory we could turn this technique on and off around each side effect, but that's even more - * complicated, requiring additional instructions, and we don't predict the typical boolean expression - * has enough subexpressions to justify the extra trouble, although the potential pay-back would be to - * avoid unnecessary global references - again not expecting that many in a typical boolean expresion - */ - assert(TREF(shift_side_effects)); + t->opcode = OC_NOOP; + t->operand[0].oprclass = t->operand[1].oprclass = NO_REF; + return; + } + /* got a side effect and don't want them short circuited */ + /* This code violates info hiding big-time and relies on the original technique of setting up a jump ladder + * then it changes the jumps into stotemps and creates a new ladder using the saved evaluations + * for the relocated jumps to use for controlling conditional transfers, When the stotemps reference mvals, + * they are optimized away when possible. The most interesting part is getting the addresses for the new jump + * operands (targets) - see comment below. In theory we could turn this technique on and off around each side effect, + * but that's even more complicated, requiring additional instructions, and we don't predict the typical boolean + * expression has enough subexpressions to justify the extra trouble, although the potential pay-back would be to + * avoid unnecessary global references - again, not expecting that many in a typical boolean expresion. + */ + assert(TREF(shift_side_effects)); + if (expr_fini = (NULL == TREF(boolchain_ptr))) /* NOTE assignment */ + { /* initialize work on boolean section of the AST */ + TREF(boolchain_ptr) = &(TREF(boolchain)); + dqinit(TREF(boolchain_ptr), exorder); t0 = t->exorder.fl; - if (expr_fini = (NULL == TREF(boolchain_ptr))) /* NOTE assignment */ - { - if (OC_BOOLFINI == t0->opcode) - { /* ex_tail wraps bools that produce a value with OC_BOOLINIT and OC_BOOLFINI */ - assert(OC_COMVAL == t0->exorder.fl->opcode); - assert(TRIP_REF == t0->operand[0].oprclass); - } else - assert(((OC_NOOP == t0->opcode) && (t0 == TREF(curtchain))) - || (oc_tab[t0->opcode].octype & OCT_BOOL)); - TREF(boolchain_ptr) = &(TREF(boolchain)); - dqinit(TREF(boolchain_ptr), exorder); + if (NULL == TREF(bool_targ_ptr)) + { /* first time - set up anchor */ + TREF(bool_targ_ptr) = &(TREF(bool_targ_anchor)); /* mcalloc won't persist over multiple complies */ + dqinit(TREF(bool_targ_ptr), que); + } else /* queue should be empty */ + assert((TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.fl) + && (TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.bl)); + /* ex_tail wraps bools that produce a value with OC_BOOLINIT (clr) and OC_BOOLFINI (set) */ + assert((OC_BOOLFINI != t0->opcode) + || ((OC_COMVAL == t0->exorder.fl->opcode) && (TRIP_REF == t0->operand[0].oprclass))); + } + for (i = t->operand; i < ARRAYTOP(t->operand); i++) + { + assert(NULL != TREF(boolchain_ptr)); + t1 = i->oprval.tref; + if (&(t->operand[0]) == i) + bx_tail(t1, jmp_type_one, p); /* do normal transform */ + else + { /* operand[1] */ + bx_tail(t1, sense, addr); /* do normal transform */ + if (!expr_fini) + break; /* only need to relocate last operand[1] */ } - for (i = t->operand; i < ARRAYTOP(t->operand); i++) - { - t1 = i->oprval.tref; - if (&(t->operand[0]) == i) - bx_tail(t1, jmp_type_one, p); - else - { /* operand[1] */ - bx_tail(t1, sense, addr); - if (!expr_fini) - break; /* only need to relocate last operand[1] */ - } + if (OC_NOOP == t1->opcode) + { /* the technique of sprinkling noops means fishing around for the actual instruction */ + do + { + t1 = t1->exorder.bl; + assert(TREF(curtchain) != t1->exorder.bl); + } while (OC_NOOP == t1->opcode); + if ((oc_tab[t1->opcode].octype & OCT_JUMP) && (OC_JMPTSET != t1->opcode) && (OC_JMPTCLR != t1->opcode)) + t1 = t1->exorder.bl; if (OC_NOOP == t1->opcode) - { /* the technique of sprinkling noops means fishing around for the actual instruction */ - do - { - t1 = t1->exorder.bl; - } while (OC_NOOP == t1->opcode); - if (oc_tab[t1->opcode].octype & OCT_JUMP) - t1 = t1->exorder.bl; - else - { - for (t1 = i->oprval.tref; OC_NOOP == t1->opcode; t1 = t1->exorder.fl) - ; - } + { + for (t1 = i->oprval.tref; OC_NOOP == t1->opcode; t1 = t1->exorder.fl) + assert(TREF(curtchain) != t1->exorder.fl); } - assert(NULL != TREF(boolchain_ptr)); - switch (t1->opcode) - { /* time to subvert the original jump ladder entry */ + } + assert(OC_NOOP != t1->opcode); + assert((oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP) + ||(OC_JMPTSET != t1->exorder.fl->opcode) || (OC_JMPTCLR != t1->exorder.fl->opcode)); + ref0 = maketriple(t1->opcode); /* copy operation for place in new ladder */ + ref1 = (TREF(boolchain_ptr))->exorder.bl; /* common setup for above op insert */ + switch (t1->opcode) + { /* time to subvert original jump ladder entry */ case OC_COBOOL: /* insert COBOOL and copy of following JMP in boolchain; overlay them with STOTEMP and NOOP */ - assert(oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP); - ref0 = maketriple(OC_COBOOL); /* coerce later while pulling it out of temp */ - ref0->operand[0] = put_tref(t1); - ref1 = (TREF(boolchain_ptr))->exorder.bl; + assert(TRIP_REF == t1->operand[0].oprclass); dqins(ref1, exorder, ref0); - t1->opcode = OC_STOTEMP; /* save the value instead of coercing now */ + if (oc_tab[t1->operand[0].oprval.tref->opcode].octype & OCT_MVAL) + { /* do we need a STOTEMP? */ + STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]); + } else + { /* make it an mval instead of COBOOL now */ + t1->opcode = OC_COMVAL; + ref0->operand[0] = put_tref(t1); /* new COBOOL points to this OC_COMVAL */ + } t1 = t1->exorder.fl; - ref0 = maketriple(t1->opcode); /* create new jump on result of coerce */ + ref0 = maketriple(t1->opcode); /* create new jmp on result of coerce */ ref0->operand[0] = t1->operand[0]; - t1->operand[0].oprclass = NOCLASS; - t1->opcode = OC_NOOP; /* wipe out original jump */ + t1->opcode = OC_NOOP; /* wipe out original jmp */ + t1->operand[0].oprclass = NO_REF; break; case OC_CONTAIN: case OC_EQU: @@ -114,85 +168,117 @@ void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean case OC_PATTERN: case OC_SORTS_AFTER: /* insert copies of orig OC and following JMP in boolchain & overly originals with STOTEMPs */ - assert(oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP); assert(TRIP_REF == t1->operand[0].oprclass); assert(TRIP_REF == t1->operand[1].oprclass); - ref0 = maketriple(t1->opcode); /* copy operands with the stotemps as args */ - ref0->operand[0] = put_tref(t1); - ref0->operand[1] = put_tref(t1->exorder.fl); - ref1 = (TREF(boolchain_ptr))->exorder.bl; dqins(ref1, exorder, ref0); - t1->opcode = OC_STOTEMP; /* overlay the original op with 1st stotemp */ + STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]); + ref1 = t1; t1 = t1->exorder.fl; - ref0 = maketriple(t1->opcode); /* copy jmp */ - ref0->operand[0] = t1->operand[0]; - t1->operand[0] = t1->exorder.bl->operand[1]; - t1->opcode = OC_STOTEMP; /* overlay jmp with 2nd stotemp */ + ref2 = maketriple(t1->opcode); /* copy jmp */ + ref2->operand[0] = t1->operand[0]; + STOTEMP_IF_NEEDED(ref0, 1, t1, ref1->operand[1]); + if (OC_NOOP == ref1->opcode) /* does op[0] need cleanup? */ + ref1->operand[0].oprclass = ref1->operand[1].oprclass = NO_REF; + ref0 = ref2; break; case OC_JMPTSET: case OC_JMPTCLR: - /* move copy of jmp to boolchain and NOOP it */ - ref0 = maketriple(t1->opcode); - ref0->operand[0] = t1->operand[0]; - t1->operand[0].oprclass = NOCLASS; - t1->opcode = OC_NOOP; /* wipe out original jump */ + /* move copy of jmp to boolchain and NOOP it */ + ref0->operand[0] = t1->operand[0]; /* new jmpt gets old target */ + ref2 = maketriple(OC_NOOP); /* insert a NOOP in new chain inplace of COBOOL */ + dqins(ref1, exorder, ref2); + t1->opcode = OC_NOOP; /* wipe out original jmp */ + t1->operand[0].oprclass = NO_REF; break; default: - GTMASSERT; - } - if (jmp_to_next) /* mark target for later adjustment */ - ref0->operand[1].oprval.tref = ref0->operand[0].oprval.tref; - ref1 = (TREF(boolchain_ptr))->exorder.bl; - dqins(ref1, exorder, ref0); - } - if (expr_fini) - { /* time to deal with new jump ladder */ - assert(NULL != TREF(boolchain_ptr)); - t0 = t0->exorder.bl; - assert(oc_tab[t0->opcode].octype & OCT_BOOL); - assert(t0 == t); - dqadd(t0, TREF(boolchain_ptr), exorder); /* insert the new jump ladder */ - ref0 = (TREF(boolchain_ptr))->exorder.bl->exorder.fl; - if (ref0 == TREF(curtchain)) - { - newtriple(OC_NOOP); - ref0 = (TREF(curtchain))->exorder.bl; - } - assert(ref0); - t0 = t->exorder.fl; - if ((OC_JMPTSET != t0->opcode) && (OC_JMPTCLR != t0->opcode)) - t0 = t0->exorder.fl; - for (; (t0 != TREF(curtchain)) && oc_tab[t0->opcode].octype & OCT_JUMP; t0 = t1) - { /* check for jumps with targets */ - assert(INDR_REF == t0->operand[0].oprclass); - t1 = t0->exorder.fl; - if (oc_tab[t1->opcode].octype & OCT_BOOL) - t1 = ref1 = t1->exorder.fl; - else - { - if ((OC_JMPTSET == t1->opcode) || (OC_JMPTCLR == t1->opcode)) - ref1 = t1; - else - break; - } - if (t0->operand[1].oprval.tref == t0->operand[0].oprval.tref) - { /* adjust relocated jump to "next" */ - if (oc_tab[ref1->opcode].octype & OCT_JUMP) - ref1 = ref1->exorder.fl; - if ((ref1 == TREF(curtchain) - || (t == t0->operand[0].oprval.tref->exorder.fl))) - ref1 = ref0; - assert((OC_NOOP == ref1->opcode) || (OC_BOOLFINI == ref1->opcode) - || (OC_COMVAL == ref1->opcode) || (oc_tab[ref1->opcode].octype & OCT_BOOL)); - t0->operand[0] = put_tjmp(ref1); - t0->operand[1].oprval.tref = NULL; - } else if (TJMP_REF == t0->operand[0].oprval.indr->oprclass) - t0->operand[0] = put_tjmp(ref0); /* adjust jump to "addr" */ - } - TREF(boolchain_ptr) = NULL; + assertpro(FALSE); } + assert((OC_STOTEMP == t1->opcode) || (OC_NOOP == t1->opcode) || (OC_COMVAL == t1->opcode) + || (OC_LITC == t1->opcode)); + assert(oc_tab[ref0->opcode].octype & OCT_JUMP); + ref1 = (TREF(boolchain_ptr))->exorder.bl; + dqins(ref1, exorder, ref0); /* common insert for new jmp */ + } + assert(oc_tab[t->opcode].octype & OCT_BOOL); + t->opcode = OC_NOOP; /* wipe out the original boolean op */ + t->operand[0].oprclass = t->operand[1].oprclass = NO_REF; + tripbp = &t->jmplist; /* borrow jmplist to track jmp targets */ + assert(NULL == tripbp->bpt); + assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); + tripbp->bpt = jmp_to_next ? (TREF(boolchain_ptr))->exorder.bl : ref0; /* point op triple at op[1] position or op[0] */ + dqins(TREF(bool_targ_ptr), que, tripbp); /* queue jmplist for clean-up */ + if (!expr_fini) + return; + /* time to deal with new jump ladder */ + assert(NULL != TREF(boolchain_ptr)); + assert(NULL != TREF(bool_targ_ptr)); + assert(TREF(bool_targ_ptr) != (TREF(bool_targ_ptr))->que.fl); + assert(t0->exorder.bl == t); + assert(t0 == t->exorder.fl); + dqadd(t, TREF(boolchain_ptr), exorder); /* insert the new jump ladder */ + ref0 = (TREF(boolchain_ptr))->exorder.bl->exorder.fl; + t0 = t->exorder.fl; + if (ref0 == TREF(curtchain)) + { /* add a safe target */ + newtriple(OC_NOOP); + ref0 = (TREF(curtchain))->exorder.bl; + } + assert((OC_COBOOL == t0->opcode) ||(OC_JMPTSET != t0->opcode) || (OC_JMPTCLR != t0->opcode)) ; + t0 = t0->exorder.fl; + assert(oc_tab[t0->opcode].octype & OCT_JUMP); + for (; (t0 != ref0) && oc_tab[t0->opcode].octype & OCT_JUMP; t0 = t0->exorder.fl) + { /* process replacement jmps */ + adj_addr = &t0->operand[0]; + assert(INDR_REF == adj_addr->oprclass); + if (NULL != (t1 = (adj_addr = adj_addr->oprval.indr)->oprval.tref)) + { /* need to adjust target; NOTE assignments above */ + if (OC_BOOLFINI != t1->opcode) + { /* not past the end of the new chain */ + assert(TJMP_REF == adj_addr->oprclass); + if ((t == t1) || (t1 == ref0)) + ref1 = ref0; /* adjust to end of boolean expression */ + else + { /* old target should have jmplist entry */ + /* from the jmp jmplisted in the old target we move past the next + * test (or NOOP) and jmp which correspond to the old target and pick + * the subsequent test (or NOOP) and jmp which correspond to those that originally followed + * the logic after the old target and are therefore the appropriate new target for this jmp + */ + assert(OC_NOOP == t1->opcode); + assert(&(t1->jmplist) != t1->jmplist.que.fl); + assert(NULL != t1->jmplist.bpt); + assert(oc_tab[t1->jmplist.bpt->opcode].octype & OCT_JUMP); + ref1 = t1->jmplist.bpt->exorder.fl; + assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_NOOP == ref1->opcode)); + assert(oc_tab[ref1->exorder.fl->opcode].octype & OCT_JUMP); + ref1 = ref1->exorder.fl->exorder.fl; + assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_BOOLFINI == ref1->opcode) + || ((OC_NOOP == ref1->opcode) && ((OC_JMPTCLR == ref1->exorder.fl->opcode) + || (OC_JMPTSET == ref1->exorder.fl->opcode) + || (TREF(curtchain) == ref1->exorder.fl)))); + } + t0->operand[0] = put_tjmp(ref1); /* no indrection simplifies later interations */ + } + } + t0 = t0->exorder.fl; + if ((OC_BOOLFINI == t0->opcode) || (TREF(curtchain) == t0->exorder.fl)) + break; + assert((oc_tab[t0->opcode].octype & OCT_BOOL) + || (OC_JMPTSET == t0->exorder.fl->opcode) || (OC_JMPTCLR == t0->exorder.fl->opcode)); + } + dqloop(TREF(bool_targ_ptr), que, tripbp) /* clean up borrowed jmplist entries */ + { + dqdel(tripbp, que); + tripbp->bpt = NULL; + } + assert((TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.fl) + && (TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.bl)); + TREF(boolchain_ptr) = NULL; + if (TREF(expr_start) != TREF(expr_start_orig)) + { /* inocculate against an unwanted GVRECTARG */ + ref0 = maketriple(OC_NOOP); + dqins(TREF(expr_start), exorder, ref0); + TREF(expr_start) = ref0; } - t->opcode = OC_NOOP; - t->operand[0].oprclass = t->operand[1].oprclass = NOCLASS; return; } diff --git a/sr_port/bx_tail.c b/sr_port/bx_tail.c index 0f87597..f8cae7a 100644 --- a/sr_port/bx_tail.c +++ b/sr_port/bx_tail.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,7 +45,7 @@ void bx_tail(triple *t, boolean_t sense, oprtype *addr) assert((1 & sense) == sense); assert(oc_tab[t->opcode].octype & OCT_BOOL); assert(TRIP_REF == t->operand[0].oprclass); - assert((TRIP_REF == t->operand[1].oprclass) || (NOCLASS == t->operand[1].oprclass)); + assert((TRIP_REF == t->operand[1].oprclass) || (NO_REF == t->operand[1].oprclass)); switch (t->opcode) { case OC_COBOOL: @@ -64,7 +64,7 @@ void bx_tail(triple *t, boolean_t sense, oprtype *addr) case OC_COM: bx_tail(t->operand[0].oprval.tref, !sense, addr); t->opcode = OC_NOOP; - t->operand[0].oprclass = 0; + t->operand[0].oprclass = NO_REF; return; case OC_NEQU: sense = !sense; diff --git a/sr_port/cache_cleanup.c b/sr_port/cache_cleanup.c index d136130..420e5a8 100644 --- a/sr_port/cache_cleanup.c +++ b/sr_port/cache_cleanup.c @@ -13,7 +13,7 @@ #include "objlabel.h" #include "cache.h" #include "hashtab_objcode.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "cache_cleanup.h" diff --git a/sr_port/cache_put.c b/sr_port/cache_put.c index 95da88b..7dcc5a1 100644 --- a/sr_port/cache_put.c +++ b/sr_port/cache_put.c @@ -16,7 +16,7 @@ #include "hashtab_objcode.h" #include "cachectl.h" #include "cacheflush.h" -#include "rtnhdr.h" +#include #include "gtm_text_alloc.h" #include "io.h" diff --git a/sr_port/cdb_sc_table.h b/sr_port/cdb_sc_table.h index 1550093..fe040c1 100644 --- a/sr_port/cdb_sc_table.h +++ b/sr_port/cdb_sc_table.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,11 +40,13 @@ CDB_SC_NUM_ENTRY( cdb_sc_normal, 0) /* 0 success */ CDB_SC_NUM_ENTRY( cdb_sc_endtree, 1) /* 1 gvcst_lftsib or gvcst_rtsib searched past end of tree */ -CDB_SC_NUM_ENTRY( cdb_sc_delete_parent, 2) /* 2 gvcst_kill_blk succeeded, but signals gvcst_kill that block was completely deleted */ +CDB_SC_NUM_ENTRY( cdb_sc_delete_parent, 2) /* 2 gvcst_kill_blk succeeded, but signals gvcst_kill + * that block was completely deleted */ CDB_SC_NUM_ENTRY( cdb_sc_nolock, 3) /* 3 mutex_lockwim was unable to obtain a lock */ -CDB_SC_NUM_ENTRY( cdb_sc_needcrit, 4) /* 4 on 4th attempt and need crit for this region -- restart transaction no penalty */ +CDB_SC_NUM_ENTRY( cdb_sc_needcrit, 4) /* 4 on 4th attempt and need crit for this region -- restart transaction + * no penalty */ CDB_SC_NUM_ENTRY( cdb_sc_helpedout, 5) /* 5 wcs_blocked when t_tries >= CDB_STAGNATE */ -CDB_SC_NUM_ENTRY( cdb_sc_gbloflow, 6) /* 6 t_end or tp_tend found the database full and could not be extended */ +CDB_SC_NUM_ENTRY( cdb_sc_gbloflow, 6) /* 6 t_end or tp_tend found database full and could not be extended */ CDB_SC_NUM_ENTRY( cdb_sc_oprnotneeded, 7) /* 7 reorg operation was not required */ CDB_SC_NUM_ENTRY( cdb_sc_starrecord, 8) /* 8 star record was found while reading the block */ CDB_SC_NUM_ENTRY( cdb_sc_extend, 9) /* 9 extend requested when none seemed needed - from gdsfilext */ @@ -54,45 +56,65 @@ CDB_SC_UCHAR_ENTRY(cdb_sc_rmisalign1, FALSE, 'A') /* 'A' gvcst_get found CDB_SC_UCHAR_ENTRY(cdb_sc_keyoflow, FALSE, 'B') /* 'B' gvcst_expand_key or gvcst_search (3) found key overflow */ CDB_SC_UCHAR_ENTRY(cdb_sc_rmisalign, FALSE, 'C') /* 'C' Record misaligned from nearly everyone */ CDB_SC_UCHAR_ENTRY(cdb_sc_r2small, FALSE, 'D') /* 'D' gvcst_expand_key found record too small */ -CDB_SC_UCHAR_ENTRY(cdb_sc_losthist, TRUE, 'E') /* 'E' t_end or tp_tend (both mm or bg) - tn could not be verified from history */ +CDB_SC_UCHAR_ENTRY(cdb_sc_losthist, TRUE, 'E') /* 'E' t_end/tp_tend (mm/bg) - tn could not be verified from history */ CDB_SC_UCHAR_ENTRY(cdb_sc_mapfail, FALSE, 'F') /* 'F' t_end or op_tcommit (from bm_getfree) failed to acquire new block */ -CDB_SC_UCHAR_ENTRY(cdb_sc_lostcr, TRUE, 'G') /* 'G' gvcst_...sib, t_end, tp_tend, tp_check_hist - found cache buffer modified */ -CDB_SC_UCHAR_ENTRY(cdb_sc_mkblk, FALSE, 'H') /* 'H' Composing a local block failed, from gvcst_kill (3) gvcst_put (14) */ -CDB_SC_UCHAR_ENTRY(cdb_sc_rdfail, FALSE, 'I') /* 'I' t_qread found block number requested is outside size of file as described by fileheader */ -CDB_SC_UCHAR_ENTRY(cdb_sc_badlvl, FALSE, 'J') /* 'J' gvcst_search found a child block didn't have the next block level below its parent */ +CDB_SC_UCHAR_ENTRY(cdb_sc_lostcr, TRUE, 'G') /* 'G' gvcst_...sib, t_end/tp_tend/tp_hist - found cache buffer modified */ +CDB_SC_UCHAR_ENTRY(cdb_sc_mkblk, FALSE, 'H') /* 'H' Composing a local block failed, from gvcst_kill(3) gvcst_put(14) */ +CDB_SC_UCHAR_ENTRY(cdb_sc_rdfail, FALSE, 'I') /* 'I' t_qread found block number requested is outside size of file + * as described by fileheader */ +CDB_SC_UCHAR_ENTRY(cdb_sc_badlvl, FALSE, 'J') /* 'J' gvcst_search found a child block didn't have the next block level + * below its parent */ CDB_SC_UCHAR_ENTRY(cdb_sc_cacheprob, TRUE, 'K') /* 'K' db_csh_get, ... found a cache control problem */ CDB_SC_UCHAR_ENTRY(cdb_sc_blkmod, FALSE, 'L') /* 'L' t_end, or tp_tend found block modified */ CDB_SC_UCHAR_ENTRY(cdb_sc_uperr, FALSE, 'M') /* 'M' t_ch received an unpredicatable error */ CDB_SC_UCHAR_ENTRY(cdb_sc_comfail, FALSE, 'N') /* 'N' Commit failed used in t_end_sysops (8) by (?) */ -CDB_SC_UCHAR_ENTRY(cdb_sc_lostbefor, TRUE, 'O') /* 'O' t_end or tp_tend found the before image needed for journaling was removed from the cache */ +CDB_SC_UCHAR_ENTRY(cdb_sc_lostbefor, TRUE, 'O') /* 'O' t_end or tp_tend found the before image needed for journaling was + * removed from the cache */ CDB_SC_UCHAR_ENTRY(cdb_sc_committfail, FALSE, 'P') /* 'P' t_commit_cleanup found a partially committed block split */ -CDB_SC_UCHAR_ENTRY(cdb_sc_dbccerr, FALSE, 'Q') /* 'Q' mutex found (in 1 of 3 places) an interlock instruction failure in critical mechanism */ -CDB_SC_UCHAR_ENTRY(cdb_sc_critreset, FALSE, 'R') /* 'R' mutex found (in 1 of 6 places) that the segment crit crash count has been incremented */ -CDB_SC_UCHAR_ENTRY(cdb_sc_maxlvl, FALSE, 'S') /* 'S' t_write_root or gvcst_search found maximum legal block level for database exceeded */ -CDB_SC_UCHAR_ENTRY(cdb_sc_blockflush, FALSE, 'T') /* 'T' t_end (hist, or bitmap) found an to update a buffer that is being flushed (GT.CX) */ -CDB_SC_UCHAR_ENTRY(cdb_sc_cyclefail, TRUE, 'U') /* 'U' t_end or tp_tend found a buffer in read(only) set was overwritten though tn static */ +CDB_SC_UCHAR_ENTRY(cdb_sc_dbccerr, FALSE, 'Q') /* 'Q' mutex found (in 1 of 3 places) an interlock instruction failure + * in critical mechanism */ +CDB_SC_UCHAR_ENTRY(cdb_sc_critreset, FALSE, 'R') /* 'R' mutex found (in 1 of 6 places) that the segment crit crash count + * has been incremented */ +CDB_SC_UCHAR_ENTRY(cdb_sc_maxlvl, FALSE, 'S') /* 'S' t_write_root or gvcst_search found maximum legal block level for + * database exceeded */ +CDB_SC_UCHAR_ENTRY(cdb_sc_blockflush, FALSE, 'T') /* 'T' t_end (hist, or bitmap) found an to update a buffer that is being + * flushed (GT.CX) */ +CDB_SC_UCHAR_ENTRY(cdb_sc_cyclefail, TRUE, 'U') /* 'U' t_end or tp_tend found a buffer in read(only) set was overwritten + * though tn static */ CDB_SC_UCHAR_ENTRY(cdb_sc_optrestart, FALSE, 'V') /* 'V' TP restart explicitly signaled by the TRESTART command */ -CDB_SC_UCHAR_ENTRY(cdb_sc_future_read, FALSE, 'W') /* 'W' dsk_read return to t_qread indicated block transaction exceeds curr_tn (GT.CX) */ +CDB_SC_UCHAR_ENTRY(cdb_sc_future_read, FALSE, 'W') /* 'W' dsk_read return to t_qread indicated block transaction exceeds + * curr_tn (GT.CX) */ CDB_SC_UCHAR_ENTRY(cdb_sc_badbitmap, FALSE, 'X') /* 'X' bm_getfree found bitmap had bad size or level */ -CDB_SC_UCHAR_ENTRY(cdb_sc_badoffset, FALSE, 'Y') /* 'Y' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) found a bad record offset */ -CDB_SC_UCHAR_ENTRY(cdb_sc_blklenerr, FALSE, 'Z') /* 'Z' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) reached the end with no match */ +CDB_SC_UCHAR_ENTRY(cdb_sc_badoffset, FALSE, 'Y') /* 'Y' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) found + * a bad record offset */ +CDB_SC_UCHAR_ENTRY(cdb_sc_blklenerr, FALSE, 'Z') /* 'Z' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) reached + * the end with no match */ CDB_SC_LCHAR_ENTRY(cdb_sc_bmlmod, FALSE, 'a') /* 'a' t_end or tp_tend (mm or bg) found bit_map modified */ CDB_SC_LCHAR_ENTRY(cdb_sc_lostbmlhist, TRUE, 'b') /* 'b' t_end or tp_tend (bg) - tn could not be verified from history */ CDB_SC_LCHAR_ENTRY(cdb_sc_lostbmlcr, TRUE, 'c') /* 'c' t_end or tp_tend (bg) - found cache buffer modified */ -CDB_SC_LCHAR_ENTRY(cdb_sc_lostoldblk, FALSE, 'd') /* 'd' t_qread or op_tcommit (tp and before image) - old_block of a used block is NULL */ +CDB_SC_LCHAR_ENTRY(cdb_sc_lostoldblk, FALSE, 'd') /* 'd' t_qread or op_tcommit (tp and before image) - old_block of a used + * block is NULL */ CDB_SC_LCHAR_ENTRY(cdb_sc_blknumerr, FALSE, 'e') /* 'e' t_qread or op_tcommit - block number is impossible */ CDB_SC_LCHAR_ENTRY(cdb_sc_blksplit, FALSE, 'f') /* 'f' recompute_upd_array recognized that the block needs to be split */ CDB_SC_LCHAR_ENTRY(cdb_sc_toomanyrecompute, FALSE, 'g') /* 'g' more than 25% of the blocks in read-set need to be recomputed */ -CDB_SC_LCHAR_ENTRY(cdb_sc_jnlstatemod, FALSE, 'h') /* 'h' csd->jnl_state changed or csd->jnl_before_image changed since start of the transaction */ -CDB_SC_LCHAR_ENTRY(cdb_sc_needlock, FALSE, 'i') /* 'i' on final retry and need to wait for M-lock - restart transaction - allow for max of 16 such restarts */ -CDB_SC_LCHAR_ENTRY(cdb_sc_bkupss_statemod, FALSE, 'j') /* 'j' t_end/tp_tend found that either online-backup-in-progress or snapshot - state changed since start of transaction */ +CDB_SC_LCHAR_ENTRY(cdb_sc_jnlstatemod, FALSE, 'h') /* 'h' csd->jnl_state changed or csd->jnl_before_image changed since start + * of the transaction */ +CDB_SC_LCHAR_ENTRY(cdb_sc_needlock, FALSE, 'i') /* 'i' on final retry and need to wait for M-lock - restart transaction + * - allow for max of 16 such restarts */ +CDB_SC_LCHAR_ENTRY(cdb_sc_bkupss_statemod, FALSE, 'j') /* 'j' t_end/tp_tend found that either online-backup-in-progress or + * snapshot state changed since start of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_crbtmismatch, TRUE, 'k') /* 'k' cr->blk and bt->blk does not match */ CDB_SC_LCHAR_ENTRY(cdb_sc_phase2waitfail, TRUE, 'l') /* 'l' wcs_phase2_commit_wait timed out when called from t_qread */ CDB_SC_LCHAR_ENTRY(cdb_sc_inhibitkills, FALSE, 'm') /* 'm' t_end/tp_tend found inhibit_kills counter greater than zero */ CDB_SC_LCHAR_ENTRY(cdb_sc_triggermod, FALSE, 'n') /* 'n' csd->db_trigger_cycle changed since start of of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_onln_rlbk1, FALSE, 'o') /* 'o' csa->onln_rlbk_cycle changed since start of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_onln_rlbk2, FALSE, 'p') /* 'p' csa->db_onln_rlbkd_cycle changed since start of transaction */ -CDB_SC_LCHAR_ENTRY(cdb_sc_truncate, FALSE, 'q') /* 'q' t_end or tp_tend (bg) - found the database truncated where it wanted to allocate blocks */ +CDB_SC_LCHAR_ENTRY(cdb_sc_truncate, FALSE, 'q') /* 'q' t_qread tried to read a block beyond the end of a database + * that has been concurrently truncated */ CDB_SC_LCHAR_ENTRY(cdb_sc_gvtrootmod, FALSE, 'r') /* 'r' gvcst_kill found a need to redo the gvcst_root_search */ +CDB_SC_LCHAR_ENTRY(cdb_sc_instancefreeze, FALSE, 's') /* 's' instance freeze detected in t_end/tp_tend, requires retry */ +CDB_SC_LCHAR_ENTRY(cdb_sc_gvtrootmod2, FALSE, 't') /* 't' t_end/tp_tend detected root blocks moved by reorg */ +CDB_SC_LCHAR_ENTRY(cdb_sc_spansize, FALSE, 'u') /* 'u' chunks of spanning node don't add up */ +CDB_SC_LCHAR_ENTRY(cdb_sc_restarted, FALSE, 'v') /* 'v' return value indicating t_retry has already happened */ +CDB_SC_LCHAR_ENTRY(cdb_sc_tqreadnowait, FALSE, 'w') /* 'w' update helper returning from t_qread instead of sleeping */ diff --git a/sr_port/cert_blk.c b/sr_port/cert_blk.c index 419d386..46ecb49 100644 --- a/sr_port/cert_blk.c +++ b/sr_port/cert_blk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,6 +41,35 @@ GBLREF uint4 dollar_tlevel; GBLREF boolean_t dse_running; +GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; + +error_def(ERR_DBBLEVMX); +error_def(ERR_DBBLEVMN); +error_def(ERR_DBBSIZMN); +error_def(ERR_DBBSIZMX); +error_def(ERR_DBRSIZMN); +error_def(ERR_DBRSIZMX); +error_def(ERR_DBCMPNZRO); +error_def(ERR_DBSTARSIZ); +error_def(ERR_DBSTARCMP); +error_def(ERR_DBCMPMX); +error_def(ERR_DBKEYMX); +error_def(ERR_DBKEYMN); +error_def(ERR_DBCMPBAD); +error_def(ERR_DBKEYORD); +error_def(ERR_DBPTRNOTPOS); +error_def(ERR_DBPTRMX); +error_def(ERR_DBPTRMAP); +error_def(ERR_DBLVLINC); +error_def(ERR_DBBMSIZE); +error_def(ERR_DBBMBARE); +error_def(ERR_DBBMINV); +error_def(ERR_DBBMMSTR); +error_def(ERR_DBROOTBURN); +error_def(ERR_DBDIRTSUBSC); +error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */ +error_def(ERR_DBINVGBL); +error_def(ERR_DBBDBALLOC); #define BITS_PER_UCHAR 8 #define BLKS_PER_UINT4 ((SIZEOF(uint4) / SIZEOF(unsigned char)) * BITS_PER_UCHAR) / BML_BITS_PER_BLK @@ -54,65 +83,38 @@ GBLREF boolean_t dse_running; #define TEXT4 ", " #define MAX_UTIL_LEN 40 -#define RTS_ERROR_FUNC(err, buff) \ -{ \ - if (gtmassert_on_error) \ - GTMASSERT; \ - rts_error_func(err, buff); \ +#define RTS_ERROR_FUNC(CSA, ERR, BUFF) \ +{ \ + if (gtmassert_on_error) \ + GTMASSERT; \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MAKE_MSG_INFO(ERR), 2, LEN_AND_STR((char_ptr_t)BUFF)); \ } -void rts_error_func(int err, uchar_ptr_t buff); - int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boolean_t gtmassert_on_error) { block_id child, prev_child; rec_hdr_ptr_t rp, r_top; int num_subscripts; - uint4 bplmap, mask1, offset; + uint4 bplmap, mask1, offset, rec_offset, rec_size; sm_uint_ptr_t chunk_p; /* Value is unaligned so will be assigned to chunk */ - uint4 chunk; + uint4 chunk, blk_size; sm_uc_ptr_t blk_top, blk_id_ptr, next_tp_child_ptr, key_base, mp, b_ptr; - unsigned char rec_cmpc, min_cmpc; /* the minimum cmpc expected in any record (except star-key) in a gvt */ + unsigned short rec_cmpc, min_cmpc; /* the minimum cmpc expected in any record (except star-key) in a gvt */ + int tmp_cmpc; unsigned char ch, prior_expkey[MAX_KEY_SZ + 1]; unsigned int prior_expkeylen; unsigned short temp_ushort; int blk_levl; - int blk_size, rec_size, comp_length, rec_offset, key_size; + int comp_length, key_size; unsigned char util_buff[MAX_UTIL_LEN]; int util_len; off_chain chain; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; boolean_t is_gvt, is_directory, first_key, full, prev_char_is_delimiter; + DCL_THREADGBL_ACCESS; - error_def(ERR_DBBLEVMX); - error_def(ERR_DBBLEVMN); - error_def(ERR_DBBSIZMN); - error_def(ERR_DBBSIZMX); - error_def(ERR_DBRSIZMN); - error_def(ERR_DBRSIZMX); - error_def(ERR_DBCMPNZRO); - error_def(ERR_DBSTARSIZ); - error_def(ERR_DBSTARCMP); - error_def(ERR_DBCMPMX); - error_def(ERR_DBKEYMX); - error_def(ERR_DBKEYMN); - error_def(ERR_DBCMPBAD); - error_def(ERR_DBKEYORD); - error_def(ERR_DBPTRNOTPOS); - error_def(ERR_DBPTRMX); - error_def(ERR_DBPTRMAP); - error_def(ERR_DBLVLINC); - error_def(ERR_DBBMSIZE); - error_def(ERR_DBBMBARE); - error_def(ERR_DBBMINV); - error_def(ERR_DBBMMSTR); - error_def(ERR_DBROOTBURN); - error_def(ERR_DBDIRTSUBSC); - error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */ - error_def(ERR_DBINVGBL); - error_def(ERR_DBBDBALLOC); - + SETUP_THREADGBL_ACCESS; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; bplmap = csd->bplmap; @@ -145,18 +147,18 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { if ((unsigned char)blk_levl != LCL_MAP_LEVL) { - RTS_ERROR_FUNC(MAKE_MSG_INFO(ERR_DBLVLINC), util_buff); + RTS_ERROR_FUNC(csa, MAKE_MSG_INFO(ERR_DBLVLINC), util_buff); return FALSE; } if (blk_size != BM_SIZE(bplmap)) { - RTS_ERROR_FUNC(ERR_DBBMSIZE, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBMSIZE, util_buff); return FALSE; } mp = (sm_uc_ptr_t)bp + SIZEOF(blk_hdr); if ((*mp & 1) != 0) { /* bitmap doesn't protect itself */ - RTS_ERROR_FUNC(ERR_DBBMBARE, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBMBARE, util_buff); return FALSE; } full = TRUE; @@ -180,14 +182,14 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo mask1 &= chunk; /* check against the original contents */ if (mask1 != 0) /* busy and reused should never appear together */ { - RTS_ERROR_FUNC(ERR_DBBMINV, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBMINV, util_buff); return FALSE; } } if (full == (NO_FREE_SPACE != gtm_ffs(blk / bplmap, MM_ADDR(csd), MASTER_MAP_BITS_PER_LMAP))) { - RTS_ERROR_FUNC(ERR_DBBMMSTR, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBMMSTR, util_buff); /* DSE CACHE -VERIFY used to fail occasionally with the DBBMMSTR error because of passing * an older twin global buffer that contained stale bitmap information. That is now fixed. * So we dont expect any more such failures. Assert accordingly. @@ -199,52 +201,57 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo } if (blk_levl > MAX_BT_DEPTH) { - RTS_ERROR_FUNC(ERR_DBBLEVMX, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBLEVMX, util_buff); return FALSE; } if (blk_levl < 0) { - RTS_ERROR_FUNC(ERR_DBBLEVMN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBLEVMN, util_buff); return FALSE; } if (blk_levl == 0) { /* data block */ if ((DIR_ROOT == blk) || (blk == root)) { /* headed for where an index block should be */ - RTS_ERROR_FUNC(ERR_DBROOTBURN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBROOTBURN, util_buff); return FALSE; } - if (blk_size < SIZEOF(blk_hdr)) + if (blk_size < (uint4)SIZEOF(blk_hdr)) { - RTS_ERROR_FUNC(ERR_DBBSIZMN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff); return FALSE; } } else { /* index block */ - if (blk_size < (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id))) + if (blk_size < (uint4)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id))) { /* must have at least one record */ - RTS_ERROR_FUNC(ERR_DBBSIZMN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff); return FALSE; } } - if (blk_size > csd->blk_size) + if (blk_size > (uint4)csd->blk_size) { - RTS_ERROR_FUNC(ERR_DBBSIZMX, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBSIZMX, util_buff); return FALSE; } - if (0 == root) - { + is_directory = FALSE; + is_gvt = FALSE; + /* if both "is_directory" and "is_gvt" are FALSE, then we dont know YET if the given block is a directory or gvt */ + if (DIR_ROOT == root) + is_directory = TRUE; + if ((0 != root) && (DIR_ROOT != root)) + is_gvt = TRUE; + /* MUPIP REORG -TRUNCATE has some special cases */ + if (MUSWP_INCR_ROOT_CYCLE == TREF(in_mu_swap_root_state)) + { /* We could be updating either a gvt root block or a directory leaf block. Don't know yet. */ is_directory = FALSE; is_gvt = FALSE; - /* if both "is_directory" and "is_gvt" are FALSE, then we dont know YET if the given block is a directory or gvt */ - } else if (DIR_ROOT == root) - { + } else if (MUSWP_DIRECTORY_SWAP == TREF(in_mu_swap_root_state)) + { /* We know we're updating a directory block, even though root is not DIR_ROOT. root and gv_target correspond + * to the gvt being REORG'ed. + */ is_directory = TRUE; is_gvt = FALSE; - } else - { - is_directory = FALSE; - is_gvt = TRUE; } blk_top = (sm_uc_ptr_t)bp + blk_size; first_key = TRUE; @@ -258,7 +265,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo for (rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bp + SIZEOF(blk_hdr)) ; rp < (rec_hdr_ptr_t)blk_top ; rp = r_top) { GET_RSIZ(rec_size, rp); - rec_offset = (int)((sm_ulong_t)rp - (sm_ulong_t)bp); + rec_offset = (uint4)((sm_ulong_t)rp - (sm_ulong_t)bp); /*add util_buff here*/ util_len=0; @@ -274,23 +281,23 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo util_len += SIZEOF(TEXT2) - 1; util_buff[util_len] = 0; - if (rec_size <= SIZEOF(rec_hdr)) + if (rec_size <= (uint4)SIZEOF(rec_hdr)) { - RTS_ERROR_FUNC(ERR_DBRSIZMN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBRSIZMN, util_buff); return FALSE; } - if (rec_size > (short)((sm_ulong_t)blk_top - (sm_ulong_t)rp)) + if (rec_size > (uint4)((sm_ulong_t)blk_top - (sm_ulong_t)rp)) { - RTS_ERROR_FUNC(ERR_DBRSIZMX, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBRSIZMX, util_buff); return FALSE; } r_top = (rec_hdr_ptr_t)((sm_ulong_t)rp + rec_size); - rec_cmpc = rp->cmpc; + rec_cmpc = EVAL_CMPC(rp); if (first_key) { if (rec_cmpc) { - RTS_ERROR_FUNC(ERR_DBCMPNZRO, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBCMPNZRO, util_buff); return FALSE; } if (0 == blk_levl) @@ -304,12 +311,12 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { /* star key */ if (rec_size != SIZEOF(rec_hdr) + SIZEOF(block_id)) { - RTS_ERROR_FUNC(ERR_DBSTARSIZ, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBSTARSIZ, util_buff); return FALSE; } if (rec_cmpc) { - RTS_ERROR_FUNC(ERR_DBSTARCMP, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBSTARCMP, util_buff); return FALSE; } blk_id_ptr = (sm_uc_ptr_t)rp + SIZEOF(rec_hdr); @@ -323,7 +330,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { if (rec_cmpc >= prior_expkeylen) { - RTS_ERROR_FUNC(ERR_DBCMPMX, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBCMPMX, util_buff); return FALSE; } for (b_ptr = prior_expkey; b_ptr < (prior_expkey + rec_cmpc); b_ptr++) @@ -354,7 +361,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo prev_char_is_delimiter = FALSE; if (blk_id_ptr >= (sm_uc_ptr_t)r_top) { - RTS_ERROR_FUNC(ERR_DBKEYMX, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBKEYMX, util_buff); return FALSE; } } @@ -365,7 +372,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo if (is_gvt) { /* this is a contradiction. a block cannot be a directory and gvt at the same time. * gvt should contain all keys with the same global name */ - RTS_ERROR_FUNC(ERR_DBINVGBL, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBINVGBL, util_buff); return FALSE; } is_directory = TRUE; /* no need to do this if it was already TRUE but we save an if check */ @@ -375,19 +382,19 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo if (is_directory) { /* this is a contradiction. a block cannot be a directory and gvt at the same time. * the directory tree should contain only name-level (i.e. unsubscripted) globals */ - RTS_ERROR_FUNC(ERR_DBDIRTSUBSC, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBDIRTSUBSC, util_buff); return FALSE; } is_gvt = TRUE; /* no need to do this if it was already TRUE but we save an if check */ } if (MAX_GVSUBSCRIPTS <= num_subscripts) { - RTS_ERROR_FUNC(ERR_DBMAXNRSUBS, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBMAXNRSUBS, util_buff); return FALSE; } if (blk_levl && (key_size != (rec_size - SIZEOF(block_id) - SIZEOF(rec_hdr)))) { - RTS_ERROR_FUNC(ERR_DBKEYMN, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBKEYMN, util_buff); return FALSE; } assert(first_key || (rec_cmpc < prior_expkeylen)); @@ -395,12 +402,12 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { if (prior_expkey[rec_cmpc] == key_base[0]) { - RTS_ERROR_FUNC(ERR_DBCMPBAD, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBCMPBAD, util_buff); return FALSE; } if (((unsigned int)prior_expkey[rec_cmpc] >= (unsigned int)key_base[0])) { - RTS_ERROR_FUNC(ERR_DBKEYORD, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBKEYORD, util_buff); return FALSE; } } @@ -419,22 +426,24 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { if (child <= 0) { - RTS_ERROR_FUNC(ERR_DBPTRNOTPOS, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff); return FALSE; } - if (child > csa->ti->total_blks) - { - RTS_ERROR_FUNC(ERR_DBPTRMX, util_buff); + if ((child > csa->ti->total_blks) && !mu_reorg_upgrd_dwngrd_in_prog) + { /* REORG -UPGRADE/DOWNGRADE can update recycled blocks, which may contain children beyond + * the total_blks if a truncate happened sometime after the block was killed. + */ + RTS_ERROR_FUNC(csa, ERR_DBPTRMX, util_buff); return FALSE; } if (!(child % bplmap)) { - RTS_ERROR_FUNC(ERR_DBPTRMAP, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBPTRMAP, util_buff); return FALSE; } if (child == prev_child) { - RTS_ERROR_FUNC(ERR_DBBDBALLOC, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBBDBALLOC, util_buff); return FALSE; } prev_child = child; @@ -442,7 +451,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo { if ((blk_id_ptr != next_tp_child_ptr) && (NULL != next_tp_child_ptr)) { - RTS_ERROR_FUNC(ERR_DBPTRNOTPOS, util_buff); + RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff); return FALSE; } next_tp_child_ptr = blk_id_ptr + chain.next_off; @@ -453,10 +462,4 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo } assert(!is_directory || !is_gvt); /* the block cannot be a directory AND gvt at the same time */ return TRUE; - -} - -void rts_error_func(int err, uchar_ptr_t buff) -{ - rts_error(VARLSTCNT(4) MAKE_MSG_INFO(err), 2, LEN_AND_STR((char_ptr_t)buff)); } diff --git a/sr_port/cg_var.c b/sr_port/cg_var.c index 043dfad..9e5b6d6 100644 --- a/sr_port/cg_var.c +++ b/sr_port/cg_var.c @@ -12,7 +12,7 @@ #include "mdef.h" #include "compiler.h" -#include "rtnhdr.h" +#include #include "obj_file.h" #include "cg_var.h" #include "stringpool.h" diff --git a/sr_port/cmd.c b/sr_port/cmd.c index 34fd7db..7f8a38d 100644 --- a/sr_port/cmd.c +++ b/sr_port/cmd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,6 +19,7 @@ #include "advancewindow.h" #include "cmd.h" #include "namelook.h" +#include "error.h" #define VMS_OS 01 #define UNIX_OS 02 @@ -207,6 +208,10 @@ LITDEF struct SETUP_THREADGBL_ACCESS; assert((SIZEOF(cmd_names) / SIZEOF(nametabent)) == cmd_index[26]); + while (TREF(expr_depth)) + DECREMENT_EXPR_DEPTH; /* in case of prior errors */ + (TREF(side_effect_base))[0] = FALSE; + TREF(temp_subs) = FALSE; CHKTCHAIN(TREF(curtchain)); TREF(pos_in_chain) = *TREF(curtchain); if (TREF(window_token) != TK_IDENT) @@ -223,9 +228,12 @@ LITDEF struct } if (0 > (x = namelook(cmd_index, cmd_names, c, (TREF(window_ident)).len))) { - stx_error(ERR_INVCMD); - if (0 > (x = namelook(cmd_index, cmd_names, "ZINVCMD", 7))) + if ((TK_COLON != TREF(director_token)) || (0 > (x = namelook(cmd_index, cmd_names, "ZINVCMD", 7)))) + { /* the 2nd term of the above if should perform the assignment, but never be true - we're just paranoid */ + stx_error(MAKE_MSG_TYPE(ERR_INVCMD, ERROR)); /* force INVCMD to an error so stx_error sees it as hard */ return FALSE; + } + stx_error(ERR_INVCMD); /* the warning form so stx_error treats it as provisional */ } if (!VALID_CMD(x) ) { @@ -234,8 +242,11 @@ LITDEF struct } advancewindow(); if ((TK_COLON != TREF(window_token)) || !cmd_data[x].pcnd_ok) + { + assert((m_zinvcmd != cmd_data[x].fcn)); cr = NULL; - else + shifting = FALSE; + } else { advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); @@ -244,8 +255,8 @@ LITDEF struct stx_error(ERR_PCONDEXPECTED); return FALSE; } - if (shifting = (TREF(expr_start) != TREF(expr_start_orig))) /* WARNING - assignent */ - { + if (shifting = ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode))) + { /* NOTE - assignent above */ temp_expr_start = TREF(expr_start); triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(temp_expr_start); @@ -291,7 +302,5 @@ LITDEF struct tnxtarg(cr); } } - if (!cr && (m_zinvcmd == cmd_data[x].fcn)) - return FALSE; return rval; } diff --git a/sr_port/cmd_qlf.h b/sr_port/cmd_qlf.h index 7203c9c..e0e93b1 100644 --- a/sr_port/cmd_qlf.h +++ b/sr_port/cmd_qlf.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,6 +42,7 @@ typedef struct #define CQ_ALIGN_STRINGS (1 << 11) /* 0x0800 */ #define CQ_UTF8 (1 << 12) /* 0x1000 */ #define CQ_NAMEOFRTN (1 << 13) /* 0x2000 */ +#define CQ_DYNAMIC_LITERALS (1 << 14) /* 0x4000 -- Set via environmental variable gtm_dynamic_literals (gtm_logicals.h) */ /* TODO: add CQ_ALIGN_STRINGS to the default list below when alignment is supported */ #define CQ_DEFAULT (CQ_WARNINGS | CQ_OBJECT | CQ_IGNORE | CQ_LOWER_LABELS | CQ_LINE_ENTRY | CQ_INLINE_LITERALS) @@ -49,6 +50,16 @@ typedef struct #define LISTTAB 10 #define PG_WID 132 +#define INIT_CMD_QLF_STRINGS(CMD_QLF, OBJ_FILE, LIST_FILE, CEPREP_FILE, SIZE) \ +{ \ + CMD_QLF.object_file.str.addr = OBJ_FILE; \ + CMD_QLF.object_file.str.len = SIZE; \ + CMD_QLF.list_file.str.addr = LIST_FILE; \ + CMD_QLF.list_file.str.len = SIZE; \ + CMD_QLF.ceprep_file.str.addr = CEPREP_FILE; \ + CMD_QLF.ceprep_file.str.len = SIZE; \ +} + typedef struct src_line_type { struct diff --git a/sr_port/code_gen.c b/sr_port/code_gen.c index 9e8aa30..a35d9a8 100644 --- a/sr_port/code_gen.c +++ b/sr_port/code_gen.c @@ -15,7 +15,7 @@ #include "mdq.h" #include "cgp.h" #include "cmd_qlf.h" -#include "rtnhdr.h" +#include #include "obj_file.h" #include "list_file.h" #include diff --git a/sr_port/comp_fini.c b/sr_port/comp_fini.c index 56adf67..61c108b 100644 --- a/sr_port/comp_fini.c +++ b/sr_port/comp_fini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,7 @@ #include "opcode.h" #include "toktyp.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "cgp.h" #include "alloc_reg.h" @@ -33,8 +33,9 @@ GBLREF char cg_phase; GBLREF unsigned char *source_buffer; error_def(ERR_INDEXTRACHARS); +error_def(ERR_INDRCOMPFAIL); -int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, mstr_len_t src_len) +int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len) { triple *ref; DCL_THREADGBL_ACCESS; @@ -44,7 +45,11 @@ int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, mstr_len_ { while (TK_SPACE == TREF(window_token)) /* Eat up trailing white space */ advancewindow(); - if (((src_len + 2) != source_column) && ('\0' != source_buffer[source_column])) + if (TK_ERROR == TREF(window_token)) + { + status = EXPR_FAIL; + stx_error(ERR_INDRCOMPFAIL); + } else if ((TK_EOL != TREF(window_token)) || (source_column < src_len)) { status = EXPR_FAIL; stx_error(ERR_INDEXTRACHARS); @@ -57,6 +62,8 @@ int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, mstr_len_ ref = newtriple(retcode); if (retopr) ref->operand[0] = *retopr; + if (OC_IRETMVAL == retcode) + ref->operand[1] = *dst; start_fetches(OC_NOOP); resolve_ref(0); /* cannot fail because there are no MLAB_REF's in indirect code */ alloc_reg(); @@ -75,6 +82,12 @@ int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, mstr_len_ ind_code(obj); indr_stringpool.free = indr_stringpool.base; } + } else + { /* If this assert fails, it means a syntax problem could have been caught earlier. Consider placing a more useful + * and specific error message at that location. + */ + assert(FALSE); + stx_error(ERR_INDRCOMPFAIL); } if (EXPR_FAIL == status) { diff --git a/sr_port/comp_indr.c b/sr_port/comp_indr.c index cf46df2..977c46f 100644 --- a/sr_port/comp_indr.c +++ b/sr_port/comp_indr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,14 +14,13 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "copy.h" #include "cache.h" #include "objlabel.h" #include "mprof.h" -#include "cacheflush.h" #include "compiler.h" #include "obj_file.h" #include "error.h" diff --git a/sr_port/comp_init.c b/sr_port/comp_init.c index 292eb3c..0864ba7 100644 --- a/sr_port/comp_init.c +++ b/sr_port/comp_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,7 @@ #include "stp_parms.h" #include "compiler.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "opcode.h" #include "cgp.h" @@ -35,7 +35,7 @@ GBLREF char cg_phase; error_def(ERR_INDRMAXLEN); -void comp_init(mstr *src) +void comp_init(mstr *src, oprtype *dst) { DCL_THREADGBL_ACCESS; @@ -64,5 +64,12 @@ void comp_init(mstr *src) curr_fetch_trip = newtriple(OC_FETCH); curr_fetch_count = 0; start_fetches(OC_FETCH); + /* op_igetdst fetches the destination (ind_result) onto the M-stack at the start of execution so that if we end up doing + * nested indirection, in which case ind_result could change, op_iretmval can put the result in the correct location. + * op_igetsrc serves a very similar purpose, placing a copy of the source mval (ind_source) on the M-stack at the start + * of execution. + */ + if (dst) + *dst = put_tref(newtriple(OC_IGETDST)); return; } diff --git a/sr_port/compile_pattern.c b/sr_port/compile_pattern.c index 59d8b6d..7904f07 100644 --- a/sr_port/compile_pattern.c +++ b/sr_port/compile_pattern.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,29 +32,23 @@ int compile_pattern(oprtype *opr, boolean_t is_indirect) ptstr retstr; mval retmval; mstr instr; - triple *oldchain, *ref, tmpchain, *triptr; + triple *oldchain, *ref; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (is_indirect) { - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(opr)) { setcurtchain(oldchain); return FALSE; } ref = newtriple(OC_INDPAT); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(opr)) diff --git a/sr_port/compiler.h b/sr_port/compiler.h index 1aeaa47..21c378c 100644 --- a/sr_port/compiler.h +++ b/sr_port/compiler.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -88,7 +88,7 @@ typedef struct oprtypestruct } oprtype; /* Values for oprclass */ -#define NOCLASS 0 +#define NO_REF 0 #define TVAR_REF 1 #define TVAL_REF 2 #define TINT_REF 3 @@ -170,6 +170,30 @@ typedef struct unsigned short opr_type; } toktabtype; +/* These two structures really belong in glvn_pool.h, but gtmpcat doesn't know to include that file. So put them here for now. */ +#include "callg.h" +typedef struct +{ + opctype sav_opcode; + uint4 mval_top; /* mval just beyond ones used by this entry */ + uint4 precursor; /* index of previous FOR slot at same level */ + mval *lvname; + gparam_list glvn_info; +} glvn_pool_entry; + +typedef struct +{ + uint4 capacity; /* total # allocated entries */ + uint4 top; /* current available glvn_pool_entry slot */ + uint4 for_slot[MAX_FOR_STACK + 1]; /* indices of most recent FOR slots */ + uint4 share_slot; /* currently active slot */ + opctype share_opcode; /* currently active opcode */ + uint4 mval_capacity; /* total # allocated mvals */ + uint4 mval_top; /* current available mval in mval_stack */ + mval *mval_stack; /* stack of mvals */ + glvn_pool_entry slot[1]; /* stack of entries */ +} glvn_pool; + #define VMS_OS 01 #define UNIX_OS 02 #define ALL_SYS (VMS_OS | UNIX_OS) @@ -202,12 +226,13 @@ typedef struct #define CHARMAXARGS 256 #define MAX_FORARGS 127 #define MAX_SRCLINE 8192 /* maximum length of a program source or indirection line */ -#define NO_FORMALLIST (-1) +#define NO_FORMALLIST (-1) /* Some errors should not cause stx_error to issue an rts_error. These are the errors related to - * a) Invalid Intrinsic Special Variables + * a) Invalid Intrinsic Commands * b) Invalid Intrinsic Function Names - * c) Invalid Deviceparameters for IO commands + * c) Invalid Intrinsic Special Variables + * d) Invalid Deviceparameters for IO commands * These should cause an error at runtime if and only if that codepath is reached. * PostConditionals can cause this path to be avoided in which case we do not want to issue an error at compile time. * Therefore issue only a warning at compile-time and proceed with compilation as if this codepath will not be reached at runtime. @@ -216,15 +241,16 @@ error_def(ERR_DEVPARINAP); error_def(ERR_DEVPARUNK); error_def(ERR_DEVPARVALREQ); error_def(ERR_FNOTONSYS); +error_def(ERR_INVCMD); error_def(ERR_INVFCN); error_def(ERR_INVSVN); error_def(ERR_SVNONEW); error_def(ERR_SVNOSET); -#define IS_STX_WARN(errcode) \ - ((ERR_INVFCN == errcode) || (ERR_FNOTONSYS == errcode) || (ERR_INVSVN == errcode) \ - || (ERR_SVNONEW == errcode) || (ERR_SVNOSET == errcode) || (ERR_DEVPARUNK == errcode) \ - || (ERR_DEVPARINAP == errcode) || (ERR_DEVPARVALREQ == errcode)) +#define IS_STX_WARN(errcode) \ + ((ERR_DEVPARINAP == errcode) || (ERR_DEVPARUNK == errcode) || (ERR_DEVPARVALREQ == errcode) \ + || (ERR_FNOTONSYS == errcode) || (ERR_INVCMD == errcode) || (ERR_INVFCN == errcode) \ + || (ERR_INVSVN == errcode) || (ERR_SVNONEW == errcode) || (ERR_SVNOSET == errcode)) /* This macro does an "stx_error" of the input errcode but before that it asserts that the input errcode is one * of the known error codes that are to be handled as a compile-time warning (instead of an error). It also set @@ -305,6 +331,146 @@ error_def(ERR_SVNOSET); } \ } +typedef struct +{ + triple *expr_start; + triple *expr_start_orig; + boolean_t shift_side_effects; + boolean_t saw_side_effect; + triple tmpchain; +} save_se; + +#define START_GVBIND_CHAIN(SS, OLDCHAIN) \ +{ \ + (SS)->expr_start = TREF(expr_start); \ + (SS)->expr_start_orig = TREF(expr_start_orig); \ + (SS)->shift_side_effects = TREF(shift_side_effects); \ + (SS)->saw_side_effect = TREF(saw_side_effect); \ + TREF(expr_start) = NULL; \ + TREF(expr_start_orig) = NULL; \ + TREF(shift_side_effects) = FALSE; \ + TREF(saw_side_effect) = FALSE; \ + dqinit(&(SS)->tmpchain, exorder); \ + OLDCHAIN = setcurtchain(&(SS)->tmpchain); \ +} + +#define PLACE_GVBIND_CHAIN(SS, OLDCHAIN) \ +{ \ + newtriple(OC_GVSAVTARG); \ + TREF(expr_start) = (SS)->expr_start; \ + TREF(expr_start_orig) = (SS)->expr_start_orig; \ + TREF(shift_side_effects) = (SS)->shift_side_effects; \ + TREF(saw_side_effect) = (SS)->saw_side_effect; \ + setcurtchain(OLDCHAIN); \ + assert(NULL != TREF(expr_start)); \ + dqadd(TREF(expr_start), &(SS)->tmpchain, exorder); \ + TREF(expr_start) = (SS)->tmpchain.exorder.bl; \ + assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); \ + newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); \ +} + +/* note assignment below */ +#define SHIFT_SIDE_EFFECTS ((TREF(saw_side_effect) = TREF(shift_side_effects)) && (GTM_BOOL == TREF(gtm_fullbool))) + +#define INITIAL_SIDE_EFFECT_DEPTH 33 /* initial allocation for expression nesting to track side effects */ + +/* note side effect for boolean shifting temporaries */ +#define ENCOUNTERED_SIDE_EFFECT \ +{ /* Needs #include "show_source_line" and #include "fullbool.h" */ \ + \ + if (TREF(shift_side_effects)) \ + { \ + TREF(saw_side_effect) = TRUE; \ + if (!run_time && (FULL_BOOL_WARN == TREF(gtm_fullbool))) \ + { /* warnings requested by by gtm_fullbool and enabled by eval_expr */ \ + show_source_line(TRUE); \ + dec_err(VARLSTCNT(1) ERR_BOOLSIDEFFECT); \ + } \ + } \ +} + +#define SE_WARN_ON (!run_time && (SE_WARN == TREF(side_effect_handling))) + +#define ISSUE_SIDEEFFECTEVAL_WARNING(COLUMN) \ +{ \ + TREF(last_source_column) = (COLUMN); \ + show_source_line(TRUE); \ + dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL); \ +} + +/* maintain array indexed by expr_depth to track side effects - for subscripts, actuallists, binary expressions and functions */ +#define INCREMENT_EXPR_DEPTH \ +{ \ + boolean_t *TMP_BASE; \ + \ + if (!(TREF(expr_depth))++) \ + TREF(expr_start) = TREF(expr_start_orig) = NULL; \ + else \ + { /* expansion is unlikely as it's hard to nest expressions deeply, but we don't want a hard limit */ \ + assertpro(TREF(expr_depth)); /* expr_depth doesn't handle rollover */ \ + assert(TREF(expr_depth) <= TREF(side_effect_depth)); \ + if (TREF(expr_depth) == TREF(side_effect_depth)) \ + { \ + TMP_BASE = TREF(side_effect_base); \ + (TREF(side_effect_depth))++; \ + TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * TREF(side_effect_depth)); \ + memcpy(TREF(side_effect_base), TMP_BASE, SIZEOF(boolean_t) * TREF(expr_depth)); \ + free(TMP_BASE); \ + (TREF(side_effect_base))[TREF(expr_depth)] = FALSE; \ + } \ + } \ + assert(FALSE == (TREF(side_effect_base))[TREF(expr_depth)]); \ +} + +/* complement of the above increment - uses the macro just below for assertpto and to clear the level we're leaving */ +#define DECREMENT_EXPR_DEPTH \ +{ \ + DISABLE_SIDE_EFFECT_AT_DEPTH; \ + if (!(--(TREF(expr_depth)))) \ + TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE; \ +} + +/* clear the current expr_depth level and propagate down */ +#define DISABLE_SIDE_EFFECT_AT_DEPTH \ +{ \ + unsigned int DEPTH; \ + \ + DEPTH = TREF(expr_depth); \ + assertpro(DEPTH); /* expr_depth shouldn't underflow */ \ + (TREF(side_effect_base))[DEPTH - 1] |= (TREF(side_effect_base))[DEPTH]; /* propagate down */ \ + (TREF(side_effect_base))[DEPTH] = FALSE; \ +} + +/* The following macro transfers subscripts from an array to the triple chain for gvn, lvn and name_glvn +* it requires includes for fullbool.m, mdq.h, and show_source_line.h, and also GBLREF of runtime +*/ +#define SUBS_ARRAY_2_TRIPLES(REF1, SB1, SB2, SUBSCRIPTS, XTRA) \ +{ \ + boolean_t PROTECT_LVN, SE_NOTIFY; \ + triple *REF2; \ + \ + if (PROTECT_LVN = (TREF(side_effect_base))[TREF(expr_depth)]) /* NOTE assignment */ \ + SE_NOTIFY = SE_WARN_ON; \ + while (SB2 < SB1) \ + { \ + if (PROTECT_LVN && (SB2 > (SUBSCRIPTS + XTRA)) && ((SB1 - SB2) > 1) \ + && ((OC_VAR == SB2->oprval.tref->opcode) || (OC_GETINDX == SB2->oprval.tref->opcode))) \ + { /* protect lvns from side effects: skip 1st (unsubscripted name), and last (nothing following) */ \ + assert(OLD_SE != TREF(side_effect_handling)); \ + REF2 = maketriple(OC_STOTEMP); \ + REF2->operand[0] = *SB2; \ + dqins(SB2->oprval.tref, exorder, REF2); /* NOTE:this violates information hiding */ \ + if (SE_NOTIFY) \ + ISSUE_SIDEEFFECTEVAL_WARNING(SB2->oprval.tref->src.column + 1); \ + *SB2 = put_tref(REF2); \ + } \ + REF2 = newtriple(OC_PARAMETER); \ + REF1->operand[1] = put_tref(REF2); \ + REF1 = REF2; \ + REF1->operand[0] = *SB2++; \ + } \ +} + /* the macro below tucks a code reference into the for_stack so a FOR that's done can move on correctly when done */ #define FOR_END_OF_SCOPE(DEPTH, RESULT) \ { \ @@ -328,37 +494,16 @@ error_def(ERR_SVNOSET); */ #define FOR_POP(ALL) \ { \ - unsigned int For_stack_level; \ - boolean_t Seen_indx; \ - \ assert(TREF(for_stack_ptr) >= (oprtype **)TADR(for_stack)); \ assert(TREF(for_stack_ptr) <= (oprtype **)TADR(for_stack) + MAX_FOR_STACK); \ - if (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)) \ - --(TREF(for_stack_ptr)); \ if (ALL) \ { \ - while (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)) \ - (TREF(for_stack_ptr))--; \ + (TREF(for_stack_ptr)) = (oprtype **)TADR(for_stack); \ *(TREF(for_stack_ptr)) = NULL; \ - } \ - if (TREF(for_stack_ptr) == (oprtype **)TADR(for_stack)) \ - { \ - for (Seen_indx = FALSE, For_stack_level = MAX_FOR_STACK; --For_stack_level; ) \ - { \ - if (!Seen_indx && (TRUE_WITH_INDX == TAREF1(for_temps, For_stack_level))) \ - { \ - (void)newtriple(OC_FORFREEINDX); \ - Seen_indx = TRUE; \ - } \ - TAREF1(for_temps, For_stack_level) = FALSE; \ - } \ - } else \ - assert(TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)); \ + } else if (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)) \ + --(TREF(for_stack_ptr)); \ } -/* value used to make for_temps entries a little more than boolean */ -#define TRUE_WITH_INDX 2 - int actuallist(oprtype *opr); int bool_expr(boolean_t op, oprtype *addr); void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr); @@ -367,10 +512,11 @@ void bx_tail(triple *t, boolean_t sense, oprtype *addr); void chktchain(triple *head); void code_gen(void); void coerce(oprtype *a, unsigned short new_type); -int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, mstr_len_t src_len); -void comp_init(mstr *src); +int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len); +void comp_init(mstr *src, oprtype *dst); void comp_indr(mstr *obj); boolean_t compiler_startup(void); +void create_temporaries(triple *sub, opctype put_oc); triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_commarg, boolean_t labref, boolean_t textname); int eval_expr(oprtype *a); int expratom(oprtype *a); @@ -390,6 +536,7 @@ int f_fnzbitget(oprtype *a, opctype op); int f_fnzbitset(oprtype *a, opctype op); int f_fnzbitstr(oprtype *a, opctype op); int f_get(oprtype *a, opctype op); +int f_get1(oprtype *a, opctype op); int f_incr(oprtype *a, opctype op); int f_justify(oprtype *a, opctype op); int f_length(oprtype *a, opctype op); @@ -423,6 +570,7 @@ int f_zechar(oprtype *a, opctype op); int f_zgetsyi(oprtype *a, opctype op); int f_zjobexam(oprtype *a, opctype op); int f_zparse(oprtype *a, opctype op); +int f_zpeek(oprtype *a, opctype op); int f_zprevious(oprtype *a, opctype op); int f_zqgblmod(oprtype *a, opctype op); int f_zsearch(oprtype *a, opctype op); @@ -433,6 +581,7 @@ int f_zsubstr(oprtype *a, opctype op); int f_ztrigger(oprtype *a, opctype op); int f_ztrnlnm(oprtype *a, opctype op); int f_zwidth(oprtype *a, opctype op); +int f_zwrite(oprtype *a, opctype op); mlabel *get_mladdr(mident *c); mvar *get_mvaddr(mident *c); int glvn(oprtype *a); diff --git a/sr_port/compiler_ch.c b/sr_port/compiler_ch.c index 2820a3f..ea17702 100644 --- a/sr_port/compiler_ch.c +++ b/sr_port/compiler_ch.c @@ -16,7 +16,7 @@ #include "cmd_qlf.h" #include "list_file.h" #include "source_file.h" -#include "rtnhdr.h" +#include #include "obj_file.h" #include "reinit_externs.h" #include "compiler.h" diff --git a/sr_port/compiler_startup.c b/sr_port/compiler_startup.c index a956d6a..10ae217 100644 --- a/sr_port/compiler_startup.c +++ b/sr_port/compiler_startup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -67,7 +67,14 @@ boolean_t compiler_startup(void) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - assert(NULL == complits_hashtab || NULL == complits_hashtab->base); + /* Although we have an invocation of compiler cleanups at the end of this module, there exist ways to avoid this + * cleanup by working in direct mode, getting certain types of errors combined with an argumentless ZGOTO that unwinds + * pretty much everything that can bypass that cleanup. So do a quick check if it is needed and if so, git-r-done + * (test is part of the macro invocation). Note this is the easiest place to make this check rather than complicating + * error handling to provide a similar effect. + */ + COMPILE_HASHTAB_CLEANUP; + reinit_externs(); memset(&null_mident, 0, SIZEOF(null_mident)); ESTABLISH_RET(compiler_ch, FALSE); /* Since the stringpool alignment is solely based on mstr_native_align, we need to initialize it based diff --git a/sr_port/compswap.h b/sr_port/compswap.h index 6a998ae..9fc0483 100644 --- a/sr_port/compswap.h +++ b/sr_port/compswap.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,8 +26,8 @@ boolean_t compswap(sm_global_latch_ptr_t lock, int compval, int newval1); # define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1) # define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1) -# elif defined(__HP_cc) - /* Use compiler inline assembly macros for HP-UX/HP C */ +# elif (defined(__HP_cc) || (defined(__hpux) && defined(__GNUC__))) + /* Use compiler inline assembly macros for HP-UX/HP C or GCC on HPUX*/ /* This is assuming 32 bit lock storage, which right now seems to be PIDs * most of the time. PIDs are currently 32 bit values, but that could change * someday, so beware @@ -46,6 +46,8 @@ _Asm_cmpxchg((_Asm_sz)_SZ_W,(_Asm_sem)_SEM_REL,(uint32_t *)LCK, \ (uint64_t)NEWVAL1, (_Asm_ldhint)_LDHINT_NONE) == (uint64_t)CMPVAL1 ? 1 : 0 \ ) +# else +# error Unsupported Platform sr_port/compswap.h # endif /* __ia64 */ #else boolean_t compswap(sm_global_latch_ptr_t lock, int compval1, int compval2, int newval1, int newval2); diff --git a/sr_port/copy_stack_frame.c b/sr_port/copy_stack_frame.c index 9b96476..cdd1221 100644 --- a/sr_port/copy_stack_frame.c +++ b/sr_port/copy_stack_frame.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mprof.h" #include "error.h" +#include "glvn_pool.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase ,*stacktop, *msp, *stackwarn; @@ -36,18 +37,21 @@ void copy_stack_frame(void) 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); } assert(msp < stackbase); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); *sf = *frame_pointer; sf->old_frame_pointer = frame_pointer; - sf->flags = 0; /* Don't propagate special flags */ - sf->for_ctrl_stack = NULL; + sf->flags = 0; /* Don't propagate special flags */ + sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is + * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate. + */ + SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED); sf->ret_value = NULL; - sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */ + sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */ frame_pointer = sf; DBGEHND((stderr, "copy_stack_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n", sf, msp_save, msp)); diff --git a/sr_port/cre_jnl_file.c b/sr_port/cre_jnl_file.c index 11d94df..bcee9e2 100644 --- a/sr_port/cre_jnl_file.c +++ b/sr_port/cre_jnl_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,6 +50,7 @@ #include "get_fs_block_size.h" #include "wbox_test_init.h" #include "gt_timer.h" +#include "anticipatory_freeze.h" /* Note : Now all system error messages are issued here. So callers do not need to issue them again */ #define STATUS_MSG(info) \ @@ -111,39 +112,34 @@ uint4 cre_jnl_file(jnl_create_info *info) { mstr filestr; int org_fn_len, rename_fn_len, fstat; - uint4 ustatus; char *org_fn, rename_fn[MAX_FN_LEN]; + boolean_t no_rename; + assert(0 != jgbl.gbl_jrec_time); if (!info->no_rename) /* ***MAY*** be rename is required */ { + no_rename = FALSE; if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, info->jnl_len, "", "", - rename_fn, &rename_fn_len, &info->status2))) - { /* prepare_unique_name calls append_time_stamp which needs to open the info->jnl file. - * We are here because append_time_stamp failed to open info->jnl or something else. - * So check if info->jnl is present in the system */ - filestr.addr = (char *)info->jnl; - filestr.len = info->jnl_len; - if (FILE_NOT_FOUND != (fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus))) - { - if (FILE_STAT_ERROR == fstat) - { - STATUS_MSG(info); /* for prepare_unique_name call */ - info->status = ustatus; - info->status2 = SS_NORMAL; - } - STATUS_MSG(info); - return EXIT_ERR; - } - if (IS_GTM_IMAGE) - send_msg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); - else - gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); - STATUS_MSG(info); - info->status = info->status2 = SS_NORMAL; - info->no_rename = TRUE; /* We wanted to rename, but not required */ - info->no_prev_link = TRUE; /* No rename => no prev_link */ + rename_fn, &rename_fn_len, jgbl.gbl_jrec_time, &info->status2))) + { + no_rename = TRUE; } else { + filestr.addr = (char *)info->jnl; + filestr.len = info->jnl_len; + if (FILE_PRESENT != (fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, (uint4 *)&info->status))) + { + if (FILE_NOT_FOUND != fstat) + { + STATUS_MSG(info); + return EXIT_ERR; + } + if (IS_GTM_IMAGE) + send_msg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); + else + gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); + no_rename = TRUE; + } /* Note if info->no_prev_link == TRUE, we do not keep previous link, though rename can happen */ if (JNL_ENABLED(info) && !info->no_prev_link) { @@ -152,6 +148,13 @@ uint4 cre_jnl_file(jnl_create_info *info) } else assert(info->no_prev_link); } + if (no_rename) + { + STATUS_MSG(info); + info->status = info->status2 = SS_NORMAL; + info->no_rename = TRUE; /* We wanted to rename, but not required anymore */ + info->no_prev_link = TRUE; /* No rename => no prev_link */ + } } /* else we know for sure rename is not required */ return (cre_jnl_file_common(info, rename_fn, rename_fn_len)); } @@ -170,13 +173,13 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ fd_type channel; char *jrecbuf, *jrecbuf_base; gd_id jnlfile_id; -#if defined(VMS) +# ifdef VMS struct FAB fab; struct NAM nam; char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN]; uint4 blk, block, zero_size; io_status_block_disk iosb; -#elif defined(UNIX) +# else struct stat stat_buf; int fstat_res; ZOS_ONLY(int realfiletag;) @@ -185,10 +188,10 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ struct stat sb; int perm; struct perm_diag_data pdd; -#endif +# endif int idx; trans_num db_tn; - uint4 temp_offset, temp_checksum; + uint4 temp_offset, temp_checksum, pfin_offset, eof_offset; uint4 jnl_fs_block_size; jrecbuf = NULL; @@ -208,13 +211,13 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ { create_fn = &fn_buff[0]; if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, (int)info->jnl_len, "", EXT_NEW, - (char *)create_fn, &create_fn_len, &info->status2))) + (char *)create_fn, &create_fn_len, 0, &info->status2))) { STATUS_MSG(info); return EXIT_ERR; } } -#if defined(UNIX) +# ifdef UNIX OPENFILE3((char *)create_fn, O_CREAT | O_EXCL | O_RDWR, 0600, channel); if (-1 == channel) { @@ -222,10 +225,10 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ STATUS_MSG(info); return EXIT_ERR; } -#if defined(__MVS__) +# ifdef __MVS__ if (-1 == gtm_zos_set_tag(channel, TAG_BINARY, TAG_NOTTEXT, TAG_FORCE, &realfiletag)) TAG_POLICY_SEND_MSG((char *)create_fn, errno, realfiletag, TAG_BINARY); -#endif +# endif FSTAT_FILE(channel, &stat_buf, fstat_res); if (-1 == fstat_res) { @@ -289,7 +292,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ jrecbuf = (char *)ROUND_UP2((uintszofptr_t)jrecbuf_base, jnl_fs_block_size); memset(jrecbuf, 0, jnl_fs_block_size); set_gdid_from_stat(&jnlfile_id, &stat_buf); -#elif defined(VMS) +# else nam = cc$rms_nam; nam.nam$l_rsa = name_buffer; nam.nam$b_rss = SIZEOF(name_buffer); @@ -325,7 +328,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ { zero_size = (blk + ZERO_SIZE_IN_BLOCKS <= info->alloc) ? ZERO_SIZE : (info->alloc - blk) * DISK_BLOCK_SIZE; - DO_FILE_WRITE(channel, blk * DISK_BLOCK_SIZE, jrecbuf, zero_size, info->status, info->status2); + JNL_DO_FILE_WRITE(NULL, NULL, channel, blk * DISK_BLOCK_SIZE, jrecbuf, zero_size, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); } @@ -333,8 +336,8 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ memcpy(jnlfile_id.did, &nam.nam$w_did, SIZEOF(jnlfile_id.did)); memcpy(jnlfile_id.fid, &nam.nam$w_fid, SIZEOF(jnlfile_id.fid)); jnl_fs_block_size = get_fs_block_size(channel); -#endif - info->checksum = jnl_get_checksum_entire((uint4 *)&jnlfile_id, SIZEOF(gd_id)); +# endif + info->checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnlfile_id, SIZEOF(gd_id)); /* Journal file header size relies on this assert */ assert(256 == GTMCRYPT_RESERVED_HASH_LEN); header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size)); @@ -350,7 +353,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ * write is not so much since it is only once per journal file at creation time. All future writes of the * file header write only the real file header and not the 0-padding. */ - DO_FILE_WRITE(channel, 0, header, JNL_HDR_LEN, info->status, info->status2); + JNL_DO_FILE_WRITE(info->csa, create_fn, channel, 0, header, JNL_HDR_LEN, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); assert(DISK_BLOCK_SIZE >= EPOCH_RECLEN + EOF_RECLEN + PFIN_RECLEN + PINI_RECLEN); @@ -361,14 +364,16 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ pini_record->prefix.tn = db_tn; pini_record->prefix.pini_addr = JNL_HDR_LEN; pini_record->prefix.time = jgbl.gbl_jrec_time; /* callers must set it */ - temp_offset = JNL_HDR_LEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - pini_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); pini_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; assert(prc_vec); memcpy((unsigned char*)&pini_record->process_vector[CURR_JPV], (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); /* Already process_vector[ORIG_JPV] is memset 0 */ - pini_record->prefix.pini_addr = JNL_HDR_LEN; + pini_record->filler = 0; + pini_record->prefix.checksum = INIT_CHECKSUM_SEED; + temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)pini_record, SIZEOF(struct_jrec_pini)); + temp_offset = JNL_HDR_LEN; + ADJUST_CHECKSUM(temp_checksum, temp_offset, temp_checksum); + ADJUST_CHECKSUM(temp_checksum, info->checksum, pini_record->prefix.checksum); /* EPOCHs are written unconditionally in Unix while they are written only for BEFORE_IMAGE in VMS */ if (JNL_HAS_EPOCH(info)) { @@ -382,9 +387,6 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ epoch_record->free_blocks = info->free_blocks; epoch_record->total_blks = info->total_blks; epoch_record->fully_upgraded = info->csd->fully_upgraded; - temp_offset = JNL_HDR_LEN + PINI_RECLEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - epoch_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); epoch_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; epoch_record->jnl_seqno = info->reg_seqno; UNIX_ONLY( @@ -399,25 +401,24 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) assert(0 == epoch_record->strm_seqno[idx]); /* should have been zeroed already by above memset */ ) + epoch_record->filler = 0; + epoch_record->prefix.checksum = INIT_CHECKSUM_SEED; + temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, + (uint4 *)epoch_record, SIZEOF(struct_jrec_epoch)); + temp_offset = JNL_HDR_LEN + PINI_RECLEN; + ADJUST_CHECKSUM(temp_checksum, temp_offset, temp_checksum); + ADJUST_CHECKSUM(temp_checksum, info->checksum, epoch_record->prefix.checksum); pfin_record = (struct_jrec_pfin *)&jrecbuf[PINI_RECLEN + EPOCH_RECLEN]; - temp_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - pfin_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); + pfin_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN; eof_record = (struct_jrec_eof *)&jrecbuf[PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN]; - temp_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - eof_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); + eof_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN; cre_jnl_rec_size = PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN; } else { pfin_record = (struct_jrec_pfin *)&jrecbuf[PINI_RECLEN]; - temp_offset = JNL_HDR_LEN + PINI_RECLEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - pfin_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); + pfin_offset = JNL_HDR_LEN + PINI_RECLEN; eof_record = (struct_jrec_eof *)&jrecbuf[PINI_RECLEN + PFIN_RECLEN]; - temp_offset = JNL_HDR_LEN + PINI_RECLEN + PFIN_RECLEN; - temp_checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, temp_offset); - eof_record->prefix.checksum = ADJUST_CHECKSUM(temp_checksum, info->checksum); + eof_offset = JNL_HDR_LEN + PINI_RECLEN + PFIN_RECLEN; cre_jnl_rec_size = PINI_RECLEN + PFIN_RECLEN + EOF_RECLEN; } pfin_record->prefix.jrec_type = JRT_PFIN; @@ -426,6 +427,11 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ pfin_record->prefix.pini_addr = JNL_HDR_LEN; pfin_record->prefix.time = jgbl.gbl_jrec_time; pfin_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; + pfin_record->filler = 0; + pfin_record->prefix.checksum = INIT_CHECKSUM_SEED; + temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)pfin_record, SIZEOF(struct_jrec_pfin)); + ADJUST_CHECKSUM(temp_checksum, pfin_offset, temp_checksum); + ADJUST_CHECKSUM(temp_checksum, info->checksum, pfin_record->prefix.checksum); eof_record->prefix.jrec_type = JRT_EOF; eof_record->prefix.forwptr = eof_record->suffix.backptr = EOF_RECLEN; eof_record->prefix.tn = db_tn; @@ -433,6 +439,11 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ eof_record->prefix.time = jgbl.gbl_jrec_time; QWASSIGN(eof_record->jnl_seqno, info->reg_seqno); eof_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; + eof_record->filler = 0; + eof_record->prefix.checksum = INIT_CHECKSUM_SEED; + temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)eof_record, SIZEOF(struct_jrec_eof)); + ADJUST_CHECKSUM(temp_checksum, eof_offset, temp_checksum); + ADJUST_CHECKSUM(temp_checksum, info->checksum, eof_record->prefix.checksum); /* Assert that the journal file header and journal records are all in sync with respect to the db tn. */ assert(header->bov_tn == db_tn); assert(header->eov_tn == db_tn); @@ -449,10 +460,10 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ */ assert(ROUND_UP2(header->virtual_size, jnl_fs_block_size/DISK_BLOCK_SIZE) > DIVIDE_ROUND_UP(JNL_HDR_LEN + write_size, DISK_BLOCK_SIZE)); - DO_FILE_WRITE(channel, JNL_HDR_LEN, jrecbuf, write_size, info->status, info->status2); + JNL_DO_FILE_WRITE(info->csa, create_fn, channel, JNL_HDR_LEN, jrecbuf, write_size, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); - UNIX_ONLY(GTM_FSYNC(channel, status);) + UNIX_ONLY(GTM_JNL_FSYNC(info->csa, channel, status);) F_CLOSE(channel, status); /* resets "channel" to FD_INVALID */ free(jrecbuf_base); jrecbuf_base = NULL; @@ -463,6 +474,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ * Following does rename of a.mjl to a.mjl_timestamp. * So system will have a.mjl_timestamp and a.mjl_new for a crash after this call */ + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(info->csa); /* wait for instance freeze before journal file renames */ if (SS_NORMAL != (info->status = gtm_rename((char *)info->jnl, (int)info->jnl_len, (char *)rename_fn, rename_fn_len, &info->status2))) { @@ -476,6 +488,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ /* Following does rename of a.mjl_new to a.mjl. * So system will have a.mjl_timestamp as previous generation and a.mjl as new/current journal file */ + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(info->csa); /* wait for instance freeze before journal file renames */ if (SS_NORMAL != (info->status = gtm_rename((char *)create_fn, create_fn_len, (char *)info->jnl, (int)info->jnl_len, &info->status2))) { @@ -493,6 +506,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_ DEBUG_ONLY( if (gtm_white_box_test_case_enabled && (WBTEST_JNL_CREATE_INTERRUPT == gtm_white_box_test_case_number)) { + UNIX_ONLY(DBGFPF((stderr, "CRE_JNL_FILE: started a wait\n"))); /* this white-box test is for UNIX */ LONG_SLEEP(600); assert(FALSE); /* Should be killed before that */ } diff --git a/sr_port/cre_jnl_file_intrpt_rename.c b/sr_port/cre_jnl_file_intrpt_rename.c index 34089be..7055e26 100644 --- a/sr_port/cre_jnl_file_intrpt_rename.c +++ b/sr_port/cre_jnl_file_intrpt_rename.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2010 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,7 +40,7 @@ void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn) filestr.addr = (char *)fn; filestr.len = fn_len; - prepare_unique_name((char *)fn, fn_len, "", EXT_NEW, (char *)ext_new_jnl_fn, &ext_new_jnl_fn_len, &ustatus); + prepare_unique_name((char *)fn, fn_len, "", EXT_NEW, (char *)ext_new_jnl_fn, &ext_new_jnl_fn_len, 0, &ustatus); assert(SS_NORMAL == ustatus); status1 = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus); if (FILE_STAT_ERROR == status1) diff --git a/sr_port/cre_private_code_copy.c b/sr_port/cre_private_code_copy.c index a335b2a..ff89a73 100644 --- a/sr_port/cre_private_code_copy.c +++ b/sr_port/cre_private_code_copy.c @@ -13,7 +13,7 @@ #include "iosp.h" #include "error.h" -#include "rtnhdr.h" +#include #include "inst_flush.h" #include "private_code_copy.h" #include "stack_frame.h" diff --git a/sr_port/db_auto_upgrade.c b/sr_port/db_auto_upgrade.c index 0ee0e60..99dde60 100644 --- a/sr_port/db_auto_upgrade.c +++ b/sr_port/db_auto_upgrade.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,6 +53,7 @@ void db_auto_upgrade(gd_region *reg) if (0 == csd->mutex_spin_parms.mutex_sleep_spin_count) csd->mutex_spin_parms.mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT; /* zero is a legitimate value for csd->mutex_spin_parms.mutex_spin_sleep_mask; so can't detect if need re-initialization */ + INIT_NUM_CRIT_ENTRY_IF_NEEDED(csd); /* Auto upgrade based on minor database version number. This code currently only does auto upgrade and does not * do auto downgrade although that certainly is possible to implement if necessary. For now, if the current version @@ -123,8 +124,16 @@ void db_auto_upgrade(gd_region *reg) /* In addition, V55000 introduced before_trunc_total_blks for MUPIP REORG -TRUNCATE. * Since it is a new field no initialization necessary. */ - break; case GDSMV55000: + UNIX_ONLY(csd->freeze_on_fail = FALSE;) + UNIX_ONLY(csd->span_node_absent = TRUE;) + UNIX_ONLY(csd->maxkeysz_assured = FALSE;) + case GDSMV60000: + 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: /* 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. */ diff --git a/sr_port/db_csh_get.c b/sr_port/db_csh_get.c index a292f56..5ed885e 100644 --- a/sr_port/db_csh_get.c +++ b/sr_port/db_csh_get.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,29 +36,18 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */ sgmnt_data_ptr_t csd; cache_rec_ptr_t cr, cr_hash_base; int blk_hash, lcnt, ocnt, hmax; - bool is_mm; # ifdef DEBUG cache_rec_ptr_t cr_low, cr_high; # endif csa = cs_addrs; csd = csa->hdr; - is_mm = (dba_mm == csd->acc_meth); - assert((FALSE == is_mm) || (csa->now_crit)); /* if MM you should be in crit */ - VMS_ONLY(assert(FALSE == is_mm);) /* in VMS, MM should never call db_csh_get */ + assert(dba_mm != csd->acc_meth); hmax = csd->bt_buckets; blk_hash = (block % hmax); - if (!is_mm) - { - DEBUG_ONLY(cr_low = &csa->acc_meth.bg.cache_state->cache_array[0];) - DEBUG_ONLY(cr_high = cr_low + csd->bt_buckets + csd->n_bts;) - cr_hash_base = csa->acc_meth.bg.cache_state->cache_array + blk_hash; - } else - { - DEBUG_ONLY(cr_low = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array);) - DEBUG_ONLY(cr_high = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets + csd->n_bts);) - cr_hash_base = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + blk_hash); - } + DEBUG_ONLY(cr_low = &csa->acc_meth.bg.cache_state->cache_array[0];) + DEBUG_ONLY(cr_high = cr_low + csd->bt_buckets + csd->n_bts;) + cr_hash_base = csa->acc_meth.bg.cache_state->cache_array + blk_hash; ocnt = 0; do { @@ -68,8 +57,7 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */ do { cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.fl); - assert(!CR_NOT_ALIGNED(cr, cr_low) && !CR_NOT_IN_RANGE(cr, cr_low, cr_high) - UNIX_ONLY(|| is_mm)); + assert(!CR_NOT_ALIGNED(cr, cr_low) && !CR_NOT_IN_RANGE(cr, cr_low, cr_high)); if (BT_QUEHEAD == cr->blk) { /* We have reached the end of the queue, validate we have run the queue * back around to the same queue header or we'll need to retry because the @@ -84,17 +72,14 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */ assert(!csa->now_crit || (0 != cr->blkque.fl) && (0 != cr->blkque.bl)); if (cr->blk == block) { - if (!is_mm) - { - if (CDB_STAGNATE <= t_tries || mu_reorg_process) - CWS_INSERT(block); - /* setting refer outside of crit may not prevent its replacement, but that's an - * inefficiency, not a tragedy because of concurrency checks in t_end or tp_tend; - * the real problem is to ensure that the cache_rec layout is such that this - * assignment does not damage other fields. - */ - cr->refer = TRUE; - } + if (CDB_STAGNATE <= t_tries || mu_reorg_process) + CWS_INSERT(block); + /* setting refer outside of crit may not prevent its replacement, but that's an + * inefficiency, not a tragedy because of concurrency checks in t_end or tp_tend; + * the real problem is to ensure that the cache_rec layout is such that this + * assignment does not damage other fields. + */ + cr->refer = TRUE; return cr; } lcnt--; diff --git a/sr_port/db_csh_getn.c b/sr_port/db_csh_getn.c index 052d1c3..00d9fb3 100644 --- a/sr_port/db_csh_getn.c +++ b/sr_port/db_csh_getn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,6 +45,7 @@ #include "have_crit.h" #include "memcoherency.h" #include "gtm_c_stack_trace.h" +#include "anticipatory_freeze.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; @@ -54,6 +55,10 @@ GBLREF unsigned int t_tries; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; GBLREF boolean_t mu_reorg_process; +#ifdef UNIX +GBLREF uint4 update_trans; +GBLREF jnlpool_addrs jnlpool; +#endif #define TRACE_AND_SLEEP(ocnt) \ { \ @@ -80,9 +85,13 @@ cache_rec_ptr_t db_csh_getn(block_id block) sgmnt_data_ptr_t csd; srch_blk_status *tp_srch_status; ht_ent_int4 *tabent; + boolean_t dont_flush_buff; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; csa = cs_addrs; csd = csa->hdr; + assert(dba_mm != csd->acc_meth); assert(csa->now_crit); assert(csa == &FILE_INFO(gv_cur_region)->s_addrs); max_ent = csd->n_bts; @@ -92,6 +101,9 @@ cache_rec_ptr_t db_csh_getn(block_id block) 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) + ); INCR_DB_CSH_COUNTER(csa, n_db_csh_getns, 1); DEFER_INTERRUPTS(INTRPT_IN_DB_CSH_GETN); for (lcnt = 0; ; lcnt++) @@ -177,7 +189,7 @@ cache_rec_ptr_t db_csh_getn(block_id block) * In VMS, another process cannot be concurrently resetting cr->dirty to 0 as the resetting routine * is "wcs_wtfini" which is executed in crit which another process cannot be in as we are in crit now. */ - if (gv_cur_region->read_only) + if (dont_flush_buff) continue; if (lcnt < pass1) { @@ -189,7 +201,7 @@ cache_rec_ptr_t db_csh_getn(block_id block) if (FALSE == wcs_get_space(gv_cur_region, 0, cr)) { /* failed to flush it out - force a rebuild */ BG_TRACE_PRO(wc_blocked_db_csh_getn_wcsstarvewrt); - assert(csd->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ + assert(csa->nl->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); break; } diff --git a/sr_port/db_csh_ini.c b/sr_port/db_csh_ini.c index dba19bc..b5935a0 100644 --- a/sr_port/db_csh_ini.c +++ b/sr_port/db_csh_ini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,11 +17,10 @@ #include "gdsfhead.h" -void db_csh_ini(sgmnt_addrs *cs) +void db_csh_ini(sgmnt_addrs *csa) { - if ((INTPTR_T)cs->hdr & 7) - GTMASSERT; - cs->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)cs->hdr + cs->nl->cache_off); - assert(cs->acc_meth.bg.cache_state); + assertpro(0 == ((INTPTR_T)csa->hdr & 7)); + csa->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)csa->hdr + csa->nl->cache_off); + assert(csa->acc_meth.bg.cache_state); return; } diff --git a/sr_port/db_csh_ref.c b/sr_port/db_csh_ref.c index 8fae6fa..89fd573 100644 --- a/sr_port/db_csh_ref.c +++ b/sr_port/db_csh_ref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,7 +25,7 @@ error_def(ERR_WCFAIL); -GBLREF int4 process_id; +GBLREF int4 process_id; #if defined(UNIX) && defined(DEBUG) GBLREF jnl_gbls_t jgbl; #endif @@ -39,49 +39,26 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init) sm_uc_ptr_t bp, bp_top; cache_rec_ptr_t cr, cr_top, cr1; int4 buffer_size, rec_size; - boolean_t is_mm; csd = csa->hdr; - /* Note the cr setups for MM should realistically be under a TARGETED_MSYNC_ONLY macro since the MM - * cache recs are only used in that mode. We don't currently use that mode but since this is one-time - * open-code, we aren't bothering. Note if targeted msyncs ever do come back into fashion, we should - * revisit the INTERLOCK_INIT_MM vs INTERLOCK_INIT usage, here and everywhere else too. - */ - is_mm = (dba_mm == csd->acc_meth); - if (!is_mm) - { - if (init) - { - longset((uchar_ptr_t)csa->acc_meth.bg.cache_state, - SIZEOF(cache_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(cache_rec), - 0); /* -1 since there is a cache_rec in cache_que_heads */ - SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_active.latch, LOCK_AVAILABLE); - SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_wip.latch, LOCK_AVAILABLE); - } - cr = cr1 = csa->acc_meth.bg.cache_state->cache_array; - buffer_size = csd->blk_size; - assert(buffer_size > 0); - assert(0 == buffer_size % DISK_BLOCK_SIZE); - rec_size = SIZEOF(cache_rec); - } else - { - if (init) - { - longset((uchar_ptr_t)csa->acc_meth.mm.mmblk_state, - SIZEOF(mmblk_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(mmblk_rec), - 0); /* -1 since there is a mmblk_rec in mmblk_que_heads */ - SET_LATCH_GLOBAL(&csa->acc_meth.mm.mmblk_state->mmblkq_active.latch, LOCK_AVAILABLE); - SET_LATCH_GLOBAL(&csa->acc_meth.mm.mmblk_state->mmblkq_wip.latch, LOCK_AVAILABLE); - } - cr = cr1 = (cache_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array; - rec_size = SIZEOF(mmblk_rec); - } cnl = csa->nl; if (init) { SET_LATCH_GLOBAL(&cnl->wc_var_lock, LOCK_AVAILABLE); SET_LATCH_GLOBAL(&cnl->db_latch, LOCK_AVAILABLE); + if (dba_mm == csd->acc_meth) + return; + longset((uchar_ptr_t)csa->acc_meth.bg.cache_state, + SIZEOF(cache_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(cache_rec), + 0); /* -1 since there is a cache_rec in cache_que_heads */ + SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_active.latch, LOCK_AVAILABLE); + SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_wip.latch, LOCK_AVAILABLE); } + cr = cr1 = csa->acc_meth.bg.cache_state->cache_array; + buffer_size = csd->blk_size; + assert(buffer_size > 0); + assert(0 == buffer_size % DISK_BLOCK_SIZE); + rec_size = SIZEOF(cache_rec); for (cr_top = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size * csd->bt_buckets); cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size)) cr->blk = BT_QUEHEAD; @@ -91,32 +68,21 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init) cnl->cur_lru_cache_rec_off = GDS_ANY_ABS2REL(csa, cr); cnl->cache_hits = 0; } - if (!is_mm) - { - bp = (sm_uc_ptr_t)ROUND_UP((sm_ulong_t)cr_top, OS_PAGE_SIZE); - bp_top = bp + (gtm_uint64_t)csd->n_bts * buffer_size; - GTMCRYPT_ONLY( - if (csd->is_encrypted) - { /* In case of an encrypted database, bp_top is actually the beginning of the encrypted global buffer - * array (an array maintained parallely with the regular unencrypted global buffer array. - */ - cnl->encrypt_glo_buff_off = (sm_off_t)((sm_uc_ptr_t)bp_top - (sm_uc_ptr_t)bp); - } - ) - } + bp = (sm_uc_ptr_t)ROUND_UP((sm_ulong_t)cr_top, OS_PAGE_SIZE); + bp_top = bp + (gtm_uint64_t)csd->n_bts * buffer_size; + GTMCRYPT_ONLY( + if (csd->is_encrypted) + { /* In case of an encrypted database, bp_top is actually the beginning of the encrypted global buffer + * array (an array maintained parallely with the regular unencrypted global buffer array. + */ + cnl->encrypt_glo_buff_off = (sm_off_t)((sm_uc_ptr_t)bp_top - (sm_uc_ptr_t)bp); + } + ) for (; cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size), cr1 = (cache_rec_ptr_t)((sm_uc_ptr_t)cr1 + rec_size)) { if (init) - { - if (!is_mm) - { - INTERLOCK_INIT(cr); - } else - { - INTERLOCK_INIT_MM(cr); - } - } + INTERLOCK_INIT(cr); cr->cycle++; /* increment cycle whenever buffer's blk number changes (for tp_hist) */ cr->blk = CR_BLKEMPTY; /* Typically db_csh_ref is invoked from db_init (when creating shared memory afresh) in which case cr->bt_index @@ -128,12 +94,9 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init) cr->bt_index = 0; if (init) { - if (!is_mm) - { - assert(bp <= bp_top); - cr->buffaddr = GDS_ANY_ABS2REL(csa, bp); - bp += buffer_size; - } + assert(bp <= bp_top); + cr->buffaddr = GDS_ANY_ABS2REL(csa, bp); + bp += buffer_size; insqt((que_ent_ptr_t)cr, (que_ent_ptr_t)cr1); } cr->refer = FALSE; diff --git a/sr_port/dbcertify.c b/sr_port/dbcertify.c index 9f982c1..72401ec 100644 --- a/sr_port/dbcertify.c +++ b/sr_port/dbcertify.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2010 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,9 +32,10 @@ #include #ifdef UNIX -#include "sig_init.h" +# include "continue_handler.h" +# include "sig_init.h" #else -#include "desblk.h" /* for desblk structure */ +# include "desblk.h" /* for desblk structure */ #endif #include "gdsroot.h" #include "v15_gdsroot.h" @@ -55,6 +56,7 @@ #include "cli.h" #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" +#include "wbox_test_init.h" GBLREF uint4 process_id; GBLREF boolean_t gtm_utf8_mode; @@ -83,15 +85,14 @@ int UNIX_ONLY(main)VMS_ONLY(dbcertify)(int argc, char **argv) psa_gbl = malloc(SIZEOF(*psa_gbl)); memset(psa_gbl, 0, SIZEOF(*psa_gbl)); UNIX_ONLY(err_init(dbcertify_base_ch)); - UNIX_ONLY(sig_init(dbcertify_signal_handler, dbcertify_signal_handler, NULL)); + UNIX_ONLY(sig_init(dbcertify_signal_handler, dbcertify_signal_handler, NULL, continue_handler)); VMS_ONLY(util_out_open(0)); VMS_ONLY(SET_EXIT_HANDLER(exi_blk, dbcertify_exit_handler, exi_condition)); /* Establish exit handler */ VMS_ONLY(ESTABLISH(dbcertify_base_ch)); process_id = getpid(); - /* Structure checks .. */ assert((24 * 1024) == SIZEOF(v15_sgmnt_data)); /* Verify V4 file header hasn't suddenly increased for some odd reason */ - + OPERATOR_LOG_MSG; /* Platform dependent method to get the option scan going and invoke necessary driver routine */ dbcertify_parse_and_dispatch(argc, argv); return SS_NORMAL; diff --git a/sr_port/dbcertify_certify_phase.c b/sr_port/dbcertify_certify_phase.c index b262711..2dc32e7 100644 --- a/sr_port/dbcertify_certify_phase.c +++ b/sr_port/dbcertify_certify_phase.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -112,6 +112,7 @@ void dbcertify_certify_phase(void) char_ptr_t errmsg; boolean_t restart_transaction, p1rec_read; unsigned short buff_len; + int tmp_cmpc; char ans[2]; unsigned char dbfn[MAX_FN_LEN + 1]; file_control *fc; @@ -128,7 +129,7 @@ void dbcertify_certify_phase(void) if (CLI_PRESENT == cli_present("BLOCKS")) { if (!cli_get_hex("BLOCKS", &psa->blocks_to_process)) - exit(1); /* Error message already raised */ + exit(EXIT_FAILURE); /* Error message already raised */ } else psa->blocks_to_process = MAXTOTALBLKS_V4; if (CLI_PRESENT == cli_present("TEMPFILE_DIR")) @@ -299,7 +300,7 @@ void dbcertify_certify_phase(void) { if (psa->blocks_to_process != rec_num) { - ((sgmnt_data_ptr_t)psa->dbc_cs_data)->certified_for_upgrade_to = GDSV5; + ((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")); @@ -416,6 +417,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty int prev_rec_offset, new_blk_len, new_rec_len, remain_offset, remain_len, blk_seg_cnt; int new_lh_blk_len, new_rh_blk_len, created_blocks, extent_size; int local_map_max, lbm_blk_index, lcl_blk, curr_rec_cmpc, cmpc; + int tmp_cmpc; int4 lclmap_not_full; uint4 total_blks; boolean_t dummy_bool; @@ -473,12 +475,31 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty */ rts_error(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); dbc_find_key(psa, psa->first_rec_key, blk_p + SIZEOF(v15_blk_hdr), psa->blk_set[0].blk_levl); + if ((0 < psa->blk_set[0].blk_levl) && (0 == psa->first_rec_key->end)) + { /* dbc_find_key found just a star-key in this index block. dbc_find_record/dbc_match_key (invoked later) + * does not know to handle this scenario so we finish this case off right away. No need to do any splits + * anyways since the block is obviously not too full. + */ + DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room (index block with only *-key)\n")); + psa->blks_bypassed++; + psa->blks_read++; + if (psa->blk_set[0].found_in_cache) + psa->blks_cached++; + return FALSE; /* No restart needed */ + } psa->first_rec_key->gvn_len = USTRLEN((char_ptr_t)psa->first_rec_key->base); /* The GVN we need to lookup in the DT */ - + if (UNIX_ONLY(8) VMS_ONLY(9) <= blk_size - blk_len) + { /* This block has room now - no longer need to split it */ + DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room\n")); + psa->blks_bypassed++; + psa->blks_read++; + if (psa->blk_set[0].found_in_cache) + psa->blks_cached++; + return FALSE; /* No restart needed */ + } /* Possibilities at this point: 1) We are looking for a DT (directory tree) block. 2) We are looking for a GVT (global variable tree) block. @@ -492,7 +513,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty from there using the level from the original block as a stopping point. One special case here is if our target block was a gvtroot block, we don't need to traverse the GVT tree to find it. We get it from the directory tree and stop our search there. - */ + */ switch(blk_type) { case gdsblk_dtindex: @@ -524,7 +545,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty */ GET_ULONG(blk_ptr, (psa->blk_set[dtblk_index].curr_rec + SIZEOF(rec_hdr) + psa->blk_set[dtblk_index].curr_blk_key->end + 1 - - ((rec_hdr *)psa->blk_set[dtblk_index].curr_rec)->cmpc)); + - EVAL_CMPC((rec_hdr *)psa->blk_set[dtblk_index].curr_rec))); gvtblk_index = dbc_read_dbblk(psa, blk_ptr, gdsblk_gvtroot); assert(-1 != gvtblk_index); /* If our target block was not the gvtroot block we just read in then we keep scanning for our @@ -633,10 +654,9 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty psa->block_depth = save_block_depth; blk_index = 0; /* reset to start *our* work in the very first block */ } - /* Now we have done the gvtroot check if we were going to. If this particular block has sufficient room in it - we don't need to split it of course. - */ + * we don't need to split it of course. + */ if (UNIX_ONLY(8) VMS_ONLY(9) <= blk_size - blk_len) { /* This block has room now - no longer need to split it */ DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room\n")); @@ -682,7 +702,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty GET_USHORT(us_rec_len, &((rec_hdr *)rec_p)->rsiz); curr_rec_len = us_rec_len; dbc_find_key(psa, blk_set_p->curr_blk_key, rec_p, blk_set_p->blk_levl); - blk_set_p->curr_match = ((rec_hdr *)rec_p)->cmpc; + blk_set_p->curr_match = EVAL_CMPC((rec_hdr *)rec_p); next_rec_p = rec_p + curr_rec_len; if (next_rec_p >= blk_endp) /* We have reached the last record in the block. Cannot skip anymore. */ break; @@ -753,7 +773,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty assert(insert_point); /* This is supposed to *be* the insert point */ } /* Make convenient copies of some commonly used record fields */ - curr_rec_cmpc = ((rec_hdr *)blk_set_p->curr_rec)->cmpc; + curr_rec_cmpc = EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec); curr_rec_shrink = blk_set_p->curr_match - curr_rec_cmpc; curr_rec_offset = (int)(blk_set_p->curr_rec - blk_set_p->old_buff); GET_USHORT(us_rec_len, &((rec_hdr *)blk_set_p->curr_rec)->rsiz); @@ -799,7 +819,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty /* Setup new record header */ new_rec_len = (int)(SIZEOF(rec_hdr) + ins_rec_len - blk_set_p->prev_match); ins_rec_hdr->rsiz = new_rec_len; - ins_rec_hdr->cmpc = blk_set_p->prev_match; + SET_CMPC(ins_rec_hdr, blk_set_p->prev_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)ins_rec_hdr, SIZEOF(rec_hdr)); /* Setup key */ BLK_ADDR(cp1, @@ -817,7 +837,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); /* Replacement rec header */ next_rec_hdr->rsiz = curr_rec_len - curr_rec_shrink; - next_rec_hdr->cmpc = blk_set_p->curr_match; + SET_CMPC(next_rec_hdr, blk_set_p->curr_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); remain_offset = curr_rec_shrink + SIZEOF(rec_hdr); /* Where rest of record plus any further records begin */ @@ -886,7 +906,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty } assert(0 < new_lh_blk_len); /* Right hand side has key of curr_rec expanded since is first key of blcok */ - new_rh_blk_len = (int)(SIZEOF(v15_blk_hdr) + ((rec_hdr *)blk_set_p->curr_rec)->cmpc + + new_rh_blk_len = (int)(SIZEOF(v15_blk_hdr) + EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec) + (curr_blk_len - curr_rec_offset)); assert(0 < new_rh_blk_len); /* Common initialization */ @@ -940,12 +960,12 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty - SIZEOF(v15_blk_hdr)); BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; - new_star_hdr->cmpc = 0; + SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (ins_rec_len ? (uchar_ptr_t)&blk_set_p->ins_rec.blk_id : (blk_set_p->prev_rec + SIZEOF(rec_hdr) + blk_set_p->prev_blk_key->end + 1 - - ((rec_hdr *)blk_set_p->prev_rec)->cmpc)), + - EVAL_CMPC((rec_hdr *)blk_set_p->prev_rec))), SIZEOF(block_id)); } /* Complete our LHS block */ @@ -1001,7 +1021,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty blk_set_rhs_p->upd_addr = bs1; /* Block building roadmap.. */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = curr_rec_len + curr_rec_cmpc; - next_rec_hdr->cmpc = 0; + SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); /* Copy the previously compressed part of the key out of curr_rec. Note, if this key is a star rec key, nothing is written because cmpc is zero */ @@ -1090,7 +1110,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty /* Replace last record with star key rec */ BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; - new_star_hdr->cmpc = 0; + SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); /* Output pointer from prev_rec as star key record's value */ BLK_SEG(bs_ptr, blk_set_p->curr_rec - SIZEOF(block_id), SIZEOF(block_id)); @@ -1149,7 +1169,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty BLK_ADDR(ins_rec_hdr, SIZEOF(rec_hdr), rec_hdr); ins_rec_hdr->rsiz = SIZEOF(rec_hdr) + blk_set_p->ins_rec.ins_key->end + 1 + SIZEOF(block_id); - ins_rec_hdr->cmpc = 0; + SET_CMPC(ins_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)ins_rec_hdr, SIZEOF(rec_hdr)); /* Now for the inserted record key */ BLK_SEG(bs_ptr, @@ -1162,7 +1182,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty it is now the second record in the new block. */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = curr_rec_len - curr_rec_shrink; - next_rec_hdr->cmpc = blk_set_p->curr_match; + SET_CMPC(next_rec_hdr, blk_set_p->curr_match); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); remain_offset = curr_rec_shrink + SIZEOF(rec_hdr); /* Where rest of record plus any further records begin */ @@ -1190,8 +1210,8 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty GTMASSERT; /* 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);; - next_rec_hdr->cmpc = 0; + next_rec_hdr->rsiz = SIZEOF(rec_hdr) + last_rec_key->end + 1 + SIZEOF(block_id); + SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, last_rec_key->base, (last_rec_key->end + 1)); BLK_ADDR(lhs_block_id_p, SIZEOF(block_id), block_id); /* First record's value */ @@ -1200,7 +1220,7 @@ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_ty /* Second record is a star key record pointing to the RHS block */ BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; - new_star_hdr->cmpc = 0; + SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_ADDR(rhs_block_id_p, SIZEOF(block_id), block_id); /* First record's value */ BLK_SEG(bs_ptr, (uchar_ptr_t)rhs_block_id_p, SIZEOF(block_id)); diff --git a/sr_port/dbcertify_funcs.c b/sr_port/dbcertify_funcs.c index 2de3b2b..c4f67f5 100644 --- a/sr_port/dbcertify_funcs.c +++ b/sr_port/dbcertify_funcs.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,7 +9,7 @@ * * ****************************************************************/ -#define _POSIX_EXIT /* Needed for VMS system() call */ +#define _POSIX_EXIT /* Needed for VMS system() call */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */ #include "mdef.h" #ifdef VMS @@ -93,11 +93,12 @@ void dbc_open_command_file(phase_static_area *psa) dont_sendmsg_on_log2long); #ifdef UNIX if (SS_LOG2LONG == status) - rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtm_dist_m.len, gtm_dist_m.addr, SIZEOF(gtm_dist_path_buff) - 1); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, + gtm_dist_m.len, gtm_dist_m.addr, SIZEOF(gtm_dist_path_buff) - 1); else #endif if (SS_NORMAL != status) - rts_error(VARLSTCNT(1) ERR_GTMDISTUNDEF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMDISTUNDEF); assert(0 < gtm_dist_path.len); VMS_ONLY(dbc_remove_command_file(psa)); /* If we don't do this, the command files versions pile up fast */ psa->tcfp = Fopen((char_ptr_t)psa->tmpcmdfile, "w"); @@ -105,7 +106,7 @@ void dbc_open_command_file(phase_static_area *psa) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } UNIX_ONLY(dbc_write_command_file(psa, SHELL_START)); @@ -128,7 +129,7 @@ void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf()"), CALLFROM, /* BYPASSOK */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf()"), CALLFROM, /* BYPASSOK */ ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } rc = CHMOD((char_ptr_t)psa->tmpcmdfile, S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IROTH); /* Change to 744 */ @@ -136,7 +137,7 @@ void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("chmod()"), CALLFROM, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("chmod()"), CALLFROM, ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } @@ -179,7 +180,7 @@ void dbc_run_command_file(phase_static_area *psa, char_ptr_t cmdname, char_ptr_t *cp = '\0'; dbc_syscmd((char_ptr_t)cmdbuf2); } - rts_error(VARLSTCNT(13) ERR_DBCCMDFAIL, 7, rc, cmd_len, cmdbuf1, RTS_ERROR_TEXT(cmdname), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_DBCCMDFAIL, 7, rc, cmd_len, cmdbuf1, RTS_ERROR_TEXT(cmdname), RTS_ERROR_TEXT(cmdargs), ERR_TEXT, 2, RTS_ERROR_LITERAL("Note that the "UNIX_ONLY("environment variable $")VMS_ONLY("logical ")GTM_DIST " must point to the current GT.M V4 installation")); @@ -200,7 +201,7 @@ void dbc_remove_command_file(phase_static_area *psa) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } @@ -219,7 +220,7 @@ void dbc_open_result_file(phase_static_area *psa) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmprsltfile_len, psa->tmprsltfile, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmprsltfile_len, psa->tmprsltfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } } @@ -240,22 +241,22 @@ uchar_ptr_t dbc_read_result_file(phase_static_area *psa, int rderrmsg, uchar_ptr { /* Non-EOF message */ save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } else { /* We have EOF */ if (0 != rderrmsg) - rts_error(VARLSTCNT(4) rderrmsg, 2, RTS_ERROR_TEXT((char_ptr_t)arg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) rderrmsg, 2, RTS_ERROR_TEXT((char_ptr_t)arg)); else { strcpy(emsg, "Temporary results file ("); strcat(emsg, (char_ptr_t)psa->tmprsltfile); strcat(emsg, " had unexpected values"); - rts_error(VARLSTCNT(6) ERR_PREMATEOF, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PREMATEOF, 0, ERR_TEXT, 2, RTS_ERROR_TEXT(emsg)); } } - exit(1); /* We shouldn't come here but in case... */ + exit(EXIT_FAILURE); /* We shouldn't come here but in case... */ } return (uchar_ptr_t)fgs; } @@ -282,7 +283,7 @@ void dbc_remove_result_file(phase_static_area *psa) { save_errno = errno; errmsg = STRERROR(save_errno); - rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, psa->tmprsltfile_len, psa->tmprsltfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } @@ -378,7 +379,7 @@ int dbc_syscmd(char_ptr_t cmdparm) #endif #ifdef VMS - /* Verify system() is supported */ + /* Verify system() is supported */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */ if (0 == SYSTEM(NULL)) GTMASSERT; #endif @@ -632,10 +633,11 @@ int dbc_read_dbblk(phase_static_area *psa, int blk_num, enum gdsblk_type blk_typ void dbc_find_key(phase_static_area *psa, dbc_gv_key *key, uchar_ptr_t rec_p, int blk_levl) { int cmpc, rec_len; + int tmp_cmpc; unsigned short us_rec_len; uchar_ptr_t key_targ_p, key_src_p; - cmpc = ((rec_hdr_ptr_t)rec_p)->cmpc; + cmpc = EVAL_CMPC((rec_hdr *)rec_p); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec_p)->rsiz); rec_len = us_rec_len; if (BSTAR_REC_SIZE == rec_len && 0 < blk_levl) @@ -694,6 +696,7 @@ int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int uchar_ptr_t rec_p, blk_p, blk_top, key1, key2; unsigned short us_rec_len; int blk_ptr, blk_levl, key_len, key_len1, key_len2, rec_len; + int tmp_cmpc; enum gdsblk_type blk_type; block_info *blk_set_p; @@ -770,7 +773,7 @@ int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Recursing down a level via keyed index record at offset 0x%lx\n", (rec_p - blk_p))); GET_ULONG(blk_ptr, (rec_p + SIZEOF(rec_hdr) + blk_set_p->curr_blk_key->end - - ((rec_hdr *)rec_p)->cmpc + 1)); + - EVAL_CMPC((rec_hdr *)rec_p) + 1)); blk_index = dbc_read_dbblk(psa, blk_ptr, blk_type); return dbc_find_record(psa, key, blk_index, min_levl, blk_type, fail_ok); } @@ -796,7 +799,7 @@ int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int if (!fail_ok) { assert(FALSE); - rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to find index record for an existing global")); } return -1; @@ -893,9 +896,9 @@ void dbc_init_db(phase_static_area *psa) if (0 != ACCESS((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (R_OK | W_OK))) { if (EACCES == errno) - rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(psa->dbc_gv_cur_region)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(psa->dbc_gv_cur_region)); else - rts_error(VARLSTCNT(5) ERR_DBOPNERR, 2, DB_LEN_STR(psa->dbc_gv_cur_region), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBOPNERR, 2, DB_LEN_STR(psa->dbc_gv_cur_region), errno); } /* Open the database which on VMS gives standalone access (for phase 2) */ psa->fc->op = FC_OPEN; @@ -906,7 +909,7 @@ void dbc_init_db(phase_static_area *psa) { /* Verify the fileid has not changed */ if (!is_gdid_gdid_identical(&psa->ofhdr.unique_id.uid, &FILE_INFO(psa->dbc_gv_cur_region)->UNIX_ONLY(fileid)VMS_ONLY(file_id))) - rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB); } /* Read in database file header */ @@ -920,9 +923,9 @@ void dbc_init_db(phase_static_area *psa) if (0 != memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 1)) { if (memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 3)) - rts_error(VARLSTCNT(4) ERR_DBNOTGDS, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBNOTGDS, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); else - rts_error(VARLSTCNT(4) ERR_BADDBVER, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.regname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADDBVER, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.regname)); } if (!psa->phase_one) @@ -943,12 +946,15 @@ void dbc_init_db(phase_static_area *psa) #endif /* Verify reserved_bytes and max_rec_len again and verify kill_in_prog is not set */ if (VMS_ONLY(9) UNIX_ONLY(8) > psa->dbc_cs_data->reserved_bytes) - rts_error(VARLSTCNT(4) ERR_DBMINRESBYTES, 2, VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBMINRESBYTES, 2, + VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes); if (SIZEOF(blk_hdr) > (psa->dbc_cs_data->blk_size - psa->dbc_cs_data->max_rec_size)) - rts_error(VARLSTCNT(5) ERR_DBMAXREC2BIG, 3, psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size, - (psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr))); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBMAXREC2BIG, 3, + psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size, + (psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr))); if (0 != psa->dbc_cs_data->kill_in_prog) - rts_error(VARLSTCNT(4) ERR_DBCKILLIP, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCKILLIP, 2, + RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); /* Turn off replication and/or journaling for our trip here */ if (jnl_open == psa->dbc_cs_data->jnl_state) { diff --git a/sr_port/dbcertify_scan_phase.c b/sr_port/dbcertify_scan_phase.c index 0d303d4..10cada3 100644 --- a/sr_port/dbcertify_scan_phase.c +++ b/sr_port/dbcertify_scan_phase.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -444,6 +444,7 @@ void dbc_write_p1out(phase_static_area *psa, void *obuf, int olen) void dbc_process_block(phase_static_area *psa, int blk_num, gtm_off_t dbptr) { int rec_len, rec1_cmpc, rec2_cmpc, key_len, blk_levl, rec1_len, rec2_len, rec2_rlen; + int tmp_cmpc; int free_bytes, blk_len; int save_errno, mm_offset; ssize_t rc; @@ -468,7 +469,7 @@ void dbc_process_block(phase_static_area *psa, int blk_num, gtm_off_t dbptr) dbc_integ_error(psa, blk_num, "Bad block level"); /* Isolate first record for length check */ rec1_ptr = psa->block_buff + SIZEOF(v15_blk_hdr); - rec1_cmpc = ((rec_hdr_ptr_t)rec1_ptr)->cmpc; + rec1_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec1_ptr); if (0 != rec1_cmpc) dbc_integ_error(psa, blk_num, "Bad compression count"); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec1_ptr)->rsiz); @@ -480,7 +481,7 @@ void dbc_process_block(phase_static_area *psa, int blk_num, gtm_off_t dbptr) * record has no value (null value). */ rec2_ptr = rec1_ptr + rec1_len; - rec2_cmpc = ((rec_hdr_ptr_t)rec2_ptr)->cmpc; + rec2_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec2_ptr); if (rec2_cmpc > rec1_len) dbc_integ_error(psa, blk_num, "Compression count too large"); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec2_ptr)->rsiz); @@ -752,6 +753,7 @@ void dbc_integ_error(phase_static_area *psa, block_id blk_num, char_ptr_t emsg) uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t trec_p) { int dtblk_index, hdr_len, rec_value_len, rec_len, rec_cmpc; + int tmp_cmpc; size_t len; uchar_ptr_t blk_p, rec_value_p, subrec_p, key_end_p, rec_p; block_info *blk_set_p; @@ -782,7 +784,7 @@ uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t trec_p) blk_set_p = &psa->blk_set[dtblk_index]; blk_p = blk_set_p->old_buff; assert(0 == ((v15_blk_hdr_ptr_t)blk_p)->levl); - rec_cmpc = ((rec_hdr *)blk_set_p->curr_rec)->cmpc; + rec_cmpc = EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec); rec_value_p = (blk_set_p->curr_rec + SIZEOF(rec_hdr) + blk_set_p->curr_blk_key->end + 1 - rec_cmpc); /* Verify that the dt record we found is the exact one we were looking for */ if ((psa->first_rec_key->gvn_len + 1) != blk_set_p->curr_blk_key->end) diff --git a/sr_port/desired_db_format_set.c b/sr_port/desired_db_format_set.c index ead191c..7c9afd8 100644 --- a/sr_port/desired_db_format_set.c +++ b/sr_port/desired_db_format_set.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,6 +41,15 @@ GBLREF jnl_gbls_t jgbl; GBLREF uint4 process_id; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ +error_def(ERR_COMMITWAITSTUCK); +error_def(ERR_CRYPTNOV4); +error_def(ERR_DBDSRDFMTCHNG); +error_def(ERR_MMNODYNDWNGRD); +error_def(ERR_MUDWNGRDTN); +error_def(ERR_MUNOACTION); +error_def(ERR_SNAPSHOTNOV4); +error_def(ERR_WCBLOCKED); + /* input parameter "command_name" is a string that is either "MUPIP REORG UPGRADE/DOWNGRADE" or "MUPIP SET VERSION" */ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *command_name) { @@ -56,14 +65,6 @@ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *comm jnl_private_control *jpc; jnl_buffer_ptr_t jbp; - error_def(ERR_COMMITWAITSTUCK); - error_def(ERR_DBDSRDFMTCHNG); - error_def(ERR_MMNODYNDWNGRD); - error_def(ERR_MUDWNGRDTN); - error_def(ERR_MUNOACTION); - error_def(ERR_WCBLOCKED); - error_def(ERR_CRYPTNOV4); - error_def(ERR_SNAPSHOTNOV4); assert(reg->open); csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; @@ -87,7 +88,7 @@ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *comm if (FALSE == was_crit) grab_crit(reg); /* if MM and desired_db_format is not V5, gvcst_init would have issued MMNODYNDWNGRD error. assert that. */ - assert(dba_bg == csd->acc_meth || (dba_mm == csd->acc_meth) && (GDSV5 == csd->desired_db_format)); + assert(dba_bg == csd->acc_meth || (dba_mm == csd->acc_meth) && (GDSV6 == csd->desired_db_format)); if (csd->desired_db_format == new_db_format) { /* no change in db_format. fix max_tn_warn if necessary and return right away. */ status = ERR_MUNOACTION; @@ -127,7 +128,7 @@ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *comm /* Wait for concurrent phase2 commits to complete before switching the desired db format */ if (csa->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL)) { /* Set wc_blocked so next process to get crit will trigger cache-recovery */ - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); wcblocked_ptr = WCS_PHASE2_COMMIT_WAIT_LIT; send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_STR(wcblocked_ptr), process_id, &csd->trans_hist.curr_tn, DB_LEN_STR(reg)); @@ -168,8 +169,8 @@ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *comm case GDSV4: csd->max_tn = MAX_TN_V4; break; - case GDSV5: - csd->max_tn = MAX_TN_V5; + case GDSV6: + csd->max_tn = MAX_TN_V6; break; default: GTMASSERT; diff --git a/sr_port/deviceparameters.c b/sr_port/deviceparameters.c index faa3597..fddb059 100644 --- a/sr_port/deviceparameters.c +++ b/sr_port/deviceparameters.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -59,6 +59,7 @@ LITDEF nametabent dev_param_names[] = ,{4,"DELE*"} ,{4,"DELE"} ,{4,"DELI*"} + ,{4,"DEST*" } ,{7,"DESTROY"} ,{3,"DET*"} ,{3,"DOU*"} ,{3,"DOW*"} @@ -66,6 +67,7 @@ LITDEF nametabent dev_param_names[] = ,{2,"EB*"} ,{4,"EBCD"} ,{2,"EC*"} ,{2,"ED*"} ,{4,"EDIT"} + ,{4,"EMPT*"} ,{7,"EMPTERM"} ,{6,"ERASEL*"} ,{6,"ERASET*"} ,{2,"ES*"} @@ -80,7 +82,8 @@ LITDEF nametabent dev_param_names[] = ,{3,"FIX*"} ,{5,"FIXED"} ,{3,"FLA*"} ,{3,"FLU*"} - ,{2,"FO*"} + ,{2,"FO"} ,{3,"FOR*"} + ,{3,"FOL*"} ,{6,"FOLLOW"} ,{1,"G"} ,{2,"GR*"} @@ -114,15 +117,18 @@ LITDEF nametabent dev_param_names[] = ,{4,"NOCE*"} ,{6,"NOCENE"} ,{6,"NOCONV*"} ,{6,"NODELI*"} + ,{6,"NODEST*"} ,{9,"NODESTROY"} ,{5,"NODOU*"} ,{4,"NOEB*"} ,{4,"NOEC*"} ,{6,"NOECHO"} ,{4,"NOED*"} ,{6,"NOEDIT"} + ,{6,"NOEMPT*"} ,{9,"NOEMPTERM"} ,{4,"NOES*"} ,{6,"NOESCA"} ,{5,"NOEXT*"} ,{5,"NOFIL*"} ,{5,"NOFIX*"} ,{5,"NOFLA*"} + ,{5,"NOFOL*"} ,{8,"NOFOLLOW"} ,{4,"NOHE*"} ,{5,"NOHOL*"} ,{5,"NOHOS*"} ,{6,"NOHOST"} @@ -256,27 +262,35 @@ LITDEF nametabent dev_param_names[] = ,{4,"ZWRA*"} }; /* Offset of letter in dev_param_names */ +/* Following array has reached the maximum value limit(255) for its entry. Hence adddition of the next deviceparameter needs + * to change this array to short or int. This will lead to change the interface to namelook() and the type of the first argument + * passed to it. Once that is implemented, remove this comment. + */ LITDEF unsigned char dev_param_index[27] = { /* A B C D E F G H I J K L M N */ - 0, 5, 9, 26, 32, 45, 57, 59, 63, 69, 69, 69, 77, 80, + 0, 5, 9, 26, 34, 49, 64, 66, 70, 76, 76, 76, 84, 87, /* O P Q R S T U V W X Y Z end */ - 140, 145, 164, 165, 178, 196, 205, 211, 212, 227, 228, 229, 243 + 153, 158, 177, 178, 191, 209, 218, 224, 225, 240, 241, 242, 255 }; /* Offset of string within letter in dev_param_names */ /* maintained in conjunction with zshow_params.h = offset in letter, letter */ LITDEF zshow_index zshow_param_index[] = { -/* ALLO BLOC COMMAND CONV CTRA DELE EBCD EDIT EXCE EXTE FIELD FIL FIXED HOST */ - {2,0}, {2,1}, {9,2}, {12,2}, {16,2}, {1,3}, {1,4}, {4,4}, {9,4}, {11,4}, {2,5}, {5,5}, {8,5}, {3,7}, -/* ICHSET INDEPENDENT INSE LAB */ - {0,8}, {2,8}, {4,8}, {1,11}, -/* LENG NOCENE NOECHO NOEDIT NOESCA NOHOST NOINSE */ - {3,11}, {7,13}, {13,13}, {15,13}, {17,13}, {25,13}, {27,13}, +/* ALLO BLOC COMMAND CONV CTRA DELE DEST EBCD EDIT EMPTERM EXCE EXTE FIELD */ + {2,0}, {2,1}, {9,2}, {12,2}, {16,2}, {1,3}, {3,3}, {1,4}, {4,4}, {6,4}, {11,4}, {13,4}, {2,5}, +/* FIL FIXED FOLLOW */ + {5,5}, {8,5}, {14,5}, +/* HOST ICHSET INDEPENDENT INSE LAB */ + {3,7}, {0,8}, {2,8}, {4,8}, {1,11}, +/* LENG NOCENE NODEST NOECHO NOEDIT NOEMPTERM NOESCA NOFOLLOW NOHOST NOINSE */ + {3,11}, {7,13}, {10,13}, {15,13}, {17,13}, {19,13}, {21,13}, {27,13}, {31,13}, {33,13}, /* NOPAST NOREADS NOTTSY NOTYPE NOWRAP OCHSET PAD PARSE PAST PRMMBX RCHK */ - {33,13}, {38,13}, {49,13}, {51,13}, {57,13}, {1,14}, {8,15}, {11,15}, {13,15}, {17,15}, {1,17}, -/* READ READS REC SHAR SHELL STDERR TERM TTSY TYPE UIC WAIT WCHK WIDTH WRITE */ - {2,17}, {4,17}, {5,17}, {5,18}, {7,18}, {15,18}, {1,19}, {6,19}, {8,19}, {1,20}, {2,22}, {4,22}, {6,22}, {10,22} + {39,13}, {44,13}, {55,13}, {57,13}, {63,13}, {1,14}, {8,15}, {11,15}, {13,15}, {17,15}, {1,17}, +/* READ READS REC SHAR SHELL STDERR TERM TTSY TYPE UIC WAIT WCHK */ + {2,17}, {4,17}, {5,17}, {5,18}, {7,18}, {15,18}, {1,19}, {6,19}, {8,19}, {1,20}, {2,22}, {4,22}, +/* WIDTH WRITE */ + {6,22}, {10,22} }; int deviceparameters(oprtype *c, char who_calls) @@ -321,6 +335,7 @@ int deviceparameters(oprtype *c, char who_calls) ,iop_delete ,iop_delete ,iop_delimiter + ,iop_destroy ,iop_destroy ,iop_detach ,iop_doublespace ,iop_downscroll @@ -328,6 +343,7 @@ int deviceparameters(oprtype *c, char who_calls) ,iop_ebcdic ,iop_ebcdic ,iop_echo ,iop_editing ,iop_editing + ,iop_empterm ,iop_empterm ,iop_eraseline ,iop_erasetape ,iop_escape @@ -342,7 +358,8 @@ int deviceparameters(oprtype *c, char who_calls) ,iop_fixed ,iop_fixed ,iop_flag ,iop_flush - ,iop_form + ,iop_form ,iop_form + ,iop_follow ,iop_follow ,iop_g_protection, iop_g_protection @@ -376,15 +393,18 @@ int deviceparameters(oprtype *c, char who_calls) ,iop_nocenable ,iop_nocenable ,iop_noconvert ,iop_nodelimiter + ,iop_nodestroy ,iop_nodestroy ,iop_nodoublespace ,iop_noebcdic ,iop_noecho ,iop_noecho ,iop_noediting ,iop_noediting + ,iop_noempterm ,iop_noempterm ,iop_noescape ,iop_noescape ,iop_inhextgap ,iop_nofilter ,iop_nofixed ,iop_noflag + ,iop_nofollow ,iop_nofollow ,iop_noheader ,iop_nohold ,iop_nohostsync ,iop_nohostsync @@ -519,8 +539,14 @@ int deviceparameters(oprtype *c, char who_calls) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26])); - assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26]); + /* The value of dev_param_index[26] should be 256 but is 255 since that is all that can fit in a unsigned char. That is why + * following asserts has (dev_param_index[26] + 1). Once the type of dev_param_index is changed, the "+ 1" in following + * assert should be removed. + */ + assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26] + 1)); + assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26] + 1); + assert(dev_param_index[26] == 255); + assert(SIZEOF(dev_param_index[26] == SIZEOF(char))); is_parm_list = (TK_LPAREN == TREF(window_token)); if (is_parm_list) advancewindow(); diff --git a/sr_port/dm_setup.c b/sr_port/dm_setup.c index 3c7057c..047a3b7 100644 --- a/sr_port/dm_setup.c +++ b/sr_port/dm_setup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,13 +10,11 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "dm_setup.h" -#ifdef UNIX #include "io.h" GBLREF io_desc *gtm_err_dev; -#endif GBLREF stack_frame *frame_pointer; diff --git a/sr_port/do_indir_do.c b/sr_port/do_indir_do.c index 3875348..6073475 100644 --- a/sr_port/do_indir_do.c +++ b/sr_port/do_indir_do.c @@ -13,7 +13,7 @@ #include "gtm_string.h" #include "toktyp.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "indir_enum.h" #include "cmd_qlf.h" diff --git a/sr_port/dollar_quit.c b/sr_port/dollar_quit.c index cb490c3..85f1c15 100644 --- a/sr_port/dollar_quit.c +++ b/sr_port/dollar_quit.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "get_ret_targ.h" diff --git a/sr_port/dollar_zlevel.c b/sr_port/dollar_zlevel.c index a512bdd..c6da7ee 100644 --- a/sr_port/dollar_zlevel.c +++ b/sr_port/dollar_zlevel.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "dollar_zlevel.h" diff --git a/sr_port/dpgbldir.c b/sr_port/dpgbldir.c index a8dfd51..2b552a5 100644 --- a/sr_port/dpgbldir.c +++ b/sr_port/dpgbldir.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,6 +42,8 @@ LITREF char gde_labels[GDE_LABEL_NUM][GDE_LABEL_SIZE]; STATICDEF gdr_name *gdr_name_head; STATICDEF gd_addr *gd_addr_head; +error_def(ERR_GDINVALID); + /*+ Function: ZGBLDIR @@ -136,7 +138,6 @@ gd_addr *gd_load(mstr *v) gd_region *reg, *reg_top; uint4 t_offset, size; short i; - error_def(ERR_GDINVALID); file_ptr = open_gd_file(v); @@ -169,13 +170,16 @@ gd_addr *gd_load(mstr *v) table->regions = (struct gd_region_struct *)((UINTPTR_T)table->regions + (UINTPTR_T)table); table->segments = (struct gd_segment_struct *)((UINTPTR_T)table->segments + (UINTPTR_T)table); table->end = (table->end + (UINTPTR_T)table); - for (map = table->maps, map_top = map + table->n_maps; map < map_top; map++) { t_offset = map->reg.offset; map->reg.addr = (gd_region *)((char *)table + t_offset); + assert(SIZEOF(map->name) == (MAX_MIDENT_LEN + 1)); + map->name[MAX_MIDENT_LEN] = '\0'; /* reset 32nd byte to 0 since only 31 bytes are used in map. + * this is necessary so "mid_len" can be invoked on this + * as it expects a null-terminated string. + */ } - for (reg = table->regions, reg_top = reg + table->n_regions; reg < reg_top; reg++) { t_offset = reg->dyn.offset; diff --git a/sr_port/dse.h b/sr_port/dse.h index 8ac7ed1..7341530 100644 --- a/sr_port/dse.h +++ b/sr_port/dse.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,10 @@ error_def(ERR_DSEWCREINIT); #define PATCH_SAVE_SIZE 128 #define DSE_DMP_TIME_FMT "DD-MON-YEAR 24:60:SS" +#define SPAN_START_BYTE 0x02 +#define SPAN_BYTE_MAX 255 +#define SPAN_BYTE_MIN 1 + #define GET_CURR_TIME_IN_DOLLARH_AND_ZDATE(dollarh_mval, dollarh_buffer, zdate_mval, zdate_buffer) \ { /* gets current time in the mval "dollarh_mval" in dollarh format and in the mval "zdate_mval" in ZDATE format \ @@ -100,7 +104,7 @@ enum dse_fmt { \ if(!cli_get_str("CONFIRMATION",(X),&(Y))) \ { \ - rts_error(VARLSTCNT(1) ERR_DSEWCINITCON); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \ return; \ } \ } @@ -115,22 +119,18 @@ enum dse_fmt GET_CONFIRM(confirm, len); \ if (confirm[0] != 'Y' && confirm[0] != 'y') \ { \ - rts_error(VARLSTCNT(1) ERR_DSEWCINITCON); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \ return; \ } \ } -#define DSE_WCREINIT(CS_ADDRS) \ -{ \ - assert(CS_ADDRS->now_crit); \ - bt_init(CS_ADDRS); \ - if (CS_ADDRS->hdr->acc_meth == dba_bg) \ - { \ - bt_refresh(CS_ADDRS, TRUE); \ - db_csh_ini(CS_ADDRS); \ - db_csh_ref(CS_ADDRS, TRUE); \ - send_msg(VARLSTCNT(4) ERR_DSEWCREINIT, 2, DB_LEN_STR(gv_cur_region)); \ - } \ +#define DSE_WCREINIT(CS_ADDRS) \ +{ \ + assert(CS_ADDRS->now_crit); \ + if (CS_ADDRS->hdr->acc_meth == dba_bg) \ + bt_refresh(CS_ADDRS, TRUE); \ + db_csh_ref(CS_ADDRS, TRUE); \ + send_msg_csa(CSA_ARG(CS_ADDRS) VARLSTCNT(4) ERR_DSEWCREINIT, 2, DB_LEN_STR(gv_cur_region)); \ } void dse_ctrlc_setup(void); @@ -138,6 +138,7 @@ int dse_data(char *dst, int *len); int dse_getki(char *dst, int *len, char *qual, int qual_len); int dse_is_blk_in(sm_uc_ptr_t rp, sm_uc_ptr_t r_top, short size); int dse_ksrch(block_id srch, block_id_ptr_t pp, int4 *off, char *targ_key, int targ_len); +int dse_key_srch(block_id srch, block_id_ptr_t pp, int4 *off, char *targ_key, int targ_len); int dse_order(block_id srch, block_id_ptr_t pp, int4 *op, char *targ_key, short int targ_len, bool dir_data_blk); void dse_rmsb(void); diff --git a/sr_port/dse.hlp b/sr_port/dse.hlp index e4da1e7..b10f29e 100644 --- a/sr_port/dse.hlp +++ b/sr_port/dse.hlp @@ -1,221 +1,498 @@ +1 Operations + Operations -1 Overview - Overview - The GT.M Database Structure Editor, DSE, examines and repairs - Greystone Technology Database Structure (GDS) database(s). GT.M uses - Buffered Global (BG) and Mapped Memory (MM) access methods for GDS - files. For more information on GDS, refer to the "Greystone Database - Structure" chapter in the GT.M Administration and Operations Guide. - MUPIP INTEG provides comprehensive error checking, which serves to - verify the results of repairs undertaken with DSE. For more - information on MUPIP INTEG, refer to the "MUMPS Peripheral Interchange - Program" chapter in the GT.M Administration and Operations Guide. For - more information on the use of DSE, refer to the "Maintaining Database - Integrity" chapter in the GT.M Administration and Operations Guide. + The GT.M Database Structure Editor, DSE, is primarily a tool for + authorized GT.M consultants to examine and, under unusual circumstances, + repair GT.M Database Structure (GDS) databases. With DSE, it is possible + to see and change most of the attributes of a GT.M database. -1 DSE_Functions - Functions of DSE - DSE is primarily a database repair utility. + DSE gives all possible control over a database and therefore, it may cause + irreparable damage when used without knowing the consequences. Therefore, + you unless you have extensive experience, you should always get guidance + from FIS or an equivalently knowledgeable support resource before running + any DSE command that changes any attribute of any production database or + other database you value. However, you can use those DSE commands that let + you see the attributes of your database for collecting database metrics + and monitoring status. - Use DSE to: + GT.M installation procedure places the DSE utility program in a directory + specified by the environment variable gtm_dist. - o Dump parts of the database for troubleshooting database errors + Invoke DSE using the "dse" command at the shell prompt. If this does not + work, consult your system manager to investigate setup and file access + issues. - o Add or delete a record in a block + Example: - o Update file, block or record header information + $gtm_dist/dse + File/usr/name/mumps.dat + Region DEFAULT + DSE> - o Update bit maps + DSE displays the DSE> prompt. - o Save copies of database fragments for analysis, audit or - restoration. + You may also specify a command when entering DSE. - Use the DSE EXIT command to leave DSE. + By default, DSE starts with the region that stands first in the list of + regions arranged in alphabetical order. In the above example, the first + region is DEFAULT. + + You may also specify a command when entering DSE. + + Example: + + $gtm_dist/dse dump -fileheader + + This command displays the fileheader of the region that stands first in + the list of regions arranged in alphabetical order and then returns to the + shell prompt. To look at other regions, at the DSE prompt you must first + issue a FIND -REGION= command. + + As previously mentioned, DSE provides control over most of the attributes + of your database. With DSE, it is possible to examine them and,with a few + exceptions, change them. + + All DSE commands are divided into two categories-Change commands and + Inquiry commands. Change commands allow you to modify the attribute of + your database, in most cases without any warning or error. As the low + level tool of last resort, Change commands allow you to take certain + actions that can cause extensive damage when undertaken without an + extensive understanding of the underlying data structures on disk and in + memory and with an imperfect understanding of the commands issued. Do not + use the Change commands unless you know exactly what you are doing and + have taken steps to protect yourself against mistakes, both inadvertent + and resulting from an incomplete understanding of the commands you issue. + Change commands are not required for normal operation, and are usually + only used under the direction of FIS support to recover from the + unanticipated consequences of failures not adequately planned for (for + example, you should configure GT.M applications such that you never need a + Change command to recover from a system crash). + + Inquiry commands let you see the attributes of your database. You may + frequently use the inquiry commands for collecting your database metrics + and status reporting. + + The list of Change commands is as follows: + + AD[D] + AL[L] + B[UFFER _FLUSH] + CH[ANGE] + CR[ITICAL] + REM[OVE] + RES[TORE] + SH[IFT] + W[CINIT] + OV[ERWRITE] + M[APS] -BU[SY] -F[REE] -M[ASTER] -R[ESTORE_ALL] + + The list of Inquiry commands is as follows: + + CL[OSE] + D[UMP] + EV[ALUATE] + EX[IT] + F[IND] + H[ELP] + I[NTEGRIT] + M[APS] -BL[OCK] + OP[EN] + P[AGE] + RA[NGE] + SA[VE] + SP[AWN] + + Although DSE can operate concurrently with other processes that access the + same database file, FIS strongly recommends using DSE in standalone mode + when using Change commands. Some DSE operations can adversely impact the + database when they occur during active use of the database. Other DSE + operations may be difficult to perform in a logically sound fashion + because a DSE operator works on a block at a time, while normal database + operations update all related blocks almost simultaneously. + + **Caution** + + When DSE attaches to a database with a version that does not match the DSE + version, DSE issues an informational message and continues. At this point, + you should exit DSE and find the version of DSE that matches the database. + You should continue after this warning if and only if you are certain that + the DSE is indeed from the GT.M version that has the database open (and + hence the error results from a damaged database file header or shared + memory that you intend to repair, following instructions from FIS). + + Use the DSE EXIT, or QUIT command to leave DSE. + +1 Commands + Commands -1 Command_Syntax - Command Syntax The format for DSE commands is: - Command qualifier + DSE> command [-qualifier[...]] [object[,...]] - DSE interprets all numeric input as hexadecimal, except for time - values, the -BLK_SIZE=, -KEY_MAX_SIZE=, -RECORD_MAX_SIZE=, - -REFERENCE_COUNT=, -TIMERS_PENDING= and -WRITES_PER_FLUSH= on CHANGE - -FILEHEADER, and -VERSION= on the REMOVE and RESTORE commands. This - convention corresponds to the displays provided by DSE and by MUPIP - INTEG. + DSE interprets all numeric input as hexadecimal, except for time values, + the values for the following qualifiers when used with CHANGE -FILEHEADER: + -BLK_SIZE=, DECLOCATION=, -KEY_MAX_SIZE=, -RECORD_MAX_SIZE, + -REFERENCE_COUNT=, -TIMERS_PENDING and -WRITES_PER_FLUSH, and the value + for -VERSION= when used with the REMOVE and RESTORE commands. These + conventions correspond to the displays provided by DSE and by MUPIP INTEG. -1 ADD - AD[D] - The ADD command adds a record to a block. +2 ADD + ADD - The format of the ADD command is: + Adds a record to a block. The format of the ADD command for blocks with a + level greater than zero (0) is: - AD[D] [-B[LOCK]=block] - - For greater than level 0 blocks add: - - -STAR -POINTER=block + ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -STAR -POINTER=block or - -OFFSET=offset|-RECORD=record -KEY=key -POINTER=block + ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -POINTER=pointer - For level 0 blocks add: + The format of the ADD command for level 0 blocks is: - -OFFSET=offset|-RECORD=record -KEY=key -D[ATA]=string + ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -DATA=string - The ADD command requires either the -OFFSET or -RECORD qualifier to - position the record in the block and either the -KEY or the -STAR + The ADD command requires either the -OFFSET or -RECORD qualifier to + position the record in the block, and either the -KEY or the -STAR qualifier to define the key for the block. - The -STAR qualifier is not valid at level 0 (i.e., for a data block). - The ADD command requires the -DATA qualifier at level 0 or the - -POINTER qualifier at any other level to provide the content of the - record. + The -STAR qualifier is invalid at level 0 (a data block). The ADD command + requires the -DATA qualifier at level 0 or the -POINTER qualifier at any + other level to provide record content. + +3 Qualifiers + Qualifiers + + -B[LOCK]=block-number -2 Qualifiers --BLOCK - -B[LOCK]=block_number Specifies the block to receive the new record. - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block oriented command, DSE uses - block one (1). + On commands with no -BLOCK= qualifier, DSE uses the last block handled by + a DSE operation. When no block has been accessed, that is, on the first + block-oriented command, DSE uses block one (1). --DATA - -D[ATA]=string - Specifies the data field for records added to a data block. Use - quotes around string and escape codes of the form \a or \ab, - where a and b are hexadecimal digits representing non-printing - characters. \\ translates to a single backslash. The -DATA - qualifier only applies at level 0 and is incompatible with the - -STAR and -POINTER qualifiers. + -D[ATA]=string --KEY - -K[EY]=key - Specifies the key of the new record. Enclose MUMPS-style global - references in quotes (""). The -KEY qualifier is incompatible - with the -STAR qualifier. + Specifies the data field for records added to a data block. Use quotation + marks around the string and escape codes of the form \a\b, where "a" and + "b" are hexadecimal digits representing non-printing characters. \\ + translates to a single backslash. \'\' translates to a NULL value. --OFFSET - -O[FFSET]=offset - Adds the new record at the next record boundary after the - specified offset. The -OFFSET qualifier is incompatible with the - -RECORD and -STAR qualifiers. + Incompatible with: -STAR,-POINTER --POINTER - -P[OINTER]=pointer - Specifies the block pointer field for records added to an index - block. The -POINTER qualifier is incompatible with the -DATA - qualifier and cannot be used at level 0. + -K[EY]=key --RECORD - -R[ECORD]=record_number - Specifies a record number of the new record. The -RECORD - qualifier is incompatible with the -OFFSET and -STAR qualifiers. + Specifies the key of the new record. Enclose M-style global references, + including the leading caret symbol (^), in quotation marks (" "). --STAR - -S[TAR] - Adds a star record (i.e., a record that identifies the last - record in an indexed block) at the end of the specified block. - The -STAR qualifier is incompatible with all qualifiers except - -BLOCK and -POINTER and cannot be used at level 0. + Incompatible with: -STAR -1 ALL - AL[L] - The ALL command applies action(s) specified by a qualifier to all GDS - regions defined by the current Global Directory. This is a very - powerful command; use caution. Be especially careful if you have an - overlapping database structure (e.g., overlapping regions accessed - from separate application global directories). + -O[FFSET]=offset -2 Qualifiers --BUFFER_FLUSH - -B[UFFER_FLUSH] - Flushes to disk buffers all regions specified by the current - Global Directory. The -BUFFER_FLUSH qualifier is incompatible - with the -RENEW qualifier. + Adds the new record at the next record boundary after the specified + offset. --CRITINIT - -C[RITINIT] - Initializes critical sections for all regions specified by the - current Global Directory. The -CRITINIT qualifier is - incompatible with the -RENEW, -RELEASE and -SEIZE qualifiers. + Incompatible with: -RECORD, -STAR --FREEZE - -[NO]F[REEZE] - Allows a user to freeze, or prevent updates to, GDS regions - specified by the current Global Directory. The -FREEZE qualifier - freezes all such GDS regions except those previously frozen by - another user. Regions frozen by a particular user are associated - with that user. A frozen region may be updated in one of two - ways: The user who froze the region may unfreeze it with the - -NOFREEZE qualifier; or another user may override the freeze - injunction with the -OVERRIDE qualifier. + -P[OINTER]=pointer - The -NOFREEZE qualifier unfreezes only those GDS regions that - were previously frozen by the operator. Once a region is - unfrozen, it may be updated by any user. To unfreeze all GDS - regions, use the -OVERRIDE qualifier. + Specifies the block pointer field for records added to an index block. The + -POINTER qualifier cannot be used at level 0. Note this means that to add + pointers at level 0 of the Directory Tree you must specify a string of + bytes or temporarily change the block level. - The -FREEZE qualifier is incompatible with the -RENEW qualifier. + Incompatible with: -DATA - DSE releases -FREEZE when it EXITs. To hold all databases, enter - ALL -FREEZE and then SPAWN to perform other operations. + -R[ECORD]=record-number --OVERRIDE - -O[VERRIDE] - The -OVERRIDE qualifier is meaningful only with the -FREEZE or - -NOFREEZE it unfreezes all GDS regions, including those frozen - by other users. When used with -FREEZE, the -OVERRIDE qualifier - freezes all GDS regions, including those frozen by other users, - associating all such freezes with the current user. The current - user must then use the -NOFREEZE qualifier to unfreeze the - database; any other user attempting a -UNFREEZE would also have - to include the -OVERRIDE qualifier. + Specifies a record number of the new record. --REFERENCE - -REF[ERENCE] - Resets reference counts to 1 for all regions specified by the - current Global Directory. The -REFERENCE qualifier is - incompatible with the -RENEW qualifier. + Incompatible with: -OFFSET,-STAR --RELEASE - -REL[EASE] - Releases critical sections for all regions specified by the - current Global Directory. The -RELEASE qualifier is incompatible - with the -CRITINIT, -RENEW and -SEIZE qualifiers. + -S[TAR] --RENEW - -REN[EW] - Reinitializes critical sections (-CRITICAL) and buffers - (-WCINIT), resets reference counts to 1 (-REFERENCE_COUNT) and - clears freeze flags for all regions specified by the current - Global Directory (-NOFREEZE). -RENEW requires confirmation. The - -RENEW qualifier is incompatible with all other qualifiers. + Adds a star record (that is, a record that identifies the last record in + an indexed block) at the end of the specified block. The -STAR qualifier + cannot be used at level 0. --SEIZE - -S[EIZE] - Seizes the critical section for all regions specified by the - current Global Directory. The -SEIZE qualifier is incompatible - with the -CRITINIT, -RELEASE and -RENEW qualifiers. + Incompatible with: -DATA,-KEY,-OFFSET,-RECORD - The SEIZE qualifier can be useful when you encounter a - DSEBLKRDFAIL error, generated when DSE is unable to read a block - from the database. +3 Examples + Examples --WCINIT - -W[CINIT] - Reinitializes buffers for all regions specified by the current - Global Directory. -WCINIT requires confirmation. The -WCINIT - qualifier is incompatible with the -RENEW qualifier. + DSE>add -block=6F -record=57 -key="^Capital(""Mongolia"")" -data="Ulan Bator" -1 BUFFER_FLUSH - B[UFFER_FLUSH] - The BUFFER_FLUSH command flushes the current region's buffers to disk. + This command adds a new record with key ^Capital("Mongolia") at the + specified location. Note that this command is applicable to level 0 blocks + only. + Example: + + DSE>add -star -bl=59A3 -pointer=2 + + This command adds a star record in block 59A3. Note that this command is + applicable to blocks > level 0. + + Example: + + DSE>add -block=3 -record=4 -key="^Fruits(4)" -data="Grapes" + + Suppose your database has 3 global nodes -- ^Fruits(1)="Apple", + ^Fruits(2)="Banana", and ^Fruits(3)="Cherry", then the above command adds + a new node ^Fruits(4)="Grapes" at record 4. Note that this command is + applicable to level 0 blocks only. The interpreted output as a result of + 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 | + + Example: + + $dse add -star -bl=1 -pointer=2 + + This command adds a star record in block 1. Note that this command is + applicable to blocks > Level 0. + + Example: + + $ dse add -block=4 -key="^Vegetables" -pointer=7 -offset=10 + + This command creates a block with key ^Vegetables pointing to block 7. + + Example: + + DSE> add -record=2 -key="^foo" -data=\'\' + + This example adds a new node (set ^foo="") as the second record of the + current database block. + +2 ALL + ALL + + Applies action(s) specified by a qualifier to all GDS regions defined by + the current global directory. + + The format of the ALL command is: + + AL[L] -B[UFFER_FLUSH] + -C[RITINIT] + -[NO]F[REEZE] + -O[VERRIDE]] + -REF[ERENCE] + -REL[EASE] + -REN[EW] + -S[EIZE] + -W[CINIT] + + o This is a very powerful command; use it with caution. + o Be especially careful if you have an overlapping database structure + (for example, overlapping regions accessed from separate application + global directories). + o If you use this type of database structure, you may need to construct + special Global Directories that exclude overlapped regions to use with + DSE. + +3 Qualifiers + Qualifiers + + -BUFFER_FLUSH + + Flushes to disk the file header and all pooled buffers for all regions of + the current global directory. + + Incompatible with: -RENEW + + -C[RITINIT] + + Initializes critical sections for all regions of the current directory. + + Incompatible with: -RENEW, -RELEASE, -SIEZE + + **Caution** + + Never use CRITINIT while concurrent updates are in progress as doing so + may damage the database. + + -[NO]F[REEZE] + + Freezes or prevents updates all regions of the current global directory. + + o The FREEZE qualifier freezes all GDS regions except those previously + frozen by another process . Regions frozen by a particular process are + associated with that process . + o A frozen region may be unfrozen for updates in one of two ways: The + process which froze the region may unfreeze it with the -NOFREEZE + qualifier; or another process may override the freeze in conjunction + with the -OVERRIDE qualifier. + o By default, the -NOFREEZE qualifier unfreezes only those GDS regions + that were previously frozen by a process . Once a region is unfrozen, + it may be updated by any process .To unfreeze all GDS regions of the + Global Directory, use the -OVERRIDE qualifier. + o DSE releases any FREEZE it holds when it exits, therefore, use the + same DSE invocation or SPAWN to perform operations after executing the + ALL -FREEZE command. + + Incompatible with: -RENEW + + -O[VERRIDE] + + Overrides the ALL -FREEZE or ALL -NOFREEZE operation. + + When used with -NOFREEZE, -OVERRIDE unfreezes all GDS regions, including + those frozen by other users. + + When used with -FREEZE, -OVERRIDE freezes all GDS regions, including those + frozen by other processes associating all such freezes with the current + process. The current process must then use -NOFREEZE to unfreeze the + database; any other process attempting a -NOFREEZE should also have to + include the -OVERRIDE qualifier. + + Meaningful only with: [NO]FREEZE + + -REF[ERENCE] + + Resets the reference count field to 1 for all regions of the current + global directory. + + o A Reference count is a file header element field that tracks how many + processes are accessing the database with read/write permissions. + o This qualifier is intended for use when DSE is the only process + attached to the databases of the curent global directory. Using it + when there are other users attached produces an incorrect value. + + Incompatible with: -RENEW + + -REL[EASE] + + Releases critical sections for all regions of the current global + directory. + + Incompatible with: -CRITINIT, -RENEW, -SEIZE + + -REN[EW] + + Reinitializes the critical sections (-CRITICAL) and buffers (-WCINIT), + resets reference counts (-REFERENCE_COUNT) to 1, and clears freeze + (-NOFREEZE) for all regions of the current global directory . + + o -RENEW requires confirmation. + o The RENEW action will cause all current accessors of the affected + database regions to receive a fatal error on their next access + attempt. + o This operation is dangerous, drastic, and a last resort if multiple + database have hangs that have not yielded to other resolution + attempts; there is almost never a good reason to use this option. + + -S[EIZE] + + Seizes the critical section for all regions of the current global + directory. The -SEIZE qualifier is useful when you encounter a + DSEBLKRDFAIL error, generated when DSE is unable to read a block from the + database. + + Incompatible with: -RENEW, -RELEASE, -CRITINIT + + -W[CINIT] + + Reinitializes the buffers for all regions of the current global directory. + + -WCINIT requires confirmation. + + **Caution** + + This operation is likely to cause database damage when used while + concurrent updates are in progress. + + Incompatible with: -RENEW + +3 Examples + Examples + + Example: + + DSE> all flush -buffer_flush + + This command flushes the file header and cache buffers to disk for all + regions. + + Example: + + DSE> ALL -CRITINIT + + This command initializes critical sections for all regions of the current + directory. + + Example: + + DSE> ALL -FREEZE + DSE> SPAWN "mumps -dir" + + The first command freezes all regions of the current global directory. The + second command creates an child (shell) process and executes the "mumps + -dir" command. Then type S ^A=1 at GTM prompt. Notice that the command + hangs because of the DSE FREEZE in place. + + Example: + + DSE> ALL -NOFREEZE -OVERRIDE + + This command removes the FREEZE on all current region including the FREEZE + placed by other users. + + Example: + + DSE> ALL -REFERENCE + + This command sets the reference count field in the file header(s) to 1. + + Example: + + DSE> ALL -RELEASE + + This command releases critical sections owned by the current process for + all regions of the current global directory. + + Example: + + DSE> ALL -RENEW + + This command reinitializes critical sections, buffers, resets the + reference count to 1, and clears freeze for all regions of the current + global directory. + + Example: + + DSE> ALL -SEIZE + + This command seizes all critical sections for all regions of the current + global directory. + + Example: + + DSE> WCINIT + + This command reinitializes the buffers for all regions of the current + global directory. + +2 Buffer_flush + Buffer_flush + + Flushes the file header and the current region's buffers to disk. The format of the BUFFER_FLUSH command is: @@ -223,240 +500,730 @@ The BUFFER_FLUSH command has no qualifiers. -1 CHANGE - CH[ANGE] - The CHANGE command changes fields of a file, block, or record header - and the bit map. +2 CHange + CHange - The CHANGE command either has a -FILEHEADER qualifier or an implicit - or explicit -BLOCK qualifier plus one or more of their associated - qualifiers to define the target of the change. + The CHANGE command changes fields of a block, file, or record header. -2 Block_Qualifiers + The format of the CHANGE command is: --BLOCK - -BL[OCK]=block_number - Specifies the block to modify. The -BLOCK qualifier is - incompatible with the -FILEHEADER qualifier and all qualifiers - related to -FILEHEADER. + CH[ANGE] - -BLOCK is the default qualifier. On commands with neither a - -BLOCK nor a -FILEHEADER qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, that is, on the first block-oriented command, DSE uses - block one (1). + The CHANGE command either has a -FILEHEADER qualifier or an implicit or + explicit -BLOCK qualifier, plus one or more of their associated + qualifiers, to define the target of the change. --BSIZ - -BS[IZ]=block_size - Changes the block size field of the specified block. Decreasing - the block size can result in loss of existing data. The -BSIZ - qualifier is incompatible with all qualifiers except -BLOCK, - -LEVEL and -TN. + -BL[OCK]=block-number and one or more of the following qualifiers: --LEVEL - -L[EVEL]=level - Changes the level field for the specified block. The -LEVEL - qualifier is incompatible with all qualifiers except -BLOCK, - -BSIZ and -TN. + -BS[IZ]=block-size + -L[EVEL]=level + -TN[=transaction-number] + -OF[FSET]=offset + -RE[CORD]=record-number + -CM[PC]=compression-count + -RS[IZ]=record-size --TN - -TN[=transaction_number] - Changes the transaction number for the current block. When a - CHANGE command does not include a -TN=, DSE sets the transaction - number to the current transaction number. Manipulation of the - block transaction number affects MUPIP BACKUP -INCREMENTAL. The - -TN qualifier is incompatible with all qualifiers except -BLOCK, - -BSIZ and -LEVEL. + or --OFFSET - -OF[FSET]=offset - Specifies the offset within the block of the target record. The - -OFFSET qualifier is incompatible with all qualifiers except - -BLOCK, -CMPC and -RSIZ. + -F[ILEHEADER] and one or more of the following qualifiers: --RECORD - -RE[CORD]=record_number - Specifies the record number of the target record. The -RECORD - qualifier is incompatible with all qualifiers except -BLOCK, - -CMPC and -RSIZ. + -AB[ANDONED_KILLS]=value + -AVG_BLKS_READ=Average-blocks-read + -B_B[YTESTREAM]=transaction-number + -B_C[OMPREHENSIVE]=transaction-number + -B_D[ATABASE]=transaction-number + -B_I[NCREMENTAL]=transaction-number + -B_R[ECORD]=transaction-number + -BLK_SIZE=block-size + -BLO[CKS_FREE]=free-blocks + -CU[RRENT_TN]=transaction-number + -COM[MITWAIT_SPIN_COUNT]=boolean + -DEC[LOCATION]=value + -DEF[_COLLATION]=value + -ENCRYPTION_HASH + -FL[USH_TIME][=delta-time] + -FR[EEZE]=value + -FU[LLY_UPGRADED]=boolean + -GV[STATSRESET] + -HARD_SPIN_CPUNT=Mutex-hard-spin-sount + -[HEXLOCATION]=value + -INT[ERRUPTED_RECOV]=boolean + -JNL_YIELD_LIMIT=journal-yeild-limit + -KE[Y_MAX_SIZE]=key-max-size + -KI[LL_IN_PROG]=value + -M[ACHINE_NAM]=value + -N[ULL_SUBSCRIPTS]=value + -NO[CRIT] + -OV[ERRIDE] + -Q[DBRUNDOWN] + -RC_SRV_COUNT + -RE_READ_TRIGGER=read-trigger + -REC[ORD_MAX_SIZE]=record-max-size + -REF[ERENCE_COUNT]=reference-count + -REG[_SEQNO]=sequence-number + -RESERVED_BYTES=reserved-bytes + -SLEEP_SPIN_COUNT=mutex-sleep-spin-count + -SPIN_SLEEP_TIME=mutex-sleep-time + -STRM_NUM=stream-number STRM_REG_SEQNO=hexa + -TIM[ERS_PENDING]=integer + -TO[TAL_BLKS]=total-blocks + -TR[IGGER_FLUSH]=trigger-flus + -UPD_RESERVED_AREA=reserved- area + -UPD_WRITER_TRIGGER_FACTOR=trigger-factor + -W[RITES_PER_FLUSH]=writes-per-flush + -WAIT_DISK=wait-disk + -Zqgblmod_S[EQNO]=sequence-number + -Zqgblmod_T[rans]=sequence-number --CMPC - -CM[PC]=compression_count - Changes the compression count field of the specified record. The - -CMPC qualifier is incompatible with all qualifiers except - -BLOCK, -OFFSET, and -RECORD. +3 BLock_Qualifiers + BLock Qualifiers --RSIZ - -RS[IZ]=record_size - Changes the record size field of the specified record. The -RSIZ - qualifier is incompatible with all qualifiers except -OFFSET and - -RECORD. + This section describes -BLOCK and all of its qualifiers. -2 File_header_qualifiers + -BL[OCK]=block_number --FILEHEADER - -FI[LEHEADER] - Enables modification of specific fields in the file header. The - -FILEHEADER qualifier is incompatible with the -BLOCK and all - qualifiers related to -BLOCK (i.e., -BSIZ, -CMPC, -LEVEL, - -OFFSET, -RECORD, -RSIZ and -TN qualifiers). + Specifies the block to modify. The -BLOCK qualifier is incompatible with + the -FILEHEADER qualifier and all qualifiers related to -FILEHEADER. --BLK_SIZE - -BLK[_SIZE]=block_size - Changes the decimal block size field of the current file. Use - the -BLK_SIZE qualifier only in conjunction with the -FILEHEADER - qualifier. Do not use this CHANGE qualifier except on - instructions from Greystone. + -BLOCK is the default qualifier. On commands with neither a -BLOCK nor a + -FILEHEADER qualifier, DSE uses the last block handled by a DSE operation. + When no block has been accessed, that is, on the first block-oriented + command, DSE uses block one (1). --BLOCKS_FREE - -BLO[CKS_FREE]=free blocks - Changes the free blocks field of the current file. Use the - -BLOCK_FREE qualifier only in conjunction with the -FILEHEADER - qualifier. Database operations maintain this field for the - user's convenience. The field does not control any database - operations. + Incompatible with: -FILEHEADER and qualifiers used with -FILEHEADER --B_COMPREHENSIVE - -B_C[OMPREHENSIVE]=transaction_number - Changes the transaction number in the fileheader of the last - comprehensive backup to the value specified. Use this qualifier - only in conjunction with the -FILEHEADER qualifier. + The following qualifiers operate on a block header. --B_INCREMENTAL - -B_I[NCREMENTAL]=transaction_number - Changes the transaction number in the fileheader of the last - incremental backup to the value specified. Use this qualifier - only in conjunction with the -FILEHEADER qualifier. + -BS[IZ]=block_size --B_RECORD - -B_R[ECORD]=transaction_number - Changes the transaction number in the fileheader of the last - -RECORD backup to the value specified. Use this qualifier only - in conjunction with the -FILEHEADER qualifier. + Changes the block size field of the specified block. --CORRUPT_FILE - -CO[RRUPT_FILE]=value - Sets the file_corrupt field in the file header. Possible values - are: TRUE, FALSE and NOCHANGE. Use the -CORRUPT_FILE qualifier - only in conjunction with the -FILEHEADER qualifier. + o block_size is in hexadecimal form. + o Decreasing the block size can result in loss of existing data. - WARNING: when DSE EXITs after a CHANGE -FILEHEADER -CORRUPT=TRUE - without a matching CHANGE -FILEHEADER -CORRUPT=FALSE, the file - becomes unavailable to all future access. + **Note** --CURRENT_TN - -CU[RRENT_TN]=transaction_number - Changes the current transaction number for the current region. - Use the -CURRENT_TN qualifier only in conjunction with the - -FILEHEADER qualifier. This qualifier has implications only for - MUPIP BACKUP -INCREMENTAL. Raising the -CURRENT_TN corrects - block transaction number too large errors. + The block size must always be less than or equal to the block size in the + file header. --FLUSH_TIME - -FL[USH_TIME][=delta_time] - Changes the flush_time default interval (in delta_time). The - time entered must be between 0 and 1 hour. + Use only with: -BLOCK, -LEVEL, -TN - Use the -FLUSH_TIME qualifier only in conjunction with the - -FILEHEADER qualifier. Do not use this CHANGE qualifier except - on instructions from Greystone. A -FLUSH_TIME with no value - resets the -FLUSH_TIME to the default value. Input is - interpreted as decimal. + -L[EVEL]=level --FREEZE - -FR[EEZE]=value - Sets availability of the region for update. Possible values are: - TRUE, FALSE and NOCHANGE. Use to "freeze" (disable database - writes) or "unfreeze" the database. Use the -FREEZE qualifier - only in conjunction with the -FILEHEADER qualifier. + Changes the level field for the specified block. - DSE releases -FREEZE when it EXITs. To hold the database(s), - CHANGE -FILEHEADER -FREEZE=TRUE and then SPAWN to perform other - operations. + **Note** --KEY_MAX_SIZE - -K[EY_MAX_SIZE]=key_max_size - Changes the decimal value for the maximum allowable key size. - Use the -KEY_MAX_SIZE qualifier only in conjunction with the - -FILEHEADER qualifier. Reducing KEY_MAX_SIZE can restrict access - to existing data and cause GT.M-generated errors. Do not create - incompatible key and record sizes. If you make a permanent - change to the key size using DSE, use GDE to check that the - appropriate Global Directory contains the same key size for the - region. For more information on key and record sizes, refer to - the "Global Directory Editor" chapter in the GT.M Administration - and Operations Guide. + DSE lets you change the level of a bitmap block to -1 (the value of the + level for a bitmap block) when the bitmap level gets corrupted and takes + on an arbitrary value. Note that you should specify -1 in hexadecimal + form, that is, FF. --NULL_SUBSCRIPTS - -N[ULL_SUBSCRIPTS]=value - Sets the acceptability of null subscripts in database keys. - Possible values are: TRUE, FALSE and NOCHANGE. Use the - -NULL_SUBSCRIPTS qualifier only in conjunction with the - -FILEHEADER qualifier. Prohibiting null-subscripts can restrict - access to existing data and cause GT.M generated errors. + Use only with: -BLOCK, -BSIZ, -TN --RECORD_MAX_SIZE - -REC[ORD_MAX_SIZE]=record_max_size - Changes the decimal value for the maximum allowable record size. - Use the -RECORD_MAX_SIZE qualifier only in conjunction with the - -FILEHEADER qualifier. Reducing the RECORD_MAX_SIZE can restrict - access to existing data and cause GT.M-generated errors. Do not - create incompatible key and record sizes. If you make a - permanent change to the record size using DSE, make sure GDE - contains the same record size for the appropriate Global - Directory. For more information on key and record sizes, refer - to "Global Directory Editor" chapter in GT.M Administration and - Operations Guide. + Example: --REFERENCE_COUNT - -REF[ERENCE_COUNT]=reference_count - Sets a field that tracks how many processes are accessing the - database from the current node. MUPIP INTEG and DSE use decimal - numbers for -REFERENCE_COUNT. Use the -REFERENCE_COUNT qualifier - only in conjunction with the -FILEHEADER qualifier. Restrict - CHANGE -FILEHEADER -REFERENCE_COUNT to the case where the - process running DSE has exclusive (stand-alone) access to the - database file. When DSE has sole access to a database file the - -REFERENCE_COUNT should be 1. This is an informational field and - does not have any effect on processing. + DSE >change -level=FF --TIMERS_PENDING - -TI[MERS_PENDING]=timers_pending - Sets field that tracks the number of processes considering a - timed flush. Use the -TIMERS_PENDING qualifier only in - conjunction with the -FILEHEADER qualifier. Proper values are 0, - 1, and 2. Do not use this CHANGE qualifier except on - instructions from Greystone. + -TN[=transaction_number] --TOTAL_BLKS - -TO[TAL_BLKS]=total_blocks - Changes the total blocks field of the current file. Use the - -TOTAL_BLKS qualifier only in conjunction with the -FILEHEADER + Changes the transaction number for the current block. + + o When a CHANGE command does not include a -TN=, DSE sets the + transaction number to the current transaction number. + o Manipulation of the block transaction number affects MUPIP BACKUP + -BYTESTREAM, and -ONLINE. + + Use only with: -BLOCK, -BSIZ, -LEVEL + + -OF[FSET]=offset + + Specifies the offset, in bytes, of the target record within the block. If + the offset does not point to the beginning of a record, DSE rounds down to + the last valid record start (for example, CHANGE -OFFSET=10 starts at + -OFFSET=A, if that was the last record). + + Use only with: -BLOCK, -CMPC, and -RSIZ. + + -RE[CORD]=record_number + + Specifies the record number of the target record. + + Use only with: -BLOCK, -CMPC, and -RSIZ. + + -CM[PC]=compression_count + + Change the compression count field of the specified record. + + o The compression count specifies the number of bytes at the beginning + of a key that are common to the previous key in the same block. + o Because compression counts propagate from the "front" of the block, + this can potentially change the keys of all records following it in + the block. If the goal is to change only a single record, it may be + preferable to add a new record and remove the old one. + + Use only with: -BLOCK, -RECORD, -OFFSET, -RSIZE + + -RS[IZ]=record_size + + Changes the record size field of the specified record. + + **Caution** + + Changing -RSIZ impacts all records following it in the block. + + Use only with: -BLOCK, -RECORD, -CMPC, -OFFSET + + Example: + + DSE> change -record=3 -rsiz=3B -block=2 + + This command changes the record size of record 3 block 2 to 59 (Hex: 3B) + bytes. + +3 FIleheader_Qualifiers + FIleheader Qualifiers + + This section describes the -FILEHEADER qualifier and the other qualifiers + that operate on a file header. + + -FI[LEHEADER] + + Modifies a file header element that you specify with an associated qualifier. - WARNING: The total blocks field should always reflect the actual - size of the database. Change this field only if it no longer - reflects the size of the database. + Incompatible with: -BSIZ, -CMPC, -TN, -LEVEL, -OFFSET, -RECORD, -RSIZ --TRIGGER_FLUSH - -TR[IGGER_FLUSH]=trigger_flush - Sets the decimal value for the triggering threshold, in buffers, - for flushing the cache modified queue. Use the -TRIGGER_FLUSH - qualifier only in conjunction with the -FILEHEADER qualifier. Do - not use this CHANGE qualifier except on instructions from - Greystone. + -AB[ANDONED_KILLS]=value --WRITES_PER_FLUSH - -WR[ITES_PER_FLUSH]=writes_per_flush - Sets the decimal number of blocks to write in each flush. Use - the -WRITES_PER_FLUSH qualifier only in conjunction with the - -FILEHEADER qualifier. Do not use this CHANGE qualifier except - on instructions from Greystone. + Changes the value of the Abandoned Kills field. The value can be "NONE" or + a positive integer. -1 CLOSE - CL[OSE] - The CLOSE command closes the currently open output file. Use to close - the opened dump file. + Use only with: -FILEHEADER; decimal + + -BLK[_SIZE]=block_size + + Changes the decimal block size field of the current file. + + o DSE does not allow you to change the block size to any arbitrary + value. It always rounds the block size to the next higher multiple of + 512. + o Use the CHANGE -BLK_SIZE qualifier only upon receiving instructions + from FIS and only in conjunction with the -FILEHEADER qualifier. This + DSE command cannot change the working block size of a database and is + useful only under very limited and extrordinary circumstances. If you + need to change the block size on a database file, unload the data with + MUPIP EXTRACT (or an appropriate alternative), change the global + directory with GDE to specify the new block size, recreate the + database with MUPIP CREATE and reload the data with MUPIP LOAD (or + appropriate alternative). + + Use only with: -FILEHEADER + + -BLO[CKS_FREE]=free blocks + + Changes the free blocks field of the current file. + + Use this to correct a value that MUPIP INTEG reports as needing a + correction, but note that the "correct" value reported by INTEG may go + out-of-date with the next update. It may be necessary to calculate a delta + value from the INTEG report, FREEZE the region with DSE, DUMP the current + -FILEHEADER value, then apply the delta and CHANGE the -BLOCKS_FREE, and + finally turn -OFF the FREEZE. + + Use only with: -FILEHEADER + + -B[YTESTREAM]=transaction_number + + Changes the transaction number in the file header of the last incremental + backup to the value specified. Use this qualifier only in conjunction with + the -FILEHEADER qualifier. For compatibility issues with priot versions, + this can still be specified as -B_COMPREHENSIVE. + + -D[ATABASE]=transaction_number + + Changes the transaction number in the file header of the last + comprehensive backup to the value specified. Use this qualifier only in + conjunction with the -FILEHEADER qualifier. For compatibility issues with + prior versions, this can still be specified as -B_COMPREHENSIVE. + + -B_R[ECORD]=transaction_number + + Changes the transaction number in the file header field that maintains + this information about the last -RECORD backup. + + -CO[RRUPT_FILE]=boolean + + Indicates whether or not a region completed a successful recovery with the + MUPIP JOURNAL -RECOVER command. Possible values are: T[RUE] or F[ALSE]. + + Changing this flag does not correct or cause database damage. When + CORRUPT_FILE is set to TRUE, the DSE DUMP command displays a message like + the following: + + %GTM-W-DBFLCORRP, /home/gtmnode1/mumps.dat Header indicates database file is corrupt + + **Caution** + + After a CHANGE -FILEHEADER -CORRUPT=TRUE, the file is unavailable to + future GT.M access other than DSE. Under normal conditions, there should + never be a need to change this flag manually. A MUPIP SET + -PARTIAL_BYPASS_RECOV sets this flag to false. + + Use only with: -FILEHEADER + + -COM[MITWAIT_SPIN_COUNT]=value + + Specifies the number of times a GT.M process waiting for control of a + block to complete a block update should spin before yielding the CPU when + GT.M runs on SMP machines. When run on a uniprocessor system, GT.M ignores + this parameter. On SMP systems, when a process needs a critical section + that another process has, if critical sections are short (as they are by + design in GT.M), spinning a little with the expectation that the process + with the critical section will release it shortly provides a way to + enhance performance at the cost of increased CPU usage. Eventually, a + process awaiting a critical section yields the CPU if spinning for a + little does not get it the needed critical section. Note that on heavily + loaded systems, increasing COMMITWAIT_SPIN_COUNT may not trade off CPU for + throughput, but may instead degrade both. If you set the + COMMITWAIT_SPIN_COUNT to 0, the waiting process performs a sequence of + small sleeps instead of the spins or yields. + + The default value is 16. + + Use only with: -FILEHEADER + + -CU[RRENT_TN]=transaction_number + + Changes the current transaction number for the current region. + + o Raising the -CURRENT_TN can correct "block transaction number too + large" errors + o This qualifier has implications for MUPIP BACKUP -INCREMENTAL and + -ONLINE. + o Used with the -BLOCK qualifier, CURRENT_TN places a transaction number + in a block header. + + Use only with: -FILEHEADER + + -DECLOCATION + + Specifies an offset with the file header. If -VALUE is specified, GT.M + puts it at that location. + + Use only with: -FILEHEADER; decimal + + -E[NCRYPTION_HASH] + + Changes the hash of the password stored in the database file header if and + when you change the hash library. + + **Caution** + + An incorrect hash renders the database useless. + + Use only with: -FILEHEADER + + -FL[USH_TIME][=delta_time] + + Changes the flush_time default interval (in delta_time). + + o The time entered must be between zero and one hour. Input is + interpreted as decimal. + o A -FLUSH_TIME with no value resets the -FLUSH_TIME to the default + value (one second for BG and 30 seconds for MM). + o The units of delta_time are hours:minutes:seconds:centi-seconds + (hundredths of a second). For example, to change the flush time + interval to a second, delta_time would be 00:00:01:00. To change it to + 30 minutes, delta_time would be 00:30:00:00. Valid values for the + qualifier are one centi-second to one hour. + + Use only with: -FILEHEADER + + -FR[EEZE]=value + + Sets availability of the region for update. Possible values are: T[RUE] or + F[ALSE]. Use to "freeze" (disable database writes) or "unfreeze" the + database. + + Use only with: -FILEHEADER + + DSE releases -FREEZE when it EXITs. To hold the database(s), CHANGE + -FILEHEADER -FREEZE=TRUE and then SPAWN to perform other operations. + + -FU[LLY_UPGRADED]=boolean + + Sets a flag that indicates whether or not the database was fully upgraded + from V4 to V5 database format.. The value is either T[RUE] or F[ALSE]. + + Use only with: -FILEHEADER + + -GV[STATSRESET] + + Resets all the database file header global access statistics to 0. Note + that this erases all statistics previously accumulated in the database + file header. + + Use only with: -FILEHEADER + + -HEXLOCATION + + Specifies an offset with the file header. If -VALUE is specified, GT.M + puts it at that location. + + Use only with: -FILEHEADER; hexadecimal + + -INT[ERRUPTED_RECOV]=boolean + + Sets a flag that indicates whether or not a recovery with the MUPIP + JOURNAL -RECOVER command was interrupted. The value is either T[RUE] or + F[ALSE]. + + Use only with: -FILEHEADER + + -K[EY_MAX_SIZE]=key_max_size + + Changes the decimal value for the maximum allowable key size. Reducing + KEY_MAX_SIZE can restrict access to existing data and cause GT.M to report + errors. Do not create incompatible key and record sizes. + + Before permanently changing the key size using DSE, use GDE to check that + the appropriate Global Directory contains the same key size for the + region. This prepares for future MUPIP CREATEs and performs a consistency + check on the key and record size values. + + Use only with: -FILEHEADER; decimal + + -KI[LL_IN_PROG]=value + + Changes the value of the KILLs in progress field. The value can be "NONE" + or a positive integer. + + Use only with: -FILEHEADER; decimal + + -N[ULL_SUBSCRIPTS]=value + + Controls whether GT.M accepts null subscripts in database keys. + + o value can either be T[RUE], F[ALSE], ALWAYS, NEVER, or EXISTING. See + GDE book for more information on these values of null_subscript. + o Prohibiting null subscripts can restrict access to existing data and + cause GT.M to report errors. + o The default value is never. + o DSE cannot change the null subscript collation order. Instead, use GDE + to change the null subscript collation order, MUPIP EXTRACT the + current content, MUPIP CREATE the database file(s) with the updated + collation and MUPIP LOAD the content. + + Use only with: -FILEHEADER + + -OV[ERRIDE] + + Releases or "steals" a FREEZE owned by another process. + + Use only with: -FREEZE + + -[NO]Q[DBRUNDOWN] + + Sets a flag that indicates whether or not the database is enabled for + quick rundown. The default value is -NOQDBRUNDOWN. + + -REC[ORD_MAX_SIZE]=record_max_size + + Changes the decimal value for the maximum allowable record size. Use the + -RECORD_MAX_SIZE qualifier only in conjunction with the -FILEHEADER + qualifier. Reducing RECORD_MAX_SIZE can restrict access to existing data + and cause GT.M to report errors. Do not create incompatible key and record + sizes. + + Before making a permanent change to the records size using DSE, use GDE to + check that the appropriate Global Directory contains the same record size + for the region. This prepares for future MUPIP CREATEs and performs a + consistency check on the key and record size values. + + -REF[ERENCE_COUNT]=reference_count + + Sets a field that tracks how many processes are accessing the database + with read/write permissions. MUPIP INTEG and DSE use decimal numbers for + -REFERENCE_COUNT. To accurately determine the proper reference count, + restrict CHANGE -FILEHEADER -REFERENCE_COUNT to the case where the process + running DSE has exclusive (standalone) access to the database file. When + DSE has sole access to a database file the -REFERENCE_COUNT should be one + (1). This is an informational field and does not have any effect on + processing. + + -REG[_SEQNO]=sequence-number + + In an LMS environment, this sets the "Region Seqno" field. + + -RESYNC_S[EQNO]=sequence-number + + In an LMS environment, this sets the "Resync Seqno" field. + + -RESYNC_T[N]=sequence-number + + In an LMS environment, this sets the "Resync transaction" field. + + -STRM_NUM=stream-number -STRM_R[EG_SEQNO]=str_num's_region_sequence_number + + Changes the Stream and its Reg Seqno. Use -STRM_NUM and -STRM_REG_SEQNO + together as part of the same CHANGE -FILEHEADER command. + + Use only with: -FILEHEADER; hexa + + -TI[MERS_PENDING]=timers_pending + + -TI[MERS_PENDING]=timers_pending + + Sets a field that tracks the number of processes considering a timed + flush. Proper values are 0, 1, and 2. + + Use the CHANGE -TIMERS_PENDING qualifier only upon receiving instructions + from FIS. + + Use only with: -FILEHEADER; decimal + + -TO[TAL_BLKS]=total_blocks + + Changes the total blocks field of the current file. Use only with: + -FILEHEADER; decimal + + **Caution** + + The total blocks field should always reflect the actual size of the + database. Change this field only if it no longer reflects the database + size. + + -TR[IGGER_FLUSH]=trigger_flush + + Sets the decimal value for the triggering threshold, in buffers, for + flushing the cache-modified queue. + + Use the CHANGE -TRIGGER_FLUSH qualifier only upon receiving instructions + from FIS, and only in conjunction with the -FILEHEADER qualifier. + + -WR[ITES_PER_FLUSH]=writes_per_flush + + Set the decimal number of block to write in each flush. The default value + is 7. + + Use only with -FILEHEADER + +3 Examples + Examples + + Example: + + DSE> change -block=3 -bsiz=400 + + This command changes the size of block 3 to 1024 bytes. + + Example: + + DSE> change -block=4 -tn=10000 + + This command changes sets the transaction number to 65536 (Hex: 10000) for + block 4. + + Example: + + DSE> change -block=2 -record=4 -CMPC=10 -key="^CUS(""Jones,Vic"")" + + This command changes the compression count of the key ^CUS(Jones,Vic) to + 10. It is assumed that the key CUS(Jones,Tom) already exists. The + following table illustrates how GT.M calculates the value of CMPC in this + case. + + +----------------------------------------------------------------+ + | RECORD KEY | COMPRESSION COUNT | RESULTING KEY in Record | + |------------------+-------------------+-------------------------| + | CUS(Jones,Tom) | 0 | CUS(Jones,Tom) | + |------------------+-------------------+-------------------------| + | CUS(Jones,Vic) | 10 | Vic) | + |------------------+-------------------+-------------------------| + | CUS(Jones,Sally) | 10 | Sally) | + |------------------+-------------------+-------------------------| + | CUS(Smith,John) | 4 | Smith,John) | + +----------------------------------------------------------------+ + + Example: + + DSE> dump -fileheader + + This command displays fields of the file header. + + Example: + + DSE> change -fileheader -blk_siz=2048 + + This command changes the block size field of the fileheader to 2048 bytes. + The block field must always be a multiples of 512 bytes. + + Example: + + DSE> change -fileheader -blocks_free=5B + + This command changes the blocks free fields of the file header to 91 (Hex: + 5B). Example: + + Example: + + DSE> change -fileheader -b_record=FF + + This command sets the RECORD backup transaction to FF. + + Example: + + DSE> change -fileheader corrupt_file=FALSE + + This command sets the CORRUPT_FILE field to false. + + Example: + + DSE> change -fileheader -current_tn=1001D1BF817 + + This command changes the current transaction number to 1100000000023 (Hex: + 1001D1BF817). After you execute this command, subsequent transaction + numbers will be greater than 1001D1BF817. + + Example: + + DSE> change -fileheader -flush_time=00:00:02:00 + + This command changes the flush time field of the file header to 2 seconds. + + Example: + + DSE> change -fileheader -freeze=true + + This command makes the default region unavailable for updates. + + Example: + + DSE> change -fileheader -key_max_size=20 + + This command changes the maximum key size to 20. Note that the default max + key size is 64. + + Example: + + DSE> CHANGE -FILEHEADER -NULL_SUBSCRIPTS="EXISTING" + + This command changes the Null Subscripts field of the file header to + EXISTING. Note that DSE cannot change the null subscript collation order. + See GDE book for more information on changing the null subscript + collation. + + Example: + + DSE> change -fileheader -reserved_bytes=8 -record_max_size=496 + + This command sets the maximum record size as 496 for the default region. + + Example: + + DSE> change -fileheader -reference_count=5 + + This command sets the reference count field of the file header to 5. + + Example: + + DSE> change -fileheader -timers_pending=2 + + This command sets the timers pending field of the file header to 2. + + Example: + + DSE> change -fileheader -TOTAL_BLKS=64 + + This command sets the total size of the database to 100 (Hex: 64) blocks. + + Example: + + DSE> change -fileheader -trigger_flush=1000 + + This command sets the Flush Trigger field of the file header to 1000. Note + the default value of Flush Trigger is 960. + + Example: + + DSE> change -fileheader -writes_per_flush=10 + + This command changes the number of writes/flush field of the file header + to 10. Note that the default value for the number of writes/flush is 7. + + Example: + + DSE> change -fileheader -zqgblmod_seqno=FF + + This command changes the ZGBLMOD_SEQNO field to 255(Hex: FF). + +2 CAche + CAche + + Operates on the cache of a database having BG access method. The format of + the CACHE command is: + + CA[CHE] -ALL + -RE[COVER + -VE[RIFY] + +3 Qualifiers + Qualifiers + + -RE[COVER] [-ALL] + + Resets the cache of a database having BG access method to a "clean" state. + + o With -ALL specified, DSE includes all region of the current global + directory for cache recovery. + o Attempt DSE -RECOVER only if a DSE CACHE -VERIFY commands reports the + cache is "NOT clean". + + -VE[RIFY] [-ALL] + + Verifies the integrity of the cache data structures as well as the + internal consistency of any GDS blocks in the global buffers of the + current region. + + o With -ALL specified, DSE performs cache verification on all regions of + the current global directory. + o It reports the time, the region and a boolean result indicating + whether the cache is clean or NOT clean. If you see "NOT clean" in + report, execute DSE CACHE -RECOVER as soon as possible to reset the + cache in a clean state. + +3 Examples + Examples + + Example: + + DSE> CACHE -VERIFY + + This command checks the integrity of the cache data structures as well as + the internal consistency of GDS blocks in the global buffers of the + current region. + + Example: + + 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. + + Example: + + DSE> CACHE -RECOVER + + This command reinitializes the cache data structures of the current region + and reverts the cache of a database having BG access to "clean" state. + +2 CLose + CLose + + The CLOSE command closes the currently open output file. The format of the CLOSE command is: @@ -464,189 +1231,356 @@ The CLOSE command has no qualifiers. -1 CRITICAL - CR[ITICAL] - The CRITICAL command along with its qualifiers displays and/or - modifies the status and contents of the critical section for the - current region. The critical section provides a control mechanism. - This field identifies, by its PID, the process presently managing - updates to database. +2 CRitical + CRitical - The format of the CRITICAL command is: + Displays and/or modifies the status and contents of the critical section + for the current region. The format of the CRITICAL command is: - CR[ITICAL] -I[NIT] - -O[WNER] - -REL[EASE] - -REM[OVE] - -S[EIZE] + CR[ITICAL] -I[NIT] + -O[WNER] + -REL[EASE] + -REM[OVE] + -RES[ET] + -S[EIZE] - By default, the CRITICAL command assumes the -OWNER qualifier, which - displays the status of the critical section. + o The critical section field identifies, by its process identification + number (PID), the process presently managing updates to database. + o Think of a critical section as a common segment of a train track. Just + as a train moves through the common segment as quickly as possible, + the same way a process moves as quickly as possible through any + critical section so that other processes can use it. + o By default, the CRITICAL command assumes the -OWNER qualifier, which + displays the status of the critical section. -2 Qualifiers --INIT - -I[NIT] - Reinitializes the critical section. The -RESET qualifier causes - all processes actively accessing that database file to signal an - error. Do not use -INIT without the -RESET parameter when other - processes are accessing the region. +3 Qualifiers + Qualifiers - CAUTION: Using CRITICAL -INIT when the write owner of a critical - section is an active GT.M process may cause structural database - damage. + -I[NIT] --OWNER - -O[WNER] - Displays the ID of the process at the head of the critical - section, the ID of the process running DSE and the count of - critical read owners. When the current process owns the critical - section, DSE displays a warning message. The -OWNER qualifier is - incompatible with other qualifiers. + Reinitializes the critical section. + + o The -INIT and -RESET qualifiers together cause all GT.M processes + actively accessing that database file to signal an error. + o FIS recommends against using -INIT without the -RESET parameter when + other processes are actively accessing the region because it risks + damaging the database. + + Use only with: -RESET + + -O[WNER] + + Displays the ID of the process at the head of the critical section. DSE + displays a warning message when the current process owns the critical + section. + + Use alone Example: - DSE> critical-owner - + DSE> critical -OWNER Write critical section is currently unowned --RELEASE - -REL[EASE] - Releases the critical section if the process running DSE owns - the section. The -RELEASE qualifier is incompatible with other - qualifiers. + -REL[EASE] --REMOVE - -REM[OVE] - Terminates any write ownership of the critical section. Use this - when the critical section is owned by a process that is - nonexistent or is known to no longer be running a GT.M image. - The -REMOVE qualifier is incompatible with other qualifiers. + Releases the critical section if the process running DSE owns the section. - CAUTION: Using CRITICAL-REMOVE when the write owner of a - critical section is an active GT.M process may cause structural - database damage. + Use alone. --SEIZE - -S[EIZE] - Seizes the critical section if the section is available. The - -SEIZE qualifier is incompatible with other qualifiers. + -REM[OVE] -1 DUMP - D[UMP] - The DUMP command displays blocks, records or file headers. DUMP serves - as one of the primary DSE examination commands. Use the error messages - reported by MUPIP INTEG to determine what to DUMP and examine from the - database. DUMP also transfers records to a sequential file for future - study and/or for input to MUPIP LOAD. + Terminates any write ownership of the critical section. Use this when the + critical section is owned by a process that is nonexistent or is known to + no longer be running a GT.M image. - The DUMP command requires specification of either -BLOCK, -HEADER, - -RECORD or -FILEHEADER. + Use alone. -2 Qualifiers --BLOCK - -B[LOCK]=block_number - Specifies the starting block of the dump. The -BLOCK qualifier - is incompatible with the -FILEHEADER qualifier. + **Caution** - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block oriented command, DSE uses - block one (1). + Using CRITICAL -REMOVE when the write owner of a critical section is an + active GT.M process may cause structural database damage. + + -RES[ET] + + Displays the number of times the critical section has been through an + online reinitialization. + + Using -RESET with -INIT causes an error for processes that are attempting + to get the critical section of the region. Under the guidance of FIS, use + -RESET -INIT as a way to clear certain types of hangs. + + Use only with: -INIT + + -S[EIZE] + + Seizes the critical section (if available). + + o You can also use SEIZE to temporarily suspend database updates. + o Subsequently, execute CRITICAL -RELEASE command to restore normal + operation. + +3 Examples + Examples Example: - DSE> dump -block=2 + DSE> critical -OWNER Write critical section owner is process id 4220 - Block 2 Size 1B Level 0 TN 2 - Rec:1 Blk 2 Off 7 Size A Cmpc 0 Ptr 8 Key ^a - 7 : | A 0 0 61 0 0 8 0 0 0 - | . . . a . . . . . . + This command displays the ID of the process holding the critical section. + Note that on catching a process ID on a lightly loaded (or unloaded) + system (for example, text environment) is like catching lightening in a + bottle. Therefore, you can artificially hold a critical section using the + DSE CRIT -SEIZE command in one session and view the owner using a + different session. - Rec:2 Blk 2 Off 11 Size A Cmpc 0 Ptr B Key ^b - 11 : | A 0 0 62 0 0 B 0 0 0 - | . . . b . . . . . . +2 Dump + Dump + Displays blocks, records, or file headers. DUMP is one of the primary DSE + examination commands. --COUNT - -C[OUNT]=count - Specifies the number of block headers or records to DUMP. The - -COUNT qualifier is incompatible with the -FILEHEADER qualifier. + The format of the DUMP command is: --FILEHEADER - -F[ILEHEADER] - Dumps file header information. The -FILEHEADER qualifier is - incompatible with all other qualifiers. + D[UMP] -A[LL] + -B[LOCK]=block_number + -C[OUNT]=count + -F[ILEHEADER] + -G[LO] + -G[VSTATS] + -[NO]C[RIT] + -[NO]H[EADER] + -O[FFSET]=offset + -R[ECORD]=record-number + -U[PDPROC] + -Z[WR] --GLO - -G[LO] - Dumps the specified record or blocks into the current output - file in Global Output (GO) format. The -GLO qualifier is - incompatible with the -HEADER and -FILEHEADER qualifiers. + Use the error messages reported by MUPIP INTEG to determine what to DUMP + and examine in the database. DUMP also can transfer records to a + sequential file for future study and/or for input to MUPIP LOAD (see the + section on OPEN). The DUMP command requires specification of an object + using either -BLOCK, -HEADER, -RECORD, or -FILEHEADER. --HEADER - -[NO]H[EADER] - Specifies whether the dump of the specified blocks or records is - restricted to, or excludes, headers. The -HEADER qualifier is - incompatible with the -GLO and -FILEHEADER qualifiers. +3 Qualifiers + Qualifiers + + -A[LL] + + When used with -FILEHEADER, the -A[LL] qualifier displays additional + information on the database most of which is useful for FIS in diagnosing + issues. A complete description of all the elements that show up with the + DSE DUMP -FILEHEADER -ALL command are beyond the scope of this book. Use + only with -FILEHEADER or -UPDPROC (which is actually redundant as -ALL + displays the UPDPROC information). + + -B[LOCK]=block-number + + Specifies the starting block of the dump. For commands without an object + qualifier, DSE uses the last block handled by a DSE operation. When no + block has been accessed, (thatis, on the first block-oriented command), + DSE uses block one (1). + + Incompatible with: -ALL, -FILEHEADER and -UPDPROC. + + -C[OUNT]=count + + Specifies the number of blocks, block headers, or records to DUMP. + + Incompatible with: -ALL, -FILEHEADER and -UPDPROC. + + -F[ILEHEADER] + + Dumps file header information. A DSE dump of a database file header prints + a 0x prefix for all fields printed in hexadecimal format. Refer to the + "Introduction" section for a description of the file header fields. + + Use only with -ALL or -UPDPROC + + -G[LO] + + Dumps the specified record or blocks into the current output file in + Global Output (GO) format. FIS strongly suggests using -ZWR rather than + -GLO as the ZWR format handles all possible content values, including some + that are problematic with -GLO. + + Incompatible with: -ALL, -FILEHEADER, -UPDPROC and -ZWR. + + -G[VSTATS] + + Displays the access statistics for global variables and database file(s). + + -NO[CRIT] + + Allows DSE DUMP to work even if another process is holding a critical + section. Since results in this mode may be inconsistent, it should only be + used if the critical section mechanism is not operating normally. + + -[NO]H[EADER] + + Specifies whether the dump of the specified blocks or records is + restricted to, or excludes, headers. -HEADER displays only the header, + -NOHEADER displays the block or record with the header suppressed. DUMP + without the -[NO]HEADER qualifier dumps both the block/record and the + header. By default, DUMP displays all information in a block or record. --OFFSET - -O[FFSET]=offset - Specifies the offset of the starting record for the dump. If the - offset does not point to the beginning of a record, DSE rounds - down to the last valid record start (e.g., DUMP -OFF=10 starts - at -OFF=A if that was the last record). The -OFFSET qualifier is - incompatible with the -RECORD and -FILEHEADER qualifiers. + Incompatible with: -ALL, -FILEHEADER, -GLO, -UPDPROC and -ZWR. --RECORD - -R[ECORD]=record_number - Specifies the record number of the starting record of the dump. - The -RECORD qualifier is incompatible with the -OFFSET and - -FILEHEADER qualifiers. + -O[FFSET]=offset -1 EVALUATE - EV[ALUATE] - The EVALUATE command displays a number in both hexadecimal and - decimal. Use it to translate a hexadecimal number to decimal and vice - versa. The -DECIMAL and -HEXADECIMAL qualifiers specify the input base - for the number. + Specifies the offset, in bytes, of the starting record for the dump. If + the offset does not point to the beginning of a record, DSE rounds down to + the last valid record start (e.g., DUMP -OFF=10 starts at -OFF=A if that + was the beginning of the record containing offset 10). - The format of the EVALUATE command is: + Incompatible with: -ALL, -FILEHEADER, and -RECORD. - EV[ALUATE] -D[ECIMAL] - -H[EXADECIMAL] - -N[UMBER]=number + -R[ECORD]=record_number - The -NUMBER qualifier is required. + Specifies the record number of the starting record of the dump. If you try + to dump a record number that is larger than the last actual record in the + block, a DSE error message provides the number of the last record in the + block. - By default, EVALUATE treats the number as having a hexadecimal base. + Incompatible with: -ALL, -FILEHEADER, and -OFFSET. -2 Qualifiers --DECIMAL - -D[ECIMAL] - Specifies that the input number has a decimal base. The -DECIMAL - qualifier is incompatible with the -HEXADECIMAL qualifier + -U[PDPROC] --HEXADECIMAL - -H[EXADECIMAL] - Specifies that the input number has a hexadecimal base. The - -HEXADECIMAL qualifier is incompatible with the -DECIMAL - qualifier. + Displays the helper process parameters with the fileheader elements. --NUMBER - -N[UMBER]=number - Specifies the number to evaluate. This qualifier is required. + Use only with -FILEHEADER. + + -Z[WR] + + Dumps the specified record or blocks into the current output file in + ZWRITE (ZWR) format. + + Incompatible with: -ALL, -GLO, -HEADER and -FILEHEADER. + +3 Examples + Examples Example: - DSE> evaluate-number=61 + DSE> DUMP -FILEHEADER - Hex: 61 Dec: 97 + This command displays an output like the following: + File /home/gtmuser1/mumps.dat + Region DEFAULT + + Date/Time 27-OCT-2009 04:25:12 [$H = 61661,15912] + Access method BG Global Buffers 1024 + Reserved Bytes 0 Block size (in bytes) 1024 + Maximum record size 256 Starting VBN 129 + Maximum key size 64 Total blocks 0x00000191 + Null subscripts NEVER Free blocks 0x0000002A + Standard Null Collation FALSE Free space 0x00000000 + Last Record Backup 0x0000000000000001 Extension Count 100 + Last Database Backup 0x0000000000000001 Number of local maps 1 + Last Bytestream Backup 0x0000000000000001 Lock space 0x00000028 + In critical section 0x00000000 Timers pending 0 + Cache freeze id 0x00000000 Flush timer 00:00:01:00 + Freeze match 0x00000000 Flush trigger 960 + Current transaction 0x0000000000007539 No. of writes/flush 7 + Maximum TN 0xFFFFFFFFE3FFFFFF Certified for Upgrade to V5 + Maximum TN Warn 0xFFFFFFFF73FFFFFF Desired DB Format V5 + Master Bitmap Size 112 Blocks to Upgrade 0x00000000 + Create in progress FALSE Modified cache blocks 0 + Reference count 1 Wait Disk 0 + Journal State [inactive] ON Journal Before imaging TRUE + Journal Allocation 100 Journal Extension 100 + Journal Buffer Size 128 Journal Alignsize 128 + Journal AutoSwitchLimit 8388600 Journal Epoch Interval 30 + Journal Yield Limit 8 Journal Sync IO TRUE + Journal File: /home/gtmuser1/mumps.mjl + Mutex Hard Spin Count 128 Mutex Sleep Spin Count 128 + Mutex Spin Sleep Time 2048 KILLs in progress 0 + Replication State OFF Region Seqno 0x0000000000000001 + Zqgblmod Seqno 0x0000000000000000 Zqgblmod Trans 0x0000000000000000 + Endian Format LITTLE Commit Wait Spin Count 17 + Database file encrypted FALSE + + Note that the certain fileheader elements appear depending on the current + state of database. For example, as Journaling is not enabled in the + database, DSE does not display Journal data element fields. + + Example: + + $ dse dump -fileheader -updproc + + This command displays the fileheader elements along with the following + helper process parameters: + + Upd reserved area [% global buffers] 50 Avg blks read per 100 records 200 + Pre read trigger factor [% upd rsrvd] 50 Upd writer trigger [%flshTrgr] 33 + +2 EValuate + EValuate + + Translates a hexadecimal number to decimal, and vice versa. + + The format of the EVALUATE command is: + + EV[ALUATE] -D[ECIMAL] + -H[EXADECIMAL] + -N[UMBER]=number + + The -DECIMAL and -HEXADECIMAL qualifiers specify the input base for the + number. The -NUMBER qualifier is mandatory. By default, EVALUATE treats + the number as having a hexadecimal base. + +3 Qualifiers + Qualifiers + + -D[ECIMAL] + + Specifies that the input number has a decimal base. + + Incompatible with: -HEXADECIMAL . + + -H[EXADECIMAL] + + Specifies that the input number has a hexadecimal base. + + Incompatible with: -DECIMAL + + -N[UMBER]=number + + Specifies the number to evaluate. Required. + +3 Examples + Examples + + Example: + + DSE> evaluate -number=10 -decimal + + Hex: A Dec: 10 + + This command displays the hexadecimal equivalent of decimal number 10. + + Example: + + DSE> evaluate -number=10 -hexadecimal + + Hex: 10 Dec: 16 + + This command displays the decimal equivalent of hexadecimal 10. + + Example: + + $ dse evaluate -number=10 + + Hex: 10 Dec: 16 + + This command displays the decimal equivalent of Hexadecimal 10. Note that + if you do not specify an qualifier with -NAME, then EVALUATE assumes + Hexadecimal input. + +2 EXit + EXit -1 EXIT - EX[IT] The EXIT command ends a DSE session. The format of the EXIT command is: @@ -655,198 +1589,448 @@ The EXIT command has no qualifiers. -1 FIND - F[IND] - The FIND command directs DSE to a given block or region. At the - beginning of a DSE session, use the FIND -REGION command to select the - target region. +2 Find + Find - The FIND command, except with the -FREEBLOCK and -REGION qualifiers, - uses the index tree to locate blocks. FIND can locate blocks only - within the index tree structure. If you need to locate keys - independent of their attachment to the tree, use the RANGE command. + Locates a given block or region. The format of the FIND command is: -2 Qualifiers --BLOCK - -B[LOCK]=block_number - Specifies the block to find. The -BLOCK qualifier is - incompatible with the -KEY and -REGION qualifiers. + F[IND] -B[LOCK]=block-number + -E[XHAUSTIVE] + -F[REEBLOCK] /H[INT] + -K[EY]=key + -[NO]C[RIT] + -R[EGION][=region] + -S[IBLINGS] - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block oriented command, DSE uses - block one (1). + o At the beginning of a DSE session, use the FIND -REGION command to + select the target region. + o The FIND command, except when used with the -FREEBLOCK and -REGION + qualifiers, uses the index tree to locate blocks. FIND can locate + blocks only within the index tree structure. If you need to locate + keys independent of their attachment to the tree, use the RANGE + command. --EXHAUSTIVE - -E[XHAUSTIVE] - Instructs DSE to search the entire index structure for the - desired path or siblings. FIND -EXHAUSTIVE is useful in locating - blocks that are in the tree but not indexed correctly. The - -EXHAUSTIVE qualifier is incompatible with the -FREEBLOCK, -KEY - and -REGION qualifiers. +3 Qualifiers + Qualifiers --FREEBLOCK - -F[REEBLOCK] - Finds the nearest free block to the block specified by -HINT. - The -FREEBLOCK qualifier is incompatible with all other - qualifiers except -BLOCK and -HINT. The -HINT qualifier is - required with the -FREEBLOCK qualifier. + -B[LOCK]=block_number --HINT - -H[INT]=block_number - Designates the starting point of a -FREEBLOCK search. The -HINT - qualifier can be used only in conjunction with the -FREEBLOCK - qualifier. + Specifies the block to find. --KEY - -K[EY]=key - Searches the database for the block containing the specified - key. Enclose a MUMPS style key in quotes (""). The -KEY - qualifier is incompatible with all other qualifiers. + On commands without the -BLOCK= qualifier, DSE uses the last block handled + by a DSE operation. When no block has been accessed, that is, on the first + block-oriented command, DSE uses block one (1). --REGION - -R[EGION][=region] - Switches to the named Global Directory region. The -REGION - qualifier is incompatible with all other qualifiers. + Incompatible with: -KEY, -REGION - -REGION without a specified region, or -REGION=*, displays all - existing regions in the database. + -E[XHAUSTIVE] --SIBLINGS - -S[IBLINGS] - Displays the block numbers of the logical siblings of the - specified block. The logical siblings are the blocks that - logically exist to the right and left of the given block in the - database tree structure. The -SIBLINGS qualifier is incompatible - with the -FREEBLOCK, -KEY and -REGION qualifiers. + Searches the entire index structure for the desired path or siblings. -1 HELP - H[ELP] - The HELP command explains DSE commands. The format of the HELP command - is: + o FIND -EXHAUSTIVE locates blocks that are in the tree but not indexed + correctly. + o FIND -EXHAUSTIVE locates all paths to a "doubly allocated" block. - H[ELP] [item] + **Note** - Item tells HELP which information to display. Enter the DSE command - (item) after the HELP command or at the Topic prompt. Use or - to return to the DSE prompt. + A doubly allocated block may cause inappropriate mingling of data. As long + as no KILLs occur, double allocation may not cause permanent loss of + additional data. However, it may cause the application programs to + generate errors and/or inappropriate results. When a block is doubly + allocated, a KILL may remove data outside its proper scope. See + "Maintaining Database Integrity Chapter" for more information on repairing + doubly allocated blocks. -1 INTEGRIT - I[NTEGRIT] - The INTEGRIT command checks the internal consistency of a non-bitmap - block. INTEG reports errors in hexadecimal notation. + Incompatible with: -KEY, -REGION, -FREEBLOCK + + -F[REEBLOCK] + + Finds the nearest free block to the block specified by -HINT. + + o The -FREEBLOCK qualifier is incompatible with all other qualifiers + except -BLOCK and -HINT. + o The -HINT qualifier is required with the -FREEBLOCK qualifier. + o FIND -FREEBLOCK relies on the bitmaps to locate its target, so be sure + to fix any blocks incorrectly marked "FREE" before using this command. + See MAP -BUSY for more information on fixing incorrectly marked free + errors. + + Required with -HINT; compatible with -BLOCK and [NO]CRIT. + + -H[INT]=block_number + + Designates the starting point of a -FREEBLOCK search. + + FIND -FREE -HINT locates the "closest" free block to the hint. This + provides a tool for locating blocks to add to the B-tree, or to hold block + copies created with SAVE that would otherwise be lost when DSE exits. FIND + -FREE relies on the bitmaps to locate its target, so be sure to fix any + blocks incorrectly marked "FREE" before using this command. + + Required with: -FREEBLOCK; compatible with -BLOCK and [NO]CRIT. + + -K[EY]=key + + Searches the database for the block containing the specified key or if the + key does not exist, the block that would contain it, if it existed. + + o Enclose an M-style key in quotation marks (" "). FIND -KEY is useful + in locating properly indexed keys. The -KEY qualifier is incompatible + with all other qualifiers. + o FIND -KEY= uses the index to locate the level zero (0) block , or data + block, containing the key. If the key does not exist, it uses the + index to locate the block in which it would reside. Note that FIND + only works with the index as currently composed. In other words, it + cannot FIND the "right" place, only the place pointed to by the index + at the time the command is issued. These two locations should be, and + may well be, the same; however, remind yourself to search for, + understand and take into account all information describing any + current database integrity issues. + + Compatible only with [NO]CRIT. + + -[NO]C[RIT] + + Allows FIND to work even if another process is holding a critical section. + + As results in this mode may be inconsistent, it should only be used if the + critical section mechanism is not operating normally + + -R[EGION][=region] + + Switches to the named Global Directory region. + + -REGION without a specified region, or -REGION="*", displays all existing + regions in the database. + + Use Alone. + + -S[IBLINGS] + + Displays the block number of the specified block and its logical siblings + in hexadecimal format. + + The logical siblings are the blocks, if any, that logically exist to the + right and left of the given block in the database tree structure. + + Incompatible with: -FREEBLOCK, -HINT, -KEY, -REGION + +3 Examples + Examples + + Example: + + DSE> find -exhaustive -block=180 + Directory path + Path--blk:off + 1:10 2:1E + + Global paths + Path--blk:off + 6:51 1A4:249 180 + + This command locates block 180 by looking through the B-tree index for any + pointer to the block. This command finds even those blocks that are + connected to the tree but the first key in the block does not match the + index path. + + Example: + + DSE> find -free -hint=180 + + Next free block is D8F. + + This command locates the "closest" free block to block 180. + + You can use this command as a tool for locating blocks to add to the + B-tree, or to hold block copies created with SAVE that would otherwise be + lost when DSE exits. + + Example: + + DSE>find -key="^biggbl(1)" + + This command locates the key ^biggbl(1) in the database. + + Example: + + DSE> find -freeblock -hint=232 + + This commands starts to search for free block after block 232. + + Example: + + DSE> FIND -FREEBLOCK -HINT=232 -NOCRIT + + This command searches for freeblocks after block 232 even if another + process is holding a critical section. + + Example: + + DSE> find -sibling -block=10 + + This command operates like FIND -BLOCK; however it reports the numbers of + the blocks that logically fall before and after block 180 on the same + level. This command produces an output like the following: + + Left sibling Current block Right sibling + 0x0000000F 0x00000010 0x00000011 + +2 Help + Help + + The HELP command explains DSE commands. The format of the HELP command is: + + -H[ELP] [help topic] + +2 Integrit + Integrit + + Checks the internal consistency of a single non-bitmap block. INTEGRIT + reports errors in hexadecimal notation. The format of the INTEGRIT command is: - I[NTEGRIT] -B[LOCK]=block_number + I[NTEGRIT] -B[LOCK]=block-number -2 Qualifiers --BLOCK - -B[LOCK]=block_number - Specifies the block for DSE to check. + **Note** - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block oriented command, DSE uses - block one (1). - -1 MAPS - M[APS] - The MAPS command examines or updates bit maps. - - MAPS forces blocks either -BUSY or -FREE. The -MASTER qualifier - reflects the current status of a local bit map back into the master - map. The -RESTORE qualifier rebuilds all maps and should be used with - a great deal of caution as it can destroy important information. - - By default, MAPS shows the status of the bit map for the specified + Unlike MUPIP INTEG, this command only detects errors internal to a block + and cannot detect errors such as indices incorrectly pointing to another block. -2 Qualifiers --BLOCK - -BL[OCK]=block_number - Specifies the target block for MAPS. The -BLOCK qualifier is - incompatible with the -RESTORE_ALL qualifier. +3 Qualifiers + Qualifiers - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block-oriented command, DSE uses - block one (1). + -B[LOCK]=block_number --BUSY - -BU[SY] - Marks the current block busy in the block's local map and - appropriately updates the master bit map. The -BUSY qualifier is - incompatible with all qualifiers except -BLOCK. + Specifies the block for DSE to check. On commands with no -BLOCK + qualifier, DSE uses the last block handled by a DSE operation. When no + block has been accessed, that is, on the first block-oriented command, DSE + uses block one (1). --FREE - -F[REE] - Marks the current block free in the block's local map and - appropriately updates the master bit map. The -FREE qualifier is - incompatible with all qualifiers except -BLOCK. + -NO[CRIT] --MASTER - -M[ASTER] - Sets the master bit map bit associated with the current block's - local map according to whether that local map is full or not. - The -MASTER qualifier is incompatible with all qualifiers except - -BLOCK. + Allows DSE INTEG to work even if another process is holding a critical + section. Since results in this mode may be inconsistent, it should only be + used if the critical section mechanism is not operating normally. --RESTORE_ALL - -R[ESTORE_ALL] - Sets all local bit maps and the master bit map to reflect the - blocks used in the database file. Use RESTORE_ALL only if the - database contents are known to be correct, but a large number of - the bit maps require correction. The -RESTORE_ALL qualifier is - incompatible with all other qualifiers. +2 Maps + Maps -1 OPEN - OP[EN] - The OPEN command opens a file for sequential output of global variable - data. OPEN a file to which you want to "dump" information. + Examines or updates bitmaps. The format of the MAPS command is: - The format of the OPEN command is: + M[APS] -BL[OCK]=block-number + -BU[SY] + -F[REE] + -M[ASTER] + -R[ESTORE_ALL] - OP[EN] -F[ILE]=file + MAPS can flag blocks as being either -BUSY or -FREE. The -MASTER qualifier + reflects the current status of a local bitmap back into the master map. + The -RESTORE_ALL qualifier rebuilds all maps and should be used with + caution since it can destroy important information. - If an OPEN command does not have a -FILE qualifier, DSE reports the - name of the current output file. + By default, MAPS shows the status of the bitmap for the specified block. + +3 Qualifiers_for_MAP + Qualifiers for MAP + + -BL[OCK]=block_number + + Specifies the target block for MAPS. The -BLOCK qualifier is incompatible + with the -RESTORE_ALL qualifier. + + On commands with no -BLOCK= or -RESTORE_ALL qualifier, DSE uses the last + block handled by a DSE operation. When no block has been accessed, that + is, on the first block-oriented command, DSE uses block one (1). + + Incompatible with: -RESTORE_ALL + + -BU[SY] + + Marks the current block as busy in the block's local map and appropriately + updates the master bitmap. + + Compatible only with: -BLOCK + + -F[REE] + + Marks the current block as free in the block's local map and appropriately + updates the master bitmap. + + Compatible only with: -BLOCK + + -M[ASTER] + + Sets the bit in the master bitmap associated with the current block's + local map according to whether or not that local map is full. + + Use only with: -BLOCK. + + -R[ESTORE_ALL] + + Sets all local bitmaps and the master bitmap to reflect the blocks used in + the database file. + + Use -RESTORE_ALL only if the database contents are known to be correct, + but a large number of the bitmaps require correction. + + **Caution** + + The -RESTORE_ALL qualifier rebuilds all maps and should be used with a + great deal of caution as it can destroy important information. + + Use alone. + +3 Examples_for_MAPS + Examples for MAPS + + Example: + + DSE> MAPS -BLOCK=20 -FREE + + This command flags block 20 as free. A sample DSE DUMP output block 0 is + as follows: + + Block 0 Size 90 Level -1 TN 10B76A V5 Master Status: Free Space + Low order High order + Block 0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 20: | :XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 40: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 60: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 80: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 100: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 120: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 140: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 160: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + Block 180: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | + 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 + a before-image journal record. + + Example: + + DSE> maps -block=20 -busy + + This command marks block 20 as busy. A sample DSE DUMP output of block 0 + 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....... ........ ........ ........ | + Block 40: | ........ ........ ........ ........ | + Block 60: | ........ ........ ........ ........ | + Block 80: | ........ ........ ........ ........ | + Block A0: | ........ ........ ........ ........ | + Block C0: | ........ ........ ........ ........ | + Block E0: | ........ ........ ........ ........ | + Block 100: | ........ ........ ........ ........ | + Block 120: | ........ ........ ........ ........ | + Block 140: | ........ ........ ........ ........ | + Block 160: | ........ ........ ........ ........ | + Block 180: | ........ ........ ........ ........ | + Block 1A0: | ........ ........ ........ ........ | + Block 1C0: | ........ ........ ........ ........ | + Block 1E0: | ........ ........ ........ ........ | + + 'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT + + Note that the BLOCK 20 is marked as BUSY. + +2 OPen + OPen + + Use the OPEN command to open a file for sequential output of global + variable data. The format of the OPEN command is: + + OP[EN] F[ILE]=file + + o OPEN a file to which you want to "dump" information. + o If an OPEN command does not have a -FILE qualifier, DSE reports the + name of the current output file. + +3 Qualifiers_for_OPEN + Qualifiers for OPEN + + -F[ILE]=file-name -2 Qualifiers --F[ILE] - -F[ILE]=file Specifies the file to open. -1 OVERWRITE - OV[ERWRITE] - The OVERWRITE command overwrites the specified string onto the given - offset in the current block. Use extreme caution when using this - command. +3 Examples + Examples + + Example: + + DSE> OPEN + + Current output file: var.out + + This command displays the current output file. In this case, the output + file is var.out. + + Example: + + DSE> OPEN -FILE=var1.out + + The command OPEN -FILE=var1.out sets the output file to var1.out. + +2 OVerwrite + OVerwrite + + Overwrites the specified string on the given offset in the current block. + Use extreme caution when using this command. The format of the OVERWRITE command is: - OV[ERWRITE] -D[ATA]=string - -O[FFSET]=offset + OV[ERWRITE] -D[ATA]=string + -O[FFSET]=offset -2 Qualifiers --D[ATA] - -D[ATA]=string - Specifies the data to be written. Use quotes around string and - escape codes of the form \a or \ab, where a and b are - hexadecimal digits, for non-printing characters. \\ translates - to a single backslash. +3 Qualifiers_for_OVERWRITE + Qualifiers for OVERWRITE --O[FFSET] - -O[FFSET]=offset - Specifies the offset in the current block where the overwrite - should begin. + -B[LOCK]=block number -1 PAGE - P[AGE] - The PAGE command sends one form feed to the output device. Use PAGE to - add form feeds to a dump file, making the hardcopy file easier to - read. If you plan to use the dump file with MUPIP LOAD, do not use - PAGE. + Directs DSE to OVERWRITE a specific block. If no block number is + specified, the default is the current block. + + -D[ATA]=string + + Specifies the data to be written. Use quotation marks around the string + and escape codes of the form \a or \ab, where "a" and "b" are hexadecimal + digits representing non-printing characters. \\ translates to a single + backslash. + + -O[FFSET]=offset + + Specifies the offset in the current block where the overwrite should + begin. + +3 Examples + Examples + + Example: + + DSE>overwrite -block=31 -data="Malvern" -offset=CA + + This command overwrites the data at the specified location. + +2 Page + Page + + Sends one form feed to the output device. Use PAGE to add form feeds to a + dump file, making the hard copy file easier to read. If you plan to use + the dump file with MUPIP LOAD, do not use PAGE. The format of the PAGE command is: @@ -854,233 +2038,743 @@ The PAGE command has no qualifiers. -1 RANGE - RA[NGE] - The RANGE command finds all blocks in the database whose first key - falls in the specified range of keys. The RANGE command may take a - very long time unless the range specified by -FROM and -TO is close - together. Use FIND -KEY first to determine whether the key appears in - the tree. +2 RAnge + RAnge + + The RANGE command finds all blocks in the database whose first key falls + in the specified range of keys. The RANGE command may take a very long + time unless the range specified by -FROM and -TO is small. Use FIND -KEY + and/or FIND -KEY -EXHAUSTIVE first to quickly determine whether the key + appears in the index tree. The format of the RANGE command is: - RA[NGE] -F[ROM]=block - -T[O]=block - -L[OWER]=key - -U[PPER]=key + RA[NGE] -F[ROM]=block-number + -T[O]=block-number + -I[NDEX] + -LOS[T] + -[NO]C[RIT] + -[NO]BU[SY] + -S[TAR] + -LOW[ER]=key + -U[PPER]=key + +3 Qualifiers + Qualifiers + + -F[ROM]=block_number -2 Qualifiers --FROM - -F[ROM]=block_number Specifies a starting block number for the range search. - By default, RANGE starts processing at the beginning of the - file. + By default, RANGE starts processing at the beginning of the file. --TO - -T[O]=block_number - Specifies an ending block number for the range search. + -T[O]=block-number - By default, RANGE stops processing at the end of the file. + Specifies an ending block number for the range search. By default, RANGE + stops processing at the end of the file. + + -I[NDEX] + + Restricts a search to index blocks. + + -LOS[T]=block_number + + Restricts a search to blocks not found by a FIND -BLOCK. + + -LOW[ER]=key --LOWER - -L[OWER]=key Specifies the lower bound for the key range. --UPPER - -U[PPER]=key + -[NO]BU[SY]=busy/free + + Restricts a search to either BUSY or FREE blocks. + + -[NO]C[RIT] + + Allows DSE RANGE to work even if another process is holding a critical + section. Since results in this mode may be inconsistent, it should only be + used if the critical section mechanism is not operating normally. + + -S[TAR] + + Includes index blocks that contain a single star key. + + -U[PPER]=key + Specifies the upper bound for the key range. -1 REMOVE - REM[OVE] - The REMOVE command removes one or more records or a save buffer. +3 Examples + Examples + + Example: + + DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC + + This command searches for a specified keys between block 10 and block 204. + Note that the range (between FROM and TO) of blocks must be valid blocks + specified in hexadecimal. + + Example: + + DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -noindex + + This command searches only data blocks for the specified keys between + block 10 and block 204. + + Example: + + DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -index + + This command searches only index blocks for the specified keys between + block 10 and block 204. + + Example: + + DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -lost + + This command includes lost blocks while searching for the specified keys + and reports only blocks which are not currently indexed. + + 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 + Block: 0000000C Level: 0 + 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). + +2 REMove + REMove + + Removes one or more records or a save buffer. The format of the REMOVE command is: - REM[OVE] -B[LOCK]=block_number - -C[OUNT]=count - -O[FFSET] - -R[ECORD]=record_number - -V[ERSION]=version_number + REM[OVE] -B[LOCK]=block-number + -C[OUNT]=count + -O[FFSET]=offset + -R[ECORD]=record-number + -V[ERSION]=version-number The version number is specified in decimal. -2 Qualifiers --BLOCK - -B[LOCK]=block_number - Specifies the block associated with the record or buffer being - deleted. +3 Qualifiers + Qualifiers - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, that is, on the first block-oriented command, DSE uses - block one (1). + -B[LOCK]=block_number --COUNT - -C[OUNT]=count - Specifies the number of records to remove. The -COUNT qualifier - is incompatible with the -VERSION qualifier. + Specifies the block associated with the record or buffer being deleted. + + On commands with no -BLOCK= qualifier, DSE uses the last block handled by + a DSE operation. When no block has been accessed, that is, on the first + block-oriented command, DSE uses block one (1). + + -C[OUNT]=count + + Specifies the number of records to remove. By default, REMOVE deletes a single record. --OFFSET - -O[FFSET]=offset - Specifies the offset of the record to remove. The -OFFSET - qualifier is incompatible with the -RECORD and -VERSION - qualifiers. + Incompatible with: -VERSION --RECORD - -R[ECORD]=record_number - Specifies the record number of the record to remove. The -RECORD - qualifier is incompatible with the -OFFSET and -VERSION - qualifiers. + -O[FFSET]=offset --VERSION - -V[ERSION]=version_number - Specifies the decimal version number in decimal of the save - buffer to remove. -VERSION is required to REMOVE a SAVE buffer. - -VERSION is incompatible with all qualifiers except -BLOCK. + Specifies the offset (in bytes) of the record to be removed. If the offset + does not point to the beginning of a record, DSE rounds down to the + beginning of the record containing the offset (for example, REMOVE -OFF=10 + starts at OFF=A if that was the last prior record boundry). + + Incompatible with: -VERSION, -RECORD + + -R[ECORD]=record_number + + Specifies the number that identifies the record to remove. The -RECORD + qualifier is incompatible with the -OFFSET and -VERSION qualifiers. + + Incompatible with: -VERSION, -OFFSET + + -V[ERSION]=version_number + + Specifies the version number, in decimal, of the save buffer to remove. + -VERSION is required to REMOVE a SAVE buffer. -VERSION is incompatible + with all qualifiers except -BLOCK. + + Use only with: -BLOCK; decimal + +2 REStore + REStore -1 RESTORE - RES[TORE] The RESTORE command restores saved versions of blocks. - The format of the RESTORE command is: - - RES[TORE] -B[LOCK]=block_number - -F[ROM]=from - -R[EGION]=region - -V[ERSION]=version_number + RES[TORE] B[LOCK]=block-number + F[ROM]=from + R[EGION]=region + V[ERSION]=version-number The version number is specified in decimal. -2 Qualifiers --BLOCK - -B[LOCK]=block_number +3 Qualifiers + Qualifiers + + -B[LOCK]=block_number + Specifies the block to restore. - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block oriented command, DSE uses - block one (1). + For commands with no -BLOCK= qualifier, DSE uses the last block handled by + a DSE operation. When no block has been accessed, (i.e., on the first + block-oriented command), DSE uses block one (1). --FROM - -F[ROM]=block_number - Specifies the block number of the save buffer to restore. + -F[ROM]=block_number - By default, RESTORE uses the target block number as the SAVE - block number. + Specifies the block number of the SAVE buffer to restore. + + DSE restores the block specified with -BLOCK qualifier with the block + specified by the -FROM qualifier. + + By default, RESTORE uses the target block number as the -FROM block + number. + + -R[EGION]=region --REGION - -R[EGION]=region_number Specifies the region of the saved buffer to restore. By default, RESTORE uses SAVE buffers from the current region. --VERSION - -V[ERSION]=version_number - Specifies the decimal version number of the block to restore. - The version number is required. + -V[ERSION]=version_number -1 SAVE - SA[VE] - The SAVE command saves versions of blocks or displays a listing of - saved versions. Saved information is lost when DSE EXITs. Use with the - RESTORE command to move blocks. As a safety feature, use SAVE to - retain fallback copies of database blocks before changing them. + Specifies the decimal version number of the block to restore. The version + number is required. + +2 SAve + SAve + + The SAVE command preserves versions of blocks, or displays a listing of + saved versions for the current DSE session. Saved information is lost when + DSE EXITs. + + Use with the RESTORE command to move SAVEd blocks to a permanent location, + and as a safety feature use SAVE to retain copies of database blocks + before changing them. The format of the SAVE command is: - SA[VE] -B[LOCK]=block_number - -C[OMMENT]=string - -L[IST] + SA[VE] -B[LOCK]=block-number + -C[OMMENT]=string + -L[IST] + -[NO]C[RIT] -2 Qualifiers --BLOCK - -B[LOCK]=block_number - Specifies the block to save. +3 Qualifiers + Qualifiers - On commands with no -BLOCK= qualifier, DSE uses the last block - handled by a DSE operation. In this case, when no block has been - accessed, .i.e., on the first block-oriented command, DSE uses - block one (1). + -B[LOCK]=block_number --COMMENT - -C[OMMENT]=string - Specifies a comment to save with the block. Enclose the comment - in quotes (""). The -COMMENT qualifier is incompatible with the - -LIST qualifier. + Specifies the block to restore. --LIST - -L[IST] - Lists saved versions of specified blocks. The -LIST qualifier is + On commands with no -BLOCK= qualifier, DSE uses the last block handled by + a DSE operation. When no block has been accessed, that is, on the first + block-oriented command, DSE uses block one (1). + + -C[OMMENT]=string + + Specifies a comment to save with the block. Enclose the comment in + quotation marks (" "). + + Incompatible with: -LIST + + -L[IST] + + Lists saved versions of specified blocks. The -LIST qualifier is incompatible with the -COMMENT qualifier. By default, SAVE -LIST provides a directory of all SAVEd blocks. -1 SHIFT - SH[IFT] - The SHIFT command shifts data in a block, filling the block with zeros - or shortening the block. The format of the SHIFT command is: + Incompatible with: -COMMENT - SH[IFT] -B[ACKWARD]=shift - -F[ORWARD]=shift - -O[FFSET]=offset + -[NO]C[RIT] -2 Qualifiers --BACKWARD - -B[ACKWARD]=shift - Specifies the extent to which DSE should shift data backwards - towards the block header. The -BACKWARD qualifier is - incompatible with the -FORWARD qualifier. + Allows DSE SAVE to work even if another process is holding a critical + section. Since results in this mode may be inconsistent, it should only be + used if the critical section mechanism is not operating normally. --FORWARD - -F[ORWARD]=shift - Specifies the extent to which DSE should shift data forward - towards the end of the block. The -FORWARD qualifier is - incompatible with the -BACKWARD qualifier. +2 SHift + SHift --OFFSET - -O[FFSET]=offset - Specifies the starting offset of the portion of the block to + Use the SHIFT command to shift data in a block, filling the block with + zeros, or shortening the block. The format of the SHIFT command is: + + SH[IFT] -B[ACKWARD]=b_shift + -F[ORWARD]=f_shift + -O[FFSET]=offset + + b_shift must always be less than or equal to offset. This means that DSE + SHIFT in the backward direction is restricted to the maximum of OFFSET + number of bytes. This ensures that the shift does not cross block + boundaries, either intentionally or unintentionally. + +3 Qualifiers + Qualifiers + + -B[ACKWARD]=shift + + Specifies the number of bytes to shift data in the direction of the block + header. + + Incompatible with: -FORWARD + + -F[ORWARD]=shift + + Specifies the number of bytes to shift data toward the end of the block. + + Incompatible with: -BACKWARD + + -O[FFSET]=offset + + Specifies the starting offset, in bytes, of the portion of the block to shift. -1 SPAWN - SP[AWN] - The SPAWN command forks a child process for access to the shell - without terminating the current DSE environment. Use the SPAWN command - to suspend a session and issue shell commands such as MUPIP INTEG - -REGION or GDE. The SPAWN command leaves your terminal at the input - prompt of the shell of the spawned process. + -SPawn + +2 SPawn + SPawn + + Use the SPAWN command to fork a child process for access to the shell + without terminating the current DSE environment. The format of the SPAWN command is: - SP[AWN] [command] + SP[AWN] [shell-command] + + o The SPAWN command accepts an optional command string for execution by + the spawned sub-process. If the SPAWN has no command string parameter, + the created sub-process issues a shell prompt and accepts any legal + shell command. To terminate the sub-process, use the shell logout + command. + o The SPAWN command has no qualifiers. + o DSE SPAWN works with an argument. If the argument contains spaces, + enclose it with quotes. The SPAWN command has no qualifiers. -1 WCINIT - W[CINIT] - The WCINIT command reinitializes the global buffers of the current - region. Because it cleans out the cache, WCINIT is a very dangerous - command and therefore should not be used except under Greystone - supervision. + DSE SPAWN works with an argument. If the argument contains spaces, enclose + it with quotes. - WARNING: A WCINIT command issued while normal database operations are - in progress can cause catastrophic damage to the database. +3 Examples + Examples + + Example: + + DSE> SPAWN "mumps -run ^GDE" + + This command suspends a DSE session and executes the shell command mumps + -run ^GDE. + +2 Wcinit + Wcinit + + Use the WCINIT command to reinitialize the global buffers of the current + region. Because it cleans out the cache, the WCINIT command should not be + used except under the guidance of FIS. + + **Caution** + + A WCINIT command issued while normal database operations are in progress + can cause catastrophic damage to the database. The format of the WCINIT command is: W[CINIT] - The WCINIT command has no qualifiers. + o The WCINIT command has no qualifiers. + o When you issue the WCINIT command, DSE issues the CONFIRMATION: + prompt. You must verify the WCINIT command by responding with "YES." - When you issue the WCINIT command, DSE issues the CONFIRMATION: - prompt. You must verify the WCINIT command by responding with a "YES." + If you do not confirm the WCINIT, DSE issues the message: - If you do not confirm the WCINIT, DSE issues the message: + No action taken, enter yes at the CONFIRMATION prompt to initialize global buffers. - No action taken, enter yes at the CONFIRMATION prompt to initialize - global buffers. + o WCINIT operations are more safely performed by MUPIP RUNDOWN. Use this + command only under instructions from FIS. +1 Summary + Summary + + +------------------------------------------------------------------------+ + | COMMAND | QUALIFIERS | COMMENTS | + |-------------+-----------------------------------+----------------------| + | AD[D] | -B[LOCK]=block number | - | + |-------------+-----------------------------------+----------------------| + | - | -D[ATA]=string | Incompatible with | + | | | -POINTER, -STAR | + |-------------+-----------------------------------+----------------------| + | - | -K[EY]=key | Incompatible with | + | | | -STAR | + |-------------+-----------------------------------+----------------------| + | - | -O[FFSET]=offset | Incompatible with | + | | | -RECORD, -STAR | + |-------------+-----------------------------------+----------------------| + | - | -P[OINTER]=pointer | Incompatible with | + | | | -DATA | + |-------------+-----------------------------------+----------------------| + | - | -R[ECORD]=record-number | Incompatible with | + | | | -OFFSET, -STAR | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -S[TAR] | -DATA,-KEY, -OFFSET, | + | | | -RECORD | + |-------------+-----------------------------------+----------------------| + | AL[L] | -B[UFFER_FLUSH] | Incompatible with | + | | | -RENEW | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -C[RITINIT] | -RENEW, -RELEASE, | + | | | -SEIZE | + |-------------+-----------------------------------+----------------------| + | - | -[NO]F[REEZE] | Incompatible with | + | | | -RENEW | + |-------------+-----------------------------------+----------------------| + | - | -O[VERRIDE] | Meaningful only with | + | | | -[NO]FREEZE | + |-------------+-----------------------------------+----------------------| + | - | -REF[ERENCE] | Incompatible with | + | | | -RENEW | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -REL[EASE] | -CRITINIT, | + | | | -RENEW,-SEIZE | + |-------------+-----------------------------------+----------------------| + | - | -REN[EW] | Use alone | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -S[EIZE] | -RENEW, -RELEASE, | + | | | -CRITINIT | + |-------------+-----------------------------------+----------------------| + | - | -W[CINIT] | Incompatible with | + | | | -RENEW | + |-------------+-----------------------------------+----------------------| + | B[UFFER | - | - | + | _FLUSH] | | | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | CH[ANGE] | -BL[OCK]=block number | -FILEHEADER and | + | | | qualifiers used with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -BS[IZ]=block-size | Use only with | + | | | -BLOCK, -LEVEL, -TN | + |-------------+-----------------------------------+----------------------| + | - | -L[EVEL]=level | Use only with | + | | | -BLOCK, -BSIZ, -TN | + |-------------+-----------------------------------+----------------------| + | | | Use only with | + | - | -TN [=transaction number] | -BLOCK, -BSIZ, | + | | | -LEVEL | + |-------------+-----------------------------------+----------------------| + | - | -OF[FSET]=offset | Use only with | + | | | -BLOCK, -CMPC, -RSIZ | + |-------------+-----------------------------------+----------------------| + | - | -RE[CORD]=record number | Use only with | + | | | -BLOCK, -CMPC, -RSIZ | + |-------------+-----------------------------------+----------------------| + | | | Use only with | + | - | -CM[PC]= compression count | -BLOCK, -RECORD, | + | | | -OFFSET, -RSIZ | + |-------------+-----------------------------------+----------------------| + | | | Use only with -CMPC | + | - | -RS[IZ]=record size | -OFFSET, -RECORD, | + | | | -BLOCK | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -F[ILEHEADER] | -BSIZ, -CMPC, -TN, | + | | | -LEVEL, -OFFSET, | + | | | -RECORD, -RSIZ | + |-------------+-----------------------------------+----------------------| + | - | AVG_BLKS_READ=Average blocks read | | + |-------------+-----------------------------------+----------------------| + | - | B_B[YTESTREAM]=transaction number | | + |-------------+-----------------------------------+----------------------| + | - | -B_C[OMPREHENSIVE]=transaction | Use only with | + | | number | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | B_D[ATABASE] = transaction number | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -B_I[NCREMENTAL] = transaction | Use only with | + | | number | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -BLK[_SIZE]=block size | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -BLO[CKS_FREE]=free blocks | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -B_R[ECORD]=transaction number | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -CO[RRUPT_FILE]=value | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -CU[RRENT_TN]=transaction number | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | DECL[OCATION]=value | Use only with | + | | | -FILHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | DEF[_COLLATION]=value | Use only with | + | | | -FILEHEADER; | + |-------------+-----------------------------------+----------------------| + | - | -ENCRYPTION_HASH | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -FL[USH_TIME][=delta time] | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -FR[EEZE]=value | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -FU[LLY_UPGRADED]=boolean | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -GV[STATSRESET] | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -HARD_SPIN_CPUNT=Mutex hard spin | Use only with | + | | count | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | | -HEXL[OCATION]=value | Use only with | + | | | -FILEHEADER;hexa | + |-------------+-----------------------------------+----------------------| + | - | -INT[ERRUPTED_RECOV]=boolean | | + |-------------+-----------------------------------+----------------------| + | - | -JNL_YIELD_LIMIT=journal yeild | | + | | limit | | + |-------------+-----------------------------------+----------------------| + | - | -K[EY_MAX_SIZE]=key_max_size | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -M[ACHINE_NAM]=value | | + |-------------+-----------------------------------+----------------------| + | - | -N[ULL_SUBSCRIPTS]=value | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -NO[CRIT] | | + |-------------+-----------------------------------+----------------------| + | - | -OV[ERRIDE] | | + |-------------+-----------------------------------+----------------------| + | - | -RC_SRV_COUNT | | + |-------------+-----------------------------------+----------------------| + | - | -RE_READ_TRIGGER=read trigger | | + |-------------+-----------------------------------+----------------------| + | - | -Q[UANTUM_INTERVAL] [=delta time] | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -REC[ORD_MAX_SIZE]=maximum record | Use only with | + | | size | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -REF[ERENCE_COUNT]=reference | Use only with | + | | count | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -REG[_SEQNO]=sequence number | Use only with | + | | | -FILEHEADER; hexa | + |-------------+-----------------------------------+----------------------| + | - | -RESERVED_BYTES=reserved bytes | Use only with | + | | | -FILEHEADER;decimal | + |-------------+-----------------------------------+----------------------| + | - | -[NO] RES[PONSE_INTERVAL] [=delta | Use only with | + | | time] | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -SLEEP_SPIN_COUNT=mutex sleep | Use only with | + | | spin count | -FILEHEADER; | + |-------------+-----------------------------------+----------------------| + | - | -SPIN_SLEEP_TIME=mutex sleep time | | + |-------------+-----------------------------------+----------------------| + | - | -[NO]S[TALENESS_TIMER] [=delta | Use only with | + | | time] | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -TIC[K_INTERVAL] [=delta time] | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -TIM[ERS_PENDING]=timers pending | Use only with | + | | | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -TO[TAL_BLKS]=total_blocks | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -TR[IGGER_FLUSH]=trigger flush | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -W[RITES_PER_FLUSH]=writes per | Use only with | + | | flush | -FILEHEADER; decimal | + |-------------+-----------------------------------+----------------------| + | - | -WAIT_DISK=wait disk | | + |-------------+-----------------------------------+----------------------| + | - | -Zqgblmod_S[EQNO] = sequence | Use only with | + | | number | -FILEHEADER;hexa | + |-------------+-----------------------------------+----------------------| + | - | -Zqgblmod_T[rans]=sequence_number | Use only with | + | | | -FILEHEADER;hexa | + |-------------+-----------------------------------+----------------------| + |-------------+-----------------------------------+----------------------| + | CL[OSE] | - | - | + |-------------+-----------------------------------+----------------------| + | CR[ITICAL] | -I[NIT] | Use only with -RESET | + |-------------+-----------------------------------+----------------------| + | - | -O[WNER] | Use alone | + |-------------+-----------------------------------+----------------------| + | - | -REL[EASE] | Use alone | + |-------------+-----------------------------------+----------------------| + | - | -REM[OVE] | Use alone | + |-------------+-----------------------------------+----------------------| + | - | -RES[ET] | Use only with -INIT | + |-------------+-----------------------------------+----------------------| + | - | -S[EIZE] | Use alone | + |-------------+-----------------------------------+----------------------| + | D[UMP] | -B[LOCK]=block_number | Incompatible with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -C[OUNT]=count | Incompatible with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -F[ILEHEADER] | Use alone | + |-------------+-----------------------------------+----------------------| + | - | -G[LO] | Incompatible with | + | | | -FILEHEADER, -HEADER | + |-------------+-----------------------------------+----------------------| + | - | -G[VSTATS] | Use only with | + | | | -FILEHEADER | + |-------------+-----------------------------------+----------------------| + | - | -[NO]H[EADER] | Incompatible with | + | | | -FILEHEADER, -GLO | + |-------------+-----------------------------------+----------------------| + | - | -O[FFSET]=offset | Incompatible with | + | | | -FILEHEADER, -RECORD | + |-------------+-----------------------------------+----------------------| + | - | -R[ECORD]=record_number | Incompatible with | + | | | -FILEHEADER, -OFFSET | + |-------------+-----------------------------------+----------------------| + | EV[ALUATE] | -D[ECIMAL] | Incompatible with | + | | | -HEXADECIMAL | + |-------------+-----------------------------------+----------------------| + | - | -H[EXADECIMAL] | Incompatible with | + | | | -DECIMAL | + |-------------+-----------------------------------+----------------------| + | - | -N[UMBER]=number | Required | + |-------------+-----------------------------------+----------------------| + | EX[IT] | | - | + |-------------+-----------------------------------+----------------------| + | F[IND] | -B[LOCK]=block_number | Incompatible with | + | | | -KEY, -REGION | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -E[XHAUSTIVE] | -KEY, -REGION, | + | | | -FREEBLOCK | + |-------------+-----------------------------------+----------------------| + | | | Required with -HINT; | + | - | -F[REEBLOCK] | compatible with | + | | | -BLOCK | + |-------------+-----------------------------------+----------------------| + | - | -H[INT]=block_number | Required with | + | | | -FREEBLOCK | + |-------------+-----------------------------------+----------------------| + | - | -K[EY]=key | Use alone | + |-------------+-----------------------------------+----------------------| + | - | -R[EGION][=region] | Use alone | + |-------------+-----------------------------------+----------------------| + | | | Incompatible with | + | - | -S[BLINGS] | -FREEBLOCK, -HINT, | + | | | -KEY, -REGION | + |-------------+-----------------------------------+----------------------| + | H[ELP] | [help topic] | - | + |-------------+-----------------------------------+----------------------| + | I[NTEGRIT] | -B[LOCK]=block&_number | - | + |-------------+-----------------------------------+----------------------| + | M[APS] | -BL[OCK]=block_number | Incompatible with | + | | | -RESTORE_ALL | + |-------------+-----------------------------------+----------------------| + | - | -BU[SY] | Compatible only with | + | | | -BLOCK | + |-------------+-----------------------------------+----------------------| + | - | -F[REE] | - | + |-------------+-----------------------------------+----------------------| + | - | -M[ASTER] | - | + |-------------+-----------------------------------+----------------------| + | - | -R[ESTORE_ALL] | Use alone | + |-------------+-----------------------------------+----------------------| + | OP[EN] | -F[ILE]=file | - | + |-------------+-----------------------------------+----------------------| + | | -B[LOCK]=block_number | | + | OV[ERWRITE] | | - | + | | -D[ATA]=string | | + |-------------+-----------------------------------+----------------------| + | - | -O[FFSET]=offset | - | + |-------------+-----------------------------------+----------------------| + | P[AGE] | - | - | + |-------------+-----------------------------------+----------------------| + | RA[NGE] | -F[ROM]=block_number | - | + |-------------+-----------------------------------+----------------------| + | - | -T[O]=block_number | - | + |-------------+-----------------------------------+----------------------| + | | -I[NDEX]=block_number | | + | | | | + | | -L[OST]=block_number | | + | | | | + | - | -[NOT]BUSY=busy/free | - | + | | | | + | | -S[TAR]=block_number | | + | | | | + | | -L[OWER]=key | | + |-------------+-----------------------------------+----------------------| + | - | -U[PPER]=key | - | + |-------------+-----------------------------------+----------------------| + | REM[OVE] | -B[LOCK]=block-number | - | + |-------------+-----------------------------------+----------------------| + | - | -C[OUNT]=count | Incompatible with | + | | | -VERSION | + |-------------+-----------------------------------+----------------------| + | - | -O[FFSET]=offset | Incompatible with | + | | | -VERSION, -RECORD | + |-------------+-----------------------------------+----------------------| + | - | -R[ECORD]=record-number | Incompatible with | + | | | -VERSION, -OFFSET | + |-------------+-----------------------------------+----------------------| + | - | -V[ERSION]=version-number | Use only with | + | | | -BLOCK; decimal | + |-------------+-----------------------------------+----------------------| + | RES[TORE] | -B[LOCK]=block-number | - | + |-------------+-----------------------------------+----------------------| + | - | -F[ROM]=block-number | - | + |-------------+-----------------------------------+----------------------| + | - | -R[EGION]=region | - | + |-------------+-----------------------------------+----------------------| + | - | -V[ERSION]=version-number | Required; decimal | + |-------------+-----------------------------------+----------------------| + | SA[VE] | -B[LOCK]=block-number | - | + |-------------+-----------------------------------+----------------------| + | - | -C[OMMENT]=string | Incompatible with | + | | | -LIST | + |-------------+-----------------------------------+----------------------| + | - | -L[IST] | Incompatible with | + | | | -COMMENT | + |-------------+-----------------------------------+----------------------| + | SH[IFT] | -B[ACKWARD]=shift | Incompatible with | + | | | -FORWARD | + |-------------+-----------------------------------+----------------------| + | - | -F[ORWARD]=shift | Incompatible with | + | | | -BACKWARD | + |-------------+-----------------------------------+----------------------| + | - | -O[FFSET]=offset | - | + |-------------+-----------------------------------+----------------------| + | SP[AWN] | [CLI command] | - | + |-------------+-----------------------------------+----------------------| + | W[CINIT] | - | - | + +------------------------------------------------------------------------+ + + * Use these qualifiers only with instructions from FIS. diff --git a/sr_port/dse_adrec.c b/sr_port/dse_adrec.c index 9182016..d0eb367 100644 --- a/sr_port/dse_adrec.c +++ b/sr_port/dse_adrec.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,34 +9,34 @@ * * ****************************************************************/ -#include +#include "mdef.h" -#include -#include -#include -#include -#include -#include -#include +#include "gtm_string.h" +#include "gdsroot.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "gdsblkops.h" +#include "gdscc.h" +#include "cli.h" +#include "copy.h" +#include "filestruct.h" +#include "jnl.h" +#include "skan_offset.h" +#include "skan_rnum.h" +#include "dse.h" /* Include prototypes */ -#include -#include -#include -#include -#include -#include -#include +#include "t_qread.h" +#include "t_write.h" +#include "t_end.h" +#include "t_begin_crit.h" +#include "gvcst_blk_build.h" +#include "util.h" +#include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; @@ -46,16 +46,15 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF gd_region *gv_cur_region; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; - void dse_adrec(void) { char data[MAX_LINE], key[MAX_KEY_SZ + 1]; - unsigned char cc; + unsigned short cc; + int tmp_cmpc; sm_uc_ptr_t new_bp, lbp, b_top, rp, r_top, key_top; short int size, new_len, rsize; int data_len, key_len; @@ -181,7 +180,7 @@ void dse_adrec(void) size = (key_len < patch_comp_count) ? key_len : patch_comp_count; for (cc = 0; cc < size && patch_comp_key[cc] == key[cc]; cc++) ; - ((rec_hdr_ptr_t)new_bp)->cmpc = cc; + SET_CMPC((rec_hdr_ptr_t)new_bp, cc); new_len = key_len - cc + data_len + SIZEOF(rec_hdr); PUT_SHORT(&((rec_hdr_ptr_t)new_bp)->rsiz, new_len); MEMCP(new_bp, &key[cc], SIZEOF(rec_hdr), key_len - cc, blk_size); @@ -203,10 +202,10 @@ void dse_adrec(void) if (!*key_top++ && !*key_top++) break; } - if (((rec_hdr_ptr_t)rp)->cmpc > patch_comp_count) + if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t)rp)->cmpc; + cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; @@ -217,7 +216,7 @@ void dse_adrec(void) size = (key_len < patch_comp_count) ? key_len : patch_comp_count; for (cc = 0; cc < size && patch_comp_key[cc] == key[cc]; cc++) ; - ((rec_hdr_ptr_t)(new_bp + new_len))->cmpc = cc; + SET_CMPC((rec_hdr_ptr_t)(new_bp + new_len), cc); rsize = patch_comp_count - cc + r_top - key_top + SIZEOF(rec_hdr); PUT_SHORT(&((rec_hdr_ptr_t)(new_bp + new_len))->rsiz, rsize); MEMCP(new_bp, &patch_comp_key[cc], new_len + SIZEOF(rec_hdr), patch_comp_count - cc, blk_size); @@ -246,7 +245,7 @@ void dse_adrec(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); diff --git a/sr_port/dse_adstar.c b/sr_port/dse_adstar.c index 705902f..421ef29 100644 --- a/sr_port/dse_adstar.c +++ b/sr_port/dse_adstar.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,7 +46,6 @@ GBLREF srch_hist dummy_hist; GBLREF gd_addr *gd_header; GBLREF block_id patch_curr_blk; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; void dse_adstar(void) { @@ -55,6 +54,7 @@ void dse_adstar(void) blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; short rsize; + int tmp_cmpc; srch_blk_status blkhist; error_def(ERR_DBRDONLY); @@ -112,7 +112,7 @@ void dse_adstar(void) } rsize = SIZEOF(rec_hdr) + SIZEOF(block_id); PUT_SHORT(&((rec_hdr_ptr_t)b_top)->rsiz, rsize); - ((rec_hdr_ptr_t) b_top)->cmpc = 0; + SET_CMPC((rec_hdr_ptr_t)b_top, 0); PUT_LONG((block_id_ptr_t)(b_top + SIZEOF(rec_hdr)), blk); ((blk_hdr_ptr_t)lbp)->bsiz += (unsigned int)(SIZEOF(rec_hdr) + SIZEOF(block_id)); @@ -126,7 +126,7 @@ void dse_adstar(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); diff --git a/sr_port/dse_all.c b/sr_port/dse_all.c index 1cfbbb3..c9dd47c 100644 --- a/sr_port/dse_all.c +++ b/sr_port/dse_all.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,6 @@ #if defined(UNIX) #include "gtm_ipc.h" -GBLREF uint4 user_id; #endif #include "gdsblk.h" @@ -40,9 +39,8 @@ GBLREF uint4 user_id; #include "min_max.h" /* needed for init_root_gv.h */ #include "init_root_gv.h" #include "dse.h" - #ifdef UNIX -#include "mutex.h" +# include "mutex.h" #endif #include "wcs_flu.h" #include /* for VSIG_ATOMIC_T */ @@ -170,11 +168,10 @@ void dse_all(void) GTMASSERT; } patch_curr_blk = get_dir_root(); - if (crit) { - UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY, TRUE);) - VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY, TRUE);) + UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE)); + VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE)); cs_addrs->nl->in_crit = 0; cs_addrs->hold_onto_crit = FALSE; /* reset this just before cs_addrs->now_crit is reset */ cs_addrs->now_crit = FALSE; diff --git a/sr_port/dse_b_dmp.c b/sr_port/dse_b_dmp.c index 0e66182..a44d044 100644 --- a/sr_port/dse_b_dmp.c +++ b/sr_port/dse_b_dmp.c @@ -121,7 +121,7 @@ boolean_t dse_b_dmp(void) util_len += i2hexl_nofill(((blk_hdr_ptr_t)bp)->tn, &util_buff[util_len], 16); memcpy(&util_buff[util_len], " ", 1); util_len++; - ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV5); + ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV6); len = STRLEN(gtm_dbversion_table[ondsk_blkver]); memcpy(&util_buff[util_len], gtm_dbversion_table[ondsk_blkver], len); util_len += len; @@ -183,7 +183,7 @@ boolean_t dse_b_dmp(void) util_len += i2hexl_nofill(((blk_hdr_ptr_t)bp)->tn, &util_buff[util_len], 16); memcpy(&util_buff[util_len], " ", 1); util_len++; - ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV5); + ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV6); len = STRLEN(gtm_dbversion_table[ondsk_blkver]); memcpy(&util_buff[util_len], gtm_dbversion_table[ondsk_blkver], len); util_len += len; diff --git a/sr_port/dse_cache.c b/sr_port/dse_cache.c index 65fb2b2..9d452de 100644 --- a/sr_port/dse_cache.c +++ b/sr_port/dse_cache.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,6 +29,9 @@ #include "op.h" /* for op_fnzdate and op_horolog prototype */ #include "wcs_recover.h" /* for wcs_recover prototype */ #include "wcs_phase2_commit_wait.h" +#include "sleep_cnt.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ +#include "memcoherency.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ +#include "wcs_sleep.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ GBLREF gd_region *gv_cur_region; GBLREF gd_addr *original_header; @@ -42,6 +45,8 @@ error_def(ERR_SIZENOTVALID4); #define RECOVER_DONE "recovery complete (see operator log for details)" #define RECOVER_NOT_APPLIC "recovery not applicable with MM access method" +error_def(ERR_SIZENOTVALID4); + void dse_cache(void) { boolean_t all_present, change_present, recover_present, show_present, verify_present, was_crit, is_clean; @@ -50,13 +55,12 @@ void dse_cache(void) sgmnt_addrs *csa; mval dollarh_mval, zdate_mval; int4 size; - uint4 offset, value, old_value; + uint4 offset, value, old_value, lcnt; char dollarh_buffer[MAXNUMLEN], zdate_buffer[SIZEOF(DSE_DMP_TIME_FMT)]; char temp_str[256], temp_str1[256]; sm_uc_ptr_t chng_ptr; cache_rec_ptr_t cr_que_lo; - mmblk_rec_ptr_t mr_que_lo; - boolean_t is_mm, was_hold_onto_crit; + boolean_t is_mm, was_hold_onto_crit, wc_blocked_ok; all_present = (CLI_PRESENT == cli_present("ALL")); @@ -78,7 +82,7 @@ void dse_cache(void) if (!cli_get_int("SIZE", &size)) return; if (!((SIZEOF(char) == size) || (SIZEOF(short) == size) || (SIZEOF(int4) == size))) - rts_error(VARLSTCNT(1) ERR_SIZENOTVALID4); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SIZENOTVALID4); } if (value_present && !cli_get_hex("VALUE", &value)) return; @@ -98,23 +102,33 @@ void dse_cache(void) { GET_CURR_TIME_IN_DOLLARH_AND_ZDATE(dollarh_mval, dollarh_buffer, zdate_mval, zdate_buffer); if (verify_present) - { /* Before invoking wcs_verify, wait for any pending phase2 commits to finish. - * Need to wait as otherwise ongoing phase2 commits can result in cache verification - * returning FALSE (e.g. due to DBCRERR message indicating that cr->in_tend is non-zero). + { /* Before invoking wcs_verify, wait for any pending phase2 commits to finish. Need to wait as + * otherwise ongoing phase2 commits can result in cache verification returning FALSE (e.g. due to + * DBCRERR message indicating that cr->in_tend is non-zero). + * Also, need to wait for concurrent writers to stop to avoid wcs_verify from incorrectly concluding + * that there is a problem with the active queue. */ + wc_blocked_ok = UNIX_ONLY(TRUE) VMS_ONLY(!is_mm); /* MM on VMS doesn't support wcs_recvoer */ + if (wc_blocked_ok) + SIGNAL_WRITERS_TO_STOP(csa->nl); /* done sooner to avoid any new writers starting up */ if (csa->nl->wcs_phase2_commit_pidcnt && !is_mm) { /* No need to check return value since even if it fails, we want to do cache verification */ wcs_phase2_commit_wait(csa, NULL); } - is_clean = wcs_verify(reg, TRUE, FALSE); /* expect_damage is TRUE, caller_is_wcs_recover is FALSE */ + if (wc_blocked_ok) + WAIT_FOR_WRITERS_TO_STOP(csa->nl, lcnt, MAXWTSTARTWAIT / 4); /* reduced wait time for DSE */ + is_clean = wcs_verify(reg, FALSE, FALSE); /* expect_damage is FALSE, caller_is_wcs_recover is + * FALSE */ + if (wc_blocked_ok) + SIGNAL_WRITERS_TO_RESUME(csa->nl); } else { if (UNIX_ONLY(TRUE)VMS_ONLY(!is_mm)) { - SET_TRACEABLE_VAR(csa->hdr->wc_blocked, TRUE); + SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); /* No need to invoke function "wcs_phase2_commit_wait" as "wcs_recover" does that anyways */ wcs_recover(reg); - assert(FALSE == csa->hdr->wc_blocked); /* wcs_recover() should have cleared this */ + assert(FALSE == csa->nl->wc_blocked); /* wcs_recover() should have cleared this */ } } assert(20 == STR_LIT_LEN(DSE_DMP_TIME_FMT)); /* if they are not the same, the !20AD below should change */ @@ -212,14 +226,6 @@ void dse_cache(void) TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE)); } else { - util_out_print("Region !AD : mmblk_state = 0x!XJ", - TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->acc_meth.mm.mmblk_state)); - mr_que_lo = &csa->acc_meth.mm.mmblk_state->mmblk_array[0]; - util_out_print("Region !AD : mmblk_que_header = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", - TRUE, REG_LEN_STR(reg), DB_ABS2REL(mr_que_lo), csa->hdr->bt_buckets, SIZEOF(mmblk_rec)); - util_out_print("Region !AD : mm_cache_record = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", - TRUE, REG_LEN_STR(reg), DB_ABS2REL(mr_que_lo + csa->hdr->bt_buckets), csa->hdr->n_bts, - SIZEOF(mmblk_rec)); util_out_print("Region !AD : shared_memory_size = 0x!XL", TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE)); util_out_print("Region !AD : db_file_header = 0x!XJ", TRUE, REG_LEN_STR(reg), csa->hdr); diff --git a/sr_port/dse_chng_bhead.c b/sr_port/dse_chng_bhead.c index 867b8b5..fd35dca 100644 --- a/sr_port/dse_chng_bhead.c +++ b/sr_port/dse_chng_bhead.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,6 +42,9 @@ #include "util.h" #include "t_abort.h" #include "gvcst_blk_build.h" /* for the BUILD_AIMG_IF_JNL_ENABLED macro */ +#ifdef GTM_CRYPT +#include "gtmcrypt.h" +#endif GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; @@ -53,7 +56,6 @@ GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF cache_rec *cr_array[((MAX_BT_DEPTH * 2) - 1) * 2]; /* Maximum number of blocks that can be in transaction */ GBLREF boolean_t unhandled_stale_timer_pop; -GBLREF unsigned char *non_tp_jfb_buff_ptr; GBLREF cw_set_element cw_set[]; error_def(ERR_DSEBLKRDFAIL); @@ -79,8 +81,9 @@ void dse_chng_bhead(void) sgmnt_data_ptr_t csd; # ifdef GTM_CRYPT int req_enc_blk_size; - int crypt_status; + int gtmcrypt_errno; blk_hdr_ptr_t bp, save_bp, save_old_block; + gd_segment *seg; # endif if (gv_cur_region->read_only) @@ -172,7 +175,7 @@ void dse_chng_bhead(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, new_hdr.levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, csa->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); } if (cli_present("TN") == CLI_PRESENT) @@ -199,7 +202,7 @@ void dse_chng_bhead(void) t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)blkhist.buffaddr)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); /* Pass the desired tn as argument to bg_update/mm_update below */ - BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, tn); + BUILD_AIMG_IF_JNL_ENABLED(csd, tn); was_hold_onto_crit = csa->hold_onto_crit; csa->hold_onto_crit = TRUE; /* need this so t_end doesn't release crit (see below comment for why) */ t_end(&dummy_hist, NULL, tn); @@ -237,10 +240,13 @@ void dse_chng_bhead(void) { ASSERT_ENCRYPTION_INITIALIZED; memcpy(save_bp, bp, SIZEOF(blk_hdr)); - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, (char *)(bp + 1), req_enc_blk_size, - (char *)(save_bp + 1), crypt_status); - if (0 != crypt_status) - GC_GTM_PUTMSG(crypt_status, gv_cur_region->dyn.addr->fname); + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, (char *)(bp + 1), req_enc_blk_size, + (char *)(save_bp + 1), gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + } } else memcpy(save_bp, bp, bp->bsiz); } diff --git a/sr_port/dse_chng_fhead.c b/sr_port/dse_chng_fhead.c index 20cdaee..595a54f 100644 --- a/sr_port/dse_chng_fhead.c +++ b/sr_port/dse_chng_fhead.c @@ -51,6 +51,7 @@ GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data *cs_data; GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; GBLREF uint4 image_count; @@ -64,9 +65,9 @@ error_def(ERR_FREEZECTRL); void dse_chng_fhead(void) { - int4 x, index_x, save_x; + int4 x, index_x, save_x, fname_len; unsigned short buf_len; - boolean_t was_crit, was_hold_onto_crit; + boolean_t was_crit, was_hold_onto_crit, corrupt_file_present; boolean_t override = FALSE; int4 nocrit_present; int4 location_present, value_present, size_present, size; @@ -75,34 +76,40 @@ void dse_chng_fhead(void) gtm_uint64_t value, old_value; seq_num seq_no; trans_num tn, prev_tn, max_tn_old, max_tn_warn_old, curr_tn_old, max_tn_new, max_tn_warn_new, curr_tn_new; - char temp_str[256], temp_str1[256], buf[MAX_LINE]; + char temp_str[256], temp_str1[256], buf[MAX_LINE], *fname_ptr; int gethostname_res; sm_uc_ptr_t chng_ptr; const char *freeze_msg[] = { "UNFROZEN", "FROZEN" } ; - GTMCRYPT_ONLY( - char hash_buff[GTMCRYPT_HASH_LEN]; - int crypt_status; - ) +# ifdef GTM_CRYPT + char hash_buff[GTMCRYPT_HASH_LEN]; + int gtmcrypt_errno; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); - memset(temp_str, 0, 256); memset(temp_str1, 0, 256); memset(buf, 0, MAX_LINE); was_crit = cs_addrs->now_crit; + /* If the user requested DSE CHANGE -FILE -CORRUPT, then skip the check in grab_crit, which triggers an rts_error, as this + * is one of the ways of turning off the file_corrupt flag in the file header + */ + TREF(skip_file_corrupt_check) = corrupt_file_present = (CLI_PRESENT == cli_present("CORRUPT_FILE")); nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); + TREF(skip_file_corrupt_check) = FALSE; /* Now that grab_crit is done, reset the global variable */ if (CLI_PRESENT == cli_present("OVERRIDE")) override = TRUE; -#ifdef VMS - if (cs_addrs->hdr->freeze && (cs_addrs->hdr->freeze != process_id || - cs_addrs->hdr->image_count != image_count) && !override) -#endif -#ifdef UNIX - if (cs_addrs->hdr->freeze && (cs_addrs->hdr->image_count != process_id) +# ifdef VMS + if (cs_data->freeze && (cs_data->freeze != process_id || + cs_data->image_count != image_count) && !override) +# endif +# ifdef UNIX + if (cs_data->freeze && (cs_data->image_count != process_id) && !override) -#endif +# endif { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); util_out_print("Region: !AD is frozen by another user, not releasing freeze.", @@ -196,7 +203,7 @@ void dse_chng_fhead(void) TRUE, location, location, size, size); else { - chng_ptr = (sm_uc_ptr_t)cs_addrs->hdr + location; + chng_ptr = (sm_uc_ptr_t)cs_data + location; if (SIZEOF(char) == size) { SPRINTF(temp_str, "!UB [0x!XB]"); @@ -246,21 +253,23 @@ void dse_chng_fhead(void) if ((CLI_PRESENT == cli_present("BLK_SIZE")) && (cli_get_int("BLK_SIZE", &x))) { if (!(x % DISK_BLOCK_SIZE) && (0 != x)) - cs_addrs->hdr->blk_size = x; + cs_data->blk_size = x; else { - cs_addrs->hdr->blk_size = ((x/DISK_BLOCK_SIZE) + 1) * DISK_BLOCK_SIZE; - gtm_putmsg(VARLSTCNT(4) ERR_BLKSIZ512, 2, x, cs_addrs->hdr->blk_size); + cs_data->blk_size = ((x/DISK_BLOCK_SIZE) + 1) * DISK_BLOCK_SIZE; + gtm_putmsg(VARLSTCNT(4) ERR_BLKSIZ512, 2, x, cs_data->blk_size); } } if ((CLI_PRESENT == cli_present("RECORD_MAX_SIZE")) && (cli_get_int("RECORD_MAX_SIZE", &x))) { - cs_addrs->hdr->max_rec_size = x; + cs_data->max_rec_size = x; gv_cur_region->max_rec_size = x; } if ((CLI_PRESENT == cli_present("KEY_MAX_SIZE")) && (cli_get_int("KEY_MAX_SIZE", &x))) { - cs_addrs->hdr->max_key_size = x; + if (cs_data->max_key_size > x) + cs_data->maxkeysz_assured = FALSE; + cs_data->max_key_size = x; gv_cur_region->max_key_size = x; } if ((CLI_PRESENT == cli_present("INHIBIT_KILLS")) && (cli_get_int("INHIBIT_KILLS", &x))) @@ -271,21 +280,21 @@ void dse_chng_fhead(void) { x = cli_t_f_n("INTERRUPTED_RECOV"); if (1 == x) - cs_addrs->hdr->recov_interrupted = TRUE; + cs_data->recov_interrupted = TRUE; else if (0 == x) - cs_addrs->hdr->recov_interrupted = FALSE; + cs_data->recov_interrupted = FALSE; } if ((CLI_PRESENT == cli_present("REFERENCE_COUNT")) && (cli_get_int("REFERENCE_COUNT", &x))) cs_addrs->nl->ref_cnt = x; if ((CLI_PRESENT == cli_present("RESERVED_BYTES")) && (cli_get_int("RESERVED_BYTES", &x))) - cs_addrs->hdr->reserved_bytes = x; + cs_data->reserved_bytes = x; if ((CLI_PRESENT == cli_present("DEF_COLLATION")) && (cli_get_int("DEF_COLLATION", &x))) - cs_addrs->hdr->def_coll = x; + cs_data->def_coll = x; if (CLI_PRESENT == cli_present("NULL_SUBSCRIPTS")) { x = cli_n_a_e("NULL_SUBSCRIPTS"); if (-1 != x) - gv_cur_region->null_subs = cs_addrs->hdr->null_subs = (unsigned char)x; + gv_cur_region->null_subs = cs_data->null_subs = (unsigned char)x; } if (CLI_PRESENT == cli_present("CERT_DB_VER")) { @@ -296,7 +305,7 @@ void dse_chng_fhead(void) for (index_x=0; index_x < GDSVLAST ; index_x++) if (0 == STRCMP(buf, gtm_dbversion_table[index_x])) { - cs_addrs->hdr->certified_for_upgrade_to = (enum db_ver)index_x; + cs_data->certified_for_upgrade_to = (enum db_ver)index_x; break; } if (GDSVLAST <= index_x) @@ -312,8 +321,8 @@ void dse_chng_fhead(void) for (index_x=0; index_x < GDSVLAST ; index_x++) if (0 == STRCMP(buf, gtm_dbversion_table[index_x])) { - cs_addrs->hdr->desired_db_format = (enum db_ver)index_x; - cs_addrs->hdr->fully_upgraded = FALSE; + cs_data->desired_db_format = (enum db_ver)index_x; + cs_data->fully_upgraded = FALSE; break; } if (GDSVLAST <= index_x) @@ -321,7 +330,7 @@ void dse_chng_fhead(void) } } /* ---------- Begin ------ CURRENT_TN/MAX_TN/WARN_MAX_TN processing -------- */ - max_tn_old = cs_addrs->hdr->max_tn; + max_tn_old = cs_data->max_tn; if ((CLI_PRESENT == cli_present("MAX_TN")) && (cli_get_hex64("MAX_TN", &max_tn_new))) max_tn_present = TRUE; else @@ -329,7 +338,7 @@ void dse_chng_fhead(void) max_tn_present = FALSE; max_tn_new = max_tn_old; } - max_tn_warn_old = cs_addrs->hdr->max_tn_warn; + max_tn_warn_old = cs_data->max_tn_warn; if ((CLI_PRESENT == cli_present("WARN_MAX_TN")) && (cli_get_hex64("WARN_MAX_TN", &max_tn_warn_new))) max_tn_warn_present = TRUE; else @@ -378,13 +387,13 @@ void dse_chng_fhead(void) if (change_tn) { if (max_tn_present) - cs_addrs->hdr->max_tn = max_tn_new; + cs_data->max_tn = max_tn_new; if (max_tn_warn_present) - cs_addrs->hdr->max_tn_warn = max_tn_warn_new; + cs_data->max_tn_warn = max_tn_warn_new; if (curr_tn_present) cs_addrs->ti->curr_tn = cs_addrs->ti->early_tn = curr_tn_new; - assert(max_tn_new == cs_addrs->hdr->max_tn); - assert(max_tn_warn_new == cs_addrs->hdr->max_tn_warn); + assert(max_tn_new == cs_data->max_tn); + assert(max_tn_warn_new == cs_data->max_tn_warn); assert(curr_tn_new == cs_addrs->ti->curr_tn); assert(max_tn_new >= max_tn_warn_new); assert(max_tn_warn_new >= curr_tn_new); @@ -397,13 +406,13 @@ void dse_chng_fhead(void) if (curr_tn_present) util_out_print("CURRENT_TN value not changed", TRUE); */ - assert(max_tn_old == cs_addrs->hdr->max_tn); - assert(max_tn_warn_old == cs_addrs->hdr->max_tn_warn); + assert(max_tn_old == cs_data->max_tn); + assert(max_tn_warn_old == cs_data->max_tn_warn); assert(curr_tn_old == cs_addrs->ti->curr_tn); } /* ---------- End ------ CURRENT_TN/MAX_TN/WARN_MAX_TN processing -------- */ if (CLI_PRESENT == cli_present("REG_SEQNO") && cli_get_hex64("REG_SEQNO", (gtm_uint64_t *)&seq_no)) - cs_addrs->hdr->reg_seqno = seq_no; + cs_data->reg_seqno = seq_no; UNIX_ONLY( if (CLI_PRESENT == cli_present("STRM_NUM")) { @@ -411,64 +420,64 @@ void dse_chng_fhead(void) if (cli_get_int("STRM_NUM", &x) && (0 <= x) && (MAX_SUPPL_STRMS > x) && (CLI_PRESENT == cli_present("STRM_REG_SEQNO")) && cli_get_hex64("STRM_REG_SEQNO", (gtm_uint64_t *)&seq_no)) - cs_addrs->hdr->strm_reg_seqno[x] = seq_no; + cs_data->strm_reg_seqno[x] = seq_no; } ) VMS_ONLY( if (CLI_PRESENT == cli_present("RESYNC_SEQNO") && cli_get_hex64("RESYNC_SEQNO", (gtm_uint64_t *)&seq_no)) - cs_addrs->hdr->resync_seqno = seq_no; + cs_data->resync_seqno = seq_no; if (CLI_PRESENT == cli_present("RESYNC_TN") && cli_get_hex64("RESYNC_TN", &tn)) - cs_addrs->hdr->resync_tn = tn; + cs_data->resync_tn = tn; ) UNIX_ONLY( if (CLI_PRESENT == cli_present("ZQGBLMOD_SEQNO") && cli_get_hex64("ZQGBLMOD_SEQNO", (gtm_uint64_t *)&seq_no)) - cs_addrs->hdr->zqgblmod_seqno = seq_no; + cs_data->zqgblmod_seqno = seq_no; if (CLI_PRESENT == cli_present("ZQGBLMOD_TN") && cli_get_hex64("ZQGBLMOD_TN", &tn)) - cs_addrs->hdr->zqgblmod_tn = tn; + cs_data->zqgblmod_tn = tn; ) if (CLI_PRESENT == cli_present("STDNULLCOLL")) { if ( -1 != (x = cli_t_f_n("STDNULLCOLL"))) - gv_cur_region->std_null_coll = cs_addrs->hdr->std_null_coll = x; + gv_cur_region->std_null_coll = cs_data->std_null_coll = x; } - if (CLI_PRESENT == cli_present("CORRUPT_FILE")) + if (corrupt_file_present) { x = cli_t_f_n("CORRUPT_FILE"); if (1 == x) - cs_addrs->hdr->file_corrupt = TRUE; + cs_data->file_corrupt = TRUE; else if (0 == x) - cs_addrs->hdr->file_corrupt = FALSE; + cs_data->file_corrupt = FALSE; } if ((CLI_PRESENT == cli_present("TIMERS_PENDING")) && (cli_get_int("TIMERS_PENDING", &x))) cs_addrs->nl->wcs_timers = x - 1; - change_fhead_timer("FLUSH_TIME", cs_addrs->hdr->flush_time, - (dba_bg == cs_addrs->hdr->acc_meth ? TIM_FLU_MOD_BG : TIM_FLU_MOD_MM), FALSE); + change_fhead_timer("FLUSH_TIME", cs_data->flush_time, + (dba_bg == cs_data->acc_meth ? TIM_FLU_MOD_BG : TIM_FLU_MOD_MM), FALSE); if ((CLI_PRESENT == cli_present("WRITES_PER_FLUSH")) && (cli_get_int("WRITES_PER_FLUSH", &x))) - cs_addrs->hdr->n_wrt_per_flu = x; + cs_data->n_wrt_per_flu = x; if ((CLI_PRESENT == cli_present("TRIGGER_FLUSH")) && (cli_get_int("TRIGGER_FLUSH", &x))) - cs_addrs->hdr->flush_trigger = x; + cs_data->flush_trigger = x; if ((CLI_PRESENT == cli_present("GOT2V5ONCE")) && (cli_get_int("GOT2V5ONCE", &x))) - cs_addrs->hdr->db_got_to_v5_once = (boolean_t)x; - change_fhead_timer("STALENESS_TIMER", cs_addrs->hdr->staleness, 5000, TRUE); - change_fhead_timer("TICK_INTERVAL", cs_addrs->hdr->ccp_tick_interval, 100, TRUE); - change_fhead_timer("QUANTUM_INTERVAL", cs_addrs->hdr->ccp_quantum_interval, 1000, FALSE); - change_fhead_timer("RESPONSE_INTERVAL", cs_addrs->hdr->ccp_response_interval, 60000, FALSE); + cs_data->db_got_to_v5_once = (boolean_t)x; + change_fhead_timer("STALENESS_TIMER", cs_data->staleness, 5000, TRUE); + change_fhead_timer("TICK_INTERVAL", cs_data->ccp_tick_interval, 100, TRUE); + change_fhead_timer("QUANTUM_INTERVAL", cs_data->ccp_quantum_interval, 1000, FALSE); + change_fhead_timer("RESPONSE_INTERVAL", cs_data->ccp_response_interval, 60000, FALSE); if ((CLI_PRESENT == cli_present("B_BYTESTREAM")) && (cli_get_hex64("B_BYTESTREAM", &tn))) - cs_addrs->hdr->last_inc_backup = tn; + cs_data->last_inc_backup = tn; if ((CLI_PRESENT == cli_present("B_COMPREHENSIVE")) && (cli_get_hex64("B_COMPREHENSIVE", &tn))) - cs_addrs->hdr->last_com_backup = tn; + cs_data->last_com_backup = tn; if ((CLI_PRESENT == cli_present("B_DATABASE")) && (cli_get_hex64("B_DATABASE", &tn))) - cs_addrs->hdr->last_com_backup = tn; + cs_data->last_com_backup = tn; if ((CLI_PRESENT == cli_present("B_INCREMENTAL")) && (cli_get_hex64("B_INCREMENTAL", &tn))) - cs_addrs->hdr->last_inc_backup = tn; + cs_data->last_inc_backup = tn; if ((CLI_PRESENT == cli_present("WAIT_DISK")) && (cli_get_int("WAIT_DISK", &x))) - cs_addrs->hdr->wait_disk_space = (x >= 0 ? x : 0); + cs_data->wait_disk_space = (x >= 0 ? x : 0); if (((CLI_PRESENT == cli_present("HARD_SPIN_COUNT")) && cli_get_int("HARD_SPIN_COUNT", &x)) UNIX_ONLY( || ((CLI_PRESENT == cli_present("MUTEX_HARD_SPIN_COUNT")) && cli_get_int("MUTEX_HARD_SPIN_COUNT", &x))) ) /* Unix should be backward compatible, accept MUTEX_ prefix qualifiers as well */ { if (0 < x) - cs_addrs->hdr->mutex_spin_parms.mutex_hard_spin_count = x; + cs_data->mutex_spin_parms.mutex_hard_spin_count = x; else util_out_print("Error: HARD SPIN COUNT should be a non zero positive number", TRUE); } @@ -477,7 +486,7 @@ void dse_chng_fhead(void) ) /* Unix should be backward compatible, accept MUTEX_ prefix qualifiers as well */ { if (0 < x) - cs_addrs->hdr->mutex_spin_parms.mutex_sleep_spin_count = x; + cs_data->mutex_spin_parms.mutex_sleep_spin_count = x; else util_out_print("Error: SLEEP SPIN COUNT should be a non zero positive number", TRUE); } @@ -500,38 +509,38 @@ void dse_chng_fhead(void) if (x > 999999) util_out_print("Error: SPIN SLEEP TIME should be less than one million micro seconds", TRUE); else - cs_addrs->hdr->mutex_spin_parms.mutex_spin_sleep_mask = x; + cs_data->mutex_spin_parms.mutex_spin_sleep_mask = x; } } UNIX_ONLY( if ((CLI_PRESENT == cli_present("COMMITWAIT_SPIN_COUNT")) && cli_get_int("COMMITWAIT_SPIN_COUNT", &x)) { if (0 <= x) - cs_addrs->hdr->wcs_phase2_commit_wait_spincnt = x; + cs_data->wcs_phase2_commit_wait_spincnt = x; else util_out_print("Error: COMMITWAIT SPIN COUNT should be a positive number", TRUE); } ) if ((CLI_PRESENT == cli_present("B_RECORD")) && (cli_get_hex64("B_RECORD", &tn))) - cs_addrs->hdr->last_rec_backup = tn; + cs_data->last_rec_backup = tn; if ((CLI_PRESENT == cli_present("BLKS_TO_UPGRADE")) && (cli_get_hex("BLKS_TO_UPGRADE", (uint4 *)&x))) { - cs_addrs->hdr->blks_to_upgrd = x; - cs_addrs->hdr->fully_upgraded = FALSE; + cs_data->blks_to_upgrd = x; + cs_data->fully_upgraded = FALSE; } if ((CLI_PRESENT == cli_present("MBM_SIZE")) && (cli_get_int("MBM_SIZE", &x))) - cs_addrs->hdr->master_map_len = x * DISK_BLOCK_SIZE; - if (cs_addrs->hdr->clustered) + cs_data->master_map_len = x * DISK_BLOCK_SIZE; + if (cs_data->clustered) { if (cs_addrs->ti->curr_tn == prev_tn) { - CHECK_TN(cs_addrs, cs_addrs->hdr, cs_addrs->ti->curr_tn);/* can issue rts_error TNTOOLARGE */ + CHECK_TN(cs_addrs, cs_data, cs_addrs->ti->curr_tn);/* can issue rts_error TNTOOLARGE */ cs_addrs->ti->early_tn++; - INCREMENT_CURR_TN(cs_addrs->hdr); + INCREMENT_CURR_TN(cs_data); } } if ((CLI_PRESENT == cli_present("RC_SRV_COUNT")) && (cli_get_int("RC_SRV_COUNT", &x))) - cs_addrs->hdr->rc_srv_cnt = x; + cs_data->rc_srv_cnt = x; if (CLI_PRESENT == cli_present("FREEZE")) { x = cli_t_f_n("FREEZE"); @@ -556,15 +565,15 @@ void dse_chng_fhead(void) } } - if (x != !(cs_addrs->hdr->freeze)) + if (x != !(cs_data->freeze)) util_out_print("Region !AD is now !AD", TRUE, REG_LEN_STR(gv_cur_region), LEN_AND_STR(freeze_msg[x])); cs_addrs->persistent_freeze = x; /* secshr_db_clnup() shouldn't clear the freeze up */ } if (CLI_PRESENT == cli_present("FULLY_UPGRADED") && cli_get_int("FULLY_UPGRADED", &x)) { - cs_addrs->hdr->fully_upgraded = (boolean_t)x; + cs_data->fully_upgraded = (boolean_t)x; if (x) - cs_addrs->hdr->db_got_to_v5_once = TRUE; + cs_data->db_got_to_v5_once = TRUE; } if (CLI_PRESENT == cli_present("GVSTATSRESET")) { @@ -607,7 +616,7 @@ void dse_chng_fhead(void) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "NONE")) - cs_addrs->hdr->abandoned_kills = 0; + cs_data->abandoned_kills = 0; else { if (('0' == buf[0]) && ('\0' == buf[1])) @@ -621,7 +630,7 @@ void dse_chng_fhead(void) if (0 > x) util_out_print("Invalid value for abandoned_kills qualifier", TRUE); else - cs_addrs->hdr->abandoned_kills = x; + cs_data->abandoned_kills = x; } } } @@ -632,7 +641,7 @@ void dse_chng_fhead(void) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "NONE")) - cs_addrs->hdr->kill_in_prog = 0; + cs_data->kill_in_prog = 0; else { if (('0' == buf[0]) && ('\0' == buf[1])) @@ -646,7 +655,7 @@ void dse_chng_fhead(void) if (0 > x) util_out_print("Invalid value for kill_in_prog qualifier", TRUE); else - cs_addrs->hdr->kill_in_prog = x; + cs_data->kill_in_prog = x; } } } @@ -658,11 +667,11 @@ void dse_chng_fhead(void) lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "CURRENT")) { - memset(cs_addrs->hdr->machine_name, 0, MAX_MCNAMELEN); - GETHOSTNAME(cs_addrs->hdr->machine_name, MAX_MCNAMELEN, gethostname_res); + memset(cs_data->machine_name, 0, MAX_MCNAMELEN); + GETHOSTNAME(cs_data->machine_name, MAX_MCNAMELEN, gethostname_res); } else if (0 == STRCMP(buf, "CLEAR")) - memset(cs_addrs->hdr->machine_name, 0, MAX_MCNAMELEN); + memset(cs_data->machine_name, 0, MAX_MCNAMELEN); else util_out_print("Invalid value for the machine_name qualifier", TRUE); } else @@ -672,42 +681,28 @@ void dse_chng_fhead(void) # ifdef GTM_CRYPT if (CLI_PRESENT == cli_present("ENCRYPTION_HASH")) { - /* It could be possible that when the user is trying to change the encryption hash in the file header, - * more than one process is accessing the database. In such a case, changing the hash might affect the - * running processes. So warn the user about the potential consequence and return. */ if (1 < cs_addrs->nl->ref_cnt) { - util_out_print("Cannot reset encryption hash in file header while !XL other processes are \ - accessing the database.", + util_out_print("Cannot reset encryption hash in file header while !XL other processes are " + "accessing the database.", TRUE, cs_addrs->nl->ref_cnt - 1); return; } - ASSERT_ENCRYPTION_INITIALIZED; /* assert that encryption is already initialized in db_init */ - - /* It is possible that the encryption hash in the database file header is corrupted and we are trying to - * reset it here. But for that to happen, GTMCRYPT_HASH_GEN should not worry about the error happened in - * db_init (unless the encryption library failed due to dlopen error as this would mean that the function - * pointers for the encryption APIs would not be initialized to a proper value and we would end up not - * reporting error). So, the below macro resets the error only if it was not caused due to a dlopen error. */ - GTMCRYPT_RESET_HASH_MISMATCH_ERR; - + fname_ptr = (char *)gv_cur_region->dyn.addr->fname; + fname_len = gv_cur_region->dyn.addr->fname_len; + ASSERT_ENCRYPTION_INITIALIZED; /* Now generate the new hash to be placed in the database file header. */ - GTMCRYPT_HASH_GEN((char *)gv_cur_region->dyn.addr->fname, - gv_cur_region->dyn.addr->fname_len, - hash_buff, - crypt_status); - if (0 != crypt_status) - GC_GTM_PUTMSG(crypt_status, gv_cur_region->dyn.addr->fname); - memcpy(cs_addrs->hdr->encryption_hash, hash_buff, GTMCRYPT_HASH_LEN); - DEBUG_ONLY( - GTMCRYPT_HASH_CHK(cs_addrs->hdr->encryption_hash, crypt_status); - assert(0 == crypt_status); - ) + GTMCRYPT_HASH_GEN(cs_addrs, fname_ptr, fname_len, hash_buff, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, fname_len, fname_ptr); + memcpy(cs_data->encryption_hash, hash_buff, GTMCRYPT_HASH_LEN); + DEBUG_ONLY(GTMCRYPT_HASH_CHK(cs_addrs, cs_data->encryption_hash, gtmcrypt_errno)); + assert(0 == gtmcrypt_errno); } # endif -#ifdef UNIX +# ifdef UNIX if (CLI_PRESENT == cli_present("JNL_YIELD_LIMIT") && cli_get_int("JNL_YIELD_LIMIT", &x)) { if (0 > x) @@ -715,44 +710,56 @@ void dse_chng_fhead(void) else if (MAX_YIELD_LIMIT < x) util_out_print("YIELD_LIMIT cannot be greater than !UL", TRUE, MAX_YIELD_LIMIT); else - cs_addrs->hdr->yield_lmt = x; + cs_data->yield_lmt = x; } -#endif + if (CLI_PRESENT == cli_present("QDBRUNDOWN")) + { + cs_data->mumps_can_bypass = TRUE; + util_out_print("Database file !AD now has quick database rundown flag set to TRUE", TRUE, + DB_LEN_STR(gv_cur_region)); + } + else if (CLI_NEGATED == cli_present("QDBRUNDOWN")) + { + cs_data->mumps_can_bypass = FALSE; + util_out_print("Database file !AD now has quick database rundown flag set to FALSE", TRUE, + DB_LEN_STR(gv_cur_region)); + } +# endif if (CLI_PRESENT == cli_present(UNIX_ONLY("JNL_SYNCIO") VMS_ONLY("JNL_CACHE"))) { x = cli_t_f_n(UNIX_ONLY("JNL_SYNCIO") VMS_ONLY("JNL_CACHE")); if (1 == x) - cs_addrs->hdr->jnl_sync_io = UNIX_ONLY(TRUE) VMS_ONLY(FALSE); + cs_data->jnl_sync_io = UNIX_ONLY(TRUE) VMS_ONLY(FALSE); else if (0 == x) - cs_addrs->hdr->jnl_sync_io = UNIX_ONLY(FALSE) VMS_ONLY(TRUE); + cs_data->jnl_sync_io = UNIX_ONLY(FALSE) VMS_ONLY(TRUE); } if ((CLI_PRESENT == cli_present("AVG_BLKS_READ")) && (cli_get_int("AVG_BLKS_READ", &x))) { if (x <= 0) util_out_print("Invalid value for AVG_BLKS_READ qualifier", TRUE); else - cs_addrs->hdr->avg_blks_per_100gbl = x; + cs_data->avg_blks_per_100gbl = x; } if ((CLI_PRESENT == cli_present("PRE_READ_TRIGGER_FACTOR")) && (cli_get_int("PRE_READ_TRIGGER_FACTOR", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for PRE_READ_TRIGGER_FACTOR qualifier", TRUE); else - cs_addrs->hdr->pre_read_trigger_factor = x; + cs_data->pre_read_trigger_factor = x; } if ((CLI_PRESENT == cli_present("UPD_RESERVED_AREA")) && (cli_get_int("UPD_RESERVED_AREA", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for UPD_RESERVED_AREA qualifier", TRUE); else - cs_addrs->hdr->reserved_for_upd = x; + cs_data->reserved_for_upd = x; } if ((CLI_PRESENT == cli_present("UPD_WRITER_TRIGGER_FACTOR")) && (cli_get_int("UPD_WRITER_TRIGGER_FACTOR", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for UPD_WRITER_TRIGGER_FACTOR qualifier", TRUE); else - cs_addrs->hdr->writer_trigger_factor = x; + cs_data->writer_trigger_factor = x; } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; diff --git a/sr_port/dse_chng_rhead.c b/sr_port/dse_chng_rhead.c index 7fea02c..bdab67e 100644 --- a/sr_port/dse_chng_rhead.c +++ b/sr_port/dse_chng_rhead.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,12 +42,11 @@ GBLREF gd_region *gv_cur_region; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF block_id patch_curr_blk; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; void dse_chng_rhead(void) { @@ -58,6 +57,7 @@ void dse_chng_rhead(void) uint4 x; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; + int tmp_cmpc; srch_blk_status blkhist; error_def(ERR_DBRDONLY); @@ -102,7 +102,7 @@ void dse_chng_rhead(void) return; } GET_SHORT(new_rec.rsiz, &((rec_hdr_ptr_t)rp)->rsiz); - new_rec.cmpc = ((rec_hdr_ptr_t)rp)->cmpc; + SET_CMPC(&new_rec, EVAL_CMPC((rec_hdr_ptr_t)rp)); if (cli_present("CMPC") == CLI_PRESENT) { if (!cli_get_hex("CMPC", &x)) @@ -110,7 +110,7 @@ void dse_chng_rhead(void) t_abort(gv_cur_region, cs_addrs); return; } - if (x > 0x7f) + if (x >= MAX_KEY_SZ) { util_out_print("Error: invalid cmpc.",TRUE); t_abort(gv_cur_region, cs_addrs); @@ -118,7 +118,7 @@ void dse_chng_rhead(void) } if (x > patch_comp_count) util_out_print("Warning: specified compression count is larger than the current expanded key size.", TRUE); - new_rec.cmpc = x; + SET_CMPC(&new_rec, x); chng_rec = TRUE; } if (cli_present("RSIZ") == CLI_PRESENT) @@ -157,7 +157,7 @@ void dse_chng_rhead(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); } return; diff --git a/sr_port/dse_crit.c b/sr_port/dse_crit.c index 319e690..5010c56 100644 --- a/sr_port/dse_crit.c +++ b/sr_port/dse_crit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -94,8 +94,8 @@ void dse_crit(void) if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); cs_addrs->hdr->image_count = 0; - UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY, crash);) - VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY, crash);) + UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), crash)); + VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), crash)); cs_addrs->nl->in_crit = 0; cs_addrs->now_crit = FALSE; util_out_print("!/Reinitialized critical section.!/", TRUE); diff --git a/sr_port/dse_dmp_fhead.c b/sr_port/dse_dmp_fhead.c index 3b3c6f8..095c8a0 100644 --- a/sr_port/dse_dmp_fhead.c +++ b/sr_port/dse_dmp_fhead.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -230,9 +230,7 @@ void dse_dmp_fhead (void) /* Mutex Stuff */ util_out_print(" Mutex Hard Spin Count !19UL", FALSE, csd->mutex_spin_parms.mutex_hard_spin_count); util_out_print(" Mutex Sleep Spin Count!12UL", TRUE, csd->mutex_spin_parms.mutex_sleep_spin_count); - util_out_print(" Mutex Spin Sleep Time !19UL", FALSE, - (csd->mutex_spin_parms.mutex_spin_sleep_mask == 0) ? - 0 : (csd->mutex_spin_parms.mutex_spin_sleep_mask + 1)); + util_out_print(" Mutex Queue Slots !19UL", FALSE, NUM_CRIT_ENTRY(csd)); util_out_print(" KILLs in progress !12UL", TRUE, (csd->kill_in_prog + csd->abandoned_kills)); util_out_print(" Replication State !AD", FALSE, 13, (csd->repl_state == repl_closed ? " OFF" @@ -250,7 +248,17 @@ void dse_dmp_fhead (void) UNIX_ONLY( util_out_print(" Commit Wait Spin Count!12UL", TRUE, csd->wcs_phase2_commit_wait_spincnt); ) - util_out_print(" Database file encrypted !AD", TRUE, 5, csd->is_encrypted ? " TRUE" : "FALSE"); + util_out_print(" Database file encrypted !AD", UNIX_ONLY(FALSE) VMS_ONLY(TRUE), 5, + csd->is_encrypted ? " TRUE" : "FALSE"); + UNIX_ONLY( + util_out_print(" Inst Freeze on Error !AD", TRUE, 5, csd->freeze_on_fail ? " TRUE" : "FALSE"); + ) + UNIX_ONLY( + util_out_print(" Spanning Node Absent !AD", FALSE, 5, csd->span_node_absent ? " TRUE" : "FALSE"); + ) + UNIX_ONLY( + util_out_print(" Maximum Key Size Assured !AD", TRUE, 5, csd->maxkeysz_assured ? " TRUE" : "FALSE"); + ) } if (CLI_PRESENT == cli_present("ALL")) { /* Only dump if -/ALL as if part of above display */ @@ -271,8 +279,14 @@ void dse_dmp_fhead (void) util_out_print(" Write cache timer count 0x!XL", TRUE, cnl->wcs_timers); util_out_print(" Free Global Buffers 0x!XL", FALSE, cnl->wc_in_free); util_out_print(" wcs_wtstart pid count 0x!XL", TRUE, cnl->in_wtstart); - util_out_print(" Write Cache is Blocked !AD", FALSE, 5, (csd->wc_blocked ? " TRUE" : "FALSE")); + util_out_print(" Write Cache is Blocked !AD", FALSE, 5, (cnl->wc_blocked ? " TRUE" : "FALSE")); util_out_print(" wcs_wtstart intent cnt 0x!XL", TRUE, cnl->intent_wtstart); +# ifdef UNIX + util_out_print(0, TRUE); + util_out_print(" Quick database rundown is active !AD", TRUE, 5, (csd->mumps_can_bypass ? " TRUE" : "FALSE")); + util_out_print(" Access control rundown bypasses !9UL", FALSE, cnl->dbrndwn_access_skip); + util_out_print(" FTOK rundown bypasses !10UL", TRUE, cnl->dbrndwn_ftok_skip); +# endif new_line = FALSE; for (index = 0; MAX_WTSTART_PID_SLOTS > index; index++) { diff --git a/sr_port/dse_f_key.c b/sr_port/dse_f_key.c index 82ec321..fc83eb1 100644 --- a/sr_port/dse_f_key.c +++ b/sr_port/dse_f_key.c @@ -38,7 +38,7 @@ void dse_f_key(void) int size, size_root, root_path_count, count, util_len; boolean_t found, was_crit, was_hold_onto_crit; - if (!dse_getki(&targ_key[0],&size,LIT_AND_LEN("KEY"))) + if (!dse_getki(&targ_key[0], &size, LIT_AND_LEN("KEY"))) return; patch_path_count = 1; root_path[0] = get_dir_root(); @@ -52,7 +52,7 @@ void dse_f_key(void) was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); - if (!dse_ksrch(root_path[0],&root_path[1],&root_offset[0],&targ_key_root[0],size_root)) + if (!dse_key_srch(root_path[0], &root_path[1], &root_offset[0], &targ_key_root[0], size_root)) { util_out_print("!/Key not found, no root present.!/",TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); @@ -62,7 +62,7 @@ void dse_f_key(void) patch_path_count = 1; path[0] = ksrch_root; patch_find_root_search = FALSE; - if (!dse_ksrch(path[0],&path[1],&offset[0],&targ_key[0],size)) + if (!dse_key_srch(path[0], &path[1], &offset[0], &targ_key[0], size)) { memcpy(util_buff,"!/Key not found, would be in block ",36); util_len = 36; util_len += i2hex_nofill(path[patch_path_count - 2], (uchar_ptr_t)&util_buff[util_len], 8); diff --git a/sr_port/dse_f_reg.c b/sr_port/dse_f_reg.c index 2b52473..4053022 100644 --- a/sr_port/dse_f_reg.c +++ b/sr_port/dse_f_reg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,6 +33,8 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; GBLREF mval dollar_zgbldir; GBLREF gd_addr *original_header; +GBLREF gv_namehead *gv_target; +GBLREF gv_key *gv_currkey; void dse_f_reg(void) { @@ -62,19 +64,19 @@ void dse_f_reg(void) gd_header = temp_gdaddr; return; } - assert (rn[0]); - - found = FALSE; - for (i=0, ptr = gd_header->regions; i < gd_header->n_regions ;i++, ptr++) - if (found = !memcmp(&ptr->rname[0],&rn[0],MAX_RN_LEN)) - break; - if (!found) - { - util_out_print("Error: region not found.",TRUE); - gd_header = temp_gdaddr; - return; - } - + assert(rn[0]); + found = FALSE; + for (i=0, ptr = gd_header->regions; i < gd_header->n_regions ;i++, ptr++) + { + if (found = !memcmp(&ptr->rname[0],&rn[0],MAX_RN_LEN)) + break; + } + if (!found) + { + util_out_print("Error: region not found.",TRUE); + gd_header = temp_gdaddr; + return; + } if (ptr == gv_cur_region) { util_out_print("Error: already in region: !AD",TRUE,REG_LEN_STR(gv_cur_region)); @@ -99,12 +101,17 @@ void dse_f_reg(void) gd_header = temp_gdaddr; return; } - - if (cs_addrs->now_crit == TRUE) + if (TRUE == cs_addrs->now_crit) + { util_out_print("Warning: now leaving region in critical section: !AD",TRUE, gv_cur_region->rname_len, gv_cur_region->rname); - + } gv_cur_region = ptr; + gv_target = NULL; /* to prevent out-of-sync situations between gv_target and cs_addrs */ + gv_currkey->base[0] = '\0'; /* prevent fast-path from op_gvname from being taken as region has been switched + * and gv_target has been reset to NULL. + */ + gv_currkey->end = 0; /* clear end so it is in sync with base[0] */ switch (gv_cur_region->dyn.addr->acc_meth) { case dba_mm: @@ -115,13 +122,10 @@ void dse_f_reg(void) default: GTMASSERT; } - if (cs_addrs && cs_addrs->critical) - { crash_count = cs_addrs->critical->crashcnt; - } + crash_count = cs_addrs->critical->crashcnt; util_out_print("!/File !_!AD",TRUE, DB_LEN_STR(gv_cur_region)); util_out_print("Region!_!AD!/",TRUE, REG_LEN_STR(gv_cur_region)); - patch_curr_blk = get_dir_root(); gv_init_reg(gv_cur_region); GET_SAVED_GDADDR(gd_header, temp_gdaddr, map, gv_cur_region); diff --git a/sr_port/dse_fdmp.c b/sr_port/dse_fdmp.c index 19252eb..f1ee782 100644 --- a/sr_port/dse_fdmp.c +++ b/sr_port/dse_fdmp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,8 +11,8 @@ #include "mdef.h" #include "gtm_string.h" - #include "mlkdef.h" + #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" @@ -22,8 +22,27 @@ #include "cli.h" #include "dse.h" #include "gvsub2str.h" +#include "gdsblk.h" #include "zshow.h" +#define COUNT_TRAILING_ZERO(NUM, WCP, TRAIL_ZERO) \ +{ \ + if (0 == NUM) \ + *WCP++ = '0'; \ + for (TRAIL_ZERO = 0; (NUM > 0) && (0 == (NUM % 10)); TRAIL_ZERO++, NUM /= 10) \ + ; \ +} + +#define OUTPUT_NUMBER(NUM, WCP, TRAIL_ZERO) \ +{ \ + for (rev_num = 0; NUM > 0; rev_num = (rev_num * 10 + NUM % 10), NUM /= 10) \ + ; \ + for (; rev_num > 0; *WCP++ = (rev_num % 10 + ASCII_0), rev_num /= 10) \ + ; \ + for (; TRAIL_ZERO > 0 ; *WCP++ = '0', TRAIL_ZERO--) \ + ; \ +} + GBLREF enum dse_fmt dse_dmp_format; GBLREF gd_region *gv_cur_region; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; @@ -35,6 +54,11 @@ boolean_t dse_fdmp(sm_uc_ptr_t data, int len) { unsigned char *key_char_ptr, *work_char_ptr; int dest_len; + unsigned char *ret_addr; + boolean_t is_snblk=FALSE; + span_subs *ss_ptr; /*spanning node key pointer */ + unsigned int snbid, offset, trail_zero, rev_num, num; + unsigned short blk_sz; if (work_buff_length < ZWR_EXP_RATIO(gv_cur_region->max_rec_size)) { @@ -53,7 +77,7 @@ boolean_t dse_fdmp(sm_uc_ptr_t data, int len) return FALSE; } key_char_ptr++; - if (*key_char_ptr) + if (SPAN_START_BYTE != *key_char_ptr) /*Global has subscript*/ { *work_char_ptr++ = '('; for (;;) @@ -67,12 +91,54 @@ boolean_t dse_fdmp(sm_uc_ptr_t data, int len) for (; *key_char_ptr ; key_char_ptr++) ; key_char_ptr++; + /* Check if this is spanning node if yes break out of the loop */ + if (SPAN_START_BYTE == *key_char_ptr + && (int)*(key_char_ptr + 1) >= SPAN_BYTE_MIN + && (int)*(key_char_ptr + 2) >= SPAN_BYTE_MIN) + { + is_snblk = TRUE; + break; + } if (*key_char_ptr) *work_char_ptr++ = ','; else break; } *work_char_ptr++ = ')'; + } else /*Spanning node without subscript*/ + is_snblk = TRUE; + if (is_snblk) + { + ss_ptr = (span_subs *)key_char_ptr; + snbid = SPAN_GVSUBS2INT(ss_ptr); + key_char_ptr = key_char_ptr + SPAN_SUBS_LEN + 1; /* Move out of special subscript of spanning node */ + blk_sz = gv_cur_region->dyn.addr->blk_size; + /* Decide the offset of the content of a block inside the value of spanning node*/ + offset = (snbid) ? (blk_sz - (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + gv_cur_region->dyn.addr->reserved_bytes + + (key_char_ptr - (uchar_ptr_t)patch_comp_key + 1))) * (snbid - 1) : 0 ; + ret_addr =(unsigned char *)memmove((void *)(work_buff+4), (void *)work_buff, (work_char_ptr - work_buff)); + assert(*ret_addr == '^'); + *work_buff = '$'; + *(work_buff + 1) = 'z'; + *(work_buff + 2) = 'e'; + *(work_buff + 3) = '('; + /* length of "$ze(" is 4, so move the work_char_ptr by 4*/ + work_char_ptr = work_char_ptr + 4; + *work_char_ptr++ = ','; + + /* Dump the offset of the content of a block inside the value of spanning node */ + num = snbid ? offset : 0; + COUNT_TRAILING_ZERO(num, work_char_ptr, trail_zero); + num = offset; + OUTPUT_NUMBER(num, work_char_ptr, trail_zero); + *work_char_ptr++ = ','; + + /* Dump the length of the content of a block */ + num = snbid ? len : 0; + COUNT_TRAILING_ZERO(num, work_char_ptr, trail_zero); + num = snbid ? len : 0; + OUTPUT_NUMBER(num, work_char_ptr, trail_zero); + *work_char_ptr++ = ')'; } assert(MAX_ZWR_KEY_SZ >= work_char_ptr - work_buff); if (GLO_FMT == dse_dmp_format) @@ -85,7 +151,13 @@ boolean_t dse_fdmp(sm_uc_ptr_t data, int len) { assert(ZWR_FMT == dse_dmp_format); *work_char_ptr++ = '='; - format2zwr(data, len, work_char_ptr, &dest_len); + if(is_snblk && !snbid) + { + *work_char_ptr++ = '"'; + *work_char_ptr++ = '"'; + dest_len = 0; + } else + format2zwr(data, len, work_char_ptr, &dest_len); if (!dse_fdmp_output(work_buff, (int4)(work_char_ptr + dest_len - work_buff))) return FALSE; } diff --git a/sr_port/dse_getki.c b/sr_port/dse_getki.c index 2b916eb..b5dace6 100644 --- a/sr_port/dse_getki.c +++ b/sr_port/dse_getki.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,7 @@ #ifdef GTM_TRIGGER #include "hashtab_mname.h" -#include "rtnhdr.h" +#include #include "gv_trigger.h" /* needed for INIT_ROOT_GVT */ #include "targ_alloc.h" #endif @@ -55,8 +55,11 @@ int dse_getki(char *dst, int *len, char *qual, int qual_len) short int max_key; unsigned short buf_len; int key_len, dlr_num, dlr_len; + int num; + unsigned char *ptr; mval key_subsc; sgmnt_addrs *csa; + span_subs subs; buf_len = SIZEOF(buf); if (!cli_get_str(qual, buf, &buf_len)) @@ -71,7 +74,7 @@ int dse_getki(char *dst, int *len, char *qual, int qual_len) } if ((*src >= 'A' && *src <= 'Z') || (*src >= 'a' && *src <= 'z') || - (*src == '%')) /* first letter must be an alphabet or % */ + (*src == '%') || (*src == '#')) /* first letter must be an alphabet or % or # */ { *temp_dst++ = *src++; } else @@ -100,13 +103,13 @@ int dse_getki(char *dst, int *len, char *qual, int qual_len) bot = (char *)&gv_currkey->base[0]; temp_dst = (char *)&gv_currkey->base[0] + gv_currkey->end; max_key = gv_cur_region->max_key_size; - if (*src == '(') + if ('(' == *src) { src++; for (;;) { key_subsc.mvtype = MV_STR; - if (*src == '$') /* may be a $char() */ + if ('$' == *src) /* may be a $char() */ { src++; if ((dlr_len = parse_dlr_char(src, top, slit)) > 0) @@ -119,6 +122,26 @@ int dse_getki(char *dst, int *len, char *qual, int qual_len) util_out_print("Error: invalid key.", TRUE); return FALSE; } + } else if ('#' == *src) + { /*Special spanning global subscript*/ + if ('S' != toupper(*(src + 1)) && 'P' != toupper(*(src + 2)) + && 'A' != toupper(*(src + 3)) && 'N' != toupper(*(src + 4))) + { + util_out_print("Error: invalid key.", TRUE); + return FALSE; + } + src = src + SPAN_SUBS_LEN + 1; + for (num = 0, src++; *src != ')'; num = (num * DECIMAL_BASE + (int)(*src++ - ASCII_0))) + ; + ptr = gv_currkey->base + gv_currkey->end; + num = num - 1; + SPAN_INITSUBS(&subs, num); + SPAN_SUBSCOPY_SRC2DST(ptr, (unsigned char *)&subs); + ptr = ptr + SPAN_SUBS_LEN; + *ptr++ = KEY_DELIMITER; + *ptr = KEY_DELIMITER; + gv_currkey->end = ptr - gv_currkey->base; + break; } else if (*src != '\"') /* numerical subscript */ { for (key_subsc.str.addr = src ; *src != ')' && *src != ','; src++) diff --git a/sr_port/dse_ksrch.c b/sr_port/dse_ksrch.c index b0a290c..8139a3f 100644 --- a/sr_port/dse_ksrch.c +++ b/sr_port/dse_ksrch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,10 +29,12 @@ GBLREF short int patch_path_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF bool patch_find_root_search; GBLDEF block_id ksrch_root; +error_def(ERR_DSEBLKRDFAIL); + int dse_ksrch(block_id srch, block_id_ptr_t pp, int4 *off, @@ -40,14 +42,14 @@ int dse_ksrch(block_id srch, int targ_len) { sm_uc_ptr_t bp, b_top, rp, r_top, key_top, blk_id; - unsigned char cc; + unsigned short cc; + int tmp_cmpc; int rsize; ssize_t size; int4 cmp; - short dummy_short; + unsigned short dummy_short; int4 dummy_int; cache_rec_ptr_t dummy_cr; - error_def(ERR_DSEBLKRDFAIL); if(!(bp = t_qread(srch, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); @@ -84,13 +86,13 @@ int dse_ksrch(block_id srch, if (((blk_hdr_ptr_t)bp)->levl && key_top > (blk_id = r_top - SIZEOF(block_id))) key_top = blk_id; - if (((rec_hdr_ptr_t) rp)->cmpc > patch_comp_count) + if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t) rp)->cmpc; + cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = (ssize_t)(key_top - rp - SIZEOF(rec_hdr)); - if (size > SIZEOF(patch_comp_key) - 2 - cc) - size = SIZEOF(patch_comp_key) - 2 - cc; + if (size > MAX_KEY_SZ - cc) + size = MAX_KEY_SZ - cc; if (size < 0) size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); @@ -118,5 +120,26 @@ int dse_ksrch(block_id srch, && dse_ksrch(*pp, pp + 1, off + 1, targ_key, targ_len)) return TRUE; return FALSE; - +} + +int dse_key_srch(block_id srch, block_id_ptr_t key_path, int4 *off, char *targ_key, int targ_len) +{ + int status = dse_ksrch(srch, key_path, off, targ_key, targ_len); + if(status) + return status; + else if(!patch_find_root_search) + { /* We are not searching for the global name in the directory tree and search for the regular-key + * has failed. So, adjust to the input key with special subscript to indicate it as a spanning node key. + * call dse_ksrch() again. + */ + targ_len -= 1; /* back off 1 to overlay terminator */ + SPAN_INITSUBS((span_subs *)(targ_key + targ_len), 0); + targ_len += SPAN_SUBS_LEN; + targ_key[targ_len++] = KEY_DELIMITER; + targ_key[targ_len++] = KEY_DELIMITER; + patch_path_count = 1; /*This indicates the length of the path of node in gvtree*/ + patch_find_root_search = FALSE; + return(dse_ksrch(srch,key_path, off, targ_key, targ_len)); + } + return FALSE; } diff --git a/sr_port/dse_maps.c b/sr_port/dse_maps.c index 80f604d..e69085f 100644 --- a/sr_port/dse_maps.c +++ b/sr_port/dse_maps.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -59,7 +59,11 @@ GBLREF gd_region *gv_cur_region; GBLREF short crash_count; GBLREF boolean_t unhandled_stale_timer_pop; GBLREF srch_hist dummy_hist; -GBLREF unsigned char *non_tp_jfb_buff_ptr; + +error_def(ERR_DBRDONLY); +error_def(ERR_DSEBLKRDFAIL); +error_def(ERR_DSEFAIL); + void dse_maps(void) { @@ -84,10 +88,6 @@ void dse_maps(void) sgmnt_addrs *csa; sgmnt_data_ptr_t csd; - error_def(ERR_DSEBLKRDFAIL); - error_def(ERR_DBRDONLY); - error_def(ERR_DSEFAIL); - if (CLI_PRESENT == cli_present("BUSY") || CLI_PRESENT == cli_present("FREE") || CLI_PRESENT == cli_present("MASTER") || CLI_PRESENT == cli_present("RESTORE_ALL")) { @@ -159,7 +159,7 @@ void dse_maps(void) grab_crit(gv_cur_region); bml_blk = blk / bplmap * bplmap; if (dba_mm == csd->acc_meth) - bp = (sm_uc_ptr_t)csa->acc_meth.mm.base_addr + (off_t)bml_blk * blk_size; + bp = MM_BASE_ADDR(csa) + (off_t)bml_blk * blk_size; else { assert(dba_bg == csd->acc_meth); @@ -220,7 +220,7 @@ void dse_maps(void) BLK_SEG(bs_ptr, blk_ptr + SIZEOF(blk_hdr), bml_size - SIZEOF(blk_hdr)); BLK_FINI(bs_ptr, bs1); t_write(&blkhist, (unsigned char *)bs1, 0, 0, LCL_MAP_LEVL, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, csa->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn); t_end(&dummy_hist, NULL, csa->ti->curr_tn); } /* Fill in master map */ diff --git a/sr_port/dse_order.c b/sr_port/dse_order.c index 0217501..55fd131 100644 --- a/sr_port/dse_order.c +++ b/sr_port/dse_order.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,7 @@ GBLREF block_id patch_path[MAX_BT_DEPTH + 1], patch_path1[MAX_BT_DEPTH + 1]; GBLREF bool patch_find_root_search; GBLREF sgmnt_addrs *cs_addrs; GBLREF short int patch_path_count; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; error_def(ERR_DSEBLKRDFAIL); @@ -44,7 +44,8 @@ int dse_order(block_id srch, bool dir_data_blk) { sm_uc_ptr_t bp, b_top, key_top, ptr, rp, r_top; - unsigned char cc; + unsigned short cc; + int tmp_cmpc; block_id last; short int rsize, size; int4 dummy_int; @@ -71,7 +72,7 @@ int dse_order(block_id srch, r_top = rp + rsize; if ((r_top > b_top) || (r_top == b_top && ((blk_hdr*)bp)->levl)) { - if ((SIZEOF(rec_hdr) + SIZEOF(block_id) != (b_top - rp)) || ((rec_hdr *)rp)->cmpc) + if ((SIZEOF(rec_hdr) + SIZEOF(block_id) != (b_top - rp)) || EVAL_CMPC((rec_hdr *)rp)) return FALSE; if (dir_data_blk && !((blk_hdr_ptr_t)bp)->levl) { @@ -92,10 +93,10 @@ int dse_order(block_id srch, key_top = ptr; } else key_top = r_top - SIZEOF(block_id); - if (((rec_hdr_ptr_t)rp)->cmpc > patch_comp_count) + if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t)rp)->cmpc; + cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if ((SIZEOF(patch_comp_key) - 2 - cc) < size) size = SIZEOF(patch_comp_key) - 2 - cc; diff --git a/sr_port/dse_over.c b/sr_port/dse_over.c index d38fd38..823dcd9 100644 --- a/sr_port/dse_over.c +++ b/sr_port/dse_over.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -56,7 +56,6 @@ GBLREF gtm_chset_t dse_over_chset; GBLREF iconv_t dse_over_cvtcd; #endif GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; GBLREF UConverter *chset_desc[]; LITREF mstr chset_names[]; GBLREF spdesc stringpool; @@ -219,7 +218,7 @@ void dse_over(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } diff --git a/sr_port/dse_range.c b/sr_port/dse_range.c index 0e5f522..8b27067 100644 --- a/sr_port/dse_range.c +++ b/sr_port/dse_range.c @@ -45,7 +45,7 @@ error_def(ERR_CTRLC); void dse_range(void) { - char lower[256], targ_key[256], upper[256], util_buff[MAX_UTIL_LEN]; + char lower[MAX_KEY_SZ + 1], targ_key[MAX_KEY_SZ + 1], upper[MAX_KEY_SZ + 1], util_buff[MAX_UTIL_LEN]; block_id from, to, blk, blk_child; sm_uc_ptr_t bp, b_top, key_bot, key_top, key_top1, rp, r_top; char level; diff --git a/sr_port/dse_rest.c b/sr_port/dse_rest.c index a8a674e..2e90b9f 100644 --- a/sr_port/dse_rest.c +++ b/sr_port/dse_rest.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,7 +50,6 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *original_header; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; void dse_rest(void) { @@ -180,7 +179,7 @@ void dse_rest(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } diff --git a/sr_port/dse_rmrec.c b/sr_port/dse_rmrec.c index ea34d9f..31ef91f 100644 --- a/sr_port/dse_rmrec.c +++ b/sr_port/dse_rmrec.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -48,9 +48,8 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF block_id patch_curr_blk; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); @@ -64,7 +63,8 @@ void dse_rmrec(void) int4 count; uchar_ptr_t lbp, b_top, rp, r_top, key_top, rp_base; char comp_key[MAX_KEY_SZ + 1]; - unsigned char cc, cc_base; + unsigned short cc, cc_base; + int tmp_cmpc; short int size, i, rsize; srch_blk_status blkhist; @@ -144,7 +144,7 @@ void dse_rmrec(void) } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; @@ -159,10 +159,10 @@ void dse_rmrec(void) if (!*key_top++ && !*key_top++) break; } - if (((rec_hdr_ptr_t)rp)->cmpc > patch_comp_count) + if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t)rp)->cmpc; + cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; @@ -178,7 +178,7 @@ void dse_rmrec(void) size = (patch_comp_count < cc_base) ? patch_comp_count : cc_base; for (i = 0; i < size && patch_comp_key[i] == comp_key[i]; i++) ; - ((rec_hdr_ptr_t)rp_base)->cmpc = i; + SET_CMPC((rec_hdr_ptr_t)rp_base, i); rsize = r_top - key_top + SIZEOF(rec_hdr) + patch_comp_count - i; PUT_SHORT(&((rec_hdr_ptr_t)rp_base)->rsiz, rsize); memcpy(rp_base + SIZEOF(rec_hdr), &patch_comp_key[i], patch_comp_count - i); @@ -194,7 +194,7 @@ void dse_rmrec(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; diff --git a/sr_port/dse_shift.c b/sr_port/dse_shift.c index 2f1deb5..3096191 100644 --- a/sr_port/dse_shift.c +++ b/sr_port/dse_shift.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,7 +46,6 @@ GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF block_id patch_curr_blk; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; void dse_shift(void) { @@ -161,7 +160,7 @@ void dse_shift(void) return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); - BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn); + BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } diff --git a/sr_port/dump_record.c b/sr_port/dump_record.c index b62237b..e5518d3 100644 --- a/sr_port/dump_record.c +++ b/sr_port/dump_record.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,7 @@ #ifdef GTM_TRIGGER #include "hashtab_mname.h" -#include "rtnhdr.h" /* needed for gv_trigger.h */ +#include /* needed for gv_trigger.h */ #include "gv_trigger.h" /* needed for INIT_ROOT_GVT */ #include "targ_alloc.h" #endif @@ -45,7 +45,7 @@ GBLDEF bool wide_out; GBLDEF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLDEF unsigned char patch_comp_count; +GBLDEF unsigned short patch_comp_count; GBLDEF int patch_rec_counter; GBLREF sgmnt_addrs *cs_addrs; GBLREF VSIG_ATOMIC_T util_interrupt; @@ -65,8 +65,9 @@ sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr sm_uc_ptr_t r_top, key_top, cptr0, cptr1, cptr_top, cptr_base = NULL, cptr_next = NULL; char key_buf[MAX_KEY_SZ + 1], *temp_ptr, *temp_key, util_buff[MAX_UTIL_LEN]; char *prefix_str, *space_str, *dot_str, *format_str; - unsigned char cc; - short int size; + unsigned short cc; + int tmp_cmpc; + unsigned short size; int4 util_len, head; uint4 ch; int buf_len, field_width,fastate, chwidth = 0; @@ -79,7 +80,7 @@ sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr return NULL; head = cli_present("HEADER"); GET_SHORT(size, &((rec_hdr_ptr_t)rp)->rsiz); - cc = ((rec_hdr_ptr_t)rp)->cmpc; + cc = EVAL_CMPC((rec_hdr_ptr_t)rp); if ((CLI_NEGATED != head) && !patch_is_fdmp) { MEMCPY_LIT(util_buff, "Rec:"); @@ -96,7 +97,7 @@ sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr util_len += i2hex_nofill(size, (uchar_ptr_t)&util_buff[util_len], 4); MEMCPY_LIT(&util_buff[util_len], " Cmpc "); util_len += SIZEOF(" Cmpc ") - 1; - util_len += i2hex_nofill(cc, (uchar_ptr_t)&util_buff[util_len], 2); + util_len += i2hex_nofill(cc, (uchar_ptr_t)&util_buff[util_len], 3); MEMCPY_LIT(&util_buff[util_len], " "); util_len += SIZEOF(" ") - 1; util_buff[util_len] = 0; @@ -120,8 +121,6 @@ sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; - if (size < 0) - size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = cc + size; patch_comp_key[patch_comp_count] = patch_comp_key[patch_comp_count + 1] = 0; @@ -147,7 +146,7 @@ sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr } util_out_print("Key ", FALSE); if (r_top == b_top - && ((blk_hdr_ptr_t)bp)->levl && !((rec_hdr_ptr_t)rp)->cmpc + && ((blk_hdr_ptr_t)bp)->levl && !EVAL_CMPC((rec_hdr_ptr_t)rp) && r_top - rp == SIZEOF(rec_hdr) + SIZEOF(block_id)) util_out_print("*", FALSE); else if (patch_comp_key[0]) diff --git a/sr_port/ecode_add.c b/sr_port/ecode_add.c index 24e805f..43937d0 100644 --- a/sr_port/ecode_add.c +++ b/sr_port/ecode_add.c @@ -14,7 +14,7 @@ #include "gtm_string.h" /* for memcpy() */ #include "min_max.h" /* for MIN macro */ -#include "rtnhdr.h" /* for stack_frame.h */ +#include /* for stack_frame.h */ #include "stack_frame.h" /* for stack_frame type */ #include "error_trap.h" diff --git a/sr_port/ecode_init.c b/sr_port/ecode_init.c index 4c218a7..7a9b412 100644 --- a/sr_port/ecode_init.c +++ b/sr_port/ecode_init.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "error.h" /* for ERROR_RTN */ #include "error_trap.h" diff --git a/sr_port/eintr_wrappers.h b/sr_port/eintr_wrappers.h index adf518a..1d9f07a 100644 --- a/sr_port/eintr_wrappers.h +++ b/sr_port/eintr_wrappers.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,7 +13,7 @@ * * FCNTL, FCNTL3 Loop until fcntl call succeeds or fails with other than EINTR. * TCFLUSH Loop until tcflush call succeeds or fails with other than EINTR. - * TCSETATTR Loop until tcsetattr call succeeds or fails with other than EINTR. + * Tcsetattr Loop until tcsetattr call succeeds or fails with other than EINTR. */ #ifndef EINTR_WRP_Included @@ -31,222 +31,231 @@ #include "wbox_test_init.h" #endif -#define ACCEPT_SOCKET(SOCKET, ADDR, LEN, RC) \ -{ \ - do \ - { \ - RC = ACCEPT(SOCKET, ADDR, LEN); \ - } while(-1 == RC && EINTR == errno); \ +#define ACCEPT_SOCKET(SOCKET, ADDR, LEN, RC) \ +{ \ + do \ + { \ + RC = ACCEPT(SOCKET, ADDR, LEN); \ + } while(-1 == RC && EINTR == errno); \ } -#define CHG_OWNER(PATH, OWNER, GRP, RC) \ -{ \ - do \ - { \ - RC = CHOWN(PATH, OWNER, GRP); \ - } while(-1 == RC && EINTR == errno); \ +#define CHG_OWNER(PATH, OWNER, GRP, RC) \ +{ \ + do \ + { \ + RC = CHOWN(PATH, OWNER, GRP); \ + } while(-1 == RC && EINTR == errno); \ } -#define CLOSEDIR(DIR, RC) \ -{ \ - do \ - { \ - RC = closedir(DIR); \ - } while(-1 == RC && EINTR == errno); \ +#define CLOSEDIR(DIR, RC) \ +{ \ + do \ + { \ + RC = closedir(DIR); \ + } while(-1 == RC && EINTR == errno); \ } -#define CONNECT_SOCKET(SOCKET, ADDR, LEN, RC) \ -{ \ - do \ - { \ - RC = CONNECT(SOCKET, ADDR, LEN); \ - } while(-1 == RC && EINTR == errno); \ +#define CONNECT_SOCKET(SOCKET, ADDR, LEN, RC) \ +{ \ + do \ + { \ + RC = CONNECT(SOCKET, ADDR, LEN); \ + } while(-1 == RC && EINTR == errno); \ } -#define CREATE_FILE(PATHNAME, MODE, RC) \ -{ \ - do \ - { \ - RC = CREAT(PATHNAME, MODE); \ - } while(-1 == RC && EINTR == errno); \ +#define CREATE_FILE(PATHNAME, MODE, RC) \ +{ \ + do \ + { \ + RC = CREAT(PATHNAME, MODE); \ + } while(-1 == RC && EINTR == errno); \ } -#define DOREAD_A_NOINT(FD, BUF, SIZE, RC) \ -{ \ - do \ - { \ - RC = DOREAD_A(FD, BUF, SIZE); \ - } while(-1 == RC && EINTR == errno); \ +#define DOREAD_A_NOINT(FD, BUF, SIZE, RC) \ +{ \ + do \ + { \ + RC = DOREAD_A(FD, BUF, SIZE); \ + } while(-1 == RC && EINTR == errno); \ } -#define DUP2(FDESC1, FDESC2, RC) \ -{ \ - do \ - { \ - RC = dup2(FDESC1, FDESC2); \ - } while(-1 == RC && EINTR == errno); \ +#define DUP2(FDESC1, FDESC2, RC) \ +{ \ + do \ + { \ + RC = dup2(FDESC1, FDESC2); \ + } while(-1 == RC && EINTR == errno); \ } -#define FCLOSE(STREAM, RC) \ -{ \ - do \ - { \ - RC = fclose(STREAM); \ - } while(-1 == RC && EINTR == errno); \ +#define FCLOSE(STREAM, RC) \ +{ \ + do \ + { \ + RC = fclose(STREAM); \ + } while(-1 == RC && EINTR == errno); \ } -#define FCNTL2(FDESC, ACTION, RC) \ -{ \ - do \ - { \ - RC = fcntl(FDESC, ACTION); \ - } while(-1 == RC && EINTR == errno); \ +#define FCNTL2(FDESC, ACTION, RC) \ +{ \ + do \ + { \ + RC = fcntl(FDESC, ACTION); \ + } while(-1 == RC && EINTR == errno); \ } -#define FCNTL3(FDESC, ACTION, ARG, RC) \ -{ \ - do \ - { \ - RC = fcntl(FDESC, ACTION, ARG); \ - } while(-1 == RC && EINTR == errno); \ +#define FCNTL3(FDESC, ACTION, ARG, RC) \ +{ \ + do \ + { \ + RC = fcntl(FDESC, ACTION, ARG); \ + } while(-1 == RC && EINTR == errno); \ } -#define FGETS_FILE(BUF, LEN, FP, RC) \ -{ \ - do \ - { \ - FGETS(BUF, LEN, FP, RC); \ +#define FGETS_FILE(BUF, LEN, FP, RC) \ +{ \ + do \ + { \ + FGETS(BUF, LEN, FP, RC); \ } while(NULL == RC && !feof(FP) && ferror(FP) && EINTR == errno); \ } -#define FSTAT_FILE(FDESC, INFO, RC) \ -{ \ - do \ - { \ - RC = fstat(FDESC, INFO); \ - } while(-1 == RC && EINTR == errno); \ +#define FSTAT_FILE(FDESC, INFO, RC) \ +{ \ + do \ + { \ + DEFER_INTERRUPTS(INTRPT_IN_FSTAT); \ + RC = fstat(FDESC, INFO); \ + ENABLE_INTERRUPTS(INTRPT_IN_FSTAT); \ + } while(-1 == RC && EINTR == errno); \ } -#define FSTATVFS_FILE(FDESC, FSINFO, RC) \ -{ \ - do \ - { \ - FSTATVFS(FDESC, FSINFO, RC); \ - } while(-1 == RC && EINTR == errno); \ +#define FSTATVFS_FILE(FDESC, FSINFO, RC) \ +{ \ + do \ + { \ + FSTATVFS(FDESC, FSINFO, RC); \ + } while(-1 == RC && EINTR == errno); \ } -#define FTRUNCATE(FDESC, LENGTH, RC) \ -{ \ - do \ - { \ - RC = ftruncate(FDESC, LENGTH); \ - } while(-1 == RC && EINTR == errno); \ +#define FTRUNCATE(FDESC, LENGTH, RC) \ +{ \ + do \ + { \ + RC = ftruncate(FDESC, LENGTH); \ + } while(-1 == RC && EINTR == errno); \ } -#define MSGSND(MSGID, MSGP, MSGSZ, FLG, RC) \ -{ \ - do \ - { \ - RC = msgsnd(MSGID, MSGP, MSGSZ, FLG);\ - } while(-1 == RC && EINTR == errno); \ +#define MSGSND(MSGID, MSGP, MSGSZ, FLG, RC) \ +{ \ + do \ + { \ + RC = msgsnd(MSGID, MSGP, MSGSZ, FLG); \ + } while(-1 == RC && EINTR == errno); \ } -#define OPEN_PIPE(FDESC, RC) \ -{ \ - do \ - { \ - RC = pipe(FDESC); \ - } while(-1 == RC && EINTR == errno); \ +#define OPEN_PIPE(FDESC, RC) \ +{ \ + do \ + { \ + RC = pipe(FDESC); \ + } while(-1 == RC && EINTR == errno); \ } -#define READ_FILE(FD, BUF, SIZE, RC) \ -{ \ - do \ - { \ - RC = read(FD, BUF, SIZE); \ - } while(-1 == RC && EINTR == errno); \ +#define READ_FILE(FD, BUF, SIZE, RC) \ +{ \ + do \ + { \ + RC = read(FD, BUF, SIZE); \ + } while(-1 == RC && EINTR == errno); \ } -#define RECVFROM_SOCK(SOCKET, BUF, LEN, FLAGS, \ - ADDR, ADDR_LEN, RC) \ -{ \ - do \ - { \ - RC = RECVFROM(SOCKET, BUF, LEN, \ - FLAGS, ADDR, ADDR_LEN);\ - } while(-1 == RC && EINTR == errno); \ +#define RECVFROM_SOCK(SOCKET, BUF, LEN, FLAGS, \ + ADDR, ADDR_LEN, RC) \ +{ \ + do \ + { \ + RC = RECVFROM(SOCKET, BUF, LEN, \ + FLAGS, ADDR, ADDR_LEN); \ + } while(-1 == RC && EINTR == errno); \ } -#define SELECT(FDS, INLIST, OUTLIST, XLIST, \ - TIMEOUT, RC) \ -{ \ - struct timeval eintr_select_timeval; \ - do \ - { \ - eintr_select_timeval = *(TIMEOUT); \ - RC = select(FDS, INLIST, OUTLIST, \ - XLIST, \ - &eintr_select_timeval);\ - } while(-1 == RC && EINTR == errno); \ +#define SELECT(FDS, INLIST, OUTLIST, XLIST, \ + TIMEOUT, RC) \ +{ \ + struct timeval eintr_select_timeval; \ + do \ + { \ + eintr_select_timeval = *(TIMEOUT); \ + RC = select(FDS, INLIST, OUTLIST, \ + XLIST, &eintr_select_timeval); \ + } while(-1 == RC && EINTR == errno); \ } -#define SEND(SOCKET, BUF, LEN, FLAGS, RC) \ -{ \ - do \ - { \ - RC = send(SOCKET, BUF, LEN, FLAGS); \ - } while(-1 == RC && EINTR == errno); \ +#define SEND(SOCKET, BUF, LEN, FLAGS, RC) \ +{ \ + do \ + { \ + RC = send(SOCKET, BUF, LEN, FLAGS); \ + } while(-1 == RC && EINTR == errno); \ } -#define SENDTO_SOCK(SOCKET, BUF, LEN, FLAGS, \ - ADDR, ADDR_LEN, RC) \ -{ \ - do \ - { \ - RC = SENDTO(SOCKET, BUF, LEN, FLAGS, \ - ADDR, ADDR_LEN); \ - } while(-1 == RC && EINTR == errno); \ +#define SENDTO_SOCK(SOCKET, BUF, LEN, FLAGS, \ + ADDR, ADDR_LEN, RC) \ +{ \ + do \ + { \ + RC = SENDTO(SOCKET, BUF, LEN, FLAGS, \ + ADDR, ADDR_LEN); \ + } while(-1 == RC && EINTR == errno); \ } -#define STAT_FILE(PATH, INFO, RC) \ -{ \ - do \ - { \ - RC = Stat(PATH, INFO); \ +#define STAT_FILE(PATH, INFO, RC) \ +{ \ + do \ + { \ + RC = Stat(PATH, INFO); \ } while((uint4)-1 == RC && EINTR == errno); \ } -#define TCFLUSH(FDESC, REQUEST, RC) \ -{ \ - do \ - { \ - RC = tcflush(FDESC, REQUEST); \ - } while(-1 == RC && EINTR == errno); \ +#define TCFLUSH(FDESC, REQUEST, RC) \ +{ \ + do \ + { \ + RC = tcflush(FDESC, REQUEST); \ + } while(-1 == RC && EINTR == errno); \ } -#define Tcsetattr(FDESC, WHEN, TERMPTR, RC) \ -{ \ - do \ - { \ - RC = tcsetattr(FDESC, WHEN, TERMPTR);\ - } while(-1 == RC && EINTR == errno); \ +#if defined(UNIX) +#define Tcsetattr(FDESC, WHEN, TERMPTR, RC, ERRNO) \ +{ \ + GBLREF sigset_t block_ttinout; \ + sigset_t oldset; \ + int rc; \ + SIGPROCMASK(SIG_BLOCK, &block_ttinout, &oldset, rc); \ + do \ + { \ + RC = tcsetattr(FDESC, WHEN, TERMPTR); \ + } while(-1 == RC && EINTR == errno); \ + ERRNO = errno; \ + SIGPROCMASK(SIG_SETMASK, &oldset, NULL, rc); \ +} +#endif + +#define TRUNCATE_FILE(PATH, LENGTH, RC) \ +{ \ + do \ + { \ + RC = TRUNCATE(PATH, LENGTH); \ + } while(-1 == RC && EINTR == errno); \ } -#define TRUNCATE_FILE(PATH, LENGTH, RC) \ -{ \ - do \ - { \ - RC = TRUNCATE(PATH, LENGTH); \ - } while(-1 == RC && EINTR == errno); \ -} - -#define WAIT(STATUS, RC) \ -{ \ - do \ - { \ - RC = wait(STATUS); \ - } while(-1 == RC && EINTR == errno); \ +#define WAIT(STATUS, RC) \ +{ \ + do \ + { \ + RC = wait(STATUS); \ + } while(-1 == RC && EINTR == errno); \ } #define WAITPID(PID, STATUS, OPTS, RC) \ @@ -256,27 +265,19 @@ * changes its state unless invoked with WNOHANG bit set. Make sure not waiting on current pid \ */ \ assert(0 != PID); \ - assert(getpid() != PID); \ + assert(getpid() != PID); \ do \ { \ - RC = waitpid(PID, STATUS, OPTS); \ + RC = waitpid(PID, STATUS, OPTS); \ } while(-1 == RC && EINTR == errno); \ } -#define WRITE_FILE(FD, BUF, SIZE, RC) \ -{ \ - do \ - { \ - RC = write(FD, BUF, SIZE); \ - } while(-1 == RC && EINTR == errno); \ -} - -#define GTM_FSYNC(FD, RC) \ -{ \ - do \ - { \ - RC = fsync(FD); \ - } while(-1 == RC && EINTR == errno); \ +#define GTM_FSYNC(FD, RC) \ +{ \ + do \ + { \ + RC = fsync(FD); \ + } while(-1 == RC && EINTR == errno); \ } #define SIGPROCMASK(FUNC, NEWSET, OLDSET, RC) \ diff --git a/sr_port/emit_code.c b/sr_port/emit_code.c index e24336c..aa3b0cc 100644 --- a/sr_port/emit_code.c +++ b/sr_port/emit_code.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "vxt.h" #include "cgp.h" #include "obj_gen.h" -#include "rtnhdr.h" +#include #include "obj_file.h" #include "list_file.h" #include "min_max.h" @@ -121,6 +121,10 @@ static boolean_t ocnt_ref_seen = FALSE; static oprtype *ocnt_ref_opr; static triple *current_triple; +error_def(ERR_MAXARGCNT); +error_def(ERR_SRCNAM); +error_def(ERR_UNIMPLOP); + void trip_gen (triple *ct) { oprtype **sopr, *opr; /* triple operand */ @@ -135,13 +139,9 @@ void trip_gen (triple *ct) short repcnt; int off; - error_def (ERR_UNIMPLOP); - error_def (ERR_MAXARGCNT); - # if !defined(TRUTH_IN_REG) && (!(defined(__osf__) || defined(__x86_64__) || defined(Linux390))) GTMASSERT; # endif - DEBUG_ONLY(opcode_emitted = FALSE); current_triple = ct; /* save for possible use by internal rtns */ tp = ttt[ct->opcode]; @@ -150,11 +150,9 @@ void trip_gen (triple *ct) stx_error(ERR_UNIMPLOP); return; } - code_idx = 0; vax_pushes_seen = 0; vax_number_of_arguments = 0; - if (cg_phase_last != cg_phase) { cg_phase_last = cg_phase; @@ -163,7 +161,6 @@ void trip_gen (triple *ct) else reset_push_list_ptr(); } - code_reference = ct->rtaddr; oct = oc_tab[ct->opcode].octype; sopr = &saved_opr[0]; @@ -179,13 +176,12 @@ void trip_gen (triple *ct) continue; } *sopr++ = opr; - if (sopr >= ARRAYTOP(saved_opr)) - rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS); + if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); } opr++; } *sopr = 0; - jmp_offset = 0; if (oct & OCT_JUMP || ct->opcode == OC_LDADDR || ct->opcode == OC_FORLOOP) { @@ -268,7 +264,6 @@ void trip_gen (triple *ct) tsp = &ttt[tp]; } else tsp = &ttt[tp]; - for (; *tsp != VXT_END;) { if (*tsp == VXT_IREPAB || *tsp == VXT_IREPL) @@ -282,7 +277,6 @@ void trip_gen (triple *ct) assert(irep_opr->oprclass == TRIP_REF); irep_opr = &irep_opr->oprval.tref->operand[1]; } - if (irep_opr->oprclass == TRIP_REF) { repl = tsp; @@ -308,9 +302,8 @@ void trip_gen (triple *ct) if (cg_phase == CGP_ASSEMBLY) emit_asmlist(ct); # endif - }/* else */ - }/* for */ - + } /* else */ + } /* for */ if (cg_phase == CGP_APPROX_ADDR) if (vax_pushes_seen > 0) add_to_vax_push_list(vax_pushes_seen); @@ -368,7 +361,6 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) int branch_idx, branch_offset, loop_top_idx, instr; code_idx = 0; - switch (cg_phase) { case CGP_ASSEMBLY: @@ -415,7 +407,6 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) case VXI_BLBS: assert(*inst == VXT_REG); inst++; - # ifdef TRUTH_IN_REG reg = GTM_REG_CODEGEN_TEMP; NON_GTM64_ONLY(GEN_LOAD_WORD(reg, gtm_reg(*inst++), 0);) @@ -448,7 +439,6 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) case VXI_BRW: emit_jmp(GENERIC_OPCODE_BR, &inst, 0); break; - case VXI_BICB2: # ifdef TRUTH_IN_REG GEN_CLEAR_TRUTH; @@ -590,7 +580,7 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) assert(*inst == VXT_XFER); inst++; emit_call_xfer((int)*inst++); - /* Callee may have popped some values so we can't count on anything left on the stack. */ + /* Callee may have popped some values so we can't count on anything left on the stack. */ stack_depth = 0; break; case VXI_MOVAB: @@ -626,7 +616,6 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) its present size and affect other platforms some day, We put the whole code gen thing in a loop so we can do this regardless of how big it gets. */ - assert(*inst == VXT_LIT); inst += 2; assert(*inst == VXT_VAL); @@ -635,7 +624,6 @@ short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) assert(*inst == VXT_VAL); inst++; emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LDA, MOVC3_TRG_REG); - # if defined(__MVS__) || defined(Linux390) /* The MVC instruction on zSeries facilitates memory copy(mval in this case) in a single * instruction instead of multiple 8/4 byte copies. @@ -868,10 +856,8 @@ void emit_jmp (uint4 branchop, short **instp, int reg) assert((jmp_offset & 3) == 0); # endif branch_offset = jmp_offset / INST_SIZE; - /* Some platforms have a different origin for the offset */ EMIT_JMP_ADJUST_BRANCH_OFFSET; - switch (cg_phase) { # ifdef DEBUG @@ -954,7 +940,6 @@ void emit_jmp (uint4 branchop, short **instp, int reg) code_buf[code_idx++] = GENERIC_OPCODE_NOP; branch_offset--; # endif - } if (EMIT_JMP_LONG_CODE_CHECK) { /* This is more common unconditional branch generation and should be mutually @@ -1015,7 +1000,6 @@ void emit_pcrel(void) int branch_offset; jmp_offset -= INTCAST((char *)&code_buf[code_idx] - (char *)&code_buf[0]); - switch (cg_phase) { # ifdef DEBUG @@ -1054,9 +1038,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r triple *ct; int low, extra, high; GTM64_ONLY(int next_ptr_offset = 8;) - - error_def(ERR_SRCNAM); - if (opr->oprclass == TRIP_REF) { ct = opr->oprval.tref; @@ -1064,7 +1045,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r opr = &ct->destination; /* else lit or error */ } - inst_emitted = FALSE; switch (cg_phase) { @@ -1079,7 +1059,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r { case OC_LIT: assert(ct->operand[0].oprclass == MLIT_REF); - if (run_time) reg = GTM_REG_PV; else @@ -1216,7 +1195,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r } } break; - case OCNT_REF: /* This ref's value is calculated in emit_call_xfer(). This value is related to TSIZ_REF in that it is used for the same reason to different calls (op_call, op_callsp, @@ -1323,7 +1301,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r break; } break; - case TINT_REF: case TVAL_REF: assert(val_output); @@ -1360,7 +1337,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r ) emit_base_offset(GTM_REG_FRAME_TMP_PTR, offset); break; - case TCAD_REF: case TVAD_REF: case TVAR_REF: @@ -1405,7 +1381,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r REVERT_GENERICINST_TO_WORD(generic_inst); } ) - emit_base_offset(reg, offset); if (val_output) /* indirection */ { @@ -1430,7 +1405,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r } } break; - case OCNT_REF: immediate = opr->oprval.offset; assert(0 < immediate); @@ -1498,7 +1472,13 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r break; case OC_TRIPSIZE: immediate = ct->operand[0].oprval.tsize->size; +# if !defined(__osf__) && !defined(__hppa) + /* Legitimate but odd call to next M line on Tru64 and HPUX-HPPA gives an + * immediate value of zero because of how offsets are calculated on + * these platforms so bypass the assert for them. + */ assert(0 < immediate); +# endif assert(MAX_BRANCH_CODEGEN_SIZE > immediate); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; @@ -1508,7 +1488,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r break; } break; - case TINT_REF: case TVAL_REF: assert(val_output); @@ -1528,7 +1507,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r ) emit_base_offset(GTM_REG_FRAME_TMP_PTR, offset); break; - case TCAD_REF: case TVAD_REF: case TVAR_REF: @@ -1541,7 +1519,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r REVERT_GENERICINST_TO_WORD(generic_inst); } ) - NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; @@ -1573,7 +1550,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r } } break; - case OCNT_REF: immediate = opr->oprval.offset; assert(0 <= immediate); @@ -1583,7 +1559,6 @@ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_r ocnt_ref_seen = TRUE; ocnt_ref_opr = opr; break; - default: GTMASSERT; break; @@ -1647,18 +1622,15 @@ int get_arg_reg(void) else arg_reg_i = GTM_REG_ACCUM; break; - case CGP_ASSEMBLY: case CGP_MACHINE: if (vax_pushes_seen == 0) /* first push of a series */ vax_number_of_arguments = next_vax_push_list(); - if (vax_number_of_arguments <= MACHINE_REG_ARGS) arg_reg_i = GET_ARG_REG(vax_number_of_arguments - 1); else arg_reg_i = GTM_REG_ACCUM; break; - default: GTMASSERT; break; @@ -1686,7 +1658,6 @@ int gtm_reg(int vax_reg) case 9: reg = GTM_REG_FRAME_TMP_PTR; break; - # ifdef TRUTH_IN_REG case 10: /* The value of $TEST is maintained in r10 for the VAX GT.M @@ -1698,7 +1669,6 @@ int gtm_reg(int vax_reg) reg = GTM_REG_DOLLAR_TRUTH; break; # endif - case 11: reg = GTM_REG_XFER_TABLE; break; @@ -1709,7 +1679,6 @@ int gtm_reg(int vax_reg) GTMASSERT; break; } - return reg; } @@ -1733,7 +1702,6 @@ void emit_push(int reg) ) } break; - case CGP_ASSEMBLY: case CGP_MACHINE: if (vax_number_of_arguments <= MACHINE_REG_ARGS) @@ -1745,12 +1713,10 @@ void emit_push(int reg) GEN_STORE_ARG(reg, stack_offset); /* Store arg on stack */ } break; - default: GTMASSERT; break; } - if (cg_phase == CGP_MACHINE || cg_phase == CGP_ASSEMBLY) { vax_number_of_arguments--; /* actually, it's the number of arguments remaining */ @@ -1776,13 +1742,9 @@ void emit_pop(int count) void add_to_vax_push_list(int pushes_seen) -{ - error_def(ERR_MAXARGCNT); - - /* Make sure there's enough room */ - if (pushes_seen > MAX_ARGS) - rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS); - +{ /* Make sure there's enough room */ + if (pushes_seen > MAX_ARGS) /* user-visible max args is MAX_ARGS - 3 */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); push_list_index++; if (push_list_index >= PUSH_LIST_SIZE) { @@ -1808,7 +1770,6 @@ int next_vax_push_list(void) GTMASSERT; current_push_list_ptr = current_push_list_ptr->next; } - return (current_push_list_ptr->value[push_list_index]); } @@ -1860,7 +1821,6 @@ void emit_call_xfer(int xfer) *obpt++ = ' '; } # endif - assert(0 == (xfer & 0x3)); offset = (int)(xfer / SIZEOF(char *)); # ifdef __x86_64__ @@ -1872,7 +1832,6 @@ void emit_call_xfer(int xfer) GEN_LOAD_IMMED(I386_REG_RAX, 0); } # endif /* __x86_64__ */ - # ifdef __ia64 if (GTM_ASM_RTN == xfer_table_desc[offset]) { @@ -1889,7 +1848,6 @@ void emit_call_xfer(int xfer) /* In the normal case we will return */ if (!ocnt_ref_seen) return; /* fast test for return .. we hope */ - /* If ocnt_ref_seen is set, then we need to compute the value to be used by a recent OCNT_REF parameter. This parameter is (currently as of 6/2003) used by op_call, op_callsp, op_forlcldo, and their mprof counterparts and is the number of bytes those entry points diff --git a/sr_port/emit_code.h b/sr_port/emit_code.h index 3bf0c2d..2828cdd 100644 --- a/sr_port/emit_code.h +++ b/sr_port/emit_code.h @@ -12,7 +12,7 @@ #ifndef EMIT_CODE_INCLUDED #define EMIT_CODE_INCLUDED -#include "emit_code_sp.h" +#include #ifdef DEBUG void emit_asmlist(triple *ct); diff --git a/sr_port/entryref.c b/sr_port/entryref.c index 6d124fa..0056db7 100644 --- a/sr_port/entryref.c +++ b/sr_port/entryref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "mlabel2xtern.h" #include "mrout2xtern.h" #include "gtmimagename.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" GBLREF stack_frame *frame_pointer; @@ -64,7 +64,7 @@ triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_comma rettrip->operand[0] = put_mlab(&labname); return rettrip; } - label.oprclass = 0; + label.oprclass = NO_REF; break; case TK_ATSIGN: if(!indirection(&label)) @@ -85,7 +85,7 @@ triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_comma return NULL; default: labname.len = 0; - label.oprclass = 0; + label.oprclass = NO_REF; break; } if (!labref && (TK_PLUS == TREF(window_token))) @@ -94,7 +94,7 @@ triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_comma if (EXPR_FAIL == expr(&offset, MUMPS_INT)) return NULL; } else - offset.oprclass = 0; + offset.oprclass = NO_REF; if (TK_CIRCUMFLEX == TREF(window_token)) { /* Have a routine name specified */ advancewindow(); diff --git a/sr_port/err_check.c b/sr_port/err_check.c index 71dc956..82f31e8 100644 --- a/sr_port/err_check.c +++ b/sr_port/err_check.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,35 +12,49 @@ #include "mdef.h" #include "error.h" -VMS_ONLY(LITREF) UNIX_ONLY(GBLREF) err_ctl merrors_ctl; -VMS_ONLY(LITREF) UNIX_ONLY(GBLREF) err_ctl cmerrors_ctl; -VMS_ONLY(LITREF) UNIX_ONLY(GBLREF) err_ctl cmierrors_ctl; -VMS_ONLY(LITREF) UNIX_ONLY(GBLREF) err_ctl gdeerrors_ctl; +VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl merrors_ctl; +VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl cmerrors_ctl; +VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl cmierrors_ctl; +VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl gdeerrors_ctl; #ifdef VMS -LITREF err_ctl laerrors_ctl; /* Roger thinks that this one is obsolete */ -LITREF err_ctl lperrors_ctl; /* Roger thinks that this one may be obsolete */ +LITREF err_ctl laerrors_ctl; /* Roger thinks that this one is obsolete */ +LITREF err_ctl lperrors_ctl; /* Roger thinks that this one may be obsolete */ #endif -STATICDEF const err_ctl *all_errors[] = {&merrors_ctl, &gdeerrors_ctl, &cmierrors_ctl, &cmerrors_ctl, +STATICDEF const err_ctl *all_errors[] = { &merrors_ctl, &gdeerrors_ctl, + &cmierrors_ctl, &cmerrors_ctl, #ifdef VMS - &laerrors_ctl, &lperrors_ctl, + &laerrors_ctl, &lperrors_ctl, #endif - NULL}; + NULL }; -const err_ctl *err_check(int errnum) -{ - const err_ctl *fac; - int errtype; +/* Returns the error control struct corresponding to the errornum if it is valid, otherwise + * returns NULL + */ +const err_ctl *err_check(int errnum) { + /* errnum structure: + * ___________________________________________ + * | 1 FACILITY 1 MSG_IDX SEV| + * |___________________________________________| + * 31 27 15 3 0 + * + */ + const err_ctl *fac; + int errtype; + int msg_id; /* Error message number once facility and severity are stripped */ - if (0 > errnum) - return NULL; + if (0 > errnum) + return NULL ; - for (errtype = 0; all_errors[errtype]; errtype++) - { + for (errtype = 0; all_errors[errtype]; errtype++) { fac = all_errors[errtype]; - if ((errnum & FACMASK(fac->facnum)) - && ((MSGMASK(errnum, fac->facnum)) <= fac->msg_cnt)) + msg_id = MSGMASK(errnum, fac->facnum); + + /* These conditions ensure: The facility bits are identical, the message index + * doesn't exceed the array size and is larger than zero */ + if (((errnum >> MSGFAC) == (FACMASK(fac->facnum) >> MSGFAC)) + && (msg_id <= fac->msg_cnt) && (1 <= msg_id)) return fac; } - return NULL; + return NULL ; } diff --git a/sr_port/error.h b/sr_port/error.h index d12fb9b..9bd9c9b 100644 --- a/sr_port/error.h +++ b/sr_port/error.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,6 +50,8 @@ typedef struct err_ctl_struct #ifdef DEBUG_ERRHND # define DBGEHND(x) DBGFPF(x) # define DBGEHND_ONLY(x) x +# include "gtm_stdio.h" +# include "gtmio.h" #else # define DBGEHND(x) # define DBGEHND_ONLY(x) @@ -71,6 +73,7 @@ CONDITION_HANDLER(gds_rundown_ch); CONDITION_HANDLER(gtcm_ch); CONDITION_HANDLER(gtcm_exi_ch); CONDITION_HANDLER(gtm_env_xlate_ch); +CONDITION_HANDLER(gtm_maxstr_ch); CONDITION_HANDLER(gtmrecv_ch); CONDITION_HANDLER(gtmrecv_fetchresync_ch); CONDITION_HANDLER(gtmsource_ch); @@ -78,11 +81,12 @@ CONDITION_HANDLER(gvcmy_open_ch); CONDITION_HANDLER(gvcmz_netopen_ch); CONDITION_HANDLER(gvzwrite_ch); CONDITION_HANDLER(hashtab_rehash_ch); -CONDITION_HANDLER(jobexam_dump_ch); -CONDITION_HANDLER(iob_io_error); CONDITION_HANDLER(io_init_ch); +CONDITION_HANDLER(iob_io_error); CONDITION_HANDLER(iomt_ch); +CONDITION_HANDLER(jnl_file_autoswitch_ch); CONDITION_HANDLER(job_init_ch); +CONDITION_HANDLER(jobexam_dump_ch); CONDITION_HANDLER(lastchance1); CONDITION_HANDLER(lastchance2); CONDITION_HANDLER(lastchance3); @@ -106,7 +110,6 @@ CONDITION_HANDLER(trans_code_ch); CONDITION_HANDLER(updproc_ch); CONDITION_HANDLER(util_base_ch); CONDITION_HANDLER(util_ch); -CONDITION_HANDLER(gtm_maxstr_ch); CONDITION_HANDLER(zshow_ch); CONDITION_HANDLER(zyerr_ch); diff --git a/sr_port/error_trap.h b/sr_port/error_trap.h index 9176346..6f0e632 100644 --- a/sr_port/error_trap.h +++ b/sr_port/error_trap.h @@ -90,8 +90,8 @@ typedef struct { \ GBLREF stack_frame *error_frame; \ \ - error_frame = NULL; \ DBGEHND((stderr, "%s: Nullifying previous error_frame (was 0x"lvaddr")\n", __FILE__, error_frame)); \ + error_frame = NULL; \ } /* Set "error_frame" to point to "frame_pointer" and mark it as an error frame type. This is an indication that diff --git a/sr_port/eval_expr.c b/sr_port/eval_expr.c index e04c35d..341ba04 100644 --- a/sr_port/eval_expr.c +++ b/sr_port/eval_expr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,37 +12,46 @@ #include "mdef.h" #include "compiler.h" #include "opcode.h" +#include "mdq.h" #include "toktyp.h" #include "advancewindow.h" #include "compile_pattern.h" +#include "fullbool.h" +#include "show_source_line.h" + +GBLREF boolean_t run_time; error_def(ERR_EXPR); error_def(ERR_RHMISSING); +error_def(ERR_SIDEEFFECTEVAL); LITREF octabstruct oc_tab[]; LITREF toktabtype tokentable[]; int eval_expr(oprtype *a) { - triple *ref, *parm, *ref1; - int op_count; - oprtype x1, x2; - opctype i; - unsigned short type; - boolean_t ind_pat; + boolean_t ind_pat, saw_local, saw_se, se_warn; + int op_count, se_handling; + opctype bin_opcode; + oprtype optyp_1, optyp_2, *optyp_ptr; + tbp *catbp, *tripbp; + triple *argtrip, *parm, *ref, *ref1, *t1, *t2; + unsigned short type; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (!expratom(&x1)) + if (!expratom(&optyp_1)) { /* If didn't already add an error of our own, do so now with catch all expression error */ if (OC_RTERROR != (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode) stx_error(ERR_EXPR); return EXPR_FAIL; } - while (i = tokentable[TREF(window_token)].bo_type) /* NOTE assignment NOT condition */ + se_handling = TREF(side_effect_handling); + se_warn = (!run_time && (SE_WARN == se_handling)); + while (bin_opcode = tokentable[TREF(window_token)].bo_type) /* NOTE assignment NOT condition */ { type = tokentable[TREF(window_token)].opr_type; - if (oc_tab[i].octype & OCT_BOOL) + if (oc_tab[bin_opcode].octype & OCT_BOOL) { if (!TREF(shift_side_effects)) { @@ -52,7 +61,7 @@ int eval_expr(oprtype *a) ; TREF(expr_start) = TREF(expr_start_orig) = ref; } - switch (i) + switch (bin_opcode) { case OC_NAND: case OC_AND: @@ -63,30 +72,83 @@ int eval_expr(oprtype *a) break; } } - coerce(&x1, type); - if (OC_CAT == i) + coerce(&optyp_1, type); + if (OC_CAT == bin_opcode) { ref1 = ref = maketriple(OC_CAT); + catbp = &ref->backptr; /* borrow backptr to track args */ + saw_se = saw_local = FALSE; for (op_count = 2; ; op_count++) /* op_count = first operand plus destination */ { parm = newtriple(OC_PARAMETER); ref1->operand[1] = put_tref(parm); ref1 = parm; - ref1->operand[0] = x1; + ref1->operand[0] = optyp_1; + if (se_handling) + { /* the following code deals with protecting lvn values from change by a following + * side effect and thereby produces a standard evaluation order. It is similar to code in + * expritem for function arguments, but has slightly different and easier circumstances + */ + assert(OLD_SE != TREF(side_effect_handling)); + assert(0 < TREF(expr_depth)); + t1 = optyp_1.oprval.tref; + t2 = (oc_tab[t1->opcode].octype & OCT_COERCE) ? t1->operand[0].oprval.tref + : t1; /* need to step back past coerce of side effects in order to detect them */ + if (((OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) && (t1 == t2)) + saw_local = TRUE; /* left operand is an lvn */ + if (saw_local) + { + if ((TREF(side_effect_base))[TREF(expr_depth)]) + saw_se = TRUE; + if (saw_se || (OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) + { /* chain stores args to manage later insert of temps to hold lvn */ + tripbp = &ref1->backptr; + assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); + tripbp->bpt = ref1; + dqins(catbp, que, tripbp); + } + } + } if (TK_UNDERSCORE != TREF(window_token)) { + if (!saw_se) /* suppressed standard or lucked out on ordering */ + saw_local = FALSE; /* just clear the backptrs - shut off other processing */ + dqloop(catbp, que, tripbp) + { /* work chained arguments which are in reverse order */ + argtrip = tripbp->bpt; + assert(NULL != argtrip); + dqdel(tripbp, que); + tripbp->bpt = NULL; + if (!saw_local) + continue; + /* some need to insert temps */ + for (optyp_ptr = &argtrip->operand[0]; INDR_REF == optyp_ptr->oprclass; + optyp_ptr = optyp_ptr->oprval.indr) + ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ + t1 = optyp_ptr->oprval.tref; + if ((OC_VAR == t1->opcode) || (OC_GETINDX == t1->opcode)) + { /* have an lvn that needs a temp because threat from some side effect */ + argtrip = maketriple(OC_STOTEMP); + argtrip->operand[0] = put_tref(t1); + dqins(t1, exorder, argtrip); /* NOTE: violates infomation hiding */ + optyp_ptr->oprval.tref = argtrip; + if (se_warn) + ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1); + } + } /* end of side effect processing */ + assert((catbp == catbp->que.fl) && (catbp == catbp->que.bl) && (NULL == catbp->bpt)); assert(op_count > 1); ref->operand[0] = put_ilit(op_count); ins_triple(ref); break; } advancewindow(); - if (!expratom(&x1)) + if (!expratom(&optyp_1)) { stx_error(ERR_RHMISSING); return EXPR_FAIL; } - coerce(&x1, type); + coerce(&optyp_1, type); } } else { @@ -98,24 +160,40 @@ int eval_expr(oprtype *a) ind_pat = TRUE; advancewindow(); } - if (!compile_pattern(&x2, ind_pat)) + if (!compile_pattern(&optyp_2, ind_pat)) return EXPR_FAIL; } else { advancewindow(); - if (!expratom(&x2)) + if (!expratom(&optyp_2)) { stx_error(ERR_RHMISSING); return EXPR_FAIL; } } - coerce(&x2, type); - ref = newtriple(i); - ref->operand[0] = x1; - ref->operand[1] = x2; + coerce(&optyp_2, type); + ref1 = optyp_1.oprval.tref; + if (((OC_VAR == ref1->opcode) || (OC_GETINDX == ref1->opcode)) + && (TREF(side_effect_base))[TREF(expr_depth)]) + { /* this section is to protect lvns from changes by a following side effect extrinsic or function + * by inserting a temporary to capture the lvn evaluation before it's changed by a "later" or + * "to-the-right" side effect; a preexisting coerce or temporary might already to the job; + * indirects may already have been shifted to evaluate early + */ + assert(OLD_SE != TREF(side_effect_handling)); + ref = maketriple(OC_STOTEMP); + ref->operand[0] = optyp_1; + optyp_1 = put_tref(ref); + dqins(ref1, exorder, ref); /* NOTE: another violation of information hiding */ + if (se_warn) + ISSUE_SIDEEFFECTEVAL_WARNING(ref1->src.column + 1); + } + ref = newtriple(bin_opcode); + ref->operand[0] = optyp_1; + ref->operand[1] = optyp_2; } - x1 = put_tref(ref); + optyp_1 = put_tref(ref); } - *a = x1; + *a = optyp_1; return (OC_INDGLVN == (TREF(curtchain))->exorder.bl->opcode) ? EXPR_INDR : EXPR_GOOD; } diff --git a/sr_port/ex_tail.c b/sr_port/ex_tail.c index b088509..a9d1bea 100644 --- a/sr_port/ex_tail.c +++ b/sr_port/ex_tail.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,7 +31,7 @@ void ex_tail(oprtype *opr) if (w & OCT_EXPRLEAF) return; assert(TRIP_REF == t->operand[0].oprclass); - assert((TRIP_REF == t->operand[1].oprclass) || (NOCLASS == t->operand[1].oprclass)); + assert((TRIP_REF == t->operand[1].oprclass) || (NO_REF == t->operand[1].oprclass)); if (!(w & OCT_BOOL)) { for (i = t->operand; ARRAYTOP(t->operand) > i; i++) diff --git a/sr_port/exfun_frame.c b/sr_port/exfun_frame.c index 32590e4..62eb4a9 100644 --- a/sr_port/exfun_frame.c +++ b/sr_port/exfun_frame.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,10 +14,11 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mprof.h" #include "error.h" +#include "glvn_pool.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *msp, *stackbase, *stackwarn, *stacktop; @@ -38,9 +39,9 @@ void exfun_frame (void) 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); } assert (msp < stackbase); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); @@ -51,17 +52,20 @@ void exfun_frame (void) 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); } sf->temps_ptr = msp; assert(msp < stackbase); memset(msp, 0, sf->rvector->temp_size); - sf->for_ctrl_stack = NULL; + SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED); sf->ret_value = NULL; sf->dollar_test = -1; sf->old_frame_pointer = frame_pointer; + sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is + * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate. + */ frame_pointer = sf; assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); DBGEHND((stderr, "exfun_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n", diff --git a/sr_port/exfunc.c b/sr_port/exfunc.c index 8908062..1265e6e 100644 --- a/sr_port/exfunc.c +++ b/sr_port/exfunc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -52,10 +52,10 @@ int exfunc(oprtype *a, boolean_t alias_target) # endif } else { + assert(TRIP_REF == calltrip->operand[1].oprclass); calltrip_opr1_tref = calltrip->operand[1].oprval.tref; if (OC_EXTEXFUN == calltrip->opcode) { - assert(TRIP_REF == calltrip->operand[1].oprclass); if (OC_CDLIT == calltrip_opr1_tref->opcode) assert(CDLT_REF == calltrip_opr1_tref->operand[0].oprclass); else @@ -73,7 +73,7 @@ int exfunc(oprtype *a, boolean_t alias_target) return FALSE; } } - } else /* $$ @dlabel [actuallist] */ + } else /* indirect: $$@(glvn)[(actuallist)]; note disabiguating parens around glvn specifying dlabel*/ { assert(OC_COMMARG == calltrip->opcode); assert(TRIP_REF == calltrip->operand[1].oprclass); diff --git a/sr_port/expr.c b/sr_port/expr.c index 780e764..7ef2b1e 100644 --- a/sr_port/expr.c +++ b/sr_port/expr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,37 +10,35 @@ ****************************************************************/ #include "mdef.h" +#include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" #include "fullbool.h" int expr(oprtype *a, int m_type) { - int rval; + int rval; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (!(TREF(expr_depth))++) - TREF(expr_start) = TREF(expr_start_orig) = NULL; + INCREMENT_EXPR_DEPTH; if (EXPR_FAIL == (rval = eval_expr(a))) /* NOTE assignment */ { - TREF(expr_depth) = 0; + DECREMENT_EXPR_DEPTH; return FALSE; } coerce(a, (MUMPS_INT == m_type) ? OCT_MINT : OCT_MVAL); ex_tail(a); - if (TREF(expr_start) != TREF(expr_start_orig)) + if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) { - assert(TREF(shift_side_effects)); assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); - if ((OC_GVSAVTARG == (TREF(expr_start))->opcode) && (GTM_BOOL == TREF(gtm_fullbool))) + if ((OC_GVSAVTARG == (TREF(expr_start))->opcode) && ((GTM_BOOL == TREF(gtm_fullbool)) || !TREF(saw_side_effect))) { if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) - || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) - newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); + || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) + newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); } } - if (!(--(TREF(expr_depth)))) - TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE; + DECREMENT_EXPR_DEPTH; return rval; } diff --git a/sr_port/expritem.c b/sr_port/expritem.c index e6f0efd..c687029 100644 --- a/sr_port/expritem.c +++ b/sr_port/expritem.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,30 +33,17 @@ error_def(ERR_FNOTONSYS); error_def(ERR_INVFCN); error_def(ERR_INVSVN); error_def(ERR_RPARENMISSING); +error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); LITREF toktabtype tokentable[]; LITREF mval literal_null; +LITREF octabstruct oc_tab[]; #ifndef UNICODE_SUPPORTED #define f_char f_zchar #endif -#define ENCOUNTERED_SIDE_EFFECT \ -{ /* Needs #include "show_source_line" and #include "fullbool.h" */ \ - char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)]; \ - \ - if (TREF(shift_side_effects)) \ - { \ - TREF(saw_side_effect) = TRUE; \ - if (!run_time && (FULL_BOOL_WARN == TREF(gtm_fullbool))) \ - { /* warnings requested by by gtm_fullbool and enabled by eval_expr */ \ - show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE); \ - dec_err(VARLSTCNT(1) ERR_BOOLSIDEFFECT); \ - } \ - } \ -} - /* note that svn_index array provides indexes into this array for each letter of the * alphabet so changes here should be reflected there. */ @@ -73,8 +60,8 @@ LITDEF nametabent svn_names[] = ,{ 1, "P" }, { 8, "PRINCIPA*" } ,{ 1, "Q" }, { 4, "QUIT" } ,{ 1, "R" }, { 8, "REFERENC*" } - ,{ 1, "S" }, { 7, "STORAGE" } ,{ 2, "ST" }, { 5, "STACK" } + ,{ 1, "S" }, { 7, "STORAGE" } ,{ 2, "SY" }, { 6, "SYSTEM" } ,{ 1, "T" }, { 4, "TEST" } ,{ 2, "TL"}, { 6, "TLEVEL"} @@ -153,8 +140,8 @@ LITDEF svn_data_type svn_data[] = ,{ SV_PRINCIPAL, FALSE, ALL_SYS }, { SV_PRINCIPAL, FALSE, ALL_SYS } ,{ SV_QUIT, FALSE, ALL_SYS }, { SV_QUIT, FALSE, ALL_SYS } ,{ SV_REFERENCE, FALSE, ALL_SYS }, { SV_REFERENCE, FALSE, ALL_SYS } - ,{ SV_STORAGE, FALSE, ALL_SYS }, { SV_STORAGE, FALSE, ALL_SYS } ,{ SV_STACK, FALSE, ALL_SYS }, { SV_STACK, FALSE, ALL_SYS } + ,{ SV_STORAGE, FALSE, ALL_SYS }, { SV_STORAGE, FALSE, ALL_SYS } ,{ SV_SYSTEM, FALSE, ALL_SYS }, { SV_SYSTEM, FALSE, ALL_SYS } ,{ SV_TEST, FALSE, ALL_SYS }, { SV_TEST, FALSE, ALL_SYS } ,{ SV_TLEVEL, FALSE, ALL_SYS }, { SV_TLEVEL, FALSE, ALL_SYS } @@ -276,6 +263,7 @@ LITDEF nametabent fun_names[] = ,{2, "ZM"}, {8, "ZMESSAGE"} ,{2, "ZP"}, {8, "ZPREVIOU*"} ,{6, "ZPARSE"} + ,{5, "ZPEEK"} ,{3, "ZPI"}, {6, "ZPIECE"} ,{4, "ZPID"} ,{5, "ZPRIV"}, {8, "ZPRIVILE*"} @@ -288,6 +276,7 @@ LITDEF nametabent fun_names[] = ,{4, "ZTRI"}, {8, "ZTRIGGER"} ,{7, "ZTRNLNM"} ,{2, "ZW"}, {6, "ZWIDTH"} + ,{3, "ZWR"}, {6, "ZWRITE"} }; /* Index into fun_names array where entries that start with each letter of the alphabet begin. */ @@ -295,7 +284,7 @@ LITDEF unsigned char fun_index[27] = { 0, 2, 2, 4, 6, 8, 12, 14, 14, /* a b c d e f g h i */ 17, 19, 19, 21, 21, 25, 27, 29, 35, /* j k l m n o p q r */ - 39, 43, 47, 47, 48, 48, 48, 48, 113 /* s t u v w x y z ~ */ + 39, 43, 47, 47, 48, 48, 48, 48, 116 /* s t u v w x y z ~ */ }; /* Each entry corresponds to an entry in fun_names */ @@ -363,6 +352,7 @@ LITDEF fun_data_type fun_data[] = ,{ OC_FNZM, ALL_SYS }, { OC_FNZM, ALL_SYS } ,{ OC_FNZPREVIOUS, ALL_SYS }, { OC_FNZPREVIOUS, ALL_SYS } ,{ OC_FNZPARSE, ALL_SYS } + ,{ OC_FNZPEEK, UNIX_OS } ,{ OC_FNZPIECE, ALL_SYS }, { OC_FNZPIECE, ALL_SYS } ,{ OC_FNZPID, VMS_OS } ,{ OC_FNZPRIV, VMS_OS }, { OC_FNZPRIV, VMS_OS } @@ -375,6 +365,7 @@ LITDEF fun_data_type fun_data[] = ,{ OC_FNZTRIGGER, TRIGGER_OS }, { OC_FNZTRIGGER, TRIGGER_OS } ,{ OC_FNZTRNLNM, ALL_SYS } ,{ OC_FNZWIDTH, ALL_SYS }, { OC_FNZWIDTH, ALL_SYS } + ,{ OC_FNZWRITE, ALL_SYS }, { OC_FNZWRITE, ALL_SYS } }; /* Each entry corresponds to an entry in fun_names */ @@ -438,6 +429,7 @@ GBLDEF int (*fun_parse[])(oprtype *, opctype) = /* contains addresses so can't f_mint, f_mint, f_zprevious, f_zprevious, f_zparse, + f_zpeek, f_piece, f_piece, f_mint, f_mstr, f_mstr, @@ -449,16 +441,19 @@ GBLDEF int (*fun_parse[])(oprtype *, opctype) = /* contains addresses so can't f_translate, f_translate, f_ztrigger, f_ztrigger, f_ztrnlnm, - f_zwidth, f_zwidth + f_zwidth, f_zwidth, + f_zwrite, f_zwrite }; int expritem(oprtype *a) { - int i, index, sv_opcode; - triple *oldchain, *ref, tmpchain; - boolean_t parse_warn; - oprtype x1; - unsigned char type; + boolean_t parse_warn, saw_local, saw_se, se_warn; + oprtype *j, *k, x1; + int i, index, sv_opcode; + tbp argbp, *funcbp, *tripbp; + triple *argtrip, *functrip, *ref, *t1, *t2, *t3; + unsigned char type; + unsigned int argcnt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -509,10 +504,12 @@ int expritem(oprtype *a) stx_error(ERR_RPARENMISSING); return FALSE; case TK_DOLLAR: + parse_warn = saw_se = FALSE; if ((TK_DOLLAR == TREF(director_token)) || (TK_AMPERSAND == TREF(director_token))) { ENCOUNTERED_SIDE_EFFECT; TREF(temp_subs) = TRUE; + saw_se = TRUE; advancewindow(); if ((TK_DOLLAR == TREF(window_token)) ? (EXPR_FAIL == exfunc(a, FALSE)) : (EXPR_FAIL == extern_func(a))) @@ -525,7 +522,6 @@ int expritem(oprtype *a) stx_error(ERR_FCNSVNEXPECTED); return FALSE; } - parse_warn = FALSE; if (TK_LPAREN == TREF(director_token)) { index = namelook(fun_index, fun_names, (TREF(window_ident)).addr, (TREF(window_ident)).len); @@ -545,8 +541,9 @@ int expritem(oprtype *a) * and as input to the $INCR function on the right), we want an UNDEF * error to show up which means we need to set "temp_subs" to TRUE. */ - TREF(temp_subs) = TRUE; - ENCOUNTERED_SIDE_EFFECT; + ENCOUNTERED_SIDE_EFFECT; + TREF(temp_subs) = TRUE; + saw_se = TRUE; } } advancewindow(); @@ -601,12 +598,132 @@ int expritem(oprtype *a) } } else *a = put_lit((mval *)&literal_null); + return TRUE; } } - return TRUE; + if (saw_se && (OLD_SE != TREF(side_effect_handling))) + { + assert(0 < TREF(expr_depth)); + assert(TREF(expr_depth) <= TREF(side_effect_depth)); + (TREF(side_effect_base))[TREF(expr_depth)] = TRUE; + } + functrip = t1 = a->oprval.tref; + if (parse_warn || !(TREF(side_effect_base))[TREF(expr_depth)] || (NO_REF == functrip->operand[1].oprclass)) + return TRUE; /* 1 argument gets a pass */ + assert(0 < TREF(expr_depth)); + switch (functrip->opcode) + { + case OC_EXFUN: /* relies on protection from actuallist */ + case OC_EXTEXFUN: /* relies on protection from actuallist */ + case OC_FNFGNCAL: /* relies on protection from actuallist */ + case OC_FNGET: /* $get() gets a pass because protects itself */ + case OC_FNINCR: /* $increment() gets a pass because its ordering needs no protection */ + case OC_FNNEXT: /* only has 1 arg, but uses 2 for lvn interface */ + case OC_FNORDER: /* may have 1 or 2 args, internally uses 1 extra for lvn arg, but protects itself */ + case OC_FNZPREVIOUS: /* only has 1 arg, but uses 2 for lvn interface */ + case OC_INDINCR: /* $increment() gets a pass because its ordering needs no protection */ + return TRUE; + } /* default falls through */ + /* This block protects lvn evaluations in earlier arguments from changes caused by side effects in later + * arguments by capturing the prechange value in a temporary; coerce or preexisting temporary might already + * do the job and indirect local evaluations may already have shifted to occur earlier. This algorithm is similar + * to one in eval_expr for concatenation, but it must deal with possible arguments in both operands for + * both the initial triple and the last parameter triple, and the possibility of empty operand[0] in some + * functions so they have not been combined. We should have least one side effect (see compiler.h) and two + * arguments to bother - to know side effect, we have an array malloc'd and high water marked to avoid a limit + * on expression nesting depth, anchored by TREF(side_effect_base) and indexed by TREF(expr_depth) so + * ENCOUNTERED_SIDE_EFFECT can mark the prior level; f_select mallocs and free its own array + */ + assert(OLD_SE != TREF(side_effect_handling)); + funcbp = &functrip->backptr; /* borrow backptr to track args */ + tripbp = &argbp; + dqinit(tripbp, que); + tripbp->bpt = NULL; + assert(NULL == funcbp->bpt); + assert((funcbp == funcbp->que.fl) && (funcbp == funcbp->que.bl)); + saw_se = saw_local = FALSE; + for (argtrip = t1; ; argtrip = t1) + { /* work functrip,oprval.tref arguments forward */ + if (argtrip != functrip) + tripbp = &argtrip->backptr; + assert(NULL == tripbp->bpt); + for (j = argtrip->operand; j < ARRAYTOP(argtrip->operand); j++) + { /* process all (two) operands */ + t1 = j->oprval.tref; + if (NO_REF == j->oprclass) + continue; /* some functions leave holes in their arguments */ + if (((ARRAYTOP(argtrip->operand) - 1) == j) && (TRIP_REF == j->oprclass) + && (OC_PARAMETER == t1->opcode)) + break; /* only need to deal with last operand[1] */ + for (k = j; INDR_REF == k->oprclass; k = k->oprval.indr) + ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ + if (TRIP_REF != k->oprclass) + continue; /* something else - not to worry */ + /* may need to step back past coerce of side effects */ + t3 = k->oprval.tref; + t2 = (oc_tab[t3->opcode].octype & OCT_COERCE) ? t3->operand[0].oprval.tref : t3; + if ((OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) + { /* it's an lvn */ + if ((t3 != t2) || ((ARRAYTOP(argtrip->operand) - 1) == (&(argtrip->operand[i])))) + continue; /* but if it's the last or there's a coerce */ + saw_local = TRUE; /* left operand may need protection */ + } + if (!saw_local) + continue; /* no local yet to worry about */ + saw_se = TRUE; + if (NULL != tripbp->bpt) + { /* this one's already flagged */ + assert((ARRAYTOP(argtrip->operand) - 1) == j); + continue; + } + /* chain stores args to manage later insert of temps to hold left values */ + assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); + tripbp->bpt = argtrip; + dqins(funcbp, que, tripbp); + } + if ((NULL == t1) || (OC_PARAMETER != t1->opcode)) + break; /* end of arg list */ + assert(argtrip->operand[1].oprval.tref == t1); + } + if (!saw_se) /* might have lucked out on ordering */ + saw_local = FALSE; /* just clear the backptrs - shut off other processing */ + saw_se = FALSE; + se_warn = (!run_time && (SE_WARN == TREF(side_effect_handling))); + dqloop(funcbp, que, tripbp) + { /* work chained arguments which are in reverse order */ + argtrip = tripbp->bpt; + assert(NULL != argtrip); + dqdel(tripbp, que); + tripbp->bpt = NULL; + if (!saw_local) + continue; + /* found some need to insert temps */ + for (j = &argtrip->operand[1]; j >= argtrip->operand; j--) + { /* match to the operand - usually 0 but have to cover 1 as well */ + for (k = j; INDR_REF == k->oprclass; k = k->oprval.indr) + ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ + assert((TRIP_REF == k->oprclass) || (NO_REF == k->oprclass)); + t1 = k->oprval.tref; + if ((NO_REF == k->oprclass) || (OC_PARAMETER == t1->opcode) + || (oc_tab[t1->opcode].octype & OCT_COERCE)) + continue; + if ((OC_VAR == t1->opcode) || (OC_GETINDX == t1->opcode)) + { /* have an operand that needs a temp because threat from some side effect */ + ref = maketriple(OC_STOTEMP); + ref->operand[0] = put_tref(t1); + dqins(t1, exorder, ref); /* NOTE:this violates infomation hiding */ + k->oprval.tref = ref; + if (se_warn) + ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1); + } else + saw_se = TRUE; + } + } + assert((funcbp == funcbp->que.fl) && (funcbp == funcbp->que.bl) && (NULL == funcbp->bpt)); + return TRUE; /* end of order of evaluation processing for functions*/ case TK_COLON: stx_error(ERR_EXPR); return FALSE; - } + } /* case default: intentionally omitted as it simply uses the below return FALSE */ return FALSE; } diff --git a/sr_port/ext2jnl.c b/sr_port/ext2jnl.c index 1e93f0a..7383b42 100644 --- a/sr_port/ext2jnl.c +++ b/sr_port/ext2jnl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,7 +38,7 @@ static int4 num_records; /* callers please set up the proper condition-handlers */ /* expects a null-terminated ext_buff. does the equivalent but inverse of jnl2ext */ -char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec) +char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno) { char *ext_next; jnl_record *temp_rec; @@ -47,7 +47,7 @@ char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec) for ( ; (NULL != (ext_next = strchr(ext_buff, '\n'))); ) { *ext_next++ = '\0'; - rec = (jnl_record *)ext2jnl(ext_buff, rec); + rec = (jnl_record *)ext2jnl(ext_buff, rec, saved_jnl_seqno, saved_strm_seqno); assert(0 == (INTPTR_T)rec % JNL_REC_START_BNDRY); if (ext_stop == ext_buff) break; @@ -62,19 +62,18 @@ char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec) /* expects a single null-terminated ptr (equivalent to one line in the extract-file) */ -char *ext2jnl(char *ptr, jnl_record *rec) +char *ext2jnl(char *ptr, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno) { unsigned char *pool_save, ch, chtmp; - int keylength, keystate, len, i, reclen, temp_reclen; + char *val_off; + int keylength, keystate, len, i, reclen, temp_reclen, val_len; bool keepgoing; mstr src, des; jnl_record *temp_rec; muextract_type exttype; enum jnl_record_type rectype; jrec_suffix *suffix; - seq_num strm_seqno; uint4 nodeflags; - uint4 strm_num; DEBUG_ONLY(uint4 tcom_num = 0;) ext_stop = ptr + strlen(ptr) + 1; @@ -89,11 +88,10 @@ char *ext2jnl(char *ptr, jnl_record *rec) if (in_tp) { if (0 == num_records) - { - num_records++; rec->prefix.jrec_type = JRT_TSET; - } else + else rec->prefix.jrec_type = JRT_USET; + num_records++; } else rec->prefix.jrec_type = JRT_SET; break; @@ -102,11 +100,10 @@ char *ext2jnl(char *ptr, jnl_record *rec) if (in_tp) { if (0 == num_records) - { - num_records++; rec->prefix.jrec_type = JRT_TKILL; - } else + else rec->prefix.jrec_type = JRT_UKILL; + num_records++; } else rec->prefix.jrec_type = JRT_KILL; break; @@ -115,11 +112,10 @@ char *ext2jnl(char *ptr, jnl_record *rec) if (in_tp) { if (0 == num_records) - { - num_records++; rec->prefix.jrec_type = JRT_TZKILL; - } else + else rec->prefix.jrec_type = JRT_UZKILL; + num_records++; } else rec->prefix.jrec_type = JRT_ZKILL; break; @@ -129,11 +125,10 @@ char *ext2jnl(char *ptr, jnl_record *rec) if (in_tp) { if (0 == num_records) - { - num_records++; rec->prefix.jrec_type = JRT_TZTWORM; - } else + else rec->prefix.jrec_type = JRT_UZTWORM; + num_records++; } else GTMASSERT; /* ZTWORMHOLE should always been seen only inside a TP fence */ break; @@ -141,11 +136,10 @@ char *ext2jnl(char *ptr, jnl_record *rec) if (in_tp) { if (0 == num_records) - { - num_records++; rec->prefix.jrec_type = JRT_TZTRIG; - } else + else rec->prefix.jrec_type = JRT_UZTRIG; + num_records++; } else GTMASSERT; /* ZTRIGGER should always been seen only inside a TP fence */ break; @@ -204,15 +198,12 @@ char *ext2jnl(char *ptr, jnl_record *rec) assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the token/jnl_seqno field */ assert(NULL != ptr); - rec->jrec_null.jnl_seqno = asc2l((uchar_ptr_t)ptr,STRLEN(ptr)); + rec->jrec_null.jnl_seqno = saved_jnl_seqno; ptr = strtok(NULL, "\\"); /* get the strm_num field */ assert(NULL != ptr); - strm_num = asc2l((uchar_ptr_t)ptr,STRLEN(ptr)); ptr = strtok(NULL, "\\"); /* get the strm_seqno field */ assert(NULL != ptr); - strm_seqno = asc2l((uchar_ptr_t)ptr,STRLEN(ptr)); - UNIX_ONLY(rec->jrec_null.strm_seqno = SET_STRM_INDEX(strm_seqno, strm_num);) - VMS_ONLY(rec->jrec_null.strm_seqno = strm_seqno;) + rec->jrec_null.strm_seqno = saved_strm_seqno; switch(exttype) { case MUEXT_NULL: @@ -234,7 +225,7 @@ char *ext2jnl(char *ptr, jnl_record *rec) ptr = strtok(NULL, "\\"); /* get the update_num field */ assert(NULL != ptr); assert(OFFSETOF(struct_jrec_upd, update_num) == OFFSETOF(struct_jrec_ztworm, update_num)); - rec->jrec_set_kill.update_num = asc2i((uchar_ptr_t)ptr, STRLEN(ptr)); + rec->jrec_set_kill.update_num = num_records; if (MUEXT_ZTWORM != exttype) { ptr = strtok(NULL, "\\"); /* get the nodeflags field */ @@ -247,8 +238,8 @@ char *ext2jnl(char *ptr, jnl_record *rec) { assert(IS_SET_KILL_ZKILL_ZTRIG(rectype)); len = STRLEN(ptr); - keylength = zwrkeylength(ptr, len); /* determine length of key */ - + val_off = ptr; + keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, NULL, NULL); /* determine length of key */ REPL_DPRINT2("ext2jnl source:KEY=DATA:%s\n", ptr); assert(keylength <= len); str2gvkey_nogvfunc(ptr, keylength, gv_currkey); @@ -266,8 +257,8 @@ char *ext2jnl(char *ptr, jnl_record *rec) return (char_ptr_t)rec + reclen; } /* we have to get the data value now */ - src.len = len - keylength - 1; - src.addr = ptr + (keylength + 1); + src.len = val_len; + src.addr = val_off; } else { /* ZTWORMHOLE */ assert(IS_ZTWORM(rectype)); diff --git a/sr_port/f_data.c b/sr_port/f_data.c index 7b7a812..5b216fb 100644 --- a/sr_port/f_data.c +++ b/sr_port/f_data.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,7 +21,8 @@ error_def(ERR_VAREXPECTED); int f_data(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; + triple *oldchain, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -41,11 +42,9 @@ int f_data(oprtype *a, opctype op) ins_triple(r); break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -53,12 +52,7 @@ int f_data(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)(OC_FNDATA == op ? indir_fndata : indir_fnzdata)); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_fnumber.c b/sr_port/f_fnumber.c index 6a90aa2..48a7424 100644 --- a/sr_port/f_fnumber.c +++ b/sr_port/f_fnumber.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,8 +20,7 @@ error_def(ERR_COMMA); int f_fnumber(oprtype *a, opctype op) { - triple *ref, *next, *r; - oprtype z; + triple *r, *ref, *ref1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -34,26 +33,20 @@ int f_fnumber(oprtype *a, opctype op) return FALSE; } advancewindow(); - if (EXPR_FAIL == expr(&r->operand[1], MUMPS_STR)) + ref = newtriple(OC_PARAMETER); + r->operand[1] = put_tref(ref); + if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_STR)) return FALSE; - if (TK_COMMA != TREF(window_token)) - { - ref = newtriple(OC_FORCENUM); - ref->operand[0] = r->operand[0]; - r->operand[0] = put_tref(ref); - } else + ref1 = newtriple(OC_PARAMETER); + ref->operand[1] = put_tref(ref1); + if (TK_COMMA == TREF(window_token)) { advancewindow(); - if (EXPR_FAIL == expr(&z, MUMPS_INT)) + if (EXPR_FAIL == expr(&ref1->operand[1], MUMPS_INT)) return FALSE; - ref = newtriple(OC_FNJ3); - ref->operand[0] = r->operand[0]; - r->operand[0] = put_tref(ref); - next = newtriple(OC_PARAMETER); - ref->operand[1] = put_tref(next); - next->operand[0] = put_ilit((mint) 0); - next->operand[1] = z; - } + ref1->operand[0] = put_ilit((mint)(1)); /* flag that the 3rd argument is real */ + } else + ref1->operand[0] = ref1->operand[1] = put_ilit((mint)0); /* flag no 3rd argument and give it default value */ ins_triple(r); *a = put_tref(r); return TRUE; diff --git a/sr_port/f_get.c b/sr_port/f_get.c index c5ebece..8a515a5 100644 --- a/sr_port/f_get.c +++ b/sr_port/f_get.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,108 +10,108 @@ ****************************************************************/ #include "mdef.h" + #include "compiler.h" #include "opcode.h" -#include "toktyp.h" #include "indir_enum.h" -#include "mdq.h" +#include "toktyp.h" #include "mmemory.h" +#include "mdq.h" #include "advancewindow.h" #include "fullbool.h" +#include "glvn_pool.h" +#include "show_source_line.h" +GBLREF boolean_t run_time; +GBLREF short int source_column; + +error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); int f_get(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; - oprtype result, *result_ptr; + boolean_t ok, used_glvn_slot; + oprtype control_slot, def_opr, *def_oprptr, indir; + short int column; + triple *oldchain, *opptr, *r, *triptr; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - result_ptr = (oprtype *)mcalloc(SIZEOF(oprtype)); - result = put_indr(result_ptr); - r = maketriple(op); + oldchain = NULL; + used_glvn_slot = FALSE; + r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ switch (TREF(window_token)) { case TK_IDENT: - if (!lvn(&r->operand[0], OC_SRCHINDX, 0)) - return FALSE; - if (TK_COMMA != TREF(window_token)) - { - ins_triple(r); - *a = put_tref(r); - return TRUE; - } - r->opcode = OC_FNGET2; - r->operand[1] = result; + r->opcode = OC_FNGET; + ok = lvn(&r->operand[0], OC_SRCHINDX, 0); break; case TK_CIRCUMFLEX: - if (!gvn()) - return FALSE; - if (TK_COMMA == TREF(window_token)) - { /* 2-argument $GET with global-variable as first argument. In this case generate the following - * sequence of opcodes. OC_FNGVGET1, opcodes-to-evaluate-second-argument-expression, OC_FNGVGET2 - */ - r->opcode = OC_FNGVGET1; - ins_triple(r); - triptr = r; - /* Prepare triple for OC_FNGVGET2 */ - r = maketriple(op); - r->opcode = OC_FNGVGET2; - r->operand[0] = put_tref(triptr); - r->operand[1] = result; - } else - { - r->opcode = OC_FNGVGET; - r->operand[0] = result; - } + r->opcode = OC_FNGVGET; + ok = gvn(); break; case TK_ATSIGN: - r->opcode = OC_INDGET; - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + r->opcode = OC_INDGET2; + if (SHIFT_SIDE_EFFECTS) + START_GVBIND_CHAIN(&save_state, oldchain); + if (ok = indirection(&indir)) /* NOTE: assignment */ { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); - if (!indirection(&r->operand[0])) - { - setcurtchain(oldchain); - return FALSE; - } - r->operand[1] = result; - if (TK_COMMA == TREF(window_token)) - { - advancewindow(); - if (EXPR_FAIL == expr(result_ptr, MUMPS_EXPR)) - return FALSE; - } else - *result_ptr = put_str(0, 0); - ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); - *a = put_tref(r); - return TRUE; + used_glvn_slot = TRUE; + INSERT_INDSAVGLVN(control_slot, indir, ANY_SLOT, 1); + r->operand[0] = control_slot; } - if (!indirection(&r->operand[0])) - return FALSE; - r->operand[1] = result; break; default: + ok = FALSE; + break; + } + if (!ok) + { + if (NULL != oldchain) + setcurtchain(oldchain); stx_error(ERR_VAREXPECTED); return FALSE; } - if (TK_COMMA == TREF(window_token)) - { - advancewindow(); - if (EXPR_FAIL == expr(result_ptr, MUMPS_EXPR)) - return FALSE; - } else - *result_ptr = put_str(0, 0); + opptr = r; ins_triple(r); + if (used_glvn_slot) + { /* house cleaning for the indirection */ + triptr = newtriple(OC_GLVNPOP); + triptr->operand[0] = control_slot; + } + if (TK_COMMA == TREF(window_token)) + { /* two argument form with a specified default value */ + advancewindow(); + column = source_column; + def_oprptr = (oprtype *)mcalloc(SIZEOF(oprtype)); + def_opr = put_indr(def_oprptr); + DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ + if (EXPR_FAIL == expr(def_oprptr, MUMPS_EXPR)) + { + if (NULL != oldchain) + setcurtchain(oldchain); + return FALSE; + } + if (SE_WARN_ON && (TREF(side_effect_base))[TREF(expr_depth)]) + ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); + if (OC_FNGET == r->opcode) + r->opcode = OC_FNGET1; + else if (OC_FNGVGET == r->opcode) + r->opcode = OC_FNGVGET1; + else + assert(OC_INDGET2 == r->opcode); + r = newtriple(OC_FNGET2); + r->operand[0] = put_tref(opptr); + r->operand[1] = def_opr; + } else if (OC_INDGET2 == r->opcode) + { /* indirect always acts like a two argument form so force that along with an empty string default */ + r = newtriple(OC_FNGET2); + r->operand[0] = put_tref(opptr); + r->operand[1] = put_str(0, 0); + } + if (NULL != oldchain) + PLACE_GVBIND_CHAIN(&save_state, oldchain); /* shift chain back to "expr_start" */ *a = put_tref(r); return TRUE; } diff --git a/sr_port/f_incr.c b/sr_port/f_incr.c index a676903..b497673 100644 --- a/sr_port/f_incr.c +++ b/sr_port/f_incr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,7 +24,6 @@ error_def(ERR_VAREXPECTED); int f_incr(oprtype *a, opctype op) { boolean_t ok; - char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)]; oprtype *increment; triple incrchain, *oldchain, *r, *savptr, targchain, tmpexpr, *triptr; DCL_THREADGBL_ACCESS; @@ -33,7 +32,6 @@ int f_incr(oprtype *a, opctype op) r = maketriple(op); /* may need to evaluate the increment (2nd arg) early and use result later: prepare to juggle triple chains */ dqinit(&targchain, exorder); /* a place for the operation and the target */ - dqinit(&incrchain, exorder); /* a place for the increment */ dqinit(&tmpexpr, exorder); /* a place to juggle the shifted chain in case it's active */ triptr = TREF(expr_start); savptr = TREF(expr_start_orig); /* but make sure expr_start_orig == expr_start since this is a new chain */ @@ -67,24 +65,24 @@ int f_incr(oprtype *a, opctype op) setcurtchain(oldchain); return FALSE; } - assert(TREF(expr_start) == tmpexpr.exorder.bl); /* maks sure nothing else did something fancy */ TREF(expr_start) = triptr; /* restore original shift chain */ TREF(expr_start_orig) = savptr; increment = &r->operand[1]; - setcurtchain(&incrchain); /* now to the increment expr, which must evaluate before the glvn in $INCR(glvn,expr) */ if (TK_COMMA != TREF(window_token)) *increment = put_ilit(1); /* default optional increment to 1 */ else { + dqinit(&incrchain, exorder); /* a place for the increment */ + setcurtchain(&incrchain); /* increment expr must evaluate before the glvn in $INCR(glvn,expr) */ advancewindow(); if (EXPR_FAIL == expr(increment, MUMPS_NUM)) { setcurtchain(oldchain); return FALSE; } + dqadd(&targchain, &incrchain, exorder); /* dir before targ - this is a violation of info hiding */ + setcurtchain(&targchain); } - triptr = incrchain.exorder.bl; /* prepare to park the target after the increment */ - dqadd(triptr, &targchain, exorder); /* this is a violation of info hiding */ coerce(increment, OCT_MVAL); ins_triple(r); if (&tmpexpr != tmpexpr.exorder.bl) @@ -92,6 +90,7 @@ int f_incr(oprtype *a, opctype op) assert(TREF(shift_side_effects)); dqadd(TREF(expr_start), &tmpexpr, exorder); /* this is a violation of info hiding */ TREF(expr_start) = tmpexpr.exorder.bl; + assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); triptr = newtriple(OC_GVRECTARG); /* restore the result of the last gvn to preserve $referece (the naked) */ triptr->operand[0] = put_tref(TREF(expr_start)); } @@ -99,17 +98,18 @@ int f_incr(oprtype *a, opctype op) { /* put it on the end of the main chain as there's no reason to play more with the ordering */ setcurtchain(oldchain); triptr = (TREF(curtchain))->exorder.bl; - dqadd(triptr, &incrchain, exorder); /* this is a violation of info hiding */ + dqadd(triptr, &targchain, exorder); /* this is a violation of info hiding */ } else /* need full side effects or indirect 1st argument so put everything on the shift chain */ { /* add the chain after "expr_start" which may be much before "curtchain" */ newtriple(OC_GVSAVTARG); setcurtchain(oldchain); assert(NULL != TREF(expr_start)); - dqadd(TREF(expr_start), &incrchain, exorder); /* this is a violation of info hiding */ - TREF(expr_start) = incrchain.exorder.bl; + dqadd(TREF(expr_start), &targchain, exorder); /* this is a violation of info hiding */ + TREF(expr_start) = targchain.exorder.bl; triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } + /* $increment() args need to avoid side effect processing but that's handled in expritem so eval_expr gets $i()'s SE flag */ *a = put_tref(r); return TRUE; } diff --git a/sr_port/f_name.c b/sr_port/f_name.c index b16768d..d5260ac 100644 --- a/sr_port/f_name.c +++ b/sr_port/f_name.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,14 +17,21 @@ #include "indir_enum.h" #include "advancewindow.h" #include "subscript.h" +#include "fullbool.h" +#include "show_source_line.h" +GBLREF boolean_t run_time; +GBLREF short int source_column; + +error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); int f_name(oprtype *a, opctype op) { boolean_t gbl; oprtype *depth; - triple *r; + short int column; + triple *r, *s; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -42,10 +49,15 @@ int f_name(oprtype *a, opctype op) depth = &r->operand[0]; break; case TK_ATSIGN: - r->opcode = OC_INDFNNAME; - if (!indirection(&(r->operand[0]))) + r->opcode = OC_INDFNNAME2; /* chomps extra subscripts of resulting string */ + s = maketriple(OC_INDFNNAME); + if (!indirection(&(s->operand[0]))) return FALSE; - depth = &r->operand[1]; + s->operand[1] = put_ilit(MAX_LVSUBSCRIPTS + 1); /* first, get all the subscripts. r will chomp them */ + coerce(&s->operand[1], OCT_MVAL); + ins_triple(s); + depth = &r->operand[0]; + r->operand[1] = put_tref(s); break; default: stx_error(ERR_VAREXPECTED); @@ -59,9 +71,13 @@ int f_name(oprtype *a, opctype op) assert(MAX_LVSUBSCRIPTS == MAX_GVSUBSCRIPTS); /* add assert to ensure our assumption is valid */ } else { + DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ advancewindow(); + column = source_column; if (EXPR_FAIL == expr(depth, MUMPS_STR)) return FALSE; + if (!run_time && (OC_INDFNNAME2 == r->opcode) && (SE_WARN == TREF(side_effect_handling))) + ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); } coerce(depth, OCT_MVAL); ins_triple(r); diff --git a/sr_port/f_next.c b/sr_port/f_next.c index ccf9555..8a5bd5d 100644 --- a/sr_port/f_next.c +++ b/sr_port/f_next.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,7 +23,8 @@ error_def(ERR_VAREXPECTED); int f_next(oprtype *a, opctype op) { - triple *oldchain, *ref, *r, tmpchain, *triptr; + triple *oldchain, *ref, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -44,8 +45,7 @@ int f_next(oprtype *a, opctype op) ref = TREF(shift_side_effects) ? TREF(expr_start) : (TREF(curtchain))->exorder.bl; if (!gvn()) return FALSE; - /* the following assumes OC_LIT and OC_GVNAME are all one - * gets for an unsubscripted global variable reference */ + /* the following assumes OC_LIT and OC_GVNAME are all one gets for an unsubscripted global variable reference */ if ((TREF(shift_side_effects) ? TREF(expr_start) : TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl == ref) { stx_error(ERR_GVNEXTARG); @@ -55,11 +55,9 @@ int f_next(oprtype *a, opctype op) ins_triple(r); break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -67,12 +65,7 @@ int f_next(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnnext); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_order.c b/sr_port/f_order.c index 79c240c..18ca797 100644 --- a/sr_port/f_order.c +++ b/sr_port/f_order.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,275 +21,207 @@ #include "advancewindow.h" #include "mvalconv.h" #include "fullbool.h" +#include "glvn_pool.h" +#include "show_source_line.h" -/* The following are static triples used to pass information between functions "f_order" and "set_opcode" */ -STATICDEF triple *gvo2_savtarg1; /* Save gv_currkey after processing gvn1 in $ORDER(gvn1,expr) */ -STATICDEF triple *gvo2_savtarg2; /* Save gv_currkey after processing gvn1 and expr in $ORDER(gvn1,expr) but before executing - * the runtime function for $ORDER (OC_GVO2) */ -STATICDEF triple *gvo2_pre_srchindx_triple; /* the end of the triple chain before OC_SRCHINDX got inserted */ +GBLREF boolean_t run_time; +GBLREF short int source_column; error_def(ERR_ORDER2); +error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); -LITDEF opctype order_opc[last_obj][last_dir] = +LITDEF opctype order_opc[LAST_OBJECT][LAST_DIRECTION] = { - /* forward backward undecided */ - { OC_GVORDER, OC_ZPREVIOUS, OC_GVO2 }, /* global */ - { OC_FNLVNAME, OC_FNLVPRVNAME, OC_FNLVNAMEO2 }, /* local_name */ - { OC_FNORDER, OC_FNZPREVIOUS, OC_FNO2 }, /* local_sub */ - { OC_INDFUN, OC_INDFUN, OC_INDO2 } /* indir */ + /* FORWARD BACKWARD TBD */ + { OC_GVORDER, OC_ZPREVIOUS, OC_GVO2 }, /* GLOBAL */ + { OC_FNORDER, OC_FNZPREVIOUS, OC_FNO2 }, /* LOCAL */ + { OC_FNLVNAME, OC_FNLVPRVNAME, OC_FNLVNAMEO2 }, /* LOCAL_NAME */ + { OC_INDFUN, OC_INDFUN, OC_INDO2 } /* INDIRECT */ }; -STATICFNDEF boolean_t set_opcode(triple *r, oprtype *result, oprtype *result_ptr, oprtype *second_opr, enum order_obj object) -{ - enum order_dir direction; - int4 dummy_intval; - triple *gvo2_post_srchindx_triple, *oldchain, *s, *t1, *t2, *tp, tmpchain, *tmptriple, *x; - DCL_THREADGBL_ACCESS; - - SETUP_THREADGBL_ACCESS; - if (TK_COMMA == TREF(window_token)) - { - advancewindow(); - if (local_sub == object) - gvo2_post_srchindx_triple = (TREF(curtchain))->exorder.bl; - if (global == object) - { /* Prepare for OC_GVSAVTARG/OC_GVRECTARG processing in case second argument has global references. - * If the first argument to $ORDER is a global variable and the second argument is a literal, - * then the opcodes generated are (in that order) - * - * OC_GVNAME, EXPR, OC_GVO2 - * - * But if the first argument is a global variable and the second argument is an expression that is - * not a literal, then the opcodes generated are (in that order) - * - * OC_GVNAME, OC_SAVTARG1, EXPR, OC_SAVTARG2, OC_RECTARG1, OC_GVO2, OC_RECTARG2 - * - * Note that OC_SAVTARG1 and OC_SAVTARG2 are the same opcode OC_SAVTARG but are placeholder indicators. - * Similarly OC_RECTARG1 and OC_RECTARG2. - * - * This opcode order ensures that OC_GVO2 is presented the right gv_currkey on entry into function - * "op_gvo2" as well as ensure that after the $ORDER returns, the naked indicator is set correctly. - */ - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); - } - if (EXPR_FAIL == expr(result_ptr, MUMPS_EXPR)) - { - if (global == object) - setcurtchain(oldchain); - return FALSE; - } - assert(TRIP_REF == result_ptr->oprclass); - s = result_ptr->oprval.tref; - if (OC_LIT == s->opcode) - { - if (MV_IS_TRUEINT(&s->operand[0].oprval.mlit->v, &dummy_intval) - && ((MV_BIAS == s->operand[0].oprval.mlit->v.m[1]) - || (-MV_BIAS == s->operand[0].oprval.mlit->v.m[1]))) - direction = (MV_BIAS == s->operand[0].oprval.mlit->v.m[1]) ? forward : backward; - else - { - if (global == object) - setcurtchain(oldchain); - stx_error(ERR_ORDER2); - return FALSE; - } - if (global == object) - { /* No need for OC_GVSAVTARG/OC_GVRECTARG processing as expr is a constant (no global references) */ - setcurtchain(oldchain); - tmptriple = (TREF(curtchain))->exorder.bl; - dqadd(tmptriple, &tmpchain, exorder); - } - } else - { - direction = undecided; - if (global == object) - { /* Need to do OC_GVSAVTARG/OC_GVRECTARG processing as expr could contain global references */ - assert(OC_GVO2 == order_opc[object][direction]); - setcurtchain(oldchain); - /* Note down the value of gv_currkey at this point */ - newtriple(OC_GVSAVTARG); - /* Add second argument triples */ - gvo2_savtarg1 = (TREF(curtchain))->exorder.bl; - tmptriple = (TREF(curtchain))->exorder.bl; - dqadd(tmptriple, &tmpchain, exorder); - /* Note down the value of gv_currkey at this point */ - newtriple(OC_GVSAVTARG); - gvo2_savtarg2 = (TREF(curtchain))->exorder.bl; - } - } - } else - direction = forward; - switch (object) - { - case global: - if (direction == undecided) - *second_opr = *result; - break; - case local_name: - if (direction == undecided) - *second_opr = *result; - else if (direction == forward) - { /* The op_fnlvname rtn needs an extra parm - insert it now */ - assert(OC_FNLVNAME == order_opc[object][direction]); - *second_opr = put_ilit(0); /* Flag not to return aliases with no value */ - } - break; - case local_sub: - if (direction == undecided) - { /* This is $ORDER(subscripted-local-variable, expr). The normal order of evaluation would be - * - * 1) Evaluate subscripts of local variable - * 2) Do OC_SRCHINDX - * 3) Evaluate expr - * 4) Do OC_FNORDER - * - * But it is possible that the subscripted local-variable is defined only by an extrinsic function - * that is part of "expr". In that case, we should NOT do the OC_SRCHINDX before "expr" gets - * evaluated (as otherwise OC_SRCHINDX will not return the right lv_val structure). That is, the - * order of evaluation should be - * - * 1) Evaluate subscripts of local variable - * 2) Evaluate expr - * 3) Do OC_SRCHINDX - * 4) Do OC_FNORDER - * - * The triples need to be reordered accordingly to implement the above evaluation order. - * This reordering of triples is implemented below by recording the end of the triple chain - * just BEFORE (variable "gvo2_pre_srchindx_triple") and just AFTER (variable - * "gvo2_post_srchindx_triple") parsing the subscripted-local-variable first argument to - * $ORDER. This is done partly in the function "f_order" and partly in "set_opcode". Once these - * are recorded, the second argument "expr" is parsed and the triples generated. After this, we - * start from gvo2_post_srchindx_triple and go back the triple chain until we find the OC_SRCHINDX - * opcode or gvo2_pre_srchindx_triple whichever is earlier (e.g. for unsubscripted names - * OC_SRCHINDX triple is not generated). This portion of the triple chain (that does the - * OC_SRCHINDX computation) is deleted and added at the end of the current triple chain. This - * accomplishes the desired evaluation reordering. Note that the value of the naked indicator is - * not affected by this reordering (since OC_SRCHINDX does not do global references). - */ - for (tmptriple = gvo2_post_srchindx_triple; (OC_SRCHINDX != tmptriple->opcode); - tmptriple = tmptriple->exorder.bl) - { - if (tmptriple == gvo2_pre_srchindx_triple) - break; - } - if (OC_SRCHINDX == tmptriple->opcode) - { - t1 = tmptriple->exorder.bl; - t2 = gvo2_post_srchindx_triple->exorder.fl; - dqdelchain(t1,t2,exorder); - dqinit(&tmpchain, exorder); - tmpchain.exorder.fl = tmptriple; - tmpchain.exorder.bl = gvo2_post_srchindx_triple; - gvo2_post_srchindx_triple->exorder.fl = &tmpchain; - tmptriple->exorder.bl = &tmpchain; - tmptriple = (TREF(curtchain))->exorder.bl; - dqadd(tmptriple, &tmpchain, exorder); - } - s = newtriple(OC_PARAMETER); - s->operand[0] = *second_opr; - s->operand[1] = *result; - *second_opr = put_tref(s); - } - break; - case indir: - if (direction == forward) - *second_opr = put_ilit((mint)indir_fnorder1); - else - if (direction == backward) - *second_opr = put_ilit((mint)indir_fnzprevious); - else - *second_opr = *result; - break; - default: - assert(FALSE); - } - r->opcode = order_opc[object][direction]; - return TRUE; -} - int f_order(oprtype *a, opctype op) { + boolean_t ok, used_glvn_slot; + enum order_dir direction; enum order_obj object; - oprtype result, *result_ptr, *second_opr; - triple *oldchain, *r, tmpchain, *triptr; + int4 intval; + opctype gv_oc; + oprtype control_slot, dir_opr, *dir_oprptr, *next_oprptr; + short int column; + triple *oldchain, *r, *sav_dirref, *sav_gv1, *sav_gvn, *sav_lvn, *sav_ref, *share, *triptr; + triple *chain2, *obp, tmpchain2; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - result_ptr = (oprtype *)mcalloc(SIZEOF(oprtype)); - result = put_indr(result_ptr); - r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ + oldchain = sav_dirref = NULL; /* default to no direction and no shifting indirection */ + used_glvn_slot = FALSE; + sav_gv1 = TREF(curtchain); + r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ switch (TREF(window_token)) { case TK_IDENT: if (TK_LPAREN == TREF(director_token)) - { /* See comment in "set_opcode" for why we maintain "gvo2_pre_srchindx_triple" here */ - gvo2_pre_srchindx_triple = (TREF(curtchain))->exorder.bl; - if (!lvn(&r->operand[0], OC_SRCHINDX, r)) - return FALSE; - object = local_sub; + { + object = LOCAL; + ok = lvn(&r->operand[0], OC_SRCHINDX, r); /* 2nd arg causes us to mess below with return from lvn */ } else { + object = LOCAL_NAME; + ok = TRUE; r->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); - object = local_name; } - second_opr = &r->operand[1]; + next_oprptr = &r->operand[1]; break; case TK_CIRCUMFLEX: - if (!gvn()) - return FALSE; - object = global; - second_opr = &r->operand[0]; + object = GLOBAL; + ok = gvn(); + sav_gvn = (TREF(curtchain))->exorder.bl; + next_oprptr = &r->operand[0]; break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) - { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); - if (!indirection(&r->operand[0])) - { - setcurtchain(oldchain); - return FALSE; - } - if (!set_opcode(r, &result, result_ptr, &r->operand[1], indir)) - return FALSE; - ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); - *a = put_tref(r); - return TRUE; - } - if (!indirection(&r->operand[0])) - return FALSE; - object = indir; - second_opr = &r->operand[1]; + object = INDIRECT; + if (SHIFT_SIDE_EFFECTS) + START_GVBIND_CHAIN(&save_state, oldchain); + ok = indirection(&r->operand[0]); + next_oprptr = &r->operand[1]; break; default: + ok = FALSE; + break; + } + if (!ok) + { + if (NULL != oldchain) + setcurtchain(oldchain); stx_error(ERR_VAREXPECTED); return FALSE; } - if (set_opcode(r, &result, result_ptr, second_opr, object)) - { /* Restore gv_currkey of the first argument (in case the second expression contained a global reference). - * This will ensure op_gvo2 has gv_currkey set properly on entry */ - if (OC_GVO2 == r->opcode) + if (TK_COMMA != TREF(window_token)) + direction = FORWARD; /* default direction */ + else + { /* two argument form: ugly logic for direction */ + advancewindow(); + column = source_column; + dir_oprptr = (oprtype *)mcalloc(SIZEOF(oprtype)); + dir_opr = put_indr(dir_oprptr); + sav_ref = newtriple(OC_GVSAVTARG); + DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ + if (EXPR_FAIL == expr(dir_oprptr, MUMPS_EXPR)) { - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(gvo2_savtarg1); - ins_triple(r); - /* Restore gv_currkey to what it was after evaluating the second argument (to preserved naked indicator) */ - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(gvo2_savtarg2); + if (NULL != oldchain) + setcurtchain(oldchain); + return FALSE; + } + assert(TRIP_REF == dir_oprptr->oprclass); + triptr = dir_oprptr->oprval.tref; + if (OC_LIT == triptr->opcode) + { /* if direction is a literal - pick it up and stop flailing about */ + if (MV_IS_TRUEINT(&triptr->operand[0].oprval.mlit->v, &intval) && (1 == intval || -1 == intval)) + { + direction = (1 == intval) ? FORWARD : BACKWARD; + sav_ref->opcode = OC_NOOP; + sav_ref = NULL; + } else + { /* bad direction */ + if (NULL != oldchain) + setcurtchain(oldchain); + stx_error(ERR_ORDER2); + return FALSE; + } } else + { + direction = TBD; + sav_dirref = newtriple(OC_GVSAVTARG); /* $R reflects direction eval even if we revisit 1st arg */ + triptr = newtriple(OC_GVRECTARG); + triptr->operand[0] = put_tref(sav_ref); + switch (object) + { + case GLOBAL: /* The direction may have had a side effect, so take copies of subscripts */ + *next_oprptr = *dir_oprptr; + for (; sav_gvn != sav_gv1; sav_gvn = sav_gvn->exorder.bl) + { /* hunt down the gv opcode */ + gv_oc = sav_gvn->opcode; + if ((OC_GVNAME == gv_oc) || (OC_GVNAKED == gv_oc) || (OC_GVEXTNAM == gv_oc)) + break; + } + assert((OC_GVNAME == gv_oc) || (OC_GVNAKED == gv_oc) || (OC_GVEXTNAM == gv_oc)); + TREF(temp_subs) = TRUE; + create_temporaries(sav_gvn, gv_oc); + break; + case LOCAL: /* Additionally need to move srchindx triple to after potential side effect */ + triptr = newtriple(OC_PARAMETER); + triptr->operand[0] = *next_oprptr; + triptr->operand[1] = *(&dir_opr); + *next_oprptr = put_tref(triptr); + sav_lvn = r->operand[0].oprval.tref; + assert((OC_SRCHINDX == sav_lvn->opcode) || (OC_VAR == sav_lvn->opcode)); + if (OC_SRCHINDX == sav_lvn->opcode) + { + dqdel(sav_lvn, exorder); + ins_triple(sav_lvn); + TREF(temp_subs) = TRUE; + create_temporaries(sav_lvn, OC_SRCHINDX); + } + assert(&r->operand[1] == next_oprptr); + assert(TRIP_REF == next_oprptr->oprclass); + assert(OC_PARAMETER == next_oprptr->oprval.tref->opcode); + assert(TRIP_REF == next_oprptr->oprval.tref->operand[0].oprclass); + sav_lvn = next_oprptr->oprval.tref->operand[0].oprval.tref; + if ((OC_VAR == sav_lvn->opcode) || (OC_GETINDX == sav_lvn->opcode)) + { /* lvn excludes the last subscript from srchindx and attaches it to the "parent" + * now we find it is an lvn and needs protection too + */ + triptr = maketriple(OC_STOTEMP); + triptr->operand[0] = put_tref(sav_lvn); + dqins(sav_lvn, exorder, triptr); /* NOTE: violation of info hiding */ + next_oprptr->oprval.tref->operand[0].oprval.tref = triptr; + } + break; + case INDIRECT: /* Save and restore the variable lookup for true left-to-right evaluation */ + *next_oprptr = *dir_oprptr; + used_glvn_slot = TRUE; + dqinit(&tmpchain2, exorder); + chain2 = setcurtchain(&tmpchain2); + INSERT_INDSAVGLVN(control_slot, r->operand[0], ANY_SLOT, 1); + setcurtchain(chain2); + obp = sav_ref->exorder.bl; /* insert before second arg */ + dqadd(obp, &tmpchain2, exorder); + r->operand[0] = control_slot; + break; + case LOCAL_NAME: /* left argument is a string - side effect can't screw it up */ + *next_oprptr = *dir_oprptr; + break; + default: + assert(FALSE); + } ins_triple(r); - *a = put_tref(r); - return TRUE; + if (used_glvn_slot) + { + triptr = newtriple(OC_GLVNPOP); + triptr->operand[0] = control_slot; + } + if (SE_WARN_ON && (TREF(side_effect_base))[TREF(expr_depth)]) + ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); + DISABLE_SIDE_EFFECT_AT_DEPTH; /* usual side effect processing doesn't work for $ORDER() */ + } } - return FALSE; + if (TBD != direction) + ins_triple(r); + if (NULL != sav_dirref) + { + triptr = newtriple(OC_GVRECTARG); + triptr->operand[0] = put_tref(sav_dirref); + } + r->opcode = order_opc[object][direction]; /* finally - the op code */ + if (NULL != oldchain) + PLACE_GVBIND_CHAIN(&save_state, oldchain); /* shift chain back to "expr_start" */ + if (OC_FNLVNAME == r->opcode) + *next_oprptr = put_ilit(0); /* Flag not to return aliases with no value */ + if (OC_INDFUN == r->opcode) + *next_oprptr = put_ilit((mint)((FORWARD == direction) ? indir_fnorder1 : indir_fnzprevious)); + *a = put_tref(r); + return TRUE; } diff --git a/sr_port/f_order1.c b/sr_port/f_order1.c index b3ea7b4..108835b 100644 --- a/sr_port/f_order1.c +++ b/sr_port/f_order1.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,8 @@ error_def(ERR_VAREXPECTED); int f_order1(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; + triple *oldchain, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -50,11 +51,9 @@ int f_order1(oprtype *a, opctype op) ins_triple(r); break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -62,12 +61,7 @@ int f_order1(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnorder1); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_query.c b/sr_port/f_query.c index 95212b0..6177128 100644 --- a/sr_port/f_query.c +++ b/sr_port/f_query.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,11 +17,12 @@ #include "mdq.h" #include "fullbool.h" -error_def (ERR_VAREXPECTED); +error_def(ERR_VAREXPECTED); int f_query(oprtype *a, opctype op) { - triple *oldchain, *r, *r0, *r1, tmpchain, *triptr; + triple *oldchain, *r, *r0, *r1; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -73,11 +74,9 @@ int f_query(oprtype *a, opctype op) ins_triple(r); break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -85,12 +84,7 @@ int f_query(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnquery); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_select.c b/sr_port/f_select.c index a0649ac..9eff1eb 100644 --- a/sr_port/f_select.c +++ b/sr_port/f_select.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,38 +10,53 @@ ****************************************************************/ #include "mdef.h" +#include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "mmemory.h" #include "advancewindow.h" +#include "fullbool.h" error_def(ERR_COLON); error_def(ERR_SELECTFALSE); LITREF octabstruct oc_tab[]; +#define SELECT_CLEANUP \ +{ \ + free(TREF(side_effect_base)); \ + TREF(side_effect_base) = save_se_base; \ + TREF(side_effect_depth) = save_se_depth; \ + TREF(expr_depth) = save_expr_depth; \ +} + int f_select(oprtype *a, opctype op) { - boolean_t first_time, save_saw_side, save_shift; - unsigned int save_depth; + boolean_t first_time, save_saw_side, *save_se_base, save_shift, shifting; opctype old_op; oprtype *cnd, endtrip, target, tmparg; triple *oldchain, *r, *ref, *save_start, *save_start_orig, tmpchain, *triptr; + uint4 save_expr_depth, save_se_depth; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - save_shift = TREF(shift_side_effects); - save_saw_side = TREF(saw_side_effect); - save_depth = TREF(expr_depth); + save_expr_depth = TREF(expr_depth); save_start = TREF(expr_start); save_start_orig = TREF(expr_start_orig); - TREF(shift_side_effects) = FALSE; - TREF(saw_side_effect) = FALSE; + save_saw_side = TREF(saw_side_effect); + save_shift = TREF(shift_side_effects); + save_se_base = TREF(side_effect_base); + save_se_depth = TREF(side_effect_depth); TREF(expr_depth) = 0; TREF(expr_start) = TREF(expr_start_orig) = NULL; - if (save_shift) + TREF(saw_side_effect) = FALSE; + TREF(shift_side_effects) = FALSE; + TREF(side_effect_depth) = INITIAL_SIDE_EFFECT_DEPTH; + TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * TREF(side_effect_depth)); + memset((char *)(TREF(side_effect_base)), 0, SIZEOF(boolean_t) * TREF(side_effect_depth)); + if (shifting = (save_shift && (!save_saw_side || (GTM_BOOL == TREF(gtm_fullbool))))) /* NOTE assignment */ { dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); @@ -54,13 +69,15 @@ int f_select(oprtype *a, opctype op) cnd = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cnd)) { - if (save_shift) + SELECT_CLEANUP; + if (shifting) setcurtchain(oldchain); return FALSE; } if (TK_COLON != TREF(window_token)) { - if (save_shift) + SELECT_CLEANUP; + if (shifting) setcurtchain(oldchain); stx_error(ERR_COLON); return FALSE; @@ -68,7 +85,8 @@ int f_select(oprtype *a, opctype op) advancewindow(); if (EXPR_FAIL == expr(&tmparg, MUMPS_EXPR)) { - if (save_shift) + SELECT_CLEANUP; + if (shifting) setcurtchain(oldchain); return FALSE; } @@ -110,19 +128,25 @@ int f_select(oprtype *a, opctype op) ref->operand[1] = put_ilit(FALSE); /* Not a subroutine reference */ ins_triple(r); assert(!TREF(expr_depth)); - TREF(shift_side_effects) = save_shift; - TREF(saw_side_effect) = save_saw_side; - TREF(expr_depth) = save_depth; TREF(expr_start) = save_start; TREF(expr_start_orig) = save_start_orig; - if (save_shift) + TREF(saw_side_effect) = save_saw_side; + TREF(shift_side_effects) = save_shift; + SELECT_CLEANUP; + TREF(expr_depth) = save_expr_depth; + if (shifting) { - newtriple(OC_GVSAVTARG); + shifting = ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)); + newtriple(shifting ? OC_GVSAVTARG : OC_NOOP); /* must have one of these two at expr_start */ setcurtchain(oldchain); dqadd(TREF(expr_start), &tmpchain, exorder); TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + if (shifting) + { /* only play this game if something else started it */ + assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); + triptr = newtriple(OC_GVRECTARG); + triptr->operand[0] = put_tref(TREF(expr_start)); + } } *a = put_tref(r); return TRUE; diff --git a/sr_port/f_zahandle.c b/sr_port/f_zahandle.c index 2703d4f..98bd1dd 100644 --- a/sr_port/f_zahandle.c +++ b/sr_port/f_zahandle.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,8 @@ error_def(ERR_VAREXPECTED); int f_zahandle(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; + triple *oldchain, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -38,11 +39,9 @@ int f_zahandle(oprtype *a, opctype op) stx_error(ERR_NAMEEXPECTED); return FALSE; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -50,12 +49,7 @@ int f_zahandle(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnzahandle); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_zprevious.c b/sr_port/f_zprevious.c index ad27ba2..6144780 100644 --- a/sr_port/f_zprevious.c +++ b/sr_port/f_zprevious.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,8 @@ error_def(ERR_VAREXPECTED); int f_zprevious(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; + triple *oldchain, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -49,11 +50,9 @@ int f_zprevious(oprtype *a, opctype op) ins_triple(r); break; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -61,12 +60,7 @@ int f_zprevious(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnzprevious); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/f_zqgblmod.c b/sr_port/f_zqgblmod.c index a688619..e09356f 100644 --- a/sr_port/f_zqgblmod.c +++ b/sr_port/f_zqgblmod.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,7 +21,8 @@ error_def(ERR_VAREXPECTED); int f_zqgblmod(oprtype *a, opctype op) { - triple *oldchain, *r, tmpchain, *triptr; + triple *oldchain, *r; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -36,11 +37,9 @@ int f_zqgblmod(oprtype *a, opctype op) break; case TK_ATSIGN: r->opcode = OC_INDFUN; - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); @@ -48,12 +47,7 @@ int f_zqgblmod(oprtype *a, opctype op) } r->operand[1] = put_ilit((mint)indir_fnzqgblmod); ins_triple(r); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) diff --git a/sr_port/fgn_glopref.c b/sr_port/fgn_glopref.c index 5dd87bf..328c064 100644 --- a/sr_port/fgn_glopref.c +++ b/sr_port/fgn_glopref.c @@ -17,7 +17,7 @@ #include "gtm_string.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "lv_val.h" /* needed by "fgncal.h" */ #include "fgncal.h" diff --git a/sr_port/fgncal_lookup.c b/sr_port/fgncal_lookup.c index 0985eb7..75dc56b 100644 --- a/sr_port/fgncal_lookup.c +++ b/sr_port/fgncal_lookup.c @@ -15,7 +15,7 @@ #include "lv_val.h" /* needed by "fgncal.h" */ #include "fgncal.h" #include "valid_mname.h" -#include "rtnhdr.h" +#include GBLREF symval *curr_symval; diff --git a/sr_port/fgncal_unwind.c b/sr_port/fgncal_unwind.c index f4c9058..ba1591c 100644 --- a/sr_port/fgncal_unwind.c +++ b/sr_port/fgncal_unwind.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "tp_frame.h" #include "error.h" diff --git a/sr_port/file_head_write.h b/sr_port/file_head_write.h index 29d3f93..5e52cef 100644 --- a/sr_port/file_head_write.h +++ b/sr_port/file_head_write.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2005 Fidelity Information Services, Inc * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,5 +13,6 @@ #define FILE_HEAD_WRITE_INCLUDED boolean_t file_head_write(char *, sgmnt_data_ptr_t, int4); +boolean_t file_head_write_secshr(char *, sgmnt_data_ptr_t, int4); #endif /* FILE_HEAD_WRITE_INCLUDED */ diff --git a/sr_port/find_line_addr.c b/sr_port/find_line_addr.c index e9d7c4a..3c49b08 100644 --- a/sr_port/find_line_addr.c +++ b/sr_port/find_line_addr.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "cmd_qlf.h" #include "gtm_caseconv.h" #include "min_max.h" diff --git a/sr_port/find_line_start.c b/sr_port/find_line_start.c index be7f093..952ac1a 100644 --- a/sr_port/find_line_start.c +++ b/sr_port/find_line_start.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include GBLREF unsigned char *stackbase, *stacktop; diff --git a/sr_port/find_mvstent.c b/sr_port/find_mvstent.c index 82148b7..6a8784c 100644 --- a/sr_port/find_mvstent.c +++ b/sr_port/find_mvstent.c @@ -16,7 +16,7 @@ #include "iotimer.h" #include "iotcpdef.h" #include "iosocketdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "find_mvstent.h" #include "stack_frame.h" diff --git a/sr_port/find_rtn_hdr.c b/sr_port/find_rtn_hdr.c index 81c56ff..fe3493f 100644 --- a/sr_port/find_rtn_hdr.c +++ b/sr_port/find_rtn_hdr.c @@ -12,7 +12,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "ident.h" #include "min_max.h" diff --git a/sr_port/flush_jmp.c b/sr_port/flush_jmp.c index 68898ce..a28e3c1 100644 --- a/sr_port/flush_jmp.c +++ b/sr_port/flush_jmp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "objlabel.h" #include "cache.h" @@ -65,9 +65,9 @@ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfe */ assert(!(frame_pointer->flags & SFF_ETRAP_ERR) || (NULL == error_frame) || (error_frame == frame_pointer)); assert(!(SFT_TRIGR & frame_pointer->type)); - frame_pointer->flags &= SFF_ETRAP_ERR_OFF; /* clear the SFF_ETRAP_ERR bit */ - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; /* clear the SFF_TRIGR_CALLD bit since this frame is being rewritten */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "flush_jmp: Turrning off SFF_TRIGR_CALLD in frame 0x"lvaddr"\n", frame_pointer))); + 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))); frame_pointer->rvector = rtn_base; frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base); frame_pointer->vartab_len = frame_pointer->rvector->vartab_len; diff --git a/sr_port/fnorder.h b/sr_port/fnorder.h index 0298955..1da0d33 100644 --- a/sr_port/fnorder.h +++ b/sr_port/fnorder.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,18 +13,18 @@ #define _FNORDER_H_INC_ enum order_obj { - global = 0, - local_name, - local_sub, - indir, - last_obj + GLOBAL = 0, + LOCAL, + LOCAL_NAME, + INDIRECT, + LAST_OBJECT }; enum order_dir { - forward = 0, - backward, - undecided, - last_dir + FORWARD = 0, + BACKWARD, + TBD, + LAST_DIRECTION }; STATICFNDCL boolean_t set_opcode(triple *r, oprtype *result, oprtype *result_ptr, oprtype *second_opr, enum order_obj object); diff --git a/sr_port/fntext_ch.c b/sr_port/fntext_ch.c index 30bdf75..5919db9 100644 --- a/sr_port/fntext_ch.c +++ b/sr_port/fntext_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,7 @@ error_def(ERR_VMSMEMORY); CONDITION_HANDLER(fntext_ch) { START_CH; + GTMTRIG_ONLY(TREF(in_op_fntext) = FALSE); if (!DUMPABLE && (SIGNAL != ERR_TPRETRY)) { UNWIND(NULL, NULL); /* As per the standard, $TEXT returns null string if there are errors while */ diff --git a/sr_port/format_lvname.c b/sr_port/format_lvname.c index 158411a..4f9cc89 100644 --- a/sr_port/format_lvname.c +++ b/sr_port/format_lvname.c @@ -29,7 +29,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "lv_val.h" #include "min_max.h" diff --git a/sr_port/fullbool.h b/sr_port/fullbool.h index 06f3a15..dd0053f 100644 --- a/sr_port/fullbool.h +++ b/sr_port/fullbool.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,4 +18,11 @@ enum gtm_bool_type FULL_BOOL_WARN }; +enum gtm_se_type +{ + OLD_SE = 0, + STD_SE, + SE_WARN +}; + #endif /* FULLBOOL_H_INCLUDED */ diff --git a/sr_port/gbldefs.c b/sr_port/gbldefs.c index e2eaaa0..4b01be1 100644 --- a/sr_port/gbldefs.c +++ b/sr_port/gbldefs.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,8 +10,14 @@ ****************************************************************/ /* General repository for global variable definitions. This keeps us from - pulling in modules and all their references when all we wanted was the - global data def.. */ + * pulling in modules and all their references when all we wanted was the + * global data def. + * + * Note, all GBLDEF fields are automatically cleared to zeroes. No initialization to + * zero (0) or NULL or any other value that translates to zeroes is necessary on these + * fields and should be avoided as it creates extra linker and image startup processing + * that can only slow things down even if only by a little. + */ #include "mdef.h" @@ -32,6 +38,9 @@ # include # include "desblk.h" #endif +#ifdef GTM_PTHREAD +# include +#endif #include "cache.h" #include "hashtab_addr.h" #include "hashtab_int4.h" @@ -42,7 +51,7 @@ /* The define of CHEXPAND below causes error.h to create GBLDEFs */ #define CHEXPAND #include "error.h" -#include "rtnhdr.h" +#include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" @@ -92,16 +101,13 @@ #include "mmemory.h" #include "have_crit.h" #include "alias.h" - /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" #include "gtmsource.h" #include "gtmrecv.h" - /* FOR MERGE RELATED GLOBALS */ #include "gvname_info.h" #include "op_merge.h" - #ifdef UNIX #include "cli.h" #include "invocation_mode.h" @@ -109,33 +115,29 @@ #include "parse_file.h" /* for MAX_FBUFF */ #include "repl_sem.h" #include "gtm_zlib.h" +#include "anticipatory_freeze.h" #endif - #include "jnl_typedef.h" - +#include "repl_ctl.h" #ifdef VMS #include "gtm_logicals.h" /* for GTM_MEMORY_NOACCESS_COUNT */ #endif - #include "gds_blk_upgrade.h" /* for UPGRADE_IF_NEEDED flag */ #include "cws_insert.h" /* for CWS_REORG_ARRAYSIZE */ - #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" +#include "gtm_conv.h" #endif - # ifdef GTM_CRYPT # include "gtmcrypt.h" # include "gdsblk.h" # include "muextr.h" # endif - #ifdef GTM_TRIGGER #include "gv_trigger.h" #include "gtm_trigger.h" #endif - #define DEFAULT_ZERROR_STR "Unprocessed $ZERROR, see $ZSTATUS" #define DEFAULT_ZERROR_LEN (SIZEOF(DEFAULT_ZERROR_STR) - 1) @@ -146,6 +148,7 @@ GBLDEF sgmnt_addrs *cs_addrs_list; /* linked list of csa corresponding to all c GBLDEF unsigned short proc_act_type; GBLDEF volatile bool ctrlc_pending; +GBLDEF bool undef_inhibit; GBLDEF volatile int4 ctrap_action_is; GBLDEF bool out_of_time; GBLDEF io_pair io_curr_device; /* current device */ @@ -154,7 +157,6 @@ GBLDEF io_log_name *dollar_principal; /* pointer to log name GTM$PRINCIPAL if de GBLDEF bool prin_in_dev_failure; GBLDEF bool prin_out_dev_failure; GBLDEF io_desc *active_device; - GBLDEF bool error_mupip, file_backed_up, gv_replopen_error, @@ -172,7 +174,6 @@ GBLDEF bool error_mupip, view_debug4, mupip_error_occurred, dec_nofac; - GBLDEF boolean_t is_updproc, is_updhelper, mupip_jnl_recover, @@ -193,7 +194,6 @@ GBLDEF VSIG_ATOMIC_T forced_exit; /* Asynchronous signal/interrupt handler sets * hence the VSIG_ATOMIC_T type in the definition. */ GBLDEF intrpt_state_t intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; /* any other value implies it is not ok to interrupt */ - GBLDEF unsigned char *msp, *mubbuf, *restart_ctxt, @@ -238,7 +238,6 @@ GBLDEF mval dollar_zinterrupt; GBLDEF boolean_t dollar_zininterrupt; GBLDEF boolean_t dollar_ztexit_bool; /* Truth value of dollar_ztexit when coerced to boolean */ GBLDEF boolean_t dollar_zquit_anyway; - GBLDEF mv_stent *mv_chain; GBLDEF sgm_info *first_sgm_info; /* List of participating regions in the TP transaction with NO ftok ordering */ GBLDEF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */ @@ -246,7 +245,7 @@ GBLDEF spdesc indr_stringpool, rts_stringpool, stringpool; GBLDEF stack_frame *frame_pointer; -GBLDEF stack_frame *zyerr_frame = NULL; +GBLDEF stack_frame *zyerr_frame; GBLDEF symval *curr_symval; GBLDEF tp_frame *tp_pointer; GBLDEF tp_region *halt_ptr, @@ -258,14 +257,12 @@ GBLDEF gv_namehead *gv_target_list; /* List of ALL gvts that were allocated (in GBLDEF gv_namehead *gvt_tp_list; /* List of gvts that were referenced in the current TP transaction */ GBLDEF gvt_container *gvt_pending_list; /* list of gvts that need to be re-examined/re-allocated when region is opened */ GBLDEF buddy_list *gvt_pending_buddy_list;/* buddy_list for maintaining memory for gv_targets to be re-examined/allocated */ - GBLDEF int4 exi_condition; GBLDEF uint4 gtmDebugLevel; GBLDEF caddr_t smCallerId; /* Caller of top level malloc/free */ GBLDEF int process_exiting; GBLDEF int4 dollar_zsystem; GBLDEF int4 dollar_zeditor; -GBLDEF boolean_t sem_incremented; GBLDEF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_top, *rtn_names_end; GBLDEF int4 break_message_mask; GBLDEF bool rc_locked; @@ -303,9 +300,7 @@ GBLDEF char cg_phase; /* code generation phase */ /* Previous code generation phase: Only used by emit_code.c to initialize the push list at the * beginning of each phase (bug fix: C9D12-002478) */ GBLDEF char cg_phase_last; - GBLDEF int cmd_cnt; - GBLDEF command_qualifier glb_cmd_qlf = { CQ_DEFAULT }, cmd_qlf = { CQ_DEFAULT }; #ifdef __osf__ @@ -316,14 +311,11 @@ GBLDEF char **cmd_arg; #ifdef __osf__ #pragma pointer_size (restore) #endif - #ifdef UNIX -GBLDEF volatile uint4 heartbeat_counter = 0; +GBLDEF volatile uint4 heartbeat_counter; GBLDEF boolean_t heartbeat_started; #endif - /* DEFERRED EVENTS */ -GBLDEF int dollar_zmaxtptime = 0; GBLDEF bool licensed = TRUE; #if defined(UNIX) @@ -337,9 +329,7 @@ GBLDEF boolean_t tp_restart_fail_sig_used; #else # error "Unsupported Platform" #endif - -GBLDEF volatile int4 fast_lock_count = 0; /* Used in wcs_stale */ - +GBLDEF volatile int4 fast_lock_count; /* Used in wcs_stale */ /* REPLICATION RELATED GLOBALS */ GBLDEF gtmsource_options_t gtmsource_options; GBLDEF gtmrecv_options_t gtmrecv_options; @@ -351,12 +341,15 @@ GBLDEF void (*tp_timeout_action_ptr)(void) = tp_timeout_action_dummy; GBLDEF void (*ctrlc_handler_ptr)() = ctrlc_handler_dummy; GBLDEF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace) = op_open_dummy; GBLDEF void (*unw_prof_frame_ptr)(void) = unw_prof_frame_dummy; +GBLDEF void (*heartbeat_timer_ptr)(void); /* Initialized only in gtm_startup() */ +#ifdef UNICODE_SUPPORTED +GBLDEF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ +#endif GBLDEF boolean_t mu_reorg_process; /* set to TRUE by MUPIP REORG */ GBLDEF boolean_t mu_reorg_in_swap_blk; /* set to TRUE for the duration of the call to "mu_swap_blk" */ GBLDEF boolean_t mu_rndwn_process; GBLDEF gv_key *gv_currkey_next_reorg; GBLDEF gv_namehead *reorg_gv_target; - #ifdef UNIX GBLDEF struct sockaddr_un gtmsecshr_sock_name; GBLDEF struct sockaddr_un gtmsecshr_cli_sock_name; @@ -366,7 +359,6 @@ GBLDEF int gtmsecshr_sockpath_len; GBLDEF int gtmsecshr_cli_sockpath_len; GBLDEF mstr gtmsecshr_pathname; GBLDEF int server_start_tries; -GBLDEF int gtmsecshr_log_file; GBLDEF int gtmsecshr_sockfd = FD_INVALID; GBLDEF boolean_t gtmsecshr_sock_init_done; GBLDEF char muext_code[MUEXT_MAX_TYPES][2] = @@ -388,16 +380,15 @@ GBLDEF mmseg *mmseg_head; GBLDEF ua_list *first_ua, *curr_ua; GBLDEF char *update_array, *update_array_ptr; GBLDEF int gv_fillfactor = 100, - rc_set_fragment; /* Contains offset within data at which data fragment starts */ -GBLDEF uint4 update_array_size = 0, - cumul_update_array_size = 0; /* the current total size of the update array */ + rc_set_fragment; /* Contains offset within data at which data fragment starts */ +GBLDEF uint4 update_array_size, + cumul_update_array_size; /* the current total size of the update array */ GBLDEF kill_set *kill_set_tail; -GBLDEF boolean_t pool_init = FALSE; -GBLDEF boolean_t is_src_server = FALSE; -GBLDEF boolean_t is_rcvr_server = FALSE; -GBLDEF jnl_format_buffer *non_tp_jfb_ptr = NULL; -GBLDEF unsigned char *non_tp_jfb_buff_ptr; -GBLDEF boolean_t dse_running = FALSE; +GBLDEF boolean_t pool_init; +GBLDEF boolean_t is_src_server; +GBLDEF boolean_t is_rcvr_server; +GBLDEF jnl_format_buffer *non_tp_jfb_ptr; +GBLDEF boolean_t dse_running; GBLDEF jnlpool_addrs jnlpool; GBLDEF jnlpool_ctl_ptr_t jnlpool_ctl; GBLDEF jnlpool_ctl_struct temp_jnlpool_ctl_struct; @@ -406,9 +397,8 @@ GBLDEF sm_uc_ptr_t jnldata_base; GBLDEF int4 jnlpool_shmid = INVALID_SHMID; GBLDEF recvpool_addrs recvpool; GBLDEF int recvpool_shmid = INVALID_SHMID; -GBLDEF int gtmsource_srv_count = 0; -GBLDEF int gtmrecv_srv_count = 0; - +GBLDEF int gtmsource_srv_count; +GBLDEF int gtmrecv_srv_count; /* The following _in_prog counters are needed to prevent deadlocks while doing jnl-qio (timer & non-timer). */ GBLDEF volatile int4 db_fsync_in_prog; GBLDEF volatile int4 jnl_qio_in_prog; @@ -432,22 +422,19 @@ GBLDEF enum gtmImageTypes image_type; /* initialized at startup i.e. in dse.c, l GBLDEF parmblk_struct *param_list; /* call-in parameters block (defined in unix/fgncalsp.h)*/ GBLDEF unsigned int invocation_mode = MUMPS_COMPILE; /* how mumps has been invoked */ GBLDEF char cli_err_str[MAX_CLI_ERR_STR] = ""; /* Parse Error message buffer */ -GBLDEF char *cli_err_str_ptr = NULL; -GBLDEF io_desc *gtm_err_dev = NULL; -GBLDEF boolean_t gtm_pipe_child = FALSE; +GBLDEF char *cli_err_str_ptr; +GBLDEF boolean_t gtm_pipe_child; #endif - +GBLDEF io_desc *gtm_err_dev; /* this array is indexed by file descriptor */ -GBLDEF boolean_t *lseekIoInProgress_flags = (boolean_t *)0; - +GBLDEF boolean_t *lseekIoInProgress_flags; #if defined(UNIX) /* Latch variable for Unix implementations. Used in SUN and HP */ GBLDEF global_latch_t defer_latch; #endif - GBLDEF int num_additional_processors; GBLDEF int gtm_errno = -1; /* holds the errno (unix) in case of an rts_error */ -GBLDEF int4 error_condition = 0; +GBLDEF int4 error_condition; GBLDEF global_tlvl_info *global_tlvl_info_head; GBLDEF buddy_list *global_tlvl_info_list; GBLDEF boolean_t job_try_again; @@ -455,17 +442,15 @@ GBLDEF volatile int4 gtmMallocDepth; /* Recursion indicator */ GBLDEF d_socket_struct *socket_pool; GBLDEF boolean_t mu_star_specified; GBLDEF backup_reg_list *mu_repl_inst_reg_list; - #ifndef VMS GBLDEF volatile int suspend_status = NO_SUSPEND; #endif - GBLDEF gv_namehead *reset_gv_target = INVALID_GV_TARGET; -GBLDEF VSIG_ATOMIC_T util_interrupt = 0; +GBLDEF VSIG_ATOMIC_T util_interrupt; GBLDEF sgmnt_addrs *kip_csa; GBLDEF boolean_t need_kip_incr; -GBLDEF int merge_args = 0; -GBLDEF merge_glvn_ptr mglvnp = NULL; +GBLDEF int merge_args; +GBLDEF merge_glvn_ptr mglvnp; GBLDEF int ztrap_form; GBLDEF boolean_t ztrap_new; GBLDEF int4 wtfini_in_prog; @@ -488,47 +473,39 @@ GBLDEF int cs_parscan; /* number of partial scans (partial cache hits) */ GBLDEF int c_clear; /* cleared due to (possible) value change */ GBLDEF boolean_t setp_work; #endif -GBLDEF z_records zbrk_recs = {NULL, NULL, NULL}; - +GBLDEF z_records zbrk_recs; #ifdef UNIX GBLDEF ipcs_mesg db_ipcs; /* For requesting gtmsecshr to update ipc fields */ -GBLDEF gd_region *ftok_sem_reg = NULL; /* Last region for which ftok semaphore is grabbed */ +GBLDEF gd_region *ftok_sem_reg; /* Last region for which ftok semaphore is grabbed */ GBLDEF int gtm_non_blocked_write_retries; /* number of retries for non-blocked write to pipe */ #endif - #ifdef VMS /* Following global variables store the state of an erroring sys$qio just before a GTMASSERT in the CHECK_CHANNEL_STATUS macro */ -GBLDEF uint4 check_channel_status = 0; /* stores the qio return status */ -GBLDEF uint4 check_channel_id = 0; /* stores the qio channel id */ +GBLDEF uint4 check_channel_status; /* stores the qio return status */ +GBLDEF uint4 check_channel_id; /* stores the qio channel id */ #endif - -GBLDEF boolean_t write_after_image = FALSE; /* true for after-image jnlrecord writing by recover/rollback */ +GBLDEF boolean_t write_after_image; /* true for after-image jnlrecord writing by recover/rollback */ GBLDEF int iott_write_error; GBLDEF int4 write_filter; -GBLDEF boolean_t need_no_standalone = FALSE; - +GBLDEF boolean_t need_no_standalone; GBLDEF int4 zdir_form = ZDIR_FORM_FULLPATH; /* $ZDIR shows full path including DEVICE and DIRECTORY */ GBLDEF mval dollar_zdir = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); - -GBLDEF int * volatile var_on_cstack_ptr = NULL; /* volatile pointer to int; volatile so that nothing gets optimized out */ +GBLDEF int * volatile var_on_cstack_ptr; /* volatile pointer to int; volatile so that nothing gets optimized out */ GBLDEF hash_table_int4 cw_stagnate; -GBLDEF boolean_t cw_stagnate_reinitialized = FALSE; +GBLDEF boolean_t cw_stagnate_reinitialized; GBLDEF uint4 pat_everything[] = { 0, 2, PATM_E, 1, 0, PAT_MAX_REPEAT, 0, PAT_MAX_REPEAT, 1 }; /* pattern = ".e" */ GBLDEF mstr_len_t sizeof_pat_everything = SIZEOF(pat_everything); - GBLDEF uint4 *pattern_typemask; GBLDEF pattern *pattern_list; GBLDEF pattern *curr_pattern; - /* Unicode related data */ GBLDEF boolean_t gtm_utf8_mode; /* Is GT.M running with Unicode Character Set; Set only after ICU initialization */ GBLDEF boolean_t is_gtm_chset_utf8; /* Is gtm_chset environment variable set to UTF8 */ GBLDEF boolean_t utf8_patnumeric; /* Should patcode N match non-ASCII numbers in pattern match ? */ -GBLDEF boolean_t badchar_inhibit = FALSE;/* Suppress malformed UTF-8 characters by default */ +GBLDEF boolean_t badchar_inhibit; /* Suppress malformed UTF-8 characters by default */ GBLDEF MSTR_DEF(dollar_zchset, 1, "M"); GBLDEF MSTR_DEF(dollar_zpatnumeric, 1, "M"); - /* Standard MUMPS pattern-match table. * This table holds the current pattern-matching attributes of each ASCII character. * Bits 0..23 of each entry correspond with the pattern-match characters, A..X. @@ -542,7 +519,6 @@ GBLDEF pattern mumps_pattern = { 1, /* namlen */ {'M', '\0'} /* name */ }; - /* mapbit is used by pattab.c and patstr.c. Note that patstr.c uses only entries until PATM_X */ GBLDEF readonly uint4 mapbit[] = { @@ -551,7 +527,6 @@ GBLDEF readonly uint4 mapbit[] = PATM_Q, PATM_R, PATM_S, PATM_T, PATM_U, PATM_V, PATM_W, PATM_X, PATM_YZ1, PATM_YZ2, PATM_YZ3, PATM_YZ4 }; - LITDEF uint4 typemask[PATENTS] = { PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 00-07 : ASCII characters */ @@ -587,9 +562,7 @@ LITDEF uint4 typemask[PATENTS] = PATM_P, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex F0-F7 : non-ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_P, PATM_C /* hex F8-FF : non-ASCII characters */ }; - GBLDEF uint4 pat_allmaskbits; /* universal set of valid pattern bit codes for currently active pattern table */ - /* globals related to caching of pattern evaluation match result. * for a given tuple, we store the evaluation result. * in the above, @@ -663,8 +636,8 @@ GBLDEF uint4 lnkrel_cnt; /* number of entries in linkage Psect to relocate */ GBLDEF int4 sym_table_size; /* size of the symbol table during compilation */ GBLDEF boolean_t stop_non_mandatory_expansion, non_mandatory_expansion; /* Used in stringpool managment */ GBLDEF jnl_fence_control jnl_fence_ctl; -GBLDEF jnl_process_vector *prc_vec = NULL; /* for current process */ -GBLDEF jnl_process_vector *originator_prc_vec = NULL; /* for client/originator */ +GBLDEF jnl_process_vector *prc_vec; /* for current process */ +GBLDEF jnl_process_vector *originator_prc_vec; /* for client/originator */ LITDEF char *jrt_label[JRT_RECTYPES] = { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) label, @@ -689,8 +662,15 @@ LITDEF boolean_t jrt_is_replicated[JRT_RECTYPES] = #include "jnl_rec_table.h" /* BYPASSOK */ #undef JNL_TABLE_ENTRY }; +LITDEF char *jnl_file_state_lit[JNL_FILE_STATES] = +{ + "JNL_FILE_UNREAD", + "JNL_FILE_OPEN", + "JNL_FILE_CLOSED", + "JNL_FILE_EMPTY" +}; /* Change the initialization if struct_jrec_tcom in jnl.h changes */ -GBLDEF struct_jrec_tcom tcom_record = {{JRT_TCOM, TCOM_RECLEN, 0, 0, 0}, +GBLDEF struct_jrec_tcom tcom_record = {{JRT_TCOM, TCOM_RECLEN, 0, 0, 0, 0}, 0, 0, 0, 0, "", {TCOM_RECLEN, JNL_REC_SUFFIX_CODE}}; GBLDEF jnl_gbls_t jgbl; GBLDEF short crash_count; @@ -717,7 +697,6 @@ GBLDEF boolean_t is_uchar_wcs_code[] = /* uppercase failure codes that imply da #undef CDB_SC_UCHAR_ENTRY #undef CDB_SC_LCHAR_ENTRY }; - GBLDEF boolean_t is_lchar_wcs_code[] = /* lowercase failure codes that imply database cache related problem */ { /* if any of the following failure codes are seen in the final retry, wc_blocked will be set to trigger cache recovery */ #define CDB_SC_NUM_ENTRY(code, value) @@ -728,7 +707,6 @@ GBLDEF boolean_t is_lchar_wcs_code[] = /* lowercase failure codes that imply da #undef CDB_SC_UCHAR_ENTRY #undef CDB_SC_LCHAR_ENTRY }; - GBLDEF boolean_t gvdupsetnoop = TRUE; /* if TRUE, duplicate SETs do not change GDS block (and therefore no PBLK journal * records will be written) although the database transaction number will be * incremented and logical SET journal records will be written. By default, this @@ -740,26 +718,21 @@ UNIX_ONLY(GBLDEF int4 gtm_shmflags;) /* Extra flags for shmat */ 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 */ #endif - -GBLDEF volatile boolean_t in_wcs_recover = FALSE; /* TRUE if in "wcs_recover", used by "bt_put" and "generic_exit_handler" */ - - -GBLDEF boolean_t in_gvcst_incr = FALSE; /* set to TRUE by gvcst_incr, set to FALSE by gvcst_put +GBLDEF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover", used by "bt_put" and "generic_exit_handler" */ +GBLDEF boolean_t in_gvcst_incr; /* set to TRUE by gvcst_incr, set to FALSE by gvcst_put * distinguishes to gvcst_put, if the current db operation is a SET or $INCR */ GBLDEF mval *post_incr_mval; /* mval pointing to the post-$INCR value */ GBLDEF mval increment_delta_mval; /* mval holding the INTEGER increment value, set by gvcst_incr, * used by gvcst_put/gvincr_recompute_upd_array which is invoked by t_end */ -GBLDEF boolean_t is_dollar_incr = FALSE; /* valid only if gvcst_put is in the call-stack (i.e. t_err == ERR_GVPUTFAIL); +GBLDEF boolean_t is_dollar_incr; /* valid only if gvcst_put is in the call-stack (i.e. t_err == ERR_GVPUTFAIL); * is a copy of "in_gvcst_incr" just before it got reset to FALSE */ GBLDEF int indir_cache_mem_size; /* Amount of memory currently in use by indirect cache */ GBLDEF hash_table_objcode cache_table; GBLDEF int cache_hits, cache_fails; - /* The alignment feature is disabled due to some issues in stringpool garbage collection. * TODO: When we sort out stringpool issues, change mstr_native_align to TRUE below */ -GBLDEF boolean_t mstr_native_align = FALSE; +GBLDEF boolean_t mstr_native_align; GBLDEF boolean_t save_mstr_native_align; - GBLDEF mvar *mvartab; GBLDEF mvax *mvaxtab,*mvaxtab_end; GBLDEF mlabel *mlabtab; @@ -786,46 +759,35 @@ VMS_ONLY( GBLDEF char object_file_name[256]; GBLDEF struct FAB obj_fab; /* file access block for the object file */ ) - GBLDEF int4 curr_addr, code_size; GBLDEF mident_fixed zlink_mname; - GBLDEF sm_uc_ptr_t reformat_buffer; GBLDEF int reformat_buffer_len; GBLDEF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */ - GBLDEF boolean_t mu_reorg_upgrd_dwngrd_in_prog; /* TRUE if MUPIP REORG UPGRADE/DOWNGRADE is in progress */ GBLDEF boolean_t mu_reorg_nosafejnl; /* TRUE if NOSAFEJNL explicitly specified */ GBLDEF trans_num mu_reorg_upgrd_dwngrd_blktn; /* tn in blkhdr of current block processed by MUPIP REORG {UP,DOWN}GRADE */ - GBLDEF inctn_opcode_t inctn_opcode = inctn_invalid_op; GBLDEF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLDEF uint4 region_open_count; /* Number of region "opens" we have executed */ - GBLDEF uint4 gtm_blkupgrade_flag = UPGRADE_IF_NEEDED; /* by default upgrade only if necessary */ GBLDEF boolean_t disk_blk_read; - -GBLDEF boolean_t gtm_dbfilext_syslog_disable = FALSE; /* by default, log every file extension message */ - +GBLDEF boolean_t gtm_dbfilext_syslog_disable; /* by default, log every file extension message */ GBLDEF int4 cws_reorg_remove_index; /* see mu_swap_blk.c for comments on the need for these two */ GBLDEF block_id cws_reorg_remove_array[CWS_REORG_REMOVE_ARRAYSIZE]; - GBLDEF uint4 log_interval; - #ifdef UNIX GBLDEF uint4 gtm_principal_editing_defaults; /* ext_cap flags if tt */ -GBLDEF boolean_t in_repl_inst_edit = FALSE; /* used by an assert in repl_inst_read/repl_inst_write */ +GBLDEF boolean_t in_repl_inst_edit; /* used by an assert in repl_inst_read/repl_inst_write */ GBLDEF boolean_t in_repl_inst_create; /* used by repl_inst_read/repl_inst_write */ GBLDEF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; /* whether a particular replication semaphore is being held * by the current process or not. */ GBLDEF boolean_t detail_specified; /* Set to TRUE if -DETAIL is specified in MUPIP REPLIC -JNLPOOL or -EDITINST */ GBLDEF boolean_t in_mupip_ftok; /* Used by an assert in repl_inst_read */ GBLDEF uint4 section_offset; /* Used by PRINT_OFFSET_PREFIX macro in repl_inst_dump.c */ - GBLDEF uint4 mutex_per_process_init_pid; /* pid that invoked "mutex_per_process_init" */ GBLDEF boolean_t gtm_quiet_halt; /* Suppress FORCEDHALT message */ #endif - #ifdef UNICODE_SUPPORTED /* Unicode line terminators. In addition to the following * codepoints, the sequence CR LF is considered a single @@ -841,7 +803,6 @@ LITDEF UChar32 u32_line_term[] = UTF_PARA_SEPARATOR, /* Paragraph Separator */ 0x0000 }; - /* Given the first byte in a UTF-8 representation, the following array returns the total number of bytes in the encoding * 00-7F : 1 byte * C2-DF : 2 bytes @@ -861,7 +822,6 @@ LITDEF unsigned int utf8_bytelen[] = 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* C0-DF */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0-FF */ }; - /* Given the first byte in a UTF-8 representation, the following array returns the number of bytes to follow * 00-7F : 0 byte * C2-DF : 1 byte @@ -881,46 +841,34 @@ LITDEF signed int utf8_followlen[] = -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0-DF */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-FF */ }; - GBLDEF gtm_wcswidth_fnptr_t gtm_wcswidth_fnptr; /* see comment in gtm_utf8.h about this typedef */ #endif - GBLDEF uint4 gtm_max_sockets; /* Maximum sockets per socket device supported by this process */ GBLDEF d_socket_struct *newdsocket; /* Commonly used temp socket area */ - GBLDEF boolean_t dse_all_dump; /* TRUE if DSE ALL -DUMP is specified */ GBLDEF int socketus_interruptus; /* How many times socket reads have been interrutped */ - GBLDEF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */ - GBLDEF uint4 process_id; GBLDEF uint4 image_count; /* not used in UNIX but defined to preserve VMS compatibility */ - GBLDEF size_t totalRmalloc; /* Total storage currently (real) malloc'd (includes extent blocks) */ GBLDEF size_t totalAlloc; /* Total allocated (includes allocation overhead but not free space */ GBLDEF size_t totalUsed; /* Sum of user allocated portions (totalAlloc - overhead) */ - GBLDEF size_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */ GBLDEF size_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */ GBLDEF size_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */ - GBLDEF volatile char *outOfMemoryMitigation; /* Cache that we will freed to help cleanup if run out of memory */ GBLDEF uint4 outOfMemoryMitigateSize;/* Size of above cache (in Kbytes) */ - GBLDEF int mcavail; GBLDEF mcalloc_hdr *mcavailptr, *mcavailbase; - GBLDEF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object code */ GBLDEF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */ - GBLDEF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */ UNIX_ONLY(GBLDEF ch_ret_type (*ht_rhash_ch)()); /* Function pointer to hashtab_rehash_ch */ UNIX_ONLY(GBLDEF ch_ret_type (*jbxm_dump_ch)()); /* Function pointer to jobexam_dump_ch */ - +UNIX_ONLY(GBLDEF ch_ret_type (*stpgc_ch)()); /* Function pointer to stp_gcol_ch */ #ifdef VMS GBLDEF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */ #endif - GBLDEF cache_rec_ptr_t pin_fail_cr; /* Pointer to the cache-record that we failed while pinning */ GBLDEF cache_rec pin_fail_cr_contents; /* Contents of the cache-record that we failed while pinning */ GBLDEF cache_rec_ptr_t pin_fail_twin_cr; /* Pointer to twin of the cache-record that we failed to pin */ @@ -933,7 +881,6 @@ GBLDEF int4 pin_fail_wcs_active_lvl; /* Number of entries in active queue when GBLDEF int4 pin_fail_ref_cnt; /* Reference count when we failed to pin */ GBLDEF int4 pin_fail_in_wtstart; /* Count of processes in wcs_wtstart when we failed to pin */ GBLDEF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 commit when we failed to pin */ - GBLDEF zwr_hash_table *zwrhtab; /* How we track aliases during zwrites */ GBLDEF uint4 zwrtacindx; /* When creating $ZWRTACxxx vars for ZWRite, this holds xxx */ GBLDEF uint4 tstartcycle; /* lv_val cycle for tstart operations */ @@ -950,9 +897,7 @@ GBLDEF mval *alias_retarg; /* Points to an alias return arg created by a "QUI #ifdef DEBUG_ALIAS GBLDEF boolean_t lvmon_enabled; /* Enable lv_val monitoring */ #endif - GBLDEF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */ - #ifdef UNIX GBLDEF int4 gtm_zlib_cmp_level; /* zlib compression level specified at process startup */ GBLDEF int4 repl_zlib_cmp_level; /* zlib compression level currently in use in replication pipe. @@ -962,52 +907,47 @@ GBLDEF int4 repl_zlib_cmp_level; /* zlib compression level currently in use in GBLDEF zlib_cmp_func_t zlib_compress_fnptr; GBLDEF zlib_uncmp_func_t zlib_uncompress_fnptr; #endif - GBLDEF mlk_stats_t mlk_stats; /* Process-private M-lock statistics */ - #ifdef UNIX -/* Initialized blockalrm and block_sigsent can be used by all */ -GBLDEF boolean_t blocksig_initialized = FALSE; /* set to TRUE when blockalrm and block_sigsent are initialized */ +/* Initialized blockalrm, block_ttinout and block_sigsent can be used by all threads */ +GBLDEF boolean_t blocksig_initialized; /* set to TRUE when blockalrm and block_sigsent are initialized */ GBLDEF sigset_t blockalrm; +UNIX_ONLY(GBLDEF sigset_t block_ttinout;) GBLDEF sigset_t block_sigsent; /* block all signals that can be sent externally (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT) */ GBLDEF char *gtm_core_file; GBLDEF char *gtm_core_putenv; #endif - #ifdef __MVS__ GBLDEF char *gtm_utf8_locale_object; GBLDEF boolean_t gtm_tag_utf8_as_ascii = TRUE; #endif #ifdef GTM_CRYPT -GBLDEF int4 gtmcrypt_init_state; /* Represents the various states of encryption library */ -GBLDEF int4 gbl_encryption_ecode; -GBLDEF char dl_err[MAX_ERRSTR_LEN]; - +LITDEF char gtmcrypt_repeat_msg[] = "Please look at prior messages related to encryption for more details"; +GBLDEF boolean_t gtmcrypt_initialized; /* Set to TRUE if gtmcrypt_init() completes successfully */ +GBLDEF char dl_err[MAX_ERRSTR_LEN]; GBLDEF gtmcrypt_init_t gtmcrypt_init_fnptr; GBLDEF gtmcrypt_close_t gtmcrypt_close_fnptr; GBLDEF gtmcrypt_hash_gen_t gtmcrypt_hash_gen_fnptr; -GBLDEF gtmcrypt_encode_t gtmcrypt_encode_fnptr; -GBLDEF gtmcrypt_decode_t gtmcrypt_decode_fnptr; +GBLDEF gtmcrypt_encrypt_t gtmcrypt_encrypt_fnptr; +GBLDEF gtmcrypt_decrypt_t gtmcrypt_decrypt_fnptr; GBLDEF gtmcrypt_getkey_by_hash_t gtmcrypt_getkey_by_hash_fnptr; GBLDEF gtmcrypt_getkey_by_name_t gtmcrypt_getkey_by_name_fnptr; GBLDEF gtmcrypt_strerror_t gtmcrypt_strerror_fnptr; - #endif /* GTM_CRYPT */ - #ifdef DEBUG /* Following definitions are related to white_box testing */ -GBLDEF boolean_t gtm_white_box_test_case_enabled = FALSE; -GBLDEF int gtm_white_box_test_case_number = 0; -GBLDEF int gtm_white_box_test_case_count = 0; -GBLDEF int gtm_wbox_input_test_case_count = 0; /* VMS allows maximum 31 characters for external identifer */ -GBLDEF boolean_t stringpool_unusable = FALSE; /* Set to TRUE by any function that does not expect any of its function +GBLDEF boolean_t gtm_white_box_test_case_enabled; +GBLDEF int gtm_white_box_test_case_number; +GBLDEF int gtm_white_box_test_case_count; +GBLDEF int gtm_wbox_input_test_case_count; /* VMS allows maximum 31 characters for external identifer */ +GBLDEF boolean_t stringpool_unusable; /* Set to TRUE by any function that does not expect any of its function * callgraph to use/expand the stringpool. */ -GBLDEF boolean_t stringpool_unexpandable = FALSE;/* Set to TRUE by any function for a small period when it has ensured +GBLDEF boolean_t stringpool_unexpandable; /* Set to TRUE by any function for a small period when it has ensured * enough space in the stringpool so it does not expect any more garbage * collections or expansions. */ -GBLDEF boolean_t donot_INVOKE_MUMTSTART = FALSE; /* Set to TRUE whenever an implicit TSTART is done in gvcst_put/kill as +GBLDEF boolean_t donot_INVOKE_MUMTSTART; /* Set to TRUE whenever an implicit TSTART is done in gvcst_put/kill as * part of an explicit + trigger update. In this situation, we dont expect * MUM_TSTART macro to be invoked at all (see skip_INVOKE_RESTART below * for description on why this is needed). So we keep this debug-only @@ -1016,7 +956,6 @@ GBLDEF boolean_t donot_INVOKE_MUMTSTART = FALSE; /* Set to TRUE whenever an impl * an rts_error) checks it never gets invoked while this is set. */ #endif - GBLDEF boolean_t block_is_free; /* Set to TRUE if the caller wants to let t_qread know that the block it is * attempting to read is actually a FREE block */ @@ -1024,7 +963,6 @@ GBLDEF int4 gv_keysize; GBLDEF gd_addr *gd_header; GBLDEF gd_binding *gd_map; GBLDEF gd_binding *gd_map_top; - #ifdef GTM_TRIGGER GBLDEF int4 gtm_trigger_depth; /* 0 if no trigger, 1 if inside trigger; 2 if inside nested trigger etc. */ GBLDEF int4 tstart_trigger_depth; /* gtm_trigger_depth at the time of the outermost "op_tstart" @@ -1045,7 +983,7 @@ GBLDEF mval *dollar_ztdata, dollar_ztslate = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0), gtm_trigger_etrap; /* Holds $ETRAP value for inside trigger */ GBLDEF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */ -GBLDEF boolean_t skip_INVOKE_RESTART = FALSE; /* set to TRUE if caller of op_tcommit/t_retry does not want it to +GBLDEF boolean_t skip_INVOKE_RESTART; /* set to TRUE if caller of op_tcommit/t_retry does not want it to * use the INVOKE_RESTART macro (which uses an rts_error to trigger * the restart) instead return code. The reason we dont want to do * rts_error is that this is an implicit tstart situation where we @@ -1067,15 +1005,13 @@ GBLDEF boolean_t explicit_update_repl_state; /* Initialized just before an expli * Value stays untouched across nested trigger invocations. */ #endif - -GBLDEF boolean_t skip_dbtriggers = FALSE; /* Set to FALSE by default (i.e. triggers are invoked). Set to TRUE +GBLDEF boolean_t skip_dbtriggers; /* Set to FALSE by default (i.e. triggers are invoked). Set to TRUE * unconditionally by MUPIP LOAD as it always skips triggers. Also set * to TRUE by journal recovery/update-process only when they encounter * updates done by MUPIP LOAD so they too skip trigger processing. In the * case of update process, this keeps primary/secondary in sync. In the * case of journal recovery, this keeps the db and jnl in sync. */ - GBLDEF boolean_t expansion_failed; /* used by string pool when trying to expand */ GBLDEF boolean_t retry_if_expansion_fails; /* used by string pool when trying to expand */ @@ -1085,7 +1021,7 @@ GBLDEF boolean_t mupip_exit_status_displayed; /* TRUE if mupip_exit has already * invoked but we will still go through mur_close_files e.g. if exit is * done directly without invoking mupip_exit). */ -GBLDEF boolean_t implicit_trollback = FALSE; /* Set to TRUE by OP_TROLLBACK macro before calling op_trollback. Set +GBLDEF boolean_t implicit_trollback; /* Set to TRUE by OP_TROLLBACK macro before calling op_trollback. Set * to FALSE by op_trollback. Used to indicate op_trollback as to * whether it is being called from generated code (opp_trollback.s) * or from C runtime code. @@ -1095,9 +1031,7 @@ GBLDEF boolean_t ok_to_UNWIND_in_exit_handling; /* see gtm_exit_handler.c for co GBLDEF boolean_t skip_block_chain_tail_check; GBLDEF boolean_t in_mu_rndwn_file; /* TRUE if we are in mu_rndwn_file (holding standalone access) */ #endif - GBLDEF char gvcst_search_clue; - #ifdef UNIX /* The following are replication related global variables. Ideally if we had a repl_gbls_t structure (like jnl_gbls_t) * this would be a member in that. But since we dont have one and since we need to initialize this specificially to a @@ -1125,14 +1059,42 @@ GBLDEF repl_conn_info_t *this_side, *remote_side; GBLDEF seq_num gtmsource_save_read_jnl_seqno; GBLDEF gtmsource_state_t gtmsource_state = GTMSOURCE_DUMMY_STATE; #endif - GBLDEF boolean_t gv_play_duplicate_kills; /* A TRUE value implies KILLs of non-existent nodes will continue to * write jnl records and increment the db curr_tn even though they dont * touch any GDS blocks in the db (i.e. treat it as a duplicate kill). * Set to TRUE for the update process & journal recovery currently. * Set to FALSE otherwise. */ - -GBLDEF boolean_t donot_fflush_NULL = FALSE; /* Set to TRUE whenever we dont want gtm_putmsg to fflush(NULL). BYPASSOK +GBLDEF boolean_t donot_fflush_NULL; /* Set to TRUE whenever we dont want gtm_putmsg to fflush(NULL). BYPASSOK * As of Jan 2012, mu_rndwn_all is the only user of this functionality. */ +#ifdef UNIX +GBLDEF boolean_t jnlpool_init_needed; /* TRUE if jnlpool_init should be done at database init time (eg., for + * anticipatory freeze supported configurations). The variable is set + * explicitly by interested commands (eg., MUPIP REORG). + */ +GBLDEF boolean_t span_nodes_disallowed; /* Indicates whether spanning nodes are not allowed. For example, + * they are not allowed for GT.CM OMI and GNP. */ +GBLDEF boolean_t argumentless_rundown; +GBLDEF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr; +GBLDEF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr; +GBLDEF boolean_t is_jnlpool_creator; +GBLDEF char gtm_dist[GTM_PATH_MAX]; /* Value of $gtm_dist env variable */ +#endif +GBLDEF boolean_t in_jnl_file_autoswitch; /* Set to TRUE for a short window inside jnl_file_extend when we are about to + * autoswitch; used by jnl_write. */ +#ifdef GTM_PTHREAD +GBLDEF pthread_t gtm_main_thread_id; /* ID of the main GT.M thread. */ +GBLDEF boolean_t gtm_main_thread_id_set; /* Indicates whether the thread ID is set. */ +GBLDEF boolean_t gtm_jvm_process; /* Indicates whether we are running with JVM or stand-alone. */ +#endif +GBLDEF size_t gtm_max_storalloc; /* Maximum that GTM allows to be allocated - used for testing */ +#ifdef VMS +GBLDEF sgmnt_addrs *vms_mutex_check_csa; /* On VMS, mutex_deadlock_check() is directly called from mutex.mar. In + * order to avoid passing csa parameter from the VMS assembly, we set this + * global from mutex_lock* callers. + */ +#endif +GBLDEF boolean_t ipv4_only; /* If TRUE, only use AF_INET. + * Reflects the value of the gtm_ipv4_only environment variable, so is process wide. + */ diff --git a/sr_port/gde.hlp b/sr_port/gde.hlp index 50a1a96..150c735 100644 --- a/sr_port/gde.hlp +++ b/sr_port/gde.hlp @@ -1,219 +1,593 @@ - 1 Overview - GDE Overview - The GT.M Global Directory Editor, GDE, is a tool for creating, - examining, and modifying Global Directories (GDs). A Global Directory - is a file that identifies: + Overview - o What global variables go to what database files + The GT.M Global Directory Editor (GDE) is a utility that enables you to + create, examine, and modify a global directory. GDE is a program written + in M and you can invoke it from the shell with $gtm_dist/mumps -run ^GDE, + with the gtm alias gtm -run GDE, or from inside the direct mode with Do + ^GDE. - o The size limits for names and values of global variables + **Note** - o Other database characteristics + The input to GDE can be a text file. In a production environment, FIS + recommends using text files to define database configurations, and putting + these text files under version control. - o If and what type of journaling should take place + A global directory stores database attributes and mapping rules. The + mapping rules are like a sieve for globals that determines which database + files hold which global names. The database attributes serve as a + blueprint that MUPIP CREATE uses to create new database file(s). Once a + database file is created, GT.M continues to use the global directory as a + sieve. However, once MUPIP CREATE applies the database attributes + (blueprint) to create a database file, GT.M does not use the blueprint + until the next MUPIP CREATE. Therefore, if you use MUPIP SET (or DSE) to + change the attributes of a database file, always perform an equivalent + change to any global directory used for a subsequent MUPIP CREATE. - All MUMPS programs that use the same Global Directory share all the - same global variables, unless the Global Directory uses environment - variables for which users have varying definitions. The local - variables are accessible only among programs executed within a single - process scope. +2 Identifying_the_Current_Global_Directory + Identifying the Current Global Directory -2 Functions - GDE Functions - The main functions of the Global Directory Editor are to: + GT.M identifies the current Global Directory by referring to the + environment variable gtmgbldir. GDE, MUPIP, LKE, DSE, and the GT.M + run-time system use this environment variable. The run-time system + normally uses this environment variable, but may also access a Global + Directory by setting $ZGBLDIR or by using the extended global reference || + or {} syntax. - o Define the mapping of global variables to database files + If you maintain multiple Global Directories, define gtmgbldir to point to + the currently active Global Directory. You may want to define gtmgbldir in + your login file. Note that this definition is a pathname. If it does not + start with a "/", then it is a relative pathname and GT.M searches for it + starting in the current working directory. - o Define the character limitations of global variable names and - records + To change the current Global Directory assignment, specify a new + definition for gtmgbldir. - o Provide the MUMPS Peripheral Interchange Program (MUPIP) with - characteristics (e.g., -ALLOCATION size) used in creating and - extending a database file - - o Define whether a database file should be journaled and how - - o Define the -ACCESS_METHOD used to access the database files and - other database characteristics - -2 Mapping - Mapping - Defining a "map," i.e., where GT.M stores a global variable, - requires defining, not only the NAME of the global variable and the - database FILE in the Global Directory, but also the REGION and - SEGMENT. - - A REGION is a logical structure that holds information such as key- - and record-size about a portion of a database. GT.M and the - operating system handle data stored in a REGION together by storing - it in the same place or places, backing it up as a unit, etc. A - REGION must map to a SEGMENT. - - A SEGMENT defines additional database storage characteristics not - required for UNIX files. A SEGMENT must map to a FILE. The SEGMENT - exists primarily for future design considerations, when a - one-to-one correspondence between the REGION and SEGMENT will no - longer be required. - - The connection in the map between a name and a file is very - important and is used by the run-time system and most GT.M - utilities. Specifying a map requires entering (a) NAME(S) with a - connection to a REGION, a REGION with a connection to a SEGMENT, - and a SEGMENT with a connection to a database file. The commands - may be issued in any order, but the final result must be a complete - logical path from name to file. - - NAME(s) ---> REGION ---> SEGMENT ---> FILE - -2 Default_GD - Creating a Default Global Directory - The Global Directory Editor creates a quick default Global - Directory for purposes such as development and testing work. A - default Global Directory also serves as a starting point or - template for a custom Global Directory. - - To create a default Global Directory structure, invoke and - immediately EXIT GDE. GDE creates a Global Directory mapping of all - NAMEs to the REGION DEFAULT, the default REGION to the SEGMENT - DEFAULT and the default SEGMENT to the default file-name MUMPS with - the default file extension of .DAT. - -2 Custom_GD - Creating a Custom Global Directory - When a default Global Directory does not meet your needs, you need - to customize a Global Directory. Usually you customize the Global - Directory when you define your production database file. This - enables you to optimize the sharing and location of your data. - - To create a custom Global Directory, invoke GDE and issue the - commands necessary to build the desired Global Directory. For more - information about mapping, refer to the "How to Map Global - Variables" section. - -2 GTM$GBLDIR - Defining the gtmgbldir Environment Variable - GT.M identifies the current Global Directory by the environment - variable gtmgbldir. GDE, MUPIP, LKE, DSE and the GT.M run-time - system use this environment variable to identify the file used as - the Global Directory. The run-time system normally uses this - environment variable, but may also access a Global Directory by - setting $ZGBLDIR or the extended global reference ([]) syntax. - - If you maintain multiple Global Directories, define gtmgbldir to - the Global Directory you currently want to use. You may want to - define gtmgbldir in your login file. - - Example + Example: $ gtmgbldir=prod.gld $ export gtmgbldir -1 Command_syntax - Command Syntax +2 Creating_a_Default_Global_Directory + Creating a Default Global Directory + + When you invoke GDE and no Global Directory exists for gtmgbldir, GDE + produces a default Global Directory that contains a minimal set of + required components and values for database characteristics. It can be + used for purposes such as development and testing work. A default Global + Directory also serves as a starting point or template for building custom + global directories. + + To retain this default Global Directory, exit GDE without making any + changes. + + Example: + + $ gtmgbldir=./mumps.gld + $ export gtmgbldir + $ gtm + GTM>d ^GDE + %GDE-I-GDUSEDEFS, Using defaults for Global Directory + /usr/accntg/jones/mumps.gld + GDE> EXIT + %GDE-I-VERIFY, Verification OK + %GDE-I-GDCREATE, Creating Global Directory file + /usr/accntg/jones/mumps.gld + +2 Mapping_Global_Variables_in_a_Global_Directory + Mapping Global Variables in a Global Directory + + Mapping is the process of connecting a global variable name to a database + file. + + A complete mapping has the following four components: + + o NAME + o REGION + o SEGMENT + o FILE + + These components may be defined in any order, but the final result must be + a complete logical path from name to file: + + NAME(s) ---> REGION ---> SEGMENT ---> FILE + + The default Global Directory contains one complete mapping that comprises + these entries for name, region, segment, and file. + + * ---> DEFAULT ---> DEFAULT ---> mumps.dat + (NAME) (REGION) (SEGMENT) (FILE) + + The * wildcard identifies all possible global names. Subsequent edits + create entries for individual global names or name prefixes. + + Regions and segments store information used to control the creation of the + file. The characteristics stored with the region and segment are passed to + MUPIP only when creating the database file using the CREATE command, so + subsequent changes to these characteristics in the Global Directory have + no effect on an existing database. + + When you create a new mapping, GDE ensures that it has all these + components by refusing to complete the EXIT command until all components + of the mapping exist. Informational messages inform you of any missing or + extra components. + +2 Examining_the_Default_Global_Directory + Examining the Default Global Directory + + The default Global Directory looks like this: + + *** TEMPLATES *** + Std Inst + Def Rec Key Null Null Freeze Qdb + Region Coll Size Size Subs Coll Jnl on Error Rndwn + ---------------------------------------------------------------------------------------------------- + 0 4080 255 NEVER Y Y DISABLED DISABLED + Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch + -------------------------------------------------------------------------------------- + Y 2308 2048 2048 8386560 + + Segment Active Acc Typ Block Alloc Exten Options + ------------------------------------------------------------------------------ + * BG DYN 4096 5000 10000 GLOB =1000 + LOCK = 40 + RES = 0 + ENCR = OFF + MM DYN 4096 5000 10000 DEFER + LOCK = 40 + + *** 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 + ------------------------------------------------------------------------------------------- + DEFAULT $gtmdir/$gtmver/g/gtm.dat + BG DYN 4096 5000 10000 GLOB=1000 + LOCK= 40 + RES = 0 + ENCR=OFF + + *** MAP *** + - - - - - - - - - - Names - - - - - - - - - - + From Up to Region / Segment / File(def ext: .dat) + -------------------------------------------------------------------------------------------------------- + % ... REG = DEFAULT + SEG = DEFAULT + FILE = $gtmdir/$gtmver/g/gtm.dat + LOCAL LOCKS REG = DEFAULT + SEG = DEFAULT + FILE = $gtmdir/$gtmver/g/gtm.dat + GDE> + + There are five primary sections in a Global Directory: + + o TEMPLATES + o NAMES + o REGIONS + o SEGMENTS + o MAP + + The function of each section in the Global Directory is described as + follows: + + TEMPLATES + + This section of the Global Directory provides a default value for every + database or file parameter passed to GT.M as part of a region or segment + definition. GDE uses templates to complete a region or segment definition + where one of these necessary values is not explicitly defined. + + GDE provides initial default values when creating a new Global Directory. + You can then change any of the values using the appropriate -REGION or + -SEGMENT qualifiers with the TEMPLATE command. + + NAMES + + An M program sees a monolithic global variable name space. The NAMES + section of the Global Directory partitions the name space so that + different globals reside in different files. While each M global can + reside in only one file, each file can store many M globals. + + REGIONS + + The REGIONS section lists all of the regions in the Global Directory. Each + region defines common properties for all the M global variables; + therefore, multiple sets of names from the NAMES section map onto a single + region. + + You assign these values by specifying the appropriate qualifier when you + create or modify individual regions. If you do not specify a value for a + particular parameter, GDE assigns the default value from the TEMPLATES + section. + + SEGMENTS + + This section of the Global Directory lists currently defined segments. + While regions specify properties of global variables, segments specify the + properties of files. There is a one-to-one mapping between regions and + segments. You assign these values by specifying the appropriate qualifier + when you create or modify individual segments. If you do not specify a + value for a particular parameter, GDE assigns the default value from the + TEMPLATES section. + + MAP + + This section of the Global Directory lists the current mapping of names to + region to segment to file. In the default Global Directory, there are two + lines in this section: one specifies the destination for all globals, the + other one is for local locks. If you add any new mapping component + definitions (that is, any new names, regions, or segments), this section + displays the current status of that mapping. Any components of the mapping + not currently defined display "NONE". Because GDE requires all elements of + a mapping to be defined, you will not be able to EXIT (and save) your + Global Directory until you complete all mappings. + +2 Global_Directory_Abbreviations + Global Directory Abbreviations + + GDE uses the following abbreviations to display the output of a global + directory. The following list show global directory abbreviations with the + associated qualifiers. For a description of the function of individual + qualifiers, see "GDE Command Summary". + + Abbreviation Full Form + Acc ACCESS_METHOD + Alloc ALLOCATION + AutoSwitch AUTOSWITCHLIMIT + Block BLOCK_SIZE + Buff BUFFER_SIZE + Def Coll COLLATION_DEFAULT + Exten EXTENSION_COUNT + File FILE_NAME + GLOB GLOBAL_BUFFER_COUNT + Inst Freeze On Error INST_FREEZE_ON_ERROR + JNL JOURNAL + KeySize KEY_SIZE + LOCK LOCK_SPACE + Null Subs NULL_SUBSCRIPTS + Qdb Rndwn QDBRUNDOWN + Std Null Coll STDNULLCOLL + Rec Size RECORD_SIZE + RES RESERVED_BYTES + Region REGION + Typ DYNAMIC_SEGMENT + +2 Customizing_a_Global_Directory + Customizing a Global Directory + + Once you have installed GT.M and verified its operation, create a Global + Directory based on your needs. To create this customized Global Directory, + use the appropriate GDE commands and qualifiers to build the desired + Global Directory. The GDE commands are described later in this chapter. + + You can also create a text file of GDE commands with a standard text + editor and process this file with GDE. In a production environment, this + gives better configuration control than interactive usage with GDE. + +3 Adding_a_Journaling_Information_Section + Adding a Journaling Information Section + + If you select the -JOURNAL option when you ADD or CHANGE a region in a + Global Directory, the following section is added to your Global Directory + and displays when you invoke SHOW. The columns provided display the values + you selected with the journal options, or defaults provided by FIS for any + options not explicitly defined. + + *** JOURNALING INFORMATION *** + Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch + ------------------------------------------------------------------------------------------ + DEFAULT $gtmdir/$gtmver/g/gtm.mjl + Y 2308 2048 2048 8386560 + +1 Using_GDE + Using GDE + + The default installation procedure places the GDE utility into a directory + assigned to the environment variable gtm_dist. + + To invoke GDE: + + from within GTM, use the command: + + GTM>do ^GDE + + from the shell, enter: + + $ mumps -r GDE + + GDE displays informational messages like the following, and then the GDE> + prompt: + + %GDE-I-LOADGD, loading Global Directory file /prod/mumps.gld + %GDE-I-VERIFY, Verification OK + GDE> + + If this does not work, contact your system manager to investigate setup + and file access issues. + + To leave GDE: + + 1. Use the GDE EXIT command to save all changes and return to the shell. + + GDE> EXIT + + 2. Use the GDE QUIT command to discard all changes and return to the + shell. This will not save any changes. + + GDE> QUIT + +2 Guidelines_for_Mapping + Guidelines for Mapping + + This section lists the parameters that apply to defining each component of + a mapping. + + NAME + + The name is the portion of the global variable name without subscripts. + More than one name can map to a single region, but a single name can only + map to one region. + + A name: + + o Maps to only one region in the Global Directory. + o Is case sensitive. + o Must begin with an alphabetic character or a percent sign (%). + o Can be one to 31 alphanumeric characters. + o Can be a discrete "global" name, for example, aaa corresponds to the + global variable ^aaa. + o Can be a partial name ending with a wild card ("*"), for example, abc* + represents all globals beginning with the letters ^abc. + + REGION + + A region is a logical structure that holds information about a portion of + a database, such as key-size and record-size. A key is the internal + representation of a global variable name. In this chapter the terms global + variable name and key are used interchangeably. A record refers to a key + and its data. + + A Global Directory must have at least one region. A region only maps to a + single segment. More than one name may map to a region. + + A region name: + + o Can include alphanumerics, dollar signs ($), and underscores ( _ ). + o Can have from 1 to 16 characters. + + GDE automatically converts region names to uppercase, and uses DEFAULT for + the default region name. + + SEGMENT + + A segment defines file-related database storage characteristics. A segment + must map to a single file. A segment can be mapped by only one region. + + GT.M uses a segment to define a physical file and access method for the + database stored in that file. + + A segment-name: + + o Can include alphanumerics, dollar signs ($), and underscores ( _ ) + o Can have from one to 16 characters + + GDE automatically converts segment names to uppercase. GDE uses DEFAULT + for the default segment name. + + FILE + + Files are the structures provided by UNIX for the storage and retrieval of + information. Files used by GT.M must be random-access files resident on + disk. + + By default, GDE uses the file-name mumps.dat for the DEFAULT segment. GDE + adds the .dat to the file name when you do not specify an extension. + Generally, avoid non-graphic and punctuation with potential semantic + significance to the file system in file names as they tend to produce + operational difficulties. + +3 Example_of_a_Basic_Mapping + Example of a Basic Mapping + + To complete this procedure, you must have already opened a Global + Directory. + + o ADD a new global variable name. + + GDE> add -name cus -region=cusreg + + This maps the global name cus to the region cusreg. + + o ADD region cusreg, if it does not exist. + + GDE> add -region cusreg -d=cusseg + + This creates the region cusreg and connects it to the segment cusseg. + -d[ynamic] is a required qualifier that takes the associated + segment-name as a value. + + o ADD segment cusreg, if it does not exist, and link it to a file. + + GDE> add -segment cusseg -file=cus + + This creates the segment cusseg and connects it to the file cus.dat. + + To review the information you have added to the Global Directory, enter + the command SHOW. + + To perform a base consistency check in the configuration, enter the + command VERIFY. + + To exit the Global Directory and save your changes, enter the command + EXIT. At this point, GDE performs an automatic verification. If + successfully confirmed, the mappings and database specifications become + part of the Global Directory, available for access by processes, + utilities, and the run-time system. + + Only MUPIP CREATE uses the database specifications; run-time processes and + other utility functions use only the map and ignore the other information + in a global directory. + +1 Commands + Commands + + This section describes the GDE commands. GDE allows abbreviations of + commands. The section describing each command provides the minimum + abbreviation for that command and a description of any qualifiers that are + not object-related. The section discussing the object-type describes all + the associated object-related qualifiers. + + Command Syntax: + The general format for GDE commands is: - command [-object-type] [object-name] [-qualifier...] - ex: -NAME Name-space -region-qualifier... - -REGION Region-name -region-qualifier... - -SEGMENT Segment-name -segment-qualifier... + command [-object-type] [object-name] [-qualifier] where: - Object-type Indicates whether the command operates on a - -N[AME], - - R[EGION] or -S[EGMENT]. + -object-type - Object-name Specifies the name of a N[AME] space, R[EGION] or - S[EGMENT]. Object-names of different types may - have the same name. + Indicates whether the command operates on a -N[AME] space, + -R[EGION], or -S[EGMENT]. - Name-space Specifies a name or name prefix that maps to a - REGION. Names may include the wildcard operator * - as a suffix. + object-name - Region-name Specifies a REGION name. + Specifies the name of the N[AME] space, R[EGION], or S[EGMENT]. + Objects of different types may have the same name. Name spaces may + include the wildcard operator (*) as a suffix. - Segment-name Specifies a SEGMENT name. + -qualifier - Qualifier Indicates a command or object qualifier. + Indicates an object qualifier. - The format for each command specifies required qualifiers for the - command. + The format description for each individual command specifies required + qualifiers for that command. - The @, EXIT, HELP, LOG, QUIT and SPAWN commands do not use this - general format. For the applicable format, refer to the section - explaining each of these commands. + The @, EXIT, HELP, LOG, QUIT, SETGD, and SPAWN commands do not use this + general format. For the applicable format, refer to the section explaining + each of these commands. - Comments on the command line may be delimited by an exclamation mark - (!). An exclamation mark not enclosed in quotes (") causes GDE to - ignore the rest of the input line. + Comments on the command line may be delimited by an exclamation mark (!). -1 at-sign - @ - The @ command executes a GDE command file. Use the @ command to run - stored GDE command sequences from an interactive session. + **Caution** + + An exclamation mark not enclosed in quotation marks ("") causes GDE to + ignore the rest of that input line. + +2 at-sign + at-sign + + The @ command executes a GDE command file. Use the @ command to execute + GDE commands stored in a text file. The format of the @ command is: - @ file-name + @file-name - The file-name specifies the command file to execute. GDE provides the - default file extension ".COM" in creating the file-name. + The file-name specifies the command file to execute. Use the file-name + alone for a file in the current working directory, or specify the relative + path, or the full path. - GDE executes each line of the command file as if the line had been - typed at the terminal. + GDE executes each line of the command file as if it were entered at the + terminal. - Example + Example: GDE> @standard - This command transfers the GDE input to STANDARD.COM in the current - default directory. STANDARD.COM should contain GDE commands; any - comments should start with an exclamation mark (!). + This command executes the GDE commands in the file to standard in the + current working directory. standard should contain GDE commands; comments + should start with an exclamation mark (!). -1 ADD - A[DD] - The ADD command inserts a new NAME, REGION, or SEGMENT into the Global +2 Add + Add + + The ADD command inserts a new name, region, or segment into the Global Directory. - The format of the ADD command is: + The format of the ADD command is one of the f ollowing: - A[DD]-N[AME] name-space -R[EGION]=region-name - A[DD]-R[EGION] region-name -D[YNAMIC]=segment-name [-region-qual...] - A[DD]-S[EGMENT] segment-name -F[ILE_NAME]=file-name [-segment-qual...] + A[DD]-N[AME] name-space -R[EGION]=region-name + A[DD]-R[EGION] region-name -D[YNAMIC]=segment-name [-REGION-qualifier...] + A[DD]-S[EGMENT] segment-name [-SEGMENT-qualifier...] -F[ILE_NAME]=file-name - The ADD command requires specification of an object-type and - object-name. GDE supplies default values for qualifiers not supplied. + The ADD command requires specification of an object-type and object-name. + GDE supplies default values from the templates for qualifiers not + explicitly supplied in the command. - Name-spaces and file namesare case-sensitive while other objects are - not. + Name spaces and file-names are case-sensitive; other objects are not + case-sensitive. -1 CHANGE - C[HANGE] - The CHANGE command alters the NAME to REGION or REGION to SEGMENT - mapping and the environment for a REGION or SEGMENT. + Example: + + GDE> add -segment temp -file_name=scratch + + This command creates a segment-name TEMP and maps it to the file + scratch.dat in the current working directory. However, if you specify + scratch is as the file-name, in other words specify it in the form of an + environment variable, GT.M finds the file using the translation of that + environment variable. + +2 Change + Change + + The CHANGE command alters the name-to-region or region-to-segment mapping + and /or the environment for a region or segment. The format of the CHANGE command is: - C[HANGE]-N[AME] name-space -R[EGION]=new-region - C[HANGE]-R[EGION] region-name [-region-qualifier...] - C[HANGE]-S[EGMENT] segment-name [-segment-qualifier...] + C[HANGE]-N[AME] name-space -R[EGION]=new-region + C[HANGE]-R[EGION] region-name [-REGION-qualifier...] + C[HANGE]-S[EGMENT] segment-name [-SEGMENT-qualifier...] - The CHANGE command requires specification of an object-type and + The CHANGE command requires specification of an object-type and object-name. - Changes to the database environment characteristics take effect the - next time you create a new file with the MUPIP CREATE command. Mapping - changes take effect for subsequent image activation, for example - following the next RUN or MUMPS-DIRECT command. + Once you exit GDE, mapping changes take effect for any subsequent image + activation (for example, the next RUN or the mumps -direct command). + Changes to database parameters only take effect for new database files + created with subsequent MUPIP CREATE commands that use the modified Global + Directory. Use the MUPIP SET command (or in some cases DSE) to change + characteristics of existing database files. -1 DELETE - D[ELETE] - The DELETE command removes a NAME, REGION, or SEGMENT from the Global - Directory. The DELETE command does not delete the actual data from the - database but can make the data inaccessible to MUMPS images using the - resulting directory. + Example: + + GDE> change -region master -dynamic=temp -key=100 + + This command changes the region master to use the segment temp and + establishes a maximum KEY_SIZE of 100 characters for the next creation of + a file for this region. The segment change takes effect the first time the + system uses the Global Directory after the GDE session EXITs, while the + KEY_SIZE change takes effect after the next MUPIP CREATE that creates a + new database file for segment temp. + +2 Delete + Delete + + The DELETE command removes a name, region, or segment from the Global + Directory. The DELETE command does not delete any actual data. However, + GT.M does not access database files that do not have mapped global + variables except through extended references using an alternative global + directory that does not map to them. Note that GT.M replication does not + support global updates made with extended references, unless they actually + map to the same file as they would with the master global directory of the + instance. The format of the DELETE command is: @@ -221,77 +595,99 @@ D[ELETE]-R[EGION] region-name D[ELETE]-S[EGMENT] segment-name - The DELETE command requires specification of an object-type and + The DELETE command requires specification of an object-type and object-name. - Deleting a NAME removes the NAME to REGION mapping. Deleting a REGION - unmaps all NAMES mapped to the REGION. Deleting a SEGMENT unmaps the - REGION mapped to the SEGMENT. + Deleting a name removes the name-to-region mapping. Deleting a region + unmaps all names mapped to the region. Deleting a segment unmaps the + region mapped to the segment. - Map the deleted names to another REGION or the deleted REGION to - another SEGMENT using the CHANGE command. - The default name-space (*) can not be deleted. + You may map the deleted names to another region or the deleted region to + another segment using the CHANGE command. -1 EXIT - E[XIT] - The EXIT command writes all changes made in the current GDE editing - session to the Global Directory. + The default name-space (*) cannot be deleted. + + Example: + + GDE> del -name T* + + This command deletes the explicit mapping of all global names starting + with the letter "T." This command does not delete any global variables. + However, it may make preexisting globals starting with the letter "T" + invisible, at least while using this global directory, because the T* + global names map to the default namespace going forward. + +2 Exit + Exit + + The EXIT command writes all changes made in the current GDE editing + session to the Global Directory and terminates the current editing + session. The format of the EXIT command is: E[XIT] - GDE performs a full verification test (VERIFY) on the data. If the - verification succeeds, GDE writes the new Global Directory to disk and - issues a verification message. + GDE performs a full verification test (VERIFY) on the data. If the + verification succeeds, GDE writes the new Global Directory to file system + and issues a verification message. - If the verification fails, GDE displays a listing of all unverifiable - mappings and waits for corrections. Make appropriate corrections or - leave the Global Directory in its original, unedited state by using - the QUIT command. + If the verification fails, GDE displays a listing of all unverifiable + mappings and waits for corrections. Make appropriate corrections, or leave + the Global Directory in its original, unedited state by using the QUIT + command. - If you have not made any changes to the Global Directory, GDE does not - create a new Global Directory. + If you have not made any changes to the Global Directory, GDE does not + save a new Global Directory unless the original global directory had an + older format which GDE has automatically upgraded. Note that while GDE + upgrades older global directories to the current version, there is no + facility to downgrade global directories to prior versions, so you should + always save copies of any global directories that might be needed to + retrieve archival data. -1 HELP - H[ELP] - The HELP command explains the GDE commands. The format of the HELP - command is: +2 Help + Help - HE[LP] [keyword...] + The HELP command displays online information about GDE commands and + qualifiers. - Specify the GDE command for which you want information at the Topic - prompt. The help facility also provides an "Overview." + The format of the HELP command is: - Use or to return to the GDE prompt. + H[ELP] [topic...] -1 LOCKS - LOC[KS] - The LOCKS command specifies the REGION into which GT.M maps locks on - names not starting with ^. GDE maps locks on global names (starting - with ^) to the region of the database specified for that name. + where topic specifies the GDE command for which you want information. If + you omit the topic, GDE prompts you for it. + +2 LOCks + LOCks + + The LOCKS command specifies the region into which GT.M maps locks on + resource names not starting with a caret symbol (^). GDE maps locks on + resource names, starting with a caret symbol (^), to the database region + mapped for the global variable name matching the resource name. The format of the LOCKS command is: LOC[KS] -R[EGION]=region-name - The LOCK -REGION= qualifier allows specification of a region for local + The LOCKS -REGION= qualifier allows specification of a region for local locks. By default, GDE maps local locks to the default region DEFAULT. + Example: - Example + GDE> lock -region=main - GDE> LOCK-REGION=MAIN + This command maps all locks on resource names that don't start with the + caret symbol, "^" to the region main. - This command maps all locks on resource names that don't start with - "^" to region MAIN. +2 LOG + LOG -1 LOG - LOG - The LOG command creates a log file of all GDE commands and displays - for the current editing session. Because the system places an - exclamation point (i.e., the comment symbol) before all display lines - in the log, a log can be used with the @ sign as a command procedure. + The LOG command creates a log file of all GDE commands and displays for + the current editing session. Because the system places an exclamation + point (!) (i.e., the comment symbol) before all display lines that are not + entered by the user. In the log, the log can be used with the @ symbol as + a command procedure. The format of the LOG command is: @@ -299,152 +695,238 @@ LOG -ON[=file-name] LOG -OF[F] - The LOG command without a qualifier reports the current status of GDE - logging. The LOG command displays a message showing whether logging is - in effect and the specification of the current log file for the GDE - session. + The LOG command, without a qualifier, reports the current status of GDE + logging. The LOG command displays a message showing whether logging is in + effect and the specification of the current log file for the GDE session. - The log facility can be turned on and off using the -ON or -OFF - qualifiers any time during a GDE session. However, GDE closes the log - files only when the GDE session ends. + The log facility can be turned on and off using the -ON or -OFF qualifiers + any time during a GDE session. However, GDE closes the log files only when + the GDE session ends. - The -ON qualifier has an optional argument of a file-name, which must - identify a legal UNIX file. GDE uses the default file extension - ".LOG". If LOG -ON has no file-name argument, GDE uses the previous - log file for the editing session. If no log file has previously been - specified during this editing session, GDE uses the default log file + The -ON qualifier has an optional argument of a file, which must identify + a legal UNIX file. If LOG -ON has no file-argument, GDE uses the previous + log file for the editing session. If no log file has previously been + specified during this editing session, GDE uses the default log file GDELOG.LOG. -1 QUIT - Q[UIT] - The QUIT command ends the current editing session without saving any - changes to the Global Directory. GDE does not create an updated Global - Directory file. + Example: + + GDE> log -on="standard.log" + + This command turns on logging of the session and directs the output to + standard.log. + +2 Quit + Quit + + The QUIT command ends the current editing session without saving any + changes to the Global Directory. GDE does not update the Global Directory + file. The format of the QUIT command is: Q[UIT] - If the session made changes to the Global Directory, GDE issues a - message warning that the Global Directory has not been updated. + If the session made changes to the Global Directory, GDE issues a message + warning that the Global Directory has not been updated. -1 RENAME - R[ENAME] - The RENAME command allows changes of a NAME, the name of a REGION or - the name of a SEGMENT. +2 Rename + Rename + + The RENAME command allows you to change a name-space, the name of a + region, or the name of a segment. The format of the RENAME command is: R[ENAME]-N[AME] old-name new-name - R[ENAME]-R[EGION] old-reg-name new-reg-name - R[ENAME]-S[EGMENT] old-seg-name new-seg-name + R[ENAME]-R[EGION] old-region-name new-region-name + R[ENAME]-S[EGMENT] old-segment-name new-segment-name - The RENAME command requires specification of an object-type and two + The RENAME command requires specification of an object-type and two object-names. - When renaming a REGION, GDE transfers all NAME mappings to the new - REGION. When renaming a SEGMENT, GDE transfers the REGION mappings to - the new SEGMENT. + When renaming a region, GDE transfers all name mappings to the new region. + When renaming a segment, GDE transfers the region mapping to the new + segment. -1 SETGD - SE[TGD] - The SETGD command closes out edits on one Global Directory and opens - edits on another. + Example: + + GDE> rename -segment stable table + + This command renames segment stable to table and shifts any region mapped + to stable so it is mapped to table. + +2 SEtgd + SEtgd + + The SETGD command closes out edits on one Global Directory and opens edits + on another. The format of the SETGD command is: SE[TGD] -F[ILE]=file-name [-Q[UIT]] - The -FILE=file-name qualifier identifies the new Global Directory. - When you provide a partial file-name, GDE uses the current default - directory and defaults the type to .GLD. + The -FILE=file-name specifies a different Global Directory file. When you + provide a file-name without a full or relative pathname GDE uses the + current working directory; if the file is missing an extension, then GDE + defaults the type to .gld. - The -QUIT qualifier specifies that any changes that have been made to - the current Global Directory are not written, i.e., are lost, during - the change of Global Directory. + The -QUIT qualifier specifies that any changes made to the current Global + Directory are not written and are lost when you change Global Directories. - A SETGD changes the Global Directory on which the GDE edits act. If - the current Global Directory has not been modified or the -QUIT - qualifier appears in the command, the change simply occurs. However, - if the current Global Directory has been modified, GDE verifies the - Global Directory, and if the verification is successful, writes that - Global Directory. If the verification is not successful, the SETGD - fails. + SETGD changes the Global Directory that GDE is editing. If the current + Global Directory has not been modified, or the -QUIT qualifier appears in + the command, the change simply occurs. However, if the current Global + Directory has been modified, GDE verifies the Global Directory, and if the + verification is successful, writes that Global Directory. If the + verification is not successful, the SETGD fails. -1 SHOW - SH[OW] - The SHOW command displays information about NAMEs, REGIONs and - SEGMENTs. + Example: + + GDE> SETGD -f="temp" + + This changes the Global Directory being edited to temp. The quotation + marks around the file name identifies the name of the file unequivocally + to UNIX. If the -f is the final qualifier on the line, then the quotation + marks are unnecessary. + +2 SHow + SHow + + The SHOW command displays information contained in the Global Directory + about names, regions, and segments. The format of the SHOW command is: + SH[OW] -C[OMMAND] -F[ILE]=[gde-command-file] SH[OW] -N[AME] [name-space] SH[OW] -R[EGION] [region-name] SH[OW] -S[EGMENT] [segment-name] - SH[OW] -M[AP] [R[EGION]=region-name] + SH[OW] -M[AP] [-R[EGION]=region-name] SH[OW] -T[EMPLATE] SH[OW] -A[LL] - The object-type is optional. -MAP, -TEMPLATE, and -ALL are special - qualifiers used as follows: + -COMMAND: Displays GDE commands that recreate the current Global Directory + state. - o -MAP - displays the mapping of all NAMES, REGIONs, SEGMENTs, and - files + -F[ILE]=gde-command-file: Optionally specifies a file to hold the GDE + commands produced by -COMMAND. -FILE must must always appear after + -COMMAND. - o -TEMPLATE - displays the current REGION and SEGMENT templates + -NAME, -REGION, -SEGMENT, -MAP, -TEMPLATE, and -ALL are qualifiers that + cause GDE to display selected portions of the Global Directory as follows: - o -ALL - displays all templates, the map, and information about each - defined NAME, REGION, and SEGMENT + -MAP: Displays the current mapping of all names, regions, segments, and + files. This qualifier corresponds to the section of the SHOW report titled + ***MAP***. The output of a SHOW -MAP may be restricted to a particular + region by specifying a -REGION qualifier with a region name argument. + + -TEMPLATE: Displays the current region and segment templates. This + qualifier corresponds to the section of the SHOW report titled: + + ***TEMPLATES*** + + -ALL: Displays the entire Global Directory. This qualifier corresponds to + displaying "all" sections of the SHOW report: + + ***TEMPLATES***, ***NAMES***, ***REGIONS***, ***SEGMENTS***, ***MAP***. By default, SHOW displays -ALL. + If you want to print the Global Directory, create a log file by executing + LOG -ON= before executing the SHOW command. The -LOG command captures all + the commands entered and output. You can print the log file if you want a + hard copy record. -1 SPAWN - SP[AWN] - The SPAWN command creates a child process for access to the shell - without terminating the current GDE environment. Use the SPAWN command - to suspend a session and issue shell commands such as ls or printenv. - The SPAWN command spawns (forks) a child process with an optional - command string. If SPAWN has no command string parameter, the GDE - command leaves the terminal at the prompt for the shell of the spawned - process. + If you want to export the current Global Directory state, create a GDE + command file with the SHOW -COMMAND -FILE=gde-command-file and run it in + the target environment. - The format of the SPAWN command is: + Example: - SP[AWN] [shell command] + GDE>show -template + *** TEMPLATES *** + Std Inst + Def Rec Key Null Null Freeze Qdb + Region Coll Size Size Subs Coll Jnl on Error Rndwn + ---------------------------------------------------------------------------------------------- + 0 4080 255 NEVER Y Y DISABLED DISABLED + Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch + ------------------------------------------------------------------------------------------ + Y 2308 2048 2048 8386560 - Example + Segment Active Acc Typ Block Alloc Exten Options + ------------------------------------------------------------------------------ + * BG DYN 4096 5000 10000 GLOB =1000 + LOCK = 40 + RES = 0 + ENCR = OFF + MM DYN 4096 5000 10000 DEFER + LOCK = 40 - GDE> SPAWN "ls *.DAT" + This displays only the TEMPLATES section of the Global Directory. - This command invokes a directory listing of all files in the current - default directory with a .DAT extension. + GDE>SHOW -command + TEMPLATE -SEGMENT -ACCESS_METHOD=MM -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 + -LOCK_SPACE=40 -RESERVED_BYTES=0 -DEFER + TEMPLATE -SEGMENT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 + -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000 + TEMPLATE -REGION -RECORD_SIZE=4080 -KEY_SIZE=255 -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL + -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN + TEMPLATE -REGION + -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560) + ! + LOCKS -REGION=DEFAULT -1 TEMPLATE - T[EMPLATE] - The TEMPLATE command maintains a set of REGION and SEGMENT qualifier - values for use as templates when ADDing regions and segments. When an - ADD command omits qualifiers, GDE uses the template values as - defaults. GDE maintains a separate set of SEGMENT qualifier values for - each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates - the appropriate set of TEMPLATEs and sets all unspecified qualifiers - to the template defaults for the new ACCESS_METHOD. Use the GDE SHOW - command to display qualifier values for all ACCESS_METHODs. + CHANGE -REGION DEFAULT -DYNAMIC=DEFAULT -COLLATION_DEFAULT=0 -RECORD_SIZE=4080 -KEY_SIZE=255 + -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL + -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560, + FILE="$gtmdir/$gtmver/g/gtm.mjl") -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN + ! + CHANGE -SEGMENT DEFAULT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 + -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000 -FILE=$gtmdir/$gtmver/g/gtm.dat + ! + + This command displays the GDE commands to recreate the current global + directory state. + +2 Template + Template + + The TEMPLATE command maintains a set of -REGION and -SEGMENT qualifier + values for use as templates when ADDing regions and segments. When an ADD + command omits qualifiers, GDE uses the template values as defaults. + + GDE maintains a separate set of -SEGMENT qualifier values for each + ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates the + appropriate set of TEMPLATEs and sets all unspecified qualifiers to the + template defaults for the new ACCESS_METHOD. Use the GDE SHOW command to + display qualifier values for all ACCESS_METHODs. The format of the TEMPLATE command is: - T[EMPLATE]-R[EGION] [-region-qualifier...] - T[EMPLATE]-S[EGMENT] [-segment-qualifier...] + T[EMPLATE] -R[EGION] [-REGION-qualifier...] + T[EMPLATE] -S[EGMENT] [-SEGMENT-qualifier...] The TEMPLATE command requires specification of an object-type. -1 VERIFY - V[ERIFY] - The VERIFY command checks the NAME to REGION mappings to insure all - NAMES map to a REGION. The VERIFY command checks REGION to SEGMENT - mappings to insure each REGION maps to a SEGMENT, each SEGMENT maps to - only one REGION and the SEGMENT maps to a UNIX file. The EXIT command - implicitly performs a VERIFY -ALL. + Example: + + GDE> template -segment -allocation=200000 + + This command modifies the segment template so that any segments ADDed + after this time produce database files with an ALLOCATION of 200,000 GDS + blocks. + +2 Verify + Verify + + The VERIFY command validates information entered into the current Global + Directory. It checks the name-to-region mappings to ensure all names map + to a region. The VERIFY command checks region-to-segment mappings to + ensure each region maps to a segment, each segment maps to only one + region, and the segment maps to a UNIX file. The EXIT command implicitly + performs a VERIFY -ALL. The format of the VERIFY command is: @@ -456,425 +938,743 @@ V[ERIFY] -T[EMPLATE] V[ERIFY] -A[LL] - The object-type is optional. -MAP, -TEMPLATE, and -ALL are special + The object-type is optional. -MAP, -TEMPLATE, and -ALL are special qualifiers used as follows: - o -MAP - checks that all NAMES map to a REGION, all REGIONs map to a - SEGMENT, and all SEGMENTs map to a FILE + -MAP - o -TEMPLATE - checks that all templates currently are consistent and - useable + Checks that all names map to a region, all regions map to a + segment, and all segments map to a file. - o -ALL - checks all map and template data + -TEMPLATE - VERIFY with no qualifier, VERIFY -MAP and VERIFY -ALL each check all + Checks that all templates currently are consistent and useable. + + -ALL + + Checks all map and template data. + + VERIFY with no qualifier, VERIFY -MAP, and VERIFY -ALL each check all current information. + Example: + + GDE> verify -region regis + + This command verifies the region regis. + 1 Qualifiers - GDE Command Qualifiers - The -NAME, -REGION, and -SEGMENT qualifiers each have additional - qualifiers used to further define or specify characteristics of a - NAME, REGION, or SEGMENT. This section discusses these additional - qualifiers. + Qualifiers + + The -NAME, -REGION, and -SEGMENT qualifiers each have additional + qualifiers used to further define or specify characteristics of a name, + region, or segment. For more information, refer to the additional topics. 2 Name_Qualifiers - Name Qualifiers - The only -NAME qualifier, used with the commands ADD or CHANGE, is - the -REGION qualifier. + Name Qualifiers -3 -REGION - -R[EGION]=region-name - Specifies the name of a REGION. + The following -NAME qualifier can be used with the ADD or CHANGE commands. + + -REGION=region-name + + Specifies the name of a region. Region names are not case-sensitive, but + are represented as uppercase by GDE. + + The minimum length is one alphabetic character. The maximum length is 16 alphanumeric characters. - Example + Example: - GDE> add-Name a*-Region=areg + GDE> add -name a* -region=areg - This command creates the name "a," if it does not exist and maps - it to the region "areg." + This command creates the name-space a*, if it does not exist, and maps it + to the region areg. + Summary + + +------------------------------------------------------------------+ + | GDE NAME Qualifiers | + |------------------------------------------------------------------| + | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM | + |------------------------------------+---------+---------+---------| + | -R[EGION]=region-name (characters) | (none) | 1A | 16A/N | + +------------------------------------------------------------------+ 2 Region_Qualifiers - Region Qualifiers - The following -REGION qualifiers can be used with the ADD, CHANGE - or TEMPLATE commands. + Region Qualifiers -3 -DYNAMIC_SEGMENT - -D[YNAMIC_SEGMENT]=segment-name - Specifies the name of a dynamic SEGMENT. A dynamic segment - allows read-write access. + The following -REGION qualifiers can be used with the ADD, CHANGE, or + TEMPLATE commands. - The minimum length is 1 alpha character. + -C[OLLATION_SEQUENCE]=id number + + Specifies the number of the collation sequence definition to be used as + the default for this database file. The number can be any integer from 0 + to 255. The number you assign as a value must match the number of a + defined collation sequence that resides in the shared library pointed to + by the environment variable gtm_collate_n. For information on defining + this environment variable and creating an alternate collation sequence, + refer to the "Internationalization" chapter in the GT.M Programmer's + Guide. + + The minimum COLLATION_SEQUENCE ID number is zero, which is the standard M + collation sequence. + + The maximum COLLATION_SEQUENCE ID number is 255. + + By default, GDE uses zero (0) as the COLLATION_SEQUENCE ID. + + -D[YNAMIC_SEGMENT]=segment-name + + Specifies the name of the segment to which the region is mapped. + Segment-names are not case-sensitive, but are displayed as uppercase by + GDE. + + The minimum length is one alphabetic character. The maximum length is 16 alphanumeric characters. -3 -KEY_SIZE - -K[EY_SIZE]=size in bytes - Specifies the maximum size of keys, in bytes, which can be - stored in the region. + -K[EY_SIZE]=size in bytes - CAUTION: The key size must be less than the record size. GDE - rejects the command if the key size is greater than the record - size. + Specifies the maximum size of keys, in bytes, which can be stored in the + region. The KEY_SIZE must be less than the RECORD_SIZE. GDE rejects the + command if the KEY_SIZE is inappropriate for the RECORD_SIZE. - The minimum key size is 3 bytes. + The minimum KEY_SIZE is three bytes. - The maximum key size is 255 bytes. + The maximum KEY_SIZE is 1019 bytes. - By default, GDE uses a key size of 64 bytes. + When determining the maximum key size, applications should consider the + following: -3 -RECORD_SIZE - -R[ECORD_SIZE]=size in bytes - Specifies the maximum record size, in bytes, which can be stored - in the region. + o A key must fit within one database block and the maximum KEY_SIZE is + limited to 40 bytes less than the block size. For example, a 1024 byte + block can support a maximum KEY_SIZE of 984 bytes and a 1536 byte + block size is the smallest that supports a maximum KEY_SIZE of 1019 + bytes. + o GT.M uses packed decimal representation for numeric subscripts which + may be larger or smaller than the original representation. + o GT.M substitutes an element terminator for the caret (^), any comma + (,), and any right parenthesis ()). + o GT.M adds an extra byte for every string element, including the global + name. - CAUTION: The key size must be less than the record size. GDE - rejects the command if the key size exceeds the record size. + For example, the key ^ACN ("Name", "Type") internally occupies 17 bytes. - The record size must be less than half the block size of the - segment to which the region maps. If the record size is not less - than half the block size minus 7 bytes, GDE issues an error - message. To VERIFY or EXIT, you must change the record size. + By default, GDE uses a KEY_SIZE of 64 bytes. - The minimum record size is 7 bytes. + -R[ECORD_SIZE]=size in bytes - The maximum record size is 32,508 bytes. + Specifies the maximum size (in bytes) of a global variable node's value + that can be stored in a region. The KEY_SIZE must be less than the + RECORD_SIZE. GDE rejects the command if the KEY_SIZE is inappropriate for + the RECORD_SIZE. - By default, GDE uses a record size of 256 bytes. + If the size of a global exceeds one database block, GT.M implicitly spans + that global across multiple database blocks. In the event a global + variable node spans multiple blocks, and the process is not already within + a TP transaction, the GT.M run-time system automatically and transparently + performs the entire operation within an implicit TP transaction (just as + is the case with triggers). -3 -NULL_SUBSCRIPTS - -[NO]N[ULL_SUBSCRIPTS] - Indicates whether GT.M allows null subscripts for global - variables stored in the region, i.e., whether GT.M permits - reference such as ^aaa("",1). + The minimum RECORD_SIZE is seven or eight, depending on your platform. - By default, REGIONS have -NONULL_SUBSCRIPTS. + The maximum RECORD_SIZE is 1,048,576 bytes (1MiB). -3 -JOURNAL - -[NO]J[OURNAL][=journal-option-list] - Specifies whether the database file allows journaling and, if it - does, establishes characteristics for the journal file. + By default, GDE uses a RECORD_SIZE of 256 bytes. - -NOJOURNAL specifies that the database file does not allow - journaling. -NOJOURNAL does not accept an argument assignment. + -[NO]N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] - -JOURNAL specifies that journaling is allowed. -JOURNAL takes - one or more arguments in a journal-option-list. The - journal-option-list contains keywords separated with commas (,) - enclosed in parentheses (). When the list contains only one - keyword, the parentheses are optional. + Indicates whether GT.M allows null subscripts for global variables stored + in the region (that is, whether GT.M permits references such as + ^aaa("",1)). - For more information about journaling, refer to the GT.M - Journaling chapter of the GT.M Administration and Operations - Guide. + ALWAYS indicates that the null subscripts for global variables are + allowed. -4 BEFORE_IMAGE - [NO]BE[FORE_IMAGE] - [NO]BEFORE_IMAGE controls whether the journal should capture - before images of information that an update is about to - modify. + NEVER indicates that null subscripts for global variables are not allowed. - A BEFORE_IMAGE journal permits the possibility of performing - "roll-back" recovery (i.e., Backward Recovery) of the - associated database file. BEFORE_IMAGE increases the load on - I/O and CPU resources and therefore may affect performance. + EXISTING indicates that null subscripts for global variable can be + accessed and updated, but not created anew. -4 FILE_NAME - F[ILE_NAME]=file-name - FILE_NAME=file-name specifies the name of the journal file. + By default, regions have -NULL_SUBSCRIPTS=NEVER. - Journal file-name are limited to 255 characters. + -[NO]STDNULLCOLL[=TRUE|FALSE] - By default, GDE derives the file-name from the database file - name. + Determines whether GT.M null subscripts collate in conformance to the M + standard. - By default, GDE uses a journal file type of .MJL. + If -STDNULLCOLL is set to TRUE or -STDNULLCOLL is specified, subscripts of + globals in the database follow the M standard where the null subscript + collates before all other subscripts. -4 ALLOCATION - A[LLOCATION]=blocks - ALLOCATION=blocks specifies the initial size of the journal - file in blocks. Because frequent journal file extensions - degrade run-time performance, make journal file allocation - ample for a production database file. + If -STDNULLCOLL is set to FALSE or -NOSTDNULLCOLL is specified, null + subscripts collate between numeric and string subscripts. - When you change the ALLOCATION and do not also specify - EXTENSION, the EXTENSION automatically changes to equal the - ALLOCATION. + -[NO]INST[_FREEZE_ON_ERROR] - The minimum allocation is 10 blocks. + Controls whether custom errors in a region should automatically cause an + Instance Freeze. This qualifier modifies the value of "Inst Freeze on + Error" file header element. - The maximum allocation is 16777216 blocks. + -[NO]Q[DBRUNDOWN] - By default, GDE uses an allocation of 100 blocks. + Quickens normal process shutdown where a large number of processes + accessing a database file are required to shutdown almost simultaneously, + for example, in benchmarking scenarios. When a terminating GT.M process + observes that a large number of processes are attached to a database file + and QDBRUNDOWN is enabled, it bypasses checking whether it is the last + process accessing the database. Such a check occurs in a critical section + and bypassing it also bypasses the usual RUNDOWN actions which accelerates + process shutdown removing a possible impediment to process startup. By + default, QDBRUNDOWN is disabled. -4 EXTENSION - E[XTENSION]=blocks - EXTENSION=blocks specifies the size by which a journal file - extends when it becomes full. EXTENSION=0 prevents automatic - journal file extension. Because frequent journal file - extensions degrade run-time performance, make the journal - file extension ample for a production database file. + Note that with QDBRUNDOWN there is a possibility of race condition that + might leave the database fileheader and IPC resources in need of cleanup. + Although QDBRUNDOWN minimizes the probability of such a race condition, it + cannot eliminate it. When using QDBRUNDOWN, FIS recommends an explicit + MUPIP RUNDOWN of the database file after the last process exits, to ensure + the cleanup of database fileheader and IPC resources. - When you change the ALLOCATION and do not also specify - EXTENSION, the EXTENSION automatically changes to equal the - ALLOCATION. + -[NO]J[OURNAL][=journal-option-list] - The minimum EXTENSION is 0 blocks. + Specifies whether the database file allows journaling. If it does, this + qualifier establishes characteristics for the journal file. - The maximum EXTENSION is 65536 blocks. + -NOJOURNAL specifies that updates to the database file are not journaled. + -NOJOURNAL does not accept an argument assignment. - By default, GDE uses an EXTENSION of 100 blocks. + -JOURNAL specifies that journaling is allowed. -JOURNAL takes one or more + arguments in a journal-option-list. The journal-option-list contains + keywords separated with commas (,) enclosed in parentheses ( ). If the + list contains only one keyword, the parentheses are optional. -4 BUFFER_SIZE - BU[FFER_SIZE]=pages - BUFFER_SIZE=pages specifies the amount of memory used to - buffer journal file output. A larger BUFFER_SIZE usually - smooths and improves run-time performance. + Although you do not have to establish the criteria for your journaling + process at this point, it is efficient to do so, even if you are not + entirely sure you will use journaling. The options available for -JOURNAL + set up the environment, so it is ready for you to enable with MUPIP SET + -JOURNAL. You can also change or add any of the established options at + that time. - A larger BUFFER_SIZE requires more memory resources, which - may be scarce. A larger BUFFER_SIZE provides more room for - journal records in memory on their way to the disk and - therefore increases the number of update records that may be - lost in a system failure. + The journal-option-list includes: - The minimum BUFFER_SIZE is enough 512-byte pages to hold 2 - GDS database blocks. + o [NO]BE[FORE_IMAGE] + o F[ILE_NAME]=file-specification-name - The maximum BUFFER_SIZE is 2000 pages. + o AUTOSWITCHLIMIT=blocks - By default, GDE uses a BUFFER_SIZE of 128 pages. + o A[LLOCATION]=blocks + + o E[XTENSION]=blocks + o BU[FFER_SIZE]=pages + + The following section describes some -JOURNAL options. + + Specifies the limit on the size of a journal file. When the journal file + size reaches the limit, GT.M automatically performs an implicit online + switch to a new journal file. + + -[NO]BE[FORE_IMAGE] + + [NO]BEFORE_IMAGE controls whether the journal should capture before images + of information that an update is about to modify. + + The BEFORE_IMAGE option is required if you plan to consider "roll-back" + (Backward) recovery of the associated database file or if you plan to use + certain database replication options. + + -F[ILE_NAME]="file-name" + + Specifies the name of the journal file. + + The name should always be enclosed in quotation marks in this context. + + Journal file-specifications-names are limited to 255 characters. + + By default, GDE derives the file-specification-name from the database + "file-name". + + By default, GDE uses a journal file extension of .mjl. + + JOL Summary + + With GDE, you can create the journal files and define the journal + parameters; however, you must use MUPIP SET to actually enable journaling. + + Summary + + The following table summarizes GDE region qualifiers. It provides their + abbreviations, defaults (as provided by FIS), and allowable minimum and + maximum values. + + +-----------------------------------------------------------------------------+ + | GDE REGION Qualifiers | + |-----------------------------------------------------------------------------| + | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM | + |--------------------------------------------+----------+---------+-----------| + |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 | + |--------------------------------------------+----------+---------+-----------| + |-D[YNAMIC_SEGMENT] =segment-name (char) |- |1 |16 | + |--------------------------------------------+----------+---------+-----------| + |-K[EY_SIZE]=size in bytes (integer) |64 |3 |1019 | + |--------------------------------------------+----------+---------+-----------| + |-R[ECORD_SIZE]=size in bytes (integer) |256 |7 |1,048,576 | + | | | |(1 MiB) | + |--------------------------------------------+----------+---------+-----------| + |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- | + |--------------------------------------------+----------+---------+-----------| + |-[NO]STDNULLCOLL |N |- |- | + |--------------------------------------------+----------+---------+-----------| + |-[NO]INST[_FREEZE_ON_ERROR] |DISABLED |- |- | + |--------------------------------------------+----------+---------+-----------| + |-[NO]Q[DBRUNDOWN] |DISABLED |- |- | + |--------------------------------------------+----------+---------+-----------| + |-[NO]J[OURNAL] [=journal-option-list] |-NOJ |- |- | + +-----------------------------------------------------------------------------+ 2 Segment_Qualifiers - Segment Qualifiers - The following -SEGMENT qualifiers can be used with the ADD, CHANGE, - or TEMPLATE commands. + Segment Qualifiers -3 -FILE_NAME - -F[ILE_NAME]="filename" - Specifies the file name for a SEGMENT. The filename must appear - in quotes to distinguish its slashes from those of the command - qualifiers. GT.M allows the use of environment variables in the - filename. + The following -SEGMENT qualifiers can be used with the ADD, CHANGE, or + TEMPLATE commands. - The maximum filename length is 255 characters. + -AC[CESS_METHOD]=code - By default, GDE uses a file name of MUMPS. + Specifies the access method or the GT.M buffering strategy for storing and + retrieving data from the global database file. - By default, GDE uses a file extension of .DAT. + o code can have 2 values - Buffered Global (BG) or Memory Mapped (MM). + The default value is BG. + o With BG, the global buffer pool manages the buffers (the OS/file + system may also provide additional buffering). You get the choice of + using BEFORE_IMAGE or NOBEFORE_IMAGE journaling for your database. -3 -ACCESS_METHOD - -AC[CESS_METHOD]=code - Specifies the access method GT.M uses to store and retrieve data - from the global database file. The two methods are Buffered - Global (BG) and Mapped Memory (MM). + o BG supports both forward and backward recovery and rollback to + recover a database without a restore. + o BG is a likely choice when you need faster recovery times from + system failures. - GDE maintains a separate set of SEGMENT qualifier values for - each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it - activates the appropriate set of TEMPLATEs and sets all - unspecified qualifiers to the template defaults for the new - ACCESS_METHOD. + o With MM, GT.M bypasses the global buffer pool and relies entirely on + the OS/file system to manage the data traffic between memory and disk. + GT.M has no control over the timing of disk updates, therefore there + is a greater reliance on the OS/file system for database performance. - By default, GDE uses an access method of BG. + o MM supports NOBEFORE_IMAGE journaling only. GT.M triggers an + error if you use MM with BEFORE_IMAGE Journaling. MM also + supports MUPIP FORWARD -RECOVER and MUPIP JOURNAL -ROLLBACK with + the -RESYNC or -FETCHRESYNC qualifiers to generate lost and + broken transaction files. For more information, see the + Journaling chapter. + o MM does not support backward recovery/rollback. + o MM is a possible choice when you need performance advantage in + situations where the above restrictions are acceptable. + o GDE maintains a separate set of segment qualifier values for each + ACCESS_METHOD. + o When GDE modifies the ACCESS_METHOD, it activates the appropriate set + of TEMPLATEs and sets all unspecified qualifiers to the default values + of the new ACCESS_METHOD. -3 -BLOCK_SIZE - -BL[OCK_SIZE]=size - Specifies the size, in bytes, of each database block on disk. - The block-size must be a multiple of 512. If the block-size is - not a multiple of 512, GDE rounds off the block-size to the next - highest multiple of 512 and issues a warning message. + Example: - If the specified block-size is less than the minimum, GDE uses - the minimum block-size. If the specified block-size is greater - than the maximum, GDE issues an error message. + GDE> change -segment DEFAULT -access_method=MM - A 1024 byte or 2048 byte block-size serves well for most - applications. + This command sets MM as the access method or the GT.M buffering strategy + for storing and retrieving database for segment DEFAULT. + -AL[LOCATION]=blocks - The minimum block-size is 512 bytes. + Specifies the number of blocks GT.M allocates to a disk file when MUPIP + creates the file. For GDS files, the number of bytes allocated is the size + of the database file header plus the ALLOCATION size times the BLOCK_SIZE. - The maximum block-size is 65,024 bytes. + o The minimum ALLOCATION is 10 blocks. + o The maximum ALLOCATION is 1,040,187,392 blocks. + o By default, GDE uses an ALLOCATION of 100 blocks. + o The maximum size of a database file is 1,040,187,392(992Mi) blocks. + o Out of the requested allocation, GT.M always reserves 32 global + buffers for BG access method for read-only use to ensure that + non-dirty global buffers are always available. + o The default ALLOCATION was chosen for initial development and + experimentation with GT.M. Because file fragmentation impairs + performance, make the initial allocation for production files and + large projects large enough to hold the anticipated contents of the + file for a length of time consistent with your UNIX file + reorganization schedule. - By default, GDE uses a block-size of 1024 bytes for BG and MM - files. + -BL[OCK_SIZE]=size -3 -ALLOCATION - -AL[LOCATION]=size - Specifies the number of blocks GT.M allocates to a disk file - when MUPIP creates the file. For GDS files, the number of bytes - allocated is ALLOCATION size times the BLOCK_SIZE. + Specifies the size, in bytes, of each database block in the file system. + The BLOCK_SIZE must be a multiple of 512. If the BLOCK_SIZE is not a + multiple of 512, GDE rounds off the BLOCK_SIZE to the next highest + multiple of 512 and issues a warning message. - The default allocation was chosen for small development - projects. Use larger allocations for production files and large - projects. Because file fragmentation impairs performance, make - the initial allocation large enough to hold the anticipated - contents of the file for a length of time consistent with your - UNIX file reorganization schedule. + If the specified BLOCK_SIZE is less than the minimum, GDE uses the minimum + BLOCK_SIZE. If the specified BLOCK_SIZE is greater than the maximum, GDE + issues an error message. - The minimum ALLOCATION is 10 blocks. + A BLOCK_SIZE that is equal to the page size used by your UNIX + implementation serves well for most applications, and is a good starting + point. - The maximum ALLOCATION is 16777216 blocks. + You should determine the block sizes for your application through + performance timing and benchmarking. In general, larger block sizes are + more efficient from the perspective of the input/output subsystem. + However, larger block sizes use more system resources (CPU and shared + memory) and may increase collision and retry rates for transaction + processing. - By default, GDE uses an ALLOCATION of 100 blocks. + **Note** -3 -EXTENSION_COUNT - -E[XTENSION_COUNT]=size - Specifies the number of extra GDS blocks of disk space by which - the file should extend. The extend amount is interpreted as the - number of usable GDS blocks to create with the extension. To - calculate the number of host operating system blocks added with - each extension, multiply the number of GDS blocks added by (GDS - block size/host block size); to this amount, add one local bit - map block for each 512-byte block added in each extension, plus - one for any remaining bytes. + Global nodes that span blocks incur some overhead and optimum application + performance is likely to be obtained from a BLOCK_SIZE that accommodates + the majority of nodes within a single block. If you adjust the BLOCK_SIZE, + you should also adjust GLOBAL_BUFFER_COUNT. - The default extension amount was chosen for small development - projects. Use larger extensions for larger files. Because many - file extensions adversely affect performance, set up extensions - appropriate to the file allocation. + GDE does not allow you to change the block size to an arbitrary number. It + always rounds the block size to the next higher multiple of 512, because + the database block size must always be a multiple of 512. - BG files may extend automatically when the file is full. A zero - extension size prevents a BG file from automatically extending. + The minimum BLOCK_SIZE is 512 bytes. - BG files may be, and MM files must be, extended with MUPIP - EXTEND. When a MUPIP EXTEND command does not include a -BLOCKS= - qualifier, EXTEND uses the extension size in the database - header. The extension amount may be changed with the MUPIP SET - command. To require explicit expansion for BG files with MUPIP - EXTEND, set -EXTENSION_COUNT to zero. + The maximum BLOCK_SIZE is 65,024 bytes. - The minimum EXTENSION is 0 blocks. + **Note** + + FIS recommends against using databases with block sizes larger than 16KB. + If a specific global variable has records that have large record sizes, + FIS recommends placing that global variable in a file by itself with large + block sizes and using more appropriate block sizes for other global + variables. 4KB and 8KB are popular database block sizes. + + By default, GDE uses a BLOCK_SIZE of 1024 bytes. + + -[NO]ENcryption + + Specifies whether or not the database file for a segment is flagged for + encryption. Note that MUPIP CREATE acquires an encryption key for this + file and puts a cryptographic hash of the key in the database file header. + + -EX[TENSION_COUNT]=blocks + + Specifies the number of extra GDS blocks of disk space by which the file + should extend. The extend amount is interpreted as the number of usable + GDS blocks to create with the extension. To calculate the number of host + operating system blocks added with each extension, multiply the number of + GDS blocks added by (GDS BLOCK_SIZE/host BLOCK_SIZE); add one local bitmap + block for each 512 blocks added in each extension to the amount from step + 1. If the extension is not a multiple of 512, remember to roundup when + figuring the number of bitmap blocks. + + When a MUPIP EXTEND command does not include a -BLOCKS= qualifier, EXTEND + uses the extension size in the database header. + + The extension amount may be changed with the MUPIP SET command. + + The minimum EXTENSION is zero blocks. The maximum EXTENSION is 65,535 blocks. By default, GDE uses an EXTENSION of 100 blocks. -3 -GLOBAL_BUFFER_COUNT - -G[LOBAL_BUFFER_COUNT]=size - Specifies the number of global buffers for a file. Global - buffers serve as part of the database caching mechanisms. + Like allocation, the default extension amount was chosen for initial + development and experimentation with GT.M projects. Use larger extensions + for larger files. Because multiple file extensions adversely affect + performance, set up extensions appropriate to the file allocation. - Avoid inadequate settings of this factor. However, if your - system is memory constrained and the database file traffic is - not heavy enough to hold the cache in memory, increasing - GLOBAL_BUFFER_COUNT may induce paging. Therefore, do not - increase this factor to a large value without careful - observation. + -F[ILE_NAME]=file-name - The proper number of GLOBAL_BUFFERs depends on the application - and the amount of primary memory available on the system. Most - production databases exhibit a direct relationship between the - number of GLOBAL_BUFFERs and performance. However, the - relationship is not linear, but rather more parabolic, so that - increases past some point have progressively less benefit. This - point of diminishing returns depends on the application. For - most applications, Greystone expects the optimum number of - GLOBAL_BUFFERs to be between 512 and 2048. + Specifies the file for a segment. - Generally, you should increase the number of GLOBAL_BUFFERs for - production GDS databases. This is because GT.M uses the shared - memory database cache associated with each GDS file for the vast - majority of caching. + The maximum file name length is 255 characters. - The minimum for BG is 64 blocks. + By default, GDE uses a file-name of mumps followed by the default + extension, which is .dat. - The maximum for BG is 4096 blocks. + -G[LOBAL_BUFFER_COUNT]=size - By default, GDE uses a GLOBAL_BUFFER_COUNT of 1024 blocks. + Specifies the number of global buffers for a file. Global buffers reside + in shared memory and are part of the database caching mechanisms. Global + buffers do not apply to MM databases. -3 -DEFER - -[NO]D[EFER] - Instructs GT.M whether or not to store updates on the disk - immediately. + Choose the settings for this qualifier carefully. Small numbers of global + buffers tend to throttle database performance. However, if your system has + limited memory and the database file traffic is not heavy enough to hold + the cache in memory, increasing GLOBAL_BUFFER_COUNT may trigger paging. - DEFER has a significant performance benefit for heavily updated - database files. However, DEFER should only be used for files, - such as those containing temporary storage for reports, which - can be recreated if the system crashes. + If database global buffers are paged out, it may result in poor + performance. Therefore, do not increase this factor to a large value + without careful observation. - By default, GDE makes MM database files -DEFER. + The proper number of GLOBAL_BUFFERs depends on the application and the + amount of primary memory available on the system. Most production + databases exhibit a direct relationship between the number of + GLOBAL_BUFFERs and performance. However, the relationship is not linear, + but asymptotic, so that increases past some point have progressively less + benefit. This point of diminishing returns depends on the application. For + most applications, FIS expects the optimum number of GLOBAL_BUFFERs to be + between 1K and 64K. -3 -LOCK_SPACE - -LOC[K_SPACE]=size - Specifies the number of pages of space to use for the lock - database stored with this segment. If GT.M runs out of space to - store locks, the system becomes slightly less efficient. The - default amount is generous for most MUMPS applications. + Because transaction processing can be involved in an update and a + transaction is limited to half the GLOBAL_BUFFER_COUNT, the value for + GLOBAL_BUFFER_COUNT should therefore be at least twenty-six plus twice the + number of the blocks required by the largest global variable node in your + application. + + Generally, you should increase the number of GLOBAL_BUFFERs for production + GDS databases. This is because GT.M uses the shared memory database cache + associated with each GDS file for the majority of caching. + + The minimum GLOBAL_BUFFER_COUNT for BG is 64 blocks. + + The maximum for GLOBAL_BUFFER_COUNT for BG is 2147483647 blocks, but may + vary depending on your platform. + + By default, GDE uses a GLOBAL_BUFFER_COUNT that is appropriate for the + typical size of the platform. + + **Note** + + If global buffers are "paged out," improvements in system performance + resulting from more global buffers will be more than offset by the + dramatic slowdown that results from globals buffers that are "paged out." + + -L[OCK_SPACE]=integer + + Specifies the number of pages of space to use for the lock database stored + with this segment. The size of a page is always 512 bytes. + + As GT.M runs out of space to store LOCK control information, LOCKs become + progressively less efficient. If a single process consumes all the LOCK + space, it cannot continue, and any other processes cannot proceed using + LOCKs. The minimum LOCK_SPACE is 10 pages. - The maximum LOCK_SPACE is 1000 pages. + The maximum LOCK_SPACE is 65,536 pages. - By default, GDE uses a LOCK_SPACE of 20 pages. + By default, GDE uses a LOCK_SPACE of 40 pages. -1 Guidelines - Mapping Guidelines - Global Directory maps consist of a hierarchy of NAMEs, REGIONs, - SEGMENTs and FILEs. The following section provides guidelines for - defining and using these mapping components. + LOCK_SPACE usage depends on the number of locks and the number of + processes waiting for locks. To estimate lock space needs, here is a rule + of thumb: -2 Names - NAME Guidelines - GT.M uses a NAME to place global variables in a physical database - file. - A NAME: + o 1.5KB overhead for the lock space, plus + o 640 bytes for each lock base name, plus + o 128 bytes for each subscript, plus + o 128 bytes for each waiting process. - o Maps to only one REGION in the Global Directory + Generally, you would limit LOCK_SPACE when memory is scarce or you want to + be made aware of unexpected levels of LOCK usage. For most other cases, + there is no reason to limit the LOCK_SPACE. If you are introducing new + code, FIS recommends using TSTART and TCOMMIT as a more efficient + alternate for most LOCKs because it pushes the responsibility for + Isolation onto GT.M, which internally manages them with optimistic + algorithms. - o Can be a discrete "global" name, e.g., aaa is a discrete global + -R[ESERVED_BYTES]=size - o Can be a partial name ending with a wild card ("*") + Specifies the size to be reserved in each database block. RESERVED_BYTES + is generally used to reserve room for compatibility with other + implementations of M or to observe communications protocol restrictions. + RESERVED_BYTES may also be used as a user-managed fill factor. - o Must begin with an alphabetic character or a % sign + The minimum RESERVED_BYTES is zero bytes. - o Can be 1 to 8 alphanumeric characters + The maximum Reserved_Bytes is the block size minus the size of the block + header (which is 7 or 8 depending on your platform) minus the maximum + record size. - o Is case sensitive + By default, GDE uses a RESERVED_BYTES size of zero bytes. - A wild card defines all names starting with the characters of the - partial name. For example, abc*, defines the range of all global - names beginning with the three characters "abc." + Summary -2 Regions - REGION Guidelines - GT.M uses a REGION to logically define a portion of the database - with the same characteristics, such as key and record-size. A - REGION maps to a SEGMENT. More than one NAME may map to a REGION. A - Global Directory must have at least one REGION. + The following table summarizes GDE segment qualifiers. It provides + abbreviations, defaults (as provided by FIS), and allowable minimum and + maximum values. - A region-name: + +------------------------------------------------------------------------+ + | GDE SEGMENT Qualifiers | + |------------------------------------------------------------------------| + | QUALIFIER | DEFAULT | MIN | MAX | + |------------------------------------------------------------------------| + | ** BLOCK_SIZE minus the size of the block header | + |------------------------------------------------------------------------| + | * May vary by platform | + |------------------------------------------------------------------------| + | -AC[CESS_METHOD]=BG|MM | BG | - | - | + |-------------------------------+-----------+-----+----------------------| + | -AL[LOCATION]=size (blocks) | 100 | 10 | 1,040,187,392(992Mi) | + |-------------------------------+-----------+-----+----------------------| + | -BL[OCK_SIZE]=size (bytes) | 1024 | 512 | 65024 | + |-------------------------------+-----------+-----+----------------------| + | -[NO]EN[CRYPTION] | 0 | | | + |-------------------------------+-----------+-----+----------------------| + | -EX[TENSION_COUNT]=size | 100 | 0 | 65,535 | + | (blocks) | | | | + |-------------------------------+-----------+-----+----------------------| + | -F[ILE_NAME]=file-name | mumps.dat | - | 255 | + | (chars) | | | | + |-------------------------------+-----------+-----+----------------------| + | -G[LOBAL_BUFFER_COUNT]=size | 1024* | 64 | 2147483647 | + | (blocks) | | | | + |-------------------------------+-----------+-----+----------------------| + | -L[OCK_SPACE]=size (pages) | 40 | 10 | 65536 | + |-------------------------------+-----------+-----+----------------------| + | -R[ESERVED_BYTES]=size | 0 | 0 | block size-7 | + | (bytes) | | | | + +------------------------------------------------------------------------+ - o Must begin with an alphabetic character, except for DEFAULT +1 Summary + Summary - o Can include alphanumerics, a dollar sign and an underscore + The following table summarizes GDE commands, abbreviations, object types, + required object names, and optional qualifiers. - o Can be 1 to 15 characters + +------------------------------------------------------------------------+ + | GDE Command Summary | + |------------------------------------------------------------------------| + | Command | Specified Object | Required Object Name/[Optional] | + | | Type | Qualifier | + |------------------------------------------------------------------------| + | * -ALL is the default for the SHOW and VERIFY commands. | + |------------------------------------------------------------------------| + | @ | N/A | file-name | + |------------+------------------+----------------------------------------| + | | | name-space | + | A[DD] | -N[AME] | | + | | | -R[EGION]=region-name | + |------------+------------------+----------------------------------------| + | | | region-name | + | - | -R[EGION] | | + | | | -D[YNAMIC]=segment-name | + | | | [-REGION-qualifier...] | + |------------+------------------+----------------------------------------| + | | | segment-name | + | - | -S[EGMENT] | | + | | | -F[ILE_NAME]=file-name | + | | | [-SEGMENT-qualifier...] | + |------------+------------------+----------------------------------------| + | | | name-space | + | C[HANGE] | -N[AME] | | + | | | -R[EGION]=new-region | + |------------+------------------+----------------------------------------| + | | | region-name | + | - | -R[EGION] | | + | | | [-REGION-qualifier...] | + |------------+------------------+----------------------------------------| + | | | segment-name | + | - | -S[EGMENT] | | + | | | [-SEGMENT-qualifier] | + |------------+------------------+----------------------------------------| + | D[ELETE] | -N[AME] | name-space | + |------------+------------------+----------------------------------------| + | - | -R[EGION] | region-name | + |------------+------------------+----------------------------------------| + | - | -S[EGMENT] | segment-name | + |------------+------------------+----------------------------------------| + | E[XIT] | N/A | N/A | + |------------+------------------+----------------------------------------| + | HE[LP] | N/A | Keyword | + |------------+------------------+----------------------------------------| + | LOC[KS] | N/A | -R[EGION]=region-name | + |------------+------------------+----------------------------------------| + | | | [-ON][=file-name] | + | LOG | N/A | | + | | | [-OF[F]] | + |------------+------------------+----------------------------------------| + | Q[UIT] | N/A | N/A | + |------------+------------------+----------------------------------------| + | R[ENAME] | -N[AME] | old-name new-name | + |------------+------------------+----------------------------------------| + | - | -R[EGION] | old-reg-name new-reg-name | + |------------+------------------+----------------------------------------| + | - | -S[EGMENT] | old-seg-name new-seg-name | + |------------+------------------+----------------------------------------| + | SE[TGD] | N/A | -F[ILE]=file-name [-Q[UIT]] | + |------------+------------------+----------------------------------------| + | SH[OW] | -N[AME] | [name-space] | + |------------+------------------+----------------------------------------| + | - | -R[EGION] | [region-name] | + |------------+------------------+----------------------------------------| + | - | -S[EGMENT] | [segment-name] | + |------------+------------------+----------------------------------------| + | - | -M[AP] | [R[EGION]=region-name] | + |------------+------------------+----------------------------------------| + | - | T[EMPLATE] | N/A | + |------------+------------------+----------------------------------------| + | - | -A[LL]* | N/A | + |------------+------------------+----------------------------------------| + | T[EMPLATE] | -R[EGION] | [-REGION-qualifier...] | + |------------+------------------+----------------------------------------| + | - | -S[EGMENT] | [ -SEGMENT-qualifier...] | + |------------+------------------+----------------------------------------| + | V[ERIFY] | -N[AME] | [name-space] | + |------------+------------------+----------------------------------------| + | - | -R[EGION] | [region-name] | + |------------+------------------+----------------------------------------| + | - | -S[EGMENT] | [segment-name] | + |------------+------------------+----------------------------------------| + | - | -M[AP] | N/A | + |------------+------------------+----------------------------------------| + | - | -T[EMPLATE] | N/A | + |------------+------------------+----------------------------------------| + | - | -A[LL]* | N/A | + +------------------------------------------------------------------------+ - GDE automatically converts region-names to upper-case. +2 Qualifier_Summary + Qualifier Summary - By default, GDE uses DEFAULT for the default region-name. - -2 Segments - SEGMENT Guidelines - GT.M uses a SEGMENT to define a physical file and access method for - the database stored in that file. A SEGMENT maps to only one UNIX - file. A SEGMENT can be mapped by only one REGION. - - A segment-name: - - o Must begin with an alphabetic character - - o Can include alphanumerics, a dollar sign and an underscore - - o Can be 1 to 15 characters - - GDE automatically converts segment-names to upper-case. - - By default, GDE uses the file name MUMPS for the DEFAULT default - segment. By default, GDE uses the file extension .DAT for database - files. + The following table summarizes all qualifiers for the ADD, CHANGE, and + TEMPLATE commands. The defaults are those supplied by FIS. + +------------------------------------------------------------------------------------------------+ + | GDE Command Qualifiers | + |------------------------------------------------------------------------------------------------| + | QUALIFIER | DEF | MIN | MAX | NAM | REG | SEG | + |------------------------------------------------------------------------------------------------| + | * DEFAULT is the default region- and segment-name | + | ** MUMPS is the default file-name | + | *** May vary by platform | + | **** -NONULL_SUBSCRIPTS | + |------------------------------------------------------------------------------------------------| + |-AC[CESS_METHOD]=code |BG |- |- |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-AL[LOCATION]=size(blocks) |100 |10 |1040187392(992Mi) |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-BL[OCK_SIZE]=size(bytes) |1024 |512 |65024 |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-D[YNAMIC_SEGMENT]=segment-name (chars) |* |1A |16A/N |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-EX[TENSION_COUNT]=size (blks) |100 |0 |65535 |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-F[ILE_NAME]=file-name (chars) |** |1A |255A/N |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-G[LOBAL_BUFFER_COUNT]=size (blocks) |1024 |64 |2147483647 *** |- |- |X | + | |*** | | | | | | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-K[EY_SIZE]=size (bytes) |64 |3 |1019 |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-L[OCK_SPACE]=size (pages) |40 |10 |65536 |- |- |X | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-[NO]INST[_FREEZE_ON_ERROR] |FALSE |- |- |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-[NO]Q[DBRUNDOWN] |FALSE |- |- |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-[NO]J[OURNAL]=option-list |-NOJ |- |- |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- |- |X |- | + | |or ****| | | | | | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-[NO]STDNULLCOLL[=TRUE|FALSE] |FALSE |- |- |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-R[ECORD_SIZE]=size (bytes) |256 |7 |1048576 |- |X |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-R[EGION] region-name (chars) |* |1A |16A/N |X |- |- | + |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| + |-R[ESERVED_BYTES]=size (bytes) |0 |0 |blocksize |- |- |X | + +------------------------------------------------------------------------------------------------+ diff --git a/sr_port/gdeadd.m b/sr_port/gdeadd.m index 93fc2b0..af7fc2a 100644 --- a/sr_port/gdeadd.m +++ b/sr_port/gdeadd.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2011 Fidelity Information Services, Inc ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -16,13 +16,10 @@ NAME s nams(NAME)=lquals("REGION") q REGION - n nullsub i $d(regs(REGION)) zm gdeerr("OBJDUP"):"Region":REGION i '$d(lquals("DYNAMIC_SEGMENT")) zm gdeerr("QUALREQD"):"Dynamic_segment" i $d(lquals("JOURNAL")),lquals("JOURNAL"),'$d(lquals("BEFORE_IMAGE")) zm gdeerr("QUALREQD"):"Before_image" - i $d(lquals("NULL_SUBSCRIPTS")) d - . s nullsub=lquals("NULL_SUBSCRIPTS") - . s lquals("NULL_SUBSCRIPTS")=$s((nullsub="ALWAYS")!(nullsub="TRUE"):1,nullsub="EXISTING":2,1:0) + i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$RQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTADD"):"Region":REGION s update=1,s="",regs=regs+1 f s s=$o(tmpreg(s)) q:'$l(s) s regs(REGION,s)=tmpreg(s) diff --git a/sr_port/gdechang.m b/sr_port/gdechang.m index 7b3fe60..b241210 100644 --- a/sr_port/gdechang.m +++ b/sr_port/gdechang.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2011 Fidelity Information Services, Inc ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -16,13 +16,10 @@ NAME s nams(NAME)=lquals("REGION") q REGION - n nullsub i '$d(regs(REGION)) zm gdeerr("OBJNOTFND"):"Region":REGION i $d(lquals("JOURNAL")),lquals("JOURNAL"),'regs(REGION,"JOURNAL"),'$d(lquals("BEFORE_IMAGE")) d . zm gdeerr("QUALREQD"):"Before_image" - i $d(lquals("NULL_SUBSCRIPTS")) d - . s nullsub=lquals("NULL_SUBSCRIPTS") - . s lquals("NULL_SUBSCRIPTS")=$s((nullsub="ALWAYS")!(nullsub="TRUE"):1,nullsub="EXISTING":2,1:0) + i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$RQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTCHG"):"region":REGION s update=1,s="" f s s=$o(lquals(s)) q:'$l(s) s regs(REGION,s)=lquals(s) diff --git a/sr_port/gdeerrors.msg b/sr_port/gdeerrors.msg index 522cd8c..4596aef 100644 --- a/sr_port/gdeerrors.msg +++ b/sr_port/gdeerrors.msg @@ -1,6 +1,6 @@ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! -! Copyright 2001, 2011 Fidelity Information Services, Inc ! +! Copyright 2001, 2012 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! @@ -69,4 +69,5 @@ WRITEERROR /info NONASCII /error/fao=4 CRYPTNOMM /error/fao=2 JNLALLOCGROW /info/fao=8 +KEYFORBLK /info/fao=4 .end diff --git a/sr_port/gdeinit.m b/sr_port/gdeinit.m index 1aff79f..064a6aa 100644 --- a/sr_port/gdeinit.m +++ b/sr_port/gdeinit.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2011 Fidelity Information Services, Inc ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -41,7 +41,7 @@ GDEINIT e s (encsupportedplat,gtm64)=FALSE i (gtm64=TRUE) f x=1:1:16 s HEX(x)=HEX(x-1)*16 i x#2=0 s TWO(x*4)=HEX(x) e f x=1:1:8 s HEX(x)=HEX(x-1)*16 i x#2=0 s TWO(x*4)=HEX(x) - f i=25:1:28 s TWO(i)=TWO(i-1)*2 + f i=25:1:30 s TWO(i)=TWO(i-1)*2 s TWO(31)=TWO(32)*.5 s lower="abcdefghijklmnopqrstuvwxyz",upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" s endian=endian($p($zver," ",4),$p($zver," ",3)) @@ -62,7 +62,7 @@ GDEINIT . s SIZEOF("gd_map")=36 . if ver'="VMS" d . . s SIZEOF("gd_region")=356 - . . s SIZEOF("gd_region_padding")=10 ; not used on VMS + . . s SIZEOF("gd_region_padding")=0 ; not used on VMS . . s SIZEOF("gd_segment")=340 . e d . . s SIZEOF("gd_region")=332 @@ -74,13 +74,19 @@ GDEINIT . s SIZEOF("gd_contents")=80 . s SIZEOF("gd_map")=40 . s SIZEOF("gd_region")=368 - . s SIZEOF("gd_region_padding")=14 + . s SIZEOF("gd_region_padding")=4 . s SIZEOF("gd_segment")=360 s SIZEOF("mident")=32 s SIZEOF("blk_hdr")=16 - s SIZEOF("rec_hdr")=3 + i ver'="VMS" d + . s SIZEOF("rec_hdr")=4 ;GTM-6941 + e d + . s SIZEOF("rec_hdr")=3 s SIZEOF("dsk_blk")=512 - s SIZEOF("max_str")=32767 + i ver'="VMS" d + . s SIZEOF("max_str")=1048576 + e d + . s SIZEOF("max_str")=32767 s SIZEOF("reg_jnl_deq")=4 ; not used on VMS s MAXNAMLN=SIZEOF("mident")-1,MAXREGLN=32,MAXSEGLN=32 ; maximum name length allowed is 31 characters s PARNAMLN=31,PARREGLN=31,PARSEGLN=31 @@ -116,16 +122,23 @@ GDEINIT s minreg("BEFORE_IMAGE")=0,minreg("COLLATION_DEFAULT")=0,minreg("STDNULLCOLL")=0 s minreg("EXTENSION")=0 i ver'="VMS" d - . s minreg("AUTOSWITCHLIMIT")=4096 - . s minreg("ALIGNSIZE")=256 ; geq RECORD_SIZE + . s minreg("AUTOSWITCHLIMIT")=16384 + . s minreg("ALIGNSIZE")=4096 ; geq RECORD_SIZE . s minreg("EPOCH_INTERVAL")=1 . s minreg("SYNC_IO")=0 . s minreg("YIELD_LIMIT")=0 + . s minreg("INST_FREEZE_ON_ERROR")=0 + . s minreg("BUFFER_SIZE")=2307 + . s minreg("QDBRUNDOWN")=0 + . s minreg("RECORD_SIZE")=0 + e d + . s minreg("RECORD_SIZE")=SIZEOF("rec_hdr")+4 s minreg("JOURNAL")=0,minreg("KEY_SIZE")=3,minreg("NULL_SUBSCRIPTS")=0 - s minreg("RECORD_SIZE")=SIZEOF("rec_hdr")+4 - s maxreg("ALLOCATION")=TWO(24),maxreg("BEFORE_IMAGE")=1,maxreg("BUFFER_SIZE")=2000 + s maxreg("ALLOCATION")=TWO(24),maxreg("BEFORE_IMAGE")=1 s maxreg("COLLATION_DEFAULT")=255,maxreg("STDNULLCOLL")=1 - i ver="VMS" s maxreg("EXTENSION")=HEX(4)-1 + i ver="VMS" do + . s maxreg("EXTENSION")=HEX(4)-1 + . s maxreg("BUFFER_SIZE")=2000 e d . s maxreg("EXTENSION")=1073741823 . s maxreg("AUTOSWITCHLIMIT")=8388607 @@ -133,14 +146,17 @@ GDEINIT . s maxreg("EPOCH_INTERVAL")=32767 . s maxreg("SYNC_IO")=1 . s maxreg("YIELD_LIMIT")=2048 - s maxreg("JOURNAL")=1,maxreg("KEY_SIZE")=255,maxreg("NULL_SUBSCRIPTS")=2 + . s maxreg("INST_FREEZE_ON_ERROR")=1 + . s maxreg("BUFFER_SIZE")=32768 + . s maxreg("QDBRUNDOWN")=1 + s maxreg("JOURNAL")=1,maxreg("KEY_SIZE")=1019,maxreg("NULL_SUBSCRIPTS")=2 s maxreg("RECORD_SIZE")=SIZEOF("max_str") ; segments ; bg s minseg("BG","ALLOCATION")=10,minseg("BG","BLOCK_SIZE")=SIZEOF("dsk_blk"),minseg("BG","EXTENSION_COUNT")=0 s minseg("BG","GLOBAL_BUFFER_COUNT")=64,minseg("BG","LOCK_SPACE")=10,minseg("BG","RESERVED_BYTES")=0 s maxseg("BG","ALLOCATION")=TWO(27),(maxseg("BG","BLOCK_SIZE"),maxseg("BG","RESERVED_BYTES"))=HEX(4)-SIZEOF("dsk_blk") - i ver'="VMS" s maxseg("BG","ALLOCATION")=TWO(28)-TWO(25) ; supports 224M blocks for UNIX only + i ver'="VMS" s maxseg("BG","ALLOCATION")=TWO(30)-TWO(25) ; supports 992M blocks for UNIX only s maxseg("BG","EXTENSION_COUNT")=HEX(4)-1,maxseg("BG","LOCK_SPACE")=65536 i (gtm64=TRUE) s maxseg("BG","GLOBAL_BUFFER_COUNT")=2147483647 ; 2G-1 e s maxseg("BG","GLOBAL_BUFFER_COUNT")=65536 @@ -148,7 +164,7 @@ GDEINIT s minseg("MM","ALLOCATION")=10,minseg("MM","BLOCK_SIZE")=SIZEOF("dsk_blk"),minseg("MM","DEFER")=0 s minseg("MM","LOCK_SPACE")=10,minseg("MM","EXTENSION_COUNT")=0,minseg("MM","RESERVED_BYTES")=0 s maxseg("MM","ALLOCATION")=TWO(27),(maxseg("MM","BLOCK_SIZE"),maxseg("BG","RESERVED_BYTES"))=HEX(4)-SIZEOF("dsk_blk") - i ver'="VMS" s maxseg("MM","ALLOCATION")=TWO(28)-TWO(25) ; supports 224M blocks for UNIX only + i ver'="VMS" s maxseg("MM","ALLOCATION")=TWO(30)-TWO(25) ; supports 992M blocks for UNIX only s maxseg("MM","DEFER")=86400,maxseg("MM","LOCK_SPACE")=1000,maxseg("MM","EXTENSION_COUNT")=HEX(4)-1 q @@ -165,6 +181,7 @@ syntabi: s syntab("ADD","REGION","STDNULLCOLL")="NEGATABLE" s syntab("ADD","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("ADD","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" + i ver'="VMS" s syntab("ADD","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("ADD","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("ADD","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("ADD","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" @@ -183,6 +200,7 @@ syntabi: s syntab("ADD","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("ADD","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("ADD","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs + i ver'="VMS" s syntab("ADD","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("ADD","REGION","RECORD_SIZE")="REQUIRED" s syntab("ADD","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("ADD","SEGMENT")="" @@ -218,6 +236,7 @@ syntabi: s syntab("CHANGE","REGION","STDNULLCOLL")="NEGATABLE" s syntab("CHANGE","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("CHANGE","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" + i ver'="VMS" s syntab("CHANGE","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("CHANGE","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("CHANGE","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" @@ -236,6 +255,7 @@ syntabi: s syntab("CHANGE","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("CHANGE","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("CHANGE","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs + i ver'="VMS" s syntab("CHANGE","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("CHANGE","REGION","RECORD_SIZE")="REQUIRED" s syntab("CHANGE","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT")="" @@ -268,6 +288,7 @@ syntabi: s syntab("TEMPLATE","REGION","STDNULLCOLL")="NEGATABLE" s syntab("TEMPLATE","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("TEMPLATE","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" + i ver'="VMS" s syntab("TEMPLATE","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("TEMPLATE","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("TEMPLATE","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" @@ -286,6 +307,7 @@ syntabi: s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs + i ver'="VMS" s syntab("TEMPLATE","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("TEMPLATE","REGION","RECORD_SIZE")="REQUIRED" s syntab("TEMPLATE","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT")="" @@ -365,8 +387,8 @@ VMS q UNIX: - s hdrlab="GTCGBDUNX007" ; must be concurrently maintained in gbldirnam.h!!! - i (gtm64=TRUE) s hdrlab="GTCGBDUNX107" ; the high order digit is a 64-bit flag + s hdrlab="GTCGBDUNX008" ; must be concurrently maintained in gbldirnam.h!!! + i (gtm64=TRUE) s hdrlab="GTCGBDUNX108" ; the high order digit is a 64-bit flag s tfile="$gtmgbldir" s accmeth="\BG\MM" s helpfile="$gtm_dist/gdehelp.gld" diff --git a/sr_port/gdemap.m b/sr_port/gdemap.m index 46deb78..db15bd6 100644 --- a/sr_port/gdemap.m +++ b/sr_port/gdemap.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2010 Fidelity Information Services, Inc ; +; Copyright 2010, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -39,48 +39,141 @@ SHOWNAM q ;---------------------------------------------------------------------------------------------------------------------------------- MAP2NAM(list) - n ar,l,s,x,xl,xn,xp,xt,xv - s x=$o(list("")) q:x'="#)" 0 - s x=$o(list(x)) - i x="%" s list("$")=list("%") k list("%") - e q:x'="$" 0 - s s=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),x=$o(list(""),-1) q:x'=s 0 - k ar,nams s nams=0,ar(0,s)="",x=$o(list(x),-1) - i x'="$",list(x)'=list(s) s xp="z" f q:xp="" s xn=xp_"*",(nams(xn),ar(1,xn))="",xp=$$lexprev(xp) - f q:x="$" d s x=$o(list(x),-1) - . i $d(list(x_")")) q - . s xl=$zl(x) - . i $ze(x,xl)=")" s xn=$ze(x,1,xl-1),(nams(xn))="" q - . i xl+1'xl&($d(list(xn))!$d(list(xn_")"))) - . i ip,ip'>in!($zl($ztr(x,"z"))&(xl+1=SIZEOF("mident")!'in)) do - . . s xp=x f ip=1:1:ip s xp=$$lexprev(xp),xn=xp_star,(nams(xn),ar(xl,xn))="" - . e s:'in&'$zl($ztr(x,"z")) in=1 s xn=x f in=1:1:in d q:$d(nams(xn))!$d(list(xn_")")) - . . s xp=xn_star,(nams(xp),ar($zl(xn),xp))="",xn=$$lexnext(xn) - s x="",ok=1 - f xl=1:1:SIZEOF("mident") d q:'ok - . f s x=$o(ar(xl,x)) q:x="" d q:'ok - . . s xt=$o(list(x)) - . . i '$zl(xt) s ok=0 q - . . s xv=list(xt) - . . i '$zl(xv) s ok=0 q - . . s xn=$$lexnext($ze(x,1,xl)) - . . f l=xl-1:-1:0 d chkprojection q:$zl(xp) - i 'ok q 0 - f s x=$o(nams(x)) q:x="" s xn=$o(list(x)),nams(x)=list(xn),nams=nams+1 - s xl=SIZEOF("mident")+1,x=$o(ar(xl,"")) - i $zl(x) f s xt=$o(ar(xl,x)) s xv=nams(x),xn=$$lexnext(x) d q:""=xt s x=xt - . f l=xl-3:-1:0 d chkprojection q:$zl(xp) - . i $zl(xt),xt'=xn,$d(nams(x)) f s nams(xn)=nams(x),nams=nams+1,xn=$$lexnext(xn) q:xt']xn - s nams("#")=list("#)"),nams("*")=list("$"),nams=nams+2 + n maxMap,currMap,currMapLen,prevMap,prevMapLen,currReg,prevPrefix,currPrefix + n namSpc,currNam,currNamLen,stopLoop,i,startMap,midentSize,prevPrevMap + s currMap=$o(list("")) q:currMap'="#)" 0 + s currMap=$o(list(currMap)) + i currMap="%" s list("$")=list("%") ; if "$" is missing, assign it the same value as "%" + e q:currMap'="$" 0 + s maxMap=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),currMap=$o(list(""),-1) q:currMap'=maxMap 0 + k nams + f q:currMap="$" s prevMap=$o(list(currMap),-1) d s currMap=prevMap + . s currReg=list(currMap) + . ; Note that with the above mapping, all keys in the range [prevMap,currMap) are mapped to currReg. + . ; where [ denotes closed interval and ) denotes open interval i.e. prevMap <= key < currMap + . ; Case (1a) : If currMap contains ")" (e.g. "abc)"), it most likely means prevMap would be "abc". + . ; In this case, just add "abc" as a namespace. No more processing needed for currMap. + . ; Case (1b) : But it is also possible prevMap is not "abc". + . ; In this case, do the "abc" namespace addition (as if prevMap was "abc"). + . ; But also proceed with the current iteration of the for loop as if "currMap" was "abc". + . s currMapLen=$zl(currMap) + . i $ze(currMap,currMapLen)=")" d q:prevMap=namSpc + . . s namSpc=$ze(currMap,1,currMapLen-1),nams(namSpc)=currReg + . . i prevMap'=namSpc s currMap=namSpc,currMapLen=currMapLen-1 + . ; Case (3) : If prevMap contains ")" (e.g. "abc)"), then check to see if its previous entry (say prevPrevMap) + . ; is the same region as currReg. If so, we can coalesce the entire range [prevPrevMap,currMap) into one with the + . ; exception of "abc" for which add an explicit namespace. Do this for as many ")" prevMap entries that you can find + . ; as long as its prevPrevMap entry is the same region as currReg. This could potentially coalesce a lot of intervals. + . ; Note: Need to handle a situation like Case (1b) here too. We do this by keeping prevMap as it is but adjusting + . ; just prevMapLen to be 1 byte less (to remove trailing ")"). + . s stopLoop=0 + . f d q:stopLoop + . . s prevMapLen=$zl(prevMap) + . . i $ze(prevMap,prevMapLen)'=")" s stopLoop=1 q + . . s namSpc=$ze(prevMap,1,$i(prevMapLen,-1)) + . . s prevPrevMap=$o(list(prevMap),-1) + . . i prevPrevMap'=namSpc s stopLoop=1 q + . . s nams(namSpc)=list(prevMap) + . . i list(prevMap)'=currReg s stopLoop=1 q + . . s prevMap=$o(list(prevMap),-1) + . . i prevMap="$" s stoploop=1,prevMapLen=1 q + . ; Note: At this point prevMap could contain a trailing ")" but in that case prevMapLen would have been adjusted to + . ; not consider that last byte. As long as all following usages of prevMap are of the form $ze(prevMap,1,prevMapLen) + . ; we will never see the ")" in prevMap. + . ; Case (4) : The map entry "currMap" exists and "prevMap" is the previous map entry. + . ; Determine the namespaces that potentially lie between the two map entries. + . ; And add them to the "nams" array. + . f i=1:1:currMapLen i $ze(currMap,i)'=$ze(prevMap,i) q + . s matchLen=i-1 ; the length of the maximal common prefix between prevMap and currMap + . ; Subcase (4a) : matchLen == prevMapLen + . ; In this case we are guaranteed that prevMapLen < currMapLen, and we need to add only ONE namespace. + . ; Example prevMap="ag", currMap="agk". Here, matchLen=2, prevMapLen=2, currMapLen=3. Add only "ag*". + . i (matchLen=prevMapLen)&(prevMapLenprevMapLen d + . . s currPrefix=prevPrefix_"z",prevPrefix=$ze(prevMap,1,i) + . . f q:currPrefix=prevPrefix s namSpc=currPrefix_"*",nams(namSpc)=currReg,currPrefix=$$lexprev(currPrefix) + . . ; Do optimization check at each sub-namespaces level. If it succeeds, stop processing any higher level sub-namespaces. + . . s startMap=$$findStartMap(currPrefix) + . . i list(startMap)=currReg s i=prevMapLen q ; set i to force quit out of for loop + . s namSpc=currPrefix_"*",nams(namSpc)=currReg + ; Update "nams" variable to contain # of elements in "nams" array + ; Take this opportunity to remove redundant namespaces. + ; Example : If "a*" and "ab*" both map to the same region, the namespace "ab*" can be safely removed. + ; But if "a*" maps to AREG, "aa*" maps to BREG, and "aaa*" maps to AREG, we cannot remove "aaa*" because + ; "a*" and "aaa*" maps to the same reg. This is because there is a more restrictive mapping "aa*" which + ; maps to a different region than "aaa*". That should prevail. + ; Similarly if "ab*" and "abc" both map to the same region, the namespace "abc" can be safely removed. + ; But if "abc*" also is mapped and to a different region than "abc", then "abc" cannot be removed. + s currNam="",nams=0 + ; With SIZEOF("mident")=32, we allow a max of 31-byte global name specifications. + ; But with SIZEOF("mident")=8 (for older versions with no longnames support, we allow a max of 8-byte global names. + ; Handle this 1-byte discrepancy for the 8-byte case by setting the variable midentSize accordingly. + s midentSize=$s(SIZEOF("mident")=8:9,1:SIZEOF("mident")) + s nams("*")=list("$") + f s currNam=$o(nams(currNam)) q:currNam="" s nams=nams+1 d + . s currNamLen=$zl(currNam) + . s currReg=nams(currNam) + . s killed=0,quitLoop=0 + . f i=$s($ze(currNam,currNamLen)="*":(currNamLen-2),1:currNamLen):-1:0 d q:quitLoop + . . s currPrefix=$ze(currNam,1,i)_"*" + . . s prevReg=$g(nams(currPrefix)) + . . i (""'=prevReg) d + . . . s quitLoop=1 + . . . i currReg=prevReg k nams(currNam) s nams=nams-1,killed=1 + . i 'killed,currNamLen'1) s xp=" " q - s xp=list(xr) - i '$zl(xp) s ok=0 q - i xv=xp k nams(x) - q +findStartMap:(key) + n startMap + s startMap=$o(list(key)) + s startMapLen=$zl(startMap) + i ($ze(startMap,startMapLen)=")")&($ze(startMap,1,startMapLen-1)=key) s startMap=$o(list(startMap)) + q startMap diff --git a/sr_port/gdemsgin.m b/sr_port/gdemsgin.m index e408838..72caec7 100644 --- a/sr_port/gdemsgin.m +++ b/sr_port/gdemsgin.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2011 Fidelity Information Services, Inc ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -22,6 +22,7 @@ GDEMSGIN s gdeerr("INPINTEG")=150503506 s gdeerr("KEYSIZIS")=150503523 s gdeerr("KEYTOOBIG")=150503515 + s gdeerr("KEYFORBLK")=150503891 s gdeerr("KEYWRDAMB")=150503530 s gdeerr("KEYWRDBAD")=150503538 s gdeerr("LOADGD")=150503547 diff --git a/sr_port/gdeshow.m b/sr_port/gdeshow.m index 78c0e71..70240d3 100644 --- a/sr_port/gdeshow.m +++ b/sr_port/gdeshow.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2011 Fidelity Information Services, Inc ; +; Copyright 2001, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -15,7 +15,6 @@ ALL COMMANDS s BOL="!" set delim=$select("VMS"=ver:"/",1:"-") - set defconst=$select("VMS"=ver:"$DEFAULT",1:"DEFAULT") i $l($get(cfile)) o cfile:(newversion:exc="w !,$ztatus c cfile zgoto $zl:cfilefail") u cfile d . d namec,segmentc,regionc,templatec . c cfile @@ -44,8 +43,7 @@ namec: w !,"LOCKS "_delim_"REGION=",nams(s) f s s=$o(nams(s)) q:'$l(s) d . i "*"'=s w !,"ADD "_delim_"NAME ",s," "_delim_"REGION=",nams(s) q - . s defreg=nams(s) - . i defconst'=defreg w !,"RENAME "_delim_"REGION "_defconst_" ",defreg + . i defreg'=nams(s) w !,"CHANGE "_delim_"NAME "_s_" "_delim_"REGION=",nams(s) w ! q REGION @@ -66,10 +64,14 @@ r1: d regionhd s jnl=0,s="" q onereg: w !,BOL,?x(1),s,?x(2),regs(s,"DYNAMIC_SEGMENT"),?x(3),$j(regs(s,"COLLATION_DEFAULT"),4) - w ?x(4),$j(regs(s,"RECORD_SIZE"),5),?x(5),$j(regs(s,"KEY_SIZE"),5) + i ver'="VMS" w ?x(4),$j(regs(s,"RECORD_SIZE"),7) + e w ?x(4),$j(regs(s,"RECORD_SIZE"),5) + w ?x(5),$j(regs(s,"KEY_SIZE"),5) w ?x(6),$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",regs(s,"NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") w ?x(7),$s(regs(s,"STDNULLCOLL"):"Y",1:"N") w ?x(8),$s(regs(s,"JOURNAL"):"Y",1:"N") + i ver'="VMS" w ?x(9),$s(regs(s,"INST_FREEZE_ON_ERROR"):"ENABLED",1:"DISABLED") + i ver'="VMS" w ?x(10),$s(regs(s,"QDBRUNDOWN"):"ENABLED",1:"DISABLED") q onejnl: w !,BOL,?x(1),s,?x(2),$s($l(regs(s,"FILE_NAME")):regs(s,"FILE_NAME"),1:"") @@ -81,21 +83,25 @@ onejnl: w !,BOL q regionc: - s s="" + n defseen,cmd + s s="",defseen=FALSE f s s=$o(regs(s)) q:'$l(s) d - . i s=defreg s defseg=regs(s,"DYNAMIC_SEGMENT") - . w !,$s(s=defreg:"CHANGE",1:"ADD")," "_delim_"REGION ",s," "_delim_"DYNAMIC=",regs(s,"DYNAMIC_SEGMENT") + . i s=defreg s defseen=TRUE,cmd="CHANGE" + . e s cmd="ADD" + . w !,cmd," "_delim_"REGION ",s," "_delim_"DYNAMIC=",regs(s,"DYNAMIC_SEGMENT") . f q="COLLATION_DEFAULT","RECORD_SIZE","KEY_SIZE" w " "_delim,q,"=",regs(s,q) - . w " "_delim_"NULL_SUBSCRIPTS=",$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",tmpreg("NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") + . w " "_delim_"NULL_SUBSCRIPTS=",$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",regs(s,"NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") . i regs(s,"STDNULLCOLL") w " "_delim_"STDNULLCOLL" . i regs(s,"JOURNAL") d - .. w " "_delim_"JOURNAL=(",$s(regs(s,"BEFORE_IMAGE"):"",1:"NO"),"BEFORE_IMAGE",",BUFFER_SIZE=",tmpreg("BUFFER_SIZE") + .. w " "_delim_"JOURNAL=(",$s(regs(s,"BEFORE_IMAGE"):"",1:"NO"),"BEFORE_IMAGE",",BUFFER_SIZE=",regs(s,"BUFFER_SIZE") .. w ",ALLOCATION=",regs(s,"ALLOCATION"),",EXTENSION=",regs(s,"EXTENSION") .. i ver'="VMS" w ",AUTOSWITCHLIMIT=",regs(s,"AUTOSWITCHLIMIT") .. i $l(regs(s,"FILE_NAME")) w ",FILE=""",regs(s,"FILE_NAME"),"""" .. w ")" . else w " "_delim_"NOJOURNAL" - i defconst'=defseg w !,"DELETE "_delim_"SEGMENT "_defconst + . i (ver'="VMS") w " "_delim_$s(regs(s,"INST_FREEZE_ON_ERROR"):"",1:"NO")_"INST_FREEZE_ON_ERROR" + . i (ver'="VMS") w " "_delim_$s(regs(s,"QDBRUNDOWN"):"",1:"NO")_"QDBRUNDOWN" + i (FALSE=defseen) w !,"DELETE "_delim_"REGION "_defreg w !,BOL q SEGMENT @@ -133,9 +139,12 @@ MM w ?x(8),$s(segs(s,"DEFER"):"DEFER",1:"NODEFER") i $ZVersion'["VMS" w !,BOL,?x(8),"ENCR=OFF" q segmentc: - s s="" + n defseen,cmd + s s="",defseen=FALSE f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD") d - . w !,$s(s=defseg:"CHANGE",1:"ADD")," "_delim_"SEGMENT ",s," "_delim_"ACCESS_METHOD=",segs(s,"ACCESS_METHOD") + . i s=defseg s defseen=TRUE,cmd="CHANGE" + . e s cmd="ADD" + . w !,cmd," "_delim_"SEGMENT ",s," "_delim_"ACCESS_METHOD=",segs(s,"ACCESS_METHOD") . i am="USER" q . f q="BLOCK_SIZE","ALLOCATION","EXTENSION_COUNT","LOCK_SPACE","RESERVED_BYTES" w " "_delim,q,"=",segs(s,q) . i "BG"=am d @@ -143,6 +152,7 @@ segmentc: .. i $zver'["VMS",encsupportedplat=TRUE,segs(s,"ENCRYPTION_FLAG") w " "_delim_"ENCRYPT" . i "MM"=am w " "_delim,$s(segs(s,"DEFER"):"DEFER",1:"NODEFER") . w " "_delim_"FILE=",segs(s,"FILE_NAME") + i (FALSE=defseen) w !,"DELETE "_delim_"SEGMENT "_defseg w !,BOL q MAP @@ -178,10 +188,14 @@ TEMPLATE q t1: d tmpreghd w !,BOL,?x(1),"",?x(3),$j(tmpreg("COLLATION_DEFAULT"),4) - w ?x(4),$j(tmpreg("RECORD_SIZE"),5),?x(5),$j(tmpreg("KEY_SIZE"),5) + i ver'="VMS" w ?x(4),$j(tmpreg("RECORD_SIZE"),7) + e w ?x(4),$j(tmpreg("RECORD_SIZE"),5) + w ?x(5),$j(tmpreg("KEY_SIZE"),5) w ?x(6),$s(tmpreg("NULL_SUBSCRIPTS")=1:"ALWAYS",tmpreg("NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") w ?x(7),$s(tmpreg("STDNULLCOLL"):"Y",1:"N") w ?x(8),$s(tmpreg("JOURNAL"):"Y",1:"N") + i ver'="VMS" w ?x(9),$s(tmpreg("INST_FREEZE_ON_ERROR"):"ENABLED",1:"DISABLED") + i ver'="VMS" w ?x(10),$s(tmpreg("QDBRUNDOWN"):"ENABLED",1:"DISABLED") i tmpreg("JOURNAL") d tmpjnlhd,tmpjnlbd d tmpseghd w !,BOL,?x(1),"",?x(2),$s(tmpacc="BG":" *",1:""),?x(3),"BG" @@ -212,11 +226,13 @@ templatec: . i "BG"=am d .. w " "_delim_"GLOBAL_BUFFER_COUNT=",tmpseg("BG","GLOBAL_BUFFER_COUNT") .. i $zver'["VMS",encsupportedplat=TRUE,tmpseg("BG","ENCRYPTION_FLAG") w " "_delim_"ENCRYPT" - . i "MM"=am w $s(tmpseg("MM","DEFER"):delim,1:delim_"NO"),"DEFER" + . i "MM"=am w " ",$s(tmpseg("MM","DEFER"):delim,1:delim_"NO"),"DEFER" w !,"TEMPLATE "_delim_"REGION" f q="RECORD_SIZE","KEY_SIZE" w " "_delim,q,"=",tmpreg(q) w " "_delim_"NULL_SUBSCRIPTS=",$s(tmpreg("NULL_SUBSCRIPTS")=1:"ALWAYS",tmpreg("NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") i tmpreg("STDNULLCOLL") w " "_delim_"STDNULLCOLL" + i (ver'="VMS") w " "_delim_$s(tmpreg("INST_FREEZE_ON_ERROR"):"",1:"NO")_"INST_FREEZE_ON_ERROR" + i (ver'="VMS") w " "_delim_$s(tmpreg("QDBRUNDOWN"):"",1:"NO")_"QDBRUNDOWN" i tmpreg("JOURNAL") d . w !,"TEMPLATE "_delim_"REGION "_delim_"JOURNAL=(" . w $s(tmpreg("BEFORE_IMAGE"):"",1:"NO"),"BEFORE_IMAGE,BUFFER_SIZE=",tmpreg("BUFFER_SIZE") @@ -235,12 +251,27 @@ namehd: w !,BOL,?x(1),$tr($j("",78)," ","-") q regionhd: - s x(0)=32,x(1)=1,x(2)=33,x(3)=65,x(4)=71,x(5)=77,x(6)=83,x(7)=94,x(8)=104 + s x(0)=32,x(1)=1,x(2)=33,x(3)=65,x(4)=71 + i ver'="VMS" s x(5)=79,x(6)=85,x(7)=96,x(8)=101,x(9)=105,x(10)=114 + e s x(5)=77,x(6)=83,x(7)=94,x(8)=104 w !,BOL,!,BOL,?x(0),"*** REGIONS ***" - w !,BOL,?x(2),"Dynamic",?x(3),$j("Def",4),?x(4),$j("Rec",5),?x(5),$j("Key",5),?x(6),"Null",?x(7),"Standard" - w !,BOL,?x(1),"Region",?x(2),"Segment",?x(3),$j("Coll",4),?x(4),$j("Size",5),?x(5),$j("Size",5) - w ?x(6),"Subs",?x(7),"NullColl",?x(8),"Journaling" - w !,BOL,?x(1),$tr($j("",114)," ","-") + w !,BOL,?x(7),"Std" + i ver'="VMS" w ?x(9),"Inst" + w !,BOL,?x(2),"Dynamic",?x(3),$j("Def",4) + i ver'="VMS" w ?x(4),$j("Rec",7) + e w ?x(4),$j("Rec",5) + w ?x(5),$j("Key",5),?x(6),"Null",?x(7),"Null" + i ver'="VMS" w ?x(9),"Freeze" + i ver'="VMS" w ?x(10),"Qdb" + w !,BOL,?x(1),"Region",?x(2),"Segment",?x(3),$j("Coll",4) + if ver'="VMS" w ?x(4),$j("Size",7) + e w ?x(4),$j("Size",5) + w ?x(5),$j("Size",5) + w ?x(6),"Subs",?x(7),"Coll",?x(8),"Jnl" + i ver'="VMS" w ?x(9),"on Error" + i ver'="VMS" w ?x(10),"Rndwn" + i ver'="VMS" w !,BOL,?x(1),$tr($j("",122)," ","-") + e w !,BOL,?x(1),$tr($j("",107)," ","-") q jnlhd: s x(0)=26,x(1)=1,x(2)=33,x(3)=59,x(4)=65,x(5)=71,x(6)=82,x(7)=$s(ver="VMS":88,1:91) @@ -264,21 +295,39 @@ maphd: w !,BOL,!,BOL,?x(0),x w !,BOL,?x(1)," - - - - - - - - - - Names - - - - - - - - - -" w !,BOL,?x(1),"From",?x(2),"Up to",?x(3),"Region / Segment / File(def ext: .dat)" - w !,BOL,?x(1),$tr($j("",131)," ","-") + w !,BOL,?x(1),$tr($j("",122)," ","-") q tmpreghd: - s x(0)=31,x(1)=1,x(2)=19,x(3)=44,x(4)=49,x(5)=55,x(6)=61,x(7)=72,x(8)=82 + s x(0)=31,x(1)=1,x(2)=19,x(3)=44,x(4)=49 + i ver'="VMS" s x(5)=57,x(6)=63,x(7)=74,x(8)=79,x(9)=83,x(10)=92 + e s x(5)=55,x(6)=61,x(7)=72,x(8)=82 w !,BOL,!,BOL,?x(0),"*** TEMPLATES ***" - w !,BOL,?x(3),$j("Def",4),?x(4),$j("Rec",5),?x(5),$j("Key",5),?x(6),"Null",?x(7),"Standard" - w !,BOL,?x(1),"Region",?x(3),$j("Coll",4),?x(4),$j("Size",5),?x(5),$j("Size",5) - w ?x(6),"Subs",?x(7),"NullColl",?x(8),"Journaling" - w !,BOL,?x(1),$tr($j("",92)," ","-") + w !,BOL,?x(7),"Std" + i ver'="VMS" w ?x(9),"Inst" + w !,BOL,?x(3),$j("Def",4) + i ver'="VMS" w ?x(4),$j("Rec",7) + e w ?x(4),$j("Rec",5) + w ?x(5),$j("Key",5),?x(6),"Null",?x(7),"Null" + i ver'="VMS" w ?x(9),"Freeze" + i ver'="VMS" w ?x(10),"Qdb" + w !,BOL,?x(1),"Region",?x(3),$j("Coll",4) + i ver'="VMS" w ?x(4),$j("Size",7) + e w ?x(4),$j("Size",5) + w ?x(5),$j("Size",5) + w ?x(6),"Subs",?x(7),"Coll",?x(8),"Jnl" + i ver'="VMS" w ?x(9),"on Error" + i ver'="VMS" w ?x(10),"Rndwn" + i ver'="VMS" w !,BOL,?x(1),$tr($j("",100)," ","-") + e w !,BOL,?x(1),$tr($j("",85)," ","-") q tmpjnlhd: s x(0)=26,x(1)=1,x(2)=18,x(3)=44,x(4)=51,x(5)=57,x(6)=68,x(7)=74 w !,BOL,?x(2),"Jnl File (def ext: .mjl)" - w ?x(3),"Before",?x(4),$j("Buff",5),?x(5),$j("Alloc",10),?x(6),"Exten" ;?x(7),"Stop" - w !,BOL,?x(1),$tr($j("",78)," ","-") + w ?x(3),"Before",?x(4),$j("Buff",5),?x(5),$j("Alloc",10) + i ver="VMS" w ?x(6),"Exten" + e w ?x(6),$j("Exten",10),?x(7),$j("AutoSwitch",13) + i ver="VMS" w !,BOL,?x(1),$tr($j("",78)," ","-") + e w !,BOL,?x(1),$tr($j("",90)," ","-") q tmpseghd: s x(0)=32,x(1)=1,x(2)=18,x(3)=38,x(4)=42,x(5)=46,x(6)=52,x(7)=63,x(8)=69 diff --git a/sr_port/gdetempl.m b/sr_port/gdetempl.m index 4331d54..1444da8 100644 --- a/sr_port/gdetempl.m +++ b/sr_port/gdetempl.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2005 Fidelity Information Services, Inc ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -10,11 +10,9 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; template: ;implement the verb: TEMPLATE REGION - n nullsub - i $d(lquals("JOURNAL")),lquals("JOURNAL"),'tmpreg("JOURNAL"),'$d(lquals("BEFORE_IMAGE")) zm gdeerr("QUALREQD"):"Before_image" - i $d(lquals("NULL_SUBSCRIPTS")) d - . s nullsub=lquals("NULL_SUBSCRIPTS") - . s lquals("NULL_SUBSCRIPTS")=$s((nullsub="ALWAYS")!(nullsub="TRUE"):1,nullsub="EXISTING":2,1:0) + i $d(lquals("JOURNAL")),lquals("JOURNAL"),'tmpreg("JOURNAL"),'$d(lquals("BEFORE_IMAGE")) d + . zm gdeerr("QUALREQD"):"Before_image" + i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$TRQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTCHG"):"region":"template" s update=1,s="" f s s=$o(lquals(s)) q:'$l(s) s tmpreg(s)=lquals(s) i s="ALLOCATION" s tmpreg("EXTENSION")=lquals(s)\10 diff --git a/sr_port/gds_blk_upgrade.c b/sr_port/gds_blk_upgrade.c index 9e8745d..46f87de 100644 --- a/sr_port/gds_blk_upgrade.c +++ b/sr_port/gds_blk_upgrade.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2009 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,8 @@ GBLREF boolean_t gtm_blkupgrade_override; GBLREF uint4 gtm_blkupgrade_flag; /* control whether dynamic upgrade is attempted or not */ +error_def(ERR_DYNUPGRDFAIL); + int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 blksize, enum db_ver *ondsk_blkver) { blk_hdr_ptr_t bp; @@ -33,8 +35,6 @@ int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 blks v15_trans_num v15tn; uint4 v15bsiz, v15levl; - error_def(ERR_DYNUPGRDFAIL); - assert(gds_blk_src); assert(gds_blk_trg); /* Assert that the input buffer is 8-byte aligned for us to freely de-reference 8-byte tn fields from the buffer header. @@ -57,7 +57,7 @@ int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 blks if (UPGRADE_IF_NEEDED == gtm_blkupgrade_flag) { if (NULL != ondsk_blkver) - *ondsk_blkver = GDSV5; + *ondsk_blkver = GDSV6; return SS_NORMAL; } else { @@ -76,6 +76,6 @@ int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 blks bp->tn = v15tn; bp->bsiz = v15bsiz; bp->levl = v15levl; - bp->bver = GDSV5; + bp->bver = GDSV6; return SS_NORMAL; } diff --git a/sr_port/gds_blk_upgrade.h b/sr_port/gds_blk_upgrade.h index 98a22a0..7385af7 100644 --- a/sr_port/gds_blk_upgrade.h +++ b/sr_port/gds_blk_upgrade.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2009 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -74,7 +74,7 @@ GBLREF boolean_t dse_running; { \ upgrdstatus = SS_NORMAL; \ if (NULL != (ondskblkver)) \ - *(ondskblkver) = GDSV5; \ + *(ondskblkver) = GDSV6; \ } else \ { \ upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr), \ @@ -86,7 +86,7 @@ GBLREF boolean_t dse_running; { \ upgrdstatus = SS_NORMAL; \ if (NULL != (ondskblkver)) \ - *(ondskblkver) = GDSV5; \ + *(ondskblkver) = GDSV6; \ } else if (UPGRADE_ALWAYS == gtm_blkupgrade_flag) \ { \ upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr), \ diff --git a/sr_port/gds_map_moved.c b/sr_port/gds_map_moved.c index ea0b117..46aba9e 100644 --- a/sr_port/gds_map_moved.c +++ b/sr_port/gds_map_moved.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,106 +25,62 @@ #include "tp.h" #include "gds_map_moved.h" #include "hashtab_mname.h" -#include "dpgbldir.h" -#include "gtmimagename.h" -GBLREF sgmnt_addrs *cs_addrs; -GBLREF sgmnt_data_ptr_t cs_data; -GBLREF gd_addr *gd_header; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data_ptr_t cs_data; +GBLREF gv_namehead *gv_target_list; -void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, off_t new_eof) + +void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz) { int hist_index; sm_long_t adj; - srch_hist *hist, *dir_hist, *dir_alt_hist, *hist1, *hist2; - ht_ent_mname *tabent, *topent; + srch_hist *hist, *hist1, *hist2; gv_namehead *gvt; - gvnh_reg_t *gvnh_reg; - hash_table_mname *tbl; - gd_addr *addr_ptr; + sgmnt_addrs *csa; - assert(cs_addrs->now_crit); - /* It's possible to arrive here via mupip_backup --> wcs_flu --> wcs_mm_recover --> gds_map_moved and have - * cs_addrs->dir_tree be NULL. To distinguish that case, we can also check if this this is the GTM image - * in the following assert and then return because there's nothing to do here. - */ - assert(!IS_GTM_IMAGE || ((NULL != cs_addrs->dir_tree) && (NULL != &cs_addrs->dir_tree->hist))); - /* This initialization has to be done irrespective of whether new_base is different from old_base or not. */ - cs_data = cs_addrs->hdr = (sgmnt_data_ptr_t)new_base; - cs_addrs->db_addrs[1] = new_base + new_eof - 1; - cs_addrs->bmm = MM_ADDR(cs_data); - cs_addrs->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_uc_ptr_t)cs_data + (cs_data->start_vbn - 1) * DISK_BLOCK_SIZE); - if (NULL != cs_addrs->sgm_info_ptr) - cs_addrs->sgm_info_ptr->tp_csd = cs_addrs->hdr; - bt_init(cs_addrs); - if (NULL == cs_addrs->dir_tree) - return; + csa = cs_addrs; + assert(csa->now_crit); + assert(cs_data == csa->hdr); + assert((NULL == csa->sgm_info_ptr) || (csa->hdr == csa->sgm_info_ptr->tp_csd)); + assert(csa->bmm == MM_ADDR(cs_data)); + assert(csa->ti == &cs_data->trans_hist); + csa->db_addrs[1] = new_base + mmap_sz - 1; /* The following adjustment needs to be done only if new_base is different from old_base */ if (new_base == old_base) return; adj = (sm_long_t)(new_base - old_base); assert(0 != adj); - dir_hist = &cs_addrs->dir_tree->hist; - dir_alt_hist = cs_addrs->dir_tree->alt_hist; - for (hist = dir_hist; (NULL != hist); hist = (hist == dir_hist) ? dir_alt_hist : NULL) - { - for (hist_index = 0; HIST_TERMINATOR != hist->h[hist_index].blk_num; hist_index++) - { - assert(MAX_BT_DEPTH >= hist_index); - if ((old_base <= hist->h[hist_index].buffaddr) && - (old_top > hist->h[hist_index].buffaddr)) - { - hist->h[hist_index].buffaddr += adj; - assert(new_base <= hist->h[hist_index].buffaddr); - } else - { - /* It has to be a private copy */ - assert((hist->h[hist_index].first_tp_srch_status != 0) || - (((off_chain *)&(hist->h[hist_index].blk_num))->flag != 0)); - } - } - } - /* It is possible that more than one global directory has regions mapping to the same physical database file. - * In this case, the search histories in the gv_targets hash tables of all those glds should be fixed. Hence, - * we go through all open glds (instead of just the currently active gd_header). + /* Scan the list of gvts allocated by this process in its lifetime and see if they map to the current csa. + * If so adjust their clues (in the histories) as appropriate to reflect the remapping of the database file. */ - assert(NULL != get_next_gdr(NULL)); /* assert that we have at least one open global directory */ - for (addr_ptr = get_next_gdr(NULL); NULL != addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) + for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh) { - tbl = addr_ptr->tab_ptr; - assert(NULL != tbl); - for (tabent = tbl->base, topent = tbl->top; tabent < topent; tabent++) + if ((csa == gvt->gd_csa) && (0 < gvt->clue.end)) { - if ((HTENT_VALID_MNAME(tabent, gvnh_reg_t, gvnh_reg)) && (NULL != (gvt = gvnh_reg->gvt)) - && (cs_addrs == gvt->gd_csa) && (0 < gvt->clue.end)) + hist1 = &gvt->hist; + hist2 = gvt->alt_hist; + for (hist = hist1; (NULL != hist); hist = (hist == hist1) ? hist2 : NULL) { - hist1 = &gvt->hist; - hist2 = gvt->alt_hist; - for (hist = hist1; (NULL != hist); hist = (hist == hist1) ? hist2 : NULL) + for (hist_index = 0; HIST_TERMINATOR != hist->h[hist_index].blk_num; hist_index++) { - if (((hist == hist1) && (hist == dir_hist)) - || ((hist == hist2) && (hist == dir_alt_hist))) - continue; - for (hist_index = 0; HIST_TERMINATOR != hist->h[hist_index].blk_num; hist_index++) + assert(MAX_BT_DEPTH >= hist_index); + if ((old_base <= hist->h[hist_index].buffaddr) + && (old_top > hist->h[hist_index].buffaddr)) { - assert(MAX_BT_DEPTH >= hist_index); - if ((old_base <= hist->h[hist_index].buffaddr) - && (old_top > hist->h[hist_index].buffaddr)) - { - hist->h[hist_index].buffaddr += adj; - assert(new_base <= hist->h[hist_index].buffaddr); - } else if ((hist == hist2) && (0 < gvt->clue.end)) - { /* alt_hist is not updated when clue is set so the buffaddr can - * point to a prior instance of the file's mapping. So, reset alt_hist. - */ - hist->h[hist_index].blk_num = HIST_TERMINATOR; - } else - { /* It's already been adjusted or it has to be a private copy */ - assert(((new_base <= hist->h[hist_index].buffaddr) - && (hist->h[hist_index].buffaddr < new_base + (old_top - old_base))) - || (0 != hist->h[hist_index].first_tp_srch_status) - || (0 != ((off_chain *)&(hist->h[hist_index].blk_num))->flag)); - } + hist->h[hist_index].buffaddr += adj; + assert(new_base <= hist->h[hist_index].buffaddr); + } else if ((hist == hist2) && (0 < gvt->clue.end)) + { /* alt_hist is not updated when clue is set so the buffaddr can + * point to a prior instance of the file's mapping. So, reset alt_hist. + */ + hist->h[hist_index].blk_num = HIST_TERMINATOR; + } else + { /* It's already been adjusted or it has to be a private copy */ + assert(((new_base <= hist->h[hist_index].buffaddr) + && (hist->h[hist_index].buffaddr < new_base + (old_top - old_base))) + || (0 != hist->h[hist_index].first_tp_srch_status) + || (0 != ((off_chain *)&(hist->h[hist_index].blk_num))->flag)); } } } diff --git a/sr_port/gds_map_moved.h b/sr_port/gds_map_moved.h index 7a37e5f..f04a2aa 100644 --- a/sr_port/gds_map_moved.h +++ b/sr_port/gds_map_moved.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 GDS_MAP_MOVED_INCLUDED #define GDS_MAP_MOVED_INCLUDED -void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, off_t new_eof); +void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz); #endif /* GDS_MAP_MOVED_INCLUDED */ diff --git a/sr_port/gds_rundown.h b/sr_port/gds_rundown.h index 15ab79f..380fb0b 100644 --- a/sr_port/gds_rundown.h +++ b/sr_port/gds_rundown.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,39 @@ #ifndef GDS_RUNDOWN_INCLUDED #define GDS_RUNDOWN_INCLUDED +#ifdef UNIX +int4 gds_rundown(void); + +#define CAN_BYPASS(SEMVAL, CANCELLED_TIMER, INST_IS_FROZEN) \ + (((IS_GTM_IMAGE && csd->mumps_can_bypass) && !CANCELLED_TIMER && (PROC_FACTOR * (num_additional_processors + 1) < SEMVAL)) \ + || ((2 < SEMVAL) && (IS_LKE_IMAGE || IS_DSE_IMAGE)) || INST_IS_FROZEN) + +#define CANCEL_DB_TIMERS(region, csa, cancelled_timer, cancelled_dbsync_timer) \ +{ \ + if (csa->timer) \ + { \ + cancel_timer((TID)region); \ + if (NULL != csa->nl) \ + DECR_CNT(&csa->nl->wcs_timers, &csa->nl->wc_var_lock); \ + cancelled_timer = TRUE; \ + csa->timer = FALSE; \ + } \ + if (csa->dbsync_timer) \ + { \ + CANCEL_DBSYNC_TIMER(csa); \ + cancelled_dbsync_timer = TRUE; \ + } \ +} + +/* A multiplicative factor to the # of processors used in determining if a GT.M process in gds_rundown can bypass semaphores */ +#ifdef DEBUG +# define PROC_FACTOR 2 +#else +# define PROC_FACTOR 20 +#endif + +#else void gds_rundown(void); +#endif #endif /* GDS_RUNDOWN_INCLUDED */ diff --git a/sr_port/gdsbgtr.h b/sr_port/gdsbgtr.h index 949d6a3..ed25755 100644 --- a/sr_port/gdsbgtr.h +++ b/sr_port/gdsbgtr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,7 +19,7 @@ */ -#define BG_TRACE_PRO_ANY(C, X) {C->hdr->X##_cntr++; C->hdr->X##_tn = C->ti->curr_tn;} +#define BG_TRACE_PRO_ANY(C, X) {C->hdr->X##_cntr++; C->hdr->X##_tn = C->hdr->trans_hist.curr_tn ;} #define BG_TRACE_PRO(Q) BG_TRACE_PRO_ANY(cs_addrs, Q) #ifdef DEBUG diff --git a/sr_port/gdsblk.h b/sr_port/gdsblk.h index 4cecaeb..3707ed2 100644 --- a/sr_port/gdsblk.h +++ b/sr_port/gdsblk.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 CST_USAR(b, r) ((b)->bsiz - ((uchar_ptr_t(r) + (r)->rsiz - (uchar_ptr_t)(b))) #define CST_KSIZ (gv_curr_key->end - gv_curr_key->base + 1) #define BSTAR_REC_SIZE INTCAST((SIZEOF(rec_hdr) + SIZEOF(block_id))) -#define BSTAR_REC(r) ((rec_hdr_ptr_t)(r))->rsiz = BSTAR_REC_SIZE; ((rec_hdr_ptr_t)(r))->cmpc = 0; +#define BSTAR_REC(r) ((rec_hdr_ptr_t)(r))->rsiz = BSTAR_REC_SIZE; SET_CMPC((rec_hdr_ptr_t)(r), 0); #define IS_LEAF(b) (0 == ((blk_hdr_ptr_t)(b))->levl) #define IS_BML(b) (BML_LEVL == ((blk_hdr_ptr_t)(b))->levl) #define IS_BSTAR_REC(r) ((r)->rsiz == BSTAR_REC_SIZE) @@ -39,6 +39,60 @@ #define MIN_EXTN_COUNT 0 #define MAX_DB_BLK_SIZE ((1 << 16) - 512) /* 64Kb - 512 (- 512 to take care of VMS's max I/O capabilities) */ + +/* Note: EVAL_CMPC not to be confused with the previously existing GET_CMPC macro in mu_reorg.h! + * The maximum key size in V5 was 255 bytes, including the two null bytes at the end. Two distinct keys + * could have a common prefix of at most 252.The 255 limit was imposed because the record header was + * 3 bytes and had only 1 byte for compression count. But on UNIX the record header is actually 4 bytes + * (see pragmas below), leaving an unused filler byte. To accommodate larger keys while + * maintaining compatibility with V5, we can overload the previously unused values of cmpc + * to get compression counts of up to 1020, which will support keys up to 1023 bytes. + * As in V5 compression counts of between 0 and 252, inclusive, are stored in the first byte. + * rp->cmpc values of 253, 254, and 255 indicate information is stored in the second byte. + * + * There are several constants used below. They are very specific and ONLY used here. We don't #define them + * because that implies you can change one and the logic will still work. But that's not the case. + * 253 --- cmpc value just beyond the highest possible in V5 (252). 253 = OLD_MAX_KEY_SZ - two terminators. + * 256 --- Number of distinct compression counts that can be stored when cmpc is either 253, 254, or 255. + * Corresponds to the one extra byte, which can store 256 values. + * 0x03FF --- Equals 1023. We want to avoid having EVAL_CMPC return huge values due to concurrent changes + * to block contents. This limits the result, preventing unintentionally large memcpy's in e.g. gvcst_put. + */ +#ifdef UNIX +# define EVAL_CMPC(RP) ((253 > (RP)->cmpc) \ + ? (RP)->cmpc \ + : (253 + ((RP)->cmpc - 253) * 256 + (int)(RP)->cmpc2) & 0x03FF) +# define EVAL_CMPC2(RP, VAR) \ +{ /* Usage note: make sure VAR is an int */ \ + VAR = (RP)->cmpc; \ + if (253 <= VAR) \ + VAR = (253 + ((VAR) - 253) * 256 + (int)(RP)->cmpc2) & 0x03FF; \ +} +# define SET_CMPC(RP, VAL) \ +{ \ + int lcl_cmpc_val; \ + \ + lcl_cmpc_val = (VAL); \ + if (253 > lcl_cmpc_val) \ + (RP)->cmpc = (unsigned char)lcl_cmpc_val; \ + else \ + { \ + (RP)->cmpc = (unsigned char)(253 + (lcl_cmpc_val - 253) / 256); \ + (RP)->cmpc2 = (unsigned char)((lcl_cmpc_val - 253) & 0xFF); \ + } \ +} +#else +# define EVAL_CMPC(RP) ((int)(RP)->cmpc) +# define EVAL_CMPC2(RP, VAR) \ +{ /* Usage note: make sure VAR is an int */ \ + VAR = (RP)->cmpc; \ +} +# define SET_CMPC(RP, VAL) \ +{ \ + (RP)->cmpc = (unsigned char)(VAL); \ +} +#endif + #if defined(__alpha) && defined(__vms) # pragma member_alignment save # pragma nomember_alignment @@ -70,6 +124,9 @@ typedef struct { unsigned short rsiz; unsigned char cmpc; +# ifdef UNIX + unsigned char cmpc2; /* extra byte allows compression count up to 1020 */ +# endif } rec_hdr; #if defined(__alpha) && defined(__vms) diff --git a/sr_port/gdsbml.h b/sr_port/gdsbml.h index 98be521..da27e4d 100644 --- a/sr_port/gdsbml.h +++ b/sr_port/gdsbml.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,19 +46,20 @@ #define BM_MINUS_BLKHDR_SIZE(bplm) ((bplm) / (BITS_PER_UCHAR / BML_BITS_PER_BLK)) #define BM_SIZE(bplm) (SIZEOF(blk_hdr) + BM_MINUS_BLKHDR_SIZE(bplm)) -#define VALIDATE_BM_BLK(blk, bp, csa, region, status) \ -{ \ - error_def(ERR_DBBMLCORRUPT); \ - \ - assert(BITS_PER_UCHAR % BML_BITS_PER_BLK == 0); /* assert this for the BM_MINUS_BLKHDR_SIZE macro */ \ - if (IS_BITMAP_BLK(blk) && ((LCL_MAP_LEVL != (bp)->levl) || (BM_SIZE(csa->hdr->bplmap) != (bp)->bsiz))) \ - { \ - send_msg(VARLSTCNT(9) ERR_DBBMLCORRUPT, 7, DB_LEN_STR(region), \ - blk, (bp)->bsiz, (bp)->levl, &(bp)->tn, &csa->ti->curr_tn); \ - status = FALSE; \ - assert(FALSE); \ - } else \ - status = TRUE; \ +#define VALIDATE_BM_BLK(blk, bp, csa, region, status) \ +{ \ + error_def(ERR_DBBMLCORRUPT); /* BYPASSOK */ \ + \ + assert(BITS_PER_UCHAR % BML_BITS_PER_BLK == 0); /* assert this for the BM_MINUS_BLKHDR_SIZE macro */ \ + if (IS_BITMAP_BLK(blk) && ((LCL_MAP_LEVL != (bp)->levl) || (BM_SIZE(csa->hdr->bplmap) != (bp)->bsiz)) \ + UNIX_ONLY(DEBUG_ONLY(|| (gtm_white_box_test_case_enabled \ + && (WBTEST_ANTIFREEZE_DBBMLCORRUPT == gtm_white_box_test_case_number))))) \ + { \ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBBMLCORRUPT, 7, DB_LEN_STR(region), \ + blk, (bp)->bsiz, (bp)->levl, &(bp)->tn, &csa->ti->curr_tn); \ + status = FALSE; \ + } else \ + status = TRUE; \ } #define NO_FREE_SPACE -1 @@ -83,6 +84,50 @@ #define MASTER_MAP_BITS_PER_LMAP 1 + +#define DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA) \ +{ \ + FUNC = (CS->reference_cnt > 0) ? bml_busy : (CSA->hdr->db_got_to_v5_once ? bml_recycled : bml_free); \ +} +#ifndef UNIX + #define DETERMINE_BML_FUNC(FUNC, CS, CSA) DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA) +#else +# define DETERMINE_BML_FUNC(FUNC, CS, CSA) \ +{ \ + GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; \ + \ + if (CSA->nl->trunc_pid) \ + { /* A truncate is in progress. If we are acquiring a block, we need to update cnl->highest_lbm_with_busy_blk to \ + * avoid interfering with the truncate. If we are truncate doing a t_recycled2free mini-transaction, we need to \ + * select bml_free. \ + */ \ + if (cs->reference_cnt > 0) \ + { \ + FUNC = bml_busy; \ + CSA->nl->highest_lbm_with_busy_blk = MAX(CS->blk, CSA->nl->highest_lbm_with_busy_blk); \ + } else if (cs->reference_cnt < 0) \ + { \ + if (CSA->hdr->db_got_to_v5_once && (CSE_LEVEL_DRT_LVL0_FREE != CS->level)) \ + FUNC = bml_recycled; \ + else \ + { /* always set the block as free when gvcst_bmp_mark_free a level-0 block in DIR tree; reset \ + * level since t_end will call bml_status_check which has an assert for bitmap block level \ + */ \ + FUNC = bml_free; \ + CS->level = LCL_MAP_LEVL; \ + } \ + } else /* cs->reference_cnt == 0 */ \ + { \ + if (CSA->hdr->db_got_to_v5_once && mu_reorg_upgrd_dwngrd_in_prog) \ + FUNC = bml_recycled; \ + else \ + FUNC = bml_free; \ + } \ + } else /* Choose bml_func as it was chosen before truncate feature. */ \ + DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA); \ +} +#endif + int4 bml_find_free(int4 hint, uchar_ptr_t base_addr, int4 total_bits); int4 bml_init(block_id bml); uint4 bml_busy(uint4 setbusy, sm_uc_ptr_t map); diff --git a/sr_port/gdsbt.h b/sr_port/gdsbt.h index 95b311f..8856aef 100644 --- a/sr_port/gdsbt.h +++ b/sr_port/gdsbt.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -180,18 +180,21 @@ typedef struct typedef struct { #if defined(UNIX) + FILL8DCL(uint4, crit_cycle, 1); global_latch_t semaphore; - CACHELINE_PAD(SIZEOF(global_latch_t), 1) - latch_t crashcnt; - int4 filler1; /* for alignment */ + CACHELINE_PAD(8 + SIZEOF(global_latch_t), 2) /* 8 for the FILL8DCL */ + FILL8DCL(latch_t, crashcnt, 3); global_latch_t crashcnt_latch; - CACHELINE_PAD(SIZEOF(latch_t) + SIZEOF(latch_t) + SIZEOF(global_latch_t), 2) - latch_t queslots; - int4 filler2; /* for alignment */ - CACHELINE_PAD(SIZEOF(latch_t) + SIZEOF(latch_t), 3) + CACHELINE_PAD(8 + SIZEOF(global_latch_t), 4) /* 8 for the FILL8DCL */ + compswap_time_field stuckexec; + CACHELINE_PAD(SIZEOF(compswap_time_field), 5) + FILL8DCL(latch_t, queslots, 6); + CACHELINE_PAD(SIZEOF(latch_t) + SIZEOF(latch_t), 7) mutex_que_head prochead; - CACHELINE_PAD(SIZEOF(mutex_que_head), 4) + CACHELINE_PAD(SIZEOF(mutex_que_head), 8) mutex_que_head freehead; + CACHELINE_PAD(SIZEOF(mutex_que_head), 9) + #elif defined(VMS) short semaphore; unsigned short wrtpnd; @@ -215,8 +218,8 @@ typedef struct typedef struct { /* keep this structure and member offsets defined in sr_avms/mutex.mar in sync */ int4 mutex_hard_spin_count; int4 mutex_sleep_spin_count; - int4 mutex_spin_sleep_mask; - int4 filler1; + int4 mutex_spin_sleep_mask; /* currently unused */ + int4 mutex_que_entry_space_size; /* total number of entries */ } mutex_spin_parms_struct; enum crit_ops @@ -311,15 +314,20 @@ typedef struct node_local_struct boolean_t ccp_jnl_closed; boolean_t glob_sec_init; uint4 wtstart_pid[MAX_WTSTART_PID_SLOTS]; /* Maintain pids of wcs_wtstart processes */ - int4 filler8_int; /* 8-byte alignment filler */ + volatile boolean_t wc_blocked; /* Set to TRUE by process that knows it is leaving the cache in a + * possibly inconsistent state. Next process grabbing crit will do + * cache recovery. This setting also stops all concurrent writers + * from working on the cache. In MM mode, it is used to call + * wcs_recover during a file extension */ global_latch_t wc_var_lock; /* latch used for access to various wc_* ref counters */ CACHELINE_PAD(SIZEOF(global_latch_t), 1) /* Keep these two latches in separate cache lines */ global_latch_t db_latch; /* latch for interlocking on hppa and tandem */ CACHELINE_PAD(SIZEOF(global_latch_t), 2) int4 cache_hits; int4 wc_in_free; /* number of write cache records in free queue */ - /* All the counters below (declared using CNTR4DCL are 4-byte counters. We would like to keep them in separate - * cachelines on load-lock/store-conditional platforms particularly and other platforms too just to be safe. + /* All counters below (declared using CNTR4DCL) are 2 or 4-bytes, depending on platform, but always stored in 4 bytes. + * CACHELINE_PAD doesn't use SIZEOF because misses any padding added by CNTR4DCL. We want to keep the counters in + * separate cachelines on load-lock/store-conditional platforms particularly and on other platforms too, just to be safe. */ volatile CNTR4DCL(wcs_timers, 1); /* number of write cache timers in use - 1 */ CACHELINE_PAD(4, 3) @@ -368,8 +376,8 @@ typedef struct node_local_struct char replinstfilename[MAX_FN_LEN + 1];/* 256 : Name of the replication instance file corresponding to this db. * In VMS, this is the name of the corresponding global directory. */ - int4 secshr_ops_index; - gtm_uint64_t secshr_ops_array[SECSHR_OPS_ARRAY_SIZE]; /* taking up 8K */ + int4 secshr_ops_index; + gtm_uint64_t secshr_ops_array[SECSHR_OPS_ARRAY_SIZE]; /* taking up 8K */ gvstats_rec_t gvstats_rec; trans_num last_wcsflu_tn; /* curr_tn when last wcs_flu was done on this database */ sm_off_t encrypt_glo_buff_off; /* offset from unencrypted global buffer to its encrypted counterpart */ @@ -384,8 +392,7 @@ typedef struct node_local_struct 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 */ - uint4 kip_pid_array[MAX_KIP_PID_SLOTS]; /* Processes actively doing kill (0 denotes empty slots) */ - + 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 */ /* from info in the file header. */ @@ -403,10 +410,21 @@ typedef struct node_local_struct block_id highest_lbm_with_busy_blk; /* Furthest lmap block known to have had a busy block during truncate. */ # if defined(UNIX) ftokhist ftok_ops_array[FTOK_OPS_ARRAY_SIZE]; + volatile uint4 root_search_cycle; /* incremented online rollback ends and mu_swap_root */ volatile uint4 onln_rlbk_cycle; /* incremented everytime an online rollback ends */ volatile uint4 db_onln_rlbkd_cycle; /* incremented everytime an online rollback takes the database back in time */ volatile uint4 onln_rlbk_pid; /* process ID of currently running online rollback. */ - uint4 dbrndwn_skip_cnt; /* # of processes that skipped gds_rundown due to a concurrent online rollback */ + uint4 dbrndwn_ftok_skip; /* # of processes that skipped FTOK semaphore in gds_rundown due to too many MUMPS + processes */ + uint4 dbrndwn_access_skip; /* # of processes that skipped access control semaphore in gds_rundown due to a + concurrent online rollback or too many MUMPS processes */ + boolean_t fastinteg_in_prog; /* Tells GT.M if fast integrity is in progress */ + uint4 wtstart_errcnt; + /* Note that although the below two fields are dbg-only, they are defined for pro since we want to keep the shared + * memory layout the same for both pro and dbg. There is some code that relies on this assumption. + */ + 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 */ # endif } node_local; @@ -457,7 +475,7 @@ typedef struct node_local_struct cnl->crit_ops_array[coidx].epid = process_id; \ cnl->crit_ops_array[coidx].crit_act = (X); \ cnl->crit_ops_array[coidx].curr_tn = (NULL != csa->hdr) ? \ - csa->ti->curr_tn : 0; \ + csa->hdr->trans_hist.curr_tn : 0; \ } /* The following macro checks that curr_tn and early_tn are equal right before beginning a transaction commit. @@ -574,12 +592,28 @@ typedef struct node_local_struct #define BT_NOT_ALIGNED(bt, bt_base) (!IS_PTR_ALIGNED((bt), (bt_base), SIZEOF(bt_rec))) #define BT_NOT_IN_RANGE(bt, bt_lo, bt_hi) (!IS_PTR_IN_RANGE((bt), (bt_lo), (bt_hi))) -#define NUM_CRIT_ENTRY 1024 -#define CRIT_SPACE (NUM_CRIT_ENTRY * SIZEOF(mutex_que_entry) + SIZEOF(mutex_struct)) -#define NODE_LOCAL_SIZE (ROUND_UP(SIZEOF(node_local), OS_PAGE_SIZE)) -#define NODE_LOCAL_SPACE (ROUND_UP(CRIT_SPACE + NODE_LOCAL_SIZE, OS_PAGE_SIZE)) +#define MIN_CRIT_ENTRY 1024 +#define MAX_CRIT_ENTRY 32768 +#define DEFAULT_NUM_CRIT_ENTRY 1024 +#define NUM_CRIT_ENTRY(CSD) (CSD)->mutex_spin_parms.mutex_que_entry_space_size +#define CRIT_SPACE(ENTRIES) ((ENTRIES) * SIZEOF(mutex_que_entry) + SIZEOF(mutex_struct)) +#define JNLPOOL_CRIT_SPACE CRIT_SPACE(DEFAULT_NUM_CRIT_ENTRY) +#define NODE_LOCAL_SIZE (ROUND_UP(SIZEOF(node_local), OS_PAGE_SIZE)) +#define NODE_LOCAL_SPACE(CSD) (ROUND_UP(CRIT_SPACE(NUM_CRIT_ENTRY(CSD)) + NODE_LOCAL_SIZE, OS_PAGE_SIZE)) +#define MIN_NODE_LOCAL_SPACE (ROUND_UP(CRIT_SPACE(MIN_CRIT_ENTRY) + NODE_LOCAL_SIZE, OS_PAGE_SIZE)) /* In order for gtmsecshr not to pull in OTS library, NODE_LOCAL_SIZE_DBS is used in secshr_db_clnup instead of NODE_LOCAL_SIZE */ -#define NODE_LOCAL_SIZE_DBS (ROUND_UP(SIZEOF(node_local), DISK_BLOCK_SIZE)) +#define NODE_LOCAL_SIZE_DBS (ROUND_UP(SIZEOF(node_local), DISK_BLOCK_SIZE)) + +#define INIT_NUM_CRIT_ENTRY_IF_NEEDED(CSD) \ +{ /* The layout of shared memory depends on the number of mutex queue entries specified in the file header. Thus in \ + * order to set, for example, csa->critical or csa->shmpool_buffer, we need to know this number. However, this \ + * number can be zero if we have not yet done db_auto_upgrade. So go ahead and upgrade to the value that will \ + * eventually be used, which is DEFAULT_NUM_CRIT_ENTRY. \ + */ \ + /* Be safe in PRO and check if we need to initialize crit entries, even for GDSMV60002 and later. */ \ + if (0 == NUM_CRIT_ENTRY(CSD)) \ + NUM_CRIT_ENTRY(CSD) = DEFAULT_NUM_CRIT_ENTRY; \ +} /* Define pointer types for above structures that may be in shared memory and need 64 bit pointers. */ @@ -600,6 +634,12 @@ typedef mutex_spin_parms_struct *mutex_spin_parms_ptr_t; typedef mutex_que_entry *mutex_que_entry_ptr_t; typedef node_local *node_local_ptr_t; +#define OLDEST_HIST_TN(CSA) (DBG_ASSERT(CSA->hdr) DBG_ASSERT(CSA->hdr->acc_meth != dba_mm) \ + ((th_rec_ptr_t)((sm_uc_ptr_t)CSA->th_base + CSA->th_base->tnque.fl))->tn) + +#define SET_OLDEST_HIST_TN(CSA, TN) (DBG_ASSERT(CSA->hdr) DBG_ASSERT(CSA->hdr->acc_meth != dba_mm) \ + ((th_rec_ptr_t)((sm_uc_ptr_t)CSA->th_base + CSA->th_base->tnque.fl))->tn = TN) + #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) diff --git a/sr_port/gdscc.h b/sr_port/gdscc.h index 5a83005..1878ad2 100644 --- a/sr_port/gdscc.h +++ b/sr_port/gdscc.h @@ -65,6 +65,29 @@ #define GDS_WRITE_PLAIN 0 #define GDS_WRITE_KILLTN 1 #define GDS_WRITE_BLOCK_SPLIT 2 +/* blk_prior_state's last bit indicates whether the block was free before update + * BLOCK FREE: 0b*******1, BLOCK NOT FREE: 0b*******0 + */ +#define BIT_SET_FREE(X) ((X) |= 0x00000001) +#define BIT_CLEAR_FREE(X) ((X) &= 0xfffffffe) +#define WAS_FREE(X) ((X) & 0x00000001) +/* blk_prior_state's last but one bit indicates whether the block was recycled before update + * BLOCK RECYCLED: 0b******1*, BLOCK NOT RECYCLED: 0b******0* + */ +#define BIT_SET_RECYCLED_AND_CLEAR_FREE(X) ((X) = ((X) & 0xfffffffc) + 0x00000002) +#define BIT_CLEAR_RECYCLED_AND_SET_FREE(X) ((X) = ((X) & 0xfffffffc) + 0x00000001) +#define BIT_CLEAR_RECYCLED(X) ((X) &= 0xfffffffd) +#define BIT_SET_RECYCLED(X) ((X) |= 0x00000002) +#define WAS_RECYCLED(X) (((X) & 0x00000002)) +/* blk_prior_state's last but two bit indicates whether the block was in directory tree or global variable tree + * IN_GV_TREE: 0b*****1**, IN_DIR_TREE: 0b*****0** + */ +#define IN_GV_TREE 4 +#define IN_DIR_TREE 0 +#define BIT_SET_DIR_TREE(X) ((X) &= 0xfffffffb) +#define BIT_SET_GV_TREE(X) ((X) |= 0x00000004) +#define KEEP_TREE_STATUS 0x00000004 + /* macro to traverse to the end of an horizontal cw_set_element list */ @@ -189,7 +212,8 @@ typedef struct cw_set_element_struct block_offset undo_next_off[2]; block_offset undo_offset[2]; uint4 blk_checksum; - uint4 was_free; + /*blk_prior_state:the block was in global variable tree/directory tree and was free/busy before update*/ + uint4 blk_prior_state; } cw_set_element; #endif diff --git a/sr_port/gdsdbver.h b/sr_port/gdsdbver.h index 6eacbcf..fbaa364 100644 --- a/sr_port/gdsdbver.h +++ b/sr_port/gdsdbver.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,7 +36,8 @@ enum db_ver { GDSNOVER = -1, GDSV4 = 0, - GDSV5, + GDSV5 = 1, + GDSV6 = 1, /*GDSV5 and GDSV6 have same value because block format is same for these two version*/ GDSVLAST }; #define GDSVCURR ((enum db_ver)(GDSVLAST - 1)) @@ -65,6 +66,9 @@ enum mdb_ver * New fields(before_trunc_total_blks, after_trunc_total_blks, before_trunc_free_blocks * before_trunc_file_size) for fixing interrupted MUPIP REORG -TRUNCATE. */ + 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 */ GDSMVLAST }; #define GDSMVCURR ((enum mdb_ver)(GDSMVLAST - 1)) diff --git a/sr_port/gdsfhead.h b/sr_port/gdsfhead.h index 88592a1..eba3477 100644 --- a/sr_port/gdsfhead.h +++ b/sr_port/gdsfhead.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,6 +40,7 @@ error_def(ERR_DBENDIAN); error_def(ERR_DBFLCORRP); error_def(ERR_GVIS); error_def(ERR_GVSUBOFLOW); +error_def(ERR_MMFILETOOLARGE); error_def(ERR_REPLINSTMISMTCH); error_def(ERR_REPLREQROLLBACK); error_def(ERR_SCNDDBNOUPD); @@ -51,64 +52,7 @@ error_def(ERR_STACKOFLOW); error_def(ERR_TNTOOLARGE); error_def(ERR_TNWARN); -/* all this record's fields should exactly be the first members of the cache_rec in the same order */ -typedef struct mmblk_rec_struct -{ - struct - { - sm_off_t fl; - sm_off_t bl; - } - blkque, /* cache records whose block numbers hash to the same location */ - state_que; /* cache records in same state (either wip or active) */ - union - { - short semaphore; - volatile int4 latch; /* int required for atomic swap on Unix */ - /* volatile required as this value is referenced outside of the lock in db_csh_getn() */ - } interlock; - block_id blk; - uint4 refer; - enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk - (prior to any dynamic conversion that may have occurred when read in). - */ - trans_num dirty; -} mmblk_rec; - -/* all the fields of this record should exactly be the first members of the cache_state_rec in the same order */ -typedef struct mmblk_state_rec_struct -{ - struct - { - sm_off_t fl; - sm_off_t bl; - } - state_que; /* WARNING -- from this point onwards this should be identical to a mmblk_rec */ - union - { - short semaphore; - volatile int4 latch; /* int required for atomic swap on Unix */ - /* volatile required as this value is referenced outside of the lock in db_csh_getn() */ - } interlock; - block_id blk; - uint4 refer; - enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk - (prior to any dynamic conversion that may have occurred when read in). - */ - trans_num dirty; -} mmblk_state_rec; - -typedef struct -{ - mmblk_que_head mmblkq_wip, /* write-in-progress queue -- unused in Unix */ - mmblkq_active; /* active queue */ - mmblk_rec mmblk_array[1]; /* the first mmblk record */ -} mmblk_que_heads; - - - /* need to keep quadword aligned */ - -/* Cache record -- NOTE: the head portion of this should exactly match with mmblk_rec */ +/* Cache record */ typedef struct cache_rec_struct { struct @@ -179,7 +123,7 @@ typedef struct cache_rec_struct on some platforms where processes are already running near the edge. */ -/* cache_state record -- NOTE: the first few fields of this should be identical to that of mmblk_state_rec */ +/* cache_state record */ typedef struct { struct @@ -244,6 +188,7 @@ typedef struct #define MBR_BLKEMPTY -1 #define FROZEN_BY_ROOT (uint4)(0xFFFFFFFF) #define BACKUP_NOT_IN_PROGRESS 0x7FFFFFFF +#define DB_CSH_RDPOOL_SZ 0x20 /* These many non-dirty buffers exist at all points in time in shared memory */ typedef struct { @@ -269,12 +214,6 @@ 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; -typedef mmblk_que_head *mmblk_que_head_ptr_t; -typedef mmblk_rec *mmblk_rec_ptr_t; -typedef mmblk_rec **mmblk_rec_ptr_ptr_t; -typedef mmblk_state_rec *mmblk_state_rec_ptr_t; -typedef mmblk_que_heads *mmblk_que_heads_ptr_t; - void verify_queue_lock(que_head_ptr_t qhdr); void verify_queue(que_head_ptr_t qhdr); @@ -292,6 +231,34 @@ void verify_queue(que_head_ptr_t qhdr); #define VERIFY_QUEUE_LOCK(base,latch) #endif +#define BLK_ZERO_OFF(CSD) ((CSD->start_vbn - 1) * DISK_BLOCK_SIZE) +#ifdef UNIX +# ifdef GTM64 +# define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ) +# else +# define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ) \ +{ \ + assert(SIZEOF(gtm_uint64_t) == SIZEOF(MMAP_SZ)); \ + assert(0 < MMAP_SZ); \ + if (MAXUINT4 < (gtm_uint64_t)(MMAP_SZ)) \ + rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(6) ERR_MMFILETOOLARGE, 4, REG_LEN_STR(REG), \ + DB_LEN_STR(REG)); \ +} +# endif +# define MMAP_FD(FD, SIZE, OFFSET, READ_ONLY) mmap((caddr_t)NULL, SIZE, MM_PROT_FLAGS(READ_ONLY), GTM_MM_FLAGS, FD, OFFSET) +# define MSYNC(BEGPTR, ENDPTR) (BEGPTR ? DBG_ASSERT(BEGPTR < ENDPTR) msync(BEGPTR, (ENDPTR - BEGPTR), MS_SYNC) \ + : 0) +# define MM_PROT_FLAGS(READ_ONLY) (READ_ONLY ? PROT_READ : (PROT_READ | PROT_WRITE)) +# define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->db_addrs[0] +# define SET_MM_BASE_ADDR(CSA, CSD) +#else +# define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->acc_meth.mm.base_addr +# define SET_MM_BASE_ADDR(CSA, CSD) \ +{ \ + CSA->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_long_t)CSD + (off_t)(CSD->start_vbn - 1) * DISK_BLOCK_SIZE); \ +} +#endif + /* The following 3 macros were introduced while solving a problem with $view where a call to $view in */ /* mumps right after a change to $zgbldir gave the old global directory - not the new one. On VMS it */ /* caused a core dump. If one were to access a global variable via $data right after the change, however, */ @@ -375,6 +342,12 @@ void verify_queue(que_head_ptr_t qhdr); GBLREF gv_key *gv_currkey; \ \ keySIZE = KEYSIZE; \ + /* Have space to store at least MAX_MIDENT_LEN bytes as otherwise name-level $order \ + * (see op_gvorder/op_zprevious) could have buffer overflow issues in gv_currkey->base. \ + * Do ROUND_UP2(x,4) to keep an assert in GVKEY_INIT macro happy. \ + */ \ + if ((MAX_MIDENT_LEN + 3) > keySIZE) \ + keySIZE = ROUND_UP2(MAX_MIDENT_LEN + 3, 4); \ assert(keySIZE); \ if (keySIZE > gv_keysize) \ { \ @@ -386,6 +359,31 @@ void verify_queue(que_head_ptr_t qhdr); && (gv_keysize == gv_currkey->top) && (gv_keysize == gv_altkey->top)); \ } +#define WAS_OPEN_TRUE TRUE +#define WAS_OPEN_FALSE FALSE + +/* Below macro sets open, opening and was_open fields of a given region after the corresponding + * database for that region is opened. Also, if the region was not already open, the macro + * invokes GVKEYSIZE_INCREASE_IF_NEEDED to allocate gv_currkey/gv_altkey based on the region's + * max_key_size. + */ +#define SET_REGION_OPEN_TRUE(REG, WAS_OPEN) \ +{ \ + DEBUG_ONLY(GBLREF int4 gv_keysize;) \ + \ + assert(!REG->was_open); \ + assert(!REG->open); \ + REG->open = TRUE; \ + REG->opening = FALSE; \ + if (WAS_OPEN) \ + { \ + REG->was_open = TRUE; \ + assert(DBKEYSIZE(REG->max_key_size) <= gv_keysize); \ + } \ + else \ + GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(REG->max_key_size)); \ +} + #define SET_CSA_DIR_TREE(csa, keysize, reg) \ { \ if (NULL == csa->dir_tree) \ @@ -510,10 +508,7 @@ void verify_queue(que_head_ptr_t qhdr); assert(cse->blk == cache_start[bufindx].blk); \ assert(dse_running || write_after_image || (process_id == cache_start[bufindx].in_cw_set)); \ } else \ - { \ - assert(cse->old_block == csa->db_addrs[0] + cse->blk * csd->blk_size \ - + (csd->start_vbn - 1) * DISK_BLOCK_SIZE); \ - } \ + assert(cse->old_block == MM_BASE_ADDR(csa) + (off_t)cse->blk * csd->blk_size); \ } \ } @@ -656,6 +651,21 @@ void verify_queue(que_head_ptr_t qhdr); 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) \ +{ \ + sav_reg = gv_cur_region; \ + sav_cs_addrs = cs_addrs; \ + sav_cs_data = cs_data; \ + TP_CHANGE_REG(reg) \ +} + +#define POP_GV_CUR_REGION(sav_reg, sav_cs_addrs, sav_cs_data) \ +{ \ + gv_cur_region = sav_reg; \ + cs_addrs = sav_cs_addrs; \ + cs_data = sav_cs_data; \ +} + /* The TP_TEND_CHANGE_REG macro is a special macro used in tp_tend.c to optimize out the unnecessary checks in * the TP_CHANGE_REG_IF_NEEDED macro. Also it sets cs_addrs and cs_data to precomputed values instead of recomputing * them from the region by dereferencing through a multitude of pointers. It does not check if gv_cur_region is @@ -870,23 +880,42 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com # endif #endif -#define JNLPOOL_INIT_IF_NEEDED(CSA, CSD, CNL) \ +/* Every process that initializes journal pool has two aspects of validation. + * 1. Validate whether this process can do logical updates to the journal pool that is initialized. If not, the process should + * issue SCNDDBNOUPD error. Examples of this would be a GT.M update that happens on a non-supplementary Receiver Side. + * + * 2. Validate whether the process is attached to the correct journal pool. If not, REPLINSTMISMTCH should be issued. This check + * ensures that we only do updates to region that is tied to the journal pool that we initialized. + * + * The below macro definitions indicate which of the above 2 checks is done by the process for a particular region until now. + * The macro VALIDATE_INITIALIZED_JNLPOOL does the actual validation. + */ +#define JNLPOOL_NOT_VALIDATED 0x00 +#define REPLINSTMISMTCH_CHECK_DONE 0x01 +#define SCNDDBNOUPD_CHECK_DONE 0x02 +#define JNLPOOL_VALIDATED 0x03 + +#define SCNDDBNOUPD_CHECK_FALSE 0x00 +#define SCNDDBNOUPD_CHECK_TRUE 0x01 + +#define VALIDATE_INITIALIZED_JNLPOOL(CSA, CNL, REG, JNLPOOL_USER, SCNDDBNOUPD_CHECK_NEEDED) \ { \ - unsigned char instfilename_copy[MAX_FN_LEN + 1]; \ - sm_uc_ptr_t jnlpool_instfilename; \ - int4 jnlpool_shmid; \ - \ GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ - GBLREF boolean_t is_replicator; \ - GBLREF boolean_t pool_init; \ GBLREF boolean_t is_updproc; \ \ - if (REPL_ALLOWED(CSD) && is_replicator) \ + unsigned char instfilename_copy[MAX_FN_LEN + 1]; \ + sm_uc_ptr_t jnlpool_instfilename; \ + int4 jnlpool_shmid; \ + uint4 jnlpool_validate_check; \ + boolean_t do_REPLINSTMISMTCH_check; \ + \ + jnlpool_validate_check = CSA->jnlpool_validate_check; \ + assert(JNLPOOL_VALIDATED >= jnlpool_validate_check); \ + if (JNLPOOL_VALIDATED != jnlpool_validate_check) \ { \ - if (FALSE == pool_init) \ - jnlpool_init((jnlpool_user)GTMPROC, (boolean_t)FALSE, (boolean_t *)NULL); \ - assert(pool_init); \ - if (!CSA->replinst_matches_db) \ + do_REPLINSTMISMTCH_check = (!(REPLINSTMISMTCH_CHECK_DONE & jnlpool_validate_check) \ + UNIX_ONLY(&& ((GTMRELAXED != JNLPOOL_USER) || !IS_GTM_IMAGE))); \ + if (!(SCNDDBNOUPD_CHECK_DONE & jnlpool_validate_check) && SCNDDBNOUPD_CHECK_NEEDED) \ { \ if (jnlpool_ctl->upd_disabled && !is_updproc) \ { /* Updates are disabled in this journal pool. Detach from journal pool and issue error. */ \ @@ -894,8 +923,12 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com jnlpool_detach(); \ assert(NULL == jnlpool.jnlpool_ctl); \ assert(FALSE == pool_init); \ - rts_error(VARLSTCNT(1) ERR_SCNDDBNOUPD); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SCNDDBNOUPD); \ } \ + CSA->jnlpool_validate_check |= SCNDDBNOUPD_CHECK_DONE; \ + } \ + if (do_REPLINSTMISMTCH_check) \ + { \ UNIX_ONLY(jnlpool_instfilename = (sm_uc_ptr_t)jnlpool_ctl->jnlpool_id.instfilename;) \ VMS_ONLY(jnlpool_instfilename = (sm_uc_ptr_t)jnlpool_ctl->jnlpool_id.gtmgbldir;) \ if (STRCMP(CNL->replinstfilename, jnlpool_instfilename) \ @@ -923,14 +956,51 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com jnlpool_detach(); \ assert(NULL == jnlpool.jnlpool_ctl); \ assert(FALSE == pool_init); \ - rts_error(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, LEN_AND_STR(instfilename_copy), jnlpool_shmid, \ - DB_LEN_STR(gv_cur_region), LEN_AND_STR(CNL->replinstfilename), CNL->jnlpool_shmid); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, \ + LEN_AND_STR(instfilename_copy), jnlpool_shmid, DB_LEN_STR(REG), \ + LEN_AND_STR(CNL->replinstfilename), CNL->jnlpool_shmid); \ } \ - CSA->replinst_matches_db = TRUE; \ + CSA->jnlpool_validate_check |= REPLINSTMISMTCH_CHECK_DONE; \ } \ } \ } +#define JNLPOOL_INIT_IF_NEEDED(CSA, CSD, CNL) \ +{ \ + GBLREF boolean_t is_replicator; \ + GBLREF boolean_t pool_init; \ + GBLREF gd_region *gv_cur_region; \ + \ + if (REPL_ALLOWED(CSD) && is_replicator) \ + { \ + if (!pool_init) \ + jnlpool_init((jnlpool_user)GTMPROC, (boolean_t)FALSE, (boolean_t *)NULL); \ + assert(pool_init); \ + VALIDATE_INITIALIZED_JNLPOOL(CSA, CNL, gv_cur_region, GTMPROC, SCNDDBNOUPD_CHECK_TRUE); \ + } \ +} + +#define ASSERT_VALID_JNLPOOL(CSA) \ +{ \ + GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ + GBLREF jnlpool_addrs jnlpool; \ + \ + assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \ + assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \ + assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \ + assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + JNLPOOL_CRIT_SPACE \ + + SIZEOF(mutex_spin_parms_struct))); \ + assert(jnlpool_ctl->filehdr_off); \ + assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \ + assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \ + assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \ + + jnlpool_ctl->filehdr_off)); \ + assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ + + jnlpool_ctl->srclcl_array_off)); \ + assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ + + jnlpool_ctl->sourcelocal_array_off)); \ +} + /* Explanation for why we need the following macro. * * Normally a cdb_sc_blkmod check is done using the "bt". This is done in t_end and tp_tend. @@ -981,19 +1051,22 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com #ifdef VMS #define MASTER_MAP_BLOCKS_DFLT 64 /* 64 gives 128M possible blocks */ #else -#define MASTER_MAP_BLOCKS_DFLT 112 /* 112 gives 224M possible blocks */ +#define MASTER_MAP_BLOCKS_DFLT 496 /* 496 gives 992M possible blocks */ +#define MASTER_MAP_BLOCKS_V5 112 /* 112 gives 224M possible blocks */ #endif #define MASTER_MAP_BLOCKS_V4 32 /* 32 gives 64M possible blocks */ -#define MASTER_MAP_BLOCKS_MAX 112 /* 112 gives 224M possible blocks */ +#define MASTER_MAP_BLOCKS_MAX MASTER_MAP_BLOCKS_DFLT /* 496 gives 992M possible blocks */ #define MASTER_MAP_BLOCKS_V5_OLD 64 /* V5 database previous master map block size */ #define MASTER_MAP_SIZE_V5_OLD (MASTER_MAP_BLOCKS_V5_OLD * DISK_BLOCK_SIZE) #define MASTER_MAP_SIZE_V4 (MASTER_MAP_BLOCKS_V4 * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE_MAX (MASTER_MAP_BLOCKS_MAX * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE_DFLT (MASTER_MAP_BLOCKS_DFLT * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ +#define MASTER_MAP_SIZE_V5 (MASTER_MAP_BLOCKS_V5 * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE(SGD) (((sgmnt_data_ptr_t)SGD)->master_map_len) #define SGMNT_HDR_LEN SIZEOF(sgmnt_data) #define SIZEOF_FILE_HDR(SGD) (SGMNT_HDR_LEN + MASTER_MAP_SIZE(SGD)) #define SIZEOF_FILE_HDR_DFLT (SGMNT_HDR_LEN + MASTER_MAP_SIZE_DFLT) +#define SIZEOF_FILE_HDR_V5 (SGMNT_HDR_LEN + MASTER_MAP_SIZE_V5) #define SIZEOF_FILE_HDR_MIN (SGMNT_HDR_LEN + MASTER_MAP_SIZE_V4) #define SIZEOF_FILE_HDR_MAX (SGMNT_HDR_LEN + MASTER_MAP_SIZE_MAX) #define MM_BLOCK (SGMNT_HDR_LEN / DISK_BLOCK_SIZE + 1) /* gt.m numbers blocks from 1 */ @@ -1005,15 +1078,20 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com #define BLKS_PER_LMAP 512 #define MAXTOTALBLKS_V4 (MASTER_MAP_SIZE_V4 * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS_V5 (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) +#define MAXTOTALBLKS_V6 (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS_MAX (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS(SGD) (MASTER_MAP_SIZE(SGD) * 8 * BLKS_PER_LMAP) #define IS_BITMAP_BLK(blk) (ROUND_DOWN2(blk, BLKS_PER_LMAP) == blk) /* TRUE if blk is a bitmap */ -/* - * UNIX - 8K fileheader (= 16 blocks) + 56K mastermap (= 112 blocks) + 1 - * VMS - 8K fileheader (= 16 blocks) + 32K mastermap (= 64 blocks) + 24K padding (= 48 blocks) + 1 */ +/* UNIX - + * V6 - 8K fileheader (= 16 blocks) + 248K mastermap (= 496 blocks) + 1 + * V5 - 8K fileheader (= 16 blocks) + 56K mastermap (= 112 blocks) + 1 + * V4 - 8K fileheader (= 16 blocks) + 16K mastermap (= 32 blocks) + 1 + * VMS - 8K fileheader (= 16 blocks) + 32K mastermap (= 64 blocks) + 24K padding (= 48 blocks) + 1 + */ +#define START_VBN_V6 513 #define START_VBN_V5 129 -#define START_VBN_V4 49 /* 8K fileheader (= 16 blocks) + 16K mastermap (= 32 blocks) + 1 */ -#define START_VBN_CURRENT START_VBN_V5 +#define START_VBN_V4 49 +#define START_VBN_CURRENT START_VBN_V6 #define STEP_FACTOR 64 /* the factor by which flush_trigger is incremented/decremented */ #define MIN_FLUSH_TRIGGER(n_bts) ((n_bts)/4) /* the minimum flush_trigger as a function of n_bts */ @@ -1066,9 +1144,9 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com #define WRITERS_ACTIVE(cnl) ((0 < cnl->intent_wtstart) || (0 < cnl->in_wtstart)) -#define SIGNAL_WRITERS_TO_STOP(csd) \ +#define SIGNAL_WRITERS_TO_STOP(cnl) \ { \ - SET_TRACEABLE_VAR((csd)->wc_blocked, TRUE); /* to stop all active writers */ \ + SET_TRACEABLE_VAR((cnl)->wc_blocked, TRUE); /* to stop all active writers */ \ /* memory barrier needed to broadcast this information to other processors */ \ SHM_WRITE_MEMORY_BARRIER; \ } @@ -1085,9 +1163,9 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com } \ } -#define SIGNAL_WRITERS_TO_RESUME(csd) \ +#define SIGNAL_WRITERS_TO_RESUME(cnl) \ { \ - SET_TRACEABLE_VAR((csd)->wc_blocked, FALSE); /* to let active writers resume */ \ + SET_TRACEABLE_VAR((cnl)->wc_blocked, FALSE); /* to let active writers resume */ \ /* memory barrier needed to broadcast this information to other processors */ \ SHM_WRITE_MEMORY_BARRIER; \ } @@ -1142,10 +1220,11 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com jpc = csa->jnl; \ assert(NULL != jpc); \ if (SS_NORMAL != jpc->status) \ - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), \ - jpc->status); \ + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), \ + DB_LEN_STR(gv_cur_region), jpc->status); \ else \ - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); \ + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), \ + DB_LEN_STR(gv_cur_region)); \ } \ } \ } @@ -1258,11 +1337,14 @@ enum tp_blkmod_type /* used for accounting in cs_data->tp_cdb_sc_blkmod[] */ * the restart will anyway be detected before commit. In this cases, this variable will take on non-zero values. * The commit logic will assert that this variable is indeed zero after validation but before proceeding with commit. */ -#define DONOTCOMMIT_TPHIST_BLKTARGET_MISMATCH (1 << 0) /* Restartable situation encountered in tp_hist */ -#define DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL (1 << 1) /* Restartable situation encountered in gvcst_delete_blk */ -#define DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR (1 << 2) /* Restartable situation encountered in jnl_get_checksum.h */ -#define DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS (1 << 3) /* Restartable situation encountered in gvcst_kill */ -#define DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN (1 << 4) /* Restartable situation encountered in gvcst_blk_build */ +#define DONOTCOMMIT_TPHIST_BLKTARGET_MISMATCH (1 << 0) /* Restartable situation encountered in tp_hist */ +#define DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL (1 << 1) /* Restartable situation encountered in gvcst_delete_blk */ +#define DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR (1 << 2) /* Restartable situation encountered in jnl_get_checksum.h */ +#define DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS (1 << 3) /* Restartable situation encountered in gvcst_kill */ +#define DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN (1 << 4) /* Restartable situation encountered in gvcst_blk_build */ +#define DONOTCOMMIT_T_QREAD_BAD_PVT_BUILD (1 << 5) /* Restartable situation due to bad private build in t_qread */ +#define DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC (1 << 6) /* Restartable situation encountered in gvcst_search */ +#define DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH (1 << 7) /* Restartable situation encountered in gvcst_search */ #define TAB_BG_TRC_REC(A,B) B, enum bg_trc_rec_type @@ -1273,24 +1355,6 @@ n_bg_trc_rec_types #undef TAB_BG_TRC_REC #define UPGRD_WARN_INTERVAL (60 * 60 * 24) /* Once every 24 hrs */ -typedef struct compswap_time_field_struct -{ /* This structure is used where we want to do a compare-n-swap (CAS) on a time value. The CAS interfaces - need an instance of global_latch_t to operate on. We will utilize the "latch_pid" field to hold the - time and the latch_word is unused except on VMS where it will hold 0. Since this structure must be of - a constant size (size of global_latch_t varies), pad the latch with sufficient space to match the - size of global_latch_t's largest size (on HPUX). - */ - global_latch_t time_latch; -#ifndef __hppa - int4 hp_latch_space[4]; /* padding only on non-hpux systems */ -#endif -} compswap_time_field; -/* takes value of time() but needs to be 4 byte so can use compswap on it. Not - using time_t as that is an indeterminate size on various platforms. - Value is time (in seconds) in a compare/swap updated field so only one - process performs a given task in a given interval -*/ -#define cas_time time_latch.u.parts.latch_pid /* The following structure is used to determine the endianess of a database header. @@ -1316,7 +1380,8 @@ typedef union endian32_struct check_endian; \ check_endian.word32 = (CSD)->minor_dbver; \ if (!check_endian.shorts.ENDIANCHECKTHIS) \ - rts_error(VARLSTCNT(6) ERR_DBENDIAN, 4, FNLEN, FNNAME, ENDIANOTHER, ENDIANTHIS); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBENDIAN, 4, FNLEN, FNNAME, ENDIANOTHER, \ + ENDIANTHIS); \ } /* This is the structure describing a segment. It is used as a database file header (for MM or BG access methods). @@ -1443,12 +1508,11 @@ typedef struct sgmnt_data_struct * >0 => defer_time * flush_time[0] is actual defer time * default value = 1 => a write-timer every csd->flush_time[0] seconds */ - volatile boolean_t wc_blocked; /* Set to TRUE by process that knows it is leaving the cache in a possibly - * inconsistent state. Next process grabbing crit will do cache recovery. - * This setting also stops all concurrent writers from working on the cache. - * In MM mode, it is used to call wcs_recover during a file extension + volatile boolean_t filler_wc_blocked; /* Now moved to node_local */ + boolean_t mumps_can_bypass; /* Allow mumps processes to bypass flushing, access control, and ftok semaphore + * in gds_rundown(). This was done to improve shutdown performance. */ - char filler_512[20]; + char filler_512[16]; /************* FIELDS Used for update process performance improvement. Some may go away in later releases ********/ uint4 reserved_for_upd; /* Percentage (%) of blocks reserved for update process disk read */ uint4 avg_blks_per_100gbl; /* Number of blocks read on average for 100 global key read */ @@ -1542,11 +1606,13 @@ typedef struct sgmnt_data_struct uint4 before_trunc_total_blks; /* Used in recover_truncate to detect interrupted truncate */ uint4 after_trunc_total_blks; /* All these fields are used to repair interrupted truncates */ uint4 before_trunc_free_blocks; - uint4 before_trunc_file_size; /* File size before truncate in terms of disk blocks */ + uint4 filler_trunc; /* Previously before_trunc_file_size, which is no longer used */ char filler_1k[24]; /************* HUGE CHARACTER ARRAYS **************/ unsigned char jnl_file_name[JNL_NAME_SIZE]; /* journal file name */ - unsigned char reorg_restart_key[256]; /* 1st key of a leaf block where reorg was done last time */ + unsigned char reorg_restart_key[OLD_MAX_KEY_SZ + 1]; /* 1st key of a leaf block where reorg was done last time. + * Note: In mu_reorg we don't save keys longer than OLD_MAX_KEY_SZ + */ 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 @@ -1599,7 +1665,10 @@ 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. */ - char filler_7k[736]; + 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]; char filler_8k[1024]; /********************************************************/ /* Master bitmap immediately follows. Tells whether the local bitmaps have any free blocks or not. */ @@ -1629,8 +1698,11 @@ typedef struct typedef struct { +# ifdef VMS FILL8DCL(sm_uc_ptr_t, base_addr, 1); - FILL8DCL(mmblk_que_heads_ptr_t, mmblk_state, 2); /* pointer to beginnings of state and blk queues */ +# else + int filler; +# endif } sgmm_addrs; #define MAX_NM_LEN MAX_MIDENT_LEN @@ -1642,6 +1714,7 @@ typedef struct #define STR_SUB_PREFIX 0x0FF #define SUBSCRIPT_STDCOL_NULL 0x01 #define STR_SUB_ESCAPE 0X01 +#define SPANGLOB_SUB_ESCAPE 0X02 #define STR_SUB_MAXVAL 0xFF #define SUBSCRIPT_ZERO 0x080 #define SUBSCRIPT_BIAS 0x0BE @@ -1666,9 +1739,11 @@ typedef struct if (MEMCMP_LIT(TSD->label, GDS_LABEL)) \ { \ if (memcmp(TSD->label, GDS_LABEL, GDS_LABEL_SZ - 3)) \ - rts_error(VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(REG)); \ + rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_DBNOTGDS, 2, \ + DB_LEN_STR(REG)); \ else \ - rts_error(VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(REG)); \ + rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_BADDBVER, 2, \ + DB_LEN_STR(REG)); \ } \ } @@ -1688,12 +1763,17 @@ typedef struct if (IS_DSE_IMAGE) \ { \ gtm_errcode = MAKE_MSG_WARNING(gtm_errcode); \ - gtm_putmsg(VARLSTCNT(4) gtm_errcode, 2, DB_LEN_STR(REG)); \ + gtm_putmsg_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \ + DB_LEN_STR(REG)); \ } else \ - rts_error(VARLSTCNT(4) gtm_errcode, 2, DB_LEN_STR(REG)); \ + rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \ + DB_LEN_STR(REG)); \ } \ } +#define REG2CSA(REG) (((REG) && (REG)->dyn.addr && (REG)->dyn.addr->file_cntl) ? (&FILE_INFO(REG)->s_addrs) : NULL) +#define JCTL2CSA(JCTL) (((JCTL) && (JCTL->reg_ctl)) ? (JCTL->reg_ctl->csa) : NULL) + typedef struct file_control_struct { sm_uc_ptr_t op_buff; @@ -1795,7 +1875,7 @@ typedef struct gd_region_struct #else unsigned short jnl_deq; #endif - short jnl_buffer_size; + unsigned short jnl_buffer_size; bool jnl_before_image; bool opening; bool read_only; @@ -1803,7 +1883,14 @@ typedef struct gd_region_struct unsigned char cmx_regnum; unsigned char def_coll; bool std_null_coll; /* 0 -> GT.M null collation,i,e, null subs collate between numeric and string - * 1-> standard null collation i.e. null subs collate before numeric and string */ + * 1-> standard null collation i.e. null subs collate before numeric and string + */ +#ifdef UNIX + bool freeze_on_fail; + bool mumps_can_bypass; /* Allow mumps processes to bypass flushing, access control, and ftok semaphore + * in gds_rundown(). This was done to improve shutdown performance. + */ +#endif unsigned char jnl_file_len; unsigned char jnl_file_name[JNL_NAME_SIZE]; @@ -1845,14 +1932,13 @@ typedef struct sgmnt_addrs_struct struct jnl_private_control_struct *jnl; struct sgm_info_struct *sgm_info_ptr; gd_region *region; /* the region corresponding to this csa */ - struct hash_table_mname_struct *gvt_hashtab; /* NON-NULL only if regcnt > 1; - * Maintains all gv_targets mapped to this db file */ + struct hash_table_mname_struct *gvt_hashtab; /* NON-NULL only if regcnt > 1; + * Maintains all gv_targets mapped to this db file */ struct reg_ctl_list_struct *rctl; /* pointer to rctl for this region (used only if jgbl.forw_phase_recovery) */ struct sgmnt_addrs_struct *next_csa; /* points to csa of NEXT database that has been opened by this process */ # ifdef GTM_CRYPT - char *encrypted_blk_contents; - gtmcrypt_key_t encr_key_handle; - int4 encrypt_init_status; + char *encrypted_blk_contents; + gtmcrypt_key_t encr_key_handle; # endif # ifdef GTM_SNAPSHOT struct snapshot_context_struct *ss_ctx; @@ -1864,16 +1950,19 @@ typedef struct sgmnt_addrs_struct /* May add new pointers here for other methods or change to void ptr */ } acc_meth; gvstats_rec_t gvstats_rec; - /* 8-byte aligned at this point on all platforms (32-bit, 64-bit or Tru64 which is a mix of 32-bit and 64-bit pointers) */ - sgmnt_data_ptr_t mm_core_hdr; /* Most OSs don't include memory mapped files in the core dump. For MM access - * mode, this is a pointer to a copy of the header that will be in the corefile. - * The pointer is only used for MM and that too only in Unix. + trans_num dbsync_timer_tn;/* copy of csa->ti->curr_tn when csa->dbsync_timer became TRUE. + * used to check if any updates happened in between when we flushed all + * dirty buffers to disk and when the idle flush timer (5 seconds) popped. */ + /* 8-byte aligned at this point on all platforms (32-bit, 64-bit or Tru64 which is a mix of 32-bit and 64-bit pointers) */ size_t fullblockwrite_len; /* Length of a full block write */ - uint4 total_blks; /* Last we knew, file was this big. Used to - * signal MM processing file was extended and - * needs to be remapped. Also now used to detect - * file truncates with BG. */ + uint4 total_blks; /* Last we knew, file was this big. Used to signal MM processing file was + * extended and needs to be remapped. In V55000 was used with BG to detect + * file truncates. It is no longer used for that purpose: it was not necessary + * in the first place because bitmap block validations in t_end/tp_tend prevent + * updates from trying to commit past the end of the file. + * See mu_truncate.c for more details. + */ uint4 prev_free_blks; /* The following uint4's are treated as bools but must be 4 bytes to avoid interaction between bools in interrupted routines and possibly lost data */ @@ -1888,7 +1977,6 @@ typedef struct sgmnt_addrs_struct block_id reorg_last_dest; /* last destinition block used for swap */ boolean_t jnl_before_image; boolean_t read_write; - boolean_t extending; boolean_t persistent_freeze; /* if true secshr_db_clnup() won't unfreeze this region */ /* The following 3 fields are in cs_addrs instead of in the file-header since they are a function * of the journal-record sizes that can change with journal-version-numbers (for the same database). @@ -1908,10 +1996,7 @@ typedef struct sgmnt_addrs_struct have a unique prefix per region (and all regions have same prefix) */ int4 n_pre_read_trigger; /* For update process to keep track of progress and when to trigger pre-read */ - boolean_t replinst_matches_db; /* TRUE if replication instance file name stored in db shared memory matches the - * instance file name stored in the journal pool that this process has attached to. - * Updates are allowed to this replicated database only if this is TRUE. - */ + uint4 jnlpool_validate_check; /* See the comment above VALIDATE_INITIALIZED_JNLPOOL for details on this field */ int4 regcnt; /* # of regions that have this as their csa */ boolean_t t_commit_crit; /* set to FALSE by default. set to TRUE if in the middle of database commit. * if access method is BG, this assumes a multi-state value. @@ -1937,11 +2022,12 @@ typedef struct sgmnt_addrs_struct boolean_t dse_crit_seize_done; /* TRUE if DSE does a CRIT -SEIZE for this region. Set to FALSE when CRIT -RELEASE * or CRIT -REMOVE is done. Other than the -SEIZE and -RELEASE window, if any other * DSE module sets csa->hold_onto_crit to TRUE (like dse_b_dmp) but encounters a - * runtime error before getting a chance to do a rel_crit, preemptive_ch should know - * to release crit even if hold_onto_crit is set to TRUE and so will rely on this - * variable + * runtime error before getting a chance to do a rel_crit, preemptive_db_clnup + * should know to release crit even if hold_onto_crit is set to TRUE and so will + * rely on this variable */ # 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 */ @@ -1975,7 +2061,18 @@ typedef struct srch_blk_status_struct int4 cycle; int4 level; struct cw_set_element_struct *cse; - struct srch_blk_status_struct *first_tp_srch_status; + struct srch_blk_status_struct *first_tp_srch_status; /* In TP, this points to an entry in the si->first_tp_hist array + * that contains the srch_blk_status structure of this block the + * first time it was referenced in this TP transaction. So basically + * gvt->hist contains pointers to the first_tp_hist array. At + * tp_clean_up time, the first_tp_hist array is cleared but all + * pointers to it are not cleaned up then. That instead happens + * when the gvt->clue gets used first in the next TP transaction, + * at which point we are guaranteed local_tn is much higher than + * gvt->read_local_tn which is an indication to complete this + * deferred cleanup. + * In non-TP, this field is maintained but not used. + */ struct gv_namehead_struct *blk_target; } srch_blk_status; @@ -1995,6 +2092,35 @@ typedef struct srch_blk_status h[MAX_BT_DEPTH + 1]; } srch_hist; +#define SUPER_HIST_SIZE 2 * MAX_BT_DEPTH + 2 /* can be increased in the future to accommodate more than 2 histories */ + +/* Currently used only by MUPIP REORG in order to pass 3 search histories to t_end. */ +typedef struct +{ + int4 depth; /* t_end's validations don't depend on this field */ + int4 filler; + srch_blk_status h[SUPER_HIST_SIZE]; +} super_srch_hist; + +#define MERGE_SUPER_HIST(SUPER_HIST, HIST1, HIST2) \ +{ /* Possible enhancement: do memcpy instead of loop */ \ + srch_hist *hist; \ + srch_blk_status *t0, *t1; \ + \ + (SUPER_HIST)->depth = 1 + (HIST1)->depth + (HIST2)->depth; \ + assert(SUPER_HIST_SIZE > (SUPER_HIST)->depth); \ + t0 = (SUPER_HIST)->h; \ + for (hist = (HIST1); (NULL != hist); hist = (hist == (HIST1)) ? (HIST2) : NULL) \ + { \ + for (t1 = hist->h; t1->blk_num; t1++) \ + { \ + *t0 = *t1; \ + t0++; \ + } \ + } \ + t0->blk_num = 0; \ +} + typedef struct gv_key_struct { unsigned short top; /* Offset to top of buffer allocated for the key */ @@ -2029,6 +2155,7 @@ typedef struct gv_namehead_struct for internationalization */ trans_num read_local_tn; /* local_tn of last reference for this global */ GTMTRIG_ONLY(trans_num trig_local_tn;) /* local_tn of last trigger driven for this global */ + GTMTRIG_ONLY(trans_num trig_read_tn;) /* local_tn when triggers for this global (^#t records) were read from db */ boolean_t noisolation; /* whether isolation is turned on or off for this global */ block_id root; /* Root of global variable tree */ mname_entry gvname; /* the name of the global */ @@ -2096,12 +2223,17 @@ typedef struct gvsavtarg_struct * This mechanism ensures that, when there are multiple functions in a given call stack that save and * restore gv_target, only the bottom most function gets to store its value in the global, reset_gv_target. * In case of rts errors, if the error is not SUCCESS or INFO, then gv_target gets restored to reset_gv_target - * (in preemptive_ch()). For SUCCESS or INFO, no restoration is necessary because CONTINUE from the condition + * (in preemptive_db_clnup()). For SUCCESS or INFO, no restoration is necessary because CONTINUE from the condition * handlers would take us through the normal path for gv_target restoration. */ -#define SKIP_GVT_GVKEY_CHECK FALSE -#define DO_GVT_GVKEY_CHECK TRUE +#define SKIP_GVT_GVKEY_CHECK 0 +#define DO_GVT_GVKEY_CHECK 1 +#define DO_GVT_GVKEY_CHECK_RESTART 2 /* do GVT_GVKEY check but skip gvt/csa check since we are in a TP transaction + * and about to restart, gv_target and cs_addrs will anyways get back in sync + * as part of the tp_restart process. This flag should be used only in TP + * as non-TP restart does not do this reset/sync. + */ #define RESET_GV_TARGET(GVT_GVKEY_CHECK) \ { \ @@ -2110,24 +2242,33 @@ typedef struct gvsavtarg_struct reset_gv_target = INVALID_GV_TARGET; \ DEBUG_ONLY( \ if (GVT_GVKEY_CHECK) \ - { \ - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; \ - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; \ - } \ + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); \ ) \ } #define RESET_GV_TARGET_LCL(SAVE_TARG) gv_target = SAVE_TARG; -#define RESET_GV_TARGET_LCL_AND_CLR_GBL(SAVE_TARG) \ -{ \ - gv_target = SAVE_TARG; \ - if (!gbl_target_was_set) \ - { \ - assert(SAVE_TARG == reset_gv_target || INVALID_GV_TARGET == reset_gv_target); \ - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; \ - reset_gv_target = INVALID_GV_TARGET; \ - } \ +#define RESET_GV_TARGET_LCL_AND_CLR_GBL(SAVE_TARG, GVT_GVKEY_CHECK) \ +{ \ + GBLREF uint4 dollar_tlevel; \ + \ + gv_target = SAVE_TARG; \ + if (!gbl_target_was_set) \ + { \ + assert(SAVE_TARG == reset_gv_target || INVALID_GV_TARGET == reset_gv_target); \ + DEBUG_ONLY( \ + if (DO_GVT_GVKEY_CHECK == (GVT_GVKEY_CHECK)) \ + { \ + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); \ + } else \ + { \ + assert((SKIP_GVT_GVKEY_CHECK == (GVT_GVKEY_CHECK)) \ + || (dollar_tlevel && (DO_GVT_GVKEY_CHECK_RESTART == (GVT_GVKEY_CHECK)))); \ + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_FALSE); \ + } \ + ) \ + reset_gv_target = INVALID_GV_TARGET; \ + } \ } @@ -2138,10 +2279,25 @@ GBLREF int process_exiting; GBLREF trans_num local_tn; GBLREF gv_namehead *gvt_tp_list; -#define ADD_TO_GVT_TP_LIST(GVT) \ +#define RESET_FIRST_TP_SRCH_STATUS_FALSE FALSE +#define RESET_FIRST_TP_SRCH_STATUS_TRUE TRUE + +#define GVT_CLEAR_FIRST_TP_SRCH_STATUS(GVT) \ +{ \ + srch_blk_status *srch_status; \ + \ + assert(GVT->clue.end); /* or else first_tp_srch_status will be reset as part of traversal */ \ + assert(GVT->read_local_tn != local_tn); \ + for (srch_status = &(GVT)->hist.h[0]; HIST_TERMINATOR != srch_status->blk_num; srch_status++) \ + srch_status->first_tp_srch_status = NULL; \ +} + +#define ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS) \ { \ if (GVT->read_local_tn != local_tn) \ { /* Set read_local_tn to local_tn; Also add GVT to list of gvtargets referenced in this TP transaction. */ \ + if (GVT->clue.end && RESET_FIRST_TP_SRCH_STATUS) \ + GVT_CLEAR_FIRST_TP_SRCH_STATUS(GVT); \ GVT->read_local_tn = local_tn; \ GVT->next_tp_gvnh = gvt_tp_list; \ gvt_tp_list = GVT; \ @@ -2151,6 +2307,10 @@ GBLREF gv_namehead *gvt_tp_list; } \ } +/* Although the below macros are used only in DBG code, they are passed as parameters so need to be defined for pro code too */ +#define CHECK_CSA_FALSE FALSE +#define CHECK_CSA_TRUE TRUE + #ifdef DEBUG #define DBG_CHECK_IN_GVT_TP_LIST(gvt, present) \ { \ @@ -2168,26 +2328,40 @@ GBLREF gv_namehead *gvt_tp_list; assert(present || (NULL == gvtarg) || (process_exiting && !dollar_tlevel)); \ } -#define DBG_CHECK_GVT_IN_GVTARGETLIST(gvt) \ -{ \ - gv_namehead *gvtarg; \ - \ - GBLREF gd_region *gv_cur_region; \ - GBLREF gv_namehead *gv_target_list; \ - \ - for (gvtarg = gv_target_list; NULL != gvtarg; gvtarg = gvtarg->next_gvnh) \ - { \ - if (gvtarg == gvt) \ - break; \ - } \ - /* For dba_cm or dba_usr type of regions, gv_target_list is not maintained so \ - * if gv_target is not part of gv_target_list, assert region is not BG or MM. \ - */ \ - assert((NULL != gvtarg) || (dba_cm == gv_cur_region->dyn.addr->acc_meth) \ - || (dba_usr == gv_cur_region->dyn.addr->acc_meth)); \ +#define DBG_CHECK_GVT_IN_GVTARGETLIST(gvt) \ +{ \ + gv_namehead *gvtarg; \ + \ + GBLREF gd_region *gv_cur_region; \ + GBLREF gv_namehead *gv_target_list; \ + \ + for (gvtarg = gv_target_list; NULL != gvtarg; gvtarg = gvtarg->next_gvnh) \ + { \ + if (gvtarg == gvt) \ + break; \ + } \ + /* For dba_cm or dba_usr type of regions, gv_target_list is not maintained so \ + * if gv_target is not part of gv_target_list, assert region is not BG or MM. \ + * The only exception is if the region was dba_cm but later closed due to an error on \ + * the server side (in which case access method gets reset back to BG. (e.g. gvcmz_error.c) \ + */ \ + assert((NULL != gvtarg) || (dba_cm == gv_cur_region->dyn.addr->acc_meth) \ + || (dba_usr == gv_cur_region->dyn.addr->acc_meth) \ + || ((FALSE == gv_cur_region->open) && (dba_bg == gv_cur_region->dyn.addr->acc_meth))); \ } -#define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC \ +/* If CHECK_CSADDRS input parameter is CHECK_CSA_TRUE, then check that GV_CURRKEY, GV_TARGET and CS_ADDRS are all in sync. + * If CHECK_CSADDRS input parameter is CHECK_CSA_FALSE, then only check GV_CURRKEY and GV_TARGET are in sync (skip CS_ADDRS check). + * The hope is that most callers of this macro use CHECK_CSA_TRUE (i.e. a stricter check). + * + * The DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) macro is used at various points in the database code to check that + * gv_currkey, gv_target and cs_addrs are in sync. This is because op_gvname relies on this in order to avoid a gv_bind_name + * function call (if incoming key matches gv_currkey from previous call, it uses gv_target and cs_addrs right + * 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. + */ +#define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) \ { \ mname_entry *gvent; \ mstr *varname; \ @@ -2203,24 +2377,29 @@ GBLREF gv_namehead *gvt_tp_list; assert((NULL != gv_currkey) || (NULL == gv_target)); \ /* make sure gv_currkey->top always reflects the maximum keysize across all dbs that we opened until now */ \ assert((NULL == gv_currkey) || (gv_currkey->top == gv_keysize)); \ - keybase = &gv_currkey->base[0]; \ - if (!process_exiting && (NULL != gv_currkey) && (0 != keybase[0]) && (INVALID_GV_TARGET == reset_gv_target)) \ + if (!process_exiting) \ { \ - assert(NULL != gv_target); \ - gvent = &gv_target->gvname; \ - varname = &gvent->var_name; \ - varlen = varname->len; \ - assert(varlen); \ - assert((0 != keybase[varlen]) || !memcmp(keybase, varname->addr, varlen)); \ - keyend = gv_currkey->end; \ - assert(!keyend || (KEY_DELIMITER == keybase[keyend])); \ - assert(!keyend || (KEY_DELIMITER == keybase[keyend - 1])); \ - /* Check that gv_target is part of the gv_target_list */ \ - DBG_CHECK_GVT_IN_GVTARGETLIST(gv_target); \ + keybase = &gv_currkey->base[0]; \ + if ((NULL != gv_currkey) && (0 != keybase[0]) && (INVALID_GV_TARGET == reset_gv_target)) \ + { \ + assert(NULL != gv_target); \ + gvent = &gv_target->gvname; \ + varname = &gvent->var_name; \ + varlen = varname->len; \ + assert(varlen); \ + assert((0 != keybase[varlen]) || !memcmp(keybase, varname->addr, varlen)); \ + keyend = gv_currkey->end; \ + assert(!keyend || (KEY_DELIMITER == keybase[keyend])); \ + assert(!keyend || (KEY_DELIMITER == keybase[keyend - 1])); \ + /* Check that gv_target is part of the gv_target_list */ \ + DBG_CHECK_GVT_IN_GVTARGETLIST(gv_target); \ + if (CHECK_CSADDRS) \ + DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; \ + } \ + /* Do gv_target sanity check too; Do not do this if it is NULL or if it is GT.CM GNP client (gd_csa is NULL) */ \ + if ((NULL != gv_target) && (NULL != gv_target->gd_csa)) \ + DBG_CHECK_GVTARGET_INTEGRITY(gv_target); \ } \ - /* Do gv_target sanity check as well; Do not do this if it is NULL or if it is GT.CM GNP client (gd_csa is NULL) */ \ - if ((NULL != gv_target) && (NULL != gv_target->gd_csa)) \ - DBG_CHECK_GVTARGET_INTEGRITY(gv_target); \ } /* Do checks on the integrity of various fields in gv_target. targ_alloc initializes these and they are supposed to @@ -2232,12 +2411,8 @@ GBLREF gv_namehead *gvt_tp_list; { \ int keysize, partial_size; \ GBLREF boolean_t dse_running; \ - GBLREF jnl_gbls_t jgbl; \ \ - /* Forward recovery does targ_alloc of MAX_KEY_SZ (independent of db max_key_size) for csa->dir_tree. \ - * Take that into account while computing keysize. \ - */ \ - keysize = (!jgbl.forw_phase_recovery || (GVT->gd_csa->dir_tree != GVT)) ? GVT->gd_csa->hdr->max_key_size : MAX_KEY_SZ; \ + keysize = GVT->gd_csa->hdr->max_key_size; \ keysize = DBKEYSIZE(keysize); \ partial_size = SIZEOF(gv_namehead) + 2 * SIZEOF(gv_key) + 3 * keysize; \ /* DSE could change the max_key_size dynamically so account for it in the below assert */ \ @@ -2254,7 +2429,7 @@ GBLREF gv_namehead *gvt_tp_list; #else # define DBG_CHECK_IN_GVT_TP_LIST(gvt, present) # define DBG_CHECK_GVT_IN_GVTARGETLIST(gvt) -# define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC +# define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) # define DBG_CHECK_GVTARGET_INTEGRITY(GVT) #endif @@ -2297,7 +2472,8 @@ GBLREF sgmnt_addrs *cs_addrs; assert(KEY_DELIMITER == GVKEY->base[GVKEY->end]); \ endBuff = format_targ_key(fmtBuff, ARRAYSIZE(fmtBuff), GVKEY, TRUE); \ GV_SET_LAST_SUBSCRIPT_INCOMPLETE(fmtBuff, endBuff); /* Note: might update "endBuff" */ \ - rts_error(VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, endBuff - fmtBuff, fmtBuff); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, \ + endBuff - fmtBuff, fmtBuff); \ } #define COPY_SUBS_TO_GVCURRKEY(mvarg, max_key, gv_currkey, was_null, is_null) \ @@ -2363,6 +2539,21 @@ GBLREF sgmnt_addrs *cs_addrs; DBG_CHECK_GVTARGET_INTEGRITY(GVT); \ } +/* If SRC_KEY->end == 0, make sure to copy the first byte of SRC_KEY->base */ +#define MEMCPY_KEY(TARG_KEY, SRC_KEY) \ +{ \ + memcpy((TARG_KEY), (SRC_KEY), OFFSETOF(gv_key, base[0]) + (SRC_KEY)->end + 1); \ +} +#define COPY_KEY(TARG_KEY, SRC_KEY) \ +{ \ + assert(TARG_KEY->top >= SRC_KEY->end); \ + /* ensure proper alignment before dereferencing SRC_KEY->end */ \ + assert(0 == (((UINTPTR_T)(SRC_KEY)) % SIZEOF(SRC_KEY->end))); \ + /* WARNING: depends on the first two bytes of gv_key structure being key top field */ \ + assert((2 == SIZEOF(TARG_KEY->top)) && ((sm_uc_ptr_t)(TARG_KEY) == (sm_uc_ptr_t)(&TARG_KEY->top))); \ + memcpy(((sm_uc_ptr_t)(TARG_KEY) + 2), ((sm_uc_ptr_t)(SRC_KEY) + 2), OFFSETOF(gv_key, base[0]) + (SRC_KEY)->end - 1); \ +} + /* Macro to denote special value of first_rec when it is no longer reliable */ #define GVT_CLUE_FIRST_REC_UNRELIABLE (short)0xffff @@ -2513,9 +2704,9 @@ typedef enum /* macros to check curr_tn */ #define MAX_TN_V4 ((trans_num)(MAXUINT4 - TN_HEADROOM_V4)) -#define MAX_TN_V5 (MAXUINT8 - TN_HEADROOM_V5) +#define MAX_TN_V6 (MAXUINT8 - TN_HEADROOM_V6) #define TN_HEADROOM_V4 (2 * MAXTOTALBLKS_V4) -#define TN_HEADROOM_V5 (2 * MAXTOTALBLKS_V5) +#define TN_HEADROOM_V6 (2 * MAXTOTALBLKS_V6) #define HEADROOM_FACTOR 4 /* the following macro checks that curr_tn < max_tn_warn <= max_tn. @@ -2534,12 +2725,14 @@ typedef enum \ if ((CSA)->hdr->max_tn <= (TN)) \ { \ - rts_error(VARLSTCNT(5) ERR_TNTOOLARGE, 3, DB_LEN_STR((CSA)->region), &(CSA)->hdr->max_tn); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(5) ERR_TNTOOLARGE, 3, DB_LEN_STR((CSA)->region), \ + &(CSA)->hdr->max_tn); \ assert(FALSE); /* should not come here */ \ } \ assert((CSD)->max_tn > (TN)); \ trans_left = (CSD)->max_tn - (TN); \ - send_msg(VARLSTCNT(6) ERR_TNWARN, 4, DB_LEN_STR((CSA)->region), &trans_left, &(CSD)->max_tn); \ + send_msg_csa(CSA_ARG(CSA) VARLSTCNT(6) ERR_TNWARN, 4, DB_LEN_STR((CSA)->region), &trans_left, \ + &(CSD)->max_tn); \ (CSD)->max_tn_warn = (TN) + 1 + ((trans_left - 1) >> 1); \ assert((TN) < (CSD)->max_tn_warn); \ assert((CSD)->max_tn_warn <= (CSD)->max_tn); \ @@ -2558,7 +2751,7 @@ typedef enum { \ trans_num headroom; \ \ - headroom = (gtm_uint64_t)(GDSV4 == (CSD)->desired_db_format ? TN_HEADROOM_V4 : TN_HEADROOM_V5); \ + headroom = (gtm_uint64_t)(GDSV4 == (CSD)->desired_db_format ? TN_HEADROOM_V4 : TN_HEADROOM_V6); \ headroom *= HEADROOM_FACTOR; \ (ret_warn_tn) = (CSD)->trans_hist.curr_tn; \ if ((headroom < (CSD)->max_tn) && ((ret_warn_tn) < ((CSD)->max_tn - headroom))) \ @@ -2586,8 +2779,6 @@ typedef enum #define CACHE_CONTROL_SIZE(X) \ (ROUND_UP((ROUND_UP((X->bt_buckets + X->n_bts) * SIZEOF(cache_rec) + SIZEOF(cache_que_heads), OS_PAGE_SIZE) \ + ((gtm_uint64_t)X->n_bts * X->blk_size * (X->is_encrypted ? 2 : 1))), OS_PAGE_SIZE)) -#define MMBLK_CONTROL_SIZE(X) (ROUND_UP((((sgmnt_data_ptr_t)X)->bt_buckets + ((sgmnt_data_ptr_t)X)->n_bts) * SIZEOF(mmblk_rec) \ - + SIZEOF(mmblk_que_heads), OS_PAGE_SIZE)) OS_PAGE_SIZE_DECLARE @@ -2658,7 +2849,7 @@ typedef replpool_identifier *replpool_id_ptr_t; { \ int idx; \ uint4 pid; \ - uint4 *kip_pid_arr_ptr; \ + pid_t *kip_pid_arr_ptr; \ GBLREF uint4 process_id; \ \ kip_pid_arr_ptr = local_csa->nl->kip_pid_array; \ @@ -2677,7 +2868,7 @@ typedef replpool_identifier *replpool_id_ptr_t; #define REMOVE_KIP_PID(local_csa) \ { \ int idx; \ - uint4 *kip_pid_arr_ptr; \ + pid_t *kip_pid_arr_ptr; \ GBLREF uint4 process_id; \ \ kip_pid_arr_ptr = local_csa->nl->kip_pid_array; \ @@ -2871,8 +3062,10 @@ 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 */ +#endif #define RESET_SHMID_CTIME(X) \ { \ @@ -2893,27 +3086,28 @@ typedef replpool_identifier *replpool_id_ptr_t; } #if defined(UNIX) -#define DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno) \ -{ \ - BG_TRACE_PRO_ANY(csa, n_db_fsyncs); \ - if (csa->now_crit) \ - BG_TRACE_PRO_ANY(csa, n_db_fsyncs_in_crit); \ - db_fsync_in_prog++; \ - save_errno = 0; \ - if (-1 == fsync(udi->fd)) \ - { \ - db_fsync_in_prog--; \ - save_errno = errno; \ - } \ - db_fsync_in_prog--; \ - assert(0 <= db_fsync_in_prog); \ +#define DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno) \ +{ \ + int rc; \ + \ + BG_TRACE_PRO_ANY(csa, n_db_fsyncs); \ + if (csa->now_crit) \ + BG_TRACE_PRO_ANY(csa, n_db_fsyncs_in_crit); \ + db_fsync_in_prog++; \ + save_errno = 0; \ + GTM_DB_FSYNC(csa, udi->fd, rc); \ + if (-1 == rc) \ + save_errno = errno; \ + db_fsync_in_prog--; \ + assert(0 <= db_fsync_in_prog); \ } #define STANDALONE(x) mu_rndwn_file(x, TRUE) -#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg(VARLSTCNT(5) msg, 2, DB_LEN_STR(gv_cur_region), status); +#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(5) msg, 2, \ + DB_LEN_STR(gv_cur_region), status); #elif defined(VMS) #define STANDALONE(x) mu_rndwn_file(TRUE) /* gv_cur_region needs to be equal to "x" */ -#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg(VARLSTCNT(6) msg, 2, DB_LEN_STR(gv_cur_region), status, \ +#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) msg, 2, DB_LEN_STR(gv_cur_region), status, \ FILE_INFO(gv_cur_region)->fab->fab$l_stv); #else #error unsupported platform @@ -2921,8 +3115,6 @@ typedef replpool_identifier *replpool_id_ptr_t; #define CR_NOT_ALIGNED(cr, cr_base) (!IS_PTR_ALIGNED((cr), (cr_base), SIZEOF(cache_rec))) #define CR_NOT_IN_RANGE(cr, cr_lo, cr_hi) (!IS_PTR_IN_RANGE((cr), (cr_lo), (cr_hi))) -#define MBR_NOT_ALIGNED(mbr, mbr_base) (!IS_PTR_ALIGNED((mbr), (mbr_base), SIZEOF(mmblk_rec))) -#define MBR_NOT_IN_RANGE(mbr, mbr_lo, mbr_hi) (!IS_PTR_IN_RANGE((mbr), (mbr_lo), (mbr_hi))) /* Examine that cr->buffaddr is indeed what it should be. If not, this macro fixes its value by * recomputing from the cache_array. @@ -2946,8 +3138,9 @@ typedef replpool_identifier *replpool_id_ptr_t; bp = bp_lo + ((cr) - (cr_lo)) * csd->blk_size; \ if (bp != cr->buffaddr) \ { \ - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, \ - RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp, CALLFROM); \ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), \ + cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), \ + cr->buffaddr, bp, CALLFROM); \ cr->buffaddr = bp; \ } \ DEBUG_ONLY(bp_top = bp_lo + (gtm_uint64_t)csd->n_bts * csd->blk_size;) \ @@ -2988,8 +3181,10 @@ typedef replpool_identifier *replpool_id_ptr_t; #define UPD_RESERVED_AREA 50 #define UPD_WRITER_TRIGGER_FACTOR 33 -#define SNAPSHOT_ALONE_IN_PROG(CSA) (CSA->snapshot_in_prog && !CSA->backup_in_prog && !(JNL_ENABLED(CSA) && CSA->jnl_before_image)) +#define ONLY_SS_BEFORE_IMAGES(CSA) (CSA->snapshot_in_prog && !CSA->backup_in_prog && !(JNL_ENABLED(CSA) && CSA->jnl_before_image)) +#define SET_SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog = TRUE) +#define CLEAR_SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog = FALSE) #ifdef GTM_SNAPSHOT # define SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog) /* Creates a new snapshot context. Called by GT.M (or utilities like update process, MUPIP LOAD which uses @@ -3003,8 +3198,9 @@ typedef replpool_identifier *replpool_id_ptr_t; \ lcl_ss_ctx = SS_CTX_CAST(CSA->ss_ctx); \ assert(NULL != lcl_ss_ctx); \ + CNL->fastinteg_in_prog ? SET_FAST_INTEG(lcl_ss_ctx) : SET_NORM_INTEG(lcl_ss_ctx); \ ss_shmcycle = CNL->ss_shmcycle; \ - CSA->snapshot_in_prog = TRUE; \ + SET_SNAPSHOTS_IN_PROG(CSA); \ assert(lcl_ss_ctx->ss_shmcycle <= ss_shmcycle); \ if (lcl_ss_ctx->ss_shmcycle != ss_shmcycle) \ { /* Process' view of snapshot is stale. Create/Update snapshot context */ \ @@ -3012,7 +3208,7 @@ typedef replpool_identifier *replpool_id_ptr_t; if (!status) \ { /* snapshot context creation failed. Reset private copy of snapshot_in_prog so that we don't \ * read the before images in t_end or op_tcommit */ \ - CSA->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ assert(!status || (SNAPSHOT_INIT_DONE == lcl_ss_ctx->cur_state)); \ assert(status || (SHADOW_FIL_OPEN_FAIL == lcl_ss_ctx->cur_state) \ @@ -3030,7 +3226,7 @@ typedef replpool_identifier *replpool_id_ptr_t; * snapshot is no longer valid. This way we don't wait for MUPIP INTEG to detect and terminate the \ * snapshots \ */ \ - CSA->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ } @@ -3069,7 +3265,7 @@ typedef replpool_identifier *replpool_id_ptr_t; if (!SNAPSHOTS_IN_PROG(cnl) || (lcl_ss_ctx->ss_shmcycle != ss_shmcycle)) \ { \ ss_destroy_context(lcl_ss_ctx); \ - CSA->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ } @@ -3087,8 +3283,9 @@ typedef replpool_identifier *replpool_id_ptr_t; */ # define BEFORE_IMAGE_NEEDED(read_before_image, CS, csa, csd, blk_no, retval) \ { \ - retval = (read_before_image && csd->db_got_to_v5_once && (!CS->was_free || SNAPSHOTS_IN_PROG(csa))); \ - retval = retval && (!SNAPSHOT_ALONE_IN_PROG(csa) || !ss_chk_shdw_bitmap(csa, SS_CTX_CAST(csa->ss_ctx), blk_no));\ + retval = (read_before_image && csd->db_got_to_v5_once); \ + retval = retval && (!WAS_FREE(CS->blk_prior_state) || SNAPSHOTS_IN_PROG(csa)); \ + retval = retval && (!ONLY_SS_BEFORE_IMAGES(csa) || !ss_chk_shdw_bitmap(csa, SS_CTX_CAST(csa->ss_ctx), blk_no));\ } # define CHK_AND_UPDATE_SNAPSHOT_STATE_IF_NEEDED(CSA, CNL, SS_NEED_TO_RESTART) \ @@ -3113,7 +3310,7 @@ typedef replpool_identifier *replpool_id_ptr_t; { /* No on going snapshots or on going snapshot is invalid. Even if we encountered error during snapshot \ * context creation outside crit, we ignore it as the snapshot is no more active/valid. \ */ \ - CSA->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } else if (lcl_ss_ctx->ss_shmcycle == CNL->ss_shmcycle) \ { /* Neither new snapshots started nor existing ones completed. However, it's possible that we might have \ * encountered error during snapshot context creation outside crit. If the values noted outside crit \ @@ -3135,13 +3332,13 @@ typedef replpool_identifier *replpool_id_ptr_t; break; \ case SNAPSHOT_SHM_ATTACH_FAIL: \ assert(0 != lcl_failure_errno); \ - assert(FALSE == CSA->snapshot_in_prog); \ + assert(FALSE == SNAPSHOTS_IN_PROG(CSA)); \ if (lcl_ss_ctx->nl_shmid == CNL->ss_shmid) \ { /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \ * snapshot is no more valid \ */ \ - send_msg(VARLSTCNT(4) ERR_SSATTACHSHM, 1, lcl_ss_ctx->nl_shmid, \ - lcl_failure_errno); \ + send_msg_csa(CSA_ARG(CSA) VARLSTCNT(4) ERR_SSATTACHSHM, 1, \ + lcl_ss_ctx->nl_shmid, lcl_failure_errno); \ ss_shm_ptr->failure_errno = lcl_failure_errno; \ ss_shm_ptr->failed_pid = process_id; \ } else /* snapshot context creation done while things were in flux */ \ @@ -3149,12 +3346,12 @@ typedef replpool_identifier *replpool_id_ptr_t; break; \ case SHADOW_FIL_OPEN_FAIL: \ assert(0 != lcl_failure_errno); \ - assert(FALSE == CSA->snapshot_in_prog); \ + assert(FALSE == SNAPSHOTS_IN_PROG(CSA)); \ if (0 == STRCMP(lcl_ss_ctx->shadow_file, ss_shm_ptr->ss_info.shadow_file)) \ { /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \ * snapshot is no more valid \ */ \ - send_msg(VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("open"), \ + send_msg_csa(CSA_ARG(CSA) VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("open"), \ LEN_AND_STR(lcl_ss_ctx->shadow_file), lcl_failure_errno); \ ss_shm_ptr->failure_errno = lcl_failure_errno; \ ss_shm_ptr->failed_pid = process_id; \ @@ -3183,6 +3380,7 @@ typedef replpool_identifier *replpool_id_ptr_t; assert(FALSE); \ } #else +/* GTM_SNAPSHOT is not defined */ # define SNAPSHOTS_IN_PROG(X) (FALSE) # define WRITE_SNAPSHOT_BLOCK(csa, cr, mm_blk_ptr, blkid, lcl_ss_ctx) # define SS_INIT_IF_NEEDED(CSA, CNL) @@ -3192,7 +3390,7 @@ typedef replpool_identifier *replpool_id_ptr_t; * backward journal recovery will never be expected to take the database to a point BEFORE the mupip upgrade). */ # define BEFORE_IMAGE_NEEDED(read_before_image, CS, csa, csd, blk_no, retval) \ - retval = (read_before_image && csd->db_got_to_v5_once && !CS->was_free); + retval = (read_before_image && csd->db_got_to_v5_once && !WAS_FREE(CS->blk_prior_state)); #endif /* Determine if the state of 'backup in progress' has changed since we grabbed crit in t_end.c/tp_tend.c */ @@ -3211,16 +3409,18 @@ typedef replpool_identifier *replpool_id_ptr_t; #ifdef GTM_TRUNCATE /* Reduction in free blocks after truncating from a to b total blocks: a = old_total (larger), b = new_total */ # define DELTA_FREE_BLOCKS(a, b) ((a - b) - (DIVIDE_ROUND_UP(a, BLKS_PER_LMAP) - DIVIDE_ROUND_UP(b, BLKS_PER_LMAP))) -# define WRITE_EOF_BLOCK(reg, csd, new_total, status) \ -{ \ - off_t new_eof; \ - char *buff; \ - \ - new_eof = ((off_t)(csd->start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)new_total * csd->blk_size); \ - buff = (char *)malloc(DISK_BLOCK_SIZE); \ - memset(buff, 0, DISK_BLOCK_SIZE); \ - LSEEKWRITE(FILE_INFO(reg)->fd, new_eof, buff, DISK_BLOCK_SIZE, status); \ - free(buff); \ +# define WRITE_EOF_BLOCK(reg, csd, new_total, status) \ +{ \ + off_t new_eof; \ + char buff[DISK_BLOCK_SIZE]; \ + sgmnt_addrs *csa; \ + unix_db_info *udi; \ + \ + new_eof = ((off_t)(csd->start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)new_total * csd->blk_size); \ + memset(buff, 0, DISK_BLOCK_SIZE); \ + udi = FILE_INFO(reg); \ + csa = &udi->s_addrs; \ + DB_LSEEKWRITE(csa, udi->fn, udi->fd, new_eof, buff, DISK_BLOCK_SIZE, status); \ } #endif @@ -3229,15 +3429,113 @@ typedef enum REG_FREEZE_SUCCESS, REG_ALREADY_FROZEN, REG_HAS_KIP -}freeze_status; +} freeze_status; + +#ifdef UNIX +/* This structure holds state captured on entry into gvcst_redo_root_search which it restores on error or exit */ +typedef struct redo_root_search_context_struct +{ + unsigned char t_fail_hist[CDB_MAX_TRIES]; + unsigned int t_tries; + unsigned int prev_t_tries; + inctn_opcode_t inctn_opcode; + trans_num start_tn; + uint4 update_trans; + uint4 t_err; + boolean_t hold_onto_crit; + char currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; + gv_key *gv_currkey; +# ifdef DEBUG + unsigned char t_fail_hist_dbg[T_FAIL_HIST_DBG_SIZE]; + unsigned int t_tries_dbg; +# endif +} redo_root_search_context; +#endif + +#define SET_GV_CURRKEY_FROM_REORG_GV_TARGET \ +{ /* see mupip reorg.c for comment */ \ + GBLREF gv_key *gv_currkey; \ + GBLREF gv_namehead *reorg_gv_target; /* for global name */ \ + GBLREF boolean_t mu_reorg_process; \ + \ + mname_entry *gvent; \ + int end; \ + \ + assert(mu_reorg_process); \ + gvent = &reorg_gv_target->gvname; \ + memcpy(gv_currkey->base, gvent->var_name.addr, gvent->var_name.len); \ + end = gvent->var_name.len + 1; \ + gv_currkey->end = end; \ + gv_currkey->base[end - 1] = 0; \ + gv_currkey->base[end] = 0; \ +} + +#define SET_WANT_ROOT_SEARCH(CDB_STATUS, WANT_ROOT_SEARCH) \ +{ \ + GBLREF uint4 t_tries; \ + GBLREF gv_namehead *gv_target; \ + \ + if (cdb_sc_normal == cdb_status) \ + cdb_status = LAST_RESTART_CODE; \ + /* Below IF check is a special case where t_retry/tp_restart detects mismatched root cycles in 2nd to 3rd retry \ + * transition. In this case, the CDB_STATUS can be anything but we still need to redo the root search \ + */ \ + if ((CDB_STAGNATE == t_tries) && !gv_target->root) \ + WANT_ROOT_SEARCH = TRUE; \ + switch(CDB_STATUS) \ + { \ + case cdb_sc_onln_rlbk1: \ + case cdb_sc_gvtrootmod: \ + case cdb_sc_gvtrootmod2: \ + WANT_ROOT_SEARCH = TRUE; \ + break; \ + case cdb_sc_onln_rlbk2: \ + /* Database was taken back to a different logical state and we are an implicit TP \ + * transaction. Issue DBROLLEDBACK error that the application programmer can catch and do \ + * the necessary stuff. \ + */ \ + assert(gtm_trigger_depth == tstart_trigger_depth); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \ + default: \ + break; \ + } \ +} + +#define REDO_ROOT_SEARCH_IF_NEEDED(WANT_ROOT_SEARCH, CDB_STATUS) \ +{ \ + DEBUG_ONLY(GBLREF tp_frame *tp_pointer;) \ + GBLREF uint4 t_err; \ + GBLREF uint4 update_trans; \ + uint4 save_update_trans, save_t_err; \ + \ + CDB_STATUS = cdb_sc_normal; \ + if (WANT_ROOT_SEARCH) \ + { /* We are implicit transaction and one of two things has happened: \ + * 1. Online rollback updated the database but did NOT take us to a different logical state in which \ + * case we've already done the restart, but the root is now reset to zero. \ + * 2. mu_swap_root concurrently moved root blocks. We've restarted and reset root to zero. \ + * In either case, do root search to establish the new root. \ + */ \ + NON_GTMTRIG_ONLY(assert(FALSE)); \ + assert(tp_pointer->implicit_tstart); \ + assert(NULL != gv_target); \ + save_t_err = t_err; \ + save_update_trans = update_trans; \ + GVCST_ROOT_SEARCH_DONOT_RESTART(CDB_STATUS); \ + t_err = save_t_err; \ + update_trans = save_update_trans; \ + if (cdb_sc_normal == CDB_STATUS) \ + WANT_ROOT_SEARCH = FALSE; \ + } \ +} #define ASSERT_BEGIN_OF_FRESH_TP_TRANS \ { \ GBLREF sgm_info *first_sgm_info; \ GBLREF sgm_info *sgm_info_ptr; \ \ - assert((NULL != first_sgm_info) && (first_sgm_info == sgm_info_ptr) && (NULL == first_sgm_info->next_sgm_info) \ - && (0 == sgm_info_ptr->num_of_blks)); \ + assert((NULL == first_sgm_info) || ((sgm_info_ptr == first_sgm_info) && (NULL == first_sgm_info->next_sgm_info))); \ + assert((NULL == first_sgm_info) || (0 == sgm_info_ptr->num_of_blks)); \ } #define GVCST_ROOT_SEARCH \ @@ -3247,7 +3545,35 @@ typedef enum */ \ assert((NULL != gv_target) && (DIR_ROOT != gv_target->root)); \ if (!gv_target->root) \ - gvcst_root_search(); \ + gvcst_root_search(FALSE); \ +} + +/* Same as GVCST_ROOT_SEARCH, but tells gvcst_root_search NOT to restart but to return the status code back to the caller */ +#define GVCST_ROOT_SEARCH_DONOT_RESTART(STATUS) \ +{ \ + assert((NULL != gv_target) && (DIR_ROOT != gv_target->root)); \ + STATUS = cdb_sc_normal; \ + if (!gv_target->root) \ + STATUS = gvcst_root_search(TRUE); \ +} + +#define GVCST_ROOT_SEARCH_AND_PREP(est_first_pass) \ +{ /* Before beginning a spanning node try in a gvcst routine, make sure the root is established. If we've restarted \ + * issue DBROLLEDBACK appropriately. \ + */ \ + GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; /* for LAST_RESTART_CODE */ \ + GBLREF stack_frame *frame_pointer; \ + \ + DCL_THREADGBL_ACCESS; \ + \ + SETUP_THREADGBL_ACCESS; \ + assert(dollar_tlevel); \ + ASSERT_BEGIN_OF_FRESH_TP_TRANS; \ + frame_pointer->flags |= SFF_IMPLTSTART_CALLD; \ + if (est_first_pass && (cdb_sc_onln_rlbk2 == LAST_RESTART_CODE)) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \ + tp_set_sgm(); \ + GVCST_ROOT_SEARCH; \ } #define GV_BIND_NAME_ONLY(ADDR, TARG) gv_bind_name(ADDR, TARG) @@ -3264,31 +3590,33 @@ typedef enum GVCST_ROOT_SEARCH; \ } - -#ifdef UNIX - -/* When invoking GRAB_LOCK, use one of the following parameters. - * GRAB_LOCK_ONLY - use when the code expects an online rollback, but wants to handle it separately (like updproc.c) - * ASSERT_NO_ONLINE_ROLLBACK - use when the code doesn't expect online rollback (because it holds some other lock (like crit)) - * HANDLE_CONCUR_ONLINE_ROLLBACK - use when the code expects online rollback, but wants the macro to handle it (currently used only - * for the source server) +/* When invoking grab_lock or grab_gtmsource_srv_latch, use one of the following parameters. + * GRAB_LOCK_ONLY : use when code expects an online rollback, but handles it separately (like updproc.c) + * GRAB_GTMSOURCE_SRV_LATCH_ONLY : Same as above (just that this is used for grab_gtmsource_srv_latch instead of grab_lock) + * ASSERT_NO_ONLINE_ROLLBACK : use when holding some other lock (like crit) that prevents online rollback + * HANDLE_CONCUR_ONLINE_ROLLBACK : use when not blocking online rollback, but handling with this macro (only source server) */ #define GRAB_LOCK_ONLY 0x01 +#define GRAB_GTMSOURCE_SRV_LATCH_ONLY 0x01 #define ASSERT_NO_ONLINE_ROLLBACK 0x02 #define HANDLE_CONCUR_ONLINE_ROLLBACK 0x03 +#ifdef UNIX +/* caller should have THREADGBL_ACCESS and gbl access to t_tries and t_fail_hist */ +# define LAST_RESTART_CODE ( (0 < t_tries) ? t_fail_hist[TREF(prev_t_tries)] : (enum cdb_sc)cdb_sc_normal ) # define SYNC_ONLN_RLBK_CYCLES \ { \ GBLREF sgmnt_addrs *cs_addrs_list; \ GBLREF jnlpool_addrs jnlpool; \ + GBLREF boolean_t mu_reorg_process; \ \ sgmnt_addrs *lcl_csa; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ - if (!TREF(only_reset_clues_if_onln_rlbk)) \ + if (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process) \ { \ - for (lcl_csa = cs_addrs_list; NULL != lcl_csa; lcl_csa= lcl_csa->next_csa) \ + for (lcl_csa = cs_addrs_list; NULL != lcl_csa; lcl_csa = lcl_csa->next_csa) \ { \ lcl_csa->onln_rlbk_cycle = lcl_csa->nl->onln_rlbk_cycle; \ lcl_csa->db_onln_rlbkd_cycle = lcl_csa->nl->db_onln_rlbkd_cycle; \ @@ -3301,6 +3629,23 @@ typedef enum } \ } \ } +# define SYNC_ROOT_CYCLES(CSA) \ +{ /* NULL CSA acts as a flag to do all regions */ \ + GBLREF sgmnt_addrs *cs_addrs_list; \ + GBLREF boolean_t mu_reorg_process; \ + \ + sgmnt_addrs *lcl_csa; \ + DCL_THREADGBL_ACCESS; \ + \ + SETUP_THREADGBL_ACCESS; \ + for (lcl_csa = cs_addrs_list; NULL != lcl_csa; lcl_csa = lcl_csa->next_csa) \ + if (NULL == (CSA) || (CSA) == lcl_csa) \ + lcl_csa->root_search_cycle = lcl_csa->nl->root_search_cycle; \ +} +# define MISMATCH_ROOT_CYCLES(CSA, CNL) ((CSA)->root_search_cycle != (CNL)->root_search_cycle) +# define MISMATCH_ONLN_RLBK_CYCLES(CSA, CNL) ((CSA)->onln_rlbk_cycle != (CNL)->onln_rlbk_cycle) +# define ONLN_RLBK_STATUS(CSA, CNL) \ + (((CSA)->db_onln_rlbkd_cycle != (CNL)->db_onln_rlbkd_cycle) ? cdb_sc_onln_rlbk2 : cdb_sc_onln_rlbk1) # define ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, TN_ABORTED) \ { \ DEBUG_ONLY(GBLREF unsigned int t_tries;) \ @@ -3310,10 +3655,12 @@ typedef enum GBLREF gv_namehead *gv_target; \ \ DEBUG_ONLY(enum cdb_sc failure;) \ + DCL_THREADGBL_ACCESS; \ \ + SETUP_THREADGBL_ACCESS; \ assert(0 < t_tries); \ assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); \ - DEBUG_ONLY(failure = t_fail_hist[t_tries - 1]); \ + DEBUG_ONLY(failure = LAST_RESTART_CODE); \ assert(NULL != gv_target); \ TN_ABORTED = FALSE; \ if (!gv_target->root) \ @@ -3321,69 +3668,13 @@ typedef enum * mu_reorg or mu_extr_getblk, no longer exists. Consider this as the end of the tree and return to the \ * caller with the appropriate code. The caller knows to continue with the next global \ */ \ - assert(cdb_sc_onln_rlbk2 == failure); \ + assert(cdb_sc_onln_rlbk2 == failure || TREF(rlbk_during_redo_root)); \ /* abort the current transaction */ \ t_abort(gv_cur_region, cs_addrs); \ TN_ABORTED = TRUE; \ } \ } -# define GRAB_LOCK(REG, ACT) \ -{ \ - GBLREF jnlpool_addrs jnlpool; \ - GBLREF boolean_t is_src_server; \ - \ - sgmnt_addrs *lcl_repl_csa; \ - unix_db_info *udi; \ - boolean_t cycle_mismatch; \ - \ - udi = FILE_INFO(REG); \ - lcl_repl_csa = &udi->s_addrs; \ - grab_lock(REG); \ - if (GRAB_LOCK_ONLY != ACT) \ - { \ - cycle_mismatch = (lcl_repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle); \ - assert((ASSERT_NO_ONLINE_ROLLBACK != ACT) || !cycle_mismatch); \ - if ((HANDLE_CONCUR_ONLINE_ROLLBACK == ACT) && cycle_mismatch) \ - { \ - assert(is_src_server); \ - SYNC_ONLN_RLBK_CYCLES; \ - gtmsource_onln_rlbk_clnup(); \ - rel_lock(REG); \ - } \ - } \ -} -# define GRAB_GTMSOURCE_SRV_LATCH(GTMSOURCE_LOCAL, MAX_EPOCH_INTERVAL) \ -{ \ - GBLREF boolean_t is_src_server; \ - GBLREF jnlpool_addrs jnlpool; \ - \ - sgmnt_addrs *lcl_repl_csa; \ - unix_db_info *udi; \ - \ - assert(is_src_server); \ - udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); \ - lcl_repl_csa = &udi->s_addrs; \ - assert(!lcl_repl_csa->now_crit); /* should not hold journal pool lock at this point */ \ - if (!grab_gtmsource_srv_latch(>MSOURCE_LOCAL->gtmsource_srv_latch, 2 * MAX_EPOCH_INTERVAL)) \ - rts_error(VARLSTCNT(5) ERR_SRVLCKWT2LNG, 2, 2 * MAX_EPOCH_INTERVAL, GTMSOURCE_LOCAL->gtmsource_pid); \ - if (jnlpool.repl_inst_filehdr->file_corrupt) \ - { /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until \ - * the rollback command is re-run to bring the journal pool/file and instance file to a \ - * consistent state. \ - */ \ - /* No need to release the latch before rts_error (mupip_exit_handler will do it for us) */ \ - rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), \ - ERR_TEXT, 2, LEN_AND_LIT("file_corrupt field in instance file header is set to TRUE")); \ - } \ - if (lcl_repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle) \ - { \ - SYNC_ONLN_RLBK_CYCLES; \ - gtmsource_onln_rlbk_clnup(); \ - rel_gtmsource_srv_latch(>MSOURCE_LOCAL->gtmsource_srv_latch); \ - } \ -} #else -# define GRAB_LOCK(REG, ACT) grab_lock(REG) # define ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, TN_ABORTED) #endif @@ -3407,6 +3698,247 @@ typedef enum assert(gv_altkey->end < gv_altkey->top); \ } +typedef struct span_subs_struct { + unsigned char b_ctrl; + unsigned char b_first; + unsigned char b_sec; +} span_subs; + +#define ASCII_0 '0' +#define SPAN_BLKID_BASE 255 +#define DECIMAL_BASE 10 + +/* SPAN_SUBS_LEN macro define the length of the special subscript of spanning node in terms of number of characters. + * The format of special spanning node subscript is '#-X-X', where X ranges from 1 to 255. Note that X never takes the + * value of '0' because '0' is used as subscript deliminiter. + */ +#define SPAN_SUBS_LEN 3 + +#define SPAN_PREFIX "#SPAN" +#define SPAN_PREFIX_LEN (SIZEOF(SPAN_PREFIX) - 1) +#define ASGN_SPAN_PREFIX(B) {*(B) = '#'; *(B + 1) = 'S'; *(B + 2) = 'P'; *(B + 3) = 'A'; *(B + 4) = 'N';} +#define SPAN_GVSUBS2INT(A) (((A)->b_first - 1) * SPAN_BLKID_BASE + (A)->b_sec - 1) +#define SPAN_INT2GVSUBS(A, B) {(A)->b_ctrl = 0x02; (A)->b_first = B / SPAN_BLKID_BASE + 1 ; (A)->b_sec = B % SPAN_BLKID_BASE + 1;} +#define SPAN_DECLSUBS(A) (span_subs A) +#define SPAN_INITSUBS(A, B) SPAN_INT2GVSUBS(A, B) +#define SPAN_INCRSUBS(A) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) + 1) +#define SPAN_INCRBYSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) + B) +#define SPAN_DECRSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) - 1) +#define SPAN_DECRBYSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) - B) + +/* The following macro assumes that the length of the special subscript for spanning node is '3'. The assert in the macro verfies + * that this assumption is true. In future, if the length of the special subscript for spanning node changes, the following macro + * needs to be fixed accordingly. + */ +#define SPAN_SUBSCOPY_SRC2DST(DST, SRC) \ +{ \ + assert(SPAN_SUBS_LEN == 3); \ + *((DST) + 0) = *((SRC) + 0); \ + *((DST) + 1) = *((SRC) + 1); \ + *((DST) + 2) = *((SRC) + 2); \ +} + +/*#include "mv_stent.h"*/ +typedef struct +{ + boolean_t span_status; + boolean_t enable_jnl_format; + boolean_t enable_trigger_read_and_fire; + boolean_t ztval_gvcst_put_redo; + mval *val_forjnl; + int4 blk_reserved_bytes; +# ifdef GTM_TRIGGER + unsigned char *save_msp; + unsigned char *save_mv_chain; /* actually mv_stent ptr */ + mval *ztold_mval; + mval *ztval_mval; +# endif +} span_parms; + +#ifdef UNIX +# define DEFINE_NSB_CONDITION_HANDLER(gvcst_xxx_ch) \ + CONDITION_HANDLER(gvcst_xxx_ch) \ + { \ + int rc; \ + \ + START_CH; \ + if ((int)ERR_TPRETRY == SIGNAL) \ + { \ + rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); \ + /*DEBUG_ONLY(printf("gvcst_xxx_ch: Unwinding due to TP Restart\n");)*/ \ + UNWIND(NULL, NULL); \ + } \ + NEXTCH; \ + } +/* Check if the value of a primary node is a dummy value: $c(0). If so, it might be a spanning node */ +# define IS_SN_DUMMY(len, addr) ((1 == (len)) && ('\0' == *(unsigned char *)(addr))) +# define RTS_ERROR_IF_SN_DISALLOWED \ +{ \ + GBLREF boolean_t span_nodes_disallowed; \ + \ + error_def(ERR_TEXT); /* BYPASSOK */ \ + error_def(ERR_UNIMPLOP); /* BYPASSOK */ \ + \ + if (span_nodes_disallowed) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, \ + LEN_AND_LIT("GT.CM Server does not support spanning nodes")); \ +} +# define IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(STATEMENT) \ +{ /* We've encountered a spanning node dummy value. Check if spanning nodes are disallowed (e.g., GT.CM). \ + * If csd->span_node_absent is TRUE we know the value really is $c(0) and we return that. Otherwise, \ + * this is potentially a spanning node. We cannot do an op_tstart to check so we issue an error instead. \ + */ \ + GBLREF sgmnt_data_ptr_t cs_data; \ + GBLREF boolean_t span_nodes_disallowed; \ + \ + if (span_nodes_disallowed) \ + { \ + if (!cs_data->span_node_absent) \ + { \ + RTS_ERROR_IF_SN_DISALLOWED; \ + } else \ + { \ + STATEMENT; \ + } \ + } \ +} +#else +# define DEFINE_NSB_CONDITION_HANDLER(gvcst_xxx_ch) +# define IF_NSB_DUMMY_RETURN +# define RTS_ERROR_IF_SN_DISALLOWED_AND_SPAN_IN_DB +# define RETURN_NO_VAL_IF_SN_DISALLOWED +# define RETURN_IF_SN_DISALLOWED(value) +#endif + +#define MAX_NSBCTRL_SZ 30 /* Upper bound on size of ctrl value. 2*10 digs + 1 comma + 1 null + overhead */ + +/* Control node value is 6 bytes, 2 for unsigned short numsubs, 4 for uint4 gblsize. Each is little-endian. */ +#ifdef BIGENDIAN +# define PUT_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ +{ \ + unsigned short swap_numsubs; \ + uint4 swap_gblsize; \ + \ + swap_numsubs = GTM_BYTESWAP_16(NUMSUBS); \ + swap_gblsize = GTM_BYTESWAP_32(GBLSIZE); \ + PUT_USHORT((unsigned char *)BYTES, swap_numsubs); \ + PUT_ULONG((unsigned char *)BYTES + 2, swap_gblsize); \ +} +# define GET_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ +{ \ + unsigned short swap_numsubs; \ + uint4 swap_gblsize; \ + \ + GET_USHORT(swap_numsubs, (unsigned char *)BYTES); \ + GET_ULONG(swap_gblsize, (unsigned char *)BYTES + 2); \ + NUMSUBS = GTM_BYTESWAP_16(swap_numsubs); \ + GBLSIZE = GTM_BYTESWAP_32(swap_gblsize); \ +} +#else +# define PUT_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ +{ \ + PUT_USHORT((unsigned char *)BYTES, NUMSUBS); \ + PUT_ULONG((unsigned char *)BYTES + 2, GBLSIZE); \ +} +# define GET_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ +{ \ + GET_USHORT(NUMSUBS, (unsigned char *)BYTES); \ + GET_ULONG(GBLSIZE, (unsigned char *)BYTES + 2); \ +} +#endif + +#define CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden) \ +{ \ + if (found) \ + { \ + CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); \ + if (!is_hidden) \ + return found; \ + } else \ + return found; \ +} +#define CHECK_HIDDEN_SUBSCRIPT_AND_BREAK(found, gv_altkey, is_hidden) \ +{ \ + if (found) \ + { \ + CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); \ + if (!is_hidden) \ + break; \ + } else \ + break; \ +} +#define CHECK_HIDDEN_SUBSCRIPT(KEY, IS_HIDDEN) \ +{ \ + sm_uc_ptr_t keyloc; \ + \ + keyloc = (KEY)->base + (KEY)->end - 5; \ + if ((KEY)->end >= 5 && 0 == *keyloc && 2 == *(keyloc+1)) \ + IS_HIDDEN = TRUE; \ + else \ + IS_HIDDEN = FALSE; \ +} +#define SAVE_GV_CURRKEY \ +{ \ + assert(NULL != gv_currkey); \ + assert((SIZEOF(gv_key) + gv_currkey->end) <= SIZEOF(save_currkey)); \ + save_gv_currkey = (gv_key *)&save_currkey[0]; \ + memcpy(save_gv_currkey, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); \ +} +#define RESTORE_GV_CURRKEY \ +{ \ + assert(gv_currkey->top == save_gv_currkey->top); \ + memcpy(gv_currkey, save_gv_currkey, SIZEOF(gv_key) + save_gv_currkey->end); \ +} +#define SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend) \ +{ \ + prev = gv_currkey->prev; \ + oldend = gv_currkey->end; \ + assert('\0' == gv_currkey->base[oldend]); \ + if (prev <= oldend) \ + memcpy(save_currkey, &gv_currkey->base[prev], oldend - prev + 1); \ +} +#define RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend) \ +{ \ + gv_currkey->prev = prev; \ + gv_currkey->end = oldend; \ + if (prev <= oldend) \ + memcpy(&gv_currkey->base[prev], save_currkey, oldend - prev + 1); \ + assert('\0' == gv_currkey->base[oldend]); \ +} + +#define CAN_APPEND_HIDDEN_SUBS(KEY) (((KEY)->end + 5 <= MAX_KEY_SZ) && ((KEY)->end + 5 <= (KEY)->top)) +#define APPEND_HIDDEN_SUB(KEY) \ +{ \ + int end; \ + \ + assert(CAN_APPEND_HIDDEN_SUBS(KEY)); \ + end = gv_currkey->end; \ + gv_currkey->end += 4; \ + (KEY)->base[end++] = 2; \ + (KEY)->base[end++] = 1; \ + (KEY)->base[end++] = 1; \ + (KEY)->base[end++] = 0; \ + (KEY)->base[end] = 0; \ +} +#define NEXT_HIDDEN_SUB(KEY, I) \ +{ \ + int end; \ + \ + end = gv_currkey->end - 4; \ + (KEY)->base[end++] = 2; \ + (KEY)->base[end++] = 1 + ((I + 1) / 0xFF); \ + (KEY)->base[end++] = 1 + ((I + 1) % 0xFF); \ + (KEY)->base[end++] = 0; \ + (KEY)->base[end] = 0; \ +} +#define RESTORE_CURRKEY(KEY, OLDEND) \ +{ \ + (KEY)->end = OLDEND; \ + (KEY)->base[OLDEND - 1] = 0; \ + (KEY)->base[OLDEND] = 0; \ +} +#define COMPUTE_CHUNK_SIZE(KEY, BLKSZ, RESERVED) \ + (BLKSZ - RESERVED - ((KEY)->end + 1) - SIZEOF(blk_hdr) - SIZEOF(rec_hdr)) void assert_jrec_member_offsets(void); bt_rec_ptr_t bt_put(gd_region *r, int4 block); @@ -3416,7 +3948,8 @@ void bt_malloc(sgmnt_addrs *csa); void bt_refresh(sgmnt_addrs *csa, boolean_t init); void db_common_init(gd_region *reg, sgmnt_addrs *csa, sgmnt_data_ptr_t csd); void grab_crit(gd_region *reg); -void grab_lock(gd_region *reg); +boolean_t grab_crit_immediate(gd_region *reg); +boolean_t grab_lock(gd_region *reg, boolean_t is_blocking_wait, uint4 onln_rlbk_action); void gv_init_reg(gd_region *reg); void gvcst_init(gd_region *greg); enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh); @@ -3460,7 +3993,7 @@ unsigned char *mval2subsc(mval *in_val, gv_key *out_key); int4 dsk_read(block_id blk, sm_uc_ptr_t buff, enum db_ver *ondisk_blkver, boolean_t blk_free); -unsigned int gds_file_size(file_control *fc); +gtm_uint64_t gds_file_size(file_control *fc); uint4 jnl_flush(gd_region *reg); void jnl_fsync(gd_region *reg, uint4 fsync_addr); diff --git a/sr_port/gdsfilext.h b/sr_port/gdsfilext.h index b6a7d79..2afb24f 100644 --- a/sr_port/gdsfilext.h +++ b/sr_port/gdsfilext.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,15 @@ #ifndef __GDSFILEXT_H__ #define __GDSFILEXT_H__ +#ifdef UNIX +uint4 gdsfilext(uint4 blocks, uint4 filesize, boolean_t trans_in_prog); +# define GDSFILEXT(BLOCKS, FILESIZE, TRANS_IN_PROG) gdsfilext(BLOCKS, FILESIZE, TRANS_IN_PROG) +#else uint4 gdsfilext(uint4 blocks, uint4 filesize); +# define GDSFILEXT(BLOCKS, FILESIZE, DUMMY) gdsfilext(BLOCKS, FILESIZE) +#endif + +#define TRANS_IN_PROG_FALSE FALSE +#define TRANS_IN_PROG_TRUE TRUE #endif diff --git a/sr_port/gdskill.h b/sr_port/gdskill.h index d38be79..cce6536 100644 --- a/sr_port/gdskill.h +++ b/sr_port/gdskill.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,21 +17,16 @@ header used by memory management system) */ #define BLKS_IN_KILL_SET 251 -/* Note the currently GDS_MAX_BLK_BITS is 28. This 28 bit block field allows for a 256M GDS block database. - * The three byte level field is the minimum required to contain the level. However, if more addressability - * is needed, the level field can likely be shrunk to a single bit to indicate a non-zero level and then the - * actual level obtained when the blocks are read in. Note that if this changes, a comment in gvcst_init() - * also needs adjustment. - */ +/* Note that currently GDS_MAX_BLK_BITS is 30. This 30 bit block field allows for a 1G GDS block database. */ typedef struct { #ifdef BIGENDIAN unsigned int flag : 1; /* Block was created by this TP transaction (not real block yet) */ - unsigned int level : 3; /* Block level (0 to 6) */ + unsigned int level : 1; /* Block level (zero or non-zero) */ unsigned int block : GDS_MAX_BLK_BITS; /* Block number */ #else unsigned int block : GDS_MAX_BLK_BITS; /* Block number */ - unsigned int level : 3; /* Block level (0 to 6) */ + unsigned int level : 1; /* Block level (zero or non-zero) */ unsigned int flag : 1; /* Block was created by this TP transaction (not real block yet) */ #endif } blk_ident; diff --git a/sr_port/gdsroot.h b/sr_port/gdsroot.h index 175dc6b..f3523df 100644 --- a/sr_port/gdsroot.h +++ b/sr_port/gdsroot.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,10 +17,20 @@ #define DIR_ROOT 1 #define CDB_STAGNATE 3 #define CDB_MAX_TRIES (CDB_STAGNATE + 2) /* used in defining arrays, usage requires it must be at least 1 more than CSB_STAGNATE*/ +#define T_FAIL_HIST_DBG_SIZE 32 #define MAX_BT_DEPTH 7 +#define CSE_LEVEL_DRT_LVL0_FREE (MAX_BT_DEPTH + 2) /* used to indicate a level-0 block in GV tree will be freed */ #define GLO_NAME_MAXLEN 33 /* 1 for length, 4 for prefix, 15 for dvi, 1 for $, 12 for fid */ #define MAX_NUM_SUBSC_LEN 10 /* one for exponent, nine for the 18 significant digits */ -#define EXTEND_WARNING_FACTOR 3 +/* Define padding in a gv_key structure to hold + * 1) A number : This way we are ensured a key buffer overflow will never occur while converting a number + * from mval representation to subscript representation. + * 2) 16 byte of a string : This way if we are about to overflow the max-key-size, we are more likely to fit the + * overflowing key in the padding space and so can give a more user-friendly GVSUBOFLOW message which + * includes the overflowing subscript in most practical situations. + */ +#define MAX_GVKEY_PADDING_LEN (MAX_NUM_SUBSC_LEN + 16) +#define EXTEND_WARNING_FACTOR 3 /* Define macro to compute the maximum key size required in the gv_key structure based on the database's maximum key size. * Align it to 4-byte boundary as this macro is mostly used by targ_alloc which allocates 3 keys one for gv_target->clue, * one for gv_target->first_rec and one for gv_target->last_rec. The alignment ensures all 3 fields start at aligned boundary. @@ -29,14 +39,20 @@ * we use the ROUND_UP macro (which has no checks). It is ok to do that instead of the more-efficient ROUND_UP2 macro * as the second parameter is a constant so all this should get evaluated at compile-time itself. */ -#define DBKEYSIZE(KSIZE) (ROUND_UP((KSIZE + MAX_NUM_SUBSC_LEN), 4)) +#define DBKEYSIZE(KSIZE) (ROUND_UP((KSIZE + MAX_GVKEY_PADDING_LEN), 4)) + +/* Possible states for TREF(in_mu_swap_root_state) (part of MUPIP REORG -TRUNCATE) */ +#define MUSWP_NONE 0 /* default; not in mu_swap_root */ +#define MUSWP_INCR_ROOT_CYCLE 1 /* moving a root block; need to increment root_search_cycle */ +#define MUSWP_FREE_BLK 2 /* freeing a directory block; need to write leaf blocks to snapshot file */ +#define MUSWP_DIRECTORY_SWAP 3 /* moving a directory block; just checked by cert_blk */ typedef gtm_uint64_t trans_num; typedef uint4 trans_num_4byte; typedef int4 block_id; /* allows for GDS block #s to have 32 bits but see GDS_MAX_BLK_BITS below */ -#define GDS_MAX_BLK_BITS 28 /* see blk_ident structure in gdskill.h for why this cannot be any greater */ +#define GDS_MAX_BLK_BITS 30 /* see blk_ident structure in gdskill.h for why this cannot be any greater */ #define GDS_MAX_VALID_BLK (1<FIELD.mvtype = MV_STR; \ + QUALIF->FIELD.str.len = glb_cmd_qlf.FIELD.str.len; \ + memcpy(QUALIF->FIELD.str.addr, glb_cmd_qlf.FIELD.str.addr, glb_cmd_qlf.FIELD.str.len); \ + } \ +} + GBLDEF list_params lst_param; GBLREF command_qualifier glb_cmd_qlf; @@ -30,6 +40,9 @@ void get_cmd_qlf(command_qualifier *qualif) qualif->qlf = glb_cmd_qlf.qlf; qualif->object_file.mvtype = qualif->list_file.mvtype = qualif->ceprep_file.mvtype = 0; + INIT_QUALIF_STR(qualif, CQ_OBJECT, object_file); + INIT_QUALIF_STR(qualif, CQ_LIST, list_file); + INIT_QUALIF_STR(qualif, CQ_CE_PREPROCESS, ceprep_file); if (gtm_utf8_mode) qualif->qlf |= CQ_UTF8; /* Mark as being compiled in UTF8 mode */ if (cli_present("OBJECT") == CLI_PRESENT) @@ -157,4 +170,8 @@ void get_cmd_qlf(command_qualifier *qualif) s->len = len; } else if (cli_negated("CE_PREPROCESS") == TRUE) qualif->qlf &= ~CQ_CE_PREPROCESS; +# ifdef USHBIN_SUPPORTED + if (CLI_PRESENT == cli_present("DYNAMIC_LITERALS")) + qualif->qlf |= CQ_DYNAMIC_LITERALS; +# endif } diff --git a/sr_port/get_frame_creation_info.c b/sr_port/get_frame_creation_info.c index a64df2a..5f59199 100644 --- a/sr_port/get_frame_creation_info.c +++ b/sr_port/get_frame_creation_info.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "stringpool.h" #include "error_trap.h" @@ -19,16 +19,20 @@ #define CREATEDBY_DO 0 #define CREATEDBY_XECUTE 1 #define CREATEDBY_FUNCTION 2 +#define CREATEDBY_ZINTR 3 +#define CREATEDBY_TRIGGER 4 GBLREF stack_frame *frame_pointer; GBLREF spdesc stringpool; #ifdef UNIX -LITDEF mstr createdby_text[3] = {{0, LEN_AND_LIT("DO")}, {0, LEN_AND_LIT("XECUTE")}, {0, LEN_AND_LIT("$$")}}; +LITDEF mstr createdby_text[5] = {{0, LEN_AND_LIT("DO")}, {0, LEN_AND_LIT("XECUTE")}, {0, LEN_AND_LIT("$$")}, + {0, LEN_AND_LIT("ZINTR")}, {0, LEN_AND_LIT("TRIGGER")}}; #endif #ifdef VMS -LITDEF mstr createdby_text[3] = {{LEN_AND_LIT("DO")}, {LEN_AND_LIT("XECUTE")}, {LEN_AND_LIT("$$")}}; +LITDEF mstr createdby_text[4] = {{LEN_AND_LIT("DO")}, {LEN_AND_LIT("XECUTE")}, {LEN_AND_LIT("$$")}, + {LEN_AND_LIT("ZINTR")}}; #endif void get_frame_creation_info(int level, int cur_zlevel, mval *result) @@ -61,12 +65,16 @@ void get_frame_creation_info(int level, int cur_zlevel, mval *result) break; } assert(fp && (fp->type & SFT_COUNT)); - if (fp->flags & SFF_INDCE) + if (fp && (fp->type & SFT_ZINTR)) + result->str = createdby_text[CREATEDBY_ZINTR]; + else if (fp && (fp->flags & SFF_INDCE)) result->str = createdby_text[CREATEDBY_XECUTE]; - else if (fp->ret_value) +# ifdef GTM_TRIGGER + else if (fp && (fp->old_frame_pointer->type & SFT_TRIGR)) + result->str = createdby_text[CREATEDBY_TRIGGER]; +# endif + else if (fp && fp->ret_value) result->str = createdby_text[CREATEDBY_FUNCTION]; else result->str = createdby_text[CREATEDBY_DO]; - s2pool(&result->str); - assert(((unsigned char *)result->str.addr + result->str.len) == stringpool.free); } diff --git a/sr_port/get_frame_place_mcode.c b/sr_port/get_frame_place_mcode.c index 80c96b9..e9bdea1 100644 --- a/sr_port/get_frame_place_mcode.c +++ b/sr_port/get_frame_place_mcode.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "stringpool.h" #include "error_trap.h" @@ -160,8 +160,8 @@ void get_frame_place_mcode(int level, stack_mode_t mode, int cur_zlevel, mval *r indce = irtnhdr->indce; assert(NULL != indce); assert(0 < indce->refcnt); /* currently used in the M stack better have a non-zero refcnt */ + s2pool(&indce->src.str); result->str = indce->src.str; - s2pool(&result->str); assert(((unsigned char *)result->str.addr + result->str.len) == stringpool.free); } else { /* Not a real indirect. The mpc may have been reset by error handling to various assembler diff --git a/sr_port/get_fs_block_size.c b/sr_port/get_fs_block_size.c index 1d2c7ec..f605a0c 100644 --- a/sr_port/get_fs_block_size.c +++ b/sr_port/get_fs_block_size.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2013 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" +#include "have_crit.h" +#include "eintr_wrappers.h" #include "get_fs_block_size.h" #ifndef VMS @@ -33,11 +35,11 @@ uint4 get_fs_block_size(int fd) assert(-1 != status); assert(SIZEOF(sys_fs_block_size) == SIZEOF(bufvfs.f_frsize)); /* If fstatvfs call fails, we dont know what the underlying filesystem size is. - * Instead of erroring out at this point, we assume a safe value and continue as much as we can. - * The higher the value, the more safe it is since it is more likely a multiple of the underlying - * filesystem size. We therefore pick 4K. + * We found some NFS implementations return bufvfs.f.frsize values that are inappropriate. + * Instead of erroring out at this point, we assume a safe value (4K) and continue as much as we can. */ - sys_fs_block_size = (-1 == status) ? 4096 : bufvfs.f_frsize; + sys_fs_block_size = ((-1 == status) || (MAX_IO_BLOCK_SIZE < bufvfs.f_frsize) + || (DISK_BLOCK_SIZE > bufvfs.f_frsize)) ? 4096 : bufvfs.f_frsize; # endif /* Fit file system block size in a 4-byte unsigned integer as that is the size in jnl_buffer. * Assert that we never get a block size > what can be held in a 4-byte unsigned integer. diff --git a/sr_port/get_ret_targ.c b/sr_port/get_ret_targ.c index 85912d3..c5a406d 100644 --- a/sr_port/get_ret_targ.c +++ b/sr_port/get_ret_targ.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "get_ret_targ.h" diff --git a/sr_port/get_symb_line.c b/sr_port/get_symb_line.c index e17a4eb..b7d70de 100644 --- a/sr_port/get_symb_line.c +++ b/sr_port/get_symb_line.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "error_trap.h" /* for error_ret()/error_ret_vms() declaration */ diff --git a/sr_port/getzposition.c b/sr_port/getzposition.c index 0f8af95..8d72e83 100644 --- a/sr_port/getzposition.c +++ b/sr_port/getzposition.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "getzposition.h" diff --git a/sr_port/glvn.c b/sr_port/glvn.c index a7cb78a..0f1dd35 100644 --- a/sr_port/glvn.c +++ b/sr_port/glvn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,8 +20,9 @@ error_def(ERR_VAREXPECTED); int glvn(oprtype *a) { - triple *oldchain, *ref, tmpchain, *triptr; - oprtype x1; + triple *oldchain, *ref; + oprtype x1; + save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -37,29 +38,24 @@ int glvn(oprtype *a) *a = put_tref(newtriple(OC_GVGET)); return TRUE; case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) + if (SHIFT_SIDE_EFFECTS) { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); + START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&x1)) { setcurtchain(oldchain); return FALSE; } ref = newtriple(OC_INDGLVN); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&x1)) return FALSE; ref = newtriple(OC_INDGLVN); } + if (TREF(expr_depth)) + (TREF(side_effect_base))[TREF(expr_depth)] = (OLD_SE != TREF(side_effect_handling)); ref->operand[0] = x1; *a = put_tref(ref); return TRUE; diff --git a/sr_port/goerrorframe.c b/sr_port/goerrorframe.c index 5e90510..63b0f59 100644 --- a/sr_port/goerrorframe.c +++ b/sr_port/goerrorframe.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "tp_frame.h" #include "golevel.h" diff --git a/sr_port/goframes.c b/sr_port/goframes.c index 52a5c6c..74b695d 100644 --- a/sr_port/goframes.c +++ b/sr_port/goframes.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" /* needed for golevel.h */ +#include /* needed for golevel.h */ #include "error.h" #include "op.h" #include "stack_frame.h" /* needed for golevel.h */ diff --git a/sr_port/golevel.h b/sr_port/golevel.h index 9d47e76..8d90983 100644 --- a/sr_port/golevel.h +++ b/sr_port/golevel.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,12 +11,11 @@ #ifndef __GOLEVEL_H__ #define __GOLEVEL_H__ - - -/* golevel() will unwind up to the counted frame corresponding to level specified by the parm. In a trigger - * environment, an additional flag that determines if landing on a trigger frame means the unwind should continue - * or not is supplied. This flag is passed to goframes() which does the actual unwind of a specific number - * of frames (counted and uncounted). Note goframes is used by both golevel and goerrorframe. +/* golevel() will unwind up to the counted frame corresponding to level specified by the parm. The first flag indicates + * whether or not it is ok to land on a $ZINTERRUPT frame or not (which it is not ok when unwinding a $ZINTERRUPT). Also, + * In a trigger environment, an additional flag that determines if landing on a trigger frame means the unwind should + * continue or not is supplied. This flag is passed to goframes() which does the actual unwind of a specific number of + * rames (counted and uncounted). Note goframes is used by both golevel and goerrorframe. */ #ifdef GTM_TRIGGER #define GOLEVEL(level, unwtrigrframe) golevel(level, unwtrigrframe) @@ -26,9 +25,10 @@ void goframes(int4 frames, boolean_t unwtrigrframe, boolean_t fromzgoto); #else #define GOLEVEL(level, unwtrigrframe) golevel(level) #define GOFRAMES(frames, unwtrigrframe, fromzgoto) goframes(frames) -void golevel(int4 level); /* unwind upto the counted frame corresponding to frame level "level" */ -void goframes(int4 frames); /* unwind "frames" number of frames */ +void golevel(int4 level); /* unwind upto the counted frame corresponding to frame level "level" */ +void goframes(int4 frames); /* unwind "frames" number of frames */ #endif -void goerrorframe(void); /* unwind upto (but not including) the frame pointed to by the "error_frame" global */ - +void goerrorframe(void); /* unwind upto (but not including) the frame pointed to by the "error_frame" + * global + */ #endif diff --git a/sr_port/gtm_c_stack_trace.h b/sr_port/gtm_c_stack_trace.h index e9dc678..3c2916d 100644 --- a/sr_port/gtm_c_stack_trace.h +++ b/sr_port/gtm_c_stack_trace.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,7 +11,6 @@ #ifndef GTM_C_STACK_TRACE_H #define GTM_C_STACK_TRACE_H -#include "gtm_stdio.h" /* For SPRINTF */ #define ONCE 1 #define TWICE 2 @@ -20,93 +19,32 @@ #define GET_C_STACK_FROM_SCRIPT(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT) #define GET_C_STACK_FOR_KIP(KIP_PIDS_ARR_PTR, TRYNUM, MAX_TRY, STUCK_CNT, MAX_PID_SLOTS) #elif defined(UNIX) -#include -#include "send_msg.h" -#include "wbox_test_init.h" -#include "gt_timer.h" -#include "gtm_logicals.h" -#include "trans_log_name.h" -#ifndef GDSFHEAD_H_INCLUDED -#include "gdsroot.h" -#include "gdsbt.h" -#include "gdsfhead.h" -#endif -error_def(ERR_STUCKACT); -error_def(ERR_SYSCALL); -error_def(ERR_TEXT); +void gtm_c_stack_trace(char *message, pid_t waiting_pid, pid_t blocking_pid, uint4 count); -#define GET_C_STACK_MULTIPLE_PIDS(MESSAGE, CNL_PID_ARRAY, MAX_PID_SLOTS, STUCK_CNT) \ -{ \ - uint4 index; \ - uint4 pid; \ - GBLREF uint4 process_id; \ - \ - for (index = 0; MAX_PID_SLOTS > index; index++) \ - { \ - pid = CNL_PID_ARRAY[index]; \ - if (0 != pid) \ - GET_C_STACK_FROM_SCRIPT(MESSAGE, process_id, pid, STUCK_CNT); \ - } \ +#define GET_C_STACK_MULTIPLE_PIDS(MESSAGE, CNL_PID_ARRAY, MAX_PID_SLOTS, STUCK_CNT) \ +{ \ + uint4 index; \ + pid_t pid; \ + GBLREF uint4 process_id; \ + \ + for (index = 0; MAX_PID_SLOTS > index; index++) \ + { \ + pid = CNL_PID_ARRAY[index]; \ + if (0 != pid) \ + GET_C_STACK_FROM_SCRIPT(MESSAGE, process_id, pid, STUCK_CNT); \ + } \ } + #define GET_C_STACK_FROM_SCRIPT(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT) \ { \ - int4 messagelen, arr_len; \ - char *command; \ - char *errptr, *currpos; \ - int rs, save_errno; \ - char *gtm_waitstuck_script; \ - mstr envvar_logical, trans; \ - char buf[MAX_TRANS_NAME_LEN]; \ - int status; \ - \ - DCL_THREADGBL_ACCESS; \ - \ - SETUP_THREADGBL_ACCESS; \ - if (!(TREF(gtm_waitstuck_script)).len) \ - { \ - envvar_logical.addr = GTM_PROCSTUCKEXEC; \ - envvar_logical.len = SIZEOF(GTM_PROCSTUCKEXEC)- 1; \ - if (SS_NORMAL == (status = TRANS_LOG_NAME(&envvar_logical, &trans, buf, SIZEOF(buf), \ - do_sendmsg_on_log2long))) \ - { \ - assert(SIZEOF(buf) > trans.len); \ - if (0 != trans.len) \ - { \ - (TREF(gtm_waitstuck_script)).len = trans.len; \ - (TREF(gtm_waitstuck_script)).addr = (char *)malloc(trans.len); \ - memcpy((TREF(gtm_waitstuck_script)).addr, trans.addr, trans.len); \ - } \ - } \ - } \ - if (0 != (TREF(gtm_waitstuck_script)).len) \ - { \ - messagelen = STRLEN(MESSAGE); \ - arr_len = GTM_MAX_DIR_LEN + messagelen + 3 * SIZEOF(uint4) + 5; \ - command = (char *)malloc (arr_len); \ - memcpy(command, (TREF(gtm_waitstuck_script)).addr, (TREF(gtm_waitstuck_script)).len); \ - currpos = (char *)command + (TREF(gtm_waitstuck_script)).len; \ - *currpos++ = ' '; \ - memcpy(currpos, MESSAGE, messagelen); \ - currpos += messagelen; \ - *currpos++ = ' '; \ - SPRINTF(currpos, "%u %u %u", WAITINGPID, BLOCKINGPID, COUNT); \ - assert (STRLEN(command) < arr_len); \ - rs = SYSTEM((char *)command); \ - if (0 != rs) \ - { \ - save_errno = errno; \ - send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("FAILURE"), LEN_AND_STR(command)); \ - send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("system"), CALLFROM, save_errno); \ - } else \ - send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("SUCCESS"), LEN_AND_STR(command)); \ - free((void *)command); \ - } \ + gtm_c_stack_trace(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT); \ } + #define GET_C_STACK_FOR_KIP(KIP_PIDS_ARR_PTR, TRYNUM, MAX_TRY, STUCK_CNT, MAX_PID_SLOTS) \ { \ boolean_t invoke_c_stack = FALSE; \ - const char *kip_wait_string = NULL; \ + char *kip_wait_string = NULL; \ \ DEBUG_ONLY( \ /* If we had waited for half the max time, get a C stack trace on the processes currently \ @@ -117,7 +55,7 @@ error_def(ERR_TEXT); invoke_c_stack = TRUE; \ kip_wait_string = "KILL_IN_PROG_HALFWAIT"; \ } \ - ) \ + ) \ /* If we had waited for max time, get a C stack trace on the processes currently doing the kill \ * irrespective of whether it's pro or dbg \ */ \ @@ -127,7 +65,7 @@ error_def(ERR_TEXT); kip_wait_string = "KILL_IN_PROG_WAIT"; \ } \ if (invoke_c_stack) \ - GET_C_STACK_MULTIPLE_PIDS(kip_wait_string, KIP_PIDS_ARR_PTR, MAX_PID_SLOTS, STUCK_CNT); \ + GET_C_STACK_MULTIPLE_PIDS(kip_wait_string, KIP_PIDS_ARR_PTR, MAX_PID_SLOTS, STUCK_CNT); \ } #else diff --git a/sr_port/gtm_env_init.c b/sr_port/gtm_env_init.c index c4dc227..3c0675c 100644 --- a/sr_port/gtm_env_init.c +++ b/sr_port/gtm_env_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2012 Fidelity Information Services, Inc * + * Copyright 2004, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,6 +37,14 @@ #include "fullbool.h" #include "trace_table.h" #include "parse_trctbl_groups.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" #ifdef DEBUG # define INITIAL_DEBUG_LEVEL GDL_Simple @@ -65,6 +73,9 @@ GBLREF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object GBLREF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */ GBLREF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */ GBLREF boolean_t gtm_stdxkill; /* Use M Standard exclusive kill instead of historical GTM */ +GBLREF boolean_t ztrap_new; /* Each time $ZTRAP is set it is automatically NEW'd */ +GBLREF size_t gtm_max_storalloc; /* Used for testing: creates an allocation barrier */ +GBLREF boolean_t ipv4_only; /* If TRUE, only use AF_INET. */ void gtm_env_init(void) { @@ -76,8 +87,9 @@ void gtm_env_init(void) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (!TREF(gtm_env_init_done)) + if (!TREF(gtm_env_init_started)) { + TREF(gtm_env_init_started) = TRUE; /* See if a debug level has been specified. Do this first since gtmDebugLevel needs * to be initialized before any mallocs are done in the system. */ @@ -97,6 +109,12 @@ void gtm_env_init(void) val.addr = GTM_BOOLEAN; val.len = SIZEOF(GTM_BOOLEAN) - 1; TREF(gtm_fullbool) = trans_numeric(&val, &is_defined, TRUE); + /* gtm_boolean environment/logical */ + val.addr = GTM_SIDE_EFFECT; + val.len = SIZEOF(GTM_SIDE_EFFECT) - 1; + TREF(side_effect_handling) = trans_numeric(&val, &is_defined, TRUE); + if (!is_defined) /* default to original behavior */ + TREF(side_effect_handling) = OLD_SE; /* NOUNDEF environment/logical */ val.addr = GTM_NOUNDEF; val.len = SIZEOF(GTM_NOUNDEF) - 1; @@ -223,6 +241,13 @@ void gtm_env_init(void) memcpy((TREF(gtmprompt)).addr, trans.addr, trans.len); } } + /* Initialize tpnotacidtime */ + TREF(tpnotacidtime) = TPNOTACID_DEFAULT_TIME; + val.addr = GTM_TPNOTACIDTIME; + val.len = SIZEOF(GTM_TPNOTACIDTIME) - 1; + if ((status = trans_numeric(&val, &is_defined, TRUE)) && (0 <= status) + && (TPNOTACID_MAX_TIME >= status) && is_defined) + TREF(tpnotacidtime) = status; /* NOTE assignment above */ /* Initialize $gtm_tprestart_log_first */ val.addr = GTM_TPRESTART_LOG_LIMIT; val.len = STR_LIT_LEN(GTM_TPRESTART_LOG_LIMIT); @@ -262,8 +287,32 @@ void gtm_env_init(void) } } } +# ifdef UNIX + /* Initialize jnl_extract_nocol */ + val.addr = GTM_EXTRACT_NOCOL; + val.len = STR_LIT_LEN(GTM_EXTRACT_NOCOL); + TREF(jnl_extract_nocol) = trans_numeric(&val, &is_defined, TRUE); +# endif + /* Initialize dollar_zmaxtptime */ + val.addr = GTM_ZMAXTPTIME; + val.len = SIZEOF(GTM_ZMAXTPTIME) - 1; + if ((status = trans_numeric(&val, &is_defined, TRUE)) && (0 <= status) && (TPTIMEOUT_MAX_TIME >= status)) + TREF(dollar_zmaxtptime) = status; /* NOTE assignment above */ + /* See if $gtm_ztrap_new/GTM_ZTRAP_NEW has been specified */ + val.addr = ZTRAP_NEW; + val.len = SIZEOF(ZTRAP_NEW) - 1; + ztrap_new = logical_truth_value(&val, FALSE, NULL); + /* See if $gtm_max_storalloc is set */ + val.addr = GTM_MAX_STORALLOC; + val.len = SIZEOF(GTM_MAX_STORALLOC) - 1; + gtm_max_storalloc = trans_numeric(&val, &is_defined, TRUE); +# ifdef UNIX + /* See if gtm_ipv4_only is set */ + val.addr = GTM_IPV4_ONLY; + val.len = SIZEOF(GTM_IPV4_ONLY) - 1; + ipv4_only = logical_truth_value(&val, FALSE, NULL); +# endif /* Platform specific initializations */ gtm_env_init_sp(); - TREF(gtm_env_init_done) = TRUE; } } diff --git a/sr_port/gtm_fcntl.h b/sr_port/gtm_fcntl.h index adf6010..4976600 100644 --- a/sr_port/gtm_fcntl.h +++ b/sr_port/gtm_fcntl.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,16 +16,20 @@ #include #ifndef GTM_FD_TRACE -# define CREAT creat -# define OPEN open -# define OPEN3 open +# define CREAT creat +# define OPEN open +# define OPEN3 open #else -# define CREAT gtm_creat -# define OPEN gtm_open -# define OPEN3 gtm_open3 -# undef open /* in case this is already defined by (at least AIX and HPUX seem to do this) */ +/* Note we no longer redefine open to gtm_open because of the problems it creates requiring includes to be specified in + * a specific order (anything that includes this include must come BEFORE gdsfhead to avoid errors). This ordering was + * nearly impossible when trace flags were specified in error.h or gtm_trigger_src.h. At the time of this removal (10/2012), + * a search was completed to verify no open() calls existed that needed this support but that does not prevent new calls from + * being added. Therefore, attentiveness is required. + */ +# define CREAT gtm_creat +# define OPEN gtm_open +# define OPEN3 gtm_open3 # undef creat /* in case this is already defined by (at least AIX and HPUX seem to do this) */ -# define open gtm_open # define creat gtm_creat #endif diff --git a/sr_port/gtm_fetch.c b/sr_port/gtm_fetch.c index 6a15713..e057ddd 100644 --- a/sr_port/gtm_fetch.c +++ b/sr_port/gtm_fetch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,15 +13,29 @@ #include -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "lookup_variable_htent.h" #include "op.h" #include "lv_val.h" +#ifdef DEBUG /* all of below is needed by the gv_target/cs_addrs assert */ +#include "gdsroot.h" +#include "gdskill.h" +#include "gdsblk.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#endif + GBLREF stack_frame *frame_pointer; GBLREF symval *curr_symval; +#ifdef DEBUG GBLREF int process_exiting; +GBLREF gv_namehead *gv_target; +GBLREF sgmnt_addrs *cs_addrs; +#endif #ifdef UNIX void gtm_fetch(unsigned int cnt_arg, unsigned int indxarg, ...) @@ -40,6 +54,11 @@ void gtm_fetch(unsigned int indxarg, ...) SETUP_THREADGBL_ACCESS; assert(!process_exiting); /* Verify that no process unwound the exit frame and continued */ + DEBUG_ONLY(DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);) /* surrounding DEBUG_ONLY needed because gdsfhead.h is + * not included for pro builds and so the macro and its + * parameters would be undefined in that case causing a + * compile-time error. + */ assert(!TREF(in_zwrite)); /* Verify in_zwrite was not left on */ VAR_START(var, indxarg); VMS_ONLY(va_count(cnt);) diff --git a/sr_port/gtm_imagetype_init.c b/sr_port/gtm_imagetype_init.c index f88ae08..3f7146d 100644 --- a/sr_port/gtm_imagetype_init.c +++ b/sr_port/gtm_imagetype_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,12 +20,17 @@ GBLREF boolean_t run_time; GBLREF boolean_t write_after_image; GBLREF boolean_t dse_running; GBLREF enum gtmImageTypes image_type; +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +GBLREF boolean_t span_nodes_disallowed; +#endif void gtm_imagetype_init(enum gtmImageTypes img_type) { boolean_t is_svc_or_gtcm; NON_GTMTRIG_ONLY(skip_dbtriggers = TRUE;) /* Do not invoke triggers for trigger non-supporting platforms. */ + UNIX_ONLY(span_nodes_disallowed = (GTCM_GNP_SERVER_IMAGE == img_type) || (GTCM_SERVER_IMAGE == img_type);) is_svc_or_gtcm = ((GTM_SVC_DAL_IMAGE == img_type) || (GTCM_GNP_SERVER_IMAGE == img_type) || (GTCM_SERVER_IMAGE == img_type)); @@ -43,6 +48,11 @@ void gtm_imagetype_init(enum gtmImageTypes img_type) # ifdef UNIX else if (MUPIP_IMAGE == img_type) run_time = FALSE; + /* GT.M typically opens journal pool during the first update (in gvcst_put, gvcst_kill or op_ztrigger). But, if + * anticipatory freeze is enabled, we want to open journal pool for any reads done by GT.M as well (basically at the time + * of first database open (in gvcst_init). So, set jnlpool_init_needed to TRUE if this is GTM_IMAGE. + */ + jnlpool_init_needed = (GTM_IMAGE == img_type); # endif image_type = img_type; return; diff --git a/sr_port/gtm_inet.h b/sr_port/gtm_inet.h index 60fd19c..7f973ab 100644 --- a/sr_port/gtm_inet.h +++ b/sr_port/gtm_inet.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,9 @@ #endif #include +#ifndef __MVS__ +#include +#endif #ifdef NeedInAddrPort typedef uint32_t in_addr_t; diff --git a/sr_port/gtm_limits.h b/sr_port/gtm_limits.h index 0cb1c7c..f8fb9b9 100644 --- a/sr_port/gtm_limits.h +++ b/sr_port/gtm_limits.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2002, 2011 Fidelity Information Services, Inc * + * Copyright 2002, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,18 +19,27 @@ #include #endif -/* The value 1023 for PATH_MAX is derived using pathconf("path", _PC_PATH_MAX) on z/OS. - * Since we cant afford calling a function on each use of PATH_MAX/GTM_PATH_MAX, - * this value is hardcoded here. +/* The value 1023 for PATH_MAX is derived using pathconf("path", _PC_PATH_MAX) on z/OS and + * we figure other POSIX platforms are at least as capable if they don't define PATH_MAX. + * Since we can't afford to call a function on each use of PATH_MAX/GTM_PATH_MAX, this + * value is hardcoded here. + * + * Note on Linux (at least), PATH_MAX is actually defined in . We would include + * that here unconditionally but on AIX, param.h includes limits.h. Note that regardless of where + * it gets defined, PATH_MAX needs to be defined prior to including stdlib.h. This is because in a + * pro build, at least Linux verifies the 2nd parm of realpath() is PATH_MAX bytes or more. + * Since param.h sets PATH_MAX to 4K on Linux, this can cause structures defined as GTM_PATH_MAX + * to raise an error when used in the 2nd argument of realpath(). */ -#if defined (__MVS__) #ifndef PATH_MAX -#define PATH_MAX 1023 +# ifdef __linux__ +# include +# else +# define PATH_MAX 1023 +# endif #endif +/* Now define our version which includes space for a terminating NULL byte */ #define GTM_PATH_MAX PATH_MAX + 1 -#else -#define GTM_PATH_MAX 1024 /* includes terminating NULL */ -#endif #if defined(LLONG_MAX) /* C99 and others */ #define GTM_INT64_MIN LLONG_MIN diff --git a/sr_port/gtm_malloc.h b/sr_port/gtm_malloc.h index 62ff7fd..c8aee7b 100644 --- a/sr_port/gtm_malloc.h +++ b/sr_port/gtm_malloc.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2010 Fidelity Information Services, Inc * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,27 +16,25 @@ typedef GTM64_ONLY(gtm_uint8) NON_GTM64_ONLY(unsigned int) gtm_msize_t; -/* Each allocated block has the following structure. The actual address - returned to the user for 'malloc' and supplied by the user for 'free' - is actually the storage beginning at the 'userStorage.userStart' area. - This holds true even for storage that is truely malloc'd. Note that true - allocated length is kept even in the pro header. -*/ +/* Each allocated block has the following structure. The actual address returned to the user for 'malloc' and supplied by the + * user for 'free' is actually the storage beginning at the 'userStorage.userStart' area. This holds true even for storage + * that is truely malloc'd. Note that true allocated length is kept even in the pro header. + */ typedef struct storElemStruct -{ /* While the following chars and short are not the best for performance, they enable us - to keep the header size to 8 bytes in a pro build. This is important since our minimum - allocation size is 16 bytes leaving 8 bytes for data. Also I have not researched what - they are, there are a bunch of 8 byte allocates in GT.M that if we were to go to a 16 - byte header would make the minimum block size 32 bytes thus doubling the storage - requirements for these small blocks. SE 03/2002 [Note 16 byte header is the norm in 64 bit] - */ +{ /* While the following chars and short are not the best for performance, they enable us to keep the header size to + * 8 bytes in a pro build. This is important since our minimum allocation size is 16 bytes leaving 8 bytes for data. + * Also I have not researched what they are, there are a bunch of 8 byte allocates in GT.M that if we were to go to + * a 16 byte header would make the minimum block size 32 bytes thus doubling the storage requirements for these small + * blocks. SE 03/2002 [Note 16 byte header is the norm in 64 bit] + */ signed char queueIndex; /* Index into TwoTable for this size of element */ unsigned char state; /* State of this block */ unsigned short extHdrOffset; /* For MAXTWO sized elements: offset to the - header that describes the extent */ + * header that describes the extent. + */ GTM64_ONLY(char filler[4];) /* Explicit filler to align the length - may be repurposed */ gtm_msize_t realLen; /* Real (total) length of allocation */ -#ifdef DEBUG +# ifdef DEBUG struct storElemStruct *fPtr; /* Next storage element on free/allocated queue */ struct storElemStruct *bPtr; /* Previous storage element on free/allocated queue */ unsigned char *allocatedBy; /* Who allocated storage */ @@ -48,7 +46,7 @@ typedef struct storElemStruct struct storElemStruct *deferFreeNext; /* Pointer to next deferred free block */ unsigned char userStart; /* First byte of user useable storage */ } userStorage; -#else +# else union /* In production mode, the links are used only when element is free */ { struct storElemStruct *deferFreeNext; /* Pointer to next deferred free block */ @@ -59,7 +57,7 @@ typedef struct storElemStruct } links; unsigned char userStart; /* First byte of user useable storage */ } userStorage; -#endif +# endif } storElem; size_t gtm_bestfitsize(size_t); diff --git a/sr_port/gtm_malloc_src.h b/sr_port/gtm_malloc_src.h index 78ed04b..984b125 100644 --- a/sr_port/gtm_malloc_src.h +++ b/sr_port/gtm_malloc_src.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,27 +10,27 @@ ****************************************************************/ /* Storage manager for "smaller" pieces of storage. Uses power-of-two - "buddy" system as described by Knuth. Currently manages pieces of - size 2K - SIZEOF(header). - - This include file is included in both gtm_malloc.c and gtm_malloc_dbg.c. - See the headers of those modules for explanations of how the storage - manager build is actually accomplished. - - Debugging is controlled via the "gtmdbglvl" environment variable in - the Unix environment and the GTM$DBGLVL logical in the VMS environment. - If this variable is set to a non-zero value, the debugging environment - is enabled. The debugging features turned on will correspond to the bit - values defined gtmdbglvl.h. Note that this mechanism is versatile enough - that non-storage-managment debugging is also hooked in here. The - debugging desired is a mask for the features desired. For example, if the - value 4 is set, then tracing is enabled. If the value is set to 6, then - both tracing and statistics are enabled. Because the code is expanded - twice in a "Pro" build, these debugging features are available even - in a pro build and can thus be enabled in the field without the need for - a "debug" version to be installed in order to chase a corruption or other - problem. -*/ + * "buddy" system as described by Knuth. Currently manages pieces of + * size 2K - SIZEOF(header). + * + * This include file is included in both gtm_malloc.c and gtm_malloc_dbg.c. + * See the headers of those modules for explanations of how the storage + * manager build is actually accomplished. + * + * Debugging is controlled via the "gtmdbglvl" environment variable in + * the Unix environment and the GTM$DBGLVL logical in the VMS environment. + * If this variable is set to a non-zero value, the debugging environment + * is enabled. The debugging features turned on will correspond to the bit + * values defined gtmdbglvl.h. Note that this mechanism is versatile enough + * that non-storage-managment debugging is also hooked in here. The + * debugging desired is a mask for the features desired. For example, if the + * value 4 is set, then tracing is enabled. If the value is set to 6, then + * both tracing and statistics are enabled. Because the code is expanded + * twice in a "Pro" build, these debugging features are available even + * in a pro build and can thus be enabled in the field without the need for + * a "debug" version to be installed in order to chase a corruption or other + * problem. + */ #include "mdef.h" /* If this is a pro build (meaning PRO_BUILD is defined), avoid the memcpy() override. That code is only @@ -71,6 +71,7 @@ #include "cache.h" #include "gtm_malloc.h" #include "have_crit.h" +#include "gtm_env_init.h" #ifdef UNIX # include "gtmio.h" # include "deferred_signal_handler.h" @@ -111,48 +112,62 @@ #ifdef VMS /* These routines for VMS are AST-safe */ -# define MALLOC(size, addr) \ -{ \ - int msize, errnum; \ - void *maddr; \ - msize = size; \ - errnum = lib$get_vm(&msize, &maddr); \ - if (SS$_NORMAL != errnum) \ - { \ - gtmMallocErrorSize = size; \ - gtmMallocErrorCallerid = CALLERID; \ - gtmMallocErrorErrno = errnum; \ - raise_gtmmemory_error(); \ - } \ - addr = (void *)maddr; \ +# define MALLOC(size, addr) \ +{ \ + int msize, errnum; \ + void *maddr; \ + if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \ + { /* Boundary check for $gtm_max_storalloc (if set) */ \ + gtmMallocErrorSize = size; \ + gtmMallocErrorCallerid = CALLERID; \ + gtmMallocErrorErrno = ERR_MALLOCMAXVMS; \ + raise_gtmmemory_error(); \ + } \ + msize = size; \ + errnum = lib$get_vm(&msize, &maddr); \ + if (SS$_NORMAL != errnum) \ + { \ + gtmMallocErrorSize = size; \ + gtmMallocErrorCallerid = CALLERID; \ + gtmMallocErrorErrno = errnum; \ + raise_gtmmemory_error(); \ + } \ + addr = (void *)maddr; \ } -# define FREE(size, addr) \ -{ \ - int msize, errnum; \ - void *maddr; \ - msize = size; \ - maddr = addr; \ - errnum = lib$free_vm(&msize, &maddr); \ - if (SS$_NORMAL != errnum) \ - { \ - --gtmMallocDepth; \ - assert(FALSE); \ - rts_error(VARLSTCNT(4) ERR_FREEMEMORY, 1, CALLERID, errnum); \ - } \ +# define FREE(size, addr) \ +{ \ + int msize, errnum; \ + void *maddr; \ + msize = size; \ + maddr = addr; \ + errnum = lib$free_vm(&msize, &maddr); \ + if (SS$_NORMAL != errnum) \ + { \ + --gtmMallocDepth; \ + assert(FALSE); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEMEMORY, 1, CALLERID, errnum); \ + } \ } # define GTM_MALLOC_REENT #else /* These routines for Unix are NOT thread-safe */ -# define MALLOC(size, addr) \ -{ \ - addr = (void *)malloc(size); \ - if (NULL == (void *)addr) \ - { \ - gtmMallocErrorSize = size; \ - gtmMallocErrorCallerid = CALLERID; \ - gtmMallocErrorErrno = errno; \ - raise_gtmmemory_error(); \ - } \ +# define MALLOC(size, addr) \ +{ \ + if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \ + { /* Boundary check for $gtm_max_storalloc (if set) */ \ + gtmMallocErrorSize = size; \ + gtmMallocErrorCallerid = CALLERID; \ + gtmMallocErrorErrno = ERR_MALLOCMAXUNIX; \ + raise_gtmmemory_error(); \ + } \ + addr = (void *)malloc(size); \ + if (NULL == (void *)addr) \ + { \ + gtmMallocErrorSize = size; \ + gtmMallocErrorCallerid = CALLERID; \ + gtmMallocErrorErrno = errno; \ + raise_gtmmemory_error(); \ + } \ } # define FREE(size, addr) free(addr); #endif @@ -163,36 +178,11 @@ # define GMR_ONLY(statement) # define NON_GMR_ONLY(statement) statement #endif - -#ifdef DEBUG -/* States a storage element may be in. Debug version has values less likely to occur naturally - although the possibilities are limited with only one byte of information. */ -enum ElemState {Allocated = 0x42, Free = 0x24}; -#else -enum ElemState {Allocated = 1, Free}; /* 0 is just "too commonly occurring" */ -#endif - -/* At the end of each block is this header which is used to track when all of the elements that - a block of real allocated storage was broken into have become free. At that point, we can return - the chunk to the OS. -*/ -typedef struct storExtHdrStruct -{ - struct - { - struct storExtHdrStruct *fl, *bl; /* In case we need to visit the entire list */ - } links; - unsigned char *extentStart; /* First byte of real extent (not aligned) */ - storElem *elemStart; /* Start of array of MAXTWO elements */ - int elemsAllocd; /* MAXTWO sized element count. When 0 this block is free */ -} storExtHdr; - #define MAXTWO 2048 /* How many "MAXTWO" elements to allocate at one time. This minimizes the waste since our subblocks must - be aligned on a suitable power of two boundary for the buddy-system to work properly -*/ + * be aligned on a suitable power of two boundary for the buddy-system to work properly. + */ #define ELEMS_PER_EXTENT 16 - #define MAXDEFERQUEUES 10 #ifdef DEBUG # define STOR_EXTENTS_KEEP 1 /* Keep only one extent in debug for maximum testing */ @@ -207,32 +197,13 @@ typedef struct storExtHdrStruct # define STE_FP(p) p->userStorage.links.fPtr # define STE_BP(p) p->userStorage.links.bPtr #endif -/* Our extent must be aligned on a MAXTWO byte boundary hence we allocate one more extent than - we actually want so we can be guarranteed usable storage. However if that allocation actually - starts on a MAXTWO boundary (on guarranteed 8 byte boundary), then we get an extra element. - Here we define our extent size and provide an initial sanity value for "extent_used". If the - allocator ever gets this extra block, this field will be increased by the size of one element - to compensate. -*/ -#define EXTENT_SIZE ((MAXTWO * (ELEMS_PER_EXTENT + 1)) + SIZEOF(storExtHdr)) -static unsigned int extent_used = (MAXTWO * ELEMS_PER_EXTENT + SIZEOF(storExtHdr)); /* Following are values used in queueIndex in a storage element. Note that both - values must be less than zero for the current code to function correctly. */ + * values must be less than zero for the current code to function correctly. + */ #define QUEUE_ANCHOR -1 #define REAL_MALLOC -2 - /* Define number of malloc and free calls we will keep track of */ #define MAXSMTRACE 128 - -/* Structure where malloc and free call trace information is kept */ -typedef struct -{ - unsigned char *smAddr; /* Addr allocated or released */ - unsigned char *smCaller; /* Who called malloc/free */ - gtm_msize_t smSize; /* Size allocated or freed */ - gtm_msize_t smTn; /* What transaction it was */ -} smTraceItem; - #ifdef DEBUG # define INCR_CNTR(x) ++x # define INCR_SUM(x, y) x += y @@ -265,17 +236,28 @@ typedef struct # else # define DEBUGSM(x) #endif +/* Macro to return an index into the TwoTable for a given size (round up to next power of two) + * Use the size2Index table to get the proper index. This table is indexed by the number of + * storage "blocks" being requested. A storage block is the size of the smallest power of two + * block we can allocate (size MINTWO). + */ +#ifdef DEBUG +# define GetSizeIndex(size) (size ? size2Index[(size - 1) / MINTWO] : assert(FALSE)) +#else +# define GetSizeIndex(size) (size2Index[(size - 1) / MINTWO]) +#endif /* Note we use unsigned char * instead of caddr_t for all references to caller_id so the caller id - is always 4 bytes. On Tru64, caddr_t is 8 bytes which will throw off the size of our - storage header in debug mode */ + * is always 4 bytes. On Tru64, caddr_t is 8 bytes which will throw off the size of our + * storage header in debug mode. + */ #ifdef GTM_MALLOC_DEBUG # define CALLERID (smCallerId) #else # define CALLERID ((unsigned char *)caller_id()) #endif - /* Define "routines" to enqueue and dequeue storage elements. Use define so we don't - have to depend on each implementation's compiler inlining to get efficient code here */ + * have to depend on each implementation's compiler inlining to get efficient code here. + */ #define ENQUEUE_STOR_ELEM(qtype, idx, elem) \ { \ storElem *qHdr, *fElem; \ @@ -286,14 +268,12 @@ typedef struct INCR_CNTR(qtype##ElemCnt[idx]); \ SET_ELEM_MAX(qtype, idx); \ } - #define DEQUEUE_STOR_ELEM(qtype, elem) \ { \ STE_FP(STE_BP(elem)) = STE_FP(elem); \ STE_BP(STE_FP(elem)) = STE_BP(elem); \ DECR_CNTR(qtype##ElemCnt[elem->queueIndex]); \ } - #define GET_QUEUED_ELEMENT(sizeIndex, uStor, qHdr, sEHdr) \ { \ qHdr = &freeStorElemQs[sizeIndex]; \ @@ -310,7 +290,6 @@ typedef struct uStor = findStorElem(sizeIndex); \ assert(0 == ((unsigned long)uStor & (TwoTable[sizeIndex] - 1))); /* Verify alignment */ \ } - #ifdef INT8_SUPPORTED # define ChunkSize 8 # define ChunkType gtm_int64_t @@ -321,6 +300,39 @@ typedef struct # define ChunkValue 0xdeadbeef #endif #define AddrMask (ChunkSize - 1) +/* States that storage can be in (although the possibilities are limited with only one byte of information) */ +enum ElemState {Allocated = 0x42, Free = 0x24}; +/* At the end of each super-block is this header which is used to track when all of the elements that + * a block of real allocated storage was broken into have become free. At that point, we can return + * the chunk to the OS. + */ +typedef struct storExtHdrStruct +{ + struct + { + struct storExtHdrStruct *fl, *bl; /* In case we need to visit the entire list */ + } links; + unsigned char *extentStart; /* First byte of real extent (not aligned) */ + storElem *elemStart; /* Start of array of MAXTWO elements */ + int elemsAllocd; /* MAXTWO sized element count. When 0 this block is free */ +} storExtHdr; +/* Structure where malloc and free call trace information is kept */ +typedef struct +{ + unsigned char *smAddr; /* Addr allocated or released */ + unsigned char *smCaller; /* Who called malloc/free */ + gtm_msize_t smSize; /* Size allocated or freed */ + gtm_msize_t smTn; /* What transaction it was */ +} smTraceItem; +/* Our extent must be aligned on a MAXTWO byte boundary hence we allocate one more extent than + * we actually want so we can be guarranteed usable storage. However if that allocation actually + * starts on a MAXTWO boundary (on guarranteed 8 byte boundary), then we get an extra element. + * Here we define our extent size and provide an initial sanity value for "extent_used". If the + * allocator ever gets this extra block, this field will be increased by the size of one element + * to compensate. + */ +#define EXTENT_SIZE ((MAXTWO * (ELEMS_PER_EXTENT + 1)) + SIZEOF(storExtHdr)) +static unsigned int extent_used = ((MAXTWO * ELEMS_PER_EXTENT) + SIZEOF(storExtHdr)); #ifdef DEBUG /* For debug builds, keep track of the last MAXSMTRACE mallocs and frees. */ @@ -331,24 +343,25 @@ GBLDEF smTraceItem smFrees[MAXSMTRACE]; /* Array of recent releasers */ GBLDEF volatile unsigned int smTn; /* Storage management (wrappable) transaction number */ GBLDEF unsigned int outOfMemorySmTn; /* smTN when ran out of memory */ #endif - GBLREF uint4 gtmDebugLevel; /* Debug level (0 = using default sm module so with - a DEBUG build, even level 0 implies basic debugging) */ + * a DEBUG build, even level 0 implies basic debugging) + */ GBLREF int process_exiting; /* Process is on it's way out */ GBLREF volatile int4 gtmMallocDepth; /* Recursion indicator. Volatile so it gets stored immediately */ GBLREF volatile void *outOfMemoryMitigation; /* Reserve that we will freed to help cleanup if run out of memory */ GBLREF uint4 outOfMemoryMitigateSize; /* Size of above reserve in Kbytes */ GBLREF int mcavail; GBLREF mcalloc_hdr *mcavailptr, *mcavailbase; +GBLREF size_t totalRallocGta; /* Size allocated by gtm_text_alloc if at all */ +GBLREF size_t gtm_max_storalloc; /* Max value for $ZREALSTOR or else memory error is raised */ GBLREF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */ UNIX_ONLY(GBLREF ch_ret_type (*ht_rhash_ch)();) /* Function pointer to hashtab_rehash_ch */ UNIX_ONLY(GBLREF ch_ret_type (*jbxm_dump_ch)();) /* Function pointer to jobexam_dump_ch */ +UNIX_ONLY(GBLREF ch_ret_type (*stpgc_ch)();) /* Function pointer to stp_gcol_ch */ /* This var allows us to call ourselves but still have callerid info */ GBLREF unsigned char *smCallerId; /* Caller of top level malloc/free */ GBLREF volatile int4 fast_lock_count; /* Stop stale/epoch processing while we have our parts exposed */ - OS_PAGE_SIZE_DECLARE - #define SIZETABLEDIM MAXTWO/MINTWO STATICD int size2Index[SIZETABLEDIM]; @@ -364,20 +377,18 @@ GBLRDEF readonly struct unsigned char nullTMark[4]; } NullStruct #ifdef DEBUG - /* Note, tiz important the first 4 bytes of this are same as markerChar defined below as that is the value both nullHMark - * and nullTMark are asserted against to validate against corruption. - */ - = {0xde, 0xad, 0xbe, 0xef, 0x00, 0xde, 0xad, 0xbe, 0xef} +/* Note, tiz important the first 4 bytes of this are same as markerChar defined below as that is the value both nullHMark + * and nullTMark are asserted against to validate against corruption. + */ += {0xde, 0xad, 0xbe, 0xef, 0x00, 0xde, 0xad, 0xbe, 0xef} #endif - ; - +; #ifdef DEBUG /* Arrays allocated with size of MAXINDEX + 2 are sized to hold an extra * entry for "real malloc" type allocations. Note that the arrays start with * the next larger element with GTM64 due to increased overhead from the * 8 byte pointers. */ - STATICD readonly uint4 TwoTable[MAXINDEX + 2] = { # ifndef GTM64 64, @@ -398,15 +409,14 @@ STATICD readonly uint4 TwoTable[MAXINDEX + 2] = { #endif STATICD storElem freeStorElemQs[MAXINDEX + 1]; /* Need full element as queue anchor for dbl-linked - list since ptrs not at top of element */ + * list since ptrs not at top of element. + */ STATICD storExtHdr storExtHdrQ; /* List of storage blocks we allocate here */ STATICD uint4 curExtents; /* Number of current extents */ - #ifdef GTM_MALLOC_REENT STATICD storElem *deferFreeQueues[MAXDEFERQUEUES]; /* Where deferred (nested) frees are queued for later processing */ STATICD boolean_t deferFreeExists; /* A deferred free is pending on a queue */ #endif - #ifdef DEBUG STATICD storElem allocStorElemQs[MAXINDEX + 2]; /* The extra element is for queueing "real" malloc'd entries */ # ifdef INT8_SUPPORTED @@ -419,7 +429,6 @@ STATICD readonly unsigned char backfillMarkC[4] = {0xde, 0xad, 0xbe, 0xef}; GBLREF size_t totalRmalloc; /* Total storage currently (real) malloc'd (includes extent blocks) */ GBLREF size_t totalAlloc; /* Total allocated (includes allocation overhead but not free space */ GBLREF size_t totalUsed; /* Sum of user allocated portions (totalAlloc - overhead) */ - #ifdef DEBUG /* Define variables used to instrument how our algorithm works */ STATICD uint4 totalMallocs; /* Total malloc requests */ @@ -443,18 +452,10 @@ error_def(ERR_INVMEMRESRV); error_def(ERR_MEMORYRECURSIVE); UNIX_ONLY(error_def(ERR_MEMORY);) UNIX_ONLY(error_def(ERR_SYSCALL);) +UNIX_ONLY(error_def(ERR_MALLOCMAXUNIX);) VMS_ONLY(error_def(ERR_FREEMEMORY);) VMS_ONLY(error_def(ERR_VMSMEMORY);) - -/* Macro to return an index into the TwoTable for a given size (round up to next power of two) - Use the size2Index table to get the proper index. This table is indexed by the number of - storage "blocks" being requested. A storage block is the size of the smallest power of two - block we can allocate (size MINTWO) */ -#ifdef DEBUG -# define GetSizeIndex(size) (size ? size2Index[(size - 1) / MINTWO] : assert(FALSE)) -#else -# define GetSizeIndex(size) (size2Index[(size - 1) / MINTWO]) -#endif +VMS_ONLY(error_def(ERR_MALLOCMAXVMS);) /* Internal prototypes */ void gtmSmInit(void); @@ -478,27 +479,39 @@ VMS_ONLY(error_def(ERR_VMSMEMORY);) UNIX_ONLY(error_def(ERR_SYSCALL);) /* Initialize the storage manangement system. Things to initialize: - - - Initialize size2Index table. This table is used to convert a malloc request size - to a storage queue index. - - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we - build a circular queue. This allows elements to be added and removed without - end-of-queue special casing. The queue anchor element is easily recognized because - it's queue index size will be set to a special value. - - Initialize debug mode. See if gtm_debug_level environment variable is set and - retrieve it's value if yes. -*/ + * + * - Initialize size2Index table. This table is used to convert a malloc request size + * to a storage queue index. + * - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we + * build a circular queue. This allows elements to be added and removed without + * end-of-queue special casing. The queue anchor element is easily recognized because + * it's queue index size will be set to a special value. + * - Initialize debug mode. See if gtm_debug_level environment variable is set and + * retrieve it's value if yes. + */ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_malloc_dbg.c */ { char *ascNum; storElem *uStor; int i, sizeIndex, testSize, blockSize, save_errno; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; + /* If this routine is entered and environment vars have not yet been processed with a call to gtm_env_init(), + * then do this now. Since this will likely trigger a call to this routine *again*, verify if we still need + * to do this and if not, just return. + */ + if (!TREF(gtm_env_init_started)) + { + gtm_env_init(); + if (gtmSmInitialized) + return; /* A nested call took care of this already so we're done! */ + } /* WARNING!! Since this is early initialization, the following asserts are not well behaved if they do - indeed trip. The best that can be hoped for is they give a condition handler exhausted error on - GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices - are setup nor (potentially) most of the GTM runtime. - */ + * indeed trip. The best that can be hoped for is they give a condition handler exhausted error on + * GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices + * are setup nor (potentially) most of the GTM runtime. + */ assert(MINTWO == TwoTable[0]); # if defined(__linux__) && !defined(__i386) /* This will make sure that all the memory allocated using 'malloc' will be in heap and no 'mmap' is used. @@ -510,10 +523,9 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo mallopt(M_MMAP_MAX, 0); # endif /* __linux__ && !__i386 */ /* Check that the storage queue offset in a storage element has sufficient reach - to cover an extent. - */ + * to cover an extent. + */ assert(((extent_used - SIZEOF(storExtHdr)) <= ((1 << (SIZEOF(uStor->extHdrOffset) * 8)) - 1))); - /* Initialize size table used to get a storage queue index */ sizeIndex = 0; testSize = blockSize = MINTWO; @@ -523,7 +535,6 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo ++sizeIndex; size2Index[i] = sizeIndex; } - /* Need to initialize the fwd/bck ptrs in the anchors to point to themselves */ for (uStor = &freeStorElemQs[0], i = 0; i <= MAXINDEX; ++i, ++uStor) { @@ -538,14 +549,13 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo } ); dqinit(&storExtHdrQ, links); - /* One last task before we consider ourselves initialized. Allocate the out-of-memory mitigation storage - that we will hold onto but not use. If we get an out-of-memory error, this storage will be released back - to the OS for it or GTM to use as necessary while we try to go about an orderly shutdown of our process. - The term "release" here means a literal release. The thinking is we don't know whether GTM's small storage - manager will make use of this storage (32K at a time) or if a larger malloc() will be done by libc for - buffers or what not so we will just give this chunk back to the OS to use as it needs it. - */ + * that we will hold onto but not use. If we get an out-of-memory error, this storage will be released back + * to the OS for it or GTM to use as necessary while we try to go about an orderly shutdown of our process. + * The term "release" here means a literal release. The thinking is we don't know whether GTM's small storage + * manager will make use of this storage (32K at a time) or if a larger malloc() will be done by libc for + * buffers or what not so we will just give this chunk back to the OS to use as it needs it. + */ if (0 < outOfMemoryMitigateSize) { assert(NULL == outOfMemoryMitigation); @@ -553,7 +563,7 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo if (NULL == outOfMemoryMitigation) { save_errno = errno; - gtm_putmsg(VARLSTCNT(5) ERR_INVMEMRESRV, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_INVMEMRESRV, 2, RTS_ERROR_LITERAL(UNIX_ONLY("$gtm_memory_reserve")VMS_ONLY("GTM_MEMORY_RESERVE")), save_errno); exit(save_errno); @@ -563,12 +573,13 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo } /* Recursive routine used to obtain an element on a given size queue. If no - elements of that size are available, we recursively call ourselves to get - an element of the next larger queue which we will then split in half to - get the one we need and place the remainder back on the free queue of its - new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of - storage, carve it up into the largest block size we handle and process as - before. */ + * elements of that size are available, we recursively call ourselves to get + * an element of the next larger queue which we will then split in half to + * get the one we need and place the remainder back on the free queue of its + * new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of + * storage, carve it up into the largest block size we handle and process as + * before. + */ storElem *findStorElem(int sizeIndex) /* Note renamed to findStorElem_dbg when included in gtm_malloc_dbg.c */ { unsigned char *uStorAlloc; @@ -582,9 +593,9 @@ storElem *findStorElem(int sizeIndex) /* Note renamed to findStorElem_dbg when i if (MAXINDEX >= sizeIndex) { /* We have more queues to search */ GET_QUEUED_ELEMENT(sizeIndex, uStor, qHdr, sEHdr); - /* We have a larger than necessary element now so break it in half and put - the second half on the queue one size smaller than us */ + * the second half on the queue one size smaller than us. + */ INCR_CNTR(elemSplits[sizeIndex]); --sizeIndex; /* Dealing now with smaller element queue */ assert(sizeIndex >= 0 && sizeIndex < MAXINDEX); @@ -605,8 +616,8 @@ storElem *findStorElem(int sizeIndex) /* Note renamed to findStorElem_dbg when i SET_MAX(maxExtents, curExtents); INCR_CNTR(totalExtents); /* Allocate size for one more subblock than we want. This guarrantees us that we can put our subblocks - on a power of two boundary necessary for buddy alignment - */ + * on a power of two boundary necessary for buddy alignment. + */ MALLOC(EXTENT_SIZE, uStorAlloc); uStor2 = (storElem *)uStorAlloc; /* Make addr "MAXTWO" byte aligned */ @@ -615,11 +626,10 @@ storElem *findStorElem(int sizeIndex) /* Note renamed to findStorElem_dbg when i SET_MAX(rmallocMax, totalRmalloc); sEHdr = (storExtHdr *)((char *)uStor + (ELEMS_PER_EXTENT * MAXTWO)); DEBUGSM(("debugsm: Allocating extent at 0x%08lx\n", uStor)); - /* If the storage given to us was aligned, we have ELEMS_PER_EXTENT+1 blocks, else we have - ELEMS_PER_EXTENT blocks. We won't put the first element on the queue since that block is - being returned to be split. - */ + * ELEMS_PER_EXTENT blocks. We won't put the first element on the queue since that block is + * being returned to be split. + */ if (uStor == uStor2) { i = 0; /* The storage was suitably aligned, we get an extra block free */ @@ -672,11 +682,13 @@ void processDeferredFrees() /* Note renamed to processDeferredFrees_dbg when inc { deferFreeExists = FALSE; /* Run queue in reverse order so we can process the highest index queues first freeing them - up that much sooner. This eliminates the problem of index creep. */ + * up that much sooner. This eliminates the problem of index creep. + */ for (dqIndex = MAXDEFERQUEUES - 1; 0 <= dqIndex; --dqIndex) { /* Check if queue is empty or not once outside of the gtmMallocDepth lock 'cause - we don't want to get the lock unless we really need to */ + * we don't want to get the lock unless we really need to. + */ if (deferFreeQueues[dqIndex]) { gtmMallocDepth = dqIndex + 2; @@ -694,7 +706,6 @@ void processDeferredFrees() /* Note renamed to processDeferredFrees_dbg when inc } #endif - /* Note, if the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */ /* Obtain free storage of the given size */ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in gtm_malloc_dbg.c */ @@ -709,20 +720,21 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. - If it has, we are in the wrong module Jack. This IF is structured so that - if this is the normal (default/optimized) case we will fall into the code - and handle the rerouting at the end. */ + * If it has, we are in the wrong module Jack. This IF is structured so that + * if this is the normal (default/optimized) case we will fall into the code + * and handle the rerouting at the end. + */ if (GDL_None == gtmDebugLevel) { # endif /* Note that this if is also structured for maximum fallthru. The else will - be near the end of this entry point */ + * be near the end of this entry point. + */ if (gtmSmInitialized) { hdrSize = OFFSETOF(storElem, userStorage); /* Size of storElem header */ - NON_GTM64_ONLY(if ((size + hdrSize) < size) GTMASSERT); /* Check for wrap in 32 bit platforms */ + NON_GTM64_ONLY(assertpro((size + hdrSize) >= size)); /* Check for wrap in 32 bit platforms */ assert((hdrSize + SIZEOF(markerChar)) < MINTWO); - NON_GMR_ONLY(fast_lock_count++); ++gtmMallocDepth; /* Nesting depth of memory calls */ reentered = (1 < gtmMallocDepth); @@ -731,7 +743,7 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in { --gtmMallocDepth; assert(FALSE); - rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } ); INCR_CNTR(totalMallocs); @@ -797,7 +809,8 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in DEBUG_ONLY(sizeIndex = MAXINDEX + 1); /* Just so the ENQUEUE below has a queue since * we use -1 as the "real" queueindex for * malloc'd storage and we don't record allocated - * storage in other than debug mode. */ + * storage in other than debug mode. + */ } totalUsed += DEBUG_ONLY(size) PRO_ONLY(tSize); totalAlloc += tSize; @@ -818,8 +831,7 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in backfill(trailerMarker + SIZEOF(markerChar), (uStor->realLen - size - hdrSize - SIZEOF(markerChar))); } - - uStor->smTn = smTn; /* transaction number */ + uStor->smTn = smTn; /* Transaction number */ GMR_ONLY(if (!reentered)) { ENQUEUE_STOR_ELEM(alloc, sizeIndex, uStor); @@ -848,7 +860,6 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in smMallocs[smLastMallocIndex].smTn = smTn; ); TRACE_MALLOC(retVal, size, smTn); - --gtmMallocDepth; GMR_ONLY( /* Check on deferred frees */ @@ -862,10 +873,10 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in { gtmSmInit(); /* Reinvoke gtm_malloc now that we are initialized. Note that this one time (the first - call to malloc), we will not record the proper caller id in the storage header or in - the traceback table. The caller will show up as gtm_malloc(). However, all subsequent - calls will be correct. - */ + * call to malloc), we will not record the proper caller id in the storage header or in + * the traceback table. The caller will show up as gtm_malloc(). However, all subsequent + * calls will be correct. + */ return (void *)gtm_malloc(size); } # ifndef DEBUG @@ -889,32 +900,32 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. - If it has, we are in the wrong module Jack. This IF is structured so that - if this is the normal (optimized) case we will fall into the code and - handle the rerouting at the end. */ + * If it has, we are in the wrong module Jack. This IF is structured so that + * if this is the normal (optimized) case we will fall into the code and + * handle the rerouting at the end. + */ if (GDL_None == gtmDebugLevel) { # endif - if (!gtmSmInitialized) /* Storage must be init'd before can free anything */ - GTMASSERT; + assertpro(gtmSmInitialized); /* Storage must be init'd before can free anything */ /* If we are exiting, don't bother with frees. Process destruction can do it *UNLESS* we are handling an - out of memory condition with the proviso that we can't return memory if we are already nested */ + * out of memory condition with the proviso that we can't return memory if we are already nested. + */ if (process_exiting && (0 != gtmMallocDepth || error_condition != UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY))) return; NON_GMR_ONLY(++fast_lock_count); ++gtmMallocDepth; /* Recursion indicator */ - # ifdef GTM_MALLOC_REENT /* If we are attempting to do a reentrant free, we will instead put the free on a queue to be released - at a later time. Ironically, since we cannot be sure of any queues of available blocks, we have to - malloc a small block to carry this info which we will free with the main storage */ + * at a later time. Ironically, since we cannot be sure of any queues of available blocks, we have to + * malloc a small block to carry this info which we will free with the main storage. + */ if (1 < gtmMallocDepth) { if ((unsigned char *)addr != &NullStruct.nullStr[0]) { dqIndex = gtmMallocDepth - 2; /* 0 origin index into defer queues */ - if (MAXDEFERQUEUES <= dqIndex) /* Can't run out of queues */ - GTMASSERT; + assertpro(MAXDEFERQUEUES > dqIndex); /* Can't run out of queues */ hdrSize = offsetof(storElem, userStorage); uStor = (storElem *)((unsigned long)addr - hdrSize); /* Backup ptr to element header */ uStor->userStorage.deferFreeNext = deferFreeQueues[dqIndex]; @@ -930,11 +941,10 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m { --gtmMallocDepth; assert(FALSE); - rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } # endif INCR_CNTR(smTn); /* Bump the transaction number */ - /* Validate null string not overwritten */ assert(0 == memcmp(&NullStruct.nullHMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); assert(0 == memcmp(&NullStruct.nullTMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); @@ -953,10 +963,10 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m TRACE_FREE(addr, uStor->allocLen, smTn); saveSize = uStor->allocLen; /* Extra checking for debugging. Note that these sanity checks are only done in debug - mode. The thinking is that we will bypass the checks in the general case for speed but - if we really need to chase a storage related problem, we should switch to the debug version - in the field to turn on these and other checks. - */ + * mode. The thinking is that we will bypass the checks in the general case for speed but + * if we really need to chase a storage related problem, we should switch to the debug version + * in the field to turn on these and other checks. + */ assert(Allocated == uStor->state); assert(0 == memcmp(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker))); trailerMarker = (unsigned char *)&uStor->userStorage.userStart + uStor->allocLen;/* Where trailer was put */ @@ -966,7 +976,6 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m assert(backfillChk(trailerMarker + SIZEOF(markerChar), (uStor->realLen - uStor->allocLen - hdrSize - SIZEOF(markerChar)))); } - /* Remove element from allocated queue unless element is from a reentered malloc call. In that case, just * manipulate the counters. */ @@ -976,7 +985,7 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m { DEQUEUE_STOR_ELEM(alloc, uStor); } else - { /* shenanigans so that counts are maintained properly in debug mode */ + { /* Shenanigans so that counts are maintained properly in debug mode */ saveIndex = uStor->queueIndex; uStor->queueIndex = MAXINDEX + 1; DEQUEUE_STOR_ELEM(alloc, uStor); @@ -991,11 +1000,13 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m assert(0 == ((unsigned long)uStor & (TwoTable[sizeIndex] - 1))); /* Verify alignment */ assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); uStor->state = Free; + DEBUG_ONLY(uStor->smTn = smTn); /* For freed blocks, set Tn when were freed */ INCR_CNTR(freeCnt[sizeIndex]); assert(uStor->realLen == TwoTable[sizeIndex]); totalAlloc -= TwoTable[sizeIndex]; /* First, if there are larger queues than this one, see if it has a buddy that it can - combine with */ + * combine with. + */ while (sizeIndex < MAXINDEX) { buddyElem = (storElem *)((unsigned long)uStor ^ TwoTable[sizeIndex]);/* Address of buddy */ @@ -1027,11 +1038,11 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m --sEHdr->elemsAllocd; assert(0 <= sEHdr->elemsAllocd); /* Check for an extent being ripe for return to the system. Requirements are: - 1) All subblocks must be free (elemsAllocd == 0). - 2) There must be more than STOR_EXTENTS_KEEP extents already allocated. - If these conditions are met, we will dequeue each individual element from - it's queue and release the entire extent in a (real) free. - */ + * 1) All subblocks must be free (elemsAllocd == 0). + * 2) There must be more than STOR_EXTENTS_KEEP extents already allocated. + * If these conditions are met, we will dequeue each individual element from + * it's queue and release the entire extent in a (real) free. + */ if (STOR_EXTENTS_KEEP < curExtents && 0 == sEHdr->elemsAllocd) { /* Release this extent */ DEBUGSM(("debugsm: Extent being freed from 0x%08lx\n", sEHdr->elemStart)); @@ -1055,7 +1066,6 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m assert(curExtents); } } - } else { assert(REAL_MALLOC == sizeIndex); /* Better be a real malloc type block */ @@ -1091,8 +1101,8 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m # ifndef DEBUG } else { /* If not a debug module and debugging is enabled, reroute call to - the debugging version. - */ + * the debugging version. + */ smCallerId = (unsigned char *)caller_id(); gtm_free_dbg(addr); } @@ -1100,10 +1110,9 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m DEFERRED_EXIT_HANDLING_CHECK; } - /* When an out-of-storage type error is encountered, besides releasing our memory reserve, we also - want to release as much unused storage within various GTM queues that we can find. -*/ + * want to release as much unused storage within various GTM queues that we can find. + */ void release_unused_storage(void) /* Note renamed to release_unused_storage_dbg when included in gtm_malloc_dbg.c */ { mcalloc_hdr *curhdr, *nxthdr; @@ -1125,62 +1134,61 @@ void release_unused_storage(void) /* Note renamed to release_unused_storage_dbg (*cache_table_relobjs)(); /* Release object code in indirect cache */ } - /* Raise ERR_MEMORY or ERR_VMSMEMORY. Separate routine since is called from hashtable logic in place of the - previous HTEXPFAIL error message. As such, it checks and properly deals with which flavor is running - (debug or non-debug). -*/ + * previous HTEXPFAIL error message. As such, it checks and properly deals with which flavor is running + * (debug or non-debug). + */ void raise_gtmmemory_error(void) /* Note renamed to raise_gtmmemory_error_dbg when included in gtm_malloc_dbg.c */ { void *addr; # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. - If it has, we are in the wrong module Jack. This IF is structured so that - if this is the normal (optimized) case we will fall into the code and - handle the rerouting at the end. - - Note: The DEBUG expansion of this code in a pro build actually has a different - entry point name (raise_gtmmeory_error_dbg) and if malloc debugging options are - on in pro, we need to call that version, but since efficiency in pro trumps - clarity, we put the redirecting call at the bottom of the if-else block to - avoid disrupting the instruction pipeline. - */ + * If it has, we are in the wrong module Jack. This IF is structured so that + * if this is the normal (optimized) case we will fall into the code and + * handle the rerouting at the end. + * + * Note: The DEBUG expansion of this code in a pro build actually has a different + * entry point name (raise_gtmmeory_error_dbg) and if malloc debugging options are + * on in pro, we need to call that version, but since efficiency in pro trumps + * clarity, we put the redirecting call at the bottom of the if-else block to + * avoid disrupting the instruction pipeline. + */ if (GDL_None == gtmDebugLevel) { # endif - if (NULL != (addr = (void *)outOfMemoryMitigation) - UNIX_ONLY(&& !(ht_rhash_ch == active_ch->ch || jbxm_dump_ch == active_ch->ch || stp_gcol_ch == active_ch->ch))) - { /* Free our reserve only if not in certain condition handlers (on UNIX) since it is */ - /* going to unwind this error and ignore it. On VMS the error will not be trapped */ + if (NULL != (addr = (void *)outOfMemoryMitigation) /* Note assignment */ + UNIX_ONLY(&& !(ht_rhash_ch == active_ch->ch || jbxm_dump_ch == active_ch->ch || stpgc_ch == active_ch->ch))) + { /* Free our reserve only if not in certain condition handlers (on UNIX) since it is + * going to unwind this error and ignore it. On VMS the error will not be trapped. + */ outOfMemoryMitigation = NULL; UNIX_ONLY(free(addr)); VMS_ONLY(lib$free_vm(addr)); DEBUG_ONLY(if (0 == outOfMemorySmTn) outOfMemorySmTn = smTn); - /* Must decr gtmMallocDepth after release above but before the */ - /* call to release_unused_storage() below. */ + /* Must decr gtmMallocDepth after release above but before the + * call to release_unused_storage() below. + */ --gtmMallocDepth; release_unused_storage(); } else --gtmMallocDepth; UNIX_ONLY(--fast_lock_count); DEFERRED_EXIT_HANDLING_CHECK; - UNIX_ONLY(rts_error(VARLSTCNT(5) ERR_MEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid, gtmMallocErrorErrno)); - VMS_ONLY(rts_error(VARLSTCNT(4) ERR_VMSMEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid)); + UNIX_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid, + gtmMallocErrorErrno)); + VMS_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_VMSMEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid)); # ifndef DEBUG } else - /* If not a debug module and debugging is enabled, reroute call to - the debugging version. - */ + /* If not a debug module and debugging is enabled, reroute call to the debugging version. */ raise_gtmmemory_error_dbg(); # endif } - /* Return the maximum size that would fully utilize a storage block given the input size. If the size will not - fit in one of the buddy list queue elems, it is returned unchanged. Otherwise, the size of the buddy list queue - element minus the overhead will be returned as the best fit size. -*/ + * fit in one of the buddy list queue elems, it is returned unchanged. Otherwise, the size of the buddy list queue + * element minus the overhead will be returned as the best fit size. + */ size_t gtm_bestfitsize(size_t size) { size_t tSize; @@ -1188,16 +1196,16 @@ size_t gtm_bestfitsize(size_t size) # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. - If it has, we are in the wrong module Jack. This IF is structured so that - if this is the normal (optimized) case we will fall into the code and - handle the rerouting at the end. - - Note: The DEBUG expansion of this code in a pro build actually has a different - entry point name (gtm_bestfitsize_dbg) and if malloc debugging options are - on in pro, we need to call that version, but since efficiency in pro trumps - clarity, we put the redirecting call at the bottom of the if-else block to - avoid disrupting the instruction pipeline. - */ + * If it has, we are in the wrong module Jack. This IF is structured so that + * if this is the normal (optimized) case we will fall into the code and + * handle the rerouting at the end. + * + * Note: The DEBUG expansion of this code in a pro build actually has a different + * entry point name (gtm_bestfitsize_dbg) and if malloc debugging options are + * on in pro, we need to call that version, but since efficiency in pro trumps + * clarity, we put the redirecting call at the bottom of the if-else block to + * avoid disrupting the instruction pipeline. + */ if (GDL_None == gtmDebugLevel) { # endif @@ -1213,23 +1221,23 @@ size_t gtm_bestfitsize(size_t size) # ifndef DEBUG } /* If not a debug module and debugging is enabled, reroute call to - the debugging version. - */ + * the debugging version. + */ return gtm_bestfitsize_dbg(size); # endif } /* Note that the DEBUG define takes on an additional meaning in this module. Not only are routines defined within - intended for DEBUG builds but they are also only generated ONCE rather than twice like most of the routines are - in this module. -*/ + * intended for DEBUG builds but they are also only generated ONCE rather than twice like most of the routines are + * in this module. + */ #ifdef DEBUG /* Backfill the requested area with marker text. We do this by doing single byte - stores up to the point where we can do aligned stores of the native register - length. Then fill the area as much as possible and finish up potentially with - a few single byte unaligned bytes at the end. -*/ + * stores up to the point where we can do aligned stores of the native register + * length. Then fill the area as much as possible and finish up potentially with + * a few single byte unaligned bytes at the end. + */ void backfill(unsigned char *ptr, gtm_msize_t len) { unsigned char *c; @@ -1252,7 +1260,6 @@ void backfill(unsigned char *ptr, gtm_msize_t len) --unalgnLen; } while(unalgnLen); } - /* Now, do aligned portion */ assert(0 == ((gtm_msize_t)ptr & AddrMask)); /* Verify aligned */ chunkCnt = len / ChunkSize; @@ -1262,7 +1269,6 @@ void backfill(unsigned char *ptr, gtm_msize_t len) *chunkPtr++ = ChunkValue; len -= SIZEOF(ChunkType); } - /* Do remaining unaligned portion if any */ if (len) { @@ -1279,9 +1285,10 @@ void backfill(unsigned char *ptr, gtm_msize_t len) /* ** still under ifdef DEBUG ** */ /* Check the given backfilled area that it was filled in exactly as - the above backfill routine would have filled it in. Again, do any - unaligned single chars first, then aligned native length areas, - then any stragler unaligned chars */ + * the above backfill routine would have filled it in. Again, do any + * unaligned single chars first, then aligned native length areas, + * then any stragler unaligned chars. + */ boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len) { unsigned char *c; @@ -1306,7 +1313,6 @@ boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len) return FALSE; } while(unalgnLen); } - /* Now, do aligned portion */ assert(0 == ((gtm_msize_t)ptr & AddrMask)); /* Verify aligned */ chunkCnt = len / ChunkSize; @@ -1318,7 +1324,6 @@ boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len) else return FALSE; } - /* Do remaining unaligned portion if any */ if (len) { @@ -1336,7 +1341,6 @@ boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len) return TRUE; } - /* ** still under ifdef DEBUG ** */ /* Routine to run the free storage chains to verify that everything is in the correct place */ void verifyFreeStorage(void) @@ -1359,14 +1363,12 @@ void verifyFreeStorage(void) assert(0 == memcmp(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker))); /* Vfy metadata marker */ assert(MAXINDEX != i || extent_used > uStor->extHdrOffset); if (GDL_SmChkFreeBackfill & gtmDebugLevel) - { /* Use backfill check method for verifying freed storage is untouched */ + /* Use backfill check method for verifying freed storage is untouched */ assert(backfillChk((unsigned char *)uStor + hdrSize, TwoTable[i] - hdrSize)); - } } } } - /* ** still under ifdef DEBUG ** */ /* Routine to run the allocated chains to verify that the markers are all still in place */ void verifyAllocatedStorage(void) @@ -1393,21 +1395,19 @@ void verifyAllocatedStorage(void) assert(0 == memcmp(trailerMarker, markerChar, SIZEOF(markerChar))); assert(MAXINDEX != i || extent_used > uStor->extHdrOffset); if (GDL_SmChkAllocBackfill & gtmDebugLevel) - { /* Use backfill check method for after-allocation metadata */ + /* Use backfill check method for after-allocation metadata */ assert(backfillChk(trailerMarker + SIZEOF(markerChar), (uStor->realLen - uStor->allocLen - hdrSize - SIZEOF(markerChar)))); - } } } } - /* ** still under ifdef DEBUG ** */ /* Routine to print the end-of-process info -- either allocation statistics or malloc trace dump. - Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one - time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily - be changed to use util_out_print instead of FPRINTF -*/ + * Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one + * time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily + * be changed to use util_out_print instead of FPRINTF. + */ void printMallocInfo(void) { int i, j; @@ -1473,10 +1473,10 @@ void printMallocInfo(void) printMallocDump(); } - +/* ** still under ifdef DEBUG ** */ /* Routine to print storage dump. This is called as part of print_malloc_info but is also potentially separately called from - op_view so is a separate routine. -*/ + * op_view so is a separate routine. + */ void printMallocDump(void) { storElem *eHdr, *uStor; diff --git a/sr_port/gtm_memcpy_validate_and_execute.c b/sr_port/gtm_memcpy_validate_and_execute.c index 670634a..b1de195 100644 --- a/sr_port/gtm_memcpy_validate_and_execute.c +++ b/sr_port/gtm_memcpy_validate_and_execute.c @@ -25,6 +25,7 @@ */ void *gtm_memcpy_validate_and_execute(void *target, const void *src, size_t len) { + assert((0 <= (signed)len) && (len <= MAXPOSINT4)); /* nothing beyond max positive int4 allowed */ if (target == src) /* Allow special case to go through but avoid actual memcpy() call */ return target; assert(((char *)(target) > (char *)(src)) diff --git a/sr_port/gtm_netdb.h b/sr_port/gtm_netdb.h index 3e6212e..b38ee61 100644 --- a/sr_port/gtm_netdb.h +++ b/sr_port/gtm_netdb.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2006 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,8 +16,28 @@ #include #define MAX_GETHOST_TRIES 8 -#define GETHOSTBYNAME gethostbyname -#define GETHOSTBYADDR gethostbyaddr -#define HSTRERROR hstrerror + +/* Macro to issue an rts_error_csa() with the results of getaddrinfo() or getnameinfo(). + * Takes ERR_GETADDRINFO or ERR_GETNAMEINFO as the mnemonic. + */ +#define RTS_ERROR_ADDRINFO(CSA, MNEMONIC, ERRCODE) \ +{ \ + if (EAI_SYSTEM == ERRCODE) \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MNEMONIC, 0, errno, 0); \ + else \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(6) MNEMONIC, 0, \ + ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \ +} +/* Same as above, but with a literal string context description. */ +#define RTS_ERROR_ADDRINFO_CTX(CSA, MNEMONIC, ERRCODE, CONTEXT) \ +{ \ + if (EAI_SYSTEM == ERRCODE) \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) MNEMONIC, 0, \ + ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), errno, 0); \ + else \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) MNEMONIC, 0, \ + ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), \ + ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \ +} #endif diff --git a/sr_port/gtm_newintrinsic.c b/sr_port/gtm_newintrinsic.c index 2cdd356..db9cb1e 100644 --- a/sr_port/gtm_newintrinsic.c +++ b/sr_port/gtm_newintrinsic.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "tp_frame.h" diff --git a/sr_port/gtm_putmsg_list.h b/sr_port/gtm_putmsg_list.h index 4e7dc06..39dad9c 100644 --- a/sr_port/gtm_putmsg_list.h +++ b/sr_port/gtm_putmsg_list.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 GTM_PUTMSG_LIST_H #define GTM_PUTMSG_LIST_H -void gtm_putmsg_list(int arg_count, va_list var); +void gtm_putmsg_list(void *csa, int arg_count, va_list var); #endif diff --git a/sr_port/gtm_rename.h b/sr_port/gtm_rename.h index 811bd7d..65d7935 100644 --- a/sr_port/gtm_rename.h +++ b/sr_port/gtm_rename.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003 Sanchez Computer Associates, Inc. * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,11 +17,17 @@ #define RENAME_NOT_REQD 1 #define RENAME_FAILED 2 +#ifdef UNIX +# define JNLSWITCH_TM_FMT "_%Y%j%H%M%S" /* yearjuliandayhoursminutesseconds */ +#else +# define JNLSWITCH_TM_FMT "|!Y4|!H04!M0!S0|" /* 'julian' day is added by append_time_stamp() explicitly */ +#endif + int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *rename_fn_len, uint4 *ustatus); uint4 gtm_rename(char *org_fn, int org_fn_len, char *rename_fn, int rename_len, uint4 *ustatus); -uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, char *rename_fn, - int *rename_fn_len, uint4 *ustatus); -uint4 append_time_stamp(char *fn, int fn_len, int *app_len, uint4 *ustatus); +uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, char *rename_fn, int *rename_fn_len, + jnl_tm_t now, uint4 *ustatus); +uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now); void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn); #endif diff --git a/sr_port/gtm_socket.h b/sr_port/gtm_socket.h index 64b6d52..b1c5839 100644 --- a/sr_port/gtm_socket.h +++ b/sr_port/gtm_socket.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,20 +13,23 @@ #ifndef GTM_SOCKETH #define GTM_SOCKETH +#ifdef VMS +#include +#else #include +#endif #define BIND bind #define CONNECT connect #define ACCEPT accept #define RECVFROM recvfrom #define SENDTO sendto +typedef struct sockaddr *sockaddr_ptr; #if defined(__osf__) && defined(__alpha) #define GTM_SOCKLEN_TYPE size_t #elif defined(VMS) #define GTM_SOCKLEN_TYPE size_t -#elif defined(__sparc) -#define GTM_SOCKLEN_TYPE int #else #define GTM_SOCKLEN_TYPE socklen_t #endif @@ -44,4 +47,27 @@ int gtm_socket(int domain, int type, int protocol); int gtm_connect(int socket, struct sockaddr *address, size_t address_len); +#if defined(VMS) && !defined(_SS_PAD2SIZE) +/* No sockaddr_storage on OpenVMS 7.2-1, but we only support AF_INET on VMS, so use sockaddr_in. */ +#define sockaddr_storage sockaddr_in +/* getnameinfo() inexplicably throws an ACCVIO/NOPRIV on OpenVMS 7.2-1, so revert to the old API. */ +#define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \ +{ \ + assert(((struct sockaddr *)(SA))->sa_family == AF_INET); \ + assert((FLAGS & NI_NUMERICHOST) || (NULL == HOST)); \ + assert((FLAGS & NI_NUMERICSERV) || (NULL == SERV)); \ + assert(FLAGS & (NI_NUMERICHOST | NI_NUMERICSERV)); \ + if ((FLAGS & NI_NUMERICHOST) && (NULL != HOST)) \ + STRNCPY(HOST, inet_ntoa(((struct sockaddr_in *)(SA))->sin_addr), HOSTLEN); \ + if ((FLAGS & NI_NUMERICSERV) && (NULL != SERV)) \ + i2asc((uchar_ptr_t)(SERV), ntohs(((struct sockaddr_in *)(SA))->sin_port)); \ + RES = 0; \ +} +#else +#define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \ +{ \ + RES = getnameinfo(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS); \ +} +#endif + #endif diff --git a/sr_port/gtm_stdlib.h b/sr_port/gtm_stdlib.h index 209b911..225827a 100644 --- a/sr_port/gtm_stdlib.h +++ b/sr_port/gtm_stdlib.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,11 +40,11 @@ char *gtm_getenv(char *varname); #define STRTOU64L strtoull #endif #define MKSTEMP(template,mkstemp_res) (mkstemp_res = mkstemp(template)) -#ifndef __CYGWIN__ -#define SYSTEM system +#ifdef VMS +#define SYSTEM system #else #define SYSTEM gtm_system -int gtm_system(const char *line); +int gtm_system(const char *cmdline); #endif #endif diff --git a/sr_port/gtm_string.h b/sr_port/gtm_string.h index d1eea3e..c542726 100644 --- a/sr_port/gtm_string.h +++ b/sr_port/gtm_string.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,17 +18,14 @@ #include #define STRERROR strerror - -#define STRCPY(SOURCE, DEST) strcpy((char *)(SOURCE), (char *)(DEST)) -#define STRNCPY_LIT(SOURCE, LITERAL) strncpy((char *)(SOURCE), (char *)(LITERAL), SIZEOF(LITERAL) - 1) /* BYPASSOK */ -#define STRNCPY_STR(SOURCE, STRING, LEN) strncpy((char *)(SOURCE), (char *)(STRING), LEN) - +#define STRCPY(DEST, SOURCE) strcpy((char *)(DEST), (char *)(SOURCE)) +#define STRNCPY_LIT(DEST, LITERAL) strncpy((char *)(DEST), (char *)(LITERAL), SIZEOF(LITERAL) - 1) /* BYPASSOK */ +#define STRNCPY_STR(DEST, STRING, LEN) strncpy((char *)(DEST), (char *)(STRING), LEN) #define STRCMP(SOURCE, DEST) strcmp((char *)(SOURCE), (char *)(DEST)) #define STRNCMP_LIT(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1) /* BYPASSOK */ /* Make sure that SIZEOF(SOURCE) > 0 or SOURCE != NULL before running. */ #define STRNCMP_LIT_FULL(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL)) /* BYPASSOK */ #define STRNCMP_STR(SOURCE, STRING, LEN) strncmp(SOURCE, STRING, LEN) - /* We need to catch any memcpy() that is used when the source and target strings overlap in any fashion so we can change * them to a memmove. So in debug builds, assert fail if this is the case. */ @@ -39,5 +36,28 @@ # endif # define memcpy(TARGET, SRC, LEN) gtm_memcpy_validate_and_execute((void *)(TARGET), (const void *)(SRC), (LEN)) #endif +/* The strnlen() function is POSIX-2008 so not widely avaiable yet so use it or our own critter as appropriate */ +#if (defined(__linux__) || defined(AIX)) +# define STRNLEN(str, maxlen, rslt) rslt = strnlen(str, maxlen) +#else +# define STRNLEN(str, maxlen, rslt) \ +{ \ + unsigned char *c, *cend; \ + \ + for (c = (unsigned char *)str, cend = c + maxlen; c < cend; ++c) \ + if ('\0' == *c) \ + break; \ + rslt = c - (unsigned char *)str; \ +} +#endif +#define STRNDUP(STR, MAXLEN, DST) \ +{ \ + size_t local_len; \ + \ + STRNLEN(STR, MAXLEN, local_len); \ + DST = (char *) malloc(local_len + 1); \ + memcpy(DST, STR, local_len); \ + DST[local_len] = '\0'; \ +} #endif diff --git a/sr_port/gtm_threadgbl_defs.h b/sr_port/gtm_threadgbl_defs.h index 3d79eb5..778cd8c 100644 --- a/sr_port/gtm_threadgbl_defs.h +++ b/sr_port/gtm_threadgbl_defs.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,9 @@ * 3. Larger arrays/structures should go nearer the end. * 4. There are no other runtime dependencies on this order. The order of fields can be switched around * any way desired with just a rebuild. + * 5. It is important for ANY DEBUG_ONLY fields to go at the VERY END. Failure to do this breaks gtmpcat. + * 6. If a DEBUG_ONLY array is declared whose dimension is a macro, then it is necessary, for gtmpcat to work, + * that the macro shouldn't be defined as DEBUG_ONLY. */ /* Priority access fields - commonly used fields in performance situations */ @@ -33,6 +36,8 @@ THREADGBLDEF(grabbing_crit, gd_region *) /* Region currently grabbing crit /* Compiler */ THREADGBLDEF(boolchain, triple) /* anchor for chain used by bx_boolop */ THREADGBLDEF(boolchain_ptr, triple *) /* pointer to anchor for chain used by bx_boolop */ +THREADGBLDEF(bool_targ_anchor, tbp) /* anchor of targ chain for bool relocation */ +THREADGBLDEF(bool_targ_ptr, tbp *) /* ptr->anchor of targ chain for bool relocation */ THREADGBLDEF(code_generated, boolean_t) /* flag that the compiler generated an object */ THREADGBLDEF(codegen_padlen, int4) /* used to pad code to section alignment */ THREADGBLDEF(compile_time, boolean_t) /* flag that the compiler's at work */ @@ -45,22 +50,22 @@ 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(for_nest_level, uint4) /* kludge feeds extra (non-lvn) arg to FOR rt ops */ 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_array, mval **) /* base of array holding indirection returns */ -THREADGBLDEF(ind_result_sp, mval **) /* pointer into array holding indirection returns */ -THREADGBLDEF(ind_result_top, mval **) /* top of array holding indirection returns */ -THREADGBLDEF(ind_source_array, mval **) /* base of array holding indirection values */ -THREADGBLDEF(ind_source_sp, mval **) /* pointer into array holding indirection values */ -THREADGBLDEF(ind_source_top, mval **) /* top of array holding indirection values */ +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(pos_in_chain, triple) /* anchor used to restart after a parsing error */ THREADGBLDEF(s2n_intlit, boolean_t) /* type info from s2n for advancewindow */ THREADGBLDEF(saw_side_effect, boolean_t) /* need side effect handling other than naked */ THREADGBLDEF(shift_side_effects, int) /* flag shifting of side-effects ahead of boolean * evalation */ +THREADGBLDEF(side_effect_base, boolean_t *) /* anchor side effect array: bin ops & func args */ +THREADGBLDEF(side_effect_depth, uint4) /* current high water of side effect expr array */ +THREADGBLDEF(side_effect_handling, int) /* side effect handling in actuallists, function + * args & non-boolean binary operator operands */ THREADGBLDEF(source_error_found, int4) /* flag to partially defer compiler error */ THREADGBLDEF(temp_subs, boolean_t) /* flag temp storing of subscripts to preserve * current evaluation */ @@ -71,9 +76,11 @@ THREADGBLDEF(window_token, char) /* current scanner token from advancewindo /* Database */ THREADGBLDEF(dbinit_max_hrtbt_delta, uint4) /* max heartbeats before we bail out in db_init */ +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(gd_targ_addr, gd_addr *) /* current global directory reference */ +THREADGBLDEF(gtm_custom_errors, mstr) THREADGBLDEF(gtm_gvundef_fatal, boolean_t) /* core and die intended for testing */ THREADGBLDEF(gv_extname_size, int4) /* part op_gvextname working memory mechanism */ THREADGBLDEF(gv_last_subsc_null, boolean_t) /* indicates whether the last subscript of @@ -94,29 +101,33 @@ THREADGBLDEF(in_op_gvget, boolean_t) /* TRUE if op_gvget() is a C-stack call THREADGBLDEF(issue_DBROLLEDBACK_anyways, boolean_t) /* currently set by MUPIP LOAD */ THREADGBLDEF(last_fnquery_return_subcnt, int) /* count subscript in last_fnquery_return_sub */ THREADGBLDEF(last_fnquery_return_varname, mval) /* returned varname of last $QUERY() */ +#ifdef VMS THREADGBLDEF(new_dbinit_ipc, int4) /* indicates whether shared memory/semaphore is * created by db_init (also used by dbinit_ch) */ +#endif THREADGBLDEF(ok_to_call_wcs_recover, boolean_t) /* Set to TRUE before a few wcs_recover callers. * Any call to wcs_recover in the final retry * assert to prevent cache recovery while in a * transaction and confuse things enough to cause * further restarts (which is out-of-design while * in the final retry). */ -THREADGBLDEF(only_reset_clues_if_onln_rlbk, boolean_t) /* skip online rollback cleanup on a restart */ +THREADGBLDEF(in_gvcst_bmp_mark_free, boolean_t) /* May need to skip online rollback cleanup or + * gvcst_redo_root_search on a restart */ THREADGBLDEF(prev_gv_target, gv_namehead *) /* saves the last gv_target for debugging */ THREADGBLDEF(ready2signal_gvundef, boolean_t) /* TRUE if GET operation about to signal GVUNDEF */ +#ifdef UNIX +THREADGBLDEF(redo_rootsrch_ctxt, redo_root_search_context) /* context to be saved and restored during + * gvcst_redo_root_search */ +#endif THREADGBLDEF(semwait2long, volatile boolean_t) /* Waited too long for a semaphore */ +THREADGBLDEF(skip_file_corrupt_check, boolean_t) /* skip file_corrupt check in grab_crit */ +THREADGBLDEF(tpnotacidtime, int4) /* limit for long non-ACID ops in transactions */ THREADGBLDEF(tp_restart_count, uint4) /* tp_restart counter */ -THREADGBLDEF(tp_restart_dont_counts, uint4) /* tp_restart count adjustment */ +THREADGBLDEF(tp_restart_dont_counts, int4) /* tp_restart count adjustment; NOTE: DEBUG only */ THREADGBLDEF(tp_restart_entryref, mval) /* tp_restart position for reporting */ THREADGBLDEF(tp_restart_failhist_indx, int4) /* tp_restart dbg restart history index */ -THREADGBLDEF(tp_restart_needlock_cnt, uint4) /* tp_restart final try counter */ -THREADGBLDEF(tp_restart_needlock_tn, trans_num) /* tp_restart final try tn */ THREADGBLDEF(tprestart_syslog_delta, int4) /* defines every n-th restart to be logged */ THREADGBLDEF(tprestart_syslog_limit, int4) /* # of TP restarts logged unconditionally */ -#ifdef ENABLE_EXTENDED_RESTART_TRACE_HIST -THREADGBLDEF(trans_restart_hist_index, uint4) -#endif THREADGBLDEF(transform, boolean_t) /* flag collation transform eligible */ THREADGBLDEF(wcs_recover_done, boolean_t) /* TRUE if wcs_recover was ever invoked in this * process. */ @@ -127,6 +138,10 @@ THREADGBLDEF(local_collseq, collseq *) /* pointer to collation algorithm for THREADGBLDEF(local_collseq_stdnull, boolean_t) /* flag temp controlling empty-string subscript * handling - if true, use standard null subscript * collation for local variables */ +THREADGBLDEF(local_coll_nums_as_strings, boolean_t) /* flag controlling whether local variables that + * evaluate to numbers are treated like numbers + * (collating before strings) or like strings in + * local collations */ THREADGBLDEF(lv_null_subs, int) /* UNIX: set in gtm_env_init_sp(), * VMS: set in gtm$startup() */ THREADGBLDEF(max_lcl_coll_xform_bufsiz, int) /* max size of local collation buffer,which extends @@ -135,6 +150,7 @@ THREADGBLDEF(max_lcl_coll_xform_bufsiz, int) /* max size of local collation /* Replication variables */ THREADGBLDEF(replgbl, replgbl_t) /* set of global variables needed by the source * server */ +THREADGBLDEF(tqread_nowait, boolean_t) /* avoid sleeping in t_qread if TRUE */ /* Miscellaneous */ THREADGBLDEF(collseq_list, collseq *) /* list of pointers to currently mapped collation * algorithms - since this seems only used in @@ -156,7 +172,13 @@ THREADGBLDEF(fnzsearch_lv_vars, lv_val *) /* UNIX op_fnzsearch lv tree ancho THREADGBLDEF(fnzsearch_sub_mval, mval) /* UNIX op_fnzsearch subscript constuctor */ THREADGBLDEF(fnzsearch_nullsubs_sav, int) /* UNIX op_fnzsearch temp for null subs control */ #endif -THREADGBLDEF(gtm_env_init_done, boolean_t) /* gtm_env_init flag for completion */ +THREADGBLDEF(glvn_pool_ptr, glvn_pool *) /* Pointer to the glvn pool */ +#if defined(UNIX) && defined(GTMDBGFLAGS_ENABLED) +THREADGBLDEF(gtmdbgflags, int) +THREADGBLDEF(gtmdbgflags_freq, int) +THREADGBLDEF(gtmdbgflags_freq_cntr, int) +#endif +THREADGBLDEF(gtm_env_init_started, boolean_t) /* gtm_env_init flag envvar processing */ THREADGBLFPTR(gtm_env_xlate_entry, int, ()) /* gtm_env_xlate() function pointer */ THREADGBLDEF(gtm_environment_init, boolean_t) /* indicates GT.M development environment rather * than a production environment */ @@ -168,12 +190,15 @@ THREADGBLDEF(gtm_trctbl_start, trctbl_entry *) /* Start of gtm trace table * THREADGBLDEF(gtm_waitstuck_script, mstr) /* Path to the script to be executed during waits*/ THREADGBLDEF(gtmprompt, mstr) /* mstr pointing to prombuf containing the GTM * prompt */ +THREADGBLDEF(gtmsecshr_comkey, unsigned int) /* Hashed version key for gtmsecshr communications + * eliminates cross-version issues */ THREADGBLDEF(in_zwrite, boolean_t) /* ZWrite is active */ THREADGBLDEF(lab_proxy, lab_tabent_proxy) /* Placeholder storing lab_ln_ptr offset / lnr_adr * pointer and has_parms value, so they are * contiguous in memory */ #ifdef VMS THREADGBLDEF(lbl_tbl_entry_index, int) /* Index of currently compiled label table entry */ +THREADGBLAR1DEF(login_time, int4, 2) /* */ #endif THREADGBLDEF(mprof_alloc_reclaim, boolean_t) /* Flag indicating whether the temporarily allocated * memory should be reclaimed */ @@ -197,15 +222,18 @@ THREADGBLDEF(open_shlib_root, open_shlib *) /* Anchor for open shared librar THREADGBLDEF(parm_pool_ptr, parm_pool *) /* Pointer to the parameter pool */ THREADGBLDEF(parms_cnt, unsigned int) /* Parameters count */ #ifdef UNIX +THREADGBLAR1DEF(zpeek_regname, char, NAME_ENTRY_SZ) /* Last $ZPEEK() region specified */ +THREADGBLDEF(zpeek_regname_len, int) /* Length of zpeekop_regname */ +THREADGBLDEF(zpeek_reg_ptr, gd_region *) /* Resolved pointer for zpeekop_regname */ THREADGBLDEF(pipefifo_interrupt, int) /* count of number of times a pipe or fifo device is * interrupted */ #endif THREADGBLDEF(prof_fp, mprof_stack_frame *) /* Stack frame that mprof currently operates on */ THREADGBLDEF(trans_code_pop, mval *) /* trans_code holder for $ZTRAP popping */ THREADGBLDEF(view_ydirt_str, char *) /* op_view working storage for ydir* ops */ -THREADGBLDEF(view_ydirt_str_len, int4) /* part of op_view working storage for ydir* ops */ -THREADGBLDEF(zdate_form, int4) /* control for default $zdate() format */ -THREADGBLAR1DEF(zintcmd_active, zintcmd_active_info, ZINTCMD_LAST) /* interrupted timed commands */ +THREADGBLDEF(view_ydirt_str_len, int4) /* Part of op_view working storage for ydir* ops */ +THREADGBLDEF(zdate_form, int4) /* Control for default $zdate() format */ +THREADGBLAR1DEF(zintcmd_active, zintcmd_active_info, ZINTCMD_LAST) /* Interrupted timed commands */ THREADGBLDEF(zro_root, zro_ent *) /* Anchor for zroutines structure entry array */ #ifdef UNIX THREADGBLDEF(zsearch_var, lv_val *) /* UNIX $zsearch() lookup variable */ @@ -214,9 +242,10 @@ THREADGBLDEF(zsearch_dir2, lv_val *) /* UNIX $zsearch() directory 2 */ #endif /* Larger structures and char strings */ +THREADGBLAR1DEF(director_string, char, SIZEOF(mident_fixed)) /* Buffer for director_ident */ THREADGBLDEF(fnpca, fnpc_area) /* $Piece cache structure area */ -THREADGBLAR1DEF(for_stack, oprtype *, MAX_FOR_STACK) /* stacks FOR scope complete (compilation) addrs */ -THREADGBLAR1DEF(for_temps, boolean_t, MAX_FOR_STACK) /* stacked flags of FOR control value temps */ +THREADGBLAR1DEF(for_stack, oprtype *, MAX_FOR_STACK) /* Stacks FOR scope complete (compilation) addrs */ +THREADGBLAR1DEF(for_temps, boolean_t, MAX_FOR_STACK) /* Stacked flags of FOR control value temps */ THREADGBLAR1DEF(last_fnquery_return_sub, mval, MAX_LVSUBSCRIPTS)/* Returned subscripts of last $QUERY() */ THREADGBLDEF(lcl_coll_xform_buff, char *) /* This buffer is for local collation * transformations, which must not nest - i.e. @@ -224,9 +253,9 @@ THREADGBLDEF(lcl_coll_xform_buff, char *) /* This buffer is for local collat * or itself. This kind of nesting would cause * overwriting of the buffer */ #ifdef UNIX -THREADGBLAR1DEF(parm_ary, char *, MAX_PARMS) /* parameter strings buffer */ -THREADGBLAR1DEF(parm_ary_len, int, MAX_PARMS) /* array element allocation length */ -THREADGBLAR1DEF(parm_str_len, int, MAX_PARMS) /* parameter strings lengths */ +THREADGBLAR1DEF(parm_ary, char *, MAX_PARMS) /* Parameter strings buffer */ +THREADGBLAR1DEF(parm_ary_len, int, MAX_PARMS) /* Array element allocation length */ +THREADGBLAR1DEF(parm_str_len, int, MAX_PARMS) /* Parameter strings lengths */ #endif THREADGBLAR1DEF(prombuf, char, (MAX_MIDENT_LEN + 1)) /* The prompt buffer size (32) would allow at * least 8 Unicode characters, but since most @@ -235,11 +264,18 @@ THREADGBLAR1DEF(prombuf, char, (MAX_MIDENT_LEN + 1)) /* The prompt buffer size * accommodate 10 Unicode characters in a prompt */ THREADGBLDEF(rt_name_tbl, hash_table_mname) /* Routine hash table for finding $TEXT() info */ THREADGBLAR1DEF(tp_restart_failhist_arry, char, FAIL_HIST_ARRAY_SIZE) /* tp_restart dbg storage of restart history */ -THREADGBLAR1DEF(director_string, char, SIZEOF(mident_fixed)) /* buffer for director_ident */ -THREADGBLAR1DEF(window_string, char, SIZEOF(mident_fixed)) /* buffer for window_ident */ -#ifdef ENABLE_EXTENDED_RESTART_TRACE_HIST -THREADGBLAR1DEF(trans_restart_hist_array, trans_restart_hist_t, TRANS_RESTART_HIST_ARRAY_SZ) /* See tp.h for usage */ +#ifdef UNIX +THREADGBLDEF(user_id, uint4) /* USERID number */ #endif +THREADGBLAR1DEF(window_string, char, SIZEOF(mident_fixed)) /* Buffer for window_ident */ + +/* Utility I/O */ +THREADGBLDEF(last_va_list_ptr, va_list) /* Last variable-length argument list used for util + * out buffer management */ +THREADGBLAR1DEF(util_outbuff, char, OUT_BUFF_SIZE * UTIL_OUTBUFF_STACK_SIZE) /* Util output buffer */ +THREADGBLDEF(util_outbuff_ptr, char *) /* Pointer to util output buffer */ +THREADGBLDEF(util_outptr, char *) /* Pointer within util output buffer */ + /* GTM Call-in related globals */ #ifdef UNIX @@ -249,8 +285,64 @@ THREADGBLDEF(ci_table, callin_entry_list *) /* Callin table in the form of THREADGBLDEF(extcall_package_root, struct extcall_package_list *) /* External call table package list */ #ifdef UNIX THREADGBLDEF(gtmci_nested_level, unsigned int) /* Current nested depth of callin environments */ +THREADGBLDEF(in_gtmci, boolean_t) /* Indicates if we are in one of the gtm_ci... + * functions. */ #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 * killed globals for effective truncate. */ +THREADGBLDEF(in_mu_swap_root_state, unsigned int) /* Three states: + * MUSWP_INCR_ROOT_CYCLE: MUPIP REORG moves GVT + * root blocks in mu_swap_root. + * MUSWP_FREE_BLK: MUPIP REORG frees blocks + * MUSWP_NONE + */ +THREADGBLDEF(prev_t_tries, unsigned int) /* t_tries - 1, before t_retry/tp_restart */ +THREADGBLDEF(rlbk_during_redo_root, boolean_t) /* set to TRUE if an online rollback which takes + * the db to a different logical state occurs + * during gvcst_redo_root_search in t_retry */ +THREADGBLDEF(mlk_yield_pid, uint4) /* if non-zero, indicates the process id for which + * we yielded a chance to get this lock. We keep + * yielding as long as the process-id that is the + * first in the wait queue ("d->pending") changes. + * If the pid stays the same, we stop yielding. + * if -1, indicates we disabled fairness mechanism + * in order to avoid livelocks. + */ +THREADGBLDEF(jnl_extract_nocol, uint4) /* If non-zero, MUPIP JOURNAL EXTRACT will skip + * reading the directory tree to find the + * collation information for each global. Note + * that this might result in garbled subscripts + * in the extract if globals do use alternative + * collation. + */ +#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. + * A complete list of all gv_targets who had + * triggers read in this transaction can be found + * by going through the gvt_tp_list and checking + * if gvt->trig_read_tn matches local_tn. This is + * useful to invalidate all those triggers in case + * of a transaction restart or rollback. + */ +THREADGBLDEF(in_op_fntext, boolean_t) /* Denote the trigger was processed in $Text() */ +#endif + +/* Debug values */ +#ifdef DEBUG +THREADGBLDEF(continue_proc_cnt, int) /* Used by whitebox secshr test to count time + * process was continued. */ +THREADGBLDEF(gtm_test_fake_enospc, boolean_t) /* DEBUG-only option to enable/disable anticipatory + * freeze fake ENOSPC testing + */ +THREADGBLDEF(gtm_usesecshr, boolean_t) /* Bypass easy methods of dealing with IPCs, files, + * wakeups, etc and always use gtmsecshr (testing). + */ +THREADGBLDEF(rts_error_unusable, boolean_t) /* Denotes the window in which an rts_error is + * unusable */ +THREADGBLDEF(rts_error_unusable_seen, boolean_t) +THREADGBLAR1DEF(trans_restart_hist_array, trans_restart_hist_t, TRANS_RESTART_HIST_ARRAY_SZ) /* See tp.h for usage */ +THREADGBLDEF(trans_restart_hist_index, uint4) +#endif diff --git a/sr_port/gtm_threadgbl_deftypes.c b/sr_port/gtm_threadgbl_deftypes.c index 99bcf35..4c0ba8d 100644 --- a/sr_port/gtm_threadgbl_deftypes.c +++ b/sr_port/gtm_threadgbl_deftypes.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,7 +39,7 @@ #include "hashtab_str.h" #include "hashtab_objcode.h" #include "error.h" -#include "rtnhdr.h" +#include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" @@ -95,6 +95,8 @@ #include "zroutines.h" #include "trace_table.h" #include "parm_pool.h" +#include "util.h" /* for util_outbuff manipulations */ +#include "nametabtyp.h" /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" @@ -110,7 +112,7 @@ # include "cli.h" # include "invocation_mode.h" # include "fgncal.h" -# include "parse_file.h" /* for MAX_FBUFF */ +# include "parse_file.h" /* for MAX_FBUFF */ # include "repl_sem.h" # include "gtm_zlib.h" # include "zro_shlibs.h" diff --git a/sr_port/gtm_threadgbl_init.c b/sr_port/gtm_threadgbl_init.c index 780a15b..0479aec 100644 --- a/sr_port/gtm_threadgbl_init.c +++ b/sr_port/gtm_threadgbl_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -49,7 +49,7 @@ #include "hashtab_str.h" #include "hashtab_objcode.h" #include "error.h" -#include "rtnhdr.h" +#include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" @@ -104,6 +104,8 @@ #include "alias.h" #include "zroutines.h" #include "parm_pool.h" +#include "util.h" /* for util_outbuff manipulations */ +#include "nametabtyp.h" /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" @@ -221,4 +223,5 @@ void gtm_threadgbl_init(void) MEMCPY_LIT(TADR(prombuf), DEFAULT_PROMPT); (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. */ } diff --git a/sr_port/gtm_time.h b/sr_port/gtm_time.h index 13a694d..b529405 100644 --- a/sr_port/gtm_time.h +++ b/sr_port/gtm_time.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,13 +15,12 @@ #include -/* CTIME collides with linux define in termios */ - -#define GTM_CTIME ctime -#define GTM_CTIME_R ctime_r - #define STRFTIME(dest, maxsize, format, timeptr, res) \ - res = strftime(dest, maxsize, format, timeptr) +{ \ + DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ + res = strftime(dest, maxsize, format, timeptr); \ + ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ +} /* To use GET_CUR_TIME macro these definitions are required * now_t now; char *time_ptr; char time_str[CTIME_BEFORE_NL + 2]; @@ -59,15 +58,48 @@ typedef time_t now_t; { \ if ((time_t)-1 == (now = time(NULL))) \ time_ptr = "****** time failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \ - else if (NULL == (time_ptr = (char *)GTM_CTIME(&now))) \ - time_ptr = "***** ctime failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \ else \ { \ - memcpy(time_str, time_ptr, CTIME_BEFORE_NL + 2); \ - time_ptr = time_str; \ + GTM_CTIME(time_ptr, &now); \ + if (NULL == time_ptr) \ + time_ptr = "***** ctime failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \ + else \ + { \ + memcpy(time_str, time_ptr, CTIME_BEFORE_NL + 2); \ + time_ptr = time_str; \ + } \ } \ } +#define GTM_MKTIME(VAR, TIME) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ + VAR = mktime(TIME); \ + ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ +} + +#define GTM_GMTIME(VAR, TIME) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ + VAR = gmtime(TIME); \ + ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ +} + #endif /* UNIX, VMS */ +#define GTM_LOCALTIME(VAR, TIME) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ + VAR = localtime(TIME); \ + ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ +} + +/* CTIME collides with linux define in termios */ +#define GTM_CTIME(VAR, TIME) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ + VAR = ctime(TIME); \ + ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ +} + #endif diff --git a/sr_port/gtm_unistd.h b/sr_port/gtm_unistd.h index b031d22..7cae350 100644 --- a/sr_port/gtm_unistd.h +++ b/sr_port/gtm_unistd.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,7 +39,11 @@ #define GTM_MAX_DIR_LEN (PATH_MAX + 1) /* DIRECTORY + terminating '\0' */ #define GETCWD(buffer, size, getcwd_res) \ - (getcwd_res = getcwd(buffer, size)) +{ \ + DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \ + getcwd_res = getcwd(buffer, size); \ + ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \ +} #endif diff --git a/sr_port/gtmmsg.h b/sr_port/gtmmsg.h index d4fcaff..d76ee3b 100644 --- a/sr_port/gtmmsg.h +++ b/sr_port/gtmmsg.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,16 +12,35 @@ #ifndef GTMMSG_H_INCLUDED #define GTMMSG_H_INCLUDED - #ifdef VMS void gtm_getmsg(uint4 msgnum, mstr *msgbuf); void gtm_putmsg(int4 msgid, ...); +#define gtm_putmsg_csa gtm_putmsg #elif defined(UNIX) void gtm_getmsg(int4 msgnum, mstr *msgbuf); void gtm_putmsg(int argcnt, ...); +void gtm_putmsg_csa(void *, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */ void gtm_putmsg_noflush(int argcnt, ...); +void gtm_putmsg_noflush_csa(void *, int argcnt, ...); + +# define GET_MSG_IDX(MSG_ID, CTL, IDX) \ +{ \ + assert(NULL != CTL); \ + assert((MSG_ID && FACMASK(CTL->facnum)) && (MSGMASK(MSG_ID, CTL->facnum) <= CTL->msg_cnt)); \ + IDX = MSGMASK(MSG_ID, CTL->facnum) - 1; \ +} + +/* Given a pointer to ctl array (merrors_ctl, gdeerrors_ctl, etc.) and a msg_id, get the structure corresponding to that msg_id */ +# define GET_MSG_INFO(MSG_ID, CTL, MSG_INFO) \ +{ \ + int idx; \ + \ + GET_MSG_IDX(MSG_ID, CTL, idx); \ + MSG_INFO = CTL->fst_msg + idx; \ +} + #else -#error Unsupported platform +# error Unsupported platform #endif #endif /* GTMMSG_H_INCLUDED */ diff --git a/sr_port/gtmrecv_changelog.c b/sr_port/gtmrecv_changelog.c index e091e8a..e225d2b 100644 --- a/sr_port/gtmrecv_changelog.c +++ b/sr_port/gtmrecv_changelog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc.* + * Copyright 2001, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,12 +34,21 @@ #include "util.h" #include "repl_log.h" +#include "gtm_fcntl.h" +#include "gtmio.h" +#include "repl_sp.h" + GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; +error_def(ERR_REPLLOGOPN); int gtmrecv_changelog(void) { uint4 changelog_desired = 0, changelog_accepted = 0; + int log_fd = 0; /*used to indicate whether the new specified log file is writable*/ + int close_status = 0; /*used to indicate if log file is successfully closed*/ + char* err_code; + int save_errno; /* Grab the recvpool jnlpool option write lock */ if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) @@ -58,9 +67,29 @@ int gtmrecv_changelog(void) changelog_desired |= REPLIC_CHANGE_LOGFILE; if (0 != strcmp(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file)) { - changelog_accepted |= REPLIC_CHANGE_LOGFILE; - strcpy(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file); - util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); +#ifdef UNIX + /*check if the new log file is writable*/ + OPENFILE3(gtmrecv_options.log_file, + O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, log_fd); + if (log_fd < 0) { + save_errno = ERRNO; + err_code = STRERROR(save_errno); + gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, + LEN_AND_STR(gtmrecv_options.log_file), + LEN_AND_STR(err_code), + LEN_AND_STR(NULL_DEVICE)); + } else { + CLOSEFILE_IF_OPEN(log_fd, close_status); + assert(close_status==0); + changelog_accepted |= REPLIC_CHANGE_LOGFILE; + strcpy(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file); + util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); + } +#elif defined(VMS) + changelog_accepted |= REPLIC_CHANGE_LOGFILE; + strcpy(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file); + util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); +#endif } else util_out_print("Log file is already !AD. Not initiating change in log file", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); diff --git a/sr_port/gtmrecv_checkhealth.c b/sr_port/gtmrecv_checkhealth.c index 2236098..340a6e8 100644 --- a/sr_port/gtmrecv_checkhealth.c +++ b/sr_port/gtmrecv_checkhealth.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -76,7 +76,7 @@ int is_recv_srv_alive(void) int gtmrecv_checkhealth(void) { - int rcv_status, upd_status, helper_status; + int rcv_status, upd_status, helper_status, save_errno; uint4 gtmrecv_pid, updproc_pid, updproc_pid_prev, helper_pid; boolean_t helper_alive; upd_helper_ctl_ptr_t upd_helper_ctl; @@ -87,8 +87,9 @@ int gtmrecv_checkhealth(void) if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) { + UNIX_ONLY(save_errno = errno); repl_log(stderr, FALSE, TRUE, "Error grabbing recvpool option write lock : %s. Could not check health of Receiver" - "Server/Update Process\n", REPL_SEM_ERROR); + "Server/Update Process\n", UNIX_ONLY(STRERROR(save_errno)) VMS_ONLY(REPL_SEM_ERROR)); return (((SRV_ERR << 2) | SRV_ERR) + NORMAL_SHUTDOWN); } diff --git a/sr_port/gtmrecv_comm_init.c b/sr_port/gtmrecv_comm_init.c index adf596f..d08162d 100644 --- a/sr_port/gtmrecv_comm_init.c +++ b/sr_port/gtmrecv_comm_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,8 @@ #include "gtm_string.h" #include "gtm_socket.h" +#include "gtm_netdb.h" /* for NI_MAXSERV and AI_V4MAPPED */ +#include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_fcntl.h" @@ -33,69 +35,77 @@ #include "gtmrecv.h" #include "repl_sp.h" #include "gtmio.h" +#include "util.h" +#include "repl_log.h" GBLDEF int gtmrecv_listen_sock_fd = FD_INVALID; +error_def(ERR_GETADDRINFO); +error_def(ERR_REPLCOMM); +error_def(ERR_TEXT); + /* Initialize communication stuff */ int gtmrecv_comm_init(in_port_t port) { - struct sockaddr_in secondary_addr; - const int enable_reuseaddr = 1; - const int disable_keepalive = 1; - struct linger disable_linger = {0, 0}; - int rc; - - error_def(ERR_REPLCOMM); - error_def(ERR_TEXT); + struct addrinfo *ai_ptr = NULL, hints; + const int enable_reuseaddr = 1; + struct linger disable_linger = {0, 0}; + int rc; + int errcode; + char port_buffer[NI_MAXSERV]; + int port_buffer_len; + int temp_sock_fd; + int af; if (FD_INVALID != gtmrecv_listen_sock_fd) /* Initialization done already */ return (0); /* Create the socket used for communicating with primary */ - if (FD_INVALID == (gtmrecv_listen_sock_fd = socket(AF_INET, SOCK_STREAM, 0))) + af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); + if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP))) { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO); - return (-1); - } - - if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with receiver server listen socket disable linger"), ERRNO); - -#ifdef REPL_DISABLE_KEEPALIVE - if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&disable_keepalive, - SIZEOF(disable_keepalive))) - { - /* Till SIGPIPE is handled properly */ - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with receiver server listen socket disable keepalive"), ERRNO); - } -#endif - - if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable_reuseaddr, - SIZEOF(enable_reuseaddr))) - { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with receiver server listen socket enable reuseaddr"), ERRNO); + af = AF_INET; + if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP))) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO); + return (-1); + } } /* Make it known to the world that you are ready for a Source Server */ - memset((char *)&secondary_addr, 0, SIZEOF(secondary_addr)); - secondary_addr.sin_family = AF_INET; - secondary_addr.sin_addr.s_addr = htonl(INADDR_ANY); - secondary_addr.sin_port = htons(port); - - if (0 > BIND(gtmrecv_listen_sock_fd, (struct sockaddr *)&secondary_addr, SIZEOF(secondary_addr))) + SERVER_HINTS(hints, af); + SPRINTF(port_buffer, "%hu", port); + if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not bind local address"), ERRNO); + CLOSEFILE(temp_sock_fd, rc); + RTS_ERROR_ADDRINFO_CTX(NULL, ERR_GETADDRINFO, errcode, "FAILED in obtaining IP address on receiver server."); + return -1; + } + + + gtmrecv_listen_sock_fd = temp_sock_fd; + if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error with receiver server listen socket disable linger"), ERRNO); + if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable_reuseaddr, + SIZEOF(enable_reuseaddr))) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error with receiver server listen socket enable reuseaddr"), ERRNO); + } + if (0 > BIND(gtmrecv_listen_sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen)) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Could not bind local address"), ERRNO); CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */ return (-1); } if (0 > listen(gtmrecv_listen_sock_fd, 5)) { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not listen"), ERRNO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Could not listen"), ERRNO); CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */ return (-1); } diff --git a/sr_port/gtmrecv_get_opt.c b/sr_port/gtmrecv_get_opt.c index 4dcedd8..5282495 100644 --- a/sr_port/gtmrecv_get_opt.c +++ b/sr_port/gtmrecv_get_opt.c @@ -64,6 +64,7 @@ int gtmrecv_get_opt(void) # ifdef UNIX gtmrecv_options.reuse_specified = (CLI_PRESENT == cli_present("REUSE")); gtmrecv_options.resume_specified = (CLI_PRESENT == cli_present("RESUME")); + gtmrecv_options.initialize_specified = (CLI_PRESENT == cli_present("INITIALIZE")); /* -UPDATERESYNC= and optional -REUSE= is supported only in Unix */ if (gtmrecv_options.updateresync) { diff --git a/sr_port/gtmrecv_helpers_init.c b/sr_port/gtmrecv_helpers_init.c index 6829b24..88d806e 100644 --- a/sr_port/gtmrecv_helpers_init.c +++ b/sr_port/gtmrecv_helpers_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc. * + * Copyright 2005, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,6 +14,7 @@ #ifdef UNIX #include #include "gtm_unistd.h" +#include "fork_init.h" #include #elif defined(VMS) #include /* Required for gtmrecv.h */ @@ -84,11 +85,12 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) save_shutdown = helper->helper_shutdown; helper->helper_shutdown = NO_SHUTDOWN; #ifdef UNIX - if (0 > (helper_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + FORK(helper_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + if (0 > helper_pid) { save_errno = errno; helper->helper_shutdown = save_shutdown; - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Could not fork update process"), save_errno); repl_errno = EREPL_UPDSTART_FORK; return UPDPROC_START_ERR; @@ -103,10 +105,11 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) dont_sendmsg_on_log2long))) { helper->helper_shutdown = save_shutdown; - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + 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")); if (SS_LOG2LONG == i4status) - gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDHELPER_CMD), SIZEOF(helper_cmd) - 1); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, + LEN_AND_LIT(UPDHELPER_CMD), SIZEOF(helper_cmd) - 1); repl_errno = EREPL_UPDSTART_BADPATH; return UPDPROC_START_ERR; } @@ -116,7 +119,7 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) { save_errno = errno; helper->helper_shutdown = save_shutdown; - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Could not exec Helper Process"), save_errno); repl_errno = EREPL_UPDSTART_EXEC; return UPDPROC_START_ERR; @@ -132,7 +135,8 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) UPDHELPER_MBX_PREFIX, mbx_suffix, &cmd_channel, &helper->helper_pid_prev, ERR_RECVPOOLSETUP))) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Unable to spawn Helper process"), status); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, + ERR_TEXT, 2, LEN_AND_LIT("Unable to spawn Helper process"), status); helper->helper_shutdown = save_shutdown; repl_errno = EREPL_UPDSTART_FORK; return UPDPROC_START_ERR; @@ -150,7 +154,7 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) /* Deassign the send-cmd mailbox channel */ if (SS_NORMAL != (status = sys$dassgn(cmd_channel))) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status); helper->helper_shutdown = save_shutdown; repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */ diff --git a/sr_port/gtmrecv_statslog.c b/sr_port/gtmrecv_statslog.c index 92a5039..823bcb4 100644 --- a/sr_port/gtmrecv_statslog.c +++ b/sr_port/gtmrecv_statslog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ #include #include #include "gtm_string.h" -#include +#include "gtm_inet.h" #ifdef UNIX #include #endif @@ -38,16 +38,21 @@ #include "repl_sem.h" #include "util.h" +#include "gtm_fcntl.h" +#include "gtmio.h" +#include "repl_log.h" +#include "repl_sp.h" + GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; - +error_def(ERR_REPLLOGOPN); +#ifdef VMS +error_def(ERR_UNIMPLOP); +error_def(ERR_TEXT); +#endif int gtmrecv_statslog(void) { - #ifdef VMS - error_def(ERR_UNIMPLOP); - error_def(ERR_TEXT); - rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Statistics logging not supported on VMS")); #endif /* Grab the recvpool option write lock */ @@ -68,31 +73,13 @@ int gtmrecv_statslog(void) if (!gtmrecv_options.statslog) { recvpool.gtmrecv_local->statslog = FALSE; - recvpool.gtmrecv_local->statslog_file[0] = '\0'; util_out_print("STATSLOG turned OFF", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); } - if ('\0' == gtmrecv_options.log_file[0]) /* Stats log file not specified, use general log file */ - { - util_out_print("No file specified for stats log. Using general log file !AD\n", TRUE, - LEN_AND_STR(recvpool.gtmrecv_local->log_file)); - strcpy(gtmrecv_options.log_file, recvpool.gtmrecv_local->log_file); - } else if (0 == strcmp(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file)) - { - util_out_print("Stats log file is already !AD. Not initiating change in log file", TRUE, - LEN_AND_STR(gtmrecv_options.log_file)); - rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); - return (ABNORMAL_SHUTDOWN); - } - - strcpy(recvpool.gtmrecv_local->statslog_file, gtmrecv_options.log_file); recvpool.gtmrecv_local->statslog = TRUE; - - util_out_print("Stats log turned on with file !AD", TRUE, strlen(recvpool.gtmrecv_local->statslog_file), - recvpool.gtmrecv_local->statslog_file); - + util_out_print("Stats log turned on", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); } diff --git a/sr_port/gtmrecv_upd_proc_init.c b/sr_port/gtmrecv_upd_proc_init.c index 69219f0..4e14fde 100644 --- a/sr_port/gtmrecv_upd_proc_init.c +++ b/sr_port/gtmrecv_upd_proc_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc.* + * Copyright 2001, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,6 +17,7 @@ #include "gtm_inet.h" #ifdef UNIX #include +#include "fork_init.h" #elif defined(VMS) #include #endif @@ -69,7 +70,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) mstr upd_proc_log_cmd, upd_proc_trans_cmd; char upd_proc_cmd[UPDPROC_CMD_MAXLEN]; - int status; + int status, save_errno; int upd_status, save_upd_status; #ifdef UNIX pid_t upd_pid, waitpid_res; @@ -80,20 +81,22 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) #endif /* Check if the update process is alive */ - if ((upd_status = is_updproc_alive()) == SRV_ERR) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Receive pool semctl failure"), REPL_SEM_ERRNO); + save_errno = errno; /* errno from get_sem_info() called from is_updproc_alive() */ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Receive pool semctl failure"), + UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO)); repl_errno = EREPL_UPDSTART_SEMCTL; return(UPDPROC_START_ERR); } else if (upd_status == SRV_ALIVE && !fresh_start) { - gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_LITERAL("Update process already exists. Not starting it")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, + RTS_ERROR_LITERAL("Update process already exists. Not starting it")); return(UPDPROC_EXISTS); } else if (upd_status == SRV_ALIVE) { - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update process already exists. Please kill it before a fresh start")); return(UPDPROC_EXISTS); } @@ -102,10 +105,11 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) recvpool.upd_proc_local->upd_proc_shutdown = NO_SHUTDOWN; #ifdef UNIX - if (0 > (upd_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + FORK(upd_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + if (0 > upd_pid) { recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork update process"), errno); repl_errno = EREPL_UPDSTART_FORK; return(UPDPROC_START_ERR); @@ -119,17 +123,18 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) dont_sendmsg_on_log2long); if (status != SS_NORMAL) { - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + 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")); if (SS_LOG2LONG == status) - gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDPROC_CMD), SIZEOF(upd_proc_cmd) - 1); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) + ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDPROC_CMD), SIZEOF(upd_proc_cmd) - 1); repl_errno = EREPL_UPDSTART_BADPATH; return(UPDPROC_START_ERR); } upd_proc_cmd[upd_proc_trans_cmd.len] = '\0'; if (EXECL(upd_proc_cmd, upd_proc_cmd, UPDPROC_CMD_ARG1, UPDPROC_CMD_ARG2, NULL) < 0) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not exec Update Process"), errno); repl_errno = EREPL_UPDSTART_EXEC; return(UPDPROC_START_ERR); @@ -140,7 +145,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) status = repl_create_server(&cmd_desc, "GTMU", "", &cmd_channel, &upd_pid, ERR_RECVPOOLSETUP); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to spawn Update process"), status); recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; repl_errno = EREPL_UPDSTART_FORK; @@ -167,7 +172,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start) /* Deassign the send-cmd mailbox channel */ if (SS_NORMAL != (status = sys$dassgn(cmd_channel))) { - gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status); recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */ @@ -184,12 +189,12 @@ int gtmrecv_start_updonly(void) if ((upd_status = is_updproc_alive()) == SRV_ALIVE) { - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 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(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in starting up update process")); return(UPDPROC_START_ERR); } @@ -205,7 +210,8 @@ int gtmrecv_start_updonly(void) if (start_status == UPDPROC_STARTED) { - gtm_putmsg(VARLSTCNT(4) ERR_REPLINFO, 2, RTS_ERROR_LITERAL("Update Process started successfully")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINFO, 2, + RTS_ERROR_LITERAL("Update Process started successfully")); return(UPDPROC_STARTED); } #ifdef VMS @@ -213,14 +219,15 @@ int gtmrecv_start_updonly(void) #endif if (start_status == UPDPROC_START) { - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 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(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error starting update process")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error starting update process")); } else if (start_status == UPDPROC_EXISTS) { - gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process exists already. New process not started")); } return(UPDPROC_START_ERR); diff --git a/sr_port/gtmsource_ch.c b/sr_port/gtmsource_ch.c index 4b0f7b2..47eee5d 100644 --- a/sr_port/gtmsource_ch.c +++ b/sr_port/gtmsource_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -63,10 +63,6 @@ CONDITION_HANDLER(gtmsource_ch) gd_region *reg_local, *reg_top; sgmnt_addrs *csa; -# ifdef UNIX - unix_db_info *udi; -# endif - START_CH; if (!(IS_GTM_ERROR(SIGNAL)) || DUMPABLE || SEVERITY == ERROR) { @@ -89,16 +85,6 @@ CONDITION_HANDLER(gtmsource_ch) if (csa && csa->now_crit) rel_lock(jnlpool.jnlpool_dummy_reg); } - UNIX_ONLY( - /* Release FTOK lock on the replication instance file if holding it */ - if (NULL != jnlpool.jnlpool_dummy_reg) - { - udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); - if (udi->grabbed_ftok_sem) - ftok_sem_release(jnlpool.jnlpool_dummy_reg, FALSE, FALSE); - assert(!udi->grabbed_ftok_sem); - } - ) NEXTCH; } /* warning, info, or success */ diff --git a/sr_port/gtmsource_comm_init.c b/sr_port/gtmsource_comm_init.c index 2fd311f..0ffb772 100644 --- a/sr_port/gtmsource_comm_init.c +++ b/sr_port/gtmsource_comm_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,6 +21,8 @@ #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_socket.h" +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" @@ -39,53 +41,78 @@ #include "gtmsource.h" #include "repl_sp.h" #include "repl_comm.h" +#include "repl_log.h" GBLDEF int gtmsource_sock_fd = FD_INVALID; GBLREF jnlpool_addrs jnlpool; +GBLREF FILE *gtmsource_log_fp; + +error_def(ERR_REPLCOMM); +error_def(ERR_GETADDRINFO); +error_def(ERR_TEXT); int gtmsource_comm_init(void) { /* Initialize communication stuff */ - - const int disable_keepalive = 0; struct linger disable_linger = {0, 0}; char error_string[1024]; int err_status; - - error_def(ERR_REPLCOMM); - error_def(ERR_TEXT); + struct addrinfo *ai_ptr = NULL, *ai_head = NULL, hints; + gtmsource_local_ptr_t gtmsource_local; + char *host; + char port_buffer[NI_MAXSERV]; + int port_len; + int errcode; + int tries; if (FD_INVALID != gtmsource_sock_fd) /* Initialization done already */ return(0); - - /* Create the socket used for communicating with secondary */ - if (FD_INVALID == (gtmsource_sock_fd = socket(AF_INET, SOCK_STREAM, 0))) + gtmsource_local = jnlpool.gtmsource_local; + port_len = 0; + I2A(port_buffer, port_len, gtmsource_local->secondary_port); + port_buffer[port_len] = '\0'; + host = gtmsource_local->secondary_host; + CLIENT_HINTS(hints); + for (tries = 0; + tries < MAX_GETHOST_TRIES && + EAI_AGAIN == (errcode = getaddrinfo(host, port_buffer, &hints, &ai_head)); + tries++); + if (0 != errcode) + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); + /* find one address valid for creating socket */ + assert(ai_head); + for(ai_ptr = ai_head; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next) { - err_status = ERRNO; - SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket create : %s", STRERROR(err_status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); - return(-1); + if (FD_INVALID == (gtmsource_sock_fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, + ai_ptr->ai_protocol))) + err_status = errno; + else + { + err_status = 0; + break; + } } - + if (0 != err_status) + { + freeaddrinfo(ai_head); /* prevent mem-leak */ + SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket create : %s", + STRERROR(err_status)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); + } + assert(NULL != ai_ptr); + assert(SIZEOF(gtmsource_local->secondary_inet_addr) >= ai_ptr->ai_addrlen); + /* only save the addrinfo and address after the socket is successfuly created */ + gtmsource_local->secondary_af = ai_ptr->ai_family; + gtmsource_local->secondary_addrlen = ai_ptr->ai_addrlen; + memcpy((struct sockaddr*)(>msource_local->secondary_inet_addr), ai_ptr->ai_addr, ai_ptr->ai_addrlen); + freeaddrinfo(ai_head); /* prevent mem-leak */ /* A connection breakage should get rid of the socket */ - if (-1 == setsockopt(gtmsource_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) { err_status = ERRNO; SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket disable linger : %s", STRERROR(err_status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); } - -#ifdef REPL_DISABLE_KEEPALIVE - if (-1 == setsockopt(gtmsource_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&disable_keepalive, - SIZEOF(disable_keepalive))) - { /* Till SIGPIPE is handled properly */ - err_status = ERRNO; - SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket disable keepalive : %s", - STRERROR(err_status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); - } -#endif return(0); } diff --git a/sr_port/gtmsource_ctl_init.c b/sr_port/gtmsource_ctl_init.c index 2578c11..45ffded 100644 --- a/sr_port/gtmsource_ctl_init.c +++ b/sr_port/gtmsource_ctl_init.c @@ -79,7 +79,7 @@ GBLREF gtmsource_state_t gtmsource_state; GBLREF uint4 process_id; #endif -error_def(ERR_JNLFILOPN); +error_def(ERR_JNLFILRDOPN); error_def(ERR_JNLNOREPL); repl_buff_t *repl_buff_create(uint4 buffsize, uint4 jnl_fs_block_size); @@ -132,7 +132,6 @@ int repl_open_jnl_file_by_name(repl_ctl_element *tmp_ctl, int jnl_fn_len, char * if (0 > tmp_fd) { status = errno; - assert(FALSE); } if (SS_NORMAL == status) { @@ -187,9 +186,7 @@ int repl_ctl_create(repl_ctl_element **ctl, gd_region *reg, int jnl_fn_len, char jnl_private_control *jpc; int tmp_fd = NOJNL; int status; - GTMCRYPT_ONLY( - int crypt_status; - ) + int gtmcrypt_errno; uint4 jnl_status; boolean_t did_jnl_ensure_open = FALSE, was_crit; int4 lcl_jnl_fn_len; @@ -310,7 +307,7 @@ int repl_ctl_create(repl_ctl_element **ctl, gd_region *reg, int jnl_fn_len, char assert(lcl_jnl_fn_len < ARRAYSIZE(lcl_jnl_fn)); memcpy(lcl_jnl_fn, tmp_ctl->jnl_fn, lcl_jnl_fn_len); lcl_jnl_fn[lcl_jnl_fn_len] = '\0'; - assert(!REPL_ALLOWED(tmp_jfh)); + assert((NULL == tmp_jfh) || !REPL_ALLOWED(tmp_jfh)); free(tmp_ctl); tmp_ctl = NULL; if (NULL != tmp_jfh_base) @@ -318,7 +315,7 @@ int repl_ctl_create(repl_ctl_element **ctl, gd_region *reg, int jnl_fn_len, char tmp_jfh = NULL; tmp_jfh_base = NULL; if (SS_NORMAL != status) - rts_error(VARLSTCNT(7) ERR_JNLFILOPN, 4, lcl_jnl_fn_len, lcl_jnl_fn, DB_LEN_STR(reg), status); + rts_error(VARLSTCNT(7) ERR_JNLFILRDOPN, 4, lcl_jnl_fn_len, lcl_jnl_fn, DB_LEN_STR(reg), status); else rts_error(VARLSTCNT(6) ERR_JNLNOREPL, 4, lcl_jnl_fn_len, lcl_jnl_fn, DB_LEN_STR(reg)); } @@ -333,12 +330,10 @@ int repl_ctl_create(repl_ctl_element **ctl, gd_region *reg, int jnl_fn_len, char # ifdef GTM_CRYPT if (tmp_jfh->is_encrypted) { - INIT_PROC_ENCRYPTION(crypt_status); - /* If the encryption init failed in db_init, the below MACRO should return an error. - * Depending on the error returned, report the error.*/ - GTMCRYPT_GETKEY(tmp_jfh->encryption_hash, tmp_ctl->encr_key_handle, crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, tmp_ctl->jnl_fn); + ASSERT_ENCRYPTION_INITIALIZED; /* should be done in db_init (gtmsource() -> gvcst_init() -> db_init()) */ + GTMCRYPT_GETKEY(csa, tmp_jfh->encryption_hash, tmp_ctl->encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, tmp_ctl->jnl_fn_len, tmp_ctl->jnl_fn); } # endif if (did_jnl_ensure_open) @@ -454,11 +449,14 @@ int gtmsource_ctl_close(void) the current head from the list; if there is an error path that returns us to this function before all elements were freed, we won't try to free elements that have been freed already */ - DEBUG_ONLY( - csa = &FILE_INFO(ctl->reg)->s_addrs; - /* jpc->channel should never be set to a valid value outside of repl_ctl_create */ - assert((NULL != csa->jnl) && (NOJNL == csa->jnl->channel)); - ) +# ifdef DEBUG + csa = &FILE_INFO(ctl->reg)->s_addrs; + /* jpc->channel should never be set to a valid value outside of repl_ctl_create. The only exception is if + * we were interrupted in the middle of repl_ctl_create by an external signal in which case the process + * better be exiting. Assert that. + */ + assert(((NULL != csa->jnl) && (NOJNL == csa->jnl->channel)) || process_exiting); +# endif repl_ctl_close(ctl); } ctl = repl_ctl_list; diff --git a/sr_port/gtmsource_heartbeat.h b/sr_port/gtmsource_heartbeat.h index ed4291e..b6de3e8 100644 --- a/sr_port/gtmsource_heartbeat.h +++ b/sr_port/gtmsource_heartbeat.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,15 +12,14 @@ #ifndef GTMSOURCE_HEARTBEAT_H #define GTMSOURCE_HEARTBEAT_H -#define gtmsource_stall_heartbeat heartbeat_stalled = TRUE; -#define gtmsource_restart_heartbeat heartbeat_stalled = FALSE; #define gtmsource_is_heartbeat_stalled (heartbeat_stalled) + #ifndef REPL_DISABLE_HEARTBEAT -#define gtmsource_is_heartbeat_due(now) \ +#define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) \ (0 != last_sent_time \ - && difftime(*(now), last_sent_time) >= (double)jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD]) + && difftime(*(NOW), last_sent_time) >= (double)jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD]) #else -#define gtmsource_is_heartbeat_due(now) FALSE +#define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) FALSE #endif GBLREF boolean_t heartbeat_stalled; diff --git a/sr_port/gtmsource_poll_actions.c b/sr_port/gtmsource_poll_actions.c index e2093f8..e30dd43 100644 --- a/sr_port/gtmsource_poll_actions.c +++ b/sr_port/gtmsource_poll_actions.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc.* + * Copyright 2001, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -51,11 +51,18 @@ GBLREF gtmsource_state_t gtmsource_state; GBLREF boolean_t gtmsource_logstats; GBLREF int gtmsource_log_fd; GBLREF FILE *gtmsource_log_fp; -GBLREF int gtmsource_statslog_fd; -GBLREF FILE *gtmsource_statslog_fp; GBLREF int gtmsource_filter; GBLREF volatile time_t gtmsource_now; GBLREF uint4 log_interval; +#ifdef UNIX +GBLREF boolean_t last_seen_freeze_flag; +#endif +error_def(ERR_REPLWARN); +#ifdef UNIX +error_def(ERR_REPLINSTFREEZECOMMENT); +error_def(ERR_REPLINSTFROZEN); +error_def(ERR_REPLINSTUNFROZEN); +#endif int gtmsource_poll_actions(boolean_t poll_secondary) { @@ -69,7 +76,6 @@ int gtmsource_poll_actions(boolean_t poll_secondary) char print_msg[1024], msg_str[1024]; boolean_t log_switched = FALSE; int status; - error_def(ERR_REPLWARN); time_t temp_time; gtm_time4_t time4; @@ -79,10 +85,33 @@ int gtmsource_poll_actions(boolean_t poll_secondary) repl_log(gtmsource_log_fp, TRUE, TRUE, "Shutdown signalled\n"); gtmsource_end(); /* Won't return */ } - if (GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_MODE_PASSIVE == gtmsource_local->mode) +# ifdef UNIX + if (jnlpool.jnlpool_ctl->freeze != last_seen_freeze_flag) + { + last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze; + if (last_seen_freeze_flag) + { + sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, + jnlpool.repl_inst_filehdr->inst_info.this_instname); + repl_log(gtmsource_log_fp, TRUE, FALSE, print_msg); + sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); + repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); + } + else + { + sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTUNFROZEN, 1, + jnlpool.repl_inst_filehdr->inst_info.this_instname); + repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); + } + } +# endif + if (GTMSOURCE_START == gtmsource_state) + return (SS_NORMAL); + if (GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsource_local->mode) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing mode from ACTIVE to PASSIVE\n"); gtmsource_state = GTMSOURCE_CHANGING_MODE; + gtmsource_local->mode = GTMSOURCE_MODE_PASSIVE; UNIX_ONLY(gtmsource_local->gtmsource_state = gtmsource_state;) return (SS_NORMAL); } @@ -95,7 +124,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary) * cause sig. time4 and temp_time are used as temporary variable for converting time to string.*/ GET_LONG(time4, &overdue_heartbeat.ack_time[0]); temp_time = time4; - time_ptr = GTM_CTIME(&temp_time); + GTM_CTIME(time_ptr, &temp_time); memcpy(time_str, time_ptr, CTIME_BEFORE_NL); time_str[CTIME_BEFORE_NL] = '\0'; VMS_ONLY(SPRINTF(msg_str, "No response received for heartbeat sent at %s with SEQNO %llu in %0.f seconds. " @@ -117,7 +146,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary) return (SS_NORMAL); } - if (gtmsource_is_heartbeat_due(&now) && !gtmsource_is_heartbeat_stalled) + if (GTMSOURCE_IS_HEARTBEAT_DUE(&now) && !heartbeat_stalled) { gtmsource_send_heartbeat(&now); if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state || @@ -139,7 +168,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary) log_switched = TRUE; repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing log file to %s\n", gtmsource_local->log_file); #ifdef UNIX - repl_log_init(REPL_GENERAL_LOG, >msource_log_fd, NULL, gtmsource_local->log_file, NULL); + repl_log_init(REPL_GENERAL_LOG, >msource_log_fd, gtmsource_local->log_file); repl_log_fd2fp(>msource_log_fp, gtmsource_log_fd); #elif defined(VMS) util_log_open(STR_AND_LEN(gtmsource_local->log_file)); @@ -155,11 +184,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary) { #ifdef UNIX gtmsource_logstats = TRUE; - repl_log_init(REPL_STATISTICS_LOG, >msource_log_fd, >msource_statslog_fd, gtmsource_local->log_file, - gtmsource_local->statslog_file); - repl_log_fd2fp(>msource_statslog_fp, gtmsource_statslog_fd); - repl_log(gtmsource_log_fp, TRUE, TRUE, "Starting stats log to %s\n", gtmsource_local->statslog_file); - repl_log(gtmsource_statslog_fp, TRUE, TRUE, "Begin statistics logging\n"); + repl_log(gtmsource_log_fp, TRUE, TRUE, "Begin statistics logging\n"); #else repl_log(gtmsource_log_fp, TRUE, TRUE, "Stats logging not supported on VMS\n"); #endif @@ -167,19 +192,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary) } else if (gtmsource_logstats && !gtmsource_local->statslog) { gtmsource_logstats = FALSE; - repl_log(gtmsource_log_fp, TRUE, TRUE, "Stopping stats log\n"); - /* Force all data out to the file before closing the file */ - repl_log(gtmsource_statslog_fp, TRUE, TRUE, "End statistics logging\n"); - CLOSEFILE_RESET(gtmsource_statslog_fd, status); /* resets "gtmsource_statslog_fd" to FD_INVALID */ - /* We need to FCLOSE because a later open() in repl_log_init() might return the same file descriptor as the one - * that we just closed. In that case, FCLOSE done in repl_log_fd2fp() affects the newly opened file and - * FDOPEN will fail returning NULL for the file pointer. So, we close both the file descriptor and file pointer. - * Note the same problem does not occur with GENERAL LOG because the current log is kept open while opening - * the new log and hence the new file descriptor will be different (we keep the old log file open in case there - * are errors during DUPing. In such a case, we do not switch the log file, but keep the current one). - * We can FCLOSE the old file pointer later in repl_log_fd2fp() */ - FCLOSE(gtmsource_statslog_fp, status); - gtmsource_statslog_fp = NULL; + repl_log(gtmsource_log_fp, TRUE, TRUE, "End statistics logging\n"); } if ((gtmsource_filter & EXTERNAL_FILTER) && ('\0' == gtmsource_local->filter_cmd[0])) { diff --git a/sr_port/gv_bind_name.c b/sr_port/gv_bind_name.c index 6e5f8f5..d1c14fb 100644 --- a/sr_port/gv_bind_name.c +++ b/sr_port/gv_bind_name.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,6 +11,7 @@ #include "mdef.h" +#include #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" @@ -37,6 +38,9 @@ GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF gd_binding *gd_map, *gd_map_top; +error_def(ERR_KEY2BIG); +error_def(ERR_GVIS); + void gv_bind_name(gd_addr *addr, mstr *targ) { gd_binding *map; @@ -47,6 +51,10 @@ void gv_bind_name(gd_addr *addr, mstr *targ) enum db_acc_method acc_meth; gd_region *reg; gvnh_reg_t *gvnh_reg; + int keylen; + char format_key[MAX_MIDENT_LEN + 1]; /* max key length + 1 byte for '^' */ + gv_namehead *tmp_gvt; + sgmnt_addrs *csa; gd_map = addr->maps; gd_map_top = gd_map + addr->n_maps; @@ -80,40 +88,53 @@ void gv_bind_name(gd_addr *addr, mstr *targ) acc_meth = gv_cur_region->dyn.addr->acc_meth; if ((dba_cm == acc_meth) || (dba_usr == acc_meth)) { - gv_target = malloc(SIZEOF(gv_namehead) + gvent.var_name.len); - memset(gv_target, 0, SIZEOF(gv_namehead) + gvent.var_name.len); - gv_target->gvname.var_name.addr = (char *)gv_target + SIZEOF(gv_namehead); - gv_target->nct = 0; - gv_target->collseq = NULL; - gv_target->regcnt = 1; - memcpy(gv_target->gvname.var_name.addr, gvent.var_name.addr, gvent.var_name.len); - gv_target->gvname.var_name.len = gvent.var_name.len; - gv_target->gvname.hash_code = gvent.hash_code; + tmp_gvt = malloc(SIZEOF(gv_namehead) + gvent.var_name.len); + memset(tmp_gvt, 0, SIZEOF(gv_namehead) + gvent.var_name.len); + tmp_gvt->gvname.var_name.addr = (char *)tmp_gvt + SIZEOF(gv_namehead); + tmp_gvt->nct = 0; + tmp_gvt->collseq = NULL; + tmp_gvt->regcnt = 1; + memcpy(tmp_gvt->gvname.var_name.addr, gvent.var_name.addr, gvent.var_name.len); + tmp_gvt->gvname.var_name.len = gvent.var_name.len; + tmp_gvt->gvname.hash_code = gvent.hash_code; } else { assert(gv_cur_region->max_key_size <= MAX_KEY_SZ); - gv_target = (gv_namehead *)targ_alloc(gv_cur_region->max_key_size, &gvent, gv_cur_region); + tmp_gvt = (gv_namehead *)targ_alloc(gv_cur_region->max_key_size, &gvent, gv_cur_region); } gvnh_reg = (gvnh_reg_t *)malloc(SIZEOF(gvnh_reg_t)); - gvnh_reg->gvt = gv_target; + gvnh_reg->gvt = tmp_gvt; gvnh_reg->gd_reg = gv_cur_region; if (NULL != tabent) { /* Since the global name was found but gv_target was null and now we created a new gv_target, * the hash table key must point to the newly created gv_target->gvname. */ - tabent->key = gv_target->gvname; + tabent->key = tmp_gvt->gvname; tabent->value = (char *)gvnh_reg; } else { - added = add_hashtab_mname((hash_table_mname *)addr->tab_ptr, &gv_target->gvname, gvnh_reg, &tabent); + added = add_hashtab_mname((hash_table_mname *)addr->tab_ptr, &tmp_gvt->gvname, gvnh_reg, &tabent); assert(added); } + gv_target = tmp_gvt; /* now that any error possibilities (out-of-memory issues in malloc/add_hashtab_mname) + * are all done, it is safe to set gv_target. Setting it before could casue gv_target + * and gv_currkey to get out of sync in case of an error condition. + */ + } + if ((keylen = gvent.var_name.len + 2) > gv_cur_region->max_key_size) /* caution: embedded assignment of "keylen" */ + { + assert(ARRAYSIZE(format_key) >= (1 + gvent.var_name.len)); + format_key[0] = '^'; + memcpy(&format_key[1], gvent.var_name.addr, gvent.var_name.len); + csa = &FILE_INFO(gv_cur_region)->s_addrs; + rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_KEY2BIG, 4, keylen, (int4)gv_cur_region->max_key_size, + REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, 1 + gvent.var_name.len, format_key); } - change_reg(); memcpy(gv_currkey->base, gvent.var_name.addr, gvent.var_name.len); gv_currkey->base[gvent.var_name.len] = 0; gvent.var_name.len++; gv_currkey->base[gvent.var_name.len] = 0; gv_currkey->end = gvent.var_name.len; gv_currkey->prev = 0; + change_reg(); return; } diff --git a/sr_port/gv_init_reg.c b/sr_port/gv_init_reg.c index 9e9be16..feaff1b 100644 --- a/sr_port/gv_init_reg.c +++ b/sr_port/gv_init_reg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,45 +33,27 @@ GBLREF gd_region *gv_cur_region; void gv_init_reg (gd_region *reg) { - gv_namehead *g; - sgmnt_addrs *csa; -#ifdef NOLICENSE - licensed= TRUE ; -#else - CRYPT_CHKSYSTEM ; -#endif +# ifdef NOLICENSE + licensed = TRUE; +# else + CRYPT_CHKSYSTEM; +# endif switch (reg->dyn.addr->acc_meth) { - case dba_usr: - gvusr_init (reg, &gv_cur_region, &gv_currkey, &gv_altkey); - break; - /* we may be left in dba_cm state for gt_cm, if we have rundown the db and again accessed - the db without quitting out of gtm */ - case dba_cm: - case dba_mm: - case dba_bg: - if (!reg->open) - gvcst_init(reg); - break; - default: - GTMASSERT; + case dba_usr: + gvusr_init (reg, &gv_cur_region, &gv_currkey, &gv_altkey); + break; + /* we may be left in dba_cm state for gt_cm, if we have rundown the db and again accessed + the db without quitting out of gtm */ + case dba_cm: + case dba_mm: + case dba_bg: + if (!reg->open) + gvcst_init(reg); + break; + default: + GTMASSERT; } assert(reg->open); - GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(reg->max_key_size)); - if (reg->dyn.addr->acc_meth == dba_bg || reg->dyn.addr->acc_meth == dba_mm) - { - if (!reg->was_open) - { - csa = (sgmnt_addrs*)&FILE_INFO(reg)->s_addrs; - g = csa->dir_tree; - if (NULL != g) - { /* It is possible that dir_tree has already been targ_alloc'ed. This is because GT.CM or VMS DAL - * calls can run down regions without the process halting out. We don't want to double malloc. - */ - g->clue.end = 0; - } - SET_CSA_DIR_TREE(csa, reg->max_key_size, reg); - } - } return; } diff --git a/sr_port/gv_rundown.c b/sr_port/gv_rundown.c index 8fe1450..f2cabb3 100644 --- a/sr_port/gv_rundown.c +++ b/sr_port/gv_rundown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,11 +36,13 @@ #include "ast.h" #include "repl_msg.h" #include "gtmsource.h" +#include "gtmrecv.h" #include "error.h" #ifdef UNIX #include "io.h" #include "gtmsecshr.h" #include "mutex.h" +#include "ftok_sems.h" #endif #include "tp_change_reg.h" @@ -53,22 +55,41 @@ #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif +#if defined(DEBUG) && defined(UNIX) +#include "anticipatory_freeze.h" +#endif + GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF boolean_t pool_init; GBLREF jnlpool_addrs jnlpool; +GBLREF recvpool_addrs recvpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +GBLREF gd_region *ftok_sem_reg; + +#if defined(DEBUG) && defined(UNIX) +GBLREF boolean_t is_jnlpool_creator; +error_def(ERR_TEXT); +#endif +error_def(ERR_NOTALLDBRNDWN); void gv_rundown(void) { gd_region *r_top, *r_save, *r_local; gd_addr *addr_ptr; sgm_info *si; -#ifdef VMS + int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ +# ifdef VMS vms_gds_info *gds_info; -#endif +# elif UNIX + unix_db_info *udi; +# endif +#if defined(DEBUG) && defined(UNIX) + sgmnt_addrs *csa; +# endif + DCL_THREADGBL_ACCESS; - error_def(ERR_TEXT); + SETUP_THREADGBL_ACCESS; r_save = gv_cur_region; /* Save for possible core dump */ gvcmy_rundown(); @@ -85,9 +106,23 @@ void gv_rundown(void) * Hence the (dba_cm != ...) check in the if above. Note that for GT.CM client regions, * region->open is TRUE although cs_addrs is NULL. */ +# if defined(DEBUG) && defined(UNIX) + if (is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE && TREF(gtm_test_fake_enospc)) + { /* Clear ENOSPC faking now that we are running down */ + csa = REG2CSA(r_local); + if (csa->nl->fake_db_enospc || csa->nl->fake_jnl_enospc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, + 2, LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc")); + csa->nl->fake_db_enospc = FALSE; + csa->nl->fake_jnl_enospc = FALSE; + } + } +# endif gv_cur_region = r_local; tp_change_reg(); - gds_rundown(); + UNIX_ONLY(rundown_status |=) gds_rundown(); + /* Now that gds_rundown is done, free up the memory associated with the region. * Ideally the following memory freeing code should go to gds_rundown, but * GT.CM calls gds_rundown() and we want to reuse memory for GT.CM. @@ -176,4 +211,38 @@ void gv_rundown(void) #endif #endif jnlpool_detach(); +# ifdef UNIX + /* Clean up any left-over ftok semaphores. This part of the code can be reached by almost all of the exit handling routines. + * If the ftok semaphore is grabbed, but not released, ftok_sem_reg will have a non-null value and grabbed_ftok_sem will be + * TRUE. We cannot rely on gv_cur_region always as it is used in so many places in so many ways. + * Note: Typically, it should suffice to check for ftok_sem_reg being non-null and pass that to ftok_sem_release. But, there + * are some cases where ftok_sem_reg can be NULL and yet jnlpool.jnlpool_dummy_reg is non-null and the process holds an ftok + * semaphore. For instance, if GT.M opened a particular region and then did a jnlpool_init which ended up with an rts_error + * (after obtaining the ftok semaphore on jnlpool_dummy_reg), gds_rundown done above (to rundown the database) sets + * ftok_sem_reg to NULL (as part of ftok_sem_release). But, jnlpool_dummy_reg is still non-null and the lingering ftok + * should be released. So, even though a subset of the below conditions should be enough, we check for all there cases just + * to be safe. + */ + if (ftok_sem_reg) + { + udi = FILE_INFO(ftok_sem_reg); + assert(udi->grabbed_ftok_sem); + ftok_sem_release(ftok_sem_reg, TRUE, TRUE); + } + if (NULL != jnlpool.jnlpool_dummy_reg) + { + udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); + if (udi->grabbed_ftok_sem) + ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + } + if (NULL != recvpool.recvpool_dummy_reg) + { + udi = FILE_INFO(recvpool.recvpool_dummy_reg); + if (udi->grabbed_ftok_sem) + ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); + } +# endif + + if (EXIT_NRM != rundown_status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBRNDWN); } diff --git a/sr_port/gv_select.c b/sr_port/gv_select.c index 1c032e3..8bf81be 100644 --- a/sr_port/gv_select.c +++ b/sr_port/gv_select.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -111,7 +111,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist } if (0 >= len) { - gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } c = gmap_beg.addr; @@ -123,7 +123,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist len--; } else { - gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } num_quote--; @@ -153,7 +153,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist *c = '~'; } else if (':' != *c) { - gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } else { @@ -170,7 +170,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist MSTR_CMP(gmap_beg, gmap_end, rslt); if (((c - gmap_end.addr) != gmap_end.len) || (0 < rslt)) { - gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } } @@ -253,7 +253,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist { if (cs_addrs->hdr->freeze) { - gtm_putmsg(VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len, gv_cur_region->rname); mupip_exit(ERR_MUNOFINISH); } @@ -261,7 +261,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist if (gv_cur_region->read_only) { util_out_print("Cannot freeze the database",TRUE); - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); mupip_exit(ERR_MUNOFINISH); } @@ -270,7 +270,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist hiber_start(1000); if (mu_ctrly_occurred || mu_ctrlc_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FREEZECTRL); mupip_exit(ERR_MUNOFINISH); } } @@ -281,7 +281,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist gl_ptr = (glist*)malloc(SIZEOF(glist) - 1 + curr_gbl_name.str.len); gl_ptr->name.mvtype = MV_STR; gl_ptr->name.str.addr = (char*)gl_ptr->nbuf; - gl_ptr->name.str.len = curr_gbl_name.str.len; + gl_ptr->name.str.len = MIN(curr_gbl_name.str.len, MAX_MIDENT_LEN); memcpy(gl_ptr->nbuf, curr_gbl_name.str.addr, curr_gbl_name.str.len); gl_ptr->next = 0; if (append_gbl) diff --git a/sr_port/gvcst_blk_search.c b/sr_port/gvcst_blk_search.c index 39642e2..c74d332 100644 --- a/sr_port/gvcst_blk_search.c +++ b/sr_port/gvcst_blk_search.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -99,6 +99,8 @@ GBLREF unsigned int t_tries; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; +error_def(ERR_TEXT); + #ifdef DEBUG #include "gdscc.h" @@ -130,8 +132,6 @@ static void gvcst_search_fail(srch_blk_status *pStat) { char buff[1024], crbuff[256], regbuff[512]; - error_def(ERR_TEXT); - assert(CDB_STAGNATE <= t_tries); assert((NULL != pStat) && ((NULL != pStat->cr) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)) && (NULL != cs_addrs)); if (NULL != pStat) @@ -169,6 +169,7 @@ enum cdb_sc gvcst_search_blk (gv_key *pKey, srch_blk_status *pStat) sm_uc_ptr_t pBlkBase, pRecBase, pTop, pRec, pPrevRec; unsigned char *pCurrTarg, *pTargKeyBase; unsigned short nRecLen; + int tmp_cmpc; /* the following load code (and code in a few other places) is coded in a "assember" style * in an attempt to encourage the compiler to get it efficient; @@ -220,7 +221,8 @@ enum cdb_sc gvcst_search_blk (gv_key *pKey, srch_blk_status *pStat) /* If current compression count > last match, then this record also matches on 'last match' characters; keep looping */ - if ((nTmp = ((rec_hdr_ptr_t)pRec)->cmpc) > nMatchCnt) + EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp) + if (nTmp > nMatchCnt) continue; if (nTmp < nMatchCnt) @@ -276,6 +278,7 @@ enum cdb_sc gvcst_search_tail (gv_key *pKey, srch_blk_status *pStat, gv_key *pOl sm_uc_ptr_t pBlkBase, pRecBase, pRec, pTop, pPrevRec; unsigned char *pCurrTarg, *pTargKeyBase, *pOldKeyBase, *pCurrTargPos; unsigned short nRecLen; + int tmp_cmpc; /* see comment in gvcst_search_blk above on coding style */ @@ -317,8 +320,9 @@ enum cdb_sc gvcst_search_tail (gv_key *pKey, srch_blk_status *pStat, gv_key *pOl } else { GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz); - - if ((nFlg = nTmp = ((rec_hdr_ptr_t)pRec)->cmpc) != 0) + EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp); + nFlg = nTmp; + if (nFlg != 0) { do { @@ -391,7 +395,8 @@ enum cdb_sc gvcst_search_tail (gv_key *pKey, srch_blk_status *pStat, gv_key *pOl pRecBase = pRec; /* If current compression count > last match, then this record also matches on 'last match' characters; keep looping */ - if ((nTmp = ((rec_hdr_ptr_t)pRec)->cmpc) > nMatchCnt) + EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp); + if (nTmp > nMatchCnt) continue; if (nTmp < nMatchCnt) /* cc_term: */ { /* Terminated on compression count < previous match, diff --git a/sr_port/gvcst_bmp_mark_free.c b/sr_port/gvcst_bmp_mark_free.c index c6da586..f90bd20 100644 --- a/sr_port/gvcst_bmp_mark_free.c +++ b/sr_port/gvcst_bmp_mark_free.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,9 +45,15 @@ #include "gvcst_bmp_mark_free.h" #include "t_busy2free.h" #include "t_abort.h" +#ifdef UNIX +#include "db_snapshot.h" +#endif +#include "muextr.h" +#include "mupip_reorg.h" GBLREF char *update_array, *update_array_ptr; GBLREF cw_set_element cw_set[]; +GBLREF unsigned char cw_set_depth; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF unsigned char rdfail_detail; @@ -82,9 +88,11 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) cache_rec_ptr_t cr; enum db_ver ondsk_blkver; enum cdb_sc status; + boolean_t mark_level_as_special; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + TREF(in_gvcst_bmp_mark_free) = TRUE; assert(inctn_bmp_mark_free_gtm == inctn_opcode || inctn_bmp_mark_free_mu_reorg == inctn_opcode); /* Note down the desired_db_format_tn before you start relying on cs_data->fully_upgraded. * If the db is fully_upgraded, take the optimal path that does not need to read each block being freed. @@ -106,14 +114,13 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) assert(cs_data->db_got_to_v5_once); /* assert all V4 fmt blocks (including RECYCLED) have space for V5 upgrade */ inctn_detail.blknum_struct.blknum = 0; /* to indicate no adjustment to "blks_to_upgrd" necessary */ /* If any of the mini transaction below restarts because of an online rollback, we don't want the application - * refresh to happen (like $ZONLNRLBK++ or rts_error(DBROLLEDBACK). This is because, although we are currently in + * refresh to happen (like $ZONLNRLBK++ or rts_error(DBROLLEDBACK). This is because, although we are currently in {BYPASSOK} * non-tp (dollar_tleve = 0), we could actually be in a TP transaction and have actually faked dollar_tlevel. In * such a case, we should NOT * be issuing a DBROLLEDBACK error as TP transactions are supposed to just restart in * case of an online rollback. So, set the global variable that gtm_onln_rlbk_clnup can check and skip doing the * application refresh, but will reset the clues. The next update will see the cycle mismatch and will accordingly * take the right action. */ - UNIX_ONLY(TREF(only_reset_clues_if_onln_rlbk) = TRUE); for ( ; blk < blk_top; blk = nextblk) { if (0 != blk->flag) @@ -138,6 +145,7 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) len = (unsigned int)((char *)nextblk - (char *)blk); update_array_ptr = (char *)updptr; alt_hist.h[0].blk_num = 0; /* need for calls to T_END for bitmaps */ + alt_hist.h[0].blk_target = NULL; /* need to initialize for calls to T_END */ /* the following assumes SIZEOF(blk_ident) == SIZEOF(int) */ assert(SIZEOF(blk_ident) == SIZEOF(int)); *(int *)update_array_ptr = 0; @@ -156,6 +164,38 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) ret_tn = 0; break; } +# ifdef GTM_SNAPSHOT + /* if this is freeing a level-0 directory tree block, we need to transition the block to free + * right away and write its before-image thereby enabling fast integ to avoid writing level-0 + * block before-images altogether. It is possible the fast integ hasn't started at this stage, + * so we cannot use FASTINTEG_IN_PROG in the if condition, but fast integ may already start later + * at bg/mm update stage, so we always need to prepare cw_set element + */ + if ((MUSWP_FREE_BLK == TREF(in_mu_swap_root_state)) && blk->level) + { /* blk->level was set as 1 for level-0 DIR tree block in mu_swap_root */ + /* for mu_swap_root, only one block is freed during bmp_mark_free */ + assert(1 == ks->used); + ctn = cs_addrs->ti->curr_tn; + alt_hist.h[0].cse = NULL; + alt_hist.h[0].tn = ctn; + alt_hist.h[0].blk_num = blk->block; + alt_hist.h[1].blk_num = 0; /* this is to terminate history reading in t_end */ + if (NULL == (alt_hist.h[0].buffaddr = t_qread(alt_hist.h[0].blk_num, + (sm_int_ptr_t)&alt_hist.h[0].cycle, + &alt_hist.h[0].cr))) + { + t_retry((enum cdb_sc)rdfail_detail); + continue; + } + t_busy2free(&alt_hist.h[0]); + /* The special level value will be used later in t_end to indicate + * before_image of this block will be written to snapshot file + */ + cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; + mark_level_as_special = TRUE; + } else + mark_level_as_special = FALSE; +# endif bmphist.blk_num = bit_map; if (NULL == (bmphist.buffaddr = t_qread(bmphist.blk_num, (sm_int_ptr_t)&bmphist.cycle, &bmphist.cr))) @@ -164,19 +204,29 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) continue; } t_write_map(&bmphist, (uchar_ptr_t)update_array, ctn, -(int4)(nextblk - blk)); +# ifdef GTM_SNAPSHOT + if (mark_level_as_special) + { + /* The special level value will be used later in gvcst_map_build to set the block to be + * freed as free rather than recycled + */ + cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; + } +# endif UNIX_ONLY(DEBUG_ONLY(lcl_t_tries = t_tries)); if ((trans_num)0 == (ret_tn = t_end(&alt_hist, NULL, TN_NOT_SPECIFIED))) { # ifdef UNIX assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); - status = t_fail_hist[t_tries - 1]; - if ((cdb_sc_onln_rlbk1 == status) || (cdb_sc_onln_rlbk2 == status)) + status = LAST_RESTART_CODE; + if ((cdb_sc_onln_rlbk1 == status) || (cdb_sc_onln_rlbk2 == status) + || TREF(rlbk_during_redo_root)) { /* t_end restarted due to online rollback. Discard bitmap free-up and return control * to the application. But, before that reset only_reset_clues_if_onln_rlbk to FALSE */ - TREF(only_reset_clues_if_onln_rlbk) = FALSE; - send_msg(VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region), - DB_LEN_STR(gv_cur_region)); + TREF(in_gvcst_bmp_mark_free) = FALSE; + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, + REG_LEN_STR(gv_cur_region), DB_LEN_STR(gv_cur_region)); t_abort(gv_cur_region, cs_addrs); return ret_tn; /* actually 0 */ } @@ -192,7 +242,6 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) break; } } - TREF(only_reset_clues_if_onln_rlbk) = FALSE; } /* for all blocks in the kill_set */ for ( ; blk < blk_top; blk++) { /* Database has NOT been completely upgraded. Have to read every block that is going to be freed @@ -221,6 +270,7 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) */ alt_hist.h[0].level = 0; /* Initialize for loop below */ alt_hist.h[1].blk_num = 0; + alt_hist.h[0].blk_target = NULL; /* need to initialize for calls to T_END */ CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ assert((block_id)blk->block - bit_map); assert(SIZEOF(block_id) == SIZEOF(blk_ident)); @@ -265,7 +315,7 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) ondsk_blkver = cr->ondsk_blkver; /* Get local copy in case cr->ondsk_blkver changes between * first and second part of the || */ - assert((GDSV5 == ondsk_blkver) || (GDSV4 == ondsk_blkver)); + assert((GDSV6 == ondsk_blkver) || (GDSV4 == ondsk_blkver)); if (GDSVCURR != ondsk_blkver) inctn_detail.blknum_struct.blknum = blk->block; else @@ -278,13 +328,24 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) continue; } t_write_map(&bmphist, (uchar_ptr_t)update_array, ctn, -1); +# ifdef GTM_SNAPSHOT + if ((MUSWP_FREE_BLK == TREF(in_mu_swap_root_state)) && blk->level) + { + assert(1 == ks->used); + cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; /* special level for gvcst_map_build */ + cw_set[cw_set_depth-2].level = CSE_LEVEL_DRT_LVL0_FREE; /* special level for t_end */ + /* Here we do not need to do BIT_SET_DIR_TREE because later the block will be always written to + * snapshot file without checking whether it belongs to DIR or GV tree + */ + } +# endif UNIX_ONLY(DEBUG_ONLY(lcl_t_tries = t_tries)); if ((trans_num)0 == (ret_tn = t_end(&alt_hist, NULL, TN_NOT_SPECIFIED))) { # ifdef UNIX assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); assert(0 < t_tries); - DEBUG_ONLY(status = t_fail_hist[t_tries - 1]); /* get the recent restart code */ + DEBUG_ONLY(status = LAST_RESTART_CODE); /* get the recent restart code */ /* We don't expect online rollback related retries because we are here with the database NOT fully * upgraded. This means, online rollback cannot even start (it issues ORLBKNOV4BLK). Assert that. */ @@ -295,5 +356,7 @@ trans_num gvcst_bmp_mark_free(kill_set *ks) break; } } /* for all blocks in the kill_set */ + TREF(in_gvcst_bmp_mark_free) = FALSE; return ret_tn; } + diff --git a/sr_port/gvcst_data.c b/sr_port/gvcst_data.c index 2ea2088..30b450b 100644 --- a/sr_port/gvcst_data.c +++ b/sr_port/gvcst_data.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,25 +26,97 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +# include "wbox_test_init.h" +#endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_data prototype */ -GBLREF gv_key *gv_currkey; +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; + +GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVDATAFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_data_ch) mint gvcst_data(void) +{ + bool found, sn_tpwrapped; + boolean_t est_first_pass; + int oldend; + mint val; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + val = gvcst_data2(); +# ifdef UNIX + if (-1 != val) + { + assert(save_dollar_tlevel == dollar_tlevel); + return val; + } + oldend = gv_currkey->end; + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_data_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + /* fix up since it should only be externally counted as one $data */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_data, (gtm_uint64_t) -1); + val = gvcst_data2(); + if (-1 == val) + { /* -1 implies node exists. Need to see if a proper descendant exists */ + val = 1; + /* 0 1 0 0 <-- append that to gv_currkey */ + gv_currkey->end = oldend + 2; + gv_currkey->base[oldend + 0] = 1; + gv_currkey->base[oldend + 1] = 0; + gv_currkey->base[oldend + 2] = 0; + found = gvcst_query(); /* want to save gv_altkey? */ + if (found && (0 == memcmp(gv_currkey->base, gv_altkey->base, oldend))) + val += 10; + } + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + RESTORE_CURRKEY(gv_currkey, oldend); + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return val; +} + +mint gvcst_data2(void) { blk_hdr_ptr_t bp; - boolean_t do_rtsib; + boolean_t do_rtsib, is_dummy; enum cdb_sc status; mint val; rec_hdr_ptr_t rp; @@ -52,8 +124,10 @@ mint gvcst_data(void) srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t b_top; + int tmp_cmpc; + int data_len, cur_val_offset, realval = 0; - assert((gv_target->root < cs_addrs->ti->total_blks) || dollar_tlevel); + VMS_ONLY(assert((gv_target->root < cs_addrs->ti->total_blks) || dollar_tlevel)); T_BEGIN_READ_NONTP_OR_TP(ERR_GVDATAFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) @@ -61,6 +135,13 @@ mint gvcst_data(void) /* The following code is duplicated in gvcst_dataget. Any changes here might need to be reflected there as well */ rt_history = gv_target->alt_hist; rt_history->h[0].blk_num = 0; +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVDATAFAIL == gtm_white_box_test_case_number)) + { + t_retry(cdb_sc_blknumerr); + continue; + } +#endif if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) { t_retry(status); @@ -72,10 +153,22 @@ mint gvcst_data(void) b_top = bh->buffaddr + bp->bsiz; match = bh->curr_rec.match; do_rtsib = FALSE; + realval = 0; if (gv_currkey->end + 1 == match) { val = 1; GET_USHORT(rsiz, &rp->rsiz); +# ifdef UNIX + /* check for spanning node dummy value: a single zero byte */ + cur_val_offset = SIZEOF(rec_hdr) + match - EVAL_CMPC((rec_hdr_ptr_t)rp); + data_len = rsiz - cur_val_offset; + is_dummy = IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + cur_val_offset); + if (is_dummy) + { + realval = -1; + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(realval = 0); /* resume since this is not a spanning node */ + } +# endif rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rsiz); if ((sm_uc_ptr_t)rp > b_top) { @@ -83,7 +176,7 @@ mint gvcst_data(void) continue; } else if ((sm_uc_ptr_t)rp == b_top) do_rtsib = TRUE; - else if (rp->cmpc >= gv_currkey->end) + else if (EVAL_CMPC(rp) >= gv_currkey->end) val += 10; } else if (match >= gv_currkey->end) val = 10; @@ -121,6 +214,6 @@ mint gvcst_data(void) } } INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_data, 1); - return val; + return (0 != realval) ? realval : val; } } diff --git a/sr_port/gvcst_dataget.c b/sr_port/gvcst_dataget.c index a56e74b..4e22481 100644 --- a/sr_port/gvcst_dataget.c +++ b/sr_port/gvcst_dataget.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,13 +33,140 @@ #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_data prototype */ -GBLREF gv_key *gv_currkey; -GBLREF gv_namehead *gv_target; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF gd_region *gv_cur_region; -GBLREF uint4 dollar_tlevel; -GBLREF unsigned int t_tries; -GBLREF uint4 t_err; +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mstr nsb_dummy; + +GBLREF gv_key *gv_currkey; +GBLREF gv_namehead *gv_target; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data_ptr_t cs_data; +GBLREF gd_region *gv_cur_region; +GBLREF uint4 dollar_tlevel; +GBLREF unsigned int t_tries; +GBLREF uint4 t_err; + +error_def(ERR_GVDATAGETFAIL); +error_def(ERR_GVKILLFAIL); +error_def(ERR_GVPUTFAIL); + +enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) +{ + boolean_t gotit, gotspan, gotpiece, gotdummy, sn_tpwrapped, check_rtsib; + mint dollar_data_ctrl, dollar_data_piece, dollar_data_null, dg_info; + mval val_ctrl, val_piece; + int gblsize, chunk_size, i, total_len, oldend, tmp_numsubs; + unsigned short numsubs; + sm_uc_ptr_t sn_ptr; + enum cdb_sc status; + int save_dollar_tlevel; + + dg_info = *dollar_data; + assert((DG_GETONLY == dg_info) || (DG_DATAGET == dg_info)); + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + assert(dollar_tlevel); + if (cdb_sc_normal != (status = gvcst_dataget2(dollar_data, val, NULL))) + { + assert(save_dollar_tlevel == dollar_tlevel); + return status; + } +# ifdef UNIX + gotit = *dollar_data % 10; + if (gotit && IS_SN_DUMMY(val->str.len, val->str.addr)) + { /* We just found a dummy nodelet. Need to look for chunks of spanning node */ + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return status); + oldend = gv_currkey->end; + APPEND_HIDDEN_SUB(gv_currkey); + /* Search for control subscript */ + dollar_data_ctrl = dg_info; + if (cdb_sc_normal != (status = gvcst_dataget2(&dollar_data_ctrl, &val_ctrl, NULL))) + { + RESTORE_CURRKEY(gv_currkey, oldend); + assert(save_dollar_tlevel == dollar_tlevel); + return status; + } + gotspan = dollar_data_ctrl % 10; + if (gotspan) + { /* Spanning node indeed, as expected. Piece it together. Recompute dollar_data. */ + if (val_ctrl.str.len == 6) + { + GET_NSBCTRL(val_ctrl.str.addr, numsubs, gblsize); + } else + { + SSCANF(val_ctrl.str.addr, "%d,%d", &tmp_numsubs, &gblsize); + numsubs = tmp_numsubs; + } + ENSURE_STP_FREE_SPACE(gblsize + cs_addrs->hdr->blk_size); /* give leeway.. think about more */ + DBG_MARK_STRINGPOOL_UNUSABLE; + sn_ptr = stringpool.free; + total_len = 0; + val->str.addr = (char *)sn_ptr; + for (i = 0; i < numsubs; i++) + { + NEXT_HIDDEN_SUB(gv_currkey, i); + /* We only need to do a rtsib on the last chunk. Only there can we check for descendants */ + check_rtsib = (((i + 1) == numsubs) && (DG_DATAGET == dg_info)); + dollar_data_piece = (check_rtsib) ? DG_GETSNDATA : DG_GETONLY; + if (cdb_sc_normal != (status = gvcst_dataget2(&dollar_data_piece, &val_piece, sn_ptr))) + { + RESTORE_CURRKEY(gv_currkey, oldend); + DBG_MARK_STRINGPOOL_USABLE; + assert(save_dollar_tlevel == dollar_tlevel); + return status; + } + gotpiece = dollar_data_piece % 10; + if (gotpiece) + { + sn_ptr += val_piece.str.len; + total_len += val_piece.str.len; + } + assert(total_len < (gblsize + cs_addrs->hdr->blk_size)); + if (!gotpiece || (total_len > gblsize)) + break; + } + if ((total_len != gblsize) || (i != numsubs)) + { /* Fetched value either too small or too big compared to what control subscript says */ + RESTORE_CURRKEY(gv_currkey, oldend); + DBG_MARK_STRINGPOOL_USABLE; + assert(save_dollar_tlevel == dollar_tlevel); + return cdb_sc_spansize; + } + assert(val->mvtype == MV_STR); + val->str.len = gblsize; + stringpool.free += gblsize; + DBG_MARK_STRINGPOOL_USABLE; + if (check_rtsib) + { + *dollar_data = dollar_data_piece; + if ((11 != dollar_data_piece) && cs_data->std_null_coll) + { /* Check for a null-subscripted descendant. Append null sub to gv_currkey and check $data */ + RESTORE_CURRKEY(gv_currkey, oldend); + gv_currkey->end = oldend + 2; + gv_currkey->base[oldend + 0] = 1; + gv_currkey->base[oldend + 1] = 0; + gv_currkey->base[oldend + 2] = 0; + dollar_data_null = DG_DATAONLY; + gvcst_dataget2(&dollar_data_null, &val_piece, NULL); + if (dollar_data_null) + *dollar_data = 11; /* Child found */ + RESTORE_CURRKEY(gv_currkey, oldend); + } + } + } + RESTORE_CURRKEY(gv_currkey, oldend); + } + if (DG_GETONLY == dg_info) + *dollar_data = (mint)gotit; /* Just return 1 if it exists and 0 if it doesn't */ + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return status; +} /* This function is the equivalent of invoking gvcst_data & gvcst_get at the same time. * One crucial difference is that this function does NOT handle restarts by automatically invoking t_retry. @@ -48,32 +175,32 @@ GBLREF uint4 t_err; * wrapped gvcst_put or gvcst_kill trigger-invoking update transaction. Additionally, this function assumes * that it is called always inside of TP (i.e. dollar_tlevel is non-zero). */ -enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) +enum cdb_sc gvcst_dataget2(mint *dollar_data, mval *val, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; boolean_t do_rtsib; enum cdb_sc status; - mint dlr_data; + mint dlr_data, dg2_info; rec_hdr_ptr_t rp; unsigned short match, rsiz; srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t b_top; - int key_size, data_len; + int key_size, data_len, delta; uint4 save_t_err; - error_def(ERR_GVDATAGETFAIL); - error_def(ERR_GVKILLFAIL); - /* The following code is lifted from gvcst_data. Any changes here might need to be reflected there as well */ assert(dollar_tlevel); assert((CDB_STAGNATE > t_tries) || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ save_t_err = t_err; - assert(ERR_GVKILLFAIL == save_t_err); /* this function should currently be called only from gvcst_kill */ + assert((ERR_GVKILLFAIL == save_t_err) || (ERR_GVPUTFAIL == save_t_err)); /* called only from gvcst_kill and gvcst_put */ t_err = ERR_GVDATAGETFAIL; /* switch t_err to reflect dataget sub-operation (under the KILL operation) */ /* In case of a failure return, it is ok to return with t_err set to ERR_GVDATAGETFAIL as that gives a better * picture of exactly where in the transaction the failure occurred. */ + dg2_info = *dollar_data; + assert((DG_GETONLY == dg2_info) || (DG_DATAGET == dg2_info) || (DG_DATAONLY == dg2_info) || (DG_GETSNDATA == dg2_info)); + delta = (DG_GETSNDATA == dg2_info) ? 4 : 0; /* next key doesn't need to match hidden subscript */ rt_history = gv_target->alt_hist; rt_history->h[0].blk_num = 0; if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) @@ -95,19 +222,26 @@ enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) dlr_data = 1; /* the following code is lifted from gvcst_get. any changes here might need to be reflected there as well */ GET_USHORT(rsiz, &rp->rsiz); - data_len = rsiz + rp->cmpc - SIZEOF(rec_hdr) - key_size; + data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign1; return status; - } else + } else if (DG_DATAONLY != dg2_info) { - ENSURE_STP_FREE_SPACE(data_len); - memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); - val->str.addr = (char *)stringpool.free; val->str.len = data_len; - stringpool.free += data_len; + if (!sn_ptr) + { + ENSURE_STP_FREE_SPACE(data_len); + memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); + val->str.addr = (char *)stringpool.free; + stringpool.free += data_len; + } else + { + memcpy(sn_ptr, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); + val->str.addr = (char *)sn_ptr; + } } /* --------------------- end code lifted from gvcst_get ---------------------------- */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rsiz); @@ -117,9 +251,9 @@ enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) return status; } else if ((sm_uc_ptr_t)rp == b_top) do_rtsib = TRUE; - else if (rp->cmpc >= gv_currkey->end) + else if (EVAL_CMPC(rp) + delta >= gv_currkey->end) dlr_data += 10; - } else if (match >= gv_currkey->end) + } else if (match + delta >= gv_currkey->end) dlr_data = 10; else { @@ -127,11 +261,11 @@ enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) if (rp == (rec_hdr_ptr_t)b_top) do_rtsib = TRUE; } - if (do_rtsib && (cdb_sc_endtree != (status = gvcst_rtsib(rt_history, 0)))) - { + if ((DG_GETONLY != dg2_info) && do_rtsib && (cdb_sc_endtree != (status = gvcst_rtsib(rt_history, 0)))) + { /* only do rtsib and search_blk if full data information is desired */ if ((cdb_sc_normal != status) || (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, rt_history->h)))) return status; - if (rt_history->h[0].curr_rec.match >= gv_currkey->end) + if (rt_history->h[0].curr_rec.match + delta >= gv_currkey->end) { assert(1 >= dlr_data); dlr_data += 10; @@ -140,7 +274,7 @@ enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) status = tp_hist(0 == rt_history->h[0].blk_num ? NULL : rt_history); if (cdb_sc_normal != status) return status; - *dollar_data = dlr_data; + *dollar_data = (DG_GETONLY != dg2_info) ? dlr_data : (dlr_data % 10); t_err = save_t_err; /* restore t_err to what it was at function entry */ return status; } diff --git a/sr_port/gvcst_delete_blk.c b/sr_port/gvcst_delete_blk.c index 7a1c084..d11ae36 100644 --- a/sr_port/gvcst_delete_blk.c +++ b/sr_port/gvcst_delete_blk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -172,7 +172,7 @@ void gvcst_delete_blk(block_id blk, int level, boolean_t committed) ks = kill_set_tail = ks->next_kill_set; } - ks->blk[ks->used].level = level; + ks->blk[ks->used].level = (level) ? 1 : 0; if (!dollar_tlevel || !chain.flag) { assert((CDB_STAGNATE > t_tries) || (blk < cs_addrs->ti->total_blks)); diff --git a/sr_port/gvcst_expand_any_key.c b/sr_port/gvcst_expand_any_key.c index 65ada75..0e52c77 100644 --- a/sr_port/gvcst_expand_any_key.c +++ b/sr_port/gvcst_expand_any_key.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -83,7 +83,7 @@ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_ GET_RSIZ(*rec_size, curptr); if (0 == cur_level || BSTAR_REC_SIZE != *rec_size) { - READ_RECORD(cur_level, curptr, *keycmpc, *rec_size, expanded_key, *keylen, status); + READ_RECORD(status, rec_size, keycmpc, keylen, expanded_key, cur_level, blk_base, curptr); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); @@ -140,7 +140,7 @@ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_ return status; if (*keylen + *keycmpc) /* Previous key exists */ { - GET_CMPC(*keycmpc, expanded_key, &expanded_star_key[0]); + GET_CMPC(*keycmpc, expanded_key, expanded_star_key); } memcpy(expanded_key, expanded_star_key, star_keylen + star_keycmpc); *keylen = star_keylen + star_keycmpc - *keycmpc; diff --git a/sr_port/gvcst_expand_free_subtree.c b/sr_port/gvcst_expand_free_subtree.c index e34a264..218f835 100644 --- a/sr_port/gvcst_expand_free_subtree.c +++ b/sr_port/gvcst_expand_free_subtree.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,6 +45,7 @@ GBLREF unsigned char rdfail_detail; GBLREF inctn_opcode_t inctn_opcode; error_def(ERR_GVKILLFAIL); +error_def(ERR_IGNBMPMRKFREE); void gvcst_expand_free_subtree(kill_set *ks_head) { @@ -66,6 +67,7 @@ void gvcst_expand_free_subtree(kill_set *ks_head) trans_num ret_tn; inctn_opcode_t save_inctn_opcode; bt_rec_ptr_t bt; + unsigned int level; csa = cs_addrs; csd = cs_data; @@ -89,6 +91,9 @@ void gvcst_expand_free_subtree(kill_set *ks_head) * and the restart logic will handle it appropriately. */ free(temp_buff); + rel_crit(gv_cur_region); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region), + DB_LEN_STR(gv_cur_region)); return; } # endif @@ -104,7 +109,7 @@ void gvcst_expand_free_subtree(kill_set *ks_head) if (!(bp = (blk_hdr_ptr_t)t_qread(blk, (sm_int_ptr_t)&cycle, &cr))) { /* This should have worked because t_qread was done in crit */ free(temp_buff); - rts_error(VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail); } if (NULL != cr) { /* It is possible that t_qread returned a buffer from first_tp_srch_status. @@ -138,7 +143,7 @@ void gvcst_expand_free_subtree(kill_set *ks_head) assert(FALSE); kill_error = cdb_sc_rmisalign; free(temp_buff); - rts_error(VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error); } GET_LONG(temp_long, (block_id_ptr_t)((sm_uc_ptr_t)rp1 - SIZEOF(block_id))); if (dollar_tlevel) @@ -151,8 +156,9 @@ void gvcst_expand_free_subtree(kill_set *ks_head) } assert(chain.flag || temp_long < csa->ti->total_blks); } - gvcst_delete_blk(temp_long, ksb->level - 1, TRUE); - if ((1 == ksb->level) && !dollar_tlevel && cs_data->dsid && !flush_cache) + level = ((blk_hdr_ptr_t)temp_buff)->levl; + gvcst_delete_blk(temp_long, level - 1, TRUE); + if ((1 == level) && !dollar_tlevel && cs_data->dsid && !flush_cache) rc_cpt_entry(temp_long); /* Invalidate single block */ } ksb->level = 0; diff --git a/sr_port/gvcst_expand_key.c b/sr_port/gvcst_expand_key.c index 5db0529..46346da 100644 --- a/sr_port/gvcst_expand_key.c +++ b/sr_port/gvcst_expand_key.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,7 @@ GBLREF unsigned int t_tries; enum cdb_sc gvcst_expand_key(blk_hdr_ptr_t bp, int4 rec_top, gv_key *key) { unsigned short temp_ushort; + int tmp_cmpc; int4 r_offset; rec_hdr_ptr_t rp, rtop; sm_uc_ptr_t p; @@ -50,7 +51,7 @@ enum cdb_sc gvcst_expand_key(blk_hdr_ptr_t bp, int4 rec_top, gv_key *key) return cdb_sc_rmisalign; } current = 1; - kend = kbase + rp->cmpc; + kend = kbase + EVAL_CMPC(rp); p = (sm_uc_ptr_t)(rp + 1); for (;;) { @@ -73,6 +74,11 @@ enum cdb_sc gvcst_expand_key(blk_hdr_ptr_t bp, int4 rec_top, gv_key *key) { key->end = kend - kbase - 1; key->prev = kprv - kbase; + if (KEY_DELIMITER == *kbase) + /* A valid key wouldn't start with a '\0' character. So the block must have been + * concurrently modified. + */ + return cdb_sc_mkblk; return cdb_sc_normal; } kprv = kend - 1; /* start of last key */ diff --git a/sr_port/gvcst_gblmod.c b/sr_port/gvcst_gblmod.c index 6af550d..d58566f 100644 --- a/sr_port/gvcst_gblmod.c +++ b/sr_port/gvcst_gblmod.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,6 +29,8 @@ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_gblmod,gvcst_search prototype */ +#include "copy.h" +#include "gtmimagename.h" /* needed for spanning nodes */ GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; @@ -36,14 +38,22 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +LITREF mstr nsb_dummy; error_def(ERR_GBLMODFAIL); bool gvcst_gblmod(mval *v) { - bool gblmod; - enum cdb_sc status; - int key_size; + boolean_t gblmod, is_dummy; + enum cdb_sc status; + int key_size, key_size2, data_len; + srch_hist *alt_history; + blk_hdr_ptr_t bp; + rec_hdr_ptr_t rp; + unsigned short match, match2, rsiz, offset_to_value, oldend; + srch_blk_status *bh; + sm_uc_ptr_t b_top; + trans_num tn_to_compare; T_BEGIN_READ_NONTP_OR_TP(ERR_GBLMODFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ @@ -52,21 +62,72 @@ bool gvcst_gblmod(mval *v) gblmod = TRUE; if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { + alt_history = gv_target->alt_hist; + alt_history->h[0].blk_num = 0; + VMS_ONLY( if (cs_addrs->hdr->resync_tn >= ((blk_hdr_ptr_t)gv_target->hist.h[0].buffaddr)->tn) gblmod = FALSE; ) - UNIX_ONLY( - if (cs_addrs->hdr->zqgblmod_tn > ((blk_hdr_ptr_t)gv_target->hist.h[0].buffaddr)->tn) +# ifdef UNIX + tn_to_compare = ((blk_hdr_ptr_t)gv_target->hist.h[0].buffaddr)->tn; + bh = gv_target->hist.h; + bp = (blk_hdr_ptr_t) bh->buffaddr; + rp = (rec_hdr_ptr_t) (bh->buffaddr + bh->curr_rec.offset); + b_top = bh->buffaddr + bp->bsiz; + GET_USHORT(rsiz, &rp->rsiz); + key_size = gv_currkey->end + 1; + data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; + match = bh->curr_rec.match; + if (key_size == match) + { + if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) + { + status = cdb_sc_rmisalign1; + t_retry(status); + continue; + } + offset_to_value = SIZEOF(rec_hdr) + key_size - EVAL_CMPC(rp); + /* If it could be a spanning node, i.e., has special value, then try to get tn from the + * block that contains the first special subscript. Since dummy nodes always have the + * same value, the tn number is not updated It s enough to do only the first piece + * since all pieces of a spanning node are killed before an update is applied. + */ + if (IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + offset_to_value)) + { + oldend = gv_currkey->end; + APPEND_HIDDEN_SUB(gv_currkey); + if (cdb_sc_normal == (status = gvcst_search(gv_currkey, alt_history))) + { + key_size2 = gv_currkey->end + 1; + match = alt_history->h[0].curr_rec.match; + if (key_size2 == match) + tn_to_compare = ((blk_hdr_ptr_t)alt_history->h[0].buffaddr)->tn; + } + else + { + gv_currkey->end = oldend; + gv_currkey->base[gv_currkey->end - 1] = KEY_DELIMITER; + gv_currkey->base[gv_currkey->end] = KEY_DELIMITER; + t_retry(status); + continue; + } + gv_currkey->end = oldend; + gv_currkey->base[gv_currkey->end - 1] = KEY_DELIMITER; + gv_currkey->base[gv_currkey->end] = KEY_DELIMITER; + } + } + if (cs_addrs->hdr->zqgblmod_tn > tn_to_compare) gblmod = FALSE; - ) +# endif if (!dollar_tlevel) { - if ((trans_num)0 == t_end(&gv_target->hist, NULL, TN_NOT_SPECIFIED)) + if ((trans_num)0 == t_end(&gv_target->hist, 0 == alt_history->h[0].blk_num ? NULL : alt_history, + TN_NOT_SPECIFIED)) continue; } else { - status = tp_hist(NULL); + status = tp_hist(0 == alt_history->h[0].blk_num ? NULL : alt_history); if (cdb_sc_normal != status) { t_retry(status); diff --git a/sr_port/gvcst_get.c b/sr_port/gvcst_get.c index 90d4702..f1c08f4 100644 --- a/sr_port/gvcst_get.c +++ b/sr_port/gvcst_get.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,12 +29,30 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +# include "wbox_test_init.h" +#endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_search,gvcst_get prototype */ +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; +LITREF mstr nsb_dummy; + GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF spdesc stringpool; @@ -43,13 +61,105 @@ GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVGETFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_get_ch) boolean_t gvcst_get(mval *v) +{ /* To avoid an extra function call, the outer if-check can be brought out into op_gvget (a final optimization) */ + boolean_t gotit, gotspan, gotpiece, gotdummy, sn_tpwrapped; + boolean_t est_first_pass; + mval val_ctrl, val_piece; + int gblsize, chunk_size, i, total_len, oldend, tmp_numsubs; + unsigned short numsubs; + sm_uc_ptr_t sn_ptr; + int debug_len; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + gotit = gvcst_get2(v, NULL); +# ifdef UNIX + DEBUG_ONLY(debug_len = (int)v->str.len); /* Ensure v isn't garbage pointer by actually accessing it */ + if (gotit && IS_SN_DUMMY(v->str.len, v->str.addr)) + { /* Start TP transaction to piece together value */ + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return gotit); + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_get_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + oldend = gv_currkey->end; + /* fix up since it should only be externally counted as one get */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); + gotdummy = gvcst_get2(v, NULL); /* Will be returned if not currently a spanning node */ + APPEND_HIDDEN_SUB(gv_currkey); + /* fix up since it should only be externally counted as one get */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); + gotspan = gvcst_get2(&val_ctrl, NULL); /* Search for control subscript */ + if (gotspan) + { /* Spanning node indeed, as expected. Piece it together */ + if (val_ctrl.str.len == 6) + { + GET_NSBCTRL(val_ctrl.str.addr, numsubs, gblsize); + } else + { /* Temporarily account for mixture of control node formats between FT04 and FT05. + * Note that this only works for block sizes greater than 1000. + */ + SSCANF(val_ctrl.str.addr, "%d,%d", &tmp_numsubs, &gblsize); + numsubs = tmp_numsubs; + } + ENSURE_STP_FREE_SPACE(gblsize + cs_addrs->hdr->blk_size); /* give leeway.. think about more */ + sn_ptr = stringpool.free; + total_len = 0; + v->str.addr = (char *)sn_ptr; + for (i = 0; i < numsubs; i++) + { + NEXT_HIDDEN_SUB(gv_currkey, i); + gotpiece = gvcst_get2(&val_piece, sn_ptr); + if (gotpiece) + { + sn_ptr += val_piece.str.len; + total_len += val_piece.str.len; + } + assert(total_len < (gblsize + cs_addrs->hdr->blk_size)); + if (!gotpiece || (total_len > gblsize)) + break; + } + if ((total_len != gblsize) || (i != numsubs)) + /* Fetched value either too small or too big compared to what control subscript says */ + t_retry(cdb_sc_spansize); + } + RESTORE_CURRKEY(gv_currkey, oldend); + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + if (gotspan) + { + v->mvtype = MV_STR; + /*v->str.addr = (char *)stringpool.free;*/ + v->str.len = gblsize; + stringpool.free += gblsize; + } + gotit = gotspan || gotdummy; + } + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return gotit; +} + +boolean_t gvcst_get2(mval *v, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; enum cdb_sc status; int key_size, data_len; + int tmp_cmpc; rec_hdr_ptr_t rp; sm_uc_ptr_t b_top; srch_blk_status *bh; @@ -71,6 +181,14 @@ boolean_t gvcst_get(mval *v) assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVGETFAIL == gtm_white_box_test_case_number)) + { + status = cdb_sc_blknumerr; + t_retry(status); + continue; + } +#endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { bh = gv_target->hist.h; @@ -83,16 +201,21 @@ boolean_t gvcst_get(mval *v) b_top = bh->buffaddr + bp->bsiz; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); GET_USHORT(rsiz, &rp->rsiz); - data_len = rsiz + rp->cmpc - SIZEOF(rec_hdr) - key_size; + data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign1; } else { - ENSURE_STP_FREE_SPACE(data_len); - assert(stringpool.top - stringpool.free >= data_len); - memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); + if (!sn_ptr) + { + ENSURE_STP_FREE_SPACE(data_len); + assert(stringpool.top - stringpool.free >= data_len); + memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); + } else + memcpy(sn_ptr, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); + if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, NULL, TN_NOT_SPECIFIED)) @@ -107,10 +230,14 @@ boolean_t gvcst_get(mval *v) } } v->mvtype = MV_STR; - v->str.addr = (char *)stringpool.free; v->str.len = data_len; - stringpool.free += data_len; - INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1); + if (!sn_ptr) + { + v->str.addr = (char *)stringpool.free; + stringpool.free += data_len; + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1); + } else + v->str.addr = (char *)sn_ptr; return TRUE; } } else diff --git a/sr_port/gvcst_init.c b/sr_port/gvcst_init.c index 37e709a..98000df 100644 --- a/sr_port/gvcst_init.c +++ b/sr_port/gvcst_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -57,6 +57,10 @@ #include "gtmmsg.h" #ifdef UNIX #include "heartbeat_timer.h" +#include "anticipatory_freeze.h" +#include "wbox_test_init.h" + +#define MAX_DBINIT_RETRY 4 #endif #ifdef GTM_FD_TRACE @@ -76,7 +80,6 @@ GBLREF ua_list *first_ua, *curr_ua; GBLREF short crash_count; GBLREF uint4 dollar_tlevel; GBLREF jnl_format_buffer *non_tp_jfb_ptr; -GBLREF unsigned char *non_tp_jfb_buff_ptr; GBLREF boolean_t mupip_jnl_recover; GBLREF buddy_list *global_tlvl_info_list; GBLREF tp_region *tp_reg_free_list; /* Ptr to list of tp_regions that are unused */ @@ -92,6 +95,11 @@ GBLREF volatile int4 fast_lock_count; GBLREF gvt_container *gvt_pending_list; GBLREF boolean_t dse_running; GBLREF jnl_gbls_t jgbl; +#ifdef UNIX +GBLREF boolean_t pool_init; +GBLREF boolean_t jnlpool_init_needed; +GBLREF jnlpool_addrs jnlpool; +#endif LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; @@ -103,6 +111,7 @@ error_def(ERR_DBNOTGDS); error_def(ERR_DBVERPERFWARN1); error_def(ERR_DBVERPERFWARN2); error_def(ERR_MMNODYNUPGRD); +error_def(ERR_REGOPENFAIL); void assert_jrec_member_offsets(void) { @@ -172,12 +181,19 @@ void assert_jrec_member_offsets(void) assert(NULL_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_null), JNL_REC_START_BNDRY))); assert(EPOCH_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_epoch), JNL_REC_START_BNDRY))); assert(EOF_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_eof), JNL_REC_START_BNDRY))); + /* Assert following comment which is relied upon in JNL_FILE_TAIL_PRESERVE macro. + * "We know PINI_RECLEN is maximum of EPOCH_RECLEN, PFIN_RECLEN, EOF_RECLEN" + */ + assert(PINI_RECLEN > EPOCH_RECLEN); + assert(PINI_RECLEN > PFIN_RECLEN); + assert(PINI_RECLEN > EOF_RECLEN); /* Assumption about the structures in code */ assert(0 == MIN_ALIGN_RECLEN % JNL_REC_START_BNDRY); assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); - assert((MAX_JNL_REC_SIZE - MAX_LOGI_JNL_REC_SIZE) > MIN_PBLK_RECLEN); + assert((SIZEOF(jnl_record) + MAX_LOGI_JNL_REC_SIZE + SIZEOF(jrec_suffix)) < MAX_JNL_REC_SIZE); assert((DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE) >= MAX_JNL_REC_SIZE);/* default alignsize supports max jnl record length */ - assert(MAX_DB_BLK_SIZE < MAX_JNL_REC_SIZE); /* Ensure a PBLK record can accommodate a full GDS block */ + assert(MAX_MAX_NONTP_JNL_REC_SIZE <= MAX_JNL_REC_SIZE); + assert(MAX_DB_BLK_SIZE < MAX_MAX_NONTP_JNL_REC_SIZE); /* Ensure a PBLK record can accommodate a full GDS block */ assert(MAX_JNL_REC_SIZE <= (1 << 24)); /* Ensure that the 24-bit length field in the journal record can accommodate the maximum journal record size */ assert(tcom_record.prefix.forwptr == tcom_record.suffix.backptr); @@ -194,6 +210,8 @@ void gvcst_init(gd_region *greg) sgmnt_data_ptr_t temp_cs_data; # endif uint4 segment_update_array_size; + int4 bsize; + boolean_t realloc_alt_buff; file_control *fc; gd_region *prev_reg, *reg_top; # ifdef DEBUG @@ -215,9 +233,16 @@ void gvcst_init(gd_region *greg) gv_namehead *gvt, *gvt_stay; gvnh_reg_t *gvnh_reg; hash_table_mname *table; - boolean_t added, first_wasopen; + boolean_t added, first_wasopen, onln_rlbk_cycle_mismatch = FALSE; intrpt_state_t save_intrpt_ok_state; +# ifdef UNIX + replpool_identifier replpool_id; + unsigned int full_len; + int4 db_init_retry; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; UNSUPPORTED_PLATFORM_CHECK; assert(!jgbl.forw_phase_recovery); CWS_INIT; /* initialize the cw_stagnate hash-table */ @@ -225,11 +250,12 @@ void gvcst_init(gd_region *greg) assert(SIZEOF(th_rec) == (SIZEOF(bt_rec) - SIZEOF(bt->blkque))); assert(SIZEOF(cache_rec) == (SIZEOF(cache_state_rec) + SIZEOF(cr->blkque))); DEBUG_ONLY(assert_jrec_member_offsets();) + assert(MAX_DB_BLK_SIZE < (1 << NEXT_OFF_MAX_BITS)); /* Ensure a off_chain record's next_off member + * can work with all possible block sizes */ set_num_additional_processors(); - DEBUG_ONLY( - /* Note that the "block" member in the blk_ident structure in gdskill.h has 28 bits. - * Currently, the maximum number of blocks is 2**28. If ever this increases, something + /* Note that the "block" member in the blk_ident structure in gdskill.h has 30 bits. + * Currently, the maximum number of blocks is 2**30. If ever this increases, something * has to be correspondingly done to the "block" member to increase its capacity. * The following assert checks that we always have space in the "block" member * to represent a GDS block number. @@ -314,20 +340,20 @@ void gvcst_init(gd_region *greg) greg->jnl_deq = csd->jnl_deq; greg->jnl_buffer_size = csd->jnl_buffer_size; greg->jnl_before_image = csd->jnl_before_image; - greg->open = TRUE; - greg->opening = FALSE; - greg->was_open = TRUE; + SET_REGION_OPEN_TRUE(greg, WAS_OPEN_TRUE); assert(1 <= csa->regcnt); csa->regcnt++; /* Increment # of regions that point to this csa */ return; } GTM_FD_TRACE_ONLY(gtm_dbjnl_dupfd_check();) /* check if any of db or jnl fds collide (D9I11-002714) */ greg->was_open = FALSE; - /* we shouldn't have crit on any region unless we are in TP and in the final retry or we are in - * mupip_set_journal trying to switch journals across all regions. Currently, there is no fine-granular - * checking for mupip_set_journal, hence a coarse MUPIP_IMAGE check for image_type + /* We shouldn't have crit on any region unless we are in TP and in the final retry or we are in mupip_set_journal trying to + * switch journals across all regions. WBTEST_HOLD_CRIT_ENABLED is an exception because it exercises a deadlock situation so + * it needs to hold multiple crits at the same time. Currently, there is no fine-granular checking for mupip_set_journal, + * hence a coarse MUPIP_IMAGE check for image_type. */ - assert(dollar_tlevel && (CDB_STAGNATE <= t_tries) || IS_MUPIP_IMAGE || (0 == have_crit(CRIT_HAVE_ANY_REG))); + assert(dollar_tlevel && (CDB_STAGNATE <= t_tries) || IS_MUPIP_IMAGE || (0 == have_crit(CRIT_HAVE_ANY_REG)) + || WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED)); if (dollar_tlevel && (0 != have_crit(CRIT_HAVE_ANY_REG))) { /* To avoid deadlocks with currently holding crits and the DLM lock request to be done in db_init(), * we should insert this region in the tp_reg_list and tp_restart should do the gvcst_init after @@ -352,9 +378,9 @@ void gvcst_init(gd_region *greg) csa->jnl = 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 */ -# ifdef VMS csa->db_addrs[0] = csa->db_addrs[1] = NULL; csa->lock_addrs[0] = csa->lock_addrs[1] = NULL; +# ifdef VMS greg_acc_meth = greg->dyn.addr->acc_meth; assert(dba_cm != greg_acc_meth); temp_cs_data = (sgmnt_data_ptr_t)cs_data_buff; @@ -437,15 +463,46 @@ void gvcst_init(gd_region *greg) assert(268 == OFFSETOF(node_local, now_running[0])); assert(36 == SIZEOF(((node_local *)NULL)->now_running)); assert(36 == MAX_REL_NAME); - UNIX_ONLY(START_HEARTBEAT_IF_NEEDED;) +# ifdef UNIX + START_HEARTBEAT_IF_NEEDED; + if (!pool_init && jnlpool_init_needed && ANTICIPATORY_FREEZE_AVAILABLE && REPL_INST_AVAILABLE) + jnlpool_init(GTMRELAXED, (boolean_t)FALSE, (boolean_t *)NULL); + /* Any LSEEKWRITEs hence forth will wait if the instance is frozen. To aid in printing the region information before + * and after the wait, csa->region is referenced. Since it is NULL at this point, set it to greg. This is a safe + * thing to do since csa->region is anyways set in db_common_init (few lines below). + */ + csa->region = greg; +# endif /* Protect the db_init and the code below until we set greg->open to TRUE. This is needed as otherwise, * if a MUPIP STOP is issued to this process at a time-window when db_init is completed but greg->open * is NOT set to TRUE, will cause gds_rundown NOT to clean up the shared memory created by db_init and * thus would be left over in the system. */ DEFER_INTERRUPTS(INTRPT_IN_GVCST_INIT); - VMS_ONLY(db_init(greg, temp_cs_data);) - UNIX_ONLY(db_init(greg);) + VMS_ONLY(db_init(greg, temp_cs_data)); +# ifdef UNIX + db_init_retry = 0; + GTM_WHITE_BOX_TEST(WBTEST_HOLD_FTOK_UNTIL_BYPASS, db_init_retry, 3); + for (; db_init_retry < MAX_DBINIT_RETRY; db_init_retry++) + { + if (0 == db_init(greg)) + break; + db_init_err_cleanup(MAX_DBINIT_RETRY > (db_init_retry + 1)); + } + if (MAX_DBINIT_RETRY == db_init_retry) /* We retried enough. Error out. */ + { + assert(IS_LKE_IMAGE || IS_DSE_IMAGE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REGOPENFAIL, 4, REG_LEN_STR(greg), DB_LEN_STR(greg)); + } + +# endif + /* At this point, we have initialized the database, but haven't yet set reg->open to TRUE. If any rts_errors happen in + * the meantime, there are no condition handlers established to handle the rts_error. More importantly, it is non-trivial + * to add logic to such a condition handler to undo the effects of db_init. Also, in some cases, the rts_error can can + * confuse future calls of db_init. By invoking DBG_MARK_RTS_ERROR_UNUSABLE, we can catch any rts_errors in future and + * eliminate it on a case by case basis. + */ + UNIX_ONLY(DBG_MARK_RTS_ERROR_UNUSABLE); crash_count = csa->critical->crashcnt; csa->regnum = ++region_open_count; csd = csa->hdr; @@ -458,17 +515,6 @@ void gvcst_init(gd_region *greg) /* set csd and fill in selected fields */ assert(greg->dyn.addr->acc_meth == csd->acc_meth); /* db_init should have made sure this assert holds good */ greg_acc_meth = csd->acc_meth; - switch (greg_acc_meth) - { - case dba_mm: - csa->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_ulong_t)csd + (int)(csd->start_vbn - 1) * DISK_BLOCK_SIZE); - break; - case dba_bg: - db_csh_ini(csa); - break; - default: - GTMASSERT; - } /* It is necessary that we do the pending gv_target list reallocation BEFORE db_common_init as the latter resets * greg->max_key_size to be equal to the csd->max_key_size and hence process_gvt_pending_list might wrongly conclude * that NO reallocation (since it checks greg->max_key_size with csd->max_key_size) is needed when in fact a @@ -492,9 +538,9 @@ void gvcst_init(gd_region *greg) && COMPSWAP_LOCK(&csd->next_upgrd_warn.time_latch, next_warn_uint4, 0, (curr_time_uint4 + UPGRD_WARN_INTERVAL), 0)) { /* The msg is due and we have successfully updated the next time interval */ if (GDSVCURR != csd->desired_db_format) - send_msg(VARLSTCNT(4) ERR_DBVERPERFWARN1, 2, DB_LEN_STR(greg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN1, 2, DB_LEN_STR(greg)); else - send_msg(VARLSTCNT(4) ERR_DBVERPERFWARN2, 2, DB_LEN_STR(greg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN2, 2, DB_LEN_STR(greg)); } /* Compute the maximum journal space requirements for a PBLK (including possible ALIGN record). @@ -541,22 +587,37 @@ void gvcst_init(gd_region *greg) assert(global_tlvl_info_list || !csa->sgm_info_ptr); if (JNL_ALLOWED(csa)) { + bsize = csd->blk_size; + realloc_alt_buff = FALSE; if (NULL == non_tp_jfb_ptr) { non_tp_jfb_ptr = (jnl_format_buffer *)malloc(SIZEOF(jnl_format_buffer)); - non_tp_jfb_buff_ptr = (unsigned char *)malloc(MAX_JNL_REC_SIZE); - non_tp_jfb_ptr->buff = (char *)non_tp_jfb_buff_ptr; - /* If the journal records need to be encrypted in the journal file and if replication is in use, - * we will need access to both the encrypted (for the journal file) and unencrypted (for the - * journal pool) journal record contents. Since this code is executed only once (for the first - * journaled database opened) by this process, we will have to allocate an alternate buffer - * for this purpose (to hold the unencrypted data) as long as this GT.M version supports encryption. - */ - GTMCRYPT_ONLY( - non_tp_jfb_ptr->alt_buff = (char *)malloc(MAX_JNL_REC_SIZE); - ) + non_tp_jfb_ptr->hi_water_bsize = bsize; + non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize)); non_tp_jfb_ptr->record_size = 0; /* initialize it to 0 since TOTAL_NONTPJNL_REC_SIZE macro uses it */ + GTMCRYPT_ONLY(non_tp_jfb_ptr->alt_buff = NULL); + } else if (bsize > non_tp_jfb_ptr->hi_water_bsize) + { /* Need a larger buffer to accommodate larger non-TP journal records */ + non_tp_jfb_ptr->hi_water_bsize = bsize; + free(non_tp_jfb_ptr->buff); + non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize)); +# ifdef GTM_CRYPT + if (NULL != non_tp_jfb_ptr->alt_buff) + { + free(non_tp_jfb_ptr->alt_buff); + realloc_alt_buff = TRUE; + } +# endif } + /* If the journal records need to be encrypted in the journal file and if replication is in use, + * we will need access to both the encrypted (for the journal file) and unencrypted (for the + * journal pool) journal record contents. Allocate an alternative buffer if any open journaled region + * is encrypted. + */ +# ifdef GTM_CRYPT + if (realloc_alt_buff || (csd->is_encrypted && (NULL == non_tp_jfb_ptr->alt_buff))) + non_tp_jfb_ptr->alt_buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(non_tp_jfb_ptr->hi_water_bsize)); +# endif /* csa->min_total_tpjnl_rec_size represents the minimum journal buffer space needed for a TP transaction. * It is a conservative estimate assuming that one ALIGN record and one PINI record will be written for * one set of fixed size jnl records written. @@ -581,8 +642,18 @@ void gvcst_init(gd_region *greg) global_tlvl_info_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(global_tlvl_info_list, SIZEOF(global_tlvl_info), GBL_TLVL_INFO_LIST_INIT_ALLOC); } - greg->open = TRUE; - greg->opening = FALSE; + assert(!greg->was_open); + SET_REGION_OPEN_TRUE(greg, WAS_OPEN_FALSE); + csa = (sgmnt_addrs*)&FILE_INFO(greg)->s_addrs; + if (NULL != csa->dir_tree) + { /* It is possible that dir_tree has already been targ_alloc'ed. This is because GT.CM or VMS DAL + * calls can run down regions without the process halting out. We don't want to double malloc. + */ + csa->dir_tree->clue.end = 0; + } + SET_CSA_DIR_TREE(csa, greg->max_key_size, greg); + /* Now that reg->open is set to TRUE and directory tree is initialized, go ahead and set rts_error back to being usable */ + UNIX_ONLY(DBG_MARK_RTS_ERROR_USABLE); /* gds_rundown if invoked from now on will take care of cleaning up the shared memory segment */ ENABLE_INTERRUPTS(INTRPT_IN_GVCST_INIT); if (dba_bg == greg_acc_meth) @@ -632,6 +703,7 @@ void gvcst_init(gd_region *greg) greg_fid = &(csa->nl->unique_id); for (regcsa = cs_addrs_list; NULL != regcsa; regcsa = regcsa->next_csa) { + UNIX_ONLY(onln_rlbk_cycle_mismatch |= (regcsa->db_onln_rlbkd_cycle != regcsa->nl->db_onln_rlbkd_cycle)); if ((NULL != prevcsa) && (regcsa->fid_index < prevcsa->fid_index)) continue; reg_fid = &((regcsa)->nl->unique_id); @@ -647,6 +719,14 @@ void gvcst_init(gd_region *greg) csa->fid_index = 1; else csa->fid_index = prevcsa->fid_index + 1; + UNIX_ONLY( + if (onln_rlbk_cycle_mismatch) + { + csa->root_search_cycle--; + csa->onln_rlbk_cycle--; + csa->db_onln_rlbkd_cycle--; + } + ) /* Add current csa into list of open csas */ csa->next_csa = cs_addrs_list; cs_addrs_list = csa; @@ -655,5 +735,21 @@ void gvcst_init(gd_region *greg) tr->file.fid_index = (&FILE_INFO(tr->reg)->s_addrs)->fid_index; DBG_CHECK_TP_REG_LIST_SORTING(tp_reg_list); } +# ifdef UNIX + if (pool_init && REPL_ALLOWED(csd) && jnlpool_init_needed) + { + /* Last parameter to VALIDATE_INITIALIZED_JNLPOOL is TRUE if the process does logical updates and FALSE otherwise. + * This parameter governs whether the macro can do SCNDDBNOUPD check or not. All the utilities that sets + * jnlpool_init_needed global variable don't do logical updates (REORG, EXTEND, etc.). But, for GT.M, + * jnlpool_init_needed is set to TRUE unconditionally. Even though GT.M can do logical updates, we pass FALSE + * unconditionally to the macro (indicating no logical updates). This is because, at this point, there is no way to + * tell if this process wants to open the database for read or write operation. If it is for a read operation, we + * don't want the below macro to issue SCNDDBNOUPD error. If it is for write operation, we will skip the + * SCNDDBNOUPD error message here. But, eventually when this process goes to gvcst_{put,kill} or op_ztrigger, + * SCNDDBNOUPD is issued. + */ + VALIDATE_INITIALIZED_JNLPOOL(csa, csa->nl, greg, GTMRELAXED, SCNDDBNOUPD_CHECK_FALSE); + } +# endif return; } diff --git a/sr_port/gvcst_jrt_null.c b/sr_port/gvcst_jrt_null.c index f79ce9f..6bdd718 100644 --- a/sr_port/gvcst_jrt_null.c +++ b/sr_port/gvcst_jrt_null.c @@ -55,8 +55,10 @@ void gvcst_jrt_null() rec = (struct_jrec_null *)non_tp_jfb_ptr->buff; rec->prefix.jrec_type = JRT_NULL; rec->prefix.forwptr = NULL_RECLEN; + rec->prefix.checksum = INIT_CHECKSUM_SEED; rec->suffix.backptr = NULL_RECLEN; rec->suffix.suffix_code = JNL_REC_SUFFIX_CODE; + rec->filler = 0; jgbl.cumul_jnl_rec_len = NULL_RECLEN; /* The rest of the initialization is taken care of by jnl_write_logical (invoked in t_end below) */ DEBUG_ONLY(jgbl.cumul_index = 1;) diff --git a/sr_port/gvcst_kill.c b/sr_port/gvcst_kill.c index 68c3cc4..d2f99d2 100644 --- a/sr_port/gvcst_kill.c +++ b/sr_port/gvcst_kill.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,7 +41,7 @@ #include "repl_msg.h" #include "gtmsource.h" #include "interlock.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #ifdef GTM_TRIGGER # include "gv_trigger.h" @@ -73,6 +73,8 @@ #include "tp_set_sgm.h" /* for tp_set_sgm prototype */ #include "op_tcommit.h" /* for op_tcommit prototype */ #include "have_crit.h" +#include "error.h" +#include "gtmimagename.h" /* needed for spanning nodes */ GBLREF gd_region *gv_cur_region; GBLREF gv_key *gv_currkey, *gv_altkey; @@ -106,9 +108,11 @@ GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; /* needed for the ENSURE_UPDATE_ARRAY_SPACE macro */ GBLREF jnl_gbls_t jgbl; +GBLREF boolean_t donot_INVOKE_MUMTSTART; #endif +UNIX_ONLY(GBLREF boolean_t span_nodes_disallowed;) -GTMTRIG_ONLY(error_def(ERR_DBROLLEDBACK);) +error_def(ERR_DBROLLEDBACK); error_def(ERR_TPRETRY); error_def(ERR_GVKILLFAIL); @@ -116,16 +120,91 @@ error_def(ERR_GVKILLFAIL); LITREF mval literal_null; LITREF mval *fndata_table[2][2]; #endif +LITREF mval literal_batch; -void gvcst_kill(bool do_subtree) +#define SKIP_ASSERT_TRUE TRUE +#define SKIP_ASSERT_FALSE FALSE + +#define GOTO_RETRY(SKIP_ASSERT) \ +{ \ + assert((CDB_STAGNATE > t_tries) || SKIP_ASSERT); \ + goto retry; \ +} + +DEFINE_NSB_CONDITION_HANDLER(gvcst_kill_ch) + +void gvcst_kill(boolean_t do_subtree) +{ + boolean_t spanstat; + boolean_t sn_tpwrapped; + boolean_t est_first_pass; + int oldend; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + if (do_subtree) + { /* If we're killing the whole subtree, that includes any spanning nodes. No need to do anything special */ + gvcst_kill2(TRUE, NULL, FALSE); + assert(save_dollar_tlevel == dollar_tlevel); + return; + } else + { /* Attempt to zkill node, but abort if we might have a spanning node */ + spanstat = 0; + gvcst_kill2(FALSE, &spanstat, FALSE); + assert(save_dollar_tlevel == dollar_tlevel); + if (!spanstat) + return; + } + VMS_ONLY(assert(FALSE)); +# ifdef UNIX + RTS_ERROR_IF_SN_DISALLOWED; + oldend = gv_currkey->end; + /* Almost certainly have a spanning node to zkill. So start a TP transaction to deal with it. */ + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &literal_batch, 0); + assert(!donot_INVOKE_MUMTSTART); + DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE); + ESTABLISH_NORET(gvcst_kill_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + /* Fire any triggers FIRST, then proceed with the kill. If we started a lcl_implicit transaction in first gvcst_kill + * triggers were rolled back. So if span_status indicates TRLBKTRIG, do them again. + * Otherwise, skip triggers because they were either kept or didn't happen. + * What if new triggers added between above gvcst_kill and now? Should cause a restart because trigger cycle changes? + */ + if (sn_tpwrapped) + gvcst_kill2(FALSE, NULL, FALSE); /* zkill primary dummy node <--- jnling + trigs happen here */ + /* kill any existing hidden subscripts */ + APPEND_HIDDEN_SUB(gv_currkey); /* append "0211" to gv_currkey */ + gvcst_kill2(FALSE, NULL, TRUE); + RESTORE_CURRKEY(gv_currkey, oldend); + if (sn_tpwrapped) + { + op_tcommit(); + DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); + REVERT; /* remove our condition handler */ + } + assert(save_dollar_tlevel == dollar_tlevel); +# endif +} + +void gvcst_kill2(boolean_t do_subtree, boolean_t *span_status, boolean_t killing_chunks) { block_id gvt_root; boolean_t clue, flush_cache; boolean_t next_fenced_was_null, write_logical_jnlrecs, jnl_format_done; boolean_t left_extra, right_extra; + boolean_t want_root_search = FALSE, is_dummy, succeeded, key_exists; + rec_hdr_ptr_t rp; + uint4 lcl_onln_rlbkd_cycle; + int data_len, cur_val_offset; + unsigned short rec_size; cw_set_element *tp_cse; enum cdb_sc cdb_status; - int lev, end; + int lev, end, target_key_size; uint4 prev_update_trans, actual_update; jnl_format_buffer *jfb, *ztworm_jfb; jnl_action_code operation; @@ -133,7 +212,7 @@ void gvcst_kill(bool do_subtree) node_local_ptr_t cnl; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; - srch_blk_status *left,*right; + srch_blk_status *bh, *left, *right; srch_hist *gvt_hist, *alt_hist, *dir_hist; srch_rec_status *left_rec_stat, local_srch_rec; uint4 segment_update_array_size; @@ -153,10 +232,9 @@ void gvcst_kill(bool do_subtree) unsigned char *save_msp; mv_stent *save_mv_chain; mval *ztold_mval = NULL, ztvalue_new, ztworm_val; - DEBUG_ONLY(enum cdb_sc save_cdb_status;) # endif # ifdef DEBUG - boolean_t is_mm; + boolean_t is_mm, root_search_done = FALSE; uint4 dbg_research_cnt; # endif DCL_THREADGBL_ACCESS; @@ -186,11 +264,11 @@ void gvcst_kill(bool do_subtree) /* In case of non-TP explicit updates that invoke triggers the kills happen inside of TP. If those kills * dont cause any actual update, we need prev_update_trans set appropriately so update_trans can be reset. */ - GTMTRIG_ONLY(prev_update_trans = 0;) + GTMTRIG_ONLY(prev_update_trans = 0); } else prev_update_trans = sgm_info_ptr->update_trans; assert(('\0' != gv_currkey->base[0]) && gv_currkey->end); - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVKILLFAIL); assert(NULL != update_array); assert(NULL != update_array_ptr); @@ -204,6 +282,28 @@ void gvcst_kill(bool do_subtree) for (;;) { actual_update = 0; +# ifdef GTM_TRIGGER + gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */ + is_tpwrap = FALSE; + /* No trigger ^#t reads needed if skip_dbtriggers is TRUE (e.g. mupip load etc.) */ + if (!skip_dbtriggers) + { + GVTR_INIT_AND_TPWRAP_IF_NEEDED(csa, csd, gv_target, gvt_trigger, lcl_implicit_tstart, is_tpwrap, + ERR_GVKILLFAIL); + assert(gvt_trigger == gv_target->gvt_trigger); + } + /* finish off any pending root search from previous retry */ + REDO_ROOT_SEARCH_IF_NEEDED(want_root_search, cdb_status); + if (cdb_sc_normal != cdb_status) + { /* gvcst_root_search invoked from REDO_ROOT_SEARCH_IF_NEEDED ended up with a restart situation but did not + * actually invoke t_retry. Instead, it returned control back to us asking us to restart. + */ + GOTO_RETRY(SKIP_ASSERT_TRUE); /* cannot enable assert (which has an assert about t_tries < CDB_STAGNATE) + * because it is possible for us to get cdb_sc_gvtrootmod2 restart when + * t_tries == CDB_STAGNATE. + */ + } +# endif /* Need to reinitialize gvt_hist & alt_hist for each try as it might have got set to a value in the previous * retry that is inappropriate for this try (e.g. gvt_root value changed between tries). */ @@ -248,12 +348,12 @@ void gvcst_kill(bool do_subtree) * Needed as t_retry only resets clue of gv_target which is not the directory tree anymore. */ csa->dir_tree->clue.end = 0; - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); } if ((gv_altkey->end + 1) == dir_hist->h[0].curr_rec.match) { /* Case (2b) : GVT now exists for this global */ cdb_status = cdb_sc_gvtrootmod; - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); } else { /* Case (2a) : GVT does not exist for this global */ gvt_hist = dir_hist; /* validate directory tree history in t_end/tp_hist */ @@ -265,71 +365,64 @@ void gvcst_kill(bool do_subtree) jnl_format_done = FALSE; write_logical_jnlrecs = JNL_WRITE_LOGICAL_RECS(csa); # ifdef GTM_TRIGGER - gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */ dlr_data = 0; - is_tpwrap = FALSE; - /* No trigger init needed if skip_dbtriggers is TRUE (e.g. mupip load etc.). - * Also if gvt_root is 0 (possible only if gv_play_duplicate_kills is TRUE) we want to only journal the + /* No trigger invocation needed if skip_dbtriggers is TRUE (e.g. mupip load etc.). + * If gvt_root is 0 (possible only if gv_play_duplicate_kills is TRUE) we want to only journal the * kill but not touch the database or invoke triggers. So skip triggers in that case too. */ - if (!skip_dbtriggers && gvt_root) + if (!skip_dbtriggers && (NULL != gvt_trigger) && gvt_root && !killing_chunks) { - GVTR_INIT_AND_TPWRAP_IF_NEEDED(csa, csd, gv_target, gvt_trigger, lcl_implicit_tstart, is_tpwrap, - ERR_GVKILLFAIL); - assert(gvt_trigger == gv_target->gvt_trigger); - if (NULL != gvt_trigger) - { - PUSH_ZTOLDMVAL_ON_M_STACK(ztold_mval, save_msp, save_mv_chain); - /* Determine $ZTOLDVAL & $ZTDATA to fill in trigparms */ - cdb_status = gvcst_dataget(&dlr_data, ztold_mval); - if (cdb_sc_normal != cdb_status) - goto retry; - assert((11 >= dlr_data) && (1 >= (dlr_data % 10))); - /* Invoke triggers for KILL as long as $data is nonzero (1 or 10 or 11). - * Invoke triggers for ZKILL only if $data is 1 or 11 (for 10 case, ZKILL is a no-op). + PUSH_ZTOLDMVAL_ON_M_STACK(ztold_mval, save_msp, save_mv_chain); + /* Determine $ZTOLDVAL & $ZTDATA to fill in trigparms */ + dlr_data = DG_DATAGET; /* tell dataget we want full info regarding descendants */ + cdb_status = gvcst_dataget(&dlr_data, ztold_mval); + if (cdb_sc_normal != cdb_status) + GOTO_RETRY(SKIP_ASSERT_FALSE); + assert((11 >= dlr_data) && (1 >= (dlr_data % 10))); + /* Invoke triggers for KILL as long as $data is nonzero (1 or 10 or 11). + * Invoke triggers for ZKILL only if $data is 1 or 11 (for 10 case, ZKILL is a no-op). + */ + if (do_subtree ? dlr_data : (dlr_data & 1)) + { /* Either node or its descendants exists. Invoke KILL triggers for this node. + * But first write journal records (ZTWORM and/or KILL) for the triggering nupdate. + * "ztworm_jfb", "jfb" and "jnl_format_done" are set by the below macro. */ - if (do_subtree ? dlr_data : (dlr_data & 1)) - { /* Either node or its descendants exists. Invoke KILL triggers for this node. - * But first write journal records (ZTWORM and/or KILL) for the triggering nupdate. - * "ztworm_jfb", "jfb" and "jnl_format_done" are set by the below macro. + JNL_FORMAT_ZTWORM_IF_NEEDED(csa, write_logical_jnlrecs, + operation, gv_currkey, NULL, ztworm_jfb, jfb, jnl_format_done); + /* Initialize trigger parms that dont depend on the context of the matching trigger */ + trigparms.ztoldval_new = ztold_mval; + trigparms.ztdata_new = fndata_table[dlr_data / 10][dlr_data & 1]; + if (NULL == trigparms.ztvalue_new) + { /* Do not pass literal_null directly since $ztval can be modified inside trigger + * code and literal_null is in read-only segment so will not be modifiable. + * Hence the need for a dummy local variable mval "ztvalue_new" in the C stack. */ - JNL_FORMAT_ZTWORM_IF_NEEDED(csa, write_logical_jnlrecs, - operation, gv_currkey, NULL, ztworm_jfb, jfb, jnl_format_done); - /* Initialize trigger parms that dont depend on the context of the matching trigger */ - trigparms.ztoldval_new = ztold_mval; - trigparms.ztdata_new = fndata_table[dlr_data / 10][dlr_data & 1]; - if (NULL == trigparms.ztvalue_new) - { /* Do not pass literal_null directly since $ztval can be modified inside trigger - * code and literal_null is in read-only segment so will not be modifiable. - * Hence the need for a dummy local variable mval "ztvalue_new" in the C stack. - */ - ztvalue_new = literal_null; - trigparms.ztvalue_new = &ztvalue_new; - } - gvtr_parms.gvtr_cmd = do_subtree ? GVTR_CMDTYPE_KILL : GVTR_CMDTYPE_ZKILL; - gvtr_parms.gvt_trigger = gvt_trigger; - /* Now that we have filled in minimal information, let "gvtr_match_n_invoke" do the rest */ - gtm_trig_status = gvtr_match_n_invoke(&trigparms, &gvtr_parms); - assert((0 == gtm_trig_status) || (ERR_TPRETRY == gtm_trig_status)); - if (ERR_TPRETRY == gtm_trig_status) - { /* A restart has been signaled that we need to handle or complete the handling of. - * This restart could have occurred reading the trigger in which case no - * tp_restart() has yet been done or it could have occurred in trigger code in - * which case we need to finish the incomplete tp_restart. In both cases this - * must be an implicitly TP wrapped transaction. Our action is to complete the - * necessary tp_restart() logic (t_retry is already completed so should be skipped) - * and then re-do the gvcst_kill logic. - */ - assert(lcl_implicit_tstart); - assert(CDB_STAGNATE >= t_tries); - cdb_status = cdb_sc_normal; /* signal "retry:" to avoid t_retry call */ - goto retry; - } - REMOVE_ZTWORM_JFB_IF_NEEDED(ztworm_jfb, jfb, sgm_info_ptr); + ztvalue_new = literal_null; + trigparms.ztvalue_new = &ztvalue_new; } - /* else : we dont invoke any KILL/ZTKILL type triggers for a node whose $data is 0 */ - POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); + gvtr_parms.gvtr_cmd = do_subtree ? GVTR_CMDTYPE_KILL : GVTR_CMDTYPE_ZKILL; + gvtr_parms.gvt_trigger = gvt_trigger; + /* Now that we have filled in minimal information, let "gvtr_match_n_invoke" do the rest */ + gtm_trig_status = gvtr_match_n_invoke(&trigparms, &gvtr_parms); + assert((0 == gtm_trig_status) || (ERR_TPRETRY == gtm_trig_status)); + if (ERR_TPRETRY == gtm_trig_status) + { /* A restart has been signaled that we need to handle or complete the handling of. + * This restart could have occurred reading the trigger in which case no + * tp_restart() has yet been done or it could have occurred in trigger code in + * which case we need to finish the incomplete tp_restart. In both cases this + * must be an implicitly TP wrapped transaction. Our action is to complete the + * necessary tp_restart() logic (t_retry is already completed so should be skipped) + * and then re-do the gvcst_kill logic. + */ + assert(lcl_implicit_tstart || *span_status); + cdb_status = cdb_sc_normal; /* signal "retry:" to avoid t_retry call */ + assert(CDB_STAGNATE >= t_tries); + GOTO_RETRY(SKIP_ASSERT_TRUE);; /* Cannot check assert because above assert is >= t_tries */ + } + REMOVE_ZTWORM_JFB_IF_NEEDED(ztworm_jfb, jfb, sgm_info_ptr); } + /* else : we dont invoke any KILL/ZTKILL type triggers for a node whose $data is 0 */ + POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); } # endif assert(csd == cs_data); /* assert csd is in sync with cs_data even if there were MM db file extensions */ @@ -353,8 +446,18 @@ void gvcst_kill(bool do_subtree) research: if (gvt_root) { +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVKILLFAIL == gtm_white_box_test_case_number)) + { + cdb_status = cdb_sc_blknumerr; + /* Skip assert inside GOTO_RETRY macro as the WBTEST_ANTIFREEZE_GVKILLFAIL white-box testcase + * intentionally triggers a GVKILLFAIL error. + */ + GOTO_RETRY(SKIP_ASSERT_TRUE); + } +#endif if (cdb_sc_normal != (cdb_status = gvcst_search(gv_currkey, NULL))) - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->top == gv_keysize); end = gv_currkey->end; @@ -368,17 +471,72 @@ research: base[++end] = KEY_DELIMITER; } else { - base[end] = 1; - base[++end] = KEY_DELIMITER; - base[++end] = KEY_DELIMITER; +# ifdef UNIX + target_key_size = gv_currkey->end + 1; + bh = &gv_target->hist.h[0]; + key_exists = (target_key_size == bh->curr_rec.match); + if (key_exists) + { /* check for spanning node dummy value: a single zero byte */ + rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bh->buffaddr + bh->curr_rec.offset); + GET_USHORT(rec_size, &rp->rsiz); + cur_val_offset = SIZEOF(rec_hdr) + target_key_size - EVAL_CMPC((rec_hdr_ptr_t)rp); + data_len = rec_size - cur_val_offset; + is_dummy = IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + cur_val_offset); + if (is_dummy && (NULL != span_status) && !(span_nodes_disallowed && csd->span_node_absent)) + { + need_kip_incr = FALSE; + if (!dollar_tlevel) + { + update_trans = 0; + succeeded = ((trans_num)0 != t_end(gvt_hist, NULL, TN_NOT_SPECIFIED)); + if (!succeeded) + { /* see other t_end */ + assert((NULL == kip_csa) && (csd == cs_data)); + update_trans = UPDTRNS_DB_UPDATED_MASK; + continue; + } + *span_status = TRUE; + return; + } else + { + cdb_status = tp_hist(NULL); + if (cdb_sc_normal != cdb_status) + GOTO_RETRY(SKIP_ASSERT_FALSE); + *span_status = TRUE; +# ifdef GTM_TRIGGER + if (lcl_implicit_tstart) + { /* Rollback triggers */ + OP_TROLLBACK(-1); + return; + } +# endif + /* do not return in case of entering with TP, still set span_status */ + } + } + } +# endif + if (killing_chunks) + { /* Second call of gvcst_kill2 within TP transaction in gvcst_kill + * Kill all hidden subscripts... + */ + base[end - 3] = STR_SUB_MAXVAL; + base[end - 2] = STR_SUB_MAXVAL; + base[end - 1] = KEY_DELIMITER; + base[end - 0] = KEY_DELIMITER; + } else + { + base[end] = 1; + base[++end] = KEY_DELIMITER; + base[++end] = KEY_DELIMITER; + } } gv_altkey->end = end; if (cdb_sc_normal != (cdb_status = gvcst_search(gv_altkey, alt_hist))) - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); if (alt_hist->depth != gvt_hist->depth) { cdb_status = cdb_sc_badlvl; - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); } right_extra = FALSE; left_extra = TRUE; @@ -406,7 +564,7 @@ research: goto research; } if (cdb_sc_delete_parent != cdb_status) - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); left_extra = right_extra = TRUE; } else @@ -433,7 +591,7 @@ research: left_extra = TRUE; cdb_status = cdb_sc_normal; } else - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); local_srch_rec.offset = local_srch_rec.match = 0; cdb_status = gvcst_kill_blk(right, lev, gv_altkey, local_srch_rec, right->curr_rec, @@ -449,7 +607,7 @@ research: right_extra = TRUE; cdb_status = cdb_sc_normal; } else - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); } } } @@ -520,12 +678,12 @@ research: } else { /* See comment above IS_OK_TO_INVOKE_GVCST_KILL macro for why the below assert is the way it is */ - assert(!jgbl.forw_phase_recovery || actual_update || (JS_IS_DUPLICATE & jgbl.mur_jrec_nodeflags) - || jgbl.mur_options_forward); + /*assert(!jgbl.forw_phase_recovery || actual_update || (JS_IS_DUPLICATE & jgbl.mur_jrec_nodeflags) + || jgbl.mur_options_forward);*/ assert(si->update_trans); } } - if (write_logical_jnlrecs && (actual_update || gv_play_duplicate_kills)) + if (write_logical_jnlrecs && (actual_update || gv_play_duplicate_kills) && !killing_chunks) { /* Maintain journal records only if the kill actually resulted in a database update OR if * "gv_play_duplicate_kills" is TRUE. In the latter case, even though no db blocks will be touched, * it will still increment the db curr_tn and write jnl records. @@ -588,9 +746,8 @@ research: WAIT_ON_INHIBIT_KILLS(cnl, MAXWAIT2KILL); } if ((trans_num)0 == t_end(gvt_hist, alt_hist, TN_NOT_SPECIFIED)) - { /* In case this is MM and t_end caused a database extension, reset csd */ - assert(is_mm || (csd == cs_data)); - csd = cs_data; + { + assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ if (jnl_fence_ctl.level && next_fenced_was_null && actual_update && write_logical_jnlrecs) { /* If ZTransaction and first KILL and the kill resulted in an update * Note that "write_logical_jnlrecs" is used above instead of JNL_WRITE_LOGICAL_RECS(csa) @@ -612,14 +769,12 @@ research: update_trans = UPDTRNS_DB_UPDATED_MASK; continue; } - /* In case this is MM and t_end caused a database extension, reset csd */ - assert(is_mm || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ } else { cdb_status = tp_hist(alt_hist); if (cdb_sc_normal != cdb_status) - goto retry; + GOTO_RETRY(SKIP_ASSERT_FALSE); } /* Note down $tlevel (used later) before it is potentially changed by op_tcommit below */ lcl_dollar_tlevel = dollar_tlevel; @@ -629,10 +784,11 @@ research: assert(gvt_root); GVTR_OP_TCOMMIT(cdb_status); if (cdb_sc_normal != cdb_status) - goto retry; + GOTO_RETRY(SKIP_ASSERT_TRUE); } # endif - INCR_GVSTATS_COUNTER(csa, cnl, n_kill, 1); + if (!killing_chunks) + INCR_GVSTATS_COUNTER(csa, cnl, n_kill, 1); if (gvt_root && (0 != gv_target->clue.end)) { /* If clue is still valid, then the deletion was confined to a single block */ assert(gvt_hist->h[0].blk_num == alt_hist->h[0].blk_num); @@ -656,11 +812,7 @@ research: assert(!csd->dsid); ENABLE_WBTEST_ABANDONEDKILL; gvcst_expand_free_subtree(&kill_set_head); - /* In case this is MM and "gvcst_expand_free_subtree" called "gvcst_bmp_mark_free" - * which in turn called "t_retry" which remapped an extended database, reset csd. - */ - assert(is_mm || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ DECR_KIP(csd, csa, kip_csa); } assert(0 < kill_set_head.used || (NULL == kip_csa)); @@ -685,11 +837,12 @@ retry: /* else: t_retry has already been done by gtm_trigger so no need to do it again for this try */ } # endif - assert((cdb_sc_normal != cdb_status) GTMTRIG_ONLY(|| lcl_implicit_tstart)); + assert((cdb_sc_normal != cdb_status) GTMTRIG_ONLY(|| lcl_implicit_tstart || *span_status)); if (cdb_sc_normal != cdb_status) { GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain)); t_retry(cdb_status); + GTMTRIG_ONLY(skip_INVOKE_RESTART = FALSE); } else { /* else: t_retry has already been done so no need to do that again but need to still invoke tp_restart * to complete pending "tprestart_state" related work. @@ -698,49 +851,30 @@ retry: assert(ERR_TPRETRY == gtm_trig_status); TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); + if (!lcl_implicit_tstart) + { /* We started an implicit transaction for spanning nodes in gvcst_kill. Invoke restart to return. */ + assert(*span_status && !skip_INVOKE_RESTART && (&gvcst_kill_ch == ctxt->ch)); + INVOKE_RESTART; + } # endif rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); assert(0 == rc GTMTRIG_ONLY(&& TPRESTART_STATE_NORMAL == tprestart_state)); } -# ifdef GTM_TRIGGER assert(0 < t_tries); +# ifdef GTM_TRIGGER if (lcl_implicit_tstart) { - assert((cdb_sc_normal != cdb_status) || (ERR_TPRETRY == gtm_trig_status)); - if (cdb_sc_normal == cdb_status) - { - DEBUG_ONLY(save_cdb_status = cdb_status); - cdb_status = t_fail_hist[t_tries - 1]; /* get the last restart code */ - } - assert(((cdb_sc_onln_rlbk1 != cdb_status) && (cdb_sc_onln_rlbk2 != cdb_status)) - || (TREF(dollar_zonlnrlbk) && !gv_target->root)); - if ((cdb_sc_onln_rlbk1 == cdb_status) || (cdb_sc_gvtrootmod == cdb_status)) - { - assert(NULL != gv_target); - ASSERT_BEGIN_OF_FRESH_TP_TRANS; /* ensures gvcst_root_search is the first thing done in the - * restarted transaction */ - /* We are implicit transaction and online rollback update the database but did NOT take us to a - * different logical state. We've already done the restart, but the root is now reset to zero. Do - * root search to establish the new root - */ - GVCST_ROOT_SEARCH; - } else if (cdb_sc_onln_rlbk2 == cdb_status) - { /* Database was taken back to a different logical state and we are an implicit TP transaction. - * Issue DBROLLEDBACK error that the application programmer can catch and do the necessary stuff. - */ - assert(gtm_trigger_depth == tstart_trigger_depth); - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); - } + SET_WANT_ROOT_SEARCH(cdb_status, want_root_search); + assert(!skip_INVOKE_RESTART); /* if set to TRUE above, should have been reset by t_retry */ } # endif - GTMTRIG_ONLY(assert(!skip_INVOKE_RESTART)); /* if set to TRUE above, should have been reset by t_retry */ /* At this point, we can be in TP only if we implicitly did a tstart in gvcst_kill (as part of a trigger update). * Assert that. Since the t_retry/tp_restart would have reset si->update_trans, we need to set it again. * So reinvoke the T_BEGIN call only in case of TP. For non-TP, update_trans is unaffected by t_retry. */ assert(!dollar_tlevel GTMTRIG_ONLY(|| lcl_implicit_tstart)); if (dollar_tlevel) - { + { /* op_ztrigger has similar code and should be maintained in parallel */ tp_set_sgm(); /* set sgm_info_ptr & first_sgm_info for TP start */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVKILLFAIL); /* set update_trans and t_err for wrapped TP */ } else @@ -751,8 +885,6 @@ retry: */ update_trans = UPDTRNS_DB_UPDATED_MASK; } - /* In case this is MM and "t_retry" remapped an extended database, reset csd */ - assert(is_mm || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ } } diff --git a/sr_port/gvcst_kill_blk.c b/sr_port/gvcst_kill_blk.c index f0b9c73..01a4735 100644 --- a/sr_port/gvcst_kill_blk.c +++ b/sr_port/gvcst_kill_blk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,6 +61,7 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, unsigned short temp_ushort; int4 temp_long; + int tmp_cmpc; int blk_size, blk_seg_cnt, lmatch, rmatch, targ_len, prev_len, targ_base, next_rec_shrink, temp_int, blkseglen; bool kill_root, first_copy; @@ -187,7 +188,7 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, /* create index block */ BLK_ADDR(new_rec_hdr, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr->rsiz = SIZEOF(rec_hdr) + SIZEOF(block_id); - new_rec_hdr->cmpc = 0; + SET_CMPC(new_rec_hdr, 0); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (bytptr)new_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (bytptr)&zeroes, SIZEOF(block_id)); @@ -220,13 +221,14 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, } else { targ_base = (rmatch < lmatch) ? rmatch : lmatch; - targ_len = ((right_extra) ? right_prev_ptr->cmpc : right_ptr->cmpc) - targ_base; - if (targ_len < 0) - targ_len = 0; prev_len = 0; if (right_extra) { - temp_int = right_prev_ptr->cmpc - right_ptr->cmpc; + EVAL_CMPC2(right_prev_ptr, tmp_cmpc); + targ_len = tmp_cmpc - targ_base; + if (targ_len < 0) + targ_len = 0; + temp_int = tmp_cmpc - EVAL_CMPC(right_ptr); if (0 >= temp_int) prev_len = - temp_int; else @@ -236,6 +238,11 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, else targ_len = 0; } + } else + { + targ_len = EVAL_CMPC(right_ptr) - targ_base; + if (targ_len < 0) + targ_len = 0; } next_rec_shrink += targ_len + prev_len; } @@ -257,7 +264,7 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, first_copy = FALSE; } BLK_ADDR(star_rec_hdr, SIZEOF(rec_hdr), rec_hdr); - star_rec_hdr->cmpc = 0; + SET_CMPC(star_rec_hdr, 0); star_rec_hdr->rsiz = (unsigned short)(SIZEOF(rec_hdr) + SIZEOF(block_id)); BLK_SEG(bs_ptr, (bytptr)star_rec_hdr, SIZEOF(rec_hdr)); GET_USHORT(temp_ushort, &left_ptr->rsiz); @@ -275,7 +282,7 @@ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, } else { BLK_ADDR(new_rec_hdr, SIZEOF(rec_hdr), rec_hdr); - new_rec_hdr->cmpc = right_ptr->cmpc - next_rec_shrink; + SET_CMPC(new_rec_hdr, EVAL_CMPC(right_ptr) - next_rec_shrink); GET_USHORT(temp_ushort, &right_ptr->rsiz); new_rec_hdr->rsiz = temp_ushort + next_rec_shrink; BLK_SEG(bs_ptr, (bytptr)new_rec_hdr, SIZEOF(rec_hdr)); diff --git a/sr_port/gvcst_map_build.c b/sr_port/gvcst_map_build.c index aeed6c9..5871c0f 100644 --- a/sr_port/gvcst_map_build.c +++ b/sr_port/gvcst_map_build.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,11 +23,10 @@ #include "send_msg.h" /* prototypes */ #include "gvcst_map_build.h" #include "min_max.h" +#include "wbox_test_init.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; -GBLREF boolean_t dse_running; -GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, trans_num ctn) { @@ -36,35 +35,17 @@ void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, tr uint4 bitnum, ret; #ifdef DEBUG int4 prev_bitnum, actual_cnt = 0; -#endif - DEBUG_ONLY(VALIDATE_BM_BLK(cs->blk, (blk_hdr_ptr_t)base_addr, cs_addrs, gv_cur_region, status);) - assert(status); /* assert it is a valid bitmap block */ + if (!gtm_white_box_test_case_enabled || (WBTEST_ANTIFREEZE_DBBMLCORRUPT != gtm_white_box_test_case_number)) + { + VALIDATE_BM_BLK(cs->blk, (blk_hdr_ptr_t)base_addr, cs_addrs, gv_cur_region, status); + assert(status); /* assert it is a valid bitmap block */ + } +#endif ((blk_hdr_ptr_t)base_addr)->tn = ctn; base_addr += SIZEOF(blk_hdr); assert(cs_addrs->now_crit); /* Don't want to be messing with highest_lbm_with_busy_blk outside crit */ - if (cs_addrs->nl->trunc_pid) - { /* A truncate is in progress. We need to 1) update cnl->highest_lbm_with_busy_blk if needed and 2) select bml_free if this is a - * t_recycled2free transaction. */ - if (cs->reference_cnt > 0) - { - bml_func = bml_busy; - cs_addrs->nl->highest_lbm_with_busy_blk = MAX(cs->blk, cs_addrs->nl->highest_lbm_with_busy_blk); - } else if (cs->reference_cnt < 0) - { - if (cs_addrs->hdr->db_got_to_v5_once) - bml_func = bml_recycled; - else - bml_func = bml_free; - } else /* cs->reference_cnt == 0 */ - { - if (cs_addrs->hdr->db_got_to_v5_once && mu_reorg_upgrd_dwngrd_in_prog) - bml_func = bml_recycled; - else - bml_func = bml_free; - } - } else /* Choose bml_func as it was chosen before truncate feature. */ - bml_func = (cs->reference_cnt > 0) ? bml_busy : (cs_addrs->hdr->db_got_to_v5_once ? bml_recycled : bml_free); + DETERMINE_BML_FUNC(bml_func, cs, cs_addrs); DEBUG_ONLY(prev_bitnum = -1;) while (bitnum = *array) /* caution : intended assignment */ { diff --git a/sr_port/gvcst_order.c b/sr_port/gvcst_order.c index c30d0b0..725e279 100644 --- a/sr_port/gvcst_order.c +++ b/sr_port/gvcst_order.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,12 +28,29 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +# include "wbox_test_init.h" +#endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_order prototype */ +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; + GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; @@ -43,24 +60,95 @@ GBLREF int4 gv_keysize; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVORDERFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_order_ch) bool gvcst_order(void) +{ /* See gvcst_query.c */ + bool found, is_hidden, sn_tpwrapped; + boolean_t est_first_pass; + char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; + gv_key *save_gv_currkey; + int end, prev, oldend; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + found = gvcst_order2(); +# ifdef UNIX + assert(save_dollar_tlevel == dollar_tlevel); + CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); + assert(found && is_hidden); + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); + SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_order_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_order, (gtm_uint64_t) -1); + found = gvcst_order2(); + if (found) + { + CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); + if (is_hidden) + { /* Replace last subscript to be the highest possible hidden subscript so another + * gvcst_order2 will give us the next non-hidden subscript. + */ + end = gv_altkey->end; + gv_currkey->base[end - 4] = 2; + gv_currkey->base[end - 3] = 0xFF; + gv_currkey->base[end - 2] = 0xFF; + gv_currkey->base[end - 1] = 1; + gv_currkey->base[end + 0] = 0; + gv_currkey->base[end + 1] = 0; + gv_currkey->end = end + 1; + /* fix up since it should only be externally counted as one $order */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_order, (gtm_uint64_t) -1); + found = gvcst_order2(); + } + } + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return found; +} + +bool gvcst_order2(void) { blk_hdr_ptr_t bp; - bool found, two_histories; + boolean_t found, two_histories; enum cdb_sc status; rec_hdr_ptr_t rp; unsigned short rec_size; srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t c1, c2, ctop, alt_top; + int tmp_cmpc; T_BEGIN_READ_NONTP_OR_TP(ERR_GVORDERFAIL); for (;;) { assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ two_histories = FALSE; +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVORDERFAIL == gtm_white_box_test_case_number)) + { + status = cdb_sc_blknumerr; + t_retry(status); + continue; + } +#endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { found = TRUE; @@ -117,7 +205,7 @@ bool gvcst_order(void) c2 = (sm_uc_ptr_t)CST_BOK(rp) + bh->curr_rec.match; memcpy(c1, gv_currkey->base, bh->curr_rec.match); c1 += bh->curr_rec.match; - c2 -= rp->cmpc; + c2 -= EVAL_CMPC(rp); GET_USHORT(rec_size, &rp->rsiz); ctop = (sm_uc_ptr_t)rp + rec_size; for (;;) diff --git a/sr_port/gvcst_protos.h b/sr_port/gvcst_protos.h index 9cbb6d0..343450b 100644 --- a/sr_port/gvcst_protos.h +++ b/sr_port/gvcst_protos.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2012 Fidelity Information Services, Inc * + * Copyright 2004, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,30 +18,46 @@ void db_auto_upgrade(gd_region *reg); #ifdef VMS void db_init(gd_region *reg, sgmnt_data_ptr_t tsd); #else -void db_init(gd_region *reg); +int db_init(gd_region *reg); +void db_init_err_cleanup(boolean_t retry_dbinit); void gvcst_redo_root_search(void); #endif gd_region *dbfilopn (gd_region *reg); void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size); mint gvcst_data(void); +mint gvcst_data2(void); enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val); +enum cdb_sc gvcst_dataget2(mint *dollar_data, mval *val, unsigned char *sn_ptr); bool gvcst_gblmod(mval *v); boolean_t gvcst_get(mval *v); +boolean_t gvcst_get2(mval *v, unsigned char *sn_ptr); void gvcst_incr(mval *increment, mval *result); void gvcst_init(gd_region *greg); -void gvcst_kill(bool do_subtree); +void gvcst_kill(boolean_t do_subtree); +void gvcst_kill2(boolean_t do_subtree, boolean_t *span_status, boolean_t killing_chunks); enum cdb_sc gvcst_lftsib(srch_hist *full_hist); bool gvcst_order(void); +bool gvcst_order2(void); void gvcst_put(mval *v); +void gvcst_put2(mval *val, span_parms *parms); bool gvcst_query(void); +bool gvcst_query2(void); boolean_t gvcst_queryget(mval *val); -void gvcst_root_search(void); +boolean_t gvcst_queryget2(mval *val, unsigned char *sn_ptr); +enum cdb_sc gvcst_root_search(boolean_t donot_restart); enum cdb_sc gvcst_rtsib(srch_hist *full_hist, int level); enum cdb_sc gvcst_search(gv_key *pKey, srch_hist *pHist); enum cdb_sc gvcst_search_blk(gv_key *pKey, srch_blk_status *pStat); enum cdb_sc gvcst_search_tail(gv_key *pKey, srch_blk_status *pStat, gv_key *pOldKey); void gvcst_tp_init(gd_region *); bool gvcst_zprevious(void); +bool gvcst_zprevious2(void); + +/* gvcst_dataget and gvcst_dataget2 take the following values as input */ +#define DG_GETONLY 2 +#define DG_DATAONLY 3 +#define DG_DATAGET 4 +#define DG_GETSNDATA 5 GBLREF boolean_t gv_play_duplicate_kills; diff --git a/sr_port/gvcst_put.c b/sr_port/gvcst_put.c index 8c5ef1d..98bf645 100644 --- a/sr_port/gvcst_put.c +++ b/sr_port/gvcst_put.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,14 +41,14 @@ #include "rc_oflow.h" #include "repl_msg.h" #include "gtmsource.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" +#include "mv_stent.h" #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" # include "gv_trigger_protos.h" # include "subscript.h" -# include "mv_stent.h" # include "stringpool.h" #endif #include "tp_frame.h" @@ -70,12 +70,19 @@ #include "tp_set_sgm.h" /* for tp_set_sgm prototype */ #include "op_tcommit.h" /* for op_tcommit prototype */ #include "have_crit.h" +#include "error.h" +#include "gtmimagename.h" /* for spanning nodes */ +#ifdef UNIX +#include "preemptive_db_clnup.h" +#endif #ifdef GTM_TRIGGER LITREF mval literal_null; LITREF mval literal_one; LITREF mval literal_zero; #endif +LITREF mval literal_batch; +LITREF mstr nsb_dummy; /* Globals that will not change in value across nested trigger calls of gvcst_put OR even if they might change in value, * the change is such that they dont need save/restore logic surrounding the "gtm_trigger" call. Any new GBLREFs that are @@ -105,6 +112,7 @@ GBLREF unsigned int t_tries; GBLREF cw_set_element cw_set[CDB_CW_SET_SIZE];/* create write set. */ GBLREF boolean_t skip_dbtriggers; /* see gbldefs.c for description of this global */ GBLREF stack_frame *frame_pointer; +GBLREF mv_stent *mv_chain; #ifdef GTM_TRIGGER GBLREF int tprestart_state; GBLREF int4 gtm_trigger_depth; @@ -114,6 +122,7 @@ GBLREF boolean_t ztwormhole_used; /* TRUE if $ztwormhole was used by trigger co #endif #ifdef DEBUG GBLREF boolean_t skip_block_chain_tail_check; +GBLREF boolean_t donot_INVOKE_MUMTSTART; #endif /* Globals that could change in value across nested trigger calls of gvcst_put AND need to be saved/restored */ @@ -126,52 +135,56 @@ GBLREF mval increment_delta_mval; GBLREF sgm_info *sgm_info_ptr; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; +UNIX_ONLY(GBLREF enum gtmImageTypes image_type;) +UNIX_ONLY(GBLREF boolean_t span_nodes_disallowed;) -GTMTRIG_ONLY(error_def(ERR_DBROLLEDBACK);) +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVINCRISOLATION); error_def(ERR_GVIS); error_def(ERR_GVPUTFAIL); error_def(ERR_REC2BIG); error_def(ERR_RSVDBYTE2HIGH); +error_def(ERR_TEXT); error_def(ERR_TPRETRY); +error_def(ERR_UNIMPLOP); /* Before issuing an error, add GVT to the list of known gvts in this TP transaction in case it is not already done. * This GVT addition is usually done by "tp_hist" but that function has most likely not yet been invoked in gvcst_put. * Doing this addition will ensure we remember to reset any non-zero clue in dir_tree as part of tp_clean_up when a TROLLBACK - * or TRESTART (implicit or explicit) occurs. Not doing so could cause transfer of control from the current gvcst_put action - * to a user-defined error trap which if it does further database references, it could end up using invalid clues from GVT - * and potentially incorrectly commit the transaction causing db integ errors as well. + * or TRESTART (implicit or explicit) occurs. Not doing so could means if an ERR_REC2BIG happens here, control will + * go to the error trap and if it does a TROLLBACK (which does a tp_clean_up) we would be left with a potentially out-of-date + * clue of GVT which if used for later global references could result in db integ errors. */ -#define ENSURE_VALUE_WITHIN_MAX_REC_SIZE(value, GVT) \ -{ \ - if (dollar_tlevel) \ - ADD_TO_GVT_TP_LIST(GVT); /* note: macro also updates read_local_tn if necessary */ \ - if (gv_currkey->end + 1 + value.len + SIZEOF(rec_hdr) > gv_cur_region->max_rec_size) \ - { \ - if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ - end = &buff[MAX_ZWR_KEY_SZ - 1]; \ - rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, gv_currkey->end + 1 + value.len + SIZEOF(rec_hdr), \ - (int4)gv_cur_region->max_rec_size, \ - REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); \ - } \ +#define ENSURE_VALUE_WITHIN_MAX_REC_SIZE(value, GVT) \ +{ \ + if (dollar_tlevel) \ + ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* note: macro updates read_local_tn if necessary */ \ + if (VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) value.len > gv_cur_region->max_rec_size) \ + { \ + if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ + end = &buff[MAX_ZWR_KEY_SZ - 1]; \ + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) \ + value.len, (int4)gv_cur_region->max_rec_size, \ + REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); \ + } \ } /* See comment before ENSURE_VALUE_WITHIN_MAX_REC_SIZE macro definition for why the ADD_TO_GVT_TP_LIST call below is necessary */ -#define ISSUE_RSVDBYTE2HIGH_ERROR(GVT) \ -{ \ - if (dollar_tlevel) \ - ADD_TO_GVT_TP_LIST(GVT); /* note: macro also updates read_local_tn if necessary */ \ - /* The record that is newly inserted/updated does not fit by itself in a separate block \ - * if the current reserved-bytes for this database is taken into account. Cannot go on. \ - */ \ - if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ - end = &buff[MAX_ZWR_KEY_SZ - 1]; \ - rts_error(VARLSTCNT(11) ERR_RSVDBYTE2HIGH, 5, new_blk_size_single, \ - REG_LEN_STR(gv_cur_region), blk_size, blk_reserved_bytes, \ - ERR_GVIS, 2, end - buff, buff); \ +#define ISSUE_RSVDBYTE2HIGH_ERROR(GVT) \ +{ \ + if (dollar_tlevel) \ + ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* note: macro updates read_local_tn if necessary */ \ + /* The record that is newly inserted/updated does not fit by itself in a separate block \ + * if the current reserved-bytes for this database is taken into account. Cannot go on. \ + */ \ + if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ + end = &buff[MAX_ZWR_KEY_SZ - 1]; \ + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(11) ERR_RSVDBYTE2HIGH, 5, new_blk_size_single, \ + REG_LEN_STR(gv_cur_region), blk_size, blk_reserved_bytes, \ + ERR_GVIS, 2, end - buff, buff); \ } -#define RESTORE_ZERO_GVT_ROOT_ON_RETRY(LCL_ROOT, GV_TARGET, TP_ROOT, DIR_HIST, DIR_TREE) \ +#define RESTORE_ZERO_GVT_ROOT_ON_RETRY(LCL_ROOT, GV_TARGET, DIR_HIST, DIR_TREE) \ { \ if (!LCL_ROOT) \ { \ @@ -182,20 +195,32 @@ error_def(ERR_TPRETRY); * was validated (in t_end/tp_hist),so we need to reset its clue before the next try. \ */ \ DIR_TREE->clue.end = 0; \ - /* Check if LCL_ROOT & GV_TARGET->root are in sync. If not make them so. */ \ - if (GV_TARGET->root) \ - { /* We had reset the root block from zero to a non-zero value within \ - * this function, but since we are restarting, we can no longer be \ - * sure of the validity of the root block. Reset it to 0 so it will \ - * be re-determined in the next global reference. \ - */ \ - assert((TP_ROOT == GV_TARGET->root) \ - || ((0 == TP_ROOT) GTMTRIG_ONLY(&& (0 < gvtr_parms.num_triggers_invoked)))); \ - GV_TARGET->root = 0; \ - } \ + /* We had reset the root block from zero to a non-zero value within \ + * this function, but since we are restarting, we can no longer be \ + * sure of the validity of the root block. Reset it to 0 so it will \ + * be re-determined in the next global reference. \ + */ \ + GV_TARGET->root = 0; \ } \ } +#define RECORD_FITS_IN_A_BLOCK(VAL, KEY, BLK_SZ, RESERVED_BYTES) \ + ((VAL)->str.len <= COMPUTE_CHUNK_SIZE(KEY, BLK_SZ, RESERVED_BYTES)) + +#define ZKILL_NODELETS \ +{ \ + APPEND_HIDDEN_SUB(gv_currkey); \ + if (gv_target->root) \ + gvcst_kill2(FALSE, NULL, TRUE); /* zkill any existing spanning nodelets.. */ \ + RESTORE_CURRKEY(gv_currkey, oldend); \ +} + +#define POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain) \ +{ \ + if (!lcl_span_status) \ + POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); \ +} + #ifdef DEBUG # define DBG_SAVE_VAL_AT_FUN_ENTRY \ { /* Save copy of "val" at function entry. \ @@ -222,14 +247,178 @@ error_def(ERR_TPRETRY); goto retry; \ } +CONDITION_HANDLER(gvcst_put_ch) +{ + int rc; + + START_CH; + if ((int)ERR_TPRETRY == SIGNAL) + { /* delay tp_restart till after the long jump and some other stuff */ + UNWIND(NULL, NULL); + } + NEXTCH; +} + void gvcst_put(mval *val) +{ + boolean_t sn_tpwrapped, fits; + boolean_t est_first_pass; + mval val_ctrl, val_piece, val_dummy; + mval *pre_incr_mval, *save_val; + block_id lcl_root; + int gblsize, chunk_size, i, oldend; + unsigned short numsubs; + unsigned char mychars[MAX_NSBCTRL_SZ]; + int save_dollar_tlevel, rc; + boolean_t save_in_gvcst_incr; /* gvcst_put2 sets this FALSE, so save it in case we need to back out */ + span_parms parms; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + parms.span_status = FALSE; + parms.blk_reserved_bytes = cs_data->reserved_bytes; /* Only want to read once for consistency */ + parms.enable_trigger_read_and_fire = TRUE; + parms.enable_jnl_format = TRUE; + lcl_root = gv_target->root; + VMS_ONLY(gvcst_put2(val, &parms)); +# ifdef UNIX /* deal with possibility of spanning nodes */ + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); + save_in_gvcst_incr = in_gvcst_incr; + if (fits) + { + gvcst_put2(val, &parms); + if (!parms.span_status) + { + assert(save_dollar_tlevel == dollar_tlevel); + return; /* We've successfully set a normal non-spanning global. */ + } + } + RTS_ERROR_IF_SN_DISALLOWED; + /* Either we need to create a spanning node, or kill one before resetting it */ + GTMTRIG_ONLY(parms.ztold_mval = NULL); + cs_data->span_node_absent = FALSE; + oldend = gv_currkey->end; + val_dummy.str = nsb_dummy; + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + save_val = val; + /* We pass the IMPLICIT_TRIGGER_TSTART flag because we might invoke a trigger, and in that case we want to avoid + * invoking a restart from within gtm_trigger. Since we remove gvcst_put_ch before invoking the trigger + * (see comment in errorsp.h), an attempt to invoke a restart returns us back to the mdb_condition_handler created + * by the initial dm-start. Unwinding from there returns to the OS -- i.e., the process silently dies. + * Also note that we need to ensure the retry logic at the bottom of gvcst_put2 is executed in case a restart + * happens within a trigger invocation. We want to return from gvtr_match_n_invoke so we can goto retry. + */ + op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &literal_batch, 0); + frame_pointer->flags |= SFF_IMPLTSTART_CALLD; + assert(!donot_INVOKE_MUMTSTART); + DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE); + ESTABLISH_NORET(gvcst_put_ch, est_first_pass); + if (est_first_pass) + { /* did a long jump back to here */ + val = save_val; + GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(parms.ztold_mval, + parms.save_msp, ((mv_stent *)parms.save_mv_chain))); + preemptive_db_clnup(ERROR); /* Bluff about SEVERITY to reset gv_target and reset_gv_target tp_restart resets + * but not reset_gv_target This matches flow with non-spanning-node tp_restart, + * which does preemptive_db_clnup in mdb_condition_handler + */ + rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); + RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, &cs_addrs->dir_tree->hist, cs_addrs->dir_tree); + fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); + if (cdb_sc_onln_rlbk2 == LAST_RESTART_CODE) + /* Database was taken back to a different logical state. We are an implicit TP transaction, and + * as in the case of implicit TP for triggers, we issue a DBROLLEDBACK error that the application + * programmer can catch. + */ + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); + } + tp_set_sgm(); + GVCST_ROOT_SEARCH; + } else + sn_tpwrapped = FALSE; + parms.span_status = TRUE; + parms.enable_trigger_read_and_fire = TRUE; + parms.enable_jnl_format = TRUE; + parms.ztval_gvcst_put_redo = FALSE; + if (save_in_gvcst_incr) + { + in_gvcst_incr = FALSE; /* allow gvcst_put2 to do a regular set */ + PUSH_MV_STENT(MVST_MVAL); /* protect pre_incr_mval from stp_gcol */ + pre_incr_mval = &mv_chain->mv_st_cont.mvs_mval; + gvcst_get(pre_incr_mval); /* what if it doesn't exist? needs to be treated as 0 */ + pre_incr_mval->mvtype = MV_STR; + op_add(pre_incr_mval, &increment_delta_mval, post_incr_mval); + POP_MV_STENT(); /* pre_incr_mval */ + assert(MV_IS_NUMERIC(post_incr_mval)); + MV_FORCE_STR(post_incr_mval); + val = post_incr_mval; /* its a number, should fit in single block.. unless ridick rsrvdbytes.. */ + fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); + } + /* Set the primary node. If we're setting a spanning node, that the primary node will have a dummy value, $char(0). + * Journal formatting and triggers happen here. If ztval changed during trigger invocations to a large value, + * we do a second gvcst_put2 to set the new value. + */ + parms.val_forjnl = val; + gvcst_put2(((fits) ? val : &val_dummy), &parms); + parms.enable_trigger_read_and_fire = FALSE; +# ifdef GTM_TRIGGER + if (parms.ztval_gvcst_put_redo) + { + val = parms.ztval_mval; + parms.enable_jnl_format = TRUE; /* new val needs to be journaled */ + parms.val_forjnl = val; + fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); + assert(!fits); + gvcst_put2(&val_dummy, &parms); + } +# endif + ZKILL_NODELETS; /* Even if not creating a spanning node, may be replacing one */ + if (!fits) + { /* Need to create a spanning node. Break value up into chunks. */ + parms.enable_jnl_format = FALSE; /* jnl formatting already done */ + APPEND_HIDDEN_SUB(gv_currkey); + chunk_size = COMPUTE_CHUNK_SIZE(gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); + gblsize = val->str.len; + numsubs = DIVIDE_ROUND_UP(gblsize, chunk_size); + PUT_NSBCTRL(mychars, numsubs, gblsize); + val_ctrl.str.addr = (char *)mychars; + val_ctrl.str.len = 6; + /* Count the spanning node set as one set */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_set, 1); + gvcst_put2(&val_ctrl, &parms); /* Set control subscript, indicating glbsize and number of chunks */ + for (i = 0; i < numsubs; i++) + { + NEXT_HIDDEN_SUB(gv_currkey, i); + val_piece.str.len = MIN(chunk_size, gblsize - i * chunk_size); + val_piece.str.addr = val->str.addr + i * chunk_size; + gvcst_put2(&val_piece, &parms); + } + RESTORE_CURRKEY(gv_currkey, oldend); + } + GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(parms.ztold_mval, parms.save_msp, ((mv_stent *)parms.save_mv_chain))); + /* pop any stacked mvals before op_tcommit as it does its own popping */ + if (sn_tpwrapped) + { + op_tcommit(); + DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); + REVERT; /* remove our condition handler */ + } + assert(save_dollar_tlevel == dollar_tlevel); +# endif /* ifdef UNIX */ +} + +void gvcst_put2(mval *val, span_parms *parms) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; node_local_ptr_t cnl; int4 blk_size, blk_fill_size, blk_reserved_bytes; const int4 zeroes = 0; - boolean_t jnl_format_done; + boolean_t jnl_format_done, is_dummy, needfmtjnl, fits, lcl_span_status; blk_segment *bs1, *bs_ptr, *new_blk_bs; block_id allocation_clue, tp_root, gvt_for_root, blk_num, last_split_blk_num[MAX_BT_DEPTH]; block_index left_hand_index, ins_chain_index, root_blk_cw_index, next_blk_index; @@ -238,14 +427,15 @@ void gvcst_put(mval *val) gv_namehead *save_targ, *split_targ, *dir_tree; enum cdb_sc status; gv_key *temp_key; + int tmp_cmpc; mstr value; off_chain chain1, curr_chain, prev_chain, chain2; - rec_hdr_ptr_t curr_rec_hdr, extra_rec_hdr, next_rec_hdr, new_star_hdr, rp; + rec_hdr_ptr_t curr_rec_hdr, extra_rec_hdr, next_rec_hdr, new_star_hdr, rp, tmp_rp; srch_blk_status *bh, *bq, *tp_srch_status; srch_hist *dir_hist; int cur_blk_size, blk_seg_cnt, delta, i, j, left_hand_offset, n, ins_chain_offset, new_blk_size_l, new_blk_size_r, new_blk_size_single, new_blk_size, blk_reserved_size, - last_possible_left_offset, new_rec_size, next_rec_shrink, next_rec_shrink1, + last_possible_left_offset, new_rec_size, next_rec_shrink, next_rec_shrink1, start_len, offset_sum, rec_cmpc, target_key_size, tp_lev, undo_index, cur_val_offset, curr_offset, bh_level; uint4 segment_update_array_size, key_top, cp2_len, bs1_2_len, bs1_3_len; char *va, last_split_direction[MAX_BT_DEPTH]; @@ -258,6 +448,7 @@ void gvcst_put(mval *val) jnl_format_buffer *jfb, *ztworm_jfb; jnl_action *ja; mval *set_val; /* actual right-hand-side value of the SET or $INCR command */ + mval *val_forjnl; ht_ent_int4 *tabent; unsigned char buff[MAX_ZWR_KEY_SZ], *end, old_ch, new_ch; sm_uc_ptr_t buffaddr; @@ -270,6 +461,7 @@ void gvcst_put(mval *val) int rc; int4 cse_first_off; enum split_dir last_split_dir; + int4 data_len; # ifdef GTM_TRIGGER boolean_t is_tpwrap; boolean_t ztval_gvcst_put_redo, skip_hasht_read; @@ -277,11 +469,11 @@ void gvcst_put(mval *val) gvt_trigger_t *gvt_trigger; gvtr_invoke_parms_t gvtr_parms; int gtm_trig_status; - int4 data_len; unsigned char *save_msp; mv_stent *save_mv_chain; mval *ztold_mval = NULL; mval *ztval_mval; + mint dlr_data; boolean_t lcl_implicit_tstart; /* local copy of the global variable "implicit_tstart" */ mval lcl_increment_delta_mval; /* local copy of "increment_delta_mval" */ boolean_t lcl_is_dollar_incr; /* local copy of is_dollar_incr taken at start of module. @@ -290,6 +482,8 @@ void gvcst_put(mval *val) * used to restore "post_incr_mval" in case of TP restarts */ mval *lcl_val; /* local copy of "val" at function entry. * used to restore "val" in case of TP restarts */ + mval *lcl_val_forjnl; + mval *pval; /* copy of "value" (an mstr), protected from stp gcol */ DEBUG_ONLY(enum cdb_sc save_cdb_status;) # endif # ifdef DEBUG @@ -349,15 +543,31 @@ void gvcst_put(mval *val) # endif JNLPOOL_INIT_IF_NEEDED(csa, csd, cnl); blk_size = csd->blk_size; - blk_reserved_bytes = csd->reserved_bytes; + blk_reserved_bytes = parms->blk_reserved_bytes; blk_fill_size = (blk_size * gv_fillfactor) / 100 - blk_reserved_bytes; - jnl_format_done = FALSE; /* do "jnl_format" only once per logical non-tp transaction irrespective of number of retries */ + lcl_span_status = parms->span_status; + if (lcl_span_status) + { + needfmtjnl = parms->enable_jnl_format; + val_forjnl = parms->val_forjnl; +# ifdef GTM_TRIGGER + ztold_mval = parms->ztold_mval; + skip_hasht_read = !parms->enable_trigger_read_and_fire; +# endif + } else + { + needfmtjnl = TRUE; + val_forjnl = val; + } + jnl_format_done = !needfmtjnl; /* do "jnl_format" only once per logical non-tp transaction irrespective of + * number of retries or number of chunks if spanning node + */ GTMTRIG_ONLY( ztval_gvcst_put_redo = FALSE; skip_hasht_read = FALSE; ) assert(('\0' != gv_currkey->base[0]) && gv_currkey->end); - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); /* this needs to be initialized before any code that does a "goto retry" since this gets used there */ save_targ = gv_target; gbl_target_was_set = (INVALID_GV_TARGET != reset_gv_target); @@ -380,7 +590,7 @@ void gvcst_put(mval *val) fresh_tn_start: DEBUG_ONLY(lcl_t_tries = -1;) DEBUG_ONLY(is_fresh_tn_start = TRUE;) - assert(!jnl_format_done || (dollar_tlevel GTMTRIG_ONLY(&& ztval_gvcst_put_redo))); + assert(!jnl_format_done || (dollar_tlevel GTMTRIG_ONLY(&& ztval_gvcst_put_redo)) || lcl_span_status); T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVPUTFAIL); tn_restart: /* t_tries should never decrease - it either increases or stays the same. If should decrease we could live-lock with @@ -405,16 +615,12 @@ tn_restart: dbg_trace_array[dbg_num_iters].retry_line = 0; split_targ = NULL; ) - /* If MM and file extension occurred, reset csd to cs_data to avoid out-of-date value. If BG we dont need the reset - * but if checks are costlier than unconditional sets in a pipelined architecture so we choose not to do the if. - */ - assert(is_mm || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ # ifdef GTM_TRIGGER gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */ assert(!ztval_gvcst_put_redo || IS_PTR_INSIDE_M_STACK(val)); is_tpwrap = FALSE; - if (!skip_dbtriggers && !skip_hasht_read) + if (!skip_dbtriggers && !skip_hasht_read && parms->enable_trigger_read_and_fire) { GVTR_INIT_AND_TPWRAP_IF_NEEDED(csa, csd, gv_target, gvt_trigger, lcl_implicit_tstart, is_tpwrap, ERR_GVPUTFAIL); assert(gvt_trigger == gv_target->gvt_trigger); @@ -432,11 +638,21 @@ tn_restart: assert(lcl_implicit_tstart); lcl_is_dollar_incr = is_dollar_incr; lcl_val = val; + lcl_val_forjnl = val_forjnl; lcl_post_incr_mval = post_incr_mval; lcl_increment_delta_mval = increment_delta_mval; + jnl_format_done = FALSE; } if (NULL != gvt_trigger) + { PUSH_ZTOLDMVAL_ON_M_STACK(ztold_mval, save_msp, save_mv_chain); + if (lcl_span_status) + { /* Need the ability to pop vals from gvcst_put. */ + parms->ztold_mval = ztold_mval; + parms->save_msp = save_msp; + parms->save_mv_chain = (unsigned char *)save_mv_chain; + } + } } # endif assert(csd == cs_data); /* assert csd is in sync with cs_data even if there were MM db file extensions */ @@ -497,9 +713,10 @@ tn_restart: GOTO_RETRY; if (gv_altkey->end + 1 == dir_hist->h[0].curr_rec.match) { + tmp_rp = (rec_hdr_ptr_t)(dir_hist->h[0].buffaddr + dir_hist->h[0].curr_rec.offset); + EVAL_CMPC2(tmp_rp, tmp_cmpc); GET_LONG(tp_root, (dir_hist->h[0].buffaddr + SIZEOF(rec_hdr) - + dir_hist->h[0].curr_rec.offset + gv_altkey->end + 1 - - ((rec_hdr_ptr_t)(dir_hist->h[0].buffaddr + dir_hist->h[0].curr_rec.offset))->cmpc)); + + dir_hist->h[0].curr_rec.offset + gv_altkey->end + 1 - tmp_cmpc)); if (dollar_tlevel) { gvt_for_root = dir_hist->h[0].blk_num; @@ -552,7 +769,7 @@ tn_restart: } BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = SIZEOF(rec_hdr) + temp_key->end + 1 + value.len; - curr_rec_hdr->cmpc = 0; + SET_CMPC(curr_rec_hdr, 0); BLK_INIT(bs_ptr, new_blk_bs); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, temp_key->end + 1, unsigned char); @@ -574,7 +791,7 @@ tn_restart: /* Create the index block */ BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = BSTAR_REC_SIZE; - curr_rec_hdr->cmpc = 0; + SET_CMPC(curr_rec_hdr, 0); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); @@ -599,11 +816,84 @@ tn_restart: no_pointers = FALSE; } else { +# ifdef GTM_TRIGGER + if (lcl_span_status && (NULL != ztold_mval) && !skip_hasht_read && parms->enable_trigger_read_and_fire) + { /* Dealing with spanning nodes, need to use a get routine to find ztold_val. Need to do this BEFORE + * gvcst_search below or we'll disrupt gv_target->hist, which is used in the subsequent constructions. + * Though we don't need dollar_data, we use gvcst_dataget since it returns status, allowing retry + * cleanup to be done (RESET_GV_TARGET_LCL_AND_CLR_GBL in particular) before invoking a restart. + */ + assert(dollar_tlevel && !skip_dbtriggers); + dlr_data = DG_GETONLY; /* tell dataget we just want to do a get; we don't care about descendants */ + status = gvcst_dataget(&dlr_data, ztold_mval); + if (cdb_sc_normal != status) + GOTO_RETRY; + } +# endif +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVINCRPUTFAIL == gtm_white_box_test_case_number)) + { + status = cdb_sc_blknumerr; + GOTO_RETRY; + } +#endif if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) GOTO_RETRY; target_key_size = gv_currkey->end + 1; bh = &gv_target->hist.h[0]; key_exists = (target_key_size == bh->curr_rec.match); +# ifdef UNIX + if (key_exists) + { /* check for spanning node dummy value: a single zero byte */ + rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bh->buffaddr + bh->curr_rec.offset); + GET_USHORT(rec_size, &rp->rsiz); + cur_val_offset = SIZEOF(rec_hdr) + target_key_size - EVAL_CMPC((rec_hdr_ptr_t)rp); + data_len = rec_size - cur_val_offset; + is_dummy = (1 == data_len) && ('\0' == *(sm_uc_ptr_t)((sm_uc_ptr_t)rp + cur_val_offset)); + if (is_dummy && !lcl_span_status && (csa->dir_tree != gv_target) + && !(span_nodes_disallowed && csd->span_node_absent)) + { /* Validate that value is really $zchar(0) and either restart or back out of gvcst_put2. + * Three cases: + * 1) not in TP, no triggers + * 2) in TP (triggers invoked or not) + * 3) weren't in TP when we entered gvcst_put2, but did an op_tstart to check for triggers + */ + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); + if (!dollar_tlevel) + { + update_trans = 0; + succeeded = ((trans_num)0 != t_end(&gv_target->hist, dir_hist, TN_NOT_SPECIFIED)); + if (!succeeded) + { /* see other t_end */ + RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); + jnl_format_done = !needfmtjnl; + GTMTRIG_DBG_ONLY(dbg_trace_array[dbg_num_iters].retry_line = __LINE__); + update_trans = UPDTRNS_DB_UPDATED_MASK; + goto tn_restart; + } + } else + { + status = tp_hist(dir_hist); + if (NULL != dir_hist) + ADD_TO_GVT_TP_LIST(dir_tree, RESET_FIRST_TP_SRCH_STATUS_FALSE); + if (cdb_sc_normal != status) + GOTO_RETRY; +# ifdef GTM_TRIGGER + if (lcl_implicit_tstart) + { /* Started TP for playing triggers. Abort and try again outside after nsb op_tstart + * Otherwise, we were already in TP when we came into gvcst_put. Triggers can stay, + * but finish put outside. + */ + POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); + OP_TROLLBACK(-1); + } +# endif + } + parms->span_status = TRUE; + return; + } + } +# endif if (is_dollar_incr) { if (key_exists) @@ -692,7 +982,7 @@ tn_restart: } else { GET_USHORT(rec_size, &rp->rsiz); - rec_cmpc = rp->cmpc; + rec_cmpc = EVAL_CMPC(rp); if ((sm_uc_ptr_t)rp + rec_size > (sm_uc_ptr_t)buffaddr + cur_blk_size) { assert(CDB_STAGNATE > t_tries); @@ -720,7 +1010,8 @@ tn_restart: assert(target_key_size > rec_cmpc); cur_val_offset = SIZEOF(rec_hdr) + (target_key_size - rec_cmpc); # ifdef GTM_TRIGGER - if (no_pointers && (NULL != ztold_mval) && !skip_hasht_read) + if (no_pointers && (NULL != ztold_mval) && !skip_hasht_read && parms->enable_trigger_read_and_fire + && !lcl_span_status) { /* Complete initialization of ztold_mval */ assert(!skip_dbtriggers); data_len = rec_size - cur_val_offset; @@ -730,14 +1021,22 @@ tn_restart: status = cdb_sc_rmisalign; GOTO_RETRY; } + ztold_mval->str.len = data_len; if (data_len) { - ENSURE_STP_FREE_SPACE(data_len); + if (!(IS_STP_SPACE_AVAILABLE(data_len))) + { + PUSH_MV_STENT(MVST_MVAL); /* protect "value" mstr from stp gcol */ + pval = &mv_chain->mv_st_cont.mvs_mval; + pval->str = value; + ENSURE_STP_FREE_SPACE(data_len); + value = pval->str; + POP_MV_STENT(); /* pval */ + } ztold_mval->str.addr = (char *)stringpool.free; memcpy(ztold_mval->str.addr, (sm_uc_ptr_t)rp + cur_val_offset, data_len); stringpool.free += data_len; } - ztold_mval->str.len = data_len; ztold_mval->mvtype = MV_STR; /* ztold_mval is now completely initialized */ } # endif @@ -800,7 +1099,7 @@ tn_restart: BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr)); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; - curr_rec_hdr->cmpc = prev_rec_match; + SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); @@ -820,7 +1119,7 @@ tn_restart: { BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = rec_size - next_rec_shrink; - next_rec_hdr->cmpc = curr_rec_match; + SET_CMPC(next_rec_hdr, curr_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); next_rec_shrink += SIZEOF(rec_hdr); } @@ -841,21 +1140,22 @@ tn_restart: */ assert(FALSE); curr_rec_hdr = (rec_hdr_ptr_t)(buffaddr + curr_rec_offset); + EVAL_CMPC2(curr_rec_hdr, tmp_cmpc); /* First piece is block prior to record + key + data prior to fragment */ BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + rc_set_fragment - + gv_currkey->end + 1 - curr_rec_hdr->cmpc); + + gv_currkey->end + 1 - tmp_cmpc); /* Second piece is fragment itself */ BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); /* Third piece is data after fragment + rest of block after record */ n = (int)(cur_blk_size - ((sm_uc_ptr_t)curr_rec_hdr - buffaddr) - SIZEOF(rec_hdr) - - (gv_currkey->end + 1 - curr_rec_hdr->cmpc) - rc_set_fragment - value.len); + - (gv_currkey->end + 1 - tmp_cmpc) - rc_set_fragment - value.len); if (0 < n) BLK_SEG(bs_ptr, - (sm_uc_ptr_t)curr_rec_hdr + gv_currkey->end + 1 - curr_rec_hdr->cmpc + (sm_uc_ptr_t)curr_rec_hdr + gv_currkey->end + 1 - tmp_cmpc + rc_set_fragment + value.len, n); } @@ -965,10 +1265,11 @@ tn_restart: { assert(dollar_tlevel); if (is_dollar_incr) - { - ADD_TO_GVT_TP_LIST(gv_target); /* See comment in ENSURE_VALUE_WITHIN_MAX_REC_SIZE - * macro definition for why this macro call is necessary */ - rts_error(VARLSTCNT(4) ERR_GVINCRISOLATION, 2, + { /* See comment in ENSURE_VALUE_WITHIN_MAX_REC_SIZE macro + * definition for why the below macro call is necessary. + */ + ADD_TO_GVT_TP_LIST(gv_target, RESET_FIRST_TP_SRCH_STATUS_FALSE); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_GVINCRISOLATION, 2, gv_target->gvname.var_name.len, gv_target->gvname.var_name.addr); } if (NULL == cse->recompute_list_tail || @@ -1008,7 +1309,6 @@ tn_restart: assert(blk_reserved_size >= blk_fill_size); extra_record_orig_size = 0; prev_rec_offset = bh->prev_rec.offset; - assert(new_blk_size_single <= new_blk_size_r); /* Decide which side (left or right) the new record goes. Ensure either side has at least one record. * This means we might not honor the desired FillFactor if the only record in a block exceeds the * blk_fill_size, but in this case we are guaranteed the block has room for the current reserved bytes. @@ -1108,7 +1408,7 @@ tn_restart: BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), prev_rec_offset - SIZEOF(blk_hdr)); BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; - new_star_hdr->cmpc = 0; + SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp - SIZEOF(block_id), SIZEOF(block_id)); } @@ -1137,7 +1437,7 @@ tn_restart: rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = target_key_size + SIZEOF(rec_hdr) + value.len; - curr_rec_hdr->cmpc = 0; + SET_CMPC(curr_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size, unsigned char); memcpy(cp1, temp_key->base, target_key_size); @@ -1153,7 +1453,7 @@ tn_restart: BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); GET_USHORT(next_rec_hdr->rsiz, &rp->rsiz); next_rec_hdr->rsiz -= next_rec_shrink; - next_rec_hdr->cmpc = new_rec ? curr_rec_match : rp->cmpc; + SET_CMPC(next_rec_hdr, new_rec ? curr_rec_match : EVAL_CMPC(rp)); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); next_rec_shrink += SIZEOF(rec_hdr); n = cur_blk_size - INTCAST(((sm_uc_ptr_t)rp - buffaddr)) - next_rec_shrink; @@ -1229,7 +1529,7 @@ tn_restart: { BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; - curr_rec_hdr->cmpc = prev_rec_match; + SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); @@ -1250,7 +1550,7 @@ tn_restart: { BLK_ADDR(extra_rec_hdr, SIZEOF(rec_hdr), rec_hdr); extra_rec_hdr->rsiz = n; - extra_rec_hdr->cmpc = curr_rec_match; + SET_CMPC(extra_rec_hdr, curr_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)extra_rec_hdr, SIZEOF(rec_hdr)); if (n < (signed)SIZEOF(rec_hdr)) /* want signed compare */ { /* as 'n' can be negative */ @@ -1272,7 +1572,7 @@ tn_restart: { BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; - curr_rec_hdr->cmpc = prev_rec_match; + SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); @@ -1286,7 +1586,7 @@ tn_restart: new_blk_size_l = curr_rec_offset + BSTAR_REC_SIZE; BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; - new_star_hdr->cmpc = 0; + SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); if (!copy_extra_record) { @@ -1315,7 +1615,7 @@ tn_restart: if (!new_rec || copy_extra_record) { /* Should guard for empty block??? */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); - rec_cmpc = rp->cmpc; + rec_cmpc = EVAL_CMPC(rp); temp_short = rec_size; GET_USHORT(rec_size, &rp->rsiz); } @@ -1337,7 +1637,7 @@ tn_restart: BLK_INIT(bs_ptr, bs1); BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = rec_size; - next_rec_hdr->cmpc = 0; + SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, rec_cmpc, unsigned char); memcpy(cp1, temp_key->base, rec_cmpc); @@ -1695,12 +1995,17 @@ tn_restart: * not many intervening possible keys and and therefore it does not matter that much whether we pass * the left or (right-1) key to the parent. * + * There are two additional cases in which we let the left key go unmodified: 1) if the backoff would + * result in a key larger than max_key_size and 2) if the left key ends in "00 00" and the right key ends + * in "00 01 ... ". Backing off the 01 would give a index key with "00 00" in the middle. + * * temp_key already holds the key corresponding to the last record of the left block. * bs1[2] and bs1[3] hold the key corresponding to the first record of the right block. */ if (level_0) { /* Determine key for record to pass on to parent index block */ cp1 = temp_key->base; + assert(KEY_DELIMITER != *temp_key->base); cp2 = (unsigned char *)bs1[2].addr; bs1_2_len = bs1[2].len; for (i = 0; (i < bs1_2_len) && (*cp2 == *cp1); ++i) @@ -1743,13 +2048,16 @@ tn_restart: } else if (1 == n) { cp1++; - if ((cp1 - temp_key->base + 2) < temp_key->top) + start_len = cp1 - temp_key->base + 2; + if (start_len < temp_key->top) { if (i == (bs1_2_len - 1)) cp2 = (unsigned char *)bs1[3].addr; else cp2++; - if ((STR_SUB_MAXVAL != *cp1) || (KEY_DELIMITER != *cp2)) + if (((KEY_DELIMITER != *(cp1 - 1)) || (KEY_DELIMITER != *(cp1 - 2))) + && ((STR_SUB_MAXVAL != *cp1) || (KEY_DELIMITER != *cp2)) + && (gv_cur_region->max_key_size > start_len)) { if (!new_rec_goes_to_right) { @@ -1794,8 +2102,11 @@ tn_restart: { /* Not root; write blocks and continue */ if (cdb_sc_normal != (status = gvcst_search_blk(temp_key, bq))) GOTO_RETRY; - cse = t_write(bh, (unsigned char *)bs1, ins_chain_offset, - ins_chain_index, bh_level, TRUE, FALSE, GDS_WRITE_PLAIN); + /* It's necessary to disable the indexmod optimization for splits of index blocks. Refer to + * GTM-7353, C9B11-001813 (GTM-3984), and C9H12-002934 (GTM-6104). + */ + cse = t_write(bh, (unsigned char *)bs1, ins_chain_offset, ins_chain_index, bh_level, + TRUE, FALSE, (level_0) ? GDS_WRITE_PLAIN : GDS_WRITE_KILLTN); assert(!dollar_tlevel || !cse->high_tlevel); if (cse) { @@ -1854,7 +2165,7 @@ tn_restart: BLK_INIT(bs_ptr, bs1); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = target_key_size + SIZEOF(rec_hdr) + SIZEOF(block_id); - curr_rec_hdr->cmpc = 0; + SET_CMPC(curr_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size, unsigned char); memcpy(cp1, temp_key->base, target_key_size); @@ -1862,7 +2173,7 @@ tn_restart: BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = BSTAR_REC_SIZE; - next_rec_hdr->cmpc = 0; + SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); if (0 == BLK_FINI(bs_ptr, bs1)) @@ -1917,7 +2228,7 @@ tn_restart: assert(succeeded); horiz_growth = FALSE; assert((csa->dir_tree == gv_target) || tp_root); - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); /* The only case where gv_target is still csa->dir_tree after the above RESET macro is if op_gvput was invoked * with gv_target being set to cs_addrs->dir_tree. In that case gbl_target_was_set would have been set to TRUE. Assert. */ @@ -1940,7 +2251,7 @@ tn_restart: inctn_opcode = inctn_gvcstput_extra_blk_split; else if (JNL_WRITE_LOGICAL_RECS(csa) && !jnl_format_done) { - jfb = jnl_format(JNL_SET, gv_currkey, (!is_dollar_incr ? val : post_incr_mval), nodeflags); + jfb = jnl_format(JNL_SET, gv_currkey, (!is_dollar_incr ? val_forjnl : post_incr_mval), nodeflags); assert(NULL != jfb); jnl_format_done = TRUE; } @@ -1960,8 +2271,9 @@ tn_restart: { /* "t_retry" would have already been invoked by "t_end". * So instead of going to "retry:", do only whatever steps from there are necessary here. */ - RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, tp_root, dir_hist, dir_tree); - jnl_format_done = FALSE; /* need to reformat jnl records for $INCR even in case of non-TP */ + RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); + /*if (is_dollar_incr)*/ + jnl_format_done = FALSE; /* need to reformat jnl records for $INCR even in case of non-TP */ GTMTRIG_DBG_ONLY(dbg_trace_array[dbg_num_iters].retry_line = __LINE__); goto tn_restart; } @@ -1972,14 +2284,16 @@ tn_restart: { /* Note that although "tp_hist" processes the "dir_hist" history, it only adds "gv_target" to gvt_tp_list. * But csa->dir_tree might have had clue, blk-split related info etc. modified as part of this * gvcst_put invocation that might also need cleanup (just like any other gv_target) so add - * csa->dir_tree to gvt_tp_list (if not already done). + * csa->dir_tree to gvt_tp_list (if not already done). Therefore treat this as if tp_hist is doing + * the ADD_TO_GVT_TP_LIST call for dir_tree. */ assert(dir_tree == csa->dir_tree); - ADD_TO_GVT_TP_LIST(dir_tree); /* note: macro also updates read_local_tn if necessary */ + ADD_TO_GVT_TP_LIST(dir_tree, RESET_FIRST_TP_SRCH_STATUS_FALSE); + /* note: above macro updates read_local_tn if necessary */ } if (cdb_sc_normal != status) GOTO_RETRY; - jnl_format_done = FALSE; + jnl_format_done = !needfmtjnl; } if (succeeded) { @@ -2015,7 +2329,7 @@ tn_restart: { /* The logical update required an extra block split operation first (which succeeded) so * get back to doing the logical update before doing any trigger invocations etc. */ - GTMTRIG_ONLY(skip_hasht_read = TRUE;) + GTMTRIG_ONLY(skip_hasht_read = (dollar_tlevel) ? TRUE : skip_hasht_read;) goto fresh_tn_start; } for (bh_level = 0; bh_level < split_depth; bh_level++) @@ -2048,10 +2362,10 @@ tn_restart: nodeflags |= JS_SKIP_TRIGGERS_MASK; if (duplicate_set) nodeflags |= JS_IS_DUPLICATE; - ja_val = (!is_dollar_incr ? val : post_incr_mval); + ja_val = (!is_dollar_incr ? val_forjnl : post_incr_mval); write_logical_jnlrecs = JNL_WRITE_LOGICAL_RECS(csa); # ifdef GTM_TRIGGER - if (!skip_dbtriggers) + if (!skip_dbtriggers && parms->enable_trigger_read_and_fire) { /* Since we are about to invoke the trigger, we better have gv_target->gvt_trigger and * the local variable gvt_trigger in sync. The only exception is when we are here because @@ -2073,7 +2387,7 @@ tn_restart: PUSH_MV_STENT(MVST_MVAL); /* protect $ztval from stp_gcol */ ztval_mval = &mv_chain->mv_st_cont.mvs_mval; if (!is_dollar_incr) - *ztval_mval = *val; + *ztval_mval = *val_forjnl; else { *ztval_mval = *post_incr_mval; @@ -2099,7 +2413,7 @@ tn_restart: * necessary tp_restart() logic (t_retry is already completed so should be skipped) * and then re-do the gvcst_put logic. */ - assert(lcl_implicit_tstart); + assert(lcl_implicit_tstart || lcl_span_status); assert(CDB_STAGNATE >= t_tries); status = cdb_sc_normal; /* signal "retry:" to avoid t_retry call */ GOTO_RETRY; @@ -2112,7 +2426,29 @@ tn_restart: */ assert(0 < gvtr_parms.num_triggers_invoked); val = trigparms.ztvalue_new; + val_forjnl = trigparms.ztvalue_new; MV_FORCE_STR(val); /* in case the updated value happens to be a numeric quantity */ + fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, blk_size, blk_reserved_bytes); + if (!fits) + { /* If val is now too big to fit in a block, we need to back out into + * gvcst_put and try again with spanning nodes. This means we should + * OP_TROLLBACK if lcl_implicit_tstart. + */ + if (lcl_implicit_tstart) + { + POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, + save_mv_chain); + OP_TROLLBACK(-1); + assert(!lcl_span_status); + parms->span_status = TRUE; + } else + { + parms->ztval_gvcst_put_redo = TRUE; + parms->ztval_mval = val; + } + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); + return; + } ztval_gvcst_put_redo = TRUE; skip_hasht_read = TRUE; /* In case, the current gvcst_put invocation was for $INCR, reset the corresponding @@ -2127,7 +2463,8 @@ tn_restart: goto fresh_tn_start; } } - POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); + /* We don't want to pop mvals yet if we still need to set chunks of ztval */ + POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain); /* pop any stacked mvals before op_tcommit as it does its own popping */ } # endif @@ -2160,7 +2497,8 @@ tn_restart: } assert(!JNL_WRITE_LOGICAL_RECS(csa) || jnl_format_done); /* Now that the SET/$INCR is finally complete, increment the corresponding GVSTAT counter */ - INCR_GVSTATS_COUNTER(csa, cnl, n_set, 1); + if (!lcl_span_status) + INCR_GVSTATS_COUNTER(csa, cnl, n_set, 1); DBG_CHECK_VAL_AT_FUN_EXIT; assert(lcl_dollar_tlevel == dollar_tlevel); return; @@ -2170,11 +2508,6 @@ retry: * invocations and in case those triggers referenced globals in different regions. But this should be fixed * by a call to t_retry/tp_restart below (it does a TP_CHANGE_REG(tp_pointer->gd_reg)). */ - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); - /* Need to restart. If directory tree was used in this transaction, nullify its clue as well (not normally - * done by t_retry). The RESTORE_ZERO_GVT_ROOT_ON_RETRY macro call below takes care of that for us. - */ - RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, tp_root, dir_hist, dir_tree); # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { @@ -2191,28 +2524,45 @@ retry: ztval_gvcst_put_redo = FALSE; skip_hasht_read = FALSE; val = lcl_val; + val_forjnl = lcl_val_forjnl; /* $increment related fields need to be restored */ is_dollar_incr = lcl_is_dollar_incr; post_incr_mval = lcl_post_incr_mval; increment_delta_mval = lcl_increment_delta_mval; } # endif - assert((cdb_sc_normal != status) GTMTRIG_ONLY(|| lcl_implicit_tstart)); + assert((cdb_sc_normal != status) GTMTRIG_ONLY(|| lcl_implicit_tstart || lcl_span_status)); if (cdb_sc_normal != status) - { - GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain)); + { /* Need to restart. If directory tree was used in this transaction, nullify its clue as well (not normally + * done by t_retry). The RESTORE_ZERO_GVT_ROOT_ON_RETRY macro call below takes care of that for us. + */ + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, dollar_tlevel ? DO_GVT_GVKEY_CHECK_RESTART : DO_GVT_GVKEY_CHECK); + RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); + GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain)); t_retry(status); + GTMTRIG_ONLY(skip_INVOKE_RESTART = FALSE); } else { /* else: t_retry has already been done so no need to do that again but need to still invoke tp_restart * to complete pending "tprestart_state" related work. + * SKIP_GVT_GVKEY_CHECK allows us to skip DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC if a trigger invocation + * restarted during GVCST_ROOT_SEARCH, in which case gv_currkey will correspond to ^#t. + * The subsequent tp_restart restores gv_currkey/gv_target to an in-sync state. */ + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, SKIP_GVT_GVKEY_CHECK); # ifdef GTM_TRIGGER assert(ERR_TPRETRY == gtm_trig_status); TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; - POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); + POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain) + if (!lcl_implicit_tstart) + { /* We started an implicit transaction for spanning nodes in gvcst_put. Invoke restart to return. */ + assert(lcl_span_status && !skip_INVOKE_RESTART && (&gvcst_put_ch == ctxt->ch)); + INVOKE_RESTART; + } # endif rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); assert(0 == rc GTMTRIG_ONLY(&& TPRESTART_STATE_NORMAL == tprestart_state)); + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); /* finishs the check skipped above */ + RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); } # ifdef GTM_TRIGGER assert(0 < t_tries); @@ -2220,16 +2570,16 @@ retry: if (cdb_sc_normal == status) { DEBUG_ONLY(save_cdb_status = status); - status = t_fail_hist[t_tries - 1]; /* get the last restart code */ + status = LAST_RESTART_CODE; } - assert(((cdb_sc_onln_rlbk1 != status) && (cdb_sc_onln_rlbk2 != status)) - || (TREF(dollar_zonlnrlbk) && !gv_target->root)); + assert((cdb_sc_onln_rlbk2 != status) || TREF(dollar_zonlnrlbk)); + assert(((cdb_sc_onln_rlbk1 != status) && (cdb_sc_onln_rlbk2 != status)) || !gv_target->root); if ((cdb_sc_onln_rlbk2 == status) && lcl_implicit_tstart) { /* Database was taken back to a different logical state and we are an implicit TP transaction. * Issue DBROLLEDBACK error that the application programmer can catch and do the necessary stuff. */ assert(gtm_trigger_depth == tstart_trigger_depth); - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); } /* Note: In case of cdb_sc_onln_rlbk1, the restart logic will take care of doing the root search */ # endif @@ -2241,11 +2591,11 @@ retry: assert(!dollar_tlevel GTMTRIG_ONLY(|| lcl_implicit_tstart)); if (dollar_tlevel) { - jnl_format_done = FALSE; /* need to reformat jnl records unconditionally in case of TP */ + jnl_format_done = !needfmtjnl; /* need to reformat jnl records unconditionally in case of TP */ tp_set_sgm(); /* set sgm_info_ptr & first_sgm_info for TP start */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVPUTFAIL); /* set update_trans and t_err for wrapped TP */ } else if (is_dollar_incr) - jnl_format_done = FALSE; /* need to reformat jnl records for $INCR even in case of non-TP */ + jnl_format_done = !needfmtjnl; /* need to reformat jnl records for $INCR even in case of non-TP */ assert(dollar_tlevel || update_trans); goto tn_restart; } diff --git a/sr_port/gvcst_query.c b/sr_port/gvcst_query.c index 0e45ebd..e8b0dc2 100644 --- a/sr_port/gvcst_query.c +++ b/sr_port/gvcst_query.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,13 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +# include "wbox_test_init.h" +#endif #include "t_end.h" #include "t_retry.h" @@ -32,6 +39,16 @@ #include "gvcst_expand_key.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_query prototype */ +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; + GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_region *gv_cur_region; @@ -40,9 +57,77 @@ GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVQUERYFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_query_ch) bool gvcst_query(void) +{ /* Similar to gvcst_order and gvcst_zprevious. In each case we skip over hidden subscripts as needed. + * + * 1 2 3 NULL <--- order/zprev... + * 1 2 3 NULL NULL + * 1 2 3 NULL NULL NULL <--- query from here... + * 1 2 3 NULL NULL NULL hidden + * 1 2 3 NULL NULL hidden + * 1 2 3 NULL hidden + * 1 2 3 hidden <--- ... skip this guy and go to bottom/top, respectively + * 1 2 3 7 <--- ... needs to end up here + */ + bool found, is_hidden, sn_tpwrapped; + boolean_t est_first_pass; + char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; + gv_key *save_gv_currkey; + int end, i; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + found = gvcst_query2(); +# ifdef UNIX + assert(save_dollar_tlevel == dollar_tlevel); + CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); + assert(found && is_hidden); + SAVE_GV_CURRKEY; + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_query_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + for (i = 0; i <= MAX_GVSUBSCRIPTS; i++) + { + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_query, (gtm_uint64_t) -1); + found = gvcst_query2(); + CHECK_HIDDEN_SUBSCRIPT_AND_BREAK(found, gv_altkey, is_hidden); + assert(found && is_hidden); + /* Replace last subscript to be the highest possible hidden subscript so another + * gvcst_query2 will give us the next non-hidden subscript. + */ + end = gv_altkey->end; + gv_currkey->base[end - 4] = 2; + gv_currkey->base[end - 3] = 0xFF; + gv_currkey->base[end - 2] = 0xFF; + gv_currkey->base[end - 1] = 1; + gv_currkey->base[end + 0] = 0; + gv_currkey->base[end + 1] = 0; + gv_currkey->end = end + 1; + } + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + RESTORE_GV_CURRKEY; + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return found; +} + +bool gvcst_query2(void) { boolean_t found, two_histories; enum cdb_sc status; @@ -57,6 +142,13 @@ bool gvcst_query(void) for (;;) { two_histories = FALSE; +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVQUERYFAIL == gtm_white_box_test_case_number)) + { + t_retry(cdb_sc_blknumerr); + continue; + } +#endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, 0))) { found = TRUE; diff --git a/sr_port/gvcst_queryget.c b/sr_port/gvcst_queryget.c index b7fbd48..f33571b 100644 --- a/sr_port/gvcst_queryget.c +++ b/sr_port/gvcst_queryget.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,6 +29,13 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +# include "wbox_test_init.h" +#endif #include "gvcst_protos.h" /* for gvcst_queryget,gvcst_search,gvcst_rtsib,gvcst_search_blk prototype */ #include "gvcst_expand_key.h" @@ -36,6 +43,17 @@ #include "t_retry.h" #include "t_end.h" +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; +LITREF mstr nsb_dummy; + GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey, *gv_altkey; @@ -45,9 +63,56 @@ GBLREF spdesc stringpool; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVQUERYGETFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_queryget_ch) boolean_t gvcst_queryget(mval *val) +{ + bool found, is_hidden, is_dummy = FALSE, sn_tpwrapped; + boolean_t est_first_pass; + char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; + gv_key *save_gv_currkey; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + found = gvcst_queryget2(val, NULL); +# ifdef UNIX + assert(save_dollar_tlevel == dollar_tlevel); + CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); + if (found && IS_SN_DUMMY(val->str.len, val->str.addr)) + is_dummy = TRUE; + if (!found || (!is_dummy && !is_hidden)) + return found; + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); + SAVE_GV_CURRKEY; + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_queryget_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + found = gvcst_query(); + COPY_KEY(gv_currkey, gv_altkey); /* set gv_currkey to gv_altkey */ + found = gvcst_get(val); + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); /* only counted externally as one get */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_query, (gtm_uint64_t) -1); + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + RESTORE_GV_CURRKEY; + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return found; +} + +boolean_t gvcst_queryget2(mval *val, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; boolean_t found, two_histories; @@ -57,6 +122,7 @@ boolean_t gvcst_queryget(mval *val) srch_blk_status *bh; srch_hist *rt_history; unsigned short temp_ushort; + int tmp_cmpc; DEBUG_ONLY(unsigned char *save_strp = NULL); T_BEGIN_READ_NONTP_OR_TP(ERR_GVQUERYGETFAIL); @@ -64,6 +130,14 @@ boolean_t gvcst_queryget(mval *val) for (;;) { two_histories = FALSE; +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVQUERYGETFAIL == gtm_white_box_test_case_number)) + { + status = cdb_sc_blknumerr; + t_retry(status); + continue; + } +#endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, 0))) { found = TRUE; @@ -109,7 +183,7 @@ boolean_t gvcst_queryget(mval *val) } key_size = gv_altkey->end + 1; GET_RSIZ(rsiz, rp); - data_len = rsiz + rp->cmpc - SIZEOF(rec_hdr) - key_size; + data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if (data_len < 0 || (sm_uc_ptr_t)rp + rsiz > (sm_uc_ptr_t)bp + ((blk_hdr_ptr_t)bp)->bsiz) { assert(CDB_STAGNATE > t_tries); @@ -122,7 +196,7 @@ boolean_t gvcst_queryget(mval *val) save_strp = stringpool.free); assert(stringpool.top - stringpool.free >= data_len); memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); - /* Assumption: t_end/tp_hist will never cause stp_gcol() call */ + /* Assumption: t_end/tp_hist will never cause stp_gcol() call BYPASSOK */ } if (!dollar_tlevel) { diff --git a/sr_port/gvcst_root_search.c b/sr_port/gvcst_root_search.c index 3211268..89008fb 100644 --- a/sr_port/gvcst_root_search.c +++ b/sr_port/gvcst_root_search.c @@ -37,6 +37,9 @@ #include "gvcst_protos.h" /* for gvcst_search,gvcst_root_search prototype */ #include "get_spec.h" #include "collseq.h" +#ifdef UNIX +#include "error.h" +#endif GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF int4 gv_keysize; @@ -47,72 +50,160 @@ GBLREF uint4 dollar_tlevel; GBLREF uint4 dollar_trestart; GBLREF unsigned int t_tries; GBLREF gv_namehead *reset_gv_target; +GBLREF boolean_t mu_reorg_process; GBLREF boolean_t mupip_jnl_recover; #ifdef UNIX # ifdef DEBUG GBLREF boolean_t is_rcvr_server; GBLREF boolean_t is_src_server; +GBLDEF unsigned char t_fail_hist_dbg[T_FAIL_HIST_DBG_SIZE]; +GBLDEF unsigned int t_tries_dbg; # endif GBLREF jnl_gbls_t jgbl; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF trans_num start_tn; GBLREF uint4 update_trans; +GBLREF inctn_opcode_t inctn_opcode; GBLREF uint4 t_err; #endif +#ifdef GTM_TRIGGER +GBLREF boolean_t skip_INVOKE_RESTART; +#endif error_def(ERR_GVGETFAIL); static mstr global_collation_mstr; +#ifdef GTM_TRIGGER +# define TRIG_TP_SET_SGM \ +{ \ + if (dollar_tlevel) \ + { \ + assert(skip_INVOKE_RESTART); \ + tp_set_sgm(); \ + } \ +} +#else +# define TRIG_TP_SET_SGM +#endif + +#define T_RETRY_AND_CLEANUP(STATUS, DONOT_RESTART) \ +{ \ + gv_target->clue.end = 0; \ + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); \ + if (DONOT_RESTART) \ + return status; /* caller will handle the restart */ \ + t_retry(STATUS); \ + save_targ->root = 0; /* May have been found by gvcst_redo_root_search. \ + * Reset and allow gvcst_root_search to find it itself. \ + */ \ + TRIG_TP_SET_SGM; \ +} + #ifdef UNIX +#define SAVE_ROOTSRCH_ENTRY_STATE \ +{ \ + int idx; \ + redo_root_search_context *rootsrch_ctxt_ptr; \ + \ + rootsrch_ctxt_ptr = &(TREF(redo_rootsrch_ctxt)); \ + rootsrch_ctxt_ptr->t_tries = t_tries; \ + for (idx = 0; CDB_MAX_TRIES > idx; idx++) \ + rootsrch_ctxt_ptr->t_fail_hist[idx] = t_fail_hist[idx]; \ + rootsrch_ctxt_ptr->prev_t_tries = TREF(prev_t_tries); \ + DEBUG_ONLY( \ + rootsrch_ctxt_ptr->t_tries_dbg = t_tries_dbg; \ + for (idx = 0; T_FAIL_HIST_DBG_SIZE > idx; idx++) \ + rootsrch_ctxt_ptr->t_fail_hist_dbg[idx] = t_fail_hist_dbg[idx]; \ + ) \ + rootsrch_ctxt_ptr->start_tn = start_tn; \ + rootsrch_ctxt_ptr->update_trans = update_trans; \ + rootsrch_ctxt_ptr->inctn_opcode = inctn_opcode; \ + inctn_opcode = 0; \ + rootsrch_ctxt_ptr->t_err = t_err; \ + rootsrch_ctxt_ptr->hold_onto_crit = cs_addrs->hold_onto_crit; \ + if (CDB_STAGNATE <= t_tries) \ + { \ + assert(cs_addrs->now_crit); \ + cs_addrs->hold_onto_crit = TRUE; \ + } \ + if (mu_reorg_process) \ + { /* In case gv_currkey/gv_target are out of sync. */ \ + rootsrch_ctxt_ptr->gv_currkey = (gv_key *)&rootsrch_ctxt_ptr->currkey[0]; \ + MEMCPY_KEY(rootsrch_ctxt_ptr->gv_currkey, gv_currkey); \ + SET_GV_CURRKEY_FROM_REORG_GV_TARGET; \ + } \ +} + +#define RESTORE_ROOTSRCH_ENTRY_STATE \ +{ \ + int idx; \ + redo_root_search_context *rootsrch_ctxt_ptr; \ + \ + rootsrch_ctxt_ptr = &(TREF(redo_rootsrch_ctxt)); \ + t_tries = rootsrch_ctxt_ptr->t_tries; \ + for (idx = 0; CDB_MAX_TRIES > idx; idx++) \ + t_fail_hist[idx] = rootsrch_ctxt_ptr->t_fail_hist[idx]; \ + TREF(prev_t_tries) = rootsrch_ctxt_ptr->prev_t_tries; \ + DEBUG_ONLY( \ + t_tries_dbg = rootsrch_ctxt_ptr->t_tries_dbg; \ + for (idx = 0; T_FAIL_HIST_DBG_SIZE > idx; idx++) \ + t_fail_hist_dbg[idx] = rootsrch_ctxt_ptr->t_fail_hist_dbg[idx]; \ + ) \ + start_tn = rootsrch_ctxt_ptr->start_tn; \ + update_trans = rootsrch_ctxt_ptr->update_trans; \ + inctn_opcode = rootsrch_ctxt_ptr->inctn_opcode; \ + t_err = rootsrch_ctxt_ptr->t_err; \ + cs_addrs->hold_onto_crit = rootsrch_ctxt_ptr->hold_onto_crit; \ + TREF(in_gvcst_redo_root_search) = FALSE; \ + if (mu_reorg_process) \ + /* Restore gv_currkey */ \ + MEMCPY_KEY(gv_currkey, rootsrch_ctxt_ptr->gv_currkey); \ +} + +CONDITION_HANDLER(gvcst_redo_root_search_ch) +{ + START_CH; + + RESTORE_ROOTSRCH_ENTRY_STATE; + + NEXTCH; +} + void gvcst_redo_root_search() { DEBUG_ONLY(boolean_t dbg_now_crit;) - boolean_t save_hold_onto_crit; - int idx; - trans_num save_start_tn; - uint4 save_update_trans, save_t_err; - unsigned char save_t_fail_hist[CDB_MAX_TRIES]; - unsigned int save_t_tries; + uint4 lcl_onln_rlbkd_cycle; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - assert(!TREF(in_gvcst_redo_root_search)); /* should never recurse */ - DEBUG_ONLY(TREF(in_gvcst_redo_root_search) = TRUE;) + ESTABLISH(gvcst_redo_root_search_ch); + assert(!TREF(in_gvcst_redo_root_search)); /* Should never recurse. However, can be called from non-redo gvcst_root_search, + * e.g. from op_gvname. In that case, the results of gvcst_redo_root_search are + * discarded and the outer root search correctly sets gv_target->root. + */ + TREF(in_gvcst_redo_root_search) = TRUE; assert(0 < t_tries); assert(!is_src_server && !is_rcvr_server); assert(!jgbl.onlnrlbk); assert((NULL != gv_target) && !gv_target->root); assert(cs_addrs == gv_target->gd_csa); assert(!dollar_tlevel); - save_t_tries = t_tries; - for (idx = 0; CDB_MAX_TRIES > idx; idx++) - save_t_fail_hist[idx] = t_fail_hist[idx]; - save_start_tn = start_tn; - save_update_trans = update_trans; - save_t_err = t_err; DEBUG_ONLY(dbg_now_crit = cs_addrs->now_crit); - save_hold_onto_crit = cs_addrs->hold_onto_crit; - if (CDB_STAGNATE <= t_tries) - { - assert(cs_addrs->now_crit); - cs_addrs->hold_onto_crit = TRUE; - } + /* save global variables now that we are going to do the root search in the middle of the current transaction */ + SAVE_ROOTSRCH_ENTRY_STATE; + lcl_onln_rlbkd_cycle = cs_addrs->db_onln_rlbkd_cycle; GVCST_ROOT_SEARCH; + if (lcl_onln_rlbkd_cycle != cs_addrs->nl->db_onln_rlbkd_cycle) + TREF(rlbk_during_redo_root) = TRUE; assert(cs_addrs->now_crit == dbg_now_crit); /* ensure crit state remains same AFTER gvcst_root_search */ /* restore global variables now that we are continuing with the original transaction */ - t_tries = save_t_tries; - cs_addrs->hold_onto_crit = save_hold_onto_crit; - for (idx = 0; CDB_MAX_TRIES > idx; idx++) - t_fail_hist[idx] = save_t_fail_hist[idx]; - start_tn = save_start_tn; - update_trans = save_update_trans; - t_err = save_t_err; - DEBUG_ONLY(TREF(in_gvcst_redo_root_search) = FALSE;) + RESTORE_ROOTSRCH_ENTRY_STATE; + REVERT; } #endif -void gvcst_root_search(void) +enum cdb_sc gvcst_root_search(boolean_t donot_restart) { srch_blk_status *h0; sm_uc_ptr_t rp; @@ -123,18 +214,24 @@ void gvcst_root_search(void) gv_namehead *save_targ; mname_entry *gvent; int altkeylen; + int tmp_cmpc; block_id lcl_root; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)); SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY; /* set up gv_altkey to be just the gblname */ save_targ = gv_target; /* Check if "gv_target->gvname" matches "gv_altkey->base". If not, there is a name mismatch (out-of-design situation). - * This check is temporary until we catch the situation that caused D9H02-002641 */ + * This check is temporary until we catch the situation that caused D9H02-002641. + * It's suspected the original situation has been fixed (see D9I08-002695). But the assertpro will remain until + * gvcst_redo_root_search has been well-tested. + */ /* --- Check BEGIN --- */ gvent = &save_targ->gvname; altkeylen = gv_altkey->end - 1; - if (!altkeylen || (altkeylen != gvent->var_name.len) || memcmp(gv_altkey->base, gvent->var_name.addr, gvent->var_name.len)) - GTMASSERT; + assertpro(altkeylen && (altkeylen == gvent->var_name.len) + && (0 == memcmp(gv_altkey->base, gvent->var_name.addr, gvent->var_name.len))); /* --- Check END --- */ if (INVALID_GV_TARGET != reset_gv_target) gbl_target_was_set = TRUE; @@ -144,12 +241,12 @@ void gvcst_root_search(void) reset_gv_target = save_targ; } gv_target = cs_addrs->dir_tree; - lcl_root = 0; T_BEGIN_READ_NONTP_OR_TP(ERR_GVGETFAIL); /* We better hold crit in the final retry (TP & non-TP). Only exception is journal recovery */ assert((t_tries < CDB_STAGNATE) || cs_addrs->now_crit || mupip_jnl_recover); for (;;) { + lcl_root = 0; /* set lcl_root to 0 at the start of every iteration (this way even retry will get fresh value) */ hdr_len = rlen = 0; gv_target = cs_addrs->dir_tree; if (dollar_trestart) @@ -161,13 +258,11 @@ void gvcst_root_search(void) { h0 = gv_target->hist.h; rp = (h0->buffaddr + h0->curr_rec.offset); - hdr_len = SIZEOF(rec_hdr) + gv_altkey->end + 1 - ((rec_hdr_ptr_t)rp)->cmpc; + hdr_len = SIZEOF(rec_hdr) + gv_altkey->end + 1 - EVAL_CMPC((rec_hdr_ptr_t)rp); GET_USHORT(rlen, rp); if (FALSE == (CHKRECLEN(rp, h0->buffaddr, rlen)) || (rlen < hdr_len + SIZEOF(block_id))) { - gv_target->clue.end = 0; - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); - t_retry(cdb_sc_rmisalign); + T_RETRY_AND_CLEANUP(cdb_sc_rmisalign, donot_restart); continue; } GET_LONG(lcl_root, (rp + hdr_len)); @@ -192,9 +287,7 @@ void gvcst_root_search(void) status = tp_hist(NULL); if (cdb_sc_normal != status) { - gv_target->clue.end = 0; - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); - t_retry(status); + T_RETRY_AND_CLEANUP(status, donot_restart); continue; } break; @@ -209,21 +302,17 @@ void gvcst_root_search(void) status = tp_hist(NULL); if (cdb_sc_normal == status) break; - gv_target->clue.end = 0; - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); - t_retry(status); + T_RETRY_AND_CLEANUP(status, donot_restart); continue; } } else { - gv_target->clue.end = 0; - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); - t_retry(status); + T_RETRY_AND_CLEANUP(status, donot_restart); continue; } } save_targ->root = lcl_root; /* now that we know the transaction validated fine, set root block in gv_target */ - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); if (rlen > hdr_len + SIZEOF(block_id)) { assert(NULL != global_collation_mstr.addr); @@ -249,5 +338,5 @@ void gvcst_root_search(void) if (gv_target->act) act_in_gvt(); assert(gv_target->act || NULL == gv_target->collseq); - return; + return cdb_sc_normal; } diff --git a/sr_port/gvcst_search.c b/sr_port/gvcst_search.c index 85637d4..ae1b082 100644 --- a/sr_port/gvcst_search.c +++ b/sr_port/gvcst_search.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -64,6 +64,7 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ register srch_blk_status *pCurr; register srch_blk_status *pNonStar; register srch_hist *pTargHist; + int tmp_cmpc; block_id nBlkId; cache_rec_ptr_t cr; int cycle; @@ -75,9 +76,11 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ boolean_t already_built, is_mm; ht_ent_int4 *tabent; sm_uc_ptr_t buffaddr; - trans_num blkhdrtn; + trans_num blkhdrtn, oldest_hist_tn; int hist_size; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; pTarg = gv_target; assert(NULL != pTarg); assert(pTarg->root); @@ -149,15 +152,13 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ * gv_target in this TP transaction and if so we need to reset the out-of-date field. */ if (pTarg->read_local_tn != local_tn) - { - for (srch_status = &pTarg->hist.h[0]; HIST_TERMINATOR != srch_status->blk_num; srch_status++) - srch_status->first_tp_srch_status = NULL; - } + GVT_CLEAR_FIRST_TP_SRCH_STATUS(pTarg); /* TP & going to use clue. check if clue path contains a leaf block with a corresponding unbuilt * cse from the previous traversal. If so build it first before gvcst_search_blk/gvcst_search_tail. */ tp_srch_status = NULL; leaf_blk_hist = &pTarg->hist.h[0]; + assert(leaf_blk_hist->blk_target == pTarg); assert(0 == leaf_blk_hist->level); chain1 = *(off_chain *)&leaf_blk_hist->blk_num; if (chain1.flag == 1) @@ -181,7 +182,7 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ cse = (NULL != tp_srch_status) ? tp_srch_status->cse : NULL; } assert(!cse || !cse->high_tlevel); - if ((NULL == tp_srch_status) || (tp_srch_status->blk_target == leaf_blk_hist->blk_target)) + if ((NULL == tp_srch_status) || (tp_srch_status->blk_target == pTarg)) { /* Either the leaf level block in clue is not already present in the current TP transaction's * hashtable OR it is already present and the corresponding globals match. If they dont match * we know for sure the clue is out-of-date (i.e. using it will lead to a transaction restart) @@ -237,19 +238,33 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ leaf_blk_hist->cycle = CYCLE_PVT_COPY; leaf_blk_hist->buffaddr = cse->new_buff; } else - { /* Keep leaf_blk_hist->buffaddr and cse->new_buff in sync. Dont know how they - * cannot be the same but it seems possible if the gvcst_blk_build happened as - * part of a t_qread call (which does not have enough information to update the - * search history buffer address) without going through gvcst_search. Since the - * consequences of these two not being in sync are database damage, we fix them - * in pro just in case they are different. + { /* Keep leaf_blk_hist->buffaddr and cse->new_buff in sync. If a TP transaction + * updates two different globals and the second update invoked t_qread for a leaf + * block corresponding to the first global and ended up constructing a private block + * then leaf_blk_hist->buffaddr of the first global will be out-of-sync with the + * cse->new_buff. However, the transaction validation done in tp_hist/tp_tend + * should detect this and restart. Set donot_commit to verify that a restart happens */ - assert(leaf_blk_hist->buffaddr == cse->new_buff); - leaf_blk_hist->buffaddr = cse->new_buff; +# ifdef DEBUG + if (leaf_blk_hist->buffaddr != cse->new_buff) + TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC; +# endif + leaf_blk_hist->buffaddr = cse->new_buff; /* sync the buffers in pro, just in case */ } } } else - status = cdb_sc_lostcr; /* two different gv_targets point to same block; discard out-of-date clue */ + { /* Two different gv_targets point to same block; discard out-of-date clue. */ +# ifdef DEBUG + if ((pTarg->read_local_tn >= local_tn) && (NULL != leaf_blk_hist->first_tp_srch_status)) + { /* Since the clue was used in *this* transaction, it cannot successfully complete. Set + * donot_commit to verify that a restart happens (either in tp_hist or tp_tend) + */ + assert(pTarg->read_local_tn == local_tn); + TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH; + } +# endif + status = cdb_sc_lostcr; + } } /* Validate EVERY level in the clue before using it for ALL retries. This way we avoid unnecessary restarts. * This is NECESSARY for the final retry (e.g. in a TP transaction that does LOTS of reads of different globals, @@ -257,9 +272,11 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ * performance reasons) in the other tries. The cost of a restart (particularly in TP) is very high that it is * considered okay to take the hit of validating the entire clue before using it even if it is not the final retry. */ - DEBUG_ONLY(is_mm = (dba_mm == cs_data->acc_meth);) if (cdb_sc_normal == status) { + is_mm = (dba_mm == cs_data->acc_meth); + if (!is_mm) + oldest_hist_tn = OLDEST_HIST_TN(cs_addrs); for (srch_status = &pTargHist->h[0]; HIST_TERMINATOR != srch_status->blk_num; srch_status++) { assert(srch_status->level == srch_status - &pTargHist->h[0]); @@ -279,8 +296,17 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ status = cdb_sc_lostcr; break; } - if (CDB_STAGNATE <= t_tries || mu_reorg_process) + if ((CDB_STAGNATE <= t_tries) || mu_reorg_process) + { CWS_INSERT(cr->blk); + if ((CDB_STAGNATE <= t_tries) && (srch_status->tn <= oldest_hist_tn)) + { /* The tn at which the history was last validated is before the earliest + * transaction in the BT. The clue can no longer be relied upon. + */ + status = cdb_sc_losthist; + break; + } + } cr->refer = TRUE; } } @@ -457,12 +483,13 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } - if (pNonStar->curr_rec.match < ((rec_hdr_ptr_t)pRec)->cmpc) + EVAL_CMPC2((rec_hdr_ptr_t)pRec, n1); + if (pNonStar->curr_rec.match < n1) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } - if ((n1 = ((rec_hdr_ptr_t)pRec)->cmpc) > (int)(pTarg->last_rec->top)) + if (n1 > (int)(pTarg->last_rec->top)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_keyoflow; diff --git a/sr_port/gvcst_zprevious.c b/sr_port/gvcst_zprevious.c index a2004ef..040b517 100644 --- a/sr_port/gvcst_zprevious.c +++ b/sr_port/gvcst_zprevious.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,6 +27,12 @@ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ +#ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ +# include "repl_msg.h" +# include "gtmsource.h" +# include "rtnhdr.h" +# include "stack_frame.h" +#endif #include "t_end.h" /* prototypes */ #include "t_retry.h" @@ -34,6 +40,16 @@ #include "gvcst_expand_key.h" #include "gvcst_protos.h" /* for gvcst_lftsib,gvcst_search,gvcst_search_blk,gvcst_zprevious prototype */ +/* needed for spanning nodes */ +#include "op.h" +#include "op_tcommit.h" +#include "error.h" +#include "tp_frame.h" +#include "tp_restart.h" +#include "gtmimagename.h" + +LITREF mval literal_batch; + GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; @@ -43,9 +59,70 @@ GBLREF int4 gv_keysize; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; +error_def(ERR_DBROLLEDBACK); error_def(ERR_GVORDERFAIL); +error_def(ERR_TPRETRY); + +DEFINE_NSB_CONDITION_HANDLER(gvcst_zprevious_ch) bool gvcst_zprevious(void) +{ /* See gvcst_query.c */ + bool found, is_hidden, sn_tpwrapped; + boolean_t est_first_pass; + char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; + gv_key *save_gv_currkey; + int end, prev, oldend; + int save_dollar_tlevel; + + DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); + found = gvcst_zprevious2(); +# ifdef UNIX + assert(save_dollar_tlevel == dollar_tlevel); + CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); + assert(found && is_hidden); + IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); + SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); + if (!dollar_tlevel) + { + sn_tpwrapped = TRUE; + op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); + ESTABLISH_NORET(gvcst_zprevious_ch, est_first_pass); + GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); + } else + sn_tpwrapped = FALSE; + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1); + found = gvcst_zprevious2(); + if (found) + { + CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); + if (is_hidden) + { /* Replace last subscript to be the lowest possible hidden subscript so another + * gvcst_zprevious2 will give us the previous non-hidden subscript. + */ + end = gv_altkey->end; + gv_currkey->base[end - 4] = 2; + gv_currkey->base[end - 3] = 1; + gv_currkey->base[end - 2] = 1; + gv_currkey->base[end - 1] = 0; + gv_currkey->base[end + 0] = 0; + gv_currkey->end = end; + /* fix up since it should only be externally counted as one $zprevious */ + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1); + found = gvcst_zprevious2(); + } + } + if (sn_tpwrapped) + { + op_tcommit(); + REVERT; /* remove our condition handler */ + } + RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); + assert(save_dollar_tlevel == dollar_tlevel); +# endif + return found; +} + +bool gvcst_zprevious2(void) { static gv_key *zprev_temp_key; static int4 zprev_temp_keysize = 0; diff --git a/sr_port/gvincr_compute_post_incr.c b/sr_port/gvincr_compute_post_incr.c index c00c294..e6bee83 100644 --- a/sr_port/gvincr_compute_post_incr.c +++ b/sr_port/gvincr_compute_post_incr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2007 Fidelity Information Services, Inc * + * Copyright 2004, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -49,6 +49,7 @@ enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh) int4 target_key_size, data_len; uint4 gvincr_malloc_len; mval pre_incr_mval; + int tmp_cmpc; buffaddr = bh->buffaddr; cur_blk_size = ((blk_hdr_ptr_t)buffaddr)->bsiz; @@ -56,7 +57,7 @@ enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh) GET_USHORT(rec_size, &rp->rsiz); target_key_size = bh->curr_rec.match; assert(target_key_size == gv_currkey->end + 1); - data_len = rec_size + rp->cmpc - SIZEOF(rec_hdr) - target_key_size; + data_len = rec_size + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - target_key_size; if ((0 > data_len) || (((sm_uc_ptr_t)rp + rec_size) > ((sm_uc_ptr_t)buffaddr + cur_blk_size))) { assert(CDB_STAGNATE > t_tries); diff --git a/sr_port/gvincr_recompute_upd_array.c b/sr_port/gvincr_recompute_upd_array.c index ed14184..fa94eea 100644 --- a/sr_port/gvincr_recompute_upd_array.c +++ b/sr_port/gvincr_recompute_upd_array.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2010 Fidelity Information Services, Inc * + * Copyright 2004, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -59,6 +59,7 @@ enum cdb_sc gvincr_recompute_upd_array(srch_blk_status *bh, struct cw_set_elemen enum cdb_sc status; int4 blk_size, blk_fill_size, cur_blk_size, blk_seg_cnt, delta, tail_len, new_rec_size; int4 target_key_size, data_len; + int tmp_cmpc; mstr value; rec_hdr_ptr_t curr_rec_hdr, rp; sm_uc_ptr_t cp1, buffaddr; @@ -114,7 +115,7 @@ enum cdb_sc gvincr_recompute_upd_array(srch_blk_status *bh, struct cw_set_elemen cur_blk_size = ((blk_hdr_ptr_t)buffaddr)->bsiz; rp = (rec_hdr_ptr_t)(buffaddr + bh->curr_rec.offset); GET_USHORT(rec_size, &rp->rsiz); - data_len = rec_size + rp->cmpc - SIZEOF(rec_hdr) - target_key_size; + data_len = rec_size + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - target_key_size; if (cdb_sc_normal != (status = gvincr_compute_post_incr(bh))) { assert(CDB_STAGNATE > t_tries); @@ -149,7 +150,7 @@ enum cdb_sc gvincr_recompute_upd_array(srch_blk_status *bh, struct cw_set_elemen BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), bh->curr_rec.offset - SIZEOF(blk_hdr)); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; - curr_rec_hdr->cmpc = bh->prev_rec.match; + SET_CMPC(curr_rec_hdr, bh->prev_rec.match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - bh->prev_rec.match, unsigned char); memcpy(cp1, gv_currkey->base + bh->prev_rec.match, target_key_size - bh->prev_rec.match); diff --git a/sr_port/gvn.c b/sr_port/gvn.c index 767eb9c..5ce3e76 100644 --- a/sr_port/gvn.c +++ b/sr_port/gvn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,10 +13,12 @@ #include "compiler.h" #include "opcode.h" #include "toktyp.h" -#include "subscript.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" +#include "show_source_line.h" + +GBLREF boolean_t run_time; error_def(ERR_EXPR); error_def(ERR_EXTGBLDEL); @@ -24,6 +26,7 @@ error_def(ERR_GBLNAME); error_def(ERR_GVNAKEDEXTNM); error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); +error_def(ERR_SIDEEFFECTEVAL); int gvn(void) { @@ -31,7 +34,7 @@ int gvn(void) char x; opctype ox; oprtype *sb1, *sb2, subscripts[MAX_GVSUBSCRIPTS]; - triple *oldchain, *ref, *s, *t1, tmpchain, *triptr; + triple *oldchain, *ref, *s, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -39,8 +42,9 @@ int gvn(void) advancewindow(); sb1 = sb2 = subscripts; ox = 0; - if (shifting = (TREF(shift_side_effects) && GTM_BOOL == TREF(gtm_fullbool))) /* NOTE assignment */ - { + if (shifting = (TREF(shift_side_effects) && (!TREF(saw_side_effect) || (GTM_BOOL == TREF(gtm_fullbool) + && (OLD_SE == TREF(side_effect_handling)))))) + { /* NOTE assignment above */ dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); } @@ -108,6 +112,7 @@ int gvn(void) ox = OC_GVNAKED; } if (TK_LPAREN == TREF(window_token)) + { for (;;) { if (sb1 >= ARRAYTOP(subscripts)) @@ -142,23 +147,26 @@ int gvn(void) return FALSE; } } + } ref = newtriple(ox); ref->operand[0] = put_ilit((mint)(sb1 - sb2)); - for ( ; sb2 < sb1 ; sb2++) - { - t1 = newtriple(OC_PARAMETER); - ref->operand[1] = put_tref(t1); - ref = t1; - ref->operand[0] = *sb2; - } + SUBS_ARRAY_2_TRIPLES(ref, sb1, sb2, subscripts, 0); if (shifting) { - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - triptr = newtriple(OC_GVRECTARG); - triptr->operand[0] = put_tref(TREF(expr_start)); + if (TREF(saw_side_effect) && ((GTM_BOOL != TREF(gtm_fullbool)) || (OLD_SE != TREF(side_effect_handling)))) + { /* saw a side effect in a subscript - time to stop shifting */ + setcurtchain(oldchain); + triptr = (TREF(curtchain))->exorder.bl; + dqadd(triptr, &tmpchain, exorder); + } else + { + newtriple(OC_GVSAVTARG); + setcurtchain(oldchain); + dqadd(TREF(expr_start), &tmpchain, exorder); + TREF(expr_start) = tmpchain.exorder.bl; + triptr = newtriple(OC_GVRECTARG); + triptr->operand[0] = put_tref(TREF(expr_start)); + } } return TRUE; } diff --git a/sr_port/gvname_env_restore.c b/sr_port/gvname_env_restore.c index e297d4c..0ff3006 100644 --- a/sr_port/gvname_env_restore.c +++ b/sr_port/gvname_env_restore.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,7 +53,8 @@ void gvname_env_restore(gvname_info *curr_gvname_info) gv_currkey->prev = curr_gvname_info->s_gv_currkey->prev; memcpy(gv_currkey->base, curr_gvname_info->s_gv_currkey->base, curr_gvname_info->s_gv_currkey->end + 1); sgm_info_ptr = curr_gvname_info->s_sgm_info_ptr; - assert((is_bg_or_mm && ((dollar_tlevel && sgm_info_ptr) || (!dollar_tlevel && !sgm_info_ptr))) || - dba_cm == gv_cur_region->dyn.addr->acc_meth || dba_usr == gv_cur_region->dyn.addr->acc_meth); + assert((is_bg_or_mm && ((dollar_tlevel && sgm_info_ptr) || (!dollar_tlevel && !sgm_info_ptr))) + || (dba_cm == gv_cur_region->dyn.addr->acc_meth) || (dba_usr == gv_cur_region->dyn.addr->acc_meth)); + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); } diff --git a/sr_port/gvname_env_save.c b/sr_port/gvname_env_save.c index c1b0082..6ae7cc4 100644 --- a/sr_port/gvname_env_save.c +++ b/sr_port/gvname_env_save.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,7 +45,7 @@ void gvname_env_save(gvname_info * curr_gvname_info) assert((is_bg_or_mm && cs_addrs->hdr == cs_data) || dba_cm == gv_cur_region->dyn.addr->acc_meth || dba_usr == gv_cur_region->dyn.addr->acc_meth); curr_gvname_info->s_cs_addrs = cs_addrs; - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); assert(gv_currkey->top <= curr_gvname_info->s_gv_currkey->top); curr_gvname_info->s_gv_currkey->end = gv_currkey->end; curr_gvname_info->s_gv_currkey->prev = gv_currkey->prev; diff --git a/sr_port/gvsub2str.c b/sr_port/gvsub2str.c index 0b6468e..5fde359 100644 --- a/sr_port/gvsub2str.c +++ b/sr_port/gvsub2str.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -54,6 +54,8 @@ unsigned char *gvsub2str(unsigned char *sub, unsigned char *targ, boolean_t xlat { unsigned char buf1[MAX_KEY_SZ + 1], ch, *ptr, trail_ch; unsigned short *tbl_ptr; + int num, rev_num, trail_zero; + span_subs *subs_ptr; int expon, in_length, length, tmp; mstr mstr_ch, mstr_targ; DCL_THREADGBL_ACCESS; @@ -93,6 +95,27 @@ unsigned char *gvsub2str(unsigned char *sub, unsigned char *targ, boolean_t xlat { /* Number */ if (SUBSCRIPT_ZERO == ch) *targ++ = '0'; + else if(SPANGLOB_SUB_ESCAPE == ch) + { + ASGN_SPAN_PREFIX(targ); + targ += SPAN_PREFIX_LEN; + subs_ptr = (span_subs *)(sub - 1); + /* Internal to the database, the spanning node blocks counting starts with 0 i.e. first spanning + * node block has ID '0' but while displaying first block of spanning node is displayed as '1' + * Hence the below adjustment in the 'num'. + */ + num = SPAN_GVSUBS2INT(subs_ptr) + 1; + sub = (sub - 1) + SPAN_SUBS_LEN; + for (trail_zero = 0; (num % DECIMAL_BASE) == 0; trail_zero++, num /= DECIMAL_BASE) + ; + for (rev_num = 0; num > 0; rev_num = (rev_num * DECIMAL_BASE + num % DECIMAL_BASE), num /= DECIMAL_BASE) + ; + for (; rev_num > 0; *targ++ = (rev_num % DECIMAL_BASE + ASCII_0), rev_num /= DECIMAL_BASE) + ; + for (; trail_zero > 0 ; *targ++ = '0', trail_zero--); + if (*sub != 0) + *targ++ = '*'; + } else { tbl_ptr = (unsigned short *)&dpos[0] - 1; diff --git a/sr_port/gvzwr_fini.c b/sr_port/gvzwr_fini.c index 903c124..44890b5 100644 --- a/sr_port/gvzwr_fini.c +++ b/sr_port/gvzwr_fini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,7 +58,7 @@ void gvzwr_fini(zshow_out *out, int pat) zwr_output = out; assert(INVALID_GV_TARGET == reset_gv_target); reset_gv_target = gv_target; - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); gvzwrite_block->gd_reg = gv_cur_region; gvzwrite_block->old_targ = (unsigned char *)gv_target; old = (gv_key *)malloc(SIZEOF(gv_key) + gv_currkey->end); diff --git a/sr_port/hashtab_mname.c b/sr_port/hashtab_mname.c index 38ca4bd..acbf138 100644 --- a/sr_port/hashtab_mname.c +++ b/sr_port/hashtab_mname.c @@ -15,7 +15,7 @@ #include "error.h" #include "send_msg.h" #include "gtmmsg.h" -#include "rtnhdr.h" +#include #include "hashtab_mname.h" #include "gdsroot.h" #include "gtm_facility.h" diff --git a/sr_port/have_crit.c b/sr_port/have_crit.c index 04aa469..d9d69cb 100644 --- a/sr_port/have_crit.c +++ b/sr_port/have_crit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -64,7 +64,7 @@ uint4 have_crit(uint4 crit_state) UNIX_ONLY(assert(!jgbl.onlnrlbk)); /* should not request crit to be released if online rollback */ crit_state |= CRIT_ALL_REGIONS; } - if (0 != crit_count) + if ((0 != crit_count) && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; if (0 == (crit_state & CRIT_ALL_REGIONS)) @@ -79,7 +79,7 @@ uint4 have_crit(uint4 crit_state) csa = &FILE_INFO(r_local)->s_addrs; if (NULL != csa) { - if (csa->now_crit) + if ((csa->now_crit) && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; /* It is possible that if DSE has done a CRIT REMOVE and stolen our crit, it @@ -98,12 +98,11 @@ uint4 have_crit(uint4 crit_state) (0 == (crit_state & CRIT_NOT_TRANS_REG) || crit_deadlock_check_cycle != csa->crit_check_cycle)) { - assert(FALSE); + assert(WBTEST_HOLD_CRIT_ENABLED); assert(!csa->hold_onto_crit); rel_crit(r_local); - send_msg(VARLSTCNT(8) ERR_MUTEXRELEASED, 6, - process_id, process_id, DB_LEN_STR(r_local), - dollar_tlevel, t_tries); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_MUTEXRELEASED, 6, process_id, + process_id, DB_LEN_STR(r_local), dollar_tlevel, t_tries); } if (0 == (crit_state & CRIT_ALL_REGIONS)) return crit_reg_cnt; @@ -132,7 +131,7 @@ uint4 have_crit(uint4 crit_state) if (NULL != jnlpool.jnlpool_ctl) { csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; - if (NULL != csa && csa->now_crit) + if ((NULL != csa) && csa->now_crit && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; if (0 != (crit_state & CRIT_RELEASE)) diff --git a/sr_port/have_crit.h b/sr_port/have_crit.h index 5558c21..c515bf6 100644 --- a/sr_port/have_crit.h +++ b/sr_port/have_crit.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,18 +18,12 @@ #endif /* states of CRIT passed as argument to have_crit() */ -#define CRIT_IN_COMMIT 0x00000001 -#define CRIT_NOT_TRANS_REG 0x00000002 -#define CRIT_RELEASE 0x00000004 -#define CRIT_ALL_REGIONS 0x00000008 - -#define CRIT_IN_WTSTART 0x00000010 /* check if csa->in_wtstart is true */ - -/* Note absence of any flags is default value which finds if any region - * or the replication pool have crit or are getting crit. It returns - * when one is found without checking further. -*/ -#define CRIT_HAVE_ANY_REG 0x00000000 +#define CRIT_HAVE_ANY_REG 0x00000001 +#define CRIT_IN_COMMIT 0x00000002 +#define CRIT_NOT_TRANS_REG 0x00000004 +#define CRIT_RELEASE 0x00000008 +#define CRIT_ALL_REGIONS 0x00000010 +#define CRIT_IN_WTSTART 0x00000020 /* check if csa->in_wtstart is true */ #ifdef DEBUG #include "wbox_test_init.h" @@ -53,26 +47,64 @@ typedef enum INTRPT_IN_TRIGGER_NOMANS_LAND, /* State where have trigger base frame but no trigger (exec) frame */ INTRPT_IN_MUR_OPEN_FILES, INTRPT_IN_TRUNC, - INTRPT_NUM_STATES, INTRPT_IN_SET_NUM_ADD_PROCS, INTRPT_IN_SYSCONF, INTRPT_NO_TIMER_EVENTS, /* State where primary reason for deferral is to avoid timer pops */ - INTRPT_IN_FFLUSH /* Deferring interrupts during fflush */ + INTRPT_IN_FFLUSH, /* Deferring interrupts during fflush */ + INTRPT_IN_SHMDT, /* Deferring interrupts during SHMDT */ + INTRPT_IN_WAIT_FOR_DISK_SPACE, /* Deferring interrupts during wait_for_disk_space.c */ + INTRPT_IN_WCS_WTSTART, /* Deferring interrupts until cnl->intent_wtstart is decremented and dbsync timer is + * started */ + INTRPT_IN_REFORMAT_BUFFER_USE, /* Deferring interrupts until buffer is reformatted */ + INTRPT_IN_X_TIME_FUNCTION, /* Deferring interrupts in non-nesting functions, such as localtime, ctime, and mktime. */ + INTRPT_IN_FUNC_WITH_MALLOC, /* Deferring interrupts while in libc- or system functions that do a malloc internally. */ + INTRPT_IN_FDOPEN, /* Deferring interrupts in fdopen. */ + INTRPT_IN_LOG_FUNCTION, /* Deferring interrupts in openlog, syslog, or closelog. */ + INTRPT_IN_FORK_OR_SYSTEM, /* Deferring interrupts in fork or system. */ + INTRPT_IN_FSTAT, /* Deferring interrupts in fstat. */ + INTRPT_NUM_STATES /* Should be the *last* one in the enum */ } intrpt_state_t; GBLREF intrpt_state_t intrpt_ok_state; GBLREF boolean_t deferred_timers_check_needed; -/* Macro to check if we are in a state that is ok to interrupt (or to do deferred signal handling). - * We do not want to interrupt if the global variable intrpt_ok_state indicates it is not ok to interrupt, - * if we are in the midst of a malloc, if we are holding crit, if we are in the midst of commit, or in - * wcs_wtstart. In the last case, we could be causing another process HOLDING CRIT on the region to wait - * in bg_update_phase1 if we hold the write interlock. Hence it is important for us to finish that as soon - * as possible and not interrupt it. +/* Macro to check if we are in a state that is ok to interrupt (or to do deferred signal handling). We do not want to interrupt if + * the global variable intrpt_ok_state indicates it is not ok to interrupt, if we are in the midst of a malloc, if we are holding + * crit, if we are in the midst of commit, or in wcs_wtstart. In the last case, we could be causing another process HOLDING CRIT on + * the region to wait in bg_update_phase1 if we hold the write interlock. Hence it is important for us to finish that as soon as + * possible and not interrupt it. */ #define OK_TO_INTERRUPT ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (0 == gtmMallocDepth) \ && (0 == have_crit(CRIT_HAVE_ANY_REG | CRIT_IN_COMMIT | CRIT_IN_WTSTART))) +/* Set the value of forced_exit to 1. This should indicate that we want a deferred signal handler to be invoked first upon leaving + * the current deferred window. Since we do not want forced_exit state to ever regress, and there might be several signals delivered + * within the same deferred window, assert that forced_exit is either 0 or 1 before setting it to 1. + */ +#define SET_FORCED_EXIT_STATE \ +{ \ + GBLREF VSIG_ATOMIC_T forced_exit; \ + \ + assert((0 == forced_exit) || (1 == forced_exit)); \ + forced_exit = 1; \ +} + +/* Set the value of forced_exit to 2. This should indicate that we are already in the exit processing, and do not want to handle any + * deferred events, from timers or other interrupts, anymore. Ensure that forced_exit state does not regress by asserting that the + * current value is 0 or 1 before setting it to 2. Note that on UNIX forced_exit can progress to 2 only from 1, while on VMS it is + * possible to generic_exit_handler or dbcertify_exit_handler to change forced_exit from 0 to 2 directly. This design ensures that + * on VMS we will not invoke sys$exit from DEFERRED_EXIT_HANDLING_CHECK after we started exit processing; on UNIX process_exiting + * flag servs the same purpose (and is also checked by DEFERRED_EXIT_HANDLING_CHECK), so it is not necessary for either + * generic_signal_handler or dbcertify_signal_handler to set forced_exit to 2. + */ +#define SET_FORCED_EXIT_STATE_ALREADY_EXITING \ +{ \ + GBLREF VSIG_ATOMIC_T forced_exit; \ + \ + assert(VMS_ONLY((0 == forced_exit) || ) (1 == forced_exit)); \ + forced_exit = 2; \ +} + /* Macro to be used whenever we want to handle any signals that we deferred handling and exit in the process. * In VMS, we dont do any signal handling, only exit handling. */ @@ -83,21 +115,29 @@ GBLREF boolean_t deferred_timers_check_needed; GBLREF VSIG_ATOMIC_T forced_exit; \ GBLREF volatile int4 gtmMallocDepth; \ \ - if (forced_exit) \ - { \ - if (!process_exiting && OK_TO_INTERRUPT) \ + /* The forced_exit state of 2 indicates that the exit is already in progress, so we do not \ + * need to process any deferred events. \ + */ \ + if (2 > forced_exit) \ + { /* If forced_exit was set while in a deferred state, disregard any deferred timers and \ + * invoke deferred_signal_handler directly. \ + */ \ + if (forced_exit) \ { \ - UNIX_ONLY(deferred_signal_handler();) \ - VMS_ONLY(sys$exit(exi_condition);) \ + if (!process_exiting && OK_TO_INTERRUPT) \ + { \ + UNIX_ONLY(deferred_signal_handler();) \ + VMS_ONLY(sys$exit(exi_condition);) \ + } \ + } \ + UNIX_ONLY( \ + else if (deferred_timers_check_needed) \ + { \ + if (!process_exiting && OK_TO_INTERRUPT) \ + check_for_deferred_timers(); \ } \ - } \ - UNIX_ONLY( \ - else if (deferred_timers_check_needed) \ - { \ - if (!process_exiting && OK_TO_INTERRUPT) \ - check_for_deferred_timers(); \ - } \ - ) \ + ) \ + } \ } /* Macro to cause deferrable interrupts to be deferred recording the cause. @@ -148,6 +188,10 @@ 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_FORK_OR_SYSTEM != intrpt_ok_state)) + uint4 have_crit(uint4 crit_state); #endif /* HAVE_CRIT_H_INCLUDED */ diff --git a/sr_port/ind_cg_var.c b/sr_port/ind_cg_var.c index a8884be..616cf80 100644 --- a/sr_port/ind_cg_var.c +++ b/sr_port/ind_cg_var.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "compiler.h" -#include "rtnhdr.h" +#include #include "cache.h" #include "obj_file.h" #include "cg_var.h" diff --git a/sr_port/ind_code.c b/sr_port/ind_code.c index e0b1926..c4408fe 100644 --- a/sr_port/ind_code.c +++ b/sr_port/ind_code.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include "compiler.h" #include "objlabel.h" -#include "rtnhdr.h" +#include #include "cache.h" #include "cgp.h" #include "stringpool.h" @@ -86,8 +86,7 @@ void ind_code(mstr *obj) /* SIZEOF(INTPTR_T) is used for alignment reasons */ + GTM64_ONLY((SECTION_ALIGN_BOUNDARY - 1)) /* extra padding to align the beginning of the code address */ + code_size /* code already aligned at SECTION_ALIGN_BOUNDARY boundary */ - + mvmax * SIZEOF(var_tabent)) /* variable table ents */ - + SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed) + (SIZEOF(uint4) * 2); /* in case of/see op_indlvadr */ + + mvmax * SIZEOF(var_tabent)); /* variable table ents */ ENSURE_STP_FREE_SPACE(indir_code_size); /* Align the beginning of the indirect object so that ihdtyp fields can be accessed normally */ stringpool.free = (unsigned char *)ROUND_UP2((UINTPTR_T)stringpool.free, SECTION_ALIGN_BOUNDARY); diff --git a/sr_port/indir.h b/sr_port/indir.h index c6186de..309a1d7 100644 --- a/sr_port/indir.h +++ b/sr_port/indir.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,14 +11,16 @@ /* The third column represents the opcodes for functions to be used by op_indfun(). * The one parameter version of $name can probably be folded into op_indfun, but at a later time. - * Note: *** Please add new entries to end of list so as not to cause execution problems for - * compilations from previous versions. Yes, they should have recompiled but we can - * avoid exploding by simply adding entries to end of list. *** + * Note: *** Please add new entries to end of list so as not to cause execution problems for + * compilations from previous versions. Yes, they should have recompiled but we can + * avoid exploding by simply adding entries to end of list. *** + * This comment and the preceeding empty lines put the first item at line 20, so adding 20 to an argcode + * places you on the line with its information or subtracting 20 from a line gives the corresponding argcode */ INDIR(indir_fndata, f_data, OC_FNDATA) ,INDIR(indir_fnnext, f_next, OC_FNNEXT) ,INDIR(indir_fnorder1, f_order1, OC_FNORDER) -,INDIR(indir_get, f_get, OC_FNGET) +,INDIR(indir_get, f_get1, OC_FNGET) ,INDIR(indir_close, m_close, 0) ,INDIR(indir_hang, m_hang, 0) ,INDIR(indir_if, m_if, 0) @@ -62,7 +64,7 @@ INDIR(indir_fndata, f_data, OC_FNDATA) ,INDIR(indir_lvnamadr, indirection, 0) ,INDIR(indir_zwithdraw, m_zwithdraw, 0) ,INDIR(indir_tstart, m_tstart, 0) -,INDIR(indir_fnname, f_name, 0) +,INDIR(indir_fnname, f_name, 0) /* f_name is really a dummy */ ,INDIR(indir_fnorder2, f_order, 0) ,INDIR(indir_fnzqgblmod, f_zqgblmod, OC_FNZQGBLMOD) ,INDIR(indir_trollback, m_trollback, 0) @@ -79,3 +81,8 @@ INDIR(indir_fndata, f_data, OC_FNDATA) ,INDIR(indir_ztrigger, m_ztrigger, 0) #endif ,INDIR(indir_zhalt, m_zhalt, 0) +,INDIR(indir_fnzwrite, f_zwrite, OC_FNZWRITE) +,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 */ + diff --git a/sr_port/indir_lits.c b/sr_port/indir_lits.c index 7b89b4e..1f97fc4 100644 --- a/sr_port/indir_lits.c +++ b/sr_port/indir_lits.c @@ -14,7 +14,7 @@ #include "compiler.h" #include "mdq.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "copy.h" #include "obj_file.h" #include "cache.h" diff --git a/sr_port/indirection.c b/sr_port/indirection.c index d6dde86..be0b419 100644 --- a/sr_port/indirection.c +++ b/sr_port/indirection.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,83 +10,99 @@ ****************************************************************/ #include "mdef.h" +#include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" +#include "mdq.h" #include "toktyp.h" -#include "subscript.h" #include "advancewindow.h" +#include "fullbool.h" +#include "show_source_line.h" +#include "stringpool.h" +GBLREF boolean_t run_time; +GBLREF char *lexical_ptr; +GBLREF spdesc stringpool; +GBLREF unsigned char *source_buffer; +GBLREF short int source_column; + +error_def(ERR_BOOLSIDEFFECT); +error_def(ERR_EXPR); error_def(ERR_LPARENMISSING); error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); +error_def(ERR_SIDEEFFECTEVAL); int indirection(oprtype *a) { char c; oprtype *sb1, *sb2, subs[MAX_INDSUBSCRIPTS], x; triple *next, *ref; + int parens, oldlen, len; + char *start, *end, *oldend; + boolean_t concat_athashes; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_ATSIGN == TREF(window_token)); - if (!(TREF(expr_depth))++) - TREF(expr_start) = TREF(expr_start_orig) = NULL; + concat_athashes = (2 == source_column); + INCREMENT_EXPR_DEPTH; advancewindow(); if (!expratom(a)) { - TREF(expr_depth) = 0; + DECREMENT_EXPR_DEPTH; + stx_error(ERR_EXPR); return FALSE; } coerce(a, OCT_MVAL); ex_tail(a); - if (!(--(TREF(expr_depth)))) - TREF(shift_side_effects) = FALSE; - TREF(saw_side_effect) = TREF(shift_side_effects); /* TRUE or FALSE, at this point they're the same */ - if (TK_ATSIGN == TREF(window_token)) + ENCOUNTERED_SIDE_EFFECT; + DECREMENT_EXPR_DEPTH; + if ((TK_ATSIGN == TREF(window_token)) || ((TK_ATHASH == TREF(window_token)) && concat_athashes)) { - advancewindow(); - if (TK_LPAREN != TREF(window_token)) - { - stx_error(ERR_LPARENMISSING); - return FALSE; - } - ref = maketriple(OC_INDNAME); - sb1 = sb2 = subs; - for (;;) - { - if (ARRAYTOP(subs) <= sb1) + (TREF(indirection_mval)).mvtype = 0; + (TREF(indirection_mval)).str.len = 0; + do { + start = lexical_ptr; + advancewindow(); + if (TK_LPAREN != TREF(window_token)) { - stx_error(ERR_MAXNRSUBSCRIPTS); + stx_error(ERR_LPARENMISSING); return FALSE; } advancewindow(); - if (EXPR_FAIL == expr(sb1++, MUMPS_EXPR)) - return FALSE; - if (TK_RPAREN == (c = TREF(window_token))) /* NOTE assignment */ - { - advancewindow(); - break; - } - if (TK_COMMA != c) + if (!parse_until_rparen_or_space() || (TK_RPAREN != TREF(window_token))) { stx_error(ERR_RPARENMISSING); return FALSE; } - } - /* store argument count...n args plus the name plus the dst*/ - ref->operand[0] = put_ilit((mint)(sb1 - sb2) + 2); - ins_triple(ref); - next = newtriple(OC_PARAMETER); - next->operand[0] = *a; - ref->operand[1] = put_tref(next); + end = (char *)source_buffer + (INTPTR_T)source_column - 1; /* lexical_ptr before last advancewindow */ + len = INTCAST(end - start); + oldlen = (TREF(indirection_mval)).str.len; + ENSURE_STP_FREE_SPACE(oldlen + len); + /* Ok to copy from beginning each iteration because we generally expect no more than two iterations, + * and that's with nested indirection. + */ + memcpy(stringpool.free, (TREF(indirection_mval)).str.addr, oldlen); + if (oldlen) + { + oldend = (char *)stringpool.free + oldlen - 1; + assert(*oldend == ')'); + *oldend = ','; + } + (TREF(indirection_mval)).mvtype = MV_STR; + (TREF(indirection_mval)).str.addr = (char *)stringpool.free; + (TREF(indirection_mval)).str.len = oldlen + len; + stringpool.free += oldlen; + memcpy(stringpool.free, start, len); + stringpool.free += len; + advancewindow(); + } while ((TK_ATHASH == TREF(window_token)) && concat_athashes); + ref = newtriple(OC_INDNAME); + ref->operand[0] = *a; + ref->operand[1] = put_lit(&(TREF(indirection_mval))); + (TREF(indirection_mval)).mvtype = 0; /* so stp_gcol (BYPASSOK) - if invoked later - can free up space */ *a = put_tref(ref); - while (sb2 < sb1) - { - ref = newtriple(OC_PARAMETER); - next->operand[1] = put_tref(ref); - ref->operand[0] = *sb2++; - next = ref; - } } return TRUE; } diff --git a/sr_port/insert_region.c b/sr_port/insert_region.c index 15eef93..bb47273 100644 --- a/sr_port/insert_region.c +++ b/sr_port/insert_region.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -54,7 +54,6 @@ #include "dbfilop.h" #include "gtmmsg.h" #include "is_file_identical.h" -#include "tp_grab_crit.h" #include "t_retry.h" #include "wcs_mm_recover.h" #include "gtmimagename.h" @@ -205,7 +204,7 @@ tp_region *insert_region( gd_region *reg, * tp_restart() (invoked through t_retry from gvcst_init) will open "reg" as well as get crit on it for us. */ DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = TRUE;) - if (FALSE == tp_grab_crit(reg)) /* Attempt lockdown now */ + if (FALSE == grab_crit_immediate(reg)) /* Attempt lockdown now */ { DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;) t_retry(cdb_sc_needcrit); /* avoid deadlock -- restart transaction */ @@ -214,6 +213,17 @@ tp_region *insert_region( gd_region *reg, DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;) assert(csa->now_crit); /* ensure we have crit now */ CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg); +# ifdef UNIX + if (MISMATCH_ROOT_CYCLES(csa, csa->nl)) + { /* Going into this retry, we have already checked in tp_restart for moved root blocks in tp_reg_list. + * Since we haven't yet checked this region, we check it here and reset clues for an globals in the + * newly inserted region. We don't want to reset ALL gvt clues because the current retry may have made + * use (and valid use at that) of clues for globals in other regions. + */ + RESET_ALL_GVT_CLUES_REG(csa); + csa->root_search_cycle = csa->nl->root_search_cycle; + } +# endif } DBG_CHECK_TP_REG_LIST_SORTING(*reg_list); return tr_new; diff --git a/sr_port/io.h b/sr_port/io.h index d26f0ac..5c83006 100644 --- a/sr_port/io.h +++ b/sr_port/io.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,13 +23,15 @@ #endif #include "gt_timer.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif +error_def(ERR_BADCHSET); + #define INSERT TRUE #define NO_INSERT FALSE #define IO_SEQ_WRT 1 @@ -38,6 +40,7 @@ #define MAX_DEVCTL_LENGTH 256 #define IO_ESC 0x1b #define MAX_DEV_TYPE_LEN 7 +#define DD_BUFLEN 80 #define CHAR_FILTER 128 #define ESC1 1 @@ -123,6 +126,8 @@ typedef struct io_desc_struct unsigned short zeof; unsigned short za; unsigned char zb[ESC_LEN]; + char key[DD_BUFLEN]; + char device[DD_BUFLEN]; }dollar; unsigned char esc_state; void *dev_sp; @@ -261,6 +266,7 @@ ioxx_open(ff); #ifdef UNIX ioxx_open(pi); xxdlr(iopi); /* we need iopi_iocontrol(), iopi_dlr_device() and iopi_dlr_key() */ +xxdlr(iott); /* we need iott_iocontrol(), iott_dlr_device() and iott_dlr_key() */ #endif ioxx_wttab(us); /* iott_ prototypes */ @@ -295,7 +301,6 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar); void iosocket_poolinit(void); /* iotcp_ prototypes */ -char *iotcp_name2ip(char *name); int iotcp_fillroutine(void); int iotcp_getlsock(io_log_name *dev); void iotcp_rmlsock(io_desc *iod); @@ -334,6 +339,7 @@ void get_dlr_key(mval *v); void flush_pio(void); void remove_rms(io_desc *ciod); +void iosocket_destroy(io_desc *ciod); dev_dispatch_struct *io_get_fgn_driver(mstr *s); @@ -397,14 +403,13 @@ LITREF unsigned char ebcdic_spaces_block[]; #define SET_ENCODING(CHSET, CHSET_MSTR) \ { \ int chset_idx; \ - error_def(ERR_BADCHSET); \ \ chset_idx = verify_chset(CHSET_MSTR); \ ; \ if (0 <= chset_idx) \ (CHSET) = (gtm_chset_t)chset_idx; \ else \ - rts_error(VARLSTCNT(4) ERR_BADCHSET, 2, (CHSET_MSTR)->len, (CHSET_MSTR)->addr); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, (CHSET_MSTR)->len, (CHSET_MSTR)->addr); \ } #endif /* IO_H */ diff --git a/sr_port/io_dev_dispatch.h b/sr_port/io_dev_dispatch.h index 0892642..3911f1b 100644 --- a/sr_port/io_dev_dispatch.h +++ b/sr_port/io_dev_dispatch.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,11 @@ UNIX_ONLY(GBLDEF) VMS_ONLY(LITDEF) dev_dispatch_struct io_dev_dispatch[] = { +# ifdef UNIX + iotype(iott, iott, iott), +# else iotype(iott, iott, nil), +# endif iotype(iomt, iomt, nil), # ifdef UNIX iotype(iorm, iorm, iopi), diff --git a/sr_port/io_rundown.c b/sr_port/io_rundown.c index 2a5e544..f703063 100644 --- a/sr_port/io_rundown.c +++ b/sr_port/io_rundown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,7 +46,7 @@ void io_rundown (int rundown_type) void io_dev_close (io_log_name *d) { - static readonly unsigned char p[] = { iop_eol}; + static readonly unsigned char p[] = {iop_rundown, iop_eol}; mval pp; if (d->iod->pair.in == io_std_device.in && d->iod->pair.out == io_std_device.out) diff --git a/sr_port/iop.h b/sr_port/iop.h index 09e81c2..d7ed558 100644 --- a/sr_port/iop.h +++ b/sr_port/iop.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -207,4 +207,11 @@ IOP_DESC(189, iop_command, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(190, iop_stderr, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(191, iop_independent, 0, IOP_OPEN_OK, 0), IOP_DESC(192, iop_parse, 0, IOP_OPEN_OK, 0), -IOP_DESC(193, n_iops, 0, 0, 0) +IOP_DESC(193, iop_destroy, 0, IOP_CLOSE_OK, 0), +IOP_DESC(194, iop_nodestroy, 0, IOP_CLOSE_OK, 0), +IOP_DESC(195, iop_rundown, 0, IOP_CLOSE_OK, 0), +IOP_DESC(196, iop_follow, 0, IOP_OPEN_OK|IOP_USE_OK, 0), +IOP_DESC(197, iop_nofollow, 0, IOP_OPEN_OK|IOP_USE_OK, 0), +IOP_DESC(198, iop_empterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0), +IOP_DESC(199, iop_noempterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0), +IOP_DESC(200, n_iops, 0, 0, 0) diff --git a/sr_port/iosocket_bind.c b/sr_port/iosocket_bind.c index 7daf73e..f3912d8 100644 --- a/sr_port/iosocket_bind.c +++ b/sr_port/iosocket_bind.c @@ -1,13 +1,13 @@ /**************************************************************** - * * - * Copyright 2001, 2009 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. * - * * - ****************************************************************/ +* * +* Copyright 2001, 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. * +* * +****************************************************************/ /* iosocket_bind.c */ #include "mdef.h" @@ -15,7 +15,8 @@ #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_inet.h" -#include +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gt_timer.h" @@ -24,59 +25,64 @@ #include "iotcpdef.h" #include "iosocketdef.h" #include "iotcproutine.h" +#include "gtm_stdlib.h" #define BOUND "BOUND" +#define IPV6_UNCERTAIN 2 GBLREF tcp_library_struct tcp_routines; +error_def(ERR_GETNAMEINFO); +error_def(ERR_GETSOCKNAMERR); +error_def(ERR_GETSOCKOPTERR); +error_def(ERR_SETSOCKOPTERR); +error_def(ERR_SOCKBIND); +error_def(ERR_SOCKINIT); +error_def(ERR_TEXT); + boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz) { - int temp_1 = 1; - char *errptr; - int4 errlen, msec_timeout, real_errno; - short len; - in_port_t actual_port; - boolean_t no_time_left = FALSE; - d_socket_struct *dsocketptr; - ABS_TIME cur_time, end_time; + int temp_1 = 1; + char *errptr; + int4 errlen, msec_timeout, real_errno; + short len; + in_port_t actual_port; + boolean_t no_time_left = FALSE; + d_socket_struct *dsocketptr; + struct addrinfo *ai_ptr; + char port_buffer[NI_MAXSERV]; + int errcode; + ABS_TIME cur_time, end_time; GTM_SOCKLEN_TYPE addrlen; GTM_SOCKLEN_TYPE sockbuflen; - error_def(ERR_SOCKINIT); - error_def(ERR_GETSOCKOPTERR); - error_def(ERR_SETSOCKOPTERR); - error_def(ERR_GETSOCKNAMERR); - dsocketptr = socketptr->dev; + ai_ptr = (struct addrinfo*)(&socketptr->local.ai); assert(NULL != dsocketptr); - dsocketptr->dollar_key[0] = '\0'; - if (timepar != NO_M_TIMEOUT) - { - msec_timeout = timeout2msec(timepar); - sys_get_curr_time(&cur_time); - add_int_to_abs_time(&cur_time, msec_timeout, &end_time); - } + dsocketptr->iod->dollar.key[0] = '\0'; + if (FD_INVALID != socketptr->temp_sd) + { + socketptr->sd = socketptr->temp_sd; + socketptr->temp_sd = FD_INVALID; + } + if (timepar != NO_M_TIMEOUT) + { + msec_timeout = timeout2msec(timepar); + sys_get_curr_time(&cur_time); + add_int_to_abs_time(&cur_time, msec_timeout, &end_time); + } do - { - if (1 != temp_1) - tcp_routines.aa_close(socketptr->sd); - if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0))) - { - real_errno = errno; - errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr); - return FALSE; - } + { temp_1 = 1; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + errlen = STRLEN(errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), real_errno, errlen, errptr); return FALSE; } @@ -87,8 +93,9 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update { real_errno = errno; errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + errlen = STRLEN(errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), real_errno, errlen, errptr); return FALSE; } @@ -100,9 +107,10 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update { real_errno = errno; errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, - RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); + errlen = STRLEN(errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } else @@ -113,20 +121,20 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update { real_errno = errno; errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, + errlen = STRLEN(errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } - temp_1 = tcp_routines.aa_bind(socketptr->sd, - (struct sockaddr *)&socketptr->local.sin, SIZEOF(struct sockaddr)); + temp_1 = tcp_routines.aa_bind(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen); if (temp_1 < 0) { real_errno = errno; - no_time_left = TRUE; - switch (real_errno) - { + no_time_left = TRUE; + switch (real_errno) + { case EADDRINUSE: if (NO_M_TIMEOUT != timepar) { @@ -139,37 +147,56 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update case EINTR: break; default: - errptr = (char *)STRERROR(real_errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBIND, 0, real_errno, 0); break; - } - if (no_time_left) - return FALSE; - hiber_start(100); - } + } + if (no_time_left) + return FALSE; + hiber_start(100); + tcp_routines.aa_close(socketptr->sd); + if (-1 == (socketptr->sd = tcp_routines.aa_socket(ai_ptr->ai_family,ai_ptr->ai_socktype, + ai_ptr->ai_protocol))) + { + real_errno = errno; + errptr = (char *)STRERROR(real_errno); + errlen = STRLEN(errptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr); + return FALSE; + } + } } while (temp_1 < 0); - addrlen = SIZEOF(socketptr->local.sin); - if (-1 == tcp_routines.aa_getsockname(socketptr->sd, (struct sockaddr *)&socketptr->local.sin, &addrlen)) + /* obtain actual port from the bound address if port 0 was specified */ + addrlen = SOCKET_ADDRLEN(socketptr, ai_ptr, local); + if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &addrlen)) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr); return FALSE; } - actual_port = GTM_NTOHS(socketptr->local.sin.sin_port); - if (0 == socketptr->local.port) - socketptr->local.port = actual_port; - assert(socketptr->local.port == actual_port); + assert(ai_ptr->ai_addrlen == addrlen); + GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); + if (0 != errcode) + { + SOCKET_FREE(socketptr); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + actual_port = ATOI(port_buffer); + if (0 == socketptr->local.port) + socketptr->local.port = actual_port; + assert(socketptr->local.port == actual_port); socketptr->state = socket_bound; len = SIZEOF(BOUND) - 1; - memcpy(&dsocketptr->dollar_key[0], BOUND, len); - dsocketptr->dollar_key[len++] = '|'; - memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); + memcpy(&dsocketptr->iod->dollar.key[0], BOUND, len); + dsocketptr->iod->dollar.key[len++] = '|'; + memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; - dsocketptr->dollar_key[len++] = '|'; - SPRINTF(&dsocketptr->dollar_key[len], "%d", socketptr->local.port); + dsocketptr->iod->dollar.key[len++] = '|'; + SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port); return TRUE; } diff --git a/sr_port/iosocket_close.c b/sr_port/iosocket_close.c index f785ec8..a1b6f87 100644 --- a/sr_port/iosocket_close.c +++ b/sr_port/iosocket_close.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,7 +35,10 @@ #include "stringpool.h" GBLREF tcp_library_struct tcp_routines; +GBLREF io_desc *active_device; LITREF unsigned char io_params_size[]; +error_def(ERR_SOCKNOTFND); + void iosocket_close(io_desc *iod, mval *pp) { boolean_t socket_specified = FALSE; @@ -46,9 +49,11 @@ void iosocket_close(io_desc *iod, mval *pp) char sock_handle[MAX_HANDLE_LEN]; int4 ii, jj, start, end, index; int p_offset = 0; - error_def(ERR_SOCKNOTFND); + boolean_t socket_destroy = FALSE; + assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)iod->dev_sp; + while (iop_eol != (ch = *(pp->str.addr + p_offset++))) { switch (ch) @@ -86,6 +91,12 @@ void iosocket_close(io_desc *iod, mval *pp) ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; + case iop_destroy: + socket_destroy = TRUE; + break; + case iop_nodestroy: + socket_destroy = FALSE; + break; default: break; } @@ -96,7 +107,7 @@ void iosocket_close(io_desc *iod, mval *pp) { if (0 > (index = iosocket_handle(sock_handle, &handle_len, FALSE, dsocketptr))) { - rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, sock_handle); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, sock_handle); return; } start = end = index; @@ -110,11 +121,7 @@ void iosocket_close(io_desc *iod, mval *pp) { socketptr = dsocketptr->socket[ii]; tcp_routines.aa_close(socketptr->sd); - iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE); /* free the delimiter space */ - free(socketptr->buffer); - if (NULL != socketptr->zff.addr) - free(socketptr->zff.addr); - free(socketptr); + SOCKET_FREE(socketptr); if (dsocketptr->current_socket >= ii) dsocketptr->current_socket--; for (jj = ii + 1; jj <= dsocketptr->n_socket - 1; jj++) @@ -122,5 +129,12 @@ void iosocket_close(io_desc *iod, mval *pp) dsocketptr->n_socket--; } if (!socket_specified) + { iod->state = dev_closed; + if (socket_destroy) + { + active_device = 0; + iosocket_destroy(iod); + } + } } diff --git a/sr_port/iosocket_connect.c b/sr_port/iosocket_connect.c index f5b70c6..70626f9 100644 --- a/sr_port/iosocket_connect.c +++ b/sr_port/iosocket_connect.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,6 @@ #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_inet.h" -#include #include "gtm_stdio.h" #include "gtm_string.h" #include "stringpool.h" @@ -25,10 +24,12 @@ #include "iotcpdef.h" #include "iosocketdef.h" #include "iotcproutine.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "outofband.h" +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #define ESTABLISHED "ESTABLISHED" @@ -42,16 +43,17 @@ GBLREF int socketus_interruptus; GBLREF d_socket_struct *newdsocket; /* in case jobinterrupt */ GBLREF int4 gtm_max_sockets; -error_def(ERR_SOCKINIT); -error_def(ERR_OPENCONN); -error_def(ERR_TEXT); +error_def(ERR_GETNAMEINFO); error_def(ERR_GETSOCKOPTERR); +error_def(ERR_OPENCONN); error_def(ERR_SETSOCKOPTERR); -error_def(ERR_ZINTRECURSEIO); +error_def(ERR_SOCKINIT); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); +error_def(ERR_TEXT); +error_def(ERR_ZINTRECURSEIO); -boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz) +boolean_t iosocket_connect(socket_struct *sockptr, int4 timepar, boolean_t update_bufsiz) { int temp_1; char *errptr; @@ -67,19 +69,21 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd ABS_TIME cur_time, end_time; struct timeval *sel_time; mv_stent *mv_zintdev; + struct addrinfo *remote_ai_ptr, *raw_ai_ptr; + int errcode, real_errno; + char ipaddr[SA_MAXLEN + 1]; GTM_SOCKLEN_TYPE sockbuflen; DBGSOCK((stdout, "socconn: ************* Entering socconn - timepar: %d\n",timepar)); /* check for validity */ - dsocketptr = socketptr->dev; + dsocketptr = sockptr->dev; assert(NULL != dsocketptr); sockintr = &dsocketptr->sock_save_state; iod = dsocketptr->iod; real_dsocketptr = (d_socket_struct *)iod->dev_sp; /* not newdsocket which is not saved on error */ real_sockintr = &real_dsocketptr->sock_save_state; - dsocketptr->dollar_key[0] = '\0'; - real_dsocketptr->dollar_key[0] = '\0'; + iod->dollar.key[0] = '\0'; need_socket = need_connect = TRUE; need_select = FALSE; @@ -89,7 +93,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd if (sockwhich_invalid == sockintr->who_saved) GTMASSERT; /* Interrupt should never have an invalid save state */ if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); if (sockwhich_connect != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socconn: *#*#*#*#*#*#*# Restarted interrupted connect\n")); @@ -99,7 +103,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd if (sockintr->end_time_valid) /* Restore end_time for timeout */ end_time = sockintr->end_time; - if (socket_connect_inprogress == socketptr->state && FD_INVALID != socketptr->sd) + if ((socket_connect_inprogress == sockptr->state) && (FD_INVALID != sockptr->sd)) { need_select = TRUE; need_socket = need_connect = FALSE; /* sd still good */ @@ -127,77 +131,127 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd real_sockintr->end_time_valid = sockintr->end_time_valid = FALSE; last_errno = 0; + remote_ai_ptr = (struct addrinfo*)(&(sockptr->remote.ai)); do { - if (need_socket && FD_INVALID != socketptr->sd) + /* If the connect was failed, we may have already changed the remote. + * So, the remote ai_addr should be restored. + */ + assertpro(NULL != sockptr->remote.ai_head); + memcpy(remote_ai_ptr, sockptr->remote.ai_head, SIZEOF(struct addrinfo)); + if (need_socket && (FD_INVALID != sockptr->sd)) { - tcp_routines.aa_close(socketptr->sd); - socketptr->sd = FD_INVALID; + tcp_routines.aa_close(sockptr->sd); + sockptr->sd = FD_INVALID; } assert(FD_INVALID == -1); if (need_socket) { - if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0))) - { - errptr = (char *)STRERROR(errno); + real_errno = -2; + for (raw_ai_ptr = remote_ai_ptr; NULL != raw_ai_ptr; raw_ai_ptr = raw_ai_ptr->ai_next) + { + if (-1 == (sockptr->sd = tcp_routines.aa_socket(raw_ai_ptr->ai_family, raw_ai_ptr->ai_socktype, + raw_ai_ptr->ai_protocol))) + real_errno = errno; + else + { + real_errno = 0; + break; + } + } + if (0 != real_errno) + { + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + assertpro(-2 != real_errno); + errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); - return FALSE; - } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + return FALSE; + } + assertpro(NULL != raw_ai_ptr);/* either there is an IPv6 or an IPv4 address */ + memcpy(remote_ai_ptr, raw_ai_ptr, SIZEOF(struct addrinfo)); + SOCKET_AI_TO_REMOTE_ADDR(sockptr, raw_ai_ptr); + remote_ai_ptr->ai_addr = SOCKET_REMOTE_ADDR(sockptr); + remote_ai_ptr->ai_addrlen = raw_ai_ptr->ai_addrlen; + remote_ai_ptr->ai_next = NULL; need_socket = FALSE; temp_1 = 1; - if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) + if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr); return FALSE; } #ifdef TCP_NODELAY - temp_1 = socketptr->nodelay ? 1 : 0; - if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, + temp_1 = sockptr->nodelay ? 1 : 0; + if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), save_errno, errlen, errptr); return FALSE; } #endif if (update_bufsiz) { - if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, - SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, SIZEOF(socketptr->bufsiz))) + if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, + SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, SIZEOF(sockptr->bufsiz))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr); return FALSE; } } else { - sockbuflen = SIZEOF(socketptr->bufsiz); - if (-1 == tcp_routines.aa_getsockopt(socketptr->sd, - SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &sockbuflen)) + sockbuflen = SIZEOF(sockptr->bufsiz); + if (-1 == tcp_routines.aa_getsockopt(sockptr->sd, + SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, &sockbuflen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; - rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr); return FALSE; } @@ -207,8 +261,8 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd if (need_connect) { /* Use plain connect to allow jobinterrupt */ - assert(FD_INVALID != socketptr->sd); - res = connect(socketptr->sd, (struct sockaddr *)&socketptr->remote.sin, SIZEOF(socketptr->remote.sin)); + assert(FD_INVALID != sockptr->sd); + res = connect(sockptr->sd, SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen); if (res < 0) { save_errno = errno; @@ -284,12 +338,12 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd } } FD_ZERO(&writefds); - FD_SET(socketptr->sd, &writefds); - res = select(socketptr->sd + 1, NULL, &writefds, NULL, sel_time); + FD_SET(sockptr->sd, &writefds); + res = select(sockptr->sd + 1, NULL, &writefds, NULL, sel_time); if (0 < res) { /* check for socket error */ sockbuflen = SIZEOF(sockerror); - res = getsockopt(socketptr->sd, SOL_SOCKET, SO_ERROR, + res = getsockopt(sockptr->sd, SOL_SOCKET, SO_ERROR, &sockerror, &sockbuflen); if (0 == res && 0 == sockerror) { /* got it */ @@ -337,38 +391,55 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd } if (save_errno) { - if (FD_INVALID != socketptr->sd) + if (FD_INVALID != sockptr->sd) { - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + } + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; } errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); if (dev_open == iod->state) { iod->dollar.za = 9; - memcpy(real_dsocketptr->dollar_device, ONE_COMMA, SIZEOF(ONE_COMMA)); - memcpy(&real_dsocketptr->dollar_device[SIZEOF(ONE_COMMA) - 1], + memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA)); + memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ } - if (socketptr->ioerror) - rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); + if (sockptr->ioerror) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); errno = save_errno; return FALSE; } if (no_time_left) + { + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } return FALSE; /* caller will close socket */ + } if (res < 0 && outofband) /* if connected delay outofband */ { DBGSOCK((stdout, "socconn: outofband interrupt received (%d) -- " "queueing mv_stent for wait intr\n", outofband)); if (need_connect) { /* no connect in progress */ - tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */ - socketptr->sd = FD_INVALID; - socketptr->state = socket_created; + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + sockptr->state = socket_created; } else - socketptr->state = socket_connect_inprogress; + sockptr->state = socket_connect_inprogress; + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } real_sockintr->who_saved = sockintr->who_saved = sockwhich_connect; if (NO_M_TIMEOUT != timepar) { @@ -384,7 +455,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd PUSH_MV_STENT(MVST_ZINTDEV); mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_chain->mv_st_cont.mvs_zintdev.io_ptr = NULL; - mv_chain->mv_st_cont.mvs_zintdev.socketptr = socketptr; /* for sd and to free structure */ + mv_chain->mv_st_cont.mvs_zintdev.socketptr = sockptr; /* for sd and to free structure */ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = d_socket_struct_len; mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; memcpy (stringpool.free, (unsigned char *)newdsocket, d_socket_struct_len); @@ -401,20 +472,36 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd hiber_start(100); } while (res < 0); - /* handle the local information later. - SPRINTF(socketptr->local.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr)); - socketptr->local.port = GTM_NTOHS(socketptr->remote.sin.sin_port); - */ - socketptr->state = socket_connected; - socketptr->first_read = socketptr->first_write = TRUE; + sockptr->state = socket_connected; + sockptr->first_read = sockptr->first_write = TRUE; /* update dollar_key */ len = SIZEOF(ESTABLISHED) - 1; - memcpy(&dsocketptr->dollar_key[0], ESTABLISHED, len); - dsocketptr->dollar_key[len++] = '|'; - memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); - len += socketptr->handle_len; - dsocketptr->dollar_key[len++] = '|'; - strcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip); /* Also copies in trailing null */ + memcpy(&iod->dollar.key[0], ESTABLISHED, len); + iod->dollar.key[len++] = '|'; + memcpy(&iod->dollar.key[len], sockptr->handle, sockptr->handle_len); + len += sockptr->handle_len; + iod->dollar.key[len++] = '|'; + /* translate internal address to numeric ip address */ + assert(FALSE == need_socket); + if (NULL != sockptr->remote.ai_head) + { + freeaddrinfo(sockptr->remote.ai_head); + sockptr->remote.ai_head = NULL; + } + GETNAMEINFO(SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode); + if (0 != errcode) + { + if (FD_INVALID != sockptr->sd) + { + tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ + sockptr->sd = FD_INVALID; + } + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + STRNDUP(ipaddr, SA_MAXLEN, sockptr->remote.saddr_ip); + strncpy(&iod->dollar.key[len], sockptr->remote.saddr_ip, DD_BUFLEN - 1 - len); + iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ return TRUE; } diff --git a/sr_port/iosocket_create.c b/sr_port/iosocket_create.c index 009b7d4..474d494 100644 --- a/sr_port/iosocket_create.c +++ b/sr_port/iosocket_create.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,8 +12,8 @@ /* iosocket_create.c */ /* this module takes care of * 1. allocate the space - * 2. for passive: local.sin.sin_addr.s_addr & local.sin.sin_port - * for active : remote.sin.sin_addr.s_addr & remote.sin.sin_port + * 2. for passive: local.sa & local.ai + * for active : remote.sa & remote.ai * for $principal: via getsockname and getsockpeer * 3. socketptr->protocol * 4. socketptr->sd (initialized to -1) unless already open via inetd @@ -29,6 +29,8 @@ #include "gtm_netdb.h" #include "gtm_socket.h" #include "gtm_inet.h" +#include "gtm_ipv6.h" +#include "gtm_stdlib.h" #include "io.h" #include "iotcproutine.h" @@ -37,128 +39,214 @@ #include "iosocketdef.h" #include "min_max.h" #include "gtm_caseconv.h" - -#ifdef __osf__ -/* Tru64 does not have the prototype for "hstrerror" even though the function is available in the library. - * Until we revamp the TCP communications setup stuff to use the new(er) POSIX definitions, we cannot move - * away from "hstrerror". Declare prototype for this function in Tru64 manually until then. - */ -const char *hstrerror(int err); -#endif +#include "util.h" GBLREF tcp_library_struct tcp_routines; +error_def(ERR_GETSOCKNAMERR); +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_INVPORTSPEC); +error_def(ERR_INVADDRSPEC); +error_def(ERR_PROTNOTSUP); +error_def(ERR_TEXT); +error_def(ERR_SOCKINIT); + +/* PORT_PROTO_FORMAT defines the format for : */ +#define PORT_PROTO_FORMAT "%hu:%3[^:]" +#define SEPARATOR ':' + socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des) { - socket_struct *socketptr; - bool passive = FALSE; - unsigned short port; - int ii, save_errno, tmplen; - GTM_SOCKLEN_TYPE socknamelen; - char temp_addr[SA_MAXLITLEN], addr[SA_MAXLEN], tcp[4], *adptr; - const char *errptr; + socket_struct *socketptr; + socket_struct *prev_socketptr; + socket_struct *socklist_head; + bool passive = FALSE; + unsigned short port; + int ii, save_errno, tmplen, errlen; + char temp_addr[SA_MAXLITLEN], tcp[4], *adptr; + const char *errptr; + struct addrinfo *ai_ptr; + struct addrinfo hints, *addr_info_ptr = NULL; + int af; + int sd; + int errcode; + char port_buffer[NI_MAXSERV]; + int port_buffer_len; + int colon_cnt; + char *last_2colon; + int addrlen; + GTM_SOCKLEN_TYPE tmp_addrlen; - error_def(ERR_INVPORTSPEC); - error_def(ERR_INVADDRSPEC); - error_def(ERR_PROTNOTSUP); - error_def(ERR_TEXT); - error_def(ERR_GETSOCKNAMERR); - - socketptr = (socket_struct *)malloc(SIZEOF(socket_struct)); - memset(socketptr, 0, SIZEOF(socket_struct)); if (0 > file_des) { /* no socket descriptor yet */ - if (SSCANF(sockaddr, "%[^:]:%hu:%3[^:]", temp_addr, &port, tcp) < 3) + memset(&hints, 0, SIZEOF(hints)); + + colon_cnt = 0; + for (ii = strlen(sockaddr) - 1; 0 <= ii; ii--) { - passive = TRUE; - socketptr->local.sin.sin_addr.s_addr = INADDR_ANY; - if(SSCANF(sockaddr, "%hu:%3[^:]", &port, tcp) < 2) + if (SEPARATOR == sockaddr[ii]) { - free(socketptr); - rts_error(VARLSTCNT(1) ERR_INVPORTSPEC); + colon_cnt++; + if (2 == colon_cnt) + { + last_2colon = &sockaddr[ii]; + break; + } + } + } + if (0 == colon_cnt) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); + return NULL; + } + if (1 == colon_cnt) + { /* for listening socket or broadcasting socket */ + if (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, tcp) < 2) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } - socketptr->local.sin.sin_port = GTM_HTONS(port); - socketptr->local.sin.sin_family = AF_INET; - socketptr->local.port = port; - } else - { - for (ii = 0; ISDIGIT_ASCII(temp_addr[ii]) || '.' == temp_addr[ii]; ii++) /* NOTE: only ASCII digits */ - ; /* allowed for dotted notation address */ - if (temp_addr[ii] != '\0') + passive = TRUE; + /* We always first try using IPv6 address, if supported */ + af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); + if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP))) { - SPRINTF(socketptr->remote.saddr_lit, "%s", temp_addr); - adptr = iotcp_name2ip(temp_addr); - if (NULL == adptr) + /* Try creating IPv4 socket */ + af = AF_INET; + if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP))) { -#if !defined(__hpux) && !defined(__MVS__) - errptr = HSTRERROR(h_errno); - rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(errptr)); -#else - /* Grumble grumble HPUX and z/OS don't have hstrerror() */ - rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); -#endif - free(socketptr); + save_errno = errno; + errptr = (char *)STRERROR(save_errno); + errlen = STRLEN(errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); return NULL; } - - SPRINTF(addr, "%s", adptr); - } else - SPRINTF(addr, "%s", temp_addr); - if ((unsigned int)-1 == (socketptr->remote.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr))) - { /* Errno not set by inet_addr() */ - free(socketptr); - rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); + } + SERVER_HINTS(hints, af); + port_buffer_len = 0; + I2A(port_buffer, port_buffer_len, port); + port_buffer[port_buffer_len]='\0'; + if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &addr_info_ptr))) + { + tcp_routines.aa_close(sd); + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return NULL; } - socketptr->remote.sin.sin_port = GTM_HTONS(port); - socketptr->remote.sin.sin_family = AF_INET; + SOCKET_ALLOC(socketptr); + socketptr->local.port = port; + socketptr->temp_sd = sd; + socketptr->sd = FD_INVALID; + ai_ptr = &(socketptr->local.ai); + memcpy(ai_ptr, addr_info_ptr, SIZEOF(struct addrinfo)); + SOCKET_AI_TO_LOCAL_ADDR(socketptr, addr_info_ptr); + ai_ptr->ai_addr = SOCKET_LOCAL_ADDR(socketptr); + ai_ptr->ai_addrlen = addr_info_ptr->ai_addrlen; + ai_ptr->ai_next = NULL; + freeaddrinfo(addr_info_ptr); + } else + { /* connection socket */ + assert(2 == colon_cnt); + if (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, tcp) < 2) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); + return NULL; + } + /* for connection socket */ + SPRINTF(port_buffer, "%hu", port); + addrlen = last_2colon - sockaddr; + if ('[' == sockaddr[0]) + { + if (NULL == memchr(sockaddr, ']', addrlen)) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); + return NULL; + } + addrlen -= 2; + memcpy(temp_addr, &sockaddr[1], addrlen); + } else + memcpy(temp_addr, sockaddr, addrlen); + temp_addr[addrlen] = 0; + CLIENT_HINTS(hints); + if (0 != (errcode = getaddrinfo(temp_addr, port_buffer, &hints, &addr_info_ptr))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); + return NULL; + } + /* we will test all address families in iosocket_connect() */ + SOCKET_ALLOC(socketptr); + socketptr->remote.ai_head = addr_info_ptr; socketptr->remote.port = port; - SPRINTF(socketptr->remote.saddr_ip, "%s", addr); + socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */ } lower_to_upper((uchar_ptr_t)tcp, (uchar_ptr_t)tcp, SIZEOF("TCP") - 1); if (0 == MEMCMP_LIT(tcp, "TCP")) - socketptr->protocol = socket_tcpip; - else { - free(socketptr); - rts_error(VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp); + socketptr->protocol = socket_tcpip; + } else + { + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp); return NULL; } - socketptr->sd = FD_INVALID; /* don't mess with 0 */ - socketptr->state = socket_created; /* Is this really useful? */ + socketptr->state = socket_created; + SOCKET_BUFFER_INIT(socketptr, bfsize); + socketptr->passive = passive; + socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; + + return socketptr; } else { /* socket already setup by inetd */ + SOCKET_ALLOC(socketptr); socketptr->sd = file_des; - socknamelen = SIZEOF(socketptr->local.sin); - if (-1 == tcp_routines.aa_getsockname(socketptr->sd, (struct sockaddr *)&socketptr->local.sin, &socknamelen)) + socketptr->temp_sd = FD_INVALID; + ai_ptr = &(socketptr->local.ai); + tmp_addrlen = SIZEOF(struct sockaddr_storage); + if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &tmp_addrlen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); tmplen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); - free(socketptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); return NULL; } - socketptr->local.port = GTM_NTOHS(socketptr->local.sin.sin_port); - socknamelen = SIZEOF(socketptr->remote.sin); - if (-1 == getpeername(socketptr->sd, (struct sockaddr *)&socketptr->remote.sin, (GTM_SOCKLEN_TYPE *)&socknamelen)) + ai_ptr->ai_addrlen = tmp_addrlen; + /* extract port information */ + GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), tmp_addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); + if (0 != errcode) + { + SOCKET_FREE(socketptr); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return NULL; + } + socketptr->local.port = ATOI(port_buffer); + tmp_addrlen = SIZEOF(struct sockaddr_storage); + if (-1 == getpeername(socketptr->sd, SOCKET_REMOTE_ADDR(socketptr), &tmp_addrlen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); tmplen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); /* need new error */ - free(socketptr); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); return NULL; } - socketptr->remote.port = GTM_NTOHS(socketptr->remote.sin.sin_port); + socketptr->remote.ai.ai_addrlen = tmp_addrlen; + assert(0 != SOCKET_REMOTE_ADDR(socketptr)->sa_family); + GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), socketptr->remote.ai.ai_addrlen, NULL, 0, port_buffer, NI_MAXSERV, + NI_NUMERICSERV, errcode); + if (0 != errcode) + { + SOCKET_FREE(socketptr); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return NULL; + } + socketptr->remote.port = ATOI(port_buffer); socketptr->state = socket_connected; socketptr->protocol = socket_tcpip; + SOCKET_BUFFER_INIT(socketptr, bfsize); + socketptr->passive = passive; + socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; + return socketptr; } - socketptr->buffer = (char *)malloc(bfsize); - socketptr->buffer_size = bfsize; - socketptr->buffered_length = socketptr->buffered_offset = 0; - socketptr->passive = passive; - socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; - return socketptr; } diff --git a/sr_port/iosocket_flush.c b/sr_port/iosocket_flush.c index edb78fd..d5f627c 100644 --- a/sr_port/iosocket_flush.c +++ b/sr_port/iosocket_flush.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,6 @@ #include "gtm_socket.h" #include "gtm_inet.h" #include -#include #include "gtm_stdio.h" #include "gtm_string.h" @@ -28,6 +27,10 @@ GBLREF tcp_library_struct tcp_routines; +error_def(ERR_SOCKWRITE); +error_def(ERR_TEXT); +error_def(ERR_CURRSOCKOFR); + void iosocket_flush(io_desc *iod) { #ifdef C9A06001531 @@ -39,10 +42,6 @@ void iosocket_flush(io_desc *iod) char *errptr; int4 errlen; - error_def(ERR_SOCKWRITE); - error_def(ERR_TEXT); - error_def(ERR_CURRSOCKOFR); - assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)iod->dev_sp; @@ -50,20 +49,20 @@ void iosocket_flush(io_desc *iod) if (dsocketptr->current_socket >= dsocketptr->n_socket) { - rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return; } - memcpy(dsocketptr->dollar_device, "0", SIZEOF("0")); - if( -1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) || + memcpy(iod->dollar.device, "0", SIZEOF("0")); + if ( -1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) || (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &off, SIZEOF(off)))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); iod->dollar.za = 9; - MEMCPY_LIT(dsocketptr->dollar_device, "1,"); - memcpy(&dsocketptr->dollar_device[SIZEOF("1,") - 1], errptr, errlen + 1); /* we want the null */ + MEMCPY_LIT(iod->dollar.device, "1,"); + memcpy(&iod->dollar.device[SIZEOF("1,") - 1], errptr, errlen + 1); /* we want the null */ if (socketptr->ioerror) - rts_error(VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); return; } diff --git a/sr_port/iosocket_iocontrol.c b/sr_port/iosocket_iocontrol.c index 81d97b8..f1fb417 100644 --- a/sr_port/iosocket_iocontrol.c +++ b/sr_port/iosocket_iocontrol.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -66,7 +66,7 @@ void iosocket_iocontrol(mstr *d) timeout = NO_M_TIMEOUT; iosocket_wait(io_curr_device.out, timeout); /* depth really means timeout here. */ } else - rts_error(VARLSTCNT(1) ERR_INVCTLMNE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE); return; } @@ -75,15 +75,12 @@ void iosocket_dlr_device(mstr *d) { io_desc *iod; int len; - d_socket_struct *dsocketptr; iod = io_curr_device.out; - dsocketptr = (d_socket_struct *)iod->dev_sp; - - len = STRLEN(dsocketptr->dollar_device); + len = STRLEN(iod->dollar.device); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); - memcpy(d->addr, dsocketptr->dollar_device, len); + memcpy(d->addr, iod->dollar.device, len); d->len = len; return; } @@ -92,16 +89,13 @@ void iosocket_dlr_key(mstr *d) { io_desc *iod; int len; - d_socket_struct *dsocketptr; iod = io_curr_device.out; - dsocketptr = (d_socket_struct *)iod->dev_sp; - - len = STRLEN(dsocketptr->dollar_key); + len = STRLEN(iod->dollar.key); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); if (len > 0) - memcpy(d->addr, dsocketptr->dollar_key, len); + memcpy(d->addr, iod->dollar.key, len); d->len = len; return; } diff --git a/sr_port/iosocket_listen.c b/sr_port/iosocket_listen.c index 247b867..e944291 100644 --- a/sr_port/iosocket_listen.c +++ b/sr_port/iosocket_listen.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,67 +29,58 @@ #include "gt_timer.h" #include "iosocketdef.h" +GBLREF tcp_library_struct tcp_routines; + +error_def(ERR_CURRSOCKOFR); +error_def(ERR_LISTENPASSBND); +error_def(ERR_LQLENGTHNA); +error_def(ERR_SOCKLISTEN); +error_def(ERR_TEXT); + #define LISTENING "LISTENING" #define MAX_LISTEN_QUEUE_LENGTH 5 -GBLREF tcp_library_struct tcp_routines; - boolean_t iosocket_listen(io_desc *iod, unsigned short len) { + char *errptr; + int4 errlen; d_socket_struct *dsocketptr; socket_struct *socketptr; - char *errptr; - int4 errlen; - - error_def(ERR_SOCKLISTEN); - error_def(ERR_TEXT); - error_def(ERR_LQLENGTHNA); - error_def(ERR_SOCKACTNA); - error_def(ERR_CURRSOCKOFR); - error_def(ERR_LISTENPASSBND); if (MAX_LISTEN_QUEUE_LENGTH < len) { - rts_error(VARLSTCNT(3) ERR_LQLENGTHNA, 1, len); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LQLENGTHNA, 1, len); return FALSE; } - - assert(iod->type == gtmsocket); - dsocketptr = (d_socket_struct *)iod->dev_sp; + assert(gtmsocket == iod->type); + dsocketptr = (d_socket_struct *)iod->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; - if (dsocketptr->current_socket >= dsocketptr->n_socket) { - rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return FALSE; } - - if ((socketptr->state != socket_bound) || (socketptr->passive != TRUE)) + if ((socketptr->state != socket_bound) || (TRUE != socketptr->passive)) { - rts_error(VARLSTCNT(1) ERR_LISTENPASSBND); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LISTENPASSBND); + return FALSE; + } + dsocketptr->iod->dollar.key[0] = '\0'; + /* establish a queue of length len for incoming connections */ + if (-1 == tcp_routines.aa_listen(socketptr->sd, len)) + { + errptr = (char *)STRERROR(errno); + errlen = STRLEN(errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } - - dsocketptr->dollar_key[0] = '\0'; - - /* establish a queue of length len for incoming connections */ - if (-1 == tcp_routines.aa_listen(socketptr->sd, len)) - { - errptr = (char *)STRERROR(errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); - return FALSE; - } - socketptr->state = socket_listening; - len = SIZEOF(LISTENING) - 1; - memcpy(&dsocketptr->dollar_key[0], LISTENING, len); - dsocketptr->dollar_key[len++] = '|'; - memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); + memcpy(&dsocketptr->iod->dollar.key[0], LISTENING, len); + dsocketptr->iod->dollar.key[len++] = '|'; + memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; - dsocketptr->dollar_key[len++] = '|'; - SPRINTF(&dsocketptr->dollar_key[len], "%d", socketptr->local.port); - + dsocketptr->iod->dollar.key[len++] = '|'; + SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port); return TRUE; } diff --git a/sr_port/iosocket_open.c b/sr_port/iosocket_open.c index e4e2ac9..7673162 100644 --- a/sr_port/iosocket_open.c +++ b/sr_port/iosocket_open.c @@ -1,4 +1,6 @@ /**************************************************************** + * * + * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -6,7 +8,6 @@ * the license, please stop and do not read further. * * * ****************************************************************/ - #include "mdef.h" #include @@ -29,6 +30,7 @@ #include "stringpool.h" #include "gtm_conv.h" #include "gtm_utf8.h" +#include "gtm_netdb.h" GBLREF tcp_library_struct tcp_routines; GBLREF d_socket_struct *socket_pool, *newdsocket; @@ -39,11 +41,20 @@ GBLREF boolean_t dollar_zininterrupt; LITREF unsigned char io_params_size[]; LITREF mstr chset_names[]; -#define FREE_SOCKPTR(sockptr) \ -{ \ - if (NULL != sockptr->buffer) free(sockptr->buffer); \ - free(sockptr); \ -} +error_def(ERR_ABNCOMPTINC); +error_def(ERR_ADDRTOOLONG); +error_def(ERR_DELIMSIZNA); +error_def(ERR_DELIMWIDTH); +error_def(ERR_DEVPARINAP); +error_def(ERR_DEVPARMNEG); +error_def(ERR_GETNAMEINFO); +error_def(ERR_ILLESOCKBFSIZE); +error_def(ERR_MRTMAXEXCEEDED); +error_def(ERR_SOCKETEXIST); +error_def(ERR_SOCKMAX); +error_def(ERR_TEXT); +error_def(ERR_ZFF2MANY); +error_def(ERR_ZINTRECURSEIO); #define ESTABLISHED "ESTABLISHED" @@ -58,7 +69,6 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 int d_socket_struct_len; ABS_TIME cur_time, end_time; io_desc *ioptr; - struct sockaddr_in peer; /* socket address + port */ fd_set tcp_fd; uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize; d_socket_struct *dsocketptr; @@ -81,19 +91,10 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 unsigned char delimiter_buffer[MAX_N_DELIMITER * (MAX_DELIM_LEN + 1)], zff_buffer[MAX_ZFF_LEN]; char ioerror, ip[3], tcp[4], sock_handle[MAX_HANDLE_LEN], delimiter[MAX_DELIM_LEN + 1]; - - error_def(ERR_DELIMSIZNA); - error_def(ERR_ADDRTOOLONG); - error_def(ERR_SOCKETEXIST); - error_def(ERR_ABNCOMPTINC); - error_def(ERR_DEVPARINAP); - error_def(ERR_DEVPARMNEG); - error_def(ERR_ILLESOCKBFSIZE); - error_def(ERR_ZFF2MANY); - error_def(ERR_DELIMWIDTH); - error_def(ERR_SOCKMAX); - error_def(ERR_ZINTRECURSEIO); - error_def(ERR_MRTMAXEXCEEDED); + int socketptr_delim_len; + char ipaddr[SA_MAXLEN]; + int errcode; + struct addrinfo *ai_ptr, *remote_ai_ptr; ioptr = dev->iod; assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops); @@ -114,6 +115,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 if (ioptr->state == dev_never_opened) { dsocketptr = ioptr->dev_sp = (void *)malloc(d_socket_struct_len); + ioptr->newly_created = TRUE; memset(dsocketptr, 0, d_socket_struct_len); dsocketptr->iod = ioptr; } else @@ -140,7 +142,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 { dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); } if (sockwhich_connect != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ @@ -163,7 +165,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 if (NULL == newdsocket) newdsocket = (d_socket_struct *)malloc(d_socket_struct_len); memcpy(newdsocket, dsocketptr, d_socket_struct_len); - memcpy(newdsocket->dollar_device, "0", SIZEOF("0")); + memcpy(ioptr->dollar.device, "0", SIZEOF("0")); zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */ delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */ ichset_specified = ochset_specified = FALSE; @@ -176,7 +178,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len) memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len); else - rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); break; case iop_ipchset: UNICODE_ONLY( @@ -261,13 +263,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 case iop_zbfsize: GET_ULONG(bfsize, pp->str.addr + p_offset); if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize)) - rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zibfsize: ibfsize_specified = TRUE; GET_ULONG(ibfsize, pp->str.addr + p_offset); if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize)) - rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zlisten: listen_specified = TRUE; @@ -277,8 +279,8 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 memset(sockaddr, 0, SIZEOF(sockaddr)); memcpy(sockaddr, pp->str.addr + p_offset + 1, len); } else - rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, - len, SA_MAXLITLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, + pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_connect: connect_specified = TRUE; @@ -288,8 +290,8 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 memset(sockaddr, 0, SIZEOF(sockaddr)); memcpy(sockaddr, pp->str.addr + p_offset + 1, len); } else - rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, - len, SA_MAXLITLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, + len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_ioerror: ioerror_specified = TRUE; @@ -308,13 +310,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 memcpy(sock_handle, pp->str.addr + p_offset + 1, handle_len); break; case iop_socket: - rts_error(VARLSTCNT(1) ERR_DEVPARINAP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARINAP); break; case iop_zff: if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset))) memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len); else - rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); break; case iop_znoff: zff_len = 0; @@ -331,9 +333,10 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 if (-1 == moreread_timeout) moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; else if (-1 > moreread_timeout) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); else if (MAX_MOREREAD_TIMEOUT < moreread_timeout) - rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, + MAX_MOREREAD_TIMEOUT); moreread_specified = TRUE; break; default: @@ -352,13 +355,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 get_chset_desc(&chset_names[ioptr->ochset]); if (listen_specified && connect_specified) { - rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("OPEN")); return FALSE; } if (delay_specified && nodelay_specified) { - rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN")); return FALSE; } @@ -382,8 +385,11 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 { if (iosocket_handle(sock_handle, &handle_len, FALSE, newdsocket) >= 0) { - FREE_SOCKPTR(socketptr); - rts_error(VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, sock_handle); + if (FD_INVALID != socketptr->temp_sd) + tcp_routines.aa_close(socketptr->temp_sd); + SOCKET_FREE(socketptr); + assert(ioptr->newly_created == FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, sock_handle); return FALSE; } } else @@ -395,17 +401,19 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 iosocket_delimiter(delimiter_buffer, delimiter_len, socketptr, (0 == delimiter_len)); if (ioptr->wrap && 0 != socketptr->n_delimiter && ioptr->width < socketptr->delimiter[0].len) { - iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE); - FREE_SOCKPTR(socketptr); - rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, ioptr->width, socketptr->delimiter[0].len); + socketptr_delim_len = socketptr->delimiter[0].len; + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, ioptr->width, socketptr_delim_len); assert(FALSE); } /* connects newdsocket and socketptr (the new socket) */ if (gtm_max_sockets <= newdsocket->n_socket) { - iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE); - FREE_SOCKPTR(socketptr); - rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); + assert(ioptr->newly_created == FALSE); + if (FD_INVALID != socketptr->temp_sd) + tcp_routines.aa_close(socketptr->temp_sd); + SOCKET_FREE(socketptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return FALSE; } socketptr->dev = newdsocket; @@ -431,24 +439,37 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 { if (socketptr->sd > 0) (void)tcp_routines.aa_close(socketptr->sd); - iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE); - if (NULL != socketptr->zff.addr) - free(socketptr->zff.addr); - FREE_SOCKPTR(socketptr); + SOCKET_FREE(socketptr); return FALSE; } else if (is_principal) { /* fill in what bind or connect would */ - strncpy(socketptr->local.saddr_ip, tcp_routines.aa_inet_ntoa(socketptr->local.sin.sin_addr), - SIZEOF(socketptr->local.saddr_ip)); - strncpy(socketptr->remote.saddr_ip, tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr), - SIZEOF(socketptr->remote.saddr_ip)); + ai_ptr = &(socketptr->local.ai); + remote_ai_ptr = &(socketptr->remote.ai); + /* translate internal address to numeric ip address */ + GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0, NI_NUMERICHOST, + errcode); + if (0 != errcode) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->local.saddr_ip); + GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), remote_ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0, + NI_NUMERICHOST, errcode); + if (0 != errcode) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->remote.saddr_ip); len = SIZEOF(ESTABLISHED) - 1; - memcpy(&newdsocket->dollar_key[0], ESTABLISHED, len); - newdsocket->dollar_key[len++] = '|'; - memcpy(&newdsocket->dollar_key[len], socketptr->handle, socketptr->handle_len); + memcpy(&ioptr->dollar.key[0], ESTABLISHED, len); + ioptr->dollar.key[len++] = '|'; + memcpy(&ioptr->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; - newdsocket->dollar_key[len++] = '|'; - strcpy(&newdsocket->dollar_key[len], socketptr->remote.saddr_ip); /* Copies in terminating NULL */ + ioptr->dollar.key[len++] = '|'; + strncpy(&ioptr->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); + ioptr->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ } /* commit the changes to the list */ if (listen_specified || connect_specified || is_principal) @@ -456,6 +477,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 socketptr->dev = dsocketptr; memcpy(dsocketptr, newdsocket, d_socket_struct_len); } - ioptr->state = dev_open; + ioptr->newly_created = FALSE; + ioptr->state = dev_open; return TRUE; } diff --git a/sr_port/iosocket_readfl.c b/sr_port/iosocket_readfl.c index 0aa1e74..814b7b2 100644 --- a/sr_port/iosocket_readfl.c +++ b/sr_port/iosocket_readfl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,7 +36,7 @@ #include "wake_alarm.h" #include "gtm_conv.h" #include "gtm_utf8.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "send_msg.h" @@ -60,23 +60,22 @@ GBLREF boolean_t dollar_zininterrupt; GBLREF int socketus_interruptus; GBLREF boolean_t gtm_utf8_mode; -error_def(ERR_IOEOF); -error_def(ERR_TEXT); -error_def(ERR_CURRSOCKOFR); -error_def(ERR_NOSOCKETINDEV); -error_def(ERR_GETSOCKOPTERR); -error_def(ERR_SETSOCKOPTERR); -error_def(ERR_MAXSTRLEN); error_def(ERR_BOMMISMATCH); -error_def(ERR_ZINTRECURSEIO); +error_def(ERR_CURRSOCKOFR); +error_def(ERR_GETSOCKOPTERR); +error_def(ERR_IOEOF); +error_def(ERR_MAXSTRLEN); +error_def(ERR_NOSOCKETINDEV); +error_def(ERR_SETSOCKOPTERR); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); +error_def(ERR_TEXT); +error_def(ERR_ZINTRECURSEIO); UNIX_ONLY(error_def(ERR_NOPRINCIO);) #ifdef UNICODE_SUPPORTED /* Maintenance of $KEY, $DEVICE and $ZB on a badchar error */ -void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned char *delimptr, - unsigned char *strend) +void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned char *delimptr, unsigned char *strend) { int tmplen, len; unsigned char *delimend; @@ -89,7 +88,7 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned vmvalptr->str.addr = (char *)stringpool.free; if (0 < datalen) { /* Return how much input we got */ - if (CHSET_M != iod->ichset && CHSET_UTF8 != iod->ichset) + if ((CHSET_M != iod->ichset) && (CHSET_UTF8 != iod->ichset)) { DBGSOCK2((stdout, "socrflbc: Converting UTF16xx data back to UTF8 for internal use\n")); vmvalptr->str.len = gtm_conv(chset_desc[iod->ichset], chset_desc[CHSET_UTF8], &vmvalptr->str, NULL, NULL); @@ -97,11 +96,11 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned } stringpool.free += vmvalptr->str.len; } - if (NULL != strend && NULL != delimptr) + if ((NULL != strend) && (NULL != delimptr)) { /* First find the end of the delimiter (max of 4 bytes) */ if (0 == delimlen) { - for (delimend = delimptr; GTM_MB_LEN_MAX >= delimlen && delimend < strend; ++delimend, ++delimlen) + for (delimend = delimptr; (GTM_MB_LEN_MAX >= delimlen) && (delimend < strend); ++delimend, ++delimlen) { if (UTF8_VALID(delimend, strend, tmplen)) break; @@ -111,13 +110,13 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned { /* Set $KEY and $ZB with the failing badchar */ memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1)); iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0'; - memcpy(dsocketptr->dollar_key, delimptr, MIN(delimlen, DD_BUFLEN - 1)); - dsocketptr->dollar_key[MIN(delimlen, DD_BUFLEN - 1)] = '\0'; + memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1)); + iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0'; } } len = SIZEOF(ONE_COMMA) - 1; - memcpy(dsocketptr->dollar_device, ONE_COMMA, len); - memcpy(&dsocketptr->dollar_device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG)); + memcpy(iod->dollar.device, ONE_COMMA, len); + memcpy(&iod->dollar.device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG)); } #endif @@ -157,13 +156,13 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) if (0 >= dsocketptr->n_socket) { iod->dollar.za = 9; - rts_error(VARLSTCNT(1) ERR_NOSOCKETINDEV); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV); return 0; } if (dsocketptr->n_socket <= dsocketptr->current_socket) { iod->dollar.za = 9; - rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return 0; } utf8_active = NON_UNICODE_ONLY(FALSE) UNICODE_ONLY(gtm_utf8_mode ? IS_UTF_CHSET(ichset) : FALSE); @@ -177,7 +176,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) vari = FALSE; width = (width < MAX_STRLEN) ? width : MAX_STRLEN; } - /* if width is set to MAX_STRLEN, we might be overly generous (assuming every char is just one byte) we must check if byte + /* If width is set to MAX_STRLEN, we might be overly generous (assuming every char is just one byte) we must check if byte * length crosses the MAX_STRLEN boundary */ socketptr = dsocketptr->socket[dsocketptr->current_socket]; @@ -190,13 +189,11 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) /* Check if new or resumed read */ if (dsocketptr->mupintr) { /* We have a pending read restart of some sort */ - if (sockwhich_invalid == sockintr->who_saved) - GTMASSERT; /* Interrupt should never have an invalid save state */ - /* check we aren't recursing on this device */ + assertpro(sockwhich_invalid != sockintr->who_saved); /* Interrupt should never have an invalid save state */ + /* Check we aren't recursing on this device */ if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); - if (sockwhich_readfl != sockintr->who_saved) - GTMASSERT; /* ZINTRECURSEIO should have caught */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); + assertpro(sockwhich_readfl == sockintr->who_saved); /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socrfl: *#*#*#*#*#*#*# Restarted interrupted read\n")); dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; @@ -227,7 +224,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) if (mv_chain == mv_zintdev) POP_MV_STENT(); /* pop if top of stack */ else - { /* else mark it unused */ + { /* Else mark it unused */ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = 0; mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = NULL; @@ -274,7 +271,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } TRCTBL_ENTRY(SOCKRFL_RESTARTED, chars_read, (INTPTR_T)max_bufflen, (INTPTR_T)stp_need, buffer_start); if (!IS_STP_SPACE_AVAILABLE(stp_need)) - { /* need more room */ + { /* Need more room */ DBGSOCK2((stdout, "socrfl: .. garbage collection done in restart after interrupt\n")); v->str.addr = (char *)buffer_start; /* Protect buffer from reclaim */ v->str.len = bytes_read; @@ -283,12 +280,12 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) TRCTBL_ENTRY(SOCKRFL_RSTGC, 0, buffer_start, stringpool.free, NULL); } if ((buffer_start + bytes_read) < stringpool.free) /* BYPASSOK */ - { /* now need to move it to the top */ + { /* Now need to move it to the top */ assert(stp_need == max_bufflen); memcpy(stringpool.free, buffer_start, bytes_read); /* BYPASSOK */ buffer_start = stringpool.free; /* BYPASSOK */ } else - { /* it should still be just under the used space */ + { /* It should still be just under the used space */ assert((buffer_start + bytes_read) == stringpool.free); /* BYPASSOK */ stringpool.free = buffer_start; /* backup the free pointer */ } @@ -299,7 +296,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } TRCTBL_ENTRY(SOCKRFL_BEGIN, chars_read, buffer_start, stringpool.free, NULL); if (iod->dollar.x && (TCP_WRITE == socketptr->lastop)) - { /* switching from write to read */ + { /* Switching from write to read */ assert(!zint_restart); if (!iod->dollar.za) iosocket_flush(iod); @@ -329,17 +326,18 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) - { /* there is time to wait */ -#ifdef UNIX - /* set blocking I/O */ + { /* There is time to wait */ +# ifdef UNIX + /* Set blocking I/O */ FCNTL2(socketptr->sd, F_GETFL, flags); if (flags < 0) { iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), - save_errno, LEN_AND_STR(errptr)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, + LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), + save_errno, LEN_AND_STR(errptr)); } FCNTL3(socketptr->sd, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res); if (fcntl_res < 0) @@ -347,17 +345,18 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), - save_errno, LEN_AND_STR(errptr)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), + save_errno, LEN_AND_STR(errptr)); } -#endif +# endif sys_get_curr_time(&cur_time); if (!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. - */ + { /* End_time taken from restart data. Compute what msec_timeout should be so timeout timer + * gets set correctly below. + */ end_time = sockintr->end_time; /* Restore end_time for timeout */ cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) @@ -378,7 +377,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } } sockintr->end_time_valid = FALSE; - dsocketptr->dollar_key[0] = '\0'; + iod->dollar.key[0] = '\0'; iod->dollar.zb[0] = '\0'; more_data = TRUE; real_errno = 0; @@ -390,7 +389,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) "buffered_length: %d\n", bytes_read, chars_read, socketptr->buffered_length)); DBGSOCK2((stdout, "socrfl: ********* read-width: %d vari: %d status: %d\n", width, vari, status)); if (bytes_read >= max_bufflen) - { /* more buffer needed. Extend the stringpool buffer by doubling the size as much as we + { /* More buffer needed. Extend the stringpool buffer by doubling the size as much as we * extended previously */ DBGSOCK((stdout, "socrfl: Buffer expand1 bytes_read(%d) max_bufflen(%d)\n", @@ -414,7 +413,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) (UINTPTR_T)max_bufflen); } } - if (has_delimiter || requeue_done || (socketptr->first_read && CHSET_M != ichset)) + if (has_delimiter || requeue_done || (socketptr->first_read && (CHSET_M != ichset))) { /* Delimiter scanning needs one char at a time. Question is how big is a char? * For the UTF character sets, we have a similar issue (with the same solution) in that * we need to make sure the entire BOM we may have is in the buffer. If the last read @@ -425,7 +424,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) */ requeue_done = FALSE; /* housekeeping -- We don't want to come back here for this reason * until it happens again */ - DBGSOCK_ONLY2(if (socketptr->first_read && CHSET_M != ichset) + DBGSOCK_ONLY2(if (socketptr->first_read && (CHSET_M != ichset)) DBGSOCK((stdout, "socrfl: Prebuffering because ichset = UTF16\n")); else DBGSOCK((stdout, "socrfl: Prebuffering because we have delimiter or requeue\n"))); @@ -442,7 +441,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) * character length to us to use for bufflen. */ charlen = (int)iosocket_snr_utf_prebuffer(iod, socketptr, 0, &time_for_read, - (!vari || has_delimiter || 0 == chars_read)); + (!vari || has_delimiter || 0 == chars_read)); DBGSOCK((stdout, "socrfl: charlen from iosocket_snr_utf_prebuffer = %d\n", charlen)); if (0 < charlen) { /* We know how long the next char is. If it fits in our buffer, then it is @@ -458,7 +457,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) max_bufflen = MAX_STRLEN; if (!IS_STP_SPACE_AVAILABLE(max_bufflen)) { - v->str.len = bytes_read; /* to keep the data read so far from + v->str.len = bytes_read; /* To keep the data read so far from * being garbage collected */ v->str.addr = (char *)stringpool.free; @@ -504,6 +503,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) { DBGSOCK((stdout, "socrfl: Data read bypassed - status: %d\n", status)); } + TRCTBL_ENTRY(SOCKRFL_RDSTATUS, status, (INTPTR_T)outofband, (INTPTR_T)out_of_time, (INTPTR_T)bytes_read); if (0 == status || -3 == status) /* -3 status can happen on EOB from prebuffering */ { DBGSOCK((stdout, "socrfl: No more data available\n")); @@ -523,7 +523,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) bytes_read += (int)status; UNIX_ONLY(if (iod == io_std_device.out) prin_in_dev_failure = FALSE); - if (socketptr->first_read && CHSET_M != ichset) /* May have a BOM to defuse */ + if (socketptr->first_read && (CHSET_M != ichset)) /* May have a BOM to defuse */ { if (CHSET_UTF8 != ichset) { /* When the type is UTF16xx, we need to check for a BOM at the beginning of the file. If @@ -538,7 +538,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) if (CHSET_UTF16LE == ichset) { iod->dollar.za = 9; - rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr, chset_names[CHSET_UTF16LE].len, @@ -554,7 +554,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) if (CHSET_UTF16BE == ichset) { iod->dollar.za = 9; - rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr, chset_names[CHSET_UTF16BE].len, @@ -587,7 +587,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } } else { /* Check for UTF8 BOM. If found, just eliminate it. */ - if (UTF8_BOM_LEN <= bytes_read && (0 == memcmp(buffptr, UTF8_BOM, UTF8_BOM_LEN))) + if ((UTF8_BOM_LEN <= bytes_read) && (0 == memcmp(buffptr, UTF8_BOM, UTF8_BOM_LEN))) { bytes_read -= UTF8_BOM_LEN; /* Throw way BOM */ DBGSOCK2((stdout, "socrfl: UTF8 BOM detected/ignored\n")); @@ -596,7 +596,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } if (socketptr->first_read) { - if (CHSET_UTF16BE == ichset || CHSET_UTF16LE == ichset) + if ((CHSET_UTF16BE == ichset) || (CHSET_UTF16LE == ichset)) { get_chset_desc(&chset_names[ichset]); if (has_delimiter) @@ -605,7 +605,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) socketptr->first_read = FALSE; } if (bytes_read && has_delimiter) - { /* ------- check to see if it is a delimiter -------- */ + { /* Check to see if it is a delimiter */ DBGSOCK((stdout, "socrfl: Searching for delimiter\n")); for (ii = 0; ii < socketptr->n_delimiter; ii++) { @@ -620,9 +620,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) memcpy(iod->dollar.zb, socketptr->idelimiter[ii].addr, MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1)); iod->dollar.zb[MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1)] = '\0'; - memcpy(dsocketptr->dollar_key, socketptr->idelimiter[ii].addr, + memcpy(iod->dollar.key, socketptr->idelimiter[ii].addr, MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)); - dsocketptr->dollar_key[MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)] = '\0'; + iod->dollar.key[MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)] = '\0'; break; } } @@ -635,7 +635,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } if (!terminator) more_data = TRUE; - } else if (EINTR == errno && !out_of_time) /* unrelated timer popped */ + } else if ((EINTR == errno) && !out_of_time) /* Unrelated timer popped */ { status = 0; continue; @@ -647,11 +647,11 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) if (bytes_read > MAX_STRLEN) { iod->dollar.za = 9; - rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); } orig_bytes_read = bytes_read; if (0 != bytes_read) - { /* find n chars read from [buffptr, buffptr + bytes_read) */ + { /* Find n chars read from [buffptr, buffptr + bytes_read) */ DBGSOCK((stdout, "socrfl: Start char scan - c_ptr: 0x"lvaddr" c_top: 0x"lvaddr"\n", buffptr, (buffptr + status))); for (c_ptr = buffptr, c_top = buffptr + status; @@ -673,9 +673,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) (CHSET_UTF16BE == ichset) ? UTF16BE_MBFOLLOW(c_ptr, c_top) : UTF16LE_MBFOLLOW(c_ptr, c_top); mb_len++; /* Account for first byte of char */ - if (0 == mb_len || c_ptr + mb_len <= c_top) + if ((0 == mb_len) || ((c_ptr + mb_len) <= c_top)) { /* The entire char is in the buffer.. badchar */ -#ifdef UNICODE_SUPPORTED +# ifdef UNICODE_SUPPORTED if (CHSET_UTF8 == ichset) { iosocket_readfl_badchar(v, (int)((unsigned char *)c_ptr - stringpool.free), @@ -692,25 +692,25 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) UTF8_BADCHAR((int)(c_ptr - inv_beg), inv_beg, c_top, chset_names[ichset].len, chset_names[ichset].addr); } -#endif +# endif } } - if (c_ptr + mb_len > c_top) /* Verify entire char is in buffer */ + if ((c_ptr + mb_len) > c_top) /* Verify entire char is in buffer */ break; } DBGSOCK((stdout, "socrfl: End char scan - c_ptr: 0x"lvaddr" c_top: 0x"lvaddr"\n", c_ptr, c_top)); - if (c_ptr < c_top) /* width size READ completed OR partial last char, push back bytes into input buffer */ + if (c_ptr < c_top) /* Width size READ completed OR partial last char, push back bytes into input buffer */ { iosocket_unsnr(socketptr, c_ptr, c_top - c_ptr); bytes_read -= (int)(c_top - c_ptr); /* We will be re-reading these bytes */ - requeue_done = TRUE; /* Force single (full) char read next time through */ + requeue_done = TRUE; /* Force single (full) char read next time through */ DBGSOCK((stdout, "socrfl: Requeue of %d bytes done - adjusted bytes_read: %d\n", (c_top - c_ptr), bytes_read)); } } if (terminator) { - assert(0 != bytes_read); + assert(0 < bytes_read); bytes_read -= socketptr->idelimiter[match_delim].len; c_ptr -= socketptr->idelimiter[match_delim].len; UNICODE_ONLY(chars_read -= socketptr->idelimiter[match_delim].char_len); @@ -727,8 +727,8 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) */ if ((chars_read >= width) || (MAX_STRLEN <= orig_bytes_read) || - (vari && !has_delimiter && 0 != chars_read && !more_data) || - (status > 0 && terminator)) + (vari && !has_delimiter && (0 != chars_read) && !more_data) || + ((0 < status) && terminator)) break; if (0 != outofband) { @@ -737,7 +737,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } if (timed) { - if (msec_timeout > 0) + if (0 < msec_timeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); @@ -753,22 +753,23 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } } if (EINTR == real_errno) - status = 0; /* don't treat a or timeout as an error */ + status = 0; /* Don't treat a or timeout as an error */ if (timed) { if (0 < msec_timeout) { -#ifdef UNIX +# ifdef UNIX FCNTL3(socketptr->sd, F_SETFL, flags, fcntl_res); if (fcntl_res < 0) { iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), - save_errno, LEN_AND_STR(errptr)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), + save_errno, LEN_AND_STR(errptr)); } -#endif +# endif if (out_of_time) { ret = FALSE; @@ -796,7 +797,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = bytes_read; sockintr->who_saved = sockwhich_readfl; - if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout) + if ((0 < msec_timeout) && (NO_M_TIMEOUT != msec_timeout)) { sockintr->end_time = end_time; sockintr->end_time_valid = TRUE; @@ -819,23 +820,25 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) GTMASSERT; /* Should *never* return from outofband_action */ return FALSE; /* For the compiler.. */ } - if (chars_read > 0) - { /* there's something to return */ - v->str.len = INTCAST(c_ptr - stringpool.free); + if (0 < chars_read) + { /* There's something to return. Note we do not assert anything using c_ptr as it is possible in a restarted + * read with nearly immediate timeout to bypass setting c_ptr so its value is not dependable at this point. + */ + assert(0 <= bytes_read); + v->str.len = bytes_read; v->str.addr = (char *)stringpool.free; UNICODE_ONLY(v->str.char_len = chars_read); - assert(v->str.len == bytes_read); DBGSOCK((stdout, "socrfl: String to return bytelen: %d charlen: %d iod-width: %d wrap: %d\n", v->str.len, chars_read, iod->width, iod->wrap)); DBGSOCK((stdout, "socrfl: x: %d y: %d\n", iod->dollar.x, iod->dollar.y)); - if (((iod->dollar.x += chars_read) >= iod->width) && iod->wrap) + if (((iod->dollar.x += chars_read) >= iod->width) && iod->wrap) /* Note increment/assignment */ { iod->dollar.y += (iod->dollar.x / iod->width); if (0 != iod->length) iod->dollar.y %= iod->length; iod->dollar.x %= iod->width; } - if (CHSET_M != ichset && CHSET_UTF8 != ichset) + if ((CHSET_M != ichset) && (CHSET_UTF8 != ichset)) { DBGSOCK((stdout, "socrfl: Converting UTF16xx data back to UTF8 for internal use\n")); v->str.len = gtm_conv(chset_desc[ichset], chset_desc[CHSET_UTF8], &v->str, NULL, NULL); @@ -846,48 +849,48 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout) } else { v->str.len = 0; - v->str.addr = dsocketptr->dollar_key; + v->str.addr = iod->dollar.key; } if (status >= 0) - { /* no real problems */ + { /* No real problems */ iod->dollar.zeof = FALSE; iod->dollar.za = 0; - memcpy(dsocketptr->dollar_device, "0", SIZEOF("0")); + memcpy(iod->dollar.device, "0", SIZEOF("0")); } else - { /* there's a significant problem */ + { /* There's a significant problem */ DBGSOCK((stdout, "socrfl: Error handling triggered - status: %d\n", status)); if (0 == chars_read) iod->dollar.x = 0; iod->dollar.za = 9; len = SIZEOF(ONE_COMMA) - 1; - memcpy(dsocketptr->dollar_device, ONE_COMMA, len); + memcpy(iod->dollar.device, ONE_COMMA, len); errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); - memcpy(&dsocketptr->dollar_device[len], errptr, errlen + 1); /* + 1 for null */ -#ifdef UNIX + memcpy(&iod->dollar.device[len], errptr, errlen + 1); /* + 1 for null */ +# ifdef UNIX if (io_curr_device.in == io_std_device.in) { if (!prin_in_dev_failure) prin_in_dev_failure = TRUE; else { - send_msg(VARLSTCNT(1) ERR_NOPRINCIO); - stop_image_no_core(); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); + stop_image_no_core(); } } -#endif +# endif if (iod->dollar.zeof || -1 == status || 0 < iod->error_handler.len) { iod->dollar.zeof = TRUE; if (socketptr->ioerror) - rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); } else iod->dollar.zeof = TRUE; } DBGSOCK_ONLY( if (!ret && out_of_time) { - DBGSOCK((stdout, "socrfl: Returning from read due to timeout\n")); + DBGSOCK((stdout, "socrfl: Returning from read due to timeout\n")); } else { DBGSOCK((stdout, "socrfl: Returning from read with success indicator set to %d\n", ret)); diff --git a/sr_port/iosocket_snr.c b/sr_port/iosocket_snr.c index e63d09b..b95a8e9 100644 --- a/sr_port/iosocket_snr.c +++ b/sr_port/iosocket_snr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -65,12 +65,12 @@ static int fcntl_res; #include "outofband.h" /* 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. -*/ + * from each active region) to interfere with this read so be generous here. + */ #define MAX_SNR_IO 50 #ifdef DEBUG -/* hold gettimeofday before and after select to debug AIX spin */ +/* Hold gettimeofday before and after select to debug AIX spin */ static struct timeval tvbefore, tvafter; #endif @@ -92,9 +92,9 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i DBGSOCK((stdout, "socsnr: socketptr: 0x"lvaddr" buffer: 0x"lvaddr" maxlength: %d, flags: %d\n", socketptr, buffer, maxlength, flags)); - /* ====================== use leftover from the previous read, if there is any ========================= */ - assert(maxlength > 0); - if (socketptr->buffered_length > 0) + /* Use leftover from the previous read, if there is any */ + assert(0 < maxlength); + if (0 < socketptr->buffered_length) { DBGSOCK2((stdout, "socsnr: read from buffer - buffered_length: %d\n", socketptr->buffered_length)); bytesread = MIN(socketptr->buffered_length, maxlength); @@ -105,7 +105,7 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i socketptr->buffered_offset, socketptr->buffered_length)); return bytesread; } - /* ===================== decide on which buffer to use and the size of the recv ======================== */ + /* Decide on which buffer to use and the size of the recv */ if (socketptr->buffer_size > maxlength) { recvbuff = socketptr->buffer; @@ -118,19 +118,19 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i VMS_ONLY(recvsize = MIN(recvsize, VMS_MAX_TCP_IO_SIZE)); DBGSOCK2((stdout, "socsnr: recvsize set to %d\n", recvsize)); - /* =================================== select and recv ================================================= */ + /* Select and recv */ assert(0 == socketptr->buffered_length); socketptr->buffered_length = 0; bytesread = (int)iosocket_snr_io(socketptr, recvbuff, recvsize, flags, time_for_read); DBGSOCK2((stdout, "socsnr: bytes read from recv: %d timeout: %d\n", bytesread, out_of_time)); if (0 < bytesread) - { /* -------- got something this time ----------- */ + { /* Got something this time */ if (recvbuff == socketptr->buffer) { if (bytesread <= maxlength) memcpy(buffer, socketptr->buffer, bytesread); else - { /* -------- got some stuff for future recv -------- */ + { /* Got some stuff for future recv */ memcpy(buffer, socketptr->buffer, maxlength); socketptr->buffered_length = bytesread - maxlength; bytesread = socketptr->buffered_offset = maxlength; @@ -143,18 +143,18 @@ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, i } /* Do the IO dirty work. Note the return value can be from either select() or recv(). - This would be a static routine but that just makes it harder to debug. -*/ + * This would be a static routine but that just makes it harder to debug. + */ 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; ABS_TIME lcl_time_for_read; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT +# ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT long poll_timeout; unsigned long poll_nfds; struct pollfd poll_fdlist[1]; -#endif +# endif DBGSOCK2((stdout, "socsnrio: Socket read request - socketptr: 0x"lvaddr" buffer: 0x"lvaddr" maxlength: %d flags: %d ", socketptr, buffer, maxlength, flags)); @@ -180,10 +180,11 @@ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength { bytesread = tcp_routines.aa_recv(socketptr->sd, buffer, maxlength, flags); 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 ------- */ + ((-1 == bytesread) && ((ECONNRESET == real_errno) || (EPIPE == real_errno) || (EINVAL == real_errno)))) + { /* Lost connection */ if (0 == bytesread) errno = ECONNRESET; return (ssize_t)(-2); @@ -196,10 +197,10 @@ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength } /* When scanning for delimiters, we have to make sure that the next read can pull in at least one full utf char. - Failure to do this means that if a partial utf8 char is read, it will be rebuffered, reread, rebuffered, forever. - A return code of zero indicates a timeout error occured. A negative return code indicates an IO error of some sort. - A positive return code is the length in bytes of the next unicode char in the buffer. -*/ + * Failure to do this means that if a partial utf8 char is read, it will be rebuffered, reread, rebuffered, forever. + * A return code of zero indicates a timeout error occured. A negative return code indicates an IO error of some sort. + * A positive return code is the length in bytes of the next unicode char in the buffer. + */ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int flags, ABS_TIME *time_for_read, boolean_t wait_for_input) { @@ -220,9 +221,9 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f DBGSOCK_ONLY2(real_errno = errno); DBGSOCK2((stdout, "socsnrupb: Buffer empty - bytes read: %d errno: %d\n", bytesread, real_errno)); DBGSOCK_ONLY2(errno = real_errno); - } while (((-1 == bytesread && EINTR == errno) || (0 == bytesread && wait_for_input)) - && !out_of_time && 0 == outofband); - if (out_of_time || 0 != outofband) + } while ((((-1 == bytesread) && (EINTR == errno)) || (0 == bytesread && wait_for_input)) + && !out_of_time && (0 == outofband)); + if (out_of_time || (0 != outofband)) { DBGSOCK_ONLY(if (out_of_time) { @@ -270,11 +271,11 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f break; case CHSET_UTF16: /* Special case as we don't know which mode we are in. This should only be used when - checking for BOMs. Check if first char is 0xFF or 0xFE. If it is, return 1 as our - (follow) length. If neither, assume UTF16BE (default UTF16 codeset) and return the - length it gives. - */ - if (0xFF == (unsigned char)*readptr || 0xFE == (unsigned char)*readptr) + * checking for BOMs. Check if first char is 0xFF or 0xFE. If it is, return 1 as our + * (follow) length. If neither, assume UTF16BE (default UTF16 codeset) and return the + * length it gives. + */ + if ((0xFF == (unsigned char)*readptr) || (0xFE == (unsigned char)*readptr)) mblen = 1; else { @@ -292,11 +293,11 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f { /* Still insufficient chars in the buffer for our utf character. Read some more in. */ if ((socketptr->buffered_offset + mblen) > socketptr->buffer_size) { /* Our char won't fit in the buffer. This can only occur if the read point is - right at the end of the buffer since the minimum buffer size is 32K. Solution - is to slide the part of the char that we have down to the beginning of the - buffer so we have plenty of room. Since this is at most 3 bytes, this is not - a major performance concern. - */ + * right at the end of the buffer since the minimum buffer size is 32K. Solution + * is to slide the part of the char that we have down to the beginning of the + * buffer so we have plenty of room. Since this is at most 3 bytes, this is not + * a major performance concern. + */ DBGSOCK2((stdout, "socsnrupb: Char won't fit in buffer, slide it down\n")); assert(SIZEOF(int) > socketptr->buffered_length); assert(socketptr->buffered_offset > socketptr->buffered_length); /* Assert no overlap */ @@ -330,8 +331,9 @@ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int f return mblen; } -/* Place len bytes pointed by buffer back into socketptr's internal buffer */ -/* Side effect: suppose the last snr was with a length > internal buffer size, we would not have used the internal buffer. For +/* Place len bytes pointed by buffer back into socketptr's internal buffer + * + * Side effect: suppose the last snr was with a length > internal buffer size, we would not have used the internal buffer. For * that case, unsnr might move data not in the internal buffer into the internal buffer and also might result in buffer * expansion */ @@ -340,9 +342,9 @@ void iosocket_unsnr(socket_struct *socketptr, unsigned char *buffer, size_t len) char *new_buff; DBGSOCK((stdout, "iosunsnr: ** Requeueing %d bytes\n", len)); - if (socketptr->buffered_length + len <= socketptr->buffer_size) + if ((socketptr->buffered_length + len) <= socketptr->buffer_size) { - if (socketptr->buffered_length > 0) + if (0 < socketptr->buffered_length) { if (socketptr->buffered_offset < len) { @@ -361,7 +363,7 @@ void iosocket_unsnr(socket_struct *socketptr, unsigned char *buffer, size_t len) { new_buff = malloc(socketptr->buffered_length + len); memcpy(new_buff, buffer, len); - if (socketptr->buffered_length > 0) + if (0 < socketptr->buffered_length) memcpy(new_buff + len, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); free(socketptr->buffer); socketptr->buffer = new_buff; diff --git a/sr_port/iosocket_use.c b/sr_port/iosocket_use.c index 532e946..1dc798b 100644 --- a/sr_port/iosocket_use.c +++ b/sr_port/iosocket_use.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,7 +20,6 @@ #include #include "gtm_inet.h" -#include #include "copy.h" #include "io.h" #include "io_params.h" @@ -51,12 +50,15 @@ LITREF unsigned char filter_index[27]; LITREF unsigned char io_params_size[]; error_def(ERR_ABNCOMPTINC); +error_def(ERR_ACOMPTBINC); error_def(ERR_ADDRTOOLONG); error_def(ERR_ANCOMPTINC); -error_def(ERR_ACOMPTBINC); error_def(ERR_CURRSOCKOFR); error_def(ERR_DELIMSIZNA); +error_def(ERR_DELIMWIDTH); +error_def(ERR_DEVPARMNEG); error_def(ERR_ILLESOCKBFSIZE); +error_def(ERR_MRTMAXEXCEEDED); error_def(ERR_SETSOCKOPTERR); error_def(ERR_SOCKBFNOTEMPTY); error_def(ERR_SOCKNOTFND); @@ -64,10 +66,7 @@ error_def(ERR_SOCKMAX); error_def(ERR_TEXT); error_def(ERR_TTINVFILTER); error_def(ERR_ZFF2MANY); -error_def(ERR_DEVPARMNEG); -error_def(ERR_DELIMWIDTH); error_def(ERR_ZINTRECURSEIO); -error_def(ERR_MRTMAXEXCEEDED); void iosocket_use(io_desc *iod, mval *pp) { @@ -117,7 +116,7 @@ void iosocket_use(io_desc *iod, mval *pp) if (dsocketptr->mupintr) { /* And if we are in $zinterrupt code this is not allowed */ if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); /* We are not in $zinterrupt code and this device was not resumed properly so clear its restartability. */ @@ -146,7 +145,7 @@ void iosocket_use(io_desc *iod, mval *pp) tab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0) { - rts_error(VARLSTCNT(1) ERR_TTINVFILTER); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) @@ -184,13 +183,13 @@ void iosocket_use(io_desc *iod, mval *pp) n_specified++; connect_specified = TRUE; len = *(pp->str.addr + p_offset); - if (len < SA_MAXLITLEN) + if (len < USR_SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else - rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, - 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, + 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN); break; case iop_delimiter: n_specified++; @@ -198,7 +197,7 @@ void iosocket_use(io_desc *iod, mval *pp) if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len) memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len); else - rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); break; case iop_nodelimiter: delimiter_len = 0; @@ -213,13 +212,13 @@ void iosocket_use(io_desc *iod, mval *pp) bfsize_specified = TRUE; GET_ULONG(bfsize, pp->str.addr + p_offset); if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize)) - rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zibfsize: ibfsize_specified = TRUE; GET_ULONG(ibfsize, pp->str.addr + p_offset); if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize)) - rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize); break; case iop_ioerror: n_specified++; @@ -230,13 +229,13 @@ void iosocket_use(io_desc *iod, mval *pp) n_specified++; listen_specified = TRUE; len = *(pp->str.addr + p_offset); - if (len < SA_MAXLITLEN) + if (len < USR_SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else - rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, - 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, + 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN); break; case iop_socket: n_specified++; @@ -266,7 +265,7 @@ void iosocket_use(io_desc *iod, mval *pp) if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset))) memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len); else - rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); break; case iop_znoff: zff_len = 0; @@ -274,14 +273,14 @@ void iosocket_use(io_desc *iod, mval *pp) case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (length < 0) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); iod->length = length; break; case iop_width: /* SOCKET WIDTH is handled the same way as TERMINAL WIDTH */ GET_LONG(width, pp->str.addr + p_offset); if (width < 0) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); if (0 == width) { iod->width = TCPDEF_WIDTH; @@ -304,9 +303,9 @@ void iosocket_use(io_desc *iod, mval *pp) if (-1 == moreread_timeout) moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; else if (-1 > moreread_timeout) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); else if (MAX_MOREREAD_TIMEOUT < moreread_timeout) - rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); moreread_specified = TRUE; break; default: @@ -322,17 +321,20 @@ void iosocket_use(io_desc *iod, mval *pp) /* ------------------------------ compatibility verification -------------------------------- */ if ((socket_specified) && ((n_specified > 2) || ((2 == n_specified) && (0 >= delimiter_len)))) { - rts_error(VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), LEN_AND_LIT("USE")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), + LEN_AND_LIT("USE")); return; } if (connect_specified && listen_specified) { - rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("USE")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), + LEN_AND_LIT("USE")); return; } if (delay_specified && nodelay_specified) { - rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), + LEN_AND_LIT("OPEN")); return; } /* ------------------ make a local copy of device structure to play with -------------------- */ @@ -343,7 +345,7 @@ void iosocket_use(io_desc *iod, mval *pp) { if (1 < n_specified) { - rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) @@ -365,12 +367,12 @@ void iosocket_use(io_desc *iod, mval *pp) */ if (1 < n_specified) { - rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) { - rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea); return; } iosocket_switch(handlea, handlea_len, socket_pool, newdsocket); @@ -395,7 +397,7 @@ void iosocket_use(io_desc *iod, mval *pp) /* use the socket flag to identify which socket to apply changes */ if (0 > (index = iosocket_handle(handles, &handles_len, FALSE, newdsocket))) { - rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles); return; } newdsocket->current_socket = index; @@ -406,10 +408,12 @@ void iosocket_use(io_desc *iod, mval *pp) if (newdsocket->n_socket <= newdsocket->current_socket) { assert(FALSE); - rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, newdsocket->n_socket); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, + newdsocket->n_socket); return; } } + socketptr->temp_sd = FD_INVALID; } newsocket = *socketptr; /* ---------------------- apply changes to the local copy of the socket --------------------- */ @@ -438,7 +442,7 @@ void iosocket_use(io_desc *iod, mval *pp) &newsocket.delimiter[0], NULL, NULL); if (MAX_DELIM_LEN < new_len) { - rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); return; } } else @@ -456,7 +460,7 @@ void iosocket_use(io_desc *iod, mval *pp) } } if (iod->wrap && 0 != newsocket.n_delimiter && iod->width < newsocket.delimiter[0].len) - rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len); if (0 <= zff_len && /* ZFF or ZNOFF specified */ 0 < (newsocket.zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */ { /* ZFF="non-zero-len-string" specified */ @@ -467,7 +471,7 @@ void iosocket_use(io_desc *iod, mval *pp) lcl_zff.len = zff_len; new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &lcl_zff, NULL, NULL); if (MAX_ZFF_LEN < new_len) - rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */ newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN); newsocket.zff.len = new_len; @@ -512,7 +516,8 @@ void iosocket_use(io_desc *iod, mval *pp) { save_errno = errno; errptr = (char *)STRERROR(save_errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, LEN_AND_STR(errptr)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, + LEN_AND_STR(errptr)); return; } #endif @@ -522,13 +527,14 @@ void iosocket_use(io_desc *iod, mval *pp) { save_errno = errno; errptr = (char *)STRERROR(save_errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, LEN_AND_STR(errptr)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, + LEN_AND_STR(errptr)); return; } if (socketptr->buffer_size != newsocket.buffer_size) { if (socketptr->buffered_length > bfsize) - rts_error(VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length); newsocket.buffer = (char *)malloc(bfsize); if (0 < socketptr->buffered_length) { @@ -544,12 +550,7 @@ void iosocket_use(io_desc *iod, mval *pp) { /* error message should be printed from bind/connect */ if (socketptr->sd > 0) (void)tcp_routines.aa_close(socketptr->sd); - iosocket_delimiter((unsigned char *)NULL, 0, &newsocket, TRUE); - if (NULL != socketptr->zff.addr) - free(socketptr->zff.addr); - if (NULL != socketptr->buffer) - free(socketptr->buffer); - free(socketptr); + SOCKET_FREE(socketptr); return; } /* ------------------------------------ commit changes -------------------------------------- */ @@ -557,7 +558,7 @@ void iosocket_use(io_desc *iod, mval *pp) { if (gtm_max_sockets <= newdsocket->n_socket) { - rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return; } /* a new socket is created. so add to the list */ diff --git a/sr_port/iosocket_wait.c b/sr_port/iosocket_wait.c index 905d942..a4a676f 100644 --- a/sr_port/iosocket_wait.c +++ b/sr_port/iosocket_wait.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,9 +34,11 @@ #include "iosocketdef.h" #include "min_max.h" #include "outofband.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" +#include "gtm_netdb.h" +#include "gtm_stdlib.h" #define CONNECTED "CONNECT" #define READ "READ" @@ -50,6 +52,7 @@ GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF mv_stent *mv_chain; +error_def(ERR_GETNAMEINFO); error_def(ERR_SOCKACPT); error_def(ERR_SOCKWAIT); error_def(ERR_TEXT); @@ -62,269 +65,234 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar) { struct timeval utimeout; ABS_TIME cur_time, end_time; - struct sockaddr_in peer; /* socket address + port */ - fd_set tcp_fd; - d_socket_struct *dsocketptr; - socket_struct *socketptr, *newsocketptr; + struct sockaddr_storage peer; /* socket address + port */ + fd_set tcp_fd; + d_socket_struct *dsocketptr; + socket_struct *socketptr, *newsocketptr; socket_interrupt *sockintr; - char *errptr; - int4 errlen, ii, msec_timeout; + char *errptr; + int4 errlen, ii, msec_timeout; int rv, max_fd, len; GTM_SOCKLEN_TYPE size; boolean_t zint_restart; mv_stent *mv_zintdev; int retry_num; + struct sockaddr *peer_sa_ptr; + char port_buffer[NI_MAXSERV], ipaddr[SA_MAXLEN + 1]; + int errcode; /* check for validity */ - assert(iod->type == gtmsocket); - dsocketptr = (d_socket_struct *)iod->dev_sp; + assert(iod->type == gtmsocket); + dsocketptr = (d_socket_struct *)iod->dev_sp; sockintr = &dsocketptr->sock_save_state; + peer_sa_ptr = ((struct sockaddr *)(&peer)); /* Check for restart */ - if (!dsocketptr->mupintr) - /* Simple path, no worries*/ - zint_restart = FALSE; - else - { /* We have a pending wait restart of some sort - check we aren't recursing on this device */ - if (sockwhich_invalid == sockintr->who_saved) - GTMASSERT; /* Interrupt should never have an invalid save state */ - if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); - if (sockwhich_wait != sockintr->who_saved) - GTMASSERT; /* ZINTRECURSEIO should have caught */ - DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n")); - mv_zintdev = io_find_mvstent(iod, FALSE); - if (mv_zintdev) - { - if (sockintr->end_time_valid) - /* Restore end_time for timeout */ - end_time = sockintr->end_time; + if (!dsocketptr->mupintr) + /* Simple path, no worries*/ + zint_restart = FALSE; + else + { /* We have a pending wait restart of some sort - check we aren't recursing on this device */ + if (sockwhich_invalid == sockintr->who_saved) + GTMASSERT; /* Interrupt should never have an invalid save state */ + if (dollar_zininterrupt) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); + if (sockwhich_wait != sockintr->who_saved) + GTMASSERT; /* ZINTRECURSEIO should have caught */ + DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n")); + mv_zintdev = io_find_mvstent(iod, FALSE); + if (mv_zintdev) + { + if (sockintr->end_time_valid) + /* Restore end_time for timeout */ + end_time = sockintr->end_time; - /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ - if (mv_chain == mv_zintdev) - POP_MV_STENT(); /* pop if top of stack */ - else - { /* else mark it unused */ - mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; - mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; - } + /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ + if (mv_chain == mv_zintdev) + POP_MV_STENT(); /* pop if top of stack */ + else + { /* else mark it unused */ + mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; + mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; + } zint_restart = TRUE; DBGSOCK((stdout, "socwait: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec)); - } else - DBGSOCK((stdout, "socwait: no mv_stent found !!\n")); - dsocketptr->mupintr = FALSE; - sockintr->who_saved = sockwhich_invalid; - } - - /* check for events */ - max_fd = 0; - FD_ZERO(&tcp_fd); - for (ii = 0; ii < dsocketptr->n_socket; ii++) - { - socketptr = dsocketptr->socket[ii]; - if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state)) - { - FD_SET(socketptr->sd, &tcp_fd); - max_fd = MAX(max_fd, socketptr->sd); - } - } - utimeout.tv_sec = timepar; - utimeout.tv_usec = 0; - msec_timeout = timeout2msec(timepar); - sys_get_curr_time(&cur_time); - if (!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. - */ - 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; - } + DBGSOCK((stdout, "socwait: no mv_stent found !!\n")); + dsocketptr->mupintr = FALSE; + sockintr->who_saved = sockwhich_invalid; } - sockintr->end_time_valid = FALSE; - - for ( ; ; ) + /* check for events */ + FD_ZERO(&tcp_fd); + while (TRUE) { - rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, - (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout)); - if (0 > rv && EINTR == errno) + max_fd = 0; + for (ii = 0; ii < dsocketptr->n_socket; ii++) { - if (0 != outofband) + socketptr = dsocketptr->socket[ii]; + if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state)) { - DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- " - "queueing mv_stent for wait intr\n", outofband)); - PUSH_MV_STENT(MVST_ZINTDEV); - 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; - dsocketptr->mupintr = TRUE; - socketus_interruptus++; - DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n", - end_time.at_sec, end_time.at_usec, socketus_interruptus)); - outofband_action(FALSE); - GTMASSERT; /* Should *never* return from outofband_action */ - return FALSE; /* For the compiler.. */ + FD_SET(socketptr->sd, &tcp_fd); + max_fd = MAX(max_fd, socketptr->sd); } - sys_get_curr_time(&cur_time); + } + utimeout.tv_sec = timepar; + utimeout.tv_usec = 0; + msec_timeout = timeout2msec(timepar); + sys_get_curr_time(&cur_time); + if (!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. + */ + 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) { - rv = 0; /* time out */ - break; - } - 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 */ - } - if (rv == 0) - { - dsocketptr->dollar_key[0] = '\0'; - return FALSE; - } else if (rv < 0) - { - errptr = (char *)STRERROR(errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); - return FALSE; - } - /* find out which socket is ready */ - for (ii = 0; ii < dsocketptr->n_socket; ii++) - { - socketptr = dsocketptr->socket[ii]; - if (0 != FD_ISSET(socketptr->sd, &tcp_fd)) - break; - } - assert(ii < dsocketptr->n_socket); - if (socket_listening == socketptr->state) - { - if (gtm_max_sockets <= dsocketptr->n_socket) - { - rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); - return FALSE; - } - size = SIZEOF(struct sockaddr_in); - rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size); - if (-1 == rv) - { -#ifdef __hpux - /*ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just - after a SYN before an accept call. Normally this is not fatal and is just a transient state. Hence - exiting just after a single error of this kind should not be done. So retry in case of HP-UX and ENOBUFS error.*/ - if (ENOBUFS == errno) - { - /*In case of succeeding with select in first go, accept will still get 5ms time difference*/ - retry_num = 0; - while (HPUX_MAX_RETRIES > retry_num) + msec_timeout = -1; + utimeout.tv_sec = 0; + utimeout.tv_usec = 0; + } else { - SHORT_SLEEP(5); - for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++) - { - utimeout.tv_sec = 0; - utimeout.tv_usec = HPUX_SEL_TIMEOUT; - FD_ZERO(&tcp_fd); - FD_SET(socketptr->sd, &tcp_fd); - rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, - &utimeout); - if (0 < rv) - break; - if (0 > rv && (EINTR == errno)) - { - if (0 != outofband) - { - DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- " - "queueing mv_stent for wait intr\n", outofband)); - PUSH_MV_STENT(MVST_ZINTDEV); - 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; - dsocketptr->mupintr = TRUE; - socketus_interruptus++; - DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts:" - " %d\n", end_time.at_sec, end_time.at_usec, - socketus_interruptus)); - outofband_action(FALSE); - GTMASSERT; /* Should *never* return from outofband_action */ - return FALSE; /* For the compiler.. */ - } - } - else - SHORT_SLEEP(5); - } - if (0 > rv) - { - errptr = (char *)STRERROR(errno); - errlen = STRLEN(errptr); - rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); - return FALSE; - } - rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size); - if ((-1 == rv) && (ENOBUFS == errno)) - retry_num++; - else - break; + 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 (-1 == rv) -#endif + sockintr->end_time_valid = FALSE; + for ( ; ; ) + { + rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, + (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout)); + if (0 > rv && EINTR == errno) + { + if (0 != outofband) + { + DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- " + "queueing mv_stent for wait intr\n", outofband)); + PUSH_MV_STENT(MVST_ZINTDEV); + 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; + dsocketptr->mupintr = TRUE; + socketus_interruptus++; + DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n", + end_time.at_sec, end_time.at_usec, socketus_interruptus)); + outofband_action(FALSE); + GTMASSERT; /* 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) + { + rv = 0; /* time out */ + break; + } + 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 */ + } + if (rv == 0) + { + iod->dollar.key[0] = '\0'; + return FALSE; + } else if (rv < 0) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } - } - /* got the connection, create a new socket in the device socket list */ - newsocketptr = (socket_struct *)malloc(SIZEOF(socket_struct)); - *newsocketptr = *socketptr; - newsocketptr->sd = rv; - memcpy(&newsocketptr->remote.sin, &peer, SIZEOF(struct sockaddr_in)); - SPRINTF(newsocketptr->remote.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr)); - newsocketptr->remote.port = GTM_NTOHS(peer.sin_port); - newsocketptr->state = socket_connected; - newsocketptr->passive = FALSE; - iosocket_delimiter_copy(socketptr, newsocketptr); - newsocketptr->buffer = (char *)malloc(socketptr->buffer_size); - newsocketptr->buffer_size = socketptr->buffer_size; - newsocketptr->buffered_length = socketptr->buffered_offset = 0; - newsocketptr->first_read = newsocketptr->first_write = TRUE; - /* put the new-born socket to the list and create a handle for it */ - iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr); - dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr; - dsocketptr->current_socket = dsocketptr->n_socket - 1; - len = SIZEOF(CONNECTED) - 1; - memcpy(&dsocketptr->dollar_key[0], CONNECTED, len); - dsocketptr->dollar_key[len++] = '|'; - memcpy(&dsocketptr->dollar_key[len], newsocketptr->handle, newsocketptr->handle_len); - len += newsocketptr->handle_len; - dsocketptr->dollar_key[len++] = '|'; - strcpy(&dsocketptr->dollar_key[len], newsocketptr->remote.saddr_ip); - } else - { - assert(socket_connected == socketptr->state); - dsocketptr->current_socket = ii; - len = SIZEOF(READ) - 1; - memcpy(&dsocketptr->dollar_key[0], READ, len); - dsocketptr->dollar_key[len++] = '|'; - memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); - len += socketptr->handle_len; - dsocketptr->dollar_key[len++] = '|'; - strcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip); + /* find out which socket is ready */ + for (ii = 0; ii < dsocketptr->n_socket; ii++) + { + socketptr = dsocketptr->socket[ii]; + if (0 != FD_ISSET(socketptr->sd, &tcp_fd)) + break; + } + assert(ii < dsocketptr->n_socket); + if (socket_listening == socketptr->state) + { + if (gtm_max_sockets <= dsocketptr->n_socket) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); + return FALSE; + } + + size = SIZEOF(struct sockaddr_storage); + rv = tcp_routines.aa_accept(socketptr->sd, peer_sa_ptr, &size); + if (-1 == rv) + { +# ifdef __hpux + if (ENOBUFS == errno) + continue; /* On HP-UX, ENOBUFS may indicate a transient condition; retry */ +# endif + errptr = (char *)STRERROR(errno); + errlen = STRLEN(errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); + return FALSE; + } + SOCKET_DUP(socketptr, newsocketptr); + newsocketptr->sd = rv; + SOCKET_ADDR_COPY(newsocketptr->remote, peer_sa_ptr, size); + /* translate internal address to numeric ip address */ + GETNAMEINFO(peer_sa_ptr, size, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode); + if (0 != errcode) + { + SOCKET_FREE(newsocketptr); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + if (NULL != newsocketptr->remote.saddr_ip) + free(newsocketptr->remote.saddr_ip); + STRNDUP(ipaddr, SA_MAXLEN, newsocketptr->remote.saddr_ip); + /* translate internal address to port number*/ + GETNAMEINFO(peer_sa_ptr, size, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); + if (0 != errcode) + { + SOCKET_FREE(newsocketptr); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + newsocketptr->remote.port = ATOI(port_buffer); + newsocketptr->state = socket_connected; + newsocketptr->passive = FALSE; + newsocketptr->first_read = newsocketptr->first_write = TRUE; + /* put the new-born socket to the list and create a handle for it */ + iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr); + dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr; + dsocketptr->current_socket = dsocketptr->n_socket - 1; + len = SIZEOF(CONNECTED) - 1; + memcpy(&iod->dollar.key[0], CONNECTED, len); + iod->dollar.key[len++] = '|'; + memcpy(&iod->dollar.key[len], newsocketptr->handle, newsocketptr->handle_len); + len += newsocketptr->handle_len; + iod->dollar.key[len++] = '|'; + strncpy(&iod->dollar.key[len], newsocketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); + iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ + } else + { + assert(socket_connected == socketptr->state); + dsocketptr->current_socket = ii; + len = SIZEOF(READ) - 1; + memcpy(&iod->dollar.key[0], READ, len); + iod->dollar.key[len++] = '|'; + memcpy(&iod->dollar.key[len], socketptr->handle, socketptr->handle_len); + len += socketptr->handle_len; + iod->dollar.key[len++] = '|'; + if (NULL != socketptr->remote.saddr_ip) + { + strncpy(&iod->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); + iod->dollar.key[DD_BUFLEN-1] = '\0'; + } else + iod->dollar.key[len] = '\0'; + } + break; } return TRUE; } diff --git a/sr_port/iosocket_write.c b/sr_port/iosocket_write.c index a130a1b..aa97211 100644 --- a/sr_port/iosocket_write.c +++ b/sr_port/iosocket_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -72,11 +72,11 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) socketptr = dsocketptr->socket[dsocketptr->current_socket]; if (dsocketptr->n_socket <= dsocketptr->current_socket) { - rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return; } if (dsocketptr->mupintr) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); #ifdef MSG_NOSIGNAL flags = MSG_NOSIGNAL; /* return EPIPE instead of SIGPIPE */ #else @@ -99,7 +99,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) DBGSOCK2((stdout, "socwrite: TCP send of BOM-BE with rc %d\n", status)); if (0 != status) { - SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status); + SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX @@ -114,7 +114,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &socketptr->zff, NULL, NULL); if (MAX_ZFF_LEN < new_len) - rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); if (NULL != socketptr->zff.addr) /* we rely on newsocket.zff.addr being set to NULL in iosocket_create() */ socketptr->zff.addr = (char *)malloc(MAX_ZFF_LEN); @@ -129,7 +129,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) &socketptr->delimiter[0], NULL, NULL); if (MAX_DELIM_LEN < new_len) { - rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); return; } socketptr->odelimiter0.len = new_len; @@ -140,7 +140,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) } socketptr->first_write = FALSE; } - memcpy(dsocketptr->dollar_device, "0", SIZEOF("0")); + memcpy(iod->dollar.device, "0", SIZEOF("0")); if (CHSET_M != iod->ochset) { /* For ochset == UTF-8, validate the output, * For ochset == UTF-16[B|L]E, convert the output (and validate during conversion) @@ -194,7 +194,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) socketptr->odelimiter0.len, status)); if (0 != status) { - SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status); + SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX @@ -234,7 +234,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output) DBGSOCK2((stdout, "socwrite: TCP data send of %d bytes with rc %d\n", b_len, status)); if (0 != status) { - SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status); + SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX diff --git a/sr_port/iosocket_wteol.c b/sr_port/iosocket_wteol.c index 01f4c30..c265c16 100644 --- a/sr_port/iosocket_wteol.c +++ b/sr_port/iosocket_wteol.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,6 @@ #include "gtm_socket.h" #include "gtm_inet.h" -#include #include "gt_timer.h" #include "io.h" diff --git a/sr_port/iosocketdef.h b/sr_port/iosocketdef.h index a68be16..951f67b 100644 --- a/sr_port/iosocketdef.h +++ b/sr_port/iosocketdef.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,9 @@ #include #include "gtm_inet.h" +#include "gtm_netdb.h" +#include "gtm_socket.h" /* for using sockaddr_storage */ +#include "iotcpdef.h" #ifndef GTM_MB_LEN_MAX #include "gtm_utf8.h" @@ -74,28 +77,110 @@ #define ONE_COMMA "1," -#define SOCKERROR(iod, dsocketptr, socketptr, gtmerror, syserror) \ -{ \ - int errlen; \ - char *errptr; \ - iod->dollar.za = 9; \ - memcpy(dsocketptr->dollar_device, ONE_COMMA, SIZEOF(ONE_COMMA)); \ - errptr = (char *)STRERROR(syserror); \ - errlen = STRLEN(errptr); \ - memcpy(&dsocketptr->dollar_device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ \ - assert(ERR_SOCKWRITE == gtmerror); \ - UNIX_ONLY(if (iod == io_std_device.out) \ - { \ - if (!prin_out_dev_failure) \ - prin_out_dev_failure = TRUE; \ - else \ - { \ - send_msg(VARLSTCNT(1) ERR_NOPRINCIO); \ - stop_image_no_core(); \ - } \ - }) \ - if (socketptr->ioerror) \ - rts_error(VARLSTCNT(6) gtmerror, 0, ERR_TEXT, 2, errlen, errptr); \ +#define SOCKERROR(iod, socketptr, gtmerror, syserror) \ +{ \ + int errlen; \ + char *errptr; \ + iod->dollar.za = 9; \ + memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA)); \ + errptr = (char *)STRERROR(syserror); \ + errlen = STRLEN(errptr); \ + memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ \ + assert(ERR_SOCKWRITE == gtmerror); \ + UNIX_ONLY(if (iod == io_std_device.out) \ + { \ + if (!prin_out_dev_failure) \ + prin_out_dev_failure = TRUE; \ + else \ + { \ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); \ + stop_image_no_core(); \ + } \ + }) \ + if (socketptr->ioerror) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) gtmerror, 0, ERR_TEXT, 2, errlen, errptr); \ +} + +#define SOCKET_ALLOC(SOCKPTR) \ +{ \ + SOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \ + memset(SOCKPTR, 0, SIZEOF(socket_struct)); \ +} + +#define SOCKET_ADDR(SOCKPTR, SOCKEND) \ + ((sockaddr_ptr)(SOCKPTR->SOCKEND.sa \ + ? SOCKPTR->SOCKEND.sa \ + : (SOCKPTR->SOCKEND.sa = (struct sockaddr *)malloc(SIZEOF(struct sockaddr_storage))))) + +#define SOCKET_LOCAL_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, local) +#define SOCKET_REMOTE_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, remote) + +#define SOCKET_ADDR_COPY(SOCKADDRESS, SOCKADDRPTR, SOCKADDRLEN) \ +{ \ + if (SOCKADDRESS.sa) \ + free(SOCKADDRESS.sa); \ + SOCKADDRESS.sa = (struct sockaddr *)malloc(SOCKADDRLEN); \ + memcpy(SOCKADDRESS.sa, SOCKADDRPTR, SOCKADDRLEN); \ +} + +#define SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, SOCKEND) SOCKET_ADDR_COPY((SOCKPTR)->SOCKEND, (AIPTR)->ai_addr, (AIPTR)->ai_addrlen) +#define SOCKET_AI_TO_LOCAL_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, local) +#define SOCKET_AI_TO_REMOTE_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, remote) + +#define SOCKET_ADDRLEN(SOCKPTR, AIPTR, SOCKEND) \ + (((SOCKPTR)->SOCKEND.sa) ? ((AIPTR)->ai_addrlen) : (SIZEOF(struct sockaddr_storage))) + +#define SOCKET_BUFFER_INIT(SOCKPTR, SIZE) \ +{ \ + SOCKPTR->buffer = (char *)malloc(SIZE); \ + SOCKPTR->buffer_size = SIZE; \ + SOCKPTR->buffered_length = SOCKPTR->buffered_offset = 0; \ +} + +#define SOCKET_FREE(SOCKPTR) \ +{ \ + if (NULL != SOCKPTR->buffer) \ + free(SOCKPTR->buffer); \ + if (NULL != SOCKPTR->zff.addr) \ + free(SOCKPTR->zff.addr); \ + if (NULL != SOCKPTR->local.sa) \ + free(SOCKPTR->local.sa); \ + if (NULL != SOCKPTR->remote.sa) \ + free(SOCKPTR->remote.sa); \ + if (NULL != SOCKPTR->local.saddr_ip) \ + free(SOCKPTR->local.saddr_ip); \ + if (NULL != SOCKPTR->remote.saddr_ip) \ + free(SOCKPTR->remote.saddr_ip); \ + iosocket_delimiter((unsigned char *)NULL, 0, SOCKPTR, TRUE); \ + free(SOCKPTR); \ +} + +#define SOCKET_DUP(SOCKPTR, NEWSOCKPTR) \ +{ \ + NEWSOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \ + *NEWSOCKPTR = *SOCKPTR; \ + if (NULL != SOCKPTR->buffer) \ + NEWSOCKPTR->buffer = (char *)malloc(SOCKPTR->buffer_size); \ + if (NULL != SOCKPTR->zff.addr) \ + { \ + NEWSOCKPTR->zff.addr = (char *)malloc(MAX_ZFF_LEN); \ + memcpy(NEWSOCKPTR->zff.addr, SOCKPTR->zff.addr, SOCKPTR->zff.len); \ + } \ + if (NULL != SOCKPTR->local.sa) \ + { \ + NEWSOCKPTR->local.sa = (struct sockaddr *)malloc(SOCKPTR->local.ai.ai_addrlen); \ + memcpy(NEWSOCKPTR->local.sa, SOCKPTR->local.sa, SOCKPTR->local.ai.ai_addrlen); \ + } \ + if (NULL != SOCKPTR->remote.sa) \ + { \ + NEWSOCKPTR->remote.sa = (struct sockaddr *)malloc(SOCKPTR->remote.ai.ai_addrlen); \ + memcpy(NEWSOCKPTR->remote.sa, SOCKPTR->remote.sa, SOCKPTR->remote.ai.ai_addrlen); \ + } \ + if (NULL != SOCKPTR->local.saddr_ip) \ + STRNDUP(SOCKPTR->local.saddr_ip, SA_MAXLEN, NEWSOCKPTR->local.saddr_ip); \ + if (NULL != SOCKPTR->remote.saddr_ip) \ + STRNDUP(SOCKPTR->remote.saddr_ip, SA_MAXLEN, NEWSOCKPTR->remote.saddr_ip); \ + iosocket_delimiter_copy(SOCKPTR, NEWSOCKPTR); \ } enum socket_state @@ -124,15 +209,17 @@ enum socket_which /* which module saved the interrupted info */ typedef struct socket_address_type { - struct sockaddr_in sin; /* accurate one */ + struct sockaddr *sa; + struct addrinfo ai; + struct addrinfo *ai_head; /* store the head of addrinfo linked list */ unsigned short port; - char saddr_ip[SA_MAXLEN]; - char saddr_lit[SA_MAXLITLEN]; + char *saddr_ip; } socket_address; typedef struct socket_struct_type { int sd; /* socket descriptor */ + int temp_sd; /* a temp socket descriptor only to test whether IPv6 can be created */ struct d_socket_struct_type *dev; /* point back to the driver */ boolean_t passive, ioerror, @@ -148,6 +235,7 @@ typedef struct socket_struct_type int handle_len; int bufsiz; /* OS internal buffer size */ int n_delimiter; + int last_recv_errno; mstr delimiter[MAX_N_DELIMITER]; mstr idelimiter[MAX_N_DELIMITER]; mstr odelimiter0; @@ -180,8 +268,6 @@ typedef struct d_socket_struct_type boolean_t mupintr; /* We were mupip interrupted */ int4 current_socket; /* current socket index */ int4 n_socket; /* number of sockets */ - char dollar_device[DD_BUFLEN]; - char dollar_key[DD_BUFLEN]; struct io_desc_struct *iod; /* Point back to main IO descriptor block */ struct socket_struct_type *socket[1]; /* Array size determined by gtm_max_sockets */ } d_socket_struct; diff --git a/sr_port/iotcp_close.c b/sr_port/iotcp_close.c index aafb0ef..76f2ad9 100644 --- a/sr_port/iotcp_close.c +++ b/sr_port/iotcp_close.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 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 "mdef.h" #include "gtm_stdio.h" -#include +#include "gtm_inet.h" #include "copy.h" #include "io_params.h" diff --git a/sr_port/iotcp_fillroutine.c b/sr_port/iotcp_fillroutine.c index 6d71024..0126610 100644 --- a/sr_port/iotcp_fillroutine.c +++ b/sr_port/iotcp_fillroutine.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -119,14 +119,6 @@ int iotcp_fillroutine(void) tcp_routines.aa_connect = gtm_connect; tcp_routines.aa_getsockname = getsockname; tcp_routines.aa_getsockopt = getsockopt; -#ifndef htons /* if htons is not a macro, assign the routine */ - tcp_routines.aa_htons = htons; -#endif - tcp_routines.aa_inet_addr = INET_ADDR; - tcp_routines.aa_inet_ntoa = INET_NTOA; -#ifndef ntohs - tcp_routines.aa_ntohs = ntohs; -#endif tcp_routines.aa_listen = listen; tcp_routines.aa_recv = (int (*)())gtm_recv; tcp_routines.aa_select = select; diff --git a/sr_port/iotcp_flush.c b/sr_port/iotcp_flush.c index b8ddc9f..d731116 100644 --- a/sr_port/iotcp_flush.c +++ b/sr_port/iotcp_flush.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include "gtm_stdio.h" -#include +#include "gtm_inet.h" #include "io.h" #include "iotcpdef.h" diff --git a/sr_port/iotcp_iocontrol.c b/sr_port/iotcp_iocontrol.c index ed725c4..76959d8 100644 --- a/sr_port/iotcp_iocontrol.c +++ b/sr_port/iotcp_iocontrol.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include -#include +#include "gtm_inet.h" #include "gtm_string.h" #include "io.h" @@ -30,15 +30,12 @@ void iotcp_dlr_device(mstr *d) { io_desc *iod; int len; - d_tcp_struct *tcpptr; iod = io_curr_device.out; - tcpptr = (d_tcp_struct *)iod->dev_sp; - - len = STRLEN(tcpptr->dollar_device); + len = STRLEN(iod->dollar.device); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); - memcpy(d->addr, tcpptr->dollar_device, len); + memcpy(d->addr, iod->dollar.device, len); d->len = len; return; } @@ -48,15 +45,12 @@ void iotcp_dlr_key(mstr *d) { io_desc *iod; int len; - d_tcp_struct *tcpptr; iod = io_curr_device.out; - tcpptr = (d_tcp_struct *)iod->dev_sp; - - len = STRLEN(tcpptr->saddr); + len = STRLEN(iod->dollar.key); /* verify internal buffer has enough space for $KEY string value */ assert((int)d->len > len); - memcpy(d->addr, tcpptr->saddr, len); + memcpy(d->addr, iod->dollar.key, len); d->len = len; return; } diff --git a/sr_port/iotcp_list.c b/sr_port/iotcp_list.c index f7b37f4..d1f5442 100644 --- a/sr_port/iotcp_list.c +++ b/sr_port/iotcp_list.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,11 +25,15 @@ #include "iotcproutine.h" #include "iotcpdef.h" +error_def(ERR_SOCKINIT); +error_def(ERR_TEXT); + /* list of listening sockets */ typedef struct lsock_rec_s { int socket; - struct sockaddr_in sin; + struct sockaddr_storage sas; + struct addrinfo ai; struct lsock_rec_s *next; io_log_name *ldev; /* listening device record */ } lsock_rec; @@ -55,8 +59,8 @@ int iotcp_getlsock(io_log_name *dev) tcpptr = (d_tcp_struct *)dev->iod->dev_sp; for (ls = lsock_list; ls != NULL; ls = ls->next) - if (tcpptr->sin.sin_addr.s_addr == ls->sin.sin_addr.s_addr && tcpptr->sin.sin_port == ls->sin.sin_port) - return ls->socket; + if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas))) + return ls->socket; return iotcp_newlsock(dev, tcpptr); } @@ -76,20 +80,16 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr) char *errptr; int4 errlen; - error_def(ERR_SOCKINIT); - error_def(ERR_TEXT); - - #ifdef DEBUG_TCP PRINTF("iotcp_newlsock ---\n"); #endif - lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); + lsock = tcp_routines.aa_socket(tcpptr->ai.ai_family, tcpptr->ai.ai_socktype, tcpptr->ai.ai_protocol); if (lsock == -1) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } @@ -99,16 +99,16 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr) errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } - if (tcp_routines.aa_bind(lsock, (struct sockaddr *)&tcpptr->sin, SIZEOF(struct sockaddr)) == -1) + if (-1 == tcp_routines.aa_bind(lsock, tcpptr->ai.ai_addr, tcpptr->ai.ai_addrlen)) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } @@ -118,7 +118,7 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr) errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } @@ -154,7 +154,9 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr) /* add to our list of tcp listening sockets */ new_lsock = (lsock_rec *)malloc(SIZEOF(lsock_rec)); new_lsock->socket = lsock; - new_lsock->sin = tcpptr->sin; + new_lsock->ai = tcpptr->ai; + new_lsock->sas = tcpptr->sas; + new_lsock->ai.ai_addr = (struct sockaddr *)(&new_lsock->sas); new_lsock->next = lsock_list; new_lsock->ldev = ldev; lsock_list = new_lsock; @@ -171,7 +173,11 @@ void iotcp_rmlsock(io_desc *iod) for (prev = NULL, ls = lsock_list; ls != NULL;) { next = ls->next; - if (tcpptr->sin.sin_port == ls->sin.sin_port) + /* Actually it's enough to just compare the port number, however extracting port from + * sas needs to call getnameinfo(). Same sas can guarantee the same port, so + * it's enough to use sas to detect whether the device is what we want to delete + */ + if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas))) { if (prev) prev->next = ls->next; diff --git a/sr_port/iotcp_open.c b/sr_port/iotcp_open.c index 31bc10a..262bd15 100644 --- a/sr_port/iotcp_open.c +++ b/sr_port/iotcp_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,11 +27,12 @@ #include "gtm_fcntl.h" #include "gtm_time.h" #include "gtm_socket.h" +#include "gtm_netdb.h" /* gtm_netdb must be in front so that AI_V4MAPPED will be defined */ +#include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_ctype.h" #include "gtm_string.h" #include "gtm_stdio.h" -#include "gtm_netdb.h" #include "copy.h" #include "gt_timer.h" @@ -45,25 +46,32 @@ #include "stringpool.h" #include "outofband.h" #include "wake_alarm.h" - -#ifdef __osf__ -/* Tru64 does not have the prototype for "hstrerror" even though the function is available in the library. - * Until we revamp the TCP communications setup stuff to use the new(er) POSIX definitions, we cannot move - * away from "hstrerror". Declare prototype for this function in Tru64 manually until then. - */ -const char *hstrerror(int err); -#endif +#include "util.h" GBLREF tcp_library_struct tcp_routines; GBLREF bool out_of_time; GBLREF volatile int4 outofband; LITREF unsigned char io_params_size[]; +error_def(ERR_DEVPARMNEG); +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_INVADDRSPEC); +error_def(ERR_INVPORTSPEC); +error_def(ERR_IPADDRREQ); +error_def(ERR_OPENCONN); +error_def(ERR_SOCKACPT); +error_def(ERR_SOCKINIT); +error_def(ERR_SOCKPARMREQ); +error_def(ERR_SOCKWAIT); +error_def(ERR_TEXT); + short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout) { boolean_t no_time_left = FALSE, timed; - char addr[SA_MAXLEN+1], *errptr, sockaddr[SA_MAXLEN+1], - temp_addr[SA_MAXLEN+1], temp_ch, *adptr; + char addr[SA_MAXLEN + 1], *errptr, sockaddr[SA_MAXLEN + 1], + temp_addr[SA_MAXLEN + 1], temp_ch; + char ipname[SA_MAXLEN]; unsigned char ch, len; int4 length, width; unsigned short port; @@ -77,22 +85,18 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti ABS_TIME cur_time, end_time, time_for_read, lcl_time_for_read; d_tcp_struct *tcpptr, newtcp; io_desc *ioptr; - struct sockaddr_in peer; /* socket address + port */ + struct sockaddr_storage peer_sas; /* socket address + port */ fd_set tcp_fd; int lsock; short retry_num; const char *terrptr; - - error_def(ERR_DEVPARMNEG); - error_def(ERR_INVADDRSPEC); - error_def(ERR_INVPORTSPEC); - error_def(ERR_IPADDRREQ); - error_def(ERR_OPENCONN); - error_def(ERR_SOCKACPT); - error_def(ERR_SOCKINIT); - error_def(ERR_SOCKPARMREQ); - error_def(ERR_SOCKWAIT); - error_def(ERR_TEXT); + int errcode; + char port_buffer[NI_MAXSERV]; + int port_len; + struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *tmp_ai_ptr, hints; + int host_len; /* addr_len + port_len + delimeters */ + int af; + int test_ipv6_sd; #ifdef DEBUG_TCP PRINTF("iotcp_open.c >>> tt = %d\n", t); @@ -119,7 +123,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti } ioptr->dollar.zeof = FALSE; newtcp = *tcpptr; - memcpy(newtcp.dollar_device, LITZERO, SIZEOF(LITZERO)); + memcpy(ioptr->dollar.device, LITZERO, SIZEOF(LITZERO)); newtcp.passive = FALSE; while (iop_eol != *(pp->str.addr + p_offset)) { @@ -132,7 +136,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti else if (width > 0) newtcp.width = width; else - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); @@ -141,62 +145,73 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti else if (length > 0) newtcp.length = length; else - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_listen: newtcp.passive = TRUE; break; case iop_socket: + /* test whether ipv6 socket is supported on local system */ + af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); + if (AF_INET6 == af) + { + test_ipv6_sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP); + if (-1 == test_ipv6_sd) + af = AF_INET; + else + tcp_routines.aa_close(test_ipv6_sd); + } len = *(pp->str.addr + p_offset); - memset(sockaddr, 0, SA_MAXLEN+1); - memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= SA_MAXLEN) ? len : SA_MAXLEN); + memset(sockaddr, 0, SA_MAXLEN + 1); + memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= USR_SA_MAXLITLEN) ? len : USR_SA_MAXLITLEN); *temp_addr = '\0'; *addr = '\0'; port = 0; if (SSCANF(sockaddr, "%[^,], %hu", temp_addr, &port) < 2) { - newtcp.sin.sin_addr.s_addr = INADDR_ANY; if (SSCANF(sockaddr, ",%hu", &port) < 1) { - rts_error(VARLSTCNT(1) ERR_INVPORTSPEC); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return FALSE; } - } else - { - ii = 0; - temp_ch = temp_addr[0]; - while(ISDIGIT_ASCII(temp_ch) || ('.' == temp_ch)) + SERVER_HINTS(hints, af); + port_len = 0; + I2A(port_buffer, port_len, port); + port_buffer[port_len]='\0'; + if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) { - ii++; - temp_ch = temp_addr[ii]; + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); + return FALSE; } + memcpy(&(newtcp.ai), ai_ptr, SIZEOF(*ai_ptr)); + memcpy(&(newtcp.sas), ai_ptr->ai_addr, ai_ptr->ai_addrlen); + freeaddrinfo(ai_ptr); + newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas); - if ('\0' != temp_ch) + } else + { /* client side (connection side) */ + SPRINTF(addr, "%s", temp_addr); + SPRINTF(port_buffer, "%hu", port); + CLIENT_HINTS_AF(hints, af); + if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr))) { - adptr = iotcp_name2ip(temp_addr); - if (NULL == adptr) + if(AF_INET6 == af) { -#if !defined(__hpux) && !defined(__MVS__) - terrptr = HSTRERROR(h_errno); - rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(terrptr)); -#else - /* Grumble grumble HPUX and z/OS don't have hstrerror() */ - rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); -#endif + af = AF_INET; + CLIENT_HINTS_AF(hints, af); + errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr); + } + if(errcode) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return FALSE; } - SPRINTF(addr, "%s", adptr); - } else - SPRINTF(addr, "%s", temp_addr); - - if ((in_addr_t)-1 == (newtcp.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr))) - { - rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); - return FALSE; } + memcpy(&(newtcp.ai), remote_ai_ptr, SIZEOF(struct addrinfo)); + memcpy(&(newtcp.sas), remote_ai_ptr->ai_addr, remote_ai_ptr->ai_addrlen); + newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas); + freeaddrinfo(remote_ai_ptr); } - newtcp.sin.sin_port = GTM_HTONS(port); - newtcp.sin.sin_family = AF_INET; break; case iop_exception: ioptr->error_handler.len = *(pp->str.addr + p_offset); @@ -209,163 +224,114 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } - if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr)) - { - rts_error(VARLSTCNT(1) ERR_SOCKPARMREQ); - return FALSE; - } + /* the previous check if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr)) is no longer needed as + * getaddrinfo() will return error for the above case + */ /* active connection must have a complete address specification */ - if ((INADDR_ANY == newtcp.sin.sin_addr.s_addr) && !newtcp.passive) - { - rts_error(VARLSTCNT(1) ERR_IPADDRREQ); - return FALSE; - } if (dev_closed == ioptr->state) { - if (newtcp.passive) /* passive connection */ + if (newtcp.passive) /* server side */ { /* no listening socket for this addr? make one. */ memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct)); if (!(lsock = iotcp_getlsock(dev))) return FALSE; /* could not create listening socket */ timer_id = (TID)iotcp_open; - out_of_time = FALSE; time_for_read.at_sec = ((0 == timeout) ? 0 : 1); time_for_read.at_usec = 0; - if (NO_M_TIMEOUT == timeout) + while (TRUE) { - timed = FALSE; - msec_timeout = NO_M_TIMEOUT; - } else - { - timed = TRUE; - msec_timeout = timeout2msec(timeout); - if (msec_timeout > 0) - { /* there is time to wait */ - sys_get_curr_time(&cur_time); - add_int_to_abs_time(&cur_time, msec_timeout, &end_time); - start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); + out_of_time = FALSE; + if (NO_M_TIMEOUT == timeout) + { + timed = FALSE; + msec_timeout = NO_M_TIMEOUT; } else - out_of_time = TRUE; - } - for (status = 0; 0 == status; ) - { - FD_ZERO(&tcp_fd); - FD_SET(lsock, &tcp_fd); - /* - * Note: the check for EINTR from the select below should remain, as aa_select is a - * function, and not all callers of aa_select behave the same when EINTR is returned. - */ - lcl_time_for_read = time_for_read; - status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, - &lcl_time_for_read); - if (0 > status) - { - if (EINTR == errno && FALSE == out_of_time) - /* interrupted by a signal which is not OUR timer */ - status = 0; - else - break; - } - if (outofband) - break; - if (timed) { + timed = TRUE; + msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) - { + { /* there is time to wait */ sys_get_curr_time(&cur_time); - cur_time = sub_abs_time(&end_time, &cur_time); - if (cur_time.at_sec <= 0) - { - out_of_time = TRUE; - cancel_timer(timer_id); - break; - } + add_int_to_abs_time(&cur_time, msec_timeout, &end_time); + start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else - break; + out_of_time = TRUE; } - } - if (timed) - { - if (0 != msec_timeout) + for (status = 0; 0 == status; ) { - cancel_timer(timer_id); - if (out_of_time || outofband) - return FALSE; - /*if (outofband) - outofband_action(FALSE);*/ - } - } - if (0 > status) - { - errptr = (char *)STRERROR(errno); - errlen = STRLEN(errptr); - iotcp_rmlsock((io_desc *)dev->iod); - rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); - return FALSE; - } - size = SIZEOF(struct sockaddr_in); - status = tcp_routines.aa_accept(lsock, &peer, &size); - if (-1 == status) - { -#ifdef __hpux - /*ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just - after a SYN before an accept call. Normally this is not fatal and is just a transient state. - Hence exiting just after a single error of this kind should not be done. - So retry in case of HP-UX and ENOBUFS error.*/ - if (ENOBUFS == errno) - { - retry_num = 0; - while (HPUX_MAX_RETRIES > retry_num) + FD_ZERO(&tcp_fd); + FD_SET(lsock, &tcp_fd); + /* + * Note: the check for EINTR from the select below should remain, as aa_select is a + * function, and not all callers of aa_select behave the same when EINTR is returned. + */ + lcl_time_for_read = time_for_read; + status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, + &lcl_time_for_read); + if (0 > status) { - /*In case of succeeding with select in first go, accept will still get 5ms time difference*/ - SHORT_SLEEP(5); - for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++) - { - lcl_time_for_read.at_sec = 0; - lcl_time_for_read.at_usec = HPUX_SEL_TIMEOUT; - FD_ZERO(&tcp_fd); - FD_SET(lsock, &tcp_fd); - status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, - (void *)0, &lcl_time_for_read); - if (0 < status) - break; - else if (outofband) - break; - else - SHORT_SLEEP(5); - } - if (outofband) - return FALSE; - if (0 >= status) - { - errptr = (char *)STRERROR(errno); - errlen = STRLEN(errptr); - iotcp_rmlsock((io_desc *)dev->iod); - rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); - return FALSE; - } - status = tcp_routines.aa_accept(lsock, &peer, &size); - if ((-1 == status) && (ENOBUFS == errno)) - retry_num++; + if (EINTR == errno && FALSE == out_of_time) + /* interrupted by a signal which is not OUR timer */ + status = 0; else break; } + if (outofband) + break; + if (timed) + { + if (msec_timeout > 0) + { + sys_get_curr_time(&cur_time); + cur_time = sub_abs_time(&end_time, &cur_time); + if (cur_time.at_sec <= 0) + { + out_of_time = TRUE; + cancel_timer(timer_id); + break; + } + } else + break; + } } - if (-1 == status) -#endif + if (timed) + { + if (0 != msec_timeout) + { + cancel_timer(timer_id); + if (out_of_time || outofband) + return FALSE; + /*if (outofband) + outofband_action(FALSE);*/ + } + } + if (0 > status) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); iotcp_rmlsock((io_desc *)dev->iod); - rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } + size = SIZEOF(struct sockaddr_storage); + status = tcp_routines.aa_accept(lsock, (struct sockaddr*)&peer_sas, &size); + if (-1 == status) + { +# ifdef __hpux + if (ENOBUFS == errno) + continue; +# endif + errptr = (char *)STRERROR(errno); + errlen = STRLEN(errptr); + iotcp_rmlsock((io_desc *)dev->iod); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); + return FALSE; + } + newtcp.socket = status; + break; } - SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(peer.sin_addr), - GTM_NTOHS(newtcp.sin.sin_port)); - newtcp.socket = status; - } else /* active connection */ + } else /* client side */ { if (NO_M_TIMEOUT != timeout) { @@ -377,14 +343,15 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti temp_1 = 1; do { - if(1 != temp_1) + if (1 != temp_1) tcp_routines.aa_close(newtcp.socket); - newtcp.socket = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); + newtcp.socket = tcp_routines.aa_socket(newtcp.ai.ai_family, newtcp.ai.ai_socktype, + newtcp.ai.ai_protocol); if (-1 == newtcp.socket) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* allow multiple connections to the same IP address */ @@ -393,7 +360,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } size=SIZEOF(newtcp.bufsiz); @@ -402,20 +369,21 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* * Note: the check for EINTR from the connect need not be converted to an EINTR wrapper macro, * since the connect is not retried on EINTR. */ - temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sin, SIZEOF(newtcp.sin)); + temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sas, + newtcp.ai.ai_addrlen); if ((temp_1 < 0) && (ECONNREFUSED != errno) && (EINTR != errno)) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } if ((temp_1 < 0) && (EINTR == errno)) @@ -438,13 +406,6 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti tcp_routines.aa_close(newtcp.socket); return FALSE; } -#ifdef ntohs /* if it's a macro, use it instead of tcp_routines.aa_ntohs */ - SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr), - ntohs(newtcp.sin.sin_port)); -#else - SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr), - tcp_routines.aa_ntohs(newtcp.sin.sin_port)); -#endif } memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct)); ioptr->state = dev_open; diff --git a/sr_port/iotcp_readfl.c b/sr_port/iotcp_readfl.c index 352644b..6bff9ad 100644 --- a/sr_port/iotcp_readfl.c +++ b/sr_port/iotcp_readfl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,6 +41,11 @@ GBLREF spdesc stringpool; GBLREF tcp_library_struct tcp_routines; GBLREF int4 outofband; +error_def(ERR_IOEOF); +error_def(ERR_TEXT); +error_def(ERR_GETSOCKOPTERR); +error_def(ERR_SETSOCKOPTERR); + int iotcp_readfl(mval *v, int4 width, int4 timeout) /* 0 == width is a flag that the caller is read and the length is not actually fixed */ /* timeout in seconds */ @@ -59,11 +64,6 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout) char *errptr; int4 errlen; - error_def(ERR_IOEOF); - error_def(ERR_TEXT); - error_def(ERR_GETSOCKOPTERR); - error_def(ERR_SETSOCKOPTERR); - #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif @@ -114,7 +114,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout) { save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, + LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } FCNTL3(tcpptr->socket, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res); @@ -122,7 +123,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout) { save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } #endif @@ -213,7 +215,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout) { save_errno = errno; errptr = (char *)STRERROR(errno); - rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), save_errno, LEN_AND_STR(errptr)); } errno = real_errno; @@ -252,29 +255,29 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout) if (tcp_routines.aa_select(tcpptr->socket + 1, (void *)(tcpptr->urgent ? &tcp_fd : 0), (void *)0, (void *)(tcpptr->urgent ? 0 : &tcp_fd), &zero) > 0) { - memcpy(tcpptr->dollar_device, "1,", len); + memcpy(io_ptr->dollar.device, "1,", len); if (tcpptr->urgent) { - memcpy(&tcpptr->dollar_device[len], "No ",SIZEOF("No ")); + memcpy(&io_ptr->dollar.device[len], "No ",SIZEOF("No ")); len += SIZEOF("No ") - 1; } - memcpy(&tcpptr->dollar_device[len], "Urgent Data", SIZEOF("Urgent Data")); + memcpy(&io_ptr->dollar.device[len], "Urgent Data", SIZEOF("Urgent Data")); } else */ - memcpy(tcpptr->dollar_device, "0", SIZEOF("0")); + memcpy(io_ptr->dollar.device, "0", SIZEOF("0")); } else { /* there's a significant problem */ if (0 == i) io_ptr->dollar.x = 0; io_ptr->dollar.za = 9; - memcpy(tcpptr->dollar_device, "1,", len); + memcpy(io_ptr->dollar.device, "1,", len); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - memcpy(&tcpptr->dollar_device[len], errptr, errlen); + memcpy(&io_ptr->dollar.device[len], errptr, errlen); if (io_ptr->dollar.zeof || -1 == status || 0 < io_ptr->error_handler.len) { io_ptr->dollar.zeof = TRUE; - rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); } else io_ptr->dollar.zeof = TRUE; } diff --git a/sr_port/iotcp_write.c b/sr_port/iotcp_write.c index 7a301bb..a85ff9d 100644 --- a/sr_port/iotcp_write.c +++ b/sr_port/iotcp_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,9 @@ GBLREF io_pair io_curr_device; GBLREF tcp_library_struct tcp_routines; +error_def(ERR_SOCKWRITE); +error_def(ERR_TEXT); + void iotcp_write(mstr *v) { io_desc *iod; @@ -35,16 +38,13 @@ void iotcp_write(mstr *v) char *errptr; int4 errlen; - error_def(ERR_SOCKWRITE); - error_def(ERR_TEXT); - #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif iod = io_curr_device.out; tcpptr = (d_tcp_struct *)iod->dev_sp; tcpptr->lastop = TCP_WRITE; - memcpy(tcpptr->dollar_device, LITZERO, SIZEOF(LITZERO)); + memcpy(iod->dollar.device, LITZERO, SIZEOF(LITZERO)); inlen = v->len; outlen = iod->width - iod->dollar.x; @@ -59,11 +59,11 @@ void iotcp_write(mstr *v) if ((size = tcp_routines.aa_send(tcpptr->socket, out, outlen, (tcpptr->urgent ? MSG_OOB : 0))) == -1) { iod->dollar.za = 9; - memcpy(tcpptr->dollar_device, LITONE_COMMA, SIZEOF(LITONE_COMMA)); + memcpy(iod->dollar.device, LITONE_COMMA, SIZEOF(LITONE_COMMA)); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); - memcpy(&tcpptr->dollar_device[SIZEOF(LITONE_COMMA) - 1], errptr, errlen); - rts_error(VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); + memcpy(&iod->dollar.device[SIZEOF(LITONE_COMMA) - 1], errptr, errlen); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); } assert(size == outlen); iod->dollar.x += size; diff --git a/sr_port/iotcpdef.h b/sr_port/iotcpdef.h index 9a49a83..f4e97a1 100644 --- a/sr_port/iotcpdef.h +++ b/sr_port/iotcpdef.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,8 @@ #ifndef __IOTCPDEF_H__ #define __IOTCPDEF_H__ #include "gtm_inet.h" +#include "gtm_socket.h" /* for NI_MAXHOST */ +#include "gtm_netdb.h" /* iotcpdef.h UNIX - TCP header file */ #define TCPDEF_WIDTH 255 @@ -21,9 +23,17 @@ #define TCP_WRITE 1 #define TCP_READ 2 -#define SA_MAXLEN 32 /* SIZEOF(123.567.901.345,78901) */ -#define SA_MAXLITLEN 128 /* maximun size of beowulf.sanchez.com */ -#define DD_BUFLEN 80 +#define SA_MAXLEN NI_MAXHOST /* NI_MAXHOST is 1025, large enough to hold any IPV6 address format + * e.g.(123:567:901:345:215:0:0:0) + */ +#define SA_MAXLITLEN NI_MAXHOST /* large enough to hold any host name, e.g. + * host name google: dfw06s16-in-x12.1e100.net + */ +#define USR_SA_MAXLITLEN 128 /* maximum size of host GTM user can specify + * the reason why the number is so small is because the host name size + * is stored as one byte in socket parameter list (refer to iosocket_use) + */ + #ifdef VMS #define VMS_MAX_TCP_IO_SIZE (64 * 1024 - 512) /* Hard limit for TCP send or recv size. On some implementations, the limit is @@ -32,40 +42,34 @@ */ #endif -/*Definitions in case of ENOBUFs error in HPUX*/ -#ifdef __hpux -#define HPUX_MAX_RETRIES 8 -#define HPUX_SEL_TIMEOUT (20 * 1000) /*20 milliseconds(reperesented in micro secs)*/ -#endif - - -#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \ -{ \ - ssize_t gtmioStatus; \ - size_t gtmioBuffLen; \ - size_t gtmioChunk; \ - sm_uc_ptr_t gtmioBuff; \ - gtmioBuffLen = SBUFF_LEN; \ - gtmioBuff = (sm_uc_ptr_t)(SBUFF); \ - for (;;) \ - { \ +#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \ +{ \ + ssize_t gtmioStatus; \ + size_t gtmioBuffLen; \ + size_t gtmioChunk; \ + sm_uc_ptr_t gtmioBuff; \ + \ + gtmioBuffLen = SBUFF_LEN; \ + gtmioBuff = (sm_uc_ptr_t)(SBUFF); \ + for (;;) \ + { \ gtmioChunk = gtmioBuffLen VMS_ONLY(> VMS_MAX_TCP_IO_SIZE ? VMS_MAX_TCP_IO_SIZE : gtmioBuffLen); \ - if ((ssize_t)-1 != (gtmioStatus = tcp_routines.aa_send(SDESC, gtmioBuff, gtmioChunk, SFLAGS))) \ - { \ - gtmioBuffLen -= gtmioStatus; \ - if (0 == gtmioBuffLen) \ - break; \ - gtmioBuff += gtmioStatus; \ - } \ - else if (EINTR != errno) \ - break; \ - } \ - if ((ssize_t)-1 == gtmioStatus) /* Had legitimate error - return it */ \ - RC = errno; \ - else if (0 == gtmioBuffLen) \ - RC = 0; \ - else \ - RC = -1; /* Something kept us from sending what we wanted */ \ + if ((ssize_t)-1 != (gtmioStatus = tcp_routines.aa_send(SDESC, gtmioBuff, gtmioChunk, SFLAGS))) \ + { \ + gtmioBuffLen -= gtmioStatus; \ + if (0 == gtmioBuffLen) \ + break; \ + gtmioBuff += gtmioStatus; \ + } \ + else if (EINTR != errno) \ + break; \ + } \ + if ((ssize_t)-1 == gtmioStatus) /* Had legitimate error - return it */ \ + RC = errno; \ + else if (0 == gtmioBuffLen) \ + RC = 0; \ + else \ + RC = -1; /* Something kept us from sending what we wanted */ \ } /* ***************************************************** */ @@ -75,8 +79,8 @@ typedef struct { char saddr[SA_MAXLEN]; /* socket address */ - char dollar_device[DD_BUFLEN]; - struct sockaddr_in sin; /* socket address + port */ + struct sockaddr_storage sas; /* socket address + port */ + struct addrinfo ai; unsigned char lastop; int bufsiz; /* OS internal buffer size */ int socket; /* socket descriptor */ @@ -84,20 +88,6 @@ typedef struct int4 length; bool passive; /* passive connection */ bool urgent; /* urgent data mode */ -}d_tcp_struct; /* tcp */ - -/* if ntohs/htons are macros, use them, otherwise, use the tcp_routines */ - -#define MAX_DELIM_BUFF 64 -#ifdef ntohs -# define GTM_NTOHS ntohs -#else -# define GTM_NTOHS tcp_routines.aa_ntohs -#endif -#ifdef htons -# define GTM_HTONS htons -#else -# define GTM_HTONS tcp_routines.aa_htons -#endif +} d_tcp_struct; /* tcp */ #endif diff --git a/sr_port/iotcproutine.h b/sr_port/iotcproutine.h index a79763b..1cd0d9a 100644 --- a/sr_port/iotcproutine.h +++ b/sr_port/iotcproutine.h @@ -1,40 +1,30 @@ /**************************************************************** - * * - * Copyright 2001, 2005 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. * - * * - ****************************************************************/ +* * +* Copyright 2001, 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. * +* * +****************************************************************/ /* pointers for tcp/ip routines */ typedef struct { - int (*aa_accept)(); - int (*aa_bind)(); - int (*aa_close)(); - int (*aa_connect)(); - int (*aa_getsockopt)(); + int (*aa_accept)(); + int (*aa_bind)(); + int (*aa_close)(); + int (*aa_connect)(); + int (*aa_getsockopt)(); int (*aa_getsockname)(); - unsigned short (*aa_htons)(in_port_t); -/* smw 1999/12/15 STDC is not a good flag to use so why is it here - perhaps should define in_addr_t somewhere if needed. */ -#if !defined(__STDC__) - uint4 (*aa_inet_addr)(); -#else - in_addr_t (*aa_inet_addr)(const char *); -#endif - char *(*aa_inet_ntoa)(); - unsigned short (*aa_ntohs)(in_port_t); - int (*aa_listen)(); - int (*aa_recv)(); - int (*aa_select)(); - int (*aa_send)(); - int (*aa_setsockopt)(); - int (*aa_shutdown)(); - int (*aa_socket)(); - bool using_tcpware; /* use tcpware(1) or ucx(0) */ + int (*aa_listen)(); + int (*aa_recv)(); + int (*aa_select)(); + int (*aa_send)(); + int (*aa_setsockopt)(); + int (*aa_shutdown)(); + int (*aa_socket)(); + bool using_tcpware; /* use tcpware(1) or ucx(0) */ }tcp_library_struct; diff --git a/sr_port/jmp_opto.c b/sr_port/jmp_opto.c index 9ea2a47..6ca8b3f 100644 --- a/sr_port/jmp_opto.c +++ b/sr_port/jmp_opto.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,6 @@ #include "mdef.h" #include "gtm_stdio.h" - #include "compiler.h" #include "opcode.h" #include "mdq.h" @@ -20,25 +19,26 @@ #include "gtmdbglvl.h" #include "cdbg_dump.h" -#define JOPT_NO_OPT 1 -#define JOPT_REP_JMP 2 -#define JOPT_REF_NXT_TRP 3 - -#define PTR_NOT_DEFINED 0 -#define IND_NOT_DEFINED ((unsigned char)-2) -#define NO_ENTRY ((unsigned char)-1) - -#define NUM_JO_TBL_ELE 11 -typedef struct -{ unsigned int opcode; - unsigned int index; - unsigned int opto_flag[NUM_JO_TBL_ELE]; -}jump_opto_struct; - LITREF octabstruct oc_tab[]; /* op-code table */ GBLREF triple t_orig; /* head of triples */ GBLREF uint4 gtmDebugLevel; -const static readonly jump_opto_struct jump_opto_table[NUM_JO_TBL_ELE] = + +#define IND_NOT_DEFINED ((unsigned char)-2) +#define JOPT_NO_OPT 1 +#define JOPT_REP_JMP 2 +#define JOPT_REF_NXT_TRP 3 +#define NO_ENTRY ((unsigned char)-1) +#define NUM_JO_TBL_ELE 11 +#define PTR_NOT_DEFINED 0 + +typedef struct +{ + unsigned int opcode; + unsigned int index; + unsigned int opto_flag[NUM_JO_TBL_ELE]; +} jump_opto_struct; + +LITDEF readonly jump_opto_struct jump_opto_table[NUM_JO_TBL_ELE] = { { OC_JMP, /* opcode */ 0, /* index */ @@ -162,10 +162,12 @@ const static readonly jump_opto_struct jump_opto_table[NUM_JO_TBL_ELE] = } } }; -static unsigned int *jo_ptr_ray[OPCODE_COUNT]; -static unsigned int jo_ind_ray[OPCODE_COUNT]; +STATICDEF unsigned int *jo_ptr_ray[OPCODE_COUNT]; +STATICDEF unsigned int jo_ind_ray[OPCODE_COUNT]; -static void jo_get_ptrs(unsigned int op) +STATICFNDCL void jo_get_ptrs(unsigned int op); + +STATICFNDEF void jo_get_ptrs(unsigned int op) { const jump_opto_struct *j, *j_top; @@ -182,7 +184,7 @@ static void jo_get_ptrs(unsigned int op) jo_ptr_ray[op] = (unsigned int *)NO_ENTRY; } -const static readonly oprtype null_operand; +STATICDEF const readonly oprtype null_operand; /************************************************************************************************************ NOTE: We may which to modify the lookup method at some point in the future. B. Shear suggests nested switch @@ -191,9 +193,9 @@ const static readonly oprtype null_operand; void jmp_opto(void) { - unsigned int i, *p, **clrp1, **clrtop1, *clrp2, *clrtop2; + unsigned int **clrp1, *clrp2, **clrtop1, *clrtop2, i, *p; tbp *b; - triple *cur_trip, *terminal_trip, *ref_trip, *jump_trip, *next_trip, *ct; + triple *ct, *cur_trip, *jump_trip, *next_trip, *ref_trip, *terminal_trip; void get_jo_ptrs(); # ifdef DEBUG @@ -205,33 +207,48 @@ void jmp_opto(void) PRINTF(" \n\n\n\n************************************ Begin jmp_opto scan *****************************\n"); } # endif - for (clrp1 = &jo_ptr_ray[0], clrtop1 = clrp1 + OPCODE_COUNT; clrp1 < clrtop1; clrp1++) *clrp1 = (unsigned int *)NO_ENTRY; for (clrp2 = &jo_ind_ray[0], clrtop2 = clrp2 + OPCODE_COUNT; clrp2 < clrtop2; clrp2++) *clrp2 = NO_ENTRY; - dqloop(&t_orig, exorder, cur_trip) { if (OC_GVSAVTARG == cur_trip->opcode) - { + { /* Look for an adjacent and therefore superfluous GVRECTARG */ for (next_trip = cur_trip->exorder.fl; oc_tab[next_trip->opcode].octype & OCT_CGSKIP; next_trip = next_trip->exorder.fl) ; - - if (OC_GVRECTARG == next_trip->opcode - && next_trip->operand[0].oprval.tref == cur_trip - && next_trip->jmplist.que.fl == &(next_trip->jmplist)) + if ((OC_GVRECTARG == next_trip->opcode) + && (next_trip->operand[0].oprval.tref == cur_trip) + && (next_trip->jmplist.que.fl == &(next_trip->jmplist))) { COMPDBG(PRINTF("jmp_opto: NOOPing OC_GVRECTARG opcode at triple addres 0x"lvaddr"\n", next_trip);); next_trip->opcode = OC_NOOP; - next_trip->operand[0].oprclass = next_trip->operand[1].oprclass = 0; + next_trip->operand[0].oprclass = next_trip->operand[1].oprclass = NO_REF; + cur_trip = cur_trip->exorder.bl; /* in case there are more than one in a row */ } continue; } - if ((oc_tab[cur_trip->opcode].octype & OCT_JUMP) && - (OC_CALL != cur_trip->opcode) && (OC_CALLSP != cur_trip->opcode)) + if (OC_GVRECTARG == cur_trip->opcode) + { /* Look for a second effectively adjacent GVRECTARG that duplicates this one */ + for (next_trip = cur_trip->exorder.fl; + oc_tab[next_trip->opcode].octype & OCT_CGSKIP; + next_trip = next_trip->exorder.fl) + ; + if ((OC_GVRECTARG == next_trip->opcode) + && (next_trip->operand[0].oprval.tref == cur_trip->operand[0].oprval.tref) + && (next_trip->jmplist.que.fl == &(next_trip->jmplist))) + { + COMPDBG(PRINTF("jmp_opto: NOOPing OC_GVRECTARG opcode at triple addres 0x"lvaddr"\n", next_trip);); + next_trip->opcode = OC_NOOP; + next_trip->operand[0].oprclass = next_trip->operand[1].oprclass = NO_REF; + cur_trip = cur_trip->exorder.bl; /* in case there are more than one in a row */ + } + continue; + } + if ((oc_tab[cur_trip->opcode].octype & OCT_JUMP) + && (OC_CALL != cur_trip->opcode) && (OC_CALLSP != cur_trip->opcode)) { assert(OPCODE_COUNT > cur_trip->opcode); if (PTR_NOT_DEFINED == (p = jo_ptr_ray[cur_trip->opcode])) /* note assignment */ @@ -246,7 +263,6 @@ void jmp_opto(void) jo_get_ptrs(jump_trip->opcode); i = jo_ind_ray[jump_trip->opcode]; } - while ((IND_NOT_DEFINED != i) && (NO_ENTRY != i)) { switch(p[i]) @@ -266,7 +282,6 @@ void jmp_opto(void) } } dqins(&jump_trip->exorder.fl->jmplist, que, b); - cur_trip->operand[0].oprval.tref = jump_trip->exorder.fl; jump_trip = cur_trip->operand[0].oprval.tref; if (IND_NOT_DEFINED == (i = jo_ind_ray[jump_trip->opcode])) /* assignmnt */ @@ -292,7 +307,6 @@ void jmp_opto(void) } } dqins(&jump_trip->operand[0].oprval.tref->jmplist, que, b); - cur_trip->operand[0] = jump_trip->operand[0]; jump_trip = cur_trip->operand[0].oprval.tref; if (IND_NOT_DEFINED == (i = jo_ind_ray[jump_trip->opcode])) /* assgnmnt */ @@ -310,7 +324,6 @@ void jmp_opto(void) break; } /* switch */ } /* while */ - terminal_trip = cur_trip->exorder.fl; while ((oc_tab[cur_trip->opcode].octype & OCT_JUMP) && (OC_CALL != cur_trip->opcode) && (OC_CALLSP != cur_trip->opcode) @@ -320,7 +333,6 @@ void jmp_opto(void) (oc_tab[ref_trip->opcode].octype & OCT_CGSKIP); (ref_trip = ref_trip->exorder.fl)) ; - if (ref_trip == terminal_trip) { cur_trip->opcode = OC_NOOP; @@ -333,7 +345,6 @@ void jmp_opto(void) cur_trip = terminal_trip->exorder.bl; } /* if */ } /* dqloop */ - # ifdef DEBUG /* If debug and compiler debugging is enabled, run through the triples again to show what we * have done to them.. diff --git a/sr_port/jnl.h b/sr_port/jnl.h index 9c030c2..cce76cc 100644 --- a/sr_port/jnl.h +++ b/sr_port/jnl.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -52,8 +52,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 "GDSJNL22" /* see above comment paragraph for todos whenever this is changed */ -#define JNL_VER_THIS 22 +#define JNL_LABEL_TEXT "GDSJNL23" /* see above comment paragraph for todos whenever this is changed */ +#define JNL_VER_THIS 23 #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 @@ -64,22 +64,28 @@ error_def(ERR_JNLENDIANLITTLE); * sent through the replication pipe and never seen by filter routines. */ #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/GDSJNL22 that can be input to replication filter */ -#define JRT_MAX_V22 JRT_UZTRIG /* Max jnlrec type in GDSJNL22 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. * 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 ALIGN_KEY 0xdeadbeef #ifdef UNIX -#define JNL_ALLOC_DEF 2048 -#define JNL_ALLOC_MIN 200 +# define JNL_ALLOC_DEF 2048 +# define JNL_ALLOC_MIN 2048 #elif defined(VMS) -#define JNL_ALLOC_DEF 100 -#define JNL_ALLOC_MIN 10 +# define JNL_ALLOC_DEF 100 +# define JNL_ALLOC_MIN 10 #endif -/* JNL_BUFFER_MIN database block size / 512 + 1 */ +#ifdef UNIX +/* The journal buffer size (specified in pages of size DISK_BLOCK_SIZE) should be large enough for one largest record, + * which is equivalent to the largest possible value (of size MAX_STRLEN) and largest possible key (of size MAX_KEY_SZ), + * plus the overhead of storing the journal records. + */ +# define JNL_BUFFER_MIN ((MAX_LOGI_JNL_REC_SIZE + ROUND_UP(2 * MAX_IO_BLOCK_SIZE, DISK_BLOCK_SIZE)) / DISK_BLOCK_SIZE + 1) +#endif #define JNL_BUFFER_MAX 32768 /* # of 512-byte blocks = 16Mb journal buffer size */ /* JNL_EXTEND_DEF allocation size / 10 @@ -89,11 +95,11 @@ error_def(ERR_JNLENDIANLITTLE); #define JNL_EXTEND_MIN 0 #ifdef UNIX -#define JNL_EXTEND_DEF 2048 -#define JNL_EXTEND_MAX 1073741823 +# define JNL_EXTEND_DEF 2048 +# define JNL_EXTEND_MAX 1073741823 #else -#define JNL_EXTEND_DEF 100 -#define JNL_EXTEND_MAX 65535 +# define JNL_EXTEND_DEF 100 +# define JNL_EXTEND_MAX 65535 #endif #define JNL_MIN_WRITE 32768 #define JNL_MAX_WRITE 65536 @@ -105,26 +111,37 @@ error_def(ERR_JNLENDIANLITTLE); * In VMS, the writes are at 512-byte boundaries only. */ #ifdef UNIX -# define JNL_WRT_START_MODULUS(jb) jb->fs_block_size +# define JNL_WRT_START_MODULUS(jb) jb->fs_block_size #elif defined(VMS) -# define JNL_WRT_START_MODULUS(jb) 512 +# define JNL_WRT_START_MODULUS(jb) 512 #endif -#define JNL_WRT_START_MASK(jb) ~(JNL_WRT_START_MODULUS(jb) - 1) +#define JNL_WRT_START_MASK(jb) ~(JNL_WRT_START_MODULUS(jb) - 1) /* mask defining where the next physical write needs to + * happen as follows from the size of JNL_WRT_START_MODULUS + */ #define JNL_WRT_END_MODULUS 8 #define JNL_WRT_END_MASK ~(JNL_WRT_END_MODULUS - 1) #ifdef UNIX -#define JNL_MIN_ALIGNSIZE (1 << 8) /* 256 disk blocks effectively 128K alignsize */ -#define JNL_DEF_ALIGNSIZE (1 << 11) /* 2048 disk blocks effectively 1M alignsize */ +# define JNL_MIN_ALIGNSIZE (1 << 12) /* 4096 disk blocks effectively 2M alignsize */ +# define JNL_DEF_ALIGNSIZE (1 << 12) /* 4096 disk blocks effectively 2M alignsize */ #else -#define JNL_MIN_ALIGNSIZE (1 << 5) /* 32 disk blocks effectively 16K alignsize */ -#define JNL_DEF_ALIGNSIZE (1 << 7) /* 128 disk blocks effectively 64K alignsize */ +# define JNL_MIN_ALIGNSIZE (1 << 5) /* 32 disk blocks effectively 16K alignsize */ +# define JNL_DEF_ALIGNSIZE (1 << 7) /* 128 disk blocks effectively 64K alignsize */ #endif #define JNL_MAX_ALIGNSIZE (1 << 22) /* 4194304 disk blocks effectively 2G alignsize */ #define JNL_REC_START_BNDRY 8 -#define MAX_LOGI_JNL_REC_SIZE (MAX_DB_BLK_SIZE) /* maximum logical journal record size */ -#define MAX_JNL_REC_SIZE (MAX_LOGI_JNL_REC_SIZE + DISK_BLOCK_SIZE) /* one more disk-block for PBLK record header/footer */ +#ifdef UNIX +/* maximum logical journal record size */ +# define MAX_LOGI_JNL_REC_SIZE (ROUND_UP(MAX_STRLEN, DISK_BLOCK_SIZE) + ROUND_UP(MAX_KEY_SZ, DISK_BLOCK_SIZE)) +#else +# define MAX_LOGI_JNL_REC_SIZE (MAX_DB_BLK_SIZE) /* maximum logical journal record size */ +#endif +/* one more disk-block for PBLK record header/footer */ +#define MAX_JNL_REC_SIZE (MAX_LOGI_JNL_REC_SIZE + DISK_BLOCK_SIZE) +/* Very large records require spanning nodes, which only happen in TP. */ +#define MAX_NONTP_JNL_REC_SIZE(BSIZE) ((BSIZE) + DISK_BLOCK_SIZE) +#define MAX_MAX_NONTP_JNL_REC_SIZE MAX_NONTP_JNL_REC_SIZE(MAX_DB_BLK_SIZE) #ifdef GTM_TRIGGER /* Define maximum size that $ZTWORMHOLE can be. Since $ZTWORMHOLE should be able to fit in a journal record and the @@ -143,8 +160,8 @@ error_def(ERR_JNLENDIANLITTLE); #define DEFAULT_YIELD_LIMIT 8 #ifdef UNIX -/* Have a minimum jnl-file-auto-switch-limit of 16 align boundaries (currently each align boundary is 128K) */ -#define JNL_AUTOSWITCHLIMIT_MIN (16 * JNL_MIN_ALIGNSIZE) +/* Have a minimum jnl-file-auto-switch-limit of 4 align boundaries (currently each align boundary is 2M) */ +#define JNL_AUTOSWITCHLIMIT_MIN (4 * JNL_MIN_ALIGNSIZE) #define JNL_AUTOSWITCHLIMIT_DEF 8386560 /* Instead of 8388607 it is adjusted for default allocation = extension = 2048 */ #else /* Have a minimum jnl-file-auto-switch-limit of 128 align boundaries (currently each align boundary is 16K) */ @@ -160,6 +177,10 @@ error_def(ERR_JNLENDIANLITTLE); #define WCSFLU_FSYNC_DB 8 /* Currently used only in Unix wcs_flu() */ #define WCSFLU_IN_COMMIT 16 /* Set if caller is t_end or tp_tend. See wcs_flu for explanation of when this is set */ #define WCSFLU_MSYNC_DB 32 /* Force a full msync if NO_MSYNC is defined. Currently used only in Unix wcs_flu(). */ +#define WCSFLU_SPEEDUP_NOBEFORE 64 /* Do not flush dirty db buffers. Just write an epoch record. + * Used to speedup nobefore jnl for Unix. Flag ignored in VMS. + */ +#define WCSFLU_CLEAN_DBSYNC 128 /* wcs_flu invoked by wcs_clean_dbsync (as opposed to t_end/tp_tend invocation) */ /* options for error_on_jnl_file_lost */ #define JNL_FILE_LOST_TURN_OFF 0 /* Turn off journaling. */ @@ -408,7 +429,10 @@ typedef struct volatile int4 free; /* relative index of first byte to write in buffer */ volatile uint4 freeaddr, /* virtual on-disk address which will correspond to free, when it is written */ end_of_data, /* Synched offset updated by jnl_write_epoch. Used by recover/rollback */ - filesize; /* highest virtual address available in the file (units in disk-blocks) */ + filesize; /* highest virtual address available in the file (units in disk-blocks) + * file size in bytes limited to 4GB by autoswitchlimit, so 'filesize' <= 8MB + * so filesize cannot overflow the four bytes of a uint4 + */ /* end mainline QUAD */ volatile int4 blocked; volatile uint4 fsync_dskaddr; /* dskaddr upto which fsync is done */ @@ -682,6 +706,7 @@ typedef struct uint4 total_blks; /* total blocks counter at time of epoch */ uint4 is_encrypted; char encryption_hash[GTMCRYPT_HASH_LEN]; + sgmnt_addrs *csa; } jnl_create_info; /* Journal record definitions */ @@ -739,13 +764,13 @@ typedef struct jnl_format_buff_struct # endif enum jnl_record_type rectype; int4 record_size; + int4 hi_water_bsize; char *buff; uint4 checksum; jnl_action ja; # ifdef GTM_CRYPT char *alt_buff; /* for storing the unencrypted jnl *SET and *KILL records to be pushed * into the jnl pool. */ - NON_GTM64_ONLY(int4 dummy_filler;) /* for alignment in 32 bit machines. */ # endif } jnl_format_buffer; @@ -984,6 +1009,21 @@ typedef union #define MIN_JNLREC_SIZE (JREC_PREFIX_SIZE + JREC_SUFFIX_SIZE) #define JREC_PREFIX_UPTO_LEN_SIZE (offsetof(jrec_prefix, pini_addr)) +/* JNL_FILE_TAIL_PRESERVE macro indicates maximum number of bytes to ensure allocated at the end of the journal file + * to store the journal records that will be written whenever the journal file gets closed. + * (i) Any process closing the journal file needs to write at most one PINI, one EPOCH, one PFIN and one EOF record + * In case of wcs_recover extra INCTN will be written + * (ii) We may need to give room for twice the above space to accommodate the EOF writing by a process that closes the journal + * and the EOF writing by the first process that reopens it and finds no space left and switches to a new journal. + * (iii) We may need to write one ALIGN record at the most since the total calculated from (i) and (ii) above is + * less than the minimum alignsize that we support (asserted before using JNL_FILE_TAIL_PRESERVE in macros below) + * The variable portion of this ALIGN record can get at the most equal to the maximum of the sizes of the + * PINI/EPOCH/PFIN/EOF record. We know PINI_RECLEN is maximum of EPOCH_RECLEN, PFIN_RECLEN, EOF_RECLEN (this + * is in fact asserted in gvcst_init.c). + */ +#define JNL_FILE_TAIL_PRESERVE (MIN_ALIGN_RECLEN + (PINI_RECLEN + EPOCH_RECLEN + INCTN_RECLEN + \ + PFIN_RECLEN + EOF_RECLEN) * 2 + PINI_RECLEN) + typedef struct set_jnl_options_struct { int cli_journal, cli_enable, cli_on, cli_replic_on; @@ -1095,6 +1135,8 @@ typedef struct # ifdef UNIX boolean_t onlnrlbk; /* TRUE if ONLINE ROLLBACK */ # endif + boolean_t mur_extract; /* a copy of mur_options.extr[0] to be accessible to GTM runtime*/ + boolean_t save_dont_reset_gbl_jrec_time; /* save a copy of dont_reset_gbl_jrec_time */ } jnl_gbls_t; @@ -1175,10 +1217,11 @@ typedef struct * But to write it out, we should have it already built before bg_update(). * Hence, we pre-build the block here itself before invoking t_end(). */ -#define BUILD_AIMG_IF_JNL_ENABLED(CSD, JFB, TN) \ +#define BUILD_AIMG_IF_JNL_ENABLED(CSD, TN) \ { \ GBLREF cw_set_element cw_set[]; \ GBLREF unsigned char cw_set_depth; \ + GBLREF jnl_format_buffer *non_tp_jfb_ptr; \ \ cw_set_element *cse; \ \ @@ -1186,7 +1229,7 @@ typedef struct { \ assert(1 == cw_set_depth); /* Only DSE uses this macro and it updates one block at a time */ \ cse = (cw_set_element *)(&cw_set[0]); \ - cse->new_buff = JFB; \ + cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; \ gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, TN); \ cse->done = TRUE; \ } \ @@ -1201,9 +1244,9 @@ typedef struct */ #define REAL_JNL_HDR_LEN SIZEOF(jnl_file_header) #ifdef UNIX -# define JNL_HDR_LEN 64*1024 +# define JNL_HDR_LEN 64 * 1024 #elif defined(VMS) -# define JNL_HDR_LEN REAL_JNL_HDR_LEN +# define JNL_HDR_LEN REAL_JNL_HDR_LEN #endif #define JNL_FILE_FIRST_RECORD JNL_HDR_LEN @@ -1265,19 +1308,19 @@ typedef struct #define ASSERT_JNLFILEID_NOT_NULL(csa) assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))); #define NULLIFY_JNL_FILE_ID(csa) memset(&csa->nl->jnl_file.jnl_file_id, 0, SIZEOF(gds_file_id)) #endif -#define JNL_INIT(csa, reg, csd) \ -{ \ - csa->jnl_state = csd->jnl_state; \ - csa->jnl_before_image = csd->jnl_before_image; \ - csa->repl_state = csd->repl_state; \ - if JNL_ALLOWED(csa) \ - { \ - JPC_ALLOC(csa); \ - csa->jnl->region = reg; \ - csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE); \ - csa->jnl->channel = NOJNL; \ - } else \ - csa->jnl = NULL; \ +#define JNL_INIT(csa, reg, csd) \ +{ \ + csa->jnl_state = csd->jnl_state; \ + csa->jnl_before_image = csd->jnl_before_image; \ + csa->repl_state = csd->repl_state; \ + if JNL_ALLOWED(csa) \ + { \ + JPC_ALLOC(csa); \ + csa->jnl->region = reg; \ + csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE); \ + csa->jnl->channel = NOJNL; \ + } else \ + csa->jnl = NULL; \ } #define JNL_FD_CLOSE(CHANNEL, RC) \ { \ @@ -1302,10 +1345,19 @@ typedef struct #define REC_JNL_SEQNO(jnlrec) ((struct_jrec_upd *)jnlrec)->token_seq.jnl_seqno #define REC_LEN_FROM_SUFFIX(ptr, reclen) ((jrec_suffix *)((unsigned char *)ptr + reclen - JREC_SUFFIX_SIZE))->backptr -#define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2(FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE \ +/* The below macro now relies on MAX_STRLEN value rather than on CSD->blk_size used previously because + * with nodes spanning blocks journal records might be comprised of several blocks, with the limit of + * MAX_STRLEN for the actual database record. + */ +#ifdef UNIX +# define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2((FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE) + MAX_STRLEN + \ + SIZEOF(jnl_str_len_t) + SIZEOF(mstr_len_t), JNL_REC_START_BNDRY) +#else +# define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2(FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE \ + ((CSD)->blk_size - SIZEOF(blk_hdr) - SIZEOF(rec_hdr)) \ + SIZEOF(jnl_str_len_t) + SIZEOF(mstr_len_t), JNL_REC_START_BNDRY) \ /* fixed size part of update record + MAX possible (key + data) len + keylen-len + datalen-len */ +#endif #define JNL_MAX_PBLK_RECLEN(CSD) (uint4)ROUND_UP2(MIN_PBLK_RECLEN + (CSD)->blk_size, JNL_REC_START_BNDRY) @@ -1317,16 +1369,16 @@ typedef struct */ #define JNL_MAX_RECLEN(JINFO, CSD) \ { \ - int4 max_logi_reclen, max_pblk_reclen; \ - \ - /* A logical record is a SET/KILL record. The SET could be as big as (CSD)->max_rec_size, but since \ + /* This macro used to compare the value returned from JNL_MAX_SET_KILL_RECLEN with that from \ + * JNL_MAX_PBLK_RECLEN and, in case of triggers, MAX_ZTWORK_JREC_LEN. However, in the current design \ + * max_logi_reclen includes MAX_STR_LEN as one of its summants, thus always exceeding both \ + * MAX_ZTWORK_JREC_LEN and JNL_MAX_PBLK_RECLEN. \ + * \ + * A logical record is a SET/KILL record. The SET could be as big as (CSD)->max_rec_size, but since \ * csd->max_rec_size can be changed independent of journal file creation (through DSE), we consider \ - * the max possible record size that can fit in a GDS block. After that we consider $ZTWORMHOLE too. \ + * the max possible record size that can be ever produced. \ */ \ - max_logi_reclen = JNL_MAX_SET_KILL_RECLEN(CSD); \ - GTMTRIG_ONLY(max_logi_reclen = MAX(max_logi_reclen, MAX_ZTWORM_JREC_LEN);) \ - max_pblk_reclen = JNL_MAX_PBLK_RECLEN(CSD); \ - (JINFO)->max_jrec_len = MAX(max_logi_reclen, max_pblk_reclen) + MIN_ALIGN_RECLEN; \ + (JINFO)->max_jrec_len = JNL_MAX_SET_KILL_RECLEN(CSD) + MIN_ALIGN_RECLEN; \ } /* Macro that checks that the region seqno in the filehdr is never more than the seqno in the journal pool */ @@ -1337,7 +1389,7 @@ typedef struct assert((NULL == jnlpool_ctl) || (csd->reg_seqno <= (jnlpool_ctl->jnl_seqno + 1))); \ } #ifdef GTM_CRYPT -#define DECODE_SET_KILL_ZKILL_ZTRIG(mumps_node_ptr, rec_size, key_handle, RC) \ +# define MUR_DECRYPT_LOGICAL_RECS(MUMPS_NODE_PTR, REC_SIZE, KEY_HANDLE, RC) \ { \ int span_length, fixed_prefix; \ \ @@ -1345,11 +1397,54 @@ typedef struct assert(FIXED_UPD_RECLEN == FIXED_ZTWORM_RECLEN); \ fixed_prefix = FIXED_UPD_RECLEN; \ ASSERT_ENCRYPTION_INITIALIZED; \ - span_length = rec_size - fixed_prefix - JREC_SUFFIX_SIZE; \ - GTMCRYPT_DECODE_FAST(key_handle, (char *)mumps_node_ptr, span_length, NULL, RC); \ + span_length = REC_SIZE - fixed_prefix - JREC_SUFFIX_SIZE; \ + GTMCRYPT_DECRYPT(NULL, KEY_HANDLE, (char *)MUMPS_NODE_PTR, span_length, NULL, RC); \ +} +#endif + +/* The following define an appendix message, used along with JNLBUFFREGUPD and JNLBUFFDBUPD messages in + * various places, as well as its length, allowing for six digits for both lower and upper journal buffer + * size limits, even though neither is expected to have more than five in the near future. */ +#define JNLBUFFUPDAPNDX "The previous value was outside the allowable range of %d to %d" +#define JNLBUFFUPDAPNDX_SIZE (SIZEOF(JNLBUFFUPDAPNDX) - 4 + (2 * 6)) + +/* Yields a portable value for the minimum journal buffer size */ +#define JNL_BUFF_PORT_MIN(CSD) (UNIX_ONLY(JNL_BUFFER_MIN) VMS_ONLY(CSD->blk_size / DISK_BLOCK_SIZE + 1)) + +/* Defines the increment value for journal buffer size's rounding-up */ +#define JNL_BUFF_ROUND_UP_STEP(CSD) (UNIX_ONLY(MIN(MAX_IO_BLOCK_SIZE, CSD->blk_size)) VMS_ONLY(CSD->blk_size) / DISK_BLOCK_SIZE) + +/* Rounds up the passed journal buffer value and assigns it to the specified variable */ +#define ROUND_UP_JNL_BUFF_SIZE(DEST, VALUE, CSD) \ +{ \ + DEST = ROUND_UP(VALUE, JNL_BUFF_ROUND_UP_STEP(CSD)); \ } -#endif /* GTM_CRYPT */ +/* Rounds up the minimum journal buffer value and assigns it to the specified variable */ +#define ROUND_UP_MIN_JNL_BUFF_SIZE(DEST, CSD) \ +{ \ + DEST = ROUND_UP(JNL_BUFF_PORT_MIN(CSD), JNL_BUFF_ROUND_UP_STEP(CSD)); \ +} + +/* Rounds down the maximum journal buffer value and assigns it to the specified variable */ +#define ROUND_DOWN_MAX_JNL_BUFF_SIZE(DEST, CSD) \ +{ \ + int jnl_buffer_adj_value, jnl_buffer_decr_step; \ + \ + jnl_buffer_decr_step = JNL_BUFF_ROUND_UP_STEP(CSD); \ + jnl_buffer_adj_value = ROUND_UP(JNL_BUFFER_MAX, jnl_buffer_decr_step); \ + while (JNL_BUFFER_MAX < jnl_buffer_adj_value) \ + jnl_buffer_adj_value -= jnl_buffer_decr_step; \ + DEST = jnl_buffer_adj_value; \ +} + +#ifdef UNIX +# define CURRENT_JNL_IO_WRITER(JB) JB->io_in_prog_latch.u.parts.latch_pid +# define CURRENT_JNL_FSYNC_WRITER(JB) JB->fsync_in_prog_latch.u.parts.latch_pid +#else +# define CURRENT_JNL_IO_WRITER(JB) JB->now_writer +#endif + /* jnl_ prototypes */ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size); uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat); @@ -1364,8 +1459,8 @@ uint4 jnl_ensure_open(void); void set_jnl_info(gd_region *reg, jnl_create_info *set_jnl_info); void jnl_write_epoch_rec(sgmnt_addrs *csa); void jnl_write_inctn_rec(sgmnt_addrs *csa); -void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb); -void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb); +void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum); +void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum); void jnl_write_eof_rec(sgmnt_addrs *csa, struct_jrec_eof *eof_record); void jnl_write_trunc_rec(sgmnt_addrs *csa, uint4 orig_total_blks, uint4 orig_free_blocks, uint4 total_blks_after_trunc); void jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, jnl_format_buffer *jfb); @@ -1392,8 +1487,8 @@ void mupip_set_journal_fname(jnl_create_info *jnl_info); uint4 mupip_set_jnlfile_aux(jnl_file_header *header, char *jnl_fname); void jnl_extr_init(void); int exttime(uint4 time, char *buffer, int extract_len); -char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec); -char *ext2jnl(char *ptr, jnl_record *rec); +char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno); +char *ext2jnl(char *ptr, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno); char *jnl2extcvt(jnl_record *rec, int4 jnl_len, char *ext_buff); char *jnl2ext(char *jnl_buff, char *ext_buff); diff --git a/sr_port/jnl_file_close.c b/sr_port/jnl_file_close.c index 21d0f8c..46cb49f 100644 --- a/sr_port/jnl_file_close.c +++ b/sr_port/jnl_file_close.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,6 +23,7 @@ #include "performcaslatchcheck.h" #include "wcs_sleep.h" #include "gt_timer.h" +#include "wbox_test_init.h" #elif defined(VMS) #include #include @@ -47,6 +48,7 @@ #include "ccp.h" #include "send_msg.h" #include "eintr_wrappers.h" +#include "anticipatory_freeze.h" #ifdef UNIX #include "wcs_clean_dbsync.h" @@ -57,9 +59,7 @@ GBLREF short astq_dyn_avail; static const unsigned short zero_fid[3]; #endif -#ifdef UNIX GBLREF jnl_gbls_t jgbl; -#endif error_def(ERR_JNLCLOSE); error_def(ERR_JNLFLUSH); @@ -109,14 +109,15 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy) header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size)); if (clean) { - jnl_write_eof_rec(csa, &eof_record); + if(!jgbl.mur_extract) + jnl_write_eof_rec(csa, &eof_record); if (SS_NORMAL != (jpc->status = jnl_flush(reg))) { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"), jpc->status); assert(FALSE); - rts_error(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"), jpc->status); } @@ -129,13 +130,16 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy) DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SYSCALL_SUCCESS(jpc->status)) { - assert(header->end_of_data <= eof_addr); - header->end_of_data = eof_addr; - header->eov_timestamp = eof_record.prefix.time; - assert(header->eov_timestamp >= header->bov_timestamp); - header->eov_tn = eof_record.prefix.tn; - assert(header->eov_tn >= header->bov_tn); - header->end_seqno = eof_record.jnl_seqno; + if(!jgbl.mur_extract) + { + assert(header->end_of_data <= eof_addr); + header->end_of_data = eof_addr; + header->eov_timestamp = eof_record.prefix.time; + assert(header->eov_timestamp >= header->bov_timestamp); + header->eov_tn = eof_record.prefix.tn; + assert(header->eov_tn >= header->bov_tn); + header->end_seqno = eof_record.jnl_seqno; + } # ifdef UNIX for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) header->strm_end_seqno[idx] = csd->strm_reg_seqno[idx]; @@ -145,21 +149,22 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy) } # endif header->crash = FALSE; - DO_FILE_WRITE(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); + JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, + 0, header, read_write_size, jpc->status, jpc->status2); if (SYSCALL_ERROR(jpc->status)) { assert(FALSE); - rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status); } UNIX_ONLY( - GTM_FSYNC(jpc->channel, rc); + GTM_JNL_FSYNC(csa, jpc->channel, rc); if (-1 == rc) { save_errno = errno; - send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno); assert(FALSE); - rts_error(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno); } ) @@ -173,13 +178,16 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy) jb->cycle++; /* increment shared cycle so all future callers of jnl_ensure_open recognize journal switch */ } JNL_FD_CLOSE(jpc->channel, rc); /* sets jpc->channel to NOJNL */ +#ifdef UNIX + GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_JNLCLOSE, rc, EIO); +#endif jpc->cycle--; /* decrement cycle so jnl_ensure_open() knows to reopen the journal */ VMS_ONLY(jpc->qio_active = FALSE;) jpc->pini_addr = 0; - if (clean && (SS_NORMAL != jpc->status)) + if (clean && (SS_NORMAL != jpc->status || SS_NORMAL != rc)) { status = jpc->status; /* jnl_send_oper resets jpc->status, so save it */ jnl_send_oper(jpc, ERR_JNLCLOSE); - rts_error(VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status); } } diff --git a/sr_port/jnl_file_lost.c b/sr_port/jnl_file_lost.c index de8c029..41d348b 100644 --- a/sr_port/jnl_file_lost.c +++ b/sr_port/jnl_file_lost.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,12 +34,20 @@ #include "send_msg.h" #include "repl_msg.h" #include "gtmsource.h" +#ifdef UNIX +#include "anticipatory_freeze.h" +#endif GBLREF jnlpool_addrs jnlpool; GBLREF gd_region *gv_cur_region; GBLREF volatile boolean_t in_wcs_recover; -GBLREF boolean_t ok_to_UNWIND_in_exit_handling; GBLREF int process_exiting; +#ifdef UNIX +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +#endif + +error_def(ERR_JNLCLOSED); +error_def(ERR_REPLJNLCLOSED); static const unsigned short zero_fid[3]; @@ -48,10 +56,8 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat) unsigned int status; sgmnt_addrs *csa; seq_num reg_seqno, jnlseqno; - bool was_lockid = FALSE; + boolean_t was_lockid = FALSE, instfreeze_environ; - error_def(ERR_REPLJNLCLOSED); - error_def(ERR_JNLCLOSED); DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -64,26 +70,36 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat) default: GTMASSERT; } -#ifdef VMS +# ifdef VMS /* The following assert has been removed as it could be FALSE if the caller is "jnl_file_extend" * assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))); */ -#endif +# endif assert(csa->now_crit); - if (JNL_FILE_LOST_ERRORS == TREF(error_on_jnl_file_lost)) + /* We issue an rts_error (instead of shutting off journaling) in the following cases : {BYPASSOK} + * 1) $gtm_error_on_jnl_file_lost is set to issue runtime error (if not already issued) in case of journaling issues. + * 2) The process has $gtm_custom_errors set (indicative of anticipatory freeze setup) in which case the goal is to + * never shut-off journaling + * 3) If $gtm_custom_errors is not set for this process, but the source server was started with $gtm_custom_errors + * set. This way, as long as the environment is configured for $gtm_custom_errors individual processes never turn + * off journaling. + */ + UNIX_ONLY(instfreeze_environ = (ANTICIPATORY_FREEZE_AVAILABLE + || ((NULL != jnlpool_ctl) && jnlpool_ctl->instfreeze_environ_inited))); + VMS_ONLY(instfreeze_environ = FALSE); + if ((JNL_FILE_LOST_ERRORS == TREF(error_on_jnl_file_lost)) || instfreeze_environ) { -#ifdef VMS - assert(FALSE); /* Not fully implemented / supported on VMS. */ -#endif - if (!process_exiting || !csa->jnl->error_reported) + VMS_ONLY(assert(FALSE)); /* Not fully implemented / supported on VMS. */ + if (!process_exiting || instfreeze_environ || !csa->jnl->error_reported) { csa->jnl->error_reported = TRUE; in_wcs_recover = FALSE; /* in case we're called in wcs_recover() */ - DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE); if (SS_NORMAL != jpc->status) - rts_error(VARLSTCNT(7) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region), jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_stat, 4, JNL_LEN_STR(csa->hdr), + DB_LEN_STR(gv_cur_region), jpc->status); else - rts_error(VARLSTCNT(6) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_stat, 4, JNL_LEN_STR(csa->hdr), + DB_LEN_STR(gv_cur_region)); } return jnl_stat; } @@ -97,9 +113,10 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat) csa->hdr->repl_state = repl_was_open; reg_seqno = csa->hdr->reg_seqno; jnlseqno = (NULL != jnlpool.jnlpool_ctl) ? jnlpool.jnlpool_ctl->jnl_seqno : MAX_SEQNO; - send_msg(VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(jpc->region), ®_seqno, ®_seqno, &jnlseqno, &jnlseqno); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(jpc->region), ®_seqno, ®_seqno, + &jnlseqno, &jnlseqno); } else - send_msg(VARLSTCNT(5) ERR_JNLCLOSED, 3, DB_LEN_STR(jpc->region), &csa->ti->curr_tn); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSED, 3, DB_LEN_STR(jpc->region), &csa->ti->curr_tn); #ifdef VMS /* We can get a jnl_file_lost before the file is even created, so locking is done only if the lock exist */ if (0 != csa->jnl->jnllsb->lockid) diff --git a/sr_port/jnl_file_open_common.c b/sr_port/jnl_file_open_common.c index a46acb3..9ff0a4d 100644 --- a/sr_port/jnl_file_open_common.c +++ b/sr_port/jnl_file_open_common.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,6 +53,7 @@ #include "repl_sp.h" #include "iosp.h" /* for SS_NORMAL */ #include "get_fs_block_size.h" +#include "anticipatory_freeze.h" GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF boolean_t pool_init; @@ -91,6 +92,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) io_status_block_disk iosb; #endif uint4 jnl_fs_block_size, read_write_size, read_size; + gtm_uint64_t header_virtual_size; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; @@ -141,7 +143,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) } if (!is_gdid_file_identical(&FILE_ID(reg), (char *)header->data_file_name, header->data_file_name_length)) { - rts_error(VARLSTCNT(7) ERR_JNLOPNERR, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), ERR_FILEIDMATCH); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_JNLOPNERR, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), ERR_FILEIDMATCH); assert(FALSE); /* we dont expect the rts_error in the line above to return */ return ERR_JNLOPNERR; } @@ -168,7 +170,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) GTMCRYPT_ONLY( if (memcmp(header->encryption_hash, csd->encryption_hash, GTMCRYPT_HASH_LEN)) { - send_msg(VARLSTCNT(6) ERR_CRYPTJNLWRONGHASH, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_CRYPTJNLWRONGHASH, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); jpc->status = ERR_CRYPTJNLWRONGHASH; return ERR_JNLOPNERR; } @@ -181,10 +183,11 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) assert(((off_jnl_t)os_file_size) % JNL_REC_START_BNDRY == 0); assert(((off_jnl_t)os_file_size) % DISK_BLOCK_SIZE == 0); assert(((off_jnl_t)os_file_size) % jnl_fs_block_size == 0); - if ((ROUND_UP2((header->virtual_size * DISK_BLOCK_SIZE), jnl_fs_block_size) < os_file_size) - || (header->jnl_deq && 0 != ((header->virtual_size - header->jnl_alq) % header->jnl_deq))) + header_virtual_size = header->virtual_size; /* saving in 8-byte int to avoid overflow below */ + if ((ROUND_UP2((header_virtual_size * DISK_BLOCK_SIZE), jnl_fs_block_size) < os_file_size) + || (header->jnl_deq && 0 != ((header_virtual_size - header->jnl_alq) % header->jnl_deq))) { - send_msg(VARLSTCNT(8) ERR_JNLVSIZE, 6, JNL_LEN_STR(csd), header->virtual_size, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLVSIZE, 6, JNL_LEN_STR(csd), header->virtual_size, header->jnl_alq, header->jnl_deq, os_file_size, jnl_fs_block_size); jpc->status = ERR_JNLVSIZE; return ERR_JNLOPNERR; @@ -199,8 +202,9 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) VMS_ONLY(jb->buff_off = 0;) jb->size = ROUND_DOWN2(csd->jnl_buffer_size * DISK_BLOCK_SIZE - jb->buff_off, jnl_fs_block_size); /* Assert that journal buffer does NOT spill past the allocated journal buffer size in shared memory */ - assert((sm_uc_ptr_t)&jb->buff[jb->buff_off + jb->size] < ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE + JNL_SHARE_SIZE(csd))); - assert((sm_uc_ptr_t)jb == ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE)); + assert((sm_uc_ptr_t)&jb->buff[jb->buff_off + jb->size] < ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd) + + JNL_SHARE_SIZE(csd))); + assert((sm_uc_ptr_t)jb == ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE)); jb->freeaddr = jb->dskaddr = UNIX_ONLY(jb->fsync_dskaddr = ) header->end_of_data; jb->fs_block_size = jnl_fs_block_size; /* The following is to make sure that the data in jnl_buffer is aligned with the data in the @@ -250,10 +254,10 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) if (REPL_ENABLED(csd) && pool_init) header->update_disabled = jnlpool_ctl->upd_disabled; ) - DO_FILE_WRITE(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); + JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SS_NORMAL != jpc->status) { - assert(FALSE); + assert(WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)); return ERR_JNLWRERR; } if (!jb->prev_jrec_time || !header->prev_jnl_file_name_length) diff --git a/sr_port/jnl_file_open_switch.c b/sr_port/jnl_file_open_switch.c index 976ea25..682f85c 100644 --- a/sr_port/jnl_file_open_switch.c +++ b/sr_port/jnl_file_open_switch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,7 @@ #include "gtmio.h" #include "repl_sp.h" #include "iosp.h" /* for SS_NORMAL */ +#include "wbox_test_init.h" GBLREF jnl_gbls_t jgbl; @@ -54,7 +55,7 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts) set_jnl_info(reg, &create); create.no_prev_link = TRUE; create.no_rename = FALSE; - assert(!jgbl.forw_phase_recovery); + assert(!jgbl.forw_phase_recovery || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)); if (!jgbl.dont_reset_gbl_jrec_time) SET_GBL_JREC_TIME; /* needed for cre_jnl_file() */ /* else mur_output_record() would have already set jgbl.gbl_jrec_time */ @@ -70,7 +71,7 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts) csa->hdr->jnl_checksum = create.checksum; csa->hdr->jnl_eovtn = csa->hdr->trans_hist.curr_tn; } - send_msg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(reg)); assert(csa->hdr->jnl_file_len == create.jnl_len); assert(0 == memcmp(csa->hdr->jnl_file_name, create.jnl, create.jnl_len)); return 0; diff --git a/sr_port/jnl_flush.c b/sr_port/jnl_flush.c index 0f7c42a..aa25090 100644 --- a/sr_port/jnl_flush.c +++ b/sr_port/jnl_flush.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,16 +20,24 @@ #include "iosp.h" #include "jnl.h" #include "wbox_test_init.h" +#ifdef UNIX +#include "gtm_threadgbl.h" +#endif GBLREF uint4 process_id; uint4 jnl_flush(gd_region *reg) { sgmnt_addrs *csa; + node_local_ptr_t cnl; jnl_private_control *jpc; jnl_buffer_ptr_t jb; uint4 status; +#ifdef UNIX + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; +#endif if (!reg || !reg->open) return SS_NORMAL; csa = &FILE_INFO(reg)->s_addrs; @@ -39,8 +47,17 @@ uint4 jnl_flush(gd_region *reg) return SS_NORMAL; jb = jpc->jnl_buff; jb->blocked = process_id; - status = (jb->freeaddr != jb->dskaddr) ? jnl_write_attempt(jpc, jb->freeaddr) : SS_NORMAL; - assert(((SS_NORMAL == status) && (jb->dskaddr == jb->freeaddr)) + if (jb->freeaddr != jb->dskaddr) + { + status = jnl_write_attempt(jpc, jb->freeaddr); + if (SS_NORMAL == status) + { + cnl = csa->nl; + INCR_GVSTATS_COUNTER(csa, cnl, n_jnl_flush, 1); + } + } else + status = SS_NORMAL; + assert(((SS_NORMAL == status) && (jb->dskaddr == jb->freeaddr)) UNIX_ONLY(|| TREF(gtm_test_fake_enospc)) || (gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); jb->blocked = 0; return status; diff --git a/sr_port/jnl_format.c b/sr_port/jnl_format.c index db2c105..cdbed5b 100644 --- a/sr_port/jnl_format.c +++ b/sr_port/jnl_format.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "jnl.h" #include "gdscc.h" #include "iosp.h" -#include "mdefsp.h" +#include #include "ccp.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ @@ -105,10 +105,14 @@ jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, ui sgmnt_data_ptr_t csd; uint4 align_fill_size, jrec_size, tmp_jrec_size, update_length; boolean_t is_ztworm_rec = FALSE; + uint4 cursum; DEBUG_ONLY( static boolean_t dbg_in_jnl_format = FALSE; ) - GTMCRYPT_ONLY(int crypt_status;) +# ifdef GTM_CRYPT + int gtmcrypt_errno; + gd_segment *seg; +# endif # ifdef GTM_TRIGGER boolean_t ztworm_matched, match_possible; mstr prev_str, *cur_str; @@ -268,6 +272,7 @@ jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, ui rec->prefix.forwptr = jrec_size; assert(&rec->jrec_set_kill.update_num == &rec->jrec_ztworm.update_num); rec->jrec_set_kill.update_num = jgbl.tp_ztp_jnl_upd_num; + rec->jrec_set_kill.num_participants = 0; local_buffer = (char *)rec + FIXED_UPD_RECLEN; mumps_node_ptr = local_buffer; if (NULL != key) @@ -304,29 +309,31 @@ jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, ui assert(REPL_ALLOWED(csa) || !is_ztworm_rec || jgbl.forw_phase_recovery); if (csd->is_encrypted) { - /* At this place we have all the components of the *SET or *KILL or *ZTWORM records filled. - * Before the variable part of the journal record gets encrypted, we make sure we copy the buff - * into alt_buff to be used in it's original form in jnl_write. - */ + /* At this point we have all the components of *SET, *KILL, *ZTWORM and *ZTRIG records filled. */ if (REPL_ALLOWED(csa)) { + /* Before encrypting the journal record, copy the unencrypted buffer to an alternate buffer + * that eventually gets copied to the journal pool (in jnl_write). This way, the replication + * stream sends unencrypted data. + */ memcpy(jfb->alt_buff, rec, jrec_size); SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, (jfb->alt_buff + FIXED_UPD_RECLEN)); } - /* With the fixed length computed above as FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE, we encode - * the remaining buffer which consists of the *SET or *KILL or *ZTWORM components. - */ ASSERT_ENCRYPTION_INITIALIZED; - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, mumps_node_ptr, update_length, NULL, crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, gv_cur_region->dyn.addr->fname); + /* Encrypt the logical portion of the record which eventually gets written to the journal buffer/file */ + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, mumps_node_ptr, update_length, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); + } } else # endif { SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, mumps_node_ptr); } /* The below call to jnl_get_checksum makes sure that checksum computation happens AFTER the encryption (if turned on) */ - jfb->checksum = jnl_get_checksum((uint4 *)mumps_node_ptr, NULL, (int)(local_buffer - mumps_node_ptr)); + jfb->checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)mumps_node_ptr, (int)(local_buffer - mumps_node_ptr)); assert(0 == ((UINTPTR_T)local_buffer % SIZEOF(jrec_suffix))); DEBUG_ONLY(dbg_in_jnl_format = FALSE;) return jfb; diff --git a/sr_port/jnl_get_checksum.c b/sr_port/jnl_get_checksum.c index 1b652b0..c08d0ae 100644 --- a/sr_port/jnl_get_checksum.c +++ b/sr_port/jnl_get_checksum.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2009 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -8,34 +8,310 @@ * the license, please stop and do not read further. * * * ****************************************************************/ + #include "mdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsfhead.h" #include "jnl_get_checksum.h" +/* The following four looktable are generated using following paramenters. + * Generator Polynomial = ................. 0x1EDC6F41 + * Generator Polynomial Length = .......... 32 bits + * Reflected Bits = ....................... TRUE + * Number of Slices = ..................... 4 slices + */ +GBLDEF uint4 csum_table[SLICE_BY][TABLE_SIZE] = { +#ifdef BIGENDIAN + { + 0x0, 0x3836bf2, 0xf7703be1, 0xf4f35013, 0x1f979ac7, 0x1c14f135, 0xe8e7a126, 0xeb64cad4, + 0xcf58d98a, 0xccdbb278, 0x3828e26b, 0x3bab8999, 0xd0cf434d, 0xd34c28bf, 0x27bf78ac, 0x243c135e, + 0x6fc75e10, 0x6c4435e2, 0x98b765f1, 0x9b340e03, 0x7050c4d7, 0x73d3af25, 0x8720ff36, 0x84a394c4, + 0xa09f879a, 0xa31cec68, 0x57efbc7b, 0x546cd789, 0xbf081d5d, 0xbc8b76af, 0x487826bc, 0x4bfb4d4e, + 0xde8ebd20, 0xdd0dd6d2, 0x29fe86c1, 0x2a7ded33, 0xc11927e7, 0xc29a4c15, 0x36691c06, 0x35ea77f4, + 0x11d664aa, 0x12550f58, 0xe6a65f4b, 0xe52534b9, 0xe41fe6d, 0xdc2959f, 0xf931c58c, 0xfab2ae7e, + 0xb149e330, 0xb2ca88c2, 0x4639d8d1, 0x45bab323, 0xaede79f7, 0xad5d1205, 0x59ae4216, 0x5a2d29e4, + 0x7e113aba, 0x7d925148, 0x8961015b, 0x8ae26aa9, 0x6186a07d, 0x6205cb8f, 0x96f69b9c, 0x9575f06e, + 0xbc1d7b41, 0xbf9e10b3, 0x4b6d40a0, 0x48ee2b52, 0xa38ae186, 0xa0098a74, 0x54fada67, 0x5779b195, + 0x7345a2cb, 0x70c6c939, 0x8435992a, 0x87b6f2d8, 0x6cd2380c, 0x6f5153fe, 0x9ba203ed, 0x9821681f, + 0xd3da2551, 0xd0594ea3, 0x24aa1eb0, 0x27297542, 0xcc4dbf96, 0xcfced464, 0x3b3d8477, 0x38beef85, + 0x1c82fcdb, 0x1f019729, 0xebf2c73a, 0xe871acc8, 0x315661c, 0x960dee, 0xf4655dfd, 0xf7e6360f, + 0x6293c661, 0x6110ad93, 0x95e3fd80, 0x96609672, 0x7d045ca6, 0x7e873754, 0x8a746747, 0x89f70cb5, + 0xadcb1feb, 0xae487419, 0x5abb240a, 0x59384ff8, 0xb25c852c, 0xb1dfeede, 0x452cbecd, 0x46afd53f, + 0xd549871, 0xed7f383, 0xfa24a390, 0xf9a7c862, 0x12c302b6, 0x11406944, 0xe5b33957, 0xe63052a5, + 0xc20c41fb, 0xc18f2a09, 0x357c7a1a, 0x36ff11e8, 0xdd9bdb3c, 0xde18b0ce, 0x2aebe0dd, 0x29688b2f, + 0x783bf682, 0x7bb89d70, 0x8f4bcd63, 0x8cc8a691, 0x67ac6c45, 0x642f07b7, 0x90dc57a4, 0x935f3c56, + 0xb7632f08, 0xb4e044fa, 0x401314e9, 0x43907f1b, 0xa8f4b5cf, 0xab77de3d, 0x5f848e2e, 0x5c07e5dc, + 0x17fca892, 0x147fc360, 0xe08c9373, 0xe30ff881, 0x86b3255, 0xbe859a7, 0xff1b09b4, 0xfc986246, + 0xd8a47118, 0xdb271aea, 0x2fd44af9, 0x2c57210b, 0xc733ebdf, 0xc4b0802d, 0x3043d03e, 0x33c0bbcc, + 0xa6b54ba2, 0xa5362050, 0x51c57043, 0x52461bb1, 0xb922d165, 0xbaa1ba97, 0x4e52ea84, 0x4dd18176, + 0x69ed9228, 0x6a6ef9da, 0x9e9da9c9, 0x9d1ec23b, 0x767a08ef, 0x75f9631d, 0x810a330e, 0x828958fc, + 0xc97215b2, 0xcaf17e40, 0x3e022e53, 0x3d8145a1, 0xd6e58f75, 0xd566e487, 0x2195b494, 0x2216df66, + 0x62acc38, 0x5a9a7ca, 0xf15af7d9, 0xf2d99c2b, 0x19bd56ff, 0x1a3e3d0d, 0xeecd6d1e, 0xed4e06ec, + 0xc4268dc3, 0xc7a5e631, 0x3356b622, 0x30d5ddd0, 0xdbb11704, 0xd8327cf6, 0x2cc12ce5, 0x2f424717, + 0xb7e5449, 0x8fd3fbb, 0xfc0e6fa8, 0xff8d045a, 0x14e9ce8e, 0x176aa57c, 0xe399f56f, 0xe01a9e9d, + 0xabe1d3d3, 0xa862b821, 0x5c91e832, 0x5f1283c0, 0xb4764914, 0xb7f522e6, 0x430672f5, 0x40851907, + 0x64b90a59, 0x673a61ab, 0x93c931b8, 0x904a5a4a, 0x7b2e909e, 0x78adfb6c, 0x8c5eab7f, 0x8fddc08d, + 0x1aa830e3, 0x192b5b11, 0xedd80b02, 0xee5b60f0, 0x53faa24, 0x6bcc1d6, 0xf24f91c5, 0xf1ccfa37, + 0xd5f0e969, 0xd673829b, 0x2280d288, 0x2103b97a, 0xca6773ae, 0xc9e4185c, 0x3d17484f, 0x3e9423bd, + 0x756f6ef3, 0x76ec0501, 0x821f5512, 0x819c3ee0, 0x6af8f434, 0x697b9fc6, 0x9d88cfd5, 0x9e0ba427, + 0xba37b779, 0xb9b4dc8b, 0x4d478c98, 0x4ec4e76a, 0xa5a02dbe, 0xa623464c, 0x52d0165f, 0x51537dad + }, + { + 0x0, 0x7798a213, 0xee304527, 0x99a8e734, 0xdc618a4e, 0xabf9285d, 0x3251cf69, 0x45c96d7a, + 0xb8c3149d, 0xcf5bb68e, 0x56f351ba, 0x216bf3a9, 0x64a29ed3, 0x133a3cc0, 0x8a92dbf4, 0xfd0a79e7, + 0x81f1c53f, 0xf669672c, 0x6fc18018, 0x1859220b, 0x5d904f71, 0x2a08ed62, 0xb3a00a56, 0xc438a845, + 0x3932d1a2, 0x4eaa73b1, 0xd7029485, 0xa09a3696, 0xe5535bec, 0x92cbf9ff, 0xb631ecb, 0x7cfbbcd8, + 0x2e38b7f, 0x757b296c, 0xecd3ce58, 0x9b4b6c4b, 0xde820131, 0xa91aa322, 0x30b24416, 0x472ae605, + 0xba209fe2, 0xcdb83df1, 0x5410dac5, 0x238878d6, 0x664115ac, 0x11d9b7bf, 0x8871508b, 0xffe9f298, + 0x83124e40, 0xf48aec53, 0x6d220b67, 0x1abaa974, 0x5f73c40e, 0x28eb661d, 0xb1438129, 0xc6db233a, + 0x3bd15add, 0x4c49f8ce, 0xd5e11ffa, 0xa279bde9, 0xe7b0d093, 0x90287280, 0x98095b4, 0x7e1837a7, + 0x4c617ff, 0x735eb5ec, 0xeaf652d8, 0x9d6ef0cb, 0xd8a79db1, 0xaf3f3fa2, 0x3697d896, 0x410f7a85, + 0xbc050362, 0xcb9da171, 0x52354645, 0x25ade456, 0x6064892c, 0x17fc2b3f, 0x8e54cc0b, 0xf9cc6e18, + 0x8537d2c0, 0xf2af70d3, 0x6b0797e7, 0x1c9f35f4, 0x5956588e, 0x2ecefa9d, 0xb7661da9, 0xc0febfba, + 0x3df4c65d, 0x4a6c644e, 0xd3c4837a, 0xa45c2169, 0xe1954c13, 0x960dee00, 0xfa50934, 0x783dab27, + 0x6259c80, 0x71bd3e93, 0xe815d9a7, 0x9f8d7bb4, 0xda4416ce, 0xaddcb4dd, 0x347453e9, 0x43ecf1fa, + 0xbee6881d, 0xc97e2a0e, 0x50d6cd3a, 0x274e6f29, 0x62870253, 0x151fa040, 0x8cb74774, 0xfb2fe567, + 0x87d459bf, 0xf04cfbac, 0x69e41c98, 0x1e7cbe8b, 0x5bb5d3f1, 0x2c2d71e2, 0xb58596d6, 0xc21d34c5, + 0x3f174d22, 0x488fef31, 0xd1270805, 0xa6bfaa16, 0xe376c76c, 0x94ee657f, 0xd46824b, 0x7ade2058, + 0xf9fac3fb, 0x8e6261e8, 0x17ca86dc, 0x605224cf, 0x259b49b5, 0x5203eba6, 0xcbab0c92, 0xbc33ae81, + 0x4139d766, 0x36a17575, 0xaf099241, 0xd8913052, 0x9d585d28, 0xeac0ff3b, 0x7368180f, 0x4f0ba1c, + 0x780b06c4, 0xf93a4d7, 0x963b43e3, 0xe1a3e1f0, 0xa46a8c8a, 0xd3f22e99, 0x4a5ac9ad, 0x3dc26bbe, + 0xc0c81259, 0xb750b04a, 0x2ef8577e, 0x5960f56d, 0x1ca99817, 0x6b313a04, 0xf299dd30, 0x85017f23, + 0xfb194884, 0x8c81ea97, 0x15290da3, 0x62b1afb0, 0x2778c2ca, 0x50e060d9, 0xc94887ed, 0xbed025fe, + 0x43da5c19, 0x3442fe0a, 0xadea193e, 0xda72bb2d, 0x9fbbd657, 0xe8237444, 0x718b9370, 0x6133163, + 0x7ae88dbb, 0xd702fa8, 0x94d8c89c, 0xe3406a8f, 0xa68907f5, 0xd111a5e6, 0x48b942d2, 0x3f21e0c1, + 0xc22b9926, 0xb5b33b35, 0x2c1bdc01, 0x5b837e12, 0x1e4a1368, 0x69d2b17b, 0xf07a564f, 0x87e2f45c, + 0xfd3cd404, 0x8aa47617, 0x130c9123, 0x64943330, 0x215d5e4a, 0x56c5fc59, 0xcf6d1b6d, 0xb8f5b97e, + 0x45ffc099, 0x3267628a, 0xabcf85be, 0xdc5727ad, 0x999e4ad7, 0xee06e8c4, 0x77ae0ff0, 0x36ade3, + 0x7ccd113b, 0xb55b328, 0x92fd541c, 0xe565f60f, 0xa0ac9b75, 0xd7343966, 0x4e9cde52, 0x39047c41, + 0xc40e05a6, 0xb396a7b5, 0x2a3e4081, 0x5da6e292, 0x186f8fe8, 0x6ff72dfb, 0xf65fcacf, 0x81c768dc, + 0xffdf5f7b, 0x8847fd68, 0x11ef1a5c, 0x6677b84f, 0x23bed535, 0x54267726, 0xcd8e9012, 0xba163201, + 0x471c4be6, 0x3084e9f5, 0xa92c0ec1, 0xdeb4acd2, 0x9b7dc1a8, 0xece563bb, 0x754d848f, 0x2d5269c, + 0x7e2e9a44, 0x9b63857, 0x901edf63, 0xe7867d70, 0xa24f100a, 0xd5d7b219, 0x4c7f552d, 0x3be7f73e, + 0xc6ed8ed9, 0xb1752cca, 0x28ddcbfe, 0x5f4569ed, 0x1a8c0497, 0x6d14a684, 0xf4bc41b0, 0x8324e3a3 + }, + { + 0x0, 0x7e9241a5, 0xd526f4f, 0x73c02eea, 0x1aa4de9e, 0x64369f3b, 0x17f6b1d1, 0x6964f074, + 0xc53e5138, 0xbbac109d, 0xc86c3e77, 0xb6fe7fd2, 0xdf9a8fa6, 0xa108ce03, 0xd2c8e0e9, 0xac5aa14c, + 0x8a7da270, 0xf4efe3d5, 0x872fcd3f, 0xf9bd8c9a, 0x90d97cee, 0xee4b3d4b, 0x9d8b13a1, 0xe3195204, + 0x4f43f348, 0x31d1b2ed, 0x42119c07, 0x3c83dda2, 0x55e72dd6, 0x2b756c73, 0x58b54299, 0x2627033c, + 0x14fb44e1, 0x6a690544, 0x19a92bae, 0x673b6a0b, 0xe5f9a7f, 0x70cddbda, 0x30df530, 0x7d9fb495, + 0xd1c515d9, 0xaf57547c, 0xdc977a96, 0xa2053b33, 0xcb61cb47, 0xb5f38ae2, 0xc633a408, 0xb8a1e5ad, + 0x9e86e691, 0xe014a734, 0x93d489de, 0xed46c87b, 0x8422380f, 0xfab079aa, 0x89705740, 0xf7e216e5, + 0x5bb8b7a9, 0x252af60c, 0x56ead8e6, 0x28789943, 0x411c6937, 0x3f8e2892, 0x4c4e0678, 0x32dc47dd, + 0xd98065c7, 0xa7122462, 0xd4d20a88, 0xaa404b2d, 0xc324bb59, 0xbdb6fafc, 0xce76d416, 0xb0e495b3, + 0x1cbe34ff, 0x622c755a, 0x11ec5bb0, 0x6f7e1a15, 0x61aea61, 0x7888abc4, 0xb48852e, 0x75dac48b, + 0x53fdc7b7, 0x2d6f8612, 0x5eafa8f8, 0x203de95d, 0x49591929, 0x37cb588c, 0x440b7666, 0x3a9937c3, + 0x96c3968f, 0xe851d72a, 0x9b91f9c0, 0xe503b865, 0x8c674811, 0xf2f509b4, 0x8135275e, 0xffa766fb, + 0xcd7b2126, 0xb3e96083, 0xc0294e69, 0xbebb0fcc, 0xd7dfffb8, 0xa94dbe1d, 0xda8d90f7, 0xa41fd152, + 0x845701e, 0x76d731bb, 0x5171f51, 0x7b855ef4, 0x12e1ae80, 0x6c73ef25, 0x1fb3c1cf, 0x6121806a, + 0x47068356, 0x3994c2f3, 0x4a54ec19, 0x34c6adbc, 0x5da25dc8, 0x23301c6d, 0x50f03287, 0x2e627322, + 0x8238d26e, 0xfcaa93cb, 0x8f6abd21, 0xf1f8fc84, 0x989c0cf0, 0xe60e4d55, 0x95ce63bf, 0xeb5c221a, + 0x4377278b, 0x3de5662e, 0x4e2548c4, 0x30b70961, 0x59d3f915, 0x2741b8b0, 0x5481965a, 0x2a13d7ff, + 0x864976b3, 0xf8db3716, 0x8b1b19fc, 0xf5895859, 0x9ceda82d, 0xe27fe988, 0x91bfc762, 0xef2d86c7, + 0xc90a85fb, 0xb798c45e, 0xc458eab4, 0xbacaab11, 0xd3ae5b65, 0xad3c1ac0, 0xdefc342a, 0xa06e758f, + 0xc34d4c3, 0x72a69566, 0x166bb8c, 0x7ff4fa29, 0x16900a5d, 0x68024bf8, 0x1bc26512, 0x655024b7, + 0x578c636a, 0x291e22cf, 0x5ade0c25, 0x244c4d80, 0x4d28bdf4, 0x33bafc51, 0x407ad2bb, 0x3ee8931e, + 0x92b23252, 0xec2073f7, 0x9fe05d1d, 0xe1721cb8, 0x8816eccc, 0xf684ad69, 0x85448383, 0xfbd6c226, + 0xddf1c11a, 0xa36380bf, 0xd0a3ae55, 0xae31eff0, 0xc7551f84, 0xb9c75e21, 0xca0770cb, 0xb495316e, + 0x18cf9022, 0x665dd187, 0x159dff6d, 0x6b0fbec8, 0x26b4ebc, 0x7cf90f19, 0xf3921f3, 0x71ab6056, + 0x9af7424c, 0xe46503e9, 0x97a52d03, 0xe9376ca6, 0x80539cd2, 0xfec1dd77, 0x8d01f39d, 0xf393b238, + 0x5fc91374, 0x215b52d1, 0x529b7c3b, 0x2c093d9e, 0x456dcdea, 0x3bff8c4f, 0x483fa2a5, 0x36ade300, + 0x108ae03c, 0x6e18a199, 0x1dd88f73, 0x634aced6, 0xa2e3ea2, 0x74bc7f07, 0x77c51ed, 0x79ee1048, + 0xd5b4b104, 0xab26f0a1, 0xd8e6de4b, 0xa6749fee, 0xcf106f9a, 0xb1822e3f, 0xc24200d5, 0xbcd04170, + 0x8e0c06ad, 0xf09e4708, 0x835e69e2, 0xfdcc2847, 0x94a8d833, 0xea3a9996, 0x99fab77c, 0xe768f6d9, + 0x4b325795, 0x35a01630, 0x466038da, 0x38f2797f, 0x5196890b, 0x2f04c8ae, 0x5cc4e644, 0x2256a7e1, + 0x471a4dd, 0x7ae3e578, 0x923cb92, 0x77b18a37, 0x1ed57a43, 0x60473be6, 0x1387150c, 0x6d1554a9, + 0xc14ff5e5, 0xbfddb440, 0xcc1d9aaa, 0xb28fdb0f, 0xdbeb2b7b, 0xa5796ade, 0xd6b94434, 0xa82b0591 + }, + { + 0x0, 0xb8aa45dd, 0x812367bf, 0x39892262, 0xf331227b, 0x4b9b67a6, 0x721245c4, 0xcab80019, + 0xe66344f6, 0x5ec9012b, 0x67402349, 0xdfea6694, 0x1552668d, 0xadf82350, 0x94710132, 0x2cdb44ef, + 0x3db164e9, 0x851b2134, 0xbc920356, 0x438468b, 0xce804692, 0x762a034f, 0x4fa3212d, 0xf70964f0, + 0xdbd2201f, 0x637865c2, 0x5af147a0, 0xe25b027d, 0x28e30264, 0x904947b9, 0xa9c065db, 0x116a2006, + 0x8b1425d7, 0x33be600a, 0xa374268, 0xb29d07b5, 0x782507ac, 0xc08f4271, 0xf9066013, 0x41ac25ce, + 0x6d776121, 0xd5dd24fc, 0xec54069e, 0x54fe4343, 0x9e46435a, 0x26ec0687, 0x1f6524e5, 0xa7cf6138, + 0xb6a5413e, 0xe0f04e3, 0x37862681, 0x8f2c635c, 0x45946345, 0xfd3e2698, 0xc4b704fa, 0x7c1d4127, + 0x50c605c8, 0xe86c4015, 0xd1e56277, 0x694f27aa, 0xa3f727b3, 0x1b5d626e, 0x22d4400c, 0x9a7e05d1, + 0xe75fa6ab, 0x5ff5e376, 0x667cc114, 0xded684c9, 0x146e84d0, 0xacc4c10d, 0x954de36f, 0x2de7a6b2, + 0x13ce25d, 0xb996a780, 0x801f85e2, 0x38b5c03f, 0xf20dc026, 0x4aa785fb, 0x732ea799, 0xcb84e244, + 0xdaeec242, 0x6244879f, 0x5bcda5fd, 0xe367e020, 0x29dfe039, 0x9175a5e4, 0xa8fc8786, 0x1056c25b, + 0x3c8d86b4, 0x8427c369, 0xbdaee10b, 0x504a4d6, 0xcfbca4cf, 0x7716e112, 0x4e9fc370, 0xf63586ad, + 0x6c4b837c, 0xd4e1c6a1, 0xed68e4c3, 0x55c2a11e, 0x9f7aa107, 0x27d0e4da, 0x1e59c6b8, 0xa6f38365, + 0x8a28c78a, 0x32828257, 0xb0ba035, 0xb3a1e5e8, 0x7919e5f1, 0xc1b3a02c, 0xf83a824e, 0x4090c793, + 0x51fae795, 0xe950a248, 0xd0d9802a, 0x6873c5f7, 0xa2cbc5ee, 0x1a618033, 0x23e8a251, 0x9b42e78c, + 0xb799a363, 0xf33e6be, 0x36bac4dc, 0x8e108101, 0x44a88118, 0xfc02c4c5, 0xc58be6a7, 0x7d21a37a, + 0x3fc9a052, 0x8763e58f, 0xbeeac7ed, 0x6408230, 0xccf88229, 0x7452c7f4, 0x4ddbe596, 0xf571a04b, + 0xd9aae4a4, 0x6100a179, 0x5889831b, 0xe023c6c6, 0x2a9bc6df, 0x92318302, 0xabb8a160, 0x1312e4bd, + 0x278c4bb, 0xbad28166, 0x835ba304, 0x3bf1e6d9, 0xf149e6c0, 0x49e3a31d, 0x706a817f, 0xc8c0c4a2, + 0xe41b804d, 0x5cb1c590, 0x6538e7f2, 0xdd92a22f, 0x172aa236, 0xaf80e7eb, 0x9609c589, 0x2ea38054, + 0xb4dd8585, 0xc77c058, 0x35fee23a, 0x8d54a7e7, 0x47eca7fe, 0xff46e223, 0xc6cfc041, 0x7e65859c, + 0x52bec173, 0xea1484ae, 0xd39da6cc, 0x6b37e311, 0xa18fe308, 0x1925a6d5, 0x20ac84b7, 0x9806c16a, + 0x896ce16c, 0x31c6a4b1, 0x84f86d3, 0xb0e5c30e, 0x7a5dc317, 0xc2f786ca, 0xfb7ea4a8, 0x43d4e175, + 0x6f0fa59a, 0xd7a5e047, 0xee2cc225, 0x568687f8, 0x9c3e87e1, 0x2494c23c, 0x1d1de05e, 0xa5b7a583, + 0xd89606f9, 0x603c4324, 0x59b56146, 0xe11f249b, 0x2ba72482, 0x930d615f, 0xaa84433d, 0x122e06e0, + 0x3ef5420f, 0x865f07d2, 0xbfd625b0, 0x77c606d, 0xcdc46074, 0x756e25a9, 0x4ce707cb, 0xf44d4216, + 0xe5276210, 0x5d8d27cd, 0x640405af, 0xdcae4072, 0x1616406b, 0xaebc05b6, 0x973527d4, 0x2f9f6209, + 0x34426e6, 0xbbee633b, 0x82674159, 0x3acd0484, 0xf075049d, 0x48df4140, 0x71566322, 0xc9fc26ff, + 0x5382232e, 0xeb2866f3, 0xd2a14491, 0x6a0b014c, 0xa0b30155, 0x18194488, 0x219066ea, 0x993a2337, + 0xb5e167d8, 0xd4b2205, 0x34c20067, 0x8c6845ba, 0x46d045a3, 0xfe7a007e, 0xc7f3221c, 0x7f5967c1, + 0x6e3347c7, 0xd699021a, 0xef102078, 0x57ba65a5, 0x9d0265bc, 0x25a82061, 0x1c210203, 0xa48b47de, + 0x88500331, 0x30fa46ec, 0x973648e, 0xb1d92153, 0x7b61214a, 0xc3cb6497, 0xfa4246f5, 0x42e80328 + } +#else + { + 0x0, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x30e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x61c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x5125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0xc38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0xf36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0xa24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x92a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x82f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0xb21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0xe330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0xd3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x7198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x20bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 + }, + { + 0x0, 0x13a29877, 0x274530ee, 0x34e7a899, 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0xb225918, 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, 0x310182de, 0x22a31aa9, 0x1644b230, 0x5e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, 0xec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, 0x2c896460, 0x3f2bfc17, 0xbcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, 0x134c95e1, 0xee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0xe2a7ec9, 0x3acdd650, 0x296f4e27, 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x50827d1, 0x16aabfa6, 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, 0x285d589d, 0x3bffc0ea, 0xf186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, 0x1798a91c, 0x43a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0xafe4234, 0x3e19eaad, 0x2dbb72da, 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x1dc1b2c, 0x127e835b, 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x4d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0xff665e5, 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, 0x35d5be23, 0x26772654, 0x12908ecd, 0x13216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, 0xa104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 + }, + { + 0x0, 0xa541927e, 0x4f6f520d, 0xea2ec073, 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, 0xa68f9adf, 0x3ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x45219e3, + 0x48f3434f, 0xedb2d131, 0x79c1142, 0xa2dd833c, 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0xb6a3b67, 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, 0x47cb61cb, 0xe28af3b5, 0x8a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, 0xf382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0xcf62a25, 0xe6d8ea56, 0x43997828, 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x32da597, 0xa66c37e9, 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0xe3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, 0xa23e2e0a, 0x77fbc74, 0xed517c07, 0x4810ee79, + 0x4b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x8479ef0, 0xe2695e83, 0x4728ccfd, 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, 0xb899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, 0x437ad51e, 0xe63b4760, 0xc158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0xfdb8fb2, 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 + }, + { + 0x0, 0xdd45aab8, 0xbf672381, 0x62228939, 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x6206a11, + 0xd725148b, 0xa60be33, 0x6842370a, 0xb5079db2, 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, 0xb327f7a3, 0x6e625d1b, 0xc40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, 0xd0846e14, 0xdc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0xbe1aebd, 0xd6a40405, 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, 0x7a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x181108e, 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, 0xdfc69b2a, 0x2833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x4a35b83, 0xd9e6f13b, 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, 0x8e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0xec3e5b0, 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0xf42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, 0x6b401616, 0xb605bcae, 0xd4273597, 0x9629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x5224b0d, 0x6700c234, 0xba45688c, 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, 0xbc65029d, 0x6120a825, 0x302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 + } +#endif +}; + /* * Input : - * buff : Pointer to the input buffer whose checksum needs to be computed. - * bufflen : Buffer size in bytes + * buff : Pointer to the input buffer whose checksum needs to be computed. + * sgmnt_addrs : Segment address + * bufflen : Buffer size in bytes * * Returns: * Computed checksum. - * - * Algorithm: - * For every 512 (DISK_BLOCK_SIZE) byte block of the input buffer, the first 16 and last 16 bytes are considered for checksum. - * The way this is implemented is as follows. - * For the 0th 512-byte block, the first 16 bytes are considered. - * For the 1st 512-byte block, the last 16 bytes of the 0th block and the first 16 bytes of the 1st block are considered. - * This is taken as a contiguous sequence of 32-bytes (i.e. CHKSUM_SEGLEN4 uint4s) - * For the 2nd 512-byte block, the last 16 bytes of the 1st block and the first 16 bytes of the 2nd block are considered. - * This is taken as a contiguous sequence of 32-bytes (i.e. CHKSUM_SEGLEN4 uint4s) - * And so on until the input buffer length is exceeded. - * If bufflen is not divisible by 4, it is ROUNDED DOWN to the nearest 4-byte (uint4) multiple. */ + uint4 jnl_get_checksum(uint4 *buff, sgmnt_addrs *csa, int bufflen) { - uint4 *top, *blk_base, *blk_top, blen, checksum; + uint4 *top, *blk_base, *blk_top, blen; # ifdef GTM_CRYPT DEBUG_ONLY( sm_uc_ptr_t orig_buff = NULL; @@ -49,20 +325,66 @@ uint4 jnl_get_checksum(uint4 *buff, sgmnt_addrs *csa, int bufflen) DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csa->hdr, (sm_uc_ptr_t)buff); } # endif - checksum = INIT_CHECKSUM_SEED; - for (blen = bufflen / SIZEOF(*buff), top = buff + blen, blk_top = buff + CHKSUM_SEGLEN4 / 2; buff < top ;) - { - if (blk_top > top) - blk_top = top; - for ( ; buff < blk_top; buff++) - checksum = ADJUST_CHECKSUM(checksum, *buff); - blk_top = (uint4 *)((sm_uc_ptr_t)buff + DISK_BLOCK_SIZE); - buff = blk_top - CHKSUM_SEGLEN4; - } - /* It is theoretically possible the computed checksum calculates to 0. Since we use a 0 to imply checksum - * was never computed, we need to return a non-zero value so in this case return INIT_CHECKSUM_SEED - */ - if (!checksum) - checksum = INIT_CHECKSUM_SEED; - return checksum; + + return (compute_checksum(INIT_CHECKSUM_SEED, buff, bufflen)); +} + + +/* + * Input : + * buff : Pointer to the input buffer whose checksum needs to be computed. + * bufflen : Buffer size in bytes + * + * Returns: + * Computed checksum. + * + * Algorithm: + * The checksum is calculated using slice-by-4 checksum calculation algorithm + */ + +uint4 compute_checksum(uint4 init_checksum, uint4 *buff, int bufflen) +{ + uint4 checksum = init_checksum; + char *byte; + int word_cnt, i, rem_bytes; + /* calculate checksum one byte at a time so that subsequent data read will be at addresses aligned to multiple of 4*/ +#ifdef GTM64 + for (byte = (char *)buff; ((gtm_uint8)byte & SIZEOF(gtm_uint8)) != 0; byte++, bufflen--) +#else + for (byte = (char *)buff; ((uint4)byte & SIZEOF(uint4)) != 0; byte++, bufflen--) +#endif + { +#ifdef BIGENDIAN + checksum = (checksum << BITS_PER_UCHAR) ^ csum_table[0][((checksum >> (3 * BITS_PER_UCHAR)) ^ *byte) & BYTEMASK]; +#else + checksum = (checksum >> BITS_PER_UCHAR) ^ csum_table[0][(checksum ^ *byte) & BYTEMASK]; +#endif + } + word_cnt = bufflen / SIZEOF(uint4); + rem_bytes = bufflen & (int)(SIZEOF(uint4) - 1); /* Equivalent to bufflen % SIZEOF(uint4) */ + for(i = 0; i < word_cnt; i++) + { + checksum = checksum ^ *(uint4 *)byte; + byte = byte + SIZEOF(uint4); +#ifdef BIGENDIAN + checksum = csum_table[LOBYTE + 0][checksum & BYTEMASK] ^ + csum_table[LOBYTE + 1][(checksum >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ + csum_table[LOBYTE + 2][(checksum >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ + csum_table[LOBYTE + 3][(checksum >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; +#else + checksum = csum_table[HIBYTE - 0][checksum & BYTEMASK] ^ + csum_table[HIBYTE - 1][(checksum >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ + csum_table[HIBYTE - 2][(checksum >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ + csum_table[HIBYTE - 3][(checksum >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; +#endif + } + for(i = 0; i < rem_bytes; i++, byte++) + { +#ifdef BIGENDIAN + checksum = (checksum << BITS_PER_UCHAR) ^ csum_table[0][((checksum >> (3 * BITS_PER_UCHAR)) ^ *byte) & BYTEMASK]; +#else + checksum = (checksum >> BITS_PER_UCHAR) ^ csum_table[0][(checksum ^ *byte) & BYTEMASK]; +#endif + } + return (checksum ? checksum : INIT_CHECKSUM_SEED); } diff --git a/sr_port/jnl_get_checksum.h b/sr_port/jnl_get_checksum.h index cbbd5c8..1654895 100644 --- a/sr_port/jnl_get_checksum.h +++ b/sr_port/jnl_get_checksum.h @@ -11,81 +11,119 @@ #ifndef __JNL_GET_CHECKSUM_H_ #define __JNL_GET_CHECKSUM_H_ -#define INIT_CHECKSUM_SEED 1 -#define CHKSUM_SEGLEN4 8 +#define INIT_CHECKSUM_SEED 0xFFFFFFFF -#define ADJUST_CHECKSUM(sum, num4) (((sum) >> 4) + ((sum) << 4) + (num4)) +#define SLICE_BY 4 +#define TABLE_SIZE 256 +#define BYTEMASK 0xFF -#ifdef UNIX -/* Include the sequence number field of the journal record as part of the checksum computation. ADJUST_CHECKSUM - * macro currently relies on 4 byte quanitites as inputs. But, the journal sequence number is an 8 byte quantity. - * To avoid multiple calls to ADJUST_CHECKSUM to include the complete 8 byte sequence number, each of which might - * take around 4-5 instructions, consider only the lower order order 4 bytes of the sequence number for the checksum - * compuation. Given that the lower order bytes are the ones that will keep changing for every transaction, this - * should suffice. - */ -#define ADJUST_CHECKSUM_WITH_SEQNO(IS_REPLICATED, CHECKSUM, SEQNO) \ -{ \ - seq_num rec_token_seq; \ - \ - if (IS_REPLICATED) \ - { \ - rec_token_seq = SEQNO; \ - CHECKSUM = ADJUST_CHECKSUM(CHECKSUM, (rec_token_seq & 0x0000FFFF)); \ - } \ +GBLREF uint4 csum_table[SLICE_BY][TABLE_SIZE]; + +#ifdef BIGENDIAN +#define LOBYTE 0 +#define ADJUST_CHECKSUM(cursum, num4, newsum) \ +{ \ + uint4 tmpsum = csum_table[LOBYTE + 0][(cursum ^ num4) & BYTEMASK] ^ \ + csum_table[LOBYTE + 1][((cursum ^ num4) >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ + csum_table[LOBYTE + 2][((cursum ^ num4) >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ + csum_table[LOBYTE + 3][((cursum ^ num4) >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; \ + newsum = tmpsum ? tmpsum : INIT_CHECKSUM_SEED; \ } #else -#define ADJUST_CHECKSUM_WITH_SEQNO(IS_REPLICATED, CHECKSUM, SEQNO) +#define HIBYTE 3 +#define ADJUST_CHECKSUM(cursum, num4, newsum) \ +{ \ + uint4 tmpsum = csum_table[HIBYTE - 0][(cursum ^ num4) & BYTEMASK] ^ \ + csum_table[HIBYTE - 1][((cursum ^ num4) >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ + csum_table[HIBYTE - 2][((cursum ^ num4) >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ + csum_table[HIBYTE - 3][((cursum ^ num4) >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; \ + newsum = tmpsum ? tmpsum : INIT_CHECKSUM_SEED; \ +} #endif -/* This macro is to be used whenever we are computing the checksum of a block that has been acquired. */ -#define JNL_GET_CHECKSUM_ACQUIRED_BLK(cse, csd, csa, old_blk, bsize) \ -{ \ - cache_rec_ptr_t cr; \ - boolean_t cr_is_null; \ - \ - GBLREF uint4 dollar_tlevel; \ - \ - /* Record current database tn before computing checksum of acquired block. This is used \ - * later by the commit logic to determine if the block contents have changed (and hence \ - * if recomputation of checksum is necessary). For BG, we have two-phase commit where \ - * phase2 is done outside of crit. So it is possible that we note down the current database \ - * tn and then compute checksums outside of crit and then get crit and yet in the validation \ - * logic find the block header tn is LESSER than the noted dbtn (even though the block \ - * contents changed after the noted dbtn). This will cause us to falsely validate this block \ - * as not needing checksum recomputation. To ensure the checksum is recomputed inside crit, \ - * we note down a tn of 0 in case the block is locked for update (cr->in_tend is non-zero). \ - */ \ - assert((gds_t_acquired == cse->mode) || (gds_t_create == cse->mode) \ - || (gds_t_recycled2free == cse->mode)); \ - assert(cse->old_block == (sm_uc_ptr_t)(old_blk)); \ - assert((bsize) <= csd->blk_size); \ - /* Since this macro is invoked only in case of before-image journaling and since MM does not \ - * support before-image journaling, we can safely assert that BG is the only access method. \ - */ \ - assert(dba_bg == csd->acc_meth); \ - /* In rare cases cse->cr can be NULL even though this block is an acquired block. This is \ - * possible if we are in TP and this block was part of the tree in the initial phase of the \ - * transaction but was marked free (by another process concurrently) in the later phase of \ - * the same TP transaction. But this case is a sureshot restart situation so be safe and \ - * ensure recomputation happens inside of crit just in case we dont restart. Also add asserts \ - * (using donot_commit variable) to ensure we do restart this transaction. \ - */ \ - cr = cse->cr; \ - cr_is_null = (NULL == cr); \ - assert(!cr_is_null || dollar_tlevel); \ - DEBUG_ONLY(if (cr_is_null) TREF(donot_commit) |= DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR;) \ - cse->tn = ((cr_is_null || cr->in_tend) ? 0 : csd->trans_hist.curr_tn); \ - /* If cr is NULL, it is a restartable situation. So dont waste time computing checksums. Also \ - * if the db is encrypted, we cannot get at the encryption global buffer (jnl_get_checksum \ - * requires this) since we dont even have a regular global buffer corresponding to this block \ - * so there is no way jnl_get_checksum can proceed in that case. So it is actually necessary \ - * to avoid computing checksums if cr is NULL. \ - */ \ - cse->blk_checksum = !cr_is_null ? jnl_get_checksum((uint4 *)(old_blk), csa, (bsize)) : 0; \ +#define ADJUST_CHECKSUM_TN(cursum, tn, newsum) \ +{ \ + uint4 tmpsum_tn; \ + ADJUST_CHECKSUM(cursum, *(uint4 *)tn, tmpsum_tn); \ + ADJUST_CHECKSUM(tmpsum_tn, *(uint4 *)((char *)tn+SIZEOF(uint4)), newsum); \ } +#define COMPUTE_COMMON_CHECKSUM(common_cksum, prefix) \ +{ \ + ADJUST_CHECKSUM_TN(INIT_CHECKSUM_SEED, &(prefix.tn), common_cksum); \ + ADJUST_CHECKSUM(common_cksum, prefix.pini_addr, common_cksum); \ + ADJUST_CHECKSUM(common_cksum, prefix.time, common_cksum); \ +} + +#define COMPUTE_PBLK_CHECKSUM(blk_checksum, pblk_rec, common_cksum, jrec_checksum) \ +{ \ + ADJUST_CHECKSUM(blk_checksum, (pblk_rec)->prefix.jrec_type, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->blknum, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->bsiz, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->ondsk_blkver, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, common_cksum, jrec_checksum); \ +} + +#define COMPUTE_AIMG_CHECKSUM(blk_checksum, aimg_rec, common_cksum, jrec_checksum) \ + COMPUTE_PBLK_CHECKSUM(blk_checksum, aimg_rec, common_cksum, jrec_checksum); + +#define COMPUTE_LOGICAL_REC_CHECKSUM(jfb_checksum, jrec, common_cksum, jrec_checksum) \ +{ \ + ADJUST_CHECKSUM(jfb_checksum, (jrec)->prefix.jrec_type, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (jrec)->update_num, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (jrec)->token_seq.token, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (jrec)->strm_seqno, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, (jrec)->num_participants, jrec_checksum); \ + ADJUST_CHECKSUM(jrec_checksum, common_cksum, jrec_checksum); \ +} + +/* This macro is to be used whenever we are computing the checksum of a block that has been acquired. */ +#define JNL_GET_CHECKSUM_ACQUIRED_BLK(cse, csd, csa, old_blk, bsize) \ +{ \ + cache_rec_ptr_t cr; \ + boolean_t cr_is_null; \ + \ + GBLREF uint4 dollar_tlevel; \ + \ + /* Record current database tn before computing checksum of acquired block. This is used \ + * later by the commit logic to determine if the block contents have changed (and hence \ + * if recomputation of checksum is necessary). For BG, we have two-phase commit where \ + * phase2 is done outside of crit. So it is possible that we note down the current database \ + * tn and then compute checksums outside of crit and then get crit and yet in the validation \ + * logic find the block header tn is LESSER than the noted dbtn (even though the block \ + * contents changed after the noted dbtn). This will cause us to falsely validate this block \ + * as not needing checksum recomputation. To ensure the checksum is recomputed inside crit, \ + * we note down a tn of 0 in case the block is locked for update (cr->in_tend is non-zero). \ + */ \ + assert((gds_t_acquired == cse->mode) || (gds_t_create == cse->mode) \ + || (gds_t_recycled2free == cse->mode)); \ + assert(cse->old_block == (sm_uc_ptr_t)(old_blk)); \ + assert((bsize) <= csd->blk_size); \ + /* Since this macro is invoked only in case of before-image journaling and since MM does not \ + * support before-image journaling, we can safely assert that BG is the only access method. \ + */ \ + assert(dba_bg == csd->acc_meth); \ + /* In rare cases cse->cr can be NULL even though this block is an acquired block. This is \ + * possible if we are in TP and this block was part of the tree in the initial phase of the \ + * transaction but was marked free (by another process concurrently) in the later phase of \ + * the same TP transaction. But this case is a sureshot restart situation so be safe and \ + * ensure recomputation happens inside of crit just in case we dont restart. Also add asserts \ + * (using donot_commit variable) to ensure we do restart this transaction. \ + */ \ + cr = cse->cr; \ + cr_is_null = (NULL == cr); \ + assert(!cr_is_null || dollar_tlevel); \ + DEBUG_ONLY(if (cr_is_null) TREF(donot_commit) |= DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR;) \ + cse->tn = ((cr_is_null || cr->in_tend) ? 0 : csd->trans_hist.curr_tn); \ + /* If cr is NULL, it is a restartable situation. So dont waste time computing checksums. Also \ + * if the db is encrypted, we cannot get at the encryption global buffer (jnl_get_checksum \ + * requires this) since we dont even have a regular global buffer corresponding to this block \ + * so there is no way jnl_get_checksum can proceed in that case. So it is actually necessary \ + * to avoid computing checksums if cr is NULL. \ + */ \ + cse->blk_checksum = !cr_is_null ? jnl_get_checksum((uint4 *)(old_blk), csa, (bsize)) : 0; \ +} uint4 jnl_get_checksum(uint4 *buff, sgmnt_addrs *csa, int bufflen); -uint4 jnl_get_checksum_entire(uint4 *buff, int bufflen); +uint4 compute_checksum(uint4 init_sum, uint4 *buff, int bufflen); #endif diff --git a/sr_port/jnl_put_jrt_pfin.c b/sr_port/jnl_put_jrt_pfin.c index 19cb291..615f8b9 100644 --- a/sr_port/jnl_put_jrt_pfin.c +++ b/sr_port/jnl_put_jrt_pfin.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,5 +42,7 @@ void jnl_put_jrt_pfin(sgmnt_addrs *csa) assert(jgbl.gbl_jrec_time); pfin_record.prefix.time = jgbl.gbl_jrec_time; pfin_record.prefix.checksum = INIT_CHECKSUM_SEED; + pfin_record.filler = 0; + pfin_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&pfin_record, SIZEOF(struct_jrec_pfin)); jnl_write(jpc, JRT_PFIN, (jnl_record *)&pfin_record, NULL, NULL); } diff --git a/sr_port/jnl_put_jrt_pini.c b/sr_port/jnl_put_jrt_pini.c index a3b9490..b6287bb 100644 --- a/sr_port/jnl_put_jrt_pini.c +++ b/sr_port/jnl_put_jrt_pini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -85,6 +85,8 @@ void jnl_put_jrt_pini(sgmnt_addrs *csa) } } memcpy((unsigned char*)&pini_record.process_vector[CURR_JPV], (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); + pini_record.filler = 0; + pini_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&pini_record, SIZEOF(struct_jrec_pini)); jnl_write(jpc, JRT_PINI, (jnl_record *)&pini_record, NULL, NULL); /* Note : jpc->pini_addr should not be updated until PINI record is written [C9D08-002376] */ jpc->pini_addr = jbp->freeaddr - PINI_RECLEN; diff --git a/sr_port/jnl_send_oper.c b/sr_port/jnl_send_oper.c index 492ca3b..324eff9 100644 --- a/sr_port/jnl_send_oper.c +++ b/sr_port/jnl_send_oper.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,6 +22,7 @@ #include "error.h" #include "send_msg.h" #include "caller_id.h" +#include "wbox_test_init.h" #define ENOSPC_LOGGING_PERIOD 100 /* every 100th ENOSPC error is logged to avoid flooding the operator log */ @@ -53,8 +54,8 @@ void jnl_send_oper(jnl_private_control *jpc, uint4 status) } csd = csa->hdr; jb = jpc->jnl_buff; - UNIX_ONLY(assert((ENOSPC != jpc->status) || jb->enospc_errcnt);) - UNIX_ONLY(assert((SS_NORMAL == jpc->status) || (ENOSPC == jpc->status) || !jb->enospc_errcnt);) + UNIX_ONLY(assert((ENOSPC != jpc->status) || jb->enospc_errcnt || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC))); + UNIX_ONLY(assert((SS_NORMAL == jpc->status) || (ENOSPC == jpc->status) || !jb->enospc_errcnt)); VMS_ONLY(assert(!jb->enospc_errcnt)); /* currently not updated in VMS, so should be 0 */ ok_to_log = (jb->enospc_errcnt ? (1 == (jb->enospc_errcnt % ENOSPC_LOGGING_PERIOD)) : TRUE); diff --git a/sr_port/jnl_write.c b/sr_port/jnl_write.c index 8564588..fe26659 100644 --- a/sr_port/jnl_write.c +++ b/sr_port/jnl_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -49,6 +49,14 @@ GBLREF jnlpool_addrs jnlpool; 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; + +#ifdef DEBUG +STATICDEF int jnl_write_recursion_depth; + +#define MAX_JNL_WRITE_RECURSION_DEPTH 2 + +#endif error_def(ERR_JNLWRTNOWWRTR); error_def(ERR_JNLWRTDEFER); @@ -91,6 +99,103 @@ error_def(ERR_JNLWRTDEFER); } \ } +/* Note: DO_JNL_WRITE_ATTEMPT_IF_NEEDED and DO_JNL_FILE_EXTEND_IF_NEEDED are macros (instead of functions) for performance + * reasons since they are invoked for the fast path (no-align-record) always and for the ALIGN record once in a while. + */ +#define DO_JNL_WRITE_ATTEMPT_IF_NEEDED(JPC, JB, LCL_DSKADDR, LCL_FREEADDR, LCL_SIZE, \ + JNL_WRT_START_MASK, REC_LEN, JNL_WRT_START_MODULUS) \ +{ \ + GBLREF uint4 process_id; \ + \ + assert((!JB->blocked) || (FALSE == is_proc_alive(JB->blocked, 0)) \ + VMS_ONLY(|| ((JB->blocked == process_id) && lib$ast_in_prog()))); \ + JB->blocked = process_id; \ + /* We should differentiate between a full and an empty journal buffer, hence the pessimism reflected \ + * in the <= check below. Hence also the -1 in LCL_FREEADDR - (LCL_SIZE - REC_LEN - 1).* This means \ + * that although we have space we might still be invoking jnl_write_attempt (very unlikely). \ + */ \ + if (JNL_SPACE_AVAILABLE(JB, LCL_DSKADDR, LCL_FREEADDR, LCL_SIZE, JNL_WRT_START_MASK) <= REC_LEN) \ + { /* The fancy ordering of operators/operands in the calculation done below is to avoid overflows. */ \ + if (SS_NORMAL != jnl_write_attempt(JPC, \ + ROUND_UP2(LCL_FREEADDR - (LCL_SIZE - REC_LEN- 1), JNL_WRT_START_MODULUS))) \ + { \ + assert(NOJNL == JPC->channel); /* jnl file lost */ \ + DEBUG_ONLY(jnl_write_recursion_depth--); \ + return; /* let the caller handle the error */ \ + } \ + } \ + JB->blocked = 0; \ +} + +#define DO_JNL_FILE_EXTEND_IF_NEEDED(JREC_LEN, JB, LCL_FREEADDR, CSA, RECTYPE, BLK_PTR, JFB, REG, JPC, JNL_REC) \ +{ \ + int4 jrec_len_padded; \ + \ + GBLREF boolean_t in_jnl_file_autoswitch; \ + \ + /* Before writing a journal record, check if we have some padding space \ + * to close the journal file in case we are on the verge of an autoswitch. \ + * If we are about to autoswitch the journal file at this point, dont \ + * do the padding check since the padding space has already been checked \ + * in jnl_write calls before this autoswitch invocation. We can safely \ + * write the input record without worrying about autoswitch limit overflow. \ + */ \ + jrec_len_padded = JREC_LEN; \ + if (!in_jnl_file_autoswitch) \ + jrec_len_padded = JREC_LEN + JNL_FILE_TAIL_PRESERVE; \ + if (JB->filesize < DISK_BLOCKS_SUM(LCL_FREEADDR, jrec_len_padded)) /* not enough room in jnl file, extend it */ \ + { /* We should never reach here if we are called from t_end/tp_tend. We check that by using the fact that \ + * early_tn is different from curr_tn in the t_end/tp_tend case. The only exception is wcs_recover which \ + * also sets these to be different in case of writing an INCTN record. For this case though it is okay to \ + * extend/autoswitch the file. So allow that. \ + */ \ + assertpro((CSA->ti->early_tn == CSA->ti->curr_tn) || (JRT_INCTN == RECTYPE)); \ + assert(!IS_REPLICATED(RECTYPE)); /* all replicated jnl records should have gone through t_end/tp_tend */ \ + assert(jrt_fixed_size[RECTYPE]); /* this is used later in re-computing checksums */ \ + assert(NULL == BLK_PTR); /* as otherwise it is a PBLK or AIMG record which is of variable record \ + * length that conflicts with the immediately above assert. \ + */ \ + assert(NULL == JFB); /* as otherwise it is a logical record with formatted journal records which \ + * is of variable record length (conflicts with the jrt_fixed_size assert). \ + */ \ + assertpro(!in_jnl_file_autoswitch); /* avoid recursion of jnl_file_extend */ \ + if (SS_NORMAL != jnl_flush(REG)) \ + { \ + assert(NOJNL == JPC->channel); /* jnl file lost */ \ + DEBUG_ONLY(jnl_write_recursion_depth--); \ + return; /* let the caller handle the error */ \ + } \ + assert(LCL_FREEADDR == JB->dskaddr); \ + if (EXIT_ERR == jnl_file_extend(JPC, JREC_LEN)) /* if extension fails, not much we can do */ \ + { \ + DEBUG_ONLY(jnl_write_recursion_depth--); \ + assert(FALSE); \ + return; \ + } \ + if (0 == JPC->pini_addr) \ + { /* This can happen only if jnl got switched in jnl_file_extend above. \ + * Write a PINI record in the new journal file and then continue writing the input record. \ + * Basically we need to redo the processing in jnl_write because a lot of the local variables \ + * have changed state (e.g. JB->freeaddr etc.). So we instead call jnl_write() \ + * recursively and then return immediately. \ + */ \ + jnl_put_jrt_pini(CSA); \ + assertpro(JPC->pini_addr); /* should have been set in "jnl_put_jrt_pini" */ \ + if (JRT_PINI != RECTYPE) \ + { \ + JNL_REC->prefix.pini_addr = JPC->pini_addr; \ + /* Checksum needs to be recomputed since prefix.pini_addr is changed in above statement */ \ + JNL_REC->prefix.checksum = INIT_CHECKSUM_SEED; \ + JNL_REC->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, \ + (uint4 *)JNL_REC, JNL_REC->prefix.forwptr); \ + jnl_write(JPC, RECTYPE, JNL_REC, NULL, NULL); \ + } \ + DEBUG_ONLY(jnl_write_recursion_depth--); \ + return; \ + } \ + } \ +} + /* jpc : Journal private control * rectype : Record type * jnl_rec : This contains fixed part of a variable size record or the complete fixed size records. @@ -105,6 +210,7 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor jnl_buffer_ptr_t jb; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; + node_local_ptr_t cnl; struct_jrec_align align_rec; uint4 status; jrec_suffix suffix; @@ -116,11 +222,13 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor char *ptr; int jnl_wrt_start_modulus, jnl_wrt_start_mask; uint4 jnl_fs_block_size, aligned_lcl_free, padding_size; + uint4 tmp_csum1, tmp_csum2; # ifdef DEBUG uint4 lcl_dskaddr, mumps_node_sz; char *mumps_node_ptr; # endif + assert(jnl_write_recursion_depth++ < MAX_JNL_WRITE_RECURSION_DEPTH); reg = jpc->region; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; @@ -170,49 +278,19 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor } jnl_wrt_start_mask = JNL_WRT_START_MASK(jb); jnl_wrt_start_modulus = JNL_WRT_START_MODULUS(jb); + cnl = csa->nl; + /* If we are currently extending the journal file and writing the closing part of journal records, + * it better be the records that we expect. This is because we will skip the padding check for these + * records. The macro JNL_FILE_TAIL_PRESERVE already takes into account padding space for these. + */ + assert(!in_jnl_file_autoswitch + || (JRT_PINI == rectype) || (JRT_PFIN == rectype) || (JRT_EPOCH == rectype) + || (JRT_INCTN == rectype) || (JRT_EOF == rectype)); if (rlen_with_align != rlen) - { /* the calls below to jnl_write_attempt() and jnl_file_extend() are duplicated for the ALIGN record and the - * non-ALIGN journal record instead of making it a function. this is purely for performance reasons. - */ - assert((!jb->blocked) || (FALSE == is_proc_alive(jb->blocked, 0)) - VMS_ONLY(|| ((jb->blocked == process_id) && lib$ast_in_prog()))); - jb->blocked = process_id; - /* We should differentiate between a full and an empty journal buffer, hence the pessimism reflected in the <= - * check below. Hence also the -1 in lcl_freeaddr - (lcl_size - align_rec_len - 1). - * This means that although we have space we might still be invoking jnl_write_attempt (very unlikely). - */ - if (JNL_SPACE_AVAILABLE(jb, lcl_dskaddr, lcl_freeaddr, lcl_size, jnl_wrt_start_mask) <= align_rec_len) - { /* The fancy ordering of operators/operands in the calculation done below is to avoid overflows. */ - if (SS_NORMAL != jnl_write_attempt(jpc, - ROUND_UP2(lcl_freeaddr - (lcl_size - align_rec_len- 1), jnl_wrt_start_modulus))) - { - assert(NOJNL == jpc->channel); /* jnl file lost */ - return; /* let the caller handle the error */ - } - } - jb->blocked = 0; - if (jb->filesize < DISK_BLOCKS_SUM(lcl_freeaddr, align_rec_len)) /* not enough room in jnl file, extend it. */ - { /* We should never reach here if we are called from t_end/tp_tend */ - assert(!IS_GTM_IMAGE || csa->ti->early_tn == csa->ti->curr_tn); - if (SS_NORMAL != jnl_flush(reg)) - { - assert(NOJNL == jpc->channel); /* jnl file lost */ - return; /* let the caller handle the error */ - } - assert(lcl_freeaddr == jb->dskaddr); - if (EXIT_ERR == jnl_file_extend(jpc, align_rec_len)) /* if extension fails, not much we can do */ - { - assert(FALSE); - return; - } - if (0 == jpc->pini_addr && JRT_PINI != rectype) - { /* This can happen only if jnl got switched in jnl_file_extend above. - * We can't proceed now since the jnl record that we are writing now contains pini_addr information - * pointing to the older journal which is inappropriate if written into the new journal. - */ - GTMASSERT; - } - } + { + DO_JNL_WRITE_ATTEMPT_IF_NEEDED(jpc, jb, lcl_dskaddr, lcl_freeaddr, lcl_size, + jnl_wrt_start_mask, align_rec_len, jnl_wrt_start_modulus); + DO_JNL_FILE_EXTEND_IF_NEEDED(align_rec_len, jb, lcl_freeaddr, csa, rectype, blk_ptr, jfb, reg, jpc, jnl_rec); align_rec.prefix.jrec_type = JRT_ALIGN; assert(align_rec_len <= jb->max_jrec_len); align_rec.prefix.forwptr = suffix.backptr = align_rec_len; @@ -223,11 +301,11 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor * first PINI journal record in the journal file which is nothing but JNL_FILE_FIRST_RECORD. */ align_rec.prefix.pini_addr = (JRT_PINI == rectype) ? JNL_FILE_FIRST_RECORD : jnl_rec->prefix.pini_addr; - checksum = ADJUST_CHECKSUM(INIT_CHECKSUM_SEED, lcl_freeaddr); - checksum = ADJUST_CHECKSUM(checksum, csd->jnl_checksum); - assert(checksum); - align_rec.prefix.checksum = checksum; + align_rec.prefix.checksum = INIT_CHECKSUM_SEED; suffix.suffix_code = JNL_REC_SUFFIX_CODE; + align_rec.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&align_rec, SIZEOF(jrec_prefix)); + ADJUST_CHECKSUM(align_rec.prefix.checksum, lcl_freeaddr, align_rec.prefix.checksum); + ADJUST_CHECKSUM(align_rec.prefix.checksum, csd->jnl_checksum, align_rec.prefix.checksum); assert(lcl_free >= 0 && lcl_free < lcl_size); if (lcl_size >= (lcl_free + align_rec_len)) { /* before the string for zeroes */ @@ -256,6 +334,8 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor if (lcl_size == lcl_free) lcl_free = 0; jpc->new_freeaddr = lcl_freeaddr + align_rec_len; + INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_other, 1); + INCR_GVSTATS_COUNTER(csa, cnl, n_jbuff_bytes, align_rec_len); assert(jgbl.gbl_jrec_time >= align_rec.prefix.time); assert(align_rec.prefix.time >= jb->prev_jrec_time); jb->prev_jrec_time = align_rec.prefix.time; @@ -279,69 +359,58 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor jb->free_update_pid = 0; DBG_CHECK_JNL_BUFF_FREEADDR(jb); if (JRT_PINI == rectype) + { jnl_rec->prefix.pini_addr = lcl_freeaddr; + /* Checksum needs to be recomputed since prefix.pini_addr is changed in above statement */ + jnl_rec->prefix.checksum = INIT_CHECKSUM_SEED; + jnl_rec->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, + (uint4 *)&jnl_rec->jrec_pini, SIZEOF(struct_jrec_pini)); + } } checksum = jnl_rec->prefix.checksum; assert(checksum); # ifdef DEBUG - /* Ensure that the checksum computed earlier in jnl_format or jnl_write_pblk matches with the block's content. For fixed - * size records and AIMG records, this check is not needed since the checksum is initialized to INIT_CHECKSUM_SEED. + /* Ensure that the checksum computed earlier in jnl_format or jnl_write_pblk or jnl_write_aimg_rec or fixed-sized records + * matches with the block's content. */ - if (!jrt_fixed_size[rectype] && (JRT_AIMG != rectype)) + if ((JRT_PBLK == rectype) || (JRT_AIMG == rectype)) { - if (JRT_PBLK == rectype) - assert(checksum == jnl_get_checksum((uint4 *)blk_ptr, NULL, jnl_rec->jrec_pblk.bsiz)); - else + COMPUTE_COMMON_CHECKSUM(tmp_csum2, jnl_rec->prefix); + tmp_csum1 = jnl_get_checksum((uint4 *)blk_ptr, NULL, jnl_rec->jrec_pblk.bsiz); + COMPUTE_PBLK_CHECKSUM(tmp_csum1, &jnl_rec->jrec_pblk, tmp_csum2, tmp_csum1); + assert(checksum == tmp_csum1); + } else if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) + { + COMPUTE_COMMON_CHECKSUM(tmp_csum2, jnl_rec->prefix); + mumps_node_ptr = jfb->buff + FIXED_UPD_RECLEN; + mumps_node_sz = jfb->record_size - (FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE); + tmp_csum1 = jnl_get_checksum((uint4 *)mumps_node_ptr, NULL, mumps_node_sz); + COMPUTE_LOGICAL_REC_CHECKSUM(tmp_csum1, &jnl_rec->jrec_set_kill, tmp_csum2, tmp_csum1); + assert(checksum == tmp_csum1); + }else if (jrt_fixed_size[rectype] || JRT_ALIGN == rectype) + { + jnl_rec->prefix.checksum = INIT_CHECKSUM_SEED; + switch(rectype) { - assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)); - mumps_node_ptr = jfb->buff + FIXED_UPD_RECLEN; - mumps_node_sz = jfb->record_size - (FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE); - assert(checksum == jnl_get_checksum((uint4 *)mumps_node_ptr, NULL, mumps_node_sz)); + case JRT_ALIGN: + tmp_csum1 = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnl_rec->jrec_align, SIZEOF(jrec_prefix)); + break; + default: + if(JRT_TRIPLE != rectype && JRT_HISTREC != rectype) + tmp_csum1 = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnl_rec->jrec_set_kill, + jnl_rec->prefix.forwptr); + break; } + assert(checksum == tmp_csum1); + jnl_rec->prefix.checksum = checksum; } # endif - checksum = ADJUST_CHECKSUM(checksum, lcl_freeaddr); - checksum = ADJUST_CHECKSUM(checksum, csd->jnl_checksum); - ADJUST_CHECKSUM_WITH_SEQNO(is_replicated, checksum, GET_JNL_SEQNO(jnl_rec)); /* Note: checksum is updated inside macro */ + ADJUST_CHECKSUM(checksum, lcl_freeaddr, checksum); + ADJUST_CHECKSUM(checksum, csd->jnl_checksum, checksum); jnl_rec->prefix.checksum = checksum; - UNIX_ONLY(assert((!jb->blocked) || (FALSE == is_proc_alive(jb->blocked, 0)));) - VMS_ONLY(assert(!jb->blocked || (jb->blocked == process_id) && lib$ast_in_prog())); /* wcs_wipchk_ast can set jb->blocked */ - jb->blocked = process_id; - /* We should differentiate between a full and an empty journal buffer, hence the pessimism reflected in the <= check below. - * Hence also the -1 in lcl_freeaddr - (lcl_size - rlen - 1). - * This means that although we have space we might still be invoking jnl_write_attempt (very unlikely). - */ - if (JNL_SPACE_AVAILABLE(jb, lcl_dskaddr, lcl_freeaddr, lcl_size, jnl_wrt_start_mask) <= rlen) - { /* The fancy ordering of operators/operands in the calculation done below is to avoid overflows. */ - if (SS_NORMAL != jnl_write_attempt(jpc, ROUND_UP2(lcl_freeaddr - (lcl_size - rlen - 1), jnl_wrt_start_modulus))) - { - assert(NOJNL == jpc->channel); /* jnl file lost */ - return; /* let the caller handle the error */ - } - } - jb->blocked = 0; - if (jb->filesize < DISK_BLOCKS_SUM(lcl_freeaddr, rlen)) /* not enough room in jnl file, extend it. */ - { /* We should never reach here if we are called from t_end/tp_tend */ - assert(!IS_GTM_IMAGE || csa->ti->early_tn == csa->ti->curr_tn); - if (SS_NORMAL != jnl_flush(reg)) - { - assert(NOJNL == jpc->channel); /* jnl file lost */ - return; /* let the caller handle the error */ - } - assert(lcl_freeaddr == jb->dskaddr); - if (EXIT_ERR == jnl_file_extend(jpc, rlen)) /* if extension fails, not much we can do */ - { - assert(FALSE); - return; - } - if (0 == jpc->pini_addr && JRT_PINI != rectype) - { /* This can happen only if jnl got switched in jnl_file_extend above. - * We can't proceed now since the jnl record that we are writing now contains pini_addr information - * pointing to the older journal which is inappropriate if written into the new journal. - */ - GTMASSERT; - } - } + DO_JNL_WRITE_ATTEMPT_IF_NEEDED(jpc, jb, lcl_dskaddr, lcl_freeaddr, lcl_size, + jnl_wrt_start_mask, rlen, jnl_wrt_start_modulus); + DO_JNL_FILE_EXTEND_IF_NEEDED(rlen, jb, lcl_freeaddr, csa, rectype, blk_ptr, jfb, reg, jpc, jnl_rec); lcl_orig_free = lcl_free; nowrap = (lcl_size >= (lcl_free + rlen)); assert(jrt_fixed_size[JRT_EOF]); @@ -370,6 +439,12 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor if (padding_size) memset(lcl_buff + lcl_free, 0, padding_size); } + /* Note: Cannot easily use ? : syntax below as INCR_GVSTATS_COUNTER macro + * is not an arithmetic expression but a sequence of statements. + */ + if (JRT_EPOCH != rectype) + INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_other, 1); + /* else for EPOCH, the increment of JRE or JRI is done after "jnl_write_epoch_rec" in caller */ } else { if (NULL != blk_ptr) /* PBLK and AIMG */ @@ -398,6 +473,7 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor /* Now write trailing characters for 8-bye alignment and then suffix */ JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jfb->buff, jfb->record_size, lcl_size); } + INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_pblk, 1); } else { /* SET, KILL, ZKILL for TP, ZTP, non-TP */ assert(IS_TP(rectype) || IS_ZTP(rectype) || (0 == ((struct_jrec_upd *)jfb->buff)->update_num)); @@ -411,6 +487,7 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor lcl_free = 0; } else JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jfb->buff, rlen, lcl_size); + INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_logical, 1); } } assert((lcl_free - lcl_orig_free + lcl_size) % lcl_size == rlen); @@ -419,6 +496,7 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor assert((lcl_freeaddr >= jb->dskaddr) || (gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); 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 the database is encrypted, then at this point jfb->buff will contain encrypted @@ -479,7 +557,9 @@ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_recor { jb->blocked = 0; jnl_file_lost(jpc, status); + DEBUG_ONLY(jnl_write_recursion_depth--); return; } ) + DEBUG_ONLY(jnl_write_recursion_depth--); } diff --git a/sr_port/jnl_write_aimg_rec.c b/sr_port/jnl_write_aimg_rec.c index 5d3dd99..31a7589 100644 --- a/sr_port/jnl_write_aimg_rec.c +++ b/sr_port/jnl_write_aimg_rec.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,7 +34,7 @@ #endif GBLREF jnl_gbls_t jgbl; -void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse) +void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse, uint4 com_csum) { struct_jrec_blk aimg_record; int tmp_jrec_size, jrec_size, zero_len; @@ -44,10 +44,13 @@ void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse) blk_hdr_ptr_t buffer, save_buffer; jnl_private_control *jpc; sgmnt_data_ptr_t csd; -#ifdef GTM_CRYPT - char *buff; - int req_enc_blk_size, init_status, crypt_status; -#endif + uint4 cursum; +# ifdef GTM_CRYPT + char *in, *out; + int in_len, gtmcrypt_errno; + gd_segment *seg; +# endif + csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; @@ -78,21 +81,24 @@ void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse) assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); save_buffer = buffer; # ifdef GTM_CRYPT - req_enc_blk_size = aimg_record.bsiz - SIZEOF(*buffer); - if (BLOCK_REQUIRE_ENCRYPTION(csd->is_encrypted, buffer->levl, req_enc_blk_size)) + in_len = aimg_record.bsiz - SIZEOF(*buffer); + if (BLOCK_REQUIRE_ENCRYPTION(csd->is_encrypted, buffer->levl, in_len)) { ASSERT_ENCRYPTION_INITIALIZED; memcpy(csa->encrypted_blk_contents, buffer, SIZEOF(*buffer)); - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, - (char *)(buffer + 1), - req_enc_blk_size, - (csa->encrypted_blk_contents + SIZEOF(*buffer)), - crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, NULL); + in = (char *)(buffer + 1); + out = csa->encrypted_blk_contents + SIZEOF(blk_hdr); + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, in, in_len, out, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = csa->region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); + } buffer = (blk_hdr_ptr_t)csa->encrypted_blk_contents; } # endif + cursum = jnl_get_checksum((uint4 *)buffer, NULL, aimg_record.bsiz); + COMPUTE_AIMG_CHECKSUM(cursum, &aimg_record, com_csum, aimg_record.prefix.checksum); jnl_write(jpc, JRT_AIMG, (jnl_record *)&aimg_record, buffer, &blk_trailer); buffer = save_buffer; } diff --git a/sr_port/jnl_write_aimg_rec.h b/sr_port/jnl_write_aimg_rec.h index a3cf65a..13667c0 100644 --- a/sr_port/jnl_write_aimg_rec.h +++ b/sr_port/jnl_write_aimg_rec.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 __JNL_WRITE_AIMG_REC_H__ #define __JNL_WRITE_AIMG_REC_H__ -void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse); +void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse, uint4 com_csum); #endif diff --git a/sr_port/jnl_write_attempt.c b/sr_port/jnl_write_attempt.c index 002b7c9..bfb0381 100644 --- a/sr_port/jnl_write_attempt.c +++ b/sr_port/jnl_write_attempt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,30 +31,32 @@ #include "is_file_identical.h" #include "have_crit.h" #include "wbox_test_init.h" +#include "anticipatory_freeze.h" #ifdef UNIX +#include "repl_msg.h" /* needed for gtmsource.h */ +#include "gtmsource.h" /* needed for jnlpool_addrs typedef */ #include "gtmmsg.h" +#include "io.h" /* needed by gtmsecshr.h */ +#include "gtmsecshr.h" /* for continue_proc */ #endif #include "gtm_c_stack_trace.h" -GBLREF pid_t process_id; -GBLREF uint4 image_count; +#ifdef UNIX +GBLREF jnlpool_addrs jnlpool; +#endif +GBLREF pid_t process_id; +GBLREF uint4 image_count; +error_def(ERR_JNLACCESS); error_def(ERR_JNLCNTRL); error_def(ERR_JNLFLUSH); error_def(ERR_JNLFLUSHNOPROG); error_def(ERR_JNLPROCSTUCK); +error_def(ERR_JNLQIOSALVAGE); error_def(ERR_JNLWRTDEFER); error_def(ERR_JNLWRTNOWWRTR); error_def(ERR_TEXT); -error_def(ERR_JNLWRTDEFER); -error_def(ERR_JNLWRTNOWWRTR); - -#ifdef VMS -# define CURRENT_WRITER jb->now_writer -#else -# define CURRENT_WRITER jb->io_in_prog_latch.u.parts.latch_pid -#endif static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, uint4 threshold) { @@ -139,9 +141,9 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, UNIX_ONLY(assert(ERR_JNLWRTNOWWRTR != status);) /* dont have asynchronous jnl writes in Unix */ if ((ERR_JNLWRTNOWWRTR != status) && (ERR_JNLWRTDEFER != status)) return status; - if ((writer != CURRENT_WRITER) || (1 == *lcnt)) + if ((writer != CURRENT_JNL_IO_WRITER(jb)) || (1 == *lcnt)) { - writer = CURRENT_WRITER; + writer = CURRENT_JNL_IO_WRITER(jb); loop_image_count = jb->image_count; *lcnt = 1; /* !!! this should be detected and limited by the caller !!! */ break; @@ -152,21 +154,19 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, break; } VMS_ONLY( - if ((CURRENT_WRITER == process_id) && (jpc->qio_active == TRUE) && (jb->iosb.cond == -2)) + if ((CURRENT_JNL_IO_WRITER(jb) == process_id) && (jpc->qio_active == TRUE) && (jb->iosb.cond == -2)) { /* this an "impossible" condition where the private flag and the io have lost sync */ GTMASSERT; /* this should only occur in VMS; secshr_db_clnup should clear the problem */ } ) - if (writer == CURRENT_WRITER) + if (writer == CURRENT_JNL_IO_WRITER(jb)) { if (!was_crit) grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */ if (VMS_ONLY(0 == writer ||) FALSE == is_proc_alive(writer, jb->image_count)) { /* no one home, clear the semaphore; */ BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_lost); - jnl_send_oper(jpc, ERR_JNLFLUSH); - send_msg(VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, CURRENT_WRITER); - send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Journal IO writer changed during wait")); + jnl_send_oper(jpc, ERR_JNLQIOSALVAGE); VMS_ONLY(jb->io_in_prog = 0); UNIX_ONLY(COMPSWAP_UNLOCK(&jb->io_in_prog_latch, writer, jb->image_count, LOCK_AVAILABLE, 0)); if (!was_crit) @@ -180,11 +180,12 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_stuck); jpc->status = status; jnl_send_oper(jpc, ERR_JNLFLUSH); - send_msg(VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, CURRENT_WRITER); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, writer); stuck_cnt++; - GET_C_STACK_FROM_SCRIPT("JNLPROCSTUCK", process_id, CURRENT_WRITER, stuck_cnt); + GET_C_STACK_FROM_SCRIPT("JNLPROCSTUCK", process_id, writer, stuck_cnt); *lcnt = 1; /* ??? is it necessary to limit this, and if so, how ??? */ status = ERR_JNLPROCSTUCK; + UNIX_ONLY(continue_proc(writer)); break; } break; @@ -203,7 +204,7 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) { jnl_buffer_ptr_t jb; - unsigned int lcnt, prev_lcnt, cnt, proc_stuck_cnt; + unsigned int lcnt, prev_lcnt, cnt; sgmnt_addrs *csa; unsigned int status; boolean_t was_crit, jnlfile_lost, exact_check; @@ -228,7 +229,7 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) * the grab_crit calls (done in jnl_write_attempt and jnl_sub_write_attempt) to ensure no deadlocks are possible. */ assert(was_crit || (0 == have_crit(CRIT_HAVE_ANY_REG))); - for (prev_lcnt = lcnt = cnt = 1, proc_stuck_cnt = 0; + for (prev_lcnt = lcnt = cnt = 1; (was_crit || (NOJNL != jpc->channel)) && (exact_check ? jb->dskaddr != threshold : jb->dskaddr < threshold); lcnt++, prev_lcnt = lcnt, cnt++) { @@ -242,28 +243,19 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) } if (SS_NORMAL == status) { - if (JNL_FLUSH_PROG_TRIES > lcnt) - { - proc_stuck_cnt = 0; - /* In VMS, jnl writes are asynchronous. The above call to "jnl_sub_write_attempt" has returned - * SS_NORMAL status. This means the jnl qio lock is not in use by anyone else and is up for grabs. - * We would have scheduled a jnl qio write through a sys$dclast call. We have no control of when - * the AST routine "jnl_start_ast" will actually get control and start the write. Until then - * we dont want to keep reinvoking "jnl_sub_write_attempt" in a hard spin loop. So sleep. - * In Unix, writes are synchronous so SS_NORMAL status return implies we have completed a jnl - * write and "jb->dskaddr" is closer to "threshold" than it was in the previous iteration. - * A sleep at this point will only slow things down unnecessarily. Hence no sleep if Unix. - */ - VMS_ONLY(wcs_sleep(lcnt);) - continue; - } - jpc->status = SS_NORMAL; - jnl_send_oper(jpc, ERR_JNLFLUSH); - send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), - ERR_TEXT, 2, LEN_AND_LIT("Could not flush all the buffered journal data")); - GTMASSERT; /* too many attempts to flush journal data */ + /* In VMS, jnl writes are asynchronous. The above call to "jnl_sub_write_attempt" has returned + * SS_NORMAL status. This means the jnl qio lock is not in use by anyone else and is up for grabs. + * We would have scheduled a jnl qio write through a sys$dclast call. We have no control of when + * the AST routine "jnl_start_ast" will actually get control and start the write. Until then + * we dont want to keep reinvoking "jnl_sub_write_attempt" in a hard spin loop. So sleep. + * In Unix, writes are synchronous so SS_NORMAL status return implies we have completed a jnl + * write and "jb->dskaddr" is closer to "threshold" than it was in the previous iteration. + * A sleep at this point will only slow things down unnecessarily. Hence no sleep if Unix. + */ + VMS_ONLY(wcs_sleep(lcnt);) + continue; } - if ((ERR_JNLCNTRL == status) + if ((ERR_JNLCNTRL == status) || (ERR_JNLACCESS == status) || (csa->now_crit && (ERR_JNLWRTDEFER != status) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLPROCSTUCK != status))) { /* If JNLCNTRL or if holding crit and not waiting for some other writer (or self in VMS) @@ -272,15 +264,19 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) if (was_crit) jb->blocked = 0; else + { + assertpro(0 == have_crit(CRIT_HAVE_ANY_REG)); grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */ + } jnlfile_lost = FALSE; if (jb->free_update_pid) { FIX_NONZERO_FREE_UPDATE_PID(csa, jb); } else { - assert(gtm_white_box_test_case_enabled - && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number)); + assert((gtm_white_box_test_case_enabled + && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number)) + UNIX_ONLY(|| TREF(gtm_test_fake_enospc) || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC))); if (JNL_ENABLED(csa->hdr)) { /* We ignore the return value of jnl_file_lost() since we always want to report the journal * error, whatever its error handling method is. Also, an operator log will be sent by some @@ -302,6 +298,15 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) else return status; } +# ifdef UNIX + if ((ERR_JNLWRTDEFER == status) && IS_REPL_INST_FROZEN) + { /* Check if the write was deferred because the instance is frozen. + * In that case, wait until the freeze is lifted instead of wasting time spinning on the latch + * in jnl_qio. + */ + WAIT_FOR_REPL_INST_UNFREEZE(csa); + } +# endif if ((ERR_JNLWRTDEFER != status) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLPROCSTUCK != status)) { /* If holding crit, then jnl_sub_write_attempt would have invoked jnl_file_lost which would have * caused the JNL_FILE_SWITCHED check at the beginning of this for loop to succeed and return from @@ -318,28 +323,11 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) } else if (prev_lcnt != lcnt) { assert(1 == lcnt); - if (ERR_JNLWRTDEFER == status) + if ((ERR_JNLWRTDEFER == status) && (JNL_FLUSH_PROG_TRIES <= cnt)) { /* Change of writer */ - if (JNL_FLUSH_PROG_TRIES <= cnt) - { - send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), - ERR_TEXT, 2, LEN_AND_LIT("No progress even with multiple writers")); - GTMASSERT; - } - proc_stuck_cnt = 0; - } else if (ERR_JNLPROCSTUCK == status && (JNL_FLUSH_PROG_FACTOR <= ++proc_stuck_cnt)) - { - send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), ERR_TEXT, 2, - LEN_AND_LIT("Progress prevented by a process stuck flushing journal data")); - VMS_ONLY( - if (TREF(gtm_environment_init)) - { - proc_stuck_cnt = 0; - continue; - } - ) - - GTMASSERT; + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), + ERR_TEXT, 2, LEN_AND_LIT("No progress even with multiple writers")); + cnt = 0; } } } diff --git a/sr_port/jnl_write_eof_rec.c b/sr_port/jnl_write_eof_rec.c index 39b3aff..27c0a1b 100644 --- a/sr_port/jnl_write_eof_rec.c +++ b/sr_port/jnl_write_eof_rec.c @@ -64,10 +64,12 @@ void jnl_write_eof_rec(sgmnt_addrs *csa, struct_jrec_eof *eof_record) { if (REPL_ALLOWED(csa)) eof_record->jnl_seqno = csa->hdr->reg_seqno;/* Note we cannot use jnlpool_ctl->jnl_seqno since - * we might not presently hold the journal pool lock */ + * we might not presently hold the journal pool lock */ else eof_record->jnl_seqno = 0; } else QWASSIGN(eof_record->jnl_seqno, jgbl.mur_jrec_seqno); + eof_record->filler = 0; + eof_record->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)eof_record, SIZEOF(struct_jrec_eof)); jnl_write(jpc, JRT_EOF, (jnl_record *)eof_record, NULL, NULL); } diff --git a/sr_port/jnl_write_epoch_rec.c b/sr_port/jnl_write_epoch_rec.c index 06b7a55..05b4995 100644 --- a/sr_port/jnl_write_epoch_rec.c +++ b/sr_port/jnl_write_epoch_rec.c @@ -39,6 +39,7 @@ #include "gtmio.h" #include "iosp.h" #include "jnl_get_checksum.h" +#include "anticipatory_freeze.h" GBLREF jnl_gbls_t jgbl; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; @@ -144,7 +145,8 @@ void jnl_write_epoch_rec(sgmnt_addrs *csa) header->strm_end_seqno[idx] = jb->strm_end_seqno[idx]; } # endif - DO_FILE_WRITE(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); + JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, + jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); /* for abnormal status do not do anything. journal file header will have previous end_of_data */ } } @@ -167,5 +169,7 @@ void jnl_write_epoch_rec(sgmnt_addrs *csa) jb->strm_end_seqno[idx] = csd->strm_reg_seqno[idx]; } # endif + epoch_record.filler = 0; + epoch_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&epoch_record, SIZEOF(struct_jrec_epoch)); jnl_write(jpc, JRT_EPOCH, (jnl_record *)&epoch_record, NULL, NULL); } diff --git a/sr_port/jnl_write_inctn_rec.c b/sr_port/jnl_write_inctn_rec.c index 78ebd8d..0270e14 100644 --- a/sr_port/jnl_write_inctn_rec.c +++ b/sr_port/jnl_write_inctn_rec.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,6 +70,9 @@ void jnl_write_inctn_rec(sgmnt_addrs *csa) * copy the entire structure (16 bytes at this point). Pipeline breaks are considered more costly than a few * unnecessary memory-to-memory copies. */ + inctn_detail.blknum_struct.filler_uint4 = 0; + inctn_detail.blknum_struct.filler_short = 0; inctn_record.detail = inctn_detail; + inctn_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&inctn_record, SIZEOF(struct_jrec_inctn)); jnl_write(jpc, JRT_INCTN, (jnl_record *)&inctn_record, NULL, NULL); } diff --git a/sr_port/jnl_write_logical.c b/sr_port/jnl_write_logical.c index 288b7a1..ea1e0b8 100644 --- a/sr_port/jnl_write_logical.c +++ b/sr_port/jnl_write_logical.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ #include "repl_msg.h" #include "gtmsource.h" #include "iosp.h" +#include "jnl_get_checksum.h" #ifdef DEBUG #include "jnl_typedef.h" #endif @@ -41,7 +42,7 @@ GBLREF jnl_gbls_t jgbl; GBLREF seq_num seq_num_zero; /* This called for TP and non-TP, but not for ZTP */ -void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) +void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum) { struct_jrec_upd *jrec; struct_jrec_null *jrec_null; @@ -66,7 +67,6 @@ void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) jrec->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jrec->prefix.tn = csa->ti->curr_tn; jrec->prefix.time = jgbl.gbl_jrec_time; - jrec->prefix.checksum = jfb->checksum; /* t_end/tp_tend/mur_output_record has already set token/jnl_seqno into jnl_fence_ctl.token */ assert((0 != jnl_fence_ctl.token) || (!dollar_tlevel && !jgbl.forw_phase_recovery && !REPL_ENABLED(csa)) || (!dollar_tlevel && jgbl.forw_phase_recovery && (repl_open != csa->hdr->intrpt_recov_repl_state))); @@ -76,13 +76,22 @@ void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) assert(OFFSETOF(struct_jrec_null, strm_seqno) == OFFSETOF(struct_jrec_upd, strm_seqno)); assert(SIZEOF(jrec_null->strm_seqno) == SIZEOF(jrec->strm_seqno)); jrec->strm_seqno = jnl_fence_ctl.strm_seqno; + /*update checksum below*/ + if(JRT_NULL != jrec->prefix.jrec_type) + { + COMPUTE_LOGICAL_REC_CHECKSUM(jfb->checksum, jrec, com_csum, jrec->prefix.checksum); + } + else + jrec->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)jrec, SIZEOF(struct_jrec_null)); + # ifdef GTM_CRYPT - if (REPL_ALLOWED(csa)) + if (csa->hdr->is_encrypted && REPL_ALLOWED(csa)) { jrec_alt = (struct_jrec_upd *)jfb->alt_buff; jrec_alt->prefix = jrec->prefix; jrec_alt->token_seq = jrec->token_seq; jrec_alt->strm_seqno = jrec->strm_seqno; + jrec_alt->num_participants = jrec->num_participants; } # endif JNL_WRITE_APPROPRIATE(csa, jpc, jfb->rectype, (jnl_record *)jrec, NULL, jfb); diff --git a/sr_port/jnl_write_pblk.c b/sr_port/jnl_write_pblk.c index 7b7ac59..45dcb16 100644 --- a/sr_port/jnl_write_pblk.c +++ b/sr_port/jnl_write_pblk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,7 @@ GBLREF jnl_gbls_t jgbl; GBLREF boolean_t dse_running; -void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer) +void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer, uint4 com_csum) { struct_jrec_blk pblk_record; int tmp_jrec_size, jrec_size, zero_len; @@ -51,7 +51,6 @@ void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer) /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); pblk_record.prefix.time = jgbl.gbl_jrec_time; - pblk_record.prefix.checksum = cse->blk_checksum; pblk_record.blknum = cse->blk; /* in case we have a bad block-size, we dont want to write a PBLK larger than the GDS block size (maximum block size). * in addition, check that checksum computed in t_end/tp_tend did take the adjusted bsiz into consideration. @@ -70,6 +69,7 @@ void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer) blk_trailer.record_size = zero_len + JREC_SUFFIX_SIZE; suffix = (jrec_suffix *)&local_buff[JNL_REC_START_BNDRY]; pblk_record.prefix.forwptr = suffix->backptr = jrec_size; + COMPUTE_PBLK_CHECKSUM(cse->blk_checksum, &pblk_record, com_csum, pblk_record.prefix.checksum); suffix->suffix_code = JNL_REC_SUFFIX_CODE; assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); jnl_write(jpc, JRT_PBLK, (jnl_record *)&pblk_record, buffer, &blk_trailer); diff --git a/sr_port/jnl_write_pblk.h b/sr_port/jnl_write_pblk.h index 4928d3c..47d2e81 100644 --- a/sr_port/jnl_write_pblk.h +++ b/sr_port/jnl_write_pblk.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,7 +13,7 @@ #define __JNL_WRITE_PBLK_H__ /* We do not put this in jnl.h, because it needs all including jnl.h must include gdsblk.h */ -void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer); +void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer, uint4 com_csum); #endif diff --git a/sr_port/jnl_write_trunc_rec.c b/sr_port/jnl_write_trunc_rec.c index 1c41461..982ee44 100644 --- a/sr_port/jnl_write_trunc_rec.c +++ b/sr_port/jnl_write_trunc_rec.c @@ -51,6 +51,7 @@ void jnl_write_trunc_rec(sgmnt_addrs *csa, uint4 orig_total_blks, uint4 orig_ trunc_rec.orig_total_blks = orig_total_blks; trunc_rec.orig_free_blocks = orig_free_blocks; trunc_rec.total_blks_after_trunc = total_blks_after_trunc; + trunc_rec.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&trunc_rec, SIZEOF(struct_jrec_trunc)); jnl_write(jpc, JRT_TRUNC, (jnl_record *)&trunc_rec, NULL, NULL); } diff --git a/sr_port/jnl_write_ztp_logical.c b/sr_port/jnl_write_ztp_logical.c index 991751f..888f784 100644 --- a/sr_port/jnl_write_ztp_logical.c +++ b/sr_port/jnl_write_ztp_logical.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,6 +29,7 @@ #include "repl_msg.h" #include "gtmsource.h" #include "iosp.h" +#include "jnl_get_checksum.h" #ifdef DEBUG #include "jnl_typedef.h" #endif @@ -40,7 +41,7 @@ GBLREF seq_num seq_num_zero; GBLREF trans_num local_tn; /* transaction number for THIS PROCESS */ GBLREF uint4 process_id; -void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) +void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum) { struct_jrec_upd *jrec; volatile seq_num temp_seqno; @@ -64,7 +65,6 @@ void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) jrec->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jrec->prefix.tn = csa->ti->curr_tn; jrec->prefix.time = jgbl.gbl_jrec_time; - jrec->prefix.checksum = jfb->checksum; temp_seqno = temp_jnlpool_ctl->jnl_seqno; if (QWEQ(jnl_fence_ctl.token, seq_num_zero)) { /* generate token once after op_ztstart and use for all its mini-transactions @@ -79,6 +79,7 @@ void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) assert(0 != jnl_fence_ctl.token); jrec->token_seq.token = jnl_fence_ctl.token; jrec->strm_seqno = 0; /* strm_seqno is only for replication & ZTCOM does not work with replic */ + COMPUTE_LOGICAL_REC_CHECKSUM(jfb->checksum, jrec, com_csum, jrec->prefix.checksum); GTMCRYPT_ONLY(assert(!REPL_ALLOWED(csa));) JNL_WRITE_APPROPRIATE(csa, jpc, jfb->rectype, (jnl_record *)jrec, NULL, jfb); } diff --git a/sr_port/job_addr.c b/sr_port/job_addr.c index c182b2a..1faf9d6 100644 --- a/sr_port/job_addr.c +++ b/sr_port/job_addr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,14 +11,14 @@ #include "mdef.h" #include "cmd_qlf.h" -#include "rtnhdr.h" +#include #include "op.h" #include "job_addr.h" #include "zbreak.h" error_def(ERR_JOBLABOFF); -void 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) { rhdtyp *rt_hdr; int4 *lp; @@ -38,7 +38,7 @@ void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) /* Label offset with routine compiled with NOLINE_ENTRY should cause error. */ lp = find_line_addr(rt_hdr, label, offset, NULL); if (!lp) - rts_error(VARLSTCNT(1) ERR_JOBLABOFF); + return (FALSE); /* Set the pointer to address / offset for line number entry storage in lab_proxy. */ USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp;) /* On non-shared-binary, calculcate the offset to the corresponding lnr_tabent record by subtracting @@ -49,4 +49,5 @@ void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) if (NULL != labaddr) *labaddr = (char *)LINE_NUMBER_ADDR(rt_hdr, lp); *hdr = (char *)rt_hdr; + return (TRUE); } diff --git a/sr_port/job_addr.h b/sr_port/job_addr.h index 2ef8f5b..b07094f 100644 --- a/sr_port/job_addr.h +++ b/sr_port/job_addr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 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_ -void 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); #endif diff --git a/sr_port/jobexam_process.c b/sr_port/jobexam_process.c index 12e2a28..5d6942f 100644 --- a/sr_port/jobexam_process.c +++ b/sr_port/jobexam_process.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "io_params.h" #include "op.h" #include "io.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "jobexam_process.h" #ifdef UNIX @@ -47,7 +47,6 @@ GBLREF uint4 process_id; GBLREF io_pair io_std_device, io_curr_device; GBLREF mv_stent *mv_chain; GBLREF unsigned char *msp, *stackwarn, *stacktop; -GBLREF char *util_outptr, util_outbuff[OUT_BUFF_SIZE]; GBLREF boolean_t created_core; UNIX_ONLY(GBLREF sigset_t blockalrm;) DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;) @@ -75,6 +74,9 @@ void jobexam_process(mval *dump_file_name, mval *dump_file_spec) struct sigaction new_action, prev_action; sigset_t savemask; # endif + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; /* If the input file name is the result of an expression, it is likely being held in the * same temporary as the output file spec. We can tell if this is true by comparing the * address of the input and output mvals. If they are the same, make a copy of the input @@ -115,22 +117,36 @@ void jobexam_process(mval *dump_file_name, mval *dump_file_spec) # endif *dump_file_spec = empty_str_mval; dev_in_use = io_curr_device; /* Save current IO device */ - /* Save text in util_outbuff which can be detrimentally overwritten by ZSHOW */ + /* Save text in util_outbuff which can be detrimentally overwritten by ZSHOW. + * NOTE: The following code needs to be eventually moved to jobinterrupt_process.c and replaced with + * SAVE/RESTORE_UTIL_OUT_BUFFER macros, as follows: + * + * char *save_util_outptr; + * va_list save_last_va_list_ptr; + * boolean_t util_copy_saved = FALSE; + * DCL_THREADGBL_ACCESS; + * + * SETUP_THREADGBL_ACCESS; + * ... + * SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); + * ... + * RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); + */ saved_util_outbuff_len = 0; - if (NULL == util_outptr) - util_outptr = util_outbuff; - if (0 != (saved_util_outbuff_len = (int)(util_outptr - util_outbuff))) /* Caution -- assignment */ + if (NULL == TREF(util_outptr)) + TREF(util_outptr) = TREF(util_outbuff_ptr); + if (0 != (saved_util_outbuff_len = (int)(TREF(util_outptr) - TREF(util_outbuff_ptr)))) /* Caution -- assignment */ { assert(0 <= saved_util_outbuff_len); assert(saved_util_outbuff_len <= SIZEOF(saved_util_outbuff)); - memcpy(saved_util_outbuff, util_outbuff, saved_util_outbuff_len); + memcpy(saved_util_outbuff, TREF(util_outbuff_ptr), saved_util_outbuff_len); } jobexam_dump(input_dump_file_name, dump_file_spec); /* If any errors occur in job_exam_dump, the condition handler will unwind the stack to this point and return. */ if (0 != saved_util_outbuff_len) { /* Restore util_outbuff values */ - memcpy(util_outbuff, saved_util_outbuff, saved_util_outbuff_len); - util_outptr = util_outbuff + saved_util_outbuff_len; + memcpy(TREF(util_outbuff_ptr), saved_util_outbuff, saved_util_outbuff_len); + TREF(util_outptr) = TREF(util_outbuff_ptr) + saved_util_outbuff_len; } io_curr_device = dev_in_use; /* Restore IO device */ /* If we saved an mval on our stack, we need to pop it off. If there was an error while doing the @@ -197,7 +213,7 @@ void jobexam_dump(mval *dump_filename_arg, mval *dump_file_spec) parms.str.len = SIZEOF(dumpable_error_dump_file_noparms); op_close(dump_file_spec, &parms); /* Notify operator dump was taken */ - send_msg(VARLSTCNT(5) ERR_JOBEXAMDONE, 3, process_id, dump_file_spec->str.len, dump_file_spec->str.addr); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JOBEXAMDONE, 3, process_id, dump_file_spec->str.len, dump_file_spec->str.addr); REVERT; } @@ -224,7 +240,7 @@ CONDITION_HANDLER(jobexam_dump_ch) UNIX_ONLY(util_out_print(0, OPER)); VMS_ONLY(sig->chf$l_sig_args -= 2); VMS_ONLY(callg(send_msg, &sig->chf$l_sig_args)); - send_msg(VARLSTCNT(3) ERR_JOBEXAMFAIL, 1, process_id); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBEXAMFAIL, 1, process_id); /* Stop the errors here and return to caller */ UNIX_ONLY(util_out_print("", RESET)); /* Prevent rts_error from flushing this error later */ diff --git a/sr_port/jobinterrupt_event.c b/sr_port/jobinterrupt_event.c index e492199..a0e089b 100644 --- a/sr_port/jobinterrupt_event.c +++ b/sr_port/jobinterrupt_event.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,6 +24,9 @@ # include # include "efn.h" #endif +#ifdef GTM_PTHREAD +# include +#endif #include "gtm_stdio.h" #include "io.h" @@ -34,17 +37,19 @@ #include "jobinterrupt_event.h" #include "fix_xfer_entry.h" -GBLREF xfer_entry_t xfer_table[]; +GBLREF xfer_entry_t xfer_table[]; GBLREF volatile int4 outofband; GBLREF volatile boolean_t dollar_zininterrupt; /* Routine called when an interrupt event occurs (signaled by mupip intrpt or other future method - of signaling interrupts). This code is driven as a signal handler on Unix and from the START_CH - macro on VMS where it intercepts the posix signal. -*/ + * of signaling interrupts). This code is driven as a signal handler on Unix and from the START_CH + * macro on VMS where it intercepts the posix signal. + */ UNIX_ONLY(void jobinterrupt_event(int sig, siginfo_t *info, void *context)) VMS_ONLY(void jobinterrupt_event(void)) -{ /* Note the (presently unused) args are to match signature for signal handlers in Unix */ +{ + FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); + /* Note the (presently unused) args are to match signature for signal handlers in Unix */ if (!dollar_zininterrupt) (void)xfer_set_handlers(outofband_event, &jobinterrupt_set, 0); } @@ -52,14 +57,14 @@ VMS_ONLY(void jobinterrupt_event(void)) /* Call back routine from xfer_set_handlers to complete outofband setup */ void jobinterrupt_set(int4 dummy_val) { - int4 status; +# ifdef VMS + int4 status; - VMS_ONLY( - status = sys$setef(efn_outofband); - assert(SS$_WASCLR == status); - if (SS$_WASCLR != status && SS$_WASSET != status) - GTMASSERT; - ) + status = sys$setef(efn_outofband); + assert(SS$_WASCLR == status); + if ((SS$_WASCLR != status) && (SS$_WASSET != status)) + GTMASSERT; +# endif if (jobinterrupt != outofband) { /* We need jobinterrupt out of band processing at our earliest convenience */ outofband = jobinterrupt; @@ -70,5 +75,5 @@ void jobinterrupt_set(int4 dummy_val) FIX_XFER_ENTRY(xf_forchk1, op_startintrrpt); FIX_XFER_ENTRY(xf_forloop, op_forintrrpt); } - VMS_ONLY(sys$wake(0,0);) + VMS_ONLY(sys$wake(0,0)); } diff --git a/sr_port/jobinterrupt_process.c b/sr_port/jobinterrupt_process.c index 1e228e0..5b8ad3e 100644 --- a/sr_port/jobinterrupt_process.c +++ b/sr_port/jobinterrupt_process.c @@ -15,7 +15,7 @@ #include "error.h" #include "indir_enum.h" -#include "rtnhdr.h" +#include #include "op.h" #include "stack_frame.h" #include "error_trap.h" diff --git a/sr_port/jobinterrupt_process_cleanup.c b/sr_port/jobinterrupt_process_cleanup.c index 2ba1aa3..fc4dbc5 100644 --- a/sr_port/jobinterrupt_process_cleanup.c +++ b/sr_port/jobinterrupt_process_cleanup.c @@ -12,7 +12,7 @@ #include "mdef.h" #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "stringpool.h" #include "objlabel.h" diff --git a/sr_port/jobparams.h b/sr_port/jobparams.h index 704dd93..b15b406 100644 --- a/sr_port/jobparams.h +++ b/sr_port/jobparams.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,9 @@ JPDEF (jp_eol, jpdt_nul), JPDEF (jp_account, jpdt_nul), +#ifdef UNIX + JPDEF (jp_cmdline, jpdt_str), +#endif JPDEF (jp_default, jpdt_str), JPDEF (jp_detached, jpdt_nul), JPDEF (jp_error, jpdt_str), diff --git a/sr_port/jobparamstrs.h b/sr_port/jobparamstrs.h index 3764529..43d9ba3 100644 --- a/sr_port/jobparamstrs.h +++ b/sr_port/jobparamstrs.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,6 +11,9 @@ JPSDEF ( 3, "ACC", jp_account), JPSDEF ( 8, "ACCOUNTI*", jp_account), +#ifdef UNIX +JPSDEF ( 3, "CMD", jp_cmdline), JPSDEF ( 7, "CMDLINE", jp_cmdline), +#endif JPSDEF ( 3, "DEF", jp_default), JPSDEF ( 7, "DEFAULT", jp_default), JPSDEF ( 3, "DET", jp_detached), JPSDEF ( 8, "DETACHED", jp_detached), JPSDEF ( 3, "ERR", jp_error), JPSDEF ( 5, "ERROR", jp_error), diff --git a/sr_port/lastchance2.c b/sr_port/lastchance2.c index 8f5d442..8a2f872 100644 --- a/sr_port/lastchance2.c +++ b/sr_port/lastchance2.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,7 +50,7 @@ CONDITION_HANDLER(lastchance2) { int4 actual_exi_condition; - actual_exi_condition = exi_condition; + actual_exi_condition = (EXIT_NRM != exi_condition ? exi_condition : EXIT_ERR); PRN_ERROR; dec_err(VARLSTCNT(1) ERR_GVRUNDOWN); ESTABLISH(lastchance3); diff --git a/sr_port/lclcol.mpt b/sr_port/lclcol.mpt index ee6cc50..a994d65 100644 --- a/sr_port/lclcol.mpt +++ b/sr_port/lclcol.mpt @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2004 Sanchez Computer Associates, Inc. ; +; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -10,14 +10,16 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %lclcol ; ; ; Local Variable Collation Control ; -get() q $v("YLCT") +get() q $v("YLCT") getncol() q $v("YLCT","ncol") ; return null collation order ; -set(lct,ncol) +getnct() q $v("YLCT","nct") ; return numeric collation type + ; +set(lct,ncol,nct) n ok,$et s $et="s $ec="""" s ok=0",ok=1 - if ok&$data(lct)&$data(ncol) v "YLCT":lct:ncol q ok - if ok&$data(lct)&'$data(ncol) v "YLCT":lct:-1 q ok - if ok&'$data(lct)&$data(ncol) v "YLCT":-1:ncol q ok - if ok&'$data(lct)&'$data(ncol) v "YLCT":-1:-1 q ok + s:'$data(lct) lct=-1 + s:'$data(ncol) ncol=-1 + s:'$data(nct) nct=-1 + v:ok "YLCT":lct:ncol:nct q ok diff --git a/sr_port/line.c b/sr_port/line.c index 8af922c..7624953 100644 --- a/sr_port/line.c +++ b/sr_port/line.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,6 +27,7 @@ GBLREF command_qualifier cmd_qlf; error_def(ERR_BLKTOODEEP); error_def(ERR_COMMAORRPAREXP); +error_def(ERR_FALLINTOFLST); error_def(ERR_LSEXPECTED); error_def(ERR_MULTFORMPARM); error_def(ERR_MULTLAB); @@ -35,12 +36,12 @@ error_def(ERR_NESTFORMP); boolean_t line(uint4 *lnc) { - boolean_t success; + boolean_t success, embed_error = FALSE; int parmcount, varnum; short int dot_count; mlabel *x; mline *curlin; - triple *first_triple, *parmbase, *parmtail, *r; + triple *first_triple, *parmbase, *parmtail, *r, *e; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -51,6 +52,8 @@ boolean_t line(uint4 *lnc) curlin = (mline *)mcalloc(SIZEOF(*curlin)); curlin->line_number = 0; curlin->table = FALSE; + assert(0 == TREF(expr_depth)); + (TREF(side_effect_base))[0] = FALSE; TREF(last_source_column) = 0; if (TK_INTLIT == TREF(window_token)) int_label(); @@ -87,43 +90,64 @@ boolean_t line(uint4 *lnc) { advancewindow(); parmbase = parmtail = newtriple(OC_BINDPARM); - for (parmcount = 0; TK_RPAREN != TREF(window_token); parmcount++) + /* To error out on fall-throughs to labels with a formallist, we are inserting an error immediately before + * the LINESTART/LINEFETCH opcode. So, first we need to find the LINESTART/LINEFETCH preceding the + * BINDPARM we just inserted. + */ + assert((OC_LINESTART == parmbase->exorder.bl->opcode) || (OC_LINEFETCH == parmbase->exorder.bl->opcode)); + assert(0 != parmbase->exorder.bl->src.line); + /* No error should be inserted before the first label of the routine. */ + if ((mlabtab->rson != x) || TREF(code_generated)) { - if (TK_IDENT != TREF(window_token)) + e = maketriple(OC_RTERROR); + e->operand[0] = put_ilit(ERR_FALLINTOFLST); + /* Not a subroutine/func reference. */ + e->operand[1] = put_ilit(FALSE); + r = parmbase->exorder.bl->exorder.bl; + dqins(r, exorder, e); + embed_error = TRUE; + } + if (success) + { + for (parmcount = 0; TK_RPAREN != TREF(window_token); parmcount++) { - stx_error(ERR_NAMEEXPECTED); - success = FALSE; - break; - } else - { - varnum = get_mvaddr(&(TREF(window_ident)))->mvidx; - for (r = parmbase->operand[1].oprval.tref; r; r = r->operand[1].oprval.tref) + if (TK_IDENT != TREF(window_token)) { - assert(TRIP_REF == r->operand[0].oprclass); - assert(ILIT_REF == r->operand[0].oprval.tref->operand[0].oprclass); - assert((TRIP_REF == r->operand[1].oprclass) || (0 == r->operand[1].oprclass)); - if (r->operand[0].oprval.tref->operand[0].oprval.ilit == varnum) - { - stx_error(ERR_MULTFORMPARM); - success = FALSE; - break; - } - } - if (!success) + stx_error(ERR_NAMEEXPECTED); + success = FALSE; break; - r = newtriple(OC_PARAMETER); - parmtail->operand[1] = put_tref(r); - r->operand[0] = put_ilit(varnum); - parmtail = r; - advancewindow(); - } - if (TK_COMMA == TREF(window_token)) - advancewindow(); - else if (TK_RPAREN != TREF(window_token)) - { - stx_error(ERR_COMMAORRPAREXP); - success = FALSE; - break; + } else + { + varnum = get_mvaddr(&(TREF(window_ident)))->mvidx; + for (r = parmbase->operand[1].oprval.tref; r; r = r->operand[1].oprval.tref) + { + assert(TRIP_REF == r->operand[0].oprclass); + assert(ILIT_REF == r->operand[0].oprval.tref->operand[0].oprclass); + assert((TRIP_REF == r->operand[1].oprclass) + || (NO_REF == r->operand[1].oprclass)); + if (r->operand[0].oprval.tref->operand[0].oprval.ilit == varnum) + { + stx_error(ERR_MULTFORMPARM); + success = FALSE; + break; + } + } + if (!success) + break; + r = newtriple(OC_PARAMETER); + parmtail->operand[1] = put_tref(r); + r->operand[0] = put_ilit(varnum); + parmtail = r; + advancewindow(); + } + if (TK_COMMA == TREF(window_token)) + advancewindow(); + else if (TK_RPAREN != TREF(window_token)) + { + stx_error(ERR_COMMAORRPAREXP); + success = FALSE; + break; + } } } if (success) @@ -199,12 +223,19 @@ boolean_t line(uint4 *lnc) assert(TREF(for_stack_ptr) == TADR(for_stack)); if (first_triple->exorder.fl == TREF(curtchain)) newtriple(OC_NOOP); /* empty line (comment, blank, etc) */ - curlin->externalentry = first_triple->exorder.fl; - /* First_triple points to the last triple before this line was processed. Its forward link will point to a - * LINEFETCH or a LINESTART, or possibly a NOOP. It the line was a comment, there is only a LINESTART, and - * hence no "real" code yet. - */ - TREF(code_generated) = TREF(code_generated) | ((OC_NOOP != first_triple->exorder.fl->opcode) - && (first_triple->exorder.fl->exorder.fl != TREF(curtchain))); + if (embed_error) + { /* The entry point to the label should be LINESTART/LINEFETCH, not the RTERROR. */ + curlin->externalentry = e->exorder.fl; + TREF(code_generated) = TRUE; + } else + { + curlin->externalentry = first_triple->exorder.fl; + /* First_triple points to the last triple before this line was processed. Its forward link will point to a + * LINEFETCH or a LINESTART, or possibly a NOOP. If the line was a comment, there is only a LINESTART, and + * hence no "real" code yet. + */ + TREF(code_generated) = TREF(code_generated) | ((OC_NOOP != first_triple->exorder.fl->opcode) + && (first_triple->exorder.fl->exorder.fl != TREF(curtchain))); + } return success; } diff --git a/sr_port/lke.hlp b/sr_port/lke.hlp index 495a584..2a80563 100644 --- a/sr_port/lke.hlp +++ b/sr_port/lke.hlp @@ -1,241 +1,554 @@ +1 Introduction + Introduction -1 Overview - The MUMPS LOCK Utility - The GT.M LOCK Utility, LKE, provides a tool for examining and changing - the GT.M LOCK environment. In MUMPS, the LOCK command reserves one or - more resource names. Only one process at a time can reserve a resource - name. No other process sharing the same environment can successfully - LOCK that resource name at the same time. MUMPS code commonly uses - LOCKs as flags controlling access to global data. Generally a LOCK - specifies the same as the name of the global variable that requires - protected access. However, this is only a convention. A LOCK argument - may contain any subscripted or unsubscripted MUMPS name including a - name with no preceding caret (^). Because they have the appearance of - local variable names, resource names with no preceding caret (^) are - commonly referred to as "local LOCKs." + The M Lock Utility (LKE) is a tool for examining and changing the GT.M + LOCK environment. For a description of M LOCKs, refer to the LOCKs section + in the General Language Features of M chapter and the description of the + LOCK command in the Commands chapter of the GT.M Programmer's Guide. - The ZALLOCATE and ZDEALLOCATE commands provide an alternative, - non-standard, mechanism for managing LOCKs. + The two primary functions of the M Lock Utility (LKE) are: -2 Functions - Functions - The two primary functions of the MUMPS LOCK Utility (LKE) are: + o SHOW all or specified LOCKs currently active + o CLEAR all or specified LOCKs currently active - o SHOW all or specified LOCKs currently active on the system + When debugging an M application, you may use LKE to identify a possible + deadlock situation, that is, two or more processes have LOCKs and are + waiting to add resource names LOCKed by the other(s). - o CLEAR all or specified LOCKs currently active on the system + Process 1 Process 2 + LOCK A + LOCK B + LOCK +A + LOCK +B - When debugging a MUMPS application, you may use LKE to identify and - clear a possible deadlock situation, i.e., two or more processes - have LOCKs and are waiting to add resource names LOCKed by the - other(s). + Process 1 has A LOCKed and attempts to LOCK B. Process 2 has B LOCKed and + attempts to LOCK A. Because these processes do not release their current + LOCKs before adding additional LOCKs, nor do they provide a timeout to + detect the problem, they are deadlocked. Neither process can proceed + normally. You can use LKE to release one of the LOCKs so both processes + may execute. However, because releasing a LOCK may cause the process to + violate its design assumptions, terminating one process is generally a + safer way to break the deadlock. - When used with GT.CM, LKE may display and change information on - other nodes of a distributed database system. + **Note** -2 LOCK_database - MUMPS LOCKs and Global Directories - GT.M distributes the LOCK database among the database files - identified by the Global Directory (GD). The Global Directory - Editor (GDE) creates and maintains Global Directories. + When a process leaves M, GT.M normally releases any LOCKs or ZALLOCATEs + held by that process. If a GT.M process terminates abnormally, or if the + system "crashes" while a GT.M process is active, GT.M cannot perform + normal clean-up. However, as soon as any other process waits several + seconds for a LOCK owned by a process that no longer exists, GT.M + automatically clears the "orphaned" LOCK. - GT.M maps LOCKs of resource names starting with a caret (^) to the - database file used to map variables with the same name. If the - Global Directory maps the name A to file A.DAT, GT.M maps all LOCKs - on resource name ^A to file A.DAT. +2 Invoke + Invoke - GT.M maps LOCKs on names not starting with a caret (^) to the - region of the database specified with the GDE command LOCK -REGION. - By default, GDE creates Global Directories mapping local LOCKs to - the region DEFAULT. + GT.M installation procedure places the LKE utility package in a directory + specified by the environment variable gtm_dist. - These two factors result in the following: + LKE requires that the environment variable gtmgbldir be defined. - o ^ LOCKs automatically intersect for all users of the same data - in any database file, because GT.M stores the ^ LOCKs in the - same file as the data + Invoke LKE using the following command at the shell prompt. If this does + not work, consult your system manager to investigate setup and file access + issues. - o "local" LOCKs intersect dependent on the Global Directory, - because users may access the database through different Global - Directories. + $gtm_dist/lke LKE> -2 Global_Directories - Establishing a Global Directory - GDE and LKE use the environment variable gtmgbldir to identify - which file to use for the Global Directory. gtmgbldir should be - defined by individual users in their login files. + **Important** - Example + Always run LKE on the node where the lock is held. - $ gtmgbldir=prod.gld - $ export gtmgbldir + When LKE is ready to accept commands, it displays the LKE> prompt. To + leave LKE, enter the EXIT command at the LKE> prompt. - When a process invokes a GT.M image, GT.M identifies the current - Global Directory by the environment variable gtmgbldir. Within - MUMPS, SET $zgbldir=expr changes the Global Directory. $zgbldir is - an intrinsic special variable. An individual LOCK, ZALLOCATE or - ZDEALLOCATE argument may specify a Global Directory with the - extended global syntax. + When additional information is entered on the command line after the LKE + command, LKE processes the additional information as its command. -1 CLEAR - C[LEAR] - The CLEAR command removes active LOCKs. The format of the CLEAR - command is: + $gtm_dist/lke show -all + + This command displays all current LOCKs and then returns to the shell + prompt. + + If your LKE argument contains quotes, precede each quote in the argument + by a back-slash (\) or enclose the entire argument in a set of quotes + (matching single or double). Apply this convention only for those LKE + commands that you run from the shell. + + $gtm_dist/lke show -lock="^Account(\"Name\")" + $gtm_dist/lke show -lock='^Account("Name")' + + Both these commands display the status of LOCK ^Account("Name") in the + default region. + +1 Commands + Commands + + The format for the LKE commands is: + + command [-qualifier[=qualifier-value]] + + LKE accepts command and qualifier abbreviations. The section describing + each command provides the minimal abbreviation that can be used for that + command, and the command qualifiers, if any. FIS recommends the use of a + minimum of four characters for key words in scripts to ensure new keywords + do not conflict with older scripts. + +2 Clear + Clear + + Use the CLEAR command to remove active LOCKs. + + **Caution** + + FIS recommends restricting the use of the LKE CLEAR facility to debugging + environments; removing LOCKs in a production environment typically + violates application design assumptions and can cause aberrant process + behavior. GT.M automatically removes abandoned LOCKs so it is typically + safer to MUPIP STOP a process that is inappropriately hanging on to a + LOCK. + + The format of the CLEAR command is: C[LEAR] [-qualifier...] - The optional CLEAR command qualifiers are: + The optional qualifiers are: -A[LL] - -I[NTERACTIVE] - -O[UTPUT]=file-spec + -L[OCK] + -[NO]C[RIT] + -[NO]EXACT + -[NO]I[NTERACTIVE] + -O[UTPUT]="file-name" -P[ID]=pid -R[EGION]=region-name By default, CLEAR operates interactively (-INTERACTIVE). -2 Qualifiers + Qualifiers for CLEAR --ALL - -A[LL] - Specifies the removal of all current LOCKs. If used with the - -REGION qualifier -ALL removes all LOCKs in the region. Issue a - CLEAR -ALL only when there are no active GT.M processes using - LOCKs or when you can predict the effect on the application. + -A[LL] - The -ALL qualifier is incompatible with the -INTERACTIVE - qualifier. + Specifies all current LOCKs. --INTERACTIVE - -I[NTERACTIVE] - Clears one LOCK at a time interactively. LKE displays each - current LOCK with the PID of the owner process and prompts for - verification that the LOCK should be cleared. LKE retains the - LOCK for any response other than Y[ES]. + o -ALL removes all current LOCKs. + o If used, CLEAR and -REGION qualifier, -ALL removes all LOCKs in that + region. + o Issue a CLEAR - ALL only when there are no active GT.M processes using + LOCKs, or when you can predict the effect on the application. + o By default, CLEAR -ALL operates interactively (-INTERACTIVE). - The -INTERACTIVE qualifier is incompatible with the -ALL - qualifier. + -[NO]C[RIT] - By default, CLEAR operates interactively (-INTERACTIVE). + Allows LKE CLEAR to work even if another process is holding a critical + section. --OUTPUT - -OUTPUT=file-spec - Directs the reporting of all cleared LOCKs. If you specify an - existing file, LKE overwrites that file. + **Caution** - The -OUTPUT qualifier is compatible with all other qualifiers. + This can damage current LOCKs and the LOCK mechanism. It is intended for + use only under the direction of FIS. - By default, CLEAR sends its messages to the standard output. + By default LKE operates in CRIT mode and ensures a consistent view of + LOCKs by using the database critical section(s). --PID - -/P[ID]=pid - Clears all LOCKs associated with the specified process - identification number. LKE interprets the PID as a decimal - number. This command provides a means for directing CLEAR to - LOCKs held by a process that is behaving abnormally. + -[NO]EXACT - The -PID qualifier is compatible with all other qualifiers. + Limits the CLEAR command to the exact resource name specified with + -LOCK=resource_name. NOEXACT (the default) treats the specified resource + name as a prefix and works not only on it, but also on any of its + descendants, since their existence effectively LOCK their parent tree. --REGION - -/R[EGION]=region-name - Clears LOCKs mapped by the current Global Directory to a region - specified by the region-name. + -L[OCK]=""resource_name"" - The -REGION qualifier is compatible with all other qualifiers. + Unless used with -EXACT, specifies the leading prefix for an implicit wild + card search of all locks that start with the resource_name. - By default, CLEAR -REGION= operates interactively (-INTERACTIVE). + o The resource_name is enclosed in two double quotation marks ("" ""). + Because M resource names are formatted the same as global nodes with + punctuation characters, in this context they are usually enclosed in + sets of double quotation marks with string subscripts enclosed in sets + of two double quotations. + o When used with CLEAR, -LOCK removes the locks that start with + resource_name. + o When used with SHOW,-LOCK provides a precise way to examine the + specified lock. -1 EXIT - E[XIT] - The EXIT command ends an LKE session. The format of the EXIT command - is: + -[NO]I[NTERACTIVE] + + Interactively clears one LOCK at a time. LKE displays each current LOCK + with the PID of the owner process and prompts for verification that the + LOCK should be cleared. LKE retains the LOCK for any response other than + Y[ES]. + + o By default, CLEAR operates interactively (-INTERACTIVE). + o To avoid holding a lock resource too long, LKE skips to the next + matching LOCK if there is no operator response for several seconds. + o -NOINTERACTIVE forces the action to take place without user + confirmation of each change. Using -NOINTERACTIVE prevents the LKE + operator from controlling the LOCK subsystem for potentially long + periods of time when many locks are held. To do this, it limits the + amount of time it waits for each response. + + -O[UTPUT]="file-name" + + Directs the reporting of all specified LOCKs to a file. + + o If you specify an existing file, LKE creates a new version and + overwrites that file. + o If file-name has permission issues, OUTPUT reports the cause of the + error. + o The -OUTPUT qualifier is compatible with all other qualifiers. + o By default, CLEAR sends output messages to stdout. + + -P[ID]=pid + + Specifies the process identification number that holds a LOCK on a + resource name. + + o LKE interprets pid as a decimal number. + o PID clears LOCKs held by the process with the specified process + identification number. + o Provides a means for directing CLEAR to LOCKs held by a process that + is behaving abnormally. + o The -PID qualifier is compatible with all other qualifiers. + + -R[EGION]=region-name + + region-namespecifies the region that holds the locked resource names. + + o REGION clears LOCKs mapped by the current global directory to a region + specified by the region-name. + o The -REGION qualifier is compatible with all other qualifiers. + o By default, CLEAR -REGION= operates interactively (-INTERACTIVE). + + Example: + + LKE>CLEAR -ALL + + This command clears all current LOCKs. + + Example: + + LKE>clear -pid=2325 -interactive + + This command presents all LOCKs held by the process with PID equal to + 2325. You can choose whether or not to clear each LOCK. + + LKE>clear -reg=areg -interactive + + This command produces an output like the following: + + AREG ^a Owned by PID= 2083 which is an existing + process Clear lock ? + + Type Yes or Y in response to the prompt. + + LKE responds with an informational message: + + %GTM-S-LCKGONE, Lock removed : ^a + + Type Yes or N or No or N until all LOCKs are displayed and acted upon. + + LKE> clear -pid=4208 -nointeractive + + This command clears the lock held by a process with PID 4208. This command + produces an output like the following: + + DEFAULT Lock removed : ^A + + Note that -NOINTERACTIVE forced the action without asking for a + confirmation. + + Example: + + LKE>clear -lock="^a("b") + Clear lock ? y + Lock removed : ^a("b") + LKE> + + This command clears lock ^a("b") in the default region. + + Example: + + LKE>clear -lock="^a" -nointeractive + + This command clears all the locks that start with "^a" in the default + region. -NOINTERACTIVE qualifier instructs LKE to clear these locks + without further user intervention. + + Example: + + LKE>clear -lock="^a" -exact -nointeractive + + This command clears lock ^a in the default region. -NOINTERACTIVE + instructs LKE to clear lock ^a without further user intervention. + + Example: + + LKE>CLEAR -PID=4109 -LOCK=""^A"" + Clear lock ? Y + Lock removed : ^A + LKE> + + This command clears LOCK ^A held by process with PID 4109. + +2 SHow + SHow + + Use the SHOW command to get status of the LOCK mechanism and the LOCK + database. The format of the SHOW command is: + + SH[OW] [-qualifier...] + + The optional qualifiers are: + + -A[LL] + -L[OCK] + -[NO]C[RIT] + -O[UTPUT]="file-name" + -P[ID]=pid + -R[EGION]=region-name + -W[AIT] + + o By default, SHOW displays -A[LL]. + o The SHOW command reports active LOCKs. Information includes the LOCK + resource name and the process identification (PID) of the LOCK owner. + o LKE SHOW displays lock space usage with a message in the form of: + "%GTM-I-LOCKSPACEUSE, Estimated free lock space: xxx% of pppp pages." + If the lock space is full, it also displays a LOCKSPACEFULL error. + o A LOCK command which finds no room in LOCK_SPACE to queue a waiting + LOCK, does a slow poll waiting for LOCK_SPACE to become available. If + LOCK does not acquire the ownership of the named resource with the + specified timeout, it returns control to the application with $TEST=0. + If timeout is not specified, the LOCK command continues to do a slow + poll till the space becomes available. + o LOCK commands which find no available lock space send a LOCKSPACEFULL + message to the operator log. To prevent flooding the operator log, + GT.M suppresses further such messages until the lock space usage drops + below 75% full. + o The results of a SHOW may be immediately "outdated" by M LOCK + activity. + o If the LOCK is owned by a GT.CM server on behalf of a client GT.M + process, then LKE SHOW displays the client NODENAME (limited to the + first 15 characters) and clientPID. The client PID (CLNTPID) is a + decimal value in UNIX. + + **Note** + + GT.CM is an RPC-like way of remotely accessing a GT.M database. + + -ALL + + Specifies all current LOCKs. + + o -ALL displays all current LOCKs in all regions and information about + the state of processes owning these LOCKs. + o The -ALL qualifier is compatible with all other qualifiers. + o When -ALL is combined with -PID or -REGION, the most restrictive + qualifier prevails. + o SHOW -ALL and -WAIT displays both -ALL and -WAIT information. + + -L[OCK]=resource_name + + resource_name specifies a single lock. + + o The resource_name is enclosed in double quotation marks ("" ""). + Because M resource names are formatted the same as global nodes with + punctuation characters, in this context they are usually enclosed in + sets of double quotation marks with string subscripts enclosed in sets + of two double quotations. + o When used with the CLEAR command, the LOCK qualifier removes the + specified lock. + o When used with the SHOW command, the LOCK qualifier provides a precise + way to examine the specified lock and any descendant LOCKed resources. + + -[NO]C[RIT] + + Allows the SHOW command to work even if another process is holding a + critical section. + + o By default LKE operates in CRIT mode and ensures a consistent view of + LOCKs by using the database critical section(s). + o Use NOCRIT with SHOW only when normal operation is unsuccessful, as + NOCRIT may cause LKE to report incomplete or inconsistent information. + + -O[UTPUT]="file-name" + + Directs the reporting of all specified LOCKs to a file. + + o If you specify an existing file, LKE creates a new version and + overwrites that file. + o The -OUTPUT qualifier is compatible with all other qualifiers. + o By default, the SHOW command send output messages to stdout. + + -P[ID]=pid + + Specifies the process identification number that holds a LOCK on a + resource name. + + o LKE interprets pid as a decimal number. + o PID displays all LOCKs owned by the specified process identification + number. + o The -PID qualifier is compatible with all other qualifiers; the most + restrictive of the qualifiers prevails. + o By default, SHOW displays the LOCKs for all PIDs. + + -R[EGION]=region-name + + Specifies the region that holds the locked resource names. + + o The REGION qualifier displays LOCKs of that specified region. + o The REGION qualifier is compatible with all other qualifiers; the most + restrictive of the qualifiers prevails. + o By default, SHOW displays the LOCKs for all regions. + + -W[AIT] + + Displays the LOCK resource name and the process state information of all + processes waiting for the LOCK to be granted. + + o SHOW -WAIT does not display the owner of the LOCK. + o SHOW -ALL -WAIT displays both -ALL and -WAIT information. + o When a process abandons a "wait" request, that request may continue to + appear in LKE SHOW -WAIT displays. This appearance is harmless, and is + automatically eliminated if the GT.M lock management requires the + space which it occupies. + + Use the following procedure to display all LOCKs active in the database(s) + defined by the current global directory. + + LKE> SHOW -ALL -WAIT + + This produces an output like the following: + + No locks were found in DEFAULT + AREG + ^a Owned by PID=2080 which is an existing process + BREG + ^b(2) Owned by PID= 2089 which is a nonexistent process + No locks were found in CREG + + Example: + + LKE>SHOW -ALL + + This command displays all LOCKs mapped to all regions of the current + global directory. It produces an output like the following: + + DEFAULT + ^A Owned by PID= 5052 which is an existing process + ^B Owned by PID= 5052 which is an existing process + %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages + + Example: + + LKE>show -lock="^a"(""b"")" + + This command shows lock ^a("b") in the default region. + + Example: + + LKE>SHOW -CRIT + + This command displays all the applicable locks held by a process that is + holding a critical section. + + Example: + + LKE>show -all -output="abc.lk" + + This command create a new file called abc.lk that contains the output of + the SHOW -ALL command. + + Example: + + LKE>show -pid=4109 + + This command displays all locks held by process with PID 4109 and the + total lock space usage. + + Example: + + LKE>show -region=DEFAULT -lock=""^A"" + + This command displays the lock on ^A in the region DEFAULT. It produces an + output like the following: + + DEFAULT + ^A Owned by PID= 5052 which is an existing process + %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages + +2 Exit + Exit + + The EXIT command ends an LKE session. The format of the EXIT command is: E[XIT] -1 HELP - H[ELP] - The HELP command explains LKE commands. The format of the HELP command - is: +2 Help + Help + + The HELP command explains LKE commands. The format of the HELP command is: H[ELP] [options...] - Enter the LKE command for which you want information at the Topic - prompt(s). Use or to return to the LKE prompt. + Enter the LKE command for which you want information at the Topic + prompt(s) and then press RETURN or CTRL-Z to return to the LKE prompt. - Example + Example: LKE> HELP SHOW This command displays help for the SHOW command. +2 SPawn + SPawn -1 SHOW - SH[OW] - The SHOW command provides a status report on the LOCK mechanism and - the LOCK database. The format of the SHOW command is: - - SH[OW] [ -qualifier...] - - By default, SHOW displays -ALL. - - The SHOW command reports active LOCKs. Information displayed about - specific LOCKs includes the LOCK resource name and the process - identification (PID) of the LOCK owner. The results of a SHOW may be - immediately "outdated" by MUMPS LOCK activity. - -2 Qualifiers --ALL - -A[LL] - Specifies a display of all current LOCKs in all regions and - information about the state of processes owning these LOCKs. The - -ALL qualifier is compatible with all other qualifiers. SHOW - -ALL -WAIT displays both -ALL and -WAIT information. - - By default, SHOW displays -ALL. - --OUTPUT - -OUTPUT=file-spec - Directs the reporting of the current LOCKs. When you specify a - file, LKE overwrites that file. - - The -OUTPUT qualifier is compatible with all other qualifiers. - - By default, SHOW directs all messages to SYS$OUTPUT. - --PID - -P[ID]=process-identification - Displays all LOCKs owned by the specified PID. - - The -PID qualifier is compatible with all other qualifiers. - - By default, SHOW displays the LOCKs for all PIDs. - --REGION - -R[EGION]=region-name - Displays LOCKs for the specified region. - - The -REGION qualifier is compatible with all other qualifiers. - - By default, SHOW displays the LOCKs for all regions. - --WAIT - -W[AIT] - Displays the LOCK resource name and the process state - information of all processes waiting for the LOCK to be granted. - LKE does not display the owner of the LOCK. SHOW -ALL -WAIT - displays both -ALL and -WAIT information. - -1 SPAWN - SP[AWN] - The SPAWN command creates a sub-process for access to the shell - without terminating the current LKE environment. Use the SPAWN command - to suspend a session and issue shell commands such as ls or printenv. - The SPAWN command accepts an optional command string for execution by - the spawned sub-process. If the SPAWN has command string parameter, - the created sub-process prompts and accepts any legal shell command. - To terminate the sub-process use the shell logout command. + Use the SPAWN command to create a sub-process for access to the shell + without terminating the current LKE environment. Use the SPAWN command to + suspend a session and issue shell commands such as ls or printenv. The format of the SPAWN command is: SP[AWN] + The SPAWN command has no qualifiers. + + Example: + + LKE>spawn + + This command creates a sub-process for access to the current shell without + terminating the current LKE environment. Type exit to return to LKE. + +1 Summary + Summary + + +-------------------------------------------------------------------+ + | COMMAND | QUALIFIER | COMMENTS | + |---------+---------------------+-----------------------------------| + | | -ALL | | + | | -L[OCK] | | + | | -[NO]CRIT | | + | | -[NO]EXACT | | + | C[LEAR] | | Use CLEAR with care and planning. | + | | -[NO]I[NTERACTIVE] | | + | | -O[UTPUT]=file-name | | + | | -P[ID]=pid | | + | | -R[EGION]=name | | + |---------+---------------------+-----------------------------------| + | E[XIT] | none | - | + |---------+---------------------+-----------------------------------| + | H[ELP] | [option] | - | + |---------+---------------------+-----------------------------------| + | | -ALL | | + | | -L[OCK] | | + | | -[NO]CRIT | | + | | -N[OINTERACTIVE] | | + | SH[OW] | | - | + | | -O[UTPUT]=file-name | | + | | -P[ID]=pid | | + | | -R[EGION]=name | | + | | -W[AIT] | | + |---------+---------------------+-----------------------------------| + | SP[AWN] | none | shellcommand | + +-------------------------------------------------------------------+ + diff --git a/sr_port/lke_clear.c b/sr_port/lke_clear.c index 4b1cc02..e80b6c2 100644 --- a/sr_port/lke_clear.c +++ b/sr_port/lke_clear.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -94,7 +94,7 @@ void lke_clear(void) locks = gtcmtr_lke_clearreq(gv_cur_region->dyn.addr->cm_blk, gv_cur_region->cmx_regnum, all, interactive, pid, &node); # else - gtm_putmsg(VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM region - locks must be cleared on the local node"), ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); continue; @@ -117,18 +117,18 @@ void lke_clear(void) rel_crit(gv_cur_region); } else { - gtm_putmsg(VARLSTCNT(2) ERR_BADREGION, 0); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_BADREGION, 0); locks = TRUE; } if (!locks) { - gtm_putmsg(VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region)); } } } if (!match && reg.len != 0) - rts_error(VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr); } diff --git a/sr_port/lke_getki.c b/sr_port/lke_getki.c index 5ef7a2a..3edcf4f 100644 --- a/sr_port/lke_getki.c +++ b/sr_port/lke_getki.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,7 @@ #include "gtm_string.h" #include "lke_getcli.h" +#include "gtm_ctype.h" /* Needed for TOUPPER() */ /* This routine performs the necessary transformation of the LOCK keys passed in * from the CLI layer and produces a canonical formatted key. This routine @@ -30,7 +31,8 @@ int lke_getki(char* src, int srclen, char* outbuff) { char *inptr, *nextptr, *intop, *outptr, *tmpptr; mval subsc = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); - char one_lockbuf[MAX_ZWR_KEY_SZ + 1]; + char one_lockbuf[MAX_ZWR_KEY_SZ + 1], *one_char; + char *valid_char = "HAR"; /* This is used for validating characters following $ZCH and $C */ if (srclen > 1 && '"' == src[0] && '"' == src[srclen - 1]) { @@ -55,9 +57,37 @@ int lke_getki(char* src, int srclen, char* outbuff) outptr += inptr - src; for (intop = src + srclen; inptr < intop; inptr = nextptr) { - if ('$' == *inptr) - { /* the entire subscript is within $C() or $ZCH() */ - *outptr++ = *inptr++; + if (')' == *inptr) /* Catches incomplete lists or string concatenations */ + return -1; + else if ('$' == *inptr) + { /* the entire subscript is within $C() or $ZCH */ + *outptr++ = '$'; + inptr++; + if (('z' == *inptr) || ('Z' == *inptr)) + { /* Very likely $ZCHAR() */ + *outptr++ = 'Z'; + inptr++; + } + if (('c' == *inptr) || ('C' == *inptr)) + { + *outptr++ = 'C'; + inptr++; + if (('Z' == *(outptr - 2)) && (('h' == *inptr) || ('H' == *inptr))) + { + *outptr++ ='H'; + inptr++; + one_char = valid_char + 1; + } + else + one_char = valid_char; + /* Validate/skip letters following C so that we allow C, CH, CHA, CHAR */ + while (('\0' != *one_char) && ('(' != *inptr)) + if (TOUPPER(*inptr++) != *one_char++) + return -1; + if ('(' != *inptr) + return -1; + } else /* We don't support anything other than $C() or $ZCH in locks */ + return -1; nextptr = memchr(inptr, ')', intop - inptr); if (NULL == nextptr) return -1; @@ -65,14 +95,35 @@ int lke_getki(char* src, int srclen, char* outbuff) memcpy(outptr, inptr, nextptr - inptr); outptr += nextptr - inptr; } else - { /* unquoted string or a number */ - nextptr = memchr(inptr, ',', intop - inptr); - if (NULL == nextptr) - { - nextptr = intop - 1;; - if (')' != *nextptr) - return -1; + { + if ('"' == *inptr) /* Is this a quoted string? */ + { /*Process character by character because '_' or ',' can be used within the quotes. */ + for (nextptr = inptr + 1; nextptr < intop; nextptr++) + if ('"' == *nextptr && (nextptr + 1 < intop)) + { + nextptr++; + if ('"' != *nextptr) + /* This is not a two double-quote so terminate. */ + break; + } + } else + { /* Fast-forward to the next separator */ + nextptr = memchr(inptr, '_', intop - inptr); + if (NULL == nextptr) + { /* Not a string concatineated with $C() or $ZCH() */ + nextptr = memchr(inptr, ',', intop - inptr); + if (NULL == nextptr) + nextptr = intop - 1; + } } + if (intop - 1 == nextptr) + { /* If it reached to the end, it had better closed the paran */ + if (')' != *nextptr) + return -1; + } + else if ((',' != *nextptr) && ('_' != *nextptr)) + /* If we are not at the end, it must be a separator*/ + return -1; subsc.str.len = INTCAST(nextptr - inptr); subsc.str.addr = inptr; if (val_iscan(&subsc)) @@ -83,13 +134,9 @@ int lke_getki(char* src, int srclen, char* outbuff) { if (nextptr - 1 > inptr && '"' == *inptr && '"' == *(nextptr - 1)) { /* The string is already enclosed by a pair of quotes */ - *outptr++ = *inptr++; /* initial quote */ - for (; inptr < nextptr - 1; *outptr++ = *inptr++) - { - if ('"' == *inptr && (++inptr >= nextptr - 1 || *inptr != '"')) - return -1; /* invalid (unescaped) quote within a quoted string */ - } - *outptr++ = *inptr++; /* final quote */ + memcpy(outptr, inptr, nextptr - inptr); + outptr += nextptr - inptr; + inptr += nextptr - inptr; } else { /* unquoted string: add quotes */ *outptr++ = '"'; @@ -98,12 +145,17 @@ int lke_getki(char* src, int srclen, char* outbuff) *outptr++ = *tmpptr; if ('"' == *tmpptr) *outptr++ = '"'; + if ('_' == *tmpptr) + { + *--outptr; + nextptr = tmpptr; + } } *outptr++ = '"'; } } } - if (',' != *nextptr && ')' != *nextptr) + if ((',' != *nextptr) && (')' != *nextptr) && ('_' != *nextptr)) return -1; *outptr++ = *nextptr++; } diff --git a/sr_port/lke_show.c b/sr_port/lke_show.c index 69afe9f..da71264 100644 --- a/sr_port/lke_show.c +++ b/sr_port/lke_show.c @@ -131,16 +131,17 @@ void lke_show(void) ls_free = MIN(1-(((float)shr_sub_len) / (ctl->subtop - ctl->subbase)), ls_free); ls_free *= 100; /* Scale to [0-100] range. (couldn't do this inside util_out_print) */ if (ls_free < 1) /* No memory? Notify user. */ - { gtm_putmsg(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(gv_cur_region)); + if (ls_free < 1 || memory) + { if (ctl->subtop > ctl->subfree) gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), - (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, - (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); + (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, + (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); else gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), - (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, - (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); + (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, + (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); } free(ctl); } else diff --git a/sr_port/lookup_variable_htent.c b/sr_port/lookup_variable_htent.c index b509fa5..53a97ec 100644 --- a/sr_port/lookup_variable_htent.c +++ b/sr_port/lookup_variable_htent.c @@ -20,7 +20,7 @@ #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "lookup_variable_htent.h" #include "alias.h" diff --git a/sr_port/lv_newname.c b/sr_port/lv_newname.c index a7f6ca7..a9de491 100644 --- a/sr_port/lv_newname.c +++ b/sr_port/lv_newname.c @@ -14,7 +14,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "lv_val.h" diff --git a/sr_port/lv_tree.c b/sr_port/lv_tree.c index 9f70efe..98cc445 100644 --- a/sr_port/lv_tree.c +++ b/sr_port/lv_tree.c @@ -656,14 +656,8 @@ lvTreeNode *lvAvlTreeCloneSubTree(lvTreeNode *node, lvTree *lvt, lvTreeNode *avl cloneNode->v = node->v; /* "cloneNode->sbs_child" initialized later */ cloneNode->tree_parent = lvt; - /* cloneNode->key_mvtype/balance/descent_dir/key_len all initialized in one shot. - * Note: We use "qw_num *" instead of "uint8 *" below because the former works on 32-bit platforms too. - */ - GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(&cloneNode->key_mvtype));) - NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(&cloneNode->key_mvtype));) - GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(&node->key_mvtype));) - NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(&node->key_mvtype));) - *(RECAST(qw_num *)&cloneNode->key_mvtype) = *(RECAST(qw_num *)&node->key_mvtype); + /* cloneNode->key_mvtype/balance/descent_dir/key_len all initialized in one shot */ + memcpy(&cloneNode->key_mvtype, &node->key_mvtype, 8); /* Asserts above keep the 8 byte length secure */ cloneNode->key_addr = node->key_addr; NON_GTM64_ONLY( assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNode, filler_8byte, lvTreeNodeNum, key_m1)); diff --git a/sr_port/lv_tree.h b/sr_port/lv_tree.h index dac9568..4faa71c 100644 --- a/sr_port/lv_tree.h +++ b/sr_port/lv_tree.h @@ -116,7 +116,7 @@ typedef struct } treeSrchStatus; typedef struct lvTreeStruct -{ +{ /* Note if first 3 fields are disturbed, make sure to fix LV_CLONE_TREE macro which references them as a group */ unsigned short ident; /* 2-byte field (same size as mvtype) set to the value MV_LV_TREE */ unsigned short sbs_depth; /* == "n" => all nodes in current avl tree represent lvns with "n" subscripts */ uint4 avl_height; /* Height of the AVL tree rooted at "avl_root" */ @@ -284,12 +284,8 @@ void lvAvlTreeNodeDelete(lvTree *lvt, lvTreeNode *node); assert(OFFSETOF(lvTree, avl_root) + SIZEOF(LVT->avl_root) == OFFSETOF(lvTree, sbs_parent)); \ assert(OFFSETOF(lvTree, sbs_parent) + SIZEOF(LVT->sbs_parent) == OFFSETOF(lvTree, lastLookup)); \ assert(OFFSETOF(lvTree, lastLookup) + SIZEOF(LVT->lastLookup) == SIZEOF(lvTree)); \ - /* Note: We use "qw_num *" instead of "uint8 *" below because the former works on 32-bit platforms too. */ \ - GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(cloneTree));) \ - NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(cloneTree));) \ - GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(LVT));) \ - NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(LVT));) \ - *(qw_num *)cloneTree = *(qw_num *)LVT; \ + /* Directly copy the first 3 fields */ \ + memcpy(cloneTree, (LVT), OFFSETOF(lvTree, avl_height) + SIZEOF(LVT->avl_height)); \ cloneTree->base_lv = BASE_LV; \ cloneTree->sbs_parent = SBS_PARENT; /* see comment in LV_TREE_CREATE macro (against sbs_parent \ * initialization) for why LVT_PARENT macro is not used */ \ diff --git a/sr_port/lv_val.h b/sr_port/lv_val.h index a95163e..8093dc1 100644 --- a/sr_port/lv_val.h +++ b/sr_port/lv_val.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -410,8 +410,6 @@ void lv_var_clone(lv_val *clone_var, lv_val *base_lv); void lvzwr_var(lv_val *lv, int4 n); void op_clralsvars(lv_val *dst); -void op_forfreeindx(void); -void op_fornestlvl(uint4 level); void op_fndata(lv_val *x, mval *y); void op_fnzdata(lv_val *x, mval *y); void op_fnincr(lv_val *local_var, mval *increment, mval *result); @@ -433,8 +431,6 @@ void op_zshow(mval *func, int type, lv_val *lvn); lv_val *op_getindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); lv_val *op_putindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); -lv_val *op_rfrshindx(uint4 level, boolean_t put); -lv_val *op_savputindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); lv_val *op_srchindx(UNIX_ONLY_COMMA(int argcnt_arg) lv_val *lv, ...); lv_val *op_m_srchindx(UNIX_ONLY_COMMA(int4 count) lv_val *lvarg, ...); diff --git a/sr_port/lvn.c b/sr_port/lvn.c index 09c03eb..bfc4440 100644 --- a/sr_port/lvn.c +++ b/sr_port/lvn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,20 +11,25 @@ #include "mdef.h" #include "compiler.h" +#include "fullbool.h" #include "opcode.h" +#include "mdq.h" #include "toktyp.h" -#include "subscript.h" #include "advancewindow.h" +#include "show_source_line.h" + +GBLREF boolean_t run_time; error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); error_def(ERR_VAREXPECTED); +error_def(ERR_SIDEEFFECTEVAL); int lvn(oprtype *a, opctype index_op, triple *parent) { - char x; - oprtype *sb, *sb1, *sb2, subscripts[MAX_LVSUBSCRIPTS]; - triple *ref, *root, *s; + char x; + oprtype *sb, *sb1, *sb2, subscripts[MAX_LVSUBSCRIPTS]; + triple *ref, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -38,7 +43,7 @@ int lvn(oprtype *a, opctype index_op, triple *parent) if (TK_LPAREN != TREF(window_token)) return TRUE; assert(TRIP_REF == a->oprclass); - ref = a->oprval.tref; + DEBUG_ONLY(ref = a->oprval.tref); assert(OC_VAR == ref->opcode); sb1 = sb2 = subscripts; *sb1++ = *a; @@ -66,26 +71,21 @@ int lvn(oprtype *a, opctype index_op, triple *parent) if (parent) { /* only $ORDER, $NEXT, $ZPREV have parent */ sb1--; - if (sb1 - sb2 == 1) /* only name and 1 subscript */ + if ((sb1 - sb2) == 1) /* only name and 1 subscript */ { /* SRCHINDX not necessary if only 1 subscript */ - sb = &parent->operand[1]; *sb = *sb1; + sb = &parent->operand[1]; + *sb = *sb1; return TRUE; } } root = ref = newtriple(index_op); ref->operand[0] = put_ilit((mint)(sb1 - sb2)); - while (sb2 < sb1) - { - s = newtriple(OC_PARAMETER); - ref->operand[1] = put_tref(s); - s->operand[0] = *sb2++; - ref = s; - } + SUBS_ARRAY_2_TRIPLES(ref, sb1, sb2, subscripts, 0); if (parent) { parent->operand[0] = put_tref(root); sb = &parent->operand[1]; - *sb = *sb2; + *sb = *sb1; return TRUE; } *a = put_tref(root); diff --git a/sr_port/lvzwr_fini.c b/sr_port/lvzwr_fini.c index 835ac70..3282545 100644 --- a/sr_port/lvzwr_fini.c +++ b/sr_port/lvzwr_fini.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "mlkdef.h" #include "zshow.h" diff --git a/sr_port/m_do.c b/sr_port/m_do.c index 3fff977..baf4491 100644 --- a/sr_port/m_do.c +++ b/sr_port/m_do.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -132,7 +132,7 @@ int m_do(void) cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); @@ -146,7 +146,7 @@ int m_do(void) calltrip->operand[0].oprclass = ILIT_REF; /* dummy placeholder */ tripsize->operand[0].oprval.tsize->ct = triptr; } - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); diff --git a/sr_port/m_for.c b/sr_port/m_for.c index 3c0ff78..9a1026e 100644 --- a/sr_port/m_for.c +++ b/sr_port/m_for.c @@ -35,21 +35,22 @@ error_def(ERR_SPOREOL); * that's not short - OC_PASSTHRU is suppose to give it a clue but having two of those in a row * seems not to work. */ -#define DEAL_WITH_DANGER(LVL, CNTL_VAR, VAL) \ +#define DEAL_WITH_DANGER(CNTRL_LVN, CNTL_VAR, VAL) \ { \ - triple *Ref; \ + triple *REF; \ \ - if ((TRUE_WITH_INDX == TAREF1(for_temps, for_stack_level))) \ + if (need_control_rfrsh) \ { \ - Ref = newtriple(OC_RFRSHINDX); \ - Ref->operand[0] = put_ilit(LVL); \ - Ref->operand[1] = put_ilit(1); \ - CNTL_VAR = put_tref(Ref); \ + REF = newtriple(OC_RFRSHLVN); \ + REF->operand[0] = CNTRL_LVN; \ + REF->operand[1] = put_ilit(OC_PUTINDX); \ + CNTL_VAR = put_tref(REF); \ + newtriple(OC_PASSTHRU)->operand[0] = CNTRL_LVN; \ newtriple(OC_PASSTHRU)->operand[0] = CNTL_VAR; /* warn off optimizer */ \ } \ - Ref = newtriple(OC_STO); \ - Ref->operand[0] = CNTL_VAR; \ - Ref->operand[1] = VAL; \ + REF = newtriple(OC_STO); \ + REF->operand[0] = CNTL_VAR; \ + REF->operand[1] = VAL; \ } /* the macro below pushes the compiler FOR stack - the FOR_POP is in compiler.h 'cause stx_error uses it @@ -66,7 +67,7 @@ error_def(ERR_SPOREOL); { \ assert(TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)); \ *(TREF(for_stack_ptr)) = NULL; \ - TAREF1(for_temps, Level) = TAREF1(for_temps, Level - 1) ? TRUE : FALSE; \ + TAREF1(for_temps, Level) = TAREF1(for_temps, Level - 1); \ } else \ { \ --(TREF(for_stack_ptr)); \ @@ -90,10 +91,11 @@ int m_for(void) { unsigned int arg_cnt, arg_index, for_stack_level; oprtype arg_eval_addr[MAX_FORARGS], increment[MAX_FORARGS], terminate[MAX_FORARGS], - arg_next_addr, arg_value, dummy, control_variable, + arg_next_addr, arg_value, dummy, control_variable, control_slot, v, *iteration_start_addr, iteration_start_addr_indr, *not_even_once_addr; - triple *eval_next_addr[MAX_FORARGS], *control_ref, - *forchk1opc, forpos_in_chain, *init_ref, *ref, *step_ref, *term_ref, *var_ref; + triple *eval_next_addr[MAX_FORARGS], *control_ref, *forchk1opc, forpos_in_chain, *init_ref, + *push, *ref, *s, *sav, *share, *step_ref, *term_ref, *var_ref; + boolean_t need_control_rfrsh = FALSE; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -117,28 +119,41 @@ int m_for(void) return TRUE; } for_stack_level = (TREF(for_stack_ptr) - TADR(for_stack)); - init_ref = newtriple(OC_FORNESTLVL); - init_ref->operand[0] = put_ilit(for_stack_level); if (TK_ATSIGN == TREF(window_token)) { - if (!indirection(&control_variable)) + if (!indirection(&v)) { FOR_POP(BLOWN_FOR); return FALSE; } - ref = newtriple(OC_INDLVADR); - ref->operand[0] = control_variable; - control_variable = put_tref(ref); - control_ref = NULL; + need_control_rfrsh = TRUE; + push = newtriple(OC_GLVNSLOT); + push->operand[0] = put_ilit(for_stack_level); + control_slot = put_tref(push); + sav = newtriple(OC_INDSAVLVN); + sav->operand[0] = v; + sav->operand[1] = control_slot; } else { - /* The following relies on the fact that lvn() always generates an OC_VAR triple first */ - control_ref = (TREF(curtchain))->exorder.bl; - if (!lvn(&control_variable, OC_SAVPUTINDX, NULL)) + DEBUG_ONLY(control_ref = (TREF(curtchain))->exorder.bl); + if (!lvn(&control_variable, OC_SAVLVN, NULL)) { FOR_POP(BLOWN_FOR); return FALSE; } + s = control_variable.oprval.tref; + if (OC_SAVLVN == s->opcode) + { /* Control variable has subscripts. If no subscripts, shouldn't need refreshing. */ + need_control_rfrsh = TRUE; + push = maketriple(OC_GLVNSLOT); + push->operand[0] = put_ilit(for_stack_level); + control_slot = put_tref(push); + share = maketriple(OC_SHARESLOT); + share->operand[0] = put_tref(push); + share->operand[1] = put_ilit(OC_SAVLVN); + dqins(s->exorder.bl, exorder, share); + dqins(share->exorder.bl, exorder, push); + } assert(OC_VAR == control_ref->exorder.fl->opcode); assert(MVAR_REF == control_ref->exorder.fl->operand[0].oprclass); } @@ -148,16 +163,21 @@ int m_for(void) FOR_POP(BLOWN_FOR); return FALSE; } + if (need_control_rfrsh) + { + ref = newtriple(OC_RFRSHLVN); + ref->operand[0] = control_slot; + ref->operand[1] = put_ilit(OC_PUTINDX); + control_variable = put_tref(ref); + TAREF1(for_temps, for_stack_level) = TRUE; + newtriple(OC_PASSTHRU)->operand[0] = control_slot; + } newtriple(OC_PASSTHRU)->operand[0] = control_variable; /* make sure optimizer doesn't ditch control_variable */ FOR_END_OF_SCOPE(1, dummy); assert((0 < for_stack_level) && (MAX_FOR_STACK >= for_stack_level)); - if ((OC_SAVPUTINDX == control_variable.oprval.tref->opcode) || (OC_INDLVADR == control_variable.oprval.tref->opcode)) - TAREF1(for_temps, for_stack_level) = TRUE_WITH_INDX; /* most uses treat this as a boolean, but some need more */ - else - init_ref->opcode = OC_NOOP; iteration_start_addr = (oprtype *)mcalloc(SIZEOF(oprtype)); iteration_start_addr_indr = put_indr(iteration_start_addr); - arg_next_addr.oprclass = NOCLASS; + arg_next_addr.oprclass = NO_REF; not_even_once_addr = NULL; /* used to skip processing where the initial control exceeds the termination */ for (arg_cnt = 0; ; ++arg_cnt) { @@ -183,8 +203,8 @@ int m_for(void) assert(TRIP_REF == arg_value.oprclass); if (TK_COLON != TREF(window_token)) { /* list point value? */ - increment[arg_cnt].oprclass = terminate[arg_cnt].oprclass = 0; - DEAL_WITH_DANGER(for_stack_level, control_variable, arg_value); + increment[arg_cnt].oprclass = terminate[arg_cnt].oprclass = NO_REF; + DEAL_WITH_DANGER(control_slot, control_variable, arg_value); } else { /* stepping value */ init_ref = newtriple(OC_STOTEMP); /* tuck it in a temp undisturbed by coming evals */ @@ -201,8 +221,7 @@ int m_for(void) ref = increment[arg_cnt].oprval.tref; if (OC_LIT != var_ref->exorder.fl->opcode) { - if (!TAREF1(for_temps, for_stack_level)) - TAREF1(for_temps, for_stack_level) = TRUE; + TAREF1(for_temps, for_stack_level) = TRUE; if (OC_VAR == var_ref->exorder.fl->opcode) { /* The above relies on lvn() always generating an OC_VAR triple first - asserted earlier */ step_ref = newtriple(OC_STOTEMP); @@ -212,8 +231,8 @@ int m_for(void) } if (TK_COLON != TREF(window_token)) { - DEAL_WITH_DANGER(for_stack_level, control_variable, put_tref(init_ref)); - terminate[arg_cnt].oprclass = 0; /* no termination on iteration for this arg */ + DEAL_WITH_DANGER(control_slot, control_variable, put_tref(init_ref)); + terminate[arg_cnt].oprclass = NO_REF; /* no termination on iteration for this arg */ } else { advancewindow(); /* past the second colon */ @@ -227,8 +246,7 @@ int m_for(void) ref = terminate[arg_cnt].oprval.tref; if (OC_LIT != ref->opcode) { - if (!TAREF1(for_temps, for_stack_level)) - TAREF1(for_temps, for_stack_level) = TRUE; + TAREF1(for_temps, for_stack_level) = TRUE; if (OC_VAR == var_ref->exorder.fl->opcode) { /* The above relies on lvn() always generating an OC_VAR triple first */ term_ref = newtriple(OC_STOTEMP); @@ -236,7 +254,7 @@ int m_for(void) terminate[arg_cnt] = put_tref(term_ref); } } - DEAL_WITH_DANGER(for_stack_level, control_variable, put_tref(init_ref)); + DEAL_WITH_DANGER(control_slot, control_variable, put_tref(init_ref)); term_ref = newtriple(OC_PARAMETER); term_ref->operand[0] = terminate[arg_cnt]; step_ref = newtriple(OC_PARAMETER); @@ -250,9 +268,8 @@ int m_for(void) } if ((0 < arg_cnt) || (TK_COMMA == TREF(window_token))) { - if (!TAREF1(for_temps, for_stack_level)) - TAREF1(for_temps, for_stack_level) = TRUE; - if (NOCLASS == arg_next_addr.oprclass) + TAREF1(for_temps, for_stack_level) = TRUE; + if (NO_REF == arg_next_addr.oprclass) arg_next_addr = put_tref(newtriple(OC_CDADDR)); (eval_next_addr[arg_cnt] = newtriple(OC_LDADDR))->destination = arg_next_addr; } @@ -260,8 +277,6 @@ int m_for(void) break; newtriple(OC_JMP)->operand[0] = iteration_start_addr_indr; } - if (not_even_once_addr) - FOR_END_OF_SCOPE(1, *not_even_once_addr); /* 1 means down a level */ forchk1opc = newtriple(OC_FORCHK1); /* FORCHK1 is a do-nothing routine used by the out-of-band mechanism */ *iteration_start_addr = put_tjmp(forchk1opc); if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))) @@ -278,6 +293,8 @@ int m_for(void) FOR_POP(BLOWN_FOR); return FALSE; } + if (not_even_once_addr) /* if above errors leave FOR remains behind, improper operval.indr explodes OC_JMPGTR */ + FOR_END_OF_SCOPE(1, *not_even_once_addr); /* 1 means down a level */ SAVE_FOR_OVER_ADDR(); /* stash address of next op in the for_stack array */ if (0 < arg_cnt) newtriple(OC_JMPAT)->operand[0] = put_tref(eval_next_addr[0]); @@ -285,19 +302,18 @@ int m_for(void) { if (0 < arg_cnt) tnxtarg(eval_next_addr[arg_index]->operand); - if (TRUE_WITH_INDX == TAREF1(for_temps, for_stack_level)) - { /* since it might have moved, before touching the control variable get a fix on it */ - ref = newtriple(OC_RFRSHINDX); - ref->operand[0] = put_ilit(for_stack_level); - ref->operand[1] = put_ilit((increment[arg_index].oprclass || terminate[arg_index].oprclass) - ? FALSE : TRUE); /* if increment rather than new value, rfrsh w/ srchindx else putindx */ - control_variable = put_tref(ref); - } else - { - assert(control_ref); - control_variable = put_mvar(&control_ref->exorder.fl->operand[0].oprval.vref->mvname); - } - newtriple(OC_PASSTHRU)->operand[0] = control_variable; /* warn off optimizer */ + if (need_control_rfrsh) + { /* since it might have moved, before touching the control variable get a fix on it */ + ref = newtriple(OC_RFRSHLVN); + ref->operand[0] = control_slot; + if (increment[arg_index].oprclass || terminate[arg_index].oprclass) + ref->operand[1] = put_ilit(OC_SRCHINDX); + else /* if increment rather than new value, rfrsh w/ srchindx else putindx */ + ref->operand[1] = put_ilit(OC_PUTINDX); + newtriple(OC_PASSTHRU)->operand[0] = control_slot; + control_variable = put_tref(ref); + } + newtriple(OC_PASSTHRU)->operand[0] = control_variable; /* warn off optimizer */ if (terminate[arg_index].oprclass) { term_ref = newtriple(OC_PARAMETER); diff --git a/sr_port/m_goto.c b/sr_port/m_goto.c index bafed68..6121fdb 100644 --- a/sr_port/m_goto.c +++ b/sr_port/m_goto.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,14 +40,14 @@ int m_goto(void) cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /*this is a violation of info hiding*/ - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); diff --git a/sr_port/m_if.c b/sr_port/m_if.c index c6e90b9..643b3b5 100644 --- a/sr_port/m_if.c +++ b/sr_port/m_if.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "mmemory.h" #include "advancewindow.h" #include "cmd.h" +#include "fullbool.h" error_def(ERR_INDEXTRACHARS); error_def(ERR_SPOREOL); @@ -41,8 +42,8 @@ int m_if(void) SETUP_THREADGBL_ACCESS; ifpos_in_chain = TREF(pos_in_chain); - jmpchain = (jmpchn*)mcalloc(SIZEOF(jmpchn)); - dqinit(jmpchain,link); + jmpchain = (jmpchn *)mcalloc(SIZEOF(jmpchn)); + dqinit(jmpchain, link); if (TK_EOL == TREF(window_token)) return TRUE; is_commarg = (1 == TREF(last_source_column)); @@ -54,7 +55,7 @@ int m_if(void) jmpref->operand[0] = x; nxtjmp = (jmpchn *)mcalloc(SIZEOF(jmpchn)); nxtjmp->jmptrip = jmpref; - dqins(jmpchain,link,nxtjmp); + dqins(jmpchain, link, nxtjmp); } else { first_time = TRUE; @@ -66,8 +67,8 @@ int m_if(void) if (((OC_JMPNEQ == (ref0 = (TREF(curtchain))->exorder.bl)->opcode)) && (OC_COBOOL == (ref1 = ref0->exorder.bl)->opcode) && (OC_INDGLVN == (ref2 = ref1->exorder.bl)->opcode)) - { - dqdel(ref0,exorder); + { /* short-circuit only optimization that turns a trailing INDGLVN COBOOL into separate indirect IF */ + dqdel(ref0, exorder); ref1->opcode = OC_JMPTSET; ref1->operand[0] = put_indr(ta_opr); ref2->opcode = OC_COMMARG; @@ -76,16 +77,30 @@ int m_if(void) t_set = (OC_JMPTSET == (TREF(curtchain))->exorder.bl->opcode); if (!t_set) newtriple(OC_CLRTEST); + if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) + { + assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); + if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) + || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) + newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); + } jmpref = newtriple(OC_JMP); jmpref->operand[0] = x; nxtjmp = (jmpchn *)mcalloc(SIZEOF(jmpchn)); nxtjmp->jmptrip = jmpref; - dqins(jmpchain,link,nxtjmp); + dqins(jmpchain, link, nxtjmp); tnxtarg(ta_opr); if (first_time) { if (!t_set) newtriple(OC_SETTEST); + if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) + { + assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); + if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) + || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) + newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); + } first_time = FALSE; } if (TK_COMMA != TREF(window_token)) diff --git a/sr_port/m_merge.c b/sr_port/m_merge.c index bf124dc..eb40a12 100644 --- a/sr_port/m_merge.c +++ b/sr_port/m_merge.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,7 @@ #include "cmd.h" #include "mvalconv.h" #include "advancewindow.h" +#include "glvn_pool.h" error_def(ERR_EQUAL); error_def(ERR_RPARENMISSING); @@ -28,13 +29,16 @@ error_def(ERR_VAREXPECTED); int m_merge(void) { int type; + boolean_t used_glvn_slot; mval mv; opctype put_oc; - oprtype mopr; - triple *obp, *ref, *restart, *s1, *sub, tmpchain; + oprtype mopr, control_slot; + triple *obp, *ref, *restart, *s1, *sub, tmpchain; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + used_glvn_slot = FALSE; + sub = NULL; restart = newtriple(OC_RESTARTPC); /* Here is where a restart should pick up */ dqinit(&tmpchain, exorder); /* Left Hand Side of EQUAL sign */ @@ -45,6 +49,8 @@ int m_merge(void) return FALSE; if (OC_PUTINDX == mopr.oprval.tref->opcode) { /* we insert left hand side argument into tmpchain. */ + sub = mopr.oprval.tref; + put_oc = OC_PUTINDX; dqdel(mopr.oprval.tref, exorder); dqins(tmpchain.exorder.bl, exorder, mopr.oprval.tref); } @@ -84,9 +90,18 @@ int m_merge(void) type = MARG1_LCL | MARG1_GBL; MV_FORCE_MVAL(&mv, type); MV_FORCE_STRD(&mv); - ref = maketriple(OC_INDMERGE); - ref->operand[0] = put_lit(&mv); - ref->operand[1] = mopr; + if (TREF(side_effect_handling)) + { /* save and restore the variable lookup for true left-to-right evaluation */ + used_glvn_slot = TRUE; + INSERT_INDSAVGLVN(control_slot, mopr, ANY_SLOT, 0); /* 0 flag to defer global reference */ + ref = maketriple(OC_INDMERGE2); + ref->operand[0] = control_slot; + } else + { /* quick and dirty old way */ + ref = maketriple(OC_INDMERGE); + ref->operand[0] = put_lit(&mv); + ref->operand[1] = mopr; + } /* we insert left hand side argument into tmpchain. */ dqins(tmpchain.exorder.bl, exorder, ref); break; @@ -101,6 +116,7 @@ int m_merge(void) } advancewindow(); /* Right Hand Side of EQUAL sign */ + TREF(temp_subs) = FALSE; switch (TREF(window_token)) { case TK_IDENT: @@ -117,6 +133,7 @@ int m_merge(void) ref->operand[0] = put_ilit(MARG2_GBL); break; case TK_ATSIGN: + TREF(temp_subs) = TRUE; if (!indirection(&mopr)) { stx_error(ERR_VAREXPECTED); @@ -140,6 +157,14 @@ int m_merge(void) */ obp = (TREF(curtchain))->exorder.bl; dqadd(obp, &tmpchain, exorder); + if (TREF(temp_subs) && TREF(side_effect_handling) && sub) + create_temporaries(sub, put_oc); + TREF(temp_subs) = FALSE; + if (used_glvn_slot) + { + ref = newtriple(OC_GLVNPOP); + ref->operand[0] = control_slot; + } ref = newtriple(OC_MERGE); return TRUE; } diff --git a/sr_port/m_set.c b/sr_port/m_set.c index 7b1a05c..06a8526 100644 --- a/sr_port/m_set.c +++ b/sr_port/m_set.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,6 +32,7 @@ #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" +#include "glvn_pool.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif @@ -91,7 +92,6 @@ LITREF fun_data_type fun_data[]; return FALSE; \ } -void m_set_create_temporaries(triple *sub, opctype put_oc); void allow_dzwrtac_as_mident(void); int m_set(void) @@ -125,12 +125,14 @@ int m_set(void) boolean_t parse_warn; /* set to TRUE in case of an invalid SVN etc. */ boolean_t curtchain_switched; /* set to TRUE if a setcurtchain was done */ boolean_t temp_subs_was_FALSE; + boolean_t used_glvn_slot; int delimlen, first_val_lit, index, last_val_lit, nakedzalias, setop; int first_setleft_invalid; /* set to TRUE if the first setleft target is invalid */ opctype put_oc; - oprtype delimval, firstval, lastval, resptr, *result, v; + oprtype delimval, firstval, lastval, resptr, *result, v, control_slot, first_control_slot; triple *curtargchain, *delimiter, discardcurtchain, *first, *get, *jmptrp1, *jmptrp2, *last, *obp, *put; triple *s, *s0, *s1, save_targchain, *save_curtchain, *save_curtchain1, *sub, targchain, *tmp; + triple *ref; mint delimlit; mval *delim_mval; mvar *mvarptr; @@ -143,6 +145,7 @@ int m_set(void) SETUP_THREADGBL_ACCESS; TREF(temp_subs) = FALSE; + used_glvn_slot = FALSE; dqinit(&targchain, exorder); result = (oprtype *)mcalloc(SIZEOF(oprtype)); resptr = put_indr(result); @@ -189,9 +192,9 @@ int m_set(void) * D - Triple that does OC_GVPUT of the new value into ^A(x,y) * This is the point where the conditional check triples will branch around to if they chose to. * - * A - triples that evaluates the arguments/subscripts in the left-hand-side of the SET command + * A - triples that evaluate the arguments/subscripts in the left-hand-side of the SET command * These triples are built in "curtchain" - * B - triples that evaluates the arguments/subscripts in the right-hand-side of the SET command + * B - triples that evaluate the arguments/subscripts in the right-hand-side of the SET command * These triples are built in "curtchain" * C - triples that do conditional check for any $PIECE/$EXTRACT in the left side of the SET command. * These triples are built in "curtargchain" @@ -266,7 +269,7 @@ int m_set(void) sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) - m_set_create_temporaries(sub, put_oc); + create_temporaries(sub, put_oc); } } else { /* Have alias variable. Argument is index into var table rather than pointer to var */ @@ -302,7 +305,7 @@ int m_set(void) dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) - m_set_create_temporaries(sub, put_oc); + create_temporaries(sub, put_oc); put = maketriple(OC_GVPUT); put->operand[0] = resptr; dqins(targchain.exorder.bl, exorder, put); @@ -320,8 +323,21 @@ int m_set(void) put->operand[1] = put_ilit(indir_set); return TRUE; } - put = maketriple(OC_INDSET); - put->operand[0] = v; + if (TREF(side_effect_handling)) + { /* save and restore the variable lookup for true left-to-right evaluation */ + INSERT_INDSAVGLVN(control_slot, v, ANY_SLOT, 0); /* 0 flag to defer global reference */ + if (!used_glvn_slot) + { + used_glvn_slot = TRUE; + first_control_slot = control_slot; + } + put = maketriple(OC_STOGLVN); + put->operand[0] = control_slot; + } else + { /* quick and dirty old way */ + put = maketriple(OC_INDSET); + put->operand[0] = v; + } put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); break; @@ -439,7 +455,7 @@ int m_set(void) sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) - m_set_create_temporaries(sub, put_oc); + create_temporaries(sub, put_oc); } get = maketriple(OC_FNGET); get->operand[0] = v; @@ -450,11 +466,16 @@ int m_set(void) case TK_ATSIGN: if (!indirection(&v)) SYNTAX_ERROR(ERR_VAREXPECTED); - get = maketriple(OC_INDGET); - get->operand[0] = v; - get->operand[1] = put_str(0, 0); - put = maketriple(OC_INDSET); - put->operand[0] = v; + INSERT_INDSAVGLVN(control_slot, v, ANY_SLOT, 0); + if (!used_glvn_slot) + { + used_glvn_slot = TRUE; + first_control_slot = control_slot; + } + get = maketriple(OC_INDGET1); + get->operand[0] = control_slot; + put = maketriple(OC_STOGLVN); + put->operand[0] = control_slot; put->operand[1] = put_tref(s); break; case TK_CIRCUMFLEX: @@ -471,7 +492,7 @@ int m_set(void) dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) - m_set_create_temporaries(sub, put_oc); + create_temporaries(sub, put_oc); get = maketriple(OC_FNGVGET); get->operand[0] = put_str(0, 0); put = maketriple(OC_GVPUT); @@ -797,98 +818,16 @@ int m_set(void) * (for example, if rhs had $$ or $& or $INCR usages). If so need to create temporaries. */ if (TREF(temp_subs) && temp_subs_was_FALSE && (NULL != sub)) - m_set_create_temporaries(sub, put_oc); + create_temporaries(sub, put_oc); TREF(temp_subs) = FALSE; + if (used_glvn_slot) + { /* Free up slots we're done with. */ + ref = newtriple(OC_GLVNPOP); + ref->operand[0] = first_control_slot; + } return TRUE; } -/* This function adds triples to the execution chain to store the values of subscripts (in glvns in compound SETs) - * in temporaries (using OC_STOTEMP opcode). This function is only invoked when - * a) The SET is a compound SET (i.e. there are multiple targets specified on the left side of the SET command). - * b) Subscripts are specified in glvns which are targets of the SET. - * e.g. set a=0,(a,array(a))=1 - * The expected result of the above command as per the M-standard is that array(0) (not array(1)) gets set to 1. - * That is, the value of the subscript "a" should be evaluated at the start of the compound SET before any sets happen - * and should be used in any subscripts that refer to the name "a". - * In the above example, since it is a compound SET and "a" is used in a subscript, we need to store the value of "a" - * before the start of the compound SET (i.e.a=0) in a temporary and use that as the subscript for "array". - * If in the above example the compound set was instead specified as set a=1,array(a)=1, the value of 1 gets substituted - * when used in "array(a)". - * This is where the compound set acts differently from a sequence of multiple sets. This is per the M-standard. - * In the above example, the subscript used was also a target within the compound SET. It is possible that the - * subscript is not also an individual target within the same compound SET. Even in that case, this function - * will be called to store the subscript in temporaries (as we dont know at compile time if a particular - * subscript is also used as a target within a compound SET). - */ -void m_set_create_temporaries(triple *sub, opctype put_oc) -{ - oprtype *sb1; - triple *s0, *s1; - DCL_THREADGBL_ACCESS; - - SETUP_THREADGBL_ACCESS; - assert(TREF(temp_subs)); - assert(NULL != sub); - sb1 = &sub->operand[1]; - if ((OC_GVNAME == put_oc) || (OC_PUTINDX == put_oc)) - { - sub = sb1->oprval.tref; /* global name */ - assert(OC_PARAMETER == sub->opcode); - sb1 = &sub->operand[1]; - } else if (OC_GVEXTNAM == put_oc) - { - sub = sb1->oprval.tref; /* first env */ - assert(OC_PARAMETER == sub->opcode); - sb1 = &sub->operand[0]; - assert(TRIP_REF == sb1->oprclass); - s0 = sb1->oprval.tref; - if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) - { - s1 = maketriple(OC_STOTEMP); - s1->operand[0] = *sb1; - *sb1 = put_tref(s1); - s0 = s0->exorder.fl; - dqins(s0->exorder.bl, exorder, s1); - } - sb1 = &sub->operand[1]; - sub = sb1->oprval.tref; /* second env */ - assert(OC_PARAMETER == sub->opcode); - sb1 = &sub->operand[0]; - assert(TRIP_REF == sb1->oprclass); - s0 = sb1->oprval.tref; - if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) - { - s1 = maketriple(OC_STOTEMP); - s1->operand[0] = *sb1; - *sb1 = put_tref(s1); - s0 = s0->exorder.fl; - dqins(s0->exorder.bl, exorder, s1); - } - sb1 = &sub->operand[1]; - sub = sb1->oprval.tref; /* global name */ - assert(OC_PARAMETER == sub->opcode); - sb1 = &sub->operand[1]; - } - while (sb1->oprclass) - { - assert(TRIP_REF == sb1->oprclass); - sub = sb1->oprval.tref; - assert(OC_PARAMETER == sub->opcode); - sb1 = &sub->operand[0]; - assert(TRIP_REF == sb1->oprclass); - s0 = sb1->oprval.tref; - if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) - { - s1 = maketriple(OC_STOTEMP); - s1->operand[0] = *sb1; - *sb1 = put_tref(s1); - s0 = s0->exorder.fl; - dqins(s0->exorder.bl, exorder, s1); - } - sb1 = &sub->operand[1]; - } -} - /* Prior to Alias support, the ZWRITE command was able to dump the entire local variable environment such that it could be * reloaded by Xecuting the dumped lines. With the addition of Alias type variables, the output lines not only include the * variable content but their alias associations as well. One aspect of this is the $ZWRTAC variable which is a temporary diff --git a/sr_port/m_write.c b/sr_port/m_write.c index ba6736e..92ab9c6 100644 --- a/sr_port/m_write.c +++ b/sr_port/m_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -133,7 +133,7 @@ int m_write(void) ref->operand[0].oprval.tref->opcode = OC_NOOP; ref->opcode = OC_NOOP; ref->operand[0].oprval.tref->operand[0].oprclass = OC_NOOP; - ref->operand[0].oprclass = 0; + ref->operand[0].oprclass = NO_REF; } ptx--; stringpool.free = (unsigned char *) cp; diff --git a/sr_port/m_xecute.c b/sr_port/m_xecute.c index c1024ac..e944cf1 100644 --- a/sr_port/m_xecute.c +++ b/sr_port/m_xecute.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,14 +53,14 @@ int m_xecute(void) cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp,&tmpchain,exorder); /* violates info hiding */ - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); diff --git a/sr_port/m_zcompile.c b/sr_port/m_zcompile.c index 57bd43c..f4c1061 100644 --- a/sr_port/m_zcompile.c +++ b/sr_port/m_zcompile.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,6 +24,6 @@ int m_zcompile(void) return FALSE; triptr = newtriple(OC_ZCOMPILE); triptr->operand[0] = x; - triptr->operand[1] = put_ilit(FALSE); /* mExtReqd arg */ + triptr->operand[1] = put_ilit(FALSE); /* ignore_dollar_zcompile arg */ return TRUE; } diff --git a/sr_port/m_zgoto.c b/sr_port/m_zgoto.c index a15704e..d3c0ef1 100644 --- a/sr_port/m_zgoto.c +++ b/sr_port/m_zgoto.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -88,14 +88,14 @@ int m_zgoto(void) cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /* this is a violation of info hiding */ - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); diff --git a/sr_port/m_zinvcmd.c b/sr_port/m_zinvcmd.c index dca7bbd..b97c8c6 100644 --- a/sr_port/m_zinvcmd.c +++ b/sr_port/m_zinvcmd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011 Fidelity Information Services, Inc * + * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,6 +15,7 @@ #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" +#include "error.h" error_def(ERR_INVCMD); @@ -35,7 +36,7 @@ int m_zinvcmd(void) if (TK_ERROR == TREF(window_token)) return FALSE; triptr = newtriple(OC_RTERROR); - triptr->operand[0] = put_ilit(ERR_INVCMD); - triptr->operand[1] = put_ilit(FALSE); /* not a subroutine reference */ + triptr->operand[0] = put_ilit(MAKE_MSG_TYPE(ERR_INVCMD, ERROR)); /* switch from warning to error */ + triptr->operand[1] = put_ilit(FALSE); /* not a subroutine reference */ return TRUE; } diff --git a/sr_port/mdb_condition_handler.c b/sr_port/mdb_condition_handler.c index 6837219..2fbb902 100644 --- a/sr_port/mdb_condition_handler.c +++ b/sr_port/mdb_condition_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,11 +17,12 @@ #include "gtm_stdio.h" #ifdef VMS -#include /* required for gtmsource.h */ -#include +# include /* required for gtmsource.h */ +# include #endif #ifdef UNIX -#include +# include +# include #endif #include "ast.h" @@ -42,7 +43,7 @@ #include "io_params.h" #include "jnl.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "outofband.h" #include "stack_frame.h" @@ -61,7 +62,7 @@ #include "objlabel.h" #include "op.h" #include "dpgbldir.h" -#include "preemptive_ch.h" +#include "preemptive_db_clnup.h" #include "compiler.h" /* needed for MAX_SRCLINE */ #include "show_source_line.h" #include "trans_code_cleanup.h" @@ -82,6 +83,7 @@ #ifdef UNIX # include "iormdef.h" # include "ftok_sems.h" +# include "gtm_putmsg_list.h" #endif #ifdef GTM_TRIGGER # include "gv_trigger.h" @@ -119,6 +121,7 @@ GBLREF mval dollar_zstatus, dollar_zerror; GBLREF mval dollar_etrap; GBLREF volatile int4 gtmMallocDepth; GBLREF int4 exi_condition; +GBLREF inctn_opcode_t inctn_opcode; #ifdef VMS GBLREF struct chf$signal_array *tp_restart_fail_sig; GBLREF boolean_t tp_restart_fail_sig_used; @@ -131,15 +134,16 @@ GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related GBLREF boolean_t in_gvcst_incr; GBLREF gv_namehead *gv_target; GBLREF gd_region *gv_cur_region; +GBLREF gv_key *gv_currkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgm_info *first_sgm_info; GBLREF dollar_stack_type dollar_stack; GBLREF mval *alias_retarg; #ifdef UNIX -GBLREF io_desc *gtm_err_dev; -GBLREF char *util_outptr, util_outbuff[OUT_BUFF_SIZE]; +GBLREF jnl_gbls_t jgbl; #endif +GBLREF io_desc *gtm_err_dev; #ifdef GTM_TRIGGER GBLREF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */ @@ -170,7 +174,9 @@ error_def(ERR_RTSLOC); error_def(ERR_SRCLOCUNKNOWN); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); +error_def(ERR_TLVLZERO); error_def(ERR_TPRETRY); +error_def(ERR_TPRESTNESTERR); error_def(ERR_TPSTACKCRIT); error_def(ERR_TPSTACKOFLOW); error_def(ERR_TPTIMEOUT); @@ -178,21 +184,25 @@ error_def(ERR_UNSOLCNTERR); error_def(ERR_VMSMEMORY); boolean_t clean_mum_tstart(void); +void setup_error(sgmnt_addrs *csa, int argcnt, ...); -#ifdef GTM_TRIGGER -/* When we go to restart generated code after handling an error, verify that we are not in frame or one created on its - * behalf that invoked a trigger and caused a dynamic TSTART to be done on its behalf. This can happen for example if - * a trigger is invoked for the first time but get a compilation or link failure error. This error is thrown from - * gtm_trigger() while no trigger based error handling is in effect so no rollback of the dynamic frame occurs which - * will result in unhandled TPQUIT errors, perhaps interminably. +#ifdef UNIX +/* When we restart generated code after handling an error, verify that we are not in the frame or one created on its + * behalf that invoked a trigger or spanning node and caused a dynamic TSTART to be done on its behalf. This can happen + * for example if a trigger is invoked for the first time but gets a compilation or link failure error or if a spanning + * node fetch or update drives an error. In the trigger case, the relevant error is thrown from gtm_trigger() while no + * trigger based error handling is in effect so no rollback of the dynamic frame occurs which results in unhandled TPQUIT + * errors, perhaps interminably. In both the trigger and spanning-node cases, the MUM_TSTART we are about to execute unrolls + * the C stack preventing any return to the C frame that did the implicit tstart and prevents it from being committed so + * it must be rolled back. */ -#define MUM_TSTART_FRAME_CHECK \ -{ \ - if ((0 == gtm_trigger_depth) && tp_pointer && tp_pointer->implicit_tstart) \ - { \ - DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \ - OP_TROLLBACK(-1); /* Unroll implicit TP frame */ \ - } \ +#define MUM_TSTART_FRAME_CHECK \ +{ \ + if (GTMTRIG_ONLY((0 == gtm_trigger_depth) &&) tp_pointer && tp_pointer->implicit_tstart) \ + { \ + DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \ + OP_TROLLBACK(-1); /* Unroll implicit TP frame */ \ + } \ } #else #define MUM_TSTART_FRAME_CHECK @@ -225,13 +235,26 @@ boolean_t clean_mum_tstart(void) return (NULL != err_act); } +#ifdef UNIX +/* Routine to setup an error in util_outbuff as if rts_error had put it there. Used when we morph ERR_TPRETRY + * to ERR_TPRESTNESTERR. Requires a va_list var containing the args so do this in this separate routine. + */ +void setup_error(sgmnt_addrs *csa, int argcnt, ...) +{ + va_list var; + + VAR_START(var, argcnt); + gtm_putmsg_list(csa, argcnt, var); + va_end(var); +} +#endif + CONDITION_HANDLER(mdb_condition_handler) { unsigned char *cp, *context, *sp_base; boolean_t dm_action; /* did the error occur on a action from direct mode */ boolean_t trans_action; /* did the error occur during "transcendental" code */ char src_line[MAX_ENTRYREF_LEN]; - char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)]; mstr src_line_d; io_desc *err_dev; tp_region *tr; @@ -243,27 +266,33 @@ CONDITION_HANDLER(mdb_condition_handler) boolean_t repeat_error, etrap_handling, reset_mpc; int level, rc; lv_val *lvptr; + boolean_t reserve_sock_dev = FALSE; # ifdef UNIX unix_db_info *udi; + stack_frame *lcl_error_frame; + mv_stent *mvst; # endif START_CH; DBGEHND((stderr, "mdb_condition_handler: Entered with SIGNAL=%d frame_pointer=0x"lvaddr"\n", SIGNAL, frame_pointer)); -# ifdef UNIX - /* It is possible that we entered here from a bad compile of the OPEN exception handler - * for an rm device. If gtm_err_dev is still set from the previous mdb_condition_handler - * invocation that drove the error handler that occurred during the OPEN command, then its - * structures should be released now. - */ if (NULL != gtm_err_dev) { - remove_rms(gtm_err_dev); + /* It is possible that we entered here from a bad compile of the OPEN exception handler + * for a device. If gtm_err_dev is still set from the previous mdb_condition_handler + * invocation that drove the error handler that occurred during the OPEN command, then its + * structures should be released now. + */ + if (gtmsocket == gtm_err_dev->type) + iosocket_destroy(gtm_err_dev); +# ifdef UNIX + else + remove_rms(gtm_err_dev); +# endif gtm_err_dev = NULL; } -# endif if (repeat_error = (ERR_REPEATERROR == SIGNAL)) /* assignment and comparison */ SIGNAL = dollar_ecode.error_last_ecode; - preemptive_ch(SEVERITY); + preemptive_db_clnup(SEVERITY); if (NULL != alias_retarg) { /* An error has occurred while an alias return arg was in-flight. Delivery won't happen now * so we need to remove the extra counts that were added in unw_retarg() and dis-enchant @@ -303,6 +332,7 @@ CONDITION_HANDLER(mdb_condition_handler) */ merge_args = 0; TREF(in_zwrite) = FALSE; + inctn_opcode = inctn_invalid_op; if ((SUCCESS != SEVERITY) && (INFO != SEVERITY)) { if (lvzwrite_block) @@ -311,71 +341,100 @@ CONDITION_HANDLER(mdb_condition_handler) } if ((int)ERR_TPRETRY == SIGNAL) { - /* Put the restart here for linking purposes. - * Utilities use T_RETRY, so calling from there causes - * all sorts of linking overlaps. - */ - VMS_ONLY(assert(FALSE == tp_restart_fail_sig_used)); -# ifdef GTM_TRIGGER - /* Assert that we never end up invoking the MUM_TSTART macro handler in case of an implicit tstart restart. - * See GBLDEF of skip_INVOKE_RESTART and donot_INVOKE_MUMTSTART in gbldefs.c for more information. - * Note that it is possible for this macro to be invoked from generated code in a trigger frame (in which - * case gtm_trigger/tp_restart ensure control passed to mdb_condition_handler only until the outermost - * implicit tstart in which case they return). Assert accordingly. - */ - assert(!donot_INVOKE_MUMTSTART || gtm_trigger_depth); - TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; -# endif - rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS); - DBGEHND((stderr, "mdb_condition_handler: tp_restart returned with rc=%d. state=%d, and SIGNAL=%d\n", - rc, tprestart_state, error_condition)); -# ifdef GTM_TRIGGER - if (0 != rc) - { /* The only time "tp_restart" will return non-zero is if the error needs to be - * rethrown. To accomplish that, we will unwind this handler which will return to - * the inner most initiating dm_start() with the return code set to whatever mumps_status - * is set to. - */ - assert(TPRESTART_STATE_NORMAL != tprestart_state); - assert(rc == SIGNAL); - assertpro((SFT_TRIGR & frame_pointer->type) && (0 < gtm_trigger_depth)); - mumps_status = rc; - DBGEHND((stderr, "mdb_condition_handler: Unwind-return to caller (gtm_trigger)\n")); - UNWIND(NULL, NULL); - } - /* "tp_restart" has succeeded so we have unwound back to the return point but check if the - * transaction was initiated by an implicit trigger TSTART. This can occur if an error was - * encountered in a trigger before the trigger base-frame was setup. It can occur at any trigger - * level if a triggered update is preceeded by a TROLLBACK. - */ - if (!(SFT_TRIGR & frame_pointer->type) && tp_pointer && tp_pointer->implicit_tstart) - { - mumps_status = rc; - DBGEHND((stderr, "mdb_condition_handler: Returning to implicit TSTART originator\n")); - UNWIND(NULL, NULL); - } - assert(!donot_INVOKE_MUMTSTART); -# endif # ifdef UNIX - if (ERR_TPRETRY == SIGNAL) /* (signal value undisturbed) */ -# elif defined VMS - if (!tp_restart_fail_sig_used) /* If tp_restart ran clean */ + lcl_error_frame = error_frame; + if ((NULL == lcl_error_frame) && dollar_zininterrupt) + { /* We are in a $zininterrupt handler AND have a restart request. See if we were in error processing + * when we started the interrupt. We can locate this in the zinterrupt mv_stent. Note this loop + * does not process the last mv_stent on the stack but since that is the MVST_STORIG entry, this is ok + * as we expect to find a ZINTRupt entry long before that. + */ + for (mvst = mv_chain; 0 != mvst->mv_st_next; mvst = (mv_stent *)(mvst->mv_st_next + (char *)mvst)) + { + if (MVST_ZINTR == mvst->mv_st_type) + break; + } + assertpro(MVST_ZINTR == mvst->mv_st_type); /* No zinterrupt block, big problemo */ + lcl_error_frame = mvst->mv_st_cont.mvs_zintr.error_frame_save; + } + if (NULL == lcl_error_frame) # endif { - /* Clean up both stacks, and set mumps program counter back tstart level 1 */ - TREF(ind_result_sp) = TREF(ind_result_array); /* clean up any active indirection pool usages */ - TREF(ind_source_sp) = TREF(ind_source_array); - MUM_TSTART; - } -# ifdef VMS - else - { /* Otherwise tp_restart had a signal that we must now deal with -- replace the TPRETRY - * information with that saved from tp_restart. - * Assert that we have room for these arguments - the array malloc is in tp_restart + VMS_ONLY(assert(FALSE == tp_restart_fail_sig_used)); +# ifdef GTM_TRIGGER + /* Assert that we never end up invoking the MUM_TSTART macro handler in case of an implicit tstart restart. + * See GBLDEF of skip_INVOKE_RESTART and donot_INVOKE_MUMTSTART in gbldefs.c for more information. + * Note that it is possible for this macro to be invoked from generated code in a trigger frame (in which + * case gtm_trigger/tp_restart ensure control passed to mdb_condition_handler only until the outermost + * implicit tstart in which case they return). Assert accordingly. */ - assert(TPRESTART_ARG_CNT >= tp_restart_fail_sig->chf$is_sig_args); - memcpy(sig, tp_restart_fail_sig, (tp_restart_fail_sig->chf$l_sig_args + 1) * SIZEOF(int)); - tp_restart_fail_sig_used = FALSE; + assert(!donot_INVOKE_MUMTSTART || gtm_trigger_depth); + TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; +# endif + rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS); + DBGEHND((stderr, "mdb_condition_handler: tp_restart returned with rc=%d. state=%d, and SIGNAL=%d\n", + rc, GTMTRIG_ONLY(tprestart_state) NON_GTMTRIG_ONLY(0), error_condition)); +# ifdef GTM_TRIGGER + if (0 != rc) + { /* The only time "tp_restart" will return non-zero is if the error needs to be + * rethrown. To accomplish that, we will unwind this handler which will return to + * the inner most initiating dm_start() with the return code set to whatever mumps_status + * is set to. + */ + assert(TPRESTART_STATE_NORMAL != tprestart_state); + assert(rc == SIGNAL); + assertpro((SFT_TRIGR & frame_pointer->type) && (0 < gtm_trigger_depth)); + mumps_status = rc; + DBGEHND((stderr, "mdb_condition_handler: Unwind-return to caller (gtm_trigger)\n")); + UNWIND(NULL, NULL); + } + /* "tp_restart" has succeeded so we have unwound back to the return point but check if the + * transaction was initiated by an implicit trigger TSTART. This can occur if an error was + * encountered in a trigger before the trigger base-frame was setup. It can occur at any trigger + * level if a triggered update is preceeded by a TROLLBACK. + */ + if (!(SFT_TRIGR & frame_pointer->type) && tp_pointer && tp_pointer->implicit_tstart) + { + mumps_status = rc; + DBGEHND((stderr, "mdb_condition_handler: Returning to implicit TSTART originator\n")); + UNWIND(NULL, NULL); + } + assert(!donot_INVOKE_MUMTSTART); +# endif +# ifdef UNIX + if (ERR_TPRETRY == SIGNAL) /* (signal value undisturbed) */ +# elif defined VMS + if (!tp_restart_fail_sig_used) /* If tp_restart ran clean */ +# endif + { + /* Set mumps program counter back tstart level 1 */ + MUM_TSTART; + } +# ifdef VMS + else + { /* Otherwise tp_restart had a signal that we must now deal with -- replace the TPRETRY + * information with that saved from tp_restart. + * Assert that we have room for these arguments - the array malloc is in tp_restart + */ + assert(TPRESTART_ARG_CNT >= tp_restart_fail_sig->chf$is_sig_args); + memcpy(sig, tp_restart_fail_sig, (tp_restart_fail_sig->chf$l_sig_args + 1) * SIZEOF(int)); + tp_restart_fail_sig_used = FALSE; + } +# endif + } +# ifdef UNIX + else + { + if (0 == dollar_tlevel) + SIGNAL = ERR_TLVLZERO; /* TPRESTART specified but not in TP */ + else + SIGNAL = ERR_TPRESTNESTERR; /* Only if actually in TP */ + /* TPRETRY encountered or requested during error handling - treat as nested error to prevent issues + * with errors being rethrown during a TP restart. Change the error from TPRETRY to either TLVLZERO or + * TPRESTNESTERR as appropriate so we don't give internal use only error name to user and let error + * continue through regular processing (both treated as nested error since error_frame non-NULL). + */ + setup_error(gv_target ? gv_target->gd_csa : NULL, VARLSTCNT(1) SIGNAL); } # endif } @@ -383,37 +442,52 @@ CONDITION_HANDLER(mdb_condition_handler) if (NULL != gv_target) { csa = gv_target->gd_csa; - if ((NULL != csa) && (csa != cs_addrs)) + if (NULL != csa) { - assert(0 < csa->regcnt); - /* If csa->regcnt is > 1, it is possible that csa->region is different from the actual gv_cur_region - * (before we encountered the runtime error). This is a case of two regions mapping to the same csa. - * The only issue with this is that some user-level error messages that have the region name (as - * opposed to the database file name) could print incorrect values. But other than that there should - * be no issues since finally the csa (corresponding to the physical database file) is what matters - * and that is the same for both the regions. Given that the region mismatch potential exists only - * until the next global reference which is different from $REFERENCE, we consider this acceptable. - */ - gv_cur_region = csa->region; - assert(gv_cur_region->open); - assert((dba_mm == gv_cur_region->dyn.addr->acc_meth) || (dba_bg == gv_cur_region->dyn.addr->acc_meth)); - /* The above assert is needed to ensure that change_reg/tp_change_reg (invoked below) - * will set cs_addrs, cs_data etc. to non-zero values. - */ - if (NULL != first_sgm_info) - change_reg(); /* updates "cs_addrs", "cs_data", "sgm_info_ptr" and maybe "first_sgm_info" */ - else - { /* We are either inside a non-TP transaction or in a TP transaction that has done NO database - * references. In either case, we do NOT want to setting sgm_info_ptr or first_sgm_info. - * Hence use tp_change_reg instead of change_reg below. + if (csa != cs_addrs) + { + assert(0 < csa->regcnt); + /* If csa->regcnt is > 1, it is possible that csa->region is different from the actual gv_cur_region + * (before we encountered the runtime error). This is a case of two regions mapping to the same csa. + * The only issue with this is that some user-level error messages that have the region name (as + * opposed to the database file name) could print incorrect values. But other than that there should + * be no issues since finally the csa (corresponding to the physical database file) is what matters + * and that is the same for both the regions. Given that the region mismatch potential exists only + * until the next global reference which is different from $REFERENCE, we consider this acceptable. */ - tp_change_reg(); /* updates "cs_addrs", "cs_data" */ + gv_cur_region = csa->region; + assert(gv_cur_region->open); + assert((dba_mm == gv_cur_region->dyn.addr->acc_meth) + || (dba_bg == gv_cur_region->dyn.addr->acc_meth)); + /* The above assert is needed to ensure that change_reg/tp_change_reg (invoked below) + * will set cs_addrs, cs_data etc. to non-zero values. + */ + if (NULL != first_sgm_info) + change_reg(); /* updates "cs_addrs", "cs_data", "sgm_info_ptr" and maybe "first_sgm_info" */ + else + { /* We are either inside a non-TP transaction or a TP transaction that has done NO database + * references. In either case, we do NOT want to setting sgm_info_ptr or first_sgm_info. + * Hence use tp_change_reg instead of change_reg below. + */ + tp_change_reg(); /* updates "cs_addrs", "cs_data" */ + } + assert(cs_addrs == csa); + assert(cs_data == csa->hdr); + assert(NULL != cs_data); + } + /* Fix gv_currkey to null-str in case gv_target points to dir_tree (possible in case of name-level-$order). + * This is similar to how we fix gv_currkey for a successful name-level-$order operation (see op_gvorder.c). + * Do same in case gv_target points to cs_addrs->hasht_tree so we dont take the fast path in op_gvname + * when gv_target is clearly not GVT of a user-visible global. + */ + if ((gv_target == csa->dir_tree) GTMTRIG_ONLY(|| (gv_target == csa->hasht_tree))) + { + gv_currkey->end = 0; + gv_currkey->base[0] = 0; } - assert(cs_addrs == csa); - assert(cs_data == csa->hdr); - assert(NULL != cs_data); } } + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); if (DUMPABLE) { /* Certain conditions we don't want to attempt to create the M-level ZSHOW dump. * 1) Unix: If gtmMallocDepth > 0 indicating memory manager was active and could be reentered. @@ -467,9 +541,9 @@ CONDITION_HANDLER(mdb_condition_handler) * duplicate message. */ assert(ERR_VMSMEMORY == SIGNAL); - send_msg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), + send_msg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - send_msg */ *(int **)(&sig->chf$is_sig_arg1 + 2)); - gtm_putmsg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), + gtm_putmsg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - gtm_putmsg */ *(int **)(&sig->chf$is_sig_arg1 + 2)); SIGNAL = ERR_GTMERREXIT; /* Override reason for "stop" */ # endif @@ -520,7 +594,12 @@ CONDITION_HANDLER(mdb_condition_handler) { csa = (sgmnt_addrs *)&FILE_INFO(reg_local)->s_addrs; if (csa && csa->now_crit) + { + assert(!csa->hold_onto_crit UNIX_ONLY(|| jgbl.onlnrlbk)); + if (csa->hold_onto_crit) + csa->hold_onto_crit = FALSE; /* Fix it in pro */ rel_crit(reg_local); + } } } } @@ -579,8 +658,6 @@ CONDITION_HANDLER(mdb_condition_handler) # endif err_dev = active_device; active_device = (io_desc *)NULL; - TREF(ind_result_sp) = TREF(ind_result_array); /* clean up any active indirection pool usages */ - TREF(ind_source_sp) = TREF(ind_source_array); dm_action = (frame_pointer->old_frame_pointer->type & SFT_DM) || (TREF(compile_time) && (frame_pointer->type & SFT_DM)); /* The errors are said to be transcendental when they occur during compilation/execution @@ -598,7 +675,7 @@ CONDITION_HANDLER(mdb_condition_handler) /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); - DBGEHND((stderr, "mdb_condition_handler(1): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt" + DBGEHND((stderr, "mdb_condition_handler(1): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; @@ -611,33 +688,40 @@ CONDITION_HANDLER(mdb_condition_handler) { /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); - DBGEHND((stderr, "mdb_condition_handler(2): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt" + DBGEHND((stderr, "mdb_condition_handler(2): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; frame_pointer->ctxt = restart_ctxt; + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " + "0x"lvaddr"\n", frame_pointer))); if (!(frame_pointer->type & SFT_DM)) dm_setup(); } else if (frame_pointer->type & SFT_DM) { frame_pointer->ctxt = GTM_CONTEXT(call_dm); frame_pointer->mpc = CODE_ADDRESS(call_dm); + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " + "0x"lvaddr"\n", frame_pointer))); } else { /* Do cleanup on indirect frames prior to reset */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer); frame_pointer->ctxt = GTM_CONTEXT(pseudo_ret); frame_pointer->mpc = CODE_ADDRESS(pseudo_ret); + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " + "0x"lvaddr"\n", frame_pointer))); } - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; /* Frame enterable now with mpc reset */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_TRIGR_CALLD (1) in frame 0x"lvaddr"\n", - frame_pointer))); PRN_ERROR; if (io_curr_device.out != io_std_device.out) - { dec_err(VARLSTCNT(4) ERR_NOTPRINCIO, 2, io_curr_device.out->trans_name->len, io_curr_device.out->trans_name->dollar_io); - } MUM_TSTART; } else if ((int)ERR_CTRAP == SIGNAL) { @@ -742,7 +826,7 @@ CONDITION_HANDLER(mdb_condition_handler) } else { PRN_ERROR; - rts_error(VARLSTCNT(1) ERR_NOEXCNOZTRAP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOEXCNOZTRAP); } } if (clean_mum_tstart()) @@ -754,8 +838,8 @@ CONDITION_HANDLER(mdb_condition_handler) { frame_pointer->ctxt = GTM_CONTEXT(call_dm); frame_pointer->mpc = CODE_ADDRESS(call_dm); - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; /* Frame enterable now with mpc reset */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_TRIGR_CALLD (2) in frame 0x" + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD (2) in frame 0x" lvaddr"\n", frame_pointer))); } else { @@ -763,8 +847,8 @@ CONDITION_HANDLER(mdb_condition_handler) IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer); frame_pointer->ctxt = GTM_CONTEXT(pseudo_ret); frame_pointer->mpc = CODE_ADDRESS(pseudo_ret); - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; /* Frame enterable now with mpc reset */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_TRIGR_CALLD (3) in frame 0x" + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD (3) in frame 0x" lvaddr"\n", frame_pointer))); } PRN_ERROR; @@ -779,7 +863,7 @@ CONDITION_HANDLER(mdb_condition_handler) { /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); - DBGEHND((stderr, "mdb_condition_handler(4): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt" + DBGEHND((stderr, "mdb_condition_handler(4): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; @@ -801,7 +885,7 @@ CONDITION_HANDLER(mdb_condition_handler) assert(stackwarn > stacktop); cp = stackwarn; stackwarn = stacktop; - push_stck(cp, 0, (void**)&stackwarn, MVST_STCK_SP); + push_stck(cp, 0, (void **)&stackwarn, MVST_STCK_SP); } if (!repeat_error) dollar_ecode.error_last_b_line = NULL; @@ -817,9 +901,7 @@ CONDITION_HANDLER(mdb_condition_handler) stringpool = rts_stringpool; /* change for set_zstatus */ } if (!repeat_error) - { dollar_ecode.error_last_b_line = SET_ZSTATUS(&context); - } assert(NULL != dollar_ecode.error_last_b_line); if (sp_base != rts_stringpool.base) { @@ -843,6 +925,7 @@ CONDITION_HANDLER(mdb_condition_handler) { proc_act_type = SFT_DEV_ACT; err_act = &err_dev->error_handler; + reserve_sock_dev = TRUE; /* Reset mpc to beginning of the current line (to retry after processing the IO exception handler) */ reset_mpc = TRUE; DBGEHND((stderr, "mdb_condition_handler: dispatching device error handler [%.*s]\n", err_act->len, @@ -857,7 +940,6 @@ CONDITION_HANDLER(mdb_condition_handler) "re-dispatching error frame\n")); MUM_TSTART_FRAME_CHECK; MUM_TSTART; /* unwind the current C-stack and restart executing from the top of the current M-stack */ - assert(FALSE); } else if ((0 != dollar_etrap.str.len) || (0 != dollar_ztrap.str.len)) { assert(!ztrap_explicit_null); @@ -915,6 +997,13 @@ CONDITION_HANDLER(mdb_condition_handler) err_act->addr)); } } + /* if the err_act points to the address err_dev->errro_handler, we cannot destroy socket here */ + if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created && !reserve_sock_dev) + { + assert(err_dev->state != dev_open); + iosocket_destroy(err_dev); + err_dev = NULL; + } if (reset_mpc) { /* Reset the mpc such that * (a) If the current frame is a counted frame, the error line is retried after the error is handled, @@ -944,6 +1033,10 @@ CONDITION_HANDLER(mdb_condition_handler) { assert(SFF_INDCE & fp->flags); fp->mpc = fp->ctxt; + fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" + " (4) in frame 0x"lvaddr"\n", frame_pointer))); break; } /* Do cleanup on indirect frames prior to reset */ @@ -953,31 +1046,90 @@ CONDITION_HANDLER(mdb_condition_handler) { /* GT.M specific error trapping retries the line with the error */ fp->mpc = dollar_ecode.error_last_b_line; fp->ctxt = context; + fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" + " (5) in frame 0x"lvaddr"\n", frame_pointer))); break; } else { fp->ctxt = GTM_CONTEXT(pseudo_ret); fp->mpc = CODE_ADDRESS(pseudo_ret); + fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY( + DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" + " (6) in frame 0x"lvaddr"\n", frame_pointer))); } - fp->flags &= SFF_TRIGR_CALLD_OFF; /* Frame enterable now with mpc reset */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_TRIGR_CALLD (4) " - "in frame 0x"lvaddr"\n", frame_pointer))); } } } if (clean_mum_tstart()) { + if (err_dev) + { +# ifdef UNIX + /* On z/OS, if opening a fifo which is not read only we need to fix the err_dev type to rm */ +# ifdef __MVS__ + if ((dev_open != err_dev->state) && (ff == err_dev->type)) + { + assert(NULL != err_dev->pair.out); + if (rm == err_dev->pair.out->type) + { + /* Have to massage the device so remove_rms will cleanup the partially + * created fifo. Refer to io_open_try.c for creation of split fifo device. + */ + err_dev->newly_created = 1; + err_dev->type = rm; + err_dev->dev_sp = err_dev->pair.out->dev_sp; + err_dev->pair.out->dev_sp = NULL; + } + } +# endif + if ((dev_open != err_dev->state) && (rm == err_dev->type)) + { + gtm_err_dev = err_dev; + /* structures pointed to by err_dev were freed so make sure it's not used again */ + err_dev = NULL; + } +# endif + if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created) + { + assert(err_dev->state != dev_open); + assert(reserve_sock_dev); + gtm_err_dev = err_dev; + err_dev = NULL; + } + } + MUM_TSTART_FRAME_CHECK; + MUM_TSTART; + } else + { + /* err_act is null, we can remove the socket device */ + if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created && !reserve_sock_dev) + { + assert(err_act == NULL); + assert(err_dev->state != dev_open); + iosocket_destroy(err_dev); + err_dev = NULL; + } + DBGEHND((stderr, "mdb_condition_handler: clean_mum_tstart returned FALSE\n")); + } + } else + { + DBGEHND((stderr, "mdb_condition_handler: Transient or direct mode frame -- bypassing handler dispatch\n")); + if (err_dev) + { # ifdef UNIX - /* On z/OS, if opening a fifo which is not read only we need to fix the type for the err_dev to rm */ + /* Executed from the direct mode so do the rms check and cleanup if necessary. On z/OS, if opening a fifo + * which is not read only we need to fix the type for the err_dev to rm. + */ # ifdef __MVS__ - if (err_dev && dev_open != err_dev->state && (ff == err_dev->type)) + if ((dev_open != err_dev->state) && (ff == err_dev->type)) { assert(NULL != err_dev->pair.out); if (rm == err_dev->pair.out->type) { - /* Have to massage the device so remove_rms will cleanup the partially - * created fifo. Refer to io_open_try.c for creation of split fifo device. - */ + /* Have to massage the device so remove_rms will cleanup the partially created fifo */ err_dev->newly_created = 1; err_dev->type = rm; err_dev->dev_sp = err_dev->pair.out->dev_sp; @@ -985,55 +1137,59 @@ CONDITION_HANDLER(mdb_condition_handler) } } # endif - if (err_dev && dev_open != err_dev->state && (rm == err_dev->type)) + if ((dev_open != err_dev->state) && (rm == err_dev->type)) { - gtm_err_dev = err_dev; - /* structures pointed to by err_dev were freed so make sure it's not used again */ + remove_rms(err_dev); err_dev = NULL; } # endif - MUM_TSTART_FRAME_CHECK; - MUM_TSTART; - } else - DBGEHND((stderr, "mdb_condition_handler: clean_mum_tstart returned FALSE\n")); - } else - { - DBGEHND((stderr, "mdb_condition_handler: Transient or direct mode frame -- bypassing handler dispatch\n")); -# ifdef UNIX - /* Executed from the direct mode so do the rms check and cleanup if necessary. On z/OS, if opening a fifo - * which is not read only we need to fix the type for the err_dev to rm. - */ -# ifdef __MVS__ - if (err_dev && dev_open != err_dev->state && (ff == err_dev->type)) - { - assert(NULL != err_dev->pair.out); - if (rm == err_dev->pair.out->type) + if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created) { - /* Have to massage the device so remove_rms will cleanup the partially created fifo */ - err_dev->newly_created = 1; - err_dev->type = rm; - err_dev->dev_sp = err_dev->pair.out->dev_sp; - err_dev->pair.out->dev_sp = NULL; + assert(err_dev->state != dev_open); + iosocket_destroy(err_dev); + err_dev = NULL; } } -# endif - if (err_dev && dev_open != err_dev->state && (rm == err_dev->type)) - { - remove_rms(err_dev); - /* Structures pointed to by err_dev were freed so make sure it's not used again */ - err_dev = NULL; - } -# endif } - if ((SFT_ZINTR | SFT_COUNT) != proc_act_type || 0 == dollar_ecode.error_last_b_line) + if (((SFT_ZINTR | SFT_COUNT) != proc_act_type) || (0 == dollar_ecode.error_last_b_line)) { /* No user console error for $zinterrupt compile problems and if not direct mode. Accomplish * this by bypassing the code inside this if which *will* be executed for most cases */ DBGEHND((stderr, "mdb_condition_handler: Printing error status\n")); - PRN_ERROR; - if (TREF(compile_time) && ((int)ERR_LABELMISSING) != SIGNAL) - show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE); + /* If we have a transcendental frame, we won't have driven an error handler but neither do we want to + * push this error out at this point. The call to trans_code_cleanup() below will null this frame and + * any other up to the next counted frame out by changing their mpc to pseudo_ret and will rethrow the + * error we have here so there is no need to push this error out here for anything but direct mode. + */ + UNIX_ONLY(if (dm_action)) + { + PRN_ERROR; + if (TREF(compile_time) && (((int)ERR_LABELMISSING) != SIGNAL)) + show_source_line(TRUE); + } } + /* Slight divergence in how we handle otherwise unhandled errors on UNIX and VMS. UNIX now has a strict no-unsolicited + * output from error messages policy unless dealing with a direct mode frame. This has a dependency on a robust + * error_return() routine which VMS does not presently have. Consequently the previous way of doing things still + * exists on VMS while on UNIX, a new cleaner (from an unsolicited console output) viewpoint is in place. Note that + * while it would be possible to extract out the common code between the two below versions, the result is nowhere + * near as clean looking. In this routine, clarity rules the roost. + */ +# ifdef UNIX + if (trans_action || dm_action) + { /* If true transcendental, do trans_code_cleanup(). If our counted frame is + * masquerading as a transcendental frame, run jobinterrupt_process_cleanup(). + */ + DBGEHND((stderr, "mdb_condition_handler: trans_code_cleanup() or jobinterrupt_process_cleanup being " + "dispatched\n")); + if (!(SFT_ZINTR & proc_act_type)) + trans_code_cleanup(); + else + jobinterrupt_process_cleanup(); + MUM_TSTART_FRAME_CHECK; + MUM_TSTART; + } +# elif VMS /* VMS only */ if (!dm_action && !trans_action && (0 != src_line_d.len)) { if (MSG_OUTPUT) @@ -1066,6 +1222,9 @@ CONDITION_HANDLER(mdb_condition_handler) dec_err(VARLSTCNT(1) ERR_SRCLOCUNKNOWN); } } +# else +# error "Unsupported platform" +# endif DBGEHND((stderr, "mdb_condition_handler: Condition not handled -- defaulting to process exit\n")); MUMPS_EXIT; } diff --git a/sr_port/mdef.h b/sr_port/mdef.h index 2cdf3b8..6c474cf 100644 --- a/sr_port/mdef.h +++ b/sr_port/mdef.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -77,6 +77,10 @@ typedef int int4; /* 4-byte signed integer */ typedef unsigned int uint4; /* 4-byte unsigned integer */ #define sssize_t size_t + +/* If ever the following macro (SHMDT) is expanded to a multi-line macro, care should be taken to save the errno immediately after + * the "shmdt" system call invocation to avoid errno from being mutated by subsequent system calls. + */ #define SHMDT(X) shmdt((void *)(X)) /* constant needed for FIFO - OS390 redefines in mdefsp.h */ @@ -84,7 +88,8 @@ typedef unsigned int uint4; /* 4-byte unsigned integer */ #include #include "mdefsa.h" -#include "mdefsp.h" +#include "gtm_common_defs.h" +#include #include "gtm_sizeof.h" #include "gtm_threadgbl.h" /* Anchor for thread-global structure rather than individual global vars */ @@ -92,9 +97,13 @@ GBLREF void *gtm_threadgbl; /* Accessed through TREF macro in gtm_threadgbl.h * #ifdef DEBUG error_def(ERR_ASSERT); -#define assert(x) ((x) ? 1 : rts_error(VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, (SIZEOF(#x) - 1), (#x))) +# define assert(x) ((x) ? 1 : rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, \ + (SIZEOF(#x) - 1), (#x))) +# ifdef UNIX +# define GTMDBGFLAGS_ENABLED +# endif #else -#define assert(x) +# define assert(x) #endif #ifdef GTM64 @@ -123,22 +132,22 @@ error_def(ERR_ASSERT); # define FD_INVALID_NONPOSIX 0 /* fd of 0 is invalid in VMS if using RMS sys$open calls (non-posix interface) */ #endif -/* Now that mdefsp.h is included, GBLDEF should have been #defined. Use it to define STATICDEF for variables - * and STATICFNDEF, STATICFNDCL for functions. Define STATICDEF to "GBLDEF". This way we know such usages are intended - * to be "static" but yet can effectively debug these variables since they are externally visible. - * For functions, do not use the "static" keyword to make them externally visible. - * Note that a STATICREF for variables does not make sense since statics are supposed to be used only within one module. - */ -#define STATICDEF GBLDEF -#define STATICFNDCL extern -#define STATICFNDEF +#if defined(UNIX) +# define USE_POLL +# define POLL_ONLY(X) X +# define SELECT_ONLY(X) +#else +# define USE_SELECT +# define POLL_ONLY(X) +# define SELECT_ONLY(X) X +#endif /* INTPTR_T is an integer that has the same length as a pointer on each platform. Its basic use is for arithmetic - or generic parameters. For all platforms except Tru64/VMS (alpha platforms), the [U]INTPTR_T types will be - equivalenced to [u]intptr_t. But since this type is used for alignment and other checking, and since Tru64/VMS - (implemented as a 32 bit platform) unconditionally sets this type to its 8 char variant, on Tru64/VMS we will - explicitly make [U]INTPTR_T a 4 byte creature. -*/ + * or generic parameters. For all platforms except Tru64/VMS (alpha platforms), the [U]INTPTR_T types will be + * equivalenced to [u]intptr_t. But since this type is used for alignment and other checking, and since Tru64/VMS + * (implemented as a 32 bit platform) unconditionally sets this type to its 8 char variant, on Tru64/VMS we will + * explicitly make [U]INTPTR_T a 4 byte creature. + */ #if !defined(__alpha) typedef intptr_t INTPTR_T; typedef uintptr_t UINTPTR_T; @@ -157,8 +166,6 @@ typedef UINTPTR_T uintszofptr_t; #ifdef GTM64 # define USER_STACK_SIZE 8192 -# define GTM64_ONLY(X) X -# define NON_GTM64_ONLY(X) # define VA_ARG_TYPE long # define VA_ARG_TYPE_BOOL int # define GTM_IS_64BIT TRUE @@ -166,8 +173,6 @@ typedef UINTPTR_T uintszofptr_t; # define GTM_BITNESS_OTHER "32-bit" #else # define USER_STACK_SIZE 4096 -# define GTM64_ONLY(X) -# define NON_GTM64_ONLY(X) X # define VA_ARG_TYPE int # define VA_ARG_TYPE_BOOL int # define GTM_IS_64BIT FALSE @@ -205,6 +210,13 @@ typedef UINTPTR_T uintszofptr_t; # define UNALIGNED_ACCESS_SUPPORTED #endif +#if defined(__i386) || defined(__x86_64__) || defined(_AIX) || defined (__sun) +# define GTM_PTHREAD +# define GTM_PTHREAD_ONLY(X) X +#else +# define GTM_PTHREAD_ONLY(X) +#endif + #if defined(__ia64) # define IA64_ONLY(X) X # define NON_IA64_ONLY(X) @@ -219,20 +231,6 @@ typedef UINTPTR_T uintszofptr_t; # define IA64_DEBUG_ONLY(X) #endif/* __ia64 */ -#if defined(__ia64) || defined(__MVS__) -# define INTCAST(X) ((int)(X)) -# define UINTCAST(X) ((uint4)(X)) -# define STRLEN(X) ((int)(strlen(X))) -# define USTRLEN(X) ((unsigned int)(strlen(X))) -# define OFFSETOF(X,Y) ((int)(offsetof(X,Y))) -#else -# define INTCAST(X) X -# define UINTCAST(X) X -# define STRLEN(X) strlen(X) -# define USTRLEN(X) strlen(X) -# define OFFSETOF(X,Y) offsetof(X,Y) -#endif - /* macro to check that the OFFSET & SIZE of TYPE1.MEMBER1 is identical to that of TYPE2.MEMBER2 */ #define IS_OFFSET_AND_SIZE_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) \ (SIZEOF(((TYPE1 *)NULL)->MEMBER1) == SIZEOF(((TYPE2 *)NULL)->MEMBER2)) \ @@ -240,10 +238,6 @@ typedef UINTPTR_T uintszofptr_t; #define IS_OFFSET_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) (OFFSETOF(TYPE1, MEMBER1) == OFFSETOF(TYPE2, MEMBER2)) -#define ARRAYSIZE(arr) SIZEOF(arr)/SIZEOF(arr[0]) /* # of elements defined in the array */ -#define ARRAYTOP(arr) (&arr[0] + ARRAYSIZE(arr)) /* address of the TOP of the array (first byte AFTER array limits). - * use &arr[0] + size instead of &arr[size] to avoid compiler warning. - */ #ifdef __x86_64__ #define X86_64_ONLY(x) x #define NON_X86_64_ONLY(x) @@ -302,7 +296,7 @@ typedef struct #define MAX_MIDENT_LEN 31 /* Maximum length of an mident/mname */ typedef mstr mident; typedef struct -{ /* Although we use 31 chars, the extra byte is to keep things aligned */ +{ /* Although we use 31 chars, the extra byte is to keep things aligned AND to keep a null terminator byte for places that care */ char c[MAX_MIDENT_LEN + 1]; } mident_fixed; #define mid_len(name) strlen(&(name)->c[0]) /* callers of mid_len should include gtm_string.h as well */ @@ -380,15 +374,6 @@ typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of #define MV_BIAS_PWR 3 #define NR_REG 16 -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif -#ifndef NULL -# define NULL ((void *) 0) -#endif #define NUL 0x00 #define SP 0x20 #define DEL 0x7f @@ -403,9 +388,19 @@ typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of #define MAX_NUM_SIZE 64 #define MAX_FORM_NUM_SUBLEN 128 /* this is enough to hold the largest numeric subscript */ #define PERIODIC_FLUSH_CHECK_INTERVAL (30 * 1000) -#define MAX_ARGS 256 /* in formallist */ -#define MAX_KEY_SZ 255 /* maximum database key size */ +#ifndef __sparc +# define MAX_ARGS 256 /* in formallist */ +#else /* Sparc super frame has room for 256 args, but functions or concatenate are limited to somewhat fewer */ +# define MAX_ARGS 242 +#endif + +#ifdef UNIX +# define MAX_KEY_SZ 1023 /* maximum database key size */ +#else +# define MAX_KEY_SZ 255 +#endif +# define OLD_MAX_KEY_SZ 255 /* For V5 and earlier, when only 1 byte was used for compression count */ /* The macro ZWR_EXP_RATIO returns the inflated length when converting the internal subscript * representation (byte) length to ZWR representation. * In "M" mode, @@ -444,6 +439,7 @@ GBLREF boolean_t gtm_utf8_mode; unsigned char *n2s(mval *mv_ptr); char *s2n(mval *u); mval *underr (mval *start, ...); +mval *underr_strict(mval *start, ...); #ifdef DEBUG # define DBG_ASSERT(X) assert(X), @@ -464,9 +460,9 @@ mval *underr (mval *start, ...); #define MV_FORCE_MVAL(M,I) (((I) >= 1000000 || (I) <= -1000000) ? i2mval((M),(int)(I)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS )) #ifdef GTM64 -#define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ul2mval((M),(unsigned long)(L)) : \ +#define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ui82mval((M),(gtm_uint64_t)(L)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS )) -#define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? l2mval((M),(long)(L)) : \ +#define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? i82mval((M),(gtm_int64_t)(L)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS )) #else #define MV_FORCE_ULMVAL MV_FORCE_UMVAL @@ -554,11 +550,6 @@ mval *underr (mval *start, ...); #define DISK_BLOCK_SIZE 512 #define LOG2_DISK_BLOCK_SIZE 9 -#define DIVIDE_ROUND_UP(VALUE, MODULUS) (((VALUE) + ((MODULUS) - 1)) / (MODULUS)) -#define DIVIDE_ROUND_DOWN(VALUE, MODULUS) ((VALUE) / (MODULUS)) -#define ROUND_UP(VALUE, MODULUS) (DIVIDE_ROUND_UP(VALUE, MODULUS) * (MODULUS)) -#define ROUND_DOWN(VALUE, MODULUS) (DIVIDE_ROUND_DOWN(VALUE, MODULUS) * (MODULUS)) - #ifdef DEBUG # define CHECKPOT(MODULUS) ((MODULUS) & ((MODULUS) - 1)) ? GTMASSERT, 0 : # define BREAK_IN_PRO__CONTINUE_IN_DBG continue @@ -602,9 +593,26 @@ int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[] #define GTMASSERT (gtm_assert(CALLFROM)) #define assertpro(x) ((x) ? 1 : gtm_assert2((SIZEOF(#x) - 1), (#x), CALLFROM)) #ifdef UNIX -int rts_error(int argcnt, ...); -void dec_err(uint4 argcnt, ...); +#ifdef DEBUG +/* The below debug only macros are always used in pairs to indicate a window where the code doesn't expect rts_errors to happen. + * One reason why the code doesn't expect rts_errors is if the logic is complicated enough that having a condition handler for + * the window is tricky and will not undo the state of various global variables that were modified. An example of such a window + * is in gvcst_init. If an rts_error happens in this window, an assert will trip in rts_error at which point, the window as well + * as the rts_error can be re-examined to see whether the rts_error can be removed or the range of the window can be changed. + */ +#define DBG_MARK_RTS_ERROR_USABLE { assert(TREF(rts_error_unusable)); TREF(rts_error_unusable) = FALSE; } +#define DBG_MARK_RTS_ERROR_UNUSABLE { assert(!TREF(rts_error_unusable)); TREF(rts_error_unusable) = TRUE; } +#else +#define DBG_MARK_RTS_ERROR_USABLE +#define DBG_MARK_RTS_ERROR_UNUSABLE +#endif +int rts_error(int argcnt, ...); +int rts_error_csa(void *csa, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */ +#define CSA_ARG(CSA) (CSA), +void dec_err(uint4 argcnt, ...); #elif defined(VMS) +#define rts_error_csa rts_error +#define CSA_ARG(CSA) /* no csa arg on VMS */ void dec_err(int4 msgnum, ...); #else #error unsupported platform @@ -621,21 +629,6 @@ int4 timeout2msec(int4 timeout); #define RTS_ERROR_LITERAL(LITERAL) LENGTH_AND_LITERAL(LITERAL) #define RTS_ERROR_STRING(STRING) LENGTH_AND_STRING(STRING) -/* the LITERAL version of the macro should be used over STRING whenever possible for efficiency reasons */ -#define STR_LIT_LEN(LITERAL) (SIZEOF(LITERAL) - 1) -#define LITERAL_AND_LENGTH(LITERAL) (LITERAL), (SIZEOF(LITERAL) - 1) -#define LENGTH_AND_LITERAL(LITERAL) (SIZEOF(LITERAL) - 1), (LITERAL) -#define STRING_AND_LENGTH(STRING) (STRING), (STRLEN((char *)(STRING))) -#define LENGTH_AND_STRING(STRING) (strlen((char *)(STRING))), (STRING) - -#define LEN_AND_LIT(LITERAL) LENGTH_AND_LITERAL(LITERAL) -#define LIT_AND_LEN(LITERAL) LITERAL_AND_LENGTH(LITERAL) -#define STR_AND_LEN(STRING) STRING_AND_LENGTH(STRING) -#define LEN_AND_STR(STRING) LENGTH_AND_STRING(STRING) - -#define MEMCMP_LIT(SOURCE, LITERAL) memcmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1) -#define MEMCPY_LIT(TARGET, LITERAL) memcpy(TARGET, LITERAL, SIZEOF(LITERAL) - 1) - #define SET_PROCESS_EXITING_TRUE \ { \ GBLREF int process_exiting; \ @@ -643,43 +636,6 @@ int4 timeout2msec(int4 timeout); process_exiting = TRUE; \ } -/* Macro to copy a source string to a malloced area that is set to the destination pointer. - * Since it is possible that DST might have multiple pointer dereferences in its usage, we - * use a local pointer variable and finally assign it to DST thereby avoiding duplication of - * those pointer dereferences (one for the malloc and one for the strcpy). - * There are two macros depending on whether a string or literal is passed. - */ -#define MALLOC_CPY_STR(DST, SRC) \ -{ \ - char *mcs_ptr; \ - int mcs_len; \ - \ - mcs_len = STRLEN(SRC) + 1; \ - mcs_ptr = malloc(mcs_len); \ - memcpy(mcs_ptr, SRC, mcs_len); \ - DST = mcs_ptr; \ -} - -#define MALLOC_CPY_LIT(DST, SRC) \ -{ \ - char *mcs_ptr; \ - int mcs_len; \ - \ - mcs_len = SIZEOF(SRC); \ - mcs_ptr = malloc(mcs_len); \ - memcpy(mcs_ptr, SRC, mcs_len); \ - DST = mcs_ptr; \ -} - -#define MALLOC_INIT(DST, SIZ) \ -{ \ - void *lcl_ptr; \ - \ - lcl_ptr = malloc(SIZ); \ - memset(lcl_ptr, 0, SIZ); \ - DST = lcl_ptr; \ -} - /* *********************************************************************************************************** */ /* Frequently used len + str combinations in macro form. */ /* *********************************************************************************************************** */ @@ -711,67 +667,12 @@ int m_usleep(int useconds); # define SHORT_SLEEP(x) hiber_start(x); #endif -/* The following "MSYNC" defines are for the MM access method - * NO_MSYNC -- minimum number of msyncs -- only in run down - * UNTARGETED_MSYNC -- msync the entire file - * TARGETED_MSYNC -- keep track of changed buffers and only msync them - * REGULAR_MSYNC -- do regular file I/O on the mapped file (ignoring the fact it is mapped) - * - * If none of the MSYNCs are explicitly defined, the ifdef and elif defined sequence will fall through - * to the else case, defining NO_MSYNC as the default. - */ #ifdef UNIX # define UNIX_ONLY(X) X # define UNIX_ONLY_COMMA(X) X, -# if defined UNTARGETED_MSYNC -# define UNTARGETED_MSYNC_ONLY(X) X -# define NON_UNTARGETED_MSYNC_ONLY(X) -# define TARGETED_MSYNC_ONLY(X) -# define NON_TARGETED_MSYNC_ONLY(X) X -# define REGULAR_MSYNC_ONLY(X) -# define NON_REGULAR_MSYNC_ONLY(X) X -# define NO_MSYNC_ONLY(X) -# define NON_NO_MSYNC_ONLY(X) -# elif defined TARGETED_MSYNC -# define UNTARGETED_MSYNC_ONLY(X) -# define NON_UNTARGETED_MSYNC_ONLY(X) X -# define TARGETED_MSYNC_ONLY(X) X -# define NON_TARGETED_MSYNC_ONLY(X) -# define REGULAR_MSYNC_ONLY(X) -# define NON_REGULAR_MSYNC_ONLY(X) X -# define NO_MSYNC_ONLY(X) -# define NON_NO_MSYNC_ONLY(X) -# elif defined REGULAR_MSYNC -# define UNTARGETED_MSYNC_ONLY(X) -# define NON_UNTARGETED_MSYNC_ONLY(X) X -# define TARGETED_MSYNC_ONLY(X) -# define NON_TARGETED_MSYNC_ONLY(X) X -# define REGULAR_MSYNC_ONLY(X) X -# define NON_REGULAR_MSYNC_ONLY(X) -# define NO_MSYNC_ONLY(X) -# define NON_NO_MSYNC_ONLY(X) -# else -# define NO_MSYNC -# define UNTARGETED_MSYNC_ONLY(X) -# define NON_UNTARGETED_MSYNC_ONLY(X) -# define TARGETED_MSYNC_ONLY(X) -# define NON_TARGETED_MSYNC_ONLY(X) -# define REGULAR_MSYNC_ONLY(X) -# define NON_REGULAR_MSYNC_ONLY(X) -# define NO_MSYNC_ONLY(X) X -# define NON_NO_MSYNC_ONLY(X) -# endif #else # define UNIX_ONLY(X) # define UNIX_ONLY_COMMA(X) -# define UNTARGETED_MSYNC_ONLY(X) -# define TARGETED_MSYNC_ONLY(X) -# define REGULAR_MSYNC_ONLY(X) -# define NON_UNTARGETED_MSYNC_ONLY(X) -# define NON_TARGETED_MSYNC_ONLY(X) -# define NON_REGULAR_MSYNC_ONLY(X) -# define NO_MSYNC_ONLY(X) -# define NON_NO_MSYNC_ONLY(X) #endif /* HP-UX on PA-RISC and z/OS are not able to have dynamic file extensions while running in MM access mode @@ -891,6 +792,24 @@ typedef struct #define GLOBAL_LATCH_HELD_BY_US(latch) (process_id == (latch)->u.parts.latch_pid \ VMS_ONLY(&& image_count == (latch)->u.parts.latch_image_count)) +typedef struct compswap_time_field_struct +{ /* This structure is used where we want to do a compare-n-swap (CAS) on a time value. The CAS interfaces + * need an instance of global_latch_t to operate on. We will utilize the "latch_pid" field to hold the + * time and the latch_word is unused except on VMS where it will hold 0. Since this structure must be of + * a constant size (size of global_latch_t varies), pad the latch with sufficient space to match the + * size of global_latch_t's largest size (on HPUX). + */ +global_latch_t time_latch; +#ifndef __hppa +int4 hp_latch_space[4]; /* padding only on non-hpux systems */ +#endif +} compswap_time_field; +/* takes value of time() but needs to be 4 byte so can use compswap on it. Not using time_t, as that is an indeterminate size on + * various platforms. Value is time (in seconds) in a compare/swap updated field so only one process performs a given task in a + * given interval + */ +#define cas_time time_latch.u.parts.latch_pid + typedef union gtm_time8_struct { time_t ctime; /* For current GTM code sem_ctime field corresponds to creation time */ @@ -911,7 +830,7 @@ typedef struct sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */ global_latch_t latch; /* required for platforms without atomic operations to modify both fl and bl concurrently; * unused on platforms with such instructions. */ -} que_head, cache_que_head, mmblk_que_head; +} que_head, cache_que_head; #define IS_PTR_ALIGNED(ptr, ptr_base, elemSize) \ (0 == ((((sm_uc_ptr_t)(ptr)) - ((sm_uc_ptr_t)(ptr_base))) % elemSize)) @@ -1276,11 +1195,11 @@ typedef INTPTR_T ptroff_t; # define CACHELINE_PAD_COND(fieldSize, fillnum) #endif -#define MEMCP(dst,src,start,count,limit){ \ - if (start+count > limit) \ - rts_error(VARLSTCNT(1) ERR_CPBEYALLOC); \ - else \ - memcpy(dst+start,src,count); \ +#define MEMCP(dst,src,start,count,limit){ \ + if (start+count > limit) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CPBEYALLOC); \ + else \ + memcpy(dst+start,src,count); \ } #ifndef USING_ICONV @@ -1321,7 +1240,8 @@ uchar_ptr_t i2asc(uchar_ptr_t p, unsigned int n); /* ascii conversion functions */ int4 asc2i(uchar_ptr_t p, int4 len); qw_num asc2l(uchar_ptr_t p, int4 len); -unsigned int asc_hex2i(char *p, int len); +unsigned int asc_hex2i(uchar_ptr_t p, int len); +gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len); /* This macro converts an integer to a decimal string (a more efficient alternative to i2asc). * It is used by format2zwr() which is called a lot during MUPIP EXTRACT (which can be time-consuming @@ -1389,7 +1309,7 @@ int val_iscan(mval *v); void mcfree(void); int4 getprime(int4 n); void push_parm(UNIX_ONLY_COMMA(unsigned int totalcnt) int truth_value, ...); -void suspend(void); +UNIX_ONLY(void suspend(int sig);) mval *push_mval(mval *arg1); void mval_lex(mval *v, mstr *output); @@ -1829,5 +1749,43 @@ enum #define MAX_ACTUALS 32 /* Maximum number of arguments allowed in an actuallist. This value also determines * how many parameters are allowed to be passed between M and C. */ +#if defined(DEBUG) && defined(UNIX) +#define OPERATOR_LOG_MSG \ +{ \ + error_def(ERR_TEXT); /* BYPASSOK */ \ + if (gtm_white_box_test_case_enabled && (WBTEST_OPER_LOG_MSG == gtm_white_box_test_case_number)) \ + { \ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Send message to operator log")); \ + } \ +} +#else +#define OPERATOR_LOG_MSG +#endif + +#ifdef GTM_PTHREAD +/* If we detect a case when the signal came to a thread other than the main GT.M thread, this macro will redirect the signal to the + * main thread if such is defined. Such scenarios is possible, for instance, if we are running along a JVM, which, upon receiving a + * signal, dispatches a new thread to invoke signal handlers other than its own. The ptrhead_kill() enables us to target the signal + * to a specific thread rather than rethrow it to the whole process. + */ +#define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG) \ +{ \ + GBLREF pthread_t gtm_main_thread_id; \ + GBLREF boolean_t gtm_main_thread_id_set; \ + \ + if (gtm_main_thread_id_set && !pthread_equal(gtm_main_thread_id, pthread_self())) \ + { /* Only redirect the signal if the main thread ID has been defined, and we are not that. */ \ + pthread_kill(gtm_main_thread_id, SIG); \ + return; \ + } \ +} +#else +#define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG) +#endif + +#ifdef DEBUG +# define MVAL_IN_RANGE(V, START, END) (((char *)(V) >= (char *)(START)) \ + && ((char *)(V) < ((char *)(START) + (INTPTR_T)(END) * SIZEOF(mval)))) +#endif #endif /* MDEF_included */ diff --git a/sr_port/mdq.h b/sr_port/mdq.h index 9a4e640..079606e 100644 --- a/sr_port/mdq.h +++ b/sr_port/mdq.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,30 +9,84 @@ * * ****************************************************************/ -#ifdef DEBUG_TRIPLES -# define CHKTCHAIN(x) chktchain(x) -#else -# define CHKTCHAIN(x) -#endif +#ifndef MDQ_H_DEFINED +#define HDQ_H_DEFINED -/* All the following macros assume a doubly-linked list using "fl" and "bl" */ +/* Define basic working macros for queue management of doubly linked list is defined using elements "n.fl" and "n.bl". + * The DSRINS insert at tail rather than head and so work FIFO rather than LIFO with DQLOOP and associated macros + */ -#define dqloop(q,n,i) for (i = (q)->n.fl; i != (q); i = (i)->n.fl) +/* Loop through a linked list given any element as the start (q) and a var to use as loop incrementer */ +#define DQLOOP(q, n, i) for (i = (q)->n.fl; i != (q); i = (i)->n.fl) -#define dqinit(q,n) ((q)->n.fl = (q)->n.bl = q) +/* Initialize an element */ +#define DQINIT(q, n) ((q)->n.fl = (q)->n.bl = q) -/* delete one element "x" from the doubly linked list */ -#define dqdel(x,n) ((x)->n.bl->n.fl = (x)->n.fl, (x)->n.fl->n.bl = (x)->n.bl) +/* Delete one element "x" from the doubly linked list */ +#define DQDEL(x, n) ((x)->n.bl->n.fl = (x)->n.fl, (x)->n.fl->n.bl = (x)->n.bl) -/* delete a doubly-linked list of elements from "x->n.fl" to "y->n.bl" (i.e. everything in between "x" and "y" excluding them) */ -#define dqdelchain(x,y,n) {((x)->n.fl = (y), (y)->n.bl = (x)); CHKTCHAIN(x); CHKTCHAIN(y);} +/* Delete a doubly-linked list of elements from "x->n.fl" to "y->n.bl" (i.e. everything in between "x" and "y" excluding them) */ +#define DQDELCHAIN(x, y, n) ((x)->n.fl = (y), (y)->n.bl = (x)) /* Insert one element "x" in between "q" and "q->n.fl" */ -#define dqins(q,n,x) ((x)->n.fl = (q)->n.fl, (x)->n.bl =(q), (q)->n.fl=(x), ((x)->n.fl)->n.bl=(x)) +#define DQINS(q, n, x) ((x)->n.fl = (q)->n.fl, (x)->n.bl = (q), (q)->n.fl = (x), ((x)->n.fl)->n.bl = (x)) + +/* Insert one element "x" in between "q" and "q->n.bl" */ +#define DQRINS(q, n, x) ((x)->n.bl = (q)->n.bl, (x)->n.fl = (q), (q)->n.bl = (x), ((x)->n.bl)->n.fl = (x)) /* Insert a doubly-linked list of elements from "n->q.fl" to "n->q.bl" in between "o" and "o->q.fl" */ -#define dqadd(o,n,q) \ -{ \ - ((o)->q.fl->q.bl=(n)->q.bl, (n)->q.bl->q.fl=(o)->q.fl, (o)->q.fl=(n)->q.fl, (n)->q.fl->q.bl=(o)); \ - CHKTCHAIN(o); \ +#define DQADD(o, n, q) ((o)->q.fl->q.bl = (n)->q.bl, (n)->q.bl->q.fl = (o)->q.fl, (o)->q.fl = (n)->q.fl, (n)->q.fl->q.bl = (o)) + +/* Define macros actually used which if #define DEBUG_TRIPLES, adds debugging information. Since these macros are + * used in several different queue types and since these debugging macros only work for the exorder field in triples, + * the test to see if should do debugging is not elegant but it does allow decent debugging. Note those macros without + * debugging are statically defined. + */ + +#define dqloop(q, n, i) DQLOOP(q, n, i) +#define dqinit(q, n) DQINIT(q, n) + +/* #define DEBUG_TRIPLES / * Uncomment this to do triple debugging */ +#ifndef DEBUG_TRIPLES +# define dqdel(x, n) DQDEL(x, n) +# define dqdelchain(x, y, n) DQDELCHAIN(x, y, n) +# define dqins(q, n, x) DQINS(q, n, x) +# define dqrins(q, n, x) DQRINS(q, n, x) +# define dqadd(o, n, q) DQADD(o, n, q) +# define CHKTCHAIN(x) +#else +# include "compiler.h" +# define CHKTCHAIN(x) chktchain((triple *)(x)) +# define IFEXOCHN(n, c) if (0 == memcmp(#n, "exorder", 3)) c /* memcmp() should be faster and for 3 chars, just as effective */ +# define dqdel(x, n) \ +{ \ + IFEXOCHN(n, CHKTCHAIN(x)); \ + DQDEL(x, n); \ } +# define dqdelchain(x, y, n) \ +{ \ + IFEXOCHN(n, CHKTCHAIN(x)); \ + DQDELCHAIN(x, y, n); \ + IFEXOCHN(n, CHKTCHAIN(y)); \ +} +# define dqins(q, n, x) \ +{ \ + IFEXOCHN(n, CHKTCHAIN(q)); \ + DQINS(q, n, x); \ + IFEXOCHN(n, CHKTCHAIN(q)); \ +} +# define dqrins(q, n, x) \ +{ \ + IFEXOCHN(n, CHKTCHAIN(q)); \ + DQRINS(q, n, x); \ + IFEXOCHN(n, CHKTCHAIN(q)); \ +} +# define dqadd(o, n, q) \ +{ \ + IFEXOCHN(n, CHKTCHAIN(o)); \ + DQADD(o, n, q); \ + IFEXOCHN(n, CHKTCHAIN(o)); \ +} +#endif + +#endif diff --git a/sr_port/merrors.msg b/sr_port/merrors.msg index becb8b2..eb1e35f 100644 --- a/sr_port/merrors.msg +++ b/sr_port/merrors.msg @@ -1,6 +1,6 @@ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! -! Copyright 2001, 2012 Fidelity Information Services, Inc ! +! Copyright 2001, 2013 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! @@ -144,25 +144,27 @@ ! ERR_OPCOMMISSED 150381275 (sent via $SNDOPR in util_output.c if prior errors) ! ! List of known undocumented messages follows (along with a comment) -! ERR_JNLREQUIRED message referenced only in GT.CX code (not supported currently) -! ERR_LKSECINIT message referenced only in GT.CX code (not supported currently) -! ERR_JNLWRTNOWWRTR internal error (not displayed to the users) ! ERR_ACK internal error (not displayed to the users) -! ERR_ENQ internal error (not displayed to the users) -! ERR_REPEATERROR internal error (not displayed to the users) -! ERR_TPRETRY internal error (not displayed to the users) -! ERR_INVDBGLVL referenced only if "gtmdbglvl" is set to non-zero value (which is a debugging feature) +! ERR_ASC2EBCDICCONV not yet documented since zOS is not officially supported ! ERR_DEFEREVENT referenced only if #define DEBUG is TRUE (i.e. for debug builds only) +! ERR_ENQ internal error (not displayed to the users) ! ERR_FREEZEID referenced only if #define DEBUG_FREEZE is TRUE. +! ERR_INVDBGLVL referenced only if "gtmdbglvl" is set to non-zero value (which is a debugging feature) +! ERR_JNLREQUIRED message referenced only in GT.CX code (not supported currently) +! ERR_JNLWRTNOWWRTR internal error (not displayed to the users) +! ERR_JOBINTRRETRHOW internal error (not displayed to users - drives rethrow of jobinterrupt) +! ERR_JOBINTRRQST internal error (not displayed to users - drives jobinterrupt) +! ERR_LKSECINIT message referenced only in GT.CX code (not supported currently) ! ERR_MUDESTROYFAIL referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE. ! ERR_MUDESTROYSUC referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE. -! ERR_ASC2EBCDICCONV not yet documented since zOS is not officially supported +! ERR_RBWRNNOTCHG not seen by user since return status of mupip_set_file (that triggers this) is not displayed. +! ERR_REPEATERROR internal error (not displayed to the users) ! ERR_SYSTEMVALUE code is not executed (set $system won't reach op_svput at all to signal the error) +! ERR_TPRETRY internal error (not displayed to the users) +! ERR_WILLEXPIRE error triggered by the license management code which has been since disabled. ! ERR_YDIRTSZ used by a percent utility, which is not documented intentionally ! ERR_ZDEFACTIVE functionality not documented (GT.CM related weirdness) ! ERR_ZDEFOFLOW functionality not documented (GT.CM related weirdness) -! ERR_WILLEXPIRE error triggered by the license management code which has been since disabled. -! ERR_RBWRNNOTCHG not seen by user since return status of mupip_set_file (that triggers this) is not displayed. ! ! ! ----- Buffer to introduce new undocumented error messages without affecting UNUSEDMSGnnn match with corresponding line numbers. @@ -171,8 +173,6 @@ ! ! ! -! -! ! In addition all messages of the LMU and GTLP message facility are not documented as Licensing is out of GT.M since V4.2. ! ACK <>/success/fao=0!/ansi=0 @@ -229,7 +229,7 @@ ERRWZTRAP /error/fao=0!/ansi=0 NUMUNXEOR /error/fao=2!/ansi=0 EXPR /error/fao=0!/ansi=0 STRUNXEOR /error/fao=2!/ansi=0 -JNLEXTEND /error/fao=2!/ansi=0 +JNLEXTEND /error/fao=2!/ansi=0 FCHARMAXARGS /error/fao=0!/ansi=0 FCNSVNEXPECTED /error/fao=0!/ansi=0 FNARGINC /error/fao=2!/ansi=2 @@ -257,11 +257,11 @@ GVSUBOFLOW /error/fao=0!/ansi=0 GVUNDEF /error/fao=2!/ansi=7 TRANSNEST /error/fao=0!/ansi=0 INDEXTRACHARS /error/fao=0!/ansi=0 -INDMAXNEST /error/fao=0!/ansi=0 +UNUSEDMSG260 /error/fao=0!/ansi=0 INDRMAXLEN /error/fao=1!/ansi=0 INSFFBCNT /error/fao=0!/ansi=0 INTEGERRS /error/fao=0!/ansi=0 -INVCMD /error/fao=0!/ansi=0 +INVCMD /warning/fao=0!/ansi=0 INVFCN /error/fao=0!/ansi=0 INVOBJ /error/fao=0!/ansi=0 INVSVN /error/fao=0!/ansi=8 @@ -357,7 +357,7 @@ TERMASTQUOTA /error/fao=0!/ans TEXTARG /error/fao=0!/ansi=5 TMPSTOREMAX /error/fao=0!/ansi=0 VIEWCMD /error/fao=0!/ansi=0 -TXTNEGLIN /error/fao=0!/ansi=12 +JNI /error/fao=2!/ansi=0 TXTSRCFMT <$TEXT encountered an invalid source program file format>/error/fao=0!/ansi=0 UIDMSG /error/fao=0!/ansi=0 UIDSND /error/fao=0!/ansi=0 @@ -366,9 +366,9 @@ UNIMPLOP /error/fao=0!/ansi=0 VAREXPECTED /error/fao=0!/ansi=39 VARRECBLKSZ /error/fao=0!/ansi=0 MAXARGCNT /error/fao=1!/ansi=0 -WCFAIL /error/fao=0!/ansi=0 +GTMSECSHRSEMGET /error/fao=1!/ansi=0 VIEWARGCNT /error/fao=2!/ansi=0 -XKILLCNTEXC /error/fao=1!/ansi=0 +GTMSECSHRDMNSTARTED /info/fao=5!/ansi=0 ZATTACHERR /error/fao=2!/ansi=0 ZDATEFMT <$ZDATE format string contains invalid character>/error/fao=0!/ansi=0 ZEDFILSPEC /error/fao=2!/ansi=0 @@ -423,7 +423,7 @@ GVRUNDOWN /error/fao=0!/ansi=0 LKRUNDOWN /error/fao=0!/ansi=0 IORUNDOWN /error/fao=0!/ansi=0 FILENOTFND /error/fao=2!/ansi=0 -MUFILRNDWNFL /info/fao=2!/ansi=0 +MUFILRNDWNFL /error/fao=2!/ansi=0 JNLTMQUAL1 /error/fao=0!/ansi=0 -UNUSEDMSG438 /error/fao=0!/ansi=11 +FALLINTOFLST /error/fao=0!/ansi=11 NOTEXTRINSIC /error/fao=0!/ansi=16 -UNUSEDMSG440 /error/fao=0!/ansi=11 +GTMSECSHRREMSEMFAIL /error/fao=1!/ansi=0 FMLLSTMISSING /error/fao=2!/ansi=20 ACTLSTTOOLONG /error/fao=2!/ansi=58 ACTOFFSET /error/fao=0!/ansi=0 MAXACTARG /error/fao=0!/ansi=0 -GTMDUMPFAIL /error/fao=0!/ansi=0 +GTMSECSHRREMSEM <[client pid !UL] Semaphore (!UL) removed>/error/fao=2!/ansi=0 JNLTMQUAL2 /error/fao=0!/ansi=0 FILECREATE /info/fao=4!/ansi=0 FILENOTCREATE /info/fao=4!/ansi=0 -JNLPROCSTUCK /info/fao=1!/ansi=0 +JNLPROCSTUCK /warning/fao=1!/ansi=0 INVGLOBALQUAL /error/fao=3!/ansi=0 COLLARGLONG /error/fao=1!/ansi=0 NOPINI /error/fao=3!/ansi=0 @@ -614,7 +614,7 @@ WCERRNOTCHG /error/fao=0!/ansi=0 WCWRNNOTCHG /warning/fao=0!/ansi=0 ZCWRONGDESC /error/fao=0!/ansi=0 MUTNWARN /warning/fao=4!/ansi=0 -JNLNAMLEN /error/fao=5!/ansi=0 +GTMSECSHRUPDDBHDR <[client pid !UL] database fileheader (!AD) updated !AD>/info/fao=5!/ansi=0 LCKSTIMOUT /warning/fao=0!/ansi=0 CTLMNEMAXLEN /error/fao=0!/ansi=0 CTLMNEXPECTED /error/fao=0!/ansi=0 @@ -667,7 +667,7 @@ CETOOLONG /error/fao=0!/ CENOINDIR /error/fao=0!/ansi=0 COLLATIONUNDEF /error/fao=1!/ansi=0 RBWRNNOTCHG /warning/fao=0!/ansi=0 -GTMSECSHRSRVF /error/fao=3!/ansi=0 +GTMSECSHRSRVF /error/fao=4!/ansi=0 FREEZECTRL /info/fao=0!/ansi=0 JNLFLUSH /info/fao=2!/ansi=0 CCPSIGDMP /info/fao=0!/ansi=0 @@ -704,7 +704,7 @@ DBCRERR /info /fao=2!/ansi=0 MUNOACTION /error /fao=0!/ansi=0 RMBIGSHARE /error/fao=0!/ansi=0 -TPRESTART /info /fao=14!/ansi=0 +TPRESTART /info /fao=14!/ansi=0 SOCKWRITE /error /fao=0!/ansi=0 DBCNTRLERR /info /fao=2!/ansi=0 NOTERMENV /info /fao=0!/ansi=0 @@ -738,26 +738,26 @@ ZCCSQRBR /error/fao=0!/ansi=0 ZCPREALLNUMEX /error/fao=0!/ansi=0 ZCPREALLVALPAR /error/fao=0!/ansi=0 VERMISMATCH /error/fao=6!/ansi=0 -JNLCNTRL /error/fao=2!/ansi=0 +JNLCNTRL /error/fao=2!/ansi=0 TRIGNAMBAD /error/fao=4!/ansi=0 BUFRDTIMEOUT /error/fao=6!/ansi=0 INVALIDRIP /error/fao=2!/ansi=0 BLKSIZ512 /info/fao=2!/ansi=0 MUTEXERR /error/fao=0!/ansi=0 JNLVSIZE /error/fao=7!/ansi=0 -MUTEXLCKALERT /warning/fao=3!/ansi=0 +MUTEXLCKALERT /warning/fao=4!/ansi=0 MUTEXFRCDTERM /warning/fao=3!/ansi=0 GTMSECSHR /error/fao=1!/ansi=0 -GTMSECSHRSRVFID /warning/fao=6!/ansi=0 -GTMSECSHRSRVFIL /warning/fao=7!/ansi=0 -SOCKACTNA /error/fao=0!/ansi=0 +GTMSECSHRSRVFID /warning/fao=6!/ansi=0 +GTMSECSHRSRVFIL /warning/fao=7!/ansi=0 +FREEBLKSLOW /warning/fao=4!/ansi=0 PROTNOTSUP /error/fao=2!/ansi=0 DELIMSIZNA /error/fao=0!/ansi=0 INVCTLMNE /error/fao=0!/ansi=0 SOCKLISTEN /error/fao=0!/ansi=0 LQLENGTHNA /error/fao=1!/ansi=0 ADDRTOOLONG /error/fao=4!/ansi=0 -UNUSEDMSG760 /error/fao=0!/ansi=76 +GTMSECSHRGETSEMFAIL /error/fao=1!/ansi=0 CPBEYALLOC /error/fao=0!/ansi=0 DBRDONLY /error/fao=2!/ansi=0 DUPTN /warning/fao=4!/ansi=0 @@ -778,7 +778,7 @@ BCKUPBUFLUSH /error/fao=0!/ansi=0 NOFORKCORE /warning/fao=0!/ansi=0 JNLREAD /error/fao=3!/ansi=0 JNLMINALIGN /warning/fao=2!/ansi=0 -JNLDSKALIGN /warning/fao=1!/ansi=0 +UNUSEDMSG781 /error/fao=0!/ansi=0 JNLPOOLSETUP /error/fao=0!/ansi=0 JNLSTATEOFF /error/fao=2!/ansi=0 RECVPOOLSETUP /error/fao=0!/ansi=0 @@ -806,7 +806,7 @@ MUKILLIP /error/fao=2!/ansi=0 ANCOMPTINC /error/fao=4!/ansi=0 ABNCOMPTINC /error/fao=6!/ansi=0 -GTMSECSHRLOGF /error/fao=3!/ansi=0 +UNUSEDMSG809 /error/fao=0!/ansi=0 SOCKNOTFND /error/fao=2!/ansi=0 CURRSOCKOFR /error/fao=2!/ansi=0 SOCKETEXIST /error/fao=2!/ansi=79 @@ -841,7 +841,7 @@ RECSIZENOTEVEN /error/fao=4!/ansi=0 MUQUALINCOMP /error/fao=0!/ansi=0 DISTPATHMAX <$gtm_dist path is greater than maximum (!UL)>/error/fao=1!/ansi=0 -MAXTRACEHEIGHT /info/fao=1!/ansi=0 +UNUSEDMSG844 /error/fao=0!/ansi=0 IMAGENAME /error/fao=4!/ansi=0 GTMSECSHRPERM /error/fao=0!/ansi=0 GTMDISTUNDEF /error/fao=0!/ansi=0 @@ -895,8 +895,8 @@ SECONDAHEAD /error/fao=0!/ansi=0 MUINFOUINT4 /info/fao=4!/ansi=0 NLMISMATCHCALC /error/fao=4!/ansi=0 -GTMSECSHRLOGSWH /error/fao=7!/ansi=0 -GTMSECSHRDEFLOG <$gtm_log is either undefined or not defined to an absolute path, thus gtm_log is set to its default !AD>/info/fao=2!/ansi=0 +UNUSEDMSG898 /error/fao=0!/ansi=0 +UNUSEDMSG899 /info/fao=0!/ansi=0 DBBADNSUB /error/fao=2!/ansi=0 DBBADKYNM /error/fao=2!/ansi=0 DBBADPNTR /error/fao=2!/ansi=0 @@ -947,7 +947,7 @@ DBMBPFRDLBM /warning/fao=2!/ansi=0 DBMAXKEYEXC /error/fao=2!/ansi=0 DBMXRSEXCMIN /error/fao=2!/ansi=0 -DBMAXRSEXBL /error/fao=2!/ansi=0 +UNUSEDMSG950 /error/fao=0!/ansi=0 DBREADBM /error/fao=2!/ansi=0 DBCOMPTOOLRG /error/fao=2!/ansi=0 DBVERPERFWARN2 /warning/fao=2!/ansi=0 @@ -969,14 +969,14 @@ MUTEXRSRCCLNUP /info/fao=2!/ansi= SEMWT2LONG /error/fao=7!/ansi=0 REPLINSTOPEN /error/fao=2!/ansi=0 REPLINSTCLOSE /error/fao=2!/ansi=0 -JNLNOTFOUND /info /fao=2!/ansi=0 +UNUSEDMSG972 /error/fao=0!/ansi=0 DBCRERR8 /info /fao=11!/ansi=0 NUMPROCESSORS /warning/fao=0!/ansi=0 DBADDRANGE8 /info /fao=9!/ansi=0 RNDWNSEMFAIL /info/fao=0!/ansi=0 GTMSECSHRSHUTDN /info/fao=0!/ansi=0 -NOSPACECRE /error/fao=4!/ansi=0 -LOWSPACECRE /warning/fao=6!/ansi=0 +NOSPACECRE /error/fao=4!/ansi=0 +LOWSPACECRE /warning/fao=6!/ansi=0 WAITDSKSPACE /info/fao=4!/ansi=0 OUTOFSPACE /fatal/fao=3!/ansi=0 JNLPVTINFO /info/fao=8!/ansi=0 @@ -986,16 +986,16 @@ REPLJNLCLOSED /warning/fao=4!/ansi=0 FILERENAME /info/fao=4!/ansi=0 JNLBUFINFO /info/fao=16!/ansi=0 -JNLQIOLOCKED /error/fao=2!/ansi=0 -JNLEOFPREZERO /error/fao=2!/ansi=0 +UNUSEDMSG989 /error/fao=0!/ansi=0 +UNUSEDMSG990 /error/fao=0!/ansi=0 TPNOTACID /info/fao=8!/ansi=0 JNLSETDATA2LONG /error/fao=2!/ansi=0 JNLNEWREC /error/fao=2!/ansi=0 REPLFTOKSEM /error/fao=2!/ansi=0 -GETCWD /error/fao=2!/ansi=0 +UNUSEDMSG995 /error/fao=0!/ansi=0 EXTRIOERR /error/fao=2!/ansi=0 EXTRCLOSEERR /error/fao=2!/ansi=0 -TRUNCATE /error/fao=3!/ansi=0 +UNUSEDMSG998 /error/fao=0!/ansi=0 REPLEXITERR /error/fao=0!/ansi=0 MUDESTROYSUC /info/fao=4!/ansi=0 DBRNDWN /error/fao=2!/ansi=0 @@ -1008,7 +1008,7 @@ TCGETATTR /error TCSETATTR /error/fao=1!/ansi=0 IOWRITERR /error/fao=5!/ansi=0 REPLINSTWRITE /error/fao=4!/ansi=0 -DBBADFREEBLKCTR /info/fao=4!/ansi=0 +DBBADFREEBLKCTR /warning/fao=4!/ansi=0 REQ2RESUME /info/fao=2!/ansi=0 TIMERHANDLER /warning/fao=3!/ansi=0 FREEMEMORY /error/fao=1!/ansi=0 @@ -1016,13 +1016,13 @@ MUREPLSECDEL /info/fao=2!/ansi=0 MUREPLSECNOTDEL /info/fao=2!/ansi=0 MUJPOOLRNDWNSUC /info/fao=4!/ansi=0 MURPOOLRNDWNSUC /info/fao=4!/ansi=0 -MUJPOOLRNDWNFL /info/fao=4!/ansi=0 -MURPOOLRNDWNFL /info/fao=4!/ansi=0 +MUJPOOLRNDWNFL /error/fao=4!/ansi=0 +MURPOOLRNDWNFL /error/fao=4!/ansi=0 MUREPLPOOL /info/fao=2!/ansi=0 REPLACCSEM /error/fao=3!/ansi=0 -JNLFLUSHNOPROG /error/fao=2!/ansi=0 +JNLFLUSHNOPROG /warning/fao=2!/ansi=0 REPLINSTCREATE /error/fao=2!/ansi=0 -SUSPENDING /info/fao=0!/ansi=0 +SUSPENDING /info/fao=1!/ansi=0 SOCKBFNOTEMPTY /error/fao=2!/ansi=0 ILLESOCKBFSIZE /error/fao=1!/ansi=0 NOSOCKETINDEV /error/fao=0!/ansi=0 @@ -1076,7 +1076,7 @@ NOSUBSCRIPT /error/fao=1!/ansi=0 SYSTEMVALUE /error/fao=2!/ansi=0 SIZENOTVALID4 /error/fao=0!/ansi=0 STRNOTVALID /error/fao=2!/ansi=0 -RECNOCREJNL /info/fao=2!/ansi=0 +UNUSEDMSG1079 /error/fao=0!/ansi=0 ERRWETRAP /error/fao=0!/ansi=0 TRACINGON /info/fao=0!/ansi=0 CITABENV /error/fao=2!/ansi=0 @@ -1094,7 +1094,7 @@ SETZDIR /error/fao=2!/ansi=0 JOBACTREF /error/fao=0!/ansi=40 ECLOSTMID <$ECODE overflow, the first and last ecodes are retained, but some intervening ecodes have been lost>/warning/fao=0!/ansi=0 ZFF2MANY /error/fao=2!/ansi=0 -JNLFSYNCLSTCK /info/fao=2!/ansi=0 +JNLFSYNCLSTCK /warning/fao=2!/ansi=0 DELIMWIDTH /error/fao=2!/ansi=0 DBBMLCORRUPT /error/fao=7!/ansi=0 DLCKAVOIDANCE /error/fao=6!/ansi=0 @@ -1104,9 +1104,9 @@ INVZDIRFORM /error/fao=1!/ansi=0 ZDIROUTOFSYNC <$ZDIRECTORY !AD is not the same as its cached value !AD>/warning/fao=4!/ansi=0 GBLNOEXIST /info/fao=2!/ansi=0 MAXBTLEVEL /error/fao=2!/ansi=0 -JNLSTRESTFL /error/fao=2!/ansi=0 +UNUSEDMSG1107 /error/fao=0!/ansi=0 JNLALIGNSZCHG /info/fao=1!/ansi=0 -MAXTRACELEVEL /info/fao=1!/ansi=0 +UNUSEDMSG1109 /error/fao=0!/ansi=0 GVFAILCORE /error/fao=0!/ansi=0 DBCDBNOCERTIFY /error/fao=2!/ansi=0 DBFRZRESETSUC /info/fao=2!/ansi=0 @@ -1128,7 +1128,7 @@ JNLFNF /info/fao=2!/ansi=0 PREVJNLLINKCUT /info/fao=4!/ansi=0 PREVJNLLINKSET /info/fao=4!/ansi=0 FILENAMETOOLONG /error/fao=0!/ansi=0 -UNUSEDMSG1131 /error/fao=0!/ansi=0 +REQRECOV /error/fao=4!/ansi=0 JNLTRANS2BIG /error/fao=4!/ansi=0 JNLSWITCHTOOSM /error/fao=4!/ansi=0 JNLSWITCHSZCHG /info/fao=6!/ansi=0 @@ -1252,7 +1252,7 @@ REPLINSTSECUNDF /error/fao=0!/a REPLINSTSEQORD /error/fao=6!/ansi=0 REPLINSTSTNDALN /error/fao=2!/ansi=0 REPLREQROLLBACK /error/fao=2!/ansi=0 -UNUSEDMSG1255 /error/fao=0!/ansi=0 +REQROLLBACK /error/fao=4!/ansi=0 UNUSEDMSG1256 /error/fao=0!/ansi=0 SRCSRVEXISTS /error/fao=3!/ansi=0 SRCSRVNOTEXIST /error/fao=2!/ansi=0 @@ -1294,7 +1294,7 @@ COMMITWAITSTUCK /error/fao=6!/ansi=0 UPDREPLSTATEOFF /error/fao=4!/ansi=0 LITNONGRAPH /warning/fao=0!/ansi=0 -DBFHEADERR8 /info /fao=6!/ansi=0 +DBFHEADERR8 /info /fao=6!/ansi=0 MMBEFOREJNL /warning/fao=2!/ansi=0 MMNOBFORRPL /warning/fao=2!/ansi=0 KILLABANDONED /warning/fao=4!/ansi=0 @@ -1307,15 +1307,15 @@ DZWRNOPAREN <$ZWRTACxxx is not allowed inside a parenthesized SET target>/error/ DZWRNOALIAS <$ZWRTAC cannot be aliased>/error/fao=0!/ansi=0 FREEZEERR /error/fao=4!/ansi=0 CLOSEFAIL /error/fao=1!/ansi=0 -CRYPTINIT /error/fao=2!/ansi=0 -CRYPTOPFAILED /error/fao=2!/ansi=0 -CRYPTDLNOOPEN /error/fao=2!/ansi=0 +CRYPTINIT /error/fao=4!/ansi=0 +CRYPTOPFAILED /error/fao=4!/ansi=0 +CRYPTDLNOOPEN /error/fao=4!/ansi=0 CRYPTNOV4 /error/fao=2!/ansi=0 CRYPTNOMM /error/fao=2!/ansi=0 CRYPTJNLWRONGHASH /error/fao=4!/ansi=0 -CRYPTKEYFETCHFAILED /error/fao=4!/ansi=0 -CRYPTKEYFETCHFAILEDNF /error/fao=2!/ansi=0 -CRYPTHASHGENFAILED /error/fao=2!/ansi=0 +CRYPTKEYFETCHFAILED /error/fao=4!/ansi=0 +CRYPTKEYFETCHFAILEDNF /error/fao=4!/ansi=0 +CRYPTHASHGENFAILED /error/fao=4!/ansi=0 CRYPTNOPSWDINTP /error/fao=0!/ansi=0 BADTAG /error/fao=4!/ansi=0 ICUVERLT36 /error/fao=4!/ansi=0 @@ -1351,7 +1351,7 @@ TRIGTCOMMIT /error/fao=2!/ansi=0 TRIGNAMEUNIQ /error/fao=3!/ansi=0 ZTRIGINVACT /error/fao=1!/ansi=0 -UNUSEDMSG1354 /error/fao=0!/ansi=0 +INDRCOMPFAIL /error/fao=0!/ansi=0 QUITALSINV /error/fao=0!/ansi=0 PROCTERM /warning/fao=7!/ansi=0 SRCLNNTDSP /info/fao=1!/ansi=0 @@ -1364,10 +1364,10 @@ TCOMMITDISALLOW SSATTACHSHM /error/fao=1!/ansi=0 TRIGDEFNOSYNC /warning/fao=7!/ansi=0 TRESTMAX /error/fao=0!/ansi=0 -TPLOCKRESTMAX /error/fao=1!/ansi=0 +UNUSEDMSG1367 /error/fao=0!/ansi=0 GBLEXPECTED /error/fao=0!/ansi=0 GVZTRIGFAIL /error/fao=2!/ansi=0 -UNUSEDMSG1370 /error/fao=0!/ansi=0 +MUUSERLBK /error/fao=2!/ansi=0 SETINSETTRIGONLY /error/fao=2!/ansi=0 DZTRIGINTRIG <$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD>/error/fao=2!/ansi=0 SECNODZTRIGINTP /error/fao=1!/ansi=0 @@ -1379,7 +1379,7 @@ REPLNOXENDIAN /error/fao=3!/ansi=0 ZGOTOINVLVL2 /error/fao=0!/ansi=0 GTMSECSHRCHDIRF /error/fao=2!/ansi=0 -UNUSEDMSG1382 /error/fao=0!/ansi=0 +JNLORDBFLU /error/fao=2!/ansi=0 ZCCLNUPRTNMISNG /error/fao=0!/ansi=0 ZCINVALIDKEYWORD /error/fao=0!/ansi=0 REPLNOMULTILINETRG /error/fao=1!/ansi=0 @@ -1410,12 +1410,12 @@ NORESYNCSUPPLONLY /error/fa NORESYNCUPDATERONLY /error/fao=0!/ansi=0 NOSUPPLSUPPL /error/fao=4!/ansi=0 REPL2OLD /error/fao=4!/ansi=0 -RCVR2MANY /error/fao=1!/ansi=0 -RLBKCONFIGBNDRY /error/fao=5!/ansi=0 +EXTRFILEXISTS /error/fao=2!/ansi=0 +MUUSERECOV /error/fao=2!/ansi=0 SECNOTSUPPLEMENTARY /error/fao=4!/ansi=0 SUPRCVRNEEDSSUPSRC /error/fao=4!/ansi=0 -SYNCTOSAMETYPE /error/fao=4!/ansi=0 -TARGINSRUNNING /error/fao=2!/ansi=0 +UNUSEDMSG1417 /info/fao=0!/ansi=0 +UNUSEDMSG1418 /info/fao=0!/ansi=0 UPDSYNC2MTINS /error/fao=0!/ansi=0 UPDSYNCINSTFILE /error/fao=0!/ansi=0 REUSEINSTNAME /error/fao=0!/ansi=0 @@ -1434,7 +1434,7 @@ ORLBKFRZOVER /info/fao=6!/ansi=0 ORLBKNOV4BLK /error/fao=4!/ansi=0 DBROLLEDBACK /error/fao=0!/ansi=0 DSEWCREINIT /info/fao=2!/ansi=0 -RNDWNSKIPCNT /info/fao=1!/ansi=0 +MURNDWNOVRD /info/fao=2!/ansi=0 ! The following error message is NOT issued to the user and is only internal to GT.M REPLONLNRLBK /error/fao=0!/ansi=0 ! @@ -1459,6 +1459,74 @@ STRMNUMMISMTCH2 /error/fao=3!/ansi=0 LOCKSPACEINFO /info/fao=8!/ansi=0 JRTNULLFAIL /error/fao=2!/ansi=0 +LOCKSUB2LONG /error/fao=1!/ansi=0 +RESRCWAIT /info/fao=8!/ansi=0 +RESRCINTRLCKBYPAS /info/fao=10!/ansi=0 +DBFHEADERRANY /info /fao=6!/ansi=0 +REPLINSTFROZEN /error/fao=1!/ansi=0 +REPLINSTFREEZECOMMENT /info/fao=1!/ansi=0 +REPLINSTUNFROZEN /info/fao=1!/ansi=0 +DSKNOSPCAVAIL /info/fao=2!/ansi=0 +DSKNOSPCBLOCKED /error/fao=2!/ansi=0 +DSKSPCAVAILABLE /info/fao=2!/ansi=0 +ENOSPCQIODEFER /info/fao=2!/ansi=0 +CUSTOMFILOPERR /error/fao=4!/ansi=0 +CUSTERRNOTFND /error/fao=2!/ansi=0 +CUSTERRSYNTAX /error/fao=3!/ansi=0 +ORLBKINPROG /info/fao=3!/ansi=0 +DBSPANGLOINCMP /error/fao=3!/ansi=0 +DBSPANCHUNKORD /error/fao=3!/ansi=0 +DBDATAMX /error/fao=2!/ansi=0 +DBIOERR /error/fao=4!/ansi=0 +INITORRESUME /error/fao=0!/ansi=0 +GTMSECSHRNOARG0 /error/fao=0!/ansi=0 +GTMSECSHRISNOT /error/fao=2!/ansi=0 +GTMSECSHRBADDIR /error/fao=0!/ansi=0 +JNLBUFFREGUPD /warning/fao=4!/ansi=0 +JNLBUFFDBUPD /warning/fao=4!/ansi=0 +LOCKINCR2HIGH /error/fao=1!/ansi=0 +LOCKIS /info/fao=2!/ansi=0 +LDSPANGLOINCMP /error/fao=0!/ansi=0 +MUFILRNDWNFL2 /error/fao=3!/ansi=0 +MUINSTFROZEN /info/fao=5!/ansi=0 +MUINSTUNFROZEN /info/fao=5!/ansi=0 +GTMEISDIR /error/fao=2!/ansi=0 +SPCLZMSG /error/fao=0!/ansi=0 +MUNOTALLINTEG /warning/fao=0!/ansi=0 +BKUPRUNNING /error/fao=3!/ansi=0 +MUSIZEINVARG /error/fao=2!/ansi=0 +MUSIZEFAIL /error/fao=2!/ansi=0 +SIDEEFFECTEVAL /warning/fao=0!/ansi=0 +CRYPTINIT2 /error/fao=4!/ansi=0 +CRYPTDLNOOPEN2 /error/fao=4!/ansi=0 +CRYPTBADCONFIG /error/fao=4!/ansi=0 +DBCOLLREQ /warning/fao=4!/ansi=0 +SETEXTRENV /error/fao=0!/ansi=0 +NOTALLDBRNDWN /error/fao=0!/ansi=0 +TPRESTNESTERR /error/fao=0!/ansi=0 +JNLFILRDOPN /error/fao=4!/ansi=0 +SEQNUMSEARCHTIMEOUT /error/fao=2!/ansi=0 +FTOKKEY /info/fao=1!/ansi=0 +SEMID /info/fao=1!/ansi=0 +JNLQIOSALVAGE /info/fao=0!/ansi=0 +FAKENOSPCLEARED /info/fao=1!/ansi=0 +MMFILETOOLARGE /error/fao=4!/ansi=0 +BADZPEEKARG /error/fao=2!/ansi=0 +BADZPEEKRANGE /error/fao=0!/ansi=0 +BADZPEEKFMT <$ZPEEK() value length inappropriate for selected format>/error/fao=0!/ansi=0 +DBMBMINCFREFIXED /warning/fao=1!/ansi=0 +NULLENTRYREF /error/fao=0!/ansi=0 +ZPEEKNORPLINFO <$ZPEEK() unable to access requested replication structure>/error/fao=0!/ansi=0 +MMREGNOACCESS /error/fao=4!/ansi=0 +MALLOCMAXUNIX /error/fao=0!/ansi=0 +MALLOCMAXVMS /error/fao=0!/ansi=0 +HOSTCONFLICT /error/fao=6!/ansi=0 +GETADDRINFO /error/fao=0!/ansi=0 +GETNAMEINFO /error/fao=0!/ansi=0 +SOCKBIND /error/fao=0!/ansi=0 +INSTFRZDEFER /info/fao=4!/ansi=0 +REGOPENRETRY /info/fao=4!/ansi=0 +REGOPENFAIL /error/fao=4!/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/mlk_lock.c b/sr_port/mlk_lock.c index 29527d3..adba18f 100644 --- a/sr_port/mlk_lock.c +++ b/sr_port/mlk_lock.c @@ -44,8 +44,7 @@ #ifdef VMS - GBLREF uint4 image_count; - GBLREF int4 login_time[2]; +GBLREF uint4 image_count; #endif GBLREF int4 process_id; @@ -77,23 +76,23 @@ uint4 mlk_lock(mlk_pvtblk *p, mlk_ctldata_ptr_t ctl; mlk_shrblk_ptr_t d; int siz, retval, status; - boolean_t blocked, was_crit, have_space; + boolean_t blocked, was_crit; sgmnt_addrs *csa; connection_struct *curr_entry; /* for GT.CM GNP server */ + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (p->region->dyn.addr->acc_meth != dba_usr) { csa = &FILE_INFO(p->region)->s_addrs; - ctl = p->ctlptr; if (csa->critical) crash_count = csa->critical->crashcnt; - - if (dollar_tlevel && !((t_tries < CDB_STAGNATE) || csa->now_crit)) /* Final retry and region not locked down */ - { /* make sure this region is in the list in case we end up retrying */ + if (dollar_tlevel) + { + assert((CDB_STAGNATE > t_tries) || csa->now_crit); + /* make sure this region is in the list in case we end up retrying */ insert_region(p->region, &tp_reg_list, &tp_reg_free_list, SIZEOF(tp_region)); - /* insert_region() will additionally attempt CRIT on the region and restart if not possible */ - assert(csa->now_crit); } if (FALSE == (was_crit = csa->now_crit)) grab_crit(p->region); @@ -106,18 +105,12 @@ uint4 mlk_lock(mlk_pvtblk *p, siz = MLK_PVTBLK_SHRSUB_SIZE(p, p->subscript_cnt); assert(siz >= 0); assert(ctl->blkcnt >= 0); - have_space = TRUE; if (ctl->subtop - ctl->subfree < siz || ctl->blkcnt < p->subscript_cnt) { mlk_garbage_collect(ctl, siz, p); - /* If there isn't any created space after garbage collection, don't attempt to lock anything. */ - if (ctl->subtop - ctl->subfree < siz || ctl->blkcnt < p->subscript_cnt) - have_space = FALSE; } - if (have_space) - blocked = mlk_shrblk_find(p, &d, auxown); - else - d = NULL; + assert(!new || (0 == TREF(mlk_yield_pid)) || (MLK_FAIRNESS_DISABLED == TREF(mlk_yield_pid))); + blocked = mlk_shrblk_find(p, &d, auxown); if (NULL != d) { if (d->owner) diff --git a/sr_port/mlk_prcblk_add.c b/sr_port/mlk_prcblk_add.c index 5143217..e903ee8 100644 --- a/sr_port/mlk_prcblk_add.c +++ b/sr_port/mlk_prcblk_add.c @@ -42,25 +42,24 @@ void mlk_prcblk_add(gd_region *reg, return; } } - if (!lcnt) - { - send_msg(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(reg)); - if (ctl->subtop > ctl->subfree) - send_msg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(reg), - (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, - (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); - else - send_msg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(reg), - (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, - (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); - rts_error(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(reg)); - } - if (ctl->prccnt < 1) - { + if (1 > ctl->prccnt) + { /* No process slot available. */ mlk_shrclean(reg, ctl, (mlk_shrblk_ptr_t)R2A(ctl->blkroot)); - if (ctl->prccnt < 1) + if (1 > ctl->prccnt) + { /* Process cleanup did not help. Issue error to syslog. */ + send_msg(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(reg)); + if (ctl->subtop > ctl->subfree) + send_msg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(reg), + (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, + (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); + else + send_msg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(reg), + (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, + (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); return; + } } + /* Process slot is available. Add process to the queue. */ ctl->prccnt--; pr = (mlk_prcblk_ptr_t)R2A(ctl->prcfree); if (0 == pr->next) diff --git a/sr_port/mlk_pvtblk_create.c b/sr_port/mlk_pvtblk_create.c index e92656b..0ddb10e 100644 --- a/sr_port/mlk_pvtblk_create.c +++ b/sr_port/mlk_pvtblk_create.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,6 +37,9 @@ GBLREF gd_addr *gd_header; static mstr gtmgbldir_mstr; +error_def(ERR_LOCKSUB2LONG); +error_def(ERR_TEXT); + /* * --------------------------------------------------------- * Create a private block structure for one nref, @@ -102,8 +105,10 @@ void mlk_pvtblk_create (int subcnt, mval *extgbl1, va_list subptr) for (len = 0, rlen=0, i = 0; i < subcnt; mp_temp=va_arg(mp, mval *), i++) { MV_FORCE_STR(mp_temp); + if ((mp_temp)->str.len > 255) + rts_error(VARLSTCNT(7) ERR_LOCKSUB2LONG, 1, (mp_temp)->str.len, + ERR_TEXT, 2, (mp_temp)->str.len, (mp_temp)->str.addr); assert((mp_temp)->mvtype & MV_STR); - assert((mp_temp)->str.len < 256); len += (int)(mp_temp)->str.len; rlen += ROUND_UP(((mp_temp)->str.len + 1), 4); } diff --git a/sr_port/mlk_shrblk_create.c b/sr_port/mlk_shrblk_create.c index 233f4ef..e0ec97e 100644 --- a/sr_port/mlk_shrblk_create.c +++ b/sr_port/mlk_shrblk_create.c @@ -31,7 +31,8 @@ mlk_shrblk_ptr_t mlk_shrblk_create(mlk_pvtblk *p, ptroff_t n; ctl = p->ctlptr; - assert((ctl->subtop - ctl->subfree) >= (MLK_PVTBLK_SHRSUB_SIZE(p, nshrs) - (val - p->value)) && ctl->blkcnt >= nshrs); + if ((ctl->subtop - ctl->subfree) < (MLK_PVTBLK_SHRSUB_SIZE(p, nshrs) - (val - p->value)) || ctl->blkcnt < nshrs) + return NULL; /* There is not enough substring or shared block space */ ret = (mlk_shrblk_ptr_t)R2A(ctl->blkfree); ctl->blkcnt--; if (ret->rsib == 0) @@ -47,8 +48,6 @@ mlk_shrblk_ptr_t mlk_shrblk_create(mlk_pvtblk *p, if (ptr) A2R(*ptr, ret); n = (ptroff_t)ROUND_UP(OFFSETOF(mlk_shrsub, data[0]) + len, SIZEOF(ptroff_t)); - if (ctl->subtop - ctl->subfree < n) - GTMASSERT; subptr = (mlk_shrsub_ptr_t)R2A(ctl->subfree); ctl->subfree += n; A2R(ret->value, subptr); diff --git a/sr_port/mlk_shrblk_find.c b/sr_port/mlk_shrblk_find.c index 956eb1d..85e1953 100644 --- a/sr_port/mlk_shrblk_find.c +++ b/sr_port/mlk_shrblk_find.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,29 +10,33 @@ ****************************************************************/ #include "mdef.h" + #include "mlkdef.h" #include "mmemory.h" #include "is_proc_alive.h" #include "mlk_shrblk_find.h" #include "mlk_shrblk_create.h" +#include "gdsroot.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "mlk_wake_pending.h" -GBLREF int4 process_id; +GBLREF uint4 process_id; -bool mlk_find_blocking_child_lock(mlk_pvtblk *p, mlk_shrblk_ptr_t child, UINTPTR_T auxown); +boolean_t mlk_find_blocking_child_lock(mlk_pvtblk *p, mlk_shrblk_ptr_t child, UINTPTR_T auxown); -bool mlk_find_blocking_child_lock(mlk_pvtblk *p, mlk_shrblk_ptr_t child, UINTPTR_T auxown) +boolean_t mlk_find_blocking_child_lock(mlk_pvtblk *p, mlk_shrblk_ptr_t child, UINTPTR_T auxown) { mlk_shrblk_ptr_t d, dhead, d1; - bool blocked; + boolean_t blocked; blocked = FALSE; - for (dhead = d = child, d1 = NULL ; dhead != d1 && !blocked ; d = d1 = (mlk_shrblk_ptr_t)R2A(d->rsib)) { - /* There is similar code below to check if the - * process that owns the lock still exists. Any change in this - * part of the code should be propogated to those segments - * too. + /* There is similar code below to check if the process that owns the lock still exists. + * Any change in this part of the code should be propogated to those segments too. */ if (d->owner && (d->owner != process_id || d->auxowner != auxown)) { /* If owned and not owned by us check if owner is alive */ @@ -50,34 +54,36 @@ bool mlk_find_blocking_child_lock(mlk_pvtblk *p, mlk_shrblk_ptr_t child, UINTPTR if (!blocked && d->children) blocked = mlk_find_blocking_child_lock(p, (mlk_shrblk_ptr_t)R2A(d->children), auxown); } - return blocked; } -bool mlk_shrblk_find(mlk_pvtblk *p, - mlk_shrblk_ptr_t *ret, - UINTPTR_T auxown) +boolean_t mlk_shrblk_find(mlk_pvtblk *p, mlk_shrblk_ptr_t *ret, UINTPTR_T auxown) { - mlk_shrblk_ptr_t pnt, d, d0, d1, dhead; - ptroff_t *chld_of_pnt, *cop1; - mlk_shrsub_ptr_t dsub; + boolean_t blocked; int i, j, slen; + mlk_ctldata_ptr_t ctl; + mlk_prcblk_ptr_t pr; + mlk_shrblk_ptr_t pnt, d, d0, d1, dhead; + mlk_shrsub_ptr_t dsub; + ptroff_t *chld_of_pnt, *cop1; unsigned char *cp; - bool blocked; + uint4 yield_pid; + DCL_THREADGBL_ACCESS; blocked = FALSE; + /* Note: If ever this function returns with "blocked" set to "TRUE", + * make sure TREF(mlk_yield_pid) is initialized appropriately. + */ *ret = 0; + SETUP_THREADGBL_ACCESS; for (pnt = 0 , chld_of_pnt = (ptroff_t *)&p->ctlptr->blkroot , i = p->subscript_cnt , cp = p->value ; i > 0 ; i-- , pnt = d , chld_of_pnt = (ptroff_t *)&d->children, cp += slen) { slen = *cp++; - if (!*chld_of_pnt) { if (!(d = mlk_shrblk_create(p, cp, slen, pnt, chld_of_pnt, i))) - { return TRUE; - } A2R(d->lsib, d); A2R(d->rsib, d); } else @@ -88,17 +94,44 @@ bool mlk_shrblk_find(mlk_pvtblk *p, j = memvcmp(cp, slen, dsub->data, dsub->length); if (!j) { /* We found the right node */ - if (d->owner && (d->owner != process_id || d->auxowner != auxown)) - { /* If owned and not owned by us check if owner is alive */ - if (is_proc_alive(d->owner, d->image_count)) - { /* Signal that this lock request is blocked by this node */ + if (d->owner) + { + if (d->owner != process_id || d->auxowner != auxown) + { /* If owned and not owned by us check if owner is alive */ + if (is_proc_alive(d->owner, d->image_count)) + { /* Signal that this lock request is blocked by this node */ + p->blocked = d; + p->blk_sequence = d->sequence; + TREF(mlk_yield_pid) = 0; + blocked = TRUE; + } else + { /* Owner is dead so release this node */ + d->owner = 0; + d->auxowner = 0; + } + } + } else if ((MLK_FAIRNESS_DISABLED != TREF(mlk_yield_pid)) && d->pending) + { /* If not owned by us, but there is another process waiting for it at the start of + * the wait queue, then yield to it once. If we find the same process at the start + * of the wait queue again, then dont yield anymore to avoid starvation. If we find + * a different pid though, note it down and give it a fresh new chance. Since + * additions to the wait queue happen at the end, we will eventually get our turn + * this way (won't starve). Fairness algorithm will not kick in if it is disabled + * which is indicated by setting TREF(mlk_yield_pid) to MLK_FAIRNESS_DISABLED. + */ + pr = (mlk_prcblk_ptr_t)R2A(d->pending); + yield_pid = TREF(mlk_yield_pid); + assert(yield_pid != process_id); + assert(pr->process_id); + if ((pr->process_id != yield_pid) && (process_id != pr->process_id)) + { p->blocked = d; p->blk_sequence = d->sequence; - blocked = TRUE; - } else - { /* Owner is dead so release this node */ - d->owner = 0; - d->auxowner = 0; + TREF(mlk_yield_pid) = pr->process_id; + blocked =TRUE; + /* Give the first waiting process a nudge to wake up */ + ctl = p->ctlptr; + mlk_wake_pending(ctl, d, p->region); } } break; @@ -110,9 +143,7 @@ bool mlk_shrblk_find(mlk_pvtblk *p, d0 = (mlk_shrblk_ptr_t)R2A(d->lsib); d1 = d; if (!(d = mlk_shrblk_create(p, cp, slen, pnt, cop1, i))) - { return TRUE; /* resource starve -- no room for new shrblk */ - } A2R(d->lsib, d0); A2R(d->rsib, d1); A2R(d0->rsib, d); @@ -123,9 +154,7 @@ bool mlk_shrblk_find(mlk_pvtblk *p, d1 = (mlk_shrblk_ptr_t)R2A(d->rsib); d0 = d; if (!(d = mlk_shrblk_create(p, cp, slen, pnt, cop1, i))) - { return TRUE; /* resource starve -- no room for new shrblk */ - } A2R(d->lsib, d0); A2R(d->rsib, d1); A2R(d0->rsib, d); @@ -138,12 +167,10 @@ bool mlk_shrblk_find(mlk_pvtblk *p, if (i == 1) *ret = d; } - if (*chld_of_pnt && !blocked) - { - /* look at the subtree owners to see if we will be blocked by someone underneath */ + { /* look at the subtree owners to see if we will be blocked by someone underneath */ blocked = mlk_find_blocking_child_lock(p, (mlk_shrblk_ptr_t)R2A(*chld_of_pnt), auxown); + TREF(mlk_yield_pid) = 0; /* clear this just in case "blocked" came back as TRUE */ } - return blocked; } diff --git a/sr_port/mlk_shrblk_find.h b/sr_port/mlk_shrblk_find.h index 962522d..acfc1a5 100644 --- a/sr_port/mlk_shrblk_find.h +++ b/sr_port/mlk_shrblk_find.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 MLK_SHRBLK_FIND_INCLUDED #define MLK_SHRBLK_FIND_INCLUDED -bool mlk_shrblk_find(mlk_pvtblk *p, mlk_shrblk_ptr_t *ret, UINTPTR_T auxown); +boolean_t mlk_shrblk_find(mlk_pvtblk *p, mlk_shrblk_ptr_t *ret, UINTPTR_T auxown); #endif /* MLK_SHRBLK_FIND_INCLUDED */ diff --git a/sr_port/mlk_unlock.c b/sr_port/mlk_unlock.c index 1122e3b..b1d2303 100644 --- a/sr_port/mlk_unlock.c +++ b/sr_port/mlk_unlock.c @@ -56,11 +56,11 @@ void mlk_unlock(mlk_pvtblk *p) d = p->nodptr; if (csa->critical) crash_count = csa->critical->crashcnt; - if (dollar_tlevel && !((t_tries < CDB_STAGNATE) || csa->now_crit)) /* Final retry and region not locked down */ - { /* make sure this region is in the list in case we end up retrying */ + if (dollar_tlevel) + { + assert((CDB_STAGNATE > t_tries) || csa->now_crit); + /* make sure this region is in the list in case we end up retrying */ insert_region(p->region, &tp_reg_list, &tp_reg_free_list, SIZEOF(tp_region)); - /* insert_region() will additionally attempt CRIT on the region and restart if not possible */ - assert(csa->now_crit); } if (FALSE == (was_crit = csa->now_crit)) grab_crit(p->region); diff --git a/sr_port/mlk_wake_pending.c b/sr_port/mlk_wake_pending.c index 7b76e97..350a921 100644 --- a/sr_port/mlk_wake_pending.c +++ b/sr_port/mlk_wake_pending.c @@ -108,7 +108,9 @@ void mlk_wake_pending(mlk_ctldata_ptr_t ctl, break; } } - if (!lcnt) - GTMASSERT; + /* The assertpro is to safeguard us against cycles/loops in the "pending" linked list. This way we dont get into an + * infinite loop and yet get a core dump to see how we got ourselves into this out-of-design state. + */ + assertpro(lcnt); return; } diff --git a/sr_port/mlkdef.h b/sr_port/mlkdef.h index a6dfa3a..32e042b 100644 --- a/sr_port/mlkdef.h +++ b/sr_port/mlkdef.h @@ -182,4 +182,6 @@ typedef struct mlk_stats_struct gtm_uint64_t n_user_locks_fail; } mlk_stats_t; +#define MLK_FAIRNESS_DISABLED ((uint4)-1) + #endif diff --git a/sr_port/mm_read.c b/sr_port/mm_read.c index 9f4d5da..7c1df66 100644 --- a/sr_port/mm_read.c +++ b/sr_port/mm_read.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,7 +30,7 @@ sm_uc_ptr_t mm_read(block_id blk) INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_dsk_read, 1); if (blk < cs_addrs->total_blks) /* use the private copy of total_blks */ - return (cs_addrs->acc_meth.mm.base_addr + (off_t)cs_addrs->hdr->blk_size * blk); + return (MM_BASE_ADDR(cs_addrs) + (off_t)cs_addrs->hdr->blk_size * blk); rdfail_detail = (blk < cs_addrs->ti->total_blks) ? cdb_sc_helpedout : cdb_sc_blknumerr; return (sm_uc_ptr_t)NULL; diff --git a/sr_port/mprof.h b/sr_port/mprof.h index 60235b0..51942cb 100644 --- a/sr_port/mprof.h +++ b/sr_port/mprof.h @@ -19,12 +19,10 @@ #include "gtm_times.h" #include #endif -#define OFFSET_LEN 8 -#ifdef GTM64 -#define PROFCALLOC_DSBLKSIZE 8192 -#else -#define PROFCALLOC_DSBLKSIZE 8180 -#endif +#define OFFSET_LEN 8 /* single-pointer padding at the beginning of pcalloc allocation; 8 is chosen to both fit a + * pointer on 32- and 64-bit architectures and ensure proper memory alignment even when we + * are dealing with 32-bit compiles on 64-bit machines */ +#define PROFCALLOC_DSBLKSIZE 8192 /* the size of pcalloc allocation chunks */ #define POPULATE_PROFILING_TABLE() { \ /* xfer_table[xf_linefetch] = op_mproflinefetch; */ \ @@ -68,9 +66,9 @@ typedef struct ext_tms_struct { - int4 tms_utime; /* user time */ - int4 tms_stime; /* system time */ - int4 tms_etime; /* elapsed time */ + gtm_uint64_t tms_utime; /* user time */ + gtm_uint64_t tms_stime; /* system time */ + gtm_uint64_t tms_etime; /* elapsed time */ } ext_tms; /* holds information identifying a line of/label in the code */ @@ -79,10 +77,10 @@ typedef struct mident *rout_name; /* routine name */ mident *label_name; /* label name */ signed int line_num; /* line number; -1 used for generic label nodes, and -2 for overflow node */ - unsigned int count; /* number of executions */ - unsigned int sys_time; /* total system time */ - unsigned int usr_time; /* total user time */ - unsigned int elp_time; /* total elapsed time */ + unsigned count; /* number of executions */ + gtm_uint64_t sys_time; /* total system time */ + gtm_uint64_t usr_time; /* total user time */ + gtm_uint64_t elp_time; /* total elapsed time */ int loop_level; /* nesting level; 0 for regular code and 1+ for (nested) loops */ char *raddr; /* return address used in FORs to record destination after current iteration */ } trace_entry; diff --git a/sr_port/mprof_funcs.c b/sr_port/mprof_funcs.c index 457bef1..c80b460 100644 --- a/sr_port/mprof_funcs.c +++ b/sr_port/mprof_funcs.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,14 +30,14 @@ #include "gtm_ctype.h" #include "gtm_string.h" #include "error.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "subscript.h" #include "svnames.h" #include "mprof.h" #include "outofband.h" #include "op.h" -#include "lv_val.h" /* needed for "callg.h" */ +#include "lv_val.h" /* Needed for callg.h. */ #include "callg.h" #include "gtmmsg.h" #include "str2gvargs.h" @@ -46,50 +46,64 @@ GBLREF boolean_t is_tracing_on; GBLREF stack_frame *frame_pointer; GBLREF mval dollar_job; GBLREF uint4 process_id; -GBLREF int * volatile var_on_cstack_ptr; /* volatile so that nothing gets optimized out */ +GBLREF int * volatile var_on_cstack_ptr; /* Volatile so that nothing gets optimized out. */ GBLREF int4 gtm_trigger_depth; -STATICDEF boolean_t save_to_gbl = TRUE; /* indicates whether profiling info is to be saved to db */ -STATICDEF boolean_t mdb_ch_set; /* indicates whether we can rely on mdb_condition_handler and issue - * an rts_error */ -STATICDEF gtm_uint64_t child_system, child_user; /* store system and user CPU time for child processes */ -STATICDEF gtm_uint64_t process_system, process_user; /* store system and user CPU time for current process */ -STATICDEF mstr mprof_mstr; /* area to hold global and subscripts */ -STATICDEF boolean_t use_realtime_flag = FALSE; /* indicates whether clock_gettime is unable to use CLOCK_MONOTONIC - * flag and so should use CLOCK_REALTIME instead */ +STATICDEF boolean_t save_to_gbl = TRUE; /* Indicates whether profiling info is to be saved to db. */ +STATICDEF boolean_t mdb_ch_set; /* Indicates whether we can rely on mdb_condition_handler and issue + * an rts_error. */ +STATICDEF gtm_uint64_t child_system, child_user; /* Store system and user CPU time for child processes. */ +STATICDEF gtm_uint64_t process_system, process_user; /* Store system and user CPU time for current process. */ +STATICDEF mstr mprof_mstr; /* Area to hold global and subscripts. */ +STATICDEF boolean_t use_realtime_flag = FALSE; /* Indicates whether clock_gettime is unable to use CLOCK_MONOTONIC + * flag and so should use CLOCK_REALTIME instead. */ +#ifdef __osf__ +STATICDEF struct rusage last_usage = {0, 0}; /* Contains the last value obtained via getrusage() on Tru64. */ +#endif LITDEF MIDENT_CONST(above_routine, "*above*"); -#define CHILDREN_TIME "*CHILDREN" /* label to store CPU time for child processes */ -#define PROCESS_TIME "*RUN" /* label to store CPU time for current process */ +#ifdef DEBUG +# define RUNTIME_LIMIT 604800000000.0 /* Not a long because on 32-bit platforms longs are only 4 bytes. */ +#endif + +#define CHILDREN_TIME "*CHILDREN" /* Label to store CPU time for child processes. */ +#define PROCESS_TIME "*RUN" /* Label to store CPU time for current process. */ #define MPROF_NULL_LABEL "^" #define MPROF_FOR_LOOP "FOR_LOOP" -/* on VMS we do not record the child processes' time */ +/* On VMS we do not record the child processes' time. */ #ifdef UNIX # define TIMES times_usec # define CHILDREN_TIMES children_times_usec -# define MPROF_RTS_ERROR(x) rts_error x +# define MPROF_RTS_ERROR(x) rts_error_csa x #elif defined(VMS) # define TIMES get_cputime # define MPROF_RTS_ERROR(x) \ { \ if (mdb_ch_set) \ - rts_error x; \ + rts_error_csa x; \ else \ { \ - gtm_putmsg x; \ + gtm_putmsg_csa x; \ exit(EXIT_FAILURE); \ } \ } #endif -#define UPDATE_TIME(x) x->e.usr_time += ((TREF(mprof_ptr))->tcurr.tms_utime - (TREF(mprof_ptr))->tprev.tms_utime); \ - x->e.sys_time += ((TREF(mprof_ptr))->tcurr.tms_stime - (TREF(mprof_ptr))->tprev.tms_stime); \ - x->e.elp_time += ((TREF(mprof_ptr))->tcurr.tms_etime - (TREF(mprof_ptr))->tprev.tms_etime); +#define UPDATE_TIME(x) \ +{ \ + x->e.usr_time += ((TREF(mprof_ptr))->tcurr.tms_utime - (TREF(mprof_ptr))->tprev.tms_utime); \ + x->e.sys_time += ((TREF(mprof_ptr))->tcurr.tms_stime - (TREF(mprof_ptr))->tprev.tms_stime); \ + x->e.elp_time += ((TREF(mprof_ptr))->tcurr.tms_etime - (TREF(mprof_ptr))->tprev.tms_etime); \ + /* It should be a reasonable assumption that in debug no M process will use more than a week of either user, \ + * system, or even absolute runtime. \ + */ \ + assert((x->e.usr_time < RUNTIME_LIMIT) && (x->e.sys_time < RUNTIME_LIMIT) && (x->e.elp_time < RUNTIME_LIMIT)); \ +} -#define RTS_ERROR_VIEWNOTFOUND(x) MPROF_RTS_ERROR((VARLSTCNT(8) ERR_VIEWNOTFOUND, 2, gvn->str.len, gvn->str.addr, \ - ERR_TEXT, 2, RTS_ERROR_STRING(x))); +#define RTS_ERROR_VIEWNOTFOUND(x) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_VIEWNOTFOUND, 2, gvn->str.len, \ + gvn->str.addr, ERR_TEXT, 2, RTS_ERROR_STRING(x))); /* do the MPROF initialization */ @@ -107,7 +121,7 @@ LITDEF MIDENT_CONST(above_routine, "*above*"); (TREF(prof_fp))->rout_name = NULL; \ (TREF(prof_fp))->label_name = NULL; -/* monotonic flag for clock_gettime() is defined differently on every platform */ +/* Monotonic flag for clock_gettime() is defined differently on every platform. */ #ifndef CLOCK_MONOTONIC # ifdef __sparc # define CLOCK_MONOTONIC CLOCK_HIGHRES @@ -117,7 +131,6 @@ LITDEF MIDENT_CONST(above_routine, "*above*"); #endif error_def(ERR_MAXNRSUBSCRIPTS); -error_def(ERR_MAXTRACELEVEL); error_def(ERR_NOTGBL); error_def(ERR_STRUNXEOR); error_def(ERR_SYSCALL); @@ -128,16 +141,35 @@ error_def(ERR_VIEWNOTFOUND); #ifdef UNIX STATICFNDEF void times_usec(ext_tms *curr) { - int res; - struct rusage usage; - struct timespec elp_time; + int res; + struct rusage usage; + struct timespec elp_time; res = getrusage(RUSAGE_SELF, &usage); - if (res == -1) - MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); - curr->tms_utime = (usage.ru_utime.tv_sec * 1000000) + usage.ru_utime.tv_usec; - curr->tms_stime = (usage.ru_stime.tv_sec * 1000000) + usage.ru_stime.tv_usec; - /* also start recording the elapsed time */ + if (-1 == res) + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); +# ifdef __osf__ + /* On Tru64 getrusage sometimes fails to increment the seconds value when the microseconds wrap around at 1M. If we detect + * this, we make a second call to getrusage if so. A more complete check would be to also verify whether the new seconds + * value is less than the previous one, but we anyway have an assert in UPDATE_TIME that would catch that, and our testing + * on Tru64 has not shown that type of faulty behavior. + */ + if (((usage.ru_utime.tv_sec == last_usage.ru_utime.tv_sec) && (usage.ru_utime.tv_usec < last_usage.ru_utime.tv_usec)) + || ((usage.ru_stime.tv_sec == last_usage.ru_stime.tv_sec) && (usage.ru_stime.tv_usec < last_usage.ru_stime.tv_usec))) + { + DEBUG_ONLY(last_usage = usage); + res = getrusage(RUSAGE_SELF, &usage); + if (-1 == res) + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); + /* In debug also ensure that a subsequent call to getrusage restored the seconds value. */ + assert((usage.ru_utime.tv_sec > last_usage.ru_utime.tv_sec) + || (usage.ru_stime.tv_sec > last_usage.ru_stime.tv_sec)); + } + last_usage = usage; +# endif + curr->tms_utime = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec; + curr->tms_stime = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec; + /* Also start recording the elapsed time. */ while (TRUE) { res = clock_gettime(use_realtime_flag ? CLOCK_REALTIME : CLOCK_MONOTONIC, &elp_time); @@ -148,24 +180,25 @@ STATICFNDEF void times_usec(ext_tms *curr) use_realtime_flag = TRUE; continue; } else - MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("clock_gettime"), CALLFROM, errno)); + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("clock_gettime"), CALLFROM, errno)); } break; } - curr->tms_etime = (elp_time.tv_sec * 1000000) + (elp_time.tv_nsec / 1000); + curr->tms_etime = (elp_time.tv_sec * (gtm_uint64_t)1000000) + (elp_time.tv_nsec / 1000); return; } STATICFNDEF void child_times_usec(void) { - int res; - struct rusage usage; + int res; + struct rusage usage; res = getrusage(RUSAGE_CHILDREN, &usage); if (res == -1) - MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); - child_user = (usage.ru_utime.tv_sec * 1000000) + usage.ru_utime.tv_usec; - child_system = (usage.ru_stime.tv_sec * 1000000) + usage.ru_stime.tv_usec; + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno)); + child_user = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec; + child_system = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec; return; } #else @@ -176,63 +209,59 @@ STATICFNDEF void get_cputime (ext_tms *curr) int jpi_code = JPI$_CPUTIM; if ((status = lib$getjpi(&jpi_code, &process_id, 0, &cpu_time_used, 0, 0)) != SS$_NORMAL) - MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status)); + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status)); curr->tms_utime = cpu_time_used; curr->tms_stime = 0; return; } #endif -/* Enables tracing and ensures that all critical structures are initialized */ +/* Enables tracing and ensures that all critical structures are initialized. */ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl) { - ext_tms curr; trace_entry tmp_trc_tbl_entry; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; mdb_ch_set = !from_env; - /* if tracing is on explicitly, or if it is implicit with saving */ + /* If tracing is on explicitly, or if it is implicit with saving. */ if (save_gbl || !from_env) { if (is_tracing_on) { - gtm_putmsg(VARLSTCNT(1) ERR_TRACINGON); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TRACINGON); return; } if ((0 == gvn->str.len) || ('^' != gvn->str.addr[0])) - MPROF_RTS_ERROR((VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr)); + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr)); } - /* the following should only be a one-time operation */ + /* The following should only be a one-time operation. */ if (!TREF(mprof_ptr)) { TREF(mprof_ptr) = (mprof_wrapper *)malloc(SIZEOF(mprof_wrapper)); memset(TREF(mprof_ptr), 0, SIZEOF(mprof_wrapper)); } - /* only need to have the gvn if we are going to save the data */ + /* Only need to have the gvn if we are going to save the data. */ if (save_gbl && (0 < gvn->str.len)) { parse_gvn(gvn); (TREF(mprof_ptr))->gbl_to_fill = *gvn; - (TREF(mprof_ptr))->gbl_to_fill.str.addr = (char *)malloc(gvn->str.len); /* len was already set up */ + (TREF(mprof_ptr))->gbl_to_fill.str.addr = (char *)malloc(gvn->str.len); /* Since len was already set up. */ memcpy((TREF(mprof_ptr))->gbl_to_fill.str.addr, gvn->str.addr, gvn->str.len); } - /* preallocate some space */ + /* Preallocate some space. */ if (!(TREF(mprof_ptr))->pcavailbase) { (TREF(mprof_ptr))->pcavailbase = (char **)malloc(PROFCALLOC_DSBLKSIZE); *(TREF(mprof_ptr))->pcavailbase = 0; } (TREF(mprof_ptr))->pcavailptr = (TREF(mprof_ptr))->pcavailbase; - (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - SIZEOF(char *); + (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - OFFSET_LEN; memset((TREF(mprof_ptr))->pcavailptr + 1, 0, (TREF(mprof_ptr))->pcavail); - curr = (TREF(mprof_ptr))->tprev; - TIMES(&curr); + TIMES(&(TREF(mprof_ptr))->tprev); UNIX_ONLY(child_times_usec();) mprof_stack_init(); - /* if tracing is started explicitly, we are in a good frame, so we can - * initialize things and start counting time - */ + /* If tracing is started explicitly, we are in a good frame, so we can initialize things and start counting time. */ if (!from_env) { TREF(prof_fp) = mprof_stack_push(); @@ -240,22 +269,22 @@ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl) tmp_trc_tbl_entry.rout_name = NULL; tmp_trc_tbl_entry.label_name = NULL; (TREF(mprof_ptr))->curr_tblnd = (TREF(mprof_ptr))->head_tblnd = NULL; - (TREF(prof_fp))->start.tms_stime = curr.tms_stime; - (TREF(prof_fp))->start.tms_utime = curr.tms_utime; - (TREF(prof_fp))->start.tms_etime = curr.tms_etime; + (TREF(prof_fp))->start.tms_stime = (TREF(mprof_ptr))->tprev.tms_stime; + (TREF(prof_fp))->start.tms_utime = (TREF(mprof_ptr))->tprev.tms_utime; + (TREF(prof_fp))->start.tms_etime = (TREF(mprof_ptr))->tprev.tms_etime; (TREF(prof_fp))->carryover.tms_stime = 0; (TREF(prof_fp))->carryover.tms_utime = 0; (TREF(prof_fp))->carryover.tms_etime = 0; (TREF(prof_fp))->dummy_stack_count = 0; (TREF(prof_fp))->rout_name = (TREF(prof_fp))->label_name = NULL; } - /* make necessary xfer_table substitutions before we begin */ + /* Make necessary xfer_table substitutions before we begin. */ if (!is_tracing_on) { POPULATE_PROFILING_TABLE(); is_tracing_on = TRUE; } - /* remember if we need to save results to a global at the end */ + /* Remember if we need to save results to a global at the end. */ if (!save_gbl) save_to_gbl = FALSE; mdb_ch_set = TRUE; @@ -263,7 +292,7 @@ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl) } /* Disables tracing and properly disposes of allocated resources; additionally, - * saves data to the database if save_to_gbl was set to TRUE + * saves data to the database if save_to_gbl was set to TRUE. */ void turn_tracing_off(mval *gvn) { @@ -277,7 +306,7 @@ void turn_tracing_off(mval *gvn) UNIX_ONLY(child_times_usec();) process_system = (TREF(mprof_ptr))->tcurr.tms_stime; process_user = (TREF(mprof_ptr))->tcurr.tms_utime; - /* update the time of previous M line if there was one */ + /* Update the time of previous M line if there was one. */ if (NULL != (TREF(mprof_ptr))->curr_tblnd) { UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd); @@ -285,8 +314,8 @@ void turn_tracing_off(mval *gvn) if (NULL != gvn) parse_gvn(gvn); assert(!save_to_gbl || (0 != (TREF(mprof_ptr))->gbl_to_fill.str.addr)); - /* if tracing was initialized from an environment variable, and it had a proper global name, save results - * to that global; otherwise, just toss the collected data + /* If tracing was initialized from an environment variable, and it had a proper global name, save results + * to that global; otherwise, just toss the collected data. */ if (save_to_gbl) { @@ -302,8 +331,8 @@ void turn_tracing_off(mval *gvn) is_tracing_on = (TREF(mprof_ptr))->is_tracing_ini = FALSE; mprof_stack_free(); (TREF(mprof_ptr))->pcavailptr = (TREF(mprof_ptr))->pcavailbase; - (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - SIZEOF(char *); - CLEAR_PROFILING_TABLE(); /* restore the original xfer_table links */ + (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - OFFSET_LEN; + CLEAR_PROFILING_TABLE(); /* Restore the original xfer_table links. */ TREF(prof_fp) = NULL; return; } @@ -320,7 +349,7 @@ void forchkhandler(char *return_address) SETUP_THREADGBL_ACCESS; get_entryref_information(TRUE, &tmp_trc_tbl_entry); - /* starting tracing now; save the info about the current FOR loop */ + /* Starting tracing now; save the info about the current FOR loop. */ if (FALSE == (TREF(mprof_ptr))->is_tracing_ini) { (TREF(mprof_ptr))->is_tracing_ini = TRUE; @@ -335,24 +364,24 @@ void forchkhandler(char *return_address) (TREF(mprof_ptr))->curr_tblnd = (mprof_tree *)mprof_tree_insert(&((TREF(mprof_ptr))->head_tblnd), &tmp_trc_tbl_entry); if (NULL == (TREF(mprof_ptr))->curr_tblnd->loop_link) - { /* first FOR for this node */ + { /* First FOR for this node. */ for_node = (mprof_tree *)new_for_node(&tmp_trc_tbl_entry, return_address); for_node->e.count = 1; for_node->e.loop_level = 1; (TREF(mprof_ptr))->curr_tblnd->loop_link = (mprof_tree *)for_node; return; } - /* some FORs have been already recorded for this line, so keep checking for more */ + /* Some FORs have been already recorded for this line, so keep checking for more. */ for_link = (mprof_tree *)(TREF(mprof_ptr))->curr_tblnd->loop_link; for_level_on_line = 1; while (TRUE) - { /* same FOR, so just update the count */ + { /* Same FOR, so just update the count. */ if (for_link->e.raddr == return_address) { for_link->e.count++; break; } - /* new FOR for this line */ + /* New FOR for this line. */ if (NULL == for_link->loop_link) { for_node = (mprof_tree *)new_for_node(&tmp_trc_tbl_entry, return_address); @@ -361,7 +390,7 @@ void forchkhandler(char *return_address) for_link->loop_link = (mprof_tree *)for_node; break; } else - { /* same FOR as last one, so increase the loop level for the line and keep searching */ + { /* Same FOR as last one, so increase the loop level for the line and keep searching. */ for_link = (mprof_tree *)for_link->loop_link; for_level_on_line++; } @@ -369,9 +398,7 @@ void forchkhandler(char *return_address) return; } -/* Records the typical line-to-line deltas in CPU and absolute time. - * Called on each linestart and linefetch. - */ +/* Records the typical line-to-line deltas in CPU and absolute time. Called on each linestart and linefetch. */ void pcurrpos(void) { trace_entry tmp_trc_tbl_entry; @@ -384,8 +411,8 @@ void pcurrpos(void) } assert(TREF(mprof_ptr)); assert(TREF(prof_fp)); - TIMES(&(TREF(mprof_ptr))->tcurr); /* remember the new time */ - /* update the time of previous M line */ + TIMES(&(TREF(mprof_ptr))->tcurr); /* Remember the new time. */ + /* Update the time of previous M line. */ if (NULL != (TREF(mprof_ptr))->curr_tblnd) { UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd); @@ -444,9 +471,9 @@ void new_prof_frame(int real_frame) } assert(TREF(mprof_ptr)); assert(TREF(prof_fp)); - /* a call to a routine, not IF or FOR with a DO */ + /* A call to a routine, not IF or FOR with a DO. */ if (real_frame) - { /* update the time of the line in the parent frame */ + { /* Update the time of the line in the parent frame. */ if (NULL != (TREF(mprof_ptr))->curr_tblnd) { TIMES(&(TREF(mprof_ptr))->tcurr); @@ -454,7 +481,7 @@ void new_prof_frame(int real_frame) } (TREF(prof_fp))->curr_node = (TREF(mprof_ptr))->curr_tblnd; (TREF(mprof_ptr))->curr_tblnd = NULL; - /* create a new frame on the stack */ + /* Create a new frame on the stack. */ TREF(prof_fp) = mprof_stack_push(); (TREF(prof_fp))->rout_name = NULL; (TREF(prof_fp))->label_name = NULL; @@ -478,40 +505,40 @@ void unw_prof_frame(void) mprof_tree *t; ext_tms carryover; stack_frame *save_fp; - unsigned int frame_usr_time, frame_sys_time, frame_elp_time; + gtm_uint64_t frame_usr_time, frame_sys_time, frame_elp_time; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TREF(mprof_ptr)); - /* do not assert on prof_fp not being NULL, as it will be NULL in - * case we quit from a function without ever disabling tracing + /* Do not assert on prof_fp not being NULL, as it will be NULL in + * case we quit from a function without ever disabling tracing. */ if (NULL == TREF(prof_fp)) return; - /* we are leaving a real frame, not an IF or FOR with a DO */ + /* We are leaving a real frame, not an IF or FOR with a DO. */ if (0 >= (TREF(prof_fp))->dummy_stack_count) { TIMES(&(TREF(mprof_ptr))->tcurr); - /* update the time of last line in this frame before returning */ + /* Update the time of last line in this frame before returning. */ if (NULL != (TREF(mprof_ptr))->curr_tblnd) { UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd); } get_entryref_information(TRUE, &tmp_trc_tbl_entry); - /* if prof_fp is NULL, it was set so in get_entryref_information, which means + /* If prof_fp is NULL, it was set so in get_entryref_information, which means * that we are not in a valid frame, so there is no point in recording timing for - * some unreal label; besides, the line timing has already been updated + * some unreal label; besides, the line timing has already been updated. */ if (NULL == TREF(prof_fp)) return; if ((TREF(prof_fp))->rout_name == &above_routine) - { /* it should have been filled in get_entryref_information */ + { /* It should have been filled in get_entryref_information. */ e.label_name = tmp_trc_tbl_entry.label_name; e.rout_name = tmp_trc_tbl_entry.rout_name; } else - { /* note that this memory allocated for the label and routine names might need + { /* Note that this memory allocated for the label and routine names might need * to be reclaimed, so set up the corresponding flag, reset the allocation count, - * and the address of the current allocation bucket + * and the address of the current allocation bucket. */ TREF(mprof_alloc_reclaim) = TRUE; TREF(mprof_reclaim_addr) = (char *)(TREF(mprof_ptr))->pcavailptr; @@ -524,16 +551,16 @@ void unw_prof_frame(void) e.rout_name->len = (TREF(prof_fp))->rout_name->len; e.rout_name->addr = pcalloc((unsigned int)e.rout_name->len); memcpy(e.rout_name->addr, (TREF(prof_fp))->rout_name->addr, (TREF(prof_fp))->rout_name->len); - TREF(mprof_alloc_reclaim) = FALSE; /* memory should not have to be reclaimed after this point, - * so stop updating the count */ + TREF(mprof_alloc_reclaim) = FALSE; /* Memory should not have to be reclaimed after this point, + * so stop updating the count. */ } e.line_num = -1; - /* insert/find a frame entry into/in the MPROF tree, -1 indicating that it is not a - * real line number, but rather an aggregation of several lines (comprising a label) + /* Insert/find a frame entry into/in the MPROF tree, -1 indicating that it is not a + * real line number, but rather an aggregation of several lines (comprising a label). */ t = mprof_tree_insert(&((TREF(mprof_ptr))->head_tblnd), &e); - TREF(mprof_reclaim_cnt) = 0; /* reset the memory allocation count */ - /* update count and timing (from prof_fp) of frame I'm leaving */ + TREF(mprof_reclaim_cnt) = 0; /* Reset the memory allocation count. */ + /* Update count and timing (from prof_fp) of frame I'm leaving. */ t->e.count++; frame_usr_time = ((TREF(mprof_ptr))->tcurr.tms_utime - (TREF(prof_fp))->start.tms_utime - (TREF(prof_fp))->carryover.tms_utime); @@ -544,21 +571,21 @@ void unw_prof_frame(void) t->e.usr_time += frame_usr_time; t->e.sys_time += frame_sys_time; t->e.elp_time += frame_elp_time; - /* not the first frame on the stack */ + /* Not the first frame on the stack. */ if ((TREF(prof_fp))->prev) { carryover = (TREF(prof_fp))->carryover; - /* move back up to parent frame */ + /* Move back up to parent frame. */ TREF(prof_fp) = mprof_stack_pop(); (TREF(prof_fp))->carryover.tms_utime += (frame_usr_time + carryover.tms_utime); (TREF(prof_fp))->carryover.tms_stime += (frame_sys_time + carryover.tms_stime); (TREF(prof_fp))->carryover.tms_etime += (frame_elp_time + carryover.tms_etime); - /* restore the context of the parent frame */ + /* Restore the context of the parent frame. */ (TREF(mprof_ptr))->tprev = (TREF(mprof_ptr))->tcurr; (TREF(mprof_ptr))->curr_tblnd = (TREF(prof_fp))->curr_node; (TREF(prof_fp))->curr_node = NULL; } else - { /* This should only be true only if the View command is not at the top-most stack level, in which case + { /* This should only be true only if the VIEW command is not at the top-most stack level, in which case * add profiling information for the current frame. To prevent stack underflow, add a new frame before * unwinding from this frame. */ @@ -569,15 +596,15 @@ void unw_prof_frame(void) save_fp = frame_pointer; # ifdef GTM_TRIGGER if (frame_pointer->type & SFT_TRIGR) - { /* in a trigger base frame, old_frame_pointer is NULL */ + { /* In a trigger base frame, old_frame_pointer is NULL. */ assert(NULL == frame_pointer->old_frame_pointer); - /* have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ + /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame(). */ frame_pointer = *(stack_frame **)(frame_pointer + 1); } else # endif frame_pointer = frame_pointer->old_frame_pointer; - /* if frame_pointer is NULL, we are likely dealing with call-ins, so there is no point trying to unwind - * any further; just restore the frame_pointer and return + /* If frame_pointer is NULL, we are likely dealing with call-ins, so there is no point trying to unwind + * any further; just restore the frame_pointer and return. */ if (!frame_pointer) { @@ -586,9 +613,9 @@ void unw_prof_frame(void) } get_entryref_information(FALSE, NULL); frame_pointer = save_fp; - /* if for some reason we made it all the way here, but prof_fp was still set to NULL by + /* If for some reason we made it all the way here, but prof_fp was still set to NULL by * get_entryref_information(), then just silently quit out of this routine to prevent unwinding into some - * nowhere land + * nowhere land. */ if (NULL == TREF(prof_fp)) return; @@ -596,7 +623,7 @@ void unw_prof_frame(void) (TREF(prof_fp))->carryover.tms_utime = 0; (TREF(prof_fp))->carryover.tms_stime = 0; (TREF(prof_fp))->carryover.tms_etime = 0; - /* tag it, so that next time it picks up label/routine info from current loc */ + /* Tag it, so that next time it picks up label/routine info from current loc. */ (TREF(prof_fp))->rout_name = (mident *)&above_routine; (TREF(prof_fp))->label_name = NULL; (TREF(prof_fp))->dummy_stack_count = 0; @@ -606,15 +633,18 @@ void unw_prof_frame(void) return; } -/* Allocate storage for profiling information */ +/* Allocate storage for profiling information. */ char *pcalloc(unsigned int n) { char **x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - GTM64_ONLY(n = ((n + 7) & ~7);) /* same logic applied for alignment */ - NON_GTM64_ONLY(n = ((n + 3) & ~3);) /* make sure that it is quad-word aliged */ +# if defined (GTM64) || defined(__osf__) || defined(VMS) + n = ((n + 7) & ~7); /* Same logic applied for alignment. */ +# else + n = ((n + 3) & ~3); /* Make sure that it is quad-word aligned. */ +# endif if (n > (TREF(mprof_ptr))->pcavail) { if (*(TREF(mprof_ptr))->pcavailptr) @@ -626,14 +656,14 @@ char *pcalloc(unsigned int n) (TREF(mprof_ptr))->pcavailptr = x; *(TREF(mprof_ptr))->pcavailptr = NULL; } - (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - SIZEOF(char *); + (TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - OFFSET_LEN; memset((TREF(mprof_ptr))->pcavailptr + 1, 0, (TREF(mprof_ptr))->pcavail); } (TREF(mprof_ptr))->pcavail -= n; if (TREF(mprof_alloc_reclaim)) - (TREF(mprof_reclaim_cnt)) += n; /* update the memory allocation count if needed */ + (TREF(mprof_reclaim_cnt)) += n; /* Update the memory allocation count if needed. */ assert((TREF(mprof_ptr))->pcavail >= 0); - return (char *)(TREF(mprof_ptr))->pcavailptr + (TREF(mprof_ptr))->pcavail + SIZEOF(char *); + return (char *)(TREF(mprof_ptr))->pcavailptr + (TREF(mprof_ptr))->pcavail + OFFSET_LEN; } /* Reclaim storage previously allocated by pcalloc(). */ @@ -643,13 +673,13 @@ void mprof_reclaim_slots(void) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (0 < TREF(mprof_reclaim_cnt)) /* in case some memory needs to be reclaimed, do so */ + if (0 < TREF(mprof_reclaim_cnt)) /* In case some memory needs to be reclaimed, do so. */ { - alloc_diff = (PROFCALLOC_DSBLKSIZE - (TREF(mprof_ptr))->pcavail - SIZEOF(char *)); - if (alloc_diff >= TREF(mprof_reclaim_cnt)) /* allocation did not need a new bucket, we are good */ + alloc_diff = (PROFCALLOC_DSBLKSIZE - (TREF(mprof_ptr))->pcavail - OFFSET_LEN); + if (alloc_diff >= TREF(mprof_reclaim_cnt)) /* Allocation did not need a new bucket, we are good. */ (TREF(mprof_ptr))->pcavail += TREF(mprof_reclaim_cnt); else - { /* go back to the previous allocation bucket and set the pcavail accordingly for the older bucket */ + { /* Go back to the previous allocation bucket and set the pcavail accordingly for the older bucket. */ (TREF(mprof_ptr))->pcavailptr = (char **)TREF(mprof_reclaim_addr); (TREF(mprof_ptr))->pcavail = (TREF(mprof_reclaim_cnt) - alloc_diff); } @@ -663,9 +693,9 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) int count, arg_index, subsc_len, tmp_str_len; INTPTR_T start_point; mval data; - char dataval[96]; /* big enough for data value */ - unsigned char subsval[12]; /* see i2asc + 1 for null char */ - unsigned char asc_line_num[12]; /* to hold the ascii equivalent of the line_num */ + char dataval[96]; /* Big enough for data value. */ + unsigned char subsval[12]; /* See i2asc + 1 for null char. */ + unsigned char asc_line_num[12]; /* To hold the ascii equivalent of the line_num. */ unsigned char *tmpnum, *end; mval *spt; DCL_THREADGBL_ACCESS; @@ -675,7 +705,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) return; count = (int)(TREF(mprof_ptr))->gvargs.count; spt = &(TREF(mprof_ptr))->subsc[count]; - /* global name --> ^PREFIX(, "rout-name", "label-name", "line-num", "forloop") */ + /* Global name --> ^PREFIX(, "rout-name", "label-name", "line-num", "forloop"). */ spt->mvtype = MV_STR; spt->str.len = p->e.rout_name->len; spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len); @@ -688,7 +718,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len); memcpy(spt->str.addr, p->e.label_name->addr, spt->str.len); } else - { /* place holder before first label */ + { /* Place holder before first label. */ spt->str.len = SIZEOF(MPROF_NULL_LABEL) - 1; spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len); memcpy(spt->str.addr, MPROF_NULL_LABEL, spt->str.len); @@ -705,7 +735,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) count++; spt++; } - /* for FOR loops */ + /* For FOR loops. */ if (is_for) { spt->mvtype = MV_STR; @@ -713,7 +743,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) spt->str.addr = (char *)pcalloc(SIZEOF(MPROF_FOR_LOOP) - 1); memcpy(spt->str.addr, MPROF_FOR_LOOP, spt->str.len); (TREF(mprof_ptr))->gvargs.args[count++] = spt++; - /* write for level into the subscript as well */ + /* Write for level into the subscript as well. */ spt->mvtype = MV_STR; tmpnum = i2asc(subsval, p->e.loop_level); spt->str.len = INTCAST(tmpnum - subsval); @@ -724,31 +754,31 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) (TREF(mprof_ptr))->gvargs.count = count; callg((INTPTR_T(*)(intszofptr_t count_arg, ...))op_gvname, (gparam_list *)&(TREF(mprof_ptr))->gvargs); (TREF(mprof_ptr))->gvargs.count = (TREF(mprof_ptr))->curr_num_subscripts; - /* data --> "count:cpu-time in user mode:cpu-time in sys mode:cpu-time total" */ + /* Data --> 'count:cpu-time in user mode:cpu-time in sys mode:cpu-time total'. */ start_point = (INTPTR_T)&dataval[0]; /* get count */ tmpnum = (unsigned char *)&dataval[0]; end = i2asc(tmpnum, p->e.count); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); - /* for non-FOR stuff get CPU time as well */ + /* For non-FOR stuff get CPU time as well. */ if (!is_for) { *tmpnum = ':'; tmpnum++; - end = i2asc(tmpnum, p->e.usr_time); + end = i2ascl(tmpnum, p->e.usr_time); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); # ifndef VMS *tmpnum = ':'; tmpnum++; - end = i2asc(tmpnum, p->e.sys_time); + end = i2ascl(tmpnum, p->e.sys_time); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); *tmpnum = ':'; tmpnum++; - end = i2asc(tmpnum, p->e.sys_time + p->e.usr_time); + end = i2ascl(tmpnum, p->e.sys_time + p->e.usr_time); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); *tmpnum = ':'; tmpnum++; - end = i2asc(tmpnum, p->e.elp_time); + end = i2ascl(tmpnum, p->e.elp_time); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); # endif } @@ -761,13 +791,13 @@ void crt_gbl(mprof_tree *p, boolean_t is_for) return; } -/* Save total CPU times for the current and all child processes */ +/* Save total CPU times for the current and all child processes. */ STATICFNDEF void insert_total_times(boolean_t for_process) { int count; INTPTR_T start_point; mval data; - char dataval[96]; /* big enough for data value */ + char dataval[96]; /* Big enough for data value. */ unsigned char *tmpnum, *end; mval *spt; DCL_THREADGBL_ACCESS; @@ -794,23 +824,23 @@ STATICFNDEF void insert_total_times(boolean_t for_process) start_point = (INTPTR_T)&dataval[0]; tmpnum = (unsigned char *)&dataval[0]; if (for_process) - end = i2asc(tmpnum, process_user); + end = i2ascl(tmpnum, process_user); else - end = i2asc(tmpnum, child_user); + end = i2ascl(tmpnum, child_user); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); *tmpnum = ':'; tmpnum++; if (for_process) - end = i2asc(tmpnum, process_system); + end = i2ascl(tmpnum, process_system); else - end = i2asc(tmpnum, child_system); + end = i2ascl(tmpnum, child_system); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); *tmpnum = ':'; tmpnum++; if (for_process) - end = i2asc(tmpnum, process_user + process_system); + end = i2ascl(tmpnum, process_user + process_system); else - end = i2asc(tmpnum, child_user + child_system); + end = i2ascl(tmpnum, child_user + child_system); tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end); data.mvtype = MV_STR; data.str.len = (((INTPTR_T)tmpnum - start_point) > 0) @@ -830,7 +860,6 @@ STATICFNDEF void get_entryref_information(boolean_t line, trace_entry *tmp_trc_t stack_frame *fp; int status; unsigned char *addr, *out_addr; - unsigned char temp[OFFSET_LEN]; int4 *line_table, *last_line, len, ct; int4 offset, in_addr_offset; unsigned long user_time, system_time; @@ -844,7 +873,7 @@ STATICFNDEF void get_entryref_information(boolean_t line, trace_entry *tmp_trc_t if (fp->type & SFT_TRIGR) { assert(NULL == fp->old_frame_pointer); - /* have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ + /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame(). */ fp = *(stack_frame **)(fp + 1); } # endif @@ -906,21 +935,21 @@ STATICFNDEF void get_entryref_information(boolean_t line, trace_entry *tmp_trc_t return; } -/* Parses the global variable name that the information will be dumped into, to make sure it is a valid gvn */ +/* Parses the global variable name that the information will be dumped into, to make sure it is a valid gvn. */ STATICFNDEF void parse_gvn(mval *gvn) { boolean_t dot_seen; mval *spt; char *c_top, *c_ref, ch; unsigned int count = 0; - char *mpsp; /* pointer into mprof_mstr area */ + char *mpsp; /* Pointer into mprof_mstr area. */ DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; c_ref = gvn->str.addr; c_top = c_ref + gvn->str.len; if (!gvn->str.len || ('^' != *c_ref++)) - MPROF_RTS_ERROR((VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr)); + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr)); if (mprof_mstr.len < 4 * gvn->str.len) { /* We are going to return an array of mvals pointing to global-name and subscript. We should * never be needing more than 4 * gvn->str.len since the only expandable entity that can be @@ -936,7 +965,7 @@ STATICFNDEF void parse_gvn(mval *gvn) mprof_mstr.addr = (char *)malloc(mprof_mstr.len); } mpsp = mprof_mstr.addr; - /* parse the global variable passed to insert the information */ + /* Parse the global variable passed to insert the information. */ spt = &(TREF(mprof_ptr))->subsc[0]; spt->mvtype = MV_STR; spt->str.addr = mpsp; @@ -952,7 +981,7 @@ STATICFNDEF void parse_gvn(mval *gvn) spt->str.len = INTCAST(mpsp - spt->str.addr); (TREF(mprof_ptr))->gvargs.args[count++] = spt++; spt->str.addr = (char *)mpsp; - /* process subscripts, if any */ + /* Process subscripts, if any. */ if (c_ref++ < c_top) { for ( ; c_ref < c_top; ) @@ -981,7 +1010,7 @@ STATICFNDEF void parse_gvn(mval *gvn) RTS_ERROR_VIEWNOTFOUND("Intrinsic value is incomplete"); if (*c_ref != 'J' && *c_ref != 'j') RTS_ERROR_VIEWNOTFOUND("Intrinsic value passed is not $j"); - c_ref++; /* past 'J' */ + c_ref++; /* Past 'J'. */ if ((c_ref < c_top) && (ISALPHA_ASCII(*c_ref))) { ch = *c_ref; @@ -995,7 +1024,7 @@ STATICFNDEF void parse_gvn(mval *gvn) } else RTS_ERROR_VIEWNOTFOUND("Intrinsic value is incomplete"); } - assert(10 > dollar_job.str.len); /* to take care of 4 * gvn->str.len allocation above */ + assert(10 > dollar_job.str.len); /* To take care of 4 * gvn->str.len allocation above. */ memcpy(mpsp, dollar_job.str.addr, dollar_job.str.len); mpsp += dollar_job.str.len; } else @@ -1031,7 +1060,7 @@ STATICFNDEF void parse_gvn(mval *gvn) } spt->str.len = INTCAST(mpsp - spt->str.addr); if (MAX_GVSUBSCRIPTS <= count) - MPROF_RTS_ERROR((VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS)); + MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS)); (TREF(mprof_ptr))->gvargs.args[count++] = spt++; if (',' != *c_ref) break; @@ -1046,7 +1075,7 @@ STATICFNDEF void parse_gvn(mval *gvn) if (++c_ref < c_top) RTS_ERROR_VIEWNOTFOUND("There are trailing characters after the global name"); } - assert((char *)mpsp <= mprof_mstr.addr + mprof_mstr.len); /* ensure we haven't overrun the malloced buffer */ + assert((char *)mpsp <= mprof_mstr.addr + mprof_mstr.len); /* Ensure we haven't overrun the malloced buffer. */ (TREF(mprof_ptr))->gvargs.count = count; (TREF(mprof_ptr))->curr_num_subscripts = (int)(TREF(mprof_ptr))->gvargs.count; return; @@ -1065,10 +1094,10 @@ void stack_leak_check(void) if (NULL == var_on_cstack_ptr) var_on_cstack_ptr = &var_on_cstack; if ((&var_on_cstack != var_on_cstack_ptr) -# ifdef __i386 /* for 32-bit Linux allow a two pointer variation to accommodate ZHELP */ - && ((SIZEOF(var_on_cstack) * 2) < ABS(&var_on_cstack - var_on_cstack_ptr)) -# endif - ) - GTMASSERT; +# ifdef __i386 /* For 32-bit Linux allow a two pointer variation to accommodate ZHELP. */ + && ((SIZEOF(var_on_cstack) * 2) < ABS(&var_on_cstack - var_on_cstack_ptr)) +# endif + ) + assertpro(FALSE); return; } diff --git a/sr_port/mprof_stack.c b/sr_port/mprof_stack.c index 145d346..9595a8e 100644 --- a/sr_port/mprof_stack.c +++ b/sr_port/mprof_stack.c @@ -12,11 +12,8 @@ #include "mdef.h" #include "mprof.h" -#ifdef DEBUG -#define MPROF_CHUNK_SIZE 2 * SIZEOF(mprof_stack_frame) /* for debug only store 2 frames per chunk */ -#else -#define MPROF_CHUNK_SIZE 8096 /* in pro make each chunk about 8K */ -#endif +#define MPROF_CHUNK_SIZE 8096 /* previously, allocation for debug was smaller; however, since we have not seen any issues, + * we made it equal with pro */ #define MPROF_STACK_ALLOC_CNT (MPROF_CHUNK_SIZE / SIZEOF(mprof_stack_frame)) /* size of allocation chunk in number of frames */ GBLREF int process_exiting; diff --git a/sr_port/mprof_tree.c b/sr_port/mprof_tree.c index f4b3b29..3b49bfa 100644 --- a/sr_port/mprof_tree.c +++ b/sr_port/mprof_tree.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -64,7 +64,7 @@ mprof_tree *new_node(trace_entry *arg) tree->e.rout_name = arg->rout_name; tree->e.label_name = arg->label_name; tree->e.line_num = arg->line_num; - tree->e.count = tree->e.usr_time = tree->e.sys_time = tree->e.loop_level = 0; + tree->e.count = tree->e.usr_time = tree->e.sys_time = tree->e.elp_time = tree->e.loop_level = 0; tree->e.raddr = NULL; tree->link[LEFT] = tree->link[RIGHT] = tree->loop_link = NULL; tree->desc_dir = NEITHER; diff --git a/sr_port/mtables.c b/sr_port/mtables.c index 6d458dc..97f5c5e 100644 --- a/sr_port/mtables.c +++ b/sr_port/mtables.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "compiler.h" #include "opcode.h" #include "toktyp.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "release_name.h" #include "gdsroot.h" /* needed for tp.h & gv_trigger.h */ @@ -31,11 +31,13 @@ #include "tp.h" #include "gtmimagename.h" #include "arit.h" - +#include "gtm_conv.h" +#include "gtm_caseconv.h" #ifdef GTM_TRIGGER -#include "trigger.h" -#include "gv_trigger.h" +# include "trigger.h" +# include "gv_trigger.h" #endif +#include "mtables.h" LITDEF char ctypetab[NUM_CHARS] = { @@ -129,7 +131,8 @@ LITDEF toktabtype tokentable[] = tokdef("TK_VBAR", 0, 0, 0), tokdef("TK_EXPONENT", OC_EXP, 0, OCT_MVAL), tokdef("TK_SORTS_AFTER", OC_SORTS_AFTER, 0, OCT_MVAL), - tokdef("TK_NSORTS_AFTER", OC_NSORTS_AFTER, 0, OCT_MVAL) + tokdef("TK_NSORTS_AFTER", OC_NSORTS_AFTER, 0, OCT_MVAL), + tokdef("TK_ATHASH", 0, 0, 0) }; GBLREF mv_stent *mv_chain; /* Needed for MV_SIZE macro */ @@ -157,8 +160,8 @@ LITDEF unsigned char mvs_size[] = }; /* All mv_stent types that need to be preserved are indicated by the mvs_save[] array. - * MVST_STCK_SP (which is the same as the MVST_STCK type everywhere else is handled specially here. - * This entry is created by mdb_condition_handler to stack the "stackwarn" global variable. + * MVST_STCK_SP (which is the same as the MVST_STCK type everywhere else) is handled specially here. + * The MVST_STCK_SP entry is created by mdb_condition_handler to stack the "stackwarn" global variable. * This one needs to be preserved since our encountering this type in flush_jmp.c indicates that we are currently * in the error-handler of a STACKCRIT error which in turn has "GOTO ..." in the $ZTRAP/$ETRAP that is * causing us to mutate the current frame we are executing in with the contents pointed to by the GOTO. @@ -172,14 +175,14 @@ LITDEF boolean_t mvs_save[] = TRUE, /* MVST_STAB */ FALSE, /* MVST_IARR */ TRUE, /* MVST_NTAB */ - FALSE, /* MVST_ZINTCMD */ + TRUE, /* MVST_ZINTCMD */ TRUE, /* MVST_PVAL */ FALSE, /* MVST_STCK */ TRUE, /* MVST_NVAL */ TRUE, /* MVST_TVAL */ TRUE, /* MVST_TPHOLD */ TRUE, /* MVST_ZINTR */ - FALSE, /* MVST_ZINTDEV */ + TRUE, /* MVST_ZINTDEV */ TRUE, /* MVST_STCK_SP */ TRUE, /* MVST_LVAL */ FALSE, /* MVST_TRIGR */ @@ -188,16 +191,16 @@ LITDEF boolean_t mvs_save[] = FALSE /* MVST_MRGZWRSV */ }; -static readonly unsigned char localpool[7] = {'1', '1' , '1' , '0', '1', '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, 1000 ); -LITDEF mval literal_ten = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 2, (char *)&localpool[2], 0, 10000 ); -LITDEF mval literal_eleven = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 2, (char *)&localpool[0], 0, 11000 ); -LITDEF mval literal_oneohoh = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[4], 0, 100000 ); -LITDEF mval literal_oneohone = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[2], 0, 101000 ); -LITDEF mval literal_oneten = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[1], 0, 110000 ); -LITDEF mval literal_oneeleven = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[0], 0, 111000 ); +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); +LITDEF mval literal_eleven = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 2, (char *)&localpool[0], 0, 11 * MV_BIAS); +LITDEF mval literal_oneohoh = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[4], 0, 100 * MV_BIAS); +LITDEF mval literal_oneohone = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[2], 0, 101 * MV_BIAS); +LITDEF mval literal_oneten = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[1], 0, 110 * MV_BIAS); +LITDEF mval literal_oneeleven = DEFINE_MVAL_LITERAL(MV_STR | MV_NM | MV_INT, 0, 0, 3, (char *)&localpool[0], 0, 111 * MV_BIAS); /* -------------------------------------------------------------------------------------------------------------------------- * All string mvals defined in this module using LITDEF need to have MV_NUM_APPROX bit set. This is because these mval @@ -296,7 +299,7 @@ LITDEF int4 gtm_version_len = SIZEOF(GTM_VERSION) - 1; LITDEF char *gtm_dbversion_table[] = { "V4", - "V5" + "V6" }; LITDEF int4 ten_pwr[NUM_DEC_DG_1L+1] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; @@ -401,6 +404,40 @@ LITDEF char alphanumeric_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0'}; LITDEF int alphanumeric_table_len = (SIZEOF(alphanumeric_table) - 1); + +LITDEF mstr chset_names[CHSET_MAX_IDX_ALL] = +{ /* Supported character set (CHSET) codes for the 3-argument form of $ZCONVERT. + * Note: Update the *_CHSET_LEN macros below if new CHSETs are added. + */ + {1, 1, "M"}, /* "M" should be the first CHSET (0th index of "chset_names" array). verify_chset() callers rely on this. + * $ZCONVERT doesn't support M, but I/O does */ + {5, 5, "UTF-8"}, + {6, 6, "UTF-16"}, + {8, 8, "UTF-16LE"}, + {8, 8, "UTF-16BE"}, + {5, 5, "ASCII"}, + {6, 6, "EBCDIC"}, + {6, 6, "BINARY"} +}; +/* This array holds the ICU converter handles corresponding to the respective + * CHSET name in the table chset_names[] + */ +GBLDEF UConverter *chset_desc[CHSET_MAX_IDX]; +GBLDEF casemap_t casemaps[MAX_CASE_IDX] = +{ /* Supported case mappings and their disposal conversion routines for both $ZCHSET modes. + * Note: since UTF-8 disposal functions for "U" and "L" are ICU "function pointers" rather + * rather than their direct addresses, they are initialized in gtm_utf8_init() instead + */ + {"U", &lower_to_upper, NULL}, + {"L", &upper_to_lower, NULL}, + {"T", NULL, NULL} +}; +#endif + +#ifdef UNIX +/* Used as the value for "regular" key (i.e., the one with no hidden subscripts) of a spanning node. */ +LITDEF mstr nsb_dummy = {0, 1, "\0"}; +/*LITDEF mstr nsb_dummy = {0, LEN_AND_LIT("dummy")};*/ #endif #ifdef DEBUG @@ -917,4 +954,13 @@ LITDEF char vxi_opcode[][6] = "CVTHD " }; +/* Routine invoked in debug mode by init_gtm() on UNIX to verify certain assumptions about some of the + * tables in this routine. Routine must be resident in this module to do these checks since dimensions + * are not known in other routines using a LITREF. + */ +void mtables_chk(void) +{ + assert(SIZEOF(mvs_size) == (MVST_LAST + 1)); + assert(SIZEOF(mvs_save) == (SIZEOF(boolean_t) * (MVST_LAST + 1))); +} #endif diff --git a/sr_port/mu_clsce.c b/sr_port/mu_clsce.c index 72f244d..9a60d6d 100644 --- a/sr_port/mu_clsce.c +++ b/sr_port/mu_clsce.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -100,6 +100,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s unsigned short temp_ushort; int new_levelp_cur_cmpc, new_levelp_cur_next_cmpc, tkeycmpc, oldblk1_last_cmpc, newblk1_mid_cmpc, newblk1_last_cmpc; + int tmp_cmpc; int levelp, level2; int old_blk1_sz, old_blk2_sz; int old_levelp_cur_prev_keysz, @@ -180,7 +181,8 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s old_levelp_cur_keysz = uncompressed size of the key old_levelp_cur_keylen = compressed size of the key */ - READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, &old_levelp_cur_key[0], old_levelp_cur_keylen, status); + READ_RECORD(status, &rec_size, &tkeycmpc, &old_levelp_cur_keylen, old_levelp_cur_key, + levelp, old_levelp_blk_base, rec_base); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); @@ -197,8 +199,9 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s old_levelp_cur_next_keylen = comressed size of the key Note: we may not have a next key (old_levelp_cur_next_keysz = 0) */ - BLK_ADDR(old_levelp_cur_next_key, gv_cur_region->max_key_size + 1, unsigned char); - READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, old_levelp_cur_next_key, old_levelp_cur_next_keylen, status); + BLK_ADDR(old_levelp_cur_next_key, MAX_KEY_SZ + 1, unsigned char); + READ_RECORD(status, &rec_size, &tkeycmpc, &old_levelp_cur_next_keylen, old_levelp_cur_next_key, + levelp, old_levelp_blk_base, rec_base); if (cdb_sc_starrecord == status) levelp_next_is_star = TRUE; else if (cdb_sc_normal != status) @@ -221,7 +224,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s oldblk1_last_cmpc = compression count of last key of working block old_last_rec_hdr1 = New working index block's last record header */ - BLK_ADDR(oldblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char); + BLK_ADDR(oldblk1_last_key, MAX_KEY_SZ + 1, unsigned char); if (0 == level) /* data block */ { if (cdb_sc_normal != (status = gvcst_expand_any_key (old_blk1_base, old_blk1_base + old_blk1_sz, @@ -247,7 +250,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } - GET_CMPC(oldblk1_last_cmpc, &oldblk1_prev_key[0], &old_levelp_cur_key[0]); + GET_CMPC(oldblk1_last_cmpc, oldblk1_prev_key, old_levelp_cur_key); oldblk1_last_keylen = old_levelp_cur_keysz - oldblk1_last_cmpc; } else /* working block has a *-key record only */ @@ -258,7 +261,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s } BLK_ADDR(old_last_rec_hdr1, SIZEOF(rec_hdr), rec_hdr); old_last_rec_hdr1->rsiz = BSTAR_REC_SIZE + oldblk1_last_keylen; - old_last_rec_hdr1->cmpc = oldblk1_last_cmpc; + SET_CMPC(old_last_rec_hdr1, oldblk1_last_cmpc); } /* @@ -270,9 +273,10 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s complete_merge = TRUE, rtsib can be completely merged with working block piece_len = Size of data from old rtsibling to be merged into working block (includes rec_hdr size) */ - BLK_ADDR(newblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char); + BLK_ADDR(newblk1_last_key, MAX_KEY_SZ + 1, unsigned char); rec_base = old_blk2_base + SIZEOF(blk_hdr); - READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status); + READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key, + level, old_blk2_base, rec_base); if (cdb_sc_starrecord == status) /* rtsib index block has *-record only */ { if (old_blk1_sz + oldblk1_last_keylen + BSTAR_REC_SIZE > i_max_fill ) /* cannot fit even one record */ @@ -309,7 +313,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s { BLK_ADDR(new_rec_hdr1, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr1->rsiz = piece_len; - new_rec_hdr1->cmpc = newblk1_mid_cmpc; + SET_CMPC(new_rec_hdr1, newblk1_mid_cmpc); } /* else only new_blk1_last_key will be appeneded in working block */ @@ -327,10 +331,11 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s complete_merge = FALSE; break; } - READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status); + READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key, + level, old_blk2_base, rec_base); if (cdb_sc_normal != status) { - assert(t_tries < CDB_STAGNATE);; + assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc; @@ -353,11 +358,11 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s piece_len += rec_size; break; /* already we know we can fit this *-record in working block */ } - READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, - newblk1_last_key, newblk1_last_keylen, status); + READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key, + level, old_blk2_base, rec_base); if (cdb_sc_normal != status) { - assert(t_tries < CDB_STAGNATE);; + assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc; @@ -383,14 +388,14 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s new_blk2_remain = base pointer of buffer including 1st record but exclude rec_header and key new_blk2_first_keysz = size of new rtsib block's first key */ - BLK_ADDR(newblk2_first_key, gv_cur_region->max_key_size + 1, unsigned char); - READ_RECORD(level, new_blk2_first_rec_base, tkeycmpc, rec_size, - newblk2_first_key, newblk2_first_keylen, status); + BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char); + READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key, + level, old_blk2_base, new_blk2_first_rec_base); if (cdb_sc_starrecord == status) /* new rtsib will have a *-record only */ new_rtsib_star_only = TRUE; else if (cdb_sc_normal != status) { - assert(t_tries < CDB_STAGNATE);; + assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } else { @@ -399,7 +404,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s new_blk2_remain = new_blk2_first_rec_base + SIZEOF(rec_hdr) + newblk2_first_keylen; BLK_ADDR(new_rec_hdr2, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr2->rsiz = rec_size + tkeycmpc; - new_rec_hdr2->cmpc = 0; + SET_CMPC(new_rec_hdr2, 0); } } @@ -429,12 +434,13 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s blk2_ances_hdr = new rtsib's ancestor's 1st record's header */ delete_all_blk2_ances = FALSE; - BLK_ADDR(new_blk2_ances_first_key, gv_cur_region->max_key_size + 1, unsigned char); + BLK_ADDR(new_blk2_ances_first_key, MAX_KEY_SZ + 1, unsigned char); rec_base = blk2ptr->h[level2].buffaddr + SIZEOF(blk_hdr); - READ_RECORD(level2, rec_base, tkeycmpc, rec_size, new_blk2_ances_first_key, tkeylen, status); + READ_RECORD(status, &rec_size, &tkeycmpc, &tkeylen, new_blk2_ances_first_key, + level2, blk2ptr->h[level2].buffaddr, rec_base); if (cdb_sc_normal != status) { - assert(t_tries < CDB_STAGNATE);; + assert(t_tries < CDB_STAGNATE); return cdb_sc_blkmod; } /* newblk1_last_key was the last key before *-key. @@ -445,7 +451,8 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s memcpy(newblk1_last_key, new_blk2_ances_first_key, newblk1_last_keysz); /* 2nd record will become 1st record of current block at level2 */ rec_base += rec_size; - READ_RECORD(level2, rec_base, tkeycmpc, rec_size, new_blk2_ances_first_key, tkeylen, status); + READ_RECORD(status, &rec_size, &tkeycmpc, &tkeylen, new_blk2_ances_first_key, + level2, blk2ptr->h[level2].buffaddr, rec_base); blk2_ances_remain = rec_base + rec_size - SIZEOF(block_id); if (cdb_sc_starrecord == status) blk2_ances_star_only = TRUE; @@ -458,26 +465,13 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s new_blk2_ances_first_keysz = tkeylen + tkeycmpc; BLK_ADDR(blk2_ances_hdr, SIZEOF(rec_hdr), rec_hdr); /* new 1st record's header */ blk2_ances_hdr->rsiz = new_blk2_ances_first_keysz + BSTAR_REC_SIZE; - blk2_ances_hdr->cmpc = 0 ; + SET_CMPC(blk2_ances_hdr, 0); } break; } } /* end for level2 */ } /* end if/else complete_merge */ - /* for following case newblk1_last_key is the 2nd last key. old_levelp_cur_next_key can be taken as last key */ - /* - if (delete_all_blk2_ances && complete_merge && !levelp_next_is_star) - { - GET_CMPC(newblk1_last_cmpc, newblk1_last_key, &old_levelp_cur_next_key[0]); - newblk1_last_keysz = old_levelp_cur_next_keysz; - newblk1_last_keylen = newblk1_last_keysz - newblk1_last_cmpc; - newblk1_last_key = old_levelp_cur_next_key; - } - */ - /* else if (delete_all_blk2_ances && complete_merge && levelp_next_is_star), - we do not need newblk1_last_key's real value */ - /* new_levelp_cur_hdr = new ancestor level curr_key header new_levelp_cur_keylen = new ancestor level curr_key length @@ -492,7 +486,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s new_levelp_cur_keylen = newblk1_last_keysz; } else /* If the previous record exists */ { - GET_CMPC(new_levelp_cur_cmpc, &old_levelp_cur_prev_key[0], newblk1_last_key); + GET_CMPC(new_levelp_cur_cmpc, old_levelp_cur_prev_key, newblk1_last_key); new_levelp_cur_keylen = newblk1_last_keysz - new_levelp_cur_cmpc; } /* @@ -501,7 +495,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s */ BLK_ADDR(new_levelp_cur_hdr, SIZEOF(rec_hdr), rec_hdr); new_levelp_cur_hdr->rsiz = BSTAR_REC_SIZE + new_levelp_cur_keylen; - new_levelp_cur_hdr->cmpc = new_levelp_cur_cmpc; + SET_CMPC(new_levelp_cur_hdr, new_levelp_cur_cmpc); } /* else old_levelp_cur_key will be deleted */ @@ -529,7 +523,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s new_levelp_cur_next_keylen = old_levelp_cur_next_keysz; } else /* If the previous record exists */ { - GET_CMPC(new_levelp_cur_next_cmpc, &old_levelp_cur_prev_key[0], old_levelp_cur_next_key); + GET_CMPC(new_levelp_cur_next_cmpc, old_levelp_cur_prev_key, old_levelp_cur_next_key); new_levelp_cur_next_keylen = old_levelp_cur_next_keysz - new_levelp_cur_next_cmpc; } } @@ -539,7 +533,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s */ BLK_ADDR(new_levelp_cur_next_hdr, SIZEOF(rec_hdr), rec_hdr); new_levelp_cur_next_hdr->rsiz = BSTAR_REC_SIZE + new_levelp_cur_next_keylen; - new_levelp_cur_next_hdr->cmpc = new_levelp_cur_next_cmpc; + SET_CMPC(new_levelp_cur_next_hdr, new_levelp_cur_next_cmpc); } else { if (!complete_merge || !delete_all_blk2_ances) @@ -552,7 +546,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s BLK_ADDR(star_rec_hdr, SIZEOF(rec_hdr), rec_hdr); star_rec_hdr->rsiz = BSTAR_REC_SIZE; - star_rec_hdr->cmpc = 0; + SET_CMPC(star_rec_hdr, 0); /* ------------------------ * Working block's t_write * ------------------------ diff --git a/sr_port/mu_extr_gblout.c b/sr_port/mu_extr_gblout.c index e8cdc46..a765db9 100644 --- a/sr_port/mu_extr_gblout.c +++ b/sr_port/mu_extr_gblout.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,11 +43,12 @@ #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif +#include "gvcst_protos.h" -#define INTEG_ERROR_RETURN \ -{ \ - gtm_putmsg(VARLSTCNT(4) ERR_EXTRFAIL, 2, gn->str.len, gn->str.addr); \ - return FALSE; \ +#define INTEG_ERROR_RETURN \ +{ \ + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_EXTRFAIL, 2, gn->str.len, gn->str.addr); \ + return FALSE; \ } GBLREF bool mu_ctrlc_occurred; @@ -62,8 +63,6 @@ GBLREF sgmnt_data_ptr_t cs_data; error_def(ERR_EXTRFAIL); error_def(ERR_RECORDSTAT); -STATICDEF readonly unsigned char gt_lit[] = "TOTAL"; - #if defined(UNIX) && defined(GTM_CRYPT) boolean_t mu_extr_gblout(mval *gn, mu_extr_stats *st, int format, muext_hash_hdr_ptr_t hash_array, boolean_t is_any_file_encrypted) @@ -75,26 +74,30 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo #error UNSUPPORTED PLATFORM #endif { - blk_hdr_ptr_t bp; - boolean_t beg_key; - int data_len, des_len, fmtd_key_len, gname_size; - rec_hdr_ptr_t rp, save_rp; - sm_uc_ptr_t blktop, cp1, rectop; - unsigned char *cp2, current, *keytop, last; - unsigned short out_size, rec_size; - static gv_key *beg_gv_currkey; /* this is used to check key out of order condition */ - static int max_zwr_len = 0; - static unsigned char *private_blk = NULL, *zwr_buffer = NULL, *key_buffer = NULL; - static uint4 private_blksz = 0; + blk_hdr_ptr_t bp; + boolean_t beg_key; + int data_len, des_len, fmtd_key_len, gname_size; + int tmp_cmpc; + rec_hdr_ptr_t rp, save_rp; + sm_uc_ptr_t blktop, cp1, rectop; + unsigned char *cp2, current, *keytop, last; + unsigned short out_size, rec_size; + static gv_key *beg_gv_currkey; /* this is used to check key out of order condition */ + static int max_zwr_len = 0; + static unsigned char *private_blk = NULL, *zwr_buffer = NULL, *key_buffer = NULL; + static uint4 private_blksz = 0; + mval *val_span = NULL; + boolean_t is_hidden, found_dummy = FALSE; # ifdef GTM_CRYPT - char *inbuf; + char *in, *out; gd_region *reg, *reg_top; - int crypt_status, init_status; + int gtmcrypt_errno; static gtmcrypt_key_t encr_key_handle; static int4 index, prev_allocated_size; static sgmnt_data_ptr_t prev_csd; static unsigned char *unencrypted_blk_buff; + gd_segment *seg; # endif op_gvname(VARLSTCNT(1) gn); /* op_gvname() must be done before any usage of cs_addrs or, gv_currkey */ @@ -126,24 +129,22 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo # ifdef GTM_CRYPT if (is_any_file_encrypted && (cs_data->is_encrypted) && (format == MU_FMT_BINARY)) { - INIT_PROC_ENCRYPTION(init_status); - if (0 != init_status) - { - GC_GTM_PUTMSG(init_status, gv_cur_region->dyn.addr->fname); - return FALSE; - } + ASSERT_ENCRYPTION_INITIALIZED; /* due to op_gvname done from gv_select in mu_extract */ if (prev_csd != cs_data) { prev_csd = cs_data; for (reg = gd_header->regions, reg_top = reg + gd_header->n_regions, index = 0; reg < reg_top; reg++, index++) + { if (gv_cur_region == reg) break; + } assert(gv_cur_region < reg_top); - GTMCRYPT_GETKEY(hash_array[index].gtmcrypt_hash, encr_key_handle, crypt_status); - if (0 != crypt_status) + GTMCRYPT_GETKEY(cs_addrs, hash_array[index].gtmcrypt_hash, encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(init_status, gv_cur_region->dyn.addr->fname); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); return FALSE; } } @@ -155,7 +156,7 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo return FALSE; if (mu_ctrlc_occurred) { - gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT(gt_lit), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT("TOTAL"), st->recknt, st->keylen, st->datalen, st->reclen); mu_ctrlc_occurred = FALSE; } @@ -177,28 +178,26 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo # ifdef GTM_CRYPT if (is_any_file_encrypted) { - /* Note that we are only encrypting data blocks */ if (cs_data->is_encrypted) { - inbuf = (char *)(rp); - + in = (char *)(rp); *(int4 *)(cs_addrs->encrypted_blk_contents) = index; - GTMCRYPT_ENCODE_FAST(encr_key_handle, - inbuf, - out_size, - cs_addrs->encrypted_blk_contents + SIZEOF(int4), - crypt_status); - if (0 != crypt_status) + out = cs_addrs->encrypted_blk_contents + SIZEOF(int4); + GTMCRYPT_ENCRYPT(cs_addrs, encr_key_handle, in, out_size, out, gtmcrypt_errno) + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, gv_cur_region->dyn.addr->fname); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); return FALSE; } + rp = (rec_hdr_ptr_t)cs_addrs->encrypted_blk_contents; } else - { - /* If we extract from a mix of encrypted and unencrypted databases, for the unencrypted - * databases, cs_addrs->encrypted_blk_contents will not be initialized in db_init. Hence - * we use a static buffer for this purpose. */ - if (NULL == unencrypted_blk_buff || (prev_allocated_size < out_size)) + { /* For unencrypted database, we cannot use cs_addrs->encrypted_blk_contents. Instead, use + * a static malloc'ed buffer. The malloc is needed because the buffer that's written out + * to the extract file is prefixed with an int4 indicating the ith database that this block + * corresponds to and -1 (if the database is unencrypted). + */ + if ((NULL == unencrypted_blk_buff) || (prev_allocated_size < out_size)) { if (NULL != unencrypted_blk_buff) free(unencrypted_blk_buff); @@ -207,9 +206,8 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo } *(int4 *)(unencrypted_blk_buff) = -1; memcpy(unencrypted_blk_buff + (SIZEOF(int4)), rp, out_size); + rp = (rec_hdr_ptr_t)unencrypted_blk_buff; } - rp = (cs_data->is_encrypted) ? (rec_hdr_ptr_t)cs_addrs->encrypted_blk_contents - : (rec_hdr_ptr_t)unencrypted_blk_buff; out_size += SIZEOF(int4); } # endif @@ -220,11 +218,12 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo { /* Start scanning a block */ GET_USHORT(rec_size, &rp->rsiz); rectop = (sm_uc_ptr_t)rp + rec_size; - if (rectop > blktop || rp->cmpc > gv_currkey->end || - (((unsigned char *)rp != private_blk + SIZEOF(blk_hdr)) && rp->cmpc < gname_size)) + EVAL_CMPC2(rp, tmp_cmpc); + if (rectop > blktop || tmp_cmpc > gv_currkey->end || + (((unsigned char *)rp != private_blk + SIZEOF(blk_hdr)) && (tmp_cmpc < gname_size))) INTEG_ERROR_RETURN cp1 = (sm_uc_ptr_t)(rp + 1); - cp2 = gv_currkey->base + rp->cmpc; + cp2 = gv_currkey->base + tmp_cmpc; if (cp2 >= keytop || cp1 >= rectop) INTEG_ERROR_RETURN if (!beg_key && (*cp2 >= *cp1)) @@ -249,9 +248,14 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo memcpy(beg_gv_currkey->base, gv_currkey->base, gv_currkey->end + 1); beg_gv_currkey->end = gv_currkey->end; } - st->recknt++; if (st->reclen < rec_size) st->reclen = rec_size; +# ifdef UNIX + CHECK_HIDDEN_SUBSCRIPT(gv_currkey, is_hidden); + if (is_hidden) + continue; +# endif + st->recknt++; if (st->keylen < gv_currkey->end + 1) st->keylen = gv_currkey->end + 1; data_len = (int)(rec_size - (cp1 - (sm_uc_ptr_t)rp)); @@ -259,6 +263,22 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo INTEG_ERROR_RETURN if (st->datalen < data_len) st->datalen = data_len; +# ifdef UNIX + if ((1 == data_len) && ('\0' == *cp1)) + { /* Possibly (probably) a spanning node. Need to read in more blocks to get the value */ + if (!val_span) + { /* protect val_span from stp_gcol in WRITE_EXTR_LINE/op_write */ + PUSH_MV_STENT(MVST_MVAL); + val_span = &mv_chain->mv_st_cont.mvs_mval; + } + gvcst_get(val_span); + cp1 = (unsigned char *)val_span->str.addr; + data_len = val_span->str.len; + found_dummy = TRUE; + if (st->datalen < data_len) + st->datalen = data_len; + } +# endif if (MU_FMT_BINARY != format) { cp2 = (unsigned char *)format_targ_key(key_buffer, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); @@ -277,6 +297,13 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo WRITE_EXTR_LINE(cp1, data_len); } } +# ifdef UNIX + if (found_dummy) + { + val_span->mvtype = 0; /* so stp_gcol can free up any space */ + found_dummy = FALSE; + } +# endif } /* End scanning a block */ if ((sm_uc_ptr_t)rp != blktop || (memcmp(gv_currkey->base, beg_gv_currkey->base, MIN(gv_currkey->end, beg_gv_currkey->end)) < 0)) diff --git a/sr_port/mu_extr_getblk.c b/sr_port/mu_extr_getblk.c index bcff87f..162bcd0 100644 --- a/sr_port/mu_extr_getblk.c +++ b/sr_port/mu_extr_getblk.c @@ -52,7 +52,9 @@ int mu_extr_getblk(unsigned char *ptr) DEBUG_ONLY(unsigned int lcl_t_tries;) boolean_t tn_aborted; # endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(0 != gv_target->root); t_begin(ERR_GVGETFAIL, 0); for (;;) diff --git a/sr_port/mu_gv_stack_init.c b/sr_port/mu_gv_stack_init.c index 6203d54..931e22f 100644 --- a/sr_port/mu_gv_stack_init.c +++ b/sr_port/mu_gv_stack_init.c @@ -20,7 +20,7 @@ #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "mu_gv_stack_init.h" diff --git a/sr_port/mu_int_blk.c b/sr_port/mu_int_blk.c index be0940d..29e7c8b 100644 --- a/sr_port/mu_int_blk.c +++ b/sr_port/mu_int_blk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,7 +31,7 @@ #include "gtmmsg.h" #include "get_spec.h" #ifdef GTM_TRIGGER -#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ +#include /* for rtn_tabent in gv_trigger.h */ #include "gv_trigger.h" #endif @@ -41,6 +41,11 @@ #define MIN_DATA (3 * SIZEOF(char)) /* a non-empty data block rec must have at least one character of key and two of terminator */ #define TEXT2 "Block " #define TEXT3 " doubly allocated" +#define SPAN_SUBS_LENGTH 5 +#define SPAN_START_BYTE 0x02 +#define SPAN_BYTE_MAX 255 +#define SPAN_BYTE_MIN 1 +#define SPAN_SUBS_OFF 48 GBLDEF unsigned char muint_temp_buff[MAX_MIDENT_LEN + 1]; GBLREF unsigned char *mu_int_locals; @@ -75,6 +80,41 @@ GBLREF gv_key *muint_end_key; GBLREF gv_key *muint_start_key; GBLREF sgmnt_data mu_int_data; GBLREF trans_num largest_tn; +GBLREF span_node_integ *sndata; + +error_def(ERR_DBBADKYNM); +error_def(ERR_DBBADNSUB); +error_def(ERR_DBBADPNTR); +error_def(ERR_DBBDBALLOC); +error_def(ERR_DBBNPNTR); +error_def(ERR_DBBSIZMN); +error_def(ERR_DBBSIZMX); +error_def(ERR_DBCMPBAD); +error_def(ERR_DBCMPNZRO); +error_def(ERR_DBCOMPTOOLRG); +error_def(ERR_DBGTDBMAX); +error_def(ERR_DBINCLVL); +error_def(ERR_DBINVGBL); +error_def(ERR_DBKEYGTIND); +error_def(ERR_DBKEYMN); +error_def(ERR_DBKEYMX); +error_def(ERR_DBKEYORD); +error_def(ERR_DBKGTALLW); +error_def(ERR_DBLRCINVSZ); +error_def(ERR_DBLTSIBL); +error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */ +error_def(ERR_DBPTRMX); +error_def(ERR_DBPTRNOTPOS); +error_def(ERR_DBRLEVTOOHI); +error_def(ERR_DBRLEVLTONE); +error_def(ERR_DBSTARCMP); +error_def(ERR_DBRSIZMN); +error_def(ERR_DBRSIZMX); +error_def(ERR_DBDATAMX); +error_def(ERR_DBTN); +error_def(ERR_DBTNTOOLG); +error_def(ERR_DBSPANGLOINCMP); +error_def(ERR_DBSPANCHUNKORD); LITDEF boolean_t mu_int_possub[16][16] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, @@ -143,50 +183,23 @@ boolean_t mu_int_blk( } sub_list; unsigned char buff[MAX_KEY_SZ + 1], old_buff[MAX_KEY_SZ + 1], temp_buff[MAX_MIDENT_LEN + 1], util_buff[MAX_UTIL_SIZE]; - unsigned char blk_levl, *c1, cc, ch, rec_cmpc; - uchar_ptr_t c0, c2, c_base, blk_base, blk_top, key_base, ptr, rec_base, rec_top; + unsigned char blk_levl, *c1, ch, *ctrlbytes; + unsigned short cc, rec_cmpc; + uchar_ptr_t c0, c2, c_base, blk_base, blk_top, key_base, ptr, rec_base, rec_top, span_key; unsigned short temp_ushort; boolean_t first_key, is_top, pstar, valid_gbl, hasht_global; boolean_t muint_range_done = FALSE; int blk_size, buff_length, b_index, cmcc, comp_length, key_size, len, name_len, num_len, rec_size, s_index, start_index, hdr_len, idx; + int tmp_cmpc, tmp_numsubs, max_allowed_key_size; block_id child, root_pointer; sub_list mu_sub_list[MAX_GVSUBSCRIPTS + 1]; sub_num check_vals; trans_num blk_tn; uchar_ptr_t subrec_ptr; enum db_ver ondsk_blkver; - - error_def(ERR_DBBDBALLOC); - error_def(ERR_DBBSIZMN); - error_def(ERR_DBBSIZMX); - error_def(ERR_DBRLEVTOOHI); - error_def(ERR_DBRLEVLTONE); - error_def(ERR_DBINCLVL); - error_def(ERR_DBTNTOOLG); - error_def(ERR_DBRSIZMN); - error_def(ERR_DBRSIZMX); - error_def(ERR_DBLRCINVSZ); - error_def(ERR_DBSTARCMP); - error_def(ERR_DBCMPNZRO); - error_def(ERR_DBINVGBL); - error_def(ERR_DBCOMPTOOLRG); - error_def(ERR_DBBADKYNM); - error_def(ERR_DBKEYMX); - error_def(ERR_DBKEYMN); - error_def(ERR_DBKGTALLW); - error_def(ERR_DBGTDBMAX); - error_def(ERR_DBCMPBAD); - error_def(ERR_DBKEYORD); - error_def(ERR_DBLTSIBL); - error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */ - error_def(ERR_DBBADNSUB); - error_def(ERR_DBPTRNOTPOS); - error_def(ERR_DBPTRMX); - error_def(ERR_DBBNPNTR); - error_def(ERR_DBBADPNTR); - error_def(ERR_DBKEYGTIND); - error_def(ERR_DBTN); + uint4 cnt, span_curr_blk, rval_len, gblsize; + unsigned short numsubs; mu_int_offset[mu_int_plen] = 0; mu_int_path[mu_int_plen++] = blk; @@ -196,7 +209,7 @@ boolean_t mu_int_blk( mu_int_err(ERR_DBBDBALLOC, TRUE, TRUE, bot_key, bot_len, top_key, top_len, (unsigned int)(level)); return FALSE; } - blk_base = mu_int_read(blk, &ondsk_blkver); /* ondsk_blkver set to GDSV4 or GDSV5 (GDSVCURR) */ + blk_base = mu_int_read(blk, &ondsk_blkver); /* ondsk_blkver set to GDSV4 or GDSV6 (GDSVCURR) */ if (!blk_base) return FALSE; blk_size = (int)((blk_hdr_ptr_t)blk_base)->bsiz; @@ -274,6 +287,15 @@ boolean_t mu_int_blk( mu_int_errknt++; trans_errors++; } + /* Stop searching the sub-tree when TN in block is larger than integ_start_tn for fast_integ. The reason being, + * fast_integ skips writing free blocks and level-0 block in GV tree to snapshot file. However, some blocks can be + * mistakenly marked free or its level is messed-up as 0. After updating these blocks, thse blocks will have TN + * larger than integ_start_tn. In this case, the child tree pointed to by one such updated block may result in + * arbitrary error report. Since we already capture the core reason for the integ error, we should not proceed + * searching its child tree; otherwise, we will have meaningless report content + */ + if (muint_fast) + return FALSE; if (blk_tn > largest_tn) largest_tn = blk_tn; } @@ -300,14 +322,14 @@ boolean_t mu_int_blk( free(blk_base); return FALSE; } - if (rec_size > blk_top - rec_base) + if ((rec_size > blk_top - rec_base)) { mu_int_err(ERR_DBRSIZMX, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl); free(blk_base); return FALSE; } rec_top = rec_base + rec_size; - rec_cmpc = ((rec_hdr_ptr_t)rec_base)->cmpc; + rec_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base); if (level && (rec_top == blk_top)) { is_top = TRUE; @@ -399,27 +421,13 @@ boolean_t mu_int_blk( free(blk_base); return FALSE; } - if (key_size > MAX_KEY_SZ) - { + if (key_size + rec_cmpc > MAX_KEY_SZ) + { /* We'll allow index keys to be whatever length, so long as they don't exceed MAX_KEY_SZ */ mu_int_err(ERR_DBKGTALLW, TRUE, TRUE, buff, comp_length, top_key, top_len, (unsigned int)blk_levl); free(blk_base); return FALSE; } - if (key_size > mu_int_data.max_key_size) - { - if (maxkey_errors < disp_maxkey_errors) - { - mu_int_err(ERR_DBGTDBMAX, TRUE, FALSE, buff, comp_length, top_key, - top_len, (unsigned int)blk_levl); - mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */ - maxkey_errors++; - } else - { - mu_int_errknt++; - maxkey_errors++; - } - } if ((short int)rec_cmpc < buff_length && buff[rec_cmpc] == *key_base) { mu_int_err(ERR_DBCMPBAD, TRUE, TRUE, buff, comp_length, top_key, top_len, @@ -618,6 +626,159 @@ boolean_t mu_int_blk( } } } + if (!level && !master_dir) + { + rval_len = rec_size - SIZEOF(rec_hdr) - key_size; + if (mu_int_data.max_rec_size < rval_len) + { + mu_int_err(ERR_DBDATAMX, TRUE, TRUE, buff, comp_length, + top_key, top_len, (unsigned int)blk_levl); + free(blk_base); + return FALSE; + } + span_key = buff + buff_length - SPAN_SUBS_LENGTH - 1; + max_allowed_key_size = mu_int_data.max_key_size; + if ((SPAN_SUBS_LENGTH < key_size + rec_cmpc) && (KEY_DELIMITER == *span_key++) + && (SPAN_START_BYTE == *span_key)) + { /* Hidden subscript detected */ + max_allowed_key_size += 4; + if (0 == (span_curr_blk = SPAN_GVSUBS2INT((span_subs *)span_key))) + { /* First record of spanning node. Get the number blocks. */ + ctrlbytes = key_base + key_size; + if (rec_top - ctrlbytes == 6) + { + GET_NSBCTRL(ctrlbytes, numsubs, gblsize); + } else + { + SSCANF((char *)ctrlbytes, "%d,%d", &tmp_numsubs, &gblsize); + numsubs = tmp_numsubs; + } + sndata->span_tot_blks = numsubs + 1; + sndata->span_node_sz = gblsize; + sndata->val_len = 0; + sndata->sn_type = SPAN_NODE; + sndata->span_prev_blk = 0; + sndata->span_blk_cnt = 1; + sndata->key_len = buff_length; + sndata->sn_cnt += 1; + memcpy(sndata->span_node_buf, buff, buff_length); + } else + { + switch (sndata->sn_type) + { + case SN_NOT: /*First block of the node-fragment*/ + sndata->sn_type = SN_CHUNK; + sndata->span_prev_blk = span_curr_blk; + sndata->span_blk_cnt = 1; + sndata->span_frag_off = span_curr_blk; + sndata->key_len = buff_length; + /*Spanning node can never have 0 rval*/ + sndata->span_node_sz = 0; + sndata->val_len = 0; + sndata->sn_cnt += 1; + memcpy(sndata->span_node_buf, buff, buff_length); + break; + case SPAN_NODE: /* Already in the spanning node */ + if((sndata->span_prev_blk + 1) == span_curr_blk) + { /*Logical continuity of block is present*/ + sndata->span_prev_blk = span_curr_blk; + sndata->span_blk_cnt = sndata->span_blk_cnt + 1; + sndata->val_len += rval_len; + if(sndata->span_blk_cnt == sndata->span_tot_blks) + { /* All the blocks of the spanning node are seen */ + sndata->sn_type = SN_NOT; + sndata->sn_blk_cnt += sndata->span_blk_cnt; + } + if (sndata->val_len > sndata->span_node_sz) + { + mu_int_err(ERR_DBDATAMX, TRUE, TRUE, + sndata->span_node_buf, + sndata->key_len, top_key, + top_len, + (unsigned int)blk_levl); + free(blk_base); + return FALSE; + } + } + else { /* ERROR 1: There is discontinuity in the spanning node + * blocks; adjacent spanning block is missing + */ + mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE, + sndata->span_node_buf, + sndata->key_len, top_key, + top_len, (unsigned int)blk_levl); + sndata->sn_type = SN_NOT; + sndata->sn_blk_cnt += sndata->span_blk_cnt; + /* continuing, so compensate for mu_int_err decrement */ + mu_int_plen++; + maxkey_errors++; + } + break; + case SN_CHUNK: /* Already in the spanning node fragment */ + if((sndata->span_prev_blk + 1) == span_curr_blk) + { /*Logical continuity of block is present*/ + sndata->span_prev_blk = span_curr_blk; + sndata->span_blk_cnt = sndata->span_blk_cnt + 1; + } + else { /* ERROR 2: Unexpected spanning-node-block occurred in + * the middle of spanning-node fragment + */ + mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE, + sndata->span_node_buf, + sndata->key_len, top_key, + top_len, (unsigned int)blk_levl); + sndata->sn_type = SN_CHUNK; + sndata->span_prev_blk = span_curr_blk; + sndata->span_blk_cnt = 1; + sndata->span_frag_off = span_curr_blk; + sndata->key_len = buff_length; + memcpy(sndata->span_node_buf, buff, buff_length); + sndata->sn_blk_cnt += sndata->span_blk_cnt; + /* continuing, so compensate for mu_int_err decrement */ + mu_int_plen++; + maxkey_errors++; + } + break; + } + } + } else if (sndata->sn_type) + { + if (SPAN_NODE == sndata->sn_type) /*INCOMPLETE SPANNING NODE*/ + { /* ERROR 1: There is discontinuity in the spanning node blocks; + * adjacent spanning block is missing + */ + mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE, + sndata->span_node_buf, sndata->key_len, top_key, + top_len, (unsigned int)blk_levl); + } else /*INCOMPLETE SPANNING NODE FRAGMENT*/ + { /* ERROR 2: Spanning-node-block occurred in the middle + * of non-spanning block + */ + mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE, + sndata->span_node_buf, sndata->key_len, top_key, + top_len, (unsigned int)blk_levl); + } + sndata->sn_blk_cnt += sndata->span_blk_cnt; + /* continuing, so compensate for mu_int_err decrement */ + mu_int_plen++; + maxkey_errors++; + sndata->sn_type = SN_NOT; + } + if (key_size + rec_cmpc > max_allowed_key_size) + { + if (maxkey_errors < disp_maxkey_errors) + { + mu_int_err(ERR_DBGTDBMAX, TRUE, FALSE, buff, comp_length, top_key, + top_len, (unsigned int)blk_levl); + mu_int_plen++; /* continuing, so compensate for mu_int_err decrement */ + maxkey_errors++; + } else + { + mu_int_errknt++; + maxkey_errors++; + } + } + } } if (level) { diff --git a/sr_port/mu_int_err.c b/sr_port/mu_int_err.c index bec9177..5b2d4bd 100644 --- a/sr_port/mu_int_err.c +++ b/sr_port/mu_int_err.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ GBLREF uint4 mu_int_errknt; GBLREF boolean_t mu_int_err_ranges; GBLREF boolean_t master_dir; GBLREF global_list *trees; +GBLREF span_node_integ *sndata; #define MAX_UTIL_LEN 40 #define BLOCK_WINDOW 8 @@ -61,26 +62,31 @@ void mu_int_err( { int i, util_len; unsigned char util_buff[MAX_UTIL_LEN]; + unsigned char span_key[MAX_KEY_SZ + 1]; if (!mu_int_errknt) util_out_print("!/Block:Offset Level", TRUE); mu_int_errknt++; mu_int_plen--; util_len=0; - memcpy(&util_buff[util_len], NEWLINE, SIZEOF(NEWLINE) - 1); + MEMCPY_LIT(&util_buff[util_len], NEWLINE); util_len += SIZEOF(NEWLINE) - 1; i2hex_blkfill(mu_int_path[mu_int_plen], &util_buff[util_len], BLOCK_WINDOW); util_len += BLOCK_WINDOW; - memcpy(&util_buff[util_len], TEXT1, SIZEOF(TEXT1) - 1); /* OFFSET_WINDOW + 1 spaces */ + MEMCPY_LIT(&util_buff[util_len], TEXT1); /* OFFSET_WINDOW + 1 spaces */ util_len += SIZEOF(TEXT3) - 1; /* Using TEXT1 to clear space? */ i2hex_nofill(mu_int_offset[mu_int_plen], (uchar_ptr_t)&util_buff[util_len], OFFSET_WINDOW); util_len += OFFSET_WINDOW + 1; i2hex_blkfill(level, (uchar_ptr_t)&util_buff[util_len], LEVEL_WINDOW); util_len += LEVEL_WINDOW; - memcpy(&util_buff[util_len], TEXT2, SIZEOF(TEXT2) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT2); util_len += SIZEOF(TEXT2) - 1; util_buff[util_len] = 0; - gtm_putmsg(VARLSTCNT(4) err, 2, LEN_AND_STR((char*)util_buff)); + if(sndata->sn_type) + gtm_putmsg(VARLSTCNT(5) err, 3, LEN_AND_STR((char*)util_buff), + (SPAN_NODE == sndata->sn_type) ? (sndata->span_prev_blk + 2) : (sndata->span_blk_cnt)); + else + gtm_putmsg(VARLSTCNT(4) err, 2, LEN_AND_STR((char*)util_buff)); if (do_path) { if (!master_dir) @@ -89,16 +95,16 @@ void mu_int_err( for (i = 0; trees->path[i + 1]; i++) { util_len = i2hex_nofill(trees->path[i], (uchar_ptr_t)util_buff, BLOCK_WINDOW); - memcpy(&util_buff[util_len], TEXT3, SIZEOF(TEXT3) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT3); util_len += SIZEOF(TEXT3) - 1; util_len += i2hex_nofill(trees->offset[i], (uchar_ptr_t)&util_buff[util_len], OFFSET_WINDOW); - memcpy(&util_buff[util_len], TEXT4, SIZEOF(TEXT4) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT4); util_len += SIZEOF(TEXT4) - 1; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, FALSE); } util_len = i2hex_nofill(trees->path[i], (uchar_ptr_t)util_buff, BLOCK_WINDOW); - memcpy(&util_buff[util_len], TEXT3, SIZEOF(TEXT3) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT3); util_len += SIZEOF(TEXT3) - 1; util_len += i2hex_nofill(trees->offset[i], (uchar_ptr_t)&util_buff[util_len], OFFSET_WINDOW); util_buff[util_len] = 0; @@ -109,16 +115,16 @@ void mu_int_err( for (i = 0; i < mu_int_plen; i++) { util_len = i2hex_nofill(mu_int_path[i], (uchar_ptr_t)util_buff, BLOCK_WINDOW); - memcpy(&util_buff[util_len], TEXT3, SIZEOF(TEXT3) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT3); util_len += SIZEOF(TEXT3) - 1; util_len += i2hex_nofill(mu_int_offset[i], (uchar_ptr_t)&util_buff[util_len], OFFSET_WINDOW); - memcpy(&util_buff[util_len], TEXT4, SIZEOF(TEXT4) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT4); util_len += SIZEOF(TEXT4) - 1; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, FALSE); } util_len = i2hex_nofill(mu_int_path[i], (uchar_ptr_t)util_buff, BLOCK_WINDOW); - memcpy(&util_buff[util_len], TEXT3, SIZEOF(TEXT3) - 1); + MEMCPY_LIT(&util_buff[util_len], TEXT3); util_len += SIZEOF(TEXT3) - 1; util_len += i2hex_nofill(mu_int_offset[i], (uchar_ptr_t)&util_buff[util_len], OFFSET_WINDOW); util_buff[util_len] = 0; @@ -148,5 +154,19 @@ void mu_int_err( util_out_print("the end", FALSE); util_out_print(" are suspect.", TRUE); } + if (!level && sndata->sn_type) + { + if (1 == sndata->sn_type) + util_out_print("Spanning Node ^", FALSE); + else + util_out_print("Spanning Node Chunk ^", FALSE); + /* in the case bot is the leftmost key of the gvtree, it needs a second null to be a properly terminated + * real key for print_target. since it is a simple set, we unconditionally do it for every key + */ + sndata->span_node_buf[sndata->key_len] = 0; + sndata->span_node_buf[sndata->key_len+1] = 0; + print_target(sndata->span_node_buf); + util_out_print(" is suspect.", TRUE); + } return; } diff --git a/sr_port/mu_int_fhead.c b/sr_port/mu_int_fhead.c index c727d63..f5135c7 100644 --- a/sr_port/mu_int_fhead.c +++ b/sr_port/mu_int_fhead.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,13 +30,14 @@ #include "db_snapshot.h" #endif -GBLDEF unsigned char *mu_int_locals; -GBLDEF int4 mu_int_ovrhd; +GBLDEF unsigned char *mu_int_locals; +GBLDEF int4 mu_int_ovrhd; -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_data mu_int_data; -GBLREF uint4 mu_int_errknt; -GBLREF boolean_t tn_reset_specified; +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_data mu_int_data; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF uint4 mu_int_errknt; +GBLREF boolean_t tn_reset_specified; error_def(ERR_DBNOTDB); error_def(ERR_DBINCRVER); @@ -53,7 +54,6 @@ error_def(ERR_DBTTLBLK0); error_def(ERR_DBTNNEQ); error_def(ERR_DBMAXKEYEXC); error_def(ERR_DBMXRSEXCMIN); -error_def(ERR_DBMAXRSEXBL); error_def(ERR_DBUNDACCMT); error_def(ERR_DBHEADINV); error_def(ERR_DBFGTBC); @@ -65,7 +65,7 @@ error_def(ERR_MUKILLIP); error_def(ERR_MUTNWARN); #ifdef GTM_SNAPSHOT -# define GET_NATIVE_SIZE(native_size) \ +# define SET_NATIVE_SIZE(native_size) \ { \ GBLREF util_snapshot_ptr_t util_ss_ptr; \ GBLREF boolean_t ointeg_this_reg; \ @@ -75,19 +75,22 @@ error_def(ERR_MUTNWARN); native_size = util_ss_ptr->native_size; \ assert(0 != native_size); /* Ensure native_size is updated properly in ss_initiate */ \ } else \ - native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); \ + native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); \ } #else -# define GET_NATIVE_SIZE(native_size) \ - native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); +# define SET_NATIVE_SIZE(native_size) native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); #endif boolean_t mu_int_fhead(void) { - unsigned char *p1; - unsigned int maps, native_size, size, block_factor; - trans_num temp_tn, max_tn_warn; - sgmnt_data_ptr_t mu_data; - GTMCRYPT_ONLY(int crypt_status;) + unsigned char *p1; + unsigned int maps, block_factor; + gtm_uint64_t size, native_size; + trans_num temp_tn, max_tn_warn; + sgmnt_data_ptr_t mu_data; +# ifdef GTM_CRYPT + gd_segment *seg; + int gtmcrypt_errno; +# endif mu_data = &mu_int_data; if (MEMCMP_LIT(mu_data->label, GDS_LABEL)) @@ -98,7 +101,7 @@ boolean_t mu_int_fhead(void) mu_int_err(ERR_DBINCRVER, 0, 0, 0, 0, 0, 0, 0); return FALSE; } - UNIX_ONLY(CHECK_DB_ENDIAN(mu_data, gv_cur_region->dyn.addr->fname_len, gv_cur_region->dyn.addr->fname)); /* bypass ok */ + UNIX_ONLY(CHECK_DB_ENDIAN(mu_data, gv_cur_region->dyn.addr->fname_len, gv_cur_region->dyn.addr->fname)); /* BYPASSOK */ if (mu_data->start_vbn < DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data), DISK_BLOCK_SIZE)) { mu_int_err(ERR_DBSVBNMIN, 0, 0, 0, 0, 0, 0, 0); @@ -165,19 +168,14 @@ boolean_t mu_int_fhead(void) } if (MAX_KEY_SZ < mu_data->max_key_size) mu_int_err(ERR_DBMAXKEYEXC, 0, 0, 0, 0, 0, 0, 0); - if (SIZEOF(rec_hdr) + SIZEOF(block_id) >= mu_data->max_rec_size) - mu_int_err(ERR_DBMXRSEXCMIN, 0, 0, 0, 0, 0, 0, 0); - if (mu_data->blk_size - SIZEOF(blk_hdr) < mu_data->max_rec_size) - mu_int_err(ERR_DBMAXRSEXBL, 0, 0, 0, 0, 0, 0, 0); # ifdef GTM_CRYPT if (mu_data->is_encrypted) { - /* Encryption init should have happened in db_init. */ - ASSERT_ENCRYPTION_INITIALIZED; - GTMCRYPT_HASH_CHK(mu_data->encryption_hash, crypt_status); - if (0 != crypt_status) + GTMCRYPT_HASH_CHK(cs_addrs, mu_data->encryption_hash, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, (gv_cur_region->dyn.addr->fname)); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); return FALSE; } } @@ -204,8 +202,8 @@ boolean_t mu_int_fhead(void) default: mu_int_err(ERR_DBUNDACCMT, 0, 0, 0, 0, 0, 0, 0); /*** WARNING: Drop thru ***/ -#ifdef VMS -#ifdef GT_CX_DEF +# ifdef VMS +# ifdef GT_CX_DEF case dba_bg: /* necessary to do calculation in this manner to prevent double rounding causing an error */ if (mu_data->unbacked_cache) mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space + @@ -217,22 +215,22 @@ boolean_t mu_int_fhead(void) case dba_mm: mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; -#else +# else case dba_bg: /*** WARNING: Drop thru ***/ case dba_mm: mu_int_ovrhd = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); break; -#endif +# endif -#elif defined(UNIX) +# elif defined(UNIX) case dba_bg: /*** WARNING: Drop thru ***/ case dba_mm: mu_int_ovrhd = (int4)DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(mu_data) + mu_data->free_space, DISK_BLOCK_SIZE); -#else -#error unsupported platform -#endif +# else +# error unsupported platform +# endif } assert(mu_data->blk_size == ROUND_UP(mu_data->blk_size, DISK_BLOCK_SIZE)); block_factor = mu_data->blk_size / DISK_BLOCK_SIZE; @@ -242,9 +240,9 @@ boolean_t mu_int_fhead(void) mu_int_err(ERR_DBHEADINV, 0, 0, 0, 0, 0, 0, 0); return FALSE; } - size = mu_int_ovrhd + block_factor * mu_data->trans_hist.total_blks; + size = mu_int_ovrhd + (off_t)block_factor * mu_data->trans_hist.total_blks; /* If ONLINE INTEG for this region is in progress, then native_size would have been calculated in ss_initiate. */ - GET_NATIVE_SIZE(native_size); + SET_NATIVE_SIZE(native_size); /* In the following tests, the EOF block should always be 1 greater * than the actual size of the file. This is due to the GDS being * allocated in even DISK_BLOCK_SIZE-byte blocks. */ @@ -255,19 +253,19 @@ boolean_t mu_int_fhead(void) else mu_int_err(ERR_DBFSTBC, 0, 0, 0, 0, 0, 0, 0); if (native_size % 2) /* Native size should be (64K + n*1K + 512) / DISK_BLOCK_SIZE , so always an odd number. */ - gtm_putmsg(VARLSTCNT(4) ERR_DBTOTBLK, 2, (native_size - mu_data->start_vbn) / block_factor, + gtm_putmsg(VARLSTCNT(4) ERR_DBTOTBLK, 2, (uint4)((native_size - mu_data->start_vbn) / block_factor), mu_data->trans_hist.total_blks); else /* Since native_size is even and the result will be rounded down, we need to add 1 before the division so we * extend by enough blocks (ie. if current nb. of blocks is 100, and the file size gives 102.5 blocks, we * need to extend by 3 blocks, not 2). */ gtm_putmsg(VARLSTCNT(6) ERR_DBMISALIGN, 4, DB_LEN_STR(gv_cur_region), - (native_size - mu_data->start_vbn) / block_factor, - ((native_size + 1 - mu_data->start_vbn) / block_factor) - mu_data->trans_hist.total_blks); + (uint4)((native_size - mu_data->start_vbn) / block_factor), + (uint4)(((native_size + 1 - mu_data->start_vbn) / block_factor) - mu_data->trans_hist.total_blks)); } /* make working space for all local bitmaps */ maps = (mu_data->trans_hist.total_blks + mu_data->bplmap - 1) / mu_data->bplmap; - size = (unsigned int)(BM_SIZE(mu_data->bplmap) - SIZEOF(blk_hdr)); + size = (gtm_uint64_t)(BM_SIZE(mu_data->bplmap) - SIZEOF(blk_hdr)); size *= maps; mu_int_locals = (unsigned char *)malloc(size); memset(mu_int_locals, FOUR_BLKS_FREE, size); diff --git a/sr_port/mu_int_init.c b/sr_port/mu_int_init.c index a29bde8..5730345 100644 --- a/sr_port/mu_int_init.c +++ b/sr_port/mu_int_init.c @@ -37,12 +37,13 @@ #endif #define MSGBUF_SIZE 256 -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_data mu_int_data; -GBLREF unsigned char *mu_int_master; -GTMCRYPT_ONLY( -GBLREF gtmcrypt_key_t mu_int_encrypt_key_handle; -) +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_data mu_int_data; +GBLREF unsigned char *mu_int_master; +GBLREF int mu_int_skipreg_cnt; +#ifdef GTM_CRYPT +GBLREF gtmcrypt_key_t mu_int_encrypt_key_handle; +#endif error_def(ERR_DBFSTHEAD); error_def(ERR_MUNODBNAME); @@ -50,13 +51,15 @@ error_def(ERR_MUSTANDALONE); boolean_t mu_int_init(void) { - unsigned int native_size, size, status; - file_control *fc; - boolean_t standalone; - char msgbuff[MSGBUF_SIZE], *msgptr; - GTMCRYPT_ONLY( - int crypt_status; - ) + unsigned int status; + gtm_uint64_t native_size; + file_control *fc; + boolean_t standalone; + char msgbuff[MSGBUF_SIZE], *msgptr; +# ifdef GTM_CRYPT + int gtmcrypt_errno; + gd_segment *seg; +# endif mu_gv_cur_reg_init(); /* get filename */ @@ -66,6 +69,7 @@ boolean_t mu_int_init(void) if (!STANDALONE(gv_cur_region)) { gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(gv_cur_region)); + mu_int_skipreg_cnt++; return (FALSE); } fc = gv_cur_region->dyn.addr->file_cntl; @@ -75,6 +79,7 @@ boolean_t mu_int_init(void) if (SS_NORMAL != status) { gtm_putmsg(VARLSTCNT(1) status); + mu_int_skipreg_cnt++; return FALSE; } native_size = gds_file_size(fc); @@ -96,18 +101,15 @@ boolean_t mu_int_init(void) return FALSE; } # ifdef GTM_CRYPT - /* Initialize encryption and the key information for the current segment to be used in mu_int_read. - * Note that this is done here and will be called only if mupip integ is called with -file option. - * In other case where mupip integ is called with -reg option, the following initialization will be done - * in db_init. */ if (mu_int_data.is_encrypted) - { - INIT_PROC_ENCRYPTION(crypt_status); - if (0 == crypt_status) - GTMCRYPT_GETKEY(mu_int_data.encryption_hash, mu_int_encrypt_key_handle, crypt_status); - if (0 != crypt_status) + { /* Initialize encryption and the key information for the current segment to be used in mu_int_read. */ + ASSERT_ENCRYPTION_INITIALIZED; /* should have been done in mu_rndwn_file called from STANDALONE macro */ + GTMCRYPT_GETKEY(NULL, mu_int_data.encryption_hash, mu_int_encrypt_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, (gv_cur_region->dyn.addr->fname)); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + mu_int_skipreg_cnt++; return FALSE; } } diff --git a/sr_port/mu_int_maps.c b/sr_port/mu_int_maps.c index 9d73dac..b63d4e2 100644 --- a/sr_port/mu_int_maps.c +++ b/sr_port/mu_int_maps.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,6 +40,23 @@ GBLREF int mu_map_errs; GBLREF int disp_trans_errors; GBLREF int trans_errors; +error_def(ERR_DBREADBM); +error_def(ERR_DBLVLINC); +error_def(ERR_DBMBSIZMN); +error_def(ERR_DBMBSIZMX); +error_def(ERR_DBMBTNSIZMX); +error_def(ERR_DBLOCMBINC); +error_def(ERR_DBBFSTAT); +error_def(ERR_DBMBPFLINT); +error_def(ERR_DBMBPFLDLBM); +error_def(ERR_DBMBPFRDLBM); +error_def(ERR_DBMBPFRINT); +error_def(ERR_DBMBPFLDIS); +error_def(ERR_DBMBPINCFL); +error_def(ERR_DBMRKFREE); +error_def(ERR_DBMRKBUSY); +error_def(ERR_DBMBMINCFRE); + void mu_int_maps(void) { unsigned char *local; @@ -52,23 +69,6 @@ void mu_int_maps(void) block_id blkno, last_bmp; enum db_ver ondsk_blkver; - error_def(ERR_DBREADBM); - error_def(ERR_DBLVLINC); - error_def(ERR_DBMBSIZMN); - error_def(ERR_DBMBSIZMX); - error_def(ERR_DBMBTNSIZMX); - error_def(ERR_DBLOCMBINC); - error_def(ERR_DBBFSTAT); - error_def(ERR_DBMBPFLINT); - error_def(ERR_DBMBPFLDLBM); - error_def(ERR_DBMBPFRDLBM); - error_def(ERR_DBMBPFRINT); - error_def(ERR_DBMBPFLDIS); - error_def(ERR_DBMBPINCFL); - error_def(ERR_DBMRKFREE); - error_def(ERR_DBMRKBUSY); - error_def(ERR_DBMBMINCFRE); - mu_int_offset[0] = 0; maps = (mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap; local = mu_int_locals; @@ -80,7 +80,7 @@ void mu_int_maps(void) assert(mapsize == mu_int_data.bplmap); blkno = mcnt * mu_int_data.bplmap; bml_busy(blkno, mu_int_locals); - disk = mu_int_read(blkno, &ondsk_blkver); /* ondsk_blkver set to GDSV4 or GDSV5 (GDSVCURR) */ + disk = mu_int_read(blkno, &ondsk_blkver); /* ondsk_blkver set to GDSV4 or GDSV6 (GDSVCURR) */ if (!disk) { mu_int_path[0] = blkno; diff --git a/sr_port/mu_int_read.c b/sr_port/mu_int_read.c index f2376c5..ea02947 100644 --- a/sr_port/mu_int_read.c +++ b/sr_port/mu_int_read.c @@ -56,10 +56,11 @@ uchar_ptr_t mu_int_read(block_id blk, enum db_ver *ondsk_blkver) int4 status; file_control *fc; unsigned char *tmp_ptr; - GTMCRYPT_ONLY( - int req_dec_blk_size; - int crypt_status; - ) +# ifdef GTM_CRYPT + int in_len, gtmcrypt_errno; + char *in; + gd_segment *seg; +# endif boolean_t have_blk = FALSE; sgmnt_addrs *csa; GTM_SNAPSHOT_ONLY( @@ -122,8 +123,8 @@ uchar_ptr_t mu_int_read(block_id blk, enum db_ver *ondsk_blkver) # endif } # ifdef GTM_CRYPT - req_dec_blk_size = MIN(mu_int_data.blk_size, ((blk_hdr_ptr_t)tmp_ptr)->bsiz) - SIZEOF(blk_hdr); - if (BLOCK_REQUIRE_ENCRYPTION(mu_int_data.is_encrypted, (((blk_hdr_ptr_t)tmp_ptr)->levl), req_dec_blk_size)) + in_len = MIN(mu_int_data.blk_size, ((blk_hdr_ptr_t)tmp_ptr)->bsiz) - SIZEOF(blk_hdr); + if (BLOCK_REQUIRE_ENCRYPTION(mu_int_data.is_encrypted, (((blk_hdr_ptr_t)tmp_ptr)->levl), in_len)) { /* The below assert cannot be moved before BLOCK_REQUIRE_ENCRYPTION check done above as tmp_ptr could * potentially point to a V4 block in which case the assert might fail when a V4 block is casted to @@ -131,13 +132,13 @@ uchar_ptr_t mu_int_read(block_id blk, enum db_ver *ondsk_blkver) */ assert(((blk_hdr_ptr_t)tmp_ptr)->bsiz <= mu_int_data.blk_size); assert(((blk_hdr_ptr_t)tmp_ptr)->bsiz >= SIZEOF(blk_hdr)); - GTMCRYPT_DECODE_FAST(mu_int_encrypt_key_handle, - (char *)(tmp_ptr + SIZEOF(blk_hdr)), - req_dec_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, gv_cur_region->dyn.addr->fname); + in = (char *)(tmp_ptr + SIZEOF(blk_hdr)); + GTMCRYPT_DECRYPT(csa, mu_int_encrypt_key_handle, in, in_len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); + } } # endif GDS_BLK_UPGRADE_IF_NEEDED(blk, tmp_ptr, tmp_ptr, &mu_int_data, ondsk_blkver, status, mu_int_data.fully_upgraded); diff --git a/sr_port/mu_int_reg.c b/sr_port/mu_int_reg.c index 9c5220a..d626c42 100644 --- a/sr_port/mu_int_reg.c +++ b/sr_port/mu_int_reg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,6 +37,7 @@ #endif #ifdef GTM_SNAPSHOT #include "db_snapshot.h" +#include "gt_timer.h" #endif #include "mupint.h" #include "wbox_test_init.h" @@ -47,50 +48,54 @@ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_data mu_int_data; GBLREF unsigned char *mu_int_master; GBLREF uint4 mu_int_errknt; +GBLREF uint4 mu_int_skipreg_cnt; GBLREF sgmnt_data_ptr_t cs_data; GBLREF pid_t process_id; - -GTMCRYPT_ONLY( - GBLREF gtmcrypt_key_t mu_int_encrypt_key_handle; -) GBLREF boolean_t ointeg_this_reg; -GTM_SNAPSHOT_ONLY( - GBLREF util_snapshot_ptr_t util_ss_ptr; - GBLREF boolean_t preserve_snapshot; - GBLREF boolean_t online_specified; -) +#ifdef GTM_CRYPT +GBLREF gtmcrypt_key_t mu_int_encrypt_key_handle; +GBLREF sgmnt_addrs *cs_addrs; +#endif +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +GBLREF util_snapshot_ptr_t util_ss_ptr; +GBLREF boolean_t preserve_snapshot; +GBLREF boolean_t online_specified; +#endif + +error_def(ERR_BUFFLUFAILED); +error_def(ERR_DBRDONLY); +error_def(ERR_MUKILLIP); +error_def(ERR_SSV4NOALLOW); +error_def(ERR_SSMMNOALLOW); void mu_int_reg(gd_region *reg, boolean_t *return_value) { sgmnt_addrs *csa; freeze_status status; - GTMCRYPT_ONLY( - int crypt_status; - ) node_local_ptr_t cnl; boolean_t need_to_wait = FALSE, read_only, was_crit; int trynum; uint4 curr_wbox_seq_num; +# ifdef GTM_CRYPT + int gtmcrypt_errno; + gd_segment *seg; +# endif - error_def(ERR_BUFFLUFAILED); - error_def(ERR_DBRDONLY); - error_def(ERR_MUKILLIP); - error_def(ERR_SSV4NOALLOW); - error_def(ERR_SSMMNOALLOW); *return_value = FALSE; - + UNIX_ONLY(jnlpool_init_needed = TRUE); ESTABLISH(mu_int_reg_ch); if (dba_usr == reg->dyn.addr->acc_meth) { util_out_print("!/Can't integ region !AD; not GDS format", TRUE, REG_LEN_STR(reg)); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } gv_cur_region = reg; if (reg_cmcheck(reg)) { util_out_print("!/Can't integ region across network", TRUE); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } gvcst_init(gv_cur_region); @@ -104,28 +109,19 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) cnl = csa->nl; read_only = gv_cur_region->read_only; # ifdef GTM_CRYPT - /* Initialize mu_int_encrypt_key_handle to be used in mu_int_read */ if (cs_data->is_encrypted) - { - /* Encryption init should have happened in db_init. */ - ASSERT_ENCRYPTION_INITIALIZED; - /* If the encryption init failed in db_init, the below MACRO should return an error. - * Depending on the error returned, report the error.*/ - GTMCRYPT_GETKEY(cs_data->encryption_hash, mu_int_encrypt_key_handle, crypt_status); - if (0 != crypt_status) + { /* Initialize mu_int_encrypt_key_handle to be used in mu_int_read */ + ASSERT_ENCRYPTION_INITIALIZED; /* should have happened in db_init() */ + GTMCRYPT_GETKEY(cs_addrs, cs_data->encryption_hash, mu_int_encrypt_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, (gv_cur_region->dyn.addr->fname)); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + mu_int_skipreg_cnt++; return; } } # endif - if (dba_mm == cs_data->acc_meth && read_only) - { - util_out_print("!/MM database is read only. MM database cannot be frozen without write access.", TRUE); - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); - mu_int_errknt++; - return; - } assert(NULL != mu_int_master); /* Ensure that we don't see an increase in the file header and master map size compared to it's maximum values */ assert(SGMNT_HDR_LEN >= SIZEOF(sgmnt_data) && (MASTER_MAP_SIZE_MAX >= MASTER_MAP_SIZE(cs_data))); @@ -141,7 +137,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) { gtm_putmsg(VARLSTCNT(4) ERR_SSV4NOALLOW, 2, DB_LEN_STR(gv_cur_region)); util_out_print(NO_ONLINE_ERR_MSG, TRUE); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } } @@ -154,7 +150,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) case REG_ALREADY_FROZEN: util_out_print("!/Database for region !AD is already frozen, not integing", TRUE, REG_LEN_STR(gv_cur_region)); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; case REG_HAS_KIP: /* We have already waited for KIP to reset. This time do not wait for KIP */ @@ -163,7 +159,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) { util_out_print("!/Database for region !AD is already frozen, not integing", TRUE, REG_LEN_STR(gv_cur_region)); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } break; @@ -172,9 +168,9 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) default: assert(FALSE); } - if (read_only && !mu_int_wait_rdonly(csa, MUPIP_INTEG)) + if (read_only && (dba_bg == csa->hdr->acc_meth) && !mu_int_wait_rdonly(csa, MUPIP_INTEG)) { - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } } @@ -183,7 +179,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) if (!read_only && !wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH)) { gtm_putmsg(VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT(MUPIP_INTEG), DB_LEN_STR(gv_cur_region)); - mu_int_errknt++; + mu_int_skipreg_cnt++; return; } /* Take a copy of the file-header. To ensure it is consistent, do it while holding crit. */ @@ -199,7 +195,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) # ifdef GTM_SNAPSHOT if (!ss_initiate(gv_cur_region, util_ss_ptr, &csa->ss_ctx, preserve_snapshot, MUPIP_INTEG)) { - mu_int_errknt++; + mu_int_skipreg_cnt++; assert(NULL != csa->ss_ctx); ss_release(&csa->ss_ctx); ointeg_this_reg = FALSE; /* Turn off ONLINE INTEG for this region */ @@ -217,7 +213,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value) { trynum = 30; /* given 30 cycles to tell you to go */ while ((curr_wbox_seq_num == cnl->wbox_test_seq_num) && trynum--) - sleep(1); + LONG_SLEEP(1); cnl->wbox_test_seq_num++; /* let them know we took the next step */ assert(trynum); } diff --git a/sr_port/mu_int_reg_ch.c b/sr_port/mu_int_reg_ch.c index 1291c54..28eca77 100644 --- a/sr_port/mu_int_reg_ch.c +++ b/sr_port/mu_int_reg_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,7 @@ GBLREF gd_region *gv_cur_region; GBLREF bool region; GBLREF uint4 mu_int_errknt; +GBLREF uint4 mu_int_skipreg_cnt; error_def(ERR_ASSERT); error_def(ERR_DBFILERR); @@ -41,7 +42,7 @@ error_def(ERR_VMSMEMORY); CONDITION_HANDLER(mu_int_reg_ch) { START_CH - mu_int_errknt++; + mu_int_skipreg_cnt++; if (DUMPABLE) NEXTCH; PRN_ERROR; diff --git a/sr_port/mu_reorg.c b/sr_port/mu_reorg.c index 803b06c..9a91804 100644 --- a/sr_port/mu_reorg.c +++ b/sr_port/mu_reorg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,6 +47,7 @@ #include "interlock.h" #include "muextr.h" #include "mu_reorg.h" +#include "anticipatory_freeze.h" /* Include prototypes */ #include "t_end.h" @@ -65,13 +66,26 @@ #include "wcs_sleep.h" #include "memcoherency.h" +#ifdef UNIX +#include "repl_msg.h" +#include "gtmsource.h" +#endif +#ifdef GTM_TRIGGER +#include "hashtab_mname.h" +#include "gv_trigger.h" +#include "gv_trigger_common.h" +#include "targ_alloc.h" +#endif + +GTMTRIG_ONLY(LITREF mval literal_hasht;) + GBLREF bool mu_ctrlc_occurred; GBLREF bool mu_ctrly_occurred; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF gv_key *gv_currkey_next_reorg; GBLREF gd_region *gv_cur_region; -GBLREF gv_key *gv_currkey; +GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF gv_namehead *gv_target; GBLREF gv_namehead *reorg_gv_target; GBLREF unsigned char cw_map_depth; @@ -92,6 +106,19 @@ error_def(ERR_GBLNOEXIST); error_def(ERR_MAXBTLEVEL); error_def(ERR_MUREORGFAIL); +#define SAVE_REORG_RESTART \ +{ \ + cs_data->reorg_restart_block = dest_blk_id; \ + if (OLD_MAX_KEY_SZ >= gv_currkey->end) \ + memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], gv_currkey->end + 1); \ + else \ + { /* Save only so much of gv_currkey as will fit in reorg_restart_key. Expect this to be no more than a very \ + * minor inconvenience for those using -RESUME */ \ + memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], OLD_MAX_KEY_SZ + 1); \ + cs_data->reorg_restart_key[OLD_MAX_KEY_SZ] = 0; \ + cs_data->reorg_restart_key[OLD_MAX_KEY_SZ - 1] = 0; \ + } \ +} #ifdef UNIX # define ABORT_TRANS_IF_GBL_EXIST_NOMORE_AND_RETURN(LCL_T_TRIES) \ @@ -101,7 +128,7 @@ error_def(ERR_MUREORGFAIL); ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, tn_aborted); \ if (tn_aborted) \ { \ - gtm_putmsg(VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr); \ + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr); \ reorg_finish(dest_blk_id, blks_processed, blks_killed, blks_reused, file_extended, lvls_reduced, blks_coalesced,\ blks_split, blks_swapped); \ return TRUE; /* It is not an error if the global (that once existed) doesn't exist anymore (due to ROLLBACK) */ \ @@ -194,7 +221,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in */ int pre_order_successor_level, level; static block_id dest_blk_id = 0; - int tkeysize; + int tkeysize, altkeylen; int blks_killed, blks_processed, blks_reused, blks_coalesced, blks_split, blks_swapped, count, file_extended, lvls_reduced; int d_max_fill, i_max_fill, blk_size, cur_blk_size, max_fill, toler, d_toler, i_toler; @@ -203,21 +230,42 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in sm_uc_ptr_t rPtr1; enum cdb_sc status; srch_hist *rtsib_hist; + super_srch_hist super_dest_hist; /* dir_hist combined with reorg_gv_target->hist */ jnl_buffer_ptr_t jbp; trans_num ret_tn; + sgmnt_addrs *csa; # ifdef UNIX DEBUG_ONLY(unsigned int lcl_t_tries;) # endif +# ifdef GTM_TRIGGER + gv_namehead *hasht_tree; + mname_entry gvent; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; + csa = cs_addrs; t_err = ERR_MUREORGFAIL; kill_set_tail = &kill_set_list; - /* Initialization for current global */ inctn_opcode = inctn_invalid_op; /* temporary reset; satisfy an assert in t_end() */ - op_gvname(VARLSTCNT(1) gn); +# ifdef GTM_TRIGGER + if (IS_MNAME_HASHT_GBLNAME(gn->str)) + { /* Initialize ^#t global for this region. Maintain reorg_restart_key as usual since this exists per region. */ + SETUP_TRIGGER_GLOBAL; + INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; + 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, gn->str.len, gn->str.addr, REG_LEN_STR(gv_cur_region)); + } + } else +# endif /* Initialization for current global */ + op_gvname(VARLSTCNT(1) gn); /* Cannot proceed for read-only data files */ if (gv_cur_region->read_only) { - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); return FALSE; } if (0 == gv_target->root) @@ -232,11 +280,13 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in if (*resume && 0 != cs_data->reorg_restart_key[0]) { /* resume from last key reorged in GVT */ - GET_KEY_LEN(tkeysize, &cs_data->reorg_restart_key[0]); + tkeysize = get_key_len(NULL, &cs_data->reorg_restart_key[0]); memcpy(gv_currkey->base, cs_data->reorg_restart_key, tkeysize); gv_currkey->end = tkeysize - 1; dest_blk_id = cs_data->reorg_restart_block; - if (0 == memcmp(cs_data->reorg_restart_key, gn->str.addr, gn->str.len)) + SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY; + altkeylen = gv_altkey->end - 1; + if (altkeylen && (altkeylen == gn->str.len) && (0 == memcmp(gv_altkey->base, gn->str.addr, gn->str.len))) /* Going to resume from current global, so it resumed and make it false */ *resume = FALSE; } else @@ -283,8 +333,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in { if (mu_ctrlc_occurred || mu_ctrly_occurred) { - cs_data->reorg_restart_block = dest_blk_id; - memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], gv_currkey->end + 1); + SAVE_REORG_RESTART; return FALSE; } complete_merge = FALSE; @@ -326,7 +375,8 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in status = mu_split(level, i_max_fill, d_max_fill, &cnt1, &cnt2); if (cdb_sc_maxlvl == status) { - gtm_putmsg(VARLSTCNT(4) ERR_MAXBTLEVEL, 2, gn->str.len, gn->str.addr); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_MAXBTLEVEL, 2, gn->str.len, + gn->str.addr); reorg_finish(dest_blk_id, blks_processed, blks_killed, blks_reused, file_extended, lvls_reduced, blks_coalesced, blks_split, blks_swapped); return FALSE; @@ -455,7 +505,8 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in * here gv_currkey_next_reorg will be set from right sibling */ cw_set_depth = cw_map_depth = 0; - GET_KEY_LEN(tkeysize, rtsib_hist->h[0].buffaddr + SIZEOF(blk_hdr) + SIZEOF(rec_hdr)); + tkeysize = get_key_len(rtsib_hist->h[0].buffaddr, rtsib_hist->h[0].buffaddr + + SIZEOF(blk_hdr) + SIZEOF(rec_hdr)); if (2 < tkeysize && MAX_KEY_SZ >= tkeysize) { memcpy(&(gv_currkey_next_reorg->base[0]), rtsib_hist->h[0].buffaddr @@ -495,8 +546,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in if (mu_ctrlc_occurred || mu_ctrly_occurred) { - cs_data->reorg_restart_block = dest_blk_id; - memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], gv_currkey->end+1); + SAVE_REORG_RESTART; return FALSE; } /* Now swap the working block */ @@ -534,6 +584,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in } else if (cdb_sc_normal == status) { UNIX_ONLY(DEBUG_ONLY(lcl_t_tries = t_tries)); + MERGE_SUPER_HIST(&super_dest_hist, reorg_gv_target->alt_hist, &(reorg_gv_target->hist)); if (0 < kill_set_list.used) { need_kip_incr = TRUE; @@ -564,7 +615,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in /* gv_target->hist is for working block's history, and reorg_gv_target->hist is for destinition block's history. Note: gv_target and reorg_gv_target can be part of different GVT. */ - else if ((trans_num)0 == (ret_tn = t_end(&(gv_target->hist), &(reorg_gv_target->hist), + else if ((trans_num)0 == (ret_tn = t_end(&(gv_target->hist), (srch_hist *)&super_dest_hist, TN_NOT_SPECIFIED))) { need_kip_incr = FALSE; @@ -592,8 +643,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in } if (mu_ctrlc_occurred || mu_ctrly_occurred) { - cs_data->reorg_restart_block = dest_blk_id; - memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], gv_currkey->end + 1); + SAVE_REORG_RESTART; return FALSE; } if (end_of_tree) @@ -605,8 +655,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in level = pre_order_successor_level; memcpy(&gv_currkey->base[0], &gv_currkey_next_reorg->base[0], gv_currkey_next_reorg->end + 1); gv_currkey->end = gv_currkey_next_reorg->end; - cs_data->reorg_restart_block = dest_blk_id; - memcpy(&cs_data->reorg_restart_key[0], &gv_currkey->base[0], gv_currkey->end + 1); + SAVE_REORG_RESTART; } } /* ================ END MAIN LOOP ================ */ diff --git a/sr_port/mu_reorg.h b/sr_port/mu_reorg.h index 5416b7c..03755fb 100644 --- a/sr_port/mu_reorg.h +++ b/sr_port/mu_reorg.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,110 +37,51 @@ /* DECR_BLK_NUM has no check for bit-map because it is always followed by INCR_BLK_NUM */ #define DECR_BLK_NUM(block_number) (block_number)-- -/********************************************************************* - Get global variable length. - Start scanning from KEY_BASE. - rPtr1 = unsigned char pointer already defined - KEY_BASE = where to start scan - KEY_LEN = length found - **********x**********************************************************/ -#define GET_GBLNAME_LEN(KEY_LEN, KEY_BASE) \ +/* + * If INVALID_RECORD evaluates to TRUE, it means some necessary record/key relations are incongruent, and we cannot proceed + * with update array calculations. Restart. + * Input: + * LEVEL := level of current block + * REC_SIZE := record size + * KEYLEN := key length + * KEYCMPC := key compression count + */ +#define INVALID_RECORD(LEVEL, REC_SIZE, KEYLEN, KEYCMPC) \ + ( (MAX_KEY_SZ < ((int)(KEYLEN) + (KEYCMPC))) \ + || (BSTAR_REC_SIZE > ((REC_SIZE) + (0 == (LEVEL) ? 1 : 0))) \ + || ((0 == (LEVEL)) && (2 >= (KEYLEN))) \ + ) + +/* Key allocation better be big enough. We can check array sizes, so we do. But we can't check arbitrary pointers, so if a pointer + * is passed to DBG_CHECK_KEY_ALLOCATION_SIZE, we ignore it. The complication below is for distinguishing arrays from pointers + * on Tru64, where pointers can be either 32-bit or 64-bit. + */ +#if defined(__osf__) && defined(DEBUG) +# pragma pointer_size(save) +# pragma pointer_size(long) +typedef char *dbg_osf_long_char_ptr_t; /* 64-bit */ +# pragma pointer_size(short) +typedef char *dbg_osf_short_char_ptr_t; /* 32-bit */ +# pragma pointer_size(restore) +# define DBG_CHECK_KEY_ALLOCATION_SIZE(KEY) assert((MAX_KEY_SZ < ARRAYSIZE((KEY))) \ + || (SIZEOF(dbg_osf_long_char_ptr_t) == SIZEOF((KEY))) || (SIZEOF(dbg_osf_short_char_ptr_t) == SIZEOF((KEY)))) +#else /* normal platforms; non-Tru64 */ +typedef char *dbg_osf_long_char_ptr_t; +typedef char *dbg_osf_short_char_ptr_t; +# define DBG_CHECK_KEY_ALLOCATION_SIZE(KEY) assert((MAX_KEY_SZ < ARRAYSIZE((KEY))) || (SIZEOF(char_ptr_t) == SIZEOF((KEY)))) +#endif + +#define GET_CMPC(KEY_CMPC, FIRST_KEY, SECOND_KEY) \ { \ - for (rPtr1 = (KEY_BASE); ; ) \ - { \ - if (0 == *rPtr1++) \ - break; \ - } \ - KEY_LEN = (int)(rPtr1 - (KEY_BASE)); \ + DBG_CHECK_KEY_ALLOCATION_SIZE(FIRST_KEY); \ + DBG_CHECK_KEY_ALLOCATION_SIZE(SECOND_KEY); \ + KEY_CMPC = get_cmpc(FIRST_KEY, SECOND_KEY); \ } -/********************************************************************** - Get key length scanning from key_base. - rPtr1 = unsigned char pointer already defined - KEY_BASE = where to start scan - KEY_LEN = length returned - **********************************************************************/ -#define GET_KEY_LEN(KEY_LEN, KEY_BASE) \ -{ \ - for (rPtr1 = (KEY_BASE); ; ) \ - { \ - if ((0 == *rPtr1++) && (0 == *rPtr1)) \ - break; \ - } \ - KEY_LEN = (int)(rPtr1 + 1 - (KEY_BASE)); \ -} - -/*********************************************************************** - Get compression count of SECOND_KEY with resprect to FIRST_KEY - CMPC = returned compression count - rPtr1, rPtr2 are unsigned character pointer defined earlier - ************************************************************************/ -#define GET_CMPC(CMPC, FIRST_KEY, SECOND_KEY) \ -{ \ - CMPC = 0; \ - if ((FIRST_KEY) != (SECOND_KEY)) \ - { \ - for (rPtr1 = (FIRST_KEY), rPtr2 = (SECOND_KEY); \ - CMPC < MAX_KEY_SZ; \ - (CMPC)++) \ - { \ - if (*rPtr1++ != *rPtr2++) \ - break; \ - } \ - } \ -} - -/************************************************************************ - validate a reocrd from - LEVEL, REC_SIZE, KEYLEN and KEYCMPC - ************************************************************************/ -#define INVALID_RECORD(LEVEL, REC_SIZE, KEYLEN, KEYCMPC) \ - (( ((0 == (LEVEL)) && (2 >= (KEYLEN)) ) || \ - (BSTAR_REC_SIZE > ((REC_SIZE) + (0 == (LEVEL) ? 1 : 0)) ) || \ - (gv_cur_region->max_key_size < ((int)(KEYLEN) + (KEYCMPC))) || \ - (gv_cur_region->max_rec_size < (REC_SIZE) ) ) ? TRUE:FALSE ) - -/************************************************************************* - Process a record and read. - Input Parameter: - LEVEL = where reading - REC_BASE = Starting address of record - Output Parameter: - KEY_CMPC = Key compression count - REC_SIZE = record size - KEY = pointer to key read - KEY_LEN = Key length - STATUS = Status of read - *************************************************************************/ -#define READ_RECORD(LEVEL, REC_BASE, KEY_CMPC, REC_SIZE, KEY, KEY_LEN, STATUS) \ -{ \ - GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)(REC_BASE))->rsiz)); \ - REC_SIZE = temp_ushort; \ - KEY_CMPC = ((rec_hdr_ptr_t)(REC_BASE))->cmpc; \ - if (0 != (LEVEL) && BSTAR_REC_SIZE == (REC_SIZE)) \ - { \ - KEY_LEN = 0; \ - STATUS = cdb_sc_starrecord; \ - } \ - else \ - { \ - for (rPtr1 = (KEY) + KEY_CMPC, rPtr2 = (REC_BASE) + SIZEOF(rec_hdr); \ - gv_cur_region->max_key_size - 1 > (rPtr2 - (REC_BASE) - SIZEOF(rec_hdr)) && \ - gv_cur_region->max_key_size - 1 > (rPtr1 - (KEY)) ;) \ - { \ - if ((0 == (*rPtr1++ = *rPtr2++)) && (0 == *rPtr2)) \ - break; \ - } \ - *rPtr1++ = *rPtr2++; \ - KEY_LEN = (int)(rPtr2 - (REC_BASE) - SIZEOF(rec_hdr)); \ - if ((gv_cur_region->max_rec_size < (REC_SIZE)) || \ - (gv_cur_region->max_key_size < ((int)(KEY_LEN)+ (KEY_CMPC))) || \ - (BSTAR_REC_SIZE > ((REC_SIZE) + ((0 == (LEVEL)) ? 1 : 0))) || \ - (2 >= (KEY_LEN)) || (0 != *(rPtr1 - 1) || 0 != *(rPtr1 - 2))) \ - STATUS = cdb_sc_blkmod; \ - else \ - STATUS = cdb_sc_normal; \ - } \ +#define READ_RECORD(STATUS, REC_SIZE_PTR, KEY_CMPC_PTR, KEY_LEN_PTR, KEY, LEVEL, BLK_BASE, REC_BASE) \ +{ \ + DBG_CHECK_KEY_ALLOCATION_SIZE(KEY); \ + STATUS = read_record(REC_SIZE_PTR, KEY_CMPC_PTR, KEY_LEN_PTR, KEY, LEVEL, BLK_BASE, REC_BASE); \ } enum reorg_options { DEFAULT = 0, @@ -149,3 +90,9 @@ enum reorg_options { DEFAULT = 0, NOSPLIT = 0x0004, NOSWAP = 0x0008, DETAIL = 0x0010}; + +int get_gblname_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base); +int get_key_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base); +int get_cmpc(sm_uc_ptr_t first_key, sm_uc_ptr_t second_key); +enum cdb_sc read_record(int *rec_size_ptr, int *key_cmpc_ptr, int *key_len_ptr, sm_uc_ptr_t key, + int level, sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_base); diff --git a/sr_port/mu_reorg_upgrd_dwngrd.c b/sr_port/mu_reorg_upgrd_dwngrd.c index a62ea78..d249306 100644 --- a/sr_port/mu_reorg_upgrd_dwngrd.c +++ b/sr_port/mu_reorg_upgrd_dwngrd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -68,6 +68,7 @@ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gv_namehead *gv_target; +GBLREF gv_namehead *gv_target_list; GBLREF inctn_opcode_t inctn_opcode; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLREF boolean_t mu_reorg_nosafejnl; /* TRUE if NOSAFEJNL explicitly specified */ @@ -81,6 +82,18 @@ GBLREF unsigned char cw_set_depth; GBLREF unsigned char cw_map_depth; GBLREF uint4 update_trans; +error_def(ERR_BUFFLUFAILED); +error_def(ERR_DBBTUWRNG); +error_def(ERR_DBFILERR); +error_def(ERR_DBRDONLY); +error_def(ERR_DSEBLKRDFAIL); +error_def(ERR_DYNUPGRDFAIL); +error_def(ERR_MUNOACTION); +error_def(ERR_MUNOFINISH); +error_def(ERR_MUREORGFAIL); +error_def(ERR_MUREUPDWNGRDEND); +error_def(ERR_REORGCTRLY); + /* actually want the following to be a static variable in this module, but getting the address of a * static variable through the debugger might be tricky on some platforms. hence use a global variable instead. */ @@ -127,18 +140,6 @@ void mu_reorg_upgrd_dwngrd(void) unsigned char save_cw_set_depth; uint4 lcl_update_trans; - error_def(ERR_BUFFLUFAILED); - error_def(ERR_DBBTUWRNG); - error_def(ERR_DBFILERR); - error_def(ERR_DBRDONLY); - error_def(ERR_DSEBLKRDFAIL); - error_def(ERR_DYNUPGRDFAIL); - error_def(ERR_MUNOACTION); - error_def(ERR_MUNOFINISH); - error_def(ERR_MUREORGFAIL); - error_def(ERR_MUREUPDWNGRDEND); - error_def(ERR_REORGCTRLY); - region = (CLI_PRESENT == cli_present("REGION")); upgrade = (CLI_PRESENT == cli_present("UPGRADE")); downgrade = (CLI_PRESENT == cli_present("DOWNGRADE")); @@ -173,8 +174,11 @@ void mu_reorg_upgrd_dwngrd(void) util_out_print("!/MUPIP REORG !AD cannot proceed with above errors!/", TRUE, LEN_AND_STR(command)); mupip_exit(ERR_MUNOACTION); } - gv_keysize = DBKEYSIZE(MAX_KEY_SZ); + GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(MAX_KEY_SZ)); /* Keep gv_currkey/gv_altkey in sync with respect to gv_keysize + * (now MAX_KEY_SZ) */ + assert(DBKEYSIZE(MAX_KEY_SZ) == gv_keysize); gv_target = targ_alloc(gv_keysize, NULL, NULL); /* t_begin needs this initialized */ + gv_target_list = NULL; memset(&alt_hist, 0, SIZEOF(alt_hist)); /* null-initialize history */ blkhist = &alt_hist.h[0]; for (rptr = grlist; NULL != rptr; rptr = rptr->fPtr) @@ -218,8 +222,8 @@ void mu_reorg_upgrd_dwngrd(void) status = ERR_MUNOFINISH; continue; } - assert(GDSVCURR == GDSV5); /* so we trip this assert in case GDSVCURR changes without a change to this module */ - new_db_format = (upgrade ? GDSV5 : GDSV4); + assert(GDSVCURR == GDSV6); /* so we trip this assert in case GDSVCURR changes without a change to this module */ + new_db_format = (upgrade ? GDSV6 : GDSV4); grab_crit(reg); curr_tn = csd->trans_hist.curr_tn; /* set the desired db format in the file header to the appropriate version, increment transaction number */ @@ -533,6 +537,14 @@ void mu_reorg_upgrd_dwngrd(void) t_write(blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)blkBase)->levl, FALSE, FALSE, GDS_WRITE_PLAIN); + /* The tree_status for now is only used to determin whether writing + * the block to snapshot file. * (see t_end_ops.c). + * For reorg upgrade/downgrade process, the block is updated in a + * sequential way without changing the gv_target. In this case, + * we assume the block is in directory tree so as to have + * it written to the snapshot file + */ + BIT_SET_DIR_TREE(cw_set[cw_set_depth-1].blk_prior_state); /* reset update_trans in case previous retry had set it to 0 */ update_trans = UPDTRNS_DB_UPDATED_MASK; if (BLK_RECYCLED == bml_status) @@ -542,6 +554,11 @@ void mu_reorg_upgrd_dwngrd(void) */ assert(cw_set[cw_set_depth-1].mode == gds_t_write); cw_set[cw_set_depth-1].mode = gds_t_write_recycled; + /* we SET block as NOT RECYCLED, otherwise, the mm_update() + * or bg_update_phase2 may skip writing it to snapshot file + * when its level is 0 + */ + BIT_CLEAR_RECYCLED(cw_set[cw_set_depth-1].blk_prior_state); } } else { /* Block got converted by another process since we did the dsk_read. @@ -586,8 +603,7 @@ void mu_reorg_upgrd_dwngrd(void) lcl_update_trans = update_trans; /* take a copy before t_end modifies it */ if ((trans_num)0 != t_end(&alt_hist, NULL, TN_NOT_SPECIFIED)) { /* In case this is MM and t_end() remapped an extended database, reset csd */ - assert((dba_mm == cs_data->acc_meth) || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); if (!lcl_update_trans) { assert(lcnt); @@ -603,9 +619,7 @@ void mu_reorg_upgrd_dwngrd(void) reorg_stats.blks_converted_nonbmp++; break; } - /* In case this is MM and t_end() remapped an extended database, reset csd */ - assert((dba_mm == cs_data->acc_meth) || (csd == cs_data)); - csd = cs_data; + assert(csd == cs_data); } } } diff --git a/sr_port/mu_split.c b/sr_port/mu_split.c index 589b090..375fd37 100644 --- a/sr_port/mu_split.c +++ b/sr_port/mu_split.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -79,6 +79,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr unsigned char curr_prev_key[MAX_KEY_SZ+1], new_blk1_last_key[MAX_KEY_SZ+1]; unsigned short temp_ushort; int rec_size, new_ins_keycmpc, tkeycmpc, new_ances_currkeycmpc, old_ances_currkeycmpc; + int tmp_cmpc; block_index left_index, right_index; block_offset ins_off, ins_off2; int level; @@ -106,7 +107,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr BLK_ADDR(star_rec_hdr, SIZEOF(rec_hdr), rec_hdr); star_rec_hdr->rsiz = BSTAR_REC_SIZE; - star_rec_hdr->cmpc = 0; + SET_CMPC(star_rec_hdr, 0); level = cur_level; max_fill = (0 == level)? d_max_fill : i_max_fill; @@ -136,8 +137,9 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr return cdb_sc_oprnotneeded; old_right_piece_len = old_blk1_sz - new_leftblk_top_off; new_blk2_frec_base = old_blk1_base + new_leftblk_top_off; - BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char); - READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size, newblk2_first_key, newblk2_first_keylen, status); + BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char); + READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key, + level, old_blk1_base, new_blk2_frec_base); if (cdb_sc_normal != status) /* restart for cdb_sc_starrecord too, because we eliminated the possibility already */ { assert(t_tries < CDB_STAGNATE); @@ -153,7 +155,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr BLK_ADDR(new_rec_hdr1b, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr1b->rsiz = rec_size + tkeycmpc; - new_rec_hdr1b->cmpc = 0; + SET_CMPC(new_rec_hdr1b, 0); /* Create new split piece, we already know that this will not be *-rec only. * Note that this has to be done BEFORE modifying working block as building this buffer relies on the @@ -224,7 +226,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr rec_base = old_blk1_base + gv_target->hist.h[level].curr_rec.offset; GET_RSIZ(rec_size, rec_base); old_blk_after_currec = rec_base + rec_size; - old_ances_currkeycmpc = ((rec_hdr_ptr_t)rec_base)->cmpc; + old_ances_currkeycmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base); old_ances_currkeylen = rec_size - BSTAR_REC_SIZE; if (INVALID_RECORD(level, rec_size, old_ances_currkeylen, old_ances_currkeycmpc)) { @@ -242,7 +244,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr } else { - BLK_ADDR(ances_currkey, gv_cur_region->max_rec_size + 1, unsigned char); + BLK_ADDR(ances_currkey, MAX_KEY_SZ + 1, unsigned char); key_base = rec_base + SIZEOF(rec_hdr); } new_ances_currkeysz = old_ances_currkeycmpc + old_ances_currkeylen; @@ -267,7 +269,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr if (SIZEOF(blk_hdr) != gv_target->hist.h[level].curr_rec.offset) { /* new_ins_key will be inseted after curr_prev_key */ - GET_CMPC(new_ins_keycmpc, &curr_prev_key[0], new_ins_key); + GET_CMPC(new_ins_keycmpc, curr_prev_key, new_ins_key); } else new_ins_keycmpc = 0; /* new_ins_key will be the 1st key */ @@ -313,9 +315,9 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr else /* process 1st record of new right block */ { - BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char); - READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size, - newblk2_first_key, newblk2_first_keylen, status); + BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char); + READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key, + level, old_blk1_base, new_blk2_frec_base); if (cdb_sc_normal == status) { memcpy(newblk2_first_key, &new_blk1_last_key[0], tkeycmpc); /* compressed piece */ @@ -323,7 +325,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr newblk2_first_keysz = newblk2_first_keylen + tkeycmpc; BLK_ADDR(new_rec_hdr2, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr2->rsiz = newblk2_first_keysz + BSTAR_REC_SIZE; - new_rec_hdr2->cmpc = 0; + SET_CMPC(new_rec_hdr2, 0); } else if (cdb_sc_starrecord != status || !new_rtblk_star_only) { @@ -358,7 +360,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr there will be some records before new_ins_key, at least prev_rec */ delta = (int)(BSTAR_REC_SIZE + new_ins_keylen - old_ances_currkeylen + new_ances_currkeylen - + ((0 == new_ins_keycmpc) ? 0 : (((rec_hdr_ptr_t)new_blk2_frec_base)->cmpc))); + + ((0 == new_ins_keycmpc) ? 0 : (EVAL_CMPC((rec_hdr_ptr_t)new_blk2_frec_base)))); if (SIZEOF(blk_hdr) + old_right_piece_len + delta <= blk_size - cs_data->reserved_bytes) { insert_in_left = FALSE; @@ -392,10 +394,10 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr split_required = FALSE; BLK_ADDR(new_rec_hdr1a, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr1a->rsiz = BSTAR_REC_SIZE + new_ins_keylen; - new_rec_hdr1a->cmpc = new_ins_keycmpc; + SET_CMPC(new_rec_hdr1a, new_ins_keycmpc); BLK_ADDR(new_rec_hdr1b, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr1b->rsiz = BSTAR_REC_SIZE + new_ances_currkeylen; - new_rec_hdr1b->cmpc = new_ances_currkeycmpc; + SET_CMPC(new_rec_hdr1b, new_ances_currkeycmpc); BLK_ADDR(bn_ptr1, SIZEOF(block_id), unsigned char); /* child pointer of ances_currkey */ memcpy(bn_ptr1, old_blk1_base + gv_target->hist.h[level].curr_rec.offset + @@ -594,7 +596,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr { BLK_ADDR(root_hdr, SIZEOF(rec_hdr), rec_hdr); root_hdr->rsiz = BSTAR_REC_SIZE + new_ins_keysz; - root_hdr->cmpc = 0; + SET_CMPC(root_hdr, 0); BLK_INIT(bs_ptr2, bs_ptr1); BLK_SEG(bs_ptr2, (sm_uc_ptr_t)root_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr2, new_ins_key, new_ins_keysz); @@ -665,7 +667,8 @@ int *last_rec_size, unsigned char last_key[], int *last_keysz, int *top_off) rec_base = blk_base + SIZEOF(blk_hdr); while (*top_off < max_fill) { - READ_RECORD(level, rec_base, tkeycmpc, rec_size, &last_key[0], *last_keysz, status); + READ_RECORD(status, &rec_size, &tkeycmpc, last_keysz, last_key, + level, blk_base, rec_base); *top_off += rec_size; *last_keysz += tkeycmpc; rec_base += rec_size; diff --git a/sr_port/mu_swap_blk.c b/sr_port/mu_swap_blk.c index 0b682d5..c71b358 100644 --- a/sr_port/mu_swap_blk.c +++ b/sr_port/mu_swap_blk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -102,11 +102,11 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt int key_len, key_len_dir; block_id dest_blk_id, work_blk_id, child1, child2; enum cdb_sc status; - srch_hist *dest_hist_ptr; + srch_hist *dest_hist_ptr, *dir_hist_ptr; cache_rec_ptr_t dest_child_cr; blk_segment *bs1, *bs_ptr; sm_uc_ptr_t saved_blk, work_blk_ptr, work_parent_ptr, dest_parent_ptr, dest_blk_ptr, - bn_ptr, bmp_buff, tblk_ptr, rec_base, rPtr1; + bn_ptr, bmp_buff, tblk_ptr, rec_base, key_base; boolean_t gbl_target_was_set, blk_was_free, deleted; gv_namehead *save_targ; srch_blk_status bmlhist, destblkhist, *hist_ptr; @@ -122,6 +122,7 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt if (NULL == TREF(gv_reorgkey)) GVKEY_INIT(TREF(gv_reorgkey), DBKEYSIZE(MAX_KEY_SZ)); dest_hist_ptr = &(reorg_gv_target->hist); + dir_hist_ptr = reorg_gv_target->alt_hist; blk_size = cs_data->blk_size; work_parent_ptr = gv_target->hist.h[level+1].buffaddr; work_parent_size = ((blk_hdr_ptr_t)work_parent_ptr)->bsiz; @@ -242,9 +243,9 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt if (SIZEOF(blk_hdr) >= ((blk_hdr_ptr_t)tblk_ptr)->bsiz) continue; /* get length of global variable name (do not read subscript) for dest_blk_id */ - GET_GBLNAME_LEN(key_len_dir, rec_base + SIZEOF(rec_hdr)); + key_len_dir = get_gblname_len(tblk_ptr, rec_base + SIZEOF(rec_hdr)); /* key_len = length of 1st key value (including subscript) for dest_blk_id */ - GET_KEY_LEN(key_len, rec_base + SIZEOF(rec_hdr)); + key_len = get_key_len(tblk_ptr, rec_base + SIZEOF(rec_hdr)); if ((1 >= key_len_dir || MAX_MIDENT_LEN + 1 < key_len_dir) || (2 >= key_len || MAX_KEY_SZ < key_len)) { /* Earlier used to restart here always. But dest_blk_id can be a block, * which is just killed and still marked busy. Skip it, if we are in last retry. @@ -273,24 +274,24 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt gv_target = reorg_gv_target; gv_target->root = cs_addrs->dir_tree->root; gv_target->clue.end = 0; - /* assign Directory tree path to find dest_blk_id in dest_hist_ptr */ - status = gvcst_search(TREF(gv_reorgkey), dest_hist_ptr); + /* assign Directory tree path to find dest_blk_id in dir_hist_ptr */ + status = gvcst_search(TREF(gv_reorgkey), dir_hist_ptr); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); return status; } - if (dest_hist_ptr->h[0].curr_rec.match != (TREF(gv_reorgkey))->end + 1) + if (dir_hist_ptr->h[0].curr_rec.match != (TREF(gv_reorgkey))->end + 1) { /* may be in a kill_set of another process */ - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); continue; } - for (wlevel = 0; wlevel <= dest_hist_ptr->depth && - dest_hist_ptr->h[wlevel].blk_num != dest_blk_id; wlevel++); - if (dest_hist_ptr->h[wlevel].blk_num == dest_blk_id) + for (wlevel = 0; wlevel <= dir_hist_ptr->depth && + dir_hist_ptr->h[wlevel].blk_num != dest_blk_id; wlevel++); + if (dir_hist_ptr->h[wlevel].blk_num == dest_blk_id) { /* do not swap a dir_tree block */ - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); continue; } /* gv_reorgkey will now have the first key from dest_blk_id, @@ -298,20 +299,20 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt */ memcpy(&((TREF(gv_reorgkey))->base[0]), rec_base + SIZEOF(rec_hdr), key_len); (TREF(gv_reorgkey))->end = key_len - 1; - GET_KEY_LEN(key_len_dir, dest_hist_ptr->h[0].buffaddr + dest_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr)); + key_base = dir_hist_ptr->h[0].buffaddr + dir_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr); + key_len_dir = get_key_len(dir_hist_ptr->h[0].buffaddr, key_base); /* Get root of GVT for dest_blk_id */ - GET_LONG(gv_target->root, - dest_hist_ptr->h[0].buffaddr + dest_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr) + key_len_dir); + GET_LONG(gv_target->root, key_base + key_len_dir); if ((0 == gv_target->root) || (gv_target->root > (cs_data->trans_hist.total_blks - 1))) { assert(t_tries < CDB_STAGNATE); - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); return cdb_sc_blkmod; } /* Assign Global Variable Tree path to find dest_blk_id in dest_hist_ptr */ gv_target->clue.end = 0; status = gvcst_search(TREF(gv_reorgkey), dest_hist_ptr); - RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ); + RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); if (dest_blk_level >= dest_hist_ptr->depth || /* do not swap in root level */ dest_hist_ptr->h[dest_blk_level].blk_num != dest_blk_id) /* must be in a kill set of another process. */ continue; @@ -406,7 +407,7 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt * cse->was_free to TRUE so that in t_end, this condition can be used to read the before images of * the FREE blocks if needed. */ - tmpcse->was_free = (BLK_FREE == x_blk_lmap); + (BLK_FREE == x_blk_lmap) ? BIT_SET_FREE(tmpcse->blk_prior_state) : BIT_CLEAR_FREE(tmpcse->blk_prior_state); /* No need to write before-image in case the block is FREE. In case the database had never been fully * upgraded from V4 to V5 format (after the MUPIP UPGRADE), all RECYCLED blocks can basically be considered * FREE (i.e. no need to write before-images since backward journal recovery will never be expected diff --git a/sr_port/mu_upgrd_header.c b/sr_port/mu_upgrd_header.c index d16f2cb..0a4f231 100644 --- a/sr_port/mu_upgrd_header.c +++ b/sr_port/mu_upgrd_header.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -103,7 +103,7 @@ void mu_upgrd_header(v15_sgmnt_data *v15_csd, sgmnt_data *csd) csd->creation_mdb_ver = v15_csd->creation_mdb_ver; csd->trans_hist.early_tn = v15_csd->trans_hist.early_tn; csd->trans_hist.curr_tn = v15_csd->trans_hist.curr_tn; /* INCREMENT_CURR_TN comment added to note curr_tn set is done */ - csd->max_tn = MAX_TN_V5; /* New in V5.0-000 */ + csd->max_tn = MAX_TN_V6; /* New in V5.0-000 */ SET_TN_WARN(csd, csd->max_tn_warn); /* New in V5.0-000 */ csd->trans_hist.last_mm_sync = v15_csd->trans_hist.last_mm_sync; csd->trans_hist.mm_tn = v15_csd->trans_hist.mm_tn; diff --git a/sr_port/mubclnup.c b/sr_port/mubclnup.c index 23c6c8d..f144012 100644 --- a/sr_port/mubclnup.c +++ b/sr_port/mubclnup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -57,8 +57,11 @@ GBLREF boolean_t backup_interrupted; #ifdef UNIX GBLREF backup_reg_list *mu_repl_inst_reg_list; GBLREF jnlpool_addrs jnlpool; +GBLREF boolean_t jnlpool_init_needed; #endif +error_def(ERR_FORCEDHALT); + void mubclnup(backup_reg_list *curr_ptr, clnup_stage stage) { sgmnt_addrs *csa; @@ -72,8 +75,6 @@ void mubclnup(backup_reg_list *curr_ptr, clnup_stage stage) int rc; #endif - error_def(ERR_FORCEDHALT); - assert(stage >= need_to_free_space && stage < num_of_clnup_stage); free(stringpool.base); @@ -179,7 +180,7 @@ void mubclnup(backup_reg_list *curr_ptr, clnup_stage stage) } UNIX_ONLY( /* Release FTOK lock on the replication instance file if holding it */ - assert((NULL == jnlpool.jnlpool_dummy_reg) || (NULL != mu_repl_inst_reg_list)); + assert((NULL == jnlpool.jnlpool_dummy_reg) || (NULL != mu_repl_inst_reg_list) || jnlpool_init_needed); if ((NULL != mu_repl_inst_reg_list) && (NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) { udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); diff --git a/sr_port/mucregini.c b/sr_port/mucregini.c index 006da19..af74e34 100644 --- a/sr_port/mucregini.c +++ b/sr_port/mucregini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -84,6 +84,10 @@ void mucregini(int4 blk_init_size) cs_data->max_key_size = gv_cur_region->max_key_size; cs_data->null_subs = gv_cur_region->null_subs; cs_data->std_null_coll = gv_cur_region->std_null_coll; +#ifdef UNIX + cs_data->freeze_on_fail = gv_cur_region->freeze_on_fail; + cs_data->mumps_can_bypass = gv_cur_region->mumps_can_bypass; +#endif cs_data->reserved_bytes = gv_cur_region->dyn.addr->reserved_bytes; cs_data->clustered = FALSE; cs_data->file_corrupt = 0; @@ -91,6 +95,7 @@ void mucregini(int4 blk_init_size) cs_data->lock_space_size = gv_cur_region->dyn.addr->lock_space * OS_PAGELET_SIZE; else cs_data->lock_space_size = DEF_LOCK_SIZE; + NUM_CRIT_ENTRY(cs_data) = DEFAULT_NUM_CRIT_ENTRY; cs_data->staleness[0] = -300000000; /* staleness timer = 30 seconds */ cs_data->staleness[1] = -1; cs_data->ccp_quantum_interval[0] = -20000000; /* 2 sec */ @@ -111,6 +116,7 @@ void mucregini(int4 blk_init_size) cs_data->jnl_state = gv_cur_region->jnl_state; cs_data->epoch_interval = JNL_ALLOWED(cs_data) ? DEFAULT_EPOCH_INTERVAL : 0; cs_data->alignsize = JNL_ALLOWED(cs_data) ? (DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE) : 0; + ROUND_UP_JNL_BUFF_SIZE(cs_data->jnl_buffer_size, gv_cur_region->jnl_buffer_size, cs_data); #ifdef UNIX if (JNL_ALLOWED(cs_data)) { @@ -125,16 +131,21 @@ void mucregini(int4 blk_init_size) else cs_data->autoswitchlimit = 0; assert(!(MAX_IO_BLOCK_SIZE % DISK_BLOCK_SIZE)); - cs_data->jnl_buffer_size = ROUND_UP(gv_cur_region->jnl_buffer_size, - MIN(MAX_IO_BLOCK_SIZE, cs_data->blk_size) / DISK_BLOCK_SIZE); - if(cs_data->jnl_alq + cs_data->jnl_deq > cs_data->autoswitchlimit) + if (cs_data->jnl_alq + cs_data->jnl_deq > cs_data->autoswitchlimit) cs_data->jnl_alq = cs_data->autoswitchlimit; #else cs_data->autoswitchlimit = JNL_ALLOWED(cs_data) ? ALIGNED_ROUND_DOWN(JNL_ALLOC_MAX, cs_data->jnl_alq, cs_data->jnl_deq) : 0; - cs_data->jnl_buffer_size = gv_cur_region->jnl_buffer_size; #endif - if (JNL_ALLOWED(cs_data) && !cs_data->jnl_buffer_size) - cs_data->jnl_buffer_size = JNL_BUFFER_DEF; + if (!cs_data->jnl_buffer_size) + ROUND_UP_JNL_BUFF_SIZE(cs_data->jnl_buffer_size, JNL_BUFFER_DEF, cs_data); + if (JNL_ALLOWED(cs_data)) + if (cs_data->jnl_buffer_size < JNL_BUFF_PORT_MIN(cs_data)) + { + ROUND_UP_MIN_JNL_BUFF_SIZE(cs_data->jnl_buffer_size, cs_data); + } else if (cs_data->jnl_buffer_size > JNL_BUFFER_MAX) + { + ROUND_DOWN_MAX_JNL_BUFF_SIZE(cs_data->jnl_buffer_size, cs_data); + } cs_data->def_coll = gv_cur_region->def_coll; if (cs_data->def_coll) { @@ -240,7 +251,7 @@ void mucregini(int4 blk_init_size) * this is because the macro relies on max_tn/max_tn_warn being set and that does not happen * until a few lines later. hence keeping it simple here by doing a plain assignment of curr_tn. */ - cs_data->max_tn = MAX_TN_V5; + cs_data->max_tn = MAX_TN_V6; SET_TN_WARN(cs_data, cs_data->max_tn_warn); SET_LATCH_GLOBAL(&cs_data->next_upgrd_warn.time_latch, LOCK_AVAILABLE); } diff --git a/sr_port/muextr.h b/sr_port/muextr.h index 79c5610..33f0287 100644 --- a/sr_port/muextr.h +++ b/sr_port/muextr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -60,19 +60,31 @@ typedef muext_hash_hdr *muext_hash_hdr_ptr_t; #ifdef UNIX #define V4_BIN_HEADER_VERSION "4" #define V4_BIN_HEADER_LABEL "GDS BINARY EXTRACT LEVEL "V4_BIN_HEADER_VERSION -#define BIN_HEADER_VERSION "5" +#define V5_BIN_HEADER_VERSION "5" +#define V5_BIN_HEADER_SZ 92 /* V4 (GTM V5.0) binary header stores null collation information [5 bytes numeric] */ +#define V5_BIN_HEADER_NUMSZ 5 +#define V5_BIN_HEADER_LABEL "GDS BINARY EXTRACT LEVEL "V5_BIN_HEADER_VERSION +#define V5_BIN_HEADER_RECOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + V5_BIN_HEADER_NUMSZ) +#define V5_BIN_HEADER_KEYOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + 2 * V5_BIN_HEADER_NUMSZ) +#define V5_BIN_HEADER_NULLCOLLOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + 3 * V5_BIN_HEADER_NUMSZ) +#define BIN_HEADER_VERSION "6" /* spanning nodes allow max_rec_len to 7 digits*/ +#define BIN_HEADER_LABEL "GDS BINARY EXTRACT LEVEL "BIN_HEADER_VERSION +#define BIN_HEADER_VERSION_ENCR "7" /* follow convention of low bit of version indicating encryption */ +#define BIN_HEADER_LABEL_ENCR "GDS BINARY EXTRACT LEVEL "BIN_HEADER_VERSION_ENCR +#define BIN_HEADER_SZ 100 +#define BIN_HEADER_NUMSZ 7 #else #define BIN_HEADER_VERSION "4" +#define BIN_HEADER_NUMSZ 5 +#define BIN_HEADER_SZ 92 /* V4 (GTM V5.0) binary header stores null collation information [5 bytes numeric] */ #endif #define BIN_HEADER_LABEL "GDS BINARY EXTRACT LEVEL "BIN_HEADER_VERSION #define BIN_HEADER_DATEFMT "YEARMMDD2460SS" -#define BIN_HEADER_NUMSZ 5 #define BIN_HEADER_LABELSZ 32 #define BIN_HEADER_BLKOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT)) #define BIN_HEADER_RECOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + BIN_HEADER_NUMSZ) #define BIN_HEADER_KEYOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + 2 * BIN_HEADER_NUMSZ) #define BIN_HEADER_NULLCOLLOFFSET (STR_LIT_LEN(BIN_HEADER_LABEL) + STR_LIT_LEN(BIN_HEADER_DATEFMT) + 3 * BIN_HEADER_NUMSZ) -#define BIN_HEADER_SZ 92 /* V4 (GTM V5.0) binary header stores null collation information [5 bytes numeric] */ #define V3_BIN_HEADER_SZ 87 #define EXTR_HEADER_LEVEL(extr_lbl) *(extr_lbl + SIZEOF(BIN_HEADER_LABEL) - 2) /* the assumption here is - level wont go beyond a single char representation */ diff --git a/sr_port/mupint.h b/sr_port/mupint.h index 27b00fa..9c7f522 100644 --- a/sr_port/mupint.h +++ b/sr_port/mupint.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,6 +40,27 @@ typedef struct } sub_num; #endif +enum sn_type +{ + SN_NOT = 0, + SPAN_NODE, + SN_CHUNK +}; + +typedef struct struct_spanode_integ{ + uint4 sn_type; /* 0: not in spanning node. 1: spanning node. 2:spanning fragment*/ + uint4 span_prev_blk; /* Left sibling of current block of spanning node */ + uint4 span_blk_cnt; /* Count of the blocks of spanning node seen so far */ + uint4 span_tot_blks; /* Total blks in the spanning nodes to be integ-checked */ + uint4 span_node_sz; /* Size of the spanning node value */ + uint4 span_frag_off; /* Spanning node fragment offset */ + uint4 key_len; /* Length of the key of spanning node */ + uint4 val_len; /* Length of the val of spanning node */ + uint4 sn_cnt; /* Spanning node count */ + uint4 sn_blk_cnt; /* Count of the blocks used by the spanning node */ +unsigned char span_node_buf[MAX_KEY_SZ]; /* Spanning node key */ +}span_node_integ; + boolean_t mu_int_blk(block_id blk, char level, boolean_t is_root, unsigned char *bot_key, int bot_len, unsigned char *top_key, int top_len, boolean_t eb_ok); boolean_t mu_int_fhead(void); diff --git a/sr_port/mupip.hlp b/sr_port/mupip.hlp index 1092a83..906036f 100644 --- a/sr_port/mupip.hlp +++ b/sr_port/mupip.hlp @@ -1,2180 +1,7131 @@ -1 BACKUP - B[ACKUP] - BACKUP copies blocks from one or more Greystone Technology Database - Structure (GDS) files to a new file or files. BACKUP suspends updates - to all regions specified by the BACKUP command from the time it starts - the first region until it finishes the last region. This ensures that - BACKUP captures a consistent application state. BACKUP does not - suspend processes that only perform retrievals. +1 Introduction + Introduction - The format of the BACKUP command is: + GT.M uses M Peripheral Interchange Program (MUPIP) for GT.M database + management, database journaling, and logical multisite replication (LMS). + This chapter summarizes the MUPIP commands pertaining to GT.M database + management and serves as a foundation for more advanced GT.M functionality + described for Journaling and LMS. - B[ACKUP][-qualifier[...]] region-list[,...] file-spec - + **Note** - By default, BACKUP is -COMPREHENSIVE. + Two MUPIP operations - INTRPT and STOP - perform process management + functions. All other MUPIP operations relate to the operation of the + database. - The first argument may specify more than one region of the current - Global Directory in a list separated with commas. + The GT.M installation procedure places the MUPIP utility program in a + directory specified by $gtm_dist. - To BACKUP only one region, the file-specification must resolve to a - UNIX file or directory name. To BACKUP several regions, the - file-specification must be a directory specification. If the - file-specification is a directory, MUPIP assigns the backup files the - same name as the file associated with the dynamic segment of each - region. Therefore, the target directory must not contain any of the - regions included in the BACKUP. + Invoke MUPIP by executing the mupip program at the shell prompt. If this + does not work, consult your system manager (MUPIP requires that the + $gtm_dist point to the directory containing the MUPIP executable image). -2 Qualifiers --COMPREHENSIVE - -C[OMPREHENSIVE] - Specifies that BACKUP copy the entire file from disk to disk. On - completion, the result is ready for use as a GT.M database. This - option does not support operation to magnetic tape. + $gtm_dist/mupip + MUPIP> - BACKUP -COMPREHENSIVE has the following advantages: + MUPIP asks for commands, with the MUPIP> prompt. Enter the EXIT command at + the MUPIP> prompt to stop the utility. MUPIP performs one operation at a + time, and automatically terminates after most operations. - o It does not require exclusive access to the file + When additional information appears on the command line after the mupip + program name, MUPIP processes the additional information as its command, + for example: - o It can interlock multiple files simultaneously + $gtm_dist/mupip stop 1158 - The -COMPREHENSIVE qualifier is not compatible with any other - qualifier. + This starts MUPIP and stops the process with Process ID (PID) 1158. - By default, BACKUP operates -COMPREHENSIVE. + Some MUPIP commands require information contained in the global directory. + Therefore, a process must have access to a valid global directory before + using any MUPIP commands other than EXIT, INTRPT, JOURNAL, RESTORE, STOP + and the -file option of any command that has that option. --INCREMENTAL - -I[NCREMENTAL] - Specifies that BACKUP include only blocks from the database that - have changed since a prior point specified by the -SINCE or - -TRANSACTION qualifier. MUPIP RESTORE integrates the results of - a BACKUP -INCREMENTAL into a database. + The environment variable gtmgbldir specifies the active global directory. - The -INCREMENTAL qualifier is not compatible with the - -COMPREHENSIVE qualifier. + A gtmgbldir value of mumps.gld tells MUPIP to look for a global directory + file mumps.gld in the current directory. See the "Global Directory Editor" + chapter for more information on the global directory. --RECORD - -R[ECORD] - Specifies that the BACKUP utility record this backup as a - reference point for subsequent backups. Each time a BACKUP - specifies -RECORD, that backup replaces the previous recorded - backup as the RECORD reference point for the file. +2 Operations + Operations --SINCE - -S[INCE]=keyword - Specifies that a BACKUP -INCREMENTAL includes blocks changed - since the last specified BACKUP. + While most MUPIP operations can be performed when GT.M processes are + actively accessing database files, some operations require stand-alone + access. When using standalone access, no other process can access the + database file(s). When using concurrent access, other processes can read + or update the database file(s) while MUPIP accesses them. A few operations + permit concurrent access to read database files, but not to update them. + All MUPIP operations can be performed with stand-alone access - there is + never a requirement for another process to be accessing database files + when MUPIP operates on them. - -SINCE accepts the keywords: + Most MUPIP operations require write access to the database files with + which they interact. The exceptions are INTRPT and STOP, which do not + require database access, but may require other privileges; EXTRACT, which + requires read access; and INTEG, which may require write access, depending + on the circumstances it encounters and the qualifiers with which it is + invoked. The following table displays some of the MUPIP operations and + their database access requirements. - o C[OMPREHENSIVE] - Backup all changes since the last BACKUP - -COMPREHENSIVE + +------------------------------------------------------------------------+ + | Operations | MUPIP command | Database Access Requirements | + |------------------------+---------------+-------------------------------| + | | | Backup never requires | + | Backup database files | MUPIP BACKUP | standalone access and | + | | | concurrent write access is | + | | | controlled by -[NO]ONLINE. | + |------------------------+---------------+-------------------------------| + | Create and initialize | MUPIP CREATE | Standalone access | + | database files | | | + |------------------------+---------------+-------------------------------| + | Converts a database | | | + | file from one endian | MUPIP | | + | format to the other | ENDIANCVT | Standalone access | + | (BIG to LITTLE or | | | + | LITTLE to BIG) | | | + |------------------------+---------------+-------------------------------| + | Recover database files | | | + | (for example, after a | | | + | system crash) and | MUPIP JOURNAL | Standalone access | + | extract journal | | | + | records | | | + |------------------------+---------------+-------------------------------| + | Restore databases from | | | + | bytestream backup | MUPIP RESTORE | Standalone access | + | files | | | + |------------------------+---------------+-------------------------------| + | Properly close | | | + | database files when | MUPIP RUNDOWN | Standalone access | + | processes terminate | | | + | abnormally. | | | + |------------------------+---------------+-------------------------------| + | | | Standalone access is required | + | | | if the MUPIP SET command | + | Modify database and/or | | specifies -ACCESS_METHOD, | + | journal file | MUPIP SET | -GLOBAL_BUFFERS, LOCK_SPACE | + | characteristics | | or -NOJOURNAL, or if any of | + | | | the -JOURNAL options ENABLE, | + | | | DISABLE, or BUFFER_SIZE are | + | | | specified. | + |------------------------+---------------+-------------------------------| + | Backup database files | MUPIP BACKUP | Concurrent access. | + |------------------------+---------------+-------------------------------| + | Grow the size of BG | MUPIP EXTEND | Concurrent access. | + | database files | | | + |------------------------+---------------+-------------------------------| + | | | Although MUPIP EXTRACT | + | | | command works with concurrent | + | Export data from | | access, it implicitly freezes | + | database files into | | the database to prevent | + | sequential (flat) or | MUPIP EXTRACT | updates. Therefore, from an | + | binary files | | application standpoint, you | + | | | might plan for a standalone | + | | | access during a MUPIP EXTRACT | + | | | operation. | + |------------------------+---------------+-------------------------------| + | Prevent updates to | MUPIP FREEZE | Standalone access. | + | database files | | | + |------------------------+---------------+-------------------------------| + | | | Concurrent access. However, | + | Check the integrity of | MUPIP INTEG | standalone access is required | + | GDS databases | | if MUPIP INTEG specifies | + | | | -FILE. | + |------------------------+---------------+-------------------------------| + | | | Although MUPIP LOAD works | + | | | with concurrent access, you | + | | | should always assess the | + | Import data into | | significance of performing a | + | databases | MUPIP LOAD | MUPIP LOAD operation when an | + | | | application is running | + | | | because it may result in an | + | | | inconsistent application | + | | | state for the database. | + |------------------------+---------------+-------------------------------| + | Defragment database | | | + | files to improve | MUPIP REORG | Concurrent access. | + | performance | | | + |------------------------+---------------+-------------------------------| + | Send an asynchronous | | | + | signal to a GT.M | MUPIP INTRPT | Non-database access. | + | process | | | + |------------------------+---------------+-------------------------------| + | Stop GT.M processes | MUPIP STOP | Non-database access. | + +------------------------------------------------------------------------+ - o I[NCREMENTAL] - Backup all changes since the last BACKUP - -INCREMENTAL +2 Syntax + Syntax - o R[ECORD] - Backup all changes since the last BACKUP -RECORD - - The -SINCE qualifier is incompatible with the -COMPREHENSIVE and - -TRANSACTION qualifiers. + The general format of MUPIP commands is: - By default, BACKUP -INCREMENTAL operates -SINCE=COMPREHENSIVE. + mupip command [-qualifier[...]] [object[,...]] [destination] --TRANSACTION - -T[RANSACTION]=transaction-number - Specifies a hexadecimal starting transaction which causes BACKUP - -INCREMENTAL to copy all blocks that have been changed by the - specified and all subsequent transactions. Transaction numbers - appear in a DSE DUMP -FILEHEADER, with a "Current TN" label. If - the transaction number is invalid, BACKUP reports an error and - rejects the command. - - BACKUP -INCREMENTAL -TRANSACTION=1 copies all in-use blocks and - has the following advantages: + MUPIP allows the abbreviation of commands and qualifiers. In each section + describing a command or qualifier, the abbreviation is also shown (for + example, B[ACKUP]). The abbreviated version of the command you can use on + the command line is B. To avoid future compatibility problems and improve + the readability, specify at least four characters when using MUPIP + commands in scripts. - o It does not require exclusive access to the file + Although you can enter commands in both upper and lower case (the mupip + program name itself must be in lower case on UNIX/Linux), the + typographical convention used in this chapter is all small letters for + commands. Another convention is in the presentation of command syntax. If + the full format of the command is too long for a single line of print, the + presentation wraps around into additional lines. - o It can interlock multiple files simultaneously + mupip backup -bytestream -transaction=1 accounts,history,tables,miscellaneous /var/production/backup/ - Different regions do not normally have a single transaction - number that marks a meaningful point. Therefore, a BACKUP - command specifying multiple regions and using the -TRANSACTION - qualifier with arguments other than one (1) is unlikely to - produce desirable results. + When you enter a MUPIP command, one of its variable arguments is the + region-list. region-list identify the target of the command and may + include the UNIX wildcards "?" and "*". Region-lists containing UNIX + wildcard characters must always be quoted, for example, "*" to prevent + inappropriate expansion by the UNIX shell. Similarly, for file and + directory names you might want to avoid non-graphic characters and most + punctuations except underbars (_), not because of GT.M conventions but + because of inappropriate expansion by UNIX shells. - The -TRANSACTION qualifier is incompatible with the - -COMPREHENSIVE and -SINCE qualifiers. + MUPIP qualifier values are restricted only by the maximum size of the + command input line, which is 4KB on some systems and upto 64KB on others. -1 CREATE - CR[EATE] - CREATE generates database files using the characteristics stored in a - Global Directory by the Global Directory Editor (GDE). CREATE uses the - Global Directory to map a region to a segment and a segment to a file. - Use the MUPIP CREATE command to create a new database or a new copy of - a previously existing file during a database reorganization. If a - database file already exists for the segment, CREATE takes no action. - If a file does not exist, CREATE sets up the file. CREATE also - initializes the database structure (GDS). +1 GDM + GDM + + The MUPIP commands described in this seciton are used for common database + operations and serves as the foundation for more advanced functionality + like Journaling and Replication. + +2 BACKUP + BACKUP + + Saves the contents of the database. It provides a consistent application + snapshot across all database regions involved in the backup operation. + + The format of the MUPIP BACKUP command is: + + B[ACKUP] + [ + -BK[UPDBJNL]={DISABLE|OFF}] + -B[YTESTREAM] [-NET[TIMEOUT]] + -DA[TABASE] + -DBG + -[NO]NEWJNLFILES[=[NO]PREVLINK],[NO]S[YNC_IO]] + -O[NLINE] + -REC[ORD] + -REPL[ACE] + -REPLINSTANCE=target_location + -S[INCE]={DATABASE|BYTESTREAM|RECORD} + -T[RANSACTION]=hexadecimal_transaction_number + ] region-list[,...] destination-list + + **Important** + + MUPIP BACKUP does a more comprehensive job of managing backup activities + than other backup techniques such as a SAN backup, breaking a disk mirror, + or a file system snapshot because it integrates journal management, + instance file management, and records timestamps in the database file + headers. To use other techniques, you must first freeze all regions + concurrently with a command such as MUPIP FREEZE -ON "*" in order to + ensure a consistent copy of files with internal structural integrity. FIS + neither endorses nor tests any third party products for backing up a GT.M + database. + + o MUPIP BACKUP supports two methods of database backup: -BYTESTREAM and + -DATABASE. MUPIP BACKUP -BYTESTREAM directs the output to a broad + range of devices, including disks, TCP sockets, and pipes. MUPIP + BACKUP -DATABASE directs the output to random access devices (that is, + disks). + o [NO]ONLINE qualifier determines whether MUPIP BACKUP should suspend + updates to regions. For example, MUPIP BACKUP -NOONLINE suspends + updates to all regions from the time it starts the first region until + it finishes the last region. However, it does not suspend processes + that only read from the database. + o By default, MUPIP BACKUP is -DATABASE -ONLINE. + o If any region name does not map to an existing accessible file, or if + any element of the destination list is invalid, BACKUP rejects the + command with an error. + o region-list may specify more than one region of the current global + directory in a list. Regions are separated by a comma, and wildcards + can be used to specify them. Any region-name may include the wildcard + characters * and % (remember to escape them to protect them from + inappropriate expansion by the shell). Any region name expansion + occurs in M (ASCII) collation order. + o Depending on the type of backup, destination-list may be a single + directory, or a comma separated list of destinations including files, + piped commands, or TCP sockets. + o Region-list and destination-list items are matched in order - the + first region is mapped to the first destination, the second to the + second destination, and so on. If GT.M encounters a region mapped to a + directory, GT.M treats that directory as the destination for all + subsequent regions in the region-list. + o GT.M implicitly timestamps both BYTESTREAM and DATABASE backups using + relative timestamps (transaction numbers). You can also explicitly + specific a RECORD timestamp for custom-control (SANS or mirrored disk) + backup protocol. You might want to use these timestamps as reference + points for subsequent backups. + o It takes approximately one (1) minute (per region) for BACKUP -ONLINE + to give up and bypass a KILLs in progress; backup does not wait for + Abandoned Kills to clear. + o The environment variable gtm_baktmpdir specifies the directory where + mupip backup creates temporary files. If gtm_baktmpdir is not defined, + GT.M uses the deprecated GTM_BAKTMPDIR environment variable if + defined, and otherwise uses the current working directory. + o When you restrict access to a database file, GT.M propagates those + restrictions to shared resources associated with the database file, + such as semaphores, shared memory, journals and temporary files used + in the course of MUPIP BACKUP. + o GT.M supports only one concurrent -ONLINE backup on a database. MUPIP + BACKUP displays the BKUPRUNNING message if started when there is an + already running BACKUP. + o MUPIP BACKUP protects against overwriting of existing destination + files. However, it cannot protect other destinations, for example, if + the destination is a pipe into a shell command that overwrites a file. + + Before starting a MUPIP BACKUP + + Perform the following tasks before you begin a database backup. + + o Ensure adequate disk space for target location and temporary files. + Set the environment variable gtm_baktmpdir to specify the directory + where MUPIP BACKUP creates temporary files. If gtm_baktmpdir is not + defined, GT.M uses the deprecated GTM_BAKTMPDIR environment variable + if defined, and otherwise uses the current working directory. Do not + place temporary files in the current directory for large databases in + production environments. + o When using replication, ensure that the Source/Receiver process is + alive (MUPIP REPLIC -SOURCE/-RECEIVER -CHECKHEALTH). Always backup the + replicating instance file with the database (BACKUP -REPLINST). + o If you intend to use a -DATABASE backup at the same time in the same + computer system as the source database, be sure to disable journaling + in the backed up database with -BKUPDBJNL=DISABLE. + o When doing a complete backup, switch journal files as part of the + backup command using -NEWJNLFILES=NOPREVLINK. This aligns the journal + files with the backup and simplifies journal file retention. + o If you follow separate procedures for backup and archive (moving to + secondary storage), you can save time by starting archive as soon as + MUPIP BACKUP completes the process of creating a backup database file + for a region. You do not need to wait for MUPIP BACKUP to complete + processing for all regions before starting archive. For example, a + message like: + + DB file /home/jdoe/.fis-gtm/V6.0-001_x86_64/g/gtm.dat backed up in file /backup/gtm.dat + Transactions up to 0x0000000000E92E04 are backed up. + + confirms that gtm.dat is backed up correctly and is ready for archive. + + o Determine an appropriate frequency, timing, and backup method + (-BYTESTREAM or -COMPREHENSIVE) based on the situation. + o Ensure the user issuing backup commands has appropriate permissions + before starting the backup. Backup files hav e the ownership of the + user running MUPIP BACKUP. + o There is one circumstance under which a MUPIP BACKUP is not advised. + When your operational procedures call for taking backups of unmodified + databases and journal files on rebooting a system after a crash, then + use an underlying operating system command (cp, cpio, gzip, tar, and + so on) which will open the files read-only. Note that for ordinary + system crashes where the system simply stops writing to open files at + power down, you can use MUPIP JOURNAL to recover journaled database + files, and taking backups on reboot should not be required. However, + for system crashes with the possibility of damage to files already + written to disk (for example, if the crash involved an IO controller + with the potential for having written random data to disk immediately + prior to power down), such backups on reboot are appropriate. + + Example: + + $ mupip backup "*" /gtm/bkup + + This example creates ready-to-run database backup of all regions. + +3 BKupdbjnl + BKupdbjnl + + A backup database shares the same journaling characteristics of the source + database. However, with BKUPDBJNL you can disable or turns off journaling + in the backup database. Use this qualifier if you intend to open your + backup database at the same time in the same environment as the source + database. + + The format of the BKUPDBJNL qualifier is: + + -BK[UPDBJNL]={DISABLE|OFF} + + o Specify DISABLE to disable journaling in the backup database. + o Specify OFF to turn off journaling is in the backup database. + o Only one of the qualifiers DISABLE or OFF can be specified at any + given point. + +3 Bytestream + Bytestream + + Ttransfers MUPIP BACKUP output to a TCP connection, file (or a backup + directory), or a pipe. If there are multiple .dat files, BYTESTREAM + transfers output to a comma separated list of TCP connections, incremental + backup files and/or directories, or pipes. When used with -SINCE or + -TRANSACTION, MUPIP BACKUP allow incremental backup, that is, include + database blocks that have changed since a prior point specified by the + -SINCE or -TRANSACTION. + + **Note** + + MUPIP BACKUP output to a TCP connection saves disk I/O bandwidth on the + current system. + + All bytream backups needs to be restored to a random access file (with + MUPIP RESTORE) before being used as a database file. -BYTESTREAM can also + send the output directly to a listening MUPIP RESTORE process via a TCP/IP + connection or a pipe. + + The format of the BYTESTREAM qualifier is: + + -B[YTESTREAM] + + o -BYTESTREAM is compatible with -SINCE and -TRANSACTION. + o -INCREMENTAL is deprecated in favor of -BYTESTREAM. For upward + compatibility, MUPIP temporarily continues to support the deprecated + -INCREMENTAL. + +3 Database + Database + + Creates a disk-to-disk backup copy of the files of all selected regions. + DATABASE backup copy is a ready-to-use a GT.M database unlike BYTESREAM + backup which is required to be restored to a random access file. + + **Note** + + The DATABASE qualifier does not support backup to magnetic tape. + + The format of the DATABASE qualifier is: + + -D[ATABASE] + + o By default, MUPIP BACKUP uses -DATABASE. + o The DATABASE qualifier is only compatible with the -[NO]NEW[JNLFILES], + -ONLINE, and -RECORD qualifiers. + o -COMPREHENSIVE is depreciated in favor of -DATABASE. For upward + compatibility, MUPIP temporarily continues to support the deprecated + -COMPREHENSIVE. + +3 NETtimeout + NETtimeout + + Specifies the timeout period when a bytestream BACKUP data is sent over a + TCP/IP connection. The format of the NETTIMEOUT qualifier is: + + NET[TIMEOUT]=seconds + + o The default value is 30 seconds. + o Use only with: -BYTESTREAM. + +3 NEWJNLFILES + NEWJNLFILES + + Determines the journaling charactertistics of the database files being + backed-up. All the established journaling characteristics apply to new + journal files. This qualifier is effective only for an ONLINE backup (the + default), when the database has journaling enabled. + + The format of the NEWJNLFILES qualifier is: + + -[NO]NEWJNLFILES[=[NO]PREVLINK], [NO]S[YNC_IO]] + + o -NEWJNLFILES can take the following three values: + + o PREVLINK: Back links new journal files with the prior generation + journal files. This is the default value. + o NOPREVLINK: Indicates that there should be no back link between + the newly created journals and prior generation journal files. + o SYNC_IO: Specifies that every WRITE to a journal file to be + committed directly to disk. On high-end disk subsystems (for + example, those that include non-volatile cache and that consider + the data to be committed when it reaches this cache), this might + result in better performance than the NOSYNC_IO option. NOSYNC_IO + turn off this option. + + o -NONEWJNLFILES causes journaling to continue with the current journal + files. It does not accept any arguments. + o The default is -NEWJNLFILES=PREVLINK. + +3 Online + Online + + Specifies that while a MUPIP BACKUP operation is active, other processes + can update the database without affecting the result of the backup. The + format of the ONLINE qualifier is: + + -[NO]O[NLINE] + + o MUPIP BACKUP -ONLINE creates a backup of the database as of the moment + the backup starts. If the running processes subsequently update the + database, the backup does not reflect those updates. + o MUPIP BACKUP -ONLINE on regions(s) waits for up to one minute so any + concurrent KILL or MUPIP REORG operations can complete. If the KILL or + MUPIP REORG operations do not complete within one minute, MUPIP BACKUP + -ONLINE starts the backup with a warning that the backup may contain + incorrectly marked busy blocks. Such blocks waste space and can + desensitize operators to much more dangerous errors, but otherwise + don't affect database integrity. If you get such an error, it may be + better to stop the backup and restart it when KILL or MUPIP REORG + operations are less likely to interfere. Performing MUPIP STOP on a + process performing a KILL or MUPIP REORG operation may leave the + database with incorrectly marked busy blocks. In this situation, GT.M + converts the ongoing KILLs flag to abandoned KILLs flag. If MUPIP + BACKUP -ONLINE encounters ADANDONED_KILLS, it gives a message and then + starts the backup. An ABANDONED_KILLS error means both the original + database and the backup database possibly have incorrectly busy blocks + which should be corrected promptly. + o By default, MUPIP BACKUP is -ONLINE. + +3 Record + Record + + Timestamps (in the form of a transaction number) a database file to mark a + reference point for subsequent bytestream, database, or custom backup + (SANS or disk mirror) protocols. Even though -DATABASE and -BYTESTREAM + both mark their own relative timestamps, -RECORD provides an additional + timestamp option. MUPIP FREEZE also provides the -RECORD qualifier because + a FREEZE may be used to set the database up for a SAN or disk-mirror based + backup mechanism. + + The format of the RECORD qualifier is: + + -R[ECORD] + + o Use -RECORD (with the hypen) to timpestamp a refererence point and use + RECORD as a keyword (as in -SINCE=RECORD) to specific the starting + point for a MUPIP BACKUP operation. + o -RECORD replaces the previously RECORDed transaction identifier for + the database file. + +3 REPLace + REPLace + + Overwrites the existing destination files. + + The format of the REPLACE qualifier is: + + -[REPL]ACE + + o By default, MUPIP BACKUP protect against overwriting the destination + files. -REPLACE disables this default behavior. + o -REPLACE is compatible only with -DATABASE. + +3 REPLInstance + REPLInstance + + Specifies the target location to place the backup of the replication + instance file. + + **Note** + + The replication instance file should always be backed up with the database + file. + + The format of the REPLINSTANCE qualifier is: + + -REPLI[NSTANCE]= + +3 Since + Since + + Includes blocks changed since the last specified backup. The format of the + SINCE qualifier is: + + -S[INCE]={DATABASE|BYTESTREAM|RECORD} + + o keyword can include any one of the following: + + o D[ATABASE] - Backup all changes since the last MUPIP BACKUP + -DATABASE. + o B[YTESTREAM] - Backup all changes since the last MUPIP BACKUP + -BYTESTREAM. + o R[ECORD] - Backup all changes since the last MUPIP BACKUP + -RECORD. + + o By default, MUPIP BACKUP -BYTESTREAM operates as -SINCE=DATABASE. + o Incompatible with: -TRANSACTION. + +3 Transaction + Transaction + + Specifies the transaction number of a starting transaction that causes + BACKUP -BYTESTREAM to copy all blocks that have been changed by that + transaction and all subsequent transactions. The format of the TRANSACTION + qualifier is: + + -T[RANSACTION]=transaction-number + + o A Transaction number is always 16 digit hexadecimal number. It appears + in a DSE DUMP -FILEHEADER with the label "Current transaction". + o If the transaction number is invalid, MUPIP BACKUP reports an error + and rejects the command. + o It may be faster than a DATABASE backup, if the database is mostly + empty. + o Incompatible with: -DATABASE, -SINCE + + **Note** + + A point in time that is consistent from an application perspective is + unlikely to have the same transaction number in all database regions. + Therefore, except for -TRANSACTION=1, this qualifier is not likely to be + useful for any backup involving multiple regions. + +3 Examples + Examples + + Example: + + $ mupip backup -bytestream REPTILES,BIRDS bkup + + Suppose that the environment variable gtmgbldir has regions REPTILES and + BIRDS that map to files called REPTILES.DAT and BIRDS.DAT (no matter which + directory or directories the files reside in). Then the above example + creates bytestream backup files REPTILES.DAT and BIRDS.DAT in the bkup + directory since the last DATABASE backup. + + Example: + + $ mupip backup -bkupdbjnl="OFF" "*" + + This command turns off journaling in the backup database. + + Example: + + $ mupip backup -bytestream "*" tcp://philadelphia:7883,tcp://tokyo:8892 + + Assuming a Global Directory with two regions pointing to ACN.DAT and + HIST.DAT, this example creates a backup of ACN.DAT to a possible MUPIP + RESTORE process listening at port 7883 on server philadelphia and HIST.DAT + to a possible MUPIP RESTORE process listening at port 8893 on server + tokyo. + + Always specify the and even if both backup and + restore are on the same system, and ensure that the MUPIP RESTORE process + is started before the MUPIP BACKUP process. + + Example: + + $ 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 + current database in directory bkup. GT.M freezes all the regions during + the backup operation. + + Example: + + $ mupip backup -bytestream -nettimeout=420 DEFAULT tcp://${org_host}:6200 + + This command creates a backup copy of the DEFAULT region with timeout of + 420 seconds. + + Example: + + $ mupip backup -bytestream DEFAULT '"| gzip -c > online5pipe.inc.gz"' + + This command sends (via a pipe) the backup of the DEFAULT region to a gzip + command. + + Example: + + $ 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 + database in directory bkup. During the backup operation, other processes + can read and update the database. + + Example: + + $ mupip backup -record DEFAULT bkup + + This command sets a reference point and creates a backup copy of the + DEFAULT region of the current database in directory bkup. + + Example: + + $ mupip backup -online -record DEFAULT bkup1921 + DB file /home/reptiles/mumps.dat backed up in file bkup1921/mumps.dat + Transactions up to 0x00000000000F4351 are backed up. + + Example: + + $ mupip backup -bytestream -since=record DEFAULT bkup1921onwards + MUPIP backup of database file /home/reptiles/mumps.dat to bkup1921onwards/mumps.dat + 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 + DEFAULT region of the current database in directory bkup1921. The second + command completes a bytestream backup starting from the reference point + set by the first command. + + Example: + + $ mupip backup -bytestream -transaction=1 DEFAULT bkup_dir + MUPIP backup of database file /gtmnode1/gtmuser1/mumps.dat to bkup_dir/mumps.dat + 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 + database to directory bkup_dir. + + Example: + + $ mupip backup -newjnlfiles=noprevlink,sync_io "*" backupdir + + This example creates new journal files for the current regions, cuts the + previous journal file link for all regions in the global directory, + enables the SYNC_IO option and takes a backup of all databases in the + directory backupdir. + +2 CREATE + CREATE + + Creates and initializes database files using the information in a Global + Directory file. If a file already exists for any segment, MUPIP CREATE + takes no action for that segment. The format of the CREATE command is: CR[EATE] [-R[EGION]=region-name] - - The optional -REGION qualifier specifies a single region for which to + + The single optional -REGION qualifier specifies a region for which to create a database file. - By default, CREATE sets up database files for all regions in the - current Global Directory. + Note that one GT.M database file grows to a maximum size of 224M + (234,881,024) blocks. This means, for example, that with an 8KB block + size, the maximum single database file size is 1,792GB (8KB*224M). Note + that this is the size of one database file -- a logical database (an M + global variable name space) can consist of an arbitrary number of database + files. -2 Qualifiers --REGION - -R[EGION]=region-name - Specifies a single region for creation of a database file. By - default, CREATE sets up (creates) database files for all regions - in the current Global Directory. +3 Region + Region -1 EXIT - EXI[T] - EXIT terminates MUPIP and returns control to the point where MUPIP was - invoked. This command is useful when you invoke MUPIP without an - action and wish to leave without performing one, or after using MUPIP - HELP. + Specifies a single region for creation of a database file. By default, + MUPIP CREATE creates database files for all regions in the current Global + Directory that do not already have a database file. - The format of the EXIT command is: + The format of the REGION qualifier is: + + -R[EGION]=region-name + +3 Examples + Examples + + Example: + + $ mupip create -region=REPTILES + + This command creates the database file specified by the Global Directory + (named by the GT.M Global Directory environment variable) for region + REPTILES. + +2 DOWNGRADE + DOWNGRADE + + The MUPIP DOWNGRADE command changes the file header format to V4 or V5. + The format of the MUPIP DOWNGRADE command is: + + D[OWNGRADE] -V[ERSION]={V4|V5} file-name + + For V4: + + o It reduces the size from 8 bytes to 4 bytes for fields like current + transaction (CTN), maximum tn (MTN) and others that contain + transaction numbers. + o It removes the results of any prior DBCERTIFY run on the database. + o You cannot downgrade a V5 database which has standard null collation. + In such a case, perform a MUPIP EXTRACT -FORMAT=ZWR operation on the + V5 database and then perform a MUPIP LOAD operation on a V4 database. + +3 VERSION + VERSION + + Specifies file header format. For more information on the downgrade + criteria for your database, refer to the release notes document of your + current GT.M version. + +3 Examples + Examples + + Example: + + $ mupip downgrade mumps.dat + + This command changes the file-header of mumps.dat to V4 format. + +2 ENDIANCVT + ENDIANCVT + + Converts a database file from one endian format to the other (BIG to + LITTLE or LITTLE to BIG). The format of the MUPIP ENDIANCVT command is: + + ENDIANCVT [-OUTDB=] -OV[ERRIDE] + + o is the source database for endian conversion. By default + ENDIANCVT converts in place. + o outdb writes the converted output to . In this case, + ENDIANCVT does not modify the source database . + o ENDIANCVT produces a of exactly the same size as + . + + **Important** + + Ensure adequate storage for to complete the endian + conversion successfully. + + o ENDIANCVT requires standalone access to the database. + o GT.M displays a confirmation request with the "from" and "to" endian + formats to perform the conversion. Conversion begins only upon + receiving positive confirmation, which is a case insensitive "yes". + o In a multi-site replication configuration, the receiver server + automatically detects the endian format of an incoming replication + stream and converts it into the native endian format. See Database + Replication chapter for more information. + o Encrypted database files converted with ENDIANCVT require the same key + and the same cipher that were used to encrypt them. + + **Note** + + GT.M on a big endian platform can convert a little endian database into + big endian and vice versa; as can GT.M on a little endian platform. GT.M + (run-time and utilities other than MUPIP ENDIANCVT) on a given endian + platform opens and processes only those databases that are in the same + endian format. An attempt to open a database of a format other than the + native endian format produces an error. + +3 OVerride + OVerride + + Enables MUPIP ENDIANCVT to continue operations even if GT.M encounters the + following errors: + + o "minor database format is not the current version" + o "kills in progress" + o "a GT.CM server is accessing the database" + + Note that the OVERRIDE qualifier does not override critical errors + (database integrity errors, and so on) that prevent a successful endian + format conversion. + +3 Examples + Examples + + $ 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 + other endian format if you type yes to confirm. + +2 EXIT + EXIT + + Stops a MUPIP process and return control to the process from which MUPIP + was invoked. + + The format of the MUPIP EXIT command is: EXI[T] - The Exit command does not accept any qualifiers. + The EXIT command does not accept any qualifiers. -1 EXTEND - EXTE[ND] - EXTEND expands a GDS database file. Databases generally extend - automatically, but this command allows you to control the time and - amount of extension. +2 EXTEND + EXTEND - The format of the EXTEND command is: + Increases the size of a database file. By default, GT.M automatically + extends a database file when there is available space. - EXTE[ND] region-name [-B[LOCKS]=blocks] - - The required region-name parameter specifies the name of the region to - expand. EXTEND uses the Global Directory to map the region to the - dynamic segment and the segment to the file. + The format of the MUPIP EXTEND command is: -2 Qualifiers --BLOCKS - -B[LOCKS]=blocks - Specifies the number of GDS database blocks by which GT.M should - extend the file. GDS files use some blocks for bit maps. EXTEND - adds the specified number of blocks and the bit map blocks - required as overhead. For more information about bit maps, refer - to the "GDS" chapter of the GT.M Administration and Operations - Guide. + EXTE[ND] [-BLOCKS=] region-name - EXTEND uses the value in the fileheader as the number of GDS - blocks by which to extend the database file. + o The only qualifier for MUPIP EXTEND is BLOCKS. + o The required region-name parameter specifies the name of the region to + expand. + o EXTEND uses the Global Directory to map the region to the dynamic + segment and the segment to the file. -1 EXTRACT - EXTR[ACT] - EXTRACT copies specified globals from the current database to a - sequential output file in one of two formats (i.e., GO, or BINARY). - Use EXTRACT to back up specific globals or when extracting data from - the database for use by another system. EXTRACT uses the Global - Directory to determine which database files to use. EXTRACT may - operate concurrently with normal GT.M database access. To ensure that - an EXTRACT reflects a consistent application state, suspend database - updates to all regions involved in the extract with the -FREEZE - qualifier. +3 Blocks + Blocks - The format of the EXTRACT command is: + 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: - EXTR[ACT][-qualifier[...]] file-specification + -BLOCKS=data-blocks-to-add - EXTRACT places its output in the file defined by the - file-specification. EXTRACT may output to a UNIX file on any device - that supports such files, including magnetic tapes. Note that magnetic - tapes may have a smaller file maximum size than disks. - produces a status message from EXTRACT. Entering twice in - quick succession aborts EXTRACT. An EXTRACT terminated abnormally by - operator action or error produces incomplete output. + By default, EXTEND uses the extension value in the file header as the + number of GDS blocks by which to extend the database file. You can specify + as many blocks as needed as long as you are within the maximum total + blocks limit (which could be as high as 224 million GDS blocks). -2 Qualifiers --SELECT - -S[ELECT]=global-name-list - Specifies the globals to extract. The "^" in the specification - of the global name is optional. Enclose lowercase global names - in quotes (""). +3 Examples + Examples - The global-specification can be: + $ mupip extend DEFAULT -blocks=400 - o A global name, such as MEF + This command adds 400 GDE database block to region DEFAULT. - o A range of global names, such as A7:B6 + Example: - o A list, such as A,B,C + $ mupip extend REPTILES -blocks=100 - o Global names with the same prefix, such as TMP* + This command adds 100 GDE database blocks to the region REPTILES. - In the first case, EXTRACT selects only global ^MEF. In the - second case, EXTRACT selects all global names between ^A7 and - ^B6, inclusive. In the third case, EXTRACT selects globals ^A, - ^B, and ^C. In the fourth case, EXTRACT selects all global names - from ^TMP through ^TMPzzzzz. +2 EXTRACT + EXTRACT - By default, EXTRACT selects all globals, as if it had the - qualifier -SELECT=*. + Backups certain globals or to extract data from the database for use by + another system. The MUPIP EXTRACT command copies globals from the current + database to a sequential output file in one of three formats-GO, BINARY, + or ZWR. The format of the EXTRACT command is: --FORMAT - -FO[RMAT]=GO|B[INARY] - Specifies the format of the output file. + EXTR[ACT] + [ + -FO[RMAT]={GO|B[INARY]|Z[WR]} + -FR[EEZE] + -LA[BEL]=text + -[NO]L[OG] + -S[ELECT]=global-name-list] + ] + {-ST[DOUT]|file-name} - The format codes are: + o By default, MUPIP EXTRACT uses -FORMAT=ZWR. + o MUPIP EXTRACT uses the Global Directory to determine which database + files to use. + o MUPIP EXTRACT supports user collation routines. When used without the + -FREEZE qualifier, EXTRACT may operate concurrently with normal GT.M + database access. + o To ensure that MUPIP EXTRACT reflects a consistent application state, + suspend the database updates to all regions involved in the extract, + typically with the FREEZE qualifier, or backup the database with the + ONLINE qualifier and extract files from the backup. + o EXTRACT places its output in the file defined by the file- name. + EXTRACT may output to a UNIX file on any device that supports such + files, including magnetic tapes. + o In UTF-8 mode, MUPIP EXTRACT write sequential output file in the UTF-8 + character encoding. Ensure that MUPIP EXTRACT commands and + corresponding MUPIP LOAD commands execute with the same setting for + the environment variable gtm_chset. - o GO - Global Output format, used for files you want to - transport or archive + **Note** - o B[INARY] - Binary format, used for database reorganization - or short term backups + Magnetic tapes may have a smaller maximum file size than disks. - -FORMAT=GO stores the data in record pairs. Each global node - produces one record for the key and one for the data. FORMAT=GO - has two header records. + For information on extracting globals with the %GO utility, refer to "M + Utility Routines" chapter of the GT.M Programmer's Guide. MUPIP EXTRACT is + typically faster, but %GO can be customized. - -FORMAT=BINARY only applies for Greystone Technology Database - Structure (GDS) files. EXTRACT -FORMAT=BINARY works much faster - than EXTRACT -FORMAT=GO. + The following sections describe the qualifiers of MUPIP EXTRACT command. - By default, EXTRACT uses -FORMAT=GO. +3 FOrmat + FOrmat --FREEZE - -FR[EEZE] - Prevents database updates to all regions of the Global Directory - used by the EXTRACT for the duration of the EXTRACT. + Specifies the format of the output file. The format of the FORMAT + qualifier is: - By default, EXTRACT does not freeze regions during operation. + -FO[RMAT]=format_code --LABEL - -LA[BEL]=text - Specifies a text string which becomes the first record in the - output file. Enclose labels containing punctuation or lowercase - labels in quotes (""). EXTRACT -FORMAT=BINARY truncates the - label text to 32 characters. + The format code is any one of the following: - By default, EXTRACT uses the label "GT.M MUPIP EXTRACT". + o B[INARY] - Binary format, used for database reorganization or short + term backups. MUPIP EXTRACT -FORMAT=BINARY works much faster than + MUPIP EXTRACT -FORMAT=GO and MUPIP EXTRACT -FORMAT=ZWR. Note: There is + no defined standard to transport binary data from one GT.M + implementation to another. Further, FIS reserves the right to modify + the binary format in new versions. The first record of a BINARY format + data file contains the header label. The header label is 87 characters + long. The following table illustrates the components of the header + label. - For a description of the -FORMAT=BINARY header label, refer to - the subsequent section on EXTRACT -FORMAT=BINARY. + +--------------------------------------------------------------------+ + | BINARY Format Data File Header Label | + |--------------------------------------------------------------------| + | CHARACTERS | EXPLANATION | + |------------+-------------------------------------------------------| + | 1-26 | Fixed-length ASCII text: "GDS BINARY EXTRACT LEVEL | + | | 4". | + |------------+-------------------------------------------------------| + | 27-40 | Date and time of extract in the $ZDATE() format: | + | | "YEARMMDD2460SS". | + |------------+-------------------------------------------------------| + | 41-45 | Decimal maximum block size of the union of each | + | | region from which data was extracted. | + |------------+-------------------------------------------------------| + | 46-50 | Decimal maximum record size of the union of each | + | | region from which data was extracted. | + |------------+-------------------------------------------------------| + | 51-55 | Decimal maximum key size of the union of each region | + | | from which data was extracted. | + |------------+-------------------------------------------------------| + | | Space-padded label specified by the -LABEL qualifier. | + | 56-87 | For extracts in UTF-8 mode, GT.M prefixes UTF-8 and a | + | | space to -LABEL. The default LABEL is "GT.M MUPIP | + | | EXTRACT" | + +--------------------------------------------------------------------+ --LOG - -[NO]LO[G] - Specifies whether or not to display a message on SYS$OUTPUT for - each global extracted. The message shows the number of global - nodes, the maximum subscript length and maximum data length for - each global. + o GO - Global Output format, used for files to transport or archive. + -FORMAT=GO stores the data in record pairs. Each global node produces + one record for the key and one for the data. MUPIP EXTRACT -FORMAT=GO + has two header records - the first is a test label (refer to the LABEL + qualifier) and the second contains a data, and time. + o ZWR - ZWRITE format, used for files to transport or archive that may + contain non-graphical information. Each global node produces one + record with both key and data. MUPIP EXTRACT -FORMAT=ZWR has two + header records, which are the same as for FORMAT=GO, except that the + second record ends with the text " ZWR" + +3 FReeze + FReeze + + Prevents database updates to all database files from which the MUPIP + EXTRACT command is copying records. FREEZE ensures that a MUPIP EXTRACT + operation captures a "sharp" image of the globals, rather than one + "blurred" by updates occurring while the copy is in progress. + + The format of the FREEZE qualifier is: + + -FR[EEZE] + + By default, MUPIP EXTRACT does not "freeze" regions during operation. + +3 LAbel + LAbel + + Specifies the text string that becomes the first record in the output + file. MUPIP EXTRACT -FORMAT=BINARY truncates the label text to 32 + characters. The format of the LABEL qualifier is: + + -LA[BEL]=text + + o By default, EXTRACT uses the label "GT.M MUPIP EXTRACT." + o For more detailed information about the -FORMAT=BINARY header label, + refer to the description of EXTRACT -FORMAT=BINARY. + +3 LOg + LOg + + Displays a message on stdout for each global extracted with the MUPIP + EXTRACT command. The message displays the number of global nodes, the + maximum subscript length and maximum data length for each global. The + format of the LOG qualifier is: + + -[NO]LO[G] By default, EXTRACT operates -LOG. -1 Global_dir - MUPIP and the Global Directory - Some of the MUPIP commands require information contained in the Global - Directory. Therefore, a process must have access to a valid Global - Directory before using any MUPIP database service commands other than - JOURNAL, RESTORE, and the -FILE options of INTEG and SET. +3 Select + Select - The environment variable gtmgbldir specifies the Global Directory. - Define gtmgbldir at the shell level. Individual users define gtmgbldir - in their login or other shell scripts. + Specifies globals for a MUPIP EXTRACT operation. The format of the SELECT + qualifier is: - Example + -S[ELECT]= global-specification - $ gtmgbldir=prod.gld - $ export gtmgbldir - -1 HELP - H[ELP] - HELP provides online information about MUPIP commands and qualifiers. - - The format of the HELP command is: - - H[ELP] [options...] - - The HELP command does not accept any qualifiers. Enter the MUPIP - command for which you want information at the Topic prompt. Use - or to leave the help facility. - -1 INTEG - I[NTEG] - The INTEG command performs an integrity check on a GDS database file. - INTEG operates on one or more regions in the current global directory - by suspending concurrent updates to those regions. INTEG of a single - file database without a Global Directory requires exclusive - (stand-alone) access to that file. - - Use INTEG at the following times: - - o Periodically - to insure ongoing integrity of database(s); frequent - INTEGs help catch integrity problems before they spread through the - database file - - o After a crash - to insure the database was not corrupted - - o When database errors are reported - to troubleshoot the problem - - The format of the INTEG command is: - - I[NTEG][-qualifier[...]] file-spec | region-list - - The filename directly identifies the GDS file to INTEG. The - region-list identifies one or more regions that in turn identify GDS - files through the current Global Directory. - - Always analyze errors reported by INTEG immediately to prevent further - corruption. Greystone strongly recommends fixing the following errors - as soon as they are discovered: - - o Blocks incorrectly marked free - these may cause accelerating - damage when processes make updates to any part of the database - region. - - o Integrity errors in an index block - these may cause accelerating - damage when processes make updates to that area of the database - region that uses the faulty index. - - INTEG -FAST and the "regular" INTEG both report these errors. Other - database errors do not pose the threat of rapidly spreading problems - in GDS files, but if operations continue the errors may cause the - following: - - o Invalid application operation due to "missing" data - - o Process errors when a database access encounters an error - - o Degrading application level integrity as a result of incomplete - update sequences caused by the prior symptoms - - You must assess the type of damage, the risk of continued operations, - and the disruption of stopping normal operation for database repair. - For information on analyzing and correcting database errors, refer to - the "Database Integrity" chapter in the GT.M Administration and - Operations Guide. - - aborts INTEG. Because INTEG does most of its reporting at the - end, aborting the process before it completes may not give you all the - information you need. - -2 -FAST - -FA[ST] - Specifies that INTEG checks only index blocks. INTEG -FAST does not - check data blocks. INTEG -FAST produces results dramatically faster - than a full INTEG. While INTEG -FAST is not a replacement for a - full INTEG, it very quickly detects the most dangerous structural - errors in a database. - - The -FAST qualifier is incompatible with the -TN_RESET qualifier. - - By default, INTEG checks all active index and data blocks in the - database. - -2 -REGION - -R[EGION] - Specifies that the INTEG parameter identifies one or more regions - rather than a database file. - - INTEG -REGION does not require sole access to databases. Instead, - it freezes updates to the database during the check. The - region-list argument may specify more than one region of the - current Global Directory in a list separated with commas. INTEG - -REGION requires the environment variable gtmgbldir to specify a - valid Global Directory. For more information on defining gtmgbldir, - refer to the "Global Directory Editor" chapter of the GT.M - Administration and Operations Guide. - - Note: Because a KILL may briefly defer marking the blocks it - releases "free" in the bit maps, INTEG -REGION may report spurious - block incorrectly marked busy errors. Because block incorrectly - marked busy errors are benign, ignore these errors unless INTEG - consistently reports a block as incorrectly marked busy. - - The -REGION qualifier is incompatible with the -FILE and -TN_RESET - qualifiers. - - By default, INTEG operates -FILE. - -2 -FILE - -FI[LE] - Specifies that the parameter to the INTEG command is a filename. - INTEG -FILE requires exclusive (stand-alone) access to a database - file and does not require a Global Directory. Because it has - stand-alone access to the file, INTEG -FILE is able to check - reference counts. - - The -FILE qualifier is incompatible with the -REGION qualifier. - - By default, INTEG operates -FILE. - -2 -TN_RESET - -TN[_RESET] - Instructs an INTEG -FILE to reset the transaction number to one in - every database block currently holding valid data. - - Transaction number overflow back to 0 disrupts the integrity of the - database. - - The -TN_RESET qualifier is incompatible with the -BLOCK, -FAST, - -REGION and -SUBSCRIPT qualifiers. - - By default, INTEG does not modify the block transaction numbers. - -2 -SUBSCRIPT - -S[UBSCRIPT]=subscript - Specifies a global or a range of keys to INTEG. Enclose the global - key in quotes ("") and identify a range by separating two - subscripts with a colon (:). -SUBSCRIPT limits map checking to - incorrectly marked free errors. - - Use -SUBSCRIPT only if you know the path to the keys in the - subscript and have reason to believe the path is not damaged. If - the path is questionable or known to be damaged, use DSE to find - the block(s) and INTEG -BLOCK. - - The -SUBSCRIPT qualifier is incompatible with the -BLOCK and - -TN_RESET qualifiers. - - Use -FULL to have INTEG report all global-names covered by a range. - -2 Examples - INTEG -SUBSCRIPT= Examples - - Example - - MUPIP INTEG -SUBSCRIPT="^a" MUMPS.DAT - - This INTEGs the global variable ^a in the database file MUMPS.DAT. - - Example - - MUPIP INTEG-SUBSCRIPT="^a(100)":"^b(""c"")"-reg DEFAULT - - This INTEGs all global variables greater than or equal to ^a(100) - and less than ^b("c") in the default region. - - Note: To specify a literal in the command string, use double quotes - e.g., ^b(""c""). - -2 -BLOCK - -BL[OCK]=block-number - Specifies the block at which to start checking a sub-tree of the - database. -BLOCK limits map checking to incorrectly marked free - errors. - - The -BLOCK qualifier is incompatible with the -SUBSCRIPT and - -TN_RESET qualifiers. - -2 -KEYRANGES - -[NO]K[EYRANGES] - Specifies whether or not the INTEG report includes key ranges that - identify the data suspected of problems detected by INTEG. - - By default, INTEG displays -KEYRANGES. - -2 -MAP - -[NO]MAP[=integer] - Specifies the maximum number of incorrectly marked busy errors that - INTEG reports. - - -NOMAP removes limits on incorrectly marked busy reporting, i.e., - INTEG reports all map errors. -NOMAP does not accept assignment of - an argument. - - Because incorrectly marked free errors are very dangerous, INTEG - always reports them, and -MAP does not affect them. - - An error in an index block prevents INTEG from processing - potentially large areas of the database. A single "primary" error - may cause large numbers of "secondary" incorrectly marked busy - errors. Because "real" or primary incorrectly marked busy errors - only make "empty" blocks unavailable to the system, they are - relatively benign. - - By default, INTEG reports a maximum of 10 map errors (-MAP=10). - -2 -MAXKEYSIZE - -[NO]MAX[KEYSIZE][=integer] - Specifies the maximum number of key size too large errors that - INTEG reports. - - -NOMAXKEYSIZE removes limits on key size reporting, i.e., INTEG - reports all key size too large errors. -NOMAXKEYSIZE does not - accept assignment of an argument. - - Key size too large error should only occur after someone uses DSE - CHANGE -FILEHEADER -KEY_MAX_SIZE to reduce the maximum key-size. - - By default, INTEG reports a maximum of 10 key size errors - (-NOMAXKEYSIZE=10). - -2 -TRANSACTION - -[NO]TR[ANSACTION][=integer] - Specifies the maximum number of block transaction number too large - errors that INTEG reports. - - -NOTRANSACTION removes limits on transaction reporting, i.e., - INTEG reports all transaction number errors. -NOTRANSACTION does - not accept assignment of an argument. - - A system crash may generate many block transaction number too large - errors. These errors can cause problems for BACKUP -INCREMENTAL, - but have no effect on the run-time environment. The DSE CHANGE - -FILEHEADER -BLOCKS_FREE= command quickly fixes block transaction - number too large number errors. - - By default, INTEG reports a maximum of 10 block transaction errors - (-TRANSACTION=10). - -2 -BRIEF - -BR[IEF] - Specifies an INTEG summary report which displays the total number - of directory, index and data blocks. The -BRIEF qualifier is - incompatible with the -FULL qualifier. - - By default, INTEG reports are -BRIEF. - -2 -FULL - -FU[LL] - Specifies an expanded INTEG report which displays the number of - index and data blocks in the directory tree and in each global tree - as well as the total number of directory, index and data blocks. - The -FULL qualifier is incompatible with the -BRIEF qualifier. - - By default, INTEG reports are -BRIEF. - -2 -ADJACENCY - -A[DJACENCY]=integer - Specifies the range of blocks within which INTEG considers a block - adjacent to another database block on the same level. The adjacency - report from INTEG gives an approximation of physical data density - which directly affects efficient database access. Use the - -ADJACENCY qualifier to adjust the reporting to reflect - characteristics of your disks, e.g., pick a factor that matches the - number of sectors on a drive. - - By default, INTEG uses -ADJACENCY=10. - -1 JOURNAL - J[OURNAL] - - The MUPIP JOURNAL command analyzes, extracts from, reports on, and - recovers journal files. - - Another MUPIP command, SET, turns journaling on and off, identifies - the type of journaling, and sets some database journaling - characteristics. - - The format for the JOURNAL command is: - - MUPIP J[OURNAL] -qualifier[...] file-specification[,...] - - -2 Action_qualifiers - Action Qualifiers - --RECOVER - -REC[OVER] - Instructs the JOURNAL command to replay database updates in the - specified journal file into the appropriate database. -RECOVER - initiates the central JOURNAL operation. JOURNAL commands may - specify -RECOVER alone or with other action qualifiers. - --VERIFY - -[NO]V[ERIFY] - Checks a journal file for proper form. JOURNAL commands may - specify -VERIFY alone or with other action qualifiers. JOURNAL - -RECOVER commands implicitly -VERIFY the file(s) on which they - operate. JOURNAL -RECOVER ignores -NOVERIFY for all qualifier - combinations that do not include -FORWARD and -FENCES=NONE. - --EXTRACT - -EX[TRACT][=file-specification] - Specifies that JOURNAL transfer the contents of one or more - journal files to a single output file in a format intended for - processing by a MUMPS program. For a description of -EXTRACT - output record formats, refer to the section on JOURNAL -EXTRACT - output records. JOURNAL commands may specify -EXTRACT alone or - with other action qualifiers. - - -EXTRACT takes an optional argument, which provides an output - file-specification. - - By default, MUPIP JOURNAL derives the output file specification - using the name of the original database file associated with the - journal and a file type of .MJF. If the command specifies more - than one journal file, JOURNAL -EXTRACT derives the default - output file specification from the name of the first database. - --SHOW - -SH[OW]=show-option-list - Specifies what information the JOURNAL command displays about a - journal file. JOURNAL commands may specify -SHOW alone or with - other action qualifiers. - - For information on the options refer to the show-option-list - topic. - -2 show-option-list - show-option-list - - The following topics detail the show-option-list elements. - -3 ALL - AL[L] - ALL displays every available type of information about the - journal file. For additional information, refer to the - descriptions of each of the other SHOW keywords. - -3 HEADER - H[EADER] - HEADER displays the journal file header information. - - This includes: - - o Database file name - - o Journal file name - - o Journal file version label (.e.g. GDSJNLnn) - - o Whether before-images were captured - - o Journal creation time/date - - o Journal creator - - o The last user to open the journal - - o The last time the journal file was opened - - The information for the creator and last user includes: - - o Process Name - - o Process Identification Number - - o Node Name - - o Terminal Number - -3 PROCESSES - P[ROCESSES] - PROCESSES displays all processes active during the period - specified implicitly or explicitly by JOURNAL command time - qualifiers. - -3 ACTIVE_PROCESSES - AC[TIVE_PROCESSES] - ACTIVE_PROCESSES displays all processes active at the end of the - period specified implicitly or explicitly by JOURNAL command - time qualifiers. - -3 BROKEN_TRANSACTIONS - B[ROKEN_TRANSACTIONS] - BROKEN_TRANSACTIONS displays all processes that had incomplete - fenced transactions at the end of the period covered by the - JOURNAL command. - -3 STATISTICS - S[TATISTICS] - STATISTICS displays a count of all journal record types - processed during the period specified implicitly or explicitly - by JOURNAL command time qualifiers. - -2 Direction_qualifiers - Direction Qualifiers - --FORWARD - -FO[RWARD] - Specifies that JOURNAL processing should proceed from the - beginning of the given journal files. If the actions include - -RECOVER, the target database file should contain a copy of that - database made at the time when MUPIP SET -JOURNAL= created the - journal files. - - -FORWARD is incompatible with -BACKWARD. - --BACKWARD - -BA[CKWARD] - Specifies that JOURNAL processing should proceed from the end of - the journal files. If the actions include -RECOVER, JOURNAL - -BACKWARD starts restoring before-images starting at the end of - the file, back to an explicitly or implicitly specified point - before it "reverses" and processes database updates in the - forward direction. The target database file should "match" the - end of the journal file, i.e., be the same as when GT.M wrote - the last record of the journal. - - -BACKWARD is incompatible with -FORWARD. - -2 Time_qualifiers - Journal time specifications - Journal qualifiers specifying time take arguments in absolute or - delta time format. Enclose time arguments in quotes ("") and - include all leading delimiters. Absolute format is "day-mm-yyyy - hh:mm:ss:cc" , where cc represents hundredths of a second. Absolute - time may indicate today's date with "--" before the hours. Delta - format is "day hh:mm:ss:cc" , where cc represents hundredths of a - second. If delta time is less than a day, it must start with zero - (0) followed by a space, or just a space, before the hours. Delta - time is always relative to the time of the last record in all - journal file arguments to the MUPIP JOURNAL command. A normal - database closure, caused by the last accessing process leaving - GT.M, also properly closes the associated journal file. - Alternatively, a system failure causes the journal to end in an - abnormal or "disorganized" fashion. JOURNAL processing deals with - both cases. - - The time qualifiers perform as follows: - - o -AFTER= only applies to JOURNAL -EXTRACT -FORWARD and specifies - a starting time; processing for all other -FORWARD actions must - start at the beginning of the journal files - - o -BEFORE= specifies an ending time for any action -FORWARD or - -BACKWARD - - o -SINCE= specifies a starting time for any action -BACKWARD - - o -LOOKBACK_LIMIT= specifies a "safety zone" for resolving open - fenced transactions when processing any action -BACKWARD; the - -LOOKBACK_LIMIT= argument may be a list of limits: "TIME=time" - and/or "OPERATIONS=integer" - - Because GT.M rounds time-stamps within the journal to hundredths of - a second and the JOURNAL processing can only determine time as - exactly as the journal records permit, the JOURNAL command - processes specified times in a "fuzzy" fashion. Because they deal - with processing completed logical transactions, -SINCE= and - -LOOKBACK= times have more "blur" than -AFTER= and -BEFORE= times. - --AFTER - -A[FTER]=time - Specifies the starting time for JOURNAL -EXTRACT -FORWARD to - commence output. The time specified references time stamps in - the journal and identifies the point after which JOURNAL - processing starts extracting information out of the journal - file. -AFTER= specifies time in absolute or delta time formats. - Delta format specifies an offset from the time of the last - record of the journal file. If -AFTER= provides a time following - the last time recorded in the journal file or following any - -BEFORE= time, JOURNAL processing produces no result. Using - -BEFORE= with -AFTER= restricts -EXTRACT to a particular period - of time. - - -AFTER= is incompatible with -BACKWARD and with all action - qualifiers except -EXTRACT. - - By default, -EXTRACT starts at the beginning of the journal - file. - --BEFORE - -BE[FORE]=time - Specifies the ending time at which JOURNAL processing stops - extracting or recovering data. The time specified references - time stamps in the journal files. -BEFORE= specifies time in - absolute or delta time formats. Delta format specifies an offset - from the time stamp in the last record of each the journal file. - If -BEFORE= provides a time preceding the first time recorded in - the journal file or preceding any -AFTER= or -SINCE= time, - JOURNAL processing produces no result. - - -BEFORE= is compatible with all other JOURNAL qualifiers. - - By default, JOURNAL processing terminates at the end of the - journal file. - --SINCE - -SI[NCE]=time - Specifies how far back in time JOURNAL -BACKWARD should process - from the end of the journal file, before starting its forward - processing. The time specified references time stamps in the - journal files. -SINCE= specifies time in absolute or delta time - formats. Delta format specifies an offset from the time of the - last record of the journal file. When JOURNAL -BACKWARD locates - the -SINCE= time, if it has open fenced transactions, it - continues processing backward to resolve them unless the command - also specifies -FENCES=NONE. The -LOOKBACK= qualifier controls - the length of processing backward past the -SINCE= time. - - If -SINCE= time exceeds the last time recorded in the journal - files, JOURNAL processing effectively ignores the qualifier. - -SINCE= is incompatible with -FORWARD. If -SINCE= provides a - time preceding any -BEFORE= time, JOURNAL processing produces no - result. - - By default, JOURNAL -BACKWARD processes the last five (5) - minutes of the journal file(s). - --LOOKBACK_LIMIT - -[NO]LOO[KBACK_LIMIT][=lookback-option-list] - Specifies how far JOURNAL -BACKWARD processes back past the - explicit (-SINCE=) or implicit turn around time while attempting - to resolve open transaction fences. -LOOKBACK= options include - time and transaction counts. - - -NOLOOKBACK_LIMIT specifies that JOURNAL -BACKWARD can process - all the way to the beginning of the journal file, if necessary, - to resolve open transaction fences. - - -LOOKBACK_LIMIT= is incompatible with -FORWARD. When - -FENCES=NONE, JOURNAL processing ignores -LOOKBACK_LIMIT=. - - The lookback-options are: - - TIME=time - limits lookback by a specified amount of delta or - absolute journal time. - - OPERATIONS=integer - limits lookback to some number of database - updates. - - The lookback-option names and values must be enclosed in quotes - (""), e.g., "Time=0 00:05" or "Oper=10." When -LOOKBACK= - specifies both options, they must be enclosed in parentheses () - and separated by a comma (,). When -LOOKBACK= specifies both - options, the first limit reached terminates the lookback. - - By default, MUPIP JOURNAL uses -LOOKBACK_LIMIT="TIME=0 00:05" - providing five minutes of journal time prior to -SINCE= in which - to resolve open fences. - -2 Control_qualifiers - Control Qualifiers - --REDIRECT - -RED[IRECT]=file-pair-list - Specifies that JOURNAL -RECOVER replay the journal file to a - database different than the one for which it was created. Use - this qualifier to create or maintain databases for training or - testing. - - JOURNAL rejects -REDIRECT unless it appears with -RECOVER. - - The file-pair-list consists of one or more pairs of - file-specifications enclosed in parentheses () and separated by - commas (,). The pairs are separated by an equal sign in the - form: - - old-file-specification=new-file-specification - - where the first file-specification names the original database - file and the second file-specification names the target of the - -RECOVER. When -REDIRECT specifies only one file pair, the - parentheses are optional. - - By default, JOURNAL directs -RECOVER to the database file from - which the journal was made. - --FENCES - -FE[NCES]=fence-option - Specifies how JOURNAL processes fenced transactions. Fenced - transactions are logical transactions made up of database - updates preceded in MUMPS by a ZTSTART command and followed by a - ZTCOMMIT command. All updates between a ZTSTART and a ZTCOMMIT - are designed such that they should all occur together, i.e., no - one of them should reach the database unless they all do. - - The fence options are: - - o NONE, which causes JOURNAL to apply all individual updates as - if transaction fences did not exist - - o ALWAYS, which causes JOURNAL to treat any unfenced or - improperly fenced updates as errors - - o PROCESS, which causes JOURNAL to accept unfenced database - updates, and also to observe fences when they appear, - generating an error in the case of a ZTSTART with no - corresponding ZTCOMMIT - - By default, MUPIP JOURNAL uses -FENCES=PROCESS. - --INTERACTIVE - -[NO]IN[TERACTIVE] - Specifies whether, for each error over the -ERROR_LIMIT, JOURNAL - processing prompts the invoking operator for an answer - controlling continuation of processing. If the operator responds - that processing should not continue, the JOURNAL command - terminates. - - -NOINTERACTIVE terminates the journal processing as soon as the - process generates the number of errors specified in - -ERROR_LIMIT. - - When processing in INTERACTIVE mode, the default is - -INTERACTIVE, otherwise, e.g., BATCH mode, the default is - -NOINTERACTIVE. - --ERROR_LIMIT - -[NO]ER[ROR_LIMIT][=integer] - Specifies the number of errors that JOURNAL processing treats as - acceptable. When the number of errors exceeds the -ERROR_LIMIT, - the -INTERACTIVE qualifier determines whether JOURNAL processing - halts or defers to the operator. - - -NOERROR_LIMIT prevents JOURNAL from stopping because of errors. - Journal processing will continue until it reaches the end of the - journal file, regardless of the number of errors. Note that - -NOERROR_LIMIT is not the same as -ERROR_LIMIT=0. - - By default, MUPIP JOURNAL uses -ERROR_LIMIT=0, causing the first - error to initiate the appropriate error action. - --CHECKTN - -[NO]C[HECKTN] - -CHECKTN specifies that JOURNAL -FORWARD must ensure that the - first database update in the journal file has the next - transaction number after the current transaction in the database - file. - - -NOCHECKTN suppresses checking of the starting journal - transaction against the ending database transaction number. - - -CHECKTN is incompatible with the -BACKWARD qualifier. - - By default, JOURNAL -FORWARD uses -CHECKTN. - -2 Selection_qualifiers - Selection Qualifiers - --GLOBAL - -G[LOBAL]=global-list - Specifies globals for JOURNAL to include or exclude from - processing. You may find this qualifier useful for extracting - and analyzing specific data. - - The global-list contains names of one or more global-names (not - including subscripts) preceded by "^" enclosed in parentheses () - and separated by commas (,). If -GLOBAL specifies only one item, - the parentheses are optional. The names may include the - wildcards ? and *. The entire list or each name may optionally - be preceded by a minus (-), requiring JOURNAL to exclude - database updates that update the specified global(s). When the - global-list with a JOURNAL -GLOBAL does not start with a minus, - JOURNAL processes only the explicitly named globals. - - By default, JOURNAL processes all globals. - --USER - -U[SER]=user-list - Specifies that JOURNAL processing include or exclude database - updates generated by one or more users. You may use this - qualifier to "back-out" database updates erroneously entered by - a specific user. - - The user-list contains names of one or more users enclosed in - parentheses () and separated by commas (,). If -USER specifies - only one item, the parentheses are optional. The names may - include the wildcards ? and *. The entire list or each name may - optionally be preceded by a minus (-), requiring JOURNAL to - exclude database updates initiated by the specified user(s). - When the user-list with a JOURNAL -USER does not start with a - minus, JOURNAL processes only database updates generated by the - explicitly named users. - - By default, JOURNAL processes database updates regardless of the - user by which they were initiated. - --ID - -ID=pid-list - Specifies that JOURNAL processing include or exclude database - updates generated by one or more processes, identified by - process identification numbers (PIDs) in hexadecimal. You may - use this qualifier for troubleshooting or analysis of data. - - The pid-list contains one or more PIDs enclosed in parentheses - () and separated by commas (,). If -ID specifies only one item, - the parentheses are optional. The entire list or each PID may - optionally be preceded by a minus (-), requiring JOURNAL to - exclude database updates associated with the specified PID(s). - When the pid-list with a JOURNAL -ID does not start with a - minus, JOURNAL processes only database updates associated with - the explicitly listed PIDs. - - By default, JOURNAL processes database updates regardless of the - process by which they were initiated. - --PROCESS - -P[ROCESS]=process-name-list - Specifies that JOURNAL processing include or exclude database - updates generated by one or more processes, identified by names. - You may use this qualifier to extract specific process-related - data for testing or troubleshooting. - - The process-name-list contains names of one or more processes - enclosed in parentheses () and separated by commas (,). If - -PROCESS specifies only one item, the parentheses are optional. - The names may include the wildcards ? and *. The entire list or - each process-name may optionally be preceded by a minus (-) - requiring JOURNAL to exclude database updates associated with - the specified process name(s). When the process-name-list with a - JOURNAL -PROCESS does not start with a minus, JOURNAL processes - only database updates associated with the explicitly named - processes. - - By default, JOURNAL processes database updates regardless of the - process by which they were initiated. - --TRANSACTION - -T[RANSACTION]=transaction-type - Specifies transaction-types for JOURNAL to include or exclude - from processing. For example, you may use this qualifier to - exclude KILL transactions and prevent an accidental KILL from - reoccurring during replay. - - The transaction-types are: - - SET - - KILL - - These types correspond to the MUMPS commands of the same names. - The transaction-type may optionally be preceded by a minus (-) - requiring JOURNAL to exclude transactions of the specified type. - When the transaction-type with a JOURNAL -TRANSACTION does not - start with a minus, JOURNAL processes only transactions of the - explicitly named type. - - By default, JOURNAL processes transactions regardless of type. - -2 Examples - Journal Examples - - Example - - $ cp /dat/cus.cat - $ mupip journal -recover -forward -fences=none cus.mjl - - The cp command copies a backup copy of the database for use in - recovery. The MUPIP JOURNAL command recovers the database using the - cus.mjl journal file. The JOURNAL command processes the journal - file in a forward direction (from the beginning of the journal). - The -FENCES=NONE directs JOURNAL to ignore any fences and recover - all individual updates. - - Example - - $ mupip set -file -journal=(before,buff=128) cus.dat - $ mupip set -file -journal=(before,buff=128) acc.dat - ... - $ mupip journal -recover -verify -back -error=2 cus.mjl,acc.mjl - - The first two command lines initiate journaling for the two - specified database files. MUPIP JOURNAL does not accept wildcards - in database file names. Because the MUPIP SET command specifies - JOURNAL=BEFORE, subsequent JOURNAL -RECOVER may have either - -FORWARD or -BACKWARD direction. The last line contains the command - to recover the two database files using the two specified journal - files. The journal recover processes in a BACKWARD direction using - before-image processing. If JOURNAL processing encounters two or - more errors (-ERROR=2), the recovery process terminates. - - Example - - $ mupip journal -forw -befo="-- 10:30" -glob="^bv%r*" -extr=bv - cus.mjl - - This command line extracts database updates that occurred from the - beginning of the journal until 10:30 to global variables with the - prefix ^bv , followed by some character, followed by r, optionally - followed by more characters. The JOURNAL -EXTRACT places the - updates in a file called bv.mjf - - Because the command does not specify an extension, JOURNAL assigns - the default extension .mjf to the output file. - - Example - - $ mupip jour -rec -back -befo="-- 10:30" -since="-- 9:30" - -lookback="time=0 00:05" cus.mjl - - This command line performs a -RECOVERY -BACKWARD of the database - file that corresponds to the journal file cus.mjl. JOURNAL - -RECOVER processes from the journal time 9:30 to journal time - 10:30. If the JOURNAL finds open fenced transactions, it "looks - back" an additional five minutes to resolve them. The -BEFORE= and - -SINCE= qualifiers in this example use absolute time. Because the - time specification omits the date, JOURNAL assumes today's date. - -2 extract_formats - JOURNAL -EXTRACT formats - EXTRACT output records are constructed of fields or "pieces" - delimited by back-slashes (\). - - The first piece of an EXTRACT output record always contains the - two-digit decimal transaction record type, e.g., 01 for a process - initialization record. - - The second piece always contains the full date and time of - operation, represented in $HOROLOG-format, with decimal seconds, - e.g., 54271,44580.55. - - The third piece always contains the process id (PID) of the process - that performed the operation, represented as a decimal number. The - remainder of the record depends on the record type. - - The fields described as "database transaction number" contain a - GT.M assigned number that is unique within the journal file. - -3 proc_initialization - Process Initialization Record - A type 1 record indicates an image-initiated contact with the - GT.M database region for the first time. The format for a - process initialization record is: - - 01\time\pid\nnam\unam\term - - where - - time full time/date - - pid process id - - nnam node name - - unam user name - - term terminal name - - -3 proc_termination - Type 2 - Process Termination Record - A type 2 record indicates an image terminated and dropped - interest in the GT.M database region. The format for a process - termination record is: - - 02\time\pid\nnam\unam\term\tnum - - where - - time full time/date - - pid process id - - nnam node name - - unam user name - - term terminal name - - tnum database transaction number - -3 end_of_file - Type 3 - End of File Record - A type 3 record indicates all GT.M images dropped interest in - the region and the journal file was closed normally. The format - for an end-of-file record is: - - 03\time\pid\nnam\unam\term\tnum - - where - - time full time/date - - pid process id - - nnam node name - - unam user name - - term terminal name - - tnum database transaction number - -3 Kill - Type 4 - Kill Record - A type 4 record indicates a database update caused by a KILL - command. The format for a KILL record is: - - 04\time\pid\tnum\node - - where - - time full time/date - - pid process id - - tnum database transaction number - - node a MUMPS node reference in external format - -3 Set - Type 5 - Set Record - A type 5 record indicates a database update caused by a SET - command. The format for a SET record is: - - 05\time\pid\tnum\sarg - - where - - time full time/date - - pid process id - - tnum database transaction number - - sarg a MUMPS set argument - - Note a MUMPS SET argument has a node reference followed by an - equal-sign (=) and MUMPS data string expression. - -3 tr_start - Type 6 - Transaction Start Record - A type 6 record indicates a ZTSTART command. The format for a - transaction start record is: - - 06\time\pid - - where - - time full time/date - - pid process id - -3 tr_commit - Type 7 - Transaction Commit Record - A type 7 record indicates a ZTCOMMIT command. The format for a - transaction commit record is: - - 07\time\pid\tnum\part - - where - - time full time/date - - pid process id - - tnum database transaction number - - part number of journal entries in the transaction - -1 Jrnl_examples - Journaling Examples - The following examples present a typical use of database journaling to - prevent loss of data. In our examples the database consists of three - regions, ACC, MAIN, and TMP, mapped respectively to files - /usr/prod/acc.dat, /usr/prod/mumps.dat and /usr/prod/tmp.dat. - -2 Setting_Database_Regions_for_Journaling - We assume that region TMP holds only process-local data, and, - therefore, does not require backups or journaling. We assume, on the - other hand, that regions ACC and MAIN hold production application data - that should be protected by journaling. Moreover, our application - requires a high degree of availability. Therefore, we set up - journaling with BEFORE_IMAGES for regions ACC and MAIN. The - BEFORE_IMAGES allow for JOURNAL RECOVER -BACKWARD, which generally - works faster than JOURNAL RECOVER -FORWARD. Because both our journaled - regions map to the database files on the usr device, we choose a - different disk with a different controller to accommodate the journal - files. This choice improves resiliency against hardware failures. - - Example - - $ mupip set -region -journal=(off,buff=200,file=/jnl/prod/acc) ACC - $ mupip set -region -journal=(off,buff=200,file=/jnl/prod/main) MAIN - - These commands must be issued when the database files are available - for exclusive (stand-alone) access. They establish several journal - characteristics. The example increases the journal buffer size from - the default of 128 pages to 200 pages. - -2 Journal_Maintenance - First backup the database files. Copy and store your existing journal - files, thencreate and initialize new journal files. - - Example - - $ mupip backup ACC,MAIN /dev/rst8/051590 - $ mupip set -region -journal=(on,before) ACC,MAIN - - This sequence of commands backs up the database files to disk and - initializes new journal files for each. MUPIP BACKUP can operate - without exclusive access to the database files by freezing all - updates. However, in order to ensure that the BACKUP captures an - application state matching the beginning of the journal files, it - should run stand-alone. - - Some applications with high rates of updates may create considerable - amount of journaling data. To save the disk space, you may archive - journal files to magnetic tapes until the next database backup. Before - archiving a journal file, first create a new one. - - Example - - $ mupip set -file -journal=(on,before) ACC.DAT - $ cp /dev/rst8/jnl.bck acc.mjl ~{ - $ purge JNL:[PROD]ACC.MJL\ - - This sequence creates a new journal file and backs up the old journal - file to the tape. Notice that the MUPIP SET requires exclusive access - to the database file to ensure that the old journal stops and the new - journal starts with consistent transaction states. - -2 Recovery_from_Journal_Files - Because we set up our databases with BEFORE_IMAGE journaling, when - both the database and journal files are available after a failure - event, we can use JOURNAL -RECOVER -BACKWARD. - - Example - - $ delete /usr/prod/tmp.dat - $ mupip create -region=tmp - $ mupip journal -reco -show -back -nointer - /jnl/prod/acc./jnl/prod/main - $ mupip integ -region * - - This first deletes and recreates tmp.dat. The MUPIP JOURNAL command - includes the -SHOW qualifier to generate a report on the status of - activity in the journal files. It also includes the -NOINTERACTIVE - qualifier to prevent operator interaction when JOURNAL processing - encounters an error. By default, this JOURNAL -RECOVER has an implicit - -ERROR_LIMIT=0, which causes the first broken transaction to terminate - processing. In addition to checking database integrity, the MUPIP - INTEG -REGION acts as the first database access after the recovery - and, if the old journal file terminates improperly, creates a new - journal file. Unlike INTEG -REGION, the command MUPIP INTEG -FILE does - not initialize a new journal file. However, if the old journal file - has damage, any other access to the data base creates a new version. - If MUPIP JOURNAL -RECOVER reports broken transactions during recovery, - reenter the transactions. - - WARNING: The new journal file created by commands such as mupip integ - -region will overwrite the existing journal file. To preserve the - existing file, save it under a different name before executing any - commands that will cause a new journal file to be created. - - If the databases were lost, for instance due to a disk drive failure, - we would have to use JOURNAL -RECOVER -FORWARD after replacing the - drive and retrieving backups of the databases. This recovery may take - much longer than backward recovery, depending on the amount of data in - the journal. - - Example - - $ lprm /usr/prod/*.dat - $ cp /usr/prod /usr/051590/acc.dat - $ cp /usr/prod /usr/051190/mumps.dat - $ mupip journal -reco -forw -err=5 /jnl/jnl/acc,/jnl/jnl/main - $ mupip create -region=TMP - $ mupip integ -region -fast * - - This sequence of commands recreates the databases to the point of the - last backup. Then it recovers all updates from the journal files. The - -ERROR_LIMIT= qualifier causes JOURNAL -RECOVER to attempt processing - through up to five (5) errors. By default, when the JOURNAL -RECOVER - executes in batch, processing terminates after five errors. However if - the command executes interactively, after five errors, MUPIP JOURNAL - prompts the the operator at the invoking terminal to choose between - continuing or terminating. Also by default, the JOURNAL -RECOVER - command implies a -VERIFY, causing a check of the journal prior to - -RECOVER processing. The commands up to this point require exclusive - (stand-alone) access to the database files. MUPIP INTEG -REGION - verifies the integrity of the recovered database. If the journal was - not properly closed, the INTEG -REGION also creates a new version of - the journal file, overwriting the existing version. Because the - databases are large, we use the -FAST qualifier on the INTEG. Because - INTEG freezes all updates and we wish to ensure database integrity - before going back into production, we continue to restrict access to - the database until the INTEG completes. Once the database has been - verified, we can resume work. One of the first items of business - should be to reenter any broken transactions. - - Should the system crash again and something such as a hard disk - failure prevent backward recovery, we must recover the database - forward, twice. First, restore the database from backup, then recover - to the point of the first crash, then finally, recover from that point - to the point of the second crash. - - Example - - $ delete *.DAT;* - $ mupip restore acc.dat usr/051590/acc.bck - $ cp /usr/prod /usr/051590/acc.dat - $ cp /usr/prod /usr/051590/mumps.dat - $ mupip journal -reco -veri -forw -err=5 /jnl/acc.mjl - $ mupip journal -reco -veri -forw -err=5 /jnl/acc.mjl - $ mupip create -region=TMP - $ mupip integ -region -fast * - - This is similar to the previous example, however, this sequence - recovers the database regions from two consecutive journal files. - -1 Jrnl_overview - Journaling overview - Journaling records an extra copy of information during database - updates in order to provide resiliency against hardware and software - failures. Journaling can reduce the "window of exposure" from some of - the most common types of failure: power loss and media loss due to - head-to-disk interference. Journals also provide a valuable tool in - cases of software errors and operational miscues. A journal file has - questionable value only in the case where the database and the journal - share a common point of failure that affects the information in both, - over a significant period of time. Therefore, using different disks - and, when possible, different disk controllers for the journal and the - database files improves the likelihood of the journal serving its - intended purpose. - - The database management portion of a MUMPS implementation ensures that - multiple concurrent updates and retrievals of the same information (or - information "close together" in ordered sequence) are handled in a - predictable and logical fashion. The database manager may have to - change multiple records, usually indices, as a result of a single - update. Therefore, interrupting a process performing such a - "multi-point" update violates a design assumption of the MUMPS - implementation and results in a malformed database. Access to a - damaged area of the database does not produce the desired result. - Instead, such an "integrity" problem causes symptoms including system - hangs, misplaced updates, failure to find information that exists, - finding information out of sequence, and run-time errors. If the bad - records contain no valid information or redundant information, the - simplest cures for integrity errors entail deleting incorrectly - formatted records. However, sometimes crashes damage information of - value and, in any case, database repair requires time and skill. GT.M - journaling provides a means to recover or replace databases that have - integrity problems. Use of journaling at this "global" level requires - no MUMPS programming. - - MUPIP and its documentation uses the term transaction to mean database - update. In journaling, the term transaction may refer to multiple - related database updates. - -2 Forward_Recovery - Forward Recovery - Forward Recovery consists of restoring a backup copy of the - database and applying the journal file to that database file. The - journal file contains copies of each database update. Forward - Recovery reads the entire journal file from beginning to end (in a - "forward" direction) and updates the backup copy of the database. - The optional MUPIP JOURNAL -BEFORE= qualifier specifies a journal - ending time that stops journal processing before the physical end - of the journal file. In general, Forward Recovery takes longer than - Backward Recovery. However, if the current database is somehow - destroyed, you must use Forward Recovery. Also, if a journal file - was created NOBEFORE_IMAGE with a MUPIP SET, that journal only - permits Forward Recovery. - - Example of Forward Recovery: - - MUPIP JOURNAL -RECOVER -FORWARD - - - -BEFORE - | - --------------------------------V-----------X--------->time - 10:30 10:32 - >>+++++++++++++++++++++++++++++>>++++++++++>> - - - This shows a recovery after a system crash at 10:32, which - processes the entire journal file forward. If we add -BEFORE="-- - 10:30" to the command, the recovery stops when processing - encounters updates that originally occurred after 10:30. - -2 Backward_Recovery - Backward Recovery - Backward Recovery works by processing from the end of the journal - file that contains information for the period just prior to the - failure event, thereby minimizing recovery time. Backward Recovery - uses "before-image" journaling. With "before-image" journaling, - GT.M captures the database updates, as well as "snap-shots" of - portions of the database immediately prior to the change caused by - the update. In effect, MUPIP JOURNAL=BEFORE_IMAGE creates - "mini-backups" preceding each database update. Backward Recovery - uses the mini-backups to restore the database as far back in time - as specified, then it goes forward in time replaying the database - updates. Using Backward Recovery with the MUPIP JOURNAL qualifiers - -BEFORE=, -SINCE=, and -LOOKBACK=, you can specify a block of time - to recover. JOURNAL -RECOVER -BACKWARD only works if the production - database is useable, and if the MUPIP SET command that created the - journal file specified the BEFORE_IMAGE characteristic. - - Note: Before-images require more disk I/O and storage space. - - Example of Backward Recovery: - - MUPIP JOURNAL -RECOVER -BACKWARD -SINCE="-- 9:30" - - - -LOOKBACK_LIMIT - | -SINCE - | | -BEFORE - | | | - ----------------V-------V-------V------X--------->time - 9:30 10:30 10:32 - <*******<++++++++++++++<< - ********++++++++>++++++>> - - - - This shows a recovery after a system crash at 10:32. The recovery - "undoes" the database updates backward to 9:30 and then forward - until the crash. If we add -BEFORE="-- 10:30" to the command, the - recovery stops when forward processing encounters updates that - originally occurred after 10:30. If the application includes - ZTSTART and ZTCOMMIT commands to fence a group of transactions, - backwards processing may continue back prior to 9:30 searching to - resolve fenced transactions that were incomplete at 9:30. The - -LOOKBACK_LIMIT= qualifier controls the maximum amount of - additional backward processing. - -2 Fencing_Transactions - Fencing Transactions - Journaling without fences in MUMPS addresses the fact that a system - crash can damage the database integrity. However, sound design - frequently dictates modelling a single "real-world" event in - updates to more than one global variable. Such real-world events - are usually captured in a single data entry session and are - referred to as logical transactions. Therefore, interrupting a - process performing a "multi-node" logical transaction violates a - design assumption of the application and results in logical - inconsistencies in the database. Such logical inconsistencies - produce symptoms including run-time errors, inappropriate branching - and incorrect reports. Sometimes logical inconsistencies are - referred to as application-level database integrity problems. - - Standard MUMPS does not yet include a method to identify the fact - that a single logical transaction may be made up of multiple global - updates. Therefore, a journal recovery that corrects database - integrity problems may perform an update that is part of an - incomplete sequence of updates intended as a single logical unit. - - GT.M provides the MUMPS commands ZTSTART to mark the beginning of a - logical transaction and ZTCOMMIT to mark the end of a logical - transaction. When ZTSTART and ZTCOMMIT fence a logical transaction, - the journal recovery can refrain from starting an incomplete - update. To take advantage of this additional level of journaling - functionality, the application must use ZTSTART and ZTCOMMIT - commands. - - Journaling does not require modification of application programs. - However, using ZTSTART and ZTCOMMIT to add transaction fences - around updates that comprise a logical unit significantly improves - the benefit of journaling. For instance, the logical transaction - "transfer funds between accounts" consists of a debit update to one - account and a credit update to another account. One of the updates - made without the other is not valid. When recovering from journal - files, JOURNAL processing recovers either all updates within the - transaction fences or none of them. MUPIP JOURNAL -RECOVER reports - the latter case during recovery. - -1 LOAD - L[OAD] - LOAD enters global variable names and their corresponding data values - into a GT.M database from a sequential file. LOAD uses the Global - Directory to determine which database files to use. LOAD may operate - concurrently with normal GT.M database access. However, a LOAD does - not use MUMPS LOCKs and therefore may produce application-level - integrity problems if run concurrently with many applications. - - The format of the LOAD command is: - - L[OAD] [qualifier...] file-specification - - LOAD takes its input from the file defined by the file-specification. - - produces a status message from LOAD. Entering twice - in quick succession aborts LOAD. A LOAD terminated abnormally by - operator action or error is incomplete but does not adversely affect - the database structure. - -2 -FORMAT - -FO[RMAT]=keyword - Specifies the format of the input file. The format must match the - actual format of the input file for LOAD to operate. - - At present, the only available format code is: - - GO - Global Output format - -3 GO - -FORMAT=GO - -FORMAT=GO stores the data in record pairs. Each global node produces - one record for the key - and one for the data. -FORMAT=GO has two header records, therefore - LOAD -FORMAT=GO - starts active work with record number three (3). - -2 -BEGIN - -BE[GIN]=integer - Specifies the record number of the input file with which LOAD should - begin. Directing LOAD to begin - at a point other than the beginning of a valid key causes an error. - - It is important to consider the number of header records when choosing a - -BEGIN point. For more - information, refer to the section on -FORMAT. - - For -FORMAT=GO input, normally the value should be an odd number. - - By default, LOAD starts at the beginning of the input file. - -2 -END - -E[ND]=integer - Specifies the record number of the input file at which LOAD should stop. - The -END=integer must be - greater than the -BEGIN=integer for LOAD to operate. LOAD terminates - after processing the record of - the number specified by -END or reaching the end of the input file. - - For -FORMAT=GO input, normally the value should be an even number. - - By default, LOAD continues to the end of the input file. - -2 -FILL_FACTOR - -FI[LL_FACTOR]=integer - Specifies the target fill density for the data blocks updated in the - database file. -FILL_FACTOR must be - an integer between 5 and 100 specifying the percentage fill rate for the - block. - - In general, maximum data densities provide the best performance. - However, if you have an - understanding of the update patterns of your application, you may - achieve a performance benefit over - time from lowering the initial fill-factor. - - By default, LOAD uses -FILL_FACTOR=100 for maximum data density. - -1 Overview - MUPIP overview - The GT.M MUMPS Peripheral Interchange Program, MUPIP, is a utility - that provides an assortment of tools for GT.M database management and - database journaling. - - MUPIP provides the following commands: - - For stand-alone database services: - - o CREATE database files - - o EXTEND Mapped Memory database files - - o JOURNAL, recover database files and extract journal records - - o INTEG, check the integrity of GDS database files - - o RESTORE incremental backups to GDS database files - - o SET database file characteristics - - For concurrent database services: - - o BACKUP GDS database files - - o BACKUP-INCREMENTAL changes to GDS database files - - o EXTEND Buffered Global database files - - o EXTRACT data from GDS databases - - o INTEG, check the integrity of GDS databases - - o LOAD databases from sequential files - - o REORGanize database files to optimize performance - - o RUNDOWN database files that are not currently accessed - - For non-database services: - - o HELP for MUPIP commands - - o STOP GT.M processes - -1 REORG - REO[RG] - MUPIP REORG offers a tool for optimizing your database files for peak - database performance. REORG - requires minimal operator resources, and runs concurrently with other - database activity, including updates. - Competing activity generally increases the time to perform a REORG, as - well as that of the competing - operations. If you use REORG concurrently with normal database access, you - may wish to lower the priority - of the process performing the REORG to minimize its impact on normal - operations. - - Note that while REORG optimizes the GDS structure of database files, it - does not deal with native file system - file fragmentation. Because native file fragmentation may significantly - impair database performance, its - prevention and control is still important. Always create files with - appropriate allocations and extensions, on - disks with large contiguous free-space. Use native utilities and, - depending on your procedures, MUPIP - utilities to eliminate file fragmentation when database files have been - extended more than a dozen times. - - The format of the REORG command is: - - REO[RG] [qualifier...] file-specification - - produces a status message from REORG. Entering twice in - quick succession - aborts REORG. A REORG terminated abnormally by operator action or error is - incomplete but does not - adversely affect the database structure. - -2 Qualifiers - --SELECT - -SELECT=global-name-list - Restricts REORG operation to a subset of specified globals. By - default, REORG operates on all - globals in all database files identified by the current global - directory for the process executing the - MUPIP command. - - Arguments to this qualifier may be an individual global name, a prefix - followed by an asterisk (*) - wild-card symbol, or a list of names and/or prefixes followed by the - wild-card symbol. The "^" in - the specification of the global name is optional. Enclose lowercase - global names in quotes (""). + o By default, EXTRACT selects all globals, as if it had the qualifier + -SELECT=* + o The caret symbol (^) in the specification of the global name is + optional. The global-specification can be: - o A global name, such as MEF + o A parenthetical list, such as (a,B,C). In this case, MUPIP EXTRACT + selects all globals except ^a, ^B, and ^C. + o A global name, such as MEF. In this case, MUPIP EXTRACT selects only + global ^MEF. + o A range of global names, such as A7:B6. In this case, MUPIP EXTRACT + selects all global names between ^A7 and ^B6, inclusive. + o A list, such as A,B,C. In this case, MUPIP EXTRACT selects globals ^A, + ^B, and ^C. + o Global names with the same prefix, such as PIGEON*. In this case, + EXTRACT selects all global names from ^PIGEON through ^PIGEONzzzzz. - o A range of global names, such as A7:B6 + **Note** - o A list, such as A,B,C + If the rules for selection are complex, it may be easier to construct an + ad hoc Global Directory that maps the global variables to be extracted to + the database file. This may not be permissible if the database file is + part of a replicated instance. If this is the case, work with a backup of + the database. - o Global names with the same prefix, such as TMP* +3 STdout + STdout - In the first case, EXTRACT selects only global ^MEF. In the second - case, EXTRACT selects all - global names between ^A7 and ^B6, inclusive. In the third case, - EXTRACT selects globals ^A, ^B, - and ^C. In the fourth case, EXTRACT selects all global names from ^TMP - through ^TMPzzzzz. + Redirects database extract to the standard output stream. The format of + the STDOUT qualifier is: --FILL_FACTOR - -FILL_FACTOR=percent-qualifier - Directs REORG to leave free space within blocks for future updates. - Arguments to this qualifier - must be integers from 5 to 100. REORG uses this figure in deciding - whether to place more - information in a block; currently REORG does not move information out - of a block to make more - room. By default, REORG attempts to fill blocks to their maximum - capacity. + -ST[DOUT] -1 RESTORE - RE[STORE] - RESTORE integrates one or more BACKUP -INCREMENTAL files into a - corresponding database. For a - RESTORE to work, the transaction numbers in the incremental file(s) must - sequentially follow those in the - database. Gaps or overlaps in the transaction numbers at RESTORE input - file boundaries cause RESTORE to - issue errors. +3 Examples + Examples - The format of the RESTORE command is: + Example: - RE[STORE] [qualifier] file-spec file-list + $ mupip extract -format=go -freeze big.glo - The file-specification identifies the name of the database file that - RESTORE uses as a starting point. The - transaction number in the database must match the starting transaction - number of each successive input to the - RESTORE. If the BACKUP -INCREMENTAL was created using -TRANSACTION=1, set - the database up - with MUPIP CREATE and do not access it with anything except the MUPIP - commands INTEG, EXTEND, - and SET before initiating the RESTORE. + This command prevents database updates during a MUPIP EXTRACT operation. - The file list specifies one or more files produced by BACKUP -INCREMENTAL - to RESTORE into the - database. The file-specifications are separated by commas (,) and must be - in sequential order, from the oldest - transaction number to the most recent. RESTORE may take its input from a - UNIX file on any device that - supports such files. + Example: -2 Qualifiers + $ mupip extract -format=GO mumps_i.go --EXTEND - -[NO]EXTEND - Specifies whether RESTORE should extend automatically if its target - database file is smaller than - the file size identified by the input BACKUP -INCREMENTAL file. MUMPS - activity between - backups may automatically extend a database file. Therefore, the - database file specified as the - starting point for a RESTORE may require an extension before the - RESTORE. If the database needs - an extension, MUPIP displays a message. The message gives the sizes of - the input and output - database files and the number of blocks by which to extend the - database. If the RESTORE specifies - more than one incremental backup with a file list, the database file - may require more than one - extension. + This command creates an extract file called mumps_i.go in "Global Output" + format. Use this format to transport or archive files. The first record of + a GO format file contains the header label, "GT.M MUPIP EXTRACT," as text. - By default, RESTORE automatically extends the database file. -1 RUNDOWN - RU[NDOWN] - When database files have not been properly closed, RUNDOWN closes those - currently inactive databases and - releases the central memory they claim. In normal operation, the last - process to close a database file performs - the RUNDOWN actions. + Example: - The format of the RUNDOWN command is: + $ mupip extract -format=BINARY v5.bin - RU[NDOWN] [-qualifier file-spec or region-list] + This command creates an extract file called v5.bin in Binary format. Use + this format for reorganizing a database or for short-term backups. - The filename or region-list identifies the target of the RUNDOWN. If - RUNDOWN has no parameter, it - ignores any qualifier and flushes the memory associated with all database - files that currently have associated - memory and no active users. + Example: - Use RUNDOWN after a system crash or after the last process accessing a - database terminates abnormally. - RUNDOWN ensures that an inactive database is properly closed and ready for - subsequent use. RUNDOWN - has no effect on any database that is actively being accessed at the time - the RUNDOWN is issued. + $ mupip extract -format=ZWR -LABEL=My_Label My_Extract_File - A RUNDOWN that specifies a target file or region can correct file state - problems which a RUNDOWN with - no parameters does not find. + This example extracts all globals from the current database to file + My_Extract_File (in ZWRITE format) with label My_Label. -2 Qualifiers --FILE - -F[ILE] - Specifies that the argument is a filename for a single database file. - The -FILE qualifier is - incompatible with the -REGION qualifier. If the rundown parameter - consists of a list of files, the - command only operates on the first item in the list. + Example: --REGION - -R[EGION] - Specifies that the argument contains one or more region-names which - identify database files mapped - by the current Global Directory. The -REGION qualifier is incompatible - with the -FILE qualifier. + $ mupip extract -nolog FL.GLO -2 SEt - SET modifies certain database characteristics. SET requires exclusive - (stand-alone) access to the - database file. SET operates on either regions or files. + This command creates a global output file, FL.GLO, (which consists of all + global variables in the database) without displaying statistics on a + global-by-global basis. As there is no label specified, the first record + in FL.GLO contains the text string "GT.M MUPIP EXTRACT." - The format of the SET command is: + Example: - SE[T] -qualifier... filename or region-list + $ mupip extract -select=Tyrannosaurus /dev/tty - The filename or region-list identifies the target of the SET. + This command instructs EXTRACT to dump the global ^Tyrannosaurus to the + device (file-name) /dev/tty. - The SET command must include one of the following qualifiers: +2 FREEZE + FREEZE - o -FILE + Temporarily suspends (freezes) updates to the database. If you prefer a + non-GT.M utility to perform a backup or reorganization, you might use this + facility to provide standalone access to your GT.M database. You might use + MUPIP FREEZE to suspend (and later resume) database updates for creating + mirrored disk configuration or re-integrating a mirror. - o -REGION + GT.M BACKUP, INTEG, and REORG operations may implicitly freeze and + unfreeze database regions. However, for most operations, this + freeze/unfreeze happens internally and is transparent to the application. + + The format of the MUPIP FREEZE command is: + + F[REEZE] {-OF[F] [-OV[ERRIDE]]|-ON [-R[ECORD]]} region-list + + o The region-list identifies the target of the FREEZE. + o MUPIP FREEZE waits for one minute so that concurrent KILL or MUPIP + REORG operations can complete. If the KILL or MUPIP REORG commands do + not complete within one minute, MUPIP FREEZE terminates operations and + unfreezes any regions it had previously marked as frozen. + o To ensure that a copy or reorganized version of a database file + contains a consistent set of records, concurrent MUPIP utilities, such + as BACKUP (without the ONLINE qualifier) and EXTRACT, include + mechanisms to ensure that the database does not change while the MUPIP + utility is performing an action. FIS recommends the use of the -ONLINE + qualifier with BACKUP. + o A MUPIP FREEZE can be removed only by the user who sets the FREEZE or + by using -OVERRIDE. + o After MUPIP FREEZE -ON, processes that are attempting updates "hang" + until the FREEZE is removed by the MUPIP FREEZE -OFF command or DSE. + Make sure that procedures for using MUPIP FREEZE, whether manual or + automated, include provisions for removing the FREEZE in all + appropriate cases, including when errors disrupt the normal flow. + o A -RECOVER/-ROLLBACK for a database reverts to a prior database update + state. Therefore, a -RECOVER/-ROLLBACK immediately after a MUPIP + FREEZE -ON removes the freeze. However, -RECOVER/-ROLLBACK does not + succeed if there are processes attached (for example when a process + attempt a database update immediately after a MUPP FREEZE -ON) to the + database. + + FREEZE must include one of the qualifiers: + + -OF[F] + -ON The optional qualifiers are: - o -G[LOBAL_BUFFERS]=integer + -OV[ERRIDE] + -R[ECORD] - o -[NO]JOURNAL[=journal-option-list] +3 OFf + OFf + Clears a freeze set by another process with the same userid. -2 Qualifiers --FILE - -F[ILE] - Specifies that the argument is a filename for a single database file. - The -FILE qualifier is - incompatible with the -REGION qualifier. + The format of the OFF qualifier is: --REGION - -R[EGION] - Specifies that the argument is a region-list which identifies database - file(s) mapped by the current - Global Directory. SET -REGION changes multiple files when the - parameter contains a list and-or - wildcards. The -REGION qualifier is incompatible with the -FILE - qualifier. + OF[F] - The following qualifiers determine the action(s) for the SET. - --GLOBAL_BUFFERS - -G[LOBAL_BUFFERS]=integer - Specifies the number of cache buffers for a BG database. For - information on determining good - working sizes for GLOBAL_BUFFERS, refer to the "Global Directory - Editor" chapter of the GT.M - Administration and Operations Guide. - - The minimum is 64 buffers and the maximum is 4096 buffers. By default, - MUPIP CREATE - establishes GLOBAL_BUFFERS using information entered in the Global - Directory with GDE. - --JOURNAL - -[NO]J[OURNAL][=journal-option-list] - Specifies whether the database allows journaling and, if it does, - characteristics for the journal file. - - -NOJOURNAL specifies the database does not allow journaling. - -NOJOURNAL does not accept an - argument assignment. - - -JOURNAL specifies journaling is allowed. -JOURNAL takes one or more - arguments in a - journal-option-list. - - For a full description of the -JOURNAL qualifier and its keywords, - refer the "GT.M Journaling" - chapter in the GT.M Administration and Operations Guide. - -1 SET - SE[T] - - MUPIP SET -JOURNAL determines whether a specified file or region(s) - have journaling activated. SET requires sole access to the database. - SET operates on either regions or files. - - The format for the SET command is: - - SE[T] -qualifier... file-spec or region-list - - The file-specification or region-list identifies the target of the - SET. Region-names separated by commas (,) make up a region-list. For - a summary table of MUPIP commands and qualifiers including MUPIP SET, - refer to the MUPIP chapter in the GT.M Administration and Operations - Guide. - -2 Object_qualifiers - Object Qualifiers - --FILE - -F[ILE] - Specifies that the argument contains a file-specification for a - single database file. The -FILE qualifier is incompatible with - the -REGION qualifier. - --REGION - -R[EGION] - Specifies that the argument contains a region-name which, - through the mapping of the current Global Directory, identifies - a database file. SET -REGION modifies multiple files when the - parameter contains more than one name. The -REGION qualifier is - incompatible with the -FILE qualifier. - -2 Action_qualifiers - Action Qualifiers - -/GLOBAL_BUFFERS - /G[LOBAL_BUFFERS]=integer - Specifies the number of cache buffers for a BG database. For - information on determining good working sizes of GLOBAL_BUFFERS, - refer to the "Global Directory Editor" chapter of the GT.M - Administration and Operations Guide. - - The minimum is 64 buffers and the maximum is 4096 buffers. By - default, MUPIP CREATE establishes GLOBAL_BUFFERS from - information entered in the Global Directory with GDE. - --JOURNAL - -[NO]J[OURNAL][=journal-option-list] - Specifies whether the database allows journaling and, if it - does, characteristics for the journal file. - - -NOJOURNAL specifies that the database does not allow - journaling. -NOJOURNAL does not accept an argument assignment. - -NOJOURNAL does not create new journal files. When a database - has been SET -NOJOURNAL, it appears to have no journaling file - name or other characteristics. - - -JOURNAL= enables journaling for a database file. -JOURNAL= - takes one or more arguments in a journal-option-list. Except - when used with the OFF option, SET -JOURNAL= always overwrites - any existing versions of the specified journal file(s). The - journal-option-list contains keywords separated with commas (,) - enclosed in parentheses (). When the list contains only one - keyword, the parentheses are optional. - - For details on the list refer to the journal-option-list topic. - -2 journal-option-list - journal-option-list elements - - The following topics detail the journal-option-list elements. + o When used with -OVERRIDE, -OFF stops a freeze operation set by a + process with a different userid. + o Incompatible with: -ON, -RECORD 3 ON - ON - ON specifies that MUPIP create a new journal file and that GT.M - record subsequent updates to the database in that journal file. - A SET -JOURNAL=ON must include either BEFORE_IMAGE or - NOBEFORE_IMAGE in the accompanying journal-option-list. When a - database has been SET -JOURNAL=ON, GT.M journals updates to that - file. + ON - By default, SET -JOURNAL= turns journaling on. + Specifies the start of a MUPIP FREEZE operation. The format of the ON + qualifier is: -3 OFF - OFF - OFF specifies that GT.M not record subsequent updates to the - database in the journal file. OFF may also be used to set up - journaling characteristics without creating a journal file or - starting journaling. When a database has been SET -JOURNAL=OFF, - it has established journal characteristics ready to turn ON, but - GT.M does not journal updates to that file. + -ON - By default, SET -JOURNAL= turns journaling on. + Incompatible with: -OFF, -OVERRIDE -3 BEFORE_IMAGE - [NO]BE[FORE_IMAGE] - [NO]BEFORE_IMAGE controls whether the journal should capture - before-images of information that an update is about to modify. - MM databases must use NOBEFORE_IMAGE journaling. A SET - -JOURNAL=ON must include either BEFORE_IMAGE or NOBEFORE_IMAGE - in the accompanying journal-option-list. +3 OVERRIDE + OVERRIDE - A BEFORE_IMAGE journal permits the possibility of performing - "roll-back" recovery (i.e., Backward Recovery) of the associated - database. BEFORE_IMAGE increases the load on I/O and CPU - resources and therefore may affect performance. + Release a freeze set by a process with a different userid. GT.M provides + OVERRIDE to allow error recovery in case a procedure with a freeze fails + to release. The format of the OVERRIDE qualifier is: -3 FILE_NAME - F[ILE_NAME]=file-specification - FILE_NAME=file-specification specifies the name of the journal - file. FILE_NAME is incompatible with SET -REGION. + -OV[ERRIDE] - Journal file-specifications are limited to 55 characters. + o OVERRIDE should not be necessary (and may even be dangerous) in most + schemes. + o Incompatible with: -ON, -RECORD - By default, MUPIP CREATE establishes the journal - file-specification from the Global Directory. If the Global - Directory does not contain a journal file-specification SET - -JOURNAL derives the journal file-specification from the - database file-specification using a file type of .MJL. Note that - because the default usually places the journal file on the same - disk drive as the database file, it does not protect well - against disk hardware failures. +3 Record + Record -3 ALLOCATION - A[LLOCATION]=blocks - ALLOCATION=blocks specifies the initial size of the journal file - in blocks. Because frequent journal file extensions degrade - run-time performance, make journal file allocation ample for a - production database. + Specifies that a MUPIP FREEZE operation should record an event as a + reference point. You might use MUPIP FREEZE to set up your database for a + custom-backup mechanism (SAN or mirror-based). - The minimum ALLOCATION is 10 blocks and the maximum is - 16,777,216 blocks. + The format of the RECORD qualifier is: - If journaling characteristics have not been previously - established by GDE or a prior SET -FILE -JOURNAL and a SET - -JOURNAL= specifies ALLOCATION but does not specify EXTENSION, - the command automatically changes EXTENSION to equal 10% of the - new ALLOCATION. + -R[ECORD] - By default, MUPIP CREATE establishes the ALLOCATION from the - Global Directory, where the Greystone supplied default is 100 - blocks. If the Global Directory does not contain ALLOCATION - information, SET -JOURNAL uses a default of 100 blocks. + o You might use -RECORD to integrate MUPIP BACKUP -BYTESTREAM with an + external backup mechanism. + o -RECORD replaces the previously RECORDed transaction identifier for + the database file. + o Incompatiable with: -OFF and -OVERRIDE. -3 EXTENSION=blocks - E[XTENSION]=blocks - EXTENSION=blocks specifies the size by which a journal file - extends when it becomes full. EXTENSION=0 disables automatic - journal file extension. While this technique exerts firm control - over disk space consumption by a journal file, running out of - journal file space terminates journaling for the region. Because - frequent journal file extensions degrade run-time performance, - make the journal file extension ample for a production database. +3 Examples + Examples - The minimum EXTENSION is 0 blocks and the maximum is 65,536 - blocks. + Example: - If journaling characteristics have not been previously - established by GDE or a prior SET -FILE -JOURNAL and a SET - -JOURNAL= specifies ALLOCATION but does not specify EXTENSION, - the command automatically changes EXTENSION to equal 10% of the - new ALLOCATION. + $ mupip freeze -off DEFAULT - By default, MUPIP CREATE establishes the EXTENSION from the - Global Directory, where the Greystone-supplied default is 100 - blocks. If the Global Directory does not contain EXTENSION - information and the SET -JOURNAL does not specify either - ALLOCATION or EXTENSION, MUPIP uses a default of 100 blocks. + This command stops an ongoing MUPIP FREEZE operation on the region + DEFAULT. -3 BUFFER_SIZE=pages - BU[FFER_SIZE]=pages - BUFFER_SIZE=pages specifies the amount of memory used to buffer - journal file output. + Example: - A larger BUFFER_SIZE usually smooths and improves run-time - performance by allowing larger, less frequent writes. On the - other hand, a larger BUFFER_SIZE requires more memory resources, - which may be scarce. A larger BUFFER_SIZE provides more room for - journal records in buffered memory and therefore increases the - number of update records that may be lost in a system failure. + $ mupip freeze -on "*" - The minimum BUFFER_SIZE is enough 512-byte pages to hold two GDS - database blocks and the maximum is 2000 pages. + This command prevents updates to all regions in the current Global + Directory. - By default, MUPIP CREATE establishes the BUFFER_SIZE from the - Global Directory, where the Greystone-supplied default is 128 - pages. If the Global Directory does not contain BUFFER_SIZE - information, SET -JOURNAL uses a default of 128 pages. + Example: -2 Examples - SET -JOURNAL Examples + $ set +e + $ mupip freeze -on -record "*" + $ tar cvf /dev/tape /prod/appl/*.dat + $ mupip freeze -off + $ set -e - Example + The set +e command instructs the shell to attempt all commands in the + sequence , regardless of errors encountered by any command. This ensures + that the freeze -off is processed even if the tar command fails. FREEZE + prevents updates to all database files identified by the current Global + Directory. The -record qualifier specifies that the current transaction in + each database be stored in the RECORD portion of the database file header. + The tar command creates a tape archive file on the device /dev/tape, + containing all the files from /prod/app that have an extension of .dat. + Presumably all database files in the current Global Directory are stored + in that directory, with that extension. The second FREEZE command + re-enables updates that were suspended by the first FREEZE. The set -e + command re-enables normal error handling by the shell. - $ mupip set -file -journal=(nobefore,buff=128) cus.dat - - This initiates journaling for the database file cus.dat. Because - the parameters include NOBEFORE, subsequent JOURNAL commands to - -RECOVER the database updates in the journal must specify -FORWARD. - The journal file created has the name cus.mjl. + Example: - Example + $ mupip freeze -override -off DEFAULT - mupip set -region -journal=(before,alloc=50000,ext=5000) + This command unfreezes the DEFAULT region even if the freeze was set by a + process with a different userid. - This enables journaling with BEFORE_IMAGES on all regions of the - current Global Directory and gives each journal an ALLOCATION of - 50000 blocks and an EXTENSION of 5000 blocks. If the regions have - significantly different levels of update, either set the ALLOCATION - and EXTENSION in the Global Directory before the MUPIP CREATE(s) - or use several MUPIP SET -FILE commands. +2 FTOK + FTOK - Example + Produces the "public" (system generated) IPC Keys (essentially hash + values) of a given file. - mupip set -region -journal=before joel.dat - - This declares journaling active with before-images for all regions - of the current Global Directory when they are next opened. + The format of the MUPIP FTOK command is: - Example + FT[OK] [-DB] [-JNLPOOL] [-RECVPOOL] file-name - mupip set -file -nojournal MUMPS.DAT - - This disables journaling on the database file MUMPS.DAT in the - current default directory. +3 DB + DB -1 STOP - ST[OP] - STOP terminates a GT.M image. The image executes an orderly rundown of all - databases in which it - currently has an interest and then exits. A MUPIP STOP may also be used to - stop non-GT.M images. + Specifies that the file-name is a database file. By default, MUPIP FTOK + uses -DB. + +3 JNLPOOL + JNLPOOL + + Specifies that the reported key is for the Journal Pool of the instance + created by the current Global Directory. + +3 RECVPOOL + RECVPOOL + + Specifies that the reported key is for the Receive Pool of the instance + created by the current Global Directory. + +2 INTEG + INTEG + + Performs an integrity check on a GT.M database file. You can perform + structural integrity checks on one or more regions in the current Global + Directory without bringing down (suspending database updates) your + application. However, a MUPIP INTEG on a single file database requires + standalone access but does not need a Global Directory. The order in which + the MUPIP INTEG command selects database regions is a function of file + system layout and may vary as files are moved or created. Execute a MUPIP + INTEG operations one database file at a time to generate an report where + the output always lists database files in a predictable sequence. For + example, to compare output with a reference file, run INTEG on one file at + a time. + + Always use MUPIP INTEG in the following conditions: + + o Periodically - to ensure ongoing integrity of the database(s); regular + INTEGs help detect any integrity problems before they spread and + extensively damage the database file. + o After a crash - to ensure the database was not corrupted. (Note: When + using before-image journaling, when the database is recovered from the + journal file after a crash, an integ is not required). + o When database errors are reported - to troubleshoot the problem. + + Improving the logical and physical adjacency of global nodes may result in + faster disk I/O. A global node is logically adjacent when it is stored + within a span of contiguous serial block numbers. A global node is + physically adjacent when it resides on adjacent hard disk sectors in a way + that a single seek operation can access it. Database updates (SETs/KILLs) + over time affect the logical adjacency of global nodes. A MUPIP INTEG + reports the logical adjacency of your global nodes which may indicate + whether a MUPIP REORG could improve the database performance. A native + file system defragmentation improves physical adjacency. + + **Note** + + Most modern SAN and I/O devices often mask the performance impact of the + adjustments in logical and physical adjacency. If achieving a particular + performance benchmark is your goal, increasing the logical and physical + adjacency should be only one of many steps that you might undertake. While + designing the database, try to ensure that the logical adjacency is close + to the number of blocks that can physically reside on your hard disk's + cylinder. You can also choose two or three cylinders, with the assumption + that short seeks are fast. + + The format of the INTEG command is: + + I[NTEG] + [ + -A[DJACENCY]=integer + -BL[OCK]=hexa;block-number + -BR[IEF] + -FA[ST] + -FU[LL] + -[NO]K[EYRANGES] + -[NO]MAP[=integer] + -[NO]MAXK[EYSIZE][=integer] + -S[UBSCRIPT]=subscript] + -TN[_RESET] + -[NO]TR[ANSACTION][=integer] + -[NO]O[NLINE] + ] + {[-FILE] file-name|-REG[ION] region-name} + + o MUPIP INTEG requires specification of either file(s) or region(s). + o Press to stop MUPIP INTEG before the process completes. + o The file-name identifies the database file for a MUPIP INTEG + operation.The region-list identifies one or more regions that, in + turn, identify database files through the current Global Directory. + o MUPIP INTEG operation keeps track of the number of blocks that do not + have the current block version during a non-fast integ (default or + full) and matches this value against the blocks to upgrade counter in + the file-header. It issues an error if the values are unmatched and + corrects the count in the file header if there are no other integrity + errors. + + **Important** + + Promptly analyze and fix all errors that MUPIP INTEG reports. Some errors + may be benign while others may be a signs of corruption or compromised + database integrity. If operations continue without fixes to serious + errors, the following problems may occur: + + o Invalid application operation due to missing or incorrect data. + o Process errors, including inappropriate indefinite looping, when a + database access encounters an error. + o Degrading application level consistency as a result of incomplete + update sequences caused by the prior symptoms. + + FIS strongly recommends fixing the following errors as soon as they are + discovered: + + o Blocks incorrectly marked free - these may cause accelerating damage + when processes make updates to any part of the database region. + o Integrity errors in an index block - these may cause accelerating + damage when processes make updates to that area of the database region + using the faulty index. + + MUPIP INTEG -FAST and the "regular" INTEG both report these errors (These + qualifiers are described later in this section). Other database errors do + not pose the threat of rapidly spreading problems in GDS files. After the + GT.M database repair, assess the type of damage, the risk of continued + operations, and the disruption in normal operation caused by the time + spent repairing the database. Contact your GT.M support channel for help + assessing INTEG errors. + + The following sections describe the qualifiers of the INTEG command. + +3 ADjacency + ADjacency + + Specifies the logical adjacency of data blocks that MUPIP INTEG should + assume while diagnosing the database. By default, MUPIP INTEG operates + with -ADJACENCY=10 and reports the logical adjacency in the "Adjacent" + column of the MUPIP INTEG report. + + o The complexity of contemporary disk controllers and the native file + system may render this report superfluous. But when it is meaningful, + this report measures the logical adjacency of data. + o A MUPIP REORG improves logical adjacency and a native file system + defragmentation improves physical adjacency. + + The format of the ADJACENCY qualifier is: + + -AD[JACENCY]=integer + +3 BLock + BLock + + Specifies the block for MUPIP INTEG command to start checking a sub-tree + of the database. MUPIP INTEG -BLOCK cannot detect "incorrectly marked busy + errors" + + The format of the BLOCK qualifier is: + + -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 + + Displays a single summary report by database file of the total number of + directory, index and data blocks. The format of the BRIEF qualifier is: + + -BR[IEF] + + o By default, MUPIP INTEG uses the BRIEF qualifier. + o Incompatible with: -FULL + +3 FAst + FAst + + Checks only index blocks. FAST does not check data blocks. + + The format of the FAST qualifier is: + + -FA[ST] + + o -FAST produces results significantly faster than a full INTEG because + the majority of blocks in a typical database are data blocks. + o While INTEG -FAST is not a replacement for a full INTEG, it very + quickly detects those errors that must be repaired immediately to + prevent accelerated database damage. + o By default, INTEG checks all active index and data blocks in the + database. + o Incompatible with: -TN_RESET. + +3 FIle + FIle + + Specifies the name of the database file for the MUPIP INTEG operation. + FILE requires exclusive (stand-alone) access to a database file and does + not require a Global Directory. The format of the FILE qualifier is: + + -FI[LE] + + o With stand-alone access to the file, MUPIP INTEG -FILE is able to + check whether the reference count is zero. A non-zero reference count + indicates prior abnormal termination of the database. + o The -FILE qualifier is incompatible with the -REGION qualifier. + o By default, INTEG operates on -FILE. + +3 FUll + FUll + + Displays an expanded report for a MUPIP INTEG operation. With -FULL + specified, MUPIP INTEG displays the number of index and data blocks in the + directory tree and in each global variable tree as well as the total + number of directory, index and data blocks. The format of the FULL + qualifier is: + + -FU[LL] + + o The -FULL qualifier is incompatible with the -BRIEF qualifier. + o By default, INTEG reports are -BRIEF. + o Use -FULL to have INTEG report all global names in a region or list of + regions. + +3 Keyranges + Keyranges + + Specify whether the MUPIP INTEG report includes key ranges that identify + the data suspected of problems it detects. The format of the KEYRANGES + qualifier is: + + -[NO]K[EYRANGES] + + By default, INTEG displays -KEYRANGES. + +3 MAP + MAP + + Specifies the maximum number of "incorrectly marked busy errors" that + MUPIP INTEG reports. The format of the MAP qualifier is: + + -[NO]MAP[=max_imb_errors] + + o specifies the threshold limit for the number of + incorrectly marked busy errors. + o -NOMAP automatically sets a high threshold limit of 1000000 (1 + million) incorrectly marked busy errors (-MAP=1000000). + o By default, INTEG reports a maximum of 10 map errors (-MAP=10). + + **Note** + + MUPIP INTEG reports "incorrectly marked free" errors as they require + prompt action. MAP does not restrict them. + + An error in an index block prevents INTEG from processing potentially + large areas of the database. A single "primary" error may cause large + numbers of "secondary" incorrectly marked busy errors, which are actually + useful in identifying valid blocks that have no valid index pointer. + Because "real" or primary incorrectly marked busy errors only make "empty" + blocks unavailable to the system, they are low impact and do not require + immediate repair. + + **Note** + + After a database recovery with -RECOVER (for example, using -BEFORE_TIME) + or -ROLLBACK (for example, using -FETCHRESYNC), the database may contain + incorrectly marked busy errors. Although these errors are benign, they + consume available space. Schedule repairs on the next opportunity. + +3 MAXkeysize + MAXkeysize + + Specifies the maximum number of "key size too large" errors that a MUPIP + INTEG operation reports. The format of the MAXKEYSIZE qualifier is: + + -[NO]MAX[KEYSIZE][=integer] + + o By default, INTEG reports a maximum of 10 key size errors (- + MAXKEYSIZE=10). + o -NOMAXKEYSIZE removes limits on key size reporting so that INTEG + reports all key size too large errors. + o -NOMAXKEYSIZE does not accept assignment of an argument. + o "Key size too large" errors normally occur only if a DSE CHANGE + -FILEHEADER -KEY_MAX_SIZE command reduces the maximum key size. + +3 Online + Online + + Specifies that while a MUPIP INTEG operation is active, other processes + can update the database without affecting the result of the backup. Allows + checking database structural integrity to run concurrently with database + updates. The format of the ONLINE qualifier is: + + -[NO]O[NLINE] + + o -NOONLINE specifies that the database should be frozen during MUPIP + INTEG. + o By default, MUPIP INTEG is online except for databases containing V4 + blocks for which the default is -NOONLINE. Note that databases + containing V4 blocks should exist only in databases that are in the + process of being migrated from V4 to V5; please complete your + migration to the V5 format before using MUPIP INTEG -ONLINE. + o Since MUPIP INTEG -ONLINE does not freeze database updates, it cannot + safely correct errors in the "blocks to upgrade" and "free blocks" + fields in the file header, while MUPIP INTEG -NOONLINE can correct + these fields. + o As it checks each database file, MUPIP INTEG -ONLINE creates a sparse + file of the same size as the database. As each GT.M process updates + the database, it places a copy of the old block in the sparse file + before updating the database. For any database blocks with a newer + transaction number than the start of the INTEG, MUPIP uses the copy in + the sparse file. Thus, analogous with MUPIP BACKUP -ONLINE, INTEG + reports on the state of the database as of when it starts, not as of + when it completes. Note: a command such as ls -l command shows sparse + files at their full size, but does not show actual disk usage. Use a + command such as du -sh to see actual disk usage. + o The environment variable GTM_BAKTMPDIR (unlike most GT.M environment + variables, this is upper case; it is the same directory used for MUPIP + BACKUP -ONLINE) can be used to indicate a directory where MUPIP should + place the snapshot files (used by MUPIP INTEG -ONLINE). If + GTM_BAKTMPDIR does not exist, MUPIP places the snapshot files in the + current directory at the time you issue the INTEG command. MUPIP and + GT.M processes automatically cleans up these temporary snapshot files + under a wider variety of conditions. + o Temporary directory security settings must allow write access by the + the MUPIP process and read access by all processes updating the + database. MUPIP creates the temporary file with the same access as the + database file so processes updating the database can write to the + temporary file. If the database is encrypted, the updating processes + write encrypted blocks to the snapshot file and the MUPIP INTEG + process must start with access to appropriate key information as it + does even -NOONLINE. + o MUPIP INTEG -NOONLINE [-FAST] {-REGION|-FILE} clears the KILLs in + progress and Abandoned Kills flags if the run includes the entire + database and there are no incorrectly marked busy blocks. + o Only one online integ can be active per database region. If an online + integ is already active, a subsequent one issues an error and + immediately terminates. If an online integ does not successfully + complete, GT.M cleans it up in one of the following ways: + + o A subsequent online integ detects that an earlier one did not + successfully complete and releases the resources held by the + prior online integ before proceeding. + o If a MUPIP STOP was issued to the online integ process, the + process cleans up any resources it held. Note: since the process + was stopped the results of the integ may not be valid. + o subsequent MUPIP RUNDOWN ensures the release of resources held by + prior unsuccessful online integs for the specified regions. + o For every 64K transactions after the online integ initiation, + online integ checks GT.M health for improperly abandoned online + integs and releases resources held by any it finds. + + o Incompatible with: -FILE, -TN_RESET (there should be no need to use + -TN_RESET on a GT.M V5 database). + +3 Region + Region + + Specifies that the INTEG parameter identifies one or more regions rather + than a database file. The format of the REGION qualifier is: + + -R[EGION] + + o MUPIP INTEG -REGION does not require stand alone access to databases. + Instead, it freezes updates (but not reads) to the database during the + check. The region-list argument may specify more than one region of + the current Global Directory in a list separated with commas. INTEG + -REGION requires the environment variable gtmgbldir to specify a valid + Global Directory. For more information on defining gtmgbldir, refer to + the "Global Directory Editor" chapter. + o Because a KILL may briefly defer marking the blocks it releases "free" + in the bit maps, INTEG -REGION may report spurious block incorrectly + marked busy errors. These errors are benign. If these errors occur in + conjunction with a "Kill in progress" error, resolve the errors after + the "Kill in progress" error is no longer present. + o By default, INTEG operates -FILE. + o Incompatible with: -FILE, -TN_RESET + +3 Subscript + Subscript + + Specifies a global or a range of keys to INTEG. The global key may be + enclosed in quotation marks (" "). Identify a range by separating two + subscripts with a colon (:). -SUBSCRIPT cannot detect incorrectly marked + busy errors. The format of the SUBSCRIPT qualifier is: + + -S[UBSCRIPT]=subscript + + Specify SUBSCRIPT only if the path to the keys in the subscript is not + damaged. If the path is questionable or known to be damaged, use DSE to + find the block(s) and INTEG -BLOCK. + + Incompatible with: -BLOCK, -TN_RESET + +3 TN_reset + TN_reset + + Resets block transaction numbers and backup event recorded transaction + numbers to (one) 1, and the current transaction number to two (2) which + makes the backup event recorded transaction numbers more meaningful and + useful. It also issues an advisory message to perform a backup. + + The format of the TN_RESET qualifier is: + + -TN[_RESET] + + o Transaction numbers can go up to 18,446,744,073,709,551,615. This + means that a transaction processing application that runs flat out at + a non-stop rate of 1,000,000 updates per second would need a TN reset + approximately every 584,554 years. + o The -TN_RESET qualifier rewrites all blocks holding data. If the + transaction overflow resets to zero (0) database operation is + disrupted. + o The -TN_RESET qualifier is a protective mechanism that prevents the + transaction overflow from resetting to 0. + o By default, INTEG does not modify the block transaction numbers. + + **Important** + + There should never be a need for a -TN_RESET on a database with only + V5 blocks, even when cleaning up after a runaway process. + + o The -TN_RESET qualifier is incompatible with the -FAST, -BLOCK, + -REGION, and -SUBSCRIPT qualifiers. + + **Note** + + Any time a GT.M update opens a database file that was not properly closed, + GT.M increments the transaction number by 1000. This automatic increment + prevents problems induced by abnormal database closes, but users must + always consider this factor in their operational procedures. The rate at + which GT.M "uses up" transaction numbers is a function of operational + procedures and real database updates. + +3 TRansaction + TRansaction + + Specifies the maximum number of block transaction- number-too-large errors + that MUPIP INTEG reports. The format of the TRANSACTION qualifier is: + + -[NO]TR[ANSACTION][=integer] + + o -NOTRANSACTION removes limits on transaction reporting so MUPIP INTEG + reports all transaction number errors. + o -NOTRANSACTION does not accept assignment of an argument. + o A system crash may generate many "block transaction number too large" + errors. These errors can cause problems for BACKUP -INCREMENTAL and + for transaction processing. Normally, the automatic increment of 1000 + blocks that GT.M adds when a database is reopened averts these errors. + If a problem still exists after the database is reopened, users can + use a value in the DSE CHANGE -FILEHEADER -CURRENT_TN= command to + quickly fix "block transaction number too large number" errors. + o By default, INTEG reports a maximum of 10 block transaction errors + (-TRANSACTION=10). + +3 Examples + Examples + + Example: + + $ mupip integ -block=4 mumps.dat + + This command performs a MUPIP INTEG operation on the BLOCK 4 of mumps.dat. + + Example: + + $ mupip integ -adjacency=20 + + 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 + Free 43 NA NA NA + Total 1200 95345 NA 1031 + + This example performs a MUPIP INTEG operation assuming that logically + related data occupies 20 data blocks in the current database. The sample + output shows that out of 1137 data blocks, 1030 data blocks are adjacent + to each other. One can improve the performance of a database if the all + blocks are as adjacent as possible. + + Example: + + $ mupip integ -brief mumps.dat + + This command performs a MUPIP INTEG operation on the database mumps.dat. A + 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 + Free 96 NA NA NA + Total 100 6 NA 2 + + Example: + + $ mupip integ -fast mumps.dat + + This command performs a MUPIP INTEG operation only on the index block of + the database file mumps.dat. A sample output from the above command + follows: + + 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 + Free 96 NA NA NA + Total 100 NA NA 1 + + Note the NA entries (highlighted in bold) for Data type. It means that the + MUPIP INTEG -FAST operation checked only index blocks. + + $ mupip integ -full mumps.dat + + The sample output from the above command follows: + + Directory tree + 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 + Free 91 NA NA NA + Total 100 508 NA 7 + + Example: + + $ mupip integ -map=20 -maxkeysize=20 -transaction=2 mumps.dat + + This command performs a MUPIP INTEG operation and restricts the maximum + number of "key size too large" errors to 20. + + Example: + + $ mupip integ -map=20 -transaction=2 mumps.dat + + This command performs a MUPIP INTEG operation and restricts the maximum + number of "block transaction- number-too-large errors" to 2. + + $ mupip integ -file mumps.dat -tn_reset + + This command resets the transaction number to one in every database block. + + Example: + + $ mupip integ -subscript="^Parrots" mumps.dat + + This example performs a MUPIP INTEG operation on the global variable + ^Parrots in the database file mumps.dat. + + Example: + + $ mupip integ -subscript="^Amsterdam(100)":"^Bolivia(""Chimes"")" -region DEFAULT + + This example performs a MUPIP INTEG operation all global variables greater + than or equal to ^Amsterdam (100) and less than or equal to + ^Bolivia("Chimes") in the default region(s). + + **Note** + + To specify a literal in the command string, use two double quotation marks + for example, ^b(""c""). + +2 INTRPT + INTRPT + + Sends an interrupt signal to the specified process. The signal used is + [POSIX] SIGUSR1. The format of the MUPIP INTRPT command is: + + INTRPT process-id + + **Important** + + Ensure that signal SIGUSR1 is not be used by any C external function calls + or any (initially non-GT.M) processes that use call-in support, as it is + interpreted by GT.M as a signal to trigger the $ZINTERRUPT mechanism. + + o To INTRPT a process belonging to its own account, a process requires + no UNIX privilege. + o To INTRPT a process belonging to its own GROUP, a process requires + UNIX membership in the user group of the target process privilege. To + INTRPT a process belonging to an account outside its own GROUP, a + process requires UNIX superuser privilege. + +2 LOAD + LOAD + + Puts the global variable names and their corresponding data values into a + GT.M database from a sequential file. + + 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]]} + -S[TDIN] + ] + file-name + + **Caution** + + From an application perspective, performing a MUPIP LOAD operation while + 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 + 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 + such files. + o 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 + %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 to produce a status message from LOAD. Entering + 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 + database structure unless terminated with a kill -9. + + **Note** + + The MUPIP EXTRACT or MUPIP LOAD procedure for large databases are time + consuming due to the volume of data that has to be converted from binary + to ZWR format (on source) and vice versa (on target). One must also + consider the fact that the extract file can be very large for a large + database. Users must ensure adequate storage support the size of the + extract file and the space occupied by the source and target databases. In + order to reduce the total time and space it takes to transfer database + content from one endian platform to another, it is efficient to convert + the endian format in-place for a database and transfer the converted + database. See MUPIP ENDIANCVT for more information on converting the + endian format of a database file. + + The following sections describe the optional qualifiers of the MUPIP LOAD + command. + +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. + + The format codes are: + + GO - Global Output format + 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 + 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) + 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). + +3 BEgin + BEgin + + Specifies the record number of the input file with which LOAD should + begin. Directing LOAD to begin at a point other than the beginning of a + valid key causes an error. The format of the BEGIN qualifier is: + + -BE[GIN]=integer + + **Important** + + 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 + -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 + 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. + +3 End + End + + Specifies the record number of the input file at which LOAD should stop. + -END=integer must be greater than the -BEGIN=integer for LOAD to operate. + LOAD terminates after processing the record of the number specified by + -END or reaching the end of the input file. The format of the END + qualifier is: + + -E[ND]=integer + + The value of -FORMAT=GO input should normally be an even number. By + default, LOAD continues to the end of the input file. + +3 FIll_factor + FIll_factor + + Specifies the quantity of data stored in a database block. Subsequent + run-time updates to the block fill the remaining available space reserved + by the FILL_FACTOR. Blocks that avoid block splits operate more + efficiently. The format of the FILL_FACTOR qualifier is: + + -FI[LL_FACTOR]=integer + + o 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 + 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. + + **Note** + + FILL_FACTOR is useful when updates add or grow records reasonably + uniformly across a broad key range. If updates are at ever ascending or + descending keys, or if the record set and record sizes are relatively + static in the face of updates, FILL_FACTOR won't provide much benefit. + +3 Stdin + Stdin + + Specifies that MUPIP LOAD takes input from standard input (stdin). The + format of the STDIN qualifier is: + + -S[TDIN] + +3 Examples + Examples + + Example: + + $ mupip load ex_file.go + + This command loads the content of the extract file ex_file.go to the + current database. + + Example: + + $ mupip load -format=go big.glo + + This command loads an extract file big.glo in the current database. + + Example: + + $ mupip load -begin=5 -end=10 rs.glo + + This command begins MUPIP LOAD operation from record number 5 and ends at + record number 10. Note that the value for BEGIN is an odd number. A sample + output from the above command follows: + + GT.M MUPIP EXTRACT + 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 + Last LOAD record number: 10 + + Example: + + $ mupip load -fill_factor=5 reobs.glo + + This command set the FILL_FACTOR to 5 for loading an extract file in the + current database. + + Example: + + $cat big.glo | mupip load -stdin + $mupip load -stdin < big.glo + + These commands loads the extract file big.glo using -stdin. + +2 REORG + REORG + + Improves database performance by defragmenting and reorganizing database + files and attempts to reduce the size of the database file. MUPIP REORG + runs concurrently with other database activity, including updates. + Competing activity generally increases the time required to perform a + REORG, as well as that of the competing operations. + + The format of the REORG command is: + + REO[RG] + [ + -D[OWNGRADE] + -E[XCLUDE]=global-name-list + -FI[LL_FACTOR]=integer + -I[NDEX_FILL_FACTOR]=integer + -R[ESUME] + -SAFEJNL + -S[ELECT]=global-name-list + -STA[RTBLK]=hexa + -STO[PBLK]=hexa + -T[RUNCATE][=percentage] + -UP[GRADE] + -US[ER_DEFINED_REORG]=reorg_list + -REG[ION]=region-list + ] + + **Note** + + While REORG optimizes the GDS structure of database files, it does not + handle native file system file fragmentation. In most cases, fragmentation + at the native file system level is more likely than fragmentation at the + GDS structure level. Therefore, FIS recommends users create files with + appropriate allocations and extensions, on disks with large amounts of + contiguous free space. Use native utilities and MUPIP utilities (depending + on operational procedures) to eliminate file fragmentation when database + files have been extended more than a dozen times. + + o Using REORG concurrently with normal database access affects the + performance of normal operation. To reduce this impact, lower the + priority of the process performing the REORG. + o MUPIP REORG does not change the logical contents of the database, and + can run on either the originating instance or replicating instance of + an LMS application. In such cases, resuming REORGs in process should + be part of the batch restart. See "GT.M Database Replication" chapter + for more information about running REORG on a dual site application. + o If you run MUPIP STOP for an ongoing MUPIP REORG process, it may leave + the database blocks in an inconsistent state. In this situation, GT.M + converts the ongoing KILLs flag to abandoned KILLs flag. If a + subsequent MUPIP REORG encounters these abandoned KILLs flags, it + gives a message and then starts its REORG actions. + o terminates REORG. A REORG terminated abnormally by operator + action or error is incomplete but does not adversely affect the + database structure, unless terminated with a kill -9. + + Assume two scenarios of putting values of ^x(1) to ^x(10000). In the first + scenarios, fill values in a sequential manner. In the second scenario, + enter values for odd subscripts and then enter values for the even + subscripts. + + Scenario 1: + + At the GT.M prompt, execute the following command sequence: + + GTM>for i=1:1:10000 set ^x(i)=$justify(i,200) + + Then, execute the following MUPIP INTEG command. + + $ mupip integ -region "*" + + 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 + Free 69 NA NA NA + Total 2600 12530 NA 2500 + + Note the high density (percent used) for index and data blocks from the + report. + + Scenario 2: + + 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: + + $ mupip integ -region "*" + + 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 + Free 95 NA NA NA + Total 4000 13904 NA 1307 + + Note that there are more and less dense index and data blocks used than in + scenario 1. MUPIP REORG addresses such issues and makes the database + (depending on the FILL_FACTOR) more compact. + + The optional qualifiers for MUPIP REORG are: + +3 Exclude + Exclude + + Specifies that REORG not handle blocks that contain information about the + globals in the associated list-this means they are neither reorganized nor + swapped in the course of reorganizing other globals; -EXCLUDE can reduce + the efficiency of REORG because it complicates and interferes with the + block swapping actions that try to improve adjacency. + + The format of the EXCLUDE qualifier is: + + -E[XCLUDE]=global-name-list + + o Assume that a single MUPIP command organizes a subset of the globals + in a database or region. If a second MUPIP REORG command selects the + remaining globals, it may tend to disrupt the results of the first + REORG by de-optimizing the previously organized blocks. This is + because there is no information passed from the previous MUPIP REORG + command to the next command. The EXCLUDE qualifier allows users to + list the name of the previously REORGed globals, so that the MUPIP + REORG bypasses the GDS blocks containing these globals. + o If global-name-list contains globals that do not exist, REORG issues a + message to the terminal and continues to process any specified globals + that exist. If REORG is unable to process any globals, it terminates + with an error. + o Global-name-list can be an individual global name, a range of global + names, or a list of names and prefixes followed by the wildcard + symbol. For example: + + 1. A global name, such as ACN. + 2. A range of global names, such as A7:B7. + 3. A list, such as A,B,C. + 4. Global names with the same prefix such as TMP*. + + In the first case, REORG only excludes global ^ACN. In the second case, + REORG excludes all global names in the collating sequence A7 to B7. For + the third case, REORG excludes A, B, and C. In the last case, REORG + excludes all globals prefixed with TMP. + + o Enclose wildcards in double-quotes ("") to prevent inappropriate + expansion by the shell. The caret symbol (^) in the specification of + the global is optional. + o By default, REORG does not EXCLUDE any globals. + o In case any global appears in the argument lists of both -SELECT and + -EXCLUDE, REORG terminates with an error. + +3 Fill_factor + Fill_factor + + Specifies how full you want each database block to be. This is a target + number. Individual blocks may be more or less full than the fill factor. + The format of the FILL_FACTOR qualifier is: + + F[ILL_FACTOR]=integer + + o The arguments for the FILL_FACTOR qualifier must be integers from 30 + to 100. These integers represent the percentage of the data block that + REORG can fill. By default, the FILL_FACTOR value is 100 for maximum + data density. + o Users who come upon database performance issues or a high rate of + database updates must examine the defined FILL_FACTORs. Unless the + application uses entirely uniform records, which is not typical for + most applications, FILL_FACTORs do not work precisely. + o The FILL_FACTOR for data that is relatively static, or grows by the + addition of new nodes that collate before or after pre-existing nodes, + should be 100 percent. The FILL_FACTOR for data that is growing by + additions to existing nodes may be chosen to leave room in the typical + node for the forecast growth for some period. Generally, this is the + time between the LOAD and first REORG, or between two REORGs. This is + also true for additions of nodes that are internal to the existing + collating sequence. + +3 Index_fill_factor + Index_fill_factor + + Directs REORG to leave free space within index blocks for future updates. + Arguments to this qualifier must be integers from 30 to 100 that represent + the percentage of the index block that REORG can fill. REORG uses this + number to decide whether to place more information in an index block, or + create space by moving data to another block. The format of the + INDEX_FILL_FACTOR qualifier is: + + -I[NDEX_FILL_FACTOR]=integer + + Under certain conditions, especially with large database block sizes, it + may be possible to achieve faster throughput by using a smaller fill + factor for index blocks than for data blocks. By default, the + INDEX_FILL_FACTOR is the value of FILL_FACTOR regardless of whether that + value is explicitly specified or implicitly obtained by default. + +3 Resume + Resume + + For an interrupted REORG operation, -RESUME allows the user to resume the + REORG operation from the point where the operation stopped. REORG stores + the last key value in the database file header. The format of the RESUME + qualifier is: + + -R[ESUME] + + o With RESUME specified, the program retrieves the last key value, from + the database file header, and restarts operations from that key. + +3 Region + Region + + Specifies that REORG operate in the regions in the associated list and + restricts REORG to the globals in those regions that are mapped by the + current global directory; it does not have the same interactions as + -EXCLUDE and -SELECT, but it does not mitigate those interactions when + combined with them. + + The format of the REGION qualifier is: + + -R[EGION]=region-list + +3 Select + Select + + Specifies that REORG reorganizes only the globals in the associated list; + globals not on the list may be modified by block swaps with selected + globals unless they are named with -EXCLUDE; -SELECT can be difficult to + use efficiently because it tends to deoptimize unselected globals unless + they are name in an -EXCLUDE list (which introduces inefficiency). + + The format of the SELECT qualifier is: + + -S[ELECT]=global-name-list + + o By default, REORG operates on all globals in all database files + identified by the current Global Directory for the process executing + the MUPIP command. + o One of the functions performed by REORG is to logically order the + globals on which it operates within the file. Unless the EXCLUDE and + SELECT qualifiers are properly used in tandem, repeating the command + with different selections in the same file wastes work and leaves only + the last selection well organized. + o If you enter the REORG -SELECT=global-name-list command and the + specified globals do not exist, REORG issues a message to the screen + and continues to process any specified globals that exist. If REORG is + unable to process any globals, it terminates with an error. + o Arguments for this qualifier may be an individual global name, a range + of global names, or a list of names and prefixes followed by the + wildcard symbol. The caret symbol (^) in the specification of the + global is optional. + o The global name can be: + + 1. A global name, such as ACN + 2. A range of global names, such as A7:B7 + 3. A list, such as A,B,C. + 4. Global names with the same prefix such as TMP*. + + o In the first case, REORG only includes global ^ACN. In the second + case, REORG includes all global names in the collating sequence A7 to + B7. For the third case, REORG includes A, B, and C. In the last case, + REORG includes all globals prefixed with TMP. + o By default, REORG selects all globals. + +3 Truncate + Truncate + + Specifies that REORG, after it has rearranged some or all of a region's + contents, should attempt to reduce the size of the database file and + return free space to the file system. The format of the TRUNCATE qualifier + is: + + -T[RUNCATE][=percentage] + + The optional percentage (0-99) provides a minimum amount for the + reclamation; in other words, REORG won't bother performing a file truncate + unless it can give back at least this percentage of the file; the default + (0) has it give back anything it can. TRUNCATE always returns space + aligned with bit map boundaries, which fall at 512 database block + intervals. TRUNCATE analyses the bit maps, and if appropriate, produces + before image journal records as needed for recycled (formerly used) + blocks; The journal extract of a truncated database file may contain INCTN + records having the inctn opcode value 9 indicating that the specific block + was marked from recycled to free by truncate. + + **Note** + + TRUNCATE does not complete if there is a concurrent online BACKUP or use + of the snapshot mechanism, for example by INTEG. + +3 Examples + Examples + + Example: + + $ mupip reorg -exclude="^b2a,^A4gsEQ2e:^A93" + + This example performs a MUPIP REORG operation on all globals excluding + ^b2a and all globals ranging from ^A4gsEQ2e to ^A93. + + Example: + + If the forecasted growth of a global is 5% per month from relatively + uniformly distributed updates, and REORGs are scheduled every quarter, the + FILL_FACTOR for both the original LOAD and subsequent REORGs might be 80 + percent 100 - ((3 months + 1 month "safety" margin) * five percent per + month). The REORG command based on the above assumptions is as follows: + + $ mupip reorg -fill_factor=80 + +2 RESTORE + RESTORE + + Integrates one or more BACKUP -INCREMENTAL files into a corresponding + database. The transaction number in the first incremental backup must be + one more than the current transaction number of the database. Otherwise, + MUPIP RESTORE terminates with an error. + + The format of the RESTORE command is: + + RE[STORE] [-[NO]E[XTEND]] file-name file-list + + o file-name identifies the name of the database file that RESTORE uses + as a starting point. + o file-list specifies one or more files produced by BACKUP -INCREMENTAL + to RESTORE into the database. The file-name are separated by commas + (,) and must be in sequential order, from the oldest transaction + number to the most recent transaction number. RESTORE may take its + input from a UNIX file on any device that supports such files. + o The current transaction number in the database must match the starting + transaction number of each successive input to the RESTORE. + o If the BACKUP -INCREMENTAL was created using -TRANSACTION=1, create a + new database with MUPIP CREATE and do not access it, except the + standalone MUPIP commands INTEG -FILE, EXTEND, and SET before + initiating the RESTORE. + +3 Extend + Extend + + Specifies whether a MUPIP RESTORE operation should extend the database + file automatically if it is smaller than the size required to load the + data. + + The format of the EXTEND qualifier is: + + -[NO]E[XTEND] + + M activity between backups may automatically extend a database file. + Therefore, the database file specified as the starting point for a RESTORE + may require an extension before the RESTORE. If the database needs an + extension and the command specifies -NOEXTEND, MUPIP displays a message + and terminates. The message provides the sizes of the input and output + database files and the number of blocks by which to extend the database. + If the RESTORE specifies more than one incremental backup with a file + list, the database file may require more than one extension. + + By default, RESTORE automatically extends the database file. + +3 Examples + Examples + + $ mupip restore backup.dat $backup_dir/backup.bk1, $backup_dir/backup.bk2, $backup_dir/backup.bk3 + + This command restores backup.dat from incremental backups stored in + directory specified by the environment variable backup_dir. + + $ mupip restore gtm.dat '"gzip -d -c online5pipe.inc.gz |"' + + This command uses a pipe to restore gtm.dat since its last DATABASE backup + from the bytestream backup stored in online5pipe.inc.gz. + +2 RUNDOWN + RUNDOWN + + When database access has not been properly terminated, RUNDOWN properly + closes currently inactive databases, removes abandoned GT.M database + semaphores, and releases any IPC resources used. Under normal operations, + the last process to close a database file performs the RUNDOWN actions, + and a MUPIP RUNDOWN is not required. If a database file is already + properly rundown, a MUPIP RUNDOWN has no effect. If in doubt, it is always + to safe to perform a rundown. FIS recommends the following method to + shutdown a GT.M application or the system: + + o Terminate all GT.M processes, and + o Rundown any and all database files that may be active. + + MUPIP RUNDOWN checks for version mismatch. If there is a mismatch, it + skips the region and continues with the next region. This makes it easier + for multiple (non-interacting) GT.M versions to co-exist on the same + machine. Note that GT.M does not support concurrent access to the same + database file by multiple versions of the software. + + The format of the RUNDOWN command is: + + RU[NDOWN] {-FILE file-name|-REGION region-list]} + + MUPIP RUNDOWN clears certain fields in a file that is already closed. This + facilitates recovery from a system crash or other operational anomaly. + + Use RUNDOWN after a system crash or after the last process accessing a + database terminates abnormally. RUNDOWN ensures that open databases are + properly closed and ready for subsequent use. RUNDOWN has no effect on any + database that is actively being accessed at the time the RUNDOWN is + issued. + + To ensure database integrity, all system shutdown algorithms should + include scripts that stop at GT.M processes and perform RUNDOWN on all + database files. + + The RUNDOWN command may include one of the following qualifiers: + + -F[ile] + -R[egion] + + 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 + associated with a GT.M database, attempts to rundown that file. + +3 File + File + + Specifies that the argument is a file-name for a single database file. The + -FILE qualifier is incompatible with the REGION qualifier. If the rundown + parameter consists of a list of files, the command only operates on the + first item in the list. + + Incompatible with: -REGION + +3 Region + Region + + Specifies that the argument contains one or more region-names that + identify database files mapped by the current Global Directory. Use the + wild card "*" to rundown all inactive regions in a global directory. + + Incompatible with: -FILE + + When MUPIP RUNDOWN has no qualifier, it performs rundown on all inactive + database memory sections on the node. Because this form has no explicit + list of databases, it does not perform any clean up on regions that have + no abandoned memory segments but may not have been shutdown in a crash. + +2 SET + SET + + Modifies certain database characteristics. MUPIP SET operates on either + regions or files. + + **Note** + + In regions that have journaling enabled and on, users can switch journal + files without either requiring standalone access or freezing updates. + + The format of the SET command is: + + SE[T] {-FI[LE] file-name|-REG[ION] region-list} + -A[CCESS_METHOD]={BG|MM} + -B[YPASS] + -DE[FER_TIME]=seconds + -E[XTENSION_COUNT]=integer(no of blocks) + -F[LUSH_TIME]=integer + -G[LOBAL_BUFFERS]= + -JN[LFILE] + -JO[URNAL]=journal-option-list + -L[OCK_SPACE]=integer + -[NO]INST[_FREEZE_ON_ERROR] + -PA[RTIAL_RECOV_BYPASS] + -REP[LICATION]={ON|OFF} + -RES[ERVED_BYTES]=integer] + -S[TANDALONENOT] + -V[ERSION]={V4|V6} + -W[AIT_DISK]=integer + + o The file-name (or region-list) identifies the target of the SET. + o The SET command must include one of the following qualifiers which + determine whether the argument to the SET is a file-name or a + region-list. + o Exclusive access to the database is required if the MUPIP SET command + specifies -ACCESS_METHOD, -GLOBAL_BUFFERS, -LOCK_SPACE or -NOJOURNAL, + or if any of the -JOURNAL options ENABLE, DISABLE, or BUFFER_SIZE are + specified. + + The following section describe the qualifiers of the MUPIP SET command. + +3 Access_method + Access_method + + Specifies the access method (GT.M buffering strategy) for storing and + retrieving data from the global database file. The format of the + ACCESS_METHOD qualifier is: + + -A[CCESS_METHOD]=code + +3 PArtial_recov_bypass + PArtial_recov_bypass + + Sets the CORRUPT_FILE flag in the database fileheader to FALSE. The + CORRUPT_FILE flag indicates whether a region completed a successful + recovery. + +3 File + File + + Specifies that the argument is a file-name for a single database file. The + format of the FILE qualifier is: + + -F[ILE] + + Incompatible with: -REGION + +3 Region + Region + + Specifies that the argument is a region-list which identifies database + file(s) mapped by the current Global Directory. The format of the REGION + qualifier is: + + -R[EGION] + + SET -REGION changes multiple files when the parameter contains a list + and/or wildcards. + + Incompatible with: -FILE + +3 Extension_count + Extension_count + + Specifies the number of GDS blocks by which an existing database file + extends. A file or region name is required. This qualifier requires + standalone access. + + The format of the EXTENSION_COUNT qualifier is: + + -E[XTENSION_COUNT]=integer + +3 Flush_time + Flush_time + + Specifies the amount of time between deferred writes of stale cache + buffers. The default value is 1 second and the maximum value is 1 hour. + -FLUSH_TIME requires standalone access. The format of the FLUSH_TIME + qualifier is: + + -F[LUSH_TIME]=[[[HOURS:]MINUTES:]SECONDS:]CENTISECONDS + +3 Global_buffers + Global_buffers + + Specifies the number of cache buffers for a BG database. This qualifier + requires standalone access.The format of the GLOBAL_BUFFERS qualifier is: + + -G[LOBAL_BUFFERS]=integer + + In general, increasing the number of global buffers improves performance + by smoothing the peaks of I/O load on the system. However, increasing the + number of global buffers also increases the memory requirements of the + system, and a larger number of global buffers can increase the probability + of the buffers getting swapped out. If global buffers are swapped out, any + performance gain from increasing the number of global buffers will be more + than offset by the performance impact of swapping global buffers. Most + applications use from 1,000 to 4,000 global buffers for database regions + that are heavily used. FIS does not recommend using fewer than 256 buffers + except under special circumstances. + + The minimum is 64 buffers and the maximum is 65536 buffers. By default, + MUPIP CREATE establishes GLOBAL_BUFFERS using information entered in the + Global Directory. + + On many UNIX systems, default kernel parameters may be inadequate for GT.M + global buffers, and may need to be adjusted by a system administrator. + +3 Lock_space + Lock_space + + Specifies the number of pages allocated to the management of M locks + associated with the database. The size of a page is always 512 bytes. + + The format of the LOCK_SPACE qualifier is: + + -L[OCK]_SPACE=integer + + o The maximum LOCK_SPACE is 65,536 pages. + o The minimum LOCK_SPACE is 10 pages. + o The default LOCK_SPACE is 40 pages. + o A file or region name is required to assign lock space. + o + o This qualifier requires standalone access. + +3 INST_freeze_on_error + INST_freeze_on_error + + Enables or disables custom errors in a region to automatically cause an + Instance Freeze. This flag modifies the "Inst Freeze on Error" file header + flag. + +3 Journal + Journal + + Specifies whether the database allows journaling and, if it does, + characteristics for the journal file. The format of the JOURNAL qualifier + is: + + -[NO]J[OURNAL][=journal-option-list] + + o -NOJOURNAL specifies that the database does not allow journaling. And + also it does not accept an argument assignment. + o -JOURNAL specifies journaling is allowed. It takes one or more + arguments in a journal-option-list. + +3 Qdbrundown + Qdbrundown + + Quickens normal process shutdown where a large number of processes + accessing a database file are required to shutdown almost simultaneously, + for example, in benchmarking scenarios. When a terminating GT.M process + observes that a large number of processes are attached to a database file + and QDBRUNDOWN is enabled, it bypasses checking whether it is the last + process accessing the database. Such a check occurs in a critical section + and bypassing it also bypasses the usual RUNDOWN actions which accelerates + process shutdown removing a possible impediment to process startup. By + default, QDBRUNDOWN is disabled. + + Note that with QDBRUNDOWN there is a possibility of race condition that + might leave the database fileheader and IPC resources in need of cleanup. + Although QDBRUNDOWN minimizes the probability of such a race condition, it + cannot eliminate it. When using QDBRUNDOWN, FIS recommends an explicit + MUPIP RUNDOWN of the database file after the last process exits, to ensure + the cleanup of database fileheader and IPC resources. + +3 REServed_bytes + REServed_bytes + + Specifies the size to be reserved in each database block. RESERVED_BYTES + is generally used to reserve room for compatibility with other + implementations of M or to observe communications protocol restrictions. + The format of the RESERVED_BYTES qualifier is: + + -RES[ERVED_BYTES]=size + + o RESERVED_BYTES may also be used as a user-managed fill factor. + o The minimum RESERVED_BYTES is 0 bytes. The maximum RESERVED_BYTES is + the block size minus the size of the block header which is 7 or 8 + depending on your platform. Realistic determinations of this amount + should leave room for at least one record of maximum size. + +3 Version + Version + + Sets the block format version (Desired DB Format field in the file header) + for all subsequent new blocks. The format of the VERSION qualifier is: + + -V[ERSION]={V4|V6} + + o MUPIP UPGRADE and MUPIP REORG -UPGRADE set the Desired DB Format field + in the database file header to V6 while MUPIP REORG -DOWNGRADE sets it + to V4. + o To set the version to V4, the current transaction number (CTN) of the + database must be within the range of a 32-bit maximum. + o V6 block format is compatible with the V5 block format. The longer key + and longer records (spanning nodes) features of V6 format are + automatically disabled when used with GT.M V5.* versions. + o For more information on the upgrading or downgrading your database, + refer to the release notes document of your current GT.M version. + +3 Examples + Examples + + Example: + + $ mupip set -journal=on,nobefore -region "*" + + This example enables NOBEFORE image journaling and turns on journaling for + all regions. + + $ mupip set -version=V4 -file mumps.dat + + Database file mumps.dat now has d esired DB format V4 + + This example sets the block format to V4 for all subsequent new blocks in + V6 database file mumps.dat. + + 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 + V4 database file mumps.dat. + + Example: + + mupip set -flush_time=01:00:00:00 -region DEFAULT + + This example sets flush time to 1 hour. You can also specify flush time in + any combination of [[[HOURS:]MINUTES:]SECONDS:]CENTISECONDS. MUPIP + interprets -FLUSH_TIME=360000 or -FLUSH_TIME=00:60:00:00 as + -FLUSH_TIME=01:00:00:00. + + Example: + + $ mupip set -region REPTILES -inst_freeze_on_error + + This example enables custom errors in region REPTILES to cause an Instance + Freeze. + +2 SIZE + SIZE + + Estimates and reports the size of global variables using a format that is + similar to the one that appears at the end of the MUPIP INTEG -FULL + report. In comparison with MUPIP INTEG -FAST -FULL, MUPIP SIZE provides + the option of choosing any one of the three estimation techniques to + estimate the size of global variables in a database file. These techniques + vary in measurement speed and estimate accuracy. The format of the MUPIP + SIZE command is: + + MUPIP SI[ZE] [-h[euristic]=estimation_technique] [-s[elect]=global-name-list] [-r[egion]=region-list] + + The optional qualifiers of MUPIP SIZE are: + + -Heuristic=estimation_technique + + Specifies the estimation technique that MUPIP SIZE should use to estimate + the size of global variables. The format of the -HEURISTIC qualifier is: + + -h[euristic]={sc[an][,level=] | a[rsample][,samples=] | i[mpsample][,samples=]} + + o smpls is the number of samples and must be greater than zero (0) + o lvl is a positive or negative tree level designation and -(level of + the root block) <= lvl <= (level of the root block) + + estimation-technique is one of the following: + + o scan,level= + + Traverses the global variable tree and counts the actual number of + records and blocks at levels from the root down to the level specified + by lvl (default is 0, the data blocks). If the given level is + non-negative, it is the lowest block level of the global for which the + count is requested. So, 0 means all blocks, 1 means all index blocks, + 2 means all index blocks of level 2 and above, and so on. SCAN counts + a negative level from the root of the global tree where -1 means + children of the root. + + o arsample,samples= + + Uses acceptance/rejection sampling of random tree traversals to + estimate the number of blocks at each level. It continues until the + specified number of samples (default is 1,000) is accepted. + + o impsample,samples= + + Uses importance sampling of random tree traversals to weight each + sample of the specified number of samples (default is 1,000) in order + to estimate size of the tree at each level. + + o If -HEURISTIC is not specified, MUPIP SIZE uses the + ARSAMPLE,SAMPLE=1000 estimation technique. + + **Important** + + For large databases, MUPIP SIZE is faster than MUPIP INTEG -FAST -FULL. + IMPSAMPLE is expected to be the fastest estimation technique, followed by + ARSAMPLE and then SCAN. + + In terms of accuracy, MUPIP INTEG -FAST -FULL is the most accurate. + + -Select + + Specifies the global variables on which MUPIP SIZE runs. If -SELECT is not + specified, MUPIP SIZE selects all global variables. + + The format of the SELECT qualifier is: + + -s[elect]=global-name-list + + global-name-list can be: + + o A comma separated list of global variables. + o A range of global variables denoted by start:end syntax. For example, + -select="g1:g4". + o A global variable with wildcards, for example, "g*" (the name must be + escaped to avoid shell filename expansion) + o "*" to select all global variables. + + -Region + + Specifies the region on which MUPIP SIZE runs. If REGION is not specified, + MUPIP SIZE selects all regions. The format of the REGION qualifier is: + + -R[EGION]=region-list + + Examples: + + $ mupip size -heuristic="impsample,samples=2000" -select="y*" -region="AREG" + + This example estimates the size of all global variable starting with "y". + It uses importance sampling with 2000 samples on the region AREG. + + $ mupip size -heuristic="scan,level=-1" + + This example counts the number of blocks and records at 1 level below the + root of the database tree. + + $ mupip size -heuristic="arsample" -select="g1:g3" + + This example estimates the size of global variables g1, g2 and g3 using + accept/reject sampling with the default number of samples regardless of + the region in which they reside. + + **Note** + + Apart from randomness caused by sampling heuristics, MUPIP SIZE also has + randomness from concurrent updates because it does not use the snapshot + technique that MUPIP INTEG uses. + +2 STOP + STOP + + Terminates a GT.M image. The image executes an orderly disengagement from + all databases that are currently open by the process, and then exits. A + MUPIP STOP performs a kill -15 and therefore may also be used to stop + non-GT.M images. The format of the STOP command is: - ST[OP] process-id + MUPIP ST[OP] process-id - Use the shell command ps to display a list of active process names and - process identifiers (PIDs). + o Use the shell command ps to display a list of active process names and + process identifiers (PIDs). + o To STOP a process belonging to its own account, a process requires no + privileges. To STOP a process belonging to another account, MUPIP STOP + must execute as root. +2 TRIGGER + TRIGGER + + Examines or loads trigger definitions. The format of the MUPIP TRIGGER + command is: + + TRIGGER {-TRIG[GERFILE]= [-NOPR[OMPT]]| + [-SELE[CT][=name-list|*][]} + + Before you run the MUPIP TRIGGER command: + + 1. Set the value of the environment variable gtmgbldir: to specify the + value of a current global directory. + 2. Ensure that the key size, record size, block size of your database is + sufficient for storing trigger definition. You may have to set the key + and record sizes larger than the database content would otherwise + require. + + The qualifiers of the MUPIP TRIGGER command are as follows: + + TRIGgerfile= + + Loads a trigger definition file to the database. The format of the + TRIGGERFILE qualifier is: + + -TRIG[GERFILE]= [-NOPR[OMPT]] + + o For information on the syntax and usage of a trigger definition file, + refer to GT.M Programmer's Guide. + o 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 + 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 + if the compilation has errors. + o 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 + process from updating different nodes with triggers using a different + character set, however, GT.M prevents a process from updating the same + triggering node with different character sets. Your coding practice, + 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 Incompatible with: -SELECT + + **Note** + + The trigger update summary reports count not only names and option changes + as "modified" but also cases where a -COMMANDS list changed, even though + those are functionally additions or deletions of separate trigger + definitions. + + SELECT=name-list + + Provides a facility to examine the current trigger definition. SELECT + 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[*]|*][ ] + + 1. 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 + extracts a list of all current triggers. + 3. 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. + + **Note** + + The output from the MUPIP TRIGGER -SELECT command may not be identical to + your trigger definition file. This is because GT.M converts some + semantically identical syntax into a single internal representation; while + -SELECT output may not be identical to the -TRIGGERFILE input, it has the + same meaning. Additionally, MUPIP TRIGGER -SELECT displays a field called + "Cycle" as part of a comment. Cycle is the number of trigger definition + updates (addition, modification, or deletion) performed on a global. + +3 Examples + Examples + + This section provides step-by-step instructions for creating, modifying, + and deleting triggers. Triggers affect all processes updating a database + unlike, for example, environment variables such as $gtmroutines which work + on a per process basis. Therefore, FIS recommends that you should always + have carefully planned procedures for changing triggers in your production + environment. + + To create a new trigger for global node ^Acct("ID"): + + 1. Using your editor, create a trigger definition file called + triggers.trg with the following entry: + + +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!""" + + 2. Execute a command like the following: + + $ mupip trigger -triggerfile=triggers.trg + + This command adds a trigger for ^Acct("ID"). On successful trigger + load, this command displays an output like the following: + + File triggers.trg, Line 1: ^Acct trigger added with index 1 + ========================================= + 1 triggers added + 0 triggers deleted + 0 trigger file entries not changed + 0 triggers modified + ========================================= + + Now, every S[et] operation on the global node ^Acct("ID") executes the + trigger. + + 3. Execute a command like the following: + + $ mupip trigger -select="^Acct*" + + This command displays the triggers. A sample output looks like the + following: + + ;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"): + + You cannot directly replace an existing trigger definition with a new one. + With the exception of -NAME and -OPTIONS, to change an existing trigger, + you have to delete the existing trigger definition and then add the + modified trigger definition as a new trigger. Note that GT.M performs two + different trigger comparisons to match trigger definitions depending on + whether or not S[ET] is the trigger invocation command. If there is a + S[ET], then the comparison is based on the global name and subscripts, + PIECES, [Z]DELIM, and XECUTE. If there is no SET, GT.M compares only the + global node with subscripts and the -XECUTE code value. + + 1. Begin by executing the following command: + + $ mupip trigger -select="^Acct*" + Output file: + + 2. Specify trigger_mod.trg as the output file. This file contains entries + like the following: + + ;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 - + (minus) for the trigger definition entry for ValidateAccount and add a + new trigger definition for ^Acct("ID"). To avoid inconsistent + application behavior, it is important to replace an old trigger with a + 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!""" + + 4. Execute a command like the following: + + $ mupip trigger -triggerfile=trigger_mod.trg + + 5. This command displays an output like the following: + + File trigger_mod.trg, Line 1: ^Acct trigger deleted + File trigger_mod.trg, Line 3: ^Acct trigger added with index 1 + ========================================= + 1 triggers added + 1 triggers deleted + 0 trigger file entries not changed + 0 triggers modified + ========================================= + + Congratulations! You have successfully modified the xecute string of + ValidateAccount with the new one. + + To delete an existing trigger for global node ^Acct("ID"): + + 1. Begin by executing the following command: + + $ mupip trigger -select="^Acct*" + Output file: + + 2. Specify trigger_delete.trg as the output file. This file contains + entries like the following: + + ;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 + definition entry for ValidateAccount. Alternatively, you can create a + file with an entry like -ValidateAccount. + 4. Now, execute a command like the following: + + $ mupip trigger -triggerfile=trigger_delete.trg + + This command displays an output like the following: + + File trigger_delete.trg, Line 2: ^Acct trigger deleted + ========================================= + 0 triggers added + 1 triggers deleted + 0 trigger file entries not changed + 0 triggers modified + ========================================= + + You have successfully deleted trigger "ValidateAccount". + + To change a trigger name for global node ^Acct("ID"): + + 1. Using your editor, create a new file called trigger_rename.trg and add + a trigger definition entry for ValidateAcct with the same trigger + signature as ValidateAccount. Your trigger definition would look + something like: + + +^Acct("ID") -name=ValidateAcct -commands=S -xecute="Write ""Hello Mars!""" + + 2. Verify that the ValidateAccount trigger exists by executing the + following command: + + $ mupip trigger -select="^Acct*" + Output file: + + 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 + +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!""" + + 4. Now, execute a command like the following: + + $ mupip trigger -triggerfile=trigger_rename.trg + + This command displays an output like the following: + + ========================================= + 0 triggers added + 0 triggers deleted + 0 trigger file entries not changed + 1 triggers modified + ========================================= + + You have successfully changed the trigger name ValidateAccount to + ValidateAcct. + +2 UPGRADE + UPGRADE + + Upgrades the file-header of a database. The format of the MUPIP UPGRADE + command is: + + UP[GRADE] + + o It increases the size from 4 bytes to 8 bytes of file-header fields + such as current transaction number (CTN), maximum TN and others that + contain transaction numbers. + o It resets the various trace counters and changes the database format + to V5. This change does not upgrade the individual database blocks but + sets the database format flag to V5. + o It also initializes a counter of the current blocks that are still in + V4 format. It decrements this counter each time an existing V4 format + block is converted to V5 format. When the counter is 0, the entire + database gets converted. + +3 Example + Example + + Example: + + $ mupip upgrade mumps.dat + + This example upgrades the file-header of mumps.dat to V5 format. + +1 Journaling + Journaling + +2 SET + SET + + MUPIP SET is the primary utility used to establish and activate journaling + (using the -JOURNAL) and replication (using the -REPLICATION). + + When GDE creates a Global Directory, it stores either the explicitly + specified journaling information, or the GDE default value for any + unspecified characteristics. + + MUPIP CREATE copies existing journaling information from the Global + Directory to the database file, establishing journaling characteristics + for all GDE supported journal-options. + + **Important** + + GT.M applies journaling information in the Global Directory to a database + file only when it is created. Thereafter use MUPIP, or possibly DSE, to + change journaling characteristics in database files. Be sure to use GDE to + reflect current journaling needs so that the next time you use MUPIP + CREATE you get the desired journaling characteristics. + + DSE DUMP -FILEHEADER displays the current values for all established + journaling characteristics. + + This section provides a description of the MUPIP SET command with specific + reference to the journaling related qualifiers. + + MUPIP SET -JOURNAL can change some database characteristics when + journaling is active for a specific file or region(s). The first run of + MUPIP SET -JOURNAL on an older database automatically changes the + maximum/minimum journal settings to match those required by the current + GT.M version. MUPIP SET operates on either regions or files. + + The format for the MUPIP SET command is: + + MUPIP SE[T] -qualifier... {-F[ILE] file-name|-REG[ION] region-list} + + The file-specification or region-list identifies the target of the SET. + Region-names separated by commas (,) make up a region-list. + + To establish journaling characteristics, use the MUPIP SET command with + the -[NO]JOURNAL[=journal-option-list] qualifier and one of the following + SET object identifying qualifiers: + + -F[ILE] + -R[EGION] + + Together with one or more of the SET action qualifiers: + + -[NO]JOURNAL[=journal-option-list] -REPLICATION=' + +3 Object_Identifying_Qualifiers + Object Identifying Qualifiers + + The following qualifiers identify the journaling targets: + + -F[ILE] + + Specify that the argument to the SET is a file-specification for a single + database file. A Journal file's name can now include characters in + Unicode. + + Old journal files stay open for about 10 seconds after a switch to a new + journal file. + + -R[EGION] + + Specify that the argument to the SET is a list of one or more + region-names, possibly including wildcards, which, through the mapping of + the current Global Directory, identifies a set of database files. SET + -REGION modifies multiple files when the parameter contains more than one + name. + + The -REGION qualifier is incompatible with the -FILE qualifier. + + -J[NLFILE] + + Specifies that the target for SET is a journal file. The format of the + JNLFILE qualifier is: + + -jnlfile jnl_file [-[no]prevjnlfile=jnlfilename] [-bypass] + [-repl_state={on|off}] [-dbfilename=file_name] + + jnl_file specifies the name of the target journal file. + + -prevjnlfile=jnlfilename + + Changes the name of the previous generation of the journal file in the + header of jnl_file to jnlfilename (for example, when moving the previous + generation journal file to a different location). The file name can be a + full path-name or a relative path name; however, before the file-name is + stored in the header, it is expanded to its full path-name. + + -noprevjnlfile + + Cuts the generation link of the journal file jnl_file.The name of the + previous generation journal file is nullified in the header of jnl_file. + Such an operation is appropriate when it is assured that there will never + be a reason for a rollback to the previous generation journal file. + + -bypass + + Override the requirement that database files (or their corresponding + journal files) affected by the set command be available standalone. + + **Caution** + + Changing the previous generation file link when a rollback operation is in + progress or when the Source Server is actively replicating, can damage the + journal file and hamper recoverability. + + -repl_state={on|off} + + Change the replication state of a journal file; this command is intended + for use only under instructions from your GT.M support provider. + + -dbfilename=file_name + + Associates a journal file with a different database file; this command may + be useful in arranging unusual RECOVER or ROLLBACK scenarios. + +3 Action_Qualifiers + Action Qualifiers + + The -JOURNAL and -REPLICATION qualifiers are the only SET qualifiers + relevant for journaling. + + -[NO]J[OURNAL][=journal-option-list] + + Enables or disables journaling for the specified database file or + region(s). MUPIP SET commands with this qualifier also establish the + characteristics for journal files. FIS believes the defaults and minimum + for journal file characteristics are in line with current hardware + capabilities and suitable for a production environment. + + The journal-option-list contains keywords separated with commas (,) + enclosed in double quotes "". These double quotes are optional when the + list contains only one keyword. This option list is a super set of the + journal-option-list available through GDE. + + o -NOJOURNAL specifies that the database does not allow journaling, or + disables journaling for a database that currently has it enabled. It + is equivalent to -JOURNAL=DISABLE. + o -NOJOURNAL does not accept an argument assignment. It does not create + new journal files. When a database has been SET -NOJOURNAL, it appears + to have no journaling file name or other characteristics. + o -JOURNAL= enables journaling for a database file. -JOURNAL= takes one + or more arguments in a journal-option-list. As long as journaling is + ENABLED and turned ON at the end of the command, SET -JOURNAL= always + creates a new version of the specified journal file(s). + o -NOJOURNAL specifies that the database does not allow journaling, or + disable journaling for a database where journaling is active. + o Enable BEFORE_IMAGE or NOBEFORE_IMAGE journaling for a database file. + o As long as journaling is ENABLED and turned ON at the end of the + command, SET -JOURNAL= always creates a new version of the specified + journal file(s). + o Every MUPIP SET -JOURNAL command on a database file that specifies an + ON or OFF journal-activation option causes the values of all + explicitly specified journal-file-options to be stored in the database + overriding any previously established characteristics for those + options. + o If you specify both -JOURNAL and -NOJOURNAL in the same command line, + the latter takes effect. + o Whenever MUPIP SET creates a new journal file, it uses all values for + journal-file-options that the user explicitly specifies in the command + line for the new journal file. If you do not specify a + journal-file-option, MUPIP SET takes the char acteristics of the + existing journal file. + o MUPIP SET supports qualifiers (like -ACCESS_METHOD, and so on) to + change non-journaling characteristics of database file(s). If you + specify these qualifiers -JOURNAL , MUPIP SET modifies the + non-journaling characteristics first and then moves on to modify the + journaling characteristics. Command execution stops when it encounters + an error. If MUPIP SET encounters an error in processing the command + line or the non-journaling characteristics, it makes no changes to any + characteristics. However, if MUPIP SET encounters an error in + processing the journaling characteristics, the non-journaling + characteristics have already been successfully changed. + o -NOJOURNAL is equivalent to -JOURNAL=DISABLE. + o -NOJOURNAL does not accept an argument assignment. It does not create + new journal files. When a database has been SET -NOJOURNAL, it appears + to have no journaling file name or other characteristics. + + -REPLI[CATION]=replication-option + + -REPLICATION sets journal characteristics and changes the replication + state simultaneously. It can also be used with the -JOURNAL qualifier. If + journaling is ENABLED and turned ON, SET -REPLICATION=ON creates new set + of journal files, cuts the back-link to the prior generation journal + files, and turns replication ON. + +4 JOURNAL_Options + JOURNAL Options + + ALI[GNSIZE]=blocks + + o Specifies the number of 512-byte-blocks in the ALIGNSIZE of the + journal file. + o If the ALIGNSIZE is not a perfect power of 2, GT.M rounds it up to the + nearest power of 2. + o The default and minimum ALIGNSIZE value is 4096 blocks. The maximum + value is 4194304 (=2 GigaBytes). + o A journal file consists of a sequential stream of journal records each + of varying size. It is typically not easy to detect the beginning of + the last valid journal record in an abnormally terminated journal file + (for example, system crash). To facilitate journal recovery in the + event of a system crash, the GT.M run-time system ensures that offsets + in the journal file which are multiple of ALIGNSIZE (excepting offset + 0 which houses the journal file header) is always the beginning of a + valid journal record. In order to ensure this, GT.M run-time system + writes padding data (if necessary) in the form of ALIGN journal + records just before the ALIGNSIZE boundary. These ALIGN records also + help in skipping past invalid records in the middle of a journal file + allowing MUPIP JOURNAL -EXTRACT -FORWARD -FULL to extract as much data + of a corrupt journal file as possible. + o While a larger align size trade off crash recovery time in favor of + increased journaling throughput, especially when before image + journaling is in use, there is marginal value in using an align size + larger than a few MB. + o The minimum ALIGNSIZE supported is always be greater than or equal to + the maximum journal record size, which in turn depends on the maximum + database block size. + o Note that a large value of ALIGNSIZE implies less aligned boundaries + for recovery to use and hence slows backward recovery down so + drastically that, for example, the maximum value of 4194304 causes + backward recovery (in case of a crash) to take as much time as forward + recovery on that journal file. + + ALL[OCATION]=blocks + + Sets the allocation size of the journal file. GT.M uses this information + to determine when it should first review the disk space available for the + journal file. The size of the journal file at creation time is a constant + (depending on the GT.M version) but once the journal file reaches the size + specified by ALLOCATION, every extension produces a check of free space + available on the device used for the journal file. + + GT.M issues informational messages to the system log whenever the free + space available is not much more than the extension size. GT.M provides + these extension checks as an operational aid for identifying, before space + runs out, that a file system holding the journal file is low on space. + When there is no more free space available on the file system holding a + journal file, GT.M shuts off journaling for the corresponding database + file. + + The default ALLOCATION value is 2048 blocks. The minimum value allowed is + 2048. The maximum value is 8,388,607 (4GB-512 bytes, the maximum journal + file size). + + AU[TOSWITCHLIMIT]=blocks + + Specifies the limit on the size of a journal file. When the journal file + size reaches the limit, GT.M automatically performs an implicit online + switch to a new journal file. + + **Note** + + It is possible to set the AUTOSWITCHLIMIT to a value higher than the + maximum file size (in blocks) for the file system. Currently GT.M does not + attempt to check for this condition at specification time. GT.M produces a + run-time error when a journal file reaches the maximum size for the file + system. Therefore, ensure that the AUTOSWITCHLIMIT never exceeds the + file-system limit. + + The default value for AUTOSWITCHLIMIT is 8388600 & the maximum value is + 8388607 blocks (4GB-512 bytes). The minimum value for AUTOSWITCHLIMIT is + 16384. GT.M produces an error if the AUTOSWITCHLIMIT value is less than + the sum of allocation and extension values. If the difference between the + AUTOSWITCHLIMIT and the allocation value is not a multiple of the + extension value, GT.M rounds-down the value to make it a multiple of the + extension value and displays an informational message. GT.M produces an + error when the rounded value of AUTOSWITCHLIMIT is less that the minimum + value. + + If you specify values for ALLOCATION, EXTENSION, and AUTOSWITCHLIMIT for a + region such that (ALLOCATION+EXTENSION>AUTOSWITCHLIMIT), either using GDE + or MUPIP SET -JOURNAL, GT.M sets ALLOCATION to match the AUTOSWITCHLIMIT, + and produces a JNLALLOCGROW message. + + At journal extension time, including journal autoswitch time, if + (ALLOCATION+EXTENSION>AUTOSWITCHLIMIT) for a region, GT.M uses the larger + of EXTENSION and AUTOSWITCHLIMIT as the increment to warn of low available + journal disk space. Otherwise, it uses EXTENSION. + + [NO]BEFORE_IMAGES + + Controls whether the journal should capture BEFORE_IMAGES of GDS blocks + that an update is about to modify. A SET -JOURNAL=ON must include either + BEFORE_IMAGES or NOBEFORE_IMAGES in the accompanying journal-option-list. + + If you specify both NOBEFORE_IMAGES and BEFORE_IMAGES in the same + journal-option-list, the last specification overrides any previous one(s). + + As GT.M creates new journal files only with the ON option and every ON + specification must include either BEFORE_IMAGES or NOBEFORE_IMAGES. If the + user specifies [NO]BEFORE_IMAGES along with the OFF option serve no + purpose. + + Although it is possible to perform an online switch of a database from (or + to) NOBEFORE-IMAGE journaling to (or from) BEFORE-IMAGE journaling, it is + important to understand that backward recovery can never succeed if it + encounters even one in a set of journal files for a database without + BEFORE-IMAGES. + + BU[FFER_SIZE]=blocks + + Specifies the amount of memory used to buffer journal file output. + + MUPIP requires standalone access to the database to modify BUFFER_SIZE. + Therefore, GT.M restricts the use of the BUFFER_SIZE option to change the + current journal-buffer-size as part of an online switch of the journal + files. + + The default value is 2308 blocks. The minimum BUFFER_SIZE is 2307 blocks. + The maximum BUFFER_SIZE is 32K blocks which means that the maximum buffer + you can set for your journal file output is 16MB. + + DISABLE + + Equivalent to the -NOJOURNAL qualifier of MUPIP SET. It specifies that + journaling is not an option for the region or file named. If the user + specifies DISABLE, then MUPIP SET ignores all other options in the + journal-option-list. + + ENABLE + + Makes the database file or region available for journaling. By default, + ENABLE turns journaling ON unless OFF is specified in the same option + list. A command that includes ENABLE must also specify BEFORE_IMAGES or + NOBEFORE_IMAGES. + + EP[OCH_INTERVAL]=seconds + + seconds specifies the elapsed time interval between two successive EPOCHs. + An EPOCH is a checkpoint, at which all updates to a database file are + committed to disk. All journal files contain epoch records. + + A smaller EPOCH_INTERVAL reduces the time to recover after a crash at the + cost of increased I/O load on the run-time system (due to more frequent + checkpoints). A larger EPOCH_INTERVAL has the opposite effect. Therefore, + set EPOCH=interval for a more efficient run-time with larger values of + interval and more efficient ROLLBACK processing with smaller values of + interval. + + The default EPOCH_INTERVAL value is 300 seconds (5 minutes). The minimum + value is 1 second. The maximum value is 32,767 (one less than 32K) + seconds, or approximately 9.1 hours. If you enable journaling and do not + specify a value for EPOCH_INTERVAL, GT.M inherits the value of + EPOCH_INTERVAL of the last journal file in that region. EPOCH_INTERVAL + only makes takes effect when the user turns journaling ON and there is no + earlier journal file. + + EX[TENSION]=blocks + + blocks specifies the size of the journal file extension by which file + expands and becomes full. + + EXTENSION=blocks specifies when GT.M should review disk space available + for the journal file after the ALLOCATION has been used up. It also + specifies how much space should be available at each review. + + As UNIX file systems use lazy allocation schemes, allocation and extension + values do not result in physical disk block allocation for the journal + file. + + The values determine when GT.M checks the file systems to see if it has + enough space to hold an extension worth of journal data. When a journal + file reaches the size of ALLOCATION and any multiple of EXTENSION, GT.M + checks the file system for room, and if the available space is less than + three times the EXTENSION, it writes warnings to the operator log. GT.M + provides these extension checks as an operational aid for identifying, + before space runs out, that a file system holding the journal file is low + on space. When there is no more free space available ) on the file system + holding a journal file or there is no authorization of a process + attempting to autoswitch a journal file, GT.M shuts off journaling for the + corresponding database file. + + The default EXTENSION value is 2048 blocks. The minimum EXTENSION is zero + (0) blocks and the maximum is 1073741823 (one less than 1 giga) blocks. + + F[ILENAME]=journal_filename + + journal_filename specifies the name of the journal file. FILENAME is + incompatible with SET -REGION, if you specify more than one region. + + GT.M treats the filename as having two components - basename and + extension. The format of the journal filename is basename.extension, where + extension does not contain any periods (.), but if the filename contains + more than one period (.), basename contains all but the last period (.). + Also note that "extension" is the empty string ("") if the filename does + not contain any periods (.). + + The convention of the default value for the FILENAME is as follows: + + o GT.M takes the basename of the database filename as the basename for + the journal file with an extension of mjl if the database has a dat + extension. For example, database name mumps.dat results in a default + name mumps.mjl. If the database filename does not have a dat + extension, GT.M replaces all occurrences of periods (.) with + underscores (_) with an extension of mjl and takes the full database + filename. For example, database name mumps.acn results in a default + name mumps_acn.mjl. Therefore, by default, a journal file has an + extension of mjl unless you explicitly specify a different extension + with the FILENAME journal option. If the new journal filename (the one + specified in the FILENAME option or the default) already exists, GT.M + renames the existing file with the string "_YYYYJJJHHMMSS" appended to + the existing file extension where the string denotes the time of + creation of the existing journal file in the following format: + + YYYY 4-digit-year such as 2011 + JJ 3-digit-Julian-day (between 1 and 366) such as 199 + HH 2-digit-hour in 24 hr format such as 14 + MM 2-digit minute such as 40 + SS 2-digit seconds such as 30 + + Assuming the above example for the string value, GT.M renames a + journal file mumps.mjl to mumps.mjl_2010199144030 when it switches to + a new journal file. + + o If GT.M detects that the rename-logic yields a filename that already + exists, the string "_N[N[N[N...]]]" is appended to the renamed + filename where "N[N[N...]]" denotes the sequence of numbers + 0,1,2,3,4,5,6,7,8,9,90,91,92,93,94,95,96,97,98,99,990,991,... + + GT.M tries all numbers from the order in the above sequence until it + finds a non-existing rename-filename. + + Taking the same example as above, in case mumps.mjl_2010199144030 and + mumps.mjl_2010119144030_0 already exists, the rename string would be + mumps.mjl_2010199144030_1. + + o If the existing file renaming scheme or the default journal file + naming scheme discussed above results in a filename longer than 255 + characters (due to the suffix creation rules), GT.M produces an error + and turns off journaling. + + A journal file name can include characters in Unicode. + + **Note** + + Whenever GT.M implicitly turns off journaling due to run-time conditions + such as no available disk space or no authorization for a process + attempting to auto-switch a journal file (and so on) , it produces an + error and accompanying messages identify the reason for that condition. + + For journal recovery, GT.M maintains a field in every journal file's + header that stores the name of the previous generation journal file for + the same database file. When a MUPIP SET changes the journal state from + DISABLED or OFF to ON, GT.M creates new journal files with no previous + generation journal file name. This indicates that this is a fresh start of + journaling for the particular database. When journaling is already ON, and + GT.M is implicitly (due to AUTOSWITCHLIMIT being reached) or explicitly + (due to MUPIP SET JOURNAL) required to create new journal files, GT.M + maintains the previous generation journal filename (after any appropriate + rename), in the new journal file's header. + + In all cases where journaling is ON both before and after a journal file + switch, GT.M maintains the previous generation journal file name in the + new journal file's header except when GT.M creates a new journal file due + to an implicit switch because it detects an abnormal termination of the + current journal file or if the current journal file was not properly + closed due to a system crash and the database was the subject of a MUPIP + RUNDOWN afterwards. + + **Note** + + In the event of a crash, FIS strongly recommends performing a MUPIP + JOURNAL ROLLBACK on a database with replication, MUPIP JOURNAL RECOVER on + a journaled database, and MUPIP RUNDOWN only if using neither journaling + nor replication. GT.M error messages provide context-specific instructions + to promote this decision-making model which helps protect and recover data + after a crash. + + The previous generation journal filename is a back link from the current + generation journal. + + GT.M produces an error and makes no change to the journaling state of the + database when the FILENAME is an existing file and is not the active + journal file for that database. In this way, GT.M prevents possible cycles + in the back-links (such as, a3.mjl has a back-link to a2.mjl which in turn + has a back-link to a1.mjl which in turn has a back-link to a3.mjl thereby + creating a cycle). Cycles could prevent journal recovery. Also, note that + cycles in back-links are possible only due to explicit FILENAME + specifications and never due to an existing FILENAME characteristics from + the database or by using the default FILENAME. + + NOPREVJNLFILE + + Eliminates the back link of a journal file. + + [NO]S[YNC_IO] + + Directs GT.M to open the journal file with certain additional IO flags + (the exact set of flags varies by the platform where SYNC_IO is supported, + for example on Linux you might utilize the O_DIRECT flag). Under normal + operation, data is written to but not read from the journal files. + Therefore, depending on your actual workload and your computer system, you + may see better throughput by using the SYNC_IO journal option. + + You should empirically determine the effect of this option, because there + is no way to predict the performance gain or impact in advance. There is + no functional difference in GT.M behavior with the use of SYNC_IO. If you + determine that different workloads perform best with a different setting + of SYNC_IO, you can change it with MUPIP SET at any time. + + The default is NOSYNC_IO. If you specify both NOSYNC_IO and SYNC_IO in the + same journal-option-list, GT.M uses the last occurrence. + + OFF + + Stops recording subsequent database updates in the journal file. Specify + OFF to establish journaling characteristics without creating a journal + file or starting journaling. + + The default for SET -JOURNAL= is ON. + + ON + + Records subsequent database updates in that journal file. MUPIP SET + -JOURNAL=ON must include either BEFORE_IMAGES or NOBEFORE_IMAGES in the + accompanying journal-option-list. By default GT.M sets journal operation + to BEFORE_IMAGE if this command changes the database replication state + from OFF to ON and JOURNAL=NOBEFORE_IMAGE is not specified. + + **Important** + + ON keyword works only on previously ENABLEd regions. GT.M ignores ON if + Journaling is DISABLEd. In other words, an ENable / DISable is like the + power switch on the back of many television sets and ON/OFF is like the + ON/OFF on the remote control. The ON/OFF on the remote control works only + when the power switch on the back of the television set is enabled. + + If the current generation journal file is damaged/missing, MUPIP SET + -JOURNAL=ON implicitly turns off journaling for the specified region, + creates a new journal file with no back pointers to the prior generation + journal file, and turns journaling back on. Further, if replication is + enabled, MUPIP SET -JOURNAL=ON temporarily switches the replication WAS_ON + state in the time window when MUPIP SET command turns off journaling and + returns normal as long as it operates out of the journal pool buffer and + doesn't need to reference the damaged journal file(s). During this + operation, MUPIP SET -JOURNAL=ON also sends the PREJNLLINKCUT message for + the region to the application and the operator log. While this operation + ensures that journaling continues even if the current generation journal + file is damaged/missing, creating a new journal file with no back pointers + creates a discontinuity with the previous journal files. Therefore, FIS + recommends taking a database backup at the earliest convenience because a + MUPIP RECOVER/ROLLBACK will not be able to go back past this + discontinuity. Also, consider switching the journal files on all regions + in the instance (with REGION "*") to ensure the RECOVER/ROLLBACK for other + regions remains unaffected. + + The default for SET -JOURNAL= is ON. + + Y[IELD_LIMIT]=yieldcount + + yieldcount specifies the number of times a process that tries to flush + journal buffer contents to disk yields its timeslice and waits for + additional journal buffer content to be filled-in by concurrently active + processes, before initiating a less than optimal I/O operation. + + A smaller YIELD_LIMIT is appropriate for light load conditions while + larger values are appropriate as the load increases. + + **Note** + + A small YIELD_LIMIT may cause performance loss due to partial page writes + while a large YIELD_LIMIT may cause performance loss due to significant + idle times (due to a lot of yields). + + The minimum YIELD_LIMIT is zero (0), the maximum YIELD_LIMIT is 2048 and + the default YIELD_LIMIT is 8. + + As the disk can only write entire blocks of data, many I/O subsystems + perform a READ-MODIFY-WRITE operation when data to be written is a partial + block as opposed to simple writes for an entire block. The YIELD_LIMIT + qualifier tries to reduce the frequency of sub-optimal partial block + writes by deferring such writes as much as possible in the hope that in + the meantime the journal buffer accumulates more content and qualifies for + an optimal entire block write. + +3 Examples + Examples + + $ mupip set -journal="enable,nobefore" -file mumps.dat + + This example enables NOBEFORE_IMAGE journaling on mumps.dat. If journaling + is already enabled, this command switches the current journal file. + + Example: + + $ mupip set -journal=on,enable,before -region "*" + + This example turn on journaling with BEFORE_IMAGE journaling. If + journaling is already enabled, this command switches the current journal + file for all regions. + + $ mupip set -file -journal="nobefore,buff=2307" gtm.dat + + This example initiates NOBEFORE_IMAGE journaling for the database file + gtm.dat with a journal buffer size of 2307 blocks. It also switches to new + journal file. This command assumes that some prior MUPIP SET -JOURNAL + specified ENABLE for gtm.dat. + + Example: + + $ mupip set -region -journal=enable,before_images,allocation=50000,ext=5000 "*" + + This example enables journaling with BEFORE_IMAGES on all regions of the + current Global Directory and gives each journal file an ALLOCATION of + 50000 blocks and an EXTENSION of 5000 blocks. If the regions have + significantly different levels of update, use several MUPIP SET -FILE or + -REGION commands. + + Example: + + $ mupip set -region -journal="enable,before" areg,breg + + This example declares journaling active with BEFORE_IMAGES for the regions + areg and breg of the current Global Directory. + + Example: + + $ mupip set -file -nojournal mumps.dat + + This example disables journaling on the database file mumps.dat. + + Example: + + $ mupip set -journal="ENABLE,BEFORE_IMAGES" -region "AREG" + $ mupip set -journal="ON,BEFORE_IMAGES" -region "*" + + This example turns on journaling only for the region AREG. Note that AGREG + is the only region that is "available" for journaling. + + Example: + + $ mupip set -access_method=MM -file gtm.dat + + This example sets MM (Memory Mapped) as the access method or GT.M + buffering strategy for storing and retrieving data from the database file + gtm.dat. Since MM is not supported with BEFORE_IMAGE journaling, this + example produces an error on a database with BEFORE_IMAGE journaling + enabled. You can also use -access_method=BG to set BG (Buffered Global) as + your buffering strategy. + + Example: + + $ mupip set -journal=before,noprevjnlfile,file=newmumps.mjl -file mumps.dat + + The above command cuts the back link of the newly created journal file + newmumps.mjl. + +2 JOURNAL + JOURNAL + + MUPIP JOURNAL command analyzes, extracts from, reports on, and recovers + journal files. The format for the MUPIP JOURNAL command is: + + MUPIP J[OURNAL] -qualifier[...] file-selection-argument + + file-selection-argument is a comma-separated list of journal files. + + -qualifier [...] is a combination of Action, Direction, Time, Sequence + Number, Control, and Selection qualifiers that perform various MUPIP + JOURNAL operations. To create any MUPIP JOURNAL command, select an + appropriate combination of qualifiers by moving horizontally from the + Action column extending to the Selection column: + + +---------------------------------------------------------------------------------------+ + | | | | Sequence | Control | Selection | + | Action |Direction| Time (optional) | Number | (optional) | (optional) | + | | | |(optional)| | | + |---------------+---------+--------------------+----------+--------------+--------------| + |One or more |Only one |One or more |Only one |One or more |One or more | + |---------------+---------+--------------------+----------+--------------+--------------| + | | | | |-[NO]AP | | + | | | | | | | + | | | | |-BR=extract | | + | | | | |file name | | + | | | | | | | + | | | | |-[NO]CHA | | + | | | | | | | + | | | | |-[NO]CHE | | + |-EX[=file | | | | | | + |specification] | | | |-[NO]ER[= | | + | | |-A=time | |integer] |-G=global list| + |-REC | | |-FET=port | | | + | | |-BE=time |number |-FE=fence |-ID=pid list | + |-RO |-BA -FO | | |option | | + | | |-[NO]LOO= lookback |-RES=jnl | |-T=transaction| + |-SH=show option| |option list] |sequence |-FU |type | + |list] | | |number | | | + | | |-SI=time | |-[NO]IN |-U=user list | + |-[NO]V | | | | | | + | | | | |-LOST=extract | | + | | | | |file name | | + | | | | | | | + | | | | |-RED=file pair| | + | | | | |list | | + | | | | | | | + | | | | |-VERB | | + | | | | | | | + | | | | |-DE | | + +---------------------------------------------------------------------------------------+ + + Also ensure that you adhere to the following rules: + + 1. -BEFORE is compatible with all other JOURNAL qualifiers except + -ROLLBACK. + 2. -AFTER is incompatible with -BACKWARD and all action qualifiers, + except -EXTRACT, -SHOW, and -VERIFY. + 3. -APPLY_AFTER_IMAGE is compatible only with -RECOVER, or -ROLLBACK. + 4. -BACKWARD is incompatible with -FORWARD, -AFTER, -CHECKTN, -NOCHAIN, + and -REDIRECT. + 5. -BROKENTRANS is compatible only with -RECOVER, -ROLLBACK, or -EXTRACT. + 6. -CHAIN is only compatible with -FORWARD. + 7. -DETAIL is compatible only with -EXTRACT. + 8. -FETCHRESYNC or -RESYNC are compatible only with -ROLLBACK. + 9. -FORWARD is incompatible with -BACKWARD, -ROLLBACK, -SINCE, and + -LOOKBACK_LIMIT. + 10. -FULL is compatible only with -EXTRACT, -SHOW, or -VERIFY. + 11. -LOSTTRANS is compatible only with -RECOVER, -ROLLBACK, or -EXTRACT. + 12. -REDIRECT is compatible only with -RECOVER. + 13. -ROLLBACK is incompatible with -RECOVER, FORWARD, -CHAIN, -CHECKTN, + -REDIRECT, time qualifiers of -SHOW. + 14. -SINCE is incompatible with -FORWARD. + 15. -TRANSACTION is compatible only with -EXTRACT and -SHOW. + 16. -USER is compatible only with -EXTRACT and -SHOW. + 17. file list must not be asterisk (*) for -REDIRECT. + 18. file list must be asterisk (*) for -ROLLBACK. + 19. Journal selection qualifiers are incompatib le with -RECOVER, + -ROLLBACK, and -VERIFY. + 20. Journal time qualifiers are incompatible with -ROLLBACK. + + For example, MUPIP JOURNAL -EXTRACT=gtm.mjf -FORWARD -DETAIL is a valid + command which performs forward processing to extract detailed the journal + records to gtm.mjf. However, MUPIP JOURNAL -EXTRACT + -REDIRECT=gtm.dat=test/gtm.dat -FORWARD is an invalid command because + -REDIRECT is not compatible with -EXTRACT. + + MUPIP JOURNAL manipulates an inactive journal file that is available for + exclusive (standalone) use. You can transcribe Journal files to tape. + However, you must always restore them to disk for processing by MUPIP + JOURNAL. + + Press CTRL+C to stop JOURNAL processing. A JOURNAL command that terminates + abnormally by operator action or error produces an incomplete result. In + this case, the resulting database may be corrupt. If you stop a JOURNAL + operation by mistake, reissue the command to produce the proper result for + -RECOVER (or -ROLLBACK) -BACKWARD. For -RECOVER -FORWARD, restore the + database from backup and reissue the command. + +3 Action_Qualifiers + Action Qualifiers + + This section describes the journaling action qualifiers. + +4 EXtract + EXtract + + Transfers information from journal files into files formatted for + processing by M routines. It reports the journal time stamps using the $H + format, as controlled by the time zone setting from the OS and the process + environment for the process running the EXTRACT. + + -EXTRACT takes or -stdout as an optional argument. + + specifies the name of the output file. -stdout specifies that + -EXTRACT write to standard output (stdout) instead of writing to a file. + + With no arguments, MUPIP JOURNAL derives the output file specification of + the extract file using the name of the first journal file that is + processed in the forward processing phase and a file type of .mjf. Note + that, if multiple journal names are specified in the command line the + first journal specified might be different from the first journal + processed in the forward phase. When -EXTRACT is specified with -RECOVER + (or -ROLLBACK), the -JOURNAL command extracts all the journal records + processed during a -RECOVER -FORWARD command or the forward phase of + (-RECOVER or -ROLLBACK) -BACKWARD command. + + -EXTRACT applies to forward processing of the journal file; if the + combined state of the journal file and the Journal Time qualifiers does + not cause forward processing, -EXTRACT does not create an output file. + + When used independent of -RECOVER (or -ROLLBACK), -EXTRACT option can + produce a result even though the database file does not exist, although it + does try to access the database if it is available. + + If a database having custom collation is inaccessible or the replication + instance is frozen with a critical section required for the access held by + another process and the environment variable gtm_extract_nocol is defined + and evaluates to a non-zero integer or any case-independent string or + leading substrings of "TRUE" or "YES", MUPIP JOURNAL -EXTRACT issues the + DBCOLLREQ warning and proceeds with the extract using the default + collation. If gtm_extract_nocol is not set or evaluates to a value other + than a positive integer or any case-independent string or leading + substrings of "FALSE" or "NO", MUPIP JOURNAL -EXTRACT exits with the + SETEXTRENV error if it encounters such a situation. Note that if default + collation is used for a database with custom collation, the subscripts + reported by MUPIP JOURNAL -EXTRACT are those stored in the database, which + may differ from those read and written by application programs. + + Note that, a broken transaction, if found, is extracted to a broken + transaction file for details), and all future complete transactions are + considered as lost transactions, and are extracted to a lost transaction + file for details). + + 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 + -RECOVER/-ROLLBACK is also specified. + +4 RECover + RECover + + Instructs MUPIP JOURNAL to initiate database recovery. -RECOVER initiates + the central JOURNAL operation for non-replicated database. From the list + of JOURNAL action qualifiers, select RECOVER alone or with any other + action qualifiers except -ROLLBACK. + + -RECOVER -FORWARD with time qualifiers initiates forward recovery. Forward + recovery ignores the current journaling state of the target database file. + It disables journaling of the target database file, (if currently ENABLE + and ON), while playing forward the database updates. However, it restores + the journaling state of the database at the end of a successful recovery + (if necessary), except when journaling is ENABLE'd and ON before the + recovery. In the latter case, the journaling state at the end of a + successful recovery, is switched to ENABLE and OFF. No journaling is + performed for the logical updates to the database for JOURNAL -RECOVER + -FORWARD. If the target database's current transaction number is less than + first transaction number to be processed in the specified journal file for + that region, -RECOVER attempts to include previous generation journal + file(s) in its processing, unless the -NOCHAIN qualifier is specified. + Following the successive previous links of journal files -RECOVER tries to + include previous generations of journal files until the transaction number + when the journal file was created is less than, or equal to that of the + target database. -RECOVER issues one or more informational messages when + it includes previous generation journal files. If target database's + current transaction number is not equal to the first transaction number of + the earliest journal file to be processed for a region, -RECOVER exits + with an error. If multiple journal files for a single region are specified + with -RECOVER -FORWARD, it behaves as if -NOCHAIN was specified. If the + journal files are not a complete set (for example mumps1.mjl and + mumps3.mjl were specified, with mumps2.mjl missing from the command line), + MUPIP JOURNAL produces an error because the journal files specified are + discontinuous in terms of database transaction numbers. On the other hand, + specifying just mumps3.mjl automatically includes mumps2.mjl and + mumps1.mjl in the recovery. + + -RECOVER -BACKWARD with time qualifiers initiates backward recovery. For + backward recovery, the target database file should be the same as when + GT.M wrote the last complete transaction to the journal. Because the + database may be in an indeterminate state due to a failure, exact checks + for this match are not possible. If the target database has journaling + DISABLE'd (or ENABLE, OFF), -RECOVER -BACKWARD exits with an error + message. + + If the target database has journaling ENABLE, ON, but the journal file + name in database file header does not match the latest generation journal + file name specified for that region, -RECOVER exits with an error. + + During forward processing phase of JOURNAL -RECOVER -BACKWARD, MUPIP + journals the logical updates to the database. It also creates before + images. It is always required to have journaling ENABLE'd and ON for + -RECOVER -BACKWARD or -ROLLBACK. + + If a transaction is found with incomplete fence, it is considered broken. + During forward phase of recovery, if a complete transaction (fenced or + unfenced) is found after a broken transaction. -RECOVER increments the + error count. If -ERRORLIMIT is reached, the complete transaction goes to + lost transaction file, otherwise, it is applied to the database. + + All broken and lost transactions are made available as the result of the + -RECOVERY. They are written as journal extract format in two different + text files. They are the broken transaction file and the lost transaction + file. + + When performing JOURNAL -RECOVER with fences (FENCES="PROCESS" or + FENCES="ALWAYS"), it is essential for the command to include all the + journal files corresponding to the complete set of database files that + make up the logical database. If the specified set of journals is + incomplete, the recovery reports all transactions that included any + missing region as broken. Typically, this means that the results of the + recovery are unsatisfactory or even unusable. + + MUPIP JOURNAL -RECOVER requires exclusive access to database files before + recovery can occur. It keeps the exclusive access to the database files, + which means that the database files become inaccessible during the time of + recovery. + + If time qualifiers are not specified, -BACKWARD -RECOVER/-ROLLBACK + performs optimal recovery. An optimal recovery checks whether the + datatabase is in a wholesome state and attempts to perform an automatic + recovery if there is a crash. If needed, optimal recovery goes back to + include some previous generation files in order to get a consistent + starting point and then comes forward as far as the available journal + record allow it to while preserving consistent application state. At the + end, the journaling state of the database stays ENABLE, ON. Note that the + gtm script performs an optimal recovery on every run. + + When a database file is rolled back by -RECOVER -BACKWARD, the + corresponding journal file is also rolled back so that the two are + synchronized. -RECOVER -BACKWARD then creates a new journal file. If no + forward play of journal records is neccessary, the newly created journal + file stays empty and the database points to the new journal file. The + values for journal allocation and extension in the new journal file, are + copied over from the database. The autoswitchlimit value in the new + journal file is the maximum of the autoswitchlimit values of all journal + files from the latest generation journal file until the turnaround point + journal file generation (turnaround point is the point in the journal file + where backward processing stops and forward processing begins). The + journal allocation/extension values in the new journal file are picked up + from the earliest generation of the set of those journal files sharing the + maximum autoswitchlimit value. + + GT.M adds a prefix rolled_bak_ to the journal file whose entire contents + are eliminated (rolled back) by -RECOVER -BACKWARD. GT.M does not use + these files after a successful recovery therefore you might want to + consider moving or deleting them. You should never use rolled_bak* files + for any future database recovery. If there is a need to process + rolled_bak* files, you should extract the journal records from + rolled_back* files and process them using a M program. + +4 ROLLBACK + ROLLBACK + + -ROLLBACK initiates the central JOURNAL operation for a replicated + database. MUPIP JOURNAL commands may specify -ROLLBACK with other action + qualifiers but not with -RECOVER. If you do not use -FETCHRESYNC, the + database rolls back to the last consistent state. Only asterisk (*) + qualifier is allowed for the journal file selection, that is, -ROLLBACK + selects journal files by itself. + + -NOO[NLINE] + + Specifies that ROLLBACK requires exclusive access to the database and the + replication instance file. This means that the database and the + replication instance files are inaccessible during a -ROLLBACK -NOONLINE. + + By default, MUPIP JOURNAL -ROLLBACK is -NOONLINE. + + -ON[LINE] + + Specifies that ROLLBACK should run without requiring exclusive access to + the database and the replication instance file. + + GT.M increments ISV $ZONLNRLBK every time a process detects a concurrent + MUPIP JOURNAL -ONLINE -ROLLBACK. + + If the logical state of the database after the completion of MUPIP JOURNAL + -ONLINE -ROLLBACK matches the logical state of the database at the start + of MUPIP JOURNAL -ONLINE -ROLLBACK, that is, only removes or commits an + uncommitted TP transaction or non-TP mini-transaction, any transaction (TP + or Non-TP) incurs a restart. + + If MUPIP JOURNAL -ONLINE -ROLLBACK changes the logical state of the + database, the behavior is as follows: + + o -ONLINE -ROLLBACK increments ISV $ZONLNRLBK + o In a TP transaction including trigger code within a transaction, + -ONLINE -ROLLBACK restarts the transaction. + o In a non-TP mini-transaction, including within an implicit transaction + caused by a trigger, -ONLINE -ROLLBACK produces a DBROLLEDBACK error, + which, in turn, invokes the error trap if $ETRAP or $ZTRAP are in + effect. + + Any utility/command attempted while MUPIP JOURNAL -ONLINE -ROLLBACK + operates waits for ROLLBACK to complete; the $gtm_db_startup_max_wait + environment variable configures the wait period. + + **Note** + + Because MUPIP ROLLBACK -ONLINE can take a database backwards in state + space, please make sure that you understand what it is that you intend it + to do when you invoke it. FIS developed it as a step towards a much larger + project and anticipates that it will not be broadly useful as is. + + -ROLLBACK -BACKWARD exits with an error message for following conditions: + + 1. Any database region corresponding to a journal file processed has + replication state turned OFF. Note that, a configuration where there + are replicated regions and at least one non-replicated-but-journaled + region is not permitted by the replication source server. The source + server errors out at startup on such a configuration without having + set up the journal pool. Since all GT.M updates to replicated regions + need the source server to have set up a journal pool, no updates are + possible until the configuration is changed to have only replicated + regions or non-replicated-and-non-journaled regions. + 2. Any database region corresponding to a journal file identified by the + command argument has journaling state DISABLE'd or ENABLE'd and OFF. + 3. Any database region corresponding to a journal file has journal state + ENABLE'd and ON, but the journal file name specified in the database + file header is different than one identified by the command argument. + + If a transaction is found with incomplete fence, it is considered broken. + For the duration of the rollback, replication is turned OFF on all regions + and turned back ON at the end of the rollback. + + During the forward phase of rollback, if a complete transaction (fenced or + unfenced) is found after a broken transaction, it is considered as a lost + transaction. During forward phase of rollback, MUPIP journals the logical + updates to the database. All broken and lost transactions are made + available as a result of the rollback. These are written as journal + extract format in two different text files. + + When a database file is rolled back by -ROLLBACK, the corresponding + journal file is also rolled back so that the two are synchronized. + -ROLLBACK then creates a new journal file. If no forward play of journal + records is necessary, the newly created journal file is empty and the + database points to the new journal file. The journal + allocation/extension/autoswitchlimit values in the new journal file is set + in the way as described for -RECOVER -BACKWARD in the previous section + under -RECOVER. + + A prefix rolled_bak_ is added to the journal file, whose entire contents + are eliminated by a -ROLLBACK. These files are not used by GT.M after the + MUPIP JOURNAL -RECOVER, and can be moved/deleted as needed. + + For -ROLLBACK the target database file should be the same as when GT.M + wrote the last complete transaction to the journal. + + If the -FETCHRESYNC or -RESYNC qualifiers are not specified, MUPIP does an + optimal rollback (that is, check whether the database is in a wholesome + state and attempt to automatically recover a database if there is a + crash). + + **Note** + + If ROLLBACK (either -NOONLINE or -ONLINE) terminates abnormally (say + because of a kill -9), it leaves the database in a potentially + inconsistent state indicated by the FILE corrupt field in the database + file header. When a ROLLBACK terminates leaving this field set, all other + processes receive DBFLCORRP errors any time they attempt to interact with + the database. You can clear this condition as following in descending + order of risk: + + o Rerun ROLLBACK to completion + o MUPIP SET -FILE -PARTIAL_RECOV_BYPASS + o DSE CHANGE -FILEHEADER -CORRUPT=FALSE -NOCRIT + + However, the MUPIP and DSE actions do not ensure that the database has + consistent state; check for database integrity with MUPIP INTEG. + +4 SHow + SHow + + Specifies which information for the JOURNAL command to display about a + journal file. + + Use -FORWARD with -SHOW together (but without -RECOVER ) to process the + entire journal file. Specify -SHOW with -RECOVER (or -ROLLBACK) to + consider all the journal files/records processed during a -RECOVER + -FORWARD command or forward phase of a -RECOVER (or -ROLLBACK) -BACKWARD + command. Without -RECOVER (or -ROLLBACK), -SHOW does not require database + access. + + The show-option-list includes (these are not case-sensitive): + + o AL[L] + + Displays all the available type of information about the journal file. + ALL is the default if you omits the show-option-list. + + o AC[TIVE_PROCESSES] + + Displays all processes active at the end of the period specified + implicitly or explicitly by the JOURNAL command time qualifiers. + + o B[ROKEN_TRANSACTIONS] + + Display all processes that had incomplete fenced transactions at the + end of the period covered by the JOURNAL command. + + o H[EADER] + + Displays the journal file header information. If the MUPIP JOURNAL + command includes only the -SHOW=HEADER action qualifier, GT.M + processes only the journal file header (not the contents) even if you + specify -BACKWARD or -FORWARD with it. The size of a journal file + header is 64K. + + HEADER displays almost all the fields in the journal file header. The + NODE field is printed up to a maximum of the first 12 characters. The + following is an example of SHOW=HEADER output: + + ------------------------------------------------------------------------------- + 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 + Journal file checksum seed 2272485152 [0x87735F20] + Crash FALSE + Recover interrupted FALSE + Journal file encrypted FALSE + Journal file hash 00000000000000000000000000000000000 + Blocks to Upgrade Adjustment 0 [0x00000000] + End of Data 65960 [0x000101A8] + Prev Recovery End of Data 0 [0x00000000] + Endian Format LITTLE + Journal Creation Time 2012/11/06 17:30:33 + Time of last update 2012/11/06 17:30:33 + Begin Transaction 1 [0x0000000000000001] + End Transaction 1 [0x0000000000000001] + Align size 2097152 [0x00200000] bytes + Epoch Interval 300 + Replication State CLOSED + Jnlfile SwitchLimit 8386560 [0x007FF800] blocks + Jnlfile Allocation 2048 [0x00000800] blocks + Jnlfile Extension 2048 [0x00000800] blocks + Maximum Journal Record Length 1048672 [0x00100060] + Turn Around Point Offset 0 [0x00000000] + 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 + + o P[ROCESSES] + + Displays all processes active during the period specified implicitly + or explicitly by the JOURNAL command time qualifiers. + + o S[TATISTICS] + + Displays a count of all journal record types processed during the + period specified implicitly or explicitly by the JOURNAL command time + qualifiers.The following is an example of SHOW=STATISTICS output: + + ------------------------------------------------------------------------------- + SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl + ------------------------------------------------------------------------------- + + Record type Count + ---------------------- + *BAD* 0 + PINI 2 + PFIN 2 + ZTCOM 0 + KILL 1333533 + FKILL 0 + GKILL 0 + SET 0 + FSET 0 + GSET 0 + PBLK 4339 + EPOCH 2 + EOF 1 + TKILL 0 + UKILL 0 + TSET 0 + USET 0 + TCOM 0 + ALIGN 49 + NULL 0 + ZKILL 0 + FZKIL 0 + GZKIL 0 + TZKIL 0 + UZKIL 0 + INCTN 4314 + AIMG 0 + TZTWO 0 + UZTWO 0 + 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 + + The following example displays the cryptographic hash of the symmetric key + 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 + 0FDF04C8ECE52A4261975B89A2 + +4 Verify + Verify + + Verifies a journal file for integrity. This qualifier cannot have a value. + -VERIFY scans the files and checks if it is in legal form, if not, it + terminates without affecting the database files. + + -VERIFY when specified along with -FORWARD verifies the entire journal + file For -NOVERIFY -FORWARD, only the tail of a journal file is verified + for cross region integrity. In both cases, if -RECOVER is also specified, + the forward play of journal records is done in a separate pass only after + the verification pass is complete and error-free. + + -VERIFY along with -BACKWARD verifies all journal records from the end of + the journal file till the turn around point. When -VERIFY -BACKWARD is + specified along with -RECOVER or -ROLLBACK, backward processing involves + two passes, the first pass to do the verification until the turn around + point, and the second pass to apply before image (PBLK) records. + + When -NOVERIFY -BACKWARD is specified along with -RECOVER or -ROLLBACK, + PBLKs are applied to the database in the same pass as the verification. + This speeds up processing. But the disadvantage of this approach is that + in the event of verification terminating in the middle of backward + processing, there is no protection of cross-region integrity. FIS + recommends the use of -VERIFY with -RECOVER or -ROLLBACK. + + When used independent of -RECOVER (or -ROLLBACK), -[NO]VERIFY option does + not need database access. The default is -VERIFY. + +3 Direction_Qualifiers + Direction Qualifiers + + The following two qualifiers control the journal processing direction: + + -BACKWARD + + Specifies that MUPIP JOURNAL processing should proceed from the end of the + journal file. If the actions include -RECOVER, JOURNAL -BACKWARD restores + before-images from the end-of the file back to an explicitly or implicitly + specified point (the turn around point), before it reverses and processes + database updates in the forward direction (the forward phase). + + **Note** + + -BACKWARD is incompatible with -FORWARD. + + -FO[RWARD] + + Specifies that MUPIP JOURNAL processing for the specified action qualifier + should proceed from the beginning of the given journal file. When + processing a -RECOVER action qualifier, in certain cases, MUPIP JOURNAL + may need to go before the first record of the specified journal file, that + is, it can start from a previous generation journal file. + + If multiple journal files are specified in the command line, -FORWARD + sorts the journal files within each region based on creation time and + processes them starting from the earliest journal file. Unless the + -NOCHECKTN qualifier is specified, -FORWARD performs checks on journal + files corresponding to each region to ensure they are contiguous, both in + terms of time span, as well as, transaction number span. -FORWARD errors + out if it detects a discontinuity. + + **Note** + + -FORWARD is incompatible with -BACKWARD and -ROLLBACK. + +3 Time_Qualifiers + Time Qualifiers + + Journal qualifiers specifying time accept arguments in absolute or delta + time format. Enclose time arguments in quotation marks (" ") . Include a + back-slash (\) delimiter before both, the beginning and ending quotation + marks to escape it from being processed by the UNIX shell. + + Absolute format is day-mon-yyyy hh:mm:ss , where day denotes the date of + the month, mon indicates the abbreviated 3-letter month name (for example, + Jan, Feb,..) and the year yyyy and hour hh are separated by a space. + Absolute time may indicate today's date with "-- " before the hours. + + Delta format is day hh:mm:ss, indicating the number of days, hours, + minutes, and seconds; where the day and the hours (hh) are separated by a + space. If delta time is less than a day, it must start with zero (0) + followed by a space. + + Delta time is always relative to the maximum time of the last record in + all journal files specified by arguments to the MUPIP JOURNAL command. + + **Note** + + All time qualifiers are incompatible with -ROLLBACK. + + The following section describes the time qualifiers in more detail: + + -A[FTER]=time + + Specifies reference time stamps in the journal and identifies the point + after which JOURNAL starts processing in the journal file(s). This time + qualifier applies to -FORWARD only. + + If -AFTER= provides a time following the last time recorded in the journal + file or following any -BEFORE= time, JOURNAL processing produces no result + and a warning message is displayed. If -AFTER provides a time preceding + the first time recorded in the journal file specified in the command line, + and, previous generation journal file(s) exists for that journal file, + then previous generation journal file(s) are not included for the + processing. You must specify previous generation journal files explicitly + in the command line in order for them to be considered. + + Using -BEFORE with -AFTER restricts processing to a particular period of + time in the journal file. + + -BE[FORE]=time + + Specifies an ending time for any action -FORWARD or -BACKWARD. The time + specified references time stamps in the journal files. If -BEFORE= + specifies a time preceding the first time recorded in the journal file, or + preceding any -AFTER= or -SINCE= time, JOURNAL processing produces no + result, and a warning message is displayed. + + If -BEFORE= time exceeds the last time recorded in journal files, JOURNAL + processing effectively ignores the qualifier and terminates at the end of + the journal file. By default, JOURNAL processing terminates a t the end of + the journal file. + + -[NO]LOO[KBACK_LIMIT][=lookback-option-list] + + Specifies how far JOURNAL -BACKWARD processes past the turnaround point + (the explicit or implicit point in journal file up to which -RECOVER + proceeds backward before it reverses and processes database in forward + direction), while attempting to resolve open transaction fences. This + option is applicable only for transactions fenced with ZTSTART and + ZTCOMMIT. For transaction fenced with TSTART and TCOMMIT, -RECOVER always + resolves open transaction fences. + + -LOOKBACK_LIMIT=options, include time and transaction counts. + -NOLOOKBACK_LIMIT specifies that JOURNAL -BACKWARD can process all the way + to the beginning of the journal file, if necessary, to resolve open + transaction fences. -LOOKBACK_LIMIT= is incompatible with -FORWARD. + + When -FENCES=NONE, JOURNAL processing ignores -LOOKBACK_LIMIT. + + The -LOOKBACK_LIMIT options are: + + o TIME=time + + This limits LOOKBACK by a specified amount of delta or absolute + journal time. + + o OPERATIONS=integer + + This limits LOOKBACK to the specified number of database transactions. + + The TIME LOOKBACK option name and its value must be enclosed in quotes + (""). + + For example: + + -lookback=\"time=0 00:00:30\" + + When -LOOKBACK_LIMIT= specifies both options, they must be separated by a + comma (,), for example: + + -lookback=\"time=0 00:00:30,operations=35\" + + When -LOOKBACK_LIMIT= specifies both options, the first limit reached + terminates the LOOKBACK. + + By default, MUPIP JOURNAL uses -LOOKBACK_LIMIT=\"TIME=0 00:05\" providing + five minutes of journal time prior to -SINCE= to resolve open fences. A + -LOOKBACK_LIMIT that specifies a limit much before the beginning of the + earliest journal file acts as if -NOLOOKBACK_LIMIT was specified. + + -SI[NCE]=time + + Specifies a starting (or checkpoint) time for an action qualifier with + -BACKWARD, that is, -SINCE specifies how far back in time JOURNAL + -BACKWARD should process (from the end of the journal file), before + starting the forward processing. + + The time specified references time stamps in the journal files. If there + are open fenced transactions when JOURNAL -BACKWARD locates the -SINCE= + time, it continues processing backward to resolve them, unless the command + also specifies -FENCES=NONE. If -SINCE= time exceeds the last time + recorded in the journal files or, follows any -BEFORE=time, JOURNAL + processing effectively ignores the qualifier, and displays a warning + message. + + By default, -SINCE= time is 0 00:00:00 which denotes the time at the end + of the journal file (the time when the last journal record was updated). + +3 SEQNO_Qualifiers + SEQNO Qualifiers + + These qualifiers are compatible only with -ROLLBACK. + + -FET[CHRESYNC]= + + In an LMS configuration, rollbacks the replicating instance to a common + synchronization point from which the originating instance can transmit + updates to allow it to catch up. This command rolls back a former + originating instance to the journal sequence number at which the current + originating instance took over. The format of the fetchresync qualifier + is: + + -fetchresync= -losttrans= file-list + + The is the communication port number that the rollback + command uses when fetching the reference point. Always use the same on the originating instance for rollback as the one used by the + Receiver Server. + + **Important** + + FIS recommends you to unconditionally script the mupip journal -rollback + -fetchresync command prior to starting any Source Server on the + replicating instance to avoid a possible out-of-sync situation. + + The reference point sent by the originating instance is the RESYNC_SEQNO + (explained later) that the originating instance once maintained. The + database/journal files are rolled back to the earlier RESYNC_SEQNO (that + is, the one received from originating instance or the one maintained + locally). If you do not use -fetchresync, the database rolls back to the + last consistent replicating instance state. + + The system stores extracted lost transactions in the file + specified by this mandatory qualifier. The starting point for the search + for lost transactions is the JNL_SEQNO obtained from the originating + instance in the -fetchresync operation. If -fetchresync is not specified, + lists the post-consistent-state transactions that were + undone by the rollback procedure to reach a consistent state. + + **Note** + + The extracted lost transactions list may contain broken transactions due + to system failures that occurred during processing. Do not resolve these + transactions --they are not considered to be committed. + + **Caution** + + The database header may get corrupted if you suspend an ongoing ROLLBACK + -FETECHRESYNC operation or if the TCP connection between the two instances + gets broken. The workaround is to restart the ROLLBACK -FETCHRESYNC + operation or wait 60 seconds for the FETCHRESYNC operation to timeout. + + Example: + + $ mupip journal -rollback -fetchresync=2299 -losttrans="glo.lost" -backward + + This command performs a ROLLBACK -FETCHRESYNC operation on a replicating + instance to bring it to a common synchronization point from where the + originating instance can begin to transmit updates to allow it to catch + up. It also generates a lost transaction file glo.lost of all those + transactions that are present on the replicating instance but not on the + originating instance at port 2299. + + -RES[YNC]= + + Specifies the journal sequence number to which GT.M must rollback the the + database/journal files need to be rolled back to a specific point. If you + specify a journal sequence number that is greater than the last consistent + state, GT.M rolls back the database/journal files to the last consistent + state. Under normal operating conditions, this qualifier is not needed. + +3 Control_Qualifiers + Control Qualifiers + + The following qualifiers control journal processing: + + -[NO]AP[PLY_AFTER_IMAGE] + + Specifies that after image records (AIMG) be applied to the database as + part of forward processing of backward recovery or rollback. AIMG are + "snapshots" of the database updates captured by GTM immediately after the + change caused by a DSE update. By default, during forward phase of + backward recovery or rollback, AIMG records are applied to the database. + + By default, -RECOVER -FORWARD does not apply AIMG record into the + database. -APPLY_AFTER_IMAGE is compatible with -RECOVER, or -ROLLBACK + action qualifiers only. + + -BR[OKENTRANS]= + + -BROKENTRANS is an optional qualifier for -ROLLBACK, -RECOVER and + -EXTRACT. If this is not specified and a broken transaction file creation + is necessary, MUPIP JOURNAL creates one using the name of the current + journal file being processed with a .broken extension. + + Note that, if selection qualifiers are specified, the broken transaction + determination (and therefore lost transaction determination as well) is + done based on the journal file that is filtered by the selection + qualifiers. This means that a transaction's journal records may be + considered complete or broken or lost, depending on the nature of the + selection qualifiers. Using -FENCES=NONE along with the selection + qualifiers will result in every journal record to be considered complete + and hence prevent broken or lost transaction processing. + + -[NO]CHA[IN] + + -CHAIN allows JOURNAL processing to include previous generations of + journal files with -FORWARD. If JOURNAL -RECOVER needs to process previous + generation journal file(s) and -NOCHAIN is specified, MUPIP JOURNAL exits + with an error. + + -CHAIN is the default. + + -[NO]CHE[CKTN] + + -CHECKTN specifies that JOURNAL -FORWARD must verify for each region that + the begin transaction number of the earliest journal file to be processed + for that region is same as the current transaction in the database file + and that the end transaction number of every journal file is equal to the + the begin transaction number of the next generation journal file for a + given region. By default, -FORWARD uses -CHECKTN. + + -NOCHECKTN forces forward recovery by overriding inbuilt mechanisms for + checking transaction integrity. Use -NOCHECKTN with caution because it may + lead to integrity issues in the recovered database and journal files. + + -CHECKTN is incompatible with -BACKWARD and -ROLLBACK. + + -[NO]ER[ROR_LIMIT][=integer] + + Specifies the number of errors that MUPIP JOURNAL processing accepts. When + the number of errors exceeds the -ERROR_LIMIT, the -INTERACTIVE qualifier + determines whether JOURNAL processing halts or defers to the operator. + -NOERROR_LIMIT prevents MUPIP JOURNAL from stopping because of errors. + Journal processing continues until it reaches the end of the journal file, + regardless of the number of errors. + + Note that, -NOERROR_LIMIT is not the same as -ERROR_LIMIT=0. + + By default, MUPIP JOURNAL uses -ERROR_LIMIT=0, causing the first error to + initiate the appropriate error action. In case of a crash there could be + some incomplete journal records at the end of a journal file. MUPIP + JOURNAL does not consider these as errors. In addition, fenced + transactions that are broken are not considered as errors. + + During the forward phase of recovery, if a broken transaction is found, + all the logical records processed afterwards are considered suspect. If a + complete transaction is found after any broken transactions, MUPIP JOURNAL + -RECOVER increments the error count and, if it is less than the error + limit, it is applied to the database. Otherwise, it is treated as a lost + transaction and extracted. If a complete transaction is found after any + broken transactions, MUPIP JOURNAL -ROLLBACK treats it as a lost + transaction and extracts it irrespective of the error limit. + + If MUPIP JOURNAL needs to increment error count during its processing, a + warning message is issued for every error encountered except in the + following cases when the error count is incremented but no warning message + is displayed: + + o When a complete transaction is found after a broken transaction + o When -EXTRACT -FULL encounters errors + + If MUPIP JOURNAL completes successfully with a non-zero value of error + count, the return status is not a success, but a warning. + + -FE[NCES][=fence-option] + + Specifies how JOURNAL processes fenced transactions. Fenced transactions + are logical transactions made up of database updates preceded by a TSTART + or ZTSTART command and followed, respectively, by a TCOMMIT or ZTCOMMIT + command. All updates between a TSTART or ZTSTART and a TCOMMIT or ZTCOMMIT + are designed to occur together so that after journal recovery the database + contains either all the updates corresponding to a fenced transaction, or + none of them. + + The argument values for -FENCES option for MUPIP -RECOVER are not + case-sensitive. + + The fence options are: + + o NONE + + This causes MUPIP JOURNAL to apply all individual updates as if + transaction fences did not exist. Note that, this means a SET/KILL + within a TP or ZTP transaction would be played as if it was an + unfenced SET/KILL. This may cause the database and new journals + created (if -BACKWARD is specified), to be different from the state + before the recovery took place. + + o ALWAYS + + This causes MUPIP JOURNAL to treat any unfenced or improperly fenced + updates as broken transactions. + + o PROCESS + + This causes MUPIP JOURNAL to accept unfenced database updates, and + also to observe fences when they appear, generating broken transaction + files in the case of a TSTART with no corresponding TCOMMIT, or a + ZTSTART with no corresponding ZTCOMMIT. It also generates broken + transactions if a multi-region transaction with TSTART and TCOMMIT + expects N regions to participate, but the number of TSTART/TCOMMIT + pairs found is less than N. The same happens for multi-region ZTSTART + and ZTCOMMIT. + + By default, MUPIP JOURNAL uses -FENCES=PROCESS. + + -FU[LL] + + -FULL when used with -EXTRACT, specifies that all journal records be + extracted. A journal file's contents can be rolled back in case of + backward recovery or rollback in order to keep the database and journal in + sync. This is achieved not by truncating the contents of the journal file + but instead setting a field in the journal file header, which shows up as + "Prev Recovery End of Data" in a MUPIP JOURNAL -SHOW=HEADER output, to + indicate the end of the journal file before rolling back and setting + another field in the file header to indicate the new end of the journal + file (this field shows up as "End of Data" in a MUPIP JOURNAL -SHOW=HEADER + output). Once a journal file's contents are rolled back, all future MUPIP + JOURNAL commands (including -EXTRACT) operate on the rolled back journal + file only. But if -FULL is specified along with -EXTRACT, the entire + journal file contents (including those records that were rolled back) are + extracted. This qualifier is to be used only as a diagnostic tool and not + in normal operation. + + -FULL qualifier is compatible with -EXTRACT only. + + -[NO]IN[TERACTIVE] + + Specifies whether, for each error over the -ERROR_LIMIT, JOURNAL + processing prompts the invoking operator for a response to control + continuation of processing. If the operator responds that processing + should not continue, the MUPIP JOURNAL command terminates. + + -NOINTERACTIVE terminates the journal processing as soon as the MUPIP + JOURNAL command generates the number of errors specified in -ERROR_LIMIT. + + This qualifier is applicable only to interactive mode or terminal mode. + The default is -INTERACTIVE. + + -LOST[TRANS]= + + -LOSTTRANS is an optional qualifier for -RECOVER, -ROLLBACK and -EXTRACT. + If this is not specified and a lost transaction file creation is + necessary, MUPIP JOURNAL creates one using the name of the current journal + file being processed with a .lost extension. + + Any complete transactions after a broken transaction is considered a lost + transaction. They are written into the lost transaction file. For -RECOVER + it might be considered as good transaction and applied to the database, if + -ERROR_LIMIT qualifier allows it to do so. + + Note that, if selection qualifiers are specified, the broken transaction + determination (and therefore lost transaction determination as well) is + done based on the journal file that is filtered by the selection + qualifiers. This means that a transaction's journal records may be + considered complete or broken or lost, depending on the nature of the + selection qualifiers. Using -FENCES=NONE along with the selection + qualifiers will result in every journal record to be considered complete + and hence prevent broken or lost transaction processing. + + In the case of a replicated database, lost transaction can have an + additional cause. If failover occurs (that is, the originating Source + Server, A, fails and the replicating Source Server, B, assumes the + originating instance's role), some transactions committed to A's database + may not be reflected in B's database. Before the former originating + instance becomes the new replicating instance, these transactions must be + rolled back. These transactions are known as "lost transactions". Note + that these are complete transactions and different from a broken + transaction. MUPIP JOURNAL -ROLLBACK stores extracted lost transactions in + the extract-file specified by this qualifier. The starting point for the + search for lost transactions is the journal sequence number obtained from + the originating Source Server in the -FETCHRESYNC operation. + + -RED[IRECT]=file-pair-list + + Replays the journal file to a database different than the one for which it + was created. Use -REDIRECT to create or maintain databases for training or + testing. + + This qualifier applies to -RECOVER action and -FORWARD direction qualifier + only. JOURNAL rejects -REDIRECT unless it appears with -RECOVER. + + The file-pair-list consists of one or more pairs of file-names enclosed in + parentheses () and separated by commas (,). The pairs are separated by an + equal sign in the form: + + old-file-name=new-file-name + + where the old file-name identifies the original database file and the new + file-specification file-name identifies the target of the -RECOVER. The + old-file-specification can always be determined using -SHOW. + + By default, JOURNAL directs -RECOVER to the database file from which the + journal was made. -REDIRECT is not compatible with -ROLLBACK. + + Example: + + $ mupip journal -recover -forward -redirect="bgdbb.dat=test.dat" bgdbb.mjl + + This JOURNAL command does a forward recovery that -REDIRECTs the updates + in bgdbb.mjl from bgdbb.dat to test.dat. + + -VERB[OSE] + + Prints verbose output in the course of processing. It is not negatable and + it is set to OFF by default. + +3 Selection_Qualifiers + Selection Qualifiers + + Journal Selection Qualifiers are compatible with -EXTRACT and -SHOW + operations only. This is because most applications are not constructed to + safely remove a subset of transactions based on criteria that is exterior + to the application design. To exclude transactions from a recovery based + on some selection criteria, the methodology is to -EXTRACT the records, + and then reapply them through application logic rather than by journal + recovery. This approach permits the application logic to appropriately + handle any interactions between the removed and the retained transactions. + Note that, selection qualifiers might result in only a subset of a fenced + transaction's journal records to be extracted (for example, a TSTART + record may not be extracted because the first update in that transaction + was filtered out by a selection qualifier, while the corresponding TCOMMIT + record may get extracted). This can cause a fenced transaction to seem + broken when actually it is not. + + The following qualifiers control the selection criteria for journal + processing. + + Except for -TRANSACTION, all qualifiers allow for specifying a comma (,) + seperated list of values. + + -G[LOBAL]=global-list + + Specifies globals for MUPIP JOURNAL to include or exclude from processing. + You might find this qualifier useful for extracting and analyzing specific + data. + + The global-list contains one or more global-names (without subscripts) + preceded by a caret symbol (^). To include more than one global use one of + the following syntaxes. + + $ mupip journal -forward -extract -global="^A*,^C" mumps.mjl + + or + + $ mupip journal -forward -extract -global="(^A*,^C)" mumps.mjl + + The names may include the asterisk (*) wildcard. That is, -GLOBAL="^A*" + selects all global variables with names starting with A. The entire list + or each name may optionally be preceded by a tilda sign (~), requiring + JOURNAL to exclude database updates to the specified global(s). When the + global-list with a MUPIP JOURNAL -GLOBAL does not start with a tilda sign + (~), JOURNAL processes only the explicitly named globals. By default, + JOURNAL processes all globals. + + To specify subscripts, using -GLOBAL="^A(1)" results in all keys under the + ^A(1) tree to be included, that is, it is equivalent to using + -GLOBAL="^A(1,*)". An asterisk (*) or a percent (%) anywhere in the global + specification is permitted. Percent (%) matches any character, and + asterisk (*) matches any string (possibly zero length too). The asterisk + (*) or percent (%) specification can be used for -USER qualifier too. + + Example: + + To extract all ^GBL* except for ^GBLTMP: + + $ mupip journal -extract -global="^GBL*,~^GBLTMP" -forward mumps.mjl + + To extract all ^GBL except for ^GBL(1,"TMP"): + + $ mupip journal -extract -global=\"^GBL,~^GBL\(1,\"\"TMP\"\"\)\" -forward mumps.mjl + + The backslash (\) delimiter characters are required in UNIX to pass MUPIP + the double quotes (") of the string subscript. + + An INVGLOBALQUAL error is issued along with the error offset in the + command line, whenever a parse error of the global qualifier string is + encountered. + + -ID=pid-list + + Specifies that JOURNAL processing include or exclude database updates + generated by one or more processes, identified by process identification + numbers (PIDs). The entire list or each PID may optionally be preceded by + a tilda sign (~), requiring JOURNAL to exclude database updates initiated + by the specified PID. You may use this qualifier for trouble shooting or + analyzing data. + + By default, JOURNAL processes database updates regardless of the PID that + initiated it. + + -T[RANSACTION]=transaction-type + + Specifies transaction-types for JOURNAL to include or exclude from + processing. For example, you may use this qualifier to report only on KILL + operations to locate possible causes for missing data. + + The transaction-types are SET and KILL and can be negated. These types + correspond to the M commands of the same names. When the transaction-type + with a JOURNAL -TRANSACTION is not negated, JOURNAL processes only + transactions of the type named (for example, -TRANSACTION=KILL), whereas + if it is negated, JOURNAL does not process transactions of the type named + (for exmaple, -TRANSACTION=NOKILL). + + By default, JOURNAL processes transactions, regardless of its type. + + -U[SER]=user-list + + Specifies that MUPIP JOURNAL processing include or exclude database + updates generated by one or more users. You can use this qualifier to + audit the actions of a particular user. The user-list contains names of + one or more users. Indicate multiple users by separating the names with + commas (,). The names may include the wildcard asterisk (*). The entire + list or each name may optionally be preceded by a minus sign (-) tilda + sign (~), requiring JOURNAL to exclude database updates initiated by the + specified user(s). When the user-list with a JOURNAL -USER does not start + with a tilda sign (~), JOURNAL processes only those database updates, + which are generated by explicitly named users. The asterisk (*) or percent + (%) specification can be used for -USER qualifier. Percent (%) matches any + character, and asterisk (*) matches any string (possibly zero length too). + + By default, JOURNAL processes database updates regardless of the user who + initiated them. + +2 Extract_Formats + Extract Formats + + Journal EXTRACT files always start with a label. For the current release + of GT.M, the label is GDSJEX06 for a simple journal extract file. This + label is necessary to identify the format of the file. + + If the environment variable gtm_chset is set of UTF-8, then file format + label is followed by another label called "UTF-8" to indicate UTF-8 mode. + + After this label, the journal record extracts follow. These journal record + extracts include fields or pieces delimited by a back slash (\). + + The first piece of an -EXTRACT output record contains a two-digit decimal + transaction record type (for example, 01 for a process initialization + record). The second piece contains the full date and time of the + operation, represented in the $HOROLOG format. The third piece contains a + GT.M assigned number (database transaction number) which uniquely + identifies the transaction within the time covered by the journal file. + The fourth piece contains the process ID (PID) of the process that + performed the operation, represented as a decimal number. The remainder of + the record depends on the record type. + + Records of type SET, KILL, ZKILL, TSTART, and TCOMMIT include the + token_seq as part of the output. It is the sixth field in the output of + the journal record extract. When replication is in use, token_seq is a + journal sequence number (jsnum) that uniquely identifies each transaction. + When replication is not in use and the transaction is a TP or ZTP + transaction, token_seq is an 8-byte token that uniquely identifies the + entire TP or ZTP transaction. For non-replicated, non-TP, and non-ZTP + journal records, token_seq has a zero (0) value. + + The format of the plain journal extract is as follows: + + NULL 00\time\tnum\pid\clntpid\jsnum\strm_num\strm_seq + PINI(U) 01\time\tnum\pid\nnam\unam\term\clntpid\clntnnam\clntunam\clntterm + PINI(V) 01\time\tnum\pid\nnam\unam\term\mode\logintime\image_count\pname\clntpid\clntnnam\clntunam\clntterm\clntmode\clntlogintime\clntimage_count\clntpname + PFIN 02\time\tnum\pid\clntpid + EOF 03\time\tnum\pid\clntpid\jsnum + KILL 04\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + SET 05\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg + ZTSTART 06\time\tnum\pid\clntpid\token + ZTCOM 07\time\tnum\pid\clntpid\token\partners + TSTART 08\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq + TCOM 09\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\partners\tid + ZKILL 10\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + ZTWORM 11\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole + ZTRIG 12\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + + where: + + 01 record indicates a process/image-initiated update (PINI) into the + current journal file for the first time. + + 02 record indicates a process/image dropped interest (PFIN) in the current + journal file. + + 03 record indicates all GT.M images dropped interest in this journal file + and the journal file was closed normally. + + 04 record indicates a database update caused by a KILL command. + + 05 record indicates a database update caused by a SET command. + + 06 record indicates a ZTSTART command. + + 07 record indicates a ZTCOMMIT command. + + 08 record indicates a TSTART command. + + 09 record indicates a TCOMMIT command. + + 10 record indicates a database update caused by a ZKILL command. + + 11 records indicates a value for/from $ZTWORMHOLE (when replication is + turned on). + + 12 record indicates a ZTRIGGER command. + + Journal extracts contain NULL records only in a multisite replication + configuration where triggers or external M-filters are active. Here are + two examples when NULL records are sent to the journal files: + + o An external filter on an instance transforms a SET record to a NULL + record that has a different schema. + o If the source side has triggers enabled and its receiver side either + runs a pre-trigger version of GT.M or runs on a platform where + triggers are not supported (for example, AXP VMS or HPUX HPPA), + trigger definition journal records from the source side are + transformed to NULL records on the receiver side. + + **Important** + + A NULL record does not have global information. Therefore, it resides in + the alphabetically last replicated region of the global directory. + + The format of the detail journal extract is as follows: + + PINI(U) time\tnum\chksum\pid\nnam\unam\term\clntpid\clntnnam\clntunam\clntterm + PINI(V) time\tnum\chksum\pid\nnam\unam\term\mode\logintime\image_count\pname\clntpid\clntnnam\clntunam\clntterm\clntmode\clntlogintime\clntimage_count\clntpname + PFIN time\tnum\chksum\pid\clntpid + EOF time\tnum\chksum\pid\clntpid\jsnum + SET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg + KILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + ZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + ZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole + ZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + TSTART time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq + TSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg + TKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + TZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + TZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole + TZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + USET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodef + lags\node=sarg + UKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + UZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + UZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole + UZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + TCOM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\partners\tid + INCTN time\tnum\chksum\pid\clntpid\opcode\incdetail + EPOCH time\tnum\chksum\pid\clntpid\jsnum\blks_to_upgrd\free_blocks\total_blks\fully_upgraded[\strm_num\strm_seq]... + PBLK time\tnum\chksum\pid\clntpid\blknum\bsiz\blkhdrtn\ondskbver + AIMG time\tnum\chksum\pid\clntpid\blknum\bsiz\blkhdrtn\ondskbver + NULL time\tnum\pid\clntpid\jsnum\strm_num\strm_seq + ZTSTART time\tnum\chksum\pid\clntpid\token + FSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg + FKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + FZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + GSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg + GKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + GZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node + ZTCOM time\tnum\chksum\pid\clntpid\token\partners + ALIGN time\tnum\chksum\pid\clntpid + + where: + + AIMG records are unique to DSE action and exist because those actions do + not have a "logical" representation. + + EPOCH records are status records that record information related to check + pointing of the journal. + + NCTN records are the transaction numbers of the sequence of critical + sections in which the process and marked the database blocks of the + globals as previously used but no longer in use in the bit maps. + + PBLK records are the before image records of the bit maps. + + ALIGN records pad journal records so every alignsize boundary (set with + MUPIP SET -JOURNAL and is visible in DSE DUMP -FILEHEADER output) in the + journal file starts with a fresh journal record. The sole purpose of these + records is to help speed up journal recovery. + + Legend (All hexadecimal fields have a 0x prefix. All numeric fields + otherwise are decimal): + + +------------------------------------------------------------------------+ + | tnum | Transaction number | + |----------------+-------------------------------------------------------| + | chksum | Checksum for the record. | + |----------------+-------------------------------------------------------| + | fully_upgraded | 1 if the db was fully upgraded (indicated by a dse | + | | dump -file -all) at the time of writing the EPOCH | + |----------------+-------------------------------------------------------| + | pid | Process id that wrote the jnl record. | + |----------------+-------------------------------------------------------| + | clntpid | If non-zero, clntpid is the process id of the GT.CM | + | | client that initiated this update on the server side. | + |----------------+-------------------------------------------------------| + | jsnum | Journal sequence number. | + |----------------+-------------------------------------------------------| + | token | Unique 8-byte token. | + |----------------+-------------------------------------------------------| + | | If replication is true and this update originated in | + | | a non-supplementary instance but was replicated to | + | | and updated a supplementary instance, this number is | + | | a non-zero value anywhere from 1 to 15 (both | + | | inclusive) indicating the non-supplementary stream | + | strm_num | number. In all other cases, this stream # value is 0. | + | | In case of an EPOCH record, anywhere from 0 to 16 | + | | such "strm_num" numbers might be displayed depending | + | | on how many sources of supplementary instance | + | | replication have replicated to the instance in its | + | | lifetime. | + |----------------+-------------------------------------------------------| + | | If replication is true and this update originated in | + | | a non-supplementary instance but was replicated to | + | | and updated a supplementary instance, this is the | + | | journal sequence number of the update on the | + | | originating non-supplementary instance. If | + | | replication is true and this update originated in a | + | | supplementary instance, this is the journal sequence | + | strm_seq | number of the update on the originating supplementary | + | | instance. In all other cases, this stream sequence | + | | number is 0. Note that the journal seqno is actually | + | | 1 more than the most recent update originating on | + | | that stream number. In case of an EPOCH record, | + | | anywhere from 0 to 16 such "strm_seq" numbers might | + | | be displayed depending on how many sources of | + | | supplementary instance replication have replicated to | + | | the instance in its lifetime. | + |----------------+-------------------------------------------------------| + | | TRANSACTIONID string (BATCH or any string of | + | | descriptive text chosen by the application) specified | + | | as an argument of the corresponding TSTART command. | + | tid | If TRANSACTIONID is not specified with TSTART, GT.M | + | | sets tid to null. TRANSACTIONID can specify any value | + | | for tid but affects GT.M behavior only when | + | | TRANSACTIONID specifies BATCH or BA. | + |----------------+-------------------------------------------------------| + | token_seq | If replication is turned on, it is the journal | + | | sequence number. If not, it is a unique 8-byte token. | + |----------------+-------------------------------------------------------| + | | =n where this is the nth update in the TP or ZTP | + | updnum | transaction. n=1 for the 1st update etc. 0 for | + | | non-TP. | + |----------------+-------------------------------------------------------| + | | Decimal number interpreted as a binary mask.. | + | | Currently only 5 bits are used. | + | | | + | | o 00001 (1) => update journaled but NOT replicated | + | | (For example, update inside a trigger) | + | | o 00010 (2) => update to a global that had at least | + | | one trigger defined, even if no trigger matched | + | | this update | + | | o 00100 (4) => $ZTWORMHOLE holds the empty string | + | | ("") at the time of this update or was not | + | | referenced during this update | + | | o 01000 (8) => update did not invoke any triggers | + | | even if they existed (For example, MUPIP LOAD) | + | | o 10000 (16) => whether the update (set or kill) is | + | nodeflags | a duplicate. In case of a KILL, it is a kill of | + | | some non-existing node aka duplicate kill. Note | + | | that the dupkill occurs only in case of the | + | | Update Process. In case of GT.M, the KILL is | + | | entirely skipped. In both cases (duplicate set or | + | | kill), only a jnl record is written, the db is | + | | untouched. | + | | | + | | Combinations of the above bits would mean each of the | + | | individual bit characteristics. For example, 00011 => | + | | update within a trigger context, and to a global with | + | | at least one trigger defined. For example, 00011 => | + | | update inside a trigger and to a global with at least | + | | one trigger defined. Certain bit combinations are | + | | impossible. For example, 01001 since GT.M replicates | + | | any update that does not invoke triggers. | + |----------------+-------------------------------------------------------| + | node | Key that is being updated in a SET or KILL. | + |----------------+-------------------------------------------------------| + | sarg | Right-hand side argument to the SET (that is, the | + | | value that the key is being SET to). | + |----------------+-------------------------------------------------------| + | | Number of journaled regions participating in this TP | + | partners | or ZTP transaction (TCOM/ZTCOM record written in this | + | | TP or ZTP) . | + |----------------+-------------------------------------------------------| + | opcode | Inctn opcode. See gdsfhead.h inctn_opcode_t for all | + | | possible values. | + |----------------+-------------------------------------------------------| + | blknum | Block number corresponding to a PBLK or AIMG or INCTN | + | | record. | + |----------------+-------------------------------------------------------| + | bsiz | Block size from the header field of a PBLK or AIMG | + | | record. | + |----------------+-------------------------------------------------------| + | blkhdrtn | Transaction number from the block header of a PBLK or | + | | AIMG record. | + |----------------+-------------------------------------------------------| + | ondskbver | On disk block version of this block at the time of | + | | writing the PBLK or AIMG record. 0 => V4, 1 => V5. | + |----------------+-------------------------------------------------------| + | incdetail | 0 if opcode=1,2,3; blks2upgrd if opcode=4,5,6; blknum | + | | if opcode=7,8,9,10,11,12,13 | + |----------------+-------------------------------------------------------| + | ztwormhole | string corresponding to $ZTWORMHOLE | + |----------------+-------------------------------------------------------| + | blks2upgrd | # of new V4 format bitmap blocks created if | + | | opcode=4,5; csd->blks_to_upgrd if opcode=6 | + |----------------+-------------------------------------------------------| + | uname | Name of the user that wrote this PINI record. | + |----------------+-------------------------------------------------------| + | clntunam | If non-empty, clntunam is the name of the GT.CM | + | | client that initiated this update on the server side. | + +------------------------------------------------------------------------+ + +1 Replication + Replication + + The following MUPIP commands and qualifiers control database replication + in a GT.M environment. + +2 Change_replication_state + Change replication state + + Command Syntax: + + mupip set {-file db-file|-region reg-list} -replication={ON|OFF} + + Qualifiers: + + -file and -region + + Use these qualifiers in the same manner that you would use them for a + MUPIP SET. + + -replication=replication-state + + Switches the GT.M replication subsystem ON/OFF and possibly modify the + current journaling [no-]before image field (which is stored in the + database file header). + + replication-state is either of the following keywords: + + OFF + + Disable replication of the database file(s) or region(s). Even if you turn + off replication, journaling continues to operate as before. + + **Important** + + GT.M creates a new set of journal files and cuts the back link to the + previous journal files if the replication-state is OFF and then turned ON + again. The database cannot rollback to a state prior to ON. Therefore, + ensure that replication-state remains ON throughout the span of database + replication. Turn replication-state OFF only if database replication is no + longer needed or the instance is about to be refreshed from the backup of + the originating instance. + + ON + + Enables replication for the selected database file(s) or region(s). When + the JOURNAL qualifier is not specified, this action turns BEFORE_IMAGE + journaling on. Specify -JOURNAL=NOBEFORE_IMAGE to enable replication with + no-before-image journaling. In both cases, GT.M creates a new journal file + for each database file or region, and switches the current journal file. + FIS recommends you to specify the desired journaling characteristics + (MUPIP SET -JOURNAL=BEFORE_IMAGE or MUPIP SET -JOURNAL=NOBEFORE_IMAGE). + + When replication is ON, a MUPIP SET REPLICATION=ON command with no JOURNAL + qualifier assumes the current journaling characteristics (which are stored + in the database file header). By default GT.M sets journal operation to + BEFORE_IMAGE if this command changes the replication state from OFF to ON + and JOURNAL=NOBEFORE_IMAGE is not specified. Therefore, conservative + scripting should always specify the desired journaling characteristics + using the JOURNAL qualifier of the MUPIP SET command. + + The replication state ON in the file header denotes normal replication + operation. + + [WAS_ON] OFF + + Denotes an implicit replication state when GT.M attempts to keep + replication working even if run-time conditions such as no available disk + space or no authorization for a process attempting to auto-switch a + journal file cause GT.M to turn journaling off. Even with journaling + turned off, the Source Server attempts to continue replication using the + records available in the replication journal pool. In this state, + replication can only continue as long as all the information it needs is + in the replication journal pool. Events such as an operationally + significant change on the replicating instance(s) or communication + problems are likely to cause the Source Server to need information older + than that in the replication journal pool and because it cannot look for + that information in journal files, at that point the Source Server shuts + down. + + **Note** + + If the replication ON state is like a bicycle running smoothly on the + road, replication WAS_ON is like a bicycle with a flat front tire being + ridden like a unicycle - the system is operating outside its intended mode + of use and is more subject to misfortune. + + WAS_ON is an implicit replication state. At all times during the WAS_ON + state, you can see the current backlog of transactions and the content of + the Journal Pool (MUPIP REPLICATE -SOURCE -SHOWBACKLOG and MUPIP REPLICATE + -SOURCE -JNLPOOL -SHOW). This information is not available in the + replication OFF state. + + Example: + + $ mupip set -replication=on -file mumps.dat + + This example enables database replication and turns before-image + journaling on for mumps.dat. + + $ mupip set -replication=on -journal=nobefore_image -file mumps.dat + + This example enables database replication and turns no-before-image + journaling on for mumps.dat. + + $ mupip set -replication=off -file mumps.dat + + This example turns off database replication for mumps.dat. + +2 Create_instance + Create instance + + Command Syntax: + + mupip replicate -instance_create -name= [-noreplace] [-supplementary] + + Qualifiers: + + -instance_create + + Creates a replication instance file. mupip replicate -instance_create + takes the file name of the replication instance file from the environment + variable gtm_repl_instance. + + If an instance file already exists, GT.M renames it with a timestamp + suffix, and creates a new replication instance file. This behavior is + similar to the manner in which GT.M renames existing journal files while + creating new journal files. Creating an instance file requires standalone + access. + + -name + + Specifies the instance name that uniquely identifies the instance and is + immutable. The instance name can be from 1 to 16 characters. GT.M takes + the instance name (not the same as instance file name) from the + environment variable gtm_repl_instname. If gtm_repl_instname is not set + and -name is not specified, GT.M produces an error. + + -noreplace + + Prevents the renaming of an existing replication instance file. + + -supplementary + + Specifies that the replication instance file is suitable for use in a + supplementary instance. + + Example: + + $ export gtm_repl_instance=mutisite.repl + $ export gtm_repl_instname=America + $ mupip replicate -instance_create + + This example creates a replication instance file called multisite.repl + specified by gtm_repl_instance with an instance name America specified by + environment variable gtm_repl_instname. + +2 Edit_instance + Edit instance + + Command Syntax: + + mupip replicate + -edit[instance] {|-source -jnlpool} + {-show [-detail]|-change [-offset=] [-size=] [-value=]} + [-name=] + + -editinstance + + Displays or changes the attributes of the specified instance-file. Use + -editinstance in combination with SHOW or CHANGE qualifiers. + + -jnlpool + + Displays or changes the attributes of Journal Pool. Always specify -source + with -jnlpool. Use -jnlpool in combination with SHOW or CHANGE qualifiers. + + -change + + The CHANGE qualifier is intended only for use under the guidance of FIS + and serves two purposes. When used with -editinstance -offset -size, it + changes the contents of the replication instance file. When used with + -jnlpool, it changes the contents of journal pool header. Although MUPIP + does not enforce standalone access when using this feature on the instance + file or the journal pool, doing so when replication is actively occurring + can lead to catastrophic failures. + + -name= + + Changes the instance name in the replication instance file header to the + new-name. Note that changing an instance name preserves the instance + history. + + -show + + Displays File Header, Source Server slots, and History Records from the + Replication Instance file. + + -detail + + When specified, all fields within each section are displayed along with + their offset from the beginning of the file and the size of each field. + Use this qualifier to find the -offset and -size of the displayed field. + To edit any displayed field, use the -change qualifier. + + -size + + Indicates the new size of the new value in bytes. The value of size can be + either 1, 2, 4, or 8. + + -offset + + Takes a hexadecimal value that is a multiple of -size. With no -offset + specified, GT.M produces an error. GT.M also produces an error if the + offset is greater than the size of the instance file or the journal pool + header. + + -value + + Specifies the new hexadecimal value of the field having the specified + -offset and -size. With no value specified, GT.M displays the current + value at the specified offset and does not perform any change. Specifying + -value= makes the change and displays both the old and new + values. + + **Caution** + + Change the instance file or the journal pool only on explicit instructions + from FIS. + + -show + + The SHOW qualifier serves two purposes. When used with -editinstance, it + displays the content of the replication instance file. When used with + -jnlpool, it displays the content of the journal pool. + + Example: + + $ mupip replicate -editinstance -show -detail multisite.repl + + This example displays the content of the replication instance file + multisite.repl. The optional detail qualifier displays each section along + with its offset from the beginning of the file and the size of each field. + Use this information when there is a need to edit the instance file. + + Example: + + $ mupip replicate -editinstance -change -offset=0x00000410 -size=0x0008 -value=0x010 multisite.repl + + This command sets the value of the field having the specified offset and + size to 16. Note that mupip replicate -editinstance -show -detail command + displays the offset and size of all fields in an instance file. + +2 Start_Source_Server + Start Source Server + + Command syntax: + + mupip replicate -source -start + {-secondary=|-passive} + [-buffsize=] + [-filter=] + [-freeze[=on|off] -[no]comment[='""'] + [-connectparams=,, + , , , + ] + -instsecondary= + -log= [-log_interval=] + {-rootprimary|-propagateprimary} [{-updok|-updnotok}] + [-cmplvl=] + + Qualifiers: + + -replicate + + Use this qualifier to access the replication subsystem. + + -source + + Identifies the Source Server. + + -start + + Starts the Source Server. + + -secondary= + + Identifies the replicating instance. includes an IP + address (or a hostname that resolves to an IP address) and the port at + which the Receiver Server is waiting for a connection. + + -passive + + Starts the Source Server in passive mode. + + -log= + + Specifies the location of the log file. The Source Server logs its + unsuccessful connection attempts starting frequently and slowing to + approximately once every five minutes. This interval does not affect the + rate of connection attempts. + + -log_interval= + + Specifies the number of transactions for which the Source Server should + wait before writing to the log file. The default logging interval is 1000 + transactions. + + -log_interval=0 sets the logging interval to the default value. + + -buffsize= + + Specifies the size of the Journal Pool. The server rounds the size up or + down to suit its needs. Any size less than 1 MB is rounded up to 1 MB. If + you do not specify a qualifier, the size defaults to the GT.M default + value of 64 MB. Remember that you cannot exceed the system-provided + maximum shared memory. For systems with high update rates, specify a + larger buffer size to avoid the overflows and file I/O that occur when the + Source Server reads journal records from journal files. + + -filter= + + Specifies the complete path of the filter program and any associated + arguments. If you specify arguments, then enclose the command string in + quotation marks. If a filter is active, the Source Server passes the + entire output stream to the filter as input. Then, the output from the + filter stream passes to the replicating instance. If the filter program is + an M program with entry-ref OLD2NEW^FILTER, specify the following path: + + filter='"$gtm_dist/mumps -run OLD2NEW^FILTER"' + + Write the filter as a UNIX process that takes its input from STDIN and + writes its output to STDOUT. + + The format of the input and output data is the MUPIP journal file extract + format. The filter must maintain a strict 1:1 relationship between + transactions on the input stream and transactions on the output stream. If + a transaction on the input results in no sets and kills in the output, the + filter must still write an empty transaction to the output stream. + + Example: + + extfilter + ; A command like mupip replic -source -start -buffsize=$gtm_buffsize + ;-instsecondary=$secondary_instance -secondary=$IP_Address:$portno + ;-filter='"$gtm_exe/mumps -run ^extfilter"' -log=$SRC_LOG_FILE + ;deploys this filter on the Source Server. + set $ztrap="goto err" + set TSTART="08" + set TCOMMIT="09" + set EOT="99" + set log=$ztrnlnm("filterlog") + ; use the environment variable filterlog" (if defined) + ;to specify which logfile to use + if logersion="" set log="logcharout" char + if $zv["VMS" sechar EOL=$C(13)_$C(10) + else set EOL=$C(10) + open log:newve:sion + use $principal:nowrap + for do + . use $principal + . read extrRec + . if $zeof halt + . set rectype=$piece(extrRec,"\",1) + . if rectype'=EOT do + .. if rectype'=TSTART set filtrOut=extrRec_EOL + .. else do + ... set filtrOut=extrRec_EOL + ... for read extrRec set filtrOut=filtrOut_extrRec_EOL quit:$zextract(extrRec,1,2)=TCOMMIT + ... if $zeof halt + .. ; set $x=0 is needed so every write starts at beginning of record position + .. ; do not write more than width characters in one output operation to avoid "chopping". + .. ; and/or eol in the middle of output stream + .. ; default width=32K-1 + .. ; use $zsubstr to chop at valid character boundary (single or multi byte character) + .. set cntr=0,tmp=filtrOut + .. for quit:tmp="" do + ... set cntr=cntr+1,$x=0,record(cntr)=$zsubstr(tmp,1,32767),tmp=$zextract(tmp,$zlength(record(cntr))+1,$zlength(tmp)) + ... write record(cntr) + . use log + . write "Received: ",EOL,$s(rectype'=TSTART:extrRec_EOL,1:filtrOut) + . if rectype'=EOT write "Sent: ",EOL,filtrOut + . else write "EOT received, halting..." halt + quit + err + set $ztrap="" + use log + write !!!,"**** ERROR ENCOUNTERED ****",!!! + zshow "*" + halt + + This example reads logical database updates associated with a transaction + from STDIN and writes them to log.out and STDOUT just like the UNIX tee + command. It runs on GT.M V5.5-000 where it is no longer required to treat + filter output as a transaction. To run this example on a pre-GT.M V5.5-000 + version, replace the line: + + .. if rectype'=TSTART set filtrOut=extrRec_EOL + + with + + .. if rectype'=TSTART set filtrOut=TSTART_EOL_extrRec_EOL_TCOMMIT_EOL + + to wrap mini-transactions in 08 09. + + -freeze[=on|off] -[no]comment[='""'] + + Promptly sets or clears an Instance Freeze on an instance irrespective of + whether a region is enabled for an Instance Freeze. -freeze with no + arguments displays the current state of the Instance Freeze on the + instance. + + -[no]comment[='""'] allows specifying a comment/reason associated + with an Instance Freeze. Specify -nocomment if you do not wish to specify + a comment/reason. + + -connectparams=,, ,, + + Specifies the connection retry parameters. If the connection between the + Source and Receiver Servers is broken or the Source Server fails to + connect to the Receiver Server at startup, the Source Server applies these + parameters to the reconnection attempts. + + First, the Source Server makes the number of reconnection attempts + specified by the value every + milliseconds. Then, the Source Server attempts reconnection every seconds and logs an alert message every + seconds. If the specified value is less than */1000 + lt;soft tries period>, it is set to the + larger value. The Source Server sends a heartbeat message to the Receiver + Server every seconds and expects a response back from + the Receiver Server within seconds. + + -instsecondary + + Identifies the replicating instance to which the Source Server replicates + data. + + With no -instsecondary specified, the Source Server uses the environment + variable gtm_repl_instsecondary for the name of the replicating instance. + + With no -instsecondary specified and environment variable + gtm_repl_instsecondary not set, mupip replicate -source -checkhealth looks + at all the Source Servers (Active or Passive) that are alive and running + and those that were abnormally shutdown (kill -9ed). Any Source Server + that was kill -15ed or MUPIP STOPped is ignored because GT.M considers + those Source Server shut down in the normal way. This command reports + something only if it finds at least one Source Server that is alive and + running or was abnormally shutdown (kill -9ed). Otherwise it returns a + zero (0) status without anything to report even when the Journal Pool + exists and GT.M processes (Update Process or Receiver Server on the + replicating instance) are up and running. + + You can start multiple Source Servers from the same originating instance + as long as each of them specifies a different name for -instsecondary. + + Specify -instsecondary explicitly (by providing a value) or implicitly + (through the environment variable gtm_repl_instsecondary) even for + starting a Passive Source Server. Whenever it activates, a Passive Source + Server connects to this replicating instance. + + Example: + + $ mupip replicate -source -start -buffsize=$gtm_buffsize -secondary=localhost:1234 -log=A2B.log -instsecondary=B + + This command starts the Source Server for the originating instance with + instance B as its replicating instance. + + -rootprimary + + Assign the current instance as the originating instance. You can specify + -rootprimary either explicitly or implicitly to start an instance as an + originating instance. + + -updok + + Instructs the Source Server to allow local updates on this instance. This + is a synonym for -rootprimary but is named so it better conveys its + purpose. + + -propagate[primary] + + Use this optional qualifier to assign the current instance as a + propagating instance. Specifying -propagateprimary disables updates on the + current instance. + + Note that it is not possible to transition an originating instance to a + propagating instance without bringing down the Journal Pool. However, it + is possible to transition a propagating instance to an originating + instance without bringing down the Journal Pool for an already running + passive Source Server (start one with -propagateprimary if none is + running). + + Both -rootprimary and -propagateprimary are optional and mutually + exclusive. However, FIS recommends you to specify both -rootprimary and + -propagateprimary explicitly in the script for clarity. + + Example: + + $ mupip replicate -source -activate -rootprimary + + This command transitions a propagating originating instance to an + originating instance without bringing down the Journal Pool. + + With neither -rootprimary nor -propagateprimary specified, GT.M uses a + default value of -propagateprimary for the passive Source Server startup + command (mupip replic -source -start -passive) and the deactivate + qualifier (mupip replicate -source -deactivate). GT.M uses a default value + of -rootprimary for the mupip replicate -source -start -secondary=... and + the mupip replic -source -activate commands. These default values make the + replication script simpler for users who are planning to limit themselves + to one originating instance and multiple replicating instance (without any + further replicating instances downstream). + + $ export gtm_repl_instance=multisite.repl + $ mupip set -journal="enable,before,on" -replication=on -region "*" + $ mupip replicate -instance_create -name=America + $ mupip replicate -source -start -buffsize=$jnlpool_size -secondary=localhost:1234 -log=A2B.log -instsecondary=Brazil + + This example starts the Source Server at port 1234 for the replicating + instance Brazil. The Source Server creates a Journal Pool. A GT.M Process + writes the updated journal records to the Journal Pool. Then, the Source + Server process transports each record from the Journal Pool to Brazil via + a TCP/IP connection. + + **Note** + + Before starting replication, always remember to rundown every replicated + database region then start the Source Server. + + **Important** + + GT.M updates to replicated regions are permitted only on the originating + instance and disabled on ALL other replicating instances. + + The Source Server records actions and errors in A2B.log. It also + periodically record statistics such as the current backlog, the number of + journal records sent since the last log, the rate of transmission, the + starting and current JNL_SEQNO, and the path of the filter program, if + any. + + -updnotok + + Instructs the Source Server to not allow local updates on this instance. + This is a synonym for -propagateprimary but is named so it better conveys + its purpose. + + -cmplvl=n + + Specifies the desired compression level for the replication stream. n is a + positive integer value indicating the level of compression desired. Level + 0 offers no compression. Level 1 offers the least compression while Level + 9 (as of version 1.2.3.3 of the zlib library) offers the most compression + (at the cost of the most CPU usage). Specifying -cmplvl without an + accompanying -start produces an error. In the case of the source server, + if N specifies any value outside of the range accepted by the zlib library + or if -cmplvl is not specified, the compression level defaults to zero + (0). In the case of the receiver server, as long as N is non-zero the + decompression feature is enabled; since the source server setting + determines the actual level, any legal non-zero value enables compressed + operation at the receiver. + + Alternatively, the environment variable gtm_zlib_cmp_level can specify the + desired compression level (in the same value range as N above) and the + source server can then be started without -cmplvl. This has the same + effect as starting it with -cmplvl specified. An explicitly specified + value on the command line overrides any value specified by the environment + variable. + + Whenever the source and receiver server connect with each other, if the + source server was started with a valid non-zero compression level, they + first determine whether the receiver server is running a version of GT.M + which handles compressed records and has been started with a non-zero + compression level. Only if this is true, do they agree to use compressed + journal records. They also verify with a test message that + compression/decompression works correctly before sending any compressed + journal data across. They automatically fall back to uncompressed mode of + transmission if this test fails or if, at any point, either side detects + that compression or decompression has failed. That is, any runtime error + in the compression/decompression logic results in uncompressed replication + (thereby reducing replication throughput) but never jeopardizes the + functional health of replication. + + The Source and Receiver Servers log all compression related events and/or + messages in their respective logs. The source server also logs the length + of the compressed data (in addition to the uncompressed data length) in + its logfile. + + **Note** + + If you plan to use the optional compression facility for replication, you + must provide the compression library. The GT.M interface for compression + libraries accepts the zlib compression libraries without any need for + adaptation. These libraries are included in many UNIX distributions and + are downloadable from the zlib home page. If you prefer to use other + compression libraries, you need to configure or adapt them to provide the + same API provided by zlib. Simple instructions for compiling zlib on a + number of platforms follow. Although GT.M uses zlib, zlib is not FIS + software and FIS does not support zlib. These instructions are merely + provided as a convenience to you. + + If a package for zlib is available with your operating system, FIS + suggests that you use it rather than building your own. + + Solaris/cc compiler from Sun Studio: + + ./configure --shared + make CFLAGS="-KPIC -m64" + + HP-UX(IA64)/HP C compiler: + + ./configure --shared + make CFLAGS="+DD64" + + AIX/XL compiler: + + ./configure --shared + Add -q64 to the LDFLAGS line of the Makefile + make CFLAGS="-q64" + + Linux/gcc: + + ./configure --shared + make CFLAGS="-m64" + + z/OS: + + Download the zlib 1.1.4 from the libpng project's download page on + SourceForge.com. Use a transfer mechanism that does not perform automatic + conversion to download a source tarball. If pax cannot read the archive, + it is a sign that the download mangled the archive. Use pax to unpack the + tarball, converting files from ASCII to EBCDIC. + + pax -r -o setfiletag -ofrom=ISO8859-1,to=IBM-1047 -f zlib-1.1.4.tar.gz + + Apply the following patch to the zlib 1.1.4 sources: + + ---------------------------------- zlib_1.1.4_zos.patch + --------------------------------------------------diff -purN + downloads/zlib/src.orig/configure downloads/zlib/src/configure--- + downloads/zlib/src.orig/configure Tue Dec 16 14:09:57 2008+++ + downloads/zlib/src/configure Mon Feb 9 14:30:49 2009@@ -116,6 +116,11 @@ + else SFLAGS=${CFLAGS-"-Kconform_pic -O"} CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};;+ OS/390*)+ CC=xlc+ SFLAGS=${CFLAGS-"-qascii + -q64 -Wc,DLL,LP64,XPLINK,EXPORTALL -D_ALL_SOURCE_NOTHREADS"}+ + CFLAGS=${CFLAGS-"-qascii -q64 -Wc,DLL,LP64,XPLINK,EXPORTALL + -D_ALL_SOURCE_NOTHREADS"}+ LDSHARED=${LDSHARED-"xlc -qascii -q64 + -Wl,dll,LP64,XPLINK "};; # send working options for other systems to + support@gzip.org *) SFLAGS=${CFLAGS-"-O"} CFLAGS=${CFLAGS-"-O"} + + Build and install the zlib DLL, placing the xlc compilers in compatibility + to mode by setting the environment variable C89_CCMODE to 1. When not in + compatibility mode, xlc follows strict placement of command line options. + Configure and build the zlib software with ./configure --shared && make. + By default, the configure script places zlib in /usr/local/lib. Install + the software with make install. To ensure that GT.M finds zlib, include + /usr/local/lib in LIBPATH, the environment variable that provides a search + path for processes to use when they link DLLs. + + By default, GT.M searches for the libz.so shared library (libz.sl on HPUX + PA-RISC) in the standard system library directories (for example, + /usr/lib, /usr/local/lib, /usr/local/lib64). If the shared library is + installed in a non-standard location, before starting replication, you + must ensure that the environment variable $LIBPATH (AIX and z/OS) or + $LD_LIBRARY_PATH (other UNIX platforms) includes the directory containung + the library. The Source and Receiver Server link the shared library at + runtime. If this fails for any reason (such as file not found, or + insufficient authorization), the replication logic logs a DLLNOOPEN error + and continues with no compression. + +2 Shutdown_Source_Server + Shutdown Source Server + + Command syntax: + + mupip replicate -source -shutdown [-timeout=] + + Qualifiers: + + -shutdown + + Shuts down the Source Server. + + -timeout= + + 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. + +2 Activate_Passive_Source_Server + Activate Passive Source Server + + Command syntax: + + mupip replicate -source -activate + -secondary= + -log= + -connectparams=,, + ,,, + ] + -instsecondary= + {-rootprimary|-propagateprimary} + + Qualifiers: + + -activate + + Activates a passive Source Server. Once activated, the Source Server reads + journal records from the Journal Pool and transports them to the system + specified by -secondary. + + -instsecondary= + + Identifies the replicating instance to which the passive Source Server + connects after activation. + + With no -instsecondary specified, the passive Source Server uses the + environment variable gtm_repl_instsecondary as the value of + -instsecondary. + + -rootprimary + + Specifies that the passive Source Server activation occurs on an + originating instance. + + -propagateprimary + + Specifies that the passive Source Server activation occurs on a + propagating instance. + + If neither -rootprimary nor -propagateprimary are specified, this command + assumes -propagateprimary. + + Example: + + $ mupip replicate -source -activate -secondary=localhost:8998 -log=A2B.log -instsecondary=America + + This example activates a Source Server from passive mode. + +2 Deactive_Active_Source_Server + Deactive Active Source Server + + Command syntax: + + mupip replicate -source -deactivate -instsecondary= + + Qualifiers: + + -deactivate + + Makes an active Source Server passive. To change the replicating instance + with which the Source Server is communicating, deactivate the Source + Server and then activate it with a different replicating instance. + + -instsecondary= + + Identifies the active Source Server to transition to the passive (standby) + state. + + With no -instsecondary specified, $gtm_repl_instsecondary determines the + active Source Server. + + -rootprimary + + Specifies that the active Source Server is on originating instance. + + -propagateprimary + + Specifies that the active Source Server is on a propagating instance. + + If neither -rootprimary nor -propagateprimary are specified, this command + assumes -propagateprimary. + +2 Stop_Source_Filter + Stop Source Filter + + There are two ways to stop an active filter on the Source Server. + + o Execute mupip replicate -source -stopsourcefilter on the originating + Source Server. + o Specify -stopsourcefilter as an option for starting the Receiver + Server. + +2 Check_Server_Health + Check Server Health + + Use the following command and qualifier to determine whether the Source + Server is running. + + Command syntax: + + mupip replicate -source -checkhealth + [-instsecondary=] [-he[lpers]] + + Qualifiers: + + -checkhealth + + Determine whether the Source Server is running. If the Source Server is + running, the exit code is 0 (zero). If the Source Server is not running or + an error exists, the exit code is not 0. + + With helpers specified, -checkhealth displays the status of Helper + Processes in addition to the status of Receiver Server and Update Process. + + -instsecondary= + + Identifies a Source Server process. + + If -instsecondary is not specified, -checkhealth checks all Source Server + processes. + + 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 + %GTM-E-SRCSRVNOTEXIST, Source server for secondary instance INSTB is not alive + +2 Change_Source_log + Change Source log + + Command syntax: + + mupip replicate -source -changelog -log= [-log_interval=] -instsecondary= + + Qualfiers: + + -changelog + + -instsecondary= + + Identifies a Source Server process. + + Instructs the Source Server to change its log file. + + -log= + + Use this mandatory qualifier to specify the name of the new log file. If + you specify the name of the current log file, no change occurs. + + Example: + + $ mupip replicate -source -changelog -log=/more_disk_space/newA2B.log -instsecondary=Brazil + + -log_interval= + + Specifies the number of transactions for which the Source Server should + wait before writing to the log file. The default logging interval is 1000 + transactions. + + -log_interval=0 reverts the logging interval to the prior value. + +2 Source_Logging + Source Logging + + Command syntax: + + mupip replicate -source -statslog={ON|OFF} + [-log_interval= + + Qualifiers: + + -statslog={ON | OFF} + + Enables or disables detailed logging. When ON, the system logs + current-state information of the Source Server and messages exchanged + between the Source and Receiver Servers. By default, detailed logging is + OFF. Once you enable it (ON), changing -statslog to OFF can stop detailed + logging. + + -log_interval= + + Specifies the number of transactions for which the Source Server should + wait before writing to the log file. The default logging interval is 1000 + transactions. + + -log_interval=0 reverts the logging interval to the prior value. + +2 Stop_Source_Server + Stop Source Server + + Command Syntax: + + mupip replic -source -shutdown [-instsecondary=] [-timeout=] + + Qualifiers: + + -instsecondary= + + Identifies a Source Server process. + + If -instsecondary is not specified, -shutdown stops all Source Server + processes. + + -timeout= + + Specifies the period of time (in seconds) a Source Server should wait + before shutting down. If you do not specify -timeout, the default timeout + period is 30 seconds. If you specify -timeout=0, shutdown occurs + immediately. + +2 Source_backlog + Source backlog + + Command syntax: + + mupip replicate -source -showbacklog + + Qualifiers: + + -showbacklog + + Reports the current backlog of journal records (in terms of JNL_SEQNO) on + the output device (normally the standard output device). This qualifier + does not affect the statistics logged in the log file. The backlog is the + difference between the last JNL_SEQNO written to the Journal Pool and the + last JNL_SEQNO sent by the Source Server to the Receiver Server. In the + WAS_ON state, -showbacklog reports the backlog information even if the + Source Server is shut down. + + Example: + + $ mupip replic -source -showbacklog -inst=INSTB + Wed May 19 18:58:29 2010 : Initiating SHOWBACKLOG operation on source server pid [0] for secondary + instance [INSTB] + 101 : backlog number of transactions written to journal pool and yet to be sent by the source server + 102 : sequence number of last transaction written to journal pool + 1 : sequence number of last transaction sent by source server + %GTM-E-SRCSRVNOTEXIST, Source server for secondary instance INSTB is not alive + +2 Process_Lost_Transactions + Process Lost Transactions + + Except following a failover when the backlog is zero, whenever a former + originating instance comes up as a new replicating instance, there is + always a lost transaction file. Apply this lost transaction file at the + new originating instance as soon as practicable because there could be + additional lost transaction files in the event of other failovers. For + example, failure of the new originating instance before the lost + transaction file is processed. These additional lost transactions files + can complicate the logic needed for lost transaction processing. + + Apply the lost transactions on the new originating instance either + manually or in a semi-automated fashion using the M-intrinsic function + $ZQGBLMOD(). If you use $ZQGBLMOD() , two perform 2 additional steps ( + mupip replicate -source -needrestart and mupip replicate -source + -losttncomplete ) as part of lost transaction processing. Failure to run + these steps can cause $ZQGBLMOD() to return false negatives that in turn + can result in application data consistency issues. + + Command Syntax: + + mupip replicate -source + {-losttncomplete | -needrestart} + -instsecondary= + + -losttncomplete + + Indicate to GT.M that all lost transaction processing using $ZQGBLMOD() is + complete. Use this qualifier either explicitly or implicitly to prevent a + future $ZQGBLMOD() on an instance from returning false positives when + applying future lost transactions. This ensures accuracy of future + $ZQGBLMOD() results. + + Always use this qualifier when an originating instance comes up as a + replicating instance. + + Always run MUPIP REPLICATE -SOURCE -LOSTTNCOMPLETE on each of the + replicating instances after applying all lost transaction files except on + the following occasions: + + o The replicating instance is connected to the originating instance at + the time the command is run on the originating instance. + o The replicating instance is not connected at the time the command is + run on the originating instance but connects to the originating + instance, before the originating instance is brought down. + + -needrestart + + Checks whether the originating instance ever communicated with the + specified replicating instance (if the receiver server or a fetchresync + rollback on the replicating instance communicated with the Source Server) + since the originating instance was brought up. If so, this command + displays the message SECONDARY INSTANCE xxxx DOES NOT NEED TO BE RESTARTED + indicating that the replicating instance communicated with the originating + instnace and hence does not need to be restarted. If not, this command + displays the message SECONDARY INSTANCE xxxx NEEDS TO BE RESTARTED FIRST. + In this case, bring up the specified instance as a replicating instance + before the lost transactions from this instance are applied. Failure to do + so before applying the corresponding lost transactions causes $ZQGBLMOD() + to return false negatives which can result in application data + inconsistencies. + + The mupip replic -source -needrestart command should be invoked once for + each lost transaction file that needs to be applied. It should be invoked + on the new originating instance before applying lost transactions. Specify + -instsecondary to provide the instance name of the replicating instance + where the lost transaction file was generated. If not, the environment + variable gtm_repl_instsecondary is implicitly assumed to hold the name of + the replicating instance. + + If the lost transaction file was generated from the same instance to which + it is to be applied, a mupip replicate -source -needrestart command is not + required. + + Always remember to bring the replicating instance (specified in the + -needrestart command) as an immediate replicating instance of the current + originating instance. If it is brought up as a replicating instance + through a different intermediate replicating instance, the -needrestart + command unconditionally considers the instance as not having communicated + with the originating instance even though it might be up and running. + + The Source Server on the originating instance and/or Receiver Server or + fetchresync rollback on the replicating instance need not be up and + running at the time you run this command. + + However, it is adequate if they were up at some point in time after the + originating instance was brought up. + + This command protects against a scenario where the originating instance + when the lost transaction file is generated is different from the primary + instance when the lost transactions are applied (note that even though + they can never be different in case of a dual-site configuration, use of + this command is nevertheless still required). + + $ZQGBLMOD() relies on two fields in the database file header of the + originating instance to be set appropriately. Zqgblmod Trans and Zqgblmod + Seqno. In an LMS configuration, if there are more than two instances, and + no instances other than the originating and replicating instances are + involved in the rollback -fetchresync participate in the sequence number + determination. Hence, they do not have their Zqgblmod Seqno (and hence + Zqgblmod Trans) set when that particular lost transaction file is + generated. If any of the non-participating instances is brought up as the + new originating instance and that particular lost transaction file is + applied on the originating instance, the return values of $ZQGBLMOD() will + be unreliable since the reference point (Zqgblmod Trans) was not set + appropriately. Hence, this command checks whether the replicating instance + where the lost transaction was previously generated has communicated with + the current originating instance after it came up as the originating + instance. If it is affirmative, the Zqgblmod Seqno and Zqgbl mod Trans + fields would have been appropriately set and hence $ZQGBLMOD() values will + be correct. + + Example: + + $ mupip replic -source -losttncomplete + + This command updates the Zqgblmod Seqno and Zqgblmod Trans fields + (displayed by a dse dump -fileheader command) in the database file headers + of all regions in the global directory to the value 0. Doing so causes a + subsequent $ZQGBLMOD() to return the safe value of one unconditionally + until the next lost transaction file is created. + +2 Start_Receiver_Server + Start Receiver Server + + Command syntax: + + mupip replicate -receiver -start + -listenport= + -log= [-log_interval="[integer1],[integer2]"] + [-autorollback[=verbose]] + [-buffsize=] + [-filter=] + [-noresync] + [-stopsourcefilter] + [-updateresync= + {[-resume=|-reuse=]} + [-initialize] [-cmplvl=n] + + Qualifiers: + + -receiver + + Identifies the Receiver Server. + + -listenport= + + Specifies the TCP port number the Receiver Server will listen to for + incoming connections from a Source Server. Note that the current + implementation of the Receiver Server does not support machines with + multiple IP addresses. + + -autorollback[=verbose] + + Allows the receiving instance of SI or BC replication to roll back as + required when the source instance rolls back with a mupip journal + -rollback -backward command. The optional value keyword VERBOSE allows + roll back to provide more diagnostic information. + + **Caution** + + As autorollback uses mupip online rollback under the covers, it should be + considered field test grade functionality as long as that function is + considered field test grade functionality. + + -log_interval="[integer1],[integer2]" + + integer1 specifies the number of transactions for which the Receiver + Server should wait before writing to the log file. integer2 specifies the + number of transactions for which the Update Process should wait before + writing to the log file. The default logging interval is 1000 + transactions. + + If integer1 or integer2 is 0, the logging interval is set to the default + value. + + -stopsourcefilter + + Starting the Receiver Server with -stopsourcefilter turns off any active + filter on the originating Source Server. Use this option at the time of + restarting the Receiver Server after a rolling upgrade is complete. + + -updateresync= + + -updateresync guarantees GT.M that the replicating instance was, or is, in + sync with the originating instance and it is now safe to resume + replication. Use -updateresync only in the following situations: + + o To replace an existing replication instance files when an upgrade to a + GT.M version changes the instance file format. Consult the release + notes to determine whether this applies to your upgrade. + o When an existing replication instance file is unusable because it was + damaged or deleted, and is replaced by a new replication instance + file. + o Setting up an A->P configuration for the first time if P is an + existing instance with existing updates that are not, and not expected + to be, in the originating instance. + o Setting up a new replicating instance from a backup of the originating + instance (A->P only) or one of its replicating secondary instances. + o If you are running a GT.M version prior to V5.5-000 and you have to + set up a replicating instance from a backup of an originating + instance. + + -updateresync uses the journal sequence number stored in the replicating + instance's database and the history record available in the backup copy of + the replication instance file of the originating instance + () to determine the journal sequence + number at which to start replication. + + When replication resumes after a suspension (due to network or maintenance + issues), GT.M compares the history records stored in the replication + instance file of the replicating instance with the history records stored + in the replication instance file of the originating instance to determine + the point at which to resume replication. This mechanism ensures that two + instances always remain in sync when a replication connection resumes + after an interruption. -updateresync bypasses this mechanism by ignoring + the replication history of the replicating instance and relying solely on + the current journal sequence number and its history record in the + originating instance's history to determine the point for resuming + replication. As it overrides a safety check, use -updateresync only after + careful consideration. You can check with your GT.M support channel as to + whether -updateresync is appropriate in your situation. + + To perform an updateresync, the originating instance must have at least + one history record. You need to take a backup (BACKUP -REPLINST) of the + replication instance file of the originating instance while the Source + Server is running. This ensures that the instance file has at least one + history record. Even though it is safe to use a copy (for example, an scp) + of the replication instance file of the originating instance taken after + shutting down its Source Server, BACKUP -REPLINST is recommended because + it does not require Source Server shutdown. You also need an empty + instance file (-INSTANCE_CREATE) of the replicating instance to ensure + that it bypasses the history information of the current and prior states. + + You also need use -updateresync to replace your existing replication + instance files if a GT.M version upgrade changes the instance file format. + The instance file format was changed in V5.5-000. Therefore, upgrading a + replicating instance from a version prior to GT.M V5.5-000 up to V5.5-000 + or higher requires replacing its instance file. + + Prior to V5.5-000, -updateresync did not require the argument + (). The syntax for -updateresync depends on the + GT.M version. + + -initialize + + Used when starting a Receiver Server of an SI replication stream with + -updateresync to specify that this is the first connection between the + instances. MUPIP ignores these qualifiers when starting BC replication + (that is, no updates permitted on the instance with the Receiver Server). + This qualifier provides additional protection against inadvertent errors. + + -resume= + + Used when starting a Receiver Server of an SI replication stream with + -updateresync in case the receiver instance has previously received from + the same source but had only its instance file (not database files) + recreated in between (thereby erasing all information about the source + instance and the stream number it corresponds to recorded in the receiver + instance file). In this case, the command mupip replic -receiv -start + -updateresync= -resume=, where strm_num is a number + from 1 to 15, instructs the receiver server to use the database file + headers to find out the current stream sequence number of the receiver + instance for the stream number specified as , but uses the input + instance file (specified with -updateresync) to locate the history record + corresponding to this stream sequence number and then exchange history + with the source to verify the two instances are in sync before resuming + replication. Note that in case -resume is not specified and only + -updateresync is specified for a SI replication stream, it uses the input + instance file name specified with -updateresync to determine the stream + sequence number as well as provide history records to exchange with the + source instance (and verify the two are in sync). Assuming that instance + files are never recreated (unless they are also accompanied by a database + recreate), this qualifier should not be required in normal usage + situations. + + -reuse= + + Used when starting a Receiver Server of an SI replication stream with + -updateresync in case the receiver instance has previously received from + fifteen (all architecturally allowed) different externally sourced streams + and is now starting to receive from yet another source stream. The command + mupip replic -receiv -start -updateresync= -reuse=, + where instname is the name of a replication instance, instructs the + receiver server to look for an existing stream in the replication instance + file header whose Group Instance Name (displayed by a mupip replic + -editinstance -show command on the receiver replication instance file) + matches the instance name specified and if one does, reuse that stream + number for the current source connection (erasing any record of the older + Group using the same stream number). + + -noresync + + Instructs the Receiver Server to accept a SI replication stream even when + the receiver is ahead of the source. In this case, the source and receiver + servers exchange history records from the replication instance file to + determine the common journal stream sequence number and replication + resumes from that point onwards. Specifying -noresync on a BC replication + stream is produces a NORESYNCSUPPLONLY error. Specifying -noresync on a SI + replication stream receiver server where the receiving instance was + started with -UPDNOTOK (updates are disabled) produces a + NORESYNCUPDATERONLY error. Note also that the noresync qualifier is not + the opposite of the resync qualifier of rollback (mupip journal -rollback + -resync), which is intended for use under the direction of FIS GT.M + support. + +2 Start_Update_Process + Start Update Process + + The following command starts the Update Process only, if it has been + shutdown independent of the Receiver Server. + + Command syntax: + + mupip replicate -receiver -start {-updateonly|-helpers[=m[,n]] + + Qualifiers: + + -updateonly + + If the Update Process has been shutdown independent of the Receiver + Server, use this qualifier to restart the Update Process. + + -helpers[=m[,n]] + + Starts additional processes to help improve the rate at which updates from + an incoming replication stream are applied on a replicating instance. + + o m is the total number of helper processes and n is the number of + reader helper processes, in other words m>=n. + o Helper processes can start only on a receiver server. + o If helper processes are already running, specifying -helpers[=m[,n]] + again starts additional helper processes. There can be a maximum of + 128 helper processes for a receiver server. + o If -helpers=0[,n] is specified, GT.M starts no helper processes. + o With the HELPERS qualifier specified but neither m nor n specified, + GT.M starts the default number of helper processes with the default + proportion of roles. The default number of aggregate helper processes + is 8, of which 5 are reader helpers and 3 writers. + o With only m specified, helper processes are started of which + floor(5*m/8) processes are reader helpers. + o With both m and n specified, GT.M starts m helper processes of which n + are reader helpers and m-n are writers. If m/cmdline on platforms that implement a /proc filesystem) as + mupip replicate -updhelper -reader and mupip replicate -updhelper + -writer. + + Example: + + $ mupip replicate -receiver -start -listenport=1234 -helpers -log=B2C.log -buffsize=$recpool_size + + This command starts the Receiver Server with Helper Processes. The + following sample output from the ps command shows that there are 5 reader + processes and 3 writer processes. + + gtmuser1 11943 1 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -receiver -start + -listenport=1234 -helpers -log=B2C.log -buff=$rec_pool_size + gtmuser1 11944 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updateproc + gtmuser1 11945 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader + gtmuser1 11946 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader + gtmuser1 11947 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader + gtmuser1 11948 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader + gtmuser1 11949 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader + gtmuser1 11950 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer + gtmuser1 11951 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer + gtmuser1 11952 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer + +2 Stop_Update_Process + Stop Update Process + + Command syntax: + + mupip replicate -receiver -shutdown [-updateonly|-helpers] [-timeout=] + + Qualifiers: + + -updateonly + + Use this qualifier to stop only the Update Process. If neither -updateonly + nor -helper are specified, the Update Process, all helper processes (if + any), and Receiver Server shut down. + + -helper + + Shuts down only the Helper Processes and leaves the Receiver Server and + Update Process to continue operating as before. All helpers processes shut + down even if -helper values are specified. + + -timeout + + Specifies the period of time (in seconds) the Receiver Server should wait + before shutting down. If you do not specify -timeout, the default timeout + period is 30 seconds. If you specify -timeout=0, shutdown occurs + immediately. + + Example: + + $ mupip replicate -receiver -shutdown -helper + + This example shuts down only the helper processes of the current Receiver + Server. Note that all helpers processes shut down even if HELPER values + are specified. + +2 Check_Receiver_Health + Check Receiver Health + + Use the following command to determine whether the Receiver Server is + running. + + Command syntax: + + mupip replicate -receiver -checkhealth + +2 Change_Receiver_log + Change Receiver log + + Command syntax: + + mupip replicate -receiver -changelog -log= [-log_interval="[integer1],[integer2]"] + + -log_interval="[integer1],[integer2]" + + integer1 specifies the number of transactions for which the Receiver + Server should wait before writing to the log file. integer2 specifies the + number of transactions for which the Update Process should wait before + writing to the log file. The default logging interval is 1000 + transactions. + + If integer1 or integer2 is 0, the logging interval reverts to the prior + value. + +2 Receiver_logging + Receiver logging + + Command syntax: + + mupip replicate -receiver -statslog={ON|OFF} + [-log_interval="[integer1],[integer2]"] + + -log_interval="[integer1],[integer2]" + + integer1 specifies the number of transactions for which the Receiver + Server should wait before writing to the log file. integer2 specifies the + number of transactions for which the Update Process should wait before + writing to the log file. The default logging interval is 1000 + transactions. + + If integer1 or integer2 is 0, the logging interval reverts to the prior + value. + +2 Receiver_backlog + Receiver backlog + + Command syntax: + + mupip replicate -receiver -showbacklog + + Qualifiers: + + -showbacklog + + Use this qualifier to report the current backlog (that is, the difference + between the last JNL_SEQNO written to the Receive Pool and the last + JNLSEQNO processed by the Update Process) of journal records on the + Receiver Server. + +2 Rollback_Database + Rollback Database + + Command syntax: + + mupip journal -rollback + {[-fetchresync=|-resync=] + [-rsync_strm=]} + -losttrans= -backward * + + Qualifiers: + + -rollback + + Use this qualifier to rollback the database. If you do not use the + -fetchresync qualifier, the database rolls back to the last consistent + state. + + -fetchresync= + + The is the communication port number that the rollback + command uses when fetching the reference point. Always use the same on the originating instance for rollback as the one used by the + Receiver Server. + + **Important** + + FIS recommends you to unconditionally script the mupip journal -rollback + -fetchresync command prior to starting any Source Server on the + replicating instance to avoid a possible out-of-sync situation. + + The reference point sent by the originating instance is the RESYNC_SEQNO + (explained later) that the originating instance once maintained. The + database/journal files are rolled back to the earlier RESYNC_SEQNO (that + is, the one received from originating instance or the one maintained + locally). If you do not use -fetchresync, the database rolls back to the + last consistent replicating instance state. + + The system stores extracted lost transactions in the file + specified by this mandatory qualifier. The starting point for the search + for lost transactions is the JNL_SEQNO obtained from the originating + instance in the -fetchresync operation. If -fetchresync is not specified, + lists the post-consistent-state transactions that were + undone by the rollback procedure to reach a consistent state. + + **Note** + + The extracted lost transactions list may contain broken transactions due + to system failures that occurred during processing. Do not resolve these + transactions-they are not considered to be committed. + + **Caution** + + The database header may get corrupted if you suspend an ongoing ROLLBACK + -FETECHRESYNC operation or if the TCP connection between the two instances + gets broken. The workaround is to restart the ROLLBACK -FETCHRESYNC + operation or wait 60 seconds for the FETCHRESYNC operation to timeout. + + Example: + + $ mupip journal -rollback -fetchresync=2299 -losttrans="glo.lost" -backward * + + This command performs a ROLLBACK -FETCHRESYNC operation on a replicating + instance to bring it to a common synchronization point from where the + originating instance can begin to transmit updates to allow it to catch + up. It also generates a lost transaction file glo.lost of all those + transactions that are present on the replicating instance but not on the + originating instance at port 2299. + + -resync= + + Use this qualifier to roll back to the transaction identified by JNL_SEQNO + (in decimal) only when the database/ journal files need to be rolled back + to a specific point. If you specify a JNL_SEQNO that is greater than the + last consistent state, the database/journal files will be rolled back to + the last consistent state. Under normal operating conditions, you would + not need this qualifier. + + -losttrans= + + If failover occurs (that is, originating instance fails and replicating + instance assumes the originating instance role), some transactions + committed to A's database may not be reflected in B's database. Before the + former originating instance becomes the new replicating instance, these + transactions must be rolled off before it can assume the role of an + originating instance. These transactions are known as "lost transactions". + + The system stores extracted lost transactions in the file + specified by this mandatory qualifier. The starting point for the search + for lost transactions is the JNL_SEQNO obtained from the originating + instance in the -fetchresync operation. If -fetchresync is not specified, + lists the post-consistent-state transactions that were + undone by the rollback procedure to reach a consistent state. + + **Note** + + The extracted lost transactions list may contain broken transactions due + to system failures that occurred during processing. Do not resolve these + transactions-they are not considered to be committed. + + -rsync_strm= + + Used when starting a rollback command with the -resync qualifier. The + command mupip journal -rollback -resync= + -rsync_strm= instructs rollback to roll back the database to a + sequence number specified with the -resync= qualifier but + that is a journal stream sequence number (not a journal + sequence number) corresponding to the stream number which can + be any value from 0 to 15. Note that like the -resync qualifier, the + -rsync_strm qualifier is also intended for use under the direction of your + GT.M support channel. + +1 Summary + Summary + + +------------------------------------------------------------------------------+ + | COMMAND | OBJECTS | MAIN QUALIFIER | + |-------------+----------------+-----------------------------------------------| + | | |-BK[UPDBJNL]=DISABLE | OFF | + | | |-B[YTESTREAM] -NET[TIMEOUT]=seconds | + | | |-C[OMPREHENSIVE] | + | | |-DA[TABASE] -REPLA[CE] | + | | |-DBG | + | | |-I[NCREMENTAL] | + | |region-name |-[NO]J[OURNAL][=journal-options-list] | + |B[ACKUP] | | | + | |file-name |-NETTIMEOUT | + | | |-[NO]NEWJNLFILES[=[NO]PREVLINK],[NO]S[YNC_IO] | + | | |-O[NLINE] | + | | |-RECORD | + | | |-REPLI[NSTANCE]=OFF | ON | + | | |-S[INCE]={DATABASE|BYTESTREAM|RECORD} | + | | |-T[RANSACTION=hexa;transaction_number] | + |-------------+----------------+-----------------------------------------------| + |CR[EATE] |- |-R[EGION]=region-name | + |-------------+----------------+-----------------------------------------------| + | | |-OUTDB= | + |EN[DIANCVT] |file-name | | + | | |-OV[ERRIDE] | + |-------------+----------------+-----------------------------------------------| + |EXI[T] |- |- | + |-------------+----------------+-----------------------------------------------| + |EXTE[ND] |region-name |-B[LOCKS]=blocks | + |-------------+----------------+-----------------------------------------------| + | | |-FO[RMAT]=GO|B[INARY]|Z[WR] | + | | |-FR[EEZE] | + | | |-LA[BEL]=text | + |EXTR[ACT] |- | | + | | |-[NO]L[OG] | + | | |-S[ELECT]=global-name-list | + | | |-O[CHSET]=character-set | + |-------------+----------------+-----------------------------------------------| + | | |-DBG | + | | |-OF[F] | + |F[REEZE] |region-list | | + | | |-OV[ERRIDE] | + | | |-ON[-R[ECORD]] | + |-------------+----------------+-----------------------------------------------| + | | |-D[B] | + |FT[OK] |File-name |-J[NLPOOL] | + | | |-R[ECVPOOL] | + |-------------+----------------+-----------------------------------------------| + |H[ELP] |command-option |- | + |-------------+----------------+-----------------------------------------------| + | | |-A[DJACENCY]=integer] | + | | |-BL[OCK]=hexa;block-number] | + | | |-BR[IEF] | + | | |-FA[ST] | + | | |-FI[LE] | + | | |-FU[LL] | + | |File-name or | | + |I[NTEG] |region-list |-NO]K[EYRANGES | + | | |-[NO][MAP]=integer | + | | |-[NO]MAXK[EYSIZE]=integer | + | | |-R[EGION] | + | | |-S[UBSCRIPT]=subscript | + | | |-TN[_RESET] | + | | |-[NO]TR[ANSACTION][=integer] | + |-------------+----------------+-----------------------------------------------| + | | |-EX[TRACT][=file-specification|-stdout] | + | | |-REC[OVER] | -RO[LLBACK] | + |J[OURNAL] |file-name |-SH[OW][=show-option-list] | + | | |-[NO]V[ERIFY] | + | | |-BA[CKWARD] | -FO[RWARD] | + |-------------+----------------+-----------------------------------------------| + | | |-BE[GIN]=integer | + | | |-BLOCK_DENSITY | + | | |-E[ND]=integer | + |L[OAD] |file-name | | + | | |-FI[LLFACTOR]=integer | + | | |-FO[RMAT]=GO|B[INARY]|Z[WR] | + | | |-S[TDIN] | + |-------------+----------------+-----------------------------------------------| + | | |-DOWNGRADE | + | | |-E[XCLUDE]=global-name-list | + | | |-FI[LL_FACTOR]=integer | + | | |-I[NDEX_FILL_FACTOR]=integer | + | | |-REG[ION] | + | | |-RES[UME] | + |REO[RG] | |-SA[FEJNL] | + | | |-S[ELECT]=global-name-list | + | | |-STA[RTBLK]=hexa | + | | |-STO[PBLK]=hexa | + | | |-T[RUNCATE][=percentage] | + | | |-UP[GRAD E] | + | | |-USER_DEFINED_REORG=reorg_list | + |-------------+----------------+-----------------------------------------------| + | | |-E[DITINSTANCE] | + | | |-I[NSTANCE_CREATE] | + | | |-R[ECEIVER | + |REP[LICATE] |file-name | | + | | |-S[OURCE] | + | | |-UPDA[TEPROC] | + | | |-UPDH[ELPER] | + |-------------+----------------+-----------------------------------------------| + |RE[STORE] |file-name or |-[NO]E[XTEND] | + | |file-list | | + |-------------+----------------+-----------------------------------------------| + | |file-name or |-F[ILE] | + |RU[NDOWN] |region-name | | + | | |-R[EGION] | + |-------------+----------------+-----------------------------------------------| + | | |-A[CCESS_METHOD=BG|MM] | + | | |-B[YPASS] | + | | |-DB[FILENAME]=database_file | + | | |-DE[FER_TIME]=seconds | + | | |-E[XTENSION_COUNT]=integer(no of blocks) | + | | |-FILE | + | | |-F[LUSH_TIME]= integer | + | | |-G[LOBAL_BUFFERS]=integer | + | | |-JN[LFILE] | + | |file-name or |-JO[URNAL]=journal-option-list | + |SE[T] |region-name | | + | | |-L[OCK_SPACE]=integer | + | | |-PA[RTIAL_RECOV_BYPASS] | + | | |-PR[EVJNLFILE]=jnl_file_name | + | | |-RE[GION] | + | | |-REPLI[CATION]=ON|OFF | + | | |-REPL_[STATE]=ON|OFF | + | | |-RES[ERVED_BYTES]=integer | + | | |-S[TANDALONENOT] | + | | |-V[ERSION]=V4|V5 | + | | |-W[AIT_DISK]=integer | + |-------------+----------------+-----------------------------------------------| + |ST[OP] |process-id |process-id | + |-------------+----------------+-----------------------------------------------| + |UP[GRADE] |- |- | + +------------------------------------------------------------------------------+ + + +------------------------------------------------------------------------------------------------------------+ + | Main Qualifier | MUPIP Command | Options/Qualifiers | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-CHANGE | + | | |-DETAIL | + | | |-OFFSET=hexa | + |-EDITINSTANCE |REPLICATE | | + | | |-VALUE=hexa | + | | |-SIZE=hexa | + | | |-VALUE=hexa | + |--------------------------------------+--------------------------+------------------------------------------| + | | |ALWAYS | + |-FENCES= |JOURNAL-RECOVER-ROLLBACK |NONE | + | | |PROCESS | + |--------------------------------------+--------------------------+------------------------------------------| + | | |ALIGNSIZE=integer | + | | |ALLOCATION=integer | + | | |AUTOSWITCHLIMIT=integer | + | | |BEFORE_IMAGES | + | | |BUFFER_SIZE=integer | + | | |DISABLE | + | |BACKUP |ENABLE | + |-JOURNAL= | | | + | |SET |EPOCH_INTERVAL=integer | + | | |EXTENSION=integer | + | | |FILENAME=file_name | + | | |OFF | + | | |ON | + | | |SYNC_IO | + | | |YIELD_LIMIT=integer | + |--------------------------------------+--------------------------+------------------------------------------| + | |-RECOVER |TIME="time" | + |-LOOKBACK_LIMIT=lookback-option-list | | | + | |-ROLLBACK |OPERATIONS=integer | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-BUFFSIZE=integer | + | | |-CHANGELOG | + | | |-CHECKHEALTH | + | | |-CMPLVL=integer | + | | |-FILTER=filter_name | + | | |-he[lpers]=[m[,n]] | + | | |-LISTENPORT=integer | + | | |-LOG=logfile | + |-RECEIVER |REPLICATE |-LOG_INTERVAL=integer | + | | |-SHOWBACKLOG | + | | |-SHUTDOWN | + | | |-START | + | | |-STATSLOG=[ON|OFF] | + | | |-STOPSOURCEFILTER | + | | |TIMEOUT=seconds | + | | |-UPDATEONLY | + | | |-UPDATERESYNC | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-AFTER=time | + | | |-APPLY_AFTER_IMAGE | + | | |-BACKWARD | + | | |-BEFORE=time | + | | |-BROKENTRANS=file | + | | |-CHAIN | + | | |-CHECKTN | + | | |-[NO]ER[ROR_LIMIT][=integer] | + | | |-FENCES=fence-option-list | + | | |-FORWARD | + |-RECOVER |JOURNAL | | + | | |-FULL | + | | |-GLOBAL= | + | | |-ID= | + | | |-INTERACTIVE | + | | |-LOOKBACK_LIMIT= | + | | |-LOSTTRANS[=file] | + | | |-RED[IRECT]=file-pair-list | + | | |-SINCE=time | + | | |-VERBOSE | + | | |-VERIFY | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-AFTER=time | + | | |-BEFORE=time | + | | |-BROKENTRANS=file | + | | |-CHAIN | + | | |-CHECKTN | + | | |-[NO]ER[ROR_LIMIT]=integer] | + | | |-FENCES=fence-option-list | + | | |-FULL | + |-EXTRACT |JOURNAL | | + | | |-GLOBAL= | + | | |-ID= | + | | |-INTERACTIVE | + | | |-LOOKBACK_LIMIT= | + | | |-LOSTTRANS[=file] | + | | |-SINCE=time | + | | |-VERBOSE | + | | |-VERIFY | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-APPLY_AFTER_IMAGE | + | | |-BACKWARD | + | | |-BEFORE=time | + | | |-BROKENTRANS=file | + | | |-[NO]ER[ROR_LIMIT][=integer] | + | | |-FENCES=fence-option-list | + |-ROLLBACK |JOURNAL | | + | | |-FETCHRESYNC | + | | |-LOOKBACK_LIMIT= | + | | |-LOSTTRANS[=file] | + | | |-RES[YNC]=hexa;journal_sequence_number | + | | |-VERBOSE | + | | |-VERIFY | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-ACTIVE_PROCESSES | + | | |-ALL | + | | |-BROKEN_TRANSACTIONS | + | | |-HEADER | + | | |-PROCESSES | + | | |-STATISTICS | + |-SHOW= |JOURNAL |-AFTER=time | + | | |-USER=user-list | + | | |-TRANSACTION=[KILL|SET] | + | | |-INTERACTIVE | + | | |-GLOBAL= | + | | |-ID= | + | | |-INTERACTIVE | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-BYTESTREAM | + | | |-COMPREHENSIVE | + |-SINCE |BACKUP |-DATABASE | + | | |-INCREMENTAL | + | | |-RECORD | + |--------------------------------------+--------------------------+------------------------------------------| + | | |-ACTIVATE | + | | |-BUFFSIZE=Buffer_size | + | | |-CHANGELOG | + | | |-CHECKHEALTH | + | | |-CMPLVL=integer | + | | |-CONNECTPARAMS=connection_options | + | | |-DEACTIVATE | + | | |-DETAIL | + | | |-FILTER=filter_name | + | | |-INSTSECONDARY=secondary_instance name | + | | |-JNLPOOL-LOG=log_file | + | | |-LOG_INTERVAL=integer | + |-SO[URCE] |REPLICATE | | + | | |-LOSTTNCOMPLETE | + | | |-NEEDRESTART | + | | |-PASSIVE | + | | |-PROPAGATEPRIMARY | + | | |-ROOTPRIMARY | + | | |-SECONDARY=secondary_instance_name | + | | |-SHOWBACKLOG | + | | |-SHUTDOWN | + | | |-START | + | | |-STATSLOG | + | | |-STOPSOURCEFILTER | + | | |-TIMEOUT=seconds | + +------------------------------------------------------------------------------------------------------------+ diff --git a/sr_port/mupip_backup.c b/sr_port/mupip_backup.c index 33da5ef..eb7bbcb 100644 --- a/sr_port/mupip_backup.c +++ b/sr_port/mupip_backup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,7 +11,7 @@ #include "mdef.h" -#if defined(UNIX) +#ifdef UNIX # include "gtm_fcntl.h" # include "gtm_stat.h" # include "gtm_unistd.h" @@ -57,7 +57,7 @@ #include "lockconst.h" #include "sleep_cnt.h" -#if defined(UNIX) +#ifdef UNIX #include "eintr_wrappers.h" #include "gtmio.h" /* for OPENFILE macro */ #include "repl_sp.h" /* for F_CLOSE macro */ @@ -99,7 +99,7 @@ #include "gtm_sem.h" #endif -#if defined(UNIX) +#ifdef UNIX # define PATH_DELIM '/' #elif defined(VMS) # define PATH_DELIM ']' @@ -139,15 +139,19 @@ GBLREF char *jnl_state_lit[]; GBLREF char *repl_state_lit[]; GBLREF jnl_gbls_t jgbl; GBLREF void (*call_on_signal)(); +GBLREF gd_addr *gd_header; #ifdef DEBUG GBLREF int process_exiting; /* Process is on it's way out */ #endif #ifdef UNIX -GBLREF backup_reg_list *mu_repl_inst_reg_list; -GBLREF jnlpool_addrs jnlpool; -GBLREF uint4 mutex_per_process_init_pid; -GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +GBLREF boolean_t jnlpool_init_needed; +GBLREF backup_reg_list *mu_repl_inst_reg_list; +GBLREF jnlpool_addrs jnlpool; +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +GBLREF uint4 mutex_per_process_init_pid; +GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +GBLREF boolean_t pool_init; #endif LITREF char gtm_release_name[]; @@ -155,6 +159,7 @@ LITREF int4 gtm_release_name_len; error_def(ERR_BACKUPCTRL); error_def(ERR_BACKUPKILLIP); +error_def(ERR_BKUPRUNNING); error_def(ERR_DBCCERR); error_def(ERR_DBFILERR); error_def(ERR_DBRDONLY); @@ -185,6 +190,7 @@ error_def(ERR_REPLSTATE); error_def(ERR_REPLSTATEERR); error_def(ERR_SYSCALL); error_def(ERR_TEXT); +ZOS_ONLY(error_def(ERR_BADTAG);) static char * const jnl_parms[] = { @@ -242,7 +248,6 @@ void mupip_backup(void) trans_num tn; shmpool_buff_hdr_ptr_t sbufh_p; shmpool_blk_hdr_ptr_t sblkh_p, next_sblkh_p; - static boolean_t once = TRUE; backup_reg_list *rptr, *rrptr, *nocritrptr; boolean_t inc_since_inc , inc_since_rec, result, newjnlfiles, tn_specified, replication_on, newjnlfiles_specified, keep_prev_link, bkdbjnl_disable_specified, @@ -262,27 +267,16 @@ void mupip_backup(void) jnl_tm_t save_gbl_jrec_time; gd_region *r_save, *reg; int sync_io_status; - boolean_t sync_io, sync_io_specified, wait_for_zero_kip; -#if defined(VMS) - struct FAB temp_fab; - struct NAM temp_nam; - struct XABPRO temp_xabpro; - short iosb[4]; - char def_jnl_fn[MAX_FN_LEN]; - GDS_INFO *gds_info; - char exp_file_name[MAX_FN_LEN]; - uint4 exp_file_name_len; - boolean_t gotit; - unsigned short ntries; -#elif defined(UNIX) + boolean_t sync_io, sync_io_specified, wait_for_zero_kip, decr_cnt; +# ifdef UNIX struct stat stat_buf; int fstat_res, fclose_res, tmpfd; gd_segment *seg; - char instfilename[MAX_FN_LEN + 1], *errptr, machine_name[MAX_MCNAMELEN]; + char instfilename[MAX_FN_LEN + 1], *errptr, scndry_msg[OUT_BUFF_SIZE]; unsigned int full_len; unix_db_info *udi; sgmnt_addrs *csa; - repl_inst_hdr repl_instance; + repl_inst_hdr repl_instance, *inst_hdr, *save_inst_hdr; unsigned char *cmdptr, command[MAX_FN_LEN * 2 + 5]; /* 5 == SIZEOF("cp") + 2 (space) + 1 (NULL) */ struct shmid_ds shm_buf; struct semid_ds semstat; @@ -293,19 +287,27 @@ void mupip_backup(void) int group_id; int perm; struct perm_diag_data pdd; -#else -# error UNSUPPORTED PLATFORM -#endif + pid_t *kip_pids_arr_ptr; +# elif defined(VMS) + struct FAB temp_fab; + struct NAM temp_nam; + struct XABPRO temp_xabpro; + short iosb[4]; + char def_jnl_fn[MAX_FN_LEN]; + GDS_INFO *gds_info; + char exp_file_name[MAX_FN_LEN]; + uint4 exp_file_name_len; + boolean_t gotit; + unsigned short ntries; +# else +# error UNSUPPORTED PLATFORM +# endif seq_num jnl_seqno; now_t now; /* for GET_CUR_TIME macro */ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */ ZOS_ONLY(int realfiletag;) - uint4 *kip_pids_arr_ptr; - - ZOS_ONLY(error_def(ERR_BADTAG);) /* ==================================== STEP 1. Initialization ======================================= */ - backup_started = backup_interrupted = FALSE; ret = SS_NORMAL; jnl_str_ptr = &jnl_str[0]; @@ -314,22 +316,15 @@ void mupip_backup(void) inc_since_inc = inc_since_rec = file_backed_up = error_mupip = FALSE; debug_mupip = (CLI_PRESENT == cli_present("DBG")); call_on_signal = mupip_backup_call_on_signal; - mu_outofband_setup(); jnl_status = 0; - if (once) - { + if (NULL == gd_header) gvinit(); - once = FALSE; - } - /* ============================ STEP 2. Parse and construct grlist ================================== */ - tn_specified = FALSE; if (incremental = (CLI_PRESENT == cli_present("INCREMENTAL") || CLI_PRESENT == cli_present("BYTESTREAM"))) { trans_num temp_tn; - if (0 == cli_get_hex64("TRANSACTION", &temp_tn)) { temp_tn = 0; @@ -381,7 +376,6 @@ void mupip_backup(void) replication_on = FALSE; if (CLI_PRESENT == cli_present("REPLICATION.ON")) /* REPLICATION.OFF is disabled at the CLI layer */ replication_on = TRUE; - bkdbjnl_disable_specified = FALSE; bkdbjnl_off_specified = FALSE; if (CLI_PRESENT == cli_present("BKUPDBJNL")) @@ -441,7 +435,7 @@ void mupip_backup(void) if (mu_ctrly_occurred || mu_ctrlc_occurred) { mubclnup(NULL, need_to_free_space); - gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL); mupip_exit(ERR_MUNOFINISH); } # ifdef UNIX @@ -456,12 +450,13 @@ void mupip_backup(void) { /* make sure backup files do not already exist */ if (FILE_PRESENT == (fstat_res = gtm_file_stat(replinstfile, NULL, NULL, FALSE, &ustatus))) { - gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, LEN_AND_STR((char *)replinstfile->addr)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILEEXISTS, 2, + LEN_AND_STR((char *)replinstfile->addr)); error_mupip = TRUE; } else if (FILE_STAT_ERROR == fstat_res) { /* stat doesn't usually return with an error. Assert so we can analyze */ assert(FALSE); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus); error_mupip = TRUE; } } @@ -487,7 +482,7 @@ void mupip_backup(void) { /* make sure that backup won't be overwriting the database file itself */ if (TRUE == is_file_identical(file->addr, (char *)rptr->reg->dyn.addr->fname)) { - gtm_putmsg(VARLSTCNT(4) ERR_MUSELFBKUP, 2, DB_LEN_STR(rptr->reg)); + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(4) ERR_MUSELFBKUP, 2, DB_LEN_STR(rptr->reg)); error_mupip = TRUE; } # ifdef UNIX @@ -495,12 +490,14 @@ void mupip_backup(void) { /* make sure backup files do not already exist */ if (FILE_PRESENT == (fstat_res = gtm_file_stat(file, NULL, NULL, FALSE, &ustatus))) { - gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, LEN_AND_STR((char *)file->addr)); + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(4) ERR_FILEEXISTS, 2, + LEN_AND_STR((char *)file->addr)); error_mupip = TRUE; } else if (FILE_STAT_ERROR == fstat_res) { /* stat doesn't usually return with an error. Assert so we can analyze */ assert(FALSE); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus); + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("stat"), CALLFROM, ustatus); error_mupip = TRUE; } } @@ -519,7 +516,7 @@ void mupip_backup(void) } } else if (!incremental) { /* non-incremental backups to "exec" and "tcp" are not supported*/ - gtm_putmsg(VARLSTCNT(1) ERR_NOTRNDMACC); + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(1) ERR_NOTRNDMACC); error_mupip = TRUE; } } @@ -533,7 +530,6 @@ void mupip_backup(void) mubmaxblk = 0; halt_ptr = grlist; size = ROUND_UP(SIZEOF_FILE_HDR_MAX, DISK_BLOCK_SIZE); - ESTABLISH(mu_freeze_ch); tempfilename = tempdir_full.addr = tempdir_full_buffer; if (TRUE == online) @@ -558,7 +554,7 @@ void mupip_backup(void) tempdir_trans_len = tempdir_trans.len; } else tempdir_trans_len = 0; - + UNIX_ONLY(jnlpool_init_needed = TRUE); for (rptr = (backup_reg_list *)(grlist); NULL != rptr; rptr = rptr->fPtr) { /* restore the original length since we are looping thru regions */ tempdir_trans.len = tempdir_trans_len; @@ -589,21 +585,21 @@ void mupip_backup(void) TP_CHANGE_REG(gv_cur_region); if (gv_cur_region->read_only) { - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); rptr->not_this_time = give_up_before_create_tempfile; continue; } /* Used to have MAX_RMS_RECORDSIZE here (instead of 32 * 1024) but this def does not exist on - UNIX where we are making the same restirction due to lack of testing more than anything else - so the hard coded value will do for now. SE 5/2005 - */ + * UNIX where we are making the same restirction due to lack of testing more than anything else + * so the hard coded value will do for now. SE 5/2005 + */ if (incremental && ((32 * 1024) - SIZEOF(shmpool_blk_hdr)) < cs_data->blk_size) { /* Limitation: VMS RMS IO limited to 32K - 1 VMS blk so we likewise limit our IO. This can be - overcome with more code to deal with the larger block sizes much like the regular - backup does but this is not being done as part of this (64bittn) project. SE 2/2005 - */ - gtm_putmsg(VARLSTCNT(5) MAKE_MSG_TYPE(ERR_MUNOSTRMBKUP, ERROR), 3, DB_LEN_STR(gv_cur_region), - 32 * 1024 - DISK_BLOCK_SIZE); + * overcome with more code to deal with the larger block sizes much like the regular + * backup does but this is not being done as part of this (64bittn) project. SE 2/2005 + */ + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) MAKE_MSG_TYPE(ERR_MUNOSTRMBKUP, ERROR), 3, + DB_LEN_STR(gv_cur_region), 32 * 1024 - DISK_BLOCK_SIZE); rptr->not_this_time = give_up_before_create_tempfile; continue; } @@ -613,7 +609,6 @@ void mupip_backup(void) memset(tempnam_prefix, 0, MAX_FN_LEN); memcpy(tempnam_prefix, gv_cur_region->rname, gv_cur_region->rname_len); SPRINTF(&tempnam_prefix[gv_cur_region->rname_len], "_%x", process_id); - if ((SS_NORMAL == trans_log_name_status) && (NULL != tempdir_trans.addr) && (0 != tempdir_trans.len)) *(tempdir_trans.addr + tempdir_trans.len) = 0; @@ -635,7 +630,7 @@ void mupip_backup(void) (tempdir_trans.len = INTCAST(ptr - rptr->backup_file.addr + 1))); tempdir_trans_buffer[tempdir_trans.len] = '\0'; } else -#if defined(UNIX) +# ifdef UNIX { tempdir_trans_buffer[0] = '.'; tempdir_trans_buffer[1] = '\0'; @@ -645,7 +640,8 @@ void mupip_backup(void) /* verify the accessibility of the tempdir */ if (FILE_STAT_ERROR == (fstat_res = gtm_file_stat(&tempdir_trans, NULL, &tempdir_full, FALSE, &ustatus))) { - gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, tempdir_trans.len, tempdir_trans.addr, ustatus); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2, tempdir_trans.len, + tempdir_trans.addr, ustatus); mubclnup(rptr, need_to_del_tempfile); mupip_exit(ustatus); } @@ -663,15 +659,16 @@ void mupip_backup(void) } else util_out_print("!/Cannot create the temporary file in directory !AD for online backup", TRUE, tempdir_trans.len, tempdir_trans.addr); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status); + error_condition = status; util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE); mubclnup(rptr, need_to_del_tempfile); mupip_exit(status); } -#ifdef __MVS__ +# ifdef __MVS__ if (-1 == gtm_zos_set_tag(rptr->backup_fd, TAG_BINARY, TAG_NOTTEXT, TAG_FORCE, &realfiletag)) TAG_POLICY_GTM_PUTMSG(tempfilename, realfiletag, TAG_BINARY, errno); -#endif +# endif /* Temporary file for backup was created above using "mkstemp" which on AIX opens the file without * large file support enabled. Work around that by closing the file descriptor returned and reopening * the file with the "open" system call (which gets correctly translated to "open64"). We need to do @@ -684,7 +681,8 @@ void mupip_backup(void) { status = errno; util_out_print("!/Error re-opening temporary file created by mkstemp()!/", TRUE); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status); + error_condition = status; util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE); mubclnup(rptr, need_to_del_tempfile); mupip_exit(status); @@ -692,10 +690,10 @@ void mupip_backup(void) /* Now that the temporary file has been opened successfully, close the fd returned by mkstemp */ F_CLOSE(tmpfd, fclose_res); /* resets "tmpfd" to FD_INVALID */ tempdir_full.len = STRLEN(tempdir_full.addr); /* update the length */ -#ifdef __MVS__ +# ifdef __MVS__ if (-1 == gtm_zos_tag_to_policy(rptr->backup_fd, TAG_BINARY, &realfiletag)) TAG_POLICY_GTM_PUTMSG(tempfilename, realfiletag, TAG_BINARY, errno); -#endif +# endif if (debug_mupip) util_out_print("!/MUPIP INFO: Temp file name: !AD", TRUE,tempdir_full.len, tempdir_full.addr); memcpy(&rptr->backup_tempfile[0], tempdir_full.addr, tempdir_full.len); @@ -705,12 +703,12 @@ void mupip_backup(void) if (-1 != fstat_res) if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0) { - send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"), RTS_ERROR_STRING( ((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn), PERMGENDIAG_ARGS(pdd)); - gtm_putmsg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"), RTS_ERROR_STRING( ((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn), @@ -725,29 +723,27 @@ void mupip_backup(void) || ((-1 != group_id) && (-1 == fchown(rptr->backup_fd, -1, group_id)))) { status = errno; - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status); + error_condition = status; util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE); mubclnup(rptr, need_to_del_tempfile); mupip_exit(status); } -#elif defined(VMS) +# elif defined(VMS) assert(FALSE); } - temp_xabpro = cc$rms_xabpro; temp_xabpro.xab$w_pro = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->xabpro->xab$w_pro & (~((XAB$M_NODEL << XAB$V_SYS) | (XAB$M_NODEL << XAB$V_OWN))); temp_nam = cc$rms_nam; temp_nam.nam$l_rsa = rptr->backup_tempfile; temp_nam.nam$b_rss = SIZEOF(rptr->backup_tempfile) - 1; /* temp solution, note it is a byte value */ - temp_fab = cc$rms_fab; temp_fab.fab$l_nam = &temp_nam; temp_fab.fab$l_xab = &temp_xabpro; temp_fab.fab$b_org = FAB$C_SEQ; temp_fab.fab$l_fop = FAB$M_MXV | FAB$M_CBT | FAB$M_TEF | FAB$M_CIF; temp_fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO | FAB$M_TRN; - gtm_tempnam(tempdir_trans.addr, tempnam_prefix, tempfilename); temp_file_name_len = exp_file_name_len = strlen(tempfilename); memcpy(exp_file_name, tempfilename, temp_file_name_len); @@ -756,16 +752,14 @@ void mupip_backup(void) { util_out_print("!/Unable to resolve concealed definition for file !AD ", TRUE, temp_file_name_len, tempfilename); - gtm_putmsg(VARLSTCNT(1) ustatus); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ustatus); mubclnup(rptr, need_to_del_tempfile); mupip_exit(ERR_MUNOACTION); } if (debug_mupip) util_out_print("!/MUPIP INFO: Temp file name: !AD", TRUE, exp_file_name_len, exp_file_name); - temp_fab.fab$l_fna = exp_file_name; temp_fab.fab$b_fns = exp_file_name_len; - ntries = 0; gotit = FALSE; while (TRUE != gotit) @@ -781,26 +775,26 @@ void mupip_backup(void) sys$close(&temp_fab); ntries++; gtm_tempnam(tempdir_trans.addr, tempnam_prefix, tempfilename); - temp_fab.fab$l_fna = tempfilename; - temp_fab.fab$b_fns = strlen(tempfilename); - break; - default: + temp_fab.fab$l_fna = tempfilename; + temp_fab.fab$b_fns = strlen(tempfilename); + break; + default: error_mupip = TRUE; - } + } if (error_mupip || (ntries > MAX_TEMP_OPEN_TRY)) { util_out_print("!/Cannot create the temporary file !AD for online backup.", TRUE, LEN_AND_STR(tempfilename)); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status); mubclnup(rptr, need_to_del_tempfile); - mupip_exit(ERR_MUNOACTION); + mupip_exit(ERR_MUNOACTION); } } rptr->backup_tempfile[temp_nam.nam$b_rsl] = '\0'; sys$close(&temp_fab); -#else -# error Unsupported Platform -#endif +# else +# error Unsupported Platform +# endif } else { while (REG_ALREADY_FROZEN == region_freeze(gv_cur_region, TRUE, FALSE, FALSE)) @@ -809,7 +803,7 @@ void mupip_backup(void) if ((TRUE == mu_ctrly_occurred) || (TRUE == mu_ctrlc_occurred)) { mubclnup(rptr, need_to_del_tempfile); - gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_FREEZECTRL); mupip_exit(ERR_MUNOFINISH); } } @@ -821,7 +815,7 @@ void mupip_backup(void) if ((TRUE == mu_ctrly_occurred) || (TRUE == mu_ctrlc_occurred)) { mubclnup(rptr, need_to_del_tempfile); - gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL); mupip_exit(ERR_MUNOFINISH); } # ifdef UNIX @@ -837,55 +831,92 @@ void mupip_backup(void) * Now, backup holds crit and needs access control semaphore whereas rollback holds the access control semaphore * and needs crit. Classic deadlock. */ - memset(machine_name, 0, SIZEOF(machine_name)); - if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, status)) + decr_cnt = FALSE; + if (!pool_init) { - gtm_putmsg(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno); - error_mupip = TRUE; - goto repl_inst_bkup_done1; - } - assert(NULL == jnlpool.jnlpool_dummy_reg); - r_save = gv_cur_region; - mu_gv_cur_reg_init(); - jnlpool.jnlpool_dummy_reg = reg = gv_cur_region; - gv_cur_region = r_save; - ASSERT_IN_RANGE(MIN_RN_LEN, SIZEOF(JNLPOOL_DUMMY_REG_NAME) - 1, MAX_RN_LEN); - MEMCPY_LIT(reg->rname, JNLPOOL_DUMMY_REG_NAME); - reg->rname_len = STR_LIT_LEN(JNLPOOL_DUMMY_REG_NAME); - reg->rname[reg->rname_len] = '\0'; - if (!repl_inst_get_name(instfilename, &full_len, MAX_FN_LEN + 1, issue_rts_error)) - GTMASSERT; /* rts_error should have been issued by repl_inst_get_name */ - udi = FILE_INFO(reg); - seg = reg->dyn.addr; - memcpy((char *)seg->fname, instfilename, full_len); - udi->fn = (char *)seg->fname; - seg->fname_len = full_len; - seg->fname[full_len] = '\0'; - if (!ftok_sem_get(jnlpool.jnlpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE)) - { - gtm_putmsg(VARLSTCNT(1) ERR_JNLPOOLSETUP); - error_mupip = TRUE; - goto repl_inst_bkup_done1; - } - repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); - jnlpool.repl_inst_filehdr = &repl_instance; - shm_id = repl_instance.jnlpool_shmid; - sem_id = repl_instance.jnlpool_semid; - if (INVALID_SEMID != sem_id) - { - assert(repl_instance.crash); - semarg.buf = &semstat; - if (-1 == semctl(repl_instance.jnlpool_semid, 0, IPC_STAT, semarg)) + if (NULL == jnlpool.jnlpool_dummy_reg) { - save_errno = errno; - gtm_putmsg(VARLSTCNT(5) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, save_errno); + r_save = gv_cur_region; + mu_gv_cur_reg_init(); + jnlpool.jnlpool_dummy_reg = reg = gv_cur_region; + gv_cur_region = r_save; + ASSERT_IN_RANGE(MIN_RN_LEN, SIZEOF(JNLPOOL_DUMMY_REG_NAME) - 1, MAX_RN_LEN); + MEMCPY_LIT(reg->rname, JNLPOOL_DUMMY_REG_NAME); + reg->rname_len = STR_LIT_LEN(JNLPOOL_DUMMY_REG_NAME); + reg->rname[reg->rname_len] = '\0'; + if (!repl_inst_get_name(instfilename, &full_len, MAX_FN_LEN + 1, issue_rts_error)) + GTMASSERT; /* rts_error should have been issued by repl_inst_get_name */ + udi = FILE_INFO(reg); + seg = reg->dyn.addr; + memcpy((char *)seg->fname, instfilename, full_len); + udi->fn = (char *)seg->fname; + seg->fname_len = full_len; + seg->fname[full_len] = '\0'; + udi->ftok_semid = INVALID_SEMID; + } + else + { /* Possible if jnlpool_init did mu_gv_cur_reg_init but returned prematurely due to NOJNLPOOL */ + assert(!jnlpool.jnlpool_dummy_reg->open); + reg = jnlpool.jnlpool_dummy_reg; + /* Since mu_gv_cur_reg_init is already done, ensure that the reg->rname is correct */ + assert(0 == MEMCMP_LIT(reg->rname, JNLPOOL_DUMMY_REG_NAME)); + assert(reg->rname_len == STR_LIT_LEN(JNLPOOL_DUMMY_REG_NAME)); + assert('\0' == reg->rname[reg->rname_len]); + udi = FILE_INFO(reg); + } + if (INVALID_SEMID == udi->ftok_semid) + { + if (!ftok_sem_get(jnlpool.jnlpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE)) + { + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); + error_mupip = TRUE; + goto repl_inst_bkup_done1; + } + decr_cnt = TRUE; + } else if (!ftok_sem_lock(reg, FALSE, FALSE)) + { + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); error_mupip = TRUE; goto repl_inst_bkup_done1; - } else if (semarg.buf->sem_ctime != repl_instance.jnlpool_semid_ctime) + } + } else + { + udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); + assert(udi->ftok_semid && (INVALID_SEMID != udi->ftok_semid)); + if (!ftok_sem_lock(jnlpool.jnlpool_dummy_reg, FALSE, FALSE)) + { + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); + error_mupip = TRUE; + goto repl_inst_bkup_done1; + } + } + assert(NULL != udi); + repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); + save_inst_hdr = pool_init ? jnlpool.repl_inst_filehdr : NULL; + inst_hdr = jnlpool.repl_inst_filehdr = &repl_instance; + assert(NULL != jnlpool.jnlpool_dummy_reg); + assert(!pool_init || (NULL != jnlpool_ctl)); + shm_id = inst_hdr->jnlpool_shmid; + sem_id = inst_hdr->jnlpool_semid; + udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); + if (INVALID_SEMID != sem_id) + { + assert(inst_hdr->crash); + semarg.buf = &semstat; + if (-1 == semctl(sem_id, DB_CONTROL_SEM, IPC_STAT, semarg)) { save_errno = errno; - gtm_putmsg(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, - ERR_TEXT, 2, RTS_ERROR_TEXT("jnlpool sem_ctime does not match")); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SEMID (%d)", sem_id); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, + ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno); + error_mupip = TRUE; + goto repl_inst_bkup_done1; + } else if (semarg.buf->sem_ctime != inst_hdr->jnlpool_semid_ctime) + { + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Creation time for Journal Pool SEMID (%d) is %d; Expected %d", + sem_id, semarg.buf->sem_ctime, inst_hdr->jnlpool_semid_ctime); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, + ERR_TEXT, 2, LEN_AND_STR(scndry_msg)); error_mupip = TRUE; goto repl_inst_bkup_done1; } @@ -894,23 +925,24 @@ void mupip_backup(void) if (SS_NORMAL != status) { save_errno = errno; - gtm_putmsg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with journal pool access semaphore"), - REPL_SEM_ERRNO); + UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO)); error_mupip = TRUE; goto repl_inst_bkup_done1; } udi->grabbed_access_sem = TRUE; + udi->counter_acc_incremented = TRUE; } /* At this point, we either hold the access control lock on the journal pool OR the journal pool * semaphore doesn't exist. In either case, we can proceed with the "cp" of the instance file */ assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] || (INVALID_SEMID == sem_id)); - if (repl_instance.file_corrupt) + if (inst_hdr->file_corrupt) { - save_errno = errno; - gtm_putmsg(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, - ERR_TEXT, 2, LEN_AND_LIT("file_corrupt field in instance file header is set to TRUE")); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE"); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, + ERR_TEXT, 2, LEN_AND_STR(scndry_msg)); error_mupip = TRUE; } } @@ -978,16 +1010,16 @@ repl_inst_bkup_done1: if (rptr->not_this_time > keep_going) continue; TP_CHANGE_REG(rptr->reg); - kip_pids_arr_ptr = cs_addrs->nl->kip_pid_array; if (debug_mupip) { GET_CUR_TIME; util_out_print("!/MUPIP INFO: !AD : Start kill-in-prog wait for database !AD", TRUE, CTIME_BEFORE_NL, time_ptr, DB_LEN_STR(gv_cur_region)); } + UNIX_ONLY(kip_pids_arr_ptr = cs_addrs->nl->kip_pid_array); while (cs_data->kill_in_prog && (MAX_CRIT_TRY > crit_counter++)) { - GET_C_STACK_FOR_KIP(kip_pids_arr_ptr, crit_counter, MAX_CRIT_TRY, 1, MAX_KIP_PID_SLOTS); + UNIX_ONLY(GET_C_STACK_FOR_KIP(kip_pids_arr_ptr, crit_counter, MAX_CRIT_TRY, 1, MAX_KIP_PID_SLOTS)); wcs_sleep(crit_counter); } } @@ -1030,8 +1062,8 @@ repl_inst_bkup_done1: break; } assert(!kip_count); - GET_C_STACK_FOR_KIP(kip_pids_arr_ptr, crit_counter, MAX_CRIT_TRY, 2, MAX_KIP_PID_SLOTS); - gtm_putmsg(VARLSTCNT(4) ERR_BACKUPKILLIP, 2, DB_LEN_STR(gv_cur_region)); + UNIX_ONLY(GET_C_STACK_FOR_KIP(kip_pids_arr_ptr, crit_counter, MAX_CRIT_TRY, 2, MAX_KIP_PID_SLOTS)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_BACKUPKILLIP, 2, DB_LEN_STR(gv_cur_region)); } /* Now that we have crit, check if this region is actively journaled and if gbl_jrec_time needs to be * adjusted (to ensure time ordering of journal records within this region's journal file). @@ -1056,11 +1088,13 @@ repl_inst_bkup_done1: if (NULL != mu_repl_inst_reg_list) { if (error_mupip) - { /* some error happened while getting the ftok or the access control. Release locks, ignore instance + { /* Some error happened while getting the ftok or the access control. Release locks, ignore instance * file and continue with the backup of database files. */ goto repl_inst_bkup_done2; } + assert(udi == FILE_INFO(jnlpool.jnlpool_dummy_reg)); + seg = jnlpool.jnlpool_dummy_reg->dyn.addr; /* re-initialize (for pool_init == TRUE case) */ cmdptr = &command[0]; memcpy(cmdptr, "cp ", 3); cmdptr += 3; @@ -1070,7 +1104,8 @@ repl_inst_bkup_done1: memcpy(cmdptr, mu_repl_inst_reg_list->backup_file.addr, mu_repl_inst_reg_list->backup_file.len); cmdptr += mu_repl_inst_reg_list->backup_file.len; *cmdptr = '\0'; - if (0 != (rv = SYSTEM((char *)command))) + rv = SYSTEM(((char *)command)); + if (0 != rv) { if (-1 == rv) { @@ -1082,70 +1117,73 @@ repl_inst_bkup_done1: error_mupip = TRUE; goto repl_inst_bkup_done2; } + assert(!pool_init || (INVALID_SHMID != shm_id)); if (INVALID_SHMID != shm_id) { if (INVALID_SEMID == sem_id) GTMASSERT; /* out-of-design situation */ - /* The journal pool exists. Note down the journal seqno from there and copy that onto - * the backed up instance file header. Also, clean up other fields in the backed up - * instance file header. + /* The journal pool exists. Note down the journal seqno from there and copy that onto the backed up + * instance file header. Also, clean up other fields in the backed up instance file header. */ - if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf)) + if (!pool_init) { - save_errno = errno; - gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, - RTS_ERROR_STRING(instfilename)); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, - RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno); - error_mupip = TRUE; - goto repl_inst_bkup_done2; - } - if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0))) - { - save_errno = errno; - gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, - RTS_ERROR_STRING(instfilename)); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmat()"), CALLFROM, - save_errno); - error_mupip = TRUE; - goto repl_inst_bkup_done2; - } - memcpy((void *)&replpool_id, (void *)start_addr, SIZEOF(replpool_identifier)); - if (memcmp(replpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ - 1)) - { - if (!memcmp(replpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ - 3)) - util_out_print("Incorrect version for the journal pool shared memory " - "segment (id = !UL) belonging to replication instance !AD", - TRUE, shm_id, LEN_AND_STR(instfilename)); - else - util_out_print("Incorrect format for the journal pool shared memory segment" - " (id = !UL) belonging to replication instance !AD", - TRUE, shm_id, LEN_AND_STR(instfilename)); - error_mupip = TRUE; - goto repl_inst_bkup_done2; - } - if (memcmp(replpool_id.now_running, gtm_release_name, gtm_release_name_len + 1)) - { - util_out_print("Attempt to access with version !AD, while already using !AD for " - "journal pool shared memory segment (id = !UL) belonging to replication " - "instance file !AD.", TRUE, gtm_release_name_len, gtm_release_name, - LEN_AND_STR(replpool_id.now_running), shm_id, LEN_AND_STR(instfilename)); - error_mupip = TRUE; - goto repl_inst_bkup_done2; - } - csa = &udi->s_addrs; - assert(!csa->hold_onto_crit); - jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr; - csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); - csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE - + SIZEOF(mutex_spin_parms_struct)); - /* Do the per process initialization of mutex stuff (needed before grab_lock is done) */ - csa->onln_rlbk_cycle = jnlpool.jnlpool_ctl->onln_rlbk_cycle; - assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id); - if (!mutex_per_process_init_pid) - mutex_per_process_init(); - UNIX_ONLY(START_HEARTBEAT_IF_NEEDED;) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf)) + { + save_errno = errno; + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, + RTS_ERROR_STRING(udi->fn)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno); + error_mupip = TRUE; + goto repl_inst_bkup_done2; + } + if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0))) + { + save_errno = errno; + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, + RTS_ERROR_STRING(udi->fn)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + RTS_ERROR_LITERAL("shmat()"), CALLFROM, save_errno); + error_mupip = TRUE; + goto repl_inst_bkup_done2; + } + memcpy((void *)&replpool_id, (void *)start_addr, SIZEOF(replpool_identifier)); + if (memcmp(replpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ - 1)) + { + if (!memcmp(replpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ - 3)) + util_out_print("Incorrect version for the journal pool shared memory " + "segment (id = !UL) belonging to replication instance !AD", + TRUE, shm_id, LEN_AND_STR(udi->fn)); + else + util_out_print("Incorrect format for the journal pool shared memory segment" + " (id = !UL) belonging to replication instance !AD", + TRUE, shm_id, LEN_AND_STR(udi->fn)); + error_mupip = TRUE; + goto repl_inst_bkup_done2; + } + if (memcmp(replpool_id.now_running, gtm_release_name, gtm_release_name_len + 1)) + { + util_out_print("Attempt to access with version !AD, while already using !AD for " + "journal pool shared memory segment (id = !UL) belonging to replication " + "instance file !AD.", TRUE, gtm_release_name_len, gtm_release_name, + LEN_AND_STR(replpool_id.now_running), shm_id, LEN_AND_STR(udi->fn)); + error_mupip = TRUE; + goto repl_inst_bkup_done2; + } + csa = &udi->s_addrs; + assert(!csa->hold_onto_crit); + jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr; + csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); + csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE + + SIZEOF(mutex_spin_parms_struct)); + /* Do the per process initialization of mutex stuff (needed before grab_lock is done) */ + csa->onln_rlbk_cycle = jnlpool.jnlpool_ctl->onln_rlbk_cycle; + assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id); + if (!mutex_per_process_init_pid) + mutex_per_process_init(); + UNIX_ONLY(START_HEARTBEAT_IF_NEEDED;) + } /* else journal pool already initialized in gvcst_init */ + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno; assert(0 != jnl_seqno); /* All the cleanup we want is exactly done by the "repl_inst_histinfo_truncate" function. But @@ -1160,17 +1198,26 @@ repl_inst_bkup_done1: COPY_JCTL_STRMSEQNO_TO_INSTHDR_IF_NEEDED; repl_inst_histinfo_truncate(jnl_seqno); /* Flush updated file header to backed up instance file */ rel_lock(jnlpool.jnlpool_dummy_reg); - udi->fn = (char *)seg->fname; - jnlpool.jnlpool_ctl = NULL; /* or else exit handling will try to rel_lock this as well */ - if (-1 == shmdt((caddr_t)start_addr)) + udi->fn = (char *)seg->fname; /* Restore */ + if (!pool_init) { - save_errno = errno; - gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, - RTS_ERROR_STRING(instfilename)); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmdt()"), CALLFROM, - save_errno); - error_mupip = TRUE; - goto repl_inst_bkup_done2; + jnlpool.jnlpool_ctl = NULL; /* or else exit handling will try to rel_lock this as well */ + if (-1 == shmdt((caddr_t)start_addr)) + { + save_errno = errno; + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id, + RTS_ERROR_STRING(udi->fn)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + RTS_ERROR_LITERAL("shmdt()"), CALLFROM, save_errno); + error_mupip = TRUE; + goto repl_inst_bkup_done2; + } + } else + { /* Now that instance file truncate is done, restore jnlpool.repl_inst_filehdr to its + * original value + */ + assert(NULL != save_inst_hdr); + jnlpool.repl_inst_filehdr = save_inst_hdr; } } else { /* We are guaranteed that NO one is actively accessing the instance file. So, no need to @@ -1189,18 +1236,18 @@ repl_inst_bkup_done2: GTMASSERT; } if (udi->grabbed_ftok_sem) - ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + ftok_sem_release(jnlpool.jnlpool_dummy_reg, decr_cnt, TRUE); } if (!error_mupip) { util_out_print("Replication Instance file !AD backed up in file !AD", TRUE, - LEN_AND_STR(instfilename), + LEN_AND_STR(udi->fn), mu_repl_inst_reg_list->backup_file.len, mu_repl_inst_reg_list->backup_file.addr); util_out_print("Journal Seqnos up to 0x!16@XQ are backed up.", TRUE, &jnl_seqno); util_out_print("", TRUE); } else util_out_print("Error backing up replication instance file !AD. Moving on to other backups.", - TRUE, LEN_AND_STR(instfilename)); + TRUE, LEN_AND_STR(udi->fn)); } # endif jgbl.dont_reset_gbl_jrec_time = TRUE; @@ -1240,7 +1287,7 @@ repl_inst_bkup_done2: { if (0 != cs_addrs->hdr->abandoned_kills) { - gtm_putmsg(VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(rptr->reg), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(rptr->reg), LEN_AND_LIT("backup database could have incorrectly marked busy integrity errors")); } sbufh_p = cs_addrs->shmpool_buffer; @@ -1249,7 +1296,7 @@ repl_inst_bkup_done2: if (TRUE == is_proc_alive(sbufh_p->backup_pid, sbufh_p->backup_image_count)) { /* someone else is doing the backup */ - util_out_print("!/Process !UL is backing up region !AD now.", TRUE, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_BKUPRUNNING, 3, sbufh_p->backup_pid, REG_LEN_STR(rptr->reg)); rptr->not_this_time = give_up_after_create_tempfile; /* Decerement counter so that inhibited KILLs can now proceed */ @@ -1287,7 +1334,7 @@ repl_inst_bkup_done2: { util_out_print("!/Journal file !AD not closed:", TRUE, jnl_info.jnl_len, jnl_info.jnl); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status); rptr->not_this_time = give_up_after_create_tempfile; DECR_INHIBIT_KILLS(cs_addrs->nl); rel_crit(rptr->reg); @@ -1302,7 +1349,7 @@ repl_inst_bkup_done2: if (FILE_STAT_ERROR == (jnl_fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus))) { - gtm_putmsg(VARLSTCNT(5) ERR_JNLFNF, 2, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_JNLFNF, 2, filestr.len, filestr.addr, ustatus); rptr->not_this_time = give_up_after_create_tempfile; DECR_INHIBIT_KILLS(cs_addrs->nl); @@ -1315,7 +1362,6 @@ repl_inst_bkup_done2: wcs_flu(WCSFLU_FSYNC_DB | WCSFLU_FLUSH_HDR | WCSFLU_MSYNC_DB); /* For VMS WCSFLU_FSYNC_DB is ignored */ if (!JNL_ENABLED(cs_data) && (NULL != cs_addrs->nl)) - { /* Cleanup the jnl file info in shared memory before switching journal file. This case occurs if mupip backup -newjnl is run after jnl_file_lost() closes journaling on a region */ @@ -1328,15 +1374,15 @@ repl_inst_bkup_done2: jnl_info.jnl_state = jnl_open; jnl_info.repl_state = repl_open; jnl_info.no_prev_link = TRUE; - gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATE, 6, LEN_AND_LIT(FILE_STR), DB_LEN_STR(gv_cur_region), LEN_AND_STR(repl_state_lit[repl_open])); - gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR), DB_LEN_STR(gv_cur_region), LEN_AND_STR(jnl_state_lit[jnl_open])); } else if (!REPL_ALLOWED(cs_data)) { - gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATEERR, 2, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATEERR, 2, DB_LEN_STR(gv_cur_region), ERR_TEXT, 2, LEN_AND_LIT("Standalone access required")); rptr->not_this_time = give_up_after_create_tempfile; @@ -1349,7 +1395,7 @@ repl_inst_bkup_done2: { /* Do not switch journal file when replication was turned OFF by jnl_file_lost() */ assert(cs_data->jnl_state == jnl_closed); - gtm_putmsg(VARLSTCNT(10) ERR_REPLJNLCNFLCT, 8, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_REPLJNLCNFLCT, 8, LEN_AND_STR(jnl_state_lit[jnl_open]), DB_LEN_STR(gv_cur_region), LEN_AND_STR(repl_state_lit[repl_closed]), @@ -1369,7 +1415,7 @@ repl_inst_bkup_done2: if (EXIT_NRM == cre_jnl_file(&jnl_info)) { if (jnl_info.no_prev_link && (save_no_prev_link != jnl_info.no_prev_link)) - gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(rptr->reg)); memcpy(cs_data->jnl_file_name, jnl_info.jnl, jnl_info.jnl_len); cs_data->jnl_file_name[jnl_info.jnl_len] = '\0'; @@ -1384,12 +1430,13 @@ repl_inst_bkup_done2: cs_data->jnl_sync_io = sync_io; cs_data->jnl_checksum = jnl_info.checksum; cs_data->jnl_eovtn = cs_data->trans_hist.curr_tn; - gtm_putmsg(VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl, - LEN_AND_LIT("region"), REG_LEN_STR(gv_cur_region), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_JNLCREATE, 8, + jnl_info.jnl_len, jnl_info.jnl, LEN_AND_LIT("region"), + REG_LEN_STR(gv_cur_region), LEN_AND_STR(before_image_lit[(jnl_info.before_images ? 1 : 0)])); if (JNL_ENABLED(cs_data) && (jnl_options[jnl_noprevjnlfile] || !keep_prev_link)) - gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region)); fc = gv_cur_region->dyn.addr->file_cntl; fc->op = FC_WRITE; @@ -1399,9 +1446,11 @@ repl_inst_bkup_done2: status = dbfilop(fc); if (SS_NORMAL != status) { - UNIX_ONLY(gtm_putmsg(VARLSTCNT(7) ERR_DBFILERR, 2, + UNIX_ONLY(gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) + ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), 0, status, 0);) - VMS_ONLY(gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2, + VMS_ONLY(gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) + ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), 0, status, 0, gds_info->fab->fab$l_stv, 0);) rptr->not_this_time = give_up_after_create_tempfile; @@ -1411,13 +1460,15 @@ repl_inst_bkup_done2: continue; } } else - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); } else - gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_JNLDISABLE), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) MAKE_MSG_WARNING(ERR_JNLDISABLE), 2, DB_LEN_STR(gv_cur_region)); } else if (replication_on && !REPL_ENABLED(cs_data)) { - gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATEERR, 2, DB_LEN_STR(gv_cur_region), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) + ERR_REPLSTATEERR, 2, DB_LEN_STR(gv_cur_region), ERR_TEXT, 2, LEN_AND_LIT("Cannot turn replication ON without also switching journal file")); rptr->not_this_time = give_up_after_create_tempfile; @@ -1428,7 +1479,7 @@ repl_inst_bkup_done2: } if (FALSE == shmpool_lock_hdr(gv_cur_region)) { - gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region), ERR_ERRCALL, 3, CALLFROM); rptr->not_this_time = give_up_after_create_tempfile; DECR_INHIBIT_KILLS(cs_addrs->nl); @@ -1444,6 +1495,14 @@ repl_inst_bkup_done2: sbufh_p->dskaddr = 0; sbufh_p->backup_errno = 0; sbufh_p->failed = 0; +# ifdef DEBUG + /* Once the process register its pid as backup_pid, sleep for the 1 seconds, so that test + * tests hits the scenario where BKUPRUNNING message is printed. Note that sleep of 1 sec + * is fine because it is the box boxes which are failing to hit the concurrency scenario. + */ + if (gtm_white_box_test_case_enabled && (WBTEST_CONCBKUP_RUNNING == gtm_white_box_test_case_number)) + LONG_SLEEP(1); +# endif VMS_ONLY(sbufh_p->backup_image_count = image_count); /* Make sure that the backup queue does not have any remnants on it. Note that we do not depend on the queue count here as it is imperative that, in the event that the count @@ -1503,7 +1562,7 @@ repl_inst_bkup_done2: } if (jnl_options[jnl_off] || bkdbjnl_off_specified || jnl_options[jnl_disable] || bkdbjnl_disable_specified) - gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR), + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR), rptr->backup_file.len, rptr->backup_file.addr, LEN_AND_STR(jnl_state_lit[rptr->backup_hdr->jnl_state])); } @@ -1522,7 +1581,7 @@ repl_inst_bkup_done2: * In either case, the BACKUP is unreliable. Cleanup and exit */ error_mupip = TRUE; - gtm_putmsg(VARLSTCNT(1) ERR_DBROLLEDBACK); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); break; } # endif @@ -1541,19 +1600,15 @@ repl_inst_bkup_done2: } else { mubclnup((backup_reg_list *)halt_ptr, need_to_rel_crit); - gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL); mupip_exit(ERR_MUNOFINISH); } - /* =============================== STEP 5. clean up ============================================== */ - mubclnup((backup_reg_list *)halt_ptr, need_to_del_tempfile); - REVERT; - if (mu_ctrly_occurred || mu_ctrlc_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL); ret = ERR_MUNOFINISH; } else if (TRUE == error_mupip) ret = ERR_MUNOFINISH; diff --git a/sr_port/mupip_downgrade.c b/sr_port/mupip_downgrade.c index 838adff..607ab1e 100644 --- a/sr_port/mupip_downgrade.c +++ b/sr_port/mupip_downgrade.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -55,6 +55,7 @@ #include "mu_upgrd_dngrd_hdr.h" #include "mu_upgrd_dngrd_confirmed.h" #include "mu_outofband_setup.h" +#include "anticipatory_freeze.h" #ifdef UNIX #include "mu_all_version_standalone.h" #endif @@ -86,12 +87,15 @@ error_def(ERR_SYSCALL); error_def(ERR_TEXT); ZOS_ONLY(error_def(ERR_BADTAG);) +#define MAX_DB_VER_LEN 2 + void mupip_downgrade(void) { - char db_fn[MAX_FN_LEN + 1]; - unsigned short db_fn_len; /* cli_get_str expects short */ + char db_fn[MAX_FN_LEN + 1], ver_spec[MAX_DB_VER_LEN + 1]; + unsigned short db_fn_len; /* cli_get_str expects short */ + unsigned short ver_spec_len=MAX_DB_VER_LEN; fd_type channel; - int save_errno, csd_size; + int save_errno, csd_size, rec_size; int fstat_res, idx; int4 status, rc; uint4 status2; @@ -104,9 +108,13 @@ void mupip_downgrade(void) #elif VMS struct FAB mupfab; struct XABFHC xabfhc; + $DESCRIPTOR(dbver_v4, "V4"); + $DESCRIPTOR(dbver_v5, "V5"); + $DESCRIPTOR(dbver_qualifier, "VERSION"); #endif ZOS_ONLY(int realfiletag;) unsigned char new_master_map[MASTER_MAP_SIZE_V4]; + enum db_ver desired_dbver; /* Structure checks .. */ assert((24 * 1024) == SIZEOF(v15_sgmnt_data)); /* Verify V4 file header hasn't suddenly increased for some odd reason */ @@ -119,6 +127,37 @@ void mupip_downgrade(void) if (!cli_get_str("FILE", db_fn, &db_fn_len)) rts_error(VARLSTCNT(1) ERR_MUNODBNAME); db_fn[db_fn_len] = '\0'; /* Null terminate */ +#ifdef VMS + if (CLI$_ABSENT != cli$present(&dbver_qualifier)) + { + if (CLI$_PRESENT == cli$present(&dbver_v4)) + desired_dbver = GDSV4; + else if (CLI$_PRESENT == cli$present(&dbver_v5)) + { + desired_dbver = GDSV5; + gtm_putmsg(VARLSTCNT(8) ERR_MUPGRDSUCC, 6, db_fn_len, db_fn, + RTS_ERROR_LITERAL("downgraded"), RTS_ERROR_LITERAL("GT.M V5")); + mupip_exit(SS_NORMAL); + } + else + assertpro(FALSE); /* CLI should prevent us ever getting here */ + } else + desired_dbver = GDSV4; /* really want to keep current format, which has not yet been read */ +#else + if (cli_present("VERSION")) + { + cli_get_str("VERSION", ver_spec, &ver_spec_len); + ver_spec[ver_spec_len] = '\0'; + cli_strupper(ver_spec); + if (0 == memcmp(ver_spec, "V4", ver_spec_len)) + desired_dbver = GDSV4; + else if (0 == memcmp(ver_spec, "V5", ver_spec_len)) + desired_dbver = GDSV5; + else + assertpro(FALSE); /* CLI should prevent us ever getting here */ + } else + desired_dbver = GDSV4; /* really want to keep version, which has not yet been read */ +#endif if (!mu_upgrd_dngrd_confirmed()) { gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Downgrade canceled by user")); @@ -202,13 +241,18 @@ void mupip_downgrade(void) gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, LEN_AND_LIT("Database is frozen")); mupip_exit(ERR_MUNODWNGRD); } - if (csd.wc_blocked) +# ifdef UNIX + /* The following used to be a check for wc_blocked which is now unreachable because it resides + * in the shared memory. + */ + if (csd.machine_name[0]) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), - 2, LEN_AND_LIT("Database modifications are disallowed because wc_blocked is set")); + 2, LEN_AND_LIT("Machine name in file header is non-null implying possible crash")); mupip_exit(ERR_MUNODWNGRD); } +# endif if (csd.file_corrupt) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ @@ -231,6 +275,57 @@ void mupip_downgrade(void) gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, LEN_AND_LIT("Recovery was interrupted")); mupip_exit(ERR_MUNODWNGRD); } + UNIX_ONLY( + if (desired_dbver == GDSV5) /*Downgrading to V5 version*/ + { + if ((START_VBN_V6 == csd.start_vbn) || (MASTER_MAP_BLOCKS_DFLT == csd.master_map_len)) + { /* DB is created with V6 version*/ + gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, + LEN_AND_LIT("Database is created with V6 version.")); + mupip_exit(ERR_MUNODWNGRD); + } + if (!csd.span_node_absent) + { /* DB might contain spanning node */ + gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, + LEN_AND_LIT("Spanning node might be present.")); + mupip_exit(ERR_MUNODWNGRD); + } + if (!csd.maxkeysz_assured) + { /* DB might contain keys larger than max_key_sz in db header */ + gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, + LEN_AND_LIT("Database might contain keys larger than MAX KEY SIZE in DB header")); + mupip_exit(ERR_MUNODWNGRD); + } + if (csd.max_key_size > OLD_MAX_KEY_SZ) + { /* DB might contain keys larger than 255 */ + gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, + LEN_AND_LIT("Database might contain keys larger than 255 bytes")); + mupip_exit(ERR_MUNODWNGRD); + } + /* Determine the max record size which is safe from spanning node perspective */ + rec_size = csd.blk_size - csd.reserved_bytes - SIZEOF(blk_hdr); + if (csd.max_rec_size > rec_size) + { /* max_rec_size is not supported for given blk_size in V5 */ + gtm_putmsg(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_TEXT, ERROR), 2, + LEN_AND_LIT("MAX REC SIZE is not supported for given BLK SIZE in V5")); + mupip_exit(ERR_MUNODWNGRD); + } + csd.freeze_on_fail = FALSE; + csd.span_node_absent = TRUE; + csd.maxkeysz_assured = FALSE; + gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, + LEN_AND_LIT("V5 supportable record size for current DB configuration "),rec_size, rec_size); + gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, + LEN_AND_LIT("V5 supportable max key size for current DB configuration"), + OLD_MAX_KEY_SZ, OLD_MAX_KEY_SZ); + gtm_putmsg(VARLSTCNT(8) ERR_MUPGRDSUCC, 6, db_fn_len, db_fn, RTS_ERROR_LITERAL("downgraded"), + RTS_ERROR_LITERAL("GT.M V5")); + DB_DO_FILE_WRITE(channel, 0, &csd, csd_size, status, status2); + F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ + UNIX_ONLY(mu_all_version_release_standalone(sem_inf)); + mupip_exit(SS_NORMAL); + } + ) gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT("Old file header size"), csd_size, csd_size); gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT8, 4, LEN_AND_LIT("Old file length"), &file_size, &file_size); gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT("Old file start_vbn"), csd.start_vbn, csd.start_vbn); @@ -280,7 +375,7 @@ void mupip_downgrade(void) /* Now call mu_dwngrd_header to do file header downgrade */ mu_dwngrd_header(&csd, &v15_csd); memcpy(v15_csd.master_map, new_master_map, MASTER_MAP_SIZE_V4); - DO_FILE_WRITE(channel, 0, &v15_csd, csd_size, status, status2); + DB_DO_FILE_WRITE(channel, 0, &v15_csd, csd_size, status, status2); if (SS_NORMAL != status) { gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, db_fn_len, db_fn, status); diff --git a/sr_port/mupip_extend.c b/sr_port/mupip_extend.c index d4c0c6d..0be62ed 100644 --- a/sr_port/mupip_extend.c +++ b/sr_port/mupip_extend.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,6 +39,7 @@ #include "gtmmsg.h" #include "gdsfilext.h" #include "wcs_backoff.h" +#include "gt_timer.h" #if defined(VMS) || defined(MM_FILE_EXT_OK) #define DB_IPCS_RESET(REG) #else @@ -51,10 +52,13 @@ } #endif -GBLREF gd_addr *gd_header; -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF sgmnt_data_ptr_t cs_data; +GBLREF gd_addr *gd_header; +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data_ptr_t cs_data; +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +#endif error_def(ERR_DBOPNERR); error_def(ERR_DBRDONLY); @@ -73,8 +77,9 @@ void mupip_extend(void) int fd; r_len = SIZEOF(regionname); + UNIX_ONLY(jnlpool_init_needed = TRUE); if (cli_get_str("REG_NAME", regionname, &r_len) == FALSE) - rts_error(VARLSTCNT(1) ERR_MUNODBNAME); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUNODBNAME); if (cli_get_int("BLOCKS",&tblocks)) { if (tblocks < 1) @@ -93,7 +98,7 @@ void mupip_extend(void) } if (i >= gd_header->n_regions) { - gtm_putmsg(VARLSTCNT(4) ERR_NOREGION, 2, r_len, regionname); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOREGION, 2, r_len, regionname); mupip_exit(ERR_MUNOACTION); } if ((dba_bg != gv_cur_region->dyn.addr->acc_meth) && (dba_mm != gv_cur_region->dyn.addr->acc_meth)) @@ -122,7 +127,7 @@ void mupip_extend(void) gvcst_init(gv_cur_region); if (gv_cur_region->was_open) { /* This should not happen as extend works on only one region at a time, but handle for safety */ - gtm_putmsg(VARLSTCNT(4) ERR_DBOPNERR, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_DBOPNERR, 2, DB_LEN_STR(gv_cur_region)); DB_IPCS_RESET(gv_cur_region); mupip_exit(ERR_MUNOACTION); } @@ -142,7 +147,7 @@ void mupip_extend(void) /* cannot extend for read_only database. */ if (gv_cur_region->read_only) { - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); DB_IPCS_RESET(gv_cur_region); mupip_exit(ERR_MUNOACTION); } @@ -153,7 +158,7 @@ void mupip_extend(void) grab_crit(gv_cur_region); GRAB_UNFROZEN_CRIT(gv_cur_region, cs_addrs, cs_data); old_total = cs_addrs->ti->total_blks; - if ((uint4)NO_FREE_SPACE == (status = gdsfilext(blocks, old_total))) + if ((uint4)NO_FREE_SPACE == (status = GDSFILEXT(blocks, old_total, TRANS_IN_PROG_FALSE))) { rel_crit(gv_cur_region); util_out_print("The extension failed on file !AD; check disk space and permissions.", TRUE, diff --git a/sr_port/mupip_freeze.c b/sr_port/mupip_freeze.c index f8f35d1..778699f 100644 --- a/sr_port/mupip_freeze.c +++ b/sr_port/mupip_freeze.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,15 +42,18 @@ #include "interlock.h" #include "sleep_cnt.h" -GBLREF bool mu_ctrly_occurred; -GBLREF bool mu_ctrlc_occurred; -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF tp_region *halt_ptr; -GBLREF tp_region *grlist; -GBLREF bool in_mupip_freeze; -GBLREF bool error_mupip; -GBLREF boolean_t debug_mupip; +GBLREF bool mu_ctrly_occurred; +GBLREF bool mu_ctrlc_occurred; +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF tp_region *halt_ptr; +GBLREF tp_region *grlist; +GBLREF bool in_mupip_freeze; +GBLREF bool error_mupip; +GBLREF boolean_t debug_mupip; +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +#endif #define INTERRUPTED (mu_ctrly_occurred || mu_ctrlc_occurred) #define PRINT_FREEZEERR \ @@ -60,6 +63,17 @@ GBLREF boolean_t debug_mupip; } #define PRINT_UNFROZEN_MSG util_out_print("All regions will be unfrozen", TRUE) + +error_def(ERR_BUFFLUFAILED); +error_def(ERR_DBRDONLY); +error_def(ERR_FREEZECTRL); +error_def(ERR_MUNOACTION); +error_def(ERR_MUPCLIERR); +error_def(ERR_MUNOFINISH); +error_def(ERR_MUKILLIP); +error_def(ERR_KILLABANDONED); +error_def(ERR_FREEZEERR); + void mupip_freeze(void) { int4 status; @@ -71,18 +85,9 @@ void mupip_freeze(void) const char *msg2[] = { "UNFROZEN", "FROZEN" } ; const char *msg3[] = { "unfrozen", "frozen" } ; - error_def(ERR_BUFFLUFAILED); - error_def(ERR_DBRDONLY); - error_def(ERR_FREEZECTRL); - error_def(ERR_MUNOACTION); - error_def(ERR_MUPCLIERR); - error_def(ERR_MUNOFINISH); - error_def(ERR_MUKILLIP); - error_def(ERR_KILLABANDONED); - error_def(ERR_FREEZEERR); - status = SS_NORMAL; in_mupip_freeze = TRUE; + UNIX_ONLY(jnlpool_init_needed = TRUE); mu_outofband_setup(); gvinit(); freeze = (CLI_PRESENT == cli_present("ON")); @@ -163,8 +168,8 @@ void mupip_freeze(void) { gtm_putmsg(VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(rptr->reg), LEN_AND_LIT("database could have incorrectly marked busy integrity errors")); - PRINT_FREEZEERR; - continue; + util_out_print("WARNING: The region !AD to be frozen contains abandoned kills", + TRUE, REG_LEN_STR(gv_cur_region)); } while (REG_FREEZE_SUCCESS != (freeze_ret = region_freeze(gv_cur_region, freeze, override, TRUE))) { diff --git a/sr_port/mupip_integ.c b/sr_port/mupip_integ.c index d9604bd..8502492 100644 --- a/sr_port/mupip_integ.c +++ b/sr_port/mupip_integ.c @@ -94,6 +94,7 @@ GBLDEF unsigned char mu_int_root_level; GBLDEF int4 mu_int_adj[MAX_BT_DEPTH + 1]; GBLDEF uint4 mu_int_errknt; +GBLDEF uint4 mu_int_skipreg_cnt=0; GBLDEF uint4 mu_int_blks[MAX_BT_DEPTH + 1]; GBLDEF uint4 mu_int_offset[MAX_BT_DEPTH + 1]; GBLDEF uint4 mu_int_recs[MAX_BT_DEPTH + 1]; @@ -122,12 +123,12 @@ GBLDEF sgmnt_data mu_int_data; GBLDEF unsigned char *mu_int_master; GBLDEF trans_num largest_tn; GBLDEF int4 mu_int_blks_to_upgrd; +GBLDEF span_node_integ *sndata; /* The following global variable is used to store the encryption information for the current database. The * variable is initialized in mu_int_init(mupip integ -file ) and mu_int_reg(mupip integ -reg ). */ GTMCRYPT_ONLY( GBLDEF gtmcrypt_key_t mu_int_encrypt_key_handle; ) - GBLREF bool mu_ctrly_occurred; GBLREF bool mu_ctrlc_occurred; GBLREF bool error_mupip; @@ -162,7 +163,10 @@ error_def(ERR_DBTNRESET); error_def(ERR_INTEGERRS); error_def(ERR_MUNOACTION); error_def(ERR_MUNOFINISH); +error_def(ERR_MUNOTALLINTEG); error_def(ERR_MUPCLIERR); +error_def(ERR_DBSPANGLOINCMP); +error_def(ERR_DBSPANCHUNKORD); void mupip_integ(void) { @@ -187,7 +191,12 @@ void mupip_integ(void) unsigned short ss_file_len = GTM_PATH_MAX; ) sgmnt_data_ptr_t csd; + span_node_integ span_node_data; + sndata = &span_node_data; + sndata->sn_cnt = 0; + sndata->sn_blk_cnt = 0; + sndata->sn_type = SN_NOT; error_mupip = FALSE; if (NULL == gv_target) gv_target = (gv_namehead *)targ_alloc(DUMMY_GLOBAL_VARIABLE_LEN, NULL, NULL); @@ -265,9 +274,8 @@ void mupip_integ(void) if (!grlist) { error_mupip = TRUE; - mu_int_errknt++; - mu_int_err(ERR_DBNOREGION, 0, 0, 0, 0, 0, 0, 0); - mupip_exit(ERR_MUNOACTION); + gtm_putmsg(VARLSTCNT(1) ERR_DBNOREGION); + mupip_exit(ERR_MUNOACTION); } rptr = grlist; } else @@ -324,7 +332,7 @@ void mupip_integ(void) assert(NULL != rptr); if (!mupfndfil(rptr->reg, NULL)) { - mu_int_errknt++; + mu_int_skipreg_cnt++; rptr = rptr->fPtr; if (NULL == rptr) break; @@ -454,9 +462,9 @@ void mupip_integ(void) gv_target->act = trees->act; gv_target->ver = trees->ver; gv_altkey->prev = 0; - gv_altkey->top = MAX_KEY_SZ; assert(trees->keysize == strlen(trees->key)); gv_altkey->end = trees->keysize; + assert(gv_altkey->end + 2 <= gv_altkey->top); memcpy(gv_altkey->base, trees->key, gv_altkey->end); gv_altkey->base[gv_altkey->end++] = '\0'; gv_altkey->base[gv_altkey->end] = '\0'; @@ -464,6 +472,30 @@ void mupip_integ(void) act_in_gvt(); if (mu_int_blk(trees->root, MAX_BT_DEPTH, TRUE, gv_altkey->base, gv_altkey->end, &dummy, 0, 0)) { + /* We are done with the INTEG CHECK for the current GVT, but if the spanning node INTEG + * check is not finished, either of the following two are occurred. + */ + if (SPAN_NODE == sndata->sn_type) + { /* ERROR 1: There is discontinuity in the spanning node blocks; + * adjacent spanning block is missing. + */ + mu_int_plen = mu_int_root_level + 1; + mu_int_err(ERR_DBSPANGLOINCMP, TRUE, FALSE, sndata->span_node_buf, sndata->key_len, + &dummy, 0, 0); + sndata->sn_blk_cnt += sndata->span_blk_cnt; + mu_int_plen = 0; + sndata->sn_type = SN_NOT; + } + if (2 == sndata->sn_type) + { /* ERROR 2: Spanning-node-block occurred in the middle of non-spanning block */ + mu_int_plen = mu_int_root_level + 1; + mu_int_err(ERR_DBSPANCHUNKORD, TRUE, FALSE, sndata->span_node_buf, sndata->key_len, + &dummy, 0, 0); + sndata->sn_blk_cnt += sndata->span_blk_cnt; + mu_int_plen = 0; + mu_int_plen = 0; + sndata->sn_type = SN_NOT; + } if (full) { if (trees->root == dir_root) @@ -627,6 +659,11 @@ void mupip_integ(void) (mu_int_data.trans_hist.total_blks + mu_int_data.bplmap - 1) / mu_int_data.bplmap, mu_dir_recs + mu_index_recs + mu_data_recs, mu_data_adj + mu_index_adj); } + if(sndata->sn_cnt) + { + util_out_print("[Spanning Nodes:!UL ; Blocks:!UL]", TRUE, sndata->sn_cnt, sndata->sn_blk_cnt); + /*[span_node:; blks: ]*/ + } if (largest_tn) { mu_int_err(ERR_DBTNLTCTN, 0, 0, 0, 0, 0, 0, 0); @@ -671,6 +708,8 @@ void mupip_integ(void) if (mu_int_blks_to_upgrd != csd->blks_to_upgrd) csd->blks_to_upgrd = mu_int_blks_to_upgrd; } + csd->span_node_absent = (sndata->sn_cnt) ? FALSE : TRUE; + csd->maxkeysz_assured = (maxkey_errors) ? FALSE : TRUE; region_freeze(gv_cur_region, FALSE, FALSE, FALSE); fc = gv_cur_region->dyn.addr->file_cntl; fc->op = FC_WRITE; @@ -687,10 +726,10 @@ void mupip_integ(void) # ifdef GTM_SNAPSHOT else { - assert(cs_addrs->snapshot_in_prog); + assert(SNAPSHOTS_IN_PROG(cs_addrs)); assert(NULL != cs_addrs->ss_ctx); ss_release(&cs_addrs->ss_ctx); - cs_addrs->snapshot_in_prog = FALSE; + CLEAR_SNAPSHOTS_IN_PROG(cs_addrs); } # endif rptr = rptr->fPtr; @@ -776,5 +815,7 @@ void mupip_integ(void) } if (0 != total_errors) mupip_exit(ERR_INTEGERRS); + if (0 != mu_int_skipreg_cnt) + mupip_exit(ERR_MUNOTALLINTEG); mupip_exit(SS_NORMAL); } diff --git a/sr_port/mupip_io_dev_dispatch.h b/sr_port/mupip_io_dev_dispatch.h index d7a7932..cc5fe00 100644 --- a/sr_port/mupip_io_dev_dispatch.h +++ b/sr_port/mupip_io_dev_dispatch.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,7 +20,7 @@ UNIX_ONLY(GBLDEF) VMS_ONLY(LITDEF) dev_dispatch_struct io_dev_dispatch_mupip[] = { # ifdef UNIX - iotype(iott, iott, nil), + iotype(iott, iott, iott), # else ionil_dev, # endif diff --git a/sr_port/mupip_load_ch.c b/sr_port/mupip_load_ch.c index 894e198..4c4e8f5 100644 --- a/sr_port/mupip_load_ch.c +++ b/sr_port/mupip_load_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,7 @@ #include "error.h" #include "util.h" +#include "preemptive_db_clnup.h" GBLDEF bool mupip_DB_full; GBLREF bool mupip_error_occurred; @@ -41,6 +42,7 @@ CONDITION_HANDLER(mupip_load_ch) CONTINUE; } else { + preemptive_db_clnup(SEVERITY); /* to clean gv_target up before continuing in case of an error */ mupip_error_occurred = TRUE; # ifdef UNIX UNWIND(NULL, NULL); diff --git a/sr_port/mupip_recover.c b/sr_port/mupip_recover.c index f8cef8e..9d97e42 100644 --- a/sr_port/mupip_recover.c +++ b/sr_port/mupip_recover.c @@ -46,6 +46,7 @@ #include "gtmmsg.h" #include "mupip_recover.h" #include "wbox_test_init.h" +#include "anticipatory_freeze.h" #ifdef GTM_TRIGGER #include "error_trap.h" #endif @@ -85,6 +86,8 @@ GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related i error_def(ERR_ASSERT); error_def(ERR_BLKCNTEDITFAIL); +error_def(ERR_DBCOLLREQ); +error_def(ERR_SETEXTRENV); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); @@ -205,8 +208,12 @@ void mupip_recover(void) repl_histinfo local_histinfo; seq_num max_reg_seqno, replinst_seqno; unix_db_info *udi; + boolean_t db_absent = FALSE; + reg_ctl_list *db_absent_rctl; #endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; ESTABLISH(mupip_recover_ch); GTMTRIG_DBG_ONLY(ch_at_trigger_init = &mupip_recover_ch); /* PHASE 1: Process user input, open journal files, create rctl for phase 2 */ @@ -215,11 +222,10 @@ void mupip_recover(void) mur_get_options(); /*DEFER_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES); */ mur_open_files_status = mur_open_files(); + jgbl.mur_extract = mur_options.extr[GOOD_TN]; /* journal extract process */ /*ENABLE_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES);*/ if (!mur_open_files_status) /* mur_open_files already issued error */ - { mupip_exit(ERR_MUNOACTION); - } VMS_ONLY(assert(!mur_options.rollback_losttnonly);) UNIX_ONLY(assert(!mur_options.rollback_losttnonly || mur_options.rollback);) murgbl.prc_vec = prc_vec; @@ -237,6 +243,13 @@ void mupip_recover(void) rctl = &mur_ctl[regno]; jctl = rctl->jctl; assert(NULL == jctl->next_gen); +# ifdef UNIX + if (!rctl->db_present) + { + db_absent = TRUE; + db_absent_rctl = rctl; + } +# endif if (!jctl->properly_closed) all_gen_properly_closed = FALSE; if (jctl->jfh->recover_interrupted) @@ -254,6 +267,24 @@ void mupip_recover(void) } } # ifdef UNIX + if (!mur_options.update && jgbl.mur_extract && (db_absent || IS_REPL_INST_FROZEN)) + { + if (TREF(jnl_extract_nocol)) + { + TREF(jnl_extract_nocol) = !mur_options.update && jgbl.mur_extract && TREF(jnl_extract_nocol); + if (db_absent) + gtm_putmsg(VARLSTCNT(6) ERR_DBCOLLREQ, 4, LEN_AND_LIT("Mising Database file"), + DB_LEN_STR(db_absent_rctl->gd)); + else + gtm_putmsg(VARLSTCNT(6) ERR_DBCOLLREQ, 4, LEN_AND_LIT("Instance is frozen."), + LEN_AND_LIT("")); + } else + { + gtm_putmsg(VARLSTCNT(1) ERR_SETEXTRENV); + mupip_exit(ERR_MUNOACTION); + } + } else + TREF(jnl_extract_nocol) = 0; max_reg_seqno = 0; for (regno = 0; regno < reg_total; regno++) { diff --git a/sr_port/mupip_reorg.c b/sr_port/mupip_reorg.c index 1f876ac..45a2882 100644 --- a/sr_port/mupip_reorg.c +++ b/sr_port/mupip_reorg.c @@ -1,6 +1,6 @@ /*************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -76,19 +76,24 @@ 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; GBLREF gd_addr *gd_header; GBLREF gd_region *gv_cur_region; -GBLREF gv_key *gv_currkey_next_reorg; +GBLREF gv_key *gv_currkey_next_reorg, *gv_currkey, *gv_altkey; +GBLREF int gv_keysize; GBLREF gv_namehead *reorg_gv_target; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF uint4 process_id; GBLREF tp_region *grlist; GBLREF bool error_mupip; - +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +#endif void mupip_reorg(void) { boolean_t resume, reorg_success = TRUE; @@ -99,6 +104,8 @@ void mupip_reorg(void) uint4 cli_status; unsigned short n_len; boolean_t truncate, cur_success, restrict_reg, arg_present; + int root_swap_statistic; + mval gn; # ifdef GTM_TRUNCATE int4 truncate_percent; boolean_t gotlock; @@ -107,10 +114,12 @@ void mupip_reorg(void) node_local_ptr_t cnl; trunc_region *reg_list, *tmp_reg, *reg_iter, *prev_reg; uint4 fs; + uint4 lcl_pid; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + UNIX_ONLY(jnlpool_init_needed = TRUE); mu_outofband_setup(); truncate = FALSE; GTM_TRUNCATE_ONLY( @@ -208,7 +217,7 @@ void mupip_reorg(void) /* gv_select will select globals for this clause */ gv_select(cli_buff, n_len, FALSE, "EXCLUDE", &exclude_gl_head, ®_max_rec, ®_max_key, ®_max_blk, FALSE); if (!exclude_gl_head.next) - gtm_putmsg(VARLSTCNT(1) ERR_NOEXCLUDE); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOEXCLUDE); } n_len = SIZEOF(cli_buff); memset(cli_buff, 0, n_len); @@ -227,72 +236,98 @@ void mupip_reorg(void) gv_select(cli_buff, n_len, FALSE, "SELECT", &gl_head, ®_max_rec, ®_max_key, ®_max_blk, restrict_reg); if (!gl_head.next) { - rts_error(VARLSTCNT(1) ERR_NOSELECT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSELECT); mupip_exit(ERR_NOSELECT); } TREF(want_empty_gvts) = FALSE; + root_swap_statistic = 0; mu_reorg_process = TRUE; assert(NULL == gv_currkey_next_reorg); - GVKEY_INIT(gv_currkey_next_reorg, DBKEYSIZE(MAX_KEY_SZ)); + gv_keysize = DBKEYSIZE(MAX_KEY_SZ); + GVKEY_INIT(gv_currkey_next_reorg, gv_keysize); + GVKEY_INIT(gv_currkey, gv_keysize); + GVKEY_INIT(gv_altkey, gv_keysize); reorg_gv_target = targ_alloc(MAX_KEY_SZ, NULL, NULL); + reorg_gv_target->hist.depth = 0; + reorg_gv_target->alt_hist->depth = 0; for (gl_ptr = gl_head.next; gl_ptr; gl_ptr = gl_ptr->next) { util_out_print(" ", FLUSH); util_out_print("Global: !AD ", FLUSH, gl_ptr->name.str.len, gl_ptr->name.str.addr); if (in_exclude_list((uchar_ptr_t)gl_ptr->name.str.addr, gl_ptr->name.str.len, &exclude_gl_head)) { - gtm_putmsg(VARLSTCNT(4) ERR_EXCLUDEREORG, 2, gl_ptr->name.str.len, gl_ptr->name.str.addr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_EXCLUDEREORG, 2, gl_ptr->name.str.len, gl_ptr->name.str.addr); reorg_success = FALSE; continue; } + /* Save the global name in reorg_gv_target. Via gv_currkey_next_reorg, it's possible for gv_currkey to become + * out of sync with gv_target. We'll use reorg_gv_target->gvname to make sure the correct root block is found. + */ + reorg_gv_target->gvname.var_name.addr = gl_ptr->name.str.addr; + reorg_gv_target->gvname.var_name.len = gl_ptr->name.str.len; cur_success = mu_reorg(&gl_ptr->name, &exclude_gl_head, &resume, index_fill_factor, data_fill_factor, reorg_op); reorg_success &= cur_success; + SET_GV_CURRKEY_FROM_REORG_GV_TARGET; # ifdef GTM_TRUNCATE - /* if we successfully reorged this global, add its corresponding region to the set (list) of regions to truncate */ - if (cur_success) - { - /* insert gv_cur_region into set */ - /* in the future, might give REORG a region option... keep that in mind */ - /* Prepare a list of regions for truncate to work on */ - for (reg_iter = reg_list, prev_reg = reg_list; reg_iter; reg_iter = reg_iter->next) - if (reg_iter->reg == gv_cur_region) - break; - else - prev_reg = reg_iter; - if (NULL == reg_iter) - { - tmp_reg = (trunc_region *)malloc(SIZEOF(trunc_region)); - tmp_reg->reg = gv_cur_region; - tmp_reg->next = NULL; - if (NULL == reg_list) - reg_list = tmp_reg; - else - prev_reg->next = tmp_reg; + if (truncate) + { /* No need to move root blocks unless truncating */ + cur_success &= mu_swap_root(&gl_ptr->name, &root_swap_statistic); + if (cur_success) + { /* add region corresponding to this global to the set (list) of regions to truncate */ + for (reg_iter = reg_list, prev_reg = reg_list; reg_iter; reg_iter = reg_iter->next) + if (reg_iter->reg == gv_cur_region) + break; + else + prev_reg = reg_iter; + if (NULL == reg_iter) + { + tmp_reg = (trunc_region *)malloc(SIZEOF(trunc_region)); + tmp_reg->reg = gv_cur_region; + tmp_reg->next = NULL; + if (NULL == reg_list) + reg_list = tmp_reg; + else + prev_reg->next = tmp_reg; +# ifdef GTM_TRIGGER + if (truncate) + { /* Reorg ^#t in this region to move it out of the way. */ + gn = literal_hasht; + reorg_gv_target->gvname.var_name.addr = gn.str.addr; + reorg_gv_target->gvname.var_name.len = gn.str.len; + cur_success = mu_reorg(&gn, &exclude_gl_head, &resume, index_fill_factor, + data_fill_factor, reorg_op); + reorg_success &= cur_success; + SET_GV_CURRKEY_FROM_REORG_GV_TARGET; + reorg_success &= mu_swap_root(&gn, &root_swap_statistic); + } +# endif + } } } # endif if (mu_ctrlc_occurred || mu_ctrly_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_REORGCTRLY); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGCTRLY); mupip_exit(ERR_MUNOFINISH); } } if (!reorg_success) { - rts_error(VARLSTCNT(1) ERR_REORGINC); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGINC); mupip_exit(ERR_REORGINC); } else if (truncate) { # ifdef GTM_TRUNCATE + util_out_print("Total root blocks moved: !UL", FLUSH, root_swap_statistic); mu_reorg_process = FALSE; /* Default threshold is 0 i.e. we attempt to truncate no matter what free_blocks is. */ truncate_percent = 0; cli_get_int("TRUNCATE", (int4 *)&truncate_percent); if (99 < truncate_percent) { - gtm_putmsg(VARLSTCNT(1) ERR_MUTRUNCPERCENT); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUTRUNCPERCENT); mupip_exit(ERR_MUTRUNCFAIL); } for (reg_iter = reg_list; reg_iter; reg_iter = reg_iter->next) @@ -304,10 +339,12 @@ void mupip_reorg(void) cnl = csa->nl; /* Ensure only one truncate process at a time operates on given region */ grab_crit(gv_cur_region); - if (cnl->trunc_pid && is_proc_alive(cnl->trunc_pid, 0)) + lcl_pid = cnl->trunc_pid; + if (lcl_pid && is_proc_alive(lcl_pid, 0)) { rel_crit(gv_cur_region); - send_msg(VARLSTCNT(4) ERR_MUTRUNC1ATIME, 3, cnl->trunc_pid, REG_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_MUTRUNC1ATIME, 3, lcl_pid, + REG_LEN_STR(gv_cur_region)); continue; } cnl->trunc_pid = process_id; @@ -321,7 +358,7 @@ void mupip_reorg(void) rel_crit(gv_cur_region); if (mu_ctrlc_occurred || mu_ctrly_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_REORGCTRLY); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGCTRLY); mupip_exit(ERR_MUNOFINISH); } } diff --git a/sr_port/mupip_reorg.h b/sr_port/mupip_reorg.h index f956538..d6a749d 100644 --- a/sr_port/mupip_reorg.h +++ b/sr_port/mupip_reorg.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,6 +15,11 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int index_fill_factor, int data_fill_factor, int reorg_op); +# ifdef UNIX +boolean_t mu_swap_root(mval *gn, int *root_swap_statistic_ptr); +block_id swap_root_or_directory_block(int parent_blk_lvl, int level, srch_hist *dir_hist_ptr, block_id child_blk_id, + sm_uc_ptr_t child_blk_ptr, kill_set *kill_set_list, trans_num curr_tn); +# endif enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_set_ptr, boolean_t *remove_rtsib); enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_created, int *lvls_increased); enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_ptr, glist *exclude_glist_ptr); diff --git a/sr_port/mupip_set.c b/sr_port/mupip_set.c index ad35e7c..8b0b19e 100644 --- a/sr_port/mupip_set.c +++ b/sr_port/mupip_set.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,8 +30,14 @@ #include "mupip_exit.h" #include "mu_getlst.h" -GBLDEF bool region; -GBLREF bool error_mupip; +GBLDEF bool region; +GBLREF bool error_mupip; +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +#endif + +error_def(ERR_MUNOACTION); +error_def(ERR_MUNODBNAME); void mupip_set(void) { @@ -42,9 +48,7 @@ void mupip_set(void) int cli_stat; boolean_t set_journal, set_replication; - error_def(ERR_MUNOACTION); - error_def(ERR_MUNODBNAME); - + UNIX_ONLY(jnlpool_init_needed = TRUE); file = cli_present("FILE") == CLI_PRESENT; region = cli_present("REGION") == CLI_PRESENT; jnlfile = cli_present("JNLFILE") == CLI_PRESENT; @@ -52,7 +56,6 @@ void mupip_set(void) set_journal = ((CLI_PRESENT == cli_stat) || (CLI_NEGATED == cli_stat)); cli_stat = cli_present("REPLICATION"); /* just save a call to cli_present */ set_replication = ((CLI_PRESENT == cli_stat) || (CLI_NEGATED == cli_stat)); - if (region) { gvinit(); @@ -77,14 +80,25 @@ void mupip_set(void) mupip_exit(status); } if (cli_present("ACCESS_METHOD") == CLI_PRESENT || +# ifdef UNIX + cli_present("INST_FREEZE_ON_ERROR") == CLI_PRESENT || + cli_present("INST_FREEZE_ON_ERROR") == CLI_NEGATED || +# endif cli_present("EXTENSION_COUNT") == CLI_PRESENT || cli_present("GLOBAL_BUFFERS") == CLI_PRESENT || cli_present("RESERVED_BYTES") == CLI_PRESENT || cli_present("FLUSH_TIME") == CLI_PRESENT || cli_present("LOCK_SPACE") == CLI_PRESENT || + cli_present("MUTEX_SLOTS") == CLI_PRESENT || cli_present("DEFER_TIME") == CLI_PRESENT || cli_present("WAIT_DISK") == CLI_PRESENT || cli_present("PARTIAL_RECOV_BYPASS") == CLI_PRESENT || +# ifdef UNIX + cli_present("KEY_SIZE") == CLI_PRESENT || + cli_present("QDBRUNDOWN") == CLI_PRESENT || + cli_present("QDBRUNDOWN") == CLI_NEGATED || + cli_present("RECORD_SIZE") == CLI_PRESENT || +# endif cli_present("VERSION") == CLI_PRESENT) { if (SS_NORMAL != (status = mupip_set_file(db_fn_len, db_fn))) diff --git a/sr_port/mupip_set.h b/sr_port/mupip_set.h index 31172e7..c17dcd0 100644 --- a/sr_port/mupip_set.h +++ b/sr_port/mupip_set.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,6 +11,6 @@ int4 mupip_set_file(int db_fn_len, char *db_fn); int4 mupip_set_jnlfile(char *jnl_fname, int jnl_fn_len); -void mupip_set_jnl_cleanup(boolean_t clean_exit); +void mupip_set_jnl_cleanup(void); uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn); void mupip_set(void); diff --git a/sr_port/mupip_set_jnl_ch.c b/sr_port/mupip_set_jnl_ch.c index 0144237..e5a02de 100644 --- a/sr_port/mupip_set_jnl_ch.c +++ b/sr_port/mupip_set_jnl_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,12 +23,12 @@ #include "mupip_exit.h" #include "mupip_set.h" /* for mupip_set_jnl_cleanup() prototype */ +error_def(ERR_MUNOFINISH); + CONDITION_HANDLER(mupip_set_jnl_ch) { - error_def(ERR_MUNOFINISH); - START_CH - mupip_set_jnl_cleanup(FALSE); + mupip_set_jnl_cleanup(); PRN_ERROR if (SEVERITY == ERROR || SEVERITY == SEVERE) mupip_exit(ERR_MUNOFINISH); diff --git a/sr_port/mupip_set_jnl_cleanup.c b/sr_port/mupip_set_jnl_cleanup.c index 774ed25..7038613 100644 --- a/sr_port/mupip_set_jnl_cleanup.c +++ b/sr_port/mupip_set_jnl_cleanup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,10 +45,13 @@ GBLREF mu_set_rlist *grlist; GBLREF gd_region *gv_cur_region; -void mupip_set_jnl_cleanup(boolean_t clean_exit) +error_def(ERR_NOTALLDBRNDWN); + +void mupip_set_jnl_cleanup(void) { mu_set_rlist *rptr; file_control *fc; + int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ VMS_ONLY( GDS_INFO *gds_info; uint4 status; @@ -93,10 +96,13 @@ void mupip_set_jnl_cleanup(boolean_t clean_exit) tp_change_reg(); assert(NULL != gv_cur_region->dyn.addr->file_cntl && NULL != rptr->sd); if (NULL != gv_cur_region->dyn.addr->file_cntl && NULL != rptr->sd) - gds_rundown(); + UNIX_ONLY(rundown_status |=) gds_rundown(); /* Note: We did not allocate, so we do not deallocate rptr->sd */ rptr->sd = NULL; } rptr->state = DEALLOCATED; } + + if (EXIT_NRM != rundown_status) + rts_error(VARLSTCNT(1) ERR_NOTALLDBRNDWN); } diff --git a/sr_port/mupip_set_journal.c b/sr_port/mupip_set_journal.c index 734bf27..d02d7b8 100644 --- a/sr_port/mupip_set_journal.c +++ b/sr_port/mupip_set_journal.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,7 @@ #endif #include "gtm_string.h" #include "gtm_time.h" +#include "gtm_stdio.h" #include "gdsroot.h" #include "gtm_facility.h" @@ -78,7 +79,8 @@ error_def(ERR_FILENAMETOOLONG); error_def(ERR_FILEPARSE); error_def(ERR_JNLALIGNTOOSM); error_def(ERR_JNLALLOCGROW); -error_def(ERR_JNLBUFFTOOSM); +error_def(ERR_JNLBUFFDBUPD); +error_def(ERR_JNLBUFFREGUPD); error_def(ERR_JNLCREATE); error_def(ERR_JNLFNF); error_def(ERR_JNLINVSWITCHLMT); @@ -109,13 +111,12 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) int curr_stat_res; /* gtm_file_stat() return value for current journal file name */ mu_set_rlist *rptr, dummy_rlist, *next_rptr; sgmnt_data_ptr_t csd; - uint4 status, - exit_status = EXIT_NRM; + uint4 status, exit_status = EXIT_NRM, gds_rundown_status = EXIT_NRM; seq_num max_reg_seqno; unsigned int fn_len; unsigned char tmp_full_jnl_fn[MAX_FN_LEN + 1], prev_jnl_fn[MAX_FN_LEN + 1]; char *db_reg_name, db_or_reg[DB_OR_REG_SIZE]; - int db_reg_name_len, db_or_reg_len, jnl_buffer_size; + int db_reg_name_len, db_or_reg_len; set_jnl_options jnl_options; boolean_t curr_jnl_present, /* for current state 2, is current journal present? */ jnl_points_to_db, keep_prev_link, safe_to_switch, newjnlfiles, jnlname_same, @@ -132,7 +133,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) jnl_file_header header; int4 status1; uint4 status2; + boolean_t header_is_usable = FALSE; # endif + boolean_t jnl_buffer_updated = FALSE, jnl_buffer_invalid = FALSE; + int jnl_buffer_size; + char s[JNLBUFFUPDAPNDX_SIZE]; /* JNLBUFFUPDAPNDX_SIZE is defined in jnl.h */ assert(SGMNT_HDR_LEN == ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE)); memset(&jnl_info, 0, SIZEOF(jnl_info)); @@ -140,7 +145,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) max_reg_seqno = 1; if (!mupip_set_journal_parse(&jnl_options, &jnl_info)) { - gtm_putmsg(VARLSTCNT(1) ERR_MUPCLIERR); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR); + error_condition = ERR_MUPCLIERR; return ERR_MUPCLIERR; } if (region && (NULL == grlist)) @@ -158,9 +164,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) return (uint4)ERR_MUNOFINISH; } } else - { /* The command line specified a single database file; - force the following do-loop to be one-trip */ - dummy_rlist.fPtr= NULL; + { /* The command line specified a single database file; force the following do-loop to be one-trip */ + dummy_rlist.fPtr = NULL; grlist = &dummy_rlist; } ESTABLISH_RET(mupip_set_jnl_ch, (uint4)ERR_MUNOFINISH); @@ -174,7 +179,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) { if (dba_usr == rptr->reg->dyn.addr->acc_meth) { - gtm_putmsg(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Journaling is not supported for access method USR")); exit_status |= EXIT_WRN; continue; @@ -213,7 +218,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) assert(!gv_cur_region->was_open); /* In case mupip_set_file opened it, they must have closed */ if (gv_cur_region->read_only) { - gtm_putmsg(VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region)); exit_status |= EXIT_RDONLY; continue; } @@ -224,7 +229,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) if (EXIT_NRM != (status = mupip_set_journal_newstate(&jnl_options, &jnl_info, rptr))) { exit_status |= status; - gds_rundown(); + UNIX_ONLY(gds_rundown_status =) gds_rundown(); + exit_status |= gds_rundown_status; rptr->sd = NULL; rptr->state = NONALLOCATED; /* This means do not call gds_rundown() again for this region * and do not process this region anymore. */ @@ -253,7 +259,9 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) (repl_closed != repl_curr_state && repl_closed == rptr->repl_new_state) || (repl_closed == repl_curr_state && repl_open == rptr->repl_new_state)) { - gds_rundown(); /* Since we did gvcst_init() and now will call mu_rndwn_file() */ + /* Since we did gvcst_init() and now will call mu_rndwn_file() */ + UNIX_ONLY(gds_rundown_status =) gds_rundown(); + exit_status |= gds_rundown_status; rptr->state = NONALLOCATED; rptr->sd = csd = NULL; /* WARNING: The remaining code uses gv_cur_region and others @@ -262,6 +270,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) assert(NULL != gv_cur_region->dyn.addr); assert(NULL != gv_cur_region->dyn.addr->file_cntl); assert(NULL != gv_cur_region->dyn.addr->file_cntl->file_info); + if (EXIT_NRM != gds_rundown_status) /* skip mu_rndwn_file (STANDALONE) */ + continue; if (STANDALONE(gv_cur_region)) { rptr->exclusive = TRUE; @@ -294,7 +304,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) rptr->state = ALLOCATED; } else { - gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_MUSTANDALONE, 2, + DB_LEN_STR(gv_cur_region)); exit_status |= EXIT_ERR; continue; } @@ -337,6 +348,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) jnl_curr_state = (enum jnl_state_codes)csd->jnl_state; repl_curr_state = (enum repl_state_codes)csd->repl_state; jnl_info.csd = csd; + jnl_info.csa = cs_addrs; jnl_info.before_images = rptr->before_images; jnl_info.repl_state = rptr->repl_new_state; jnl_info.jnl_state = csd->jnl_state; @@ -369,10 +381,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) jnl_info.alloc = (0 == csd->jnl_alq) ? JNL_ALLOC_DEF : csd->jnl_alq; assert(JNL_ALLOC_DEF >= JNL_ALLOC_MIN); if (JNL_ALLOC_MIN > jnl_info.alloc) - { /* Fix file header in addition to fixing new journal file settings */ - csd->jnl_alq = JNL_ALLOC_MIN; - jnl_info.alloc = JNL_ALLOC_MIN; - } + jnl_info.alloc = JNL_ALLOC_MIN; /* Fix new journal settings. */ } if (!jnl_options.alignsize_specified) { @@ -380,19 +389,18 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) csd->alignsize; /* In bytes */ assert(JNL_DEF_ALIGNSIZE >= JNL_MIN_ALIGNSIZE); if ((DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE) > jnl_info.alignsize) - { /* Fix file header in addition to fixing new journal file settings */ - csd->alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE); - jnl_info.alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE); - } + jnl_info.alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE); /* Fix new journal settings. */ } if (jnl_info.alignsize <= csd->blk_size) { if (region) - gtm_putmsg(VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, jnl_info.alignsize, csd->blk_size, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, + jnl_info.alignsize, csd->blk_size, LEN_AND_LIT("region"), REG_LEN_STR(gv_cur_region), (DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE)); else - gtm_putmsg(VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, jnl_info.alignsize, csd->blk_size, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, + jnl_info.alignsize, csd->blk_size, LEN_AND_LIT("database file"), jnl_info.fn_len, jnl_info.fn, (DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE)); @@ -411,32 +419,22 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) /* jnl_info.extend = (0 == csd->jnl_deq) ? jnl_info.alloc * JNL_EXTEND_DEF_PERC : csd->jnl_deq; * Uncomment this section when code is ready to use extension = 10% of allocation */ } - if (!jnl_options.buffer_size_specified || jnl_info.buffer < csd->blk_size / DISK_BLOCK_SIZE + 1) + if (!jnl_options.buffer_size_specified) + jnl_info.buffer = (0 == csd->jnl_buffer_size) ? JNL_BUFFER_DEF : csd->jnl_buffer_size; + ROUND_UP_JNL_BUFF_SIZE(jnl_buffer_size, jnl_info.buffer, csd); + if (jnl_buffer_size < JNL_BUFF_PORT_MIN(csd)) { - if (jnl_options.buffer_size_specified) - { - gtm_putmsg(VARLSTCNT(4) ERR_JNLBUFFTOOSM, 2, - jnl_info.buffer, csd->blk_size / DISK_BLOCK_SIZE + 1); - exit_status |= EXIT_WRN; - } - jnl_buffer_size = (0 == csd->jnl_buffer_size) ? JNL_BUFFER_DEF : csd->jnl_buffer_size; - } else - jnl_buffer_size = jnl_info.buffer; - jnl_buffer_size = ROUND_UP(jnl_buffer_size, MIN(MAX_IO_BLOCK_SIZE, cs_data->blk_size) / DISK_BLOCK_SIZE); - if ((jnl_options.buffer_size_specified && jnl_buffer_size != jnl_info.buffer) - || (!jnl_options.buffer_size_specified - && 0 != csd->jnl_buffer_size && jnl_buffer_size != csd->jnl_buffer_size)) + jnl_buffer_invalid = TRUE; + ROUND_UP_MIN_JNL_BUFF_SIZE(jnl_buffer_size, csd); + } else if (jnl_buffer_size > JNL_BUFFER_MAX) { - if (region) - util_out_print("Journal file buffer size for region !AD is now !SL", TRUE, - REG_LEN_STR(gv_cur_region), jnl_buffer_size); - else - util_out_print("Journal file buffer size for database file !AD is now !SL", TRUE, - jnl_info.fn_len, jnl_info.fn, jnl_buffer_size); + jnl_buffer_invalid = TRUE; + ROUND_DOWN_MAX_JNL_BUFF_SIZE(jnl_buffer_size, csd); } + if (jnl_buffer_size != jnl_info.buffer) + jnl_buffer_updated = TRUE; /* ensure we have exclusive access in case csd->jnl_buffer_size is going to be changed */ - assert((!(jnl_options.buffer_size_specified && csd->jnl_buffer_size != jnl_buffer_size)) - || rptr->exclusive); + assert(!(jnl_options.buffer_size_specified && jnl_buffer_updated) || rptr->exclusive); if (!jnl_options.epoch_interval_specified) jnl_info.epoch_interval = (0 == csd->epoch_interval) ? DEFAULT_EPOCH_INTERVAL : csd->epoch_interval; JNL_MAX_RECLEN(&jnl_info, csd); @@ -454,18 +452,19 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) */ if (jnl_info.autoswitchlimit < jnl_info.alloc) { - gtm_putmsg(VARLSTCNT(7) ERR_JNLSWITCHTOOSM, 5, jnl_info.autoswitchlimit, - jnl_info.alloc, DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_JNLSWITCHTOOSM, 5, + jnl_info.autoswitchlimit, jnl_info.alloc, DB_LEN_STR(gv_cur_region)); if (newjnlfiles) - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_ERR; break; #ifdef UNIX } else if (jnl_info.alloc + jnl_info.extend > jnl_info.autoswitchlimit && jnl_info.alloc != jnl_info.autoswitchlimit) { - gtm_putmsg(VARLSTCNT(8) ERR_JNLALLOCGROW, 6, jnl_info.alloc, jnl_info.autoswitchlimit, - "database file", DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLALLOCGROW, 6, jnl_info.alloc, + jnl_info.autoswitchlimit, "database file", DB_LEN_STR(gv_cur_region)); jnl_info.alloc = jnl_info.autoswitchlimit; #endif } else @@ -482,15 +481,15 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) if (jnl_options.autoswitchlimit_specified || jnl_options.extension_specified || jnl_options.allocation_specified) { /* print rounding down of autoswitchlimit only if journal options were specified */ - gtm_putmsg(VARLSTCNT(8) ERR_JNLSWITCHSZCHG, 6, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSWITCHSZCHG, 6, jnl_info.autoswitchlimit, align_autoswitch, jnl_info.alloc, jnl_info.extend, DB_LEN_STR(gv_cur_region)); } jnl_info.autoswitchlimit = align_autoswitch; if (JNL_AUTOSWITCHLIMIT_MIN > jnl_info.autoswitchlimit) { - gtm_putmsg(VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info.autoswitchlimit, - JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, + jnl_info.autoswitchlimit, JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX); exit_status |= EXIT_ERR; break; } @@ -506,9 +505,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) jnldef.len = SIZEOF(JNL_EXT_DEF) - 1; if (FILE_STAT_ERROR == (new_stat_res = gtm_file_stat(&jnlfile, &jnldef, &tmpjnlfile, TRUE, &status))) { - gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len, jnlfile.addr, status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len, + jnlfile.addr, status); if (newjnlfiles) - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnlfile.len, jnlfile.addr); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnlfile.len, jnlfile.addr); exit_status |= EXIT_ERR; break; } @@ -518,8 +519,9 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) /* Note: At this point jnlfile should have expanded journal name with extension */ if (MAX_FN_LEN + 1 < jnl_info.jnl_len) { - gtm_putmsg(VARLSTCNT(1) ERR_FILENAMETOOLONG); - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_FILENAMETOOLONG); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_ERR; break; } @@ -531,9 +533,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) { if (FILE_STAT_ERROR == (curr_stat_res = gtm_file_stat(&jnlfile, NULL, NULL, TRUE, &status))) { - gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len, jnlfile.addr, status); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2, + jnlfile.len, jnlfile.addr, status); if (newjnlfiles) - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_ERR; break; } @@ -576,13 +580,14 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) if (is_file_identical((char *)header.data_file_name, (char *)jnl_info.fn)) jnl_points_to_db = TRUE; + UNIX_ONLY(header_is_usable = TRUE;) } } } /* If journal file we are about to create exists, allow the switch only it is safe to do so. * This way we prevent multiple environments from interfering with each other through a * common journal file name. Also this way we disallow switching to a user-specified new - * journal file that already exists (say the database file itself due to a commandline typo). + * journal file that already exists (say the database file itself due to a command line typo). */ if (FILE_PRESENT & curr_stat_res) { @@ -604,8 +609,10 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) } if ((FILE_PRESENT & new_stat_res) && !safe_to_switch) { - gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl); - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_FILEEXISTS, 2, + jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_ERR; break; } @@ -624,14 +631,17 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) { if (FILE_READONLY & curr_stat_res) { - gtm_putmsg(VARLSTCNT(4) ERR_JNLRDONLY, 2, JNL_LEN_STR(csd)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLRDONLY, 2, + JNL_LEN_STR(csd)); if (newjnlfiles) - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) + ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_RDONLY; continue; } } else - gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, JNL_LEN_STR(csd)); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLFNF, 2, + JNL_LEN_STR(csd)); } if (!rptr->exclusive) { @@ -643,8 +653,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) VMS_ONLY(if (memcmp(cs_addrs->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid)))) { if (SS_NORMAL != (status = set_jnl_file_close(SET_JNL_FILE_CLOSE_SETJNL))) - { - /* Invoke jnl_file_lost to turn off journaling and retry journal creation + { /* Invoke jnl_file_lost to turn off journaling and retry journal creation * to create fresh journal files. */ jnl_file_lost(jpc, status); @@ -653,6 +662,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) next_rptr = rptr; continue; } + UNIX_ONLY(header.crash = FALSE;) /* Even if the journal was crashed, that + * should be fixed now */ } else { /* Ideally, no other process should have a journal file for this database open. * But, As part of C9I03-002965, we realized it is possible for processes accessing @@ -665,6 +676,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) assert(NULL != jpc); jpc->jnl_buff->cycle++; } +# ifdef UNIX + /* Cut the link if the journal is crashed and there is no shared memory around */ + if (header_is_usable && header.crash) + keep_prev_link = FALSE; +# endif /* For MM, set_jnl_file_close() can call wcs_flu() which can remap the file. * So reset csd and rptr->sd since their value may have changed. */ @@ -689,8 +705,10 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) # ifdef VMS if (!jnlname_same && (FILE_PRESENT & new_stat_res)) { - gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl); - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) + ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) + ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); exit_status |= EXIT_ERR; break; } @@ -720,20 +738,21 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) if (EXIT_NRM != (status = cre_jnl_file(&jnl_info))) { /* There was an error attempting to create the journal file */ exit_status |= status; - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2, + jnl_info.jnl_len, jnl_info.jnl); continue; } csd->jnl_checksum = jnl_info.checksum; csd->jnl_eovtn = csd->trans_hist.curr_tn; - gtm_putmsg(VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl, db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name, LEN_AND_STR(before_image_lit[(jnl_info.before_images ? 1 : 0)])); if ((!curr_jnl_present && (jnl_open == jnl_curr_state)) || (curr_jnl_present && jnl_info.no_prev_link) || this_iter_prevlinkcut_error) { - gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, jnl_info.jnl_len, jnl_info.jnl, DB_LEN_STR(gv_cur_region)); - send_msg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, jnl_info.jnl_len, jnl_info.jnl, DB_LEN_STR(gv_cur_region)); } } @@ -746,6 +765,21 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) csd->alignsize = jnl_info.alignsize; csd->autoswitchlimit = jnl_info.autoswitchlimit; csd->jnl_buffer_size = jnl_buffer_size; + if (jnl_buffer_updated) + if (jnl_buffer_invalid) + { + SNPRINTF(s, JNLBUFFUPDAPNDX_SIZE, JNLBUFFUPDAPNDX, JNL_BUFF_PORT_MIN(csd), JNL_BUFFER_MAX); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) + (region ? ERR_JNLBUFFREGUPD : ERR_JNLBUFFDBUPD), 4, + (region ? gv_cur_region->rname_len : jnl_info.fn_len), + (region ? gv_cur_region->rname : jnl_info.fn), + jnl_info.buffer, jnl_buffer_size, ERR_TEXT, 2, LEN_AND_STR(s)); + } else + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) + (region ? ERR_JNLBUFFREGUPD : ERR_JNLBUFFDBUPD), 4, + (region ? gv_cur_region->rname_len : jnl_info.fn_len), + (region ? gv_cur_region->rname : jnl_info.fn), + jnl_info.buffer, jnl_buffer_size); csd->epoch_interval = jnl_info.epoch_interval; csd->jnl_deq = jnl_info.extend; memcpy(csd->jnl_file_name, jnl_info.jnl, jnl_info.jnl_len); @@ -771,11 +805,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) UNIX_ONLY(csd->yield_lmt = DEFAULT_YIELD_LIMIT;) } if (CLI_ABSENT != jnl_options.cli_journal || CLI_ABSENT != jnl_options.cli_replic_on) - gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name, - LEN_AND_STR(jnl_state_lit[rptr->jnl_new_state])); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, + db_reg_name, LEN_AND_STR(jnl_state_lit[rptr->jnl_new_state])); if (CLI_ABSENT != jnl_options.cli_replic_on) - gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name, - LEN_AND_STR(repl_state_lit[jnl_info.repl_state])); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, + db_reg_name, LEN_AND_STR(repl_state_lit[jnl_info.repl_state])); /* Write the updated information back to the database file */ fc->op = FC_WRITE; fc->op_buff = (sm_uc_ptr_t)csd; @@ -792,7 +826,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn) jgbl.dont_reset_gbl_jrec_time = FALSE; /* Ensure jgbl.gbl_jrec_time did not get reset by any of the jnl writing functions */ assert(save_gbl_jrec_time == jgbl.gbl_jrec_time); - mupip_set_jnl_cleanup(TRUE); + REVERT; + mupip_set_jnl_cleanup(); if (EXIT_NRM == exit_status) return (uint4)SS_NORMAL; if (exit_status & EXIT_WRN) diff --git a/sr_port/mupip_set_journal_parse.c b/sr_port/mupip_set_journal_parse.c index dd240b5..58272c2 100644 --- a/sr_port/mupip_set_journal_parse.c +++ b/sr_port/mupip_set_journal_parse.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,7 +35,6 @@ error_def(ERR_BFRQUALREQ); error_def(ERR_FILEPARSE); error_def(ERR_JNLALIGNSZCHG); -error_def(ERR_JNLBUFFTOOLG); error_def(ERR_JNLINVALLOC); error_def(ERR_JNLINVEXT); error_def(ERR_JNLINVSWITCHLMT); @@ -136,11 +135,6 @@ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info return FALSE; if (jnl_info->buffer <= 0) return FALSE; - if (jnl_info->buffer > JNL_BUFFER_MAX) - { - gtm_putmsg(VARLSTCNT(4) ERR_JNLBUFFTOOLG, 2, jnl_info->buffer, JNL_BUFFER_MAX); - return FALSE; - } } if (jnl_options->epoch_interval_specified = (CLI_PRESENT == cli_present("EPOCH_INTERVAL"))) { diff --git a/sr_port/mupip_upgrade.c b/sr_port/mupip_upgrade.c index 5bf58c0..34829a7 100644 --- a/sr_port/mupip_upgrade.c +++ b/sr_port/mupip_upgrade.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,6 +61,7 @@ #include "mu_upgrd_dngrd_confirmed.h" #include "mu_outofband_setup.h" #include "gdsbml.h" +#include "anticipatory_freeze.h" #ifdef UNIX #include "mu_all_version_standalone.h" #endif @@ -136,7 +137,7 @@ void mupip_upgrade(void) UNIX_ONLY(mu_all_version_get_standalone(db_fn, sem_inf)); mu_outofband_setup(); /* Will ignore user interrupts. Note that now the * elapsed time for this is order of milliseconds */ - /* ??? Should we set this just before DO_FILE_WRITE to have smallest time window of ignoring signal? */ + /* ??? Should we set this just before DB_DO_FILE_WRITE to have smallest time window of ignoring signal? */ #ifdef VMS mupfab = cc$rms_fab; mupfab.fab$l_fna = db_fn; @@ -207,23 +208,23 @@ void mupip_upgrade(void) { /* We have detected the master map which supports only 128M blocks so we need to * bump it up to one that supports 224M blocks. */ - csd.master_map_len = MASTER_MAP_SIZE_DFLT; - assert(START_VBN_CURRENT == csd.start_vbn); + csd.master_map_len = MASTER_MAP_SIZE_V5; + assert(START_VBN_V5 == csd.start_vbn); DEBUG_ONLY ( - norm_vbn = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE) + 1; - assert(START_VBN_CURRENT == norm_vbn); + norm_vbn = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_V5, DISK_BLOCK_SIZE) + 1; + assert(START_VBN_V5 == norm_vbn); ) csd.free_space = 0; - DO_FILE_WRITE(channel, 0, &csd, SIZEOF(csd), status, status2); + DB_DO_FILE_WRITE(channel, 0, &csd, SIZEOF(csd), status, status2); if (SS_NORMAL != status) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, db_fn_len, db_fn, status); mupip_exit(ERR_MUNOUPGRD); } - memset(new_v5_master_map, BMP_EIGHT_BLKS_FREE, (MASTER_MAP_SIZE_DFLT - MASTER_MAP_SIZE_V5_OLD)); - DO_FILE_WRITE(channel, SIZEOF(csd) + MASTER_MAP_SIZE_V5_OLD, new_v5_master_map, - (MASTER_MAP_SIZE_DFLT - MASTER_MAP_SIZE_V5_OLD), status, status2); + memset(new_v5_master_map, BMP_EIGHT_BLKS_FREE, (MASTER_MAP_SIZE_V5 - MASTER_MAP_SIZE_V5_OLD)); + DB_DO_FILE_WRITE(channel, SIZEOF(csd) + MASTER_MAP_SIZE_V5_OLD, new_v5_master_map, + (MASTER_MAP_SIZE_V5 - MASTER_MAP_SIZE_V5_OLD), status, status2); if (SS_NORMAL != status) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ @@ -316,14 +317,14 @@ void mupip_upgrade(void) mu_upgrd_header(&v15_csd, &csd); csd.master_map_len = MASTER_MAP_SIZE_V4; /* V5 master map is not part of file header */ memcpy(new_master_map, v15_csd.master_map, MASTER_MAP_SIZE_V4); - DO_FILE_WRITE(channel, 0, &csd, SIZEOF(csd), status, status2); + DB_DO_FILE_WRITE(channel, 0, &csd, SIZEOF(csd), status, status2); if (SS_NORMAL != status) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, db_fn_len, db_fn, status); mupip_exit(ERR_MUNOUPGRD); } - DO_FILE_WRITE(channel, SIZEOF(csd), new_master_map, MASTER_MAP_SIZE_V4, status, status2); + DB_DO_FILE_WRITE(channel, SIZEOF(csd), new_master_map, MASTER_MAP_SIZE_V4, status, status2); if (SS_NORMAL != status) { F_CLOSE(channel, rc); /* resets "channel" to FD_INVALID */ diff --git a/sr_port/mupipbckup.h b/sr_port/mupipbckup.h index daeae4a..de01d42 100644 --- a/sr_port/mupipbckup.h +++ b/sr_port/mupipbckup.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -74,6 +74,39 @@ typedef struct backup_reg_list_struct #define HDR_MSG "END OF FILE HEADER" #define MAP_MSG "END OF MASTER MAP" +/* check for online backup - ATTN: this part of code is similar to that in mm_update */ +#define BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, nontp_block_saved, tp_block_saved) \ +{ \ + boolean_t read_before_image; \ + trans_num bkup_blktn; \ + shmpool_buff_hdr_ptr_t sbufh_p; \ + \ + DEBUG_ONLY(read_before_image = \ + ((JNL_ENABLED(csa) && csa->jnl_before_image) || csa->backup_in_prog || SNAPSHOTS_IN_PROG(csa));) \ + assert(!read_before_image || (NULL == cs->old_block) || (backup_blk_ptr == cs->old_block)); \ + assert(csd == cs_data); /* backup_block uses cs_data hence this check */ \ + if ((blkid >= cnl->nbb) && (NULL != cs->old_block)) \ + { \ + sbufh_p = csa->shmpool_buffer; \ + if (0 == sbufh_p->failed) \ + { \ + bkup_blktn = ((blk_hdr_ptr_t)(backup_blk_ptr))->tn; \ + if ((bkup_blktn < sbufh_p->backup_tn) && (bkup_blktn >= sbufh_p->inc_backup_tn)) \ + { \ + assert(backup_cr->blk == blkid); \ + assert(cs->old_block == backup_blk_ptr); \ + /* to write valid before-image, ensure buffer is protected against preemption */ \ + assert(process_id == backup_cr->in_cw_set); \ + backup_block(csa, blkid, backup_cr, NULL); \ + if (!dollar_tlevel) \ + nontp_block_saved = TRUE; \ + else \ + tp_block_saved = TRUE; \ + } \ + } \ + } \ +} + LITREF mval mu_bin_datefmt; boolean_t backup_block(sgmnt_addrs *csa, block_id blk, cache_rec_ptr_t backup_cr, sm_uc_ptr_t backup_blk_p); diff --git a/sr_port/muprec.h b/sr_port/muprec.h index a212b81..c175e98 100644 --- a/sr_port/muprec.h +++ b/sr_port/muprec.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -154,7 +154,7 @@ error_def(ERR_MUJNLSTAT); struct tm *tsp; \ \ short_time = (time_t)input_time; \ - tsp = localtime((const time_t *)&short_time); \ + GTM_LOCALTIME(tsp, (const time_t *)&short_time); \ SPRINTF(time_str, "%04d/%02d/%02d %02d:%02d:%02d", \ (1900 + tsp->tm_year), (1 + tsp->tm_mon), tsp->tm_mday, tsp->tm_hour, tsp->tm_min, tsp->tm_sec); \ } @@ -648,6 +648,7 @@ typedef struct reg_ctl_list_struct boolean_t deleted_from_unprocessed_list; jnl_ctl_list *last_processed_jctl; uint4 last_processed_rec_offset; + seq_num last_processed_jnl_seqno; /* last jnl_seqno processed in this region */ # endif boolean_t db_present; /* TRUE if database pointed by curr->gd is present or not */ } reg_ctl_list; @@ -987,6 +988,25 @@ typedef struct onln_rlbk_reg_list_struct #define MUR_WITHIN_ERROR_LIMIT(err_cnt, error_limit) ((++err_cnt <= error_limit) || (mur_options.interactive && mur_interactive())) +#ifdef DEBUG +# define MUR_DBG_SET_LAST_PROCESSED_JNL_SEQNO(TOKEN, RCTL) \ + { \ + if (NULL != RCTL) \ + { \ + assert(!mur_options.rollback || RCTL->last_processed_jnl_seqno <= TOKEN); \ + RCTL->last_processed_jnl_seqno = TOKEN; \ + } \ + } +#else +# define MUR_DBG_SET_LAST_PROCESSED_JNL_SEQNO(TOKEN, RCTL) +#endif + +#define MUR_SET_JNL_FENCE_CTL_TOKEN(TOKEN, RCTL) \ +{ \ + MUR_DBG_SET_LAST_PROCESSED_JNL_SEQNO(TOKEN, RCTL); \ + jnl_fence_ctl.token = TOKEN; \ +} + #if defined(UNIX) #define MUR_TOKEN_LOOKUP(token, image_count, rec_time, fence) mur_token_lookup(token, rec_time, fence) #elif defined(VMS) @@ -1068,27 +1088,6 @@ typedef struct onln_rlbk_reg_list_struct assert(!holds_sem[RECV][RECV_SERV_OPTIONS_SEM]); \ } -#define ASSERT_VALID_JNLPOOL(CSA) \ -{ \ - GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ - GBLREF jnlpool_addrs jnlpool; \ - \ - assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \ - assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \ - assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \ - assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + CRIT_SPACE \ - + SIZEOF(mutex_spin_parms_struct))); \ - assert(jnlpool_ctl->filehdr_off); \ - assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \ - assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \ - assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->filehdr_off)); \ - assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->srclcl_array_off)); \ - assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->sourcelocal_array_off)); \ -} - /* Prototypes */ #ifdef UNIX seq_num mur_get_max_strm_reg_seqno(int strm_index); @@ -1102,7 +1101,7 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num jnl_tm_t alt_tp_resolve_time); uint4 mur_block_count_correct(reg_ctl_list *rctl); int4 mur_blocks_free(reg_ctl_list *rctl); -void mur_close_files(void); +boolean_t mur_close_files(void); void mur_close_file_extfmt(void); int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat); boolean_t mur_do_wildcard(char *jnl_str, char *pat_str, int jnl_len, int pat_len); diff --git a/sr_port/mur_apply_pblk.c b/sr_port/mur_apply_pblk.c index e274c12..b9e7a1a 100644 --- a/sr_port/mur_apply_pblk.c +++ b/sr_port/mur_apply_pblk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,6 +34,8 @@ #include "bit_clear.h" #include "bit_set.h" #include "min_max.h" +#include "anticipatory_freeze.h" +#include "eintr_wrappers.h" #ifdef GTM_CRYPT #include "gtm_string.h" #endif @@ -44,17 +46,18 @@ #include "repl_msg.h" #include "gtmsource.h" #include -GBLREF gd_region *gv_cur_region; GBLREF volatile int4 db_fsync_in_prog; /* for DB_FSYNC macro usage */ GBLREF sigset_t block_sigsent; GBLREF boolean_t blocksig_initialized; GBLREF jnlpool_addrs jnlpool; #endif +GBLREF gd_region *gv_cur_region; GBLREF reg_ctl_list *mur_ctl; GBLREF mur_gbls_t murgbl; GBLREF mur_opt_struct mur_options; GBLREF seq_num seq_num_zero; GBLREF jnl_gbls_t jgbl; +GBLREF sgmnt_data_ptr_t cs_data; error_def(ERR_JNLREAD); error_def(ERR_JNLREADBOF); @@ -82,6 +85,7 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk) for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++) { + TP_CHANGE_REG(rctl->gd); if (!apply_intrpt_pblk) { assert(NULL != rctl->jctl_turn_around); @@ -255,8 +259,8 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk) } else if (jctl->rec_offset < jctl->jfh->turn_around_offset) { PRINT_VERBOSE_STAT(jctl, "mur_apply_blk:turn_around_offset is bad"); - gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, - jctl->jnl_fn, jctl->rec_offset); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, + jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset); return ERR_JNLBADRECFMT; } } @@ -271,17 +275,17 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk) break; if (ERR_NOPREVLINK == status) { - gtm_putmsg(VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn); return ERR_NOPREVLINK; } else if (ERR_JNLREADBOF == status) { - gtm_putmsg(VARLSTCNT(4) ERR_JNLREADBOF, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_JNLREADBOF, 2, jctl->jnl_fn_len, jctl->jnl_fn); return ERR_JNLREADBOF; } else if (ERR_JNLREAD == status) /* This message is already issued in mur_read_file */ return ERR_JNLREAD; if ((NULL != jctl->next_gen) || (jctl->rec_offset < jctl->jfh->end_of_data)) { - gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset); return status; } @@ -292,17 +296,17 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk) if (SS_NORMAL != mur_fread_eof_crash(jctl, jctl->jfh->end_of_data, jctl->rec_offset)) return ERR_JNLBADRECFMT; } /* end infinite for */ - UNIX_ONLY( - gv_cur_region = rctl->csa->region; - udi = FILE_INFO(gv_cur_region); - DB_FSYNC(gv_cur_region, udi, rctl->csa, db_fsync_in_prog, save_errno); - if (0 != save_errno) - { - send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - gtm_putmsg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - return ERR_DBFSYNCERR; - } - ) +# ifdef UNIX + assert(gv_cur_region == rctl->gd && rctl->gd == rctl->csa->region); + udi = FILE_INFO(gv_cur_region); + DB_FSYNC(gv_cur_region, udi, rctl->csa, db_fsync_in_prog, save_errno); + if (0 != save_errno) + { + send_msg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + return ERR_DBFSYNCERR; + } +# endif } return SS_NORMAL; } @@ -313,16 +317,17 @@ uint4 mur_output_pblk(reg_ctl_list *rctl) file_control *db_ctl; struct_jrec_blk pblkrec; uchar_ptr_t pblkcontents, pblk_jrec_start; - int4 size, fbw_size, fullblockwrite_len, blks_in_lmap; + int4 fullblockwrite_len, blks_in_lmap; + uint4 size, fbw_size; sgmnt_addrs *csa, *repl_csa; node_local *cnl; sgmnt_data_ptr_t csd; jnl_record *jnlrec; - GTMCRYPT_ONLY( - int req_enc_blk_size; - int crypt_status; - blk_hdr_ptr_t bp; - ) +# ifdef GTM_CRYPT + int in_len, gtmcrypt_errno; + blk_hdr_ptr_t bp; + gd_segment *seg; +# endif UNIX_ONLY(sigset_t savemask;) /* In case of a LOSTTNONLY rollback, it is still possible to reach here if one region has NOBEFORE_IMAGE @@ -374,8 +379,8 @@ uint4 mur_output_pblk(reg_ctl_list *rctl) db_ctl->op_pos = ((gtm_int64_t)(csd->blk_size / DISK_BLOCK_SIZE) * pblkrec.blknum) + csd->start_vbn; /* Use jrec size even if downgrade may have shrunk block. If the block has an integ error, we don't run into any trouble. */ size = pblkrec.bsiz; - assert(size <= csd->blk_size); - if (size > csd->blk_size) /* safety check in pro to avoid buffer overflows */ + assert(size <= (uint4)csd->blk_size); + if (size > (uint4)csd->blk_size) /* safety check in pro to avoid buffer overflows */ size = csd->blk_size; /* If full-block-writes are enabled, round size up to next full logical filesys block. We want to use "dbfilop" to * do the write but it does not honour full-block-writes setting. So prepare the buffer accordingly before invoking it. @@ -413,31 +418,32 @@ uint4 mur_output_pblk(reg_ctl_list *rctl) fbw_size = size; db_ctl->op_buff = pblkcontents; db_ctl->op_len = fbw_size; - /* During recovery process, the dat file is recreated by reading the PBLK records from the jnl file and applying them - * to the dat file. In case the database is encrypted, the journal file would also have encrypted PBLK records so - * as long as both the journal file and database file have the same encryption keys (usual case) we dont need to do - * any encryption in this function. But if the keys are different, we need to decrypt the journal record using the - * key from the journal file and re-encrypt it using the key from the database file before applying the PBLK record. - */ # ifdef GTM_CRYPT bp = (blk_hdr_ptr_t) pblkcontents; - req_enc_blk_size = MIN(csd->blk_size, bp->bsiz) - SIZEOF(*bp); + in_len = MIN(csd->blk_size, bp->bsiz) - SIZEOF(*bp); jctl = rctl->jctl; - if (!jctl->is_same_hash_as_db && BLOCK_REQUIRE_ENCRYPTION(csd->is_encrypted, bp->levl, req_enc_blk_size)) - { + if (!jctl->is_same_hash_as_db && BLOCK_REQUIRE_ENCRYPTION(csd->is_encrypted, bp->levl, in_len)) + { /* Database and Journals are setup with different encryption keys. So, decrypt the PBLK records with the journal's + * encryption key and encrypt it with the database's encryption key before writing it to the database file. + */ ASSERT_ENCRYPTION_INITIALIZED; /* The below assert cannot be moved before BLOCK_REQUIRE_ENCRYPTION check done above as tmp_ptr could * potentially point to a V4 block in which case the assert might fail when a V4 block is casted to * a V5 block header. */ assert((bp->bsiz <= csd->blk_size) && (bp->bsiz >= SIZEOF(*bp))); - GTMCRYPT_DECODE_FAST(jctl->encr_key_handle, (char *)(bp + 1), req_enc_blk_size, NULL, crypt_status); - if (0 == crypt_status) - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, (char *)(bp + 1), req_enc_blk_size, NULL, crypt_status); - if (0 != crypt_status) + GTMCRYPT_DECRYPT(csa, jctl->encr_key_handle, (char *)(bp + 1), in_len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, NULL); - return crypt_status; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, jctl->jnl_fn_len, jctl->jnl_fn); + return gtmcrypt_errno; + } + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, (char *)(bp + 1), in_len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = csa->region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + return gtmcrypt_errno; } } # endif @@ -448,8 +454,8 @@ uint4 mur_output_pblk(reg_ctl_list *rctl) murgbl.incr_onln_rlbk_cycle = TRUE; /* Now that we have started updating the database, do NOT honor any more interrupts like MUPIP STOP */ assert(NULL != jnlpool.repl_inst_filehdr); - send_msg(VARLSTCNT(1) ERR_ORLBKNOSTP); - gtm_putmsg(VARLSTCNT(1) ERR_ORLBKNOSTP); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ORLBKNOSTP); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ORLBKNOSTP); assert(blocksig_initialized); /* set to TRUE at process startup time */ savemask = block_sigsent; sigdelset(&savemask, SIGALRM); /* Block all signals except SIGALRM */ diff --git a/sr_port/mur_back_process.c b/sr_port/mur_back_process.c index fc0b599..297249f 100644 --- a/sr_port/mur_back_process.c +++ b/sr_port/mur_back_process.c @@ -1,6 +1,6 @@ /**************************************************************** - * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -48,6 +48,7 @@ #ifdef GTM_TRUNCATE #include "gdsfilext_nojnl.h" #endif +#include "have_crit.h" GBLREF mur_gbls_t murgbl; GBLREF reg_ctl_list *mur_ctl; @@ -73,38 +74,56 @@ error_def(ERR_RESOLVESEQNO); error_def(ERR_RESOLVESEQSTRM); error_def(ERR_TEXT); -#define SAVE_PRE_RESOLVE_SEQNO(rectype, rec_time, rec_token_seq, pre_resolve_seqno) \ -{ \ - if ((JRT_EPOCH == rectype) || (JRT_EOF == rectype)) \ - { \ - if (rec_token_seq > *pre_resolve_seqno) \ - *pre_resolve_seqno = rec_token_seq; \ - } else \ - { \ - if ((rec_token_seq + 1) > *pre_resolve_seqno) \ - *pre_resolve_seqno = rec_token_seq + 1; \ - } \ - if (mur_options.verbose) \ - { \ - gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT8, 4, LEN_AND_LIT("Pre-resolve seqno"), \ - pre_resolve_seqno, pre_resolve_seqno); \ - } \ +#define MAX_BACK_PROCESS_REDO_CNT 8 + +#define SAVE_PRE_RESOLVE_SEQNO(rectype, rec_time, rec_token_seq, pre_resolve_seqno) \ +{ \ + if ((JRT_EPOCH == rectype) || (JRT_EOF == rectype)) \ + { \ + if (rec_token_seq > *pre_resolve_seqno) \ + *pre_resolve_seqno = rec_token_seq; \ + } else \ + { \ + if ((rec_token_seq + 1) > *pre_resolve_seqno) \ + *pre_resolve_seqno = rec_token_seq + 1; \ + } \ + if (mur_options.verbose) \ + { \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUINFOUINT8, 4, LEN_AND_LIT("Pre-resolve seqno"), \ + pre_resolve_seqno, pre_resolve_seqno); \ + } \ } -#define MUR_BACK_PROCESS_ERROR(JCTL, JJCTL, MESSAGE_STRING) \ -{ \ - if (JCTL->after_end_of_data) \ - { \ - *JJCTL = JCTL; \ - return ERR_JNLBADRECFMT; \ - } \ - gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT(MESSAGE_STRING)); \ - if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \ - { \ - *JJCTL = JCTL; \ - return ERR_JNLBADRECFMT; \ - } else \ - continue; \ +#define MUR_BACK_PROCESS_ERROR(JCTL, JJCTL, MESSAGE_STRING) \ +{ \ + if (JCTL->after_end_of_data) \ + { \ + *JJCTL = JCTL; \ + return ERR_JNLBADRECFMT; \ + } \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT(MESSAGE_STRING)); \ + if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \ + { \ + *JJCTL = JCTL; \ + return ERR_JNLBADRECFMT; \ + } else \ + continue; \ +} + +#define MUR_BACK_PROCESS_ERROR_STR(JCTL, JJCTL, MESSAGE_STRING) \ +{ \ + if (JCTL->after_end_of_data) \ + { \ + *JJCTL = JCTL; \ + return ERR_JNLBADRECFMT; \ + } \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(MESSAGE_STRING)); \ + if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \ + { \ + *JJCTL = JCTL; \ + return ERR_JNLBADRECFMT; \ + } else \ + continue; \ } #ifdef VMS @@ -116,8 +135,14 @@ error_def(ERR_TEXT); * and have not yet reached the last epoch in backward processing and the \ * pini_addr should also point to an offset that is after the last epoch. \ */ \ - assert(JCTL->jfh->crash && (JCTL->rec_offset > JNLREC->prefix.pini_addr) \ - && (JNLREC->prefix.pini_addr > JCTL->jfh->end_of_data)); \ + assert(JCTL->jfh->crash && (JCTL->rec_offset >= JNLREC->prefix.pini_addr) \ + && (JNLREC->prefix.pini_addr >= JCTL->jfh->end_of_data)); \ + /* Register the offset of the corrupt record to be the PINI record (not the \ + * current journal record), this way the "mur_back_processing" redo logic \ + * inside "mur_back_process" restarts mur_fread_eof_crash search from the \ + * lower offset and avoids lots of mur_back_processing redos (GTM-7393). \ + */ \ + JCTL->rec_offset = JNLREC->prefix.pini_addr; \ MUR_BACK_PROCESS_ERROR(JCTL, JJCTL, "pini_addr is bad"); \ } \ } @@ -178,6 +203,10 @@ error_def(ERR_TEXT); } \ } +#define TRANS_NUM_CONT_CHK_FAILED "Transaction number continuity check failed: [0x%08X] vs [0x%08X]" +#define SEQ_NUM_CONT_CHK_FAILED "Sequence number continuity check failed: [0x%08X] vs [0x%08X]" +#define TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ (MAX(SIZEOF(TRANS_NUM_CONT_CHK_FAILED), SIZEOF(SEQ_NUM_CONT_CHK_FAILED)) + 2 * 20) + STATICFNDCL void save_turn_around_point(reg_ctl_list *rctl, jnl_ctl_list *jctl, boolean_t apply_pblk); STATICFNDEF void save_turn_around_point(reg_ctl_list *rctl, jnl_ctl_list *jctl, boolean_t apply_pblk) @@ -225,7 +254,7 @@ boolean_t mur_back_process(boolean_t apply_pblk, seq_num *pre_resolve_seqno) jnl_ctl_list *jctl; reg_ctl_list *rctl; uint4 status; - int regno, reg_total; + int redo_cnt, regno, reg_total; jnl_tm_t alt_tp_resolve_time; jnl_record *jnlrec; @@ -233,8 +262,10 @@ boolean_t mur_back_process(boolean_t apply_pblk, seq_num *pre_resolve_seqno) assert(!mur_options.forward || 0 == mur_options.lookback_time); reg_total = murgbl.reg_total; alt_tp_resolve_time = 0; - for ( ; ; ) + for ( redo_cnt = 0; ; redo_cnt++) { + assert(MAX_BACK_PROCESS_REDO_CNT > redo_cnt); + /* ensure we are not doing too many redos of "mur_fread_eof_crash"/"mur_back_processing" */ *pre_resolve_seqno = 0; DEBUG_ONLY(jctl = NULL;) status = mur_back_processing(&jctl, apply_pblk, pre_resolve_seqno, alt_tp_resolve_time); @@ -248,12 +279,13 @@ boolean_t mur_back_process(boolean_t apply_pblk, seq_num *pre_resolve_seqno) } else if (ERR_CHNGTPRSLVTM == status) { jnlrec = jctl->reg_ctl->mur_desc->jnlrec; - gtm_putmsg(VARLSTCNT(6) ERR_CHNGTPRSLVTM, 4, jgbl.mur_tp_resolve_time, jnlrec->prefix.time, - jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(jctl->reg_ctl->csa) VARLSTCNT(6) ERR_CHNGTPRSLVTM, 4, jgbl.mur_tp_resolve_time, + jnlrec->prefix.time, jctl->jnl_fn_len, jctl->jnl_fn); assert(jgbl.mur_tp_resolve_time > jnlrec->prefix.time); alt_tp_resolve_time = jnlrec->prefix.time; } else /* An error message must have already been printed if status != SS_NORMAL */ break; + JNL_PUT_MSG_PROGRESS("Restarting Backward processing"); REINITIALIZE_LIST(murgbl.multi_list); reinitialize_hashtab_int8(&murgbl.token_table); murgbl.broken_cnt = 0; @@ -301,9 +333,10 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) uint4 max_blk_size, max_rec_size; uint4 status, val_len; unsigned short max_key_size; - GTMCRYPT_ONLY( - int crypt_status; - ) +# ifdef GTM_CRYPT + int gtmcrypt_errno; +# endif + char s[TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ]; /* for appending sequence or transaction number */ # ifdef GTM_TRUNCATE uint4 cur_total, old_total; # endif @@ -349,13 +382,17 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Checksum validation failed"); if ((jnlrec->prefix.tn != rec_tn) && (jnlrec->prefix.tn != (rec_tn - 1))) { + SNPRINTF(s, TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ, TRANS_NUM_CONT_CHK_FAILED, + jnlrec->prefix.tn, rec_tn); rec_tn = jnlrec->prefix.tn; - MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Transaction number continuty check failed"); + MUR_BACK_PROCESS_ERROR_STR(jctl, jjctl, s); } if (mur_options.rollback && REC_HAS_TOKEN_SEQ(rectype) && (GET_JNL_SEQNO(jnlrec) > rec_token_seq)) { + SNPRINTF(s, TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ, SEQ_NUM_CONT_CHK_FAILED, + GET_JNL_SEQNO(jnlrec), rec_token_seq); rec_token_seq = GET_JNL_SEQNO(jnlrec); - MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Sequence number continuty check failed"); + MUR_BACK_PROCESS_ERROR_STR(jctl, jjctl, s); } if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) { @@ -365,13 +402,13 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) # ifdef GTM_CRYPT if (jctl->jfh->is_encrypted) { - DECODE_SET_KILL_ZKILL_ZTRIG(keystr, jnlrec->prefix.forwptr, - jctl->encr_key_handle, crypt_status); - if (0 != crypt_status) + MUR_DECRYPT_LOGICAL_RECS(keystr, jnlrec->prefix.forwptr, jctl->encr_key_handle, + gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, NULL); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, jctl->jnl_fn_len, jctl->jnl_fn); *jjctl = jctl; - return crypt_status; + return gtmcrypt_errno; } } # endif @@ -390,7 +427,7 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) if (IS_SET(rectype)) { GET_MSTR_LEN(val_len, &keystr->text[keystr->length]); - if (keystr->length + 1 + SIZEOF(rec_hdr) + val_len > max_rec_size) + if (val_len > max_rec_size) MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Record size check failed"); } } @@ -524,7 +561,7 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) (NULL != rctl->csd) && (rec_tn > rctl->csd->trans_hist.curr_tn)) { assert(FALSE); - gtm_putmsg(VARLSTCNT(7) ERR_EPOCHTNHI, 5, jctl->rec_offset, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(7) ERR_EPOCHTNHI, 5, jctl->rec_offset, jctl->jnl_fn_len, jctl->jnl_fn, &rec_tn, &rctl->csd->trans_hist.curr_tn); MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Epoch transaction number check failed"); } @@ -532,10 +569,10 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) { if (mur_options.verbose) { - gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT(" First Epoch Record Offset"), jctl->rec_offset, jctl->rec_offset); - gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOUINT4, 4, LEN_AND_LIT(" First Epoch Record timestamp"), rec_time, rec_time); } first_epoch = FALSE; @@ -786,7 +823,8 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options) save_turn_around_point(rctl, jctl, apply_pblk_this_region); } else { - gtm_putmsg(VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_NOPREVLINK, + 2, jctl->jnl_fn_len, jctl->jnl_fn); *jjctl = jctl; return ERR_NOPREVLINK; } @@ -912,14 +950,14 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num *p } } if (murgbl.resync_seqno) - gtm_putmsg(VARLSTCNT(4) ERR_RESOLVESEQNO, 2, &murgbl.resync_seqno, &murgbl.resync_seqno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RESOLVESEQNO, 2, &murgbl.resync_seqno, &murgbl.resync_seqno); UNIX_ONLY( if (murgbl.resync_strm_seqno_nonzero) { for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) { if (murgbl.resync_strm_seqno[idx]) - gtm_putmsg(VARLSTCNT(5) ERR_RESOLVESEQSTRM, 3, idx, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RESOLVESEQSTRM, 3, idx, &murgbl.resync_strm_seqno[idx], &murgbl.resync_strm_seqno[idx]); } /* If -resync= is specified, we dont yet know what jnl_seqno it maps back to. @@ -980,8 +1018,8 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num *p assert(jctl->reg_ctl == rctl); assert(NULL == jctl->next_gen); if (mur_options.verbose) - gtm_putmsg(VARLSTCNT(6) ERR_MUINFOSTR, 4, LEN_AND_LIT("Processing started for journal file"), - jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOSTR, 4, + LEN_AND_LIT("Processing started for journal file"), jctl->jnl_fn_len, jctl->jnl_fn); jctl->rec_offset = jctl->lvrec_off; status = mur_prev(jctl, jctl->rec_offset); mur_desc = rctl->mur_desc; diff --git a/sr_port/mur_block_count_correct.c b/sr_port/mur_block_count_correct.c index 392ea01..3746950 100644 --- a/sr_port/mur_block_count_correct.c +++ b/sr_port/mur_block_count_correct.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,7 +46,7 @@ error_def(ERR_WAITDSKSPACE); uint4 mur_block_count_correct(reg_ctl_list *rctl) { - unsigned int native_size, size; + gtm_uint64_t native_size, size; sgmnt_data_ptr_t mu_data; int4 mu_int_ovrhd; uint4 total_blks; @@ -78,7 +78,7 @@ uint4 mur_block_count_correct(reg_ctl_list *rctl) } mu_int_ovrhd += 1; assert(mu_int_ovrhd == mu_data->start_vbn); - size = mu_int_ovrhd + (mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; + size = mu_int_ovrhd + (off_t)(mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); /* In the following tests, the EOF block should always be 1 greater than the actual size of the file. * This is due to the GDS being allocated in even DISK_BLOCK_SIZE-byte blocks. @@ -102,7 +102,7 @@ uint4 mur_block_count_correct(reg_ctl_list *rctl) bplmap = cs_data->bplmap; new_blocks = (native_size - size)/(mu_data->blk_size / DISK_BLOCK_SIZE); new_bit_maps = DIVIDE_ROUND_UP(total_blks + new_blocks, bplmap) - DIVIDE_ROUND_UP(total_blks, bplmap); - if (SS_NORMAL != (status = gdsfilext(new_blocks - new_bit_maps, total_blks))) + if (SS_NORMAL != (status = GDSFILEXT(new_blocks - new_bit_maps, total_blks, TRANS_IN_PROG_FALSE))) { jgbl.dont_reset_gbl_jrec_time = TRUE; return (status); @@ -110,7 +110,7 @@ uint4 mur_block_count_correct(reg_ctl_list *rctl) jgbl.dont_reset_gbl_jrec_time = TRUE; DEBUG_ONLY( /* Check that the filesize and blockcount in the fileheader match now after the extend */ - size = mu_int_ovrhd + (mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; + size = mu_int_ovrhd + (off_t)(mu_data->blk_size / DISK_BLOCK_SIZE) * mu_data->trans_hist.total_blks; native_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); assert(size == native_size); ) diff --git a/sr_port/mur_close_file_extfmt.c b/sr_port/mur_close_file_extfmt.c index e33891b..4e93fb5 100644 --- a/sr_port/mur_close_file_extfmt.c +++ b/sr_port/mur_close_file_extfmt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,9 +47,10 @@ pars.str.len = SIZEOF(no_param); \ pars.str.addr = (char *)&no_param; \ val.mvtype = MV_STR; \ - \ val.str.len = ((unix_file_info *)file_info)->fn_len; \ val.str.addr = (char *) (((unix_file_info *)(file_info))->fn); \ + if (NULL == val.str.addr) \ + continue; \ op_close(&val, &pars); \ } #elif defined(VMS) diff --git a/sr_port/mur_close_files.c b/sr_port/mur_close_files.c index ef390f4..4393974 100644 --- a/sr_port/mur_close_files.c +++ b/sr_port/mur_close_files.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,6 +15,7 @@ #include "gtm_string.h" #include "gtm_time.h" #if defined(UNIX) +#include #include "gtm_unistd.h" #elif defined(VMS) #include @@ -56,6 +57,8 @@ #include "have_crit.h" #include "gtmsource_srv_latch.h" #include +#include "anticipatory_freeze.h" +#include "ipcrmid.h" #endif #include "util.h" #ifdef DEBUG @@ -63,18 +66,18 @@ #endif #include "interlock.h" -#define WARN_STATUS(jctl) \ -if (SS_NORMAL != jctl->status) \ -{ \ - assert(FALSE); \ - if (SS_NORMAL != jctl->status2) \ - gtm_putmsg(VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, \ - jctl->status, PUT_SYS_ERRNO(jctl->status2)); \ - else \ - gtm_putmsg(VARLSTCNT(5) ERR_JNLWRERR, \ - 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); \ - wrn_count++; \ -} \ +#define WARN_STATUS(jctl) \ +if (SS_NORMAL != jctl->status) \ +{ \ + assert(FALSE); \ + if (SS_NORMAL != jctl->status2) \ + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, \ + jctl->status, PUT_SYS_ERRNO(jctl->status2)); \ + else \ + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, \ + 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); \ + wrn_count++; \ +} \ GBLREF void (*call_on_signal)(); GBLREF jnl_gbls_t jgbl; @@ -100,22 +103,23 @@ error_def(ERR_JNLACTINCMPLT); error_def(ERR_JNLBADLABEL); error_def(ERR_JNLREAD); error_def(ERR_JNLSTATE); -error_def(ERR_JNLSTRESTFL); error_def(ERR_JNLSUCCESS); error_def(ERR_JNLWRERR); error_def(ERR_MUJNLSTAT); +error_def(ERR_MUJPOOLRNDWNSUC); error_def(ERR_MUNOACTION); error_def(ERR_ORLBKCMPLT); error_def(ERR_ORLBKTERMNTD); error_def(ERR_PREMATEOF); error_def(ERR_RENAMEFAIL); +error_def(ERR_REPLPOOLINST); error_def(ERR_REPLSTATE); +error_def(ERR_NOTALLDBRNDWN); UNIX_ONLY(error_def(ERR_REPLFTOKSEM);) UNIX_ONLY(error_def(ERR_RLBKSTRMSEQ);) VMS_ONLY(error_def(ERR_SETREG2RESYNC);) - -void mur_close_files(void) +boolean_t mur_close_files(void) { char *head_jnl_fn, *rename_fn, fn[MAX_FN_LEN]; int head_jnl_fn_len, wrn_count = 0, rename_fn_len; @@ -126,28 +130,33 @@ void mur_close_files(void) sgmnt_data *csd, csd_temp; uint4 ustatus; int4 status; + int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ # if defined(VMS) boolean_t set_resync_to_region = FALSE; # elif defined(UNIX) - int idx, finish_err_code; + int idx, finish_err_code, save_errno; const char *fini_str = NULL; + const char *termntd_str; + unsigned char ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr; + struct shmid_ds shm_buf; unix_db_info *udi = NULL; gtmsrc_lcl gtmsrc_lcl_array[NUM_GTMSRC_LCL]; repl_inst_hdr repl_instance; repl_inst_hdr_ptr_t inst_hdr = NULL; seq_num max_strm_seqno[MAX_SUPPL_STRMS], this_strm_seqno; - boolean_t incr_jnlpool_rlbk_cycle = TRUE, got_ftok; + boolean_t incr_jnlpool_rlbk_cycle = TRUE, got_ftok, anticipatory_freeze_available, was_crit; gtmsource_local_ptr_t gtmsourcelocal_ptr; global_latch_t *latch; seq_num max_zqgblmod_seqno = 0, last_histinfo_seqno; DEBUG_ONLY(int semval;) - const char *termntd_str; # endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (mur_close_files_done) { assert(mupip_exit_status_displayed); - return; + return TRUE; } call_on_signal = NULL; /* Do not recurs via call_on_signal if there is an error */ SET_PROCESS_EXITING_TRUE; /* In case the database is encrypted, this value is used to avoid using @@ -155,16 +164,15 @@ void mur_close_files(void) */ csd = &csd_temp; assert(murgbl.losttn_seqno == murgbl.save_losttn_seqno); - UNIX_ONLY( - if (mur_options.rollback) - memset(&max_strm_seqno[0], 0, SIZEOF(max_strm_seqno)); - ); /* If journaling, gds_rundown will need to write PINI/PFIN records. The timestamp of that journal record will * need to be adjusted to the current system time to reflect that it is recovery itself writing that record * instead of simulating GT.M activity. Reset jgbl.dont_reset_gbl_jrec_time to allow for adjustments to gbl_jrec_time. */ jgbl.dont_reset_gbl_jrec_time = FALSE; # ifdef UNIX + if (mur_options.rollback) + memset(&max_strm_seqno[0], 0, SIZEOF(max_strm_seqno)); + anticipatory_freeze_available = ANTICIPATORY_FREEZE_AVAILABLE; inst_hdr = jnlpool.repl_inst_filehdr; /* Note that murgbl.consist_jnl_seqno is maintained even if the only thing done by rollback was lost transaction processing. * In this case, we shouldn't consider the instance as being rolled back. So, set murgbl.incr_db_rlbkd_cycle = FALSE; @@ -176,9 +184,13 @@ void mur_close_files(void) } assert(!murgbl.incr_db_rlbkd_cycle || murgbl.incr_onln_rlbk_cycle); assert(jnlpool.jnlpool_ctl == jnlpool_ctl); +#if 0 + /* disable assertion until we make jnlpool_init conditional on anticipatory freeze available */ assert(jgbl.onlnrlbk || (NULL == jnlpool_ctl)); +#endif assert((NULL == jnlpool_ctl) || (TRUE == inst_hdr->crash)); - if (jgbl.onlnrlbk && (NULL != jnlpool_ctl)) + assert((NULL == jnlpool_ctl) || jgbl.onlnrlbk || anticipatory_freeze_available); + if (NULL != jnlpool_ctl) { csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; ASSERT_VALID_JNLPOOL(csa); @@ -236,16 +248,28 @@ void mur_close_files(void) if (mur_options.update && (murgbl.clean_exit || !rctl->db_updated) && (NULL != csa->nl)) csa->nl->donotflush_dbjnl = FALSE; /* shared memory is now clean for dbjnl flushing */ if (UNIX_ONLY(mur_options.forward) VMS_ONLY(TRUE)) - gds_rundown(); + UNIX_ONLY(rundown_status =) gds_rundown(); + if (EXIT_NRM != rundown_status) + { + wrn_count++; + continue; + } # ifdef UNIX assert(!jgbl.onlnrlbk || (csa->now_crit && csa->hold_onto_crit) || (!murgbl.clean_exit && !rctl->db_updated)); if (jgbl.onlnrlbk) { if (murgbl.incr_onln_rlbk_cycle) + { + csa->nl->root_search_cycle++; csa->nl->onln_rlbk_cycle++; + } if (murgbl.incr_db_rlbkd_cycle) + { + assert(murgbl.incr_db_rlbkd_cycle); csa->nl->db_onln_rlbkd_cycle++; + } + csa->root_search_cycle = csa->nl->root_search_cycle; csa->onln_rlbk_cycle = csa->nl->onln_rlbk_cycle; csa->db_onln_rlbkd_cycle = csa->nl->db_onln_rlbkd_cycle; if (incr_jnlpool_rlbk_cycle && (NULL != jnlpool_ctl) && murgbl.incr_onln_rlbk_cycle) @@ -282,11 +306,13 @@ void mur_close_files(void) csa->repl_state = csd->repl_state = rctl->repl_state; /* After recover replication state is always closed */ if (rctl->repl_state != csd->repl_state) - gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6, LEN_AND_LIT(FILE_STR), - DB_LEN_STR(reg), LEN_AND_STR(repl_state_lit[csd->repl_state])); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_REPLSTATE, 6, + LEN_AND_LIT(FILE_STR), DB_LEN_STR(reg), + LEN_AND_STR(repl_state_lit[csd->repl_state])); if (rctl->jnl_state != csd->jnl_state) - gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR), - DB_LEN_STR(reg), LEN_AND_STR(jnl_state_lit[csd->jnl_state])); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLSTATE, 6, + LEN_AND_LIT(FILE_STR), DB_LEN_STR(reg), + LEN_AND_STR(jnl_state_lit[csd->jnl_state])); # ifdef UNIX if ((NULL != rctl->jctl) && !mur_options.rollback_losttnonly) { @@ -338,8 +364,9 @@ void mur_close_files(void) { csd->resync_seqno = csd->reg_seqno; if (mur_options.verbose) - gtm_putmsg(VARLSTCNT(6) ERR_SETREG2RESYNC, 4, - &csd->resync_seqno, &csd->reg_seqno, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_SETREG2RESYNC, + 4, &csd->resync_seqno, &csd->reg_seqno, + DB_LEN_STR(reg)); } csd->reg_seqno = murgbl.consist_jnl_seqno; if (csd->resync_seqno > murgbl.consist_jnl_seqno) @@ -426,7 +453,11 @@ void mur_close_files(void) if (jctl->jfh->recover_interrupted) { jctl->jfh->recover_interrupted = FALSE; - DO_FILE_WRITE(jctl->channel, 0, jctl->jfh, REAL_JNL_HDR_LEN, + /* Since overwriting the journal file header (an already allocated block + * in the file) should not cause ENOSPC, we dont take the trouble of + * passing csa or jnl_fn (first two parameters). Instead we pass NULL. + */ + JNL_DO_FILE_WRITE(NULL, NULL, jctl->channel, 0, jctl->jfh, REAL_JNL_HDR_LEN, jctl->status, jctl->status2); WARN_STATUS(jctl); } @@ -459,7 +490,12 @@ void mur_close_files(void) assert(jctl->jfh->prev_recov_blks_to_upgrd_adjust <= rctl->blks_to_upgrd_adjust); jctl->jfh->prev_recov_blks_to_upgrd_adjust = rctl->blks_to_upgrd_adjust; jctl->jfh->next_jnl_file_name_length = 0; - DO_FILE_WRITE(jctl->channel, 0, jctl->jfh, REAL_JNL_HDR_LEN, jctl->status, jctl->status2); + /* Since overwriting the journal file header (an already allocated block + * in the file) should not cause ENOSPC, we dont take the trouble of + * passing csa or jnl_fn (first two parameters). Instead we pass NULL. + */ + JNL_DO_FILE_WRITE(NULL, NULL, jctl->channel, 0, + jctl->jfh, REAL_JNL_HDR_LEN, jctl->status, jctl->status2); WARN_STATUS(jctl); /* we have to clear next_jnl_file_name fields in the post-turn-around-point journal files. * but if we get killed in this process, a future recover should be able to resume @@ -473,22 +509,28 @@ void mur_close_files(void) { /* Clear next_jnl_file_name fields in the post-turn-around-point journal files */ assert(0 == end_jctl->turn_around_offset); end_jctl->jfh->next_jnl_file_name_length = 0; - DO_FILE_WRITE(end_jctl->channel, 0, end_jctl->jfh, REAL_JNL_HDR_LEN, + /* Since overwriting the journal file header (an already allocated block + * in the file) should not cause ENOSPC, we dont take the trouble of + * passing csa or jnl_fn (first two parameters). Instead we pass NULL. + */ + JNL_DO_FILE_WRITE(NULL, NULL, end_jctl->channel, 0, end_jctl->jfh, REAL_JNL_HDR_LEN, end_jctl->status, end_jctl->status2); WARN_STATUS(end_jctl); /* Rename journals whose entire contents have been undone with * the rolled_bak prefix. user can decide to delete these */ rename_fn = fn; prepare_unique_name((char *)end_jctl->jnl_fn, end_jctl->jnl_fn_len, - PREFIX_ROLLED_BAK, "", rename_fn, &rename_fn_len, &ustatus); + PREFIX_ROLLED_BAK, "", rename_fn, &rename_fn_len, 0, &ustatus); + UNIX_ONLY(WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa)); + /* wait for instance freeze before journal file renames */ if (SS_NORMAL == gtm_rename((char *)end_jctl->jnl_fn, end_jctl->jnl_fn_len, rename_fn, rename_fn_len, &ustatus)) { - gtm_putmsg(VARLSTCNT (6) ERR_FILERENAME, 4, end_jctl->jnl_fn_len, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT (6) ERR_FILERENAME, 4, end_jctl->jnl_fn_len, end_jctl->jnl_fn, rename_fn_len, rename_fn); } else { - gtm_putmsg(VARLSTCNT(6) ERR_RENAMEFAIL, 4, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_RENAMEFAIL, 4, end_jctl->jnl_fn_len, end_jctl->jnl_fn, rename_fn_len, rename_fn); wrn_count++; } @@ -514,6 +556,7 @@ void mur_close_files(void) assert(NULL == rctl->mur_desc); # endif } + # ifdef UNIX /* If rollback, we better have the standalone lock. The only exception is if we could not get standalone access * (due to some other process still accessing the instance file and/or db/jnl). In that case "clean_exit" should be FALSE. @@ -545,7 +588,7 @@ void mur_close_files(void) if (this_strm_seqno) { assert(0 == GET_STRM_INDEX(this_strm_seqno)); - gtm_putmsg(VARLSTCNT(5) ERR_RLBKSTRMSEQ, 3, idx, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLBKSTRMSEQ, 3, idx, &this_strm_seqno, &this_strm_seqno); } } @@ -554,19 +597,30 @@ void mur_close_files(void) { /* Virtually truncate the history in the replication instance file if necessary. For online * rollback, we should truncate the history records ONLY if the instance was actually rolled back * (indicated by incr_db_rlbkd_cycle) + * Also, the repl_inst_histinfo_truncate function expects the caller to hold journal pool crit + * if jnlpool exists. We can come here with journal pool if: + * (a) ONLINE ROLLBACK + * (b) Regular ROLLBACK with Anticipatory Freeze scheme */ + if ((NULL != jnlpool_ctl) && !(was_crit = csa->now_crit)) /* note: assignment */ + { + assert(!jgbl.onlnrlbk); + assert(anticipatory_freeze_available); + assert(!csa->hold_onto_crit); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); + } last_histinfo_seqno = repl_inst_histinfo_truncate(murgbl.consist_jnl_seqno); + if ((NULL != jnlpool_ctl) && !was_crit) + rel_lock(jnlpool.jnlpool_dummy_reg); /* The above also updates "repl_inst_filehdr->jnl_seqno". If regular rollback, it also updates * "repl_inst_filehdr->crash" to FALSE. For online rollback, we have to update the crash field * ONLY if there is NO journal pool and that is done below. */ - assert(inst_hdr->num_histinfo || (1 == murgbl.consist_jnl_seqno)); - if (NULL != jnlpool_ctl) + if ((NULL != jnlpool_ctl) && jgbl.onlnrlbk) { /* journal pool still exists and some backward and forward processing happened. More * importantly, the database was taken to a prior logical state. Refresh the journal * pool fields to reflect the new state. */ - assert(jgbl.onlnrlbk); assert(csa->now_crit && csa->hold_onto_crit); jnlpool_ctl->last_histinfo_seqno = last_histinfo_seqno; jnlpool_ctl->jnl_seqno = murgbl.consist_jnl_seqno; @@ -622,7 +676,7 @@ void mur_close_files(void) } repl_inst_write(udi->fn, (off_t)REPL_INST_HDR_SIZE, (sm_uc_ptr_t)gtmsrc_lcl_array, GTMSRC_LCL_SIZE); } - if (NULL != jnlpool_ctl) + if ((NULL != jnlpool_ctl) && jgbl.onlnrlbk) { /* Remove any locks that we acquired in mur_open_files. Needs to be done even if this is NOT a clean exit */ assert(0 != jnlpool_ctl->onln_rlbk_pid || !murgbl.clean_exit); assert((csa->now_crit && csa->hold_onto_crit) || !murgbl.clean_exit); @@ -655,16 +709,20 @@ void mur_close_files(void) assert(!jgbl.onlnrlbk || (cs_addrs->now_crit && cs_addrs->hold_onto_crit) || !murgbl.clean_exit); DEBUG_ONLY(udi = FILE_INFO(reg)); assert(!rctl->standalone || (1 == (semval = semctl(udi->semid, 0, GETVAL)))); - gds_rundown(); /* does the final rel_crit */ - assert(!rctl->standalone || (1 == (semval = semctl(udi->semid, 0, GETVAL)))); + UNIX_ONLY(rundown_status =) gds_rundown(); /* does the final rel_crit */ + if (EXIT_NRM != rundown_status) + wrn_count++; + assert((EXIT_NRM != rundown_status) || !rctl->standalone + || (1 == (semval = semctl(udi->semid, 0, GETVAL)))); assert(!cs_addrs->now_crit && !cs_addrs->hold_onto_crit); } /* If this was a RECOVER/ROLLBACK and rctl->standalone is FALSE, then gvcst_init/mu_rndwn_file did not happen in * successfully for this region. Increment wrn_count in this case */ assert(!mur_options.update || rctl->standalone || !murgbl.clean_exit); - if (rctl->standalone && !db_ipcs_reset(reg)) - wrn_count++; + if (rctl->standalone UNIX_ONLY(&& EXIT_NRM == rundown_status)) + if (!db_ipcs_reset(reg)) + wrn_count++; rctl->standalone = FALSE; rctl->gd = NULL; rctl->csa = NULL; @@ -672,11 +730,12 @@ void mur_close_files(void) mur_rctl_desc_free(rctl); /* free them up now */ assert(NULL == rctl->mur_desc); } + if (mur_options.rollback && murgbl.repl_standalone) { udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); ASSERT_HOLD_REPLPOOL_SEMS; - /* repl_inst_read and mu_replpool_remove_sem expects that the caller holds the ftok semaphore as it is about to + /* repl_inst_read and mu_replpool_release_sem expects that the caller holds the ftok semaphore as it is about to * read the replication instance file and assumes there are no concurrent writers. However, ROLLBACK grabs all the * access control semaphores of both jnlpool and receiver pool as well as the replication locks in mur_open_files. * This means - @@ -692,12 +751,84 @@ void mur_close_files(void) * the cleanup. */ repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); - if (NULL == jnlpool_ctl) - repl_instance.crash = FALSE; repl_instance.file_corrupt = inst_hdr->file_corrupt; + if (NULL == jnlpool_ctl) + repl_instance.crash = inst_hdr->crash = FALSE; + else + { /* Online Rollback OR Anticipatory Freeze is in effect. Detach from the journal pool as all the database + * writes are now over. Since the attach count is 1 (we are the only one attached) go ahead and remove the + * journal pool. We've already flushed all the contents to the instance file at the beginning of rollback + */ + assert(anticipatory_freeze_available || jgbl.onlnrlbk); + assert(INVALID_SHMID != repl_instance.jnlpool_shmid); + /* Receive pool is typically rundown by almost all callers of mu_rndwn_repl_instance except for ONLINE + * ROLLBACK which can keep it up and running if no one is attached to it (by design). Note: This is just + * an assert to validate our understanding and has no implications in PRO + */ + assert(INVALID_SHMID == repl_instance.recvpool_shmid || jgbl.onlnrlbk); + /* Ensure that no new processes have attached to the journal pool */ + if (-1 == shmctl(repl_instance.jnlpool_shmid, IPC_STAT, &shm_buf)) + { + save_errno = errno; + assert(FALSE); + ISSUE_REPLPOOLINST(save_errno, repl_instance.jnlpool_shmid, repl_instance.inst_info.this_instname, + "shmctl()"); + } + if (-1 == shmdt((caddr_t)jnlpool_ctl)) + { + save_errno = errno; + ISSUE_REPLPOOLINST(save_errno, repl_instance.jnlpool_shmid, repl_instance.inst_info.this_instname, + "shmdt()"); + assert(FALSE); + } + /* Since journal pool is no longer attached, null out fields to indicate it is invalid. */ + jnlpool.jnlpool_ctl = NULL; + jnlpool_ctl = NULL; + jnlpool.gtmsrc_lcl_array = NULL; + jnlpool.gtmsource_local_array = NULL; + jnlpool.jnldata_base = NULL; + jnlpool.repl_inst_filehdr = NULL; + if (1 == shm_buf.shm_nattch) + { /* We are the only one attached. Go ahead and remove the shared memory ID and invalidate it in the + * instance file header as well. + */ + if (-1 == shm_rmid(repl_instance.jnlpool_shmid)) + { + save_errno = errno; + assert(FALSE); + ISSUE_REPLPOOLINST(save_errno, repl_instance.jnlpool_shmid, repl_instance.inst_info. + this_instname, "shm_rmid()"); + } + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, repl_instance.jnlpool_shmid); + *ipcs_ptr = '\0'; + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(udi->fn)); + /* Now that the journal pool shared memory is removed, go ahead and invalidate it in the file + * header + */ + repl_instance.jnlpool_shmid = INVALID_SHMID; + repl_instance.jnlpool_shmid_ctime = 0; + repl_instance.crash = FALSE; /* reset crash bit as the journal pool no longer exists */ + } + inst_hdr = &repl_instance; /* now that shared memory is gone, re-point inst_hdr to the one read from file */ + } + /* flush the instance file header to the disk before releasing the semaphores. This way, any process waiting on + * the semaphores will not notice stale values for "crash" and "file_corrupt" flags leading to incorrect + * REPLREQROLLBACK errors. This means writing the instance file header twice (first here and the second one a little + * later (for flushing the sem-id fields). But, these should have negligible penalty as the file system caches the + * disk reads/writes. + */ + repl_inst_write(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); got_ftok = ftok_sem_lock(jnlpool.jnlpool_dummy_reg, FALSE, TRUE); /* immediate=TRUE */ - mu_replpool_remove_sem(&repl_instance, JNLPOOL_SEGMENT, got_ftok); - mu_replpool_remove_sem(&repl_instance, RECVPOOL_SEGMENT, got_ftok); + /* Note: The decision to remove the Journal Pool Access Control Semaphores should be based on two things: + * 1. If we have the ftok on the instance file + * AND + * 2. If the instance is NOT crashed indicating that Journal Pool is rundown as well. This condition ensures that + * we don't cause a situation where the Journal Pool is left-around but the semaphores are removed which is an + * out-of-design situation. + */ + mu_replpool_release_sem(&repl_instance, JNLPOOL_SEGMENT, got_ftok && !repl_instance.crash); + mu_replpool_release_sem(&repl_instance, RECVPOOL_SEGMENT, got_ftok); if (got_ftok) ftok_sem_release(jnlpool.jnlpool_dummy_reg, FALSE, TRUE); /* immediate=TRUE */ murgbl.repl_standalone = FALSE; @@ -724,17 +855,17 @@ void mur_close_files(void) { /* If inst_hdr is NULL, it means we exited even before getting standalone access on the journal pool. * No point issuing the ORLBKCMPLT or ORLBKTERMNTD message because ORLBKSTART will not even be issued. */ - gtm_putmsg(VARLSTCNT(6) finish_err_code, 4, LEN_AND_STR(inst_hdr->inst_info.this_instname), - LEN_AND_STR(udi->fn)); - send_msg(VARLSTCNT(6) finish_err_code, 4, LEN_AND_STR(inst_hdr->inst_info.this_instname), - LEN_AND_STR(udi->fn)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) finish_err_code, 4, + LEN_AND_STR(inst_hdr->inst_info.this_instname), LEN_AND_STR(udi->fn)); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) finish_err_code, 4, + LEN_AND_STR(inst_hdr->inst_info.this_instname), LEN_AND_STR(udi->fn)); } } # endif mur_close_file_extfmt(); mur_free(); /* free up whatever was allocated by "mur_init" */ if (wrn_count) - gtm_putmsg(VARLSTCNT (1) ERR_JNLACTINCMPLT); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_JNLACTINCMPLT); else if (!mupip_exit_status_displayed) { /* This exit path is not coming through "mupip_exit". Print an error message indicating incomplete recovery. * The || in the assert below is to take care of a white-box test that primarily tests the @@ -746,15 +877,22 @@ void mur_close_files(void) && ((WBTEST_MUR_ABNORMAL_EXIT_EXPECTED == gtm_white_box_test_case_number) || (WBTEST_TP_HIST_CDB_SC_BLKMOD == gtm_white_box_test_case_number) || (WBTEST_JNL_FILE_OPEN_FAIL == gtm_white_box_test_case_number) - || (WBTEST_JNL_CREATE_FAIL == gtm_white_box_test_case_number))); + || (WBTEST_JNL_CREATE_FAIL == gtm_white_box_test_case_number) + || (WBTEST_RECOVER_ENOSPC == gtm_white_box_test_case_number) + || (WBTEST_WCS_FLU_FAIL == gtm_white_box_test_case_number))); assert(!murgbl.clean_exit); if (murgbl.wrn_count) - gtm_putmsg(VARLSTCNT (1) ERR_JNLACTINCMPLT); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_JNLACTINCMPLT); else - gtm_putmsg(VARLSTCNT (1) ERR_MUNOACTION); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_MUNOACTION); } else if (murgbl.clean_exit && !murgbl.wrn_count) JNL_SUCCESS_MSG(mur_options); JNL_PUT_MSG_PROGRESS("End processing"); mupip_exit_status_displayed = TRUE; mur_close_files_done = TRUE; +# if defined(UNIX) && defined(DEBUG) + if (WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC) && (0 == gtm_white_box_test_case_count)) + util_out_print("Total number of writes !UL",TRUE, gtm_wbox_input_test_case_count); +# endif + return (0 == wrn_count); } diff --git a/sr_port/mur_forward.c b/sr_port/mur_forward.c index 82116a6..e273751 100644 --- a/sr_port/mur_forward.c +++ b/sr_port/mur_forward.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -94,8 +94,22 @@ uint4 mur_forward(jnl_tm_t min_broken_time, seq_num min_broken_seqno, seq_num lo seq_num rec_token_seq; forw_multi_struct *forw_multi; multi_struct *multi; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; skip_dbtriggers = TRUE; /* do not want to invoke any triggers for updates done by journal recovery */ +# ifdef UNIX + /* In case of mupip journal -recover -backward or -rollback -backward, the forward phase replays the journal records + * and creates new journal records. If there is no space to write these journal records, "jnl_file_lost" will eventually + * get called. In this case, we want it to issue a runtime error (thereby terminating the journal recovery with an + * abnormal exit status, forcing the user to free up more space and reissue the journal recovery) and not turn + * journaling off (which would silently let recovery proceed and exit with normal status even though the db might + * have integ errors at that point). Use the error_on_jnl_file_lost feature to implement this error triggering. + * This error_on_jnl_file_lost feature is not currently implemented in VMS hence the #ifdef UNIX for now. + */ + if (mur_options.update) + TREF(error_on_jnl_file_lost) = JNL_FILE_LOST_ERRORS; +# endif murgbl.extr_buff = (char *)malloc(murgbl.max_extr_record_length); for (recstat = (enum broken_type)0; recstat < TOT_EXTR_TYPES; recstat++) murgbl.extr_file_create[recstat] = TRUE; @@ -155,7 +169,7 @@ uint4 mur_forward(jnl_tm_t min_broken_time, seq_num min_broken_seqno, seq_num lo cs_addrs->rctl = rctl; rctl->csd = cs_data; rctl->sgm_info_ptr = cs_addrs->sgm_info_ptr; - SET_CSA_DIR_TREE(cs_addrs, MAX_KEY_SZ, reg); + assert(!reg->open || (NULL != cs_addrs->dir_tree)); gv_target = cs_addrs->dir_tree; } jctl->after_end_of_data = FALSE; @@ -164,6 +178,7 @@ uint4 mur_forward(jnl_tm_t min_broken_time, seq_num min_broken_seqno, seq_num lo if (SS_NORMAL != status) return status; PRINT_VERBOSE_STAT(jctl, "mur_forward:at the start"); + rctl->process_losttn = FALSE; /* Any multi-region TP transaction will be processed as multiple single-region TP transactions up * until the tp-resolve-time is reached. From then on, they will be treated as one multi-region TP * transaction. This is needed for proper lost-tn determination (any multi-region transaction that @@ -199,7 +214,6 @@ uint4 mur_forward(jnl_tm_t min_broken_time, seq_num min_broken_seqno, seq_num lo * Do not even consider region for next processing loop */ } rctl->last_tn = 0; - rctl->process_losttn = FALSE; murgbl.regcnt_remaining++; /* # of regions participating in recovery at this point */ if (NULL == rctl_start) rctl_start = rctl; diff --git a/sr_port/mur_forward_play_cur_jrec.c b/sr_port/mur_forward_play_cur_jrec.c index 0973397..d1f4047 100644 --- a/sr_port/mur_forward_play_cur_jrec.c +++ b/sr_port/mur_forward_play_cur_jrec.c @@ -45,6 +45,7 @@ #include "gvcst_protos.h" /* for gvcst_root_search prototype */ #include "tp_set_sgm.h" #include "tp_frame.h" +#include "wbox_test_init.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif @@ -56,9 +57,7 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF mur_gbls_t murgbl; GBLREF mur_opt_struct mur_options; GBLREF uint4 dollar_tlevel; -#ifdef DEBUG GBLREF jnl_gbls_t jgbl; -#endif error_def(ERR_DUPTN); error_def(ERR_JNLTPNEST); @@ -90,14 +89,16 @@ uint4 mur_forward_play_cur_jrec(reg_ctl_list *rctl) ht_ent_mname *tabent; mname_entry gvent; gvnh_reg_t *gvnh_reg; - GTMCRYPT_ONLY( - int4 crypt_status; - ) +# ifdef GTM_CRYPT + int4 gtmcrypt_errno; +# endif forw_multi_struct *forw_multi; # if (defined(DEBUG) && defined(UNIX)) int4 strm_idx; # endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(!rctl->forw_eof_seen); jctl = rctl->jctl; /* Ensure we never DOUBLE process the same journal record in the forward phase */ @@ -119,11 +120,11 @@ uint4 mur_forward_play_cur_jrec(reg_ctl_list *rctl) # ifdef GTM_CRYPT if (jctl->jfh->is_encrypted) { - DECODE_SET_KILL_ZKILL_ZTRIG(keystr, rec->prefix.forwptr, jctl->encr_key_handle, crypt_status); - if (0 != crypt_status) + MUR_DECRYPT_LOGICAL_RECS(keystr, rec->prefix.forwptr, jctl->encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, NULL); - return crypt_status; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, jctl->jnl_fn_len, jctl->jnl_fn); + return gtmcrypt_errno; } } # endif @@ -249,7 +250,7 @@ uint4 mur_forward_play_cur_jrec(reg_ctl_list *rctl) return status; /* "mur_pini_state" failed due to bad pini_addr */ ++jctl->jnlrec_cnt[rectype]; /* for -show=STATISTICS */ } - if (!mur_options.update && !mur_options.extr[GOOD_TN]) + if (!mur_options.update && !jgbl.mur_extract) return SS_NORMAL; if (murgbl.ok_to_update_db && IS_TUPD(rectype) && (GOOD_TN == recstat)) { /* Even for FENCE_NONE we apply fences. Otherwise a TUPD becomes UPD etc. @@ -323,7 +324,8 @@ uint4 mur_forward_play_cur_jrec(reg_ctl_list *rctl) assert(added); } } - GVCST_ROOT_SEARCH; + if (!TREF(jnl_extract_nocol)) + GVCST_ROOT_SEARCH; } } if (GOOD_TN == recstat) @@ -362,7 +364,7 @@ uint4 mur_forward_play_cur_jrec(reg_ctl_list *rctl) assert(!mur_options.rollback || (murgbl.consist_jnl_seqno <= murgbl.losttn_seqno)); } } - if (GOOD_TN != recstat || mur_options.extr[GOOD_TN]) + if (GOOD_TN != recstat || jgbl.mur_extract) { if (murgbl.extr_file_create[recstat]) { diff --git a/sr_port/mur_forward_play_multireg_tp.c b/sr_port/mur_forward_play_multireg_tp.c index 5c5ef59..77e191e 100644 --- a/sr_port/mur_forward_play_multireg_tp.c +++ b/sr_port/mur_forward_play_multireg_tp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -133,7 +133,7 @@ uint4 mur_forward_play_multireg_tp(forw_multi_struct *forw_multi, reg_ctl_list * num_tcoms++; if ((num_tcoms == num_participants) && murgbl.ok_to_update_db && (GOOD_TN == recstat)) { /* TCOM record of LAST region. Do actual transaction commit */ - jnl_fence_ctl.token = rec_token_seq; + MUR_SET_JNL_FENCE_CTL_TOKEN(rec_token_seq, ((reg_ctl_list *)NULL)); jgbl.mur_jrec_participants = rec->jrec_tcom.num_participants; memcpy(tcom_record.jnl_tid, rec->jrec_tcom.jnl_tid, TID_STR_SIZE); assert(jnl_fence_ctl.token == rec->jrec_tcom.token_seq.token); diff --git a/sr_port/mur_get_options.c b/sr_port/mur_get_options.c index d66d925..ab015ae 100644 --- a/sr_port/mur_get_options.c +++ b/sr_port/mur_get_options.c @@ -98,9 +98,14 @@ void mur_get_options(void) redirect_list *rl_ptr, *rl_ptr1, *tmp_rl_ptr; select_list *sl_ptr, *sl_ptr1; boolean_t interactive, parse_error; -#ifdef VMS +# ifdef VMS int4 item_code, mode; jnl_proc_time max_time; +# endif + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; +# ifdef VMS DEBUG_ONLY( JNL_WHOLE_TIME(max_time); /* The following assert is to make sure we get some fix for the toggling of max_time's bit 55 (bit 0 lsb, 63 msb). @@ -108,11 +113,10 @@ void mur_get_options(void) * approximately every 41700 days (114 years). We need to fix the way mupip recover operates to take care of such * transition periods. And the fix needs to be done before it is too late. Hence this assert. This assert will * fail in year 2084, approximately 980 days before the toggle time (in year 2087). - */ + */ assert(JNL_FULL_HI_TIME(max_time) < JNL_HITIME_WARN_THRESHOLD); ) -#endif - +# endif qual_buffer = (char *)malloc(MAX_LINE); entry = (char *)malloc(MAX_LINE); memset(&mur_options, 0, SIZEOF(mur_options)); @@ -133,7 +137,7 @@ void mur_get_options(void) jgbl.onlnrlbk = onln_rlbk_val ? (onln_rlbk_val != CLI_NEGATED) : FALSE; /* Default is -NOONLINE */ ) } - mupip_jnl_recover = mur_options.update; + TREF(skip_file_corrupt_check) = mupip_jnl_recover = mur_options.update; jgbl.mur_rollback = mur_options.rollback; /* needed to set jfh->repl_state properly for newly created jnl files */ UNIX_ONLY(murgbl.resync_strm_index = INVALID_SUPPL_STRM;) if (CLI_PRESENT == cli_present("RESYNC")) diff --git a/sr_port/mur_get_pini.c b/sr_port/mur_get_pini.c index 3d1fba0..d775463 100644 --- a/sr_port/mur_get_pini.c +++ b/sr_port/mur_get_pini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2010 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,6 +35,10 @@ GBLREF mur_gbls_t murgbl; GBLREF mur_opt_struct mur_options; GBLREF jnl_gbls_t jgbl; +error_def(ERR_JNLREAD); +error_def(ERR_JNLBADRECFMT); +error_def(ERR_NOPINI); + #define PROCEED_IF_EXTRACT_SHOW_VERIFY(JCTL, PINI_ADDR, PLST, PPLST) \ { /* allow EXTRACT/SHOW/VERIFY to proceed after printing BAD PINI error if error_limit permits. \ * the way we proceed is by returning as if PINI_ADDR was the first journal record in the file. \ @@ -76,10 +80,6 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p reg_ctl_list *rctl; mur_read_desc_t *mur_desc; - error_def(ERR_JNLREAD); - error_def(ERR_JNLBADRECFMT); - error_def(ERR_NOPINI); - if (NULL != (tabent = lookup_hashtab_int4(&jctl->pini_list, (uint4 *)&pini_addr))) plst = tabent->value; else @@ -98,8 +98,9 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p { if (mur_options.update && jctl->after_end_of_data && !jgbl.forw_phase_recovery) return ERR_JNLBADRECFMT; - gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset); - gtm_putmsg(VARLSTCNT(5) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr); assert(FALSE); murgbl.wrn_count++; PROCEED_IF_EXTRACT_SHOW_VERIFY(jctl, pini_addr, plst, pplst); @@ -111,9 +112,10 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p { if (mur_options.update && jctl->after_end_of_data && !jgbl.forw_phase_recovery) return ERR_JNLBADRECFMT; - gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset); if (JRT_PINI != pinirec->prefix.jrec_type) - gtm_putmsg(VARLSTCNT(5) ERR_NOPINI, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_NOPINI, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr); assert(FALSE); murgbl.wrn_count++; PROCEED_IF_EXTRACT_SHOW_VERIFY(jctl, pini_addr, plst, pplst); diff --git a/sr_port/mur_init.c b/sr_port/mur_init.c index b6c0608..1fb511c 100644 --- a/sr_port/mur_init.c +++ b/sr_port/mur_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -93,7 +93,6 @@ void mur_init(void) */ for (index = 0; index < CDB_STAGNATE; index++) t_fail_hist[index] = '0'; - call_on_signal = mur_close_files; DEBUG_ONLY(assert_jrec_member_offsets();) } diff --git a/sr_port/mur_insert_prev.c b/sr_port/mur_insert_prev.c index 2f7fcc8..8545082 100644 --- a/sr_port/mur_insert_prev.c +++ b/sr_port/mur_insert_prev.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -66,8 +66,8 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) } if (SS_NORMAL != (new_jctl->status = mur_fread_eof(new_jctl, rctl))) { - gtm_putmsg(VARLSTCNT(6) ERR_JNLBADRECFMT, 3, new_jctl->jnl_fn_len, new_jctl->jnl_fn, - new_jctl->rec_offset, new_jctl->status); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_JNLBADRECFMT, 3, new_jctl->jnl_fn_len, + new_jctl->jnl_fn, new_jctl->rec_offset, new_jctl->status); free(new_jctl); return FALSE; } @@ -79,7 +79,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) assert((new_jctl->properly_closed && !new_jctl->jfh->crash) || (jctl->jfh->recover_interrupted && !new_jctl->jfh->recover_interrupted)); assert(!mur_options.forward || (!(jctl->jfh->recover_interrupted && !new_jctl->jfh->recover_interrupted))); - /* Skip the continuty of journal files check if both of these are true: + /* Skip the continuity of journal files check if both of these are true: * 1) if current generation was created by recover and * 2) the new one to be inserted was not created by recover */ @@ -96,7 +96,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) } if ((!mur_options.forward || !mur_options.notncheck) && (new_jctl->jfh->eov_tn != jctl->jfh->bov_tn)) { - gtm_putmsg(VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6, &new_jctl->jfh->eov_tn, new_jctl->jnl_fn_len, new_jctl->jnl_fn, &jctl->jfh->bov_tn, jctl->jnl_fn_len, jctl->jnl_fn); free(new_jctl); @@ -115,9 +115,9 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) } if (NULL == rl_ptr) { - gtm_putmsg(VARLSTCNT(8) ERR_DBJNLNOTMATCH, 6, DB_LEN_STR(rctl->gd), new_jctl->jnl_fn_len, - new_jctl->jnl_fn, new_jctl->jfh->data_file_name_length, - new_jctl->jfh->data_file_name); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(8) ERR_DBJNLNOTMATCH, + 6, DB_LEN_STR(rctl->gd), new_jctl->jnl_fn_len, new_jctl->jnl_fn, + new_jctl->jfh->data_file_name_length, new_jctl->jfh->data_file_name); free(new_jctl); return FALSE; } @@ -127,7 +127,8 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) if (new_jctl->jfh->prev_jnl_file_name_length == cur_jctl->jnl_fn_len && 0 == memcmp(new_jctl->jfh->prev_jnl_file_name, cur_jctl->jnl_fn, cur_jctl->jnl_fn_len)) { - gtm_putmsg(VARLSTCNT(6) ERR_JNLCYCLE, 4, cur_jctl->jnl_fn_len, cur_jctl->jnl_fn, DB_LEN_STR(rctl->gd)); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_JNLCYCLE, 4, cur_jctl->jnl_fn_len, + cur_jctl->jnl_fn, DB_LEN_STR(rctl->gd)); free(new_jctl); return FALSE; } @@ -153,6 +154,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl) rctl->jctl = rctl->jctl_head = new_jctl; assert(new_jctl->reg_ctl == rctl); *jjctl = new_jctl; - gtm_putmsg(VARLSTCNT(6) ERR_MUJNLPREVGEN, 4, new_jctl->jnl_fn_len, new_jctl->jnl_fn, DB_LEN_STR(rctl->gd)); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUJNLPREVGEN, 4, new_jctl->jnl_fn_len, + new_jctl->jnl_fn, DB_LEN_STR(rctl->gd)); return TRUE; } diff --git a/sr_port/mur_open_files.c b/sr_port/mur_open_files.c index 27894bc..d6d40da 100644 --- a/sr_port/mur_open_files.c +++ b/sr_port/mur_open_files.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -82,27 +82,28 @@ #include "wcs_flu.h" #include "wcs_recover.h" #include "is_proc_alive.h" +#include "anticipatory_freeze.h" -#define RELEASE_ACCESS_CONTROL(REGLIST) \ -{ \ - unix_db_info *lcl_udi; \ - gd_region *lcl_reg; \ - reg_ctl_list *lcl_rctl; \ - int save_errno; \ - \ - lcl_reg = REGLIST->reg; \ - lcl_rctl = REGLIST->rctl; \ - lcl_udi = FILE_INFO(lcl_reg); \ - assert(INVALID_SEMID != lcl_udi->semid); \ - assert(lcl_udi->grabbed_access_sem && lcl_rctl->standalone); \ - if (0 != (save_errno = do_semop(lcl_udi->semid, 0, -1, SEM_UNDO))) \ - { \ - assert(FALSE); /* we hold it, so we should be able to release it*/ \ - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5,\ - RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \ - } \ - lcl_udi->grabbed_access_sem = FALSE; \ - lcl_rctl->standalone = FALSE; \ +#define RELEASE_ACCESS_CONTROL(REGLIST) \ +{ \ + unix_db_info *lcl_udi; \ + gd_region *lcl_reg; \ + reg_ctl_list *lcl_rctl; \ + int save_errno; \ + \ + lcl_reg = REGLIST->reg; \ + lcl_rctl = REGLIST->rctl; \ + lcl_udi = FILE_INFO(lcl_reg); \ + assert(INVALID_SEMID != lcl_udi->semid); \ + assert(lcl_udi->grabbed_access_sem && lcl_rctl->standalone); \ + if (0 != (save_errno = do_semop(lcl_udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO))) \ + { \ + assert(FALSE); /* we hold it, so we should be able to release it*/ \ + rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5, \ + RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \ + } \ + lcl_udi->grabbed_access_sem = FALSE; \ + lcl_rctl->standalone = FALSE; \ } #define GRAB_ACCESS_CONTROL(REGLIST) \ @@ -131,7 +132,7 @@ rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5,\ RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \ } \ - lcl_udi->grabbed_access_sem = TRUE; \ + lcl_udi->grabbed_access_sem = TRUE; \ lcl_rctl->standalone = TRUE; \ } \ } @@ -145,6 +146,7 @@ GBLREF mur_gbls_t murgbl; GBLREF gd_region *gv_cur_region; GBLREF jnlpool_addrs jnlpool; GBLREF gd_addr *gd_header; +GBLREF sgmnt_data *cs_data; #ifdef UNIX GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF sgmnt_addrs *cs_addrs; @@ -152,7 +154,7 @@ GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; GBLREF int4 strm_index; GBLREF uint4 process_id; GBLREF jnl_gbls_t jgbl; -GBLREF sgmnt_data *cs_data; +GBLREF boolean_t jnlpool_init_needed; #endif @@ -229,6 +231,7 @@ boolean_t mur_open_files() # else /* ONLINE ROLLBACK specific variables */ onln_rlbk_reg_list *reglist = NULL, *rl, *rl_last, *save_rl, *rl_new; boolean_t x_lock, wait_for_kip, replinst_file_corrupt = FALSE, inst_requires_rlbk; + boolean_t jnlpool_sem_created; sgmnt_addrs *tmpcsa; sgmnt_data *tmpcsd; gd_region *reg; @@ -244,6 +247,7 @@ boolean_t mur_open_files() DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + UNIX_ONLY(jnlpool_init_needed = !mur_options.update); jnl_file_list_len = MAX_LINE; if (FALSE == CLI_GET_STR_ALL("FILE", jnl_file_list, &jnl_file_list_len)) mupip_exit(ERR_MUPCLIERR); @@ -269,11 +273,8 @@ boolean_t mur_open_files() /* We assume recovery will be done only on current global directory. * That is, journal file names specified must be from current global directory. */ - if (star_specified || mur_options.update && !mur_options.redirect) - { /* "*" is specified or it is -recover or -rollback. We require gtmgbldir to be set in all these cases. - * The only exception is "-redirect" in which case the target database is obtained from -redirect - * instead of from the global directory. - */ + if (star_specified || mur_options.update) + { /* "*" is specified or it is -recover or -rollback. We require gtmgbldir to be set in all these cases */ assert(NULL == gd_header); gvinit(); /* read in current global directory */ assert(NULL != gd_header); @@ -295,17 +296,17 @@ boolean_t mur_open_files() { /* Rundown the Jnlpool and Recvpool */ # if defined(UNIX) if (!repl_inst_get_name((char *)replpool_id.instfilename, &full_len, SIZEOF(replpool_id.instfilename), - issue_gtm_putmsg)) + issue_gtm_putmsg)) { /* appropriate gtm_putmsg would have already been issued by repl_inst_get_name */ return FALSE; } assert(NUM_SRC_SEMS == NUM_RECV_SEMS); ASSERT_DONOT_HOLD_REPLPOOL_SEMS; assert(NULL == jnlpool.repl_inst_filehdr); - if (!mu_rndwn_repl_instance(&replpool_id, FALSE, TRUE)) + if (!mu_rndwn_repl_instance(&replpool_id, FALSE, TRUE, &jnlpool_sem_created)) return FALSE; /* mu_rndwn_repl_instance will have printed appropriate message in case of error */ assert(jnlpool.jnlpool_ctl == jnlpool_ctl); - assert(jgbl.onlnrlbk || (NULL == jnlpool_ctl)); + assert(jgbl.onlnrlbk || ANTICIPATORY_FREEZE_AVAILABLE || (NULL == jnlpool_ctl)); ASSERT_HOLD_REPLPOOL_SEMS; assert(NULL != jnlpool.repl_inst_filehdr); assert(INVALID_SEMID != jnlpool.repl_inst_filehdr->jnlpool_semid); @@ -317,9 +318,10 @@ boolean_t mur_open_files() */ if (jnlpool.repl_inst_filehdr->is_supplementary) { - assert(INVALID_SUPPL_STRM == strm_index); + assert((INVALID_SUPPL_STRM == strm_index) || (0 == strm_index)); strm_index = 0; } + ENABLE_FREEZE_ON_ERROR; # elif defined(VMS) gbldir_mstr.addr = GTM_GBLDIR; gbldir_mstr.len = SIZEOF(GTM_GBLDIR) - 1; @@ -411,11 +413,11 @@ boolean_t mur_open_files() rctl->db_present = TRUE; if (mur_options.update) { - gv_cur_region = rctl->gd; /* mu_rndwn_file() assumes gv_cur_region is set in VMS */ # ifdef UNIX if (!jgbl.onlnrlbk) { # endif + VMS_ONLY(gv_cur_region = rctl->gd); /* VMS mu_rndwn_file() assumes gv_cur_region is set */ if (!STANDALONE(rctl->gd)) /* STANDALONE macro calls mu_rndwn_file() */ { gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(rctl->gd)); @@ -429,10 +431,10 @@ boolean_t mur_open_files() if (mur_options.update || mur_options.extr[GOOD_TN]) { gvcst_init(rctl->gd); + TP_CHANGE_REG(rctl->gd); # ifdef UNIX if (jgbl.onlnrlbk) { - TP_CHANGE_REG(rctl->gd); if (!cs_data->fully_upgraded) { gtm_putmsg(VARLSTCNT(6) ERR_ORLBKNOV4BLK, 4, REG_LEN_STR(gv_cur_region), @@ -485,12 +487,11 @@ boolean_t mur_open_files() { /* Get hold of all the gtmsource_srv_latch in all the source server slots in the journal pool. Hold * onto it until the end (in mur_close_files). */ - if (!grab_gtmsource_srv_latch(>msourcelocal_ptr->gtmsource_srv_latch, 2 * max_epoch_interval)) - { - gtm_putmsg(VARLSTCNT(5) ERR_SRVLCKWT2LNG, 2, (2 * max_epoch_interval), - gtmsourcelocal_ptr->gtmsource_pid); - return FALSE; - } + jnlpool.gtmsource_local = gtmsourcelocal_ptr; + if (!grab_gtmsource_srv_latch(>msourcelocal_ptr->gtmsource_srv_latch, + 2 * max_reg_total * max_epoch_interval, GRAB_GTMSOURCE_SRV_LATCH_ONLY)) + assertpro(FALSE); /* should not reach here due to rts_error in the above function */ + } } /* For online rollback we need to grab crit on all the regions. But, this has to be done in the ftok order. To @@ -564,7 +565,7 @@ boolean_t mur_open_files() */ if (NULL != jnlpool_ctl) { /* Validate the journal pool is accessible and the offsets of various structures within it are intact */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); csa->hold_onto_crit = TRUE; /* No more unconditional rel_lock() */ assert(jnlpool.repl_inst_filehdr->crash); /* since we haven't removed the journal pool */ repl_inst_flush_jnlpool(FALSE, FALSE); @@ -579,7 +580,7 @@ boolean_t mur_open_files() TP_CHANGE_REG(reg); # ifdef DEBUG udi = FILE_INFO(reg); - assert(1 == (semval = semctl(udi->semid, 0, GETVAL))); + assert(1 == (semval = semctl(udi->semid, DB_CONTROL_SEM, GETVAL))); # endif assert(cs_addrs->now_crit); cs_addrs->hold_onto_crit = TRUE; /* No more unconditional grab_crit/rel_crit on this region */ @@ -598,7 +599,7 @@ boolean_t mur_open_files() if (!wcs_flu(WCSFLU_NONE)) { assert(cs_addrs->nl->wcs_phase2_commit_pidcnt); /* only reason why wcs_flu can fail */ - SET_TRACEABLE_VAR(cs_addrs->hdr->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cs_addrs->nl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(cs_addrs, wc_blocked_onln_rlbk); send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wc_blocked_onln_rlbk"), process_id, &cs_addrs->ti->curr_tn, DB_LEN_STR(gv_cur_region)); @@ -644,6 +645,7 @@ boolean_t mur_open_files() if (mur_options.update || mur_options.extr[GOOD_TN]) { /* NOTE: Only for collation info extract needs database access */ DEFER_INTERRUPTS(INTRPT_IN_MUR_OPEN_FILES); /* temporarily disable MUPIP STOP/signal handling. */ + TP_CHANGE_REG(rctl->gd); csa = rctl->csa = &FILE_INFO(rctl->gd)->s_addrs; csd = rctl->csd = rctl->csa->hdr; @@ -721,9 +723,13 @@ boolean_t mur_open_files() } } else { - if (!REPL_ALLOWED(csd)) - { - if (JNL_ENABLED(csd)) + if (!REPL_ENABLED(csd)) + { /* Replication is either OFF or WAS_ON. Journaling could be ENABLED or not. + * If replication is OFF and journaling is DISABLED, there is no issue. + * Any other combination (including replication being WAS_ON) is an error + * as we dont have the complete set of journal records to do the rollback. + */ + if (REPL_ALLOWED(csd) || JNL_ENABLED(csd)) { gtm_putmsg(VARLSTCNT(4) ERR_REPLSTATEOFF, 2, DB_LEN_STR(rctl->gd)); return FALSE; @@ -1109,6 +1115,19 @@ boolean_t mur_open_files() } } } /* if mur_options.update */ + if (mur_options.extr[GOOD_TN]) + { + csa = rctl->csa; + if (NULL != csa) + { +# if (defined(DEBUG) && defined(VMS)) + /* set wc_blocked as true to invoke wcs_recover */ + GTM_WHITE_BOX_TEST(WBTEST_SET_WC_BLOCKED, csa->nl->wc_blocked, TRUE); +# endif + if (csa->nl->wc_blocked) + TREF(donot_write_inctn_in_wcs_recover) = TRUE; + } + } while (NULL != jctl->next_gen) /* Check for continuity */ { if (!mur_options.notncheck && (jctl->next_gen->jfh->bov_tn != jctl->jfh->eov_tn)) diff --git a/sr_port/mur_output_record.c b/sr_port/mur_output_record.c index cc8a13a..621d085 100644 --- a/sr_port/mur_output_record.c +++ b/sr_port/mur_output_record.c @@ -41,7 +41,7 @@ #include "send_msg.h" #include "svnames.h" /* for SV_ZTWORMHOLE */ #ifdef GTM_TRIGGER -#include "rtnhdr.h" +#include #include "gv_trigger.h" #endif /* Include prototypes */ @@ -95,11 +95,10 @@ uint4 mur_output_record(reg_ctl_list *rctl) sgmnt_data_ptr_t csd; jnl_ctl_list *jctl; jnl_format_buffer *ztworm_jfb; - GTMCRYPT_ONLY( - blk_hdr_ptr_t aimg_blk_ptr; - int req_dec_blk_size; - int crypt_status; - ) +# ifdef GTM_CRYPT + blk_hdr_ptr_t aimg_blk_ptr; + int in_len, gtmcrypt_errno ; +# endif assert(mur_options.update); rec = rctl->mur_desc->jnlrec; @@ -161,7 +160,7 @@ uint4 mur_output_record(reg_ctl_list *rctl) keystr = (jnl_string *)&rec->jrec_set_kill.mumps_node; if (jnl_enabled) { - jnl_fence_ctl.token = rec->jrec_set_kill.token_seq.token; + MUR_SET_JNL_FENCE_CTL_TOKEN(rec->jrec_set_kill.token_seq.token, rctl); jnl_fence_ctl.strm_seqno = rec->jrec_set_kill.strm_seqno; jgbl.tp_ztp_jnl_upd_num = rec->jrec_set_kill.update_num; DEBUG_ONLY(jgbl.max_tp_ztp_jnl_upd_num = MAX(jgbl.max_tp_ztp_jnl_upd_num, jgbl.tp_ztp_jnl_upd_num);) @@ -251,7 +250,7 @@ uint4 mur_output_record(reg_ctl_list *rctl) if (jnl_enabled) { /* Format the ZTWORM journal record */ assert(dollar_tlevel); /* op_tstart should already have been done by mur_forward */ - jnl_fence_ctl.token = rec->jrec_ztworm.token_seq.token; + MUR_SET_JNL_FENCE_CTL_TOKEN(rec->jrec_ztworm.token_seq.token, rctl); jnl_fence_ctl.strm_seqno = rec->jrec_ztworm.strm_seqno; jgbl.tp_ztp_jnl_upd_num = rec->jrec_ztworm.update_num; DEBUG_ONLY(jgbl.max_tp_ztp_jnl_upd_num = MAX(jgbl.max_tp_ztp_jnl_upd_num, jgbl.tp_ztp_jnl_upd_num);) @@ -271,23 +270,24 @@ uint4 mur_output_record(reg_ctl_list *rctl) * are done playing the journal records of ALL regions involved in the TP. */ if (NULL == rctl->forw_multi) - { /* Even for FENCE_NONE we apply fences. Otherwise an TUPD/UUPD becomes UPD etc. */ + { /* Even for FENCE_NONE we apply fences. Otherwise a TUPD/UUPD becomes UPD etc. */ if (jnl_enabled) { - jnl_fence_ctl.token = rec->jrec_tcom.token_seq.token; + MUR_SET_JNL_FENCE_CTL_TOKEN(rec->jrec_tcom.token_seq.token, rctl); jnl_fence_ctl.strm_seqno = rec->jrec_tcom.strm_seqno; jgbl.mur_jrec_participants = rec->jrec_tcom.num_participants; memcpy(tcom_record.jnl_tid, rec->jrec_tcom.jnl_tid, TID_STR_SIZE); } assert(dollar_tlevel); op_tcommit(); - } + } else + MUR_DBG_SET_LAST_PROCESSED_JNL_SEQNO(rec->jrec_tcom.token_seq.token, rctl); break; case JRT_ZTCOM: /* Even for FENCE_NONE we apply fences. Otherwise an FUPD/GUPD becomes UPD etc. */ if (jnl_enabled) { - jnl_fence_ctl.token = rec->jrec_ztcom.token; + MUR_SET_JNL_FENCE_CTL_TOKEN(rec->jrec_ztcom.token, rctl); jnl_fence_ctl.strm_seqno = 0; /* strm_seqno is only for replication & ZTCOM does not work with replic */ jgbl.mur_jrec_participants = rec->jrec_ztcom.participants; } @@ -326,22 +326,18 @@ uint4 mur_output_record(reg_ctl_list *rctl) return SS_NORMAL; write_after_image = TRUE; # ifdef GTM_CRYPT - /* Decrypt AIMG records if applicable. */ aimg_blk_ptr = (blk_hdr_ptr_t)&rec->jrec_aimg.blk_contents[0]; if (csd->is_encrypted) { assert((aimg_blk_ptr->bsiz <= csd->blk_size) && (aimg_blk_ptr->bsiz >= SIZEOF(blk_hdr))); - req_dec_blk_size = MIN(csd->blk_size, aimg_blk_ptr->bsiz) - SIZEOF(blk_hdr); + in_len = MIN(csd->blk_size, aimg_blk_ptr->bsiz) - SIZEOF(blk_hdr); ASSERT_ENCRYPTION_INITIALIZED; - if (IS_BLK_ENCRYPTED(aimg_blk_ptr->levl, req_dec_blk_size)) + if (IS_BLK_ENCRYPTED(aimg_blk_ptr->levl, in_len)) { - GTMCRYPT_DECODE_FAST(jctl->encr_key_handle, - (char *)(aimg_blk_ptr + 1), - req_dec_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, NULL); + GTMCRYPT_DECRYPT(csa, jctl->encr_key_handle, (char *)(aimg_blk_ptr + 1), in_len, NULL, + gtmcrypt_errno) + if (0 != gtmcrypt_errno) + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, jctl->jnl_fn_len, jctl->jnl_fn); } } # endif @@ -374,6 +370,11 @@ uint4 mur_output_record(reg_ctl_list *rctl) break; case JRT_NULL: assert(cs_addrs == rctl->csa); + if (jnl_enabled) + { + MUR_SET_JNL_FENCE_CTL_TOKEN(rec->jrec_null.jnl_seqno, rctl); + jnl_fence_ctl.strm_seqno = rec->jrec_null.strm_seqno; + } gvcst_jrt_null(); break; default: diff --git a/sr_port/mur_output_show.c b/sr_port/mur_output_show.c index e24fa93..804c8b4 100644 --- a/sr_port/mur_output_show.c +++ b/sr_port/mur_output_show.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 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 #endif #include "real_len.h" /* for real_len() prototype */ +#include "have_crit.h" GBLREF mur_opt_struct mur_options; GBLREF reg_ctl_list *mur_ctl; @@ -133,7 +134,7 @@ int format_time(jnl_proc_time proc_time, char *string, int string_len, int time_ short_time = MID_TIME(proc_time); else short_time = (time_t)proc_time; - tsp = localtime((const time_t *)&short_time); + GTM_LOCALTIME(tsp, (const time_t *)&short_time); SPRINTF(string, "%04d/%02d/%02d %02d:%02d:%02d", (1900 + tsp->tm_year), (1 + tsp->tm_mon), tsp->tm_mday, tsp->tm_hour, tsp->tm_min, tsp->tm_sec); assert(LENGTH_OF_TIME >= strlen(string)); @@ -243,7 +244,7 @@ void mur_show_header(jnl_ctl_list * jctl) } util_out_print("!/Process That Created the Journal File:!/", TRUE); mur_show_jpv(&hdr->who_created, TRUE); - util_out_print("!/Process That Last Wrote to the Journal File:!/", TRUE); + util_out_print("!/Process That First Opened the Journal File:!/", TRUE); mur_show_jpv(&hdr->who_opened, TRUE); util_out_print("", TRUE); } diff --git a/sr_port/mur_process_intrpt_recov.c b/sr_port/mur_process_intrpt_recov.c index 6b3b7b7..6f3112f 100644 --- a/sr_port/mur_process_intrpt_recov.c +++ b/sr_port/mur_process_intrpt_recov.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" +#include "gtmio.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" @@ -40,8 +41,8 @@ #include "muprec.h" #include "iosp.h" #include "jnl_typedef.h" -#include "gtmio.h" #include "gtmmsg.h" +#include "anticipatory_freeze.h" #include "wcs_flu.h" /* for wcs_flu() prototype */ #include "wbox_test_init.h" @@ -53,7 +54,7 @@ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; -error_def(ERR_PREMATEOF); /* for DO_FILE_WRITE */ +error_def(ERR_PREMATEOF); /* for JNL_DO_FILE_WRITE */ error_def(ERR_JNLNOCREATE); error_def(ERR_JNLWRERR); error_def(ERR_JNLFSYNCERR); @@ -77,14 +78,14 @@ uint4 mur_process_intrpt_recov() io_status_block_disk iosb; ) boolean_t jfh_changed; - jnl_record *jnlrec; - jnl_file_header *jfh; + jnl_record *jnlrec; + jnl_file_header *jfh; + jnl_tm_t now; for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++) { - gv_cur_region = rctl->gd; /* wcs_flu requires this to be set */ - cs_addrs = rctl->csa; - csd = cs_data = rctl->csd; /* MM logic after wcs_flu call requires this to be set */ + TP_CHANGE_REG(rctl->gd); + csd = cs_data; /* MM logic after wcs_flu call requires this to be set */ assert(csd == rctl->csa->hdr); jctl = rctl->jctl_turn_around; max_jnl_alq = max_jnl_deq = max_autoswitchlimit = 0; @@ -218,8 +219,8 @@ uint4 mur_process_intrpt_recov() * is in progress */ bt_refresh(cs_addrs, FALSE); /* sets earliest bt TN to be the turn around TN */ - db_csh_ref(cs_addrs, FALSE); } + db_csh_ref(cs_addrs, FALSE); assert(NULL != cs_addrs->jnl); jpc = cs_addrs->jnl; assert(NULL != jpc->jnl_buff); @@ -238,22 +239,24 @@ uint4 mur_process_intrpt_recov() jbp->prev_jrec_time = jctl->turn_around_time; } else if (dba_bg == csd->acc_meth) { /* set earliest bt TN to be the turn-around TN (taken from bt_refresh()) */ - ((th_rec *)((uchar_ptr_t)cs_addrs->th_base + cs_addrs->th_base->tnque.fl))->tn = cs_addrs->ti->curr_tn - 1; + SET_OLDEST_HIST_TN(cs_addrs, cs_addrs->ti->curr_tn - 1); } # else if (dba_bg == csd->acc_meth) { /* set earliest bt TN to be the turn-around TN (taken from bt_refresh()) */ - ((th_rec *)((uchar_ptr_t)cs_addrs->th_base + cs_addrs->th_base->tnque.fl))->tn = cs_addrs->ti->curr_tn - 1; + SET_OLDEST_HIST_TN(cs_addrs, cs_addrs->ti->curr_tn - 1); } # endif csd->turn_around_point = FALSE; - assert(((th_rec *)((uchar_ptr_t)cs_addrs->th_base + cs_addrs->th_base->tnque.fl))->tn == cs_addrs->ti->curr_tn - 1); + assert(OLDEST_HIST_TN(cs_addrs) == (cs_addrs->ti->curr_tn - 1)); /* In case this is MM and wcs_flu() remapped an extended database, reset rctl->csd */ assert((dba_mm == cs_data->acc_meth) || (rctl->csd == cs_data)); rctl->csd = cs_data; } + JNL_SHORT_TIME(now); for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++) { + TP_CHANGE_REG_IF_NEEDED(rctl->gd); if (!rctl->jfh_recov_interrupted) jctl = rctl->jctl_turn_around; else @@ -273,7 +276,7 @@ uint4 mur_process_intrpt_recov() assert(rctl->csd->jnl_file_len == jctl->jnl_fn_len); /* latest gener file name */ assert(0 == memcmp(rctl->csd->jnl_file_name, jctl->jnl_fn, jctl->jnl_fn_len)); /* should match db header */ if (SS_NORMAL != (status = prepare_unique_name((char *)jctl->jnl_fn, jctl->jnl_fn_len, "", "", - rename_fn, &rename_fn_len, &status2))) + rename_fn, &rename_fn_len, now, &status2))) return status; jctl->jnl_fn_len = rename_fn_len; /* change the name in memory to the proposed name */ memcpy(jctl->jnl_fn, rename_fn, rename_fn_len + 1); @@ -325,29 +328,34 @@ uint4 mur_process_intrpt_recov() } if (jfh_changed) { - DO_FILE_WRITE(jctl->channel, 0, jfh, REAL_JNL_HDR_LEN, jctl->status, jctl->status2); + /* Since overwriting the journal file header (an already allocated block + * in the file) should not cause ENOSPC, we dont take the trouble of + * passing csa or jnl_fn (first two parameters). Instead we pass NULL. + */ + JNL_DO_FILE_WRITE(NULL, NULL, jctl->channel, 0, jfh, + REAL_JNL_HDR_LEN, jctl->status, jctl->status2); if (SS_NORMAL != jctl->status) { assert(FALSE); if (SS_NORMAL == jctl->status2) - gtm_putmsg(VARLSTCNT(5) ERR_JNLWRERR, 2, jctl->jnl_fn_len, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); else - gtm_putmsg(VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status, PUT_SYS_ERRNO(jctl->status2)); return jctl->status; } UNIX_ONLY( - GTM_FSYNC(jctl->channel, jctl->status); - if (-1 == jctl->status) - { - jctl->status2 = errno; - assert(FALSE); - gtm_putmsg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, - jctl->jnl_fn_len, jctl->jnl_fn, - ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), jctl->status2); - return ERR_JNLFSYNCERR; - } + GTM_JNL_FSYNC(rctl->csa, jctl->channel, jctl->status); + if (-1 == jctl->status) + { + jctl->status2 = errno; + assert(FALSE); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, + jctl->jnl_fn_len, jctl->jnl_fn, + ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), jctl->status2); + return ERR_JNLFSYNCERR; + } ) } jfh_changed = FALSE; @@ -367,7 +375,7 @@ uint4 mur_process_intrpt_recov() jgbl.gbl_jrec_time = rctl->jctl_turn_around->turn_around_time; /* time needed for cre_jnl_file_common() */ if (EXIT_NRM != cre_jnl_file_common(&jnl_info, rename_fn, rename_fn_len)) { - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); + gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl); return jnl_info.status; } # ifdef UNIX diff --git a/sr_port/mur_process_timequal.c b/sr_port/mur_process_timequal.c index 8c73a8b..4619d19 100644 --- a/sr_port/mur_process_timequal.c +++ b/sr_port/mur_process_timequal.c @@ -1,6 +1,6 @@ /**************************************************************** * - * Copyright 2005 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,9 +31,16 @@ #include "gtmmsg.h" /* for gtm_putmsg() prototype */ #include "cli.h" #include "mupip_exit.h" +#include "have_crit.h" GBLREF mur_opt_struct mur_options; +error_def (ERR_JNLTMQUAL1); +error_def (ERR_JNLTMQUAL2); +error_def (ERR_JNLTMQUAL3); +error_def (ERR_JNLTMQUAL4); +error_def (ERR_MUNOACTION); + #ifdef VMS static int4 mur_rel2abstime(jnl_proc_time deltatime, jnl_proc_time basetime, boolean_t roundup) { @@ -107,12 +114,6 @@ void mur_process_timequal(jnl_tm_t max_lvrec_time, jnl_tm_t min_bov_time) { char time_str1[LENGTH_OF_TIME + 1], time_str2[LENGTH_OF_TIME + 1]; - error_def (ERR_JNLTMQUAL1); - error_def (ERR_JNLTMQUAL2); - error_def (ERR_JNLTMQUAL3); - error_def (ERR_JNLTMQUAL4); - error_def (ERR_MUNOACTION); - /* All time qualifiers are specified in delta time or absolute time. * mur_options.since_time == 0 means no since time was specified * mur_options.since_time < 0 means it is the delta since time. diff --git a/sr_port/mur_put_aimg_rec.c b/sr_port/mur_put_aimg_rec.c index 92b5675..0cd2607 100644 --- a/sr_port/mur_put_aimg_rec.c +++ b/sr_port/mur_put_aimg_rec.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,7 +47,7 @@ GBLREF srch_hist dummy_hist; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF cw_set_element cw_set[]; -GBLREF unsigned char *non_tp_jfb_buff_ptr; +GBLREF jnl_format_buffer *non_tp_jfb_ptr; /* Modified on the similar lines of dse AIMG record logic, needed for recover to write journal records */ void mur_put_aimg_rec(jnl_record *rec) @@ -87,7 +87,7 @@ void mur_put_aimg_rec(jnl_record *rec) if (JNL_ENABLED(cs_data)) { cse = (cw_set_element *)(&cw_set[0]); - cse->new_buff = non_tp_jfb_buff_ptr; + cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, cs_addrs->ti->curr_tn); cse->done = TRUE; } diff --git a/sr_port/mur_read_file.c b/sr_port/mur_read_file.c index b246fa9..0bcd56d 100644 --- a/sr_port/mur_read_file.c +++ b/sr_port/mur_read_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2012 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -48,13 +48,17 @@ #include "gtmmsg.h" #include "mur_validate_checksum.h" #include "repl_sp.h" /* for F_CLOSE (used by JNL_FD_CLOSE) */ +#ifdef GTM_CRYPT +#include "gtmcrypt.h" +#include "error.h" +#endif error_def(ERR_BEGSEQGTENDSEQ); error_def(ERR_BOVTNGTEOVTN); error_def(ERR_GTMASSERT); error_def(ERR_JNLBADRECFMT); error_def(ERR_JNLFILECLOSERR); -error_def(ERR_JNLFILOPN); +error_def(ERR_JNLFILRDOPN); error_def(ERR_JNLINVALID); error_def(ERR_JNLNOBIJBACK); error_def(ERR_JNLREAD); @@ -105,8 +109,8 @@ uint4 mur_prev_rec(jnl_ctl_list **jjctl) if (JRT_EOF != mur_desc->jnlrec->prefix.jrec_type) return SS_NORMAL; /* unexpected EOF record in the middle of the file */ - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, - ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [prev_rec]")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [prev_rec]")); status = ERR_JNLBADRECFMT; } if (ERR_JNLBADRECFMT != status) @@ -124,8 +128,8 @@ uint4 mur_prev_rec(jnl_ctl_list **jjctl) * Notice that the offset jctl->rec_offset points to a good record. The badly formatted * journal record is actually one record BEFORE the printed offset. */ - gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, - ERR_TEXT, 2, LEN_AND_LIT("Error accessing previous record")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Error accessing previous record")); } else { /* offset is at tail of journal file after crash. Caller could be backward recovery or * forward recovery or even extract/verify/show if they are in tail_analysis. We expect @@ -151,7 +155,7 @@ uint4 mur_prev_rec(jnl_ctl_list **jjctl) return ERR_NOPREVLINK; } if (!mur_insert_prev(&jctl)) - return ERR_JNLFILOPN; + return ERR_JNLFILRDOPN; } jctl->rec_offset = jctl->lvrec_off; /* lvrec_off was set in fread_eof that was called when we opened the file(s) */ *jjctl = jctl; @@ -188,8 +192,8 @@ uint4 mur_next_rec(jnl_ctl_list **jjctl) assert(jctl->rec_offset <= jctl->lvrec_off); if (JRT_EOF != mur_desc->jnlrec->prefix.jrec_type || jctl->rec_offset == jctl->lvrec_off) return SS_NORMAL; - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, - ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [next_rec]")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [next_rec]")); status = ERR_JNLBADRECFMT; } if (ERR_JNLBADRECFMT != status) @@ -202,8 +206,8 @@ uint4 mur_next_rec(jnl_ctl_list **jjctl) /* continue in distress, look for other valid records */ return mur_valrec_next(jctl, jctl->rec_offset + rec_size); } - gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, - ERR_TEXT, 2, LEN_AND_LIT("Error accessing next record")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Error accessing next record")); return status; } assert(jctl->rec_offset == jctl->lvrec_off); @@ -244,16 +248,16 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) assert(dskaddr >= JNL_HDR_LEN); if (dskaddr >= jctl->eof_addr || dskaddr < JNL_HDR_LEN) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [prev]")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, + dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [prev]")); return (dskaddr >= jctl->eof_addr ? ERR_JNLREADEOF : ERR_JNLREADBOF); } assert(dskaddr == ROUND_UP2(dskaddr, JNL_REC_START_BNDRY)); /* dskaddr must be aligned at JNL_REC_START_BNDRY */ MUR_FREAD_CANCEL(jctl, mur_desc, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [prev]"), jctl->status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [prev]"), jctl->status); return jctl->status; } mur_desc->buff_index = 1; @@ -266,8 +270,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) /* we rely on reading at least up to the record length field (forwptr) */ if (SS_NORMAL != (status = mur_freadw(jctl, mur_desc->cur_buff))) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->cur_buff->dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Error from synchronous read into cur_buff [prev]"), status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Error from synchronous read into cur_buff [prev]"), status); return status; } mur_desc->jnlrec = (jnl_record *)(mur_desc->cur_buff->base + buff_offset); @@ -281,8 +286,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not initiate read into sec_buff in [prev] (dskaddr > 0)"), status); return status; @@ -301,15 +306,15 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) { if (SS_NORMAL != (status = mur_freadw(jctl, &mur_desc->aux_buff2))) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->aux_buff2.dskaddr, ERR_TEXT, 2, - LEN_AND_LIT("Error in synchronous read into aux_buff [prev]"), status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, + jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->aux_buff2.dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Error in synchronous read into aux_buff [prev]"), status); return status; } } else { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, - jctl->jnl_fn, dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, + jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Requested offset beyond end of file [prev] (dskaddr > 0)")); return ERR_JNLBADRECFMT; } @@ -334,10 +339,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, - LEN_AND_LIT("Could not initiate read into sec_buff [prev] (dskaddr == 0)"), - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Could not initiate read into sec_buff [prev] (dskaddr == 0)"), status); return status; } } @@ -357,8 +361,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Error waiting for sec_buff read to complete [prev]"), status); return status; @@ -374,8 +378,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->cur_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not initiate read into cur_buff [prev]"), status); return status; } @@ -395,9 +399,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr) mur_desc->jreclen = suffix->backptr; if (jctl->rec_offset < mur_desc->jreclen + JNL_HDR_LEN) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, - jctl->rec_offset, ERR_TEXT, 2, - LEN_AND_LIT("Requested offset beyond beginning of file [prev]")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, + jctl->jnl_fn, jctl->rec_offset, ERR_TEXT, 2, + LEN_AND_LIT("Requested offset beyond beginning of file [prev]")); return ERR_JNLBADRECFMT; } } @@ -433,16 +437,16 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) assert(dskaddr >= JNL_HDR_LEN); if (dskaddr >= jctl->eof_addr || dskaddr < JNL_HDR_LEN) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [next]")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, + dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [next]")); return (dskaddr >= jctl->eof_addr ? ERR_JNLREADEOF : ERR_JNLREADBOF); } assert(dskaddr == ROUND_UP2(dskaddr, JNL_REC_START_BNDRY)); /* dskaddr must be aligned at JNL_REC_START_BNDRY */ MUR_FREAD_CANCEL(jctl, mur_desc, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [next]"), jctl->status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [next]"), jctl->status); return jctl->status; } mur_desc->buff_index = 0; @@ -455,9 +459,9 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) * the record length field (forwptr) */ if (SS_NORMAL != (status = mur_freadw(jctl, mur_desc->cur_buff))) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->cur_buff->dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Error from synchronous read into cur_buff [next]"), - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Error from synchronous read into cur_buff [next]"), status); return status; } mur_desc->jnlrec = (jnl_record *)(mur_desc->cur_buff->base + buff_offset); @@ -471,8 +475,8 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr > 0)"), status); return status; @@ -483,10 +487,11 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, - LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr > 0)"), - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, + jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Error waiting for sec_buff read to complete [next] " + "(dskaddr > 0)"), + status); return status; } /* is the record available in its entirety? */ @@ -498,8 +503,9 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) /* is the record available in its entirety? */ if (!good_prefix) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, - ERR_TEXT, 2, LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr > 0)")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, + jctl->jnl_fn, dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr > 0)")); return ERR_JNLBADRECFMT; } } /* end good_prefix */ @@ -524,10 +530,10 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, - LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr == 0)"), - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr == 0)"), + status); return status; } } @@ -547,10 +553,10 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, - LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr == 0)"), - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2, + LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr == 0)"), + status); return status; } } @@ -564,8 +570,8 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) MUR_FREAD_START(jctl, mur_desc->cur_buff, status); if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, - mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, + jctl->jnl_fn, mur_desc->cur_buff->dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not initiate read into cur_buff [next]"), status); return status; } @@ -589,7 +595,7 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr) { if (!jctl->tail_analysis) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr == 0)")); return ERR_JNLBADRECFMT; @@ -782,8 +788,8 @@ uint4 mur_valrec_prev(jnl_ctl_list *jctl, off_jnl_t lo_off, off_jnl_t hi_off) mur_desc->random_buff.blen = blen; if (SS_NORMAL != (status = mur_read(jctl))) { - gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->random_buff.dskaddr, - status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + mur_desc->random_buff.dskaddr, status); return status; } rec = (jnl_record *)mur_desc->random_buff.base; @@ -835,7 +841,7 @@ uint4 mur_valrec_prev(jnl_ctl_list *jctl, off_jnl_t lo_off, off_jnl_t hi_off) rec_offset = jctl->rec_offset; if (SS_NORMAL != (status = mur_next(jctl, rec_offset))) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, rec_offset, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Error received from mur_valrec_prev calling mur_next(rec_offset)")); return status; } @@ -933,9 +939,9 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) char jrecbuf[PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN]; jnl_record *jrec; int cre_jnl_rec_size; - GTMCRYPT_ONLY( - int crypt_status; - ) +# ifdef GTM_CRYPT + int gtmcrypt_errno; +# endif if (!mur_fopen_sp(jctl)) return FALSE; @@ -955,14 +961,15 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) */ jfh->data_file_name_length = 0; if (ERR_JNLINVALID == jctl->status) - gtm_putmsg(VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn, jfh->data_file_name_length, - jfh->data_file_name, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn, + jfh->data_file_name_length, jfh->data_file_name, ERR_TEXT, 2, LEN_AND_LIT("Journal file does not have complete file header")); else if (SS_NORMAL != jctl->status2) - gtm_putmsg(VARLSTCNT1(7) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, jctl->status, - PUT_SYS_ERRNO(jctl->status2)); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT1(7) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, + jctl->status, PUT_SYS_ERRNO(jctl->status2)); else - gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, jctl->status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, + jctl->status); return FALSE; } if (SS_NORMAL == jctl->status) @@ -980,12 +987,13 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) DO_FILE_READ(jctl->channel, JNL_HDR_LEN, jrecbuf, cre_jnl_rec_size, jctl->status, jctl->status2); if (SS_NORMAL != jctl->status) { - gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN, jctl->status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, + JNL_HDR_LEN, jctl->status); return FALSE; } } else { - gtm_putmsg(VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn, + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn, jfh->data_file_name_length, jfh->data_file_name, ERR_TEXT, 2, LEN_AND_LIT("File size is less than minimum expected for a valid journal file")); return FALSE; @@ -995,23 +1003,27 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) VMS_ONLY(assert(!mur_options.rollback_losttnonly);) if (mur_options.rollback_losttnonly) { /* Already prepared for a LOSTTNONLY rollback. Allow NOBEFORE_IMAGE journal file but issue a warning. */ - gtm_putmsg(VARLSTCNT(4) ERR_RLBKJNLNOBIMG, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_RLBKJNLNOBIMG, 2, jctl->jnl_fn_len, + jctl->jnl_fn); } else { - gtm_putmsg(VARLSTCNT(4) ERR_JNLNOBIJBACK, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_JNLNOBIJBACK, 2, jctl->jnl_fn_len, + jctl->jnl_fn); return FALSE; } } - if (!REPL_ALLOWED(jfh) && mur_options.rollback) + assert(!REPL_WAS_ENABLED(jfh)); /* a journal file can never be created if replication is in WAS_ON state */ + assert(REPL_ALLOWED(jfh) == REPL_ENABLED(jfh)); + if (!REPL_ENABLED(jfh) && mur_options.rollback) { - gtm_putmsg(VARLSTCNT(4) ERR_REPLNOTON, 2, jctl->jnl_fn_len, jctl->jnl_fn); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_REPLNOTON, 2, jctl->jnl_fn_len, jctl->jnl_fn); return FALSE; } jrec = (jnl_record *)jrecbuf; if (!IS_VALID_JNLREC(jrec, jfh) || JRT_PINI != jrec->prefix.jrec_type) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN, - ERR_TEXT, 2, LEN_AND_LIT("Invalid or no PINI record found")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + JNL_HDR_LEN, ERR_TEXT, 2, LEN_AND_LIT("Invalid or no PINI record found")); return FALSE; } /* We have at least one good record */ @@ -1020,27 +1032,29 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) jrec = (jnl_record *)((char *)jrec + PINI_RECLEN); if (!IS_VALID_JNLREC(jrec, jfh) || JRT_EPOCH != jrec->prefix.jrec_type) { - gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN + PINI_RECLEN, - ERR_TEXT, 2, LEN_AND_LIT("Invalid or no EPOCH record found")); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, + JNL_HDR_LEN + PINI_RECLEN, ERR_TEXT, 2, LEN_AND_LIT("Invalid or no EPOCH record found")); return FALSE; } /* We have at least one valid EPOCH */ } if (mur_options.update && jfh->bov_tn > jfh->eov_tn) { - gtm_putmsg(VARLSTCNT(6) ERR_BOVTNGTEOVTN, 4, jctl->jnl_fn_len, jctl->jnl_fn, &jfh->bov_tn, &jfh->eov_tn); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_BOVTNGTEOVTN, 4, jctl->jnl_fn_len, jctl->jnl_fn, + &jfh->bov_tn, &jfh->eov_tn); return FALSE; } if (jfh->bov_timestamp > jfh->eov_timestamp) { /* This is not a severe error to exit, may be user changed system time which we do not allow now. - * But we can still try to continue recovery. We already removed time continuty check from mur_fread_eof(). + * But we can still try to continue recovery. We already removed time continuity check from mur_fread_eof(). * So if error limit allows, we will continue recovery */ if (!mur_report_error(jctl, MUR_BOVTMGTEOVTM)) return FALSE; } if (mur_options.rollback && (jfh->start_seqno > jfh->end_seqno)) { - gtm_putmsg(VARLSTCNT(6) ERR_BEGSEQGTENDSEQ, 4, jctl->jnl_fn_len, jctl->jnl_fn, &jfh->start_seqno, &jfh->end_seqno); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_BEGSEQGTENDSEQ, 4, jctl->jnl_fn_len, jctl->jnl_fn, + &jfh->start_seqno, &jfh->end_seqno); return FALSE; } init_hashtab_int4(&jctl->pini_list, MUR_PINI_LIST_INIT_ELEMS, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE); @@ -1049,16 +1063,13 @@ boolean_t mur_fopen(jnl_ctl_list *jctl) murgbl.max_extr_record_length = ZWR_EXP_RATIO(jctl->jfh->max_jrec_len); # ifdef GTM_CRYPT jctl->is_same_hash_as_db = TRUE; - if (FALSE == process_exiting && jfh->is_encrypted) + if (!process_exiting && jfh->is_encrypted) { - /* Encryption initialization will not happen in db_init for all cases. - * Eg: MUPIP JOURNAL -BACKWARD -SHOW -NOVERIFY */ - INIT_PROC_ENCRYPTION(crypt_status); - /* If the encryption init failed in db_init, the below MACRO should return an error. - * But, since this will be called for those operations that might not actually require encryption/decryption, - * we don't report the error immediately. Instead wait for the first encryption/decryption task and report - * accordingly. */ - GTMCRYPT_GETKEY(jfh->encryption_hash, jctl->encr_key_handle, crypt_status); + INIT_PROC_ENCRYPTION(cs_addrs, gtmcrypt_errno); + if (0 == gtmcrypt_errno) + GTMCRYPT_GETKEY(cs_addrs, jfh->encryption_hash, jctl->encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + GTMCRYPT_REPORT_ERROR(MAKE_MSG_WARNING(gtmcrypt_errno), gtm_putmsg, jctl->jnl_fn_len, jctl->jnl_fn); if (NULL != mur_ctl->csd && (0 != memcmp(mur_ctl->csd->encryption_hash, jfh->encryption_hash, GTMCRYPT_HASH_LEN))) jctl->is_same_hash_as_db = FALSE; } @@ -1081,6 +1092,7 @@ boolean_t mur_fclose(jnl_ctl_list *jctl) return TRUE; UNIX_ONLY(jctl->status = errno;) assert(FALSE); - gtm_putmsg(VARLSTCNT(5) ERR_JNLFILECLOSERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); + gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(5) ERR_JNLFILECLOSERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, + jctl->status); return FALSE; } diff --git a/sr_port/mur_read_file.h b/sr_port/mur_read_file.h index 7fbea64..abaef41 100644 --- a/sr_port/mur_read_file.h +++ b/sr_port/mur_read_file.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2010 Fidelity Information Services, Inc * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,7 +11,11 @@ #ifndef MUR_READ_FILE_H_INCLUDED #define MUR_READ_FILE_H_INCLUDED -#define MUR_BUFF_SIZE (DISK_BLOCK_SIZE * 256) +#ifdef UNIX +# define MUR_BUFF_SIZE (DISK_BLOCK_SIZE * 4096) +#else +# define MUR_BUFF_SIZE (DISK_BLOCK_SIZE * 256) +#endif #if defined (MUR_USE_AIO) || defined(VMS) diff --git a/sr_port/mur_validate_checksum.c b/sr_port/mur_validate_checksum.c index c598944..1b8a5d0 100644 --- a/sr_port/mur_validate_checksum.c +++ b/sr_port/mur_validate_checksum.c @@ -1,6 +1,6 @@ /**************************************************************** * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,38 +25,58 @@ #include "hashtab_int8.h" /* needed for muprec.h */ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" +#include "min_max.h" #include "mur_validate_checksum.h" #include "jnl_get_checksum.h" boolean_t mur_validate_checksum(jnl_ctl_list *jctl) { enum jnl_record_type rectype; - uint4 rec_checksum; + uint4 rec_csum, tmp_csum; unsigned char *start_ptr, *end_ptr; jnl_record *jnlrec; reg_ctl_list *rctl; mur_read_desc_t *mur_desc; - rec_checksum = INIT_CHECKSUM_SEED; + rec_csum = INIT_CHECKSUM_SEED; rctl = jctl->reg_ctl; mur_desc = rctl->mur_desc; jnlrec = mur_desc->jnlrec; rectype = (enum jnl_record_type)jnlrec->prefix.jrec_type; if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) /* TUPD/UUPD/FUPD/GUPD */ { + COMPUTE_COMMON_CHECKSUM(tmp_csum, jnlrec->prefix); assert(&jnlrec->jrec_set_kill.mumps_node == &jnlrec->jrec_ztworm.ztworm_str); start_ptr = (unsigned char *)&jnlrec->jrec_set_kill.mumps_node; end_ptr = (unsigned char *)(jnlrec) + mur_desc->jreclen - JREC_SUFFIX_SIZE; - rec_checksum = jnl_get_checksum((uint4 *)start_ptr, NULL, (int)(end_ptr - start_ptr)); - } else if (JRT_PBLK == rectype) + rec_csum = jnl_get_checksum((uint4 *)start_ptr, NULL, (int)(end_ptr - start_ptr)); + COMPUTE_LOGICAL_REC_CHECKSUM(rec_csum, &jnlrec->jrec_set_kill, tmp_csum, rec_csum); + + } else if (JRT_PBLK == rectype || JRT_AIMG == rectype) { + COMPUTE_COMMON_CHECKSUM(tmp_csum, jnlrec->prefix); start_ptr = (unsigned char *)jnlrec->jrec_pblk.blk_contents; - rec_checksum = jnl_get_checksum((uint4 *)start_ptr, NULL, jnlrec->jrec_pblk.bsiz); + rec_csum = jnl_get_checksum((uint4 *)start_ptr, NULL, MIN(jnlrec->jrec_pblk.prefix.forwptr, + jnlrec->jrec_pblk.bsiz)); + COMPUTE_PBLK_CHECKSUM(rec_csum, &jnlrec->jrec_pblk, tmp_csum, rec_csum); + } else if (IS_FIXED_SIZE(rectype) || rectype == JRT_ALIGN) + { + tmp_csum = jnlrec->prefix.checksum; + jnlrec->prefix.checksum = INIT_CHECKSUM_SEED; + switch (rectype) + { + case JRT_ALIGN: + rec_csum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnlrec->jrec_align, SIZEOF(jrec_prefix)); + break; + default: + if (JRT_TRIPLE != rectype && JRT_HISTREC != rectype) + rec_csum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnlrec->jrec_set_kill, jnlrec->prefix.forwptr); + break; + } + jnlrec->prefix.checksum = tmp_csum; } - rec_checksum = ADJUST_CHECKSUM(rec_checksum, jctl->rec_offset); - rec_checksum = ADJUST_CHECKSUM(rec_checksum, jctl->jfh->checksum); - /* Note: rec_checksum updated inside the below macro */ - ADJUST_CHECKSUM_WITH_SEQNO(jrt_is_replicated[rectype], rec_checksum, GET_JNL_SEQNO(jnlrec)); - /* assert(jnlrec->prefix.checksum == rec_checksum); Can fail only for journal after crash or with holes */ - return (jnlrec->prefix.checksum == rec_checksum); + ADJUST_CHECKSUM(rec_csum, jctl->rec_offset, rec_csum); + ADJUST_CHECKSUM(rec_csum, jctl->jfh->checksum, rec_csum); + /* assert(jnlrec->prefix.checksum == rec_csum); Can fail only for journal after crash or with holes */ + return (jnlrec->prefix.checksum == rec_csum); } diff --git a/sr_port/mutex.h b/sr_port/mutex.h index c0b68b7..8868da3 100644 --- a/sr_port/mutex.h +++ b/sr_port/mutex.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,6 +22,7 @@ #error Unsupported Platform #endif +#define MUTEXLCKALERT_INTERVAL 32 /* seconds [UNIX only] */ #define MUTEX_SLEEP_SPIN_COUNT 128 #define MUTEX_SHORT_WAIT_MS 2 /* ms. Keep this a power of 2 */ #define MUTEX_SHORT_WAIT_US (MUTEX_SHORT_WAIT_MS << 10) /* micro sec */ @@ -35,6 +36,4 @@ #define MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR 3 -#define MUTEX_MAX_WRITE_LOCK_ATTEMPTS 8 - #endif /* MUTEX_H */ diff --git a/sr_port/mutex_deadlock_check.c b/sr_port/mutex_deadlock_check.c index 963a19e..9875827 100644 --- a/sr_port/mutex_deadlock_check.c +++ b/sr_port/mutex_deadlock_check.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -63,13 +63,25 @@ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF volatile boolean_t in_mutex_deadlock_check; GBLREF volatile int4 crit_count; +VMS_ONLY(GBLREF sgmnt_addrs *vms_mutex_check_csa;) +#ifdef VMS /* VMS calls this function from mutex.mar which does not pass *csa as a parameter */ void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr) +#else +void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr, sgmnt_addrs *csa) +#endif { tp_region *tr; - sgmnt_addrs *csa; + sgmnt_addrs *tp_list_csa_element, *repl_csa; int4 save_crit_count; + boolean_t passed_cur_region; + gd_region *region; +# ifdef VMS + sgmnt_addrs *csa; + csa = vms_mutex_check_csa; /* vms_mutex_check_csa should be set by mutex_lock* callers */ +# endif + assert(csa); if (in_mutex_deadlock_check) return; in_mutex_deadlock_check = TRUE; @@ -105,53 +117,51 @@ void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr) */ if (is_replicator || mu_reorg_process) { + ++crit_deadlock_check_cycle; + repl_csa = ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) + ? &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs : NULL; if (!dollar_tlevel) { - if ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) - { - ++crit_deadlock_check_cycle; - if (FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs.critical == criticalPtr) - { /* grab_lock going for crit on the jnlpool region. gv_cur_region points to the current - * region of interest, which better have REPL_ENABLED or REPL_WAS_ENABLED, and be now crit - */ - assert(cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs); - csa = &FILE_INFO(gv_cur_region)->s_addrs; - csa->crit_check_cycle = crit_deadlock_check_cycle; /* allow for crit in gv_cur_region */ - } + if ((NULL != repl_csa) && (repl_csa->critical == criticalPtr)) + { /* grab_lock going for crit on the jnlpool region. gv_cur_region points to the current region of + * interest, which better have REPL_ENABLED or REPL_WAS_ENABLED, and be now crit + */ + assert(cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs); + cs_addrs->crit_check_cycle = crit_deadlock_check_cycle; /* allow for crit in gv_cur_region */ } } else - { /* Need to mark the regions allowed to have crit as follows: - * Place the current cycle into the csa's of regions allowed to have crit so have_crit() can easily test. - * Note that should the system be up long enough for the 2**32 cycle value to - * wrap and a region be unused for most of that time, such a region might not be entitled to crit - * but have an old csa->crit_cycle_check matching the current crit_deadlock_cycle_check - - * that case would not trigger have_crit() to release crit on that region; - * however, the next call to this routine increments crit_deadlock_check_cycle and so - * crit on that region gets released after two calls instead of (the usual) one. + { /* Need to mark the regions allowed to have crit as follows: Place the current cycle into the csa's of + * regions allowed to have crit so have_crit() can easily test. Note that should the system be up long + * enough for the 2**32 cycle value to wrap and a region be unused for most of that time, such a region + * might not be entitled to crit but have an old csa->crit_cycle_check matching the current + * crit_deadlock_cycle_check - that case would not trigger have_crit() to release crit on that region; + * however, the next call to this routine increments crit_deadlock_check_cycle and so crit on that region + * gets released after two calls instead of (the usual) one. */ - ++crit_deadlock_check_cycle; + passed_cur_region = FALSE; for (tr = tp_reg_list; NULL != tr; tr = tr->fPtr) - { + { /* Keep in mind that We may not have a tp_reg_list with a multiple elements. If we are about to grab + * crit on only one region among this list, it is not a deadlock situation (valid FTOK order). + */ if (!tr->reg->open) continue; - csa = &FILE_INFO(tr->reg)->s_addrs; - if (csa->now_crit) - csa->crit_check_cycle = crit_deadlock_check_cycle; - else - { /* Seen first non-crit region. Make sure either of the following is true. - * (i) this is the region we are currently grabbing crit on - * (ii) we do not hold crit on any region in the tp_reg_list. - * If neither of the above, we have an out of design condition that can only - * warrant blowing the process up.. - */ - if ((csa->critical != criticalPtr) && (tr != tp_reg_list)) - GTMASSERT; - break; + tp_list_csa_element = &FILE_INFO(tr->reg)->s_addrs; + /* Make sure csa is at the end of this list */ + if (tp_list_csa_element == csa) + passed_cur_region = TRUE; + if (tp_list_csa_element->now_crit) + { + tp_list_csa_element->crit_check_cycle = crit_deadlock_check_cycle; + if (passed_cur_region) + break; } } + /* All regions including current must be in the tp_reg_list. */ + /* Journal pool dummy region will NEVER be in the tp_reg_list */ + assert(passed_cur_region || (csa == repl_csa)); } /* Release crit in regions not legitimately part of this TP/non-TP transaction */ - have_crit(CRIT_RELEASE | CRIT_NOT_TRANS_REG); + have_crit(CRIT_HAVE_ANY_REG | CRIT_RELEASE | CRIT_NOT_TRANS_REG); } /* Reset "crit_count" before resetting "in_mutex_deadlock_check" to FALSE. The order of the sets is important. * The periodic dbsync timer "wcs_clean_dbsync" depends on this order to correctly check if mainline code is diff --git a/sr_port/mutex_deadlock_check.h b/sr_port/mutex_deadlock_check.h index 6cabbf5..49cce6b 100644 --- a/sr_port/mutex_deadlock_check.h +++ b/sr_port/mutex_deadlock_check.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,10 @@ #ifndef MUTEX_DEADLOCK_CHECK_INCLUDED #define MUTEX_DEADLOCK_CHECK_INCLUDED +#ifdef VMS void mutex_deadlock_check(mutex_struct_ptr_t addr); +#else +void mutex_deadlock_check(mutex_struct_ptr_t addr, sgmnt_addrs *csa); +#endif #endif diff --git a/sr_port/mv_stent.h b/sr_port/mv_stent.h index 7905ddd..cf1a26c 100644 --- a/sr_port/mv_stent.h +++ b/sr_port/mv_stent.h @@ -227,7 +227,7 @@ void push_stck(void* val, int val_size, void** addr, int mvst_stck_type); #define MVST_ZINTR 11 /* Environmental save for $zinterrupt */ #define MVST_ZINTDEV 12 /* In I/O when ZINTR, mstr input to now protected */ #define MVST_STCK_SP 13 /* same as the MVST_STCK type except that it needs special handling in flush_jmp.c - * (see comment there) + * (see comment in mtables.c where mvs_save is defined). */ #define MVST_LVAL 14 /* Same as MVST_MVAL except we are pushing an lv_val instead of an mval */ #define MVST_TRIGR 15 /* Used to save the base environment for Trigger execution */ @@ -247,16 +247,17 @@ void push_stck(void* val, int val_size, void** addr, int mvst_stck_type); #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)), \ - mv_chain = (mv_stent *) msp) + (((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 -= (mvs_size[st_type] + (size))) <= stackwarn) ? \ - ((msp <= stacktop) ? (msp += (mvs_size[st_type] + (size))/* fix stack */, rts_error(VARLSTCNT(1) ERR_STACKOFLOW)) : \ - rts_error(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) +#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)) : \ + (((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) #ifdef DEBUG #define POP_MV_STENT() (assert(msp == (unsigned char *) mv_chain), \ diff --git a/sr_port/mval2subsc.c b/sr_port/mval2subsc.c index 3c094ef..cc8eae8 100644 --- a/sr_port/mval2subsc.c +++ b/sr_port/mval2subsc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -118,7 +118,7 @@ unsigned char *mval2subsc(mval *in_val, gv_key *out_key) * store the STR_SUB_ESCAPE byte. Decrement the available space until it becomes zero * at which point issue a GVSUBOFLOW error as well. */ - avail_bytes = (out_key->top - MAX_NUM_SUBSC_LEN) - (out_key->end + tmp_len + 3); + avail_bytes = out_key->top - (out_key->end + tmp_len + 3); if (0 > avail_bytes) ISSUE_GVSUBOFLOW_ERROR(out_key); if (0 < tmp_len) @@ -146,11 +146,11 @@ unsigned char *mval2subsc(mval *in_val, gv_key *out_key) *out_ptr++ = (!TREF(transform) || (0 == gv_cur_region->std_null_coll)) ? STR_SUB_PREFIX : SUBSCRIPT_STDCOL_NULL; } - goto FINI; + goto ALLDONE; } /* Its a number, is it an integer? But before this assert that we have enough allocated space in the key * to store the maximum possible numeric subscript and two terminating 0s at the end of the key */ - assert((MAX_NUM_SUBSC_LEN + 2) <= (int)(out_key->top - out_key->end)); + assert((MAX_GVKEY_PADDING_LEN + 1) <= (int)(out_key->top - out_key->end)); if (mvt & MV_INT) { /* Yes, its an integer, convert it */ is_negative = FALSE; @@ -163,7 +163,7 @@ unsigned char *mval2subsc(mval *in_val, gv_key *out_key) } else if (0 == mt) { *out_ptr++ = SUBSCRIPT_ZERO; - goto FINI; + goto ALLDONE; } if (10 > mt) { @@ -290,16 +290,16 @@ LAST_LONGWORD: FINISH_NUMBER: if (is_negative) *out_ptr++ = NEG_MNTSSA_END; -FINI: +ALLDONE: *out_ptr++ = KEY_DELIMITER; *out_ptr = KEY_DELIMITER; out_key->prev = out_key->end; out_key->end = out_ptr - out_key->base; /* Check if after adding the current subscript and the second terminating NULL byte, there is still - * MAX_NUM_SUBSC_LEN bytes (allocated additionally as part of the DBKEYSIZE macro) left at the end. + * MAX_GVKEY_PADDING_LEN bytes (allocated additionally as part of the DBKEYSIZE macro) left at the end. * If not, we have overflown the original max-key-size length. Issue error. */ - if ((MAX_NUM_SUBSC_LEN + 1) >= (int)(out_key->top - out_key->end)) + if ((MAX_GVKEY_PADDING_LEN + 1) > (int)(out_key->top - out_key->end)) ISSUE_GVSUBOFLOW_ERROR(out_key); return out_ptr; } diff --git a/sr_port/mval_write.c b/sr_port/mval_write.c index d8c1c8c..faec428 100644 --- a/sr_port/mval_write.c +++ b/sr_port/mval_write.c @@ -16,7 +16,7 @@ #include "zshow.h" #include "patcode.h" #include "compiler.h" /* for CHARMAXARGS */ -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" /* for POP_MV_STENT */ diff --git a/sr_port/mvalconv.c b/sr_port/mvalconv.c index f94c598..a1a94ac 100644 --- a/sr_port/mvalconv.c +++ b/sr_port/mvalconv.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,11 +18,10 @@ #include "gtm_stdio.h" /* this is here due to the need for an SPRINTF, * which is in turn due the kudge that is the current double2mval routine */ -#ifdef GTM64 /* we return strings for >18 digit 64-bit numbers, so pull in stringpool */ #include "stringpool.h" + GBLREF spdesc stringpool; -#endif LITREF int4 ten_pwr[]; @@ -68,9 +67,9 @@ void i2smval(mval *v, uint4 i) assert(v->m[1] < MANT_HI); } -void xi2mval(mval *v, unsigned int i); +void xi2mval(mval *v, unsigned int i); -void i2usmval(mval *v, unsigned int i) +void i2usmval(mval *v, unsigned int i) { v->mvtype = MV_NM; v->sgn = 0; @@ -78,7 +77,7 @@ void i2usmval(mval *v, unsigned int i) xi2mval(v, i); } -void i2mval(mval *v, int i) +void i2mval(mval *v, int i) { int4 n; @@ -100,14 +99,14 @@ void i2mval(mval *v, int i) * The primary routines set the sgn flag and pass the absolute value * to xi2mval. */ -void xi2mval(mval *v, unsigned int i) +void xi2mval(mval *v, unsigned int i) { int exp; if (i < INT_HI) { v->mvtype |= MV_INT; - v->m[1] = MV_BIAS * i; + v->m[1] = MV_BIAS * (v->sgn ? -(int)i : i); } else { if (i < MANT_HI) @@ -128,20 +127,19 @@ void xi2mval(mval *v, unsigned int i) } } -#ifdef GTM64 -void xl2mval(mval *v, unsigned long i); +void xi82mval(mval *v, gtm_uint64_t i); -void ul2mval(mval *v, unsigned long i) +void ui82mval(mval *v, gtm_uint64_t i) { v->mvtype = MV_NM; v->sgn = 0; - xl2mval(v, i); + xi82mval(v, i); } -void l2mval(mval *v, long i) +void i82mval(mval *v, gtm_int64_t i) { - gtm_uint8 absi; + gtm_uint64_t absi; v->mvtype = MV_NM; if (i < 0) @@ -154,27 +152,25 @@ void l2mval(mval *v, long i) absi = i; } - xl2mval(v, absi); + xi82mval(v, absi); } -/* xl2mval does the bulk of the conversion for l2mval and ul2mval. - * The primary routines set the sgn flag and pass the absolute value - * to xl2mval. In the case of a >18 digit number, xl2mval examines the - * sgn flag to determine whether to convert back to signed before string - * conversion. */ - -void xl2mval(mval *v, unsigned long i) +/* This function does the bulk of the conversion for i82mval and ui82mval. The primary routines set the sgn flag and pass the + * absolute value to xi82mval(). In the case of a >18 digit number, xi82mval() examines the sgn flag to determine whether to + * switch back to a signed value before string conversion. + */ +void xi82mval(mval *v, gtm_uint64_t i) { int exp; uint4 low; uint4 high; - char buf[21]; /* [possible] sign, [up to] 19L/20UL digits, and terminator */ + char buf[21]; /* [possible] sign, [up to] 19L/20UL digits, and terminator. */ int len; if (i < INT_HI) { v->mvtype |= MV_INT; - v->m[1] = MV_BIAS * (uint4)i; + v->m[1] = MV_BIAS * (v->sgn ? -(int4)i : (uint4)i); } else { if (i < MANT_HI) @@ -190,43 +186,38 @@ void xl2mval(mval *v, unsigned long i) v->e = exp; v->m[0] = low; v->m[1] = high; - } else if (i < (unsigned long)MANT_HI*MANT_HI) + } else if (i < (gtm_uint64_t)MANT_HI * MANT_HI) { low = i % MANT_HI; high = i / MANT_HI; exp = EXP_IDX_BIAL + 9; - while (high < MANT_LO) { - high = high*10 + low/MANT_LO; - low = low%MANT_LO * 10; + high = (high * 10) + (low / MANT_LO); + low = (low % MANT_LO) * 10; exp--; } v->e = exp; v->m[0] = low; v->m[1] = high; } else - { - /* the value won't fit in 18 digits, so return a string */ + { /* The value won't fit in 18 digits, so return a string. */ if (v->sgn) - len = SPRINTF(buf, "%ld", -(long)i); + len = SPRINTF(buf, "%lld", -(gtm_int64_t)i); else - len = SPRINTF(buf, "%lu", i); - + len = SPRINTF(buf, "%llu", i); + assert(18 < len); ENSURE_STP_FREE_SPACE(len); memcpy(stringpool.free, buf, len); - v->mvtype = MV_STR; v->str.len = len; v->str.addr = (char *)stringpool.free; - stringpool.free += len; } - assert(v->mvtype != MV_NM || v->m[1] < MANT_HI); - assert(v->mvtype != MV_NM || v->m[1] >= MANT_LO); + assert((v->mvtype != MV_NM) || (v->m[1] < MANT_HI)); + assert((v->mvtype != MV_NM) || (v->m[1] >= MANT_LO)); } } -#endif double mval2double(mval *v) { @@ -241,7 +232,7 @@ double mval2double(mval *v) { exp = v->e; y = v->m[0]; - y = y/MANT_HI; + y = y / MANT_HI; while (exp > EXP_IDX_BIAL) { x *= MANT_HI; @@ -262,11 +253,17 @@ double mval2double(mval *v) return x; } -/* a (barely suitable) double2mval */ -void double2mval(mval *dst, double src) +void float2mval(mval *dst, float src) { - char buf[67]; /* [possible] sign, decimal-point, [up to] 64 digits, and terminator */ - SPRINTF(buf, "%lf", src); + char buf[16]; /* The maximum-length value in the 'F' representation would look like -0.123457 (that is, + * sign[1] + zero[1] + dot[1] + digits[6] = 9). Note that for values below -1 the number would + * be shorter, since the integer part would be counted against the precision capacity. However, + * a longer representation is possible in the 'E' format: -1.23456E+12 (that is, sign[1] + + * digit[1] + dot[1] + digits[5] + E[1] + sign[1] + exp[2] = 12). Although we only need to + * additionally worry about one termination character, we will be safe and allocate 16 bytes + * instead of 13. */ + + SPRINTF(buf, "%.6G", src); dst->mvtype = MV_STR; dst->str.len = STRLEN(buf); dst->str.addr = buf; @@ -275,8 +272,26 @@ void double2mval(mval *dst, double src) return; } +void double2mval(mval *dst, double src) +{ + char buf[32]; /* The maximum-length value in the 'F' representation would look like -0.123456789012345 + * (that is, sign[1] + zero[1] + dot[1] + digits[15] = 18). Note that for values below -1 + * the number would be shorter, since the integer part would be counted against the + * precision capacity. However, a longer representation is possible in the 'E' format: + * -1.234567890123456E+123 (that is, sign[1] + digit[1] + dot[1] + digits[14] + E[1] + + * sign[1] + exp[3] = 23). Although we only need to additionally worry about one termination + * character, we will be safe and allocate 32 bytes instead of 24. */ -/* converts an mval into a 32-bit signed integer, or MAXPOSINT4 on overflow */ + SPRINTF(buf, "%.15G", src); + dst->mvtype = MV_STR; + dst->str.len = STRLEN(buf); + dst->str.addr = buf; + s2n(dst); + dst->mvtype &= ~MV_STR; + return; +} + +/* Converts an mval into a 32-bit signed integer, or MAXPOSINT4 on overflow. */ int4 mval2i(mval *v) { int4 i; @@ -285,7 +300,7 @@ int4 mval2i(mval *v) MV_FORCE_NUM(v); if (v->mvtype & MV_INT) - i = v->m[1]/MV_BIAS; + i = v->m[1] / MV_BIAS; else { exp = v->e; @@ -301,7 +316,7 @@ int4 mval2i(mval *v) return i; } -/* converts an mval into a 32-bit unsigned integer, or MAXUINT4 on overflow */ +/* Converts an mval into a 32-bit unsigned integer, or MAXUINT4 on overflow. */ uint4 mval2ui(mval *v) { uint4 i; @@ -310,7 +325,7 @@ uint4 mval2ui(mval *v) MV_FORCE_NUM(v); if (v->mvtype & MV_INT) - i = v->m[1]/MV_BIAS; + i = v->m[1] / MV_BIAS; else { exp = v->e; @@ -326,13 +341,79 @@ uint4 mval2ui(mval *v) return i; } + +/* Converts an mval into a 64-bit unsigned integer. */ +gtm_uint64_t mval2ui8(mval *v) +{ + return (gtm_uint64_t)mval2i8(v); +} + +gtm_int64_t mval2i8(mval *v) +{ + gtm_int64_t x, y; + int exp; + + MV_FORCE_NUM(v); + if (v->mvtype & MV_INT) + x = v->m[1] / MV_BIAS; + else + { + exp = v->e; + if (exp > EXP_IDX_BIAL) + { /* Case where to get the actual value we need to multiply by power of exponent. */ + x = v->m[1]; + y = v->m[0]; + if (y > 0) + { /* Both m[0] and m[1] are used, so multiply in parallel, but first ensure that the m[1] part has + * a decimal exponent of MANT_HI order. + */ + x *= MANT_HI; + while (exp > EXP_IDX_BIAL + 18) + { /* Keep multiplying by 10^9, but keep a precision "buffer" of 18 to prevent further + * divisions, as we might otherwise compromise the available precision of mval. + */ + x *= MANT_HI; + y *= MANT_HI; + exp -= 9; + } + if (exp >= EXP_IDX_BIAL + 9) + { /* Multiply by the remaining power of the exponent. */ + x *= ten_pwr[exp - EXP_IDX_BIAL - 9]; + y *= ten_pwr[exp - EXP_IDX_BIAL - 9]; + } else + { /* Case where exponent indicates a total power of less than 10^9, which, given that both + * m[0] and m[1] are used and that x has already been multiplied by 10^9, requires a + * division to make the sum of m[0] and m[1] represent the right number. + */ + x /= ten_pwr[EXP_IDX_BIAL + 9 - exp]; + y /= ten_pwr[EXP_IDX_BIAL + 9 - exp]; + } + } else + { /* Since m[0] is not used, just multiply x by the excess power of the exponent. */ + while (exp > EXP_IDX_BIAL + 9) + { + x *= MANT_HI; + exp -= 9; + } + x *= ten_pwr[exp - EXP_IDX_BIAL]; + } + + x = (v->sgn ? -x - y : x + y); + } else if (exp < MV_XBIAS) + x = 0; + else + x = (v->sgn ? -v->m[1] : v->m[1]) / ten_pwr[EXP_IDX_BIAL - exp]; + } + return x; +} + /* isint == v can be represented as a 9 digit (or less) integer (positive or negative). * If return value is TRUE, then "*intval" contains the integer value stored in "v". * Note: "*intval" could have been updated even if return value is FALSE. */ boolean_t isint(mval *v, int4 *intval) { - int exp, m1, mvtype, divisor, m1_div, m1_sgn; + int exp, m1, mvtype, divisor, m1_div; DEBUG_ONLY(boolean_t is_canonical;) mvtype = v->mvtype; diff --git a/sr_port/mvalconv.h b/sr_port/mvalconv.h index c71a069..a32e26f 100644 --- a/sr_port/mvalconv.h +++ b/sr_port/mvalconv.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,13 +19,14 @@ void i2smval(mval *v, uint4 i); void i2usmval(mval *v, unsigned int i); void i2mval(mval *v, int i); -#ifdef GTM64 -void ul2mval(mval *v, unsigned long i); -void l2mval(mval *v, long i); -#endif +void ui82mval(mval *v, gtm_uint64_t i); +void i82mval(mval *v, gtm_int64_t i); +void float2mval(mval *dst, float src); void double2mval(mval *dst, double src); double mval2double(mval *v); int4 mval2i(mval *v); +gtm_int64_t mval2i8(mval *v); +gtm_uint64_t mval2ui8(mval *v); uint4 mval2ui(mval *v); boolean_t isint (mval *v, int4 *intval); diff --git a/sr_port/name_glvn.c b/sr_port/name_glvn.c index 51ecbe0..acce616 100644 --- a/sr_port/name_glvn.c +++ b/sr_port/name_glvn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,15 +13,20 @@ #include "compiler.h" #include "opcode.h" #include "toktyp.h" -#include "subscript.h" #include "fnname.h" +#include "fullbool.h" +#include "mdq.h" #include "advancewindow.h" +#include "show_source_line.h" + +GBLREF boolean_t run_time; error_def(ERR_COMMA); error_def(ERR_EXTGBLDEL); error_def(ERR_GBLNAME); error_def(ERR_GVNAKEDEXTNM); error_def(ERR_MAXNRSUBSCRIPTS); +error_def(ERR_SIDEEFFECTEVAL); int name_glvn(boolean_t gblvn, oprtype *a) { @@ -30,15 +35,16 @@ int name_glvn(boolean_t gblvn, oprtype *a) int fnname_type; /* Note: MAX_LVSUBSCRIPTS and MAX_GVSUBSCRIPTS are currently equal. Should that change, this should also change */ - oprtype subscripts[MAX_LVSUBSCRIPTS + 1], *sb1, *sb2; - triple *ref, *t1, *t2; + oprtype subscripts[MAX_LVSUBSCRIPTS + 1], *sb1, *sb2; + triple *ref, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; sb1 = sb2 = subscripts; sb1++; /* save room for type indicator */ if (gblvn) - { fnname_type = FNGBL; + { + fnname_type = FNGBL; if ((TK_LBRACKET == TREF(window_token)) || (TK_VBAR == TREF(window_token))) { vbar = (TK_VBAR == TREF(window_token)); @@ -85,8 +91,10 @@ int name_glvn(boolean_t gblvn, oprtype *a) advancewindow(); } if (TK_LPAREN == TREF(window_token)) - { for (;;) - { if (sb1 - sb2 > MAX_GVSUBSCRIPTS) + { + for (;;) + { + if (sb1 - sb2 > MAX_GVSUBSCRIPTS) { stx_error(ERR_MAXNRSUBSCRIPTS); return FALSE; @@ -108,15 +116,9 @@ int name_glvn(boolean_t gblvn, oprtype *a) } } subscripts[0] = put_ilit(fnname_type); - ref = t1 = newtriple(OC_PARAMETER); - ref->operand[0] = put_ilit((mint)(sb1 - sb2 + 2)); /* # of subscripts + dst + depth argument (determine at f_name) */ - for ( ; sb2 < sb1 ; sb2++) - { - t2 = newtriple(OC_PARAMETER); - t1->operand[1] = put_tref(t2); - t1 = t2; - t1->operand[0] = *sb2; - } - *a = put_tref(ref); + root = ref = newtriple(OC_PARAMETER); + ref->operand[0] = put_ilit((mint)(sb1 - sb2 + 2)); /* # of subscripts + dst + depth argument (determine at f_name) */ + SUBS_ARRAY_2_TRIPLES(ref, sb1, sb2, subscripts, 1); /* last argument (1) accounts for fnname_type in the 1st slot */ + *a = put_tref(root); return TRUE; } diff --git a/sr_port/new_stack_frame.c b/sr_port/new_stack_frame.c index c7c2f4b..1d471ab 100644 --- a/sr_port/new_stack_frame.c +++ b/sr_port/new_stack_frame.c @@ -14,10 +14,11 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mprof.h" #include "error.h" +#include "glvn_pool.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; @@ -51,7 +52,7 @@ void new_stack_frame(rhdtyp *rtn_base, unsigned char *context, unsigned char *tr sf->ctxt = context; sf->mpc = transfer_addr; sf->flags = 0; - sf->for_ctrl_stack = NULL; + SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED); sf->ret_value = NULL; sf->dollar_test = -1; #ifdef HAS_LITERAL_SECT diff --git a/sr_port/objlabel.h b/sr_port/objlabel.h index f2d0b3a..be31810 100644 --- a/sr_port/objlabel.h +++ b/sr_port/objlabel.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,7 @@ * Note that OBJ_UNIX_LABEL and OBJ_PLATFORM_LABEL should not exceed 255. */ -#define OBJ_UNIX_LABEL 23 /* When changed, be sure to zero the platform specific numbers below (if any non-0) */ +#define OBJ_UNIX_LABEL 25 /* 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 7907a1b..beffda0 100644 --- a/sr_port/one_job_param.c +++ b/sr_port/one_job_param.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,13 +35,26 @@ const static readonly jp_type job_param_data[] = { #include "jobparamstrs.h" /* BYPASSOK */ }; - +/* Index is the number of param strings before the character + * For instance index(D) = n(A) + n(B) + n(C) = 2 + 0 + 0 =2 + */ +#ifdef UNIX +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, 36, 36, 36, 36, 36, 36, 36, + 36 +}; +#else const static readonly unsigned char job_param_index[27] = { 0, 2, 2, 2, 6, 8, 8, 10, 10, 14, 14, 14, 16, 16, 22, 24, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34 }; +#endif #undef JPDEF #define JPDEF(a,b) b @@ -50,9 +63,15 @@ LITDEF jp_datatype job_param_datatypes[] = #include "jobparams.h" }; +/* Maximum length string for any JOB parameter. Length limit + * dictated by having only one byte to represent the string + * length. That translates to 255 characters*/ +#define MAXJOBPARSTRLEN 255 + error_def(ERR_JOBPARNOVAL); error_def(ERR_JOBPARNUM); error_def(ERR_JOBPARSTR); +error_def(ERR_JOBPARTOOLONG); error_def(ERR_JOBPARUNK); error_def(ERR_JOBPARVALREQ); @@ -105,6 +124,11 @@ int one_job_param (char **parptr) return FALSE; } len = (TREF(window_mval)).str.len; + if (MAXJOBPARSTRLEN < len) + { + stx_error (ERR_JOBPARTOOLONG); + return FALSE; + } *(*parptr)++ = len; memcpy(*parptr, (TREF(window_mval)).str.addr, len); *parptr += len; diff --git a/sr_port/op.h b/sr_port/op.h index e933d74..07f1140 100644 --- a/sr_port/op.h +++ b/sr_port/op.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #ifndef OP_INCLUDED #define OP_INCLUDED -#include "rtnhdr.h" /* Avoid changing a few hundred op_* and other modules to put this first */ +#include /* Avoid changing a few hundred op_* and other modules to put this first */ #ifdef VMS /* Define a TWO-argument VMS_ONLY macro (first argument is empty string but is needed because of the VMS-only , that follows) */ @@ -54,23 +54,23 @@ void op_fnascii(int4 num, mval *in, mval *out); void op_fnchar(UNIX_ONLY_COMMA(int cnt) mval *dst, ...); void op_fnextract(int last, int first, mval *src, mval *dest); #ifdef __sun -void op_fnfgncal(uint4 n_mvals, ...); int op_fnfgncal_rpc(unsigned int n_mvals, ...); /* typ to keep the compiler happy as set into xfer_table, which is int */ -#elif defined(UNIX) +#endif +#if defined(UNIX) void op_fnfgncal(uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, ...); #elif defined(VMS) void op_fnfgncal(mval *dst, ...); #endif int4 op_fnfind(mval *src, mval *del, mint first, mval *dst); -void op_fnfnumber(mval *src, mval *fmt, mval *dst); -void op_fnget2(mval *dst, mval *src, mval *defval); +void op_fnfnumber(mval *src, mval *fmt, boolean_t use_fract, int fract, mval *dst); +void op_fnget1(mval *src, mval *dst); +void op_fnget2(mval *src, mval *def, mval *dst); void op_fngetdvi(mval *device, mval *keyword, mval *ret); void op_fngetjpi(mint jpid, mval *kwd, mval *ret); void op_fngetlki(mval *lkid_mval, mval *keyword, mval *ret); void op_fngetsyi(mval *keyword, mval *node, mval *ret); -void op_fngvget(mval *v, mval *def); -void op_fngvget1(mval *v); -int op_fngvget2(mval *res, mval *val, mval *optional); +void op_fngvget(mval *dst); +void op_fngvget1(mval *dst); void op_fnj2(mval *src, int len, mval *dst); void op_fnj3(mval *src, int width, int fract, mval *dst); void op_fnlength(mval *a1, mval *a0); @@ -127,6 +127,9 @@ void op_fnzlkid(mint boolex, mval *retval); void op_fnzm(mint x, mval *v); void op_fnzp1(mval *src, int del, int trgpcidx, UNIX1_VMS2(mval *dst, boolean_t srcisliteral)); void op_fnzparse(mval *file, mval *field, mval *def1, mval *def2, mval *type, mval *ret); +#ifdef UNIX +void op_fnzpeek(mval *baseaddr, int offset, int len, mval *format, mval *ret); +#endif void op_fnzpid(mint boolexpr, mval *ret); void op_fnzpiece(mval *src, mval *del, int first, int last, UNIX1_VMS2(mval *dst, boolean_t srcisliteral)); void op_fnzpopulation(mval *arg1, mval *arg2, mval *dst); @@ -148,6 +151,7 @@ void op_fnztrnlnm(mval *name, mval *table, int4 ind, mval *mode, mval *case_blin #ifdef UNIX void op_fnzwidth(mval *str, mval *dst); #endif +void op_fnzwrite(mval *str, mval *dst); int op_forchk1(); #ifdef UNIX int op_forintrrpt(); @@ -177,32 +181,37 @@ void op_hang(mval *num); void op_hardret(void); void op_horolog(mval *s); void op_idiv(mval *u, mval *v, mval *q); +mval *op_igetdst(void); void op_igetsrc(mval *v); int op_incrlock(int timeout); void op_inddevparms(mval *devpsrc, int4 ok_iop_parms, mval *devpiopl); void op_indfnname(mval *dst, mval *target, mval *value); +void op_indfnname2(mval *finaldst, mval *depthval, mval *prechomp); void op_indfun(mval *v, mint argcode, mval *dst); -void op_indget(mval *dst, mval *target, mval *value); +void op_indget1(uint4 indx, mval *dst); /* Used by [SET] */ +void op_indget2(mval *dst, uint4 indx); void op_indglvn(mval *v, mval *dst); void op_indincr(mval *dst, mval *increment, mval *target); void op_indlvadr(mval *target); void op_indlvarg(mval *v, mval *dst); void op_indlvnamadr(mval *target); void op_indmerge(mval *glvn_mv, mval *arg1_or_arg2); -void op_indname(UNIX_ONLY_COMMA(int argcnt) mval *dst, ...); -void op_indo2(mval *dst, mval *target, mval *value); +void op_indmerge2(uint4 indx); +void op_indname(mval *dst, mval *target, mval *subs); +void op_indo2(mval *dst, uint4 indx, mval *value); void op_indpat(mval *v, mval *dst); void op_indrzshow(mval *s1, mval *s2); void op_indset(mval *target, mval *value); void op_indtext(mval *lab, mint offset, mval *rtn, mval *dst); void op_iocontrol(UNIX_ONLY_COMMA(int4 n) mval *vparg, ...); -void op_iretmval(mval *v); +void op_iretmval(mval *v, mval *dst); int op_job(UNIX_ONLY(int4 argcnt) VMS_ONLY(mval *label), ...); void op_killaliasall(void); void op_killall(void); void op_killall(void); int op_linefetch(); int op_linestart(); +void op_litc(mval *dst, mval *src); void op_lkinit(void); void op_lkname(UNIX_ONLY_COMMA(int subcnt) mval *extgbl1, ...); int op_lock(int timeout); @@ -240,6 +249,7 @@ int op_startintrrpt(); #elif defined(VMS) void op_startintrrpt(); #endif +void op_stolitc(mval *val); void op_sub(mval *u, mval *v, mval *s); void op_sub(mval *u, mval *v, mval *s); void op_svget(int varnum, mval *v); @@ -274,13 +284,11 @@ void op_wtone(int c); void op_wttab(mint x); void op_xkill(UNIX_ONLY_COMMA(int n) mval *lvname_arg, ...); void op_xnew(UNIX_ONLY_COMMA(unsigned int argcnt_arg) mval *s_arg, ...); -int op_zalloc2(int4 timeout, UINTPTR_T auxown); int op_zallocate(int timeout); -int op_zallocate(int timeout); /***type int added***/ void op_zattach(mval *); int op_zbfetch(); int op_zbstart(); -void op_zcompile(mval *v, boolean_t mExtReqd); +void op_zcompile(mval *v, boolean_t ignore_dollar_zcompile); void op_zcont(void); void op_zdealloc2(int4 timeout, UINTPTR_T auxown); void op_zdeallocate(int4 timeout); diff --git a/sr_port/op_bindparm.c b/sr_port/op_bindparm.c index 986fe70..501f4a3 100644 --- a/sr_port/op_bindparm.c +++ b/sr_port/op_bindparm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,7 @@ #include "gtm_string.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "op.h" @@ -69,9 +69,12 @@ void op_bindparm(UNIX_ONLY_COMMA(int frmc) int frmp_arg, ...) prev_count = *prev_count_ptr; /* If we were dealing with a new job, then push_parm would not have been called if the number of * actuals was 0; so, by checking for proper frame value stored in the parameter pool we ensure - * that we are not looking at some uninitialized value here. + * that we are not looking at some uninitialized value here. Note that although we protect against + * fall-throughs into labels with a formallist now, in case two consecutive invocations to + * op_bindparm happen without a push_parm in between, do not attempt to use a previously utilized + * parameter set. */ - if (PARM_ACT_FRAME(curr_slot, prev_count) != frame_pointer) + if ((PARM_ACT_FRAME(curr_slot, prev_count) != frame_pointer) || (SAFE_TO_OVWRT <= prev_count)) actc = 0; else { /* Acquire mask, actual count, and pointer to actual list from the parameter pool. */ @@ -91,7 +94,7 @@ void op_bindparm(UNIX_ONLY_COMMA(int frmc) int frmp_arg, ...) { error = TRUE; *prev_count_ptr += SAFE_TO_OVWRT; - rts_error(VARLSTCNT(1) ERR_ACTLSTTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ACTLSTTOOLONG); } VAR_START(var, frmp_arg); for (i = 0; i < frmc; i++, frmp = va_arg(var, int4), actp++) diff --git a/sr_port/op_break.c b/sr_port/op_break.c index 128b757..48ea7a9 100644 --- a/sr_port/op_break.c +++ b/sr_port/op_break.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "io.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "break.h" #include "op.h" diff --git a/sr_port/op_close.c b/sr_port/op_close.c index 5c6ccd7..5ffb4b5 100644 --- a/sr_port/op_close.c +++ b/sr_port/op_close.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,20 +10,26 @@ ****************************************************************/ #include "mdef.h" + +#ifdef VMS +#include +#include +#endif + #include "io.h" #include "iosp.h" #include "op.h" #include "trans_log_name.h" -#ifdef __MVS__ #include "iormdef.h" -#endif - GBLREF io_log_name *io_root_log_name; GBLREF io_pair io_curr_device; GBLREF io_pair io_std_device; GBLREF io_desc *active_device; +error_def(ERR_LOGTOOLONG); +error_def(ERR_TEXT); + void op_close(mval *v, mval *p) { char buf[MAX_TRANS_NAME_LEN]; /* buffer to hold translated name */ @@ -33,10 +39,7 @@ void op_close(mval *v, mval *p) io_log_name *tl; /* logical record for translated name */ int4 stat; /* status */ mstr tn; /* translated name */ - ZOS_ONLY(d_rm_struct *rm_ptr;) - - error_def(ERR_LOGTOOLONG); - error_def(ERR_TEXT); + d_rm_struct *rm_ptr; MV_FORCE_STR(v); MV_FORCE_STR(p); @@ -98,9 +101,6 @@ void op_close(mval *v, mval *p) if (DEFAULT_CODE_SET != ciod->out_code_set) ICONV_CLOSE_CD(ciod->output_conv_cd); #endif - (ciod->disp_ptr->close)(ciod, p); active_device = 0; - if (ciod->type == rm) - remove_rms (ciod); } diff --git a/sr_port/op_clralsvars.c b/sr_port/op_clralsvars.c index 6cf1731..a7b2f4a 100644 --- a/sr_port/op_clralsvars.c +++ b/sr_port/op_clralsvars.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "hashtab_mname.h" diff --git a/sr_port/op_commarg.c b/sr_port/op_commarg.c index b1af95c..3ac2879 100644 --- a/sr_port/op_commarg.c +++ b/sr_port/op_commarg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "compiler.h" #include "cmd.h" #include "toktyp.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "opcode.h" #include "indir_enum.h" @@ -54,7 +54,7 @@ void op_commarg(mval *v, unsigned char argcode) (frame_pointer->type & SFT_COUNT) && v->str.len && (MAX_MIDENT_LEN > v->str.len) && !proc_act_type && do_indir_do(v, argcode)) return; - comp_init(&v->str); + comp_init(&v->str, NULL); for (;;) { if (EXPR_FAIL == (rval = (*indir_fcn[argcode])())) /* NOTE assignment */ @@ -72,7 +72,7 @@ void op_commarg(mval *v, unsigned char argcode) rts_error(VARLSTCNT(1) ERR_INDEXTRACHARS); } } - if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, 0, v->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, NULL, NULL, v->str.len)) return; indir_src.str.addr = v->str.addr; /* reassign because stp_gcol might have changed v->str.addr */ cache_put(&indir_src, obj); diff --git a/sr_port/op_dmode.c b/sr_port/op_dmode.c index 3f982b3..4e18ee9 100644 --- a/sr_port/op_dmode.c +++ b/sr_port/op_dmode.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "iottdef.h" #endif #include "iotimer.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ @@ -46,8 +46,9 @@ #include "have_crit.h" /* for the TPNOTACID_CHECK macro */ #endif -#define DIRECTMODESTR "Entering DIRECT MODE" +#define DIRECTMODESTR "Entering DIRECT MODE - TP RESTART will fail" +GBLREF uint4 dollar_trestart; GBLREF io_pair io_curr_device; GBLREF io_pair io_std_device; GBLREF stack_frame *frame_pointer; @@ -89,15 +90,9 @@ void op_dmode(void) io_curr_device = io_std_device; if ((TRUE == io_curr_device.in->dollar.zeof) || kill) op_halt(); - - /***************************************************** - The following code is meant to avoid an infinite - loop on UNIX systems which occurs when there is an - error in writing the the principal output device here - that results in a call to the condition handler - and an eventual return to this location. - *****************************************************/ - + /* The following code avoids an infinite loop on UNIX systems when there is an error in writing to the principal device + * resulting in a call to the condition handler and an eventual return to this location + */ # ifdef UNIX if ((loop_cnt > 0) && (errno == old_errno)) { /* Tried and failed 2x to write to principal device */ @@ -108,10 +103,8 @@ void op_dmode(void) ++loop_cnt; old_errno = errno; # endif - *((INTPTR_T **)&restart_pc) = (INTPTR_T *)CODE_ADDRESS(call_dm); *((INTPTR_T **)&restart_ctxt) = (INTPTR_T *)GTM_CONTEXT(call_dm); - # ifdef UNIX loop_cnt = 0; old_errno = 0; @@ -122,7 +115,6 @@ void op_dmode(void) if (!tt_ptr || !tt_ptr->mupintr) # endif op_wteol(1); - TPNOTACID_CHECK(DIRECTMODESTR); if (io_curr_device.in->type == tt) dm_read(input_line); diff --git a/sr_port/op_exfunret.c b/sr_port/op_exfunret.c index 7dec8ac..c04d04a 100644 --- a/sr_port/op_exfunret.c +++ b/sr_port/op_exfunret.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" diff --git a/sr_port/op_exfunretals.c b/sr_port/op_exfunretals.c index 08a9c20..a993b5d 100644 --- a/sr_port/op_exfunretals.c +++ b/sr_port/op_exfunretals.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "hashtab_mname.h" diff --git a/sr_port/op_exp.c b/sr_port/op_exp.c index e2caa5d..eb4dbfa 100644 --- a/sr_port/op_exp.c +++ b/sr_port/op_exp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,384 +12,296 @@ #include "mdef.h" #include "gtm_string.h" +#include #include "arit.h" -#ifdef UNIX -#include -#endif #include "stringpool.h" #include "op.h" #include "mvalconv.h" #define ACCUR_PERCENT 0.00000000000000055 -#define TEN_DEG_INT 1000000000 #define MAX_M_INT 999999999 +LITREF int4 ten_pwr[]; LITREF mval literal_one; LITREF mval literal_zero; +STATICFNDEF void op_exp_flgchk(mval *mv); + +error_def(ERR_NEGFRACPWR); +error_def(ERR_NUMOFLOW); + void op_exp(mval *u, mval* v, mval *p) { - mval u1, *u1_p; - double accuracy; - double x, x1, y, z, z2, z3, z4, z5, id, il; -#ifndef UNIX - double pow(); -#endif - int im0, im1, ie, i, j, j1; - bool fraction = FALSE, in = FALSE; - bool neg = FALSE, change_sn = FALSE, even = TRUE; - mval w, zmv; - int4 n, n1; -#ifdef UNIX - double infinity, np = 20, inf = 9999999999999999.0; -#endif - - error_def(ERR_NUMOFLOW); - error_def(ERR_NEGFRACPWR); + mval u1, *u1_p; + double accuracy, exponent; + double x, x1, y, z, z2, z3, z4, z5, id, il; + 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; + 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 (v->m[1] == 0 && v->m[0] == 0) - { - *p = literal_one; - return; - } - - if ((v->mvtype & MV_INT) != 0) - { - n = v->m[1]; - if (n == 0) - { + 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; + } + 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 */ *p = literal_one; return; } - if ((u1_p->mvtype & MV_INT) != 0) - { - if (u1_p->m[1] == 0) - { - *p = literal_zero; + if (0 != (u1_p->mvtype & MV_INT)) + { /* Integer-ish base */ + if (0 == u1_p->m[1]) + { /* 0**anything = 0 */ + *p = literal_zero; return; } - } else if (u1_p->m[1] == 0 && u1_p->m[0] == 0) - { + } else if ((0 == u1_p->m[1]) && (0 == u1_p->m[0])) + { /* 0**anything = 0 */ *p = literal_zero; return; } - n1 = n / MV_BIAS; - if (n == n1 * MV_BIAS) - { - if (v->m[1]==0) - { - *p = literal_one; - return; - } - if (n1 < 0) - { - op_div((mval *)&literal_one, u1_p, &w); - n1 = -n1; - } else - w = *u1_p; - zmv = literal_one; - for ( ; ; ) - { - if (n1 & 1) - op_mul(&zmv,&w,&zmv); - n1 /= 2; - if (!n1) - break; - op_mul(&w,&w,&w); - } - *p = zmv; - return; - } else - { - if ((u1_p->mvtype & MV_INT) != 0) - { - if (u1_p->m[1] < 0) - { - rts_error(VARLSTCNT(1) ERR_NEGFRACPWR); - return; - } + 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); + n1 = -n1; } else - { + w = *u1_p; + zmv = literal_one; + for ( ; ; ) + { /* Compute integer exponent */ + if (n1 & 1) + op_mul(&zmv, &w, &zmv); + n1 /= 2; + if (!n1) + break; + op_mul(&w, &w, &w); + } + *p = zmv; + return; + } else + { /* Have non-integer exponent (has fractional component) */ + if (0 != (u1_p->mvtype & MV_INT)) + { /* Base is integer-ish */ + if (0 > u1_p->m[1]) + { /* Base is negative, invalid exponent expression */ + rts_error(VARLSTCNT(1) ERR_NEGFRACPWR); + return; + } + } else + { /* Base is NOT integer-sh */ if (u1_p->sgn) - { + { /* Base is negative, invalid exponent expression */ rts_error(VARLSTCNT(1) ERR_NEGFRACPWR); return; } } } } else - { - if ((u1_p->mvtype & MV_INT) != 0) - { - if (u1_p->m[1] < 0) - { - u1_p->m[1] = - u1_p->m[1]; + { /* 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; } - if (u1_p->m[1] == 0) - { + if (0 == u1_p->m[1]) + { /* 0**anything is 0 */ *p = literal_zero; return; } } 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 (u1_p->m[1] == 0 && u1_p->m[0] == 0) - { + if ((0 == u1_p->m[1]) && (0 == u1_p->m[0])) + { /* 0**anything is zero */ *p = literal_zero; return; } } - if ((ie = v->e - MV_XBIAS) < NUM_DEC_DG_2L) - { - if (ie > 0) - { - if (ie < NUM_DEC_DG_1L) - { - for (i=1,j=10; i < NUM_DEC_DG_1L - ie; j *= 10, i++); + 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) + * 2. If the base value is negative, result is negative based on whether exponent is even/odd + * Since all exponent digits are visible, determine these items. + */ + if (0 < ie) + { /* Decimal point shifting to right - see if fully integer*/ + if (NUM_DEC_DG_1L > ie) + { /* Exponent fits in int4 */ + for (i = 1, j = 10; (NUM_DEC_DG_1L - ie) > i; j *= 10, i++) + ; /* Determine exponential scale */ im1 = v->m[1]; - if ((i = im1 % j) != 0) + if (0 != (i = im1 % j)) /* Note assignment */ fraction = TRUE; else - if ((i = im1 % (2 * j)) != 0) + if (0 != (i = im1 % (2 * j))) even = FALSE; } else { im0 = v->m[0]; - if (ie == NUM_DEC_DG_1L) - { - if (im0 == 0) + if (NUM_DEC_DG_1L == ie) + { /* Var ie is at max for no loss in single int */ + if (0 == im0) { im1 = v->m[1]; - if ((i = im1 % 2) != 0) + if (0 != (i = im1 % 2)) /* Note assignment */ even = FALSE; } else fraction = TRUE; } else { - for (i=1,j=10; i < NUM_DEC_DG_2L - ie; j *= 10, i++); - im0 = v->m[0]; - if ((i = im0 % j) == 0) + for (i=1, j=10; (NUM_DEC_DG_2L - ie) > i; j *= 10, i++) + ; + if (0 == (i = im0 % j)) /* Note assignment */ { - if ((i = im0 % (2 * j)) != 0) + if (0 != (i = im0 % (2 * j))) /* Note assignment */ even = FALSE; } else fraction = TRUE; } } - } else + } else /* Var ie is negative (fraction) or 0. This is a non-integerish number so ie + * must be a fraction. ie must be > 0 to be non-integer. + */ fraction = TRUE; } else { - if (ie == NUM_DEC_DG_2L) - { + if (NUM_DEC_DG_2L == ie) + { /* Var ie is max to have no significant digit loss */ im0 = v->m[0]; - if ((i = im0 % 2) != 0) + if (0 != (i = im0 % 2)) /* Note assignment */ even = FALSE; } } - if (!fraction) - { - if (neg) - { - if (!even) - change_sn = TRUE; - } - } else - { - if (neg) - { - rts_error(VARLSTCNT(1) ERR_NEGFRACPWR); - return; - } + if (fraction && neg) + { /* Fractional exponent and negative base not valid */ + rts_error(VARLSTCNT(1) ERR_NEGFRACPWR); + return; } } - - x = mval2double(u1_p); + x = mval2double(u1_p); /* Convert base and exponent to double for feeding to pow*() function */ y = mval2double(v); - z = pow(x, y); - -#ifdef UNIX -#ifdef __sun - /* Solaris doesn't define the more portable HUGE_VAL, but all the other Unix platforms do, so we have to use pow() to - * cause an overflow and capture that value for the comparison. */ - infinity = pow(inf, np); -#else - infinity = HUGE_VAL; -#endif - if (z == infinity) +# ifdef UNIX + if (HUGE_VAL == z) /* Infinity return value check */ { rts_error(VARLSTCNT(1) ERR_NUMOFLOW); return; } -#endif - - if (change_sn) - z = -z; - - if (z < 0) - { - z = -z; - p->sgn = 1; - } else - p->sgn = 0; - - if (z == 0) +# endif + assert(!neg); /* Should be taken care of in one of the op_mul() using sections dealing with whole exponents */ + p->sgn = 0; /* Positive numbers only from here on out */ + if (0 == z) { *p = literal_zero; return; } - + /* Remaining code's main purpose is to convert the double float value to our internal format taking care that + * actual integer values (e.g. 4**.5 is 2) are correctly rendered. This can be tricky not only because floating + * point values are often imprecise (e.g. 3.0 represented as 2.999999999999999) but because the double-float + * type has fewer digits of accuracy than GTM carries. + */ accuracy = z * ACCUR_PERCENT; - for (z2 = ACCUR_PERCENT; accuracy == 0; z2 *= 10, accuracy = z * z2); - - if (z <= accuracy) - { + /* Scale accuracy up in case it turned to zero above */ + for (z2 = ACCUR_PERCENT; (0.0 == accuracy); z2 *= 10, accuracy = z * z2) + ; + if ((fabs(z) <= accuracy) || (0 >= z)) + { /* Zero equivalency test - some small chance pow() could return a very small negative number. Any + * possible negative numbers must have whole number exponent which is handled earlier via op_mul(). + */ *p = literal_zero; return; } - - if (z < 1) - { - if (1 - z <= accuracy) - { - *p = literal_one; - return; - } - for(id = 1, j = 0; z < id; id /=10, j++) - { - if ((id - z) < accuracy) - { - in = TRUE; - if (j <= (i = MV_XBIAS - EXP_INT_UNDERF)) - { - *p = literal_one; - p->mvtype = MV_NM | MV_INT; - p->m[1] = (int)(p->m[1] * id); - if (p->m[1] == TEN_DEG_INT) - p->m[1] = MAX_M_INT; - if (p->sgn) - p->m[1] = - p->m[1]; - return; - } - j++; - break; - } - } - if (!in && (z - id < accuracy)) - { - if (j <= (i = MV_XBIAS - EXP_INT_UNDERF)) - { - *p = literal_one; - p->mvtype = MV_NM | MV_INT; - p->m[1] = (int)(p->m[1] * id); - if (p->m[1] == TEN_DEG_INT) - p->m[1] = MAX_M_INT; - if (p->sgn) - p->m[1] = - p->m[1]; - return; - } - } - p->mvtype = MV_NM; - if (MV_XBIAS - j + 1 < EXPLO) - { - *p = literal_zero; + /* Integer check - GT.M pseudo int MV_INT check - must be decimal form 999999.999 */ + z2 = floor((z + .0005) * MV_BIAS); + if (MANT_HI > z2) + { /* Have proper range, check if accuracy warrants conversion */ + n1 = (int)z2; + z2 = (double)n1 / MV_BIAS; + if (fabs(z - z2) < accuracy) + { /* We can treat this as a GT.M int */ + ((mval_b *)p)->sgne = 0; + p->mvtype = (MV_NM | MV_INT); + p->m[0] = 0; + p->m[1] = (p->sgn) ? -n1 : n1; return; } - p->e = MV_XBIAS - j +1; - j1 = NUM_DEC_DG_2L - 1 + j; - for (i = 0,z2 = z; i < j1; z2 *= 10,i++); - j1 = NUM_DEC_DG_1L - 1 + j; - for (i = 0,z4 = z; i < j1; z4 *= 10,i++); - p->m[1] = (int)z4; - if (p->m[1] == TEN_DEG_INT) - p->m[1] = MAX_M_INT; - z4 = ((double)(p->m[1]))*MANT_HI; - z3 = z2 - z4; - p->m[0] = (int)z3; - if (p->m[0] == TEN_DEG_INT) - p->m[0] = MAX_M_INT; - return; } - - if (z - 1 <= accuracy) + /* Store as a type-2 non-'integer', i.e. put z in the form z1_rnd * 10^n + z2_rnd * 10^(n-9). + * Could add checks for zero/infinity here to avoid lengthy (300ish iterations) while loops below. + */ + n = 0; + while (1e16 <= z) { - *p = literal_one; - return; + n += 5; + z *= 1e-5; } - - if (z > 1) + while (1e1 > z) { - for(il = 10, j = 1; z > il; il *=10, j++) - { - if ((z - il) < accuracy) - { - in = TRUE; - if (++j <= (i = EXP_INT_OVERF - MV_XBIAS)) - { - i2mval(p, (int)il); - if (p->sgn) - p->m[1] = - p->m[1]; - return; - } - break; - } - } - if (!in && (il - z < accuracy)) - { - if (j <= (i = EXP_INT_OVERF - MV_XBIAS)) - { - i2mval(p, (int)il); - if (p->sgn) - p->m[1] = - p->m[1]; - return; - } - } - p->mvtype = MV_NM; - if ((j + MV_XBIAS) >= EXPHI) - { - rts_error(VARLSTCNT(1) ERR_NUMOFLOW); - return; - } - p->e = j + MV_XBIAS; - if (j < NUM_DEC_DG_2L) - { - j1 = NUM_DEC_DG_2L - j; - for (i = 0,z2 = z; i < j1; z2 *= 10,i++); - } else - { - if (j == NUM_DEC_DG_2L) - z2 = z; - else - { - j1 = j - NUM_DEC_DG_2L; - for (i = 0,z2 = z; i < j1; z2 /= 10,i++); - } - } - p->m[1] = z2 / MANT_HI; - if (p->m[1] == TEN_DEG_INT) - p->m[1] = MAX_M_INT; - z4 = ((double)(p->m[1]))*MANT_HI; - p->m[0] = (int)(z2 - z4); - if (p->m[0] == TEN_DEG_INT) - p->m[0] = MAX_M_INT; + n -= 5; + z *= 1e5; + } + while (1e9 <= z) + { + n++; + z *= .1; + } + while (1e8 > z) + { + n--; + z *= 10.0; + } + z1_rnd = (int)z; /* casts should keep z1_rnd and z2_rnd in proper range, hence the assert below */ + z -= (double)z1_rnd; + z *= 1e9; + z2_rnd = (int)z; + assert(((MANT_LO <= z1_rnd) && (MANT_HI > z1_rnd)) && ((0 <= z2_rnd) && (MANT_HI > z2_rnd))); + if ((0 == z2_rnd) && (-11 <= n) && (-3 >= n) && (0 == (z1_rnd % ten_pwr[-3 - n]))) + { /* This is a second-chance at detection an integer in case something slipped through the earlier + * check. Not expecting it to ever be invoked but is here as a safety net. + */ + z1_rnd /= ten_pwr[-3-n]; + ((mval_b *)p)->sgne = 0; + p->mvtype = (MV_NM | MV_INT); + p->m[1] = z1_rnd; return; } + exponent = MV_XBIAS + n + 9; + if (exponent >= EXPHI) + { + rts_error(VARLSTCNT(1) ERR_NUMOFLOW); + return; + } + if (exponent < EXPLO) + { + *p = literal_zero; + return; + } + p->mvtype = MV_NM; + p->e = exponent; + p->m[1] = z1_rnd; + p->m[0] = z2_rnd; + return; } - - - - - - - - diff --git a/sr_port/op_fnfnumber.c b/sr_port/op_fnfnumber.c index 64c53dd..786b4f8 100644 --- a/sr_port/op_fnfnumber.c +++ b/sr_port/op_fnfnumber.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,42 +23,48 @@ GBLREF spdesc stringpool; -void op_fnfnumber(mval *src, mval *fmt, mval *dst) -{ - mval temp, *temp_p; - unsigned char fncode, sign, *ch, *cp, *ff, *ff_top, *t; - int ct, x, y, z, xx; - boolean_t comma, paren; - error_def(ERR_FNARGINC); - error_def(ERR_FNUMARG); +LITREF mval literal_zero; +error_def(ERR_FNARGINC); +error_def(ERR_FNUMARG); + +void op_fnfnumber(mval *src, mval *fmt, boolean_t use_fract, int fract, mval *dst) +{ + boolean_t comma, paren; + int ct, x, xx, y, z; + mval t_src, *t_src_p; + unsigned char *ch, *cp, *ff, *ff_top, fncode, sign, *t; + + if (!MV_DEFINED(fmt)) /* catch this up front so noundef mode can't cause trouble - so fmt no empty context */ + rts_error(VARLSTCNT(2) ERR_FNUMARG, 0); + t_src_p = &t_src; /* operate on src in a temp, so conversions are possible without modifying src */ + *t_src_p = *src; + if (use_fract) + op_fnj3(t_src_p, 0, fract, t_src_p); + else if (MV_DEFINED(t_src_p)) + { /* if the source operand is not a canonical number, force conversion */ + MV_FORCE_NUM(t_src_p); + MV_FORCE_CANONICAL(t_src_p); + } else + t_src_p = underr(t_src_p); assert (stringpool.free >= stringpool.base); assert (stringpool.free <= stringpool.top); - /* assure that there is adequate space for two string forms of a number - as a local version of the src must be operated upon in order to get - a canonical number - */ + /* assure there is adequate space for two string forms of a number as a local + * version of the src must be operated upon in order to get a canonical number + */ ENSURE_STP_FREE_SPACE(MAX_NUM_SIZE * 2); - /* operate on the src operand in a temp, so that - conversions are possible without destroying the source - */ - temp_p = &temp; - *temp_p = *src; - /* if the source operand is not a canonical number, force conversion - */ - MV_FORCE_STR(temp_p); MV_FORCE_STR(fmt); - if (fmt->str.len == 0) + MV_FORCE_STR(t_src_p); + if (0 == fmt->str.len) { - *dst = *temp_p; + *dst = *t_src_p; return; } - temp_p->mvtype = MV_STR; - ch = (unsigned char *)temp_p->str.addr; - ct = temp_p->str.len; + ch = (unsigned char *)t_src_p->str.addr; + ct = t_src_p->str.len; cp = stringpool.free; fncode = 0; - for (ff = (unsigned char *)fmt->str.addr , ff_top = ff + fmt->str.len ; ff < ff_top ; ) + for (ff = (unsigned char *)fmt->str.addr, ff_top = ff + fmt->str.len; ff < ff_top;) { switch(*ff++) { @@ -84,7 +90,7 @@ void op_fnfnumber(mval *src, mval *fmt, mval *dst) break; } } - if (0 != (fncode & PAREN) && 0 != (fncode & FNERROR)) + if ((0 != (fncode & PAREN)) && (0 != (fncode & FNERROR))) rts_error(VARLSTCNT(4) ERR_FNARGINC, 2, fmt->str.len, fmt->str.addr); else { @@ -107,20 +113,21 @@ void op_fnfnumber(mval *src, mval *fmt, mval *dst) else *cp++ = ' '; } /* Only add '+' if > 0 */ - if (0 != (fncode & PLUS) && 0 == sign) + if ((0 != (fncode & PLUS)) && (0 == sign)) { /* Need to make into num and check for int 0 in case was preprocessed by op_fnj3() */ - MV_FORCE_NUM(temp_p); - if (0 == (temp_p->mvtype & MV_INT) || 0 != temp_p->m[1]) + MV_FORCE_NUM(t_src_p); + if ((0 == (t_src_p->mvtype & MV_INT)) || (0 != t_src_p->m[1])) sign = '+'; } - if (0 != (fncode & MINUS) && '-' == sign) + if ((0 != (fncode & MINUS)) && ('-' == sign)) sign = 0; - if (0 == (fncode & TRAIL) && 0 != sign) + if ((0 == (fncode & TRAIL)) && (0 != sign)) *cp++ = sign; if (0 != (fncode & COMMA)) { comma = FALSE; - for (x = 0, t = ch; '.' != *t && ++x < ct; t++) ; + for (x = 0, t = ch; (('.' != *t) && (++x < ct)); t++) + ; z = x; if ((y = x % 3) > 0) { @@ -128,7 +135,7 @@ void op_fnfnumber(mval *src, mval *fmt, mval *dst) *cp++ = *ch++; comma = TRUE; } - for ( ; x / 3 != 0 ; x -= 3, cp += 3, ch +=3) + for ( ; (0 != (x / 3)); x -= 3, cp += 3, ch +=3) { if (comma) *cp++ = ','; @@ -154,7 +161,7 @@ void op_fnfnumber(mval *src, mval *fmt, mval *dst) } if (0 != (fncode & PAREN)) { - if (paren) *cp++ = ')'; + if (paren)*cp++ = ')'; else *cp++ = ' '; } dst->mvtype = MV_STR; @@ -163,5 +170,5 @@ void op_fnfnumber(mval *src, mval *fmt, mval *dst) stringpool.free = cp; return; } - GTMASSERT; + assertpro(FALSE); } diff --git a/sr_port/op_fnget2.c b/sr_port/op_fnget2.c index f134b7f..015f2f8 100644 --- a/sr_port/op_fnget2.c +++ b/sr_port/op_fnget2.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,12 +12,15 @@ #include "mdef.h" #include "op.h" -void op_fnget2(mval *dst, mval *src, mval *defval) +LITREF mval literal_null; + +/* This gets a src from op_fnget1 or op_fngvget1 which either contains the "gotten" value or is undefined, in which case this + * returns the specified default value; this slight of hand deals with order of evaluation issues. + */ +void op_fnget2(mval *src, mval *def, mval *dst) { - MV_FORCE_DEFINED(defval); - if (src && MV_DEFINED(src)) - *dst = *src; - else - *dst = *defval; - dst->mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ + MV_FORCE_DEFINED(def); + *dst = MV_DEFINED(src) ? *src : *def; + assert(0 == (dst->mvtype & MV_ALIASCONT)); /* Should be no alias container flag */ + return; } diff --git a/sr_port/op_fngvget.c b/sr_port/op_fngvget.c index caa5471..c3a3a2d 100644 --- a/sr_port/op_fngvget.c +++ b/sr_port/op_fngvget.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,12 +25,14 @@ GBLREF gv_namehead *gv_target; GBLREF gd_region *gv_cur_region; -/* This code is very similar to "op_fngvget1.c" except that this one returns the default value - * (while op_fngvget1 returns an undefined value) if the global variable that we are trying to get is undefined. - * +LITREF mval literal_null; + +/* This code is very similar to op_fngvget1.c except if the gvn is undefined, this one returns the default empty string + * while op_fngvget1 returns an undefined value as a signal to op_fnget2, which, in turn, returns a specified "default" string; + * that slight of hand deals with order of evaluation issues. * Any changes to this routine most likely have to be made in op_fngvget1.c as well. */ -void op_fngvget(mval *v, mval *def) +void op_fngvget(mval *dst) { boolean_t gotit; DCL_THREADGBL_ACCESS; @@ -42,24 +44,19 @@ void op_fngvget(mval *v, mval *def) { case dba_bg : case dba_mm : - if (gv_target->root) - gotit = gvcst_get(v); - else - gotit = FALSE; + gotit = gv_target->root ? gvcst_get(dst) : FALSE; break; case dba_cm : - gotit = gvcmx_get(v); + gotit = gvcmx_get(dst); break; default : - gotit = gvusr_get(v); - if (gotit) - s2pool(&v->str); + ; + if (gotit = gvusr_get(dst)) /* NOTE: assignment */ + s2pool(&dst->str); break; } if (!gotit) - { - *v = *def; - v->mvtype &= ~MV_ALIASCONT; /* Make sure do not allow alias container property to pass */ - } + *dst = literal_null; + assert(0 == (dst->mvtype & MV_ALIASCONT)); /* Should be no alias container flag */ return; } diff --git a/sr_port/op_fngvget1.c b/sr_port/op_fngvget1.c index 5d6e559..323fb2a 100644 --- a/sr_port/op_fngvget1.c +++ b/sr_port/op_fngvget1.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,10 +25,11 @@ GBLREF gv_namehead *gv_target; GBLREF gd_region *gv_cur_region; -/* This code is very similar to "op_fngvget.c" except that this one returns an undefined mval "v" (while - * op_fngvget returns a default value) if the global variable that we are trying to get is undefined. +/* This code is very similar to op_fngvget.c except, if the gvn is undefined, this returns an undefined value as a signal to + * op_fnget2, which, in turn, returns a specified "default" value; that slight of hand deals with order of evaluation issues + * Any changes to this routine most likely have to be made in op_fngvget.c as well. */ -void op_fngvget1(mval *v) +void op_fngvget1(mval *dst) { boolean_t gotit; DCL_THREADGBL_ACCESS; @@ -41,21 +42,18 @@ void op_fngvget1(mval *v) { case dba_bg : case dba_mm : - if (gv_target->root) - gotit = gvcst_get(v); - else - gotit = FALSE; + gotit = gv_target->root ? gvcst_get(dst) : FALSE; break; case dba_cm : - gotit = gvcmx_get(v); + gotit = gvcmx_get(dst); break; default : - gotit = gvusr_get(v); - if (gotit) - s2pool(&v->str); + if (gotit = gvusr_get(dst)) /* NOTE: assignment */ + s2pool(&dst->str); break; } if (!gotit) - v->mvtype = 0; + dst->mvtype = 0; + assert(0 == (dst->mvtype & MV_ALIASCONT)); /* Should be no alias container flag */ return; } diff --git a/sr_port/op_fnname.c b/sr_port/op_fnname.c index 33449ab..47aeae0 100644 --- a/sr_port/op_fnname.c +++ b/sr_port/op_fnname.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "gdsbt.h" #include "gdsfhead.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "fnname.h" #include "op.h" @@ -33,6 +33,12 @@ GBLREF spdesc stringpool; GBLREF mv_stent *mv_chain; GBLREF unsigned char *msp, *stackwarn, *stacktop; +error_def(ERR_MAXSTRLEN); +error_def(ERR_GVNAKED); +error_def(ERR_FNNAMENEG); +error_def(ERR_STACKOFLOW); +error_def(ERR_STACKCRIT); + #ifdef TEST_DOLLAR_NAME_GCOL #define TEST_FAKE_STRINGPOOL_FULL stringpool.free = stringpool.top /* force gcol at various stages of $NAME processing */ #else @@ -85,6 +91,9 @@ GBLREF unsigned char *msp, *stackwarn, *stacktop; dst->str.len++; \ } +/* Implementation note: $NAME does not edit check the result, such as if the key size exceeds the maximum for a global. +* So, the result if used in other operations (such as SET, KILL) may generate run time errors (GVSUBOFLOW, etc) +*/ void op_fnname(UNIX_ONLY_COMMA(int sub_count) mval *finaldst, ...) { int space_needed; @@ -95,15 +104,6 @@ void op_fnname(UNIX_ONLY_COMMA(int sub_count) mval *finaldst, ...) va_list var; unsigned char *sptr, *key_ptr, *key_top; - error_def(ERR_MAXSTRLEN); - error_def(ERR_GVNAKED); - error_def(ERR_FNNAMENEG); - error_def(ERR_STACKOFLOW); - error_def(ERR_STACKCRIT); - - /* Implementation note: $NAME does not edit check the result, such as if the key size exceeds the maximum for a global. - * So, the result if used in other operations (such as SET, KILL) may generate run time errors (GVSUBOFLOW, etc) */ - VAR_START(var, finaldst); VMS_ONLY(va_count(sub_count);) assert(3 <= sub_count); @@ -111,13 +111,11 @@ void op_fnname(UNIX_ONLY_COMMA(int sub_count) mval *finaldst, ...) depth = va_arg(var, mval *); /* if second arg to $NAME not specified, compiler sets depth_count to MAXPOSINT4 */ depth_count = MV_FORCE_INT(depth); sub_count -=3; - if (depth_count < 0) { va_end(var); rts_error(VARLSTCNT(1) ERR_FNNAMENEG); } - /* Note about garbage collection : *dst and all possible *arg's in this function are anchored in the stringpool chains * and preserved during garbage collection (run time argument mvals provided by compiler). So, if we maintain dst->str.len * as we copy stuff to the stringpool, we are protected from mval_lex->stp_gcol shuffling strings around. Since the @@ -141,7 +139,8 @@ void op_fnname(UNIX_ONLY_COMMA(int sub_count) mval *finaldst, ...) rts_error(VARLSTCNT(1) ERR_GVNAKED); } /* Reserve enough space for naked reference. Include space for ^() and a maximum of sub_count ',' separators for - * subscripts specified as arguments to $NAME() in addition to those in the naked reference */ + * subscripts specified as arguments to $NAME() in addition to those in the naked reference + */ space_needed = (int)((STR_LIT_LEN("^()") + ZWR_EXP_RATIO(MAX_KEY_SZ) + sub_count)); TEST_FAKE_STRINGPOOL_FULL; ENSURE_STP_FREE_SPACE(space_needed); diff --git a/sr_port/op_fnquery.c b/sr_port/op_fnquery.c index 1d70abe..28e47f0 100644 --- a/sr_port/op_fnquery.c +++ b/sr_port/op_fnquery.c @@ -18,7 +18,7 @@ #include "lv_val.h" #include "subscript.h" #include "stringpool.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "collseq.h" #include "compiler.h" diff --git a/sr_port/op_fnstack1.c b/sr_port/op_fnstack1.c index b49bb20..6fe2e01 100644 --- a/sr_port/op_fnstack1.c +++ b/sr_port/op_fnstack1.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mvalconv.h" #include "op.h" diff --git a/sr_port/op_fnstack2.c b/sr_port/op_fnstack2.c index 014ce6a..3b7c928 100644 --- a/sr_port/op_fnstack2.c +++ b/sr_port/op_fnstack2.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mvalconv.h" #include "op.h" diff --git a/sr_port/op_fntext.c b/sr_port/op_fntext.c index bd7a1cc..4687862 100644 --- a/sr_port/op_fntext.c +++ b/sr_port/op_fntext.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,7 @@ #include "gtm_stdio.h" #include "error.h" -#include "rtnhdr.h" +#include #include "srcline.h" #include "op.h" #include "stringpool.h" @@ -25,7 +25,6 @@ GBLREF spdesc stringpool; -error_def(ERR_TXTNEGLIN); error_def(ERR_TXTSRCMAT); error_def(ERR_ZLINKFILE); error_def(ERR_ZLMODULE); @@ -42,7 +41,9 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret) uint4 stat; rhdtyp *rtn_vector; boolean_t is_trigger; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; MV_FORCE_STR(label); MV_FORCE_STR(rtn); temp_rtn = &temp_mval; @@ -56,8 +57,16 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret) stat = ZEROLINE; else { - GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"))); +#ifdef GTM_TRIGGER + if (is_trigger) + { + DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n")); + assert(FALSE == TREF(in_op_fntext)); + TREF(in_op_fntext) = TRUE; + } +#endif stat = get_src_line(temp_rtn, label, int_exp, &sld, VERIFY); + GTMTRIG_ONLY(TREF(in_op_fntext) = FALSE); } if (0 == (stat & (CHECKSUMFAIL | NEGATIVELINE))) { diff --git a/sr_port/op_fnview.c b/sr_port/op_fnview.c index 66fdd20..adcef90 100644 --- a/sr_port/op_fnview.c +++ b/sr_port/op_fnview.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,6 +38,7 @@ #include "alias.h" #include "gtmimagename.h" #include "fullbool.h" +#include "wbox_test_init.h" GBLREF spdesc stringpool; GBLREF int4 cache_hits, cache_fails; @@ -268,7 +269,7 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...) case VTK_NOISOLATION: if (NOISOLATION_NULL != parmblk.ni_list.type || NULL == parmblk.ni_list.gvnh_list || NULL != parmblk.ni_list.gvnh_list->next) - rts_error(VARLSTCNT(1) ERR_VIEWFN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWFN); n = parmblk.ni_list.gvnh_list->gvnh->noisolation; break; case VTK_PATCODE: @@ -276,23 +277,35 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...) s2pool(&tmpstr); dst->str = tmpstr; break; +#ifdef DEBUG + case VTK_PROBECRIT: + if (!gd_header) /* IF GD_HEADER ==0 THEN OPEN GBLDIR */ + gvinit(); + if (!parmblk.gv_ptr->open) + gv_init_reg(parmblk.gv_ptr); + reg = parmblk.gv_ptr; + grab_crit(reg); + if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED)) + rel_crit(reg); + break; +#endif case VTK_REGION: - /* if gd_header is null then get the current one, and update the gd_map */ - if (!gd_header) - { - SET_GD_HEADER(v); - SET_GD_MAP; - } - DEBUG_ONLY(else GD_HEADER_ASSERT); - map = gd_map; - map++; /* get past local locks */ - for (; memcmp(parmblk.ident.c, map->name, SIZEOF(mident_fixed)) >= 0; map++) - assert(map < gd_map_top); - reg = map->reg.addr; - tmpstr.addr = (char *)reg->rname; - tmpstr.len = reg->rname_len; - s2pool(&tmpstr); - dst->str = tmpstr; + /* if gd_header is null then get the current one, and update the gd_map */ + if (!gd_header) + { + SET_GD_HEADER(v); + SET_GD_MAP; + } + DEBUG_ONLY(else GD_HEADER_ASSERT); + map = gd_map; + map++; /* get past local locks */ + for (; memcmp(parmblk.ident.c, map->name, SIZEOF(mident_fixed)) >= 0; map++) + assert(map < gd_map_top); + reg = map->reg.addr; + tmpstr.addr = (char *)reg->rname; + tmpstr.len = reg->rname_len; + s2pool(&tmpstr); + dst->str = tmpstr; break; case VTK_RTNEXT: view_routines(dst, &parmblk.ident); @@ -402,13 +415,15 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...) RESET_GV_TARGET(DO_GVT_GVKEY_CHECK); break; case VTK_YLCT: - if (!arg) - n = TREF(local_collseq) ? (TREF(local_collseq))->act : 0; - else + n = -1; + if (arg) { - assert(!MEMCMP_LIT(arg->str.addr, "ncol")); - n = TREF(local_collseq_stdnull); - } + if (0 == MEMCMP_LIT(arg->str.addr, "nct")) + n = TREF(local_coll_nums_as_strings) ? 1 : 0; + else if (0 == MEMCMP_LIT(arg->str.addr, "ncol")) + n = TREF(local_collseq_stdnull); + } else + n = TREF(local_collseq) ? (TREF(local_collseq))->act : 0; break; case VTK_ZDEFBUFF: n = 0; @@ -463,13 +478,16 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...) dst->str.len = gtmImageNames[image_type].imageNameLen; dst->str.addr = gtmImageNames[image_type].imageName; break; -#ifndef VMS + case VTK_LOGTPRESTART: + n = TREF(tprestart_syslog_delta); + break; +# ifndef VMS case VTK_JNLERROR: n = TREF(error_on_jnl_file_lost); break; -#endif +# endif default: - rts_error(VARLSTCNT(1) ERR_VIEWFN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWFN); } dst->mvtype = vtp->restype; if (MV_NM == vtp->restype) diff --git a/sr_port/op_fnztrigger.c b/sr_port/op_fnztrigger.c index e71b3a0..9372f3f 100644 --- a/sr_port/op_fnztrigger.c +++ b/sr_port/op_fnztrigger.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -48,6 +48,9 @@ GBLREF gv_namehead *gv_target; GBLREF boolean_t dollar_ztrigger_invoked; GBLREF int4 gtm_trigger_depth; GBLREF mstr *dollar_ztname; +#ifdef DEBUG +GBLREF boolean_t donot_INVOKE_MUMTSTART; +#endif LITREF mval literal_zero; LITREF mval literal_one; @@ -63,9 +66,10 @@ STATICDEF boolean_t save_gv_last_subsc_null, save_gv_some_subsc_null; STATICDEF boolean_t in_op_fnztrigger; #endif +error_def(ERR_DZTRIGINTRIG); error_def(ERR_FILENAMETOOLONG); error_def(ERR_ZTRIGINVACT); -error_def(ERR_DZTRIGINTRIG); + enum ztrprms { @@ -135,6 +139,7 @@ CONDITION_HANDLER(op_fnztrigger_ch) START_CH; RESTORE_ZTRIGGER_ENTRY_STATE; + DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); NEXTCH; @@ -204,7 +209,10 @@ void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst) * from this function. */ if (gv_currkey) + { gv_currkey->end = 0; + gv_currkey->base[0] = KEY_DELIMITER; + } TREF(gv_last_subsc_null) = TREF(gv_some_subsc_null) = FALSE; ESTABLISH(op_fnztrigger_ch); dollar_ztrigger_invoked = TRUE; /* reset after use when the transaction commits, restarts or rollbacks */ @@ -240,10 +248,11 @@ void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst) return; } #else /* !GTM_TRIGGER */ + +error_def(ERR_UNIMPLOP); + void op_fnztrigger(mval *func, mval *arg1, mval *arg2, mval *dst) { - error_def(ERR_UNIMPLOP); - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); } #endif diff --git a/sr_port/op_get_msf.c b/sr_port/op_get_msf.c index c2cdb8e..8b4ae9d 100644 --- a/sr_port/op_get_msf.c +++ b/sr_port/op_get_msf.c @@ -21,7 +21,7 @@ every new release of GT.M. */ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" GBLREF stack_frame *frame_pointer; diff --git a/sr_port/op_gvextnam.c b/sr_port/op_gvextnam.c index 38b41e1..633676d 100644 --- a/sr_port/op_gvextnam.c +++ b/sr_port/op_gvextnam.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "dpgbldir.h" #include "sgnl.h" #include "mvalconv.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */ #include "gvcst_protos.h" /* for gvcst_root_search in GV_BIND_NAME_AND_ROOT_SEARCH macro */ @@ -63,6 +63,8 @@ void op_gvextnam(UNIX_ONLY_COMMA(int4 count) mval *val1, ...) MV_FORCE_STR(val1); val1 = gtm_env_translate(val1, val2, &val_xlated); assert(!TREF(gv_extname_size) || (NULL != extnam_str.addr)); + if (!gd_header) + gvinit(); if (val1->str.len) { tmp_mstr_ptr = &val1->str; @@ -70,8 +72,6 @@ void op_gvextnam(UNIX_ONLY_COMMA(int4 count) mval *val1, ...) } else { tmp_mstr_ptr = &dollar_zgbldir.str; - if (!gd_header) - gvinit(); TREF(gd_targ_addr) = gd_header; } extnam_str.len = tmp_mstr_ptr->len; @@ -83,11 +83,7 @@ void op_gvextnam(UNIX_ONLY_COMMA(int4 count) mval *val1, ...) extnam_str.addr = (char *)malloc(TREF(gv_extname_size)); } memcpy(extnam_str.addr, tmp_mstr_ptr->addr, tmp_mstr_ptr->len); - if (gv_target) - { - assert(INVALID_GV_TARGET != gv_target); - gv_target->clue.end = 0; - } + assert((NULL == gv_target) || (INVALID_GV_TARGET != gv_target)); val = va_arg(var, mval *); if (!MV_IS_STRING(val)) GTMASSERT; diff --git a/sr_port/op_gvnaked.c b/sr_port/op_gvnaked.c index 24f1f5f..12063d9 100644 --- a/sr_port/op_gvnaked.c +++ b/sr_port/op_gvnaked.c @@ -28,7 +28,7 @@ #include "hashtab_int4.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */ #include "subscript.h" #include "op.h" @@ -77,23 +77,23 @@ void op_gvnaked(UNIX_ONLY_COMMA(int count_arg) mval *val_arg, ...) UNIX_ONLY(count = count_arg;) /* i386 assembler modules may depend on unchanged count */ if (0 >= count) GTMASSERT; - gv_currkey->end = gv_currkey->prev; is_null = FALSE; - assert(gv_currkey->end); + assert(gv_currkey->prev); was_null = TREF(gv_some_subsc_null); sbs_cnt = 0; if (1 < count) { /* Use of naked reference can cause increase in number of subscripts. So count the subscripts */ ptr = gv_currkey->base; - end_ptr = ptr + gv_currkey->end; + end_ptr = ptr + gv_currkey->prev; while (ptr < end_ptr) if (KEY_DELIMITER == *ptr++) sbs_cnt++; - if (MAX_GVSUBSCRIPTS < count + sbs_cnt) + if (MAX_GVSUBSCRIPTS < (count + sbs_cnt)) rts_error(VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS); } /* else naked reference will not increase number of subscripts, so do not worry about exceeding the limit */ + gv_currkey->end = gv_currkey->prev; VAR_START(var, val_arg); val = val_arg; max_key = gv_cur_region->max_key_size; diff --git a/sr_port/op_gvname.c b/sr_port/op_gvname.c index f00eadf..16103c7 100644 --- a/sr_port/op_gvname.c +++ b/sr_port/op_gvname.c @@ -28,7 +28,7 @@ #include "hashtab_int4.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" /* for COPY_SUBS_TO_GVCURRKEY macro */ #include "op.h" #include "gvcst_protos.h" /* for gvcst_root_search prototype */ @@ -50,6 +50,10 @@ GBLREF sgm_info *sgm_info_ptr; GBLREF uint4 dollar_tlevel; GBLREF mstr extnam_str; +#ifdef DEBUG +GBLDEF boolean_t dbg_opgvname_fast_path; +#endif + void op_gvname(UNIX_ONLY_COMMA(int count_arg) mval *val_arg, ...) { int count; @@ -61,19 +65,20 @@ void op_gvname(UNIX_ONLY_COMMA(int count_arg) mval *val_arg, ...) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); extnam_str.len = 0; if (!gd_header) gvinit(); TREF(gd_targ_addr) = gd_header; VAR_START(var, val_arg); VMS_ONLY(va_count(count)); - UNIX_ONLY(count = count_arg;) /* need to preserve stack copy for i386 */ + UNIX_ONLY(count = count_arg); /* need to preserve stack copy for i386 */ count--; val = val_arg; if ((gd_header->maps == gd_map) && gv_currkey && (0 == gv_currkey->base[val->str.len]) && (0 == memcmp(gv_currkey->base, val->str.addr, val->str.len))) { + DEBUG_ONLY(dbg_opgvname_fast_path = TRUE); gv_currkey->end = val->str.len + 1; gv_currkey->base[gv_currkey->end] = 0; gv_currkey->prev = 0; @@ -85,8 +90,15 @@ void op_gvname(UNIX_ONLY_COMMA(int count_arg) mval *val_arg, ...) assert(INVALID_GV_TARGET != gv_target); GVCST_ROOT_SEARCH; } + /* IF gv_target and cs_addrs are out of sync at this point, we could end up in database damage. + * Hence the assertpro. In the else block, we do a GV_BIND_NAME which ensures they are in sync + * (asserted by the DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC check later) hence this assertpro check + * is not done in that case. + */ + assertpro(gv_target->gd_csa == cs_addrs); } else { + DEBUG_ONLY(dbg_opgvname_fast_path = FALSE); GV_BIND_NAME_AND_ROOT_SEARCH(gd_header, &(val->str)); DEBUG_ONLY( bgormm = ((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth))); @@ -94,8 +106,12 @@ void op_gvname(UNIX_ONLY_COMMA(int count_arg) mval *val_arg, ...) assert(!bgormm || (gv_cur_region && &FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data)); assert(bgormm || !dollar_tlevel); assert(!dollar_tlevel || sgm_info_ptr && (sgm_info_ptr->tp_csa == cs_addrs)); - assert(gv_target->gd_csa == cs_addrs); - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + assert(NULL != gv_target); + assert(gv_currkey->end); + assert('\0' != gv_currkey->base[0]); /* ensure the below DBG_CHECK_... assert does a proper check (which it wont + * if it finds gv_currkey->base[0] is '\0' + */ + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); assert(TREF(gd_targ_addr) == gd_header); was_null = is_null = FALSE; max_key = gv_cur_region->max_key_size; diff --git a/sr_port/op_gvnext.c b/sr_port/op_gvnext.c index 51849dd..e5fd09e 100644 --- a/sr_port/op_gvnext.c +++ b/sr_port/op_gvnext.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,58 +22,55 @@ #include "gvcmx.h" #include "gvusr.h" -GBLREF gv_namehead *gv_target; -GBLREF gv_key *gv_currkey; GBLREF gv_key *gv_altkey; -GBLREF spdesc stringpool; +GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; +GBLREF gv_namehead *gv_target; +GBLREF spdesc stringpool; /****************** SHOULD BE IN .H FILES !!!!!!!! ***********************/ -#define MAX_SUBSC_LEN 255 -#define MAX_NUM_SLEN 128 +#define MAX_NUM_SLEN 128 /*************************************************************************/ void op_gvnext(mval *v) { - register char *c; boolean_t found; - int4 n; enum db_acc_method acc_meth; + int4 n; + register char *c; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; acc_meth = gv_cur_region->dyn.addr->acc_meth; /* if the lowest subscript is -1, then make it null */ - if ( (gv_currkey->end == gv_currkey->prev + 4) && - *(&gv_currkey->base[0] + gv_currkey->prev) == 0x40 && - *(&gv_currkey->base[0] + gv_currkey->prev + 1) == 0xEE && - *(&gv_currkey->base[0] + gv_currkey->prev + 2) == 0xFF) - + if ((gv_currkey->end == gv_currkey->prev + 4) + && *(gv_currkey->base + gv_currkey->prev) == 0x40 + && *(gv_currkey->base + gv_currkey->prev + 1) == 0xEE + && *(gv_currkey->base + gv_currkey->prev + 2) == 0xFF) { - *(&gv_currkey->base[0] + gv_currkey->prev) = 01; - *(char *)(&gv_currkey->base[0] + gv_currkey->prev + 2) = 0; + *(gv_currkey->base + gv_currkey->prev) = 01; + *(char *)(gv_currkey->base + gv_currkey->prev + 2) = KEY_DELIMITER; if (0 == gv_cur_region->std_null_coll) { - *(char *)(&gv_currkey->base[0] + gv_currkey->prev + 1) = 0; + *(char *)(gv_currkey->base + gv_currkey->prev + 1) = KEY_DELIMITER; gv_currkey->end -= 2; } else { - *(char *)(&gv_currkey->base[0] + gv_currkey->prev + 1) = 1; - *(char *)(&gv_currkey->base[0] + gv_currkey->prev + 3) = 0; + *(char *)(gv_currkey->base + gv_currkey->prev + 1) = 1; + *(char *)(gv_currkey->base + gv_currkey->prev + 3) = KEY_DELIMITER; gv_currkey->end --; } } else { - if (!TREF(gv_last_subsc_null) || gv_cur_region->std_null_coll ) + if (!TREF(gv_last_subsc_null) || gv_cur_region->std_null_coll) { - *(&gv_currkey->base[0] + gv_currkey->end - 1) = 1; - *(&gv_currkey->base[0] + gv_currkey->end + 1) = 0; + *(gv_currkey->base + gv_currkey->end - 1) = 1; + *(gv_currkey->base + gv_currkey->end + 1) = KEY_DELIMITER; gv_currkey->end += 1; } else - *(&gv_currkey->base[0] + gv_currkey->prev) = 01; + *(gv_currkey->base + gv_currkey->prev) = 01; } - - if (acc_meth == dba_bg || acc_meth == dba_mm) + if ((acc_meth == dba_bg) || (acc_meth == dba_mm)) { if (gv_target->root) found = gvcst_order(); @@ -83,8 +80,7 @@ void op_gvnext(mval *v) found = gvcmx_order(); else found = gvusr_order(); - - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by this to-be-overwritten mval */ + v->mvtype = 0; /* so stp_gcol, if invoked below, can free up space currently occupied by this to-be-overwritten mval */ if (!found) { ENSURE_STP_FREE_SPACE(2); @@ -92,11 +88,12 @@ void op_gvnext(mval *v) *c++ = '-'; *c = '1'; v->str.len = 2; - stringpool.free += 2; + stringpool.free += 2; + } else { gv_altkey->prev = gv_currkey->prev; - if (stringpool.top - stringpool.free < MAX_SUBSC_LEN) + if (!IS_STP_SPACE_AVAILABLE(MAX_KEY_SZ + 1)) { if (*(&gv_altkey->base[0] + gv_altkey->prev) != 0xFF) n = MAX_NUM_SLEN; @@ -107,14 +104,24 @@ void op_gvnext(mval *v) } ENSURE_STP_FREE_SPACE(n); } - v->str.addr = (char *) stringpool.free; + v->str.addr = (char *)stringpool.free; c = (char *)(&gv_altkey->base[0] + gv_altkey->prev); stringpool.free = gvsub2str ((uchar_ptr_t)c,stringpool.free, FALSE); v->str.len = INTCAST(stringpool.free - (unsigned char *) v->str.addr); assert (v->str.addr < (char *) stringpool.top && v->str.addr >= (char *) stringpool.base); - assert (v->str.addr + v->str.len <= (char *) stringpool.top && - v->str.addr + v->str.len >= (char *) stringpool.base); + assert (v->str.addr + v->str.len <= (char *) stringpool.top + && v->str.addr + v->str.len >= (char *) stringpool.base); + } v->mvtype = MV_STR; /* initialize mvtype now that mval has been otherwise completely set up */ + if ((2 == v->str.len) && ('-' == *v->str.addr) && ('1' == *(v->str.addr + 1))) + { /* adjust so $REFERENCE would be correct */ + gv_currkey->end = gv_currkey->prev; + *(gv_currkey->base + gv_currkey->end++) = 0x40; + *(gv_currkey->base + gv_currkey->end++) = 0xEE; + *(gv_currkey->base + gv_currkey->end++) = 0xFF; + *(gv_currkey->base + gv_currkey->end++) = KEY_DELIMITER; + *(gv_currkey->base + gv_currkey->end) = KEY_DELIMITER; + } return; } diff --git a/sr_port/op_gvorder.c b/sr_port/op_gvorder.c index dbd78f2..935e7b1 100644 --- a/sr_port/op_gvorder.c +++ b/sr_port/op_gvorder.c @@ -82,7 +82,7 @@ void op_gvorder (mval *v) found = gvcmx_order(); else found = gvusr_order(); - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by + v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by (BYPASSOK) * this to-be-overwritten mval */ if (found) { @@ -185,12 +185,14 @@ void op_gvorder (mval *v) { assert(SIZEOF(map->name) == SIZEOF(mident_fixed)); gv_currkey->end = mid_len((mident_fixed *)map->name); + assert(gv_currkey->end <= MAX_MIDENT_LEN); memcpy(&gv_currkey->base[0], map->name, gv_currkey->end); gv_currkey->base[ gv_currkey->end - 1 ] -= 1; gv_currkey->base[ gv_currkey->end ] = 0xFF; /* back off 1 spot from map */ gv_currkey->base[ gv_currkey->end + 1] = 0; gv_currkey->base[ gv_currkey->end + 2] = 0; gv_currkey->end += 2; + assert(gv_currkey->top > gv_currkey->end); /* ensure we are within allocated bounds */ } } /* Reset gv_currkey as we have potentially skipped one or more regions so we no @@ -198,13 +200,13 @@ void op_gvorder (mval *v) */ gv_currkey->end = 0; gv_currkey->base[0] = 0; - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by + v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by (BYPASSOK) * this to-be-overwritten mval */ if (found) { if (!IS_STP_SPACE_AVAILABLE(name.len + 1)) { - v->str.len = 0; /* so stp_gcol ignores otherwise incompletely setup mval */ + v->str.len = 0; /* so stp_gcol ignores otherwise incompletely setup mval (BYPASSOK) */ INVOKE_STP_GCOL(name.len + 1); } #ifdef mips diff --git a/sr_port/op_gvput.c b/sr_port/op_gvput.c index 7df97bb..df0be49 100644 --- a/sr_port/op_gvput.c +++ b/sr_port/op_gvput.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -51,7 +51,7 @@ void op_gvput(mval *var) { assert(gv_currkey->end + 1 <= gv_cur_region->max_key_size); MV_FORCE_STR(var); - if (gv_currkey->end + 1 + var->str.len + SIZEOF(rec_hdr) <= gv_cur_region->max_rec_size) + if (VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) var->str.len <= gv_cur_region->max_rec_size) { switch (gv_cur_region->dyn.addr->acc_meth) { @@ -94,8 +94,8 @@ void op_gvput(mval *var) { if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, gv_currkey->end + 1 + var->str.len + SIZEOF(rec_hdr), - (int4)gv_cur_region->max_rec_size, + rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) + var->str.len, (int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); } } else diff --git a/sr_port/op_gvrectarg.c b/sr_port/op_gvrectarg.c index 85051c2..52d75b4 100644 --- a/sr_port/op_gvrectarg.c +++ b/sr_port/op_gvrectarg.c @@ -140,7 +140,6 @@ void op_gvrectarg(mval *v) assert(KEY_DELIMITER == gv_currkey->base[end - 1]); } gv_currkey->base[end] = KEY_DELIMITER; - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); return; } diff --git a/sr_port/op_gvsavtarg.c b/sr_port/op_gvsavtarg.c index ad464f1..6f29f36 100644 --- a/sr_port/op_gvsavtarg.c +++ b/sr_port/op_gvsavtarg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -49,9 +49,9 @@ void op_gvsavtarg(mval *v) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied by this to-be-overwritten mval */ + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); + v->mvtype = 0; /* BYPASSOK */ /* so stp_gcol (if invoked below) can free up space currently + * occupied by this to-be-overwritten mval */ if (NULL == gv_currkey) { /* Simplest case, finish it off */ v->str.len = 0; diff --git a/sr_port/op_halt.c b/sr_port/op_halt.c index 7ab626b..d8124b8 100644 --- a/sr_port/op_halt.c +++ b/sr_port/op_halt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,6 +47,6 @@ void op_halt(void) 0, zposition.str.len, zposition.str.addr); } # endif - exit(0); + exit(EXIT_SUCCESS); #endif } diff --git a/sr_port/op_hang.c b/sr_port/op_hang.c index fad0524..28ace8f 100644 --- a/sr_port/op_hang.c +++ b/sr_port/op_hang.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,19 +36,43 @@ # include "wcs_sleep.h" # include "wbox_test_init.h" # include "gtmio.h" -# include "have_crit.h" # include "deferred_signal_handler.h" +# include "util.h" #endif +#include "gdsroot.h" +#include "gdskill.h" +#include "gdsbt.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsfhead.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" +#include "send_msg.h" +#include "gtmmsg.h" /* for gtm_putmsg() prototype */ +#include "change_reg.h" +#include "setterm.h" +#include "getzposition.h" +#ifdef DEBUG +#include "have_crit.h" /* for the TPNOTACID_CHECK macro */ +#endif + +GBLREF uint4 dollar_trestart; +GBLREF mv_stent *mv_chain; GBLREF int4 outofband; GBLREF unsigned char *restart_pc, *restart_ctxt; -GBLREF mv_stent *mv_chain; #ifdef DEBUG GBLREF stack_frame *frame_pointer; #endif error_def(ERR_SYSCALL); +#define HANGSTR "HANG time too long" + /* * ------------------------------------------ * Hang the process for a specified time. @@ -57,6 +81,10 @@ error_def(ERR_SYSCALL); * Any caught signal will terminate the sleep * following the execution of that signal's catching routine. * + * The actual hang duration should be NO LESS than the specified + * duration for specified durations greater than .001 seconds. + * Certain applications depend on this assumption. + * * Arguments: * num - time to sleep * @@ -67,6 +95,7 @@ error_def(ERR_SYSCALL); void op_hang(mval* num) { int ms; + double tmp; mv_stent *mv_zintcmd; ABS_TIME cur_time, end_time; # ifdef VMS @@ -86,14 +115,16 @@ void op_hang(mval* num) ms = num->m[1] * (1000 / MV_BIAS); } } else if (0 == num->sgn) /* if sign is not 0 it means num is negative */ - ms = mval2i(num) * 1000; /* too big to care about fractional amounts */ + { + tmp = mval2double(num) * (double)1000; + ms = ((double)MAXPOSINT4 >= tmp) ? (int)tmp : (int)MAXPOSINT4; + } if (ms) { + if (TREF(tpnotacidtime) * 1000 < ms) + TPNOTACID_CHECK(HANGSTR); # if defined(DEBUG) && defined(UNIX) - if (gtm_white_box_test_case_enabled - && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number) - && (3 > gtm_white_box_test_case_count) - && (123000 == ms)) + if (WBTEST_ENABLED(WBTEST_DEFERRED_TIMERS) && (3 > gtm_white_box_test_case_count) && (123000 == ms)) { DEFER_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); DBGFPF((stderr, "OP_HANG: will sleep for 20 seconds\n")); @@ -102,15 +133,19 @@ void op_hang(mval* num) ENABLE_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); return; } - if (gtm_white_box_test_case_enabled - && (WBTEST_BREAKMPC == gtm_white_box_test_case_number) - && (0 == gtm_white_box_test_case_count) - && (999 == ms)) + if (WBTEST_ENABLED(WBTEST_BREAKMPC)&& (0 == gtm_white_box_test_case_count) && (999 == ms)) { frame_pointer->old_frame_pointer->mpc = (unsigned char *)GTM64_ONLY(0xdeadbeef12345678) NON_GTM64_ONLY(0xdead1234); return; } + if (WBTEST_ENABLED(WBTEST_UTIL_OUT_BUFFER_PROTECTION) && (0 == gtm_white_box_test_case_count) && (999 == ms)) + { /* Upon seeing a .999s hang this white-box test launches a timer that pops with a period of + * UTIL_OUT_SYSLOG_INTERVAL and prints a long message via util_out_ptr. + */ + start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL); + return; + } # endif sys_get_curr_time(&cur_time); mv_zintcmd = find_mvstent_cmd(ZINTCMD_HANG, restart_pc, restart_ctxt, FALSE); @@ -140,28 +175,27 @@ void op_hang(mval* num) if (0 == ms) return; /* done HANGing */ } - UNIX_ONLY(hiber_start(ms);) - VMS_ONLY( - time[0] = -time_low_ms(ms); - time[1] = -time_high_ms(ms) - 1; - efn_mask = (1 << efn_outofband | 1 << efn_timer); - if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0))) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status); - if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask))) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status); - ) +# ifdef UNIX + hiber_start(ms); +# elif defined(VMS) + time[0] = -time_low_ms(ms); + time[1] = -time_high_ms(ms) - 1; + efn_mask = (1 << efn_outofband | 1 << efn_timer); + if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status); + if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status); if (outofband) { - VMS_ONLY( - if (SS$_WASCLR == (status = sys$readef(efn_timer, &efn_mask))) - { - if (SS$_NORMAL != (status = sys$cantim(&time, 0))) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$cantim"), CALLFROM, - status); - } else - assertpro(SS$_WASSET == status); - ) + if (SS$_WASCLR == (status = sys$readef(efn_timer, &efn_mask))) + { + if (SS$_NORMAL != (status = sys$cantim(&time, 0))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$cantim"), + CALLFROM, status); + } else + assertpro(SS$_WASSET == status); } +# endif } else rel_quant(); if (outofband) diff --git a/sr_port/op_hardret.c b/sr_port/op_hardret.c index a00c3e7..3299446 100644 --- a/sr_port/op_hardret.c +++ b/sr_port/op_hardret.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "unwind_nocounts.h" @@ -24,7 +24,7 @@ void op_hardret(void) dmode = unwind_nocounts(); assert(frame_pointer->old_frame_pointer); - assert(SFT_COUNT == frame_pointer->type); + assert(SFT_COUNT & frame_pointer->type); /* QUIT in dmode should + re-install SFT_DM frame that would have been unwound by unwind_nocounts diff --git a/sr_port/op_igetsrc.c b/sr_port/op_igetsrc.c index eede3bd..c8b8537 100644 --- a/sr_port/op_igetsrc.c +++ b/sr_port/op_igetsrc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,10 +17,7 @@ void op_igetsrc(mval *v) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - (TREF(ind_source_sp))--; - assert(TREF(ind_source_sp) < TREF(ind_source_top)); - assert(TREF(ind_source_sp) >= TREF(ind_source_array)); - *v = **(TREF(ind_source_sp)); + *v = *(TREF(ind_source)); /* see comment in comp_init.c */ v->mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ return; } diff --git a/sr_port/op_inddevparms.c b/sr_port/op_inddevparms.c index 3fa8aff..930ef3f 100644 --- a/sr_port/op_inddevparms.c +++ b/sr_port/op_inddevparms.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,7 +21,6 @@ #include "deviceparameters.h" #include "op.h" -error_def(ERR_INDMAXNEST); error_def(ERR_INDEXTRACHARS); void op_inddevparms(mval *devpsrc, int4 ok_iop_parms, mval *devpiopl) @@ -29,20 +28,18 @@ void op_inddevparms(mval *devpsrc, int4 ok_iop_parms, mval *devpiopl) int rval; icode_str indir_src; mstr *obj, object; - oprtype devpopr, plist; + oprtype devpopr, plist, getdst; triple *indref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ MV_FORCE_STR(devpsrc); indir_src.str = devpsrc->str; indir_src.code = indir_devparms; if (NULL == (obj = cache_get(&indir_src))) /* NOTE assignment */ { /* No cached version, compile it now */ obj = &object; - comp_init(&devpsrc->str); + comp_init(&devpsrc->str, &getdst); if (TK_ATSIGN == TREF(window_token)) { /* For the indirection-obsessive */ if (EXPR_FAIL != (rval = indirection(&devpopr))) /* NOTE assignment */ @@ -54,13 +51,13 @@ void op_inddevparms(mval *devpsrc, int4 ok_iop_parms, mval *devpiopl) } } else /* We have the parm string to process now */ rval = deviceparameters(&plist, ok_iop_parms); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &plist, devpsrc->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &plist, &getdst, devpsrc->str.len)) return; indir_src.str.addr = devpsrc->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = devpiopl; /* Where to store return value */ + TREF(ind_result) = devpiopl; /* Where to store return value */ comp_indr(obj); return; } diff --git a/sr_port/op_indfnname.c b/sr_port/op_indfnname.c index 8e26371..e3546e4 100644 --- a/sr_port/op_indfnname.c +++ b/sr_port/op_indfnname.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,7 +20,6 @@ #include "hashtab_objcode.h" #include "op.h" -error_def(ERR_INDMAXNEST); error_def(ERR_VAREXPECTED); void op_indfnname(mval *dst, mval *target, mval *depth) @@ -29,13 +28,11 @@ void op_indfnname(mval *dst, mval *target, mval *depth) icode_str indir_src; int rval; mstr *obj, object; - oprtype v; + oprtype v, getdst; triple *s, *src; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if ((TREF(ind_source_sp) >= TREF(ind_source_top)) || (TREF(ind_result_sp) >= TREF(ind_result_top))) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp & ind_source_sp */ MV_FORCE_STR(target); indir_src.str = target->str; indir_src.code = indir_fnname; @@ -43,7 +40,7 @@ void op_indfnname(mval *dst, mval *target, mval *depth) { obj = &object; gbl = FALSE; - comp_init(&target->str); + comp_init(&target->str, &getdst); src = newtriple(OC_IGETSRC); s = maketriple(OC_FNNAME); switch (TREF(window_token)) @@ -54,33 +51,28 @@ void op_indfnname(mval *dst, mval *target, mval *depth) /* caution fall through */ case TK_IDENT: if (EXPR_FAIL != (rval = name_glvn(gbl, &s->operand[1]))) /* NOTE assignment */ - { - ins_triple(s); s->operand[0] = put_tref(src); - } break; case TK_ATSIGN: s->opcode = OC_INDFNNAME; if (EXPR_FAIL != (rval = indirection(&(s->operand[0])))) /* NOTE assignment */ - { s->operand[1] = put_tref(src); - ins_triple(s); - } break; default: stx_error(ERR_VAREXPECTED); rval = EXPR_FAIL; break; } + ins_triple(s); v = put_tref(s); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &v, target->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &v, &getdst, target->str.len)) return; indir_src.str.addr = target->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; - *(TREF(ind_source_sp))++ = depth; + TREF(ind_result) = dst; + TREF(ind_source) = depth; comp_indr(obj); return; } diff --git a/sr_port/op_indfun.c b/sr_port/op_indfun.c index 26c432b..cb75c79 100644 --- a/sr_port/op_indfun.c +++ b/sr_port/op_indfun.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,19 +26,15 @@ static readonly opctype indir_opcode[] = { }; #undef INDIR -error_def(ERR_INDMAXNEST); - void op_indfun(mval *v, mint argcode, mval *dst) { icode_str indir_src; int rval; mstr *obj, object; - oprtype x; + oprtype x, getdst; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ assert((SIZEOF(indir_opcode)/SIZEOF(indir_opcode[0])) > argcode); assert(indir_opcode[argcode]); MV_FORCE_STR(v); @@ -47,15 +43,15 @@ void op_indfun(mval *v, mint argcode, mval *dst) if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&v->str); + comp_init(&v->str, &getdst); rval = (*indir_fcn[argcode])(&x, indir_opcode[argcode]); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, v->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, &getdst, v->str.len)) return; indir_src.str.addr = v->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; /* Where to store return value */ + TREF(ind_result) = dst; /* Where to store return value */ comp_indr(obj); return; } diff --git a/sr_port/op_indglvn.c b/sr_port/op_indglvn.c index 481abcf..e5c64b8 100644 --- a/sr_port/op_indglvn.c +++ b/sr_port/op_indglvn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,6 +11,7 @@ #include "mdef.h" +#include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "lv_val.h" #include "compiler.h" #include "opcode.h" @@ -18,14 +19,13 @@ #include "toktyp.h" #include "cache.h" #include "op.h" -#include "rtnhdr.h" +#include #include "valid_mname.h" GBLREF bool undef_inhibit; GBLREF symval *curr_symval; LITREF mval literal_null; -error_def(ERR_INDMAXNEST); error_def(ERR_UNDEF); void op_indglvn(mval *v,mval *dst) @@ -34,7 +34,7 @@ void op_indglvn(mval *v,mval *dst) icode_str indir_src; int rval; mstr *obj, object; - oprtype x; + oprtype x, getdst; var_tabent targ_key; DCL_THREADGBL_ACCESS; @@ -63,19 +63,18 @@ void op_indglvn(mval *v,mval *dst) dst->mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ return; } - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ obj = &object; - comp_init(&v->str); + comp_init(&v->str, &getdst); + INCREMENT_EXPR_DEPTH; rval = glvn(&x); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, v->str.len)) + DECREMENT_EXPR_DEPTH; + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, &getdst, v->str.len)) return; indir_src.str.addr = v->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ - } else if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ - *(TREF(ind_result_sp))++ = dst; + } + TREF(ind_result) = dst; comp_indr(obj); return; } diff --git a/sr_port/op_indincr.c b/sr_port/op_indincr.c index 1f4ec12..788a9da 100644 --- a/sr_port/op_indincr.c +++ b/sr_port/op_indincr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2011 Fidelity Information Services, Inc * + * Copyright 2004, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,6 @@ #include "mvalconv.h" /* for i2mval prototype for the MV_FORCE_MVAL macro */ #include "fullbool.h" -error_def(ERR_INDMAXNEST); error_def(ERR_VAREXPECTED); void op_indincr(mval *dst, mval *increment, mval *target) @@ -30,20 +29,18 @@ void op_indincr(mval *dst, mval *increment, mval *target) icode_str indir_src; int rval; mstr *obj, object; - oprtype v; + oprtype v, getdst; triple *s, *src, *oldchain, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if ((TREF(ind_source_sp) >= TREF(ind_source_top)) || (TREF(ind_result_sp) >= TREF(ind_result_top))) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp & ind_source_sp */ MV_FORCE_STR(target); indir_src.str = target->str; indir_src.code = indir_increment; if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&target->str); + comp_init(&target->str, &getdst); src = newtriple(OC_IGETSRC); switch (TREF(window_token)) { @@ -99,14 +96,14 @@ void op_indincr(mval *dst, mval *increment, mval *target) break; } v = put_tref(s); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &v, target->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &v, &getdst, target->str.len)) return; indir_src.str.addr = target->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; - *(TREF(ind_source_sp))++ = increment; + TREF(ind_result) = dst; + TREF(ind_source) = increment; comp_indr(obj); return; } diff --git a/sr_port/op_indlvadr.c b/sr_port/op_indlvadr.c index 6f1f398..71ee210 100644 --- a/sr_port/op_indlvadr.c +++ b/sr_port/op_indlvadr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,6 +29,7 @@ GBLREF stack_frame *frame_pointer; error_def(ERR_VAREXPECTED); +/* note: not currently used anywhere */ void op_indlvadr(mval *target) { char *ptr; @@ -50,35 +51,15 @@ void op_indlvadr(mval *target) if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&target->str); + comp_init(&target->str, NULL); switch (TREF(window_token)) { case TK_IDENT: - rval = lvn(&v, OC_SAVPUTINDX, NULL); - s = v.oprval.tref; /* this ugliness serves to return a flag compiled code can use to adjust flow */ - if (OC_SAVPUTINDX != s->opcode) - { /* this block grabs a way to look up the name later and is similar to some code in op_savputindx */ - assert(MVAR_REF == s->operand->oprclass); - saved_indx = (mval *)malloc(SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed)); - saved_indx->mvtype = MV_STR; - ptr = (char *)saved_indx + SIZEOF(mval); - saved_indx->str.addr = ptr; - targ_key = (mname_entry *)ptr; - ptr += SIZEOF(mname_entry); - targ_key->var_name.addr = ptr; - len = s->operand[0].oprval.vref->mvname.len; - assert(SIZEOF(mident_fixed) > len); - memcpy(ptr, s->operand[0].oprval.vref->mvname.addr, len); - targ_key->var_name.len = len; - saved_indx->str.len = SIZEOF(mname_entry) + len; - COMPUTE_HASH_MNAME(targ_key); - targ_key->marked = FALSE; - MANAGE_FOR_INDX(frame_pointer, TREF(for_nest_level), saved_indx); - } + rval = lvn(&v, OC_PUTINDX, NULL); break; case TK_ATSIGN: if (EXPR_FAIL != (rval = indirection(&v))) /* NOTE assignment */ - { /* if the indirection nests, for_ctrl_indr_subs doesn't matter until we get the "real" lvn */ + { s = newtriple(OC_INDLVADR); s->operand[0] = v; v = put_tref(s); @@ -89,58 +70,9 @@ void op_indlvadr(mval *target) rval = EXPR_FAIL; break; } - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAD, &v, target->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAD, &v, NULL, target->str.len)) return; - /* before cache and execute, tack a little something on at end of object */ - assert(indir_src.str.addr == target->str.addr); - len = SIZEOF(uint4) * 2; - if (NULL != saved_indx) - len += SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed); /* overlength, but ends aligned */ - align_padlen = mstr_native_align ? PADLEN(stringpool.free, NATIVE_WSIZE) : 0; - len += align_padlen; - ptr = obj->addr + obj->len + align_padlen; - assert((char *)stringpool.free - align_padlen == ptr); - assert(ptr + len <= (char *)stringpool.top); /* ind_code, called by comp_fini, reserves to prevent gc */ - if (NULL != saved_indx) - { /* it's an unsubscripted name, so save the name infomation with the cached object */ - memcpy(ptr, (char *)saved_indx, SIZEOF(mval) + saved_indx->str.len); - ptr += (len - (SIZEOF(uint4) * 2)); - *(uint4 *)ptr = align_padlen; - } - ptr += SIZEOF(uint4); - *(uint4 *)ptr = len; - stringpool.free += len; - assert((ptr + SIZEOF(uint4)) == (char *)stringpool.free); - obj->len += len; - cache_put(&indir_src, obj); /* this copies the "extended" object to the cache */ - } else - { /* if cached, the object has stuff at the end that might need pulling into the run-time context */ - ptr = (char *)(obj->addr + obj->len); - len = *(uint4 *)(ptr - SIZEOF(uint4)); - if (SIZEOF(mval) < len) /* not nested and not subscripted ? */ - { /* grab the name information at the end of the cached indirect object and copy it to be useful to FOR */ - align_padlen = *(uint4 *)(ptr - (SIZEOF(uint4) * 2)); - assert(NATIVE_WSIZE > align_padlen); - assert(SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed) + (SIZEOF(uint4) * 2) - + NATIVE_WSIZE > len); - ptr -= (len + align_padlen); - saved_indx = (mval *)ptr; - assert(MV_STR == saved_indx->mvtype); - len = SIZEOF(mval) + saved_indx->str.len; - ptr = malloc(len); - memcpy(ptr, (char *)saved_indx, len); - saved_indx = (mval *)ptr; - ptr += SIZEOF(mval); - saved_indx->str.addr = ptr; - assert(MAX_MIDENT_LEN >= ((mname_entry *)(saved_indx->str.addr))->var_name.len); - assert((SIZEOF(mname_entry) + ((mname_entry *)(saved_indx->str.addr))->var_name.len) - == saved_indx->str.len); - ptr += SIZEOF(mname_entry); - ((mname_entry *)(saved_indx->str.addr))->var_name.addr = ptr; - len = SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed) + (SIZEOF(uint4) * 2); - assert(*(uint4 *)(obj->addr + obj->len - SIZEOF(uint4)) == len); - MANAGE_FOR_INDX(frame_pointer, TREF(for_nest_level), saved_indx); - } + cache_put(&indir_src, obj); } comp_indr(obj); return; diff --git a/sr_port/op_indlvarg.c b/sr_port/op_indlvarg.c index 4089f7f..a70005c 100644 --- a/sr_port/op_indlvarg.c +++ b/sr_port/op_indlvarg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,7 +19,6 @@ #include "op.h" #include "valid_mname.h" -error_def(ERR_INDMAXNEST); error_def(ERR_VAREXPECTED); void op_indlvarg(mval *v, mval *dst) @@ -27,13 +26,11 @@ void op_indlvarg(mval *v, mval *dst) icode_str indir_src; int rval; mstr *obj, object; - oprtype x; + oprtype x, getdst; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ MV_FORCE_STR(v); if (v->str.len < 1) rts_error(VARLSTCNT(1) ERR_VAREXPECTED); @@ -52,20 +49,20 @@ void op_indlvarg(mval *v, mval *dst) obj = &object; obj->addr = v->str.addr; obj->len = v->str.len; - comp_init(obj); + comp_init(obj, &getdst); if (EXPR_FAIL != (rval = indirection(&x))) /* NOTE assignment */ { ref = newtriple(OC_INDLVARG); ref->operand[0] = x; x = put_tref(ref); } - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, obj->len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, &getdst, obj->len)) return; indir_src.str.addr = v->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; /* Where to store return value */ + TREF(ind_result) = dst; /* Where to store return value */ comp_indr(obj); return; } diff --git a/sr_port/op_indlvnamadr.c b/sr_port/op_indlvnamadr.c index 0a258db..c238d3d 100644 --- a/sr_port/op_indlvnamadr.c +++ b/sr_port/op_indlvnamadr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,6 +17,7 @@ #include "cache.h" #include "hashtab_objcode.h" #include "op.h" +#include "advancewindow.h" error_def(ERR_VAREXPECTED); @@ -36,12 +37,13 @@ void op_indlvnamadr(mval *target) if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&target->str); + comp_init(&target->str, NULL); switch (TREF(window_token)) { case TK_IDENT: rval = EXPR_GOOD; v = put_mvar(&(TREF(window_ident))); + advancewindow(); break; case TK_ATSIGN: if (EXPR_FAIL != (rval = indirection(&v))) /* NOTE assignment */ @@ -56,7 +58,7 @@ void op_indlvnamadr(mval *target) rval = EXPR_FAIL; break; } - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAD, &v, target->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAD, &v, NULL, target->str.len)) return; indir_src.str.addr = target->str.addr; cache_put(&indir_src, obj); diff --git a/sr_port/op_indmerge.c b/sr_port/op_indmerge.c index de906b3..719bc82 100644 --- a/sr_port/op_indmerge.c +++ b/sr_port/op_indmerge.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,7 +34,6 @@ #include "hashtab_objcode.h" #include "stringpool.h" -error_def(ERR_INDMAXNEST); error_def(ERR_VAREXPECTED); void op_indmerge(mval *glvn_mv, mval *arg1_or_arg2) @@ -58,7 +57,7 @@ void op_indmerge(mval *glvn_mv, mval *arg1_or_arg2) if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&glvn_mv->str); + comp_init(&glvn_mv->str, NULL); switch (TREF(window_token)) { case TK_IDENT: @@ -93,7 +92,7 @@ void op_indmerge(mval *glvn_mv, mval *arg1_or_arg2) rval = EXPR_FAIL; break; } - if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, 0, glvn_mv->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, NULL, NULL, glvn_mv->str.len)) return; indir_src.str.addr = glvn_mv->str.addr; cache_put(&indir_src, obj); diff --git a/sr_port/op_indname.c b/sr_port/op_indname.c index 6462d86..2b03bff 100644 --- a/sr_port/op_indname.c +++ b/sr_port/op_indname.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,7 +11,6 @@ #include "mdef.h" -#include #include "gtm_string.h" #include "compiler.h" @@ -20,122 +19,38 @@ GBLREF spdesc stringpool; -void op_indname(UNIX_ONLY_COMMA(int argcnt) mval *dst, ...) +error_def(ERR_INDRMAXLEN); +error_def(ERR_STRINGOFLOW); +error_def(ERR_VAREXPECTED); + +void op_indname(mval *dst, mval *target, mval *subs) { - va_list var, sublst; - mval *src, *subs; int i; - VMS_ONLY(int argcnt;) - unsigned char *ch, *ctop, *out, *double_chk; - unsigned char outch; + unsigned char *out, *end, *start; - error_def(ERR_INDRMAXLEN); - error_def(ERR_STRINGOFLOW); - error_def(ERR_VAREXPECTED); - - VAR_START(var, dst); - VMS_ONLY(va_count(argcnt);) - - VAR_COPY(sublst, var); - src = va_arg(var, mval *); - for (i = argcnt - 1 ; i > 0 ; i-- ) - { - subs = va_arg(sublst, mval *); - MV_FORCE_STR(subs); - } - va_end(sublst); + MV_FORCE_STR(target); + MV_FORCE_STR(subs); ENSURE_STP_FREE_SPACE(MAX_SRCLINE); - out = stringpool.free; - if (out + src->str.len > stringpool.top) + start = out = stringpool.free; + if ((target->str.len + subs->str.len) > MAX_SRCLINE) rts_error(VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_SRCLINE); - if (src->str.len < 1) - rts_error(VARLSTCNT(1) ERR_VAREXPECTED); - memcpy(out , src->str.addr, src->str.len); - out += src->str.len - 1; - if (*stringpool.free == '@') + memcpy(out, target->str.addr, target->str.len); + out += target->str.len; + if (*start == '@') { - double_chk = stringpool.free + 1; - if (*double_chk == '@') - { - out++; - *out++ = '@'; - outch = '('; - } else - { - while(double_chk <= out) - if (*double_chk == '@') - break; - else - double_chk++; - - if (double_chk > out) - { - out++; - *out++ = '@'; - outch = '('; - } else if (*out != ')') - { - outch = '('; - out++; - } else - outch = ','; - } - } else if (*out != ')') - { - outch = '('; - out++; + *out++ = '@'; + *out++ = '#'; + *out++ = '('; } else - outch = ','; - VAR_COPY(sublst, var); - for (i = argcnt - 2 ; i > 0 ; i--) { - subs = va_arg(sublst, mval * ); - /* Note that in this second pass of the mvals, if the mval was undefined in the first pass and we are in - NOUNDEF mode, that the mval was not modified and is again undefined. Make sure this incarnation is defined.. - */ - MV_FORCE_DEFINED(subs); - ch = (unsigned char *)subs->str.addr; - ctop = ch + subs->str.len; - if (stringpool.top - out < subs->str.len + 5) - rts_error(VARLSTCNT(1) ERR_STRINGOFLOW); - *out++ = outch; - outch = ','; - *out++ = '"'; - for ( ; ch < ctop ; ch++) - { - if (*ch < 32) - { - if (stringpool.top - out < ctop - ch + 11) - rts_error(VARLSTCNT(1) ERR_STRINGOFLOW); - *out++ = '"'; - *out++ = '_'; - *out++ = '$'; - *out++ = 'C'; - *out++ = '('; - if (*ch > 9) - *out++ = (*ch / 10) + '0'; - *out++ = (*ch % 10) + '0'; - *out++ = ')'; - *out++ = '_'; - *out++ = '"'; - } else - { - if (*ch == '"') - { - if (stringpool.top - out < ctop - ch + 3) - rts_error(VARLSTCNT(1) ERR_STRINGOFLOW); - *out++ = '"'; - } - *out++ = *ch; - } - } - *out++ = '"'; + end = out - 1; + if (*end == ')') + *end = ','; /* replace trailing ')' with a comma since we're appending more subscripts */ + else + *out++ = '('; } - va_end(var); - va_end(sublst); - assert(out < stringpool.top); - assert(out > stringpool.free); - *out++ = ')'; + memcpy(out, subs->str.addr, subs->str.len); + out += subs->str.len; dst->mvtype = MV_STR; dst->str.addr = (char *)stringpool.free; dst->str.len = INTCAST((char *)out - dst->str.addr); diff --git a/sr_port/op_indo2.c b/sr_port/op_indo2.c index e71e87a..d04e8ac 100644 --- a/sr_port/op_indo2.c +++ b/sr_port/op_indo2.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,117 +11,62 @@ #include "mdef.h" -#include "toktyp.h" #include "compiler.h" #include "opcode.h" -#include "indir_enum.h" -#include "mdq.h" -#include "advancewindow.h" -#include "cache.h" -#include "hashtab_objcode.h" #include "op.h" -#include "fullbool.h" +#include "lv_val.h" +#include "mvalconv.h" +#include "glvn_pool.h" -error_def(ERR_INDMAXNEST); +error_def(ERR_ORDER2); error_def(ERR_VAREXPECTED); -void op_indo2(mval *dst, mval *target, mval *value) +void op_indo2(mval *dst, uint4 indx, mval *direct) { - icode_str indir_src; - int rval; - mstr *obj, object; - oprtype v, sav_opr; - triple *s, *src, *oldchain, tmpchain, *r; + glvn_pool_entry *slot; + int4 dummy_intval; + intszofptr_t n; + lv_val *lv; + mval *key; + opctype oc; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if ((TREF(ind_source_sp) >= TREF(ind_source_top)) || (TREF(ind_result_sp) >= TREF(ind_result_top))) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp & ind_source_sp */ - MV_FORCE_DEFINED(value); - MV_FORCE_STR(target); - indir_src.str = target->str; - indir_src.code = indir_fnorder2; - if (NULL == (obj = cache_get(&indir_src))) - { - obj = &object; - comp_init(&target->str); - src = newtriple(OC_IGETSRC); - s = maketriple(OC_NOOP); /* we'll fill it in as we go along */ - switch (TREF(window_token)) - { - case TK_IDENT: - if (TREF(director_token) != TK_LPAREN) - { - s->opcode = OC_FNLVNAMEO2; - s->operand[0] = put_str((TREF(window_ident)).addr,(TREF(window_ident)).len); - s->operand[1] = put_tref(src); - ins_triple(s); - advancewindow(); - rval = EXPR_GOOD; - break; - } - if (EXPR_FAIL != (rval = lvn(&s->operand[0], OC_SRCHINDX, s))) /* NOTE assignment */ - { - s->opcode = OC_FNO2; - sav_opr = s->operand[1]; - r = newtriple(OC_PARAMETER); - r->operand[0] = sav_opr; - r->operand[1] = put_tref(src); - s->operand[1] = put_tref(r); - ins_triple(s); - } - break; - case TK_CIRCUMFLEX: - if (EXPR_FAIL != (rval = gvn())) /* NOTE assignment */ - { - s->opcode = OC_GVO2; - s->operand[0] = put_tref(src); - ins_triple(s); - } - break; - case TK_ATSIGN: - TREF(saw_side_effect) = TREF(shift_side_effects); - if (TREF(shift_side_effects) && (GTM_BOOL == TREF(gtm_fullbool))) - { - dqinit(&tmpchain, exorder); - oldchain = setcurtchain(&tmpchain); - if (EXPR_FAIL != (rval = indirection(&s->operand[0]))) /* NOTE assignment */ - { - s->opcode = OC_INDO2; - s->operand[1] = put_tref(src); - ins_triple(s); - newtriple(OC_GVSAVTARG); - setcurtchain(oldchain); - dqadd(TREF(expr_start), &tmpchain, exorder); - TREF(expr_start) = tmpchain.exorder.bl; - r = newtriple(OC_GVRECTARG); - r->operand[0] = put_tref(TREF(expr_start)); - } else - setcurtchain(oldchain); - } else - { - if (EXPR_FAIL != (rval = indirection(&s->operand[0]))) /* NOTE assignment */ - { - s->opcode = OC_INDO2; - s->operand[1] = put_tref(src); - ins_triple(s); - } - } - break; - default: - stx_error(ERR_VAREXPECTED); - rval = FALSE; - break; + MV_FORCE_NUM(direct); + if (!MV_IS_TRUEINT(direct, &dummy_intval) || (direct->m[1] != (1 * MV_BIAS) && direct->m[1] != (-1 * MV_BIAS))) + rts_error(VARLSTCNT(1) ERR_ORDER2); + slot = &((TREF(glvn_pool_ptr))->slot[indx]); + oc = slot->sav_opcode; + if (OC_SAVLVN == oc) + { /* lvn */ + n = --slot->glvn_info.n; + if (0 == n) + { /* lvn name */ + slot->glvn_info.n++; /* quick restore count so glvnpop works correctly */ + /* like op_fnlvnameo2 */ + if ((1 * MV_BIAS) == direct->m[1]) + op_fnlvname(slot->lvname, FALSE, dst); + else + op_fnlvprvname(slot->lvname, dst); + } else + { /* subscripted lv */ + key = (mval *)slot->glvn_info.arg[n]; + lv = op_rfrshlvn(indx, OC_RFRSHLVN); /* funky opcode prevents UNDEF in rfrlvn */ + slot->glvn_info.n++; /* quick restore count so glvnpop works correctly */ + /* like op_fnno2 */ + if ((1 * MV_BIAS) == direct->m[1]) + op_fnorder(lv, key, dst); + else + op_fnzprevious(lv, key, dst); } - v = put_tref(s); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &v, target->str.len)) - return; - indir_src.str.addr = target->str.addr; - cache_put(&indir_src, obj); - /* Fall into code activation below */ + } else if (OC_NOOP != oc) /* if indirect error blew set up, skip this */ + { /* gvn */ + op_rfrshgvn(indx, oc); + /* like op_gvno2 */ + if ((1 * MV_BIAS) == direct->m[1]) + op_gvorder(dst); + else + op_zprevious(dst); } - *(TREF(ind_result_sp))++ = dst; - *(TREF(ind_source_sp))++ = value; - comp_indr(obj); return; } diff --git a/sr_port/op_indpat.c b/sr_port/op_indpat.c index b3d6b51..d01b8f2 100644 --- a/sr_port/op_indpat.c +++ b/sr_port/op_indpat.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,35 +21,31 @@ GBLREF short int source_column; -error_def(ERR_INDMAXNEST); - void op_indpat(mval *v, mval *dst) { int rval; icode_str indir_src; mstr *obj, object; - oprtype x; + oprtype x, getdst; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ MV_FORCE_STR(v); indir_src.str = v->str; indir_src.code = indir_pattern; if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&v->str); + comp_init(&v->str, &getdst); source_column = 1; /* to coordinate with scanner redirection*/ rval = compile_pattern(&x, (TK_ATSIGN == TREF(window_token))); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, v->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &x, &getdst, v->str.len)) return; indir_src.str.addr = v->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; /* Where to store return value */ + TREF(ind_result) = dst; /* Where to store return value */ comp_indr(obj); return; } diff --git a/sr_port/op_indrzshow.c b/sr_port/op_indrzshow.c index 1363006..5b6ea99 100644 --- a/sr_port/op_indrzshow.c +++ b/sr_port/op_indrzshow.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,7 +20,6 @@ #include "op.h" error_def(ERR_VAREXPECTED); -error_def(ERR_INDMAXNEST); void op_indrzshow(mval *s1, mval *s2) { @@ -32,15 +31,13 @@ void op_indrzshow(mval *s1, mval *s2) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_source_sp) >= TREF(ind_source_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_source_sp */ MV_FORCE_STR(s2); indir_src.str = s2->str; indir_src.code = indir_zshow; if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&s2->str); + comp_init(&s2->str, NULL); src = maketriple(OC_IGETSRC); ins_triple(src); switch(TREF(window_token)) @@ -83,14 +80,14 @@ void op_indrzshow(mval *s1, mval *s2) rval = EXPR_FAIL; break; } - if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, 0, s2->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, NULL, NULL, s2->str.len)) return; indir_src.str = s2->str; indir_src.code = indir_zshow; cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_source_sp))++ = s1; /* Where to store return value */ + TREF(ind_source) = s1; comp_indr(obj); return; } diff --git a/sr_port/op_indset.c b/sr_port/op_indset.c index 3af8021..d11ecb4 100644 --- a/sr_port/op_indset.c +++ b/sr_port/op_indset.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,12 +18,11 @@ #include "indir_enum.h" #include "cache.h" #include "op.h" -#include "rtnhdr.h" +#include #include "valid_mname.h" GBLREF symval *curr_symval; -error_def(ERR_INDMAXNEST); error_def(ERR_VAREXPECTED); void op_indset(mval *target, mval *value) @@ -55,10 +54,8 @@ void op_indset(mval *target, mval *value) ((lv_val *)tabent->value)->v = *value; return; } - if (TREF(ind_source_sp) >= TREF(ind_source_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_source_sp */ obj = &object; - comp_init(&target->str); + comp_init(&target->str, NULL); src = maketriple(OC_IGETSRC); ins_triple(src); switch (TREF(window_token)) @@ -94,13 +91,12 @@ void op_indset(mval *target, mval *value) rval = EXPR_FAIL; break; } - if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, 0, target->str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_RET, NULL, NULL, target->str.len)) return; indir_src.str.addr = target->str.addr; cache_put(&indir_src, obj); /* Fall into code activation below */ - } else if (TREF(ind_source_sp) >= TREF(ind_source_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_source_sp */ - *(TREF(ind_source_sp))++ = value; + } + TREF(ind_source) = value; comp_indr(obj); } diff --git a/sr_port/op_indtext.c b/sr_port/op_indtext.c index c5b18af..45c6b73 100644 --- a/sr_port/op_indtext.c +++ b/sr_port/op_indtext.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,7 +24,7 @@ #include "opcode.h" #include "stringpool.h" #include "toktyp.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" GBLREF unsigned char *source_buffer; @@ -33,7 +33,6 @@ GBLREF spdesc stringpool; GBLREF mv_stent *mv_chain; GBLREF unsigned char *msp, *stackwarn, *stacktop; -error_def(ERR_INDMAXNEST); error_def(ERR_STACKOFLOW); error_def(ERR_STACKCRIT); @@ -43,13 +42,11 @@ void op_indtext(mval *lab, mint offset, mval *rtn, mval *dst) int rval; mstr *obj, object; mval mv_off; - oprtype opt; + oprtype opt, getdst; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (TREF(ind_result_sp) >= TREF(ind_result_top)) - rts_error(VARLSTCNT(1) ERR_INDMAXNEST); /* mdbcondition_handler resets ind_result_sp */ MV_FORCE_STR(lab); indir_src.str.len = lab->str.len; indir_src.str.len += SIZEOF("+^") - 1; @@ -83,9 +80,9 @@ void op_indtext(mval *lab, mint offset, mval *rtn, mval *dst) if (NULL == (obj = cache_get(&indir_src))) { obj = &object; - comp_init(&indir_src.str); + comp_init(&indir_src.str, &getdst); rval = f_text(&opt, OC_FNTEXT); - if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &opt, indir_src.str.len)) + if (EXPR_FAIL == comp_fini(rval, obj, OC_IRETMVAL, &opt, &getdst, indir_src.str.len)) { assert(MVST_MVAL == mv_chain->mv_st_type); POP_MV_STENT(); @@ -95,7 +92,7 @@ void op_indtext(mval *lab, mint offset, mval *rtn, mval *dst) cache_put(&indir_src, obj); /* Fall into code activation below */ } - *(TREF(ind_result_sp))++ = dst; /* Where to store return value */ + TREF(ind_result) = dst; /* Where to store return value */ assert(MVST_MVAL == mv_chain->mv_st_type); POP_MV_STENT(); /* unwind the mval entry before the new frame gets added by comp_indir below */ comp_indr(obj); diff --git a/sr_port/op_iretmval.c b/sr_port/op_iretmval.c index a719a76..ecb1669 100644 --- a/sr_port/op_iretmval.c +++ b/sr_port/op_iretmval.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,16 +12,12 @@ #include "mdef.h" #include "op.h" -void op_iretmval(mval *v) +void op_iretmval(mval *v, mval *dst) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - (TREF(ind_result_sp))--; - assert(TREF(ind_result_sp) < TREF(ind_result_top)); - assert(TREF(ind_result_sp) >= TREF(ind_result_array)); - MV_FORCE_DEFINED(v); - **(TREF(ind_result_sp)) = *v; - (*(TREF(ind_result_sp)))->mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ + *dst = *v; + dst->mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ op_unwind(); } diff --git a/sr_port/op_killalias.c b/sr_port/op_killalias.c index 955be2b..2b3fc99 100644 --- a/sr_port/op_killalias.c +++ b/sr_port/op_killalias.c @@ -14,7 +14,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" diff --git a/sr_port/op_labaddr.c b/sr_port/op_labaddr.c index 544ba19..ab16ed2 100644 --- a/sr_port/op_labaddr.c +++ b/sr_port/op_labaddr.c @@ -17,7 +17,7 @@ #endif #include "cmd_qlf.h" -#include "rtnhdr.h" +#include #include "zbreak.h" error_def(ERR_LABELMISSING); diff --git a/sr_port/op_lock2.c b/sr_port/op_lock2.c index afe8d1b..815cafb 100644 --- a/sr_port/op_lock2.c +++ b/sr_port/op_lock2.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,6 +17,7 @@ #include "cmmdef.h" #include "gdsroot.h" #include "gt_timer.h" +#include "gtm_threadgbl.h" #include "iotimer.h" #include "locklits.h" #include "mlkdef.h" @@ -28,6 +29,7 @@ #include "mlk_unpend.h" #include "outofband.h" #include "lk_check_own.h" +#include "lock_str_to_buff.h" #include "gvcmx.h" #include "gvcmz.h" #include "rel_quant.h" @@ -36,23 +38,65 @@ #include "op.h" #include "mv_stent.h" #include "find_mvstent.h" +#include "gdskill.h" +#include "gdsbt.h" +#include "gtm_facility.h" +#include "gtm_maxstr.h" +#include "fileinfo.h" +#include "gdsfhead.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "io.h" +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" +#include "send_msg.h" +#include "gtmmsg.h" /* for gtm_putmsg() prototype */ +#include "change_reg.h" +#include "setterm.h" +#include "getzposition.h" +#ifdef DEBUG +#include "have_crit.h" /* for the TPNOTACID_CHECK macro */ +#endif -GBLREF bool out_of_time; -GBLREF bool remlkreq; GBLREF unsigned char cm_action; -GBLREF unsigned short lks_this_cmd; GBLREF uint4 dollar_tlevel; -GBLREF unsigned int t_tries; -GBLREF uint4 process_id; -GBLREF int4 outofband; +GBLREF uint4 dollar_trestart; +GBLREF unsigned short lks_this_cmd; GBLREF mlk_pvtblk *mlk_pvt_root; GBLREF mlk_stats_t mlk_stats; /* Process-private M-lock statistics */ -GBLREF unsigned char *restart_pc, *restart_ctxt; GBLREF mv_stent *mv_chain; +GBLREF int4 outofband; +GBLREF bool out_of_time; +GBLREF uint4 process_id; +GBLREF bool remlkreq; +GBLREF unsigned char *restart_ctxt, *restart_pc; +GBLREF unsigned int t_tries; + +error_def(ERR_LOCKINCR2HIGH); +error_def(ERR_LOCKIS); + +#define LOCKTIMESTR "LOCK time too long" +#define ZALLOCTIMESTR "ZALLOCATE time too long" + +/* We made this a error seperate function because we did not wanted to do the MAXSTR_BUFF_DECL(buff) declartion in op_lock2, + * because MAXSTR_BUFF_DECL macro would allocate a huge stack every time op_lock2 is called. + */ +STATICFNDCL void level_err(mlk_pvtblk *pvt_ptr); /* This definition is made here because there is no appropriate place to + * put this prototype. This will not be used anywhere else so we did not + * wanted to create a op_lock2.h just for this function. + */ +STATICFNDCL void level_err(mlk_pvtblk *pvt_ptr) +{ + MAXSTR_BUFF_DECL(buff); + MAXSTR_BUFF_INIT; + lock_str_to_buff(pvt_ptr, buff, MAX_STRBUFF_INIT); + rts_error(VARLSTCNT(7) ERR_LOCKINCR2HIGH, 1, pvt_ptr->level, ERR_LOCKIS, 2, LEN_AND_STR(buff)); +} /* * ----------------------------------------------- - * Maintain in parallel with op_zalloc2 * Arguments: * timeout - max. time to wait for locks before giving up * laflag - passed to gvcmx* routines as "laflag" argument; @@ -72,11 +116,11 @@ GBLREF mv_stent *mv_chain; */ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ { - bool blocked, timer_on; + boolean_t blocked, timer_on; signed char gotit; unsigned short locks_bckout, locks_done; int4 msec_timeout; /* timeout in milliseconds */ - mlk_pvtblk *pvt_ptr1, *pvt_ptr2, **prior; + mlk_pvtblk *pvt_ptr1, *pvt_ptr2, **prior, *already_locked; unsigned char action; ABS_TIME cur_time, end_time, remain_time; mv_stent *mv_zintcmd; @@ -85,9 +129,17 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ SETUP_THREADGBL_ACCESS; gotit = -1; cm_action = laflag; - timer_on = (NO_M_TIMEOUT != timeout); out_of_time = FALSE; - if (!timer_on) + if (timeout < 0) + timeout = 0; + else if (TREF(tpnotacidtime) < timeout) + { + if (CM_ZALLOCATES == cm_action) + TPNOTACID_CHECK(ZALLOCTIMESTR) + else + TPNOTACID_CHECK(LOCKTIMESTR) + } + if (!(timer_on = (NO_M_TIMEOUT != timeout))) /* NOTE assignment */ msec_timeout = NO_M_TIMEOUT; else { @@ -133,6 +185,8 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ } } lckclr(); + TREF(mlk_yield_pid) = 0; + already_locked = NULL; for (blocked = FALSE; !blocked;) { /* if this is a request for a remote node */ if (remlkreq) @@ -147,10 +201,15 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ break; } } + /* If we gave up the fairness algorithm at least once during this invocation of op_lock2(), continue with that until + * the end of op_lock2() + */ for (pvt_ptr1 = mlk_pvt_root, locks_done = 0; locks_done < lks_this_cmd; pvt_ptr1 = pvt_ptr1->next, locks_done++) { /* Go thru the list of all locks to be obtained attempting to lock - * each one. If any lock could not be obtained, break out of the loop */ - if (!mlk_lock(pvt_ptr1, 0, TRUE)) + * each one. If any lock could not be obtained, break out of the loop + * If the lock is already obtained, then skip that lock. + */ + if ((pvt_ptr1 == already_locked) || !mlk_lock(pvt_ptr1, 0, TRUE)) { /* If lock is obtained */ pvt_ptr1->granted = TRUE; switch (laflag) @@ -159,7 +218,13 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ pvt_ptr1->level = 1; break; case INCREMENTAL: - pvt_ptr1->level += pvt_ptr1->translev; + if (pvt_ptr1->level < 511) /* The same lock can not be incremented more than 511 times. */ + pvt_ptr1->level += pvt_ptr1->translev; + else + level_err(pvt_ptr1); + break; + case CM_ZALLOCATES: + pvt_ptr1->zalloc = TRUE; break; default: GTMASSERT; @@ -183,7 +248,8 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ action = LOCKED; break; case INCREMENTAL: - action = INCREMENTAL; + case CM_ZALLOCATES: + action = cm_action; break; default: GTMASSERT; @@ -196,14 +262,12 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ mlk_bckout(pvt_ptr2, action); } if (dollar_tlevel && (CDB_STAGNATE <= t_tries)) - { - mlk_unpend(pvt_ptr1); /* Eliminated the dangling request block */ - if (timer_on && !out_of_time) - { - cancel_timer((TID)&timer_on); - timer_on = FALSE; - } - t_retry(cdb_sc_needlock); /* release crit to prevent a deadlock */ + { /* upper TPNOTACID_CHECK conditioned on no short timeout; this one rel_crits to avoid potential deadlock */ + assert(TREF(tpnotacidtime) >= timeout); + if (CM_ZALLOCATES == action) + TPNOTACID_CHECK(ZALLOCTIMESTR) + else + TPNOTACID_CHECK(LOCKTIMESTR) } for (;;) { @@ -220,14 +284,14 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ gvcmz_clrlkreq(); remlkreq = FALSE; } - if (outofband) + if (outofband && !out_of_time) { - if (timer_on && !out_of_time) + if (timer_on) { cancel_timer((TID)&timer_on); timer_on = FALSE; } - if (!out_of_time && (NO_M_TIMEOUT != timeout)) + if (NO_M_TIMEOUT != timeout) { /* get remain = end_time - cur_time */ sys_get_curr_time(&cur_time); remain_time = sub_abs_time(&end_time, &cur_time); @@ -242,41 +306,59 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ timer_on = FALSE; /* as if LOCK :0 */ break; } - PUSH_MV_STENT(MVST_ZINTCMD); - mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = remain_time; - mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt; - mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc; - /* save current information from zintcmd_active */ - mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior - = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last; - mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior - = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last; - TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = restart_pc; - TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last = restart_ctxt; - TAREF1(zintcmd_active, ZINTCMD_LOCK).count++; - mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_LOCK; + if ((tptimeout != outofband) && (ctrlc != outofband)) + { + PUSH_MV_STENT(MVST_ZINTCMD); + mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = remain_time; + mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt; + mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc; + /* save current information from zintcmd_active */ + mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior + = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last; + mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior + = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last; + TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = restart_pc; + TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last + = restart_ctxt; + TAREF1(zintcmd_active, ZINTCMD_LOCK).count++; + mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_LOCK; + } + outofband_action(FALSE); /* no return */ + } else outofband_action(FALSE); /* no return */ - } } break; } } + /* Sleep first before reattempting a blocked lock. Note: this is used by the lock fairness algorithm + * in mlk_shrblk_find. If mlk_lock is invoked for the second (or higher) time in op_lock2 for the + * same lock resource, "mlk_shrblk_find" assumes a sleep has happened in between two locking attempts. + */ + hiber_start_wait_any(LOCK_SELF_WAKE); + /* Note that "TREF(mlk_yield_pid)" is not initialized here as we want to use any value inherited + * from previous calls to mlk_lock for this lock. + */ if (!mlk_lock(pvt_ptr1, 0, FALSE)) { /* If we got the lock, break out of timer loop */ blocked = FALSE; + if (MLK_FAIRNESS_DISABLED != TREF(mlk_yield_pid)) + TREF(mlk_yield_pid) = 0; /* Allow yielding for the other locks */ if (pvt_ptr1 != mlk_pvt_root) { rel_quant(); /* attempt to get a full timeslice for maximum chance to get all */ mlk_unlock(pvt_ptr1); - } + already_locked = NULL; + } else + already_locked = pvt_ptr1; break; } if (pvt_ptr1->nodptr) lk_check_own(pvt_ptr1); /* clear an abandoned owner */ - hiber_start_wait_any(LOCK_SELF_WAKE); } if (blocked && out_of_time) break; + if (locks_bckout) + TREF(mlk_yield_pid) = MLK_FAIRNESS_DISABLED; /* Disable fairness to avoid livelocks */ } if (remlkreq) { @@ -304,3 +386,4 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ mlk_stats.n_user_locks_success++; return (TRUE); } + diff --git a/sr_port/op_merge.c b/sr_port/op_merge.c index 91a807f..4a63f89 100644 --- a/sr_port/op_merge.c +++ b/sr_port/op_merge.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,7 @@ #include "min_max.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "gdsroot.h" #include "gdskill.h" @@ -75,9 +75,11 @@ } \ } +GBLREF sgmnt_addrs *cs_addrs; GBLREF mv_stent *mv_chain; GBLREF unsigned char *msp, *stackwarn, *stacktop; GBLREF int4 outofband; +GBLREF uint4 dollar_tlevel; GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF zshow_out *zwr_output; @@ -95,7 +97,7 @@ error_def(ERR_STACKOFLOW); void op_merge(void) { - boolean_t found, check_for_null_subs, is_base_var; + boolean_t found, check_for_null_subs, is_base_var, nontp_and_bgormm; lv_val *dst_lv; mval *mkey, *value, *subsc; int org_glvn1_keysz, org_glvn2_keysz, delta2, dollardata_src, dollardata_dst, sbs_depth; @@ -135,6 +137,9 @@ void op_merge(void) merge_args = 0; /* Must reset to zero to reuse the Global */ return; } + nontp_and_bgormm = ((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)) + && !dollar_tlevel; + assert(!nontp_and_bgormm || gv_target->root); if (NULL == TREF(gv_mergekey2)) { /* We need to initialize gvn2 (right hand side). */ GVKEY_INIT(TREF(gv_mergekey2), DBKEYSIZE(MAX_KEY_SZ)); @@ -188,6 +193,18 @@ void op_merge(void) gv_currkey->base[gv_currkey->end + 1] = 0; gv_currkey->base[gv_currkey->end + 2] = 0; gv_currkey->end += 2; +# ifdef UNIX + if (nontp_and_bgormm && (0 == gv_target->root)) + { /* This is to handle root blocks moved by REORG. Merge alternates between two + * different gv_targets. If op_gvput below detects a moved root block, it will + * set the root of both to zero, but it will only redo root search for IND1. + * We want op_gvqueryget to redo root search for IND2, so we fake its root + * which will get it far enough to do so. + */ + cs_addrs->root_search_cycle--; + gv_target->root = 2; + } +# endif /* Do atomic $QUERY and $GET of current glvn2: * mkey is a mstr which contains $QUERY result in database format (So no conversion necessary) * value is a mstr which contains $GET result diff --git a/sr_port/op_newvar.c b/sr_port/op_newvar.c index 211900d..caeec16 100644 --- a/sr_port/op_newvar.c +++ b/sr_port/op_newvar.c @@ -15,7 +15,7 @@ #include "gtm_string.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "tp_frame.h" diff --git a/sr_port/op_oldvar.c b/sr_port/op_oldvar.c index a8a1bea..c0fc283 100644 --- a/sr_port/op_oldvar.c +++ b/sr_port/op_oldvar.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "op.h" #include "error.h" diff --git a/sr_port/op_open.c b/sr_port/op_open.c index 6112ede..88569c7 100644 --- a/sr_port/op_open.c +++ b/sr_port/op_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,30 +18,58 @@ #include "op.h" #include "trans_log_name.h" +#include "gdsroot.h" +#include "gdskill.h" +#include "gdsbt.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsfhead.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" +#include "send_msg.h" +#include "gtmmsg.h" /* for gtm_putmsg() prototype */ +#include "change_reg.h" +#include "setterm.h" +#include "getzposition.h" +#ifdef DEBUG +#include "have_crit.h" /* for the TPNOTACID_CHECK macro */ +#endif + +GBLREF uint4 dollar_trestart; +GBLREF io_log_name *io_root_log_name; GBLREF bool licensed; GBLREF int4 lkid, lid; -GBLREF io_log_name *io_root_log_name; + +LITREF unsigned char io_params_size[]; + +error_def(ERR_LOGTOOLONG); +error_def(LP_NOTACQ); /* bad license */ + +#define OPENTIMESTR "OPEN time too long" int op_open(mval *device, mval *devparms, int timeout, mval *mspace) { - LITREF unsigned char io_params_size[]; char buf1[MAX_TRANS_NAME_LEN]; /* buffer to hold translated name */ io_log_name *naml; /* logical record for passed name */ io_log_name *tl; /* logical record for translated name */ io_log_name *prev; /* logical record for removal search */ int4 stat; /* status */ mstr tn; /* translated name */ + DCL_THREADGBL_ACCESS; - error_def(ERR_LOGTOOLONG); - error_def(LP_NOTACQ); /* bad license */ - + SETUP_THREADGBL_ACCESS; MV_FORCE_STR(device); MV_FORCE_STR(devparms); if (mspace) MV_FORCE_STR(mspace); - if (timeout < 0) timeout = 0; + else if (TREF(tpnotacidtime) < timeout) + TPNOTACID_CHECK(OPENTIMESTR); assert((unsigned char)*devparms->str.addr < n_iops); naml = get_log_name(&device->str, INSERT); if (naml->iod != 0) diff --git a/sr_port/op_putindx.c b/sr_port/op_putindx.c index e3e892a..f7fe905 100644 --- a/sr_port/op_putindx.c +++ b/sr_port/op_putindx.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 "alias.h" #include "compiler.h" #include "callg.h" -#include "rtnhdr.h" +#include #include "toktyp.h" #include "valid_mname.h" #include "stack_frame.h" @@ -161,101 +161,3 @@ lv_val *op_putindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...) active_lv = lv; return lv; } - -/* this tucks all the information needed to reaccess a subscripted FOR control variable into a single mval - * so that op_rfrshindx can later either replace the control variable or determine it was ditched in the scope of the loop - * the saved information hangs off the stack because the compiler doesn't seem to have a way (assembly modules possible - * excepted) to manage an mval pointer and no where else provides a stable enough anchor - */ -lv_val *op_savputindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...) -{ /* this saves the arguments as statics and then does a putindx */ - char *c, *ptr; - lvname_info_ptr lvn_info; - lv_val *lv; - mname_entry *targ_key; - mval *key, *saved_indx; - uint4 subs_level, total_len; - va_list var; - VMS_ONLY(int argcnt;) - DCL_THREADGBL_ACCESS; - - SETUP_THREADGBL_ACCESS; - VAR_START(var, start); - VMS_ONLY(va_count(argcnt);) - assert(0 < argcnt); - assert(NULL != start); - total_len = SIZEOF(mval) + SIZEOF(mname_entry) + SIZEOF(mident_fixed) + SIZEOF(lvname_info); - total_len += (SIZEOF(mval) * (argcnt - 1)); - saved_indx = (mval *)malloc(total_len); - ptr = (char *)saved_indx + SIZEOF(mval); - saved_indx->mvtype = MV_STR; - saved_indx->str.addr = (char *)ptr; - saved_indx->str.len = total_len - SIZEOF(mval); - targ_key = (mname_entry *)ptr; - ptr += SIZEOF(mname_entry); - targ_key->var_name.addr = (char *)ptr; - ptr += SIZEOF(mident_fixed); - lvn_info = (lvname_info_ptr)ptr; - ptr += SIZEOF(lvname_info); - lvn_info->total_lv_subs = argcnt--; - assert((0 <= argcnt) && (MAX_FORARGS > argcnt)); - lvn_info->start_lvp = start; - for (subs_level = 0; subs_level < argcnt; subs_level++) - { - key = va_arg(var, mval *); - lvn_info->lv_subs[subs_level] = (mval *)ptr; - *(mval *)ptr = *(mval *)key; - ptr += SIZEOF(mval); - } - assert((char *)saved_indx + total_len >= ptr); - va_end(var); - lv = (lv_val *)callg((INTPTR_T (*)(intszofptr_t argcnt_arg, ...))op_putindx, (gparam_list *)lvn_info); - c = (char *)format_lvname(start, (unsigned char *)targ_key->var_name.addr, SIZEOF(mident_fixed)); - assert((c < ptr) && (c > (char *)targ_key->var_name.addr)); - targ_key->var_name.len = c - targ_key->var_name.addr; - COMPUTE_HASH_MNAME(targ_key) - targ_key->marked = FALSE; - MANAGE_FOR_INDX(frame_pointer, TREF(for_nest_level), saved_indx); - return lv; -} -/* this fishs out values saved by op_savputindx or op_indlvaddr, looks up the variable using add_hashtab_mname_symval and calls - * op_putindx or op_srchtindx as appropriate protecting the long-lived FOR control variable from subsequent actons on the line - */ -lv_val *op_rfrshindx(uint4 level, boolean_t put) -{ - boolean_t added; - ht_ent_mname *tabent; - lvname_info_ptr lvn_info; - lv_val *lv; - mname_entry *targ_key; - mval *saved_indx; - unsigned char buff[512], *end; - DCL_THREADGBL_ACCESS; - - SETUP_THREADGBL_ACCESS; - saved_indx = frame_pointer->for_ctrl_stack->saved_for_indx[level]; - assert(MV_STR & saved_indx->mvtype); - targ_key = (mname_entry *)saved_indx->str.addr; - assert((mname_entry *)((char *)saved_indx + SIZEOF(mval)) == targ_key); - assert((char *)targ_key + SIZEOF(mname_entry) == targ_key->var_name.addr); - assert(SIZEOF(mident_fixed) > targ_key->var_name.len); - added = add_hashtab_mname_symval(&curr_symval->h_symtab, targ_key, NULL, &tabent); - lvn_info = (lvname_info_ptr)((char *)targ_key + SIZEOF(mname_entry) + SIZEOF(mident_fixed)); - if ((saved_indx->str.addr + saved_indx->str.len) < (char *)lvn_info) - { /* Only a name */ - assert((SIZEOF(mname_entry) + ((mname_entry *)(saved_indx->str.addr))->var_name.len) == saved_indx->str.len); - if (put || MV_DEFINED((mval *)tabent->value)) - return (lv_val *)tabent->value; - rts_error(VARLSTCNT(4) ERR_UNDEF, 2, targ_key->var_name.len, targ_key->var_name.addr); - } - lvn_info->start_lvp = (lv_val *)tabent->value; - lv = (added && !put) ? NULL : (lv_val *)callg((INTPTR_T (*)(intszofptr_t argcnt_arg, ...))(put ? op_putindx : op_srchindx), - (gparam_list *)lvn_info); - assert(NULL != lv || !put); - if ((NULL != lv) && (put || LV_IS_VAL_DEFINED(lv))) - return lv; - end = format_key_mvals(buff, SIZEOF(buff), lvn_info); - rts_error(VARLSTCNT(4) ERR_UNDEF, 2, end - buff, buff); - assert(FALSE); /* should not come back from rts error */ - return lv; /* make some compilers happy */ -} diff --git a/sr_port/op_read.c b/sr_port/op_read.c index d342825..8f7dd80 100644 --- a/sr_port/op_read.c +++ b/sr_port/op_read.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,10 +18,36 @@ #include "op.h" #include "ebc_xlat.h" +#include "gdsroot.h" +#include "gdskill.h" +#include "gdsbt.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsfhead.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" +#include "send_msg.h" +#include "gtmmsg.h" /* for gtm_putmsg() prototype */ +#include "change_reg.h" +#include "setterm.h" +#include "getzposition.h" +#ifdef DEBUG +#include "have_crit.h" /* for the TPNOTACID_CHECK macro */ +#endif + +GBLREF uint4 dollar_trestart; GBLREF io_pair io_curr_device; GBLREF io_desc *active_device; GBLREF spdesc stringpool; +error_def(ERR_TEXT); + +#define READTIMESTR "READ time too long" + int op_read(mval *v, int4 timeout) { int stat; @@ -29,18 +55,21 @@ int op_read(mval *v, int4 timeout) size_t cnt, insize, outsize; unsigned char *temp_ch; char *start_ptr, *save_ptr; - error_def(ERR_TEXT); + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (timeout < 0) timeout = 0; + else if (TREF(tpnotacidtime) < timeout) + TPNOTACID_CHECK(READTIMESTR); active_device = io_curr_device.in; v->mvtype = MV_STR; v->str.len = 0; stat = (io_curr_device.in->disp_ptr->read)(v, timeout); - if (stringpool.free == (unsigned char *)v->str.addr) + if (stringpool.free == (unsigned char *)v->str.addr) /* BYPASSOK */ stringpool.free += v->str.len; /* see UNIX iott_readfl */ assert(stringpool.free <= stringpool.top); -#ifdef KEEP_zOS_EBCDIC +# ifdef KEEP_zOS_EBCDIC if (DEFAULT_CODE_SET != io_curr_device.in->in_code_set) { cnt = insize = outsize = v->str.len; @@ -55,7 +84,7 @@ int op_read(mval *v, int4 timeout) ICONVERT(io_curr_device.in->input_conv_cd, (unsigned char **)&v->str.addr, &insize, &temp_ch, &outsize); v->str.addr = start_ptr; } -#endif +# endif active_device = 0; if (NO_M_TIMEOUT != timeout) return(stat); diff --git a/sr_port/op_readfl.c b/sr_port/op_readfl.c index 0e67909..3b1dd39 100644 --- a/sr_port/op_readfl.c +++ b/sr_port/op_readfl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,6 +22,10 @@ GBLREF spdesc stringpool; GBLREF io_desc *active_device; GBLREF boolean_t gtm_utf8_mode; +error_def(ERR_TEXT); +error_def(ERR_RDFLTOOSHORT); +error_def(ERR_RDFLTOOLONG); + int op_readfl(mval *v, int4 length, int4 timeout) { int4 stat; /* status */ @@ -29,33 +33,31 @@ int op_readfl(mval *v, int4 length, int4 timeout) char *start_ptr, *save_ptr; unsigned char *temp_ch; int b_length; - error_def(ERR_TEXT); - error_def(ERR_RDFLTOOSHORT); - error_def(ERR_RDFLTOOLONG); if (timeout < 0) timeout = 0; - /* length is in units of characters, MAX_STRLEN and allocation unit in stp is bytes. Compute the worst case need in bytes */ - /* worst case, every Unicode char is 4 bytes */ + /* Length is in units of characters, MAX_STRLEN and allocation unit in stp is bytes. Compute the worst case need in bytes. + * Worst case, every Unicode char is 4 bytes + */ b_length = (!IS_UTF_CHSET(io_curr_device.in->ichset)) ? length : (length * 4); - if (length <= 0) + if (0 >= length) rts_error(VARLSTCNT(1) ERR_RDFLTOOSHORT); - if (length > MAX_STRLEN) /* this check is more useful in "M" mode. For UTF-8 mode, checks have to be done while reading */ + /* This check is more useful in "M" mode. For UTF-8 mode, checks have to be done while reading */ + if (MAX_STRLEN < length) rts_error(VARLSTCNT(1) ERR_RDFLTOOLONG); assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); - ENSURE_STP_FREE_SPACE(b_length + ESC_LEN); v->mvtype = MV_STR; + v->str.len = 0; /* Nothing kept from any old value */ + ENSURE_STP_FREE_SPACE(b_length + ESC_LEN); v->str.addr = (char *)stringpool.free; - v->str.len = 0; active_device = io_curr_device.in; stat = (io_curr_device.in->disp_ptr->readfl)(v, length, timeout); - if (stringpool.free == (unsigned char *)v->str.addr) + if (stringpool.free == (unsigned char *)v->str.addr) /* BYPASSOK */ stringpool.free += v->str.len; /* see UNIX iott_readfl */ assert((int4)v->str.len <= b_length); assert(stringpool.free <= stringpool.top); - -#if defined(KEEP_zOS_EBCDIC) || defined(VMS) +# if defined(KEEP_zOS_EBCDIC) || defined(VMS) if (DEFAULT_CODE_SET != active_device->in_code_set) { cnt = insize = outsize = v->str.len; @@ -67,13 +69,10 @@ int op_readfl(mval *v, int4 length, int4 timeout) stringpool.free += cnt; assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); - ICONVERT(active_device->input_conv_cd, (unsigned char **)&(v->str.addr), &insize, &temp_ch, &outsize); - v->str.addr = start_ptr; } -#endif - +# endif active_device = 0; if (NO_M_TIMEOUT != timeout) return (stat); diff --git a/sr_port/op_rhdaddr.c b/sr_port/op_rhdaddr.c index e5b3475..4a7b3b6 100644 --- a/sr_port/op_rhdaddr.c +++ b/sr_port/op_rhdaddr.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "op.h" GBLREF mident_fixed zlink_mname; diff --git a/sr_port/op_setals2als.c b/sr_port/op_setals2als.c index 4378250..f155c0b 100644 --- a/sr_port/op_setals2als.c +++ b/sr_port/op_setals2als.c @@ -14,7 +14,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" diff --git a/sr_port/op_setalsctin2als.c b/sr_port/op_setalsctin2als.c index c4d9d82..58b80fa 100644 --- a/sr_port/op_setalsctin2als.c +++ b/sr_port/op_setalsctin2als.c @@ -14,7 +14,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" diff --git a/sr_port/op_setalsin2alsct.c b/sr_port/op_setalsin2alsct.c index d7a2a4e..17fbf41 100644 --- a/sr_port/op_setalsin2alsct.c +++ b/sr_port/op_setalsin2alsct.c @@ -14,7 +14,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" diff --git a/sr_port/op_setfnretin2als.c b/sr_port/op_setfnretin2als.c index 6531f24..89283ac 100644 --- a/sr_port/op_setfnretin2als.c +++ b/sr_port/op_setfnretin2als.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 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 "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "lv_val.h" @@ -60,14 +60,10 @@ void op_setfnretin2als(mval *srcmv, int destindx) int4 srcsymvlvl; boolean_t added; - error_def(ERR_ALIASEXPECTED); - assert(alias_retarg == srcmv); assert(srcmv); assert(srcmv->mvtype & MV_ALIASCONT); - /* Verify is a temp mval */ - assert((char *)srcmv >= (char *)frame_pointer->temps_ptr - && (char *)srcmv < ((char *)frame_pointer->temps_ptr + (SIZEOF(char *) * frame_pointer->temp_mvals))); + assert(MVAL_IN_RANGE(srcmv, frame_pointer->temps_ptr, frame_pointer->temp_mvals)); /* Verify is a temp mval */ srclvc = (lv_val *)srcmv->str.addr; assert(srclvc); assert(LV_IS_BASE_VAR(srclvc)); /* Verify base var */ diff --git a/sr_port/op_setfnretin2alsct.c b/sr_port/op_setfnretin2alsct.c index 4390fb1..8f6b1df 100644 --- a/sr_port/op_setfnretin2alsct.c +++ b/sr_port/op_setfnretin2alsct.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,9 +50,7 @@ void op_setfnretin2alsct(mval *srcmv, lv_val *dstlv) assert(srcmv == alias_retarg); assert(!LV_IS_BASE_VAR(dstlv)); /* Verify subscripted var */ assert(srcmv->mvtype & MV_ALIASCONT); - /* Verify is a temp mval */ - assert((char *)srcmv >= (char *)frame_pointer->temps_ptr - && (char *)srcmv < ((char *)frame_pointer->temps_ptr + (SIZEOF(char *) * frame_pointer->temp_mvals))); + assert(MVAL_IN_RANGE(srcmv, frame_pointer->temps_ptr, frame_pointer->temp_mvals)); /* Verify is a temp mval */ assert(MV_IS_STRING(srcmv) && (0 == srcmv->str.len)); src_lvref = (lv_val *)srcmv->str.addr; assert(src_lvref); diff --git a/sr_port/op_setzbrk.c b/sr_port/op_setzbrk.c index b6c7bb1..3fbfd96 100644 --- a/sr_port/op_setzbrk.c +++ b/sr_port/op_setzbrk.c @@ -15,7 +15,7 @@ #include "gtm_stdio.h" #include "cache.h" -#include "rtnhdr.h" +#include #include "zbreak.h" #include "stack_frame.h" #include "xfer_enum.h" diff --git a/sr_port/op_setzextract.c b/sr_port/op_setzextract.c index 4d09c31..3cce1a1 100644 --- a/sr_port/op_setzextract.c +++ b/sr_port/op_setzextract.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2009 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,6 +18,8 @@ GBLREF spdesc stringpool; +error_def(ERR_MAXSTRLEN); + /* * ---------------------------------------------------------- * Set version of $extract @@ -33,14 +35,12 @@ GBLREF spdesc stringpool; * none * ---------------------------------------------------------- */ - void op_setzextract(mval *src, mval *expr, int schar, int echar, mval *dst) { - int srclen, padlen, pfxlen, sfxoff, sfxlen, strlen; + size_t strlen, padlen; + int pfxlen, sfxoff, sfxlen, srclen; unsigned char *srcptr, *pfx, *straddr; - error_def(ERR_MAXSTRLEN); - padlen = pfxlen = sfxlen = 0; MV_FORCE_STR(expr); /* Expression to put into piece place */ if (MV_DEFINED(src)) @@ -48,23 +48,21 @@ void op_setzextract(mval *src, mval *expr, int schar, int echar, mval *dst) MV_FORCE_STR(src); /* Make sure is string prior to length check */ srclen = src->str.len; } else - { /* Source is not defined -- treat as a null string */ + /* Source is not defined -- treat as a null string */ srclen = 0; - } schar = MAX(schar, 1); /* schar starts at 1 at a minimum */ - /* There are four cases in the spec: - - 1) schar > echar or echar < 1 -- glvn and naked indicator are not changed. This is - handled by generated code in m_set - 2) echar '< schar-1 > srclen -- dst = src_$J("",schar-1-srclen)_expr - 3) schar-1 '> srclen < echar -- dst = $E(src,1,schar-1)_expr - 4) All others -- dst = $E(src,1,schar-1)_expr_$E(src,echar+1,srclen) - */ + * + * 1) schar > echar or echar < 1 -- glvn and naked indicator are not changed. This is + * handled by generated code in m_set + * 2) echar '< schar-1 > srclen -- dst = src_$J("",schar-1-srclen)_expr + * 3) schar-1 '> srclen < echar -- dst = $E(src,1,schar-1)_expr + * 4) All others -- dst = $E(src,1,schar-1)_expr_$E(src,echar+1,srclen) + */ if ((schar - 1) > srclen) { /* Case #2 -- echar test handled in generated code */ pfxlen = srclen; - padlen = schar - 1 - srclen; + padlen = (size_t)schar - 1 - (size_t)srclen; /* Note, no suffix, just expr after the padlen */ } else { /* (schar-1) <= srclen) (Case #3 and common part of Default case) */ @@ -76,42 +74,36 @@ void op_setzextract(mval *src, mval *expr, int schar, int echar, mval *dst) sfxlen = srclen - echar; } } - /* Calculate total string len. delim_cnt has needed padding delimiters for null fields */ - strlen = pfxlen + padlen + expr->str.len + sfxlen; - if (strlen > MAX_STRLEN) + strlen = (size_t)pfxlen + padlen + (size_t)expr->str.len + (size_t)sfxlen; + if (MAX_STRLEN < strlen) rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); - ENSURE_STP_FREE_SPACE(strlen); + ENSURE_STP_FREE_SPACE((int)strlen); pfx = (unsigned char *)src->str.addr; straddr = stringpool.free; - /* copy prefix */ if (0 < pfxlen) { memcpy(straddr, pfx, pfxlen); straddr += pfxlen; } - /* insert padding */ - while (padlen-- > 0) + while (0 < padlen--) *straddr++ = ' '; - /* copy expression */ if (0 < expr->str.len) { memcpy(straddr, expr->str.addr, expr->str.len); straddr += expr->str.len; } - /* copy suffix */ if (0 < sfxlen) { memcpy(straddr, pfx + sfxoff, sfxlen); straddr += sfxlen; } - - assert(straddr - stringpool.free == strlen); + assert((straddr - stringpool.free) == strlen); dst->mvtype = MV_STR; dst->str.len = INTCAST(straddr - stringpool.free); dst->str.addr = (char *)stringpool.free; diff --git a/sr_port/op_setzp1.c b/sr_port/op_setzp1.c index 5bec056..12788eb 100644 --- a/sr_port/op_setzp1.c +++ b/sr_port/op_setzp1.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,6 +34,8 @@ GBLREF int cs_small_pcs; /* chars scanned by small scan */ # define INCR_COUNT(x,y) #endif +error_def(ERR_MAXSTRLEN); + /* * ---------------------------------------------------------- * Fast path setzpiece when delimiter is one (lit) char replacing @@ -52,7 +54,8 @@ GBLREF int cs_small_pcs; /* chars scanned by small scan */ */ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) { - int len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, str_len, delim_cnt, pfx_scan_offset; + size_t str_len, delim_cnt; + int len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, pfx_scan_offset; int cpy_cache_lines; unsigned char ldelimc, lc, *start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx; boolean_t do_scan; @@ -61,38 +64,34 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) delimfmt ldelim; DCL_THREADGBL_ACCESS; - error_def(ERR_MAXSTRLEN); - SETUP_THREADGBL_ACCESS; ldelim.unichar_val = delim; /* Local copys (in unsigned char and integer formats) */ ldelimc = ldelim.unibytes_val[0]; - do_scan = FALSE; cpy_cache_lines = -1; - MV_FORCE_STR(expr); /* Expression to put into piece place */ if (MV_DEFINED(src)) { /* We have 3 possible scenarios: - - 1) The source string is null. Nothing to do but proceed to building output. - 2) If the requested piece is larger than can be cached by op_fnzp1, call fnzp1 - for the maximum piece possible, use the cache info to "prime the pump" and - then process the rest of the string ourselves. - 3) If the requested piece can be obtained from the cache, call op_fnzp1 to validate - and rebuild the cache if necessary and then retrieve the necessary info from - the fnpc cache. - */ + * + * 1) The source string is null. Nothing to do but proceed to building output. + * 2) If the requested piece is larger than can be cached by op_fnzp1, call fnzp1 + * for the maximum piece possible, use the cache info to "prime the pump" and + * then process the rest of the string ourselves. + * 3) If the requested piece can be obtained from the cache, call op_fnzp1 to validate + * and rebuild the cache if necessary and then retrieve the necessary info from + * the fnpc cache. + */ MV_FORCE_STR(src); /* Make sure is string prior to length check */ if (0 == src->str.len) { /* We have a null source string */ pfx_str_len = sfx_str_len = sfx_start_offset = 0; - delim_cnt = ind - 1; + delim_cnt = (0 < ind) ? (size_t)ind - 1 : 0; } else if (FNPC_ELEM_MAX >= ind) { /* 3) Best of all possible cases. The op_fnzp1 can do most of our work for us - and we can preload the cache on the new string to help its subsequent - uses along as well. - */ + * and we can preload the cache on the new string to help its subsequent + * uses along as well. + */ SETWON; op_fnzp1(src, delim, ind, &dummymval); SETWOFF; @@ -102,8 +101,8 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) assert(cfnpc->delim == ldelim.unichar_val); assert(0 < cfnpc->npcs); /* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran - out of text or #3 piece is beyond what can be cached - */ + * out of text or #3 piece is beyond what can be cached + */ if (cfnpc->npcs >= ind) { /* #1 The piece we want is totally within the cache which is good news */ pfx_str_len = cfnpc->pstart[ind - 1]; @@ -114,10 +113,10 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) cpy_cache_lines = ind - 1; } else { /* #2 The string was too short so the cache does not contain our string. This means - that the prefix becomes any text that IS in the cache and we set the delim_cnt - to be the number of missing pieces so the delimiters can be put in as part of the - prefix when we build the new string. - */ + * that the prefix becomes any text that IS in the cache and we set the delim_cnt + * to be the number of missing pieces so the delimiters can be put in as part of the + * prefix when we build the new string. + */ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1; delim_cnt = ind - cfnpc->npcs; sfx_start_offset = 0; @@ -126,9 +125,9 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) } } else { /* 2) We have a element that would not be able to be in the fnpc cache. Go ahead - and call op_fnzp1 to get cache info up to the maximum and then we will continue - the scan on our own. - */ + * and call op_fnzp1 to get cache info up to the maximum and then we will continue + * the scan on our own. + */ SETWON; op_fnzp1(src, delim, FNPC_ELEM_MAX, &dummymval); SETWOFF; @@ -139,18 +138,18 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) assert(0 < cfnpc->npcs); if (FNPC_ELEM_MAX > cfnpc->npcs) { /* We ran out of text so the scan is complete. This is basically the same - as case #2 above. - */ + * as case #2 above. + */ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1; - delim_cnt = ind - cfnpc->npcs; + delim_cnt = (size_t)(ind - cfnpc->npcs); sfx_start_offset = 0; sfx_str_len = 0; cpy_cache_lines = cfnpc->npcs; } else { /* We have a case where the piece we want cannot be kept in cache. In the special - case where there is no more text to handle, we don't need to scan further. Otherwise - we prime the pump and continue the scan where the cache left off. - */ + * case where there is no more text to handle, we don't need to scan further. Otherwise + * we prime the pump and continue the scan where the cache left off. + */ if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len) { /* Normal case where we prime the pump */ do_scan = TRUE; @@ -160,73 +159,64 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) sfx_start_offset = 0; sfx_str_len = 0; } - delim_cnt = ind - FNPC_ELEM_MAX; + delim_cnt = (size_t)ind - FNPC_ELEM_MAX; cpy_cache_lines = FNPC_ELEM_MAX; } - } } else { /* Source is not defined -- treat as a null string */ pfx_str_len = sfx_str_len = sfx_start_offset = 0; - delim_cnt = ind - 1; + delim_cnt = (size_t)ind - 1; } - /* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been - set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters - still need to be processed. - */ + * set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters + * still need to be processed. + */ if (do_scan) - { /* Scan the line isolating prefix piece, and end of the - piece being replaced - */ + { /* Scan the line isolating prefix piece, and end of the piece being replaced */ COUNT_EVENT(cs_small); end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset; end_src = (unsigned char *)src->str.addr + src->str.len; - /* The compiler would unroll this loop this way anyway but we want to - adjust the start_sfx pointer after the loop but only if we have gone - into it at least once. - */ - if (0 < delim_cnt && start_sfx < end_src) + * adjust the start_sfx pointer after the loop but only if we have gone + * into it at least once. + */ + if ((0 < delim_cnt) && (start_sfx < end_src)) { do { end_pfx = start_sfx; - while (start_sfx < end_src && (lc = *start_sfx) != ldelimc) start_sfx++; + while ((start_sfx < end_src) && ((lc = *start_sfx) != ldelimc)) start_sfx++; /* Note assignment */ start_sfx++; delim_cnt--; - } while (0 < delim_cnt && start_sfx < end_src); - + } while ((0 < delim_cnt) && (start_sfx < end_src)); /* We have to backup up the suffix start pointer except under the condition - that the last character in the buffer is the last delimiter we were looking - for. - */ - if (0 == delim_cnt || start_sfx < end_src || lc != ldelimc) + * that the last character in the buffer is the last delimiter we were looking for. + */ + if ((0 == delim_cnt) || (start_sfx < end_src) || (lc != ldelimc)) --start_sfx; /* Back up suffix to include delimiter char */ - /* If we scanned to the end (no text left) and still have delimiters to - find, the entire src text should be part of the prefix */ - if (start_sfx >= end_src && 0 < delim_cnt) + * find, the entire src text should be part of the prefix + */ + if ((start_sfx >= end_src) && (0 < delim_cnt)) { end_pfx = start_sfx; if (lc == ldelimc) /* if last char was delim, reduce delim cnt */ --delim_cnt; } - } else { /* If not doing any token finding, then this count becomes the number - of tokens to output. Adjust accordingly. - */ - if (0 > --delim_cnt) - delim_cnt = 0; + * of tokens to output. Adjust accordingly. + */ + if (0 < delim_cnt) + delim_cnt--; } - INCR_COUNT(cs_small_pcs, ind - delim_cnt); - + INCR_COUNT(cs_small_pcs, (int)((size_t)ind - delim_cnt)); /* Now having the following situation: - end_pfx -> end of the prefix piece including delimiter - start_sfx -> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none - */ + * end_pfx -> end of the prefix piece including delimiter + * start_sfx -> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none + */ pfx_str_len = (int)(end_pfx - (unsigned char *)src->str.addr); if (0 > pfx_str_len) pfx_str_len = 0; @@ -235,51 +225,44 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) if (0 > sfx_str_len) sfx_str_len = 0; } - /* Calculate total string len. delim_cnt has needed padding delimiters for null fields */ - str_len = expr->str.len + pfx_str_len + delim_cnt + sfx_str_len; + str_len = (size_t)expr->str.len + (size_t)pfx_str_len + delim_cnt + (size_t)sfx_str_len; if (str_len > MAX_STRLEN) rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); - ENSURE_STP_FREE_SPACE(str_len); + ENSURE_STP_FREE_SPACE((int)str_len); str_addr = stringpool.free; start_pfx = (unsigned char *)src->str.addr; - /* copy prefix */ if (0 < pfx_str_len) { memcpy(str_addr, src->str.addr, pfx_str_len); str_addr += pfx_str_len; } - /* copy delimiters */ - while (delim_cnt-- > 0) + while (0 < delim_cnt--) *str_addr++ = ldelimc; - /* copy expression */ if (0 < expr->str.len) { memcpy(str_addr, expr->str.addr, expr->str.len); str_addr += expr->str.len; } - /* copy suffix */ if (0 < sfx_str_len) { memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len); str_addr += sfx_str_len; } - - assert(str_addr - stringpool.free == str_len); + assert((str_addr - stringpool.free) == (int)str_len); dst->mvtype = MV_STR; dst->str.len = INTCAST(str_addr - stringpool.free); dst->str.addr = (char *)stringpool.free; stringpool.free = str_addr; - /* If available, update the cache information for this newly created mval to hopefully - give it a head start on its next usage. Note that we can only copy over the cache info - for the prefix. We cannot include information for the 'expression' except where it starts - because the expression could itself contain delimiters that would be found on a rescan. - */ + * give it a head start on its next usage. Note that we can only copy over the cache info + * for the prefix. We cannot include information for the 'expression' except where it starts + * because the expression could itself contain delimiters that would be found on a rescan. + */ if (0 < cpy_cache_lines) { pfnpc = cfnpc; /* pointer for src mval's cache */ @@ -290,16 +273,15 @@ void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst) cfnpc = &(TREF(fnpca)).fnpcs[0]; (TREF(fnpca)).fnpcsteal = cfnpc + 1; /* -> next element to steal */ } while (cfnpc == pfnpc); /* Make sure we don't step on ourselves */ - cfnpc->last_str = dst->str; /* Save validation info */ cfnpc->delim = ldelim.unichar_val; cfnpc->npcs = cpy_cache_lines; cfnpc->byte_oriented = TRUE; dst->fnpc_indx = cfnpc->indx + 1; /* Save where we are putting this element - (1 based index in mval so 0 isn't so common) */ + * (1 based index in mval so 0 isn't so common) + */ memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * SIZEOF(unsigned int)); } else - { /* No cache available -- just reset index pointer to get fastest cache validation failure */ + /* No cache available -- just reset index pointer to get fastest cache validation failure */ dst->fnpc_indx = (unsigned char)-1; - } } diff --git a/sr_port/op_setzpiece.c b/sr_port/op_setzpiece.c index 4b6ef69..e2089f6 100644 --- a/sr_port/op_setzpiece.c +++ b/sr_port/op_setzpiece.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2009 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,6 +19,8 @@ GBLREF spdesc stringpool; +error_def(ERR_MAXSTRLEN); + /* -------------------------------------------------------------------- * NOTE: This module is a near copy of sr_unix/op_setpiece.c differing * only in that it calls "matchb" instead of "matchc" to do matching. @@ -44,14 +46,12 @@ GBLREF spdesc stringpool; */ void op_setzpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval *dst) { - int match_res, len, src_len, str_len, delim_cnt; - int first_src_ind, second_src_ind, numpcs; + size_t str_len, delim_cnt; + int match_res, len, src_len, first_src_ind, second_src_ind, numpcs; unsigned char *match_ptr, *src_str, *str_addr, *tmp_str; delimfmt unichar; - error_def(ERR_MAXSTRLEN); - - if (--first < 0) + if (0 > --first) first = 0; assert(last >= first); second_src_ind = last - first; @@ -114,18 +114,18 @@ void op_setzpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval second_src_ind = (0 == match_res) ? -1 : INTCAST(match_ptr - (unsigned char *)src->str.addr - del->str.len); } } - delim_cnt = first; + delim_cnt = (size_t)first; /* Calculate total string len. */ - str_len = expr->str.len + (first_src_ind + del->str.len * delim_cnt); + str_len = (size_t)expr->str.len + ((size_t)first_src_ind + ((size_t)del->str.len * delim_cnt)); /* add len. of trailing chars past insertion point */ - if (second_src_ind >= 0) - str_len += (src->str.len - second_src_ind); - if (str_len > MAX_STRLEN) + if (0 <= second_src_ind) + str_len += (size_t)(src->str.len - second_src_ind); + if (MAX_STRLEN < str_len) { rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); return; } - ENSURE_STP_FREE_SPACE(str_len); + ENSURE_STP_FREE_SPACE((int)str_len); str_addr = stringpool.free; /* copy prefix */ if (first_src_ind) @@ -134,7 +134,7 @@ void op_setzpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval str_addr += first_src_ind; } /* copy delimiters */ - while (delim_cnt-- > 0) + while (0 < delim_cnt--) { memcpy(str_addr, del->str.addr, del->str.len); str_addr += del->str.len; @@ -143,14 +143,14 @@ void op_setzpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval memcpy(str_addr, expr->str.addr, expr->str.len); str_addr += expr->str.len; /* copy trailing pieces */ - if (second_src_ind >= 0) + if (0 <= second_src_ind) { len = src->str.len - second_src_ind; tmp_str = (unsigned char *)src->str.addr + second_src_ind; memcpy(str_addr, tmp_str, len); str_addr += len; } - assert(str_addr - stringpool.free == str_len); + assert((str_addr - stringpool.free) == str_len); dst->mvtype = MV_STR; dst->str.len = INTCAST(str_addr - stringpool.free); dst->str.addr = (char *)stringpool.free; diff --git a/sr_port/op_svget.c b/sr_port/op_svget.c index 99d2553..ff84916 100644 --- a/sr_port/op_svget.c +++ b/sr_port/op_svget.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "io.h" #include "iottdef.h" #include "jnl.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "stringpool.h" #include "svnames.h" @@ -49,7 +49,10 @@ #include "get_reference.h" #include "dollar_quit.h" #ifdef UNIX -#include "iormdef.h" +# include "iormdef.h" +# ifdef DEBUG +# include "wbox_test_init.h" +# endif #endif #define ESC_OFFSET 4 @@ -69,7 +72,6 @@ GBLREF mval dollar_job; GBLREF uint4 dollar_zjob; GBLREF mval dollar_zstatus; GBLREF mval dollar_zstep; -GBLREF int dollar_zmaxtptime; GBLREF mval dollar_zsource; GBLREF int4 dollar_zsystem; GBLREF int4 dollar_zeditor; @@ -118,7 +120,7 @@ void op_svget(int varnum, mval *v) { io_log_name *tl; int count; - unsigned int ucount; + gtm_uint64_t ucount; char *c1, *c2; mval *mvp; # ifdef UNIX @@ -127,6 +129,27 @@ void op_svget(int varnum, mval *v) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; +# if defined(UNIX) && defined(DEBUG) + if (gtm_white_box_test_case_enabled && (WBTEST_HUGE_ALLOC == gtm_white_box_test_case_number)) + { + if (1 == gtm_white_box_test_case_count) + totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xffff; + else if (2 == gtm_white_box_test_case_count) + totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xfffffff; + else if (3 == gtm_white_box_test_case_count) + { +# ifdef GTM64 + if (8 == SIZEOF(size_t)) + totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta + = totalUsed = totalUsedGta = 0xfffffffffffffff; + else +# endif + totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xfffffff; + } else + totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed + = totalUsedGta = GTM64_ONLY(SIZEOF(size_t)) NON_GTM64_ONLY(SIZEOF(size_t) > 4 ? 4 : SIZEOF(size_t)); + } +# endif switch (varnum) { case SV_HOROLOG: @@ -282,7 +305,7 @@ void op_svget(int varnum, mval *v) *v = TREF(dollar_zmode); break; case SV_ZMAXTPTIME: - i2mval(v, dollar_zmaxtptime); + i2mval(v, TREF(dollar_zmaxtptime)); break; case SV_ZPOS: getzposition(v); @@ -385,16 +408,16 @@ void op_svget(int varnum, mval *v) *v = dollar_ztexit; break; case SV_ZALLOCSTOR: - ucount = (unsigned int)(totalAlloc + totalAllocGta); - MV_FORCE_UMVAL(v, ucount); + ucount = (gtm_uint64_t)totalAlloc + (gtm_uint64_t)totalAllocGta; + ui82mval(v, ucount); break; case SV_ZREALSTOR: - ucount = (unsigned int)(totalRmalloc + totalRallocGta); - MV_FORCE_UMVAL(v, ucount); + ucount = (gtm_uint64_t)totalRmalloc + (gtm_uint64_t)totalRallocGta; + ui82mval(v, ucount); break; case SV_ZUSEDSTOR: - ucount = (unsigned int)(totalUsed + totalUsedGta); - MV_FORCE_UMVAL(v, ucount); + ucount = (gtm_uint64_t)totalUsed + (gtm_uint64_t)totalUsedGta; + ui82mval(v, ucount); break; case SV_ZCHSET: v->mvtype = MV_STR; diff --git a/sr_port/op_svput.c b/sr_port/op_svput.c index 5b72b13..7b29ea4 100644 --- a/sr_port/op_svput.c +++ b/sr_port/op_svput.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,7 +38,7 @@ #include "error_trap.h" #include "gtm_ctype.h" #include "setzdir.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "getzdir.h" #include "gtm_newintrinsic.h" @@ -60,7 +60,6 @@ GBLREF mval dollar_zstatus; GBLREF mval dollar_zgbldir; GBLREF mval dollar_zstep; GBLREF mval dollar_zsource; -GBLREF int dollar_zmaxtptime; GBLREF int ztrap_form; GBLREF mval dollar_etrap; GBLREF mval dollar_zerror; @@ -166,7 +165,7 @@ void op_svput(int varnum, mval *v) } break; case SV_ZMAXTPTIME: - dollar_zmaxtptime = mval2i(v); + TREF(dollar_zmaxtptime) = mval2i(v); break; case SV_ZROUTINES: MV_FORCE_STR(v); diff --git a/sr_port/op_tcommit.c b/sr_port/op_tcommit.c index 7c64b23..1b56735 100644 --- a/sr_port/op_tcommit.c +++ b/sr_port/op_tcommit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -65,7 +65,7 @@ #endif #ifdef GTM_TRIGGER -#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ +#include /* for rtn_tabent in gv_trigger.h */ #include "gv_trigger.h" #include "gtm_trigger.h" #endif @@ -75,6 +75,7 @@ GBLREF uint4 dollar_trestart; GBLREF jnl_fence_control jnl_fence_ctl; GBLREF tp_frame *tp_pointer; GBLREF gd_region *gv_cur_region; +GBLREF gv_key *gv_currkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgm_info *first_sgm_info, *sgm_info_ptr; @@ -108,6 +109,68 @@ error_def(ERR_TRIGTCOMMIT); error_def(ERR_TCOMMITDISALLOW); #endif +STATICFNDCL void fix_updarray_and_oldblock_ptrs(sm_uc_ptr_t old_db_addrs[2], sgm_info *si); + +STATICFNDEF void fix_updarray_and_oldblock_ptrs(sm_uc_ptr_t old_db_addrs[2], sgm_info *si) +{ + cw_set_element *cse; + srch_blk_status *t1; + blk_segment *array, *seg, *stop_ptr; + sm_long_t delta; + sgmnt_addrs *csa; +# ifdef DEBUG + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; +# endif + csa = si->tp_csa; + delta = (sm_long_t)(csa->db_addrs[0] - old_db_addrs[0]); + assert(0 != delta); + /* update cse's update array and old_block */ + for (cse = si->first_cw_set; NULL != cse; cse = cse->next_cw_set) + { + TRAVERSE_TO_LATEST_CSE(cse); + if (gds_t_writemap != cse->mode) + { + array = (blk_segment *)cse->upd_addr; + stop_ptr = cse->first_copy ? array : array + 1; + seg = (blk_segment *)array->addr; + while (seg != stop_ptr) + { + if ((old_db_addrs[0] <= seg->addr) && (old_db_addrs[1] >= seg->addr)) + seg->addr += delta; + seg--; + } + } + if (NULL != cse->old_block) + { + if ((old_db_addrs[0] <= cse->old_block) && (old_db_addrs[1] >= cse->old_block)) + cse->old_block += delta; + /* else, old_block is already updated -- this is mostly the case with gds_t_writemap in which case + * bm_getfree invokes t_write_map + */ +# ifdef DEBUG + if (!((csa->db_addrs[0] <= cse->old_block) && (csa->db_addrs[1] >= cse->old_block))) + { /* cse->old_block is pointing outside mmap bounds; most likely it points to the private memory. + * But cse->old_block, at all times should point to the before image of the database block and so + * should NOT point to private memory. This indicates that t_qread (below) did a private build on + * an incorrect block and tp_tend will detect this and restart. To be sure, set donot_commit. + */ + assert(CDB_STAGNATE > t_tries); + TREF(donot_commit) |= DONOTCOMMIT_T_QREAD_BAD_PVT_BUILD; + } +# endif + } + } + /* update all the tp_hist */ + for (t1 = si->first_tp_hist; t1 != si->last_tp_hist; t1++) + { + if ((old_db_addrs[0] <= t1->buffaddr) && (old_db_addrs[1] >= t1->buffaddr)) + t1->buffaddr += delta; + } + return; +} + enum cdb_sc op_tcommit(void) { boolean_t blk_used, is_mm, was_crit; @@ -127,12 +190,7 @@ enum cdb_sc op_tcommit(void) kill_set *ks; off_chain chain1; tp_region *tr; - /* for MM extend */ - cw_set_element *update_cse; - blk_segment *seg, *stop_ptr, *array; - sm_long_t delta; - sm_uc_ptr_t old_db_addrs[2]; - srch_blk_status *t1; + sm_uc_ptr_t old_db_addrs[2]; /* for MM extend */ jnl_buffer_ptr_t jbp; /* jbp is non-NULL only if before-image journaling */ blk_hdr_ptr_t old_block; boolean_t read_before_image; /* TRUE if before-image journaling or online backup in progress @@ -153,7 +211,7 @@ enum cdb_sc op_tcommit(void) skip_invoke_restart = FALSE; /* no triggers so set local variable to default state */ # endif if (!dollar_tlevel) - rts_error(VARLSTCNT(1) ERR_TLVLZERO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TLVLZERO); assert(0 == jnl_fence_ctl.level); status = cdb_sc_normal; tp_kill_bitmaps = FALSE; @@ -174,7 +232,8 @@ enum cdb_sc op_tcommit(void) * trigger invocation to be done before completing the explicit (outside-trigger) update. * Cannot commit such a transaction. Issue error. */ - rts_error(VARLSTCNT(4) ERR_TRIGTCOMMIT, 2, gtm_trigger_depth, tstart_trigger_depth); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGTCOMMIT, 2, gtm_trigger_depth, + tstart_trigger_depth); } if (tp_pointer->cannot_commit) { /* If this TP transaction was implicit, any unhandled error when crossing the trigger boundary @@ -183,11 +242,11 @@ enum cdb_sc op_tcommit(void) * transaction so we should never see an implicit TP inside op_tcommit. */ assert(!tp_pointer->implicit_tstart); - rts_error(VARLSTCNT(1) ERR_TCOMMITDISALLOW); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TCOMMITDISALLOW); } ) save_cur_region = gv_cur_region; - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); if (NULL != first_sgm_info) /* if (database work in the transaction) */ { for (temp_si = si = first_sgm_info; (cdb_sc_normal == status) && (NULL != si); si = si->next_sgm_info) @@ -197,7 +256,7 @@ enum cdb_sc op_tcommit(void) csa = cs_addrs; csd = cs_data; cnl = csa->nl; - is_mm = (dba_mm == cs_addrs->hdr->acc_meth); + is_mm = (dba_mm == csa->hdr->acc_meth); si->cr_array_index = 0; if (!is_mm && (si->cr_array_size < (si->num_of_blks + (si->cw_set_depth * 2)))) { /* reallocate a bigger cr_array. We need atmost read-set (si->num_of_blks) + @@ -237,7 +296,7 @@ enum cdb_sc op_tcommit(void) */ SS_INIT_IF_NEEDED(csa, cnl); } else - csa->snapshot_in_prog = FALSE; + CLEAR_SNAPSHOTS_IN_PROG(csa); # endif read_before_image = ((NULL != jbp) || csa->backup_in_prog || SNAPSHOTS_IN_PROG(csa)); /* The following section allocates new blocks required by the transaction it is done @@ -259,80 +318,37 @@ enum cdb_sc op_tcommit(void) if (gds_t_create == cse->mode) { old_cw_depth = si->cw_set_depth; - old_db_addrs[0] = csa->db_addrs[0]; - old_db_addrs[1] = csa->db_addrs[1]; first_cse = si->first_cw_set; TRAVERSE_TO_LATEST_CSE(first_cse); + old_db_addrs[0] = csa->db_addrs[0]; + old_db_addrs[1] = csa->db_addrs[1]; while (FILE_EXTENDED == (new_blk = bm_getfree(cse->blk, &blk_used, cw_depth, first_cse, &si->cw_set_depth))) { assert(is_mm); - was_crit = csa->now_crit; - if (!csa->hold_onto_crit && !was_crit) - grab_crit(si->gv_cur_region); /* for wcs_mm_recover */ - wcs_mm_recover(si->gv_cur_region); - if (!csa->hold_onto_crit && !was_crit) - rel_crit(si->gv_cur_region); - delta = (sm_long_t)((sm_uc_ptr_t)csa->hdr - (sm_uc_ptr_t)csd); - csd = csa->hdr; - /* update cse's update array and old_block */ - for (update_cse = si->first_cw_set; NULL != update_cse; - update_cse = update_cse->next_cw_set) - { - TRAVERSE_TO_LATEST_CSE(update_cse); - if (gds_t_writemap != update_cse->mode) - { - array = (blk_segment *)update_cse->upd_addr; - stop_ptr = update_cse->first_copy ? - array : array + 1; - seg = (blk_segment *)array->addr; - while (seg != stop_ptr) - { - if ((old_db_addrs[0] < seg->addr) - && (old_db_addrs[1] >= seg->addr)) - seg->addr += delta; - seg--; - } - } - if (NULL != update_cse->old_block) - { - assert((old_db_addrs[0] < update_cse->old_block) && - (old_db_addrs[1] > update_cse->old_block)); - update_cse->old_block += delta; - } - } - /* update all the tp_hist */ - for (t1 = si->first_tp_hist; t1 != si->last_tp_hist; t1++) - { - if ((old_db_addrs[0] < t1->buffaddr) - && (old_db_addrs[1] >= t1->buffaddr)) - t1->buffaddr += delta; - } - /* In case the while loop above needs to repeat more than once, - * the mmaped addresses for the file's start and end could have - * changed if wcs_mm_recover() caused a file extension. In that - * case, reset the limits to the new values. - */ + MM_DBFILEXT_REMAP_IF_NEEDED(csa, si->gv_cur_region); if (csa->db_addrs[0] != old_db_addrs[0]) { + fix_updarray_and_oldblock_ptrs(old_db_addrs, si); old_db_addrs[0] = csa->db_addrs[0]; old_db_addrs[1] = csa->db_addrs[1]; - csd = csa->hdr; } } + assert(csd == csa->hdr); if (0 > new_blk) { GET_CDB_SC_CODE(new_blk, status); /* code is set in status */ break; /* transaction must attempt restart */ } else - cse->was_free = !blk_used; + blk_used ? BIT_CLEAR_FREE(cse->blk_prior_state) + : BIT_SET_FREE(cse->blk_prior_state); BEFORE_IMAGE_NEEDED(read_before_image, cse, csa, csd, new_blk, before_image_needed); if (!before_image_needed) cse->old_block = NULL; else { - block_is_free = cse->was_free; + block_is_free = WAS_FREE(cse->blk_prior_state); cse->old_block = t_qread(new_blk, (sm_int_ptr_t)&cse->cycle, &cse->cr); old_block = (blk_hdr_ptr_t)cse->old_block; @@ -341,8 +357,8 @@ enum cdb_sc op_tcommit(void) status = (enum cdb_sc)rdfail_detail; break; } - if (!cse->was_free - && (NULL != jbp) && (old_block->tn < jbp->epoch_tn)) + if (!WAS_FREE(cse->blk_prior_state) && (NULL != jbp) + && (old_block->tn < jbp->epoch_tn)) { /* Compute CHECKSUM for writing PBLK record before crit. * It is possible that we are reading a block that is * actually marked free in the bitmap (due to concurrency @@ -364,9 +380,10 @@ enum cdb_sc op_tcommit(void) cse->blk = new_blk; cse->mode = gds_t_acquired; assert(GDSVCURR == cse->ondsk_blkver); - assert(CDB_STAGNATE > t_tries || - (is_mm ? (cse->blk < csa->total_blks) - : (cse->blk < csa->ti->total_blks))); + /* Assert that in final retry total_blks (private and shared) are in sync */ + assert((CDB_STAGNATE > t_tries) || !is_mm + || (csa->total_blks == csa->ti->total_blks)); + assert((CDB_STAGNATE > t_tries) || (cse->blk < csa->ti->total_blks)); } /* if (gds_t_create == cse->mode) */ } /* for (all cw_set_elements) */ if (NULL == si->first_cw_bitmap) @@ -401,8 +418,8 @@ enum cdb_sc op_tcommit(void) if (cdb_sc_normal != status) { t_fail_hist[t_tries] = status; - SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, status); - TP_RETRY_ACCOUNTING(csa, cnl, status); + SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, cnl, status); + TP_RETRY_ACCOUNTING(csa, cnl); } if ((cdb_sc_normal == status) && tp_tend()) ; @@ -417,9 +434,10 @@ enum cdb_sc op_tcommit(void) ) if (cdb_sc_gbloflow == status) { - if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, cse->blk_target->last_rec, TRUE))) + if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); } else if (!skip_invoke_restart) INVOKE_RESTART; GTMTRIG_ONLY(DBGTRIGR((stderr, "op_tcommit: Return status = %d\n", status));) @@ -476,7 +494,7 @@ enum cdb_sc op_tcommit(void) tp_clean_up(FALSE); /* Not the rollback type of cleanup */ gv_cur_region = save_cur_region; TP_CHANGE_REG(gv_cur_region); - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); /* Cancel or clear any pending TP timeout only if real commit (i.e. outermost commit) */ (*tp_timeout_clear_ptr)(); } else /* an intermediate commit */ diff --git a/sr_port/op_trollback.c b/sr_port/op_trollback.c index 3d3aa9c..6587c94 100644 --- a/sr_port/op_trollback.c +++ b/sr_port/op_trollback.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,18 +35,21 @@ GBLREF uint4 dollar_tlevel; GBLREF uint4 dollar_trestart; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; +GBLREF gd_addr *gd_header; GBLREF tp_region *tp_reg_list; /* Chained list of regions used in this transaction not cleared on tp_restart */ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF void (*tp_timeout_clear_ptr)(void); GBLREF int process_exiting; +GBLREF gd_binding *gd_map; #ifdef GTM_TRIGGER GBLREF int4 gtm_trigger_depth; GBLREF int4 tstart_trigger_depth; #endif #ifdef DEBUG GBLREF boolean_t donot_INVOKE_MUMTSTART; +GBLREF unsigned char *tpstackbase, *tpstacktop; #endif GBLREF boolean_t implicit_trollback; GBLREF tp_frame *tp_pointer; @@ -63,13 +66,14 @@ error_def(ERR_INVROLLBKLVL); void op_trollback(int rb_levels) /* rb_levels -> # of transaction levels by which we need to rollback : BYPASSOK */ { - boolean_t lcl_implicit_trollback = FALSE; + boolean_t lcl_implicit_trollback = FALSE, reg_reset; uint4 newlevel; gd_region *save_cur_region; /* saved copy of gv_cur_region before tp_clean_up/tp_incr_clean_up modifies it */ gd_region *curreg; gv_key *gv_orig_key_ptr; sgmnt_addrs *csa; tp_region *tr; + int tl; if (implicit_trollback) { @@ -89,20 +93,7 @@ void op_trollback(int rb_levels) /* rb_levels -> # of transaction levels by whi } else if (dollar_tlevel <= rb_levels) rts_error(VARLSTCNT(4) ERR_INVROLLBKLVL, 2, rb_levels, dollar_tlevel); newlevel = (0 > rb_levels) ? dollar_tlevel + rb_levels : rb_levels; - /* The DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC macro is used at various points in the database code to check that - * gv_target and cs_addrs are in sync. This is because op_gvname relies on this in order to avoid a gv_bind_name - * function call (if incoming key matches gv_currkey from previous call, it uses gv_target and cs_addrs right - * away instead of recomputing them). We want to check that here as well. 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. - */ - DEBUG_ONLY( - if (!process_exiting) - { - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; - } - ) + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); save_cur_region = gv_cur_region; GTMTRIG_ONLY(assert(tstart_trigger_depth <= gtm_trigger_depth);) /* see similar assert in op_tcommit.c for why */ if (!newlevel) @@ -122,28 +113,33 @@ void op_trollback(int rb_levels) /* rb_levels -> # of transaction levels by whi if (csa->now_crit && !csa->hold_onto_crit) rel_crit(curreg); /* release any crit regions */ } - if (lcl_implicit_trollback && tp_pointer->implicit_tstart) + reg_reset = FALSE; + if (!process_exiting && lcl_implicit_trollback && tp_pointer->implicit_tstart) { /* This is an implicit TROLLBACK of an implicit TSTART started for a non-tp explicit update. * gv_currkey needs to be restored to the value it was at the beginning of the implicit TSTART. - * This is necessary so as to maintain $reference accurately in case of an error during the - * ^#t processing initiated by an explicit non-tp update. + * This is necessary so as to maintain $reference accurately (to user-visible global name) in case + * of an error during the ^#t processing initiated by an explicit non-tp update. + * Note that in case the process is already exiting, it is not necessary to do this maintenance. + * And since it is safer to minimize processing during exiting, we skip this step. */ - assert(NULL != gv_currkey); + /* Determine tp_pointer corresponding to outermost TSTART first */ + for (tl = dollar_tlevel - 1; tl > newlevel; --tl) + tp_pointer = tp_pointer->old_tp_frame; + assert(NULL == tp_pointer->old_tp_frame); /* this is indeed the outermost TSTART */ + assert(tp_pointer->implicit_tstart); /* assert implicit_tstart is inherited across nested TSTARTs */ assert(tp_pointer && tp_pointer->orig_key); + assert(tp_pointer >= (tp_frame *)tpstacktop); + assert(tp_pointer <= (tp_frame *)tpstackbase); + assert(NULL != gv_currkey); gv_orig_key_ptr = tp_pointer->orig_key; - /* At this point we expect tp_pointer->orig_key and gv_currkey to be in sync. However there are two - * exceptions to this. - * (a) If MUPIP TRIGGER detects that all of the triggers are erroneous and attempts an "op_trollback", - * gv_currkey would be pointing to ^#t. However, tp_pointer->orig_key would remain at "" (initialized - * during op_tstart). - * (b) If an M program defines $etrap to do a halt and an explicit Non-TP update causes a trigger to be - * executed that further causes a runtime error which will now invoke the $etrap code. Since the - * $etrap code does a halt, gtm_exit_handler will invoke "op_trollback" (since dollar_tlevel is > 0). - * At this point, tp_pointer->orig_key and gv_currkey need not be in sync. - * To maintain $reference accurately, we need to restore gv_currkey from tp_pointer->orig_key. - */ - memcpy(gv_currkey->base, gv_orig_key_ptr->base, gv_orig_key_ptr->end); - } else if (gv_currkey != NULL) + COPY_KEY(gv_currkey, gv_orig_key_ptr); + gv_target = tp_pointer->orig_gv_target; + gd_header = tp_pointer->gd_header; + gd_map = gd_header->maps; + gv_cur_region = tp_pointer->gd_reg; + TP_CHANGE_REG(gv_cur_region); + reg_reset = TRUE; /* so we dont restore gv_cur_region again */ + } else if (NULL != gv_currkey) { gv_currkey->base[0] = '\0'; gv_currkey->end = gv_currkey->prev = 0; @@ -154,7 +150,8 @@ void op_trollback(int rb_levels) /* rb_levels -> # of transaction levels by whi /* Now that we are out of TP, reset the debug-only global variable that is relevant only if we are in TP */ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE;) dollar_trestart = 0; - RESTORE_GV_CUR_REGION; + if (!reg_reset) + RESTORE_GV_CUR_REGION; JOBINTR_TP_RETHROW; /* rethrow job interrupt($ZINT) if $ZTEXIT, when coerced to boolean, is true */ } else { @@ -167,10 +164,5 @@ void op_trollback(int rb_levels) /* rb_levels -> # of transaction levels by whi RESTORE_GV_CUR_REGION; tp_unwind(newlevel, ROLLBACK_INVOCATION, NULL); } - DEBUG_ONLY( - if (!process_exiting) - { - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; - } - ) + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); } diff --git a/sr_port/op_tstart.c b/sr_port/op_tstart.c index 2dc9170..d20568a 100644 --- a/sr_port/op_tstart.c +++ b/sr_port/op_tstart.c @@ -29,7 +29,7 @@ #include "lv_val.h" #include "jnl.h" #include "mlkdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "tp_frame.h" @@ -92,7 +92,6 @@ GBLREF boolean_t gtm_utf8_mode; GBLREF uint4 tstartcycle; GBLREF char *update_array_ptr; GBLREF ua_list *curr_ua, *first_ua; -GBLREF int4 dollar_zmaxtptime; #ifdef GTM_TRIGGER GBLREF mval dollar_ztwormhole; GBLREF int4 gtm_trigger_depth; @@ -188,11 +187,21 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */ { jnl_fence_ctl.fence_list = JNL_FENCE_LIST_END; jgbl.cumul_jnl_rec_len = 0; - DEBUG_ONLY(jgbl.cumul_index = jgbl.cu_jnl_index = 0); +# ifdef DEBUG + if (1 == jgbl.cumul_index) /* when 1 == jgbl.cumul_index and 0 == jgbl.cumul_index, non-TP morphed into TP */ + jgbl.cumul_index = 0; + else + assert(0 == jgbl.cumul_index); + TREF(tp_restart_dont_counts) = 0; +# endif + assert(0 == jgbl.cu_jnl_index); GTMTRIG_ONLY(memcpy(&dollar_ztslate, &literal_null, SIZEOF(mval))); /* Zap $ZTSLate at start of lvl 1 trans */ GTMTRIG_ONLY(if (!implicit_tstart || !implicit_trigger)) { /* This is the path for all non-implicit-trigger type TP fences including the implicit fences * created by the update process and by mupip recover forward. + * Note: For recover/rollback, t_tries is set to CDB_STAGNATE because unlike Non-TP restarts, TP restarts + * need more context to determine the restart point which is non-trivial for recover/rollback since the + * updates are done with journal records extracted by sequentially reading the journal file. */ t_tries = (FALSE == mupip_jnl_recover) ? 0 : CDB_STAGNATE; t_fail_hist[t_tries] = cdb_sc_normal; @@ -220,7 +229,7 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */ * kicking in at all. */ /* recovery logic does not invoke triggers */ - assert(!(SFF_TRIGR_CALLD & frame_pointer->flags) || (FALSE == mupip_jnl_recover)); + assert(!(SFF_IMPLTSTART_CALLD & frame_pointer->flags) || (FALSE == mupip_jnl_recover)); } # endif for (tr = tp_reg_list; NULL != tr; tr = tr_next) @@ -392,7 +401,7 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */ { /* 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. */ - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); } # endif /* If the TP structures have not yet been initialized, do that now. */ @@ -403,7 +412,7 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */ } tf->orig_key = (gv_key *)&((TREF(gv_tporigkey_ptr))->gv_orig_key[dollar_tlevel][0]); assert(NULL != gv_currkey); - memcpy(tf->orig_key, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); + MEMCPY_KEY(tf->orig_key, gv_currkey); tf->gd_header = gd_header; tf->gd_reg = gv_cur_region; tf->zgbldir = dollar_zgbldir; @@ -580,8 +589,8 @@ void op_tstart(int implicit_flag, ...) /* value of $T when TSTART */ si->tlvl_info_head = new_tli; } /* If starting first TP level, also start TP timer if set to non-default value */ - assert(0 <= dollar_zmaxtptime); - if ((0 < dollar_zmaxtptime) && (1 == dollar_tlevel)) - (*tp_timeout_start_timer_ptr)(dollar_zmaxtptime); + assert(0 <= TREF(dollar_zmaxtptime)); + if ((0 < TREF(dollar_zmaxtptime)) && (1 == dollar_tlevel)) + (*tp_timeout_start_timer_ptr)(TREF(dollar_zmaxtptime)); DBGRFCT((stderr, "\nop_tstart: complete\n")); } diff --git a/sr_port/op_unwind.c b/sr_port/op_unwind.c index 0e955f8..2cec65b 100644 --- a/sr_port/op_unwind.c +++ b/sr_port/op_unwind.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "tp_frame.h" @@ -26,6 +26,8 @@ #include "tp_timeout.h" #include "compiler.h" #include "parm_pool.h" +#include "opcode.h" +#include "glvn_pool.h" #ifdef GTM_TRIGGER # include "gtm_trigger_trc.h" #endif @@ -53,7 +55,6 @@ error_def(ERR_TPQUIT); void op_unwind(void) { mv_stent *mvc; - stack_frame *rfp; DBGEHND_ONLY(stack_frame *prevfp;) DCL_THREADGBL_ACCESS; @@ -88,25 +89,6 @@ void op_unwind(void) assert(msp <= stackbase && msp > stacktop); assert(mv_chain <= (mv_stent *)stackbase && mv_chain > (mv_stent *)stacktop); assert(frame_pointer <= (stack_frame*)stackbase && frame_pointer > (stack_frame *)stacktop); - if (NULL != frame_pointer->for_ctrl_stack) - { /* someone used an ugly FOR control variable */ - if (frame_pointer->flags & SFF_INDCE) - { /* a FOR control variable indx set up in an indirect frame belongs in the underlying "real" frame - * By "real" we mean non-indirect as in not @ induced, in other words: normal code, or XECUTE-like code - * ZTRAP is an interesting case because it might be a label rather than code, but fortunately that condition - * can't intersect with a FOR control variable, which is the case the outer if condition filters on - */ - for (rfp = frame_pointer; rfp && !(rfp->type & SFT_LINE_OF_CODE_FRAME); rfp = rfp->old_frame_pointer) - ; - assert(rfp); - if (NULL == rfp->for_ctrl_stack) - rfp->for_ctrl_stack = frame_pointer->for_ctrl_stack; - else /* indirect compilation already cloned the pointer */ - assert(rfp->for_ctrl_stack == frame_pointer->for_ctrl_stack); - } else /* otherwise, done with this level - clean it up */ - FREE_SAVED_FOR_INDX(frame_pointer); - frame_pointer->for_ctrl_stack = NULL; - } /* See if unwinding an indirect frame */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY(frame_pointer); for (mvc = mv_chain; mvc < (mv_stent *)frame_pointer; ) @@ -123,16 +105,17 @@ void op_unwind(void) if (msp > stackbase) rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO); # ifdef GTM_TRIGGER - if (SFF_TRIGR_CALLD & frame_pointer->type) - DBGTRIGR((stderr, "op_unwind: Unwinding frame 0x"lvaddr" with type %d which has SFF_TRIGR_CALLD turned on\n", + if (SFF_IMPLTSTART_CALLD & frame_pointer->type) + DBGTRIGR((stderr, "op_unwind: Unwinding frame 0x"lvaddr" with type %d which has SFF_IMPLTSTART_CALLD turned on\n", frame_pointer, frame_pointer->type)); # endif + DRAIN_GLVN_POOL_IF_NEEDED; PARM_ACT_UNSTACK_IF_NEEDED; 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)); if (NULL != zyerr_frame && frame_pointer > zyerr_frame) - zyerr_frame = NULL; + zyerr_frame = NULL; /* If we have unwound past zyerr_frame, clear it */ if (frame_pointer) { if ((frame_pointer < (stack_frame *)msp) || (frame_pointer > (stack_frame *)stackbase) diff --git a/sr_port/op_view.c b/sr_port/op_view.c index 271d3b1..c2bda1b 100644 --- a/sr_port/op_view.c +++ b/sr_port/op_view.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,14 +12,20 @@ #include "mdef.h" #include +#if defined(UNIX) && defined(DEBUG) +# include "gtm_syslog.h" /* Needed for white box case in VTK_STORDUMP */ +#endif #include "gtm_string.h" +#include "gtm_stdio.h" #include "gtmio.h" +#include "util.h" #include "have_crit.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" +#include "gdsbgtr.h" #include "gdsfhead.h" #include "filestruct.h" #include "cmd_qlf.h" @@ -46,12 +52,23 @@ #include "gtm_malloc.h" #include "alias.h" #include "fullbool.h" +#include "anticipatory_freeze.h" #ifdef GTM_TRIGGER -#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ -#include "gv_trigger.h" -#include "gtm_trigger.h" +# include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ +# include "gv_trigger.h" +# include "gtm_trigger.h" +#endif +#ifdef UNIX +# include "wbox_test_init.h" +# include "mutex.h" +# ifdef DEBUG +# include "gtmsecshr.h" +# endif #endif +STATICFNDCL void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg); + +GBLREF volatile int4 db_fsync_in_prog; GBLREF boolean_t certify_all_blocks; GBLREF bool undef_inhibit, jobpid; GBLREF bool view_debug1, view_debug2, view_debug3, view_debug4; @@ -76,10 +93,12 @@ GBLREF uint4 gtmDebugLevel; GBLREF boolean_t lvmon_enabled; GBLREF spdesc stringpool; GBLREF boolean_t is_updproc; +GBLREF pid_t process_id; error_def(ERR_ACTRANGE); error_def(ERR_COLLATIONUNDEF); error_def(ERR_COLLDATAEXISTS); +error_def(ERR_DBFSYNCERR); error_def(ERR_INVZDIRFORM); error_def(ERR_ISOLATIONSTSCHN); error_def(ERR_JNLFLUSH); @@ -100,22 +119,22 @@ error_def(ERR_ZDEFACTIVE); #define WRITE_LITERAL(x) (outval.str.len = SIZEOF(x) - 1, outval.str.addr = (x), op_write(&outval)) /* if changing noisolation status within TP and already referenced the global, then error */ -#define SET_GVNH_NOISOLATION_STATUS(gvnh, status) \ -{ \ - GBLREF uint4 dollar_tlevel; \ - \ - if (!dollar_tlevel || gvnh->read_local_tn != local_tn || status == gvnh->noisolation) \ - gvnh->noisolation = status; \ - else \ - rts_error(VARLSTCNT(6) ERR_ISOLATIONSTSCHN, 4, gvnh->gvname.var_name.len, \ - gvnh->gvname.var_name.addr, gvnh->noisolation, status); \ +#define SET_GVNH_NOISOLATION_STATUS(gvnh, status) \ +{ \ + GBLREF uint4 dollar_tlevel; \ + \ + if (!dollar_tlevel || gvnh->read_local_tn != local_tn || status == gvnh->noisolation) \ + gvnh->noisolation = status; \ + else \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ISOLATIONSTSCHN, 4, gvnh->gvname.var_name.len, \ + gvnh->gvname.var_name.addr, gvnh->noisolation, status); \ } void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) { int4 testvalue, tmpzdefbufsiz; uint4 jnl_status, dummy_errno; - int status; + int status, lcnt, icnt; gd_region *reg, *r_top, *save_reg; gv_namehead *gvnh; mval *arg, *nextarg, outval; @@ -125,7 +144,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) viewtab_entry *vtp; gd_addr *addr_ptr; noisolation_element *gvnh_entry; - int lct, ncol; + int lct, ncol, nct; collseq *new_lcl_collseq; ht_ent_mname *tabent, *topent; lv_val *lv; @@ -196,30 +215,13 @@ 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_DBSYNC: + case VTK_EPOCH: case VTK_FLUSH: - if (NULL == gd_header) /* open gbldir */ - gvinit(); - save_reg = gv_cur_region; - if (NULL == parmblk.gv_ptr) - { /* flush all regions */ - reg = gd_header->regions; - r_top = reg + gd_header->n_regions - 1; - } else /* flush selected region */ - r_top = reg = parmblk.gv_ptr; - for (; reg <= r_top; reg++) - { - if (!reg->open) - gv_init_reg(reg); - if (!reg->read_only) - { - gv_cur_region = reg; - change_reg(); /* for jnl_ensure_open */ - ENSURE_JNL_OPEN(cs_addrs, gv_cur_region); - wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH); - } - } - gv_cur_region = save_reg; - change_reg(); + case VTK_JNLFLUSH: + case VTK_DBFLUSH: + arg = (numarg > 1) ? va_arg(var, mval *) : NULL; + view_dbflushop(vtp->keycode, &parmblk, arg); break; case VTK_FULLBOOL: TREF(gtm_fullbool) = FULL_BOOL; @@ -318,58 +320,6 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) } break; # endif - case VTK_JNLFLUSH: - if (NULL == gd_header) /* open gbldir */ - gvinit(); - save_reg = gv_cur_region; - if (NULL == parmblk.gv_ptr) - { /* flush all journal files */ - reg = gd_header->regions; - r_top = reg + gd_header->n_regions - 1; - } else /* flush journal for selected region */ - r_top = reg = parmblk.gv_ptr; - for (; reg <= r_top; reg++) - { - if (!reg->open) - gv_init_reg(reg); - gv_cur_region = reg; - change_reg(); - csa = cs_addrs; - csd = csa->hdr; - if (JNL_ENABLED(csd)) - { - was_crit = csa->now_crit; - if (!was_crit) - grab_crit(reg); - if (JNL_ENABLED(csd)) - { - jnl_status = jnl_ensure_open(); - if (0 == jnl_status) - { - jb = csa->jnl->jnl_buff; - if (SS_NORMAL == (jnl_status = jnl_flush(reg))) - { - assert(jb->dskaddr == jb->freeaddr); - UNIX_ONLY(jnl_fsync(reg, jb->dskaddr)); - UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr)); - } else - { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), - ERR_TEXT, 2, - RTS_ERROR_TEXT("Error with journal flush during op_view"), - jnl_status); - assert(FALSE); - } - } else - send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); - } - if (!was_crit) - rel_crit(reg); - } - } - gv_cur_region = save_reg; - change_reg(); - break; case VTK_JNLWAIT: /* go through all regions that could have possibly been open across all global directories */ for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) @@ -417,7 +367,8 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (0 == status) { va_end(var); - rts_error(VARLSTCNT(4) ERR_PATTABNOTFND, 2, parmblk.value->str.len, parmblk.value->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PATTABNOTFND, 2, parmblk.value->str.len, + parmblk.value->str.addr); } break; case VTK_RESETGVSTATS: @@ -461,7 +412,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (TREF(view_ydirt_str_len) > MAX_YDIRTSTR) { va_end(var); - rts_error(VARLSTCNT(1) ERR_YDIRTSZ); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_YDIRTSZ); } if (TREF(view_ydirt_str_len) > 0) memcpy(TREF(view_ydirt_str), parmblk.value->str.addr, TREF(view_ydirt_str_len)); @@ -494,7 +445,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) else { va_end(var); - rts_error(VARLSTCNT(1) ERR_REQDVIEWPARM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REQDVIEWPARM); } nextarg = NULL; ncol = -1; @@ -503,7 +454,14 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) nextarg = va_arg(var, mval *); ncol = MV_FORCE_INT(nextarg); } - if ((-1 == lct) && (-1 == ncol)) + nextarg = NULL; + nct = -1; + if (numarg > 2) + { + nextarg = va_arg(var, mval *); + nct = MV_FORCE_INT(nextarg); + } + if ((-1 == lct) && (-1 == ncol) && (-1 == nct)) break; /* lct = -1 indicates user wants to change only ncol, not lct */ if (-1 != lct) @@ -511,7 +469,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if ((lct < MIN_COLLTYPE) || (lct > MAX_COLLTYPE)) { va_end(var); - rts_error(VARLSTCNT(3) ERR_ACTRANGE, 1, lct); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ACTRANGE, 1, lct); } } /* at this point, verify that there is no local data with subscripts */ @@ -526,7 +484,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (lv && LV_HAS_CHILD(lv)) { va_end(var); - rts_error(VARLSTCNT(1) ERR_COLLDATAEXISTS); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COLLDATAEXISTS); } } } @@ -539,7 +497,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (0 == new_lcl_collseq) { va_end(var); - rts_error(VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct); } TREF(local_collseq) = new_lcl_collseq; } else @@ -556,12 +514,15 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) } if (-1 != ncol) TREF(local_collseq_stdnull) = (ncol ? TRUE: FALSE); + if (-1 != nct) + TREF(local_coll_nums_as_strings) = (nct ? TRUE: FALSE); break; case VTK_PATLOAD: if (!load_pattern_table(parmblk.value->str.len, parmblk.value->str.addr)) { va_end(var); - rts_error(VARLSTCNT(4) ERR_PATLOAD, 2, parmblk.value->str.len, parmblk.value->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PATLOAD, 2, parmblk.value->str.len, + parmblk.value->str.addr); } break; case VTK_NOUNDEF: @@ -578,7 +539,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (zdefactive) { va_end(var); - rts_error(VARLSTCNT(1) ERR_ZDEFACTIVE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZDEFACTIVE); } zdefactive = TRUE; tmpzdefbufsiz = MV_FORCE_INT(parmblk.value); @@ -600,7 +561,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (2 > numarg) { va_end(var); - rts_error(VARLSTCNT(1) ERR_TRACEON); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TRACEON); } arg = va_arg(var, mval *); MV_FORCE_STR(arg); @@ -624,7 +585,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) if (!IS_VALID_ZDIR_FORM(testvalue)) { va_end(var); - rts_error(VARLSTCNT(3) ERR_INVZDIRFORM, 1, testvalue); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INVZDIRFORM, 1, testvalue); } } else testvalue = ZDIR_FORM_FULLPATH; @@ -665,6 +626,26 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) DEFER_BASE_REL_HASHTAB(table, FALSE); break; 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)) + { /* 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); + DBGGSSHR((LOGFLAGS, "op_view: Pid %d, initial icnt: %d\n", process_id, icnt)); + for (lcnt = 0; (MUTEXLCKALERT_INTERVAL * 12) > lcnt; lcnt++) + { /* Poll for icnt to be increased - check every quarter second */ + SHORT_SLEEP(250); /* Quarter second nap */ + if (TREF(continue_proc_cnt) > icnt) + break; + DBGGSSHR((LOGFLAGS, "op_view: loop: %d - continue_proc_cnt: %d\n", lcnt, + TREF(continue_proc_cnt))); + } + DBGGSSHR((LOGFLAGS, "op_view: pid %d, lcnt: %d, icnt: %d, continue_proc_cnt: %d\n", + process_id, lcnt, icnt, TREF(continue_proc_cnt))); + rel_crit(gv_cur_region); + } else /* If we do the white box test, avoid the rest */ +# endif if (gtmDebugLevel) { /* gtmdbglvl must be non-zero to have hope of printing a storage dump */ dbgdmpenabled = (GDL_SmDump & gtmDebugLevel); @@ -674,6 +655,37 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) gtmDebugLevel &= (~GDL_SmDump); /* Shut indicator back off */ } break; + case VTK_LOGTPRESTART: + /* The TPRESTART logging frequency can be specified through environment variable or + * through VIEW command. The default value for logging frequency is 1 if value is + * not specified in the view command and env variable is not defined. There are 4 + * possible combinations which will determine the final value of logging frequency + * depending upon whether value is specified in the VIEW command or env variables + * is defined. These combinations are summarized in the following table. + * + * value in environment Final + * VIEW command variable value + * X X 1 + * X A A + * B X B + * B C B + */ + if (!numarg) + { + if (!TREF(tprestart_syslog_delta)) + TREF(tprestart_syslog_delta) = 1; + } + else + { + TREF(tprestart_syslog_delta) = MV_FORCE_INT(parmblk.value); + if (0 > TREF(tprestart_syslog_delta)) + TREF(tprestart_syslog_delta) = 0; + } + TREF(tp_restart_count) = 0; + break; + case VTK_NOLOGTPRESTART: + TREF(tprestart_syslog_delta) = 0; + break; # ifdef DEBUG_ALIAS case VTK_LVMONOUT: als_lvmon_output(); @@ -698,11 +710,139 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...) als_lvmon_output(); lvmon_enabled = FALSE; break; +# endif +# ifdef DEBUG + case VTK_LVDMP: /* Write partial lv_val into to output device */ + outval.mvtype = MV_STR; + 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); + outval.str.addr = TREF(util_outptr); + outval.str.len = STRLEN(TREF(util_outptr)); + op_write(&outval); + op_wteol(1); + break; # endif default: va_end(var); - rts_error(VARLSTCNT(1) ERR_VIEWCMD); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWCMD); } va_end(var); return; } + +void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg) +{ + uint4 jnl_status, dummy_errno; + int4 nbuffs; + int save_errno; + int status, lcnt, icnt; + gd_region *reg, *r_top, *save_reg; + sgmnt_addrs *csa; + sgmnt_data_ptr_t csd; + jnl_buffer_ptr_t jb; + boolean_t was_crit; + UNIX_ONLY(unix_db_info *udi;) + + if (NULL == gd_header) /* open gbldir */ + gvinit(); + save_reg = gv_cur_region; + if (NULL == parmblkptr->gv_ptr) + { /* operate on all regions */ + reg = gd_header->regions; + r_top = reg + gd_header->n_regions - 1; + } else /* operate on selected region */ + r_top = reg = parmblkptr->gv_ptr; + for (; reg <= r_top; reg++) + { + if (!reg->open) + gv_init_reg(reg); + gv_cur_region = reg; + switch(keycode) + { + case VTK_DBSYNC: +# ifdef UNIX + if (!reg->read_only) + { + change_reg(); + csa = cs_addrs; + udi = FILE_INFO(reg); + DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno); + if (0 != save_errno) + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), + save_errno); + save_errno = 0; + } + } +# endif + break; + case VTK_FLUSH: + case VTK_EPOCH: + if (!reg->read_only) + { + change_reg(); /* for jnl_ensure_open */ + ENSURE_JNL_OPEN(cs_addrs, gv_cur_region); + /* We should NOT invoke wcs_recover here because it's possible we are in the final retry + * of a TP transaction. In this case, we likely have pointers to non-dirty global buffers + * in our transaction histories. Doing cache recovery could dry clean most of these buffers. + * And that might cause us to get confused, attempt to restart, and incorrectly issue a + * TPFAIL error because we are already in the final retry. By passing the WCSFLU_IN_COMMIT + * bit, we instruct wcs_flu to avoid wcs_recover. + */ + wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_IN_COMMIT); + } + break; + case VTK_JNLFLUSH: + change_reg(); + csa = cs_addrs; + csd = csa->hdr; + if (JNL_ENABLED(csd)) + { + was_crit = csa->now_crit; + if (!was_crit) + grab_crit(reg); + if (JNL_ENABLED(csd)) + { + jnl_status = jnl_ensure_open(); + if (0 == jnl_status) + { + jb = csa->jnl->jnl_buff; + if (SS_NORMAL == (jnl_status = jnl_flush(reg))) + { + assert(jb->dskaddr == jb->freeaddr); + UNIX_ONLY(jnl_fsync(reg, jb->dskaddr)); + UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr)); + } else + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, + JNL_LEN_STR(csd), ERR_TEXT, 2, + RTS_ERROR_TEXT("Error with journal flush during op_view"), + jnl_status); + assert(FALSE); + } + } else + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(reg)); + } + if (!was_crit) + 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); + } + break; + } + } + gv_cur_region = save_reg; + change_reg(); + return; +} diff --git a/sr_port/op_xkill.c b/sr_port/op_xkill.c index aabd957..1fd6dd4 100644 --- a/sr_port/op_xkill.c +++ b/sr_port/op_xkill.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,8 +34,6 @@ void op_xkill(UNIX_ONLY_COMMA(int n) mval *lvname_arg, ...) ht_ent_mname *tabent, *top; boolean_t lcl_stdxkill; - error_def(ERR_XKILLCNTEXC); - active_lv = (lv_val *)NULL; /* if we get here, subscript set was successful. clear active_lv to avoid later cleanup problems */ /* GTM supports two methods for exclusive kill that affect the way aliases and pass-by-reference (PBR) parameters are diff --git a/sr_port/op_xnew.c b/sr_port/op_xnew.c index 083e17d..c8365a5 100644 --- a/sr_port/op_xnew.c +++ b/sr_port/op_xnew.c @@ -23,7 +23,7 @@ #include "gdsbt.h" #include "gdsfhead.h" #include "op.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "alias.h" diff --git a/sr_port/op_zallocate.c b/sr_port/op_zallocate.c index baf7330..f9e6ae8 100644 --- a/sr_port/op_zallocate.c +++ b/sr_port/op_zallocate.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,6 +11,9 @@ #include "mdef.h" #include "op.h" +#include "hashtab_mname.h" /* needed for cmmdef.h */ +#include "cmidefsp.h" /* needed for cmmdef.h */ +#include "cmmdef.h" /* * ----------------------------------------------- * This routine is a one-argument front-end for op_zallocate @@ -32,5 +35,5 @@ int op_zallocate(int timeout) { - return (op_zalloc2(timeout,0)); + return op_lock2(timeout, CM_ZALLOCATES); } diff --git a/sr_port/op_zbreak.c b/sr_port/op_zbreak.c index c7d6927..ffeecb6 100644 --- a/sr_port/op_zbreak.c +++ b/sr_port/op_zbreak.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "cache.h" #include "zbreak.h" diff --git a/sr_port/op_zcompile.c b/sr_port/op_zcompile.c index 1b88d15..bf9fe77 100644 --- a/sr_port/op_zcompile.c +++ b/sr_port/op_zcompile.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,7 +30,7 @@ GBLREF mcalloc_hdr *mcavailptr; #define FILE_NAME_SIZE 255 -void op_zcompile(mval *v, boolean_t mExtReqd) +void op_zcompile(mval *v, boolean_t ignore_dollar_zcompile) { unsigned status; command_qualifier save_qlf; @@ -51,14 +51,17 @@ void op_zcompile(mval *v, boolean_t mExtReqd) if (!v->str.len) return; save_qlf = glb_cmd_qlf; - glb_cmd_qlf.object_file.str.addr = obj_file; - glb_cmd_qlf.object_file.str.len = FILE_NAME_SIZE; - glb_cmd_qlf.list_file.str.addr = list_file; - glb_cmd_qlf.list_file.str.len = FILE_NAME_SIZE; - glb_cmd_qlf.ceprep_file.str.addr = ceprep_file; - glb_cmd_qlf.ceprep_file.str.len = FILE_NAME_SIZE; - zl_cmd_qlf(&v->str, &glb_cmd_qlf); - cmd_qlf = glb_cmd_qlf; +# ifdef UNIX /* VMS retains old behavior, for which $ZCOMPILE only affects ZLINK, not ZCOMPILE or compile mode */ + if (!ignore_dollar_zcompile) + { + INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, FILE_NAME_SIZE); + zl_cmd_qlf(&(TREF(dollar_zcompile)), &cmd_qlf); /* Process $ZCOMPILE qualifiers */ + glb_cmd_qlf = cmd_qlf; + } +# endif + INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, FILE_NAME_SIZE); + zl_cmd_qlf(&v->str, &cmd_qlf); /* Process ZCOMPILE arg. Override any conflicting quals in $ZCOMPILE */ + glb_cmd_qlf = cmd_qlf; assert(run_time); assert(rts_stringpool.base == stringpool.base); rts_stringpool = stringpool; @@ -94,7 +97,7 @@ void op_zcompile(mval *v, boolean_t mExtReqd) status; status = cli_get_str("INFILE",source_file_string, &len)) { - compile_source_file(len, source_file_string, mExtReqd); + compile_source_file(len, source_file_string, FALSE); len = FILE_NAME_SIZE; } /* Determine if need to remove any added added mc blocks. Min value of mcallocated will ensure diff --git a/sr_port/op_zcont.c b/sr_port/op_zcont.c index 2c302fb..5c8d373 100644 --- a/sr_port/op_zcont.c +++ b/sr_port/op_zcont.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" diff --git a/sr_port/op_zg1.c b/sr_port/op_zg1.c index 3807de3..68a664f 100644 --- a/sr_port/op_zg1.c +++ b/sr_port/op_zg1.c @@ -15,7 +15,7 @@ #include "gtm_stdlib.h" #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "dollar_zlevel.h" diff --git a/sr_port/op_zgoto.c b/sr_port/op_zgoto.c index f9f75ac..165edea 100644 --- a/sr_port/op_zgoto.c +++ b/sr_port/op_zgoto.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011, 2012 Fidelity Information Services, Inc * + * Copyright 2011, 2013 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 "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "op.h" #include "flush_jmp.h" @@ -64,13 +64,13 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level) if (0 > level) { /* Negative level specified, means to use relative level change */ if ((-level) > curlvl) - rts_error(VARLSTCNT(1) ERR_ZGOTOLTZERO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO); level += curlvl; /* Compute relative desired level */ } else { /* Else level is the level we wish to achieve - compute unrolls necessary */ if (0 > (curlvl - level)) /* Couldn't get to the level we were trying to unwind to */ - rts_error(VARLSTCNT(1) ERR_ZGOTOTOOBIG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG); } /* Migrate mval parm contents to private buffers since the mvals could die as we unwind things */ MV_FORCE_STR(rtn_name); @@ -90,7 +90,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level) * was NULL. */ if (0 == lblname.str.len) - rts_error(VARLSTCNT(1) ERR_RTNNAME); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RTNNAME); rtnhdr = frame_pointer->rvector; if (0 == level) { /* If doing unlink, recall name of routine as well as will need it later */ @@ -118,7 +118,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level) * since the base frame cannot be rewritten as a GTM frame. */ if (0 == level) - rts_error(VARLSTCNT(1) ERR_ZGOTOINVLVL2); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOINVLVL2); # endif # ifdef GTM_TRIGGER if (!IS_GTM_IMAGE && (1 >= level)) @@ -127,7 +127,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level) * entry ref was coded) and are not resume-able (if no entry ref were specified) so we cannot * permit ZGOTOs to these levels in a utility. */ - rts_error(VARLSTCNT(5) ERR_ZGOTOINVLVL, 3, GTMIMAGENAMETXT(image_type), level); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZGOTOINVLVL, 3, GTMIMAGENAMETXT(image_type), level); # endif # ifdef UNIX /* One last check if we are unlinking, make sure no call-in frames exist on our stack */ @@ -140,7 +140,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level) continue; if (fp->flags & SFF_CI) /* We have a call-in frame - cannot do unlink */ - rts_error(VARLSTCNT(1) ERR_ZGOCALLOUTIN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOCALLOUTIN); if (NULL == fpprev) { /* Next frame is some sort of base frame */ # ifdef GTM_TRIGGER diff --git a/sr_port/op_zprevious.c b/sr_port/op_zprevious.c index 4e24452..a07578c 100644 --- a/sr_port/op_zprevious.c +++ b/sr_port/op_zprevious.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -89,7 +89,7 @@ void op_zprevious(mval *v) found = gvcmx_zprevious(); else found = gvusr_zprevious(); - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied + v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK) * by this to-be-overwritten mval */ if (found) { @@ -104,7 +104,7 @@ void op_zprevious(mval *v) n = gv_altkey->end - gv_altkey->prev; assert(n > 0); } - v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this + v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this (BYPASSOK) * to-be-overwritten mval */ ENSURE_STP_FREE_SPACE(n); } @@ -152,11 +152,13 @@ void op_zprevious(mval *v) found = gvcmx_zprevious(); else found = gvusr_zprevious(); + if ('#' == gv_altkey->base[0]) /* don't want to give any hidden ^#* global, e.g "^#t" */ + found = FALSE; if (!found) break; assert(1 < gv_altkey->end); assert(gv_altkey->end < (MAX_MIDENT_LEN + 2)); /* until names are not in midents */ - if (memcmp(gv_altkey->base, (map - 1)->name, gv_altkey->end - 1) < 0) + if (memcmp(gv_altkey->base, (map - 1)->name, gv_altkey->end) < 0) { found = FALSE; break; @@ -181,18 +183,20 @@ void op_zprevious(mval *v) assert(SIZEOF((map - 1)->name) == SIZEOF(mident_fixed)); assert(0 == (map - 1)->name[SIZEOF((map - 1)->name) - 1]); gv_currkey->end = mid_len((mident_fixed *)((map - 1)->name)); + assert(gv_currkey->end <= MAX_MIDENT_LEN); memcpy(gv_currkey->base, (map - 1)->name, gv_currkey->end); gv_currkey->base[gv_currkey->end++] = KEY_DELIMITER; gv_currkey->base[gv_currkey->end] = KEY_DELIMITER; + assert(gv_currkey->top > gv_currkey->end); /* ensure we are within allocated bounds */ } } gv_currkey->end = 0; gv_currkey->base[0] = KEY_DELIMITER; - v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied + v->mvtype = 0; /* so stp_gcol (if invoked below) can free up space currently occupied (BYPASSOK) * by this to-be-overwritten mval */ if (found) { - v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this + v->str.len = 0; /* so stp_gcol (if invoked) can free up space currently occupied by this (BYPASSOK) * to-be-overwritten mval */ ENSURE_STP_FREE_SPACE(name.len + 1); v->str.addr = (char *)stringpool.free; diff --git a/sr_port/op_zprint.c b/sr_port/op_zprint.c index 5bdd22b..187d627 100644 --- a/sr_port/op_zprint.c +++ b/sr_port/op_zprint.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "srcline.h" #include "error.h" #include "op.h" diff --git a/sr_port/op_zst_break.c b/sr_port/op_zst_break.c index 25501e1..016a88a 100644 --- a/sr_port/op_zst_break.c +++ b/sr_port/op_zst_break.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "xfer_enum.h" #include "indir_enum.h" diff --git a/sr_port/op_zstep.c b/sr_port/op_zstep.c index 0056d0a..754be5d 100644 --- a/sr_port/op_zstep.c +++ b/sr_port/op_zstep.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "zstep.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "xfer_enum.h" #include "indir_enum.h" diff --git a/sr_port/op_zsystem.c b/sr_port/op_zsystem.c index 79fc77c..72e1c0a 100644 --- a/sr_port/op_zsystem.c +++ b/sr_port/op_zsystem.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,10 +47,14 @@ #define ZSYSTEMSTR "ZSYSTEM" #define MAXZSYSSTRLEN 4096 /* maximum command line length supported by most Unix shells */ +GBLREF uint4 dollar_trestart; GBLREF int4 dollar_zsystem; /* exit status of child */ GBLREF io_pair io_std_device; GBLREF uint4 trust; +error_def(ERR_INVSTRLEN); +error_def(ERR_SYSCALL); + void op_zsystem(mval *v) { int len; @@ -67,14 +71,14 @@ void op_zsystem(mval *v) #else #error UNSUPPORTED PLATFORM #endif - error_def(ERR_INVSTRLEN); - error_def(ERR_SYSCALL); + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; TPNOTACID_CHECK(ZSYSTEMSTR); MV_FORCE_STR(v); #ifdef UNIX if (v->str.len > (MAXZSYSSTRLEN - 32 - 1)) /* 32 char for shell name, remaining for ZSYSTEM command */ - rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, v->str.len, (MAXZSYSSTRLEN - 32 - 1)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_INVSTRLEN, 2, v->str.len, (MAXZSYSSTRLEN - 32 - 1)); /* get SHELL environment */ sh = GETENV("SHELL"); /* use bourn shell as default */ @@ -100,7 +104,7 @@ void op_zsystem(mval *v) #ifdef UNIX dollar_zsystem = SYSTEM(cmd); if (-1 == dollar_zsystem) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("system"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("system"), CALLFROM, errno); #ifdef _BSD assert(SIZEOF(wait_stat) == SIZEOF(int4)); wait_stat.w_status = dollar_zsystem; @@ -116,7 +120,7 @@ void op_zsystem(mval *v) setterm(io_std_device.in); #ifdef VMS if (status != SS$_NORMAL) - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); #endif return; } diff --git a/sr_port/op_ztcommit.c b/sr_port/op_ztcommit.c index 447ea2f..1bb99da 100644 --- a/sr_port/op_ztcommit.c +++ b/sr_port/op_ztcommit.c @@ -57,7 +57,7 @@ void op_ztcommit(int4 n) jnl_buffer_ptr_t jbp; jnl_tm_t save_gbl_jrec_time; int4 prev_index; - static struct_jrec_ztcom ztcom_record = {{JRT_ZTCOM, ZTCOM_RECLEN, 0, 0, 0}, + static struct_jrec_ztcom ztcom_record = {{JRT_ZTCOM, ZTCOM_RECLEN, 0, 0, 0, 0}, 0, 0, 0, 0, {ZTCOM_RECLEN, JNL_REC_SUFFIX_CODE}}; assert(ZTCOM_RECLEN == ztcom_record.suffix.backptr); @@ -164,6 +164,8 @@ void op_ztcommit(int4 n) ztcom_record.prefix.tn = csa->ti->curr_tn; ztcom_record.prefix.checksum = INIT_CHECKSUM_SEED; ztcom_record.prefix.time = jgbl.gbl_jrec_time; + ztcom_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, + (uint4 *)&ztcom_record, SIZEOF(struct_jrec_ztcom)); JNL_WRITE_APPROPRIATE(csa, jpc, JRT_ZTCOM, (jnl_record *)&ztcom_record, NULL, NULL); if (!csa->hold_onto_crit) rel_crit(jpc->region); diff --git a/sr_port/opcode_def.h b/sr_port/opcode_def.h index 08b735f..d652c5e 100644 --- a/sr_port/opcode_def.h +++ b/sr_port/opcode_def.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -245,7 +245,6 @@ OPCODE_DEF(OC_TRESTART, (OCT_NULL)) OPCODE_DEF(OC_TCOMMIT, (OCT_NULL)) OPCODE_DEF(OC_EXP, (OCT_MVAL)) OPCODE_DEF(OC_FNGET2, (OCT_MVAL | OCT_EXPRLEAF)) -OPCODE_DEF(OC_INDGET, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_INDINCR, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNNAME, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_INDFNNAME, (OCT_MVAL | OCT_EXPRLEAF)) @@ -268,7 +267,7 @@ OPCODE_DEF(OC_FGNLOOKUP, (OCT_CDADDR)) OPCODE_DEF(OC_SORTS_AFTER, (OCT_BOOL)) OPCODE_DEF(OC_NSORTS_AFTER, (OCT_BOOL)) OPCODE_DEF(OC_FNGVGET1, (OCT_MVAL | OCT_EXPRLEAF)) -OPCODE_DEF(OC_FNGVGET2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_FNGET1, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETP1, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZQGBLMOD, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETEXTRACT, (OCT_MVAL | OCT_EXPRLEAF)) @@ -303,6 +302,7 @@ OPCODE_DEF(OC_FNZTRANSLATE, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZCONVERT2, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZCONVERT3, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZWIDTH, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_FNZWRITE, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZSUBSTR, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETALS2ALS, (OCT_NULL)) OPCODE_DEF(OC_SETALSIN2ALSCT, (OCT_NULL)) @@ -324,3 +324,21 @@ OPCODE_DEF(OC_SAVPUTINDX, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FORFREEINDX, (OCT_NULL)) OPCODE_DEF(OC_FORNESTLVL, (OCT_NULL)) OPCODE_DEF(OC_ZHALT, (OCT_NULL)) +OPCODE_DEF(OC_IGETDST, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDGET1, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_GLVNPOP, (OCT_NULL)) +OPCODE_DEF(OC_GLVNSLOT, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDSAVGLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDSAVLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_RFRSHLVN, (OCT_MVADDR | OCT_MVAL)) +OPCODE_DEF(OC_SAVGVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_SAVLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_SHARESLOT, (OCT_NULL)) +OPCODE_DEF(OC_STOGLVN, (OCT_NULL)) +OPCODE_DEF(OC_RFRSHGVN, (OCT_NULL)) +OPCODE_DEF(OC_INDFNNAME2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDGET2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDMERGE2, (OCT_NULL)) +OPCODE_DEF(OC_LITC, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_STOLITC, (OCT_NULL)) +OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF)) diff --git a/sr_port/outofband_action.c b/sr_port/outofband_action.c index 8c04ac2..fd4d505 100644 --- a/sr_port/outofband_action.c +++ b/sr_port/outofband_action.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" #include "io.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "outofband.h" diff --git a/sr_port/parm_pool.c b/sr_port/parm_pool.c index 7b33661..d7f81c9 100644 --- a/sr_port/parm_pool.c +++ b/sr_port/parm_pool.c @@ -16,7 +16,7 @@ #include "min_max.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "compiler.h" #include "gdsroot.h" diff --git a/sr_port/performcaslatchcheck.c b/sr_port/performcaslatchcheck.c index b57f040..8196edf 100644 --- a/sr_port/performcaslatchcheck.c +++ b/sr_port/performcaslatchcheck.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,9 @@ /* Check that a CAS latch is not stuck on a dead process. If it is release it */ #include "mdef.h" + +#include "gtm_limits.h" + #include "compswap.h" #include "lockconst.h" #include "util.h" diff --git a/sr_port/prepare_unique_name.c b/sr_port/prepare_unique_name.c index 470d63b..2a0a649 100644 --- a/sr_port/prepare_unique_name.c +++ b/sr_port/prepare_unique_name.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2007 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,13 +29,13 @@ /* Given org_fn this will create rename_fn * a) If prefix is not null, rename_fn = prefix + org_fn - * b) If suffix is not null, rename_fn = org_fn + suffix - * c) If prefix and suffix both not null Then + * b) If suffix is not null, rename_fn = org_fn + suffix + * c) If prefix and suffix are both null, then * rename_fn = org_fn + timestamp * If rename_fn exists, add numbers to make it non-existance file */ uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, - char *rename_fn, int *rename_fn_len, uint4 *ustatus) + char *rename_fn, int *rename_fn_len, jnl_tm_t now, uint4 *ustatus) { mstr filestr; char *filename_begin, append_char[MAX_CHARS_APPEND] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; @@ -82,9 +82,8 @@ uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suf filestr.len = org_fn_len; rename_fn[filestr.len] = 0; assert(filestr.len + 1 < MAX_FN_LEN); - if (SS_NORMAL != (status1 = append_time_stamp(rename_fn, filestr.len, &length, ustatus))) + if (SS_NORMAL != (status1 = append_time_stamp(rename_fn, &filestr.len, now))) return status1; - filestr.len += length; if (FILE_PRESENT == (file_stat = gtm_file_stat(&filestr, NULL, NULL, FALSE, ustatus))) /* One already exists */ { /* new name refers to an existing file - stuff numbers on the end until its unique */ rename_fn[filestr.len] = '_'; diff --git a/sr_port/print_target.c b/sr_port/print_target.c index 9271649..4cb5f4a 100644 --- a/sr_port/print_target.c +++ b/sr_port/print_target.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -66,7 +66,7 @@ void print_target(unsigned char *c) } else { is_string = FALSE; - ptop1 = ptr + MAX_NUM_SUBSC_LEN; + ptop1 = ptr + MAX_GVKEY_PADDING_LEN; } for (ptr1 = ptr; *ptr1; ptr1++) { diff --git a/sr_port/process_deferred_stale.c b/sr_port/process_deferred_stale.c index 14d7a6a..5757210 100644 --- a/sr_port/process_deferred_stale.c +++ b/sr_port/process_deferred_stale.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -76,37 +76,18 @@ void process_deferred_stale(void) * So, assert that is indeed the case. Also, have a much stricter assert to ensure that * gv_target->root = DIR_ROOT (indicating we are in gvcst_root_search). Also, since we want to * avoid flushing buffers if already holding crit, continue to the next region. + * (c) In case of DSE commands (like DSE MAPS -RESTORE), we could come here with csa->hold_onto_crit + * being TRUE (see t_begin_crit which DSE invokes). */ - assert(!T_IN_CRIT_OR_COMMIT_OR_WRITE(csa) || csa->hold_onto_crit); - assert(!T_IN_CRIT_OR_COMMIT_OR_WRITE(csa) + assert(!T_IN_CRIT_OR_COMMIT_OR_WRITE(csa) || csa->hold_onto_crit UNIX_ONLY(|| jgbl.onlnrlbk || (NULL == gv_target) || (DIR_ROOT == gv_target->root))); -# ifdef UNIX - if (!jgbl.onlnrlbk && csa->now_crit) + if (UNIX_ONLY(!jgbl.onlnrlbk && )csa->now_crit) continue; -# endif if (csa->stale_defer) { gv_cur_region = r_cur; tp_change_reg(); -#if defined(UNIX) && defined(UNTARGETED_MSYNC) - if (csa->ti->last_mm_sync != csa->ti->curr_tn) - { - boolean_t was_crit; - - was_crit = csa->now_crit; - if (FALSE == was_crit) - grab_crit(r_cur); - msync((caddr_t)csa->db_addrs[0], - (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), - MS_SYNC); - /* Save when did last full sync */ - csa->ti->last_mm_sync = csa->ti->curr_tn; - if (FALSE == was_crit) - rel_crit(r_cur); - } -#else DCLAST_WCS_WTSTART(r_cur, 0, status); -#endif csa->stale_defer = FALSE; BG_TRACE_ANY(csa, stale_defer_processed); } diff --git a/sr_port/push_lvval.c b/sr_port/push_lvval.c index 1199d6d..ce492b0 100644 --- a/sr_port/push_lvval.c +++ b/sr_port/push_lvval.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "lv_val.h" #include "mv_stent.h" #include "push_lvval.h" diff --git a/sr_port/push_mval.c b/sr_port/push_mval.c index e9e007e..7950745 100644 --- a/sr_port/push_mval.c +++ b/sr_port/push_mval.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" GBLREF mv_stent *mv_chain; diff --git a/sr_port/push_stck.c b/sr_port/push_stck.c index e4bf98a..2d951be 100644 --- a/sr_port/push_stck.c +++ b/sr_port/push_stck.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" GBLREF mv_stent *mv_chain; diff --git a/sr_port/push_tval.c b/sr_port/push_tval.c index 916c145..13d6f36 100644 --- a/sr_port/push_tval.c +++ b/sr_port/push_tval.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "push_tval.h" diff --git a/sr_port/region_freeze.c b/sr_port/region_freeze.c index b9d77dd..7cb5547 100644 --- a/sr_port/region_freeze.c +++ b/sr_port/region_freeze.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,14 +14,13 @@ #include "gtm_stdio.h" #ifdef VMS -#include -#include +# include +# include #endif - #ifdef VVMS_GTCX -#include -#include -#include +# include +# include +# include #endif #include "gdsroot.h" @@ -30,11 +29,10 @@ #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" - #ifdef VVMS_GTCX -#include "ccp.h" -#include "ccpact.h" -#include "iosp.h" +# include "ccp.h" +# include "ccpact.h" +# include "iosp.h" #endif #include "send_msg.h" #include "caller_id.h" @@ -47,23 +45,23 @@ #include "cli.h" #include "util.h" #include "wbox_test_init.h" +#include "have_crit.h" GBLREF bool caller_id_flag; GBLREF bool in_mupip_freeze; GBLREF uint4 process_id; GBLREF boolean_t debug_mupip; #ifdef UNIX -GBLREF uint4 user_id; -#define FREEZE_ID (0 == user_id ? FROZEN_BY_ROOT : user_id) -#define FREEZE_MATCH process_id -#define OWNERSHIP (in_mupip_freeze ? (csd->freeze == freeze_id) : (csd->image_count == FREEZE_MATCH)) +# define FREEZE_ID (0 == TREF(user_id) ? FROZEN_BY_ROOT : TREF(user_id)) +# define FREEZE_MATCH process_id +# define OWNERSHIP (in_mupip_freeze ? (csd->freeze == freeze_id) : (csd->image_count == FREEZE_MATCH)) #elif defined VMS GBLREF uint4 image_count; -#define FREEZE_ID process_id -#define FREEZE_MATCH image_count -#define OWNERSHIP ((csd->freeze == process_id) && (in_mupip_freeze || (csd->image_count == FREEZE_MATCH))) +# define FREEZE_ID process_id +# define FREEZE_MATCH image_count +# define OWNERSHIP ((csd->freeze == process_id) && (in_mupip_freeze || (csd->image_count == FREEZE_MATCH))) #else -#error Unsupported Platform +# error Unsupported Platform #endif #define SEND_FREEZEID(state) \ @@ -75,6 +73,8 @@ GBLREF uint4 image_count; caller_id_flag = TRUE; \ } +error_def(ERR_FREEZEID); + freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t override, boolean_t wait_for_kip) { uint4 freeze_id, sleep_counter; @@ -83,9 +83,9 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr now_t now; /* for GET_CUR_TIME macro */ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */ boolean_t was_crit; + DCL_THREADGBL_ACCESS; - error_def(ERR_FREEZEID); - + SETUP_THREADGBL_ACCESS; freeze_id = FREEZE_ID; csa = &FILE_INFO(region)->s_addrs; csd = csa->hdr; @@ -120,7 +120,7 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr { GET_CUR_TIME; util_out_print("!/MUPIP INFO: !AD : Start kill-in-prog wait for database !AD", TRUE, - CTIME_BEFORE_NL, time_ptr, DB_LEN_STR(region)); + CTIME_BEFORE_NL, time_ptr, DB_LEN_STR(region)); } do { @@ -136,7 +136,7 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr { GET_CUR_TIME; util_out_print("!/MUPIP INFO: !AD : Done with kill-in-prog wait on region", TRUE, - CTIME_BEFORE_NL, time_ptr); + CTIME_BEFORE_NL, time_ptr); } } /* if can't ever be true when override is true. */ @@ -153,18 +153,18 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr DECR_INHIBIT_KILLS(csa->nl); if (!was_crit) rel_crit(region); -#ifdef VVMS_GTCX +# ifdef VVMS_GTCX if (csd->clustered) { unsigned short iosb[4]; (void)sys$qiow(EFN$C_ENF, FILE_INFO(region)->fab->fab$l_stv, IO$_WRITEVBLK, iosb, NULL, 0, - csd, (MM_BLOCK - 1) * DISK_BLOCK_SIZE, 1, 0, 0, 0); + csd, (MM_BLOCK - 1) * DISK_BLOCK_SIZE, 1, 0, 0, 0); } -#endif -#ifdef DEBUG_FREEZE +# endif +# ifdef DEBUG_FREEZE SEND_FREEZEID("FREEZE"); -#endif +# endif return REG_FREEZE_SUCCESS; } if (0 == csd->freeze) @@ -174,7 +174,7 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr csd->image_count = 0; /* the order of this line and the next is important */ csd->freeze = 0; csa->freeze = FALSE; -#ifdef VVMS_GTCX +# ifdef VVMS_GTCX if (csd->clustered) { ccp_action_aux_value msg; @@ -182,7 +182,7 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr void ccp_sendmsg(); (void)sys$qiow(EFN$C_ENF, FILE_INFO(region)->fab->fab$l_stv, IO$_WRITEVBLK, iosb, NULL, 0, - csd, (MM_BLOCK - 1) * DISK_BLOCK_SIZE, 1, 0, 0, 0); + csd, (MM_BLOCK - 1) * DISK_BLOCK_SIZE, 1, 0, 0, 0); if (csa->nl->ccp_crit_blocked) { msg.exreq.fid = FILE_INFO(region)->file_id; @@ -190,10 +190,10 @@ freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t overr ccp_sendmsg(CCTR_EXITWM, &msg); } } -#endif -#ifdef DEBUG_FREEZE +# endif +# ifdef DEBUG_FREEZE SEND_FREEZEID("UNFREEZE"); -#endif +# endif return REG_FREEZE_SUCCESS; } return REG_ALREADY_FROZEN; diff --git a/sr_port/region_init.c b/sr_port/region_init.c index 0c9d028..4b6c7da 100644 --- a/sr_port/region_init.c +++ b/sr_port/region_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,11 +24,12 @@ GBLREF gd_region *gv_cur_region; void region_open(void); +error_def (ERR_DBNOREGION); + boolean_t region_init(bool cm_regions) { gd_region *region_top; boolean_t file_open, is_cm, all_files_open; - error_def (ERR_DBNOREGION); file_open = FALSE; all_files_open = TRUE; @@ -50,7 +51,7 @@ boolean_t region_init(bool cm_regions) } } if (!file_open) - rts_error(VARLSTCNT(1) ERR_DBNOREGION); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBNOREGION); /* arbitrary assignment of the first region */ for (gv_cur_region = gd_header->regions; gv_cur_region < region_top; gv_cur_region++) diff --git a/sr_port/release_private_code_copy.c b/sr_port/release_private_code_copy.c index 911b810..4cf6434 100644 --- a/sr_port/release_private_code_copy.c +++ b/sr_port/release_private_code_copy.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "private_code_copy.h" #include "gtm_text_alloc.h" diff --git a/sr_port/rename_file_if_exists.c b/sr_port/rename_file_if_exists.c index 298b043..97530fb 100644 --- a/sr_port/rename_file_if_exists.c +++ b/sr_port/rename_file_if_exists.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2010 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,7 @@ #include "gtm_string.h" #include "gtm_fcntl.h" +#include "gtm_time.h" #include #include "gdsroot.h" @@ -31,6 +32,9 @@ #include "gtmmsg.h" #include "gtm_file_stat.h" +error_def(ERR_FILERENAME); +error_def(ERR_RENAMEFAIL); + /* -------------------------------------------------------------------------------- This function renames a file, if exists. Otherwise do nothing. --------------------------------------------------------------------------------- */ @@ -38,8 +42,7 @@ int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *re { mstr orgfile; int status; - error_def(ERR_FILERENAME); - error_def(ERR_RENAMEFAIL); + jnl_tm_t now; memcpy(rename_fn, org_fn, org_fn_len + 1); /* Ensure it to be NULL terminated */ *rename_fn_len = org_fn_len; @@ -51,7 +54,8 @@ int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *re return RENAME_FAILED; /* File is present in the system */ assert(0 < MAX_FN_LEN - org_fn_len - 1); - if (SS_NORMAL != (status = prepare_unique_name(org_fn, org_fn_len, "", "", rename_fn, rename_fn_len, ustatus))) + JNL_SHORT_TIME(now); + if (SS_NORMAL != (status = prepare_unique_name(org_fn, org_fn_len, "", "", rename_fn, rename_fn_len, now, ustatus))) return RENAME_FAILED; assert(0 == rename_fn[*rename_fn_len]); if (SS_NORMAL != (status= gtm_rename(org_fn, org_fn_len, rename_fn, *rename_fn_len, ustatus))) diff --git a/sr_port/repl_comm.c b/sr_port/repl_comm.c index ab74633..a9cacd1 100644 --- a/sr_port/repl_comm.c +++ b/sr_port/repl_comm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,22 +11,22 @@ #include "mdef.h" -#include "gtm_stdio.h" -#include "gtm_string.h" -#include "gtmio.h" - #include -#include "gtm_socket.h" -#include "gtm_inet.h" #include #include +#ifdef USE_POLL +# include +#endif + +#include "gtm_stdio.h" +#include "gtm_string.h" +#include "gtm_socket.h" +#include "gtm_inet.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gtm_stat.h" -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT -#include -#endif +#include "gtmio.h" #include "repl_msg.h" #include "repl_errno.h" #include "repl_dbg.h" @@ -39,6 +39,7 @@ #include "iotcpdef.h" #include "gtmmsg.h" #include "gt_timer.h" + /* These statistics are useful and should perhaps be collected - Vinaya 2003/08/18 * * Common: @@ -72,7 +73,7 @@ * # calls to recv that would have blocked (EWOULDBLOCK) */ -GBLDEF int repl_max_send_buffsize, repl_max_recv_buffsize; +GBLDEF int repl_max_send_buffsize, repl_max_recv_buffsize; #if defined(__hppa) || defined(__vms) #define REPL_SEND_TRACE_BUFF_SIZE 65536 #define REPL_RECV_TRACE_BUFF_SIZE 65536 @@ -91,184 +92,163 @@ STATICDEF unsigned char * repl_recv_trace_buff = 0; STATICDEF int repl_recv_size_trace_pos = 0; STATICDEF int repl_recv_size_trace[REPL_RECV_SIZE_TRACE_SIZE]; -int repl_send(int sock_fd, unsigned char *buff, int *send_len, boolean_t skip_pipe_ready_check, struct timeval *max_pipe_ready_wait) -{ /* On entry, *send_len is the number of bytes to be sent - * On exit, *send_len contains the number of bytes sent - */ - int send_size, status, eintr_cnt, eagain_cnt, ewouldblock_cnt, emsgsize_cnt; +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_GETSOCKNAMERR); +error_def(ERR_TEXT); + +#define REPL_TRACE_BUFF(TRACE_BUFF, TRACE_BUFF_POS, IO_BUFF, IO_SIZE, MAX_TRACE_SIZE) \ +{ \ + if (IO_SIZE > MAX_TRACE_SIZE) \ + { \ + memcpy(TRACE_BUFF, IO_BUFF + IO_SIZE - MAX_TRACE_SIZE, MAX_TRACE_SIZE); \ + TRACE_BUFF_POS = 0; \ + } else \ + { \ + int space_to_end = MAX_TRACE_SIZE - TRACE_BUFF_POS; \ + if (IO_SIZE > space_to_end) \ + { \ + memcpy(TRACE_BUFF + TRACE_BUFF_POS, IO_BUFF, space_to_end); \ + memcpy(TRACE_BUFF, IO_BUFF + space_to_end, IO_SIZE - space_to_end); \ + } else \ + memcpy(TRACE_BUFF + TRACE_BUFF_POS, IO_BUFF, IO_SIZE); \ + TRACE_BUFF_POS = (TRACE_BUFF_POS + IO_SIZE) % MAX_TRACE_SIZE; \ + } \ +} + +int fd_ioready(int sock_fd, boolean_t pollin, int timeout) +{ + int save_errno, status, EAGAIN_cnt = 0; +# ifdef USE_POLL + struct pollfd fds; +# else + fd_set fds, *readfds, *writefds; + struct timeval timeout_spec; +# endif + + assert(timeout < MILLISECS_IN_SEC); + SELECT_ONLY(timeout = timeout * 1000); /* Convert to microseconds (~ 1sec) */ + assert((timeout >= 0) && (timeout < POLL_ONLY(MILLISECS_IN_SEC) SELECT_ONLY(MICROSEC_IN_SEC))); +# ifdef USE_POLL + fds.fd = sock_fd; + fds.events = pollin ? POLLIN : POLLOUT; +# else + readfds = writefds = NULL; + timeout_spec.tv_sec = 0; + timeout_spec.tv_usec = timeout; + FD_ZERO(&fds); + FD_SET(sock_fd, &fds); + writefds = !pollin ? &fds : NULL; + readfds = pollin ? &fds : NULL; +# endif + POLL_ONLY(while (-1 == (status = poll(&fds, 1, timeout)))) + SELECT_ONLY(while (-1 == (status = select(sock_fd + 1, readfds, writefds, NULL, &timeout_spec)))) + { + save_errno = ERRNO; + if (EINTR == save_errno) + { /* Give it another shot. But, halve the timeout so we don't keep doing this forever. */ + timeout = timeout >> 1; + } else if (EAGAIN == save_errno) + { /* Resource starved system; relinquish the processor in the hope that we may get the required resources + * next time around. + */ + if (0 == ++EAGAIN_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL) + { + repl_log(stderr, TRUE, TRUE, "Communication subsytem warning: System appears to be resource " + "starved. EAGAIN returned from select()/poll() %d times\n", EAGAIN_cnt); + } + rel_quant(); + } else + return -1; + /* Just in case select() modifies the incoming arguments, restore fd_set and timeout_spec */ + SELECT_ONLY( + assert(0 == timeout_spec.tv_sec); + timeout_spec.tv_usec = timeout; /* Note: timeout is the reduced value (in case of EINTR) */ + FD_SET(sock_fd, &fds); + ) + } + return status; +} + +int repl_send(int sock_fd, unsigned char *buff, int *send_len, int timeout) +{ + int send_size, status, eintr_cnt, ewouldblock_cnt = 0, emsgsize_cnt = 0, io_ready, save_errno; ssize_t bytes_sent; - long wait_val; - fd_set output_fds; - struct timeval timeout; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT - long poll_timeout; - unsigned long poll_nfds; - struct pollfd poll_fdlist[1]; -#endif - int space_to_end; if (!repl_send_trace_buff) repl_send_trace_buff = malloc(REPL_SEND_TRACE_BUFF_SIZE); /* Note: there is no corresponding free for this malloc since it is only done once per process and will not * accumulate across multiple process invocations. It will be "freed" when the mupip process exits. */ + assert(FD_INVALID != sock_fd); send_size = *send_len; /* VMS returns SYSTEM-F-INVBUFLEN if send_size is larger than the hard limit VMS_MAX_TCP_SEND_SIZE (64K - 1 on some * impelementations, 64K - 512 on some others). VMS_MAX_TCP_SEND_SIZE may be larger than repl_max_send_buffsize, and * empirically we have noticed send() successfully sending repl_max_send_buffsize or more bytes. */ - VMS_ONLY(send_size = MIN(send_size, VMS_MAX_TCP_SEND_SIZE);) - REPL_DPRINT3("repl_send: called with send_size %d, limiting send_size to %d\n", *send_len, send_size); + VMS_ONLY(send_size = MIN(send_size, VMS_MAX_TCP_SEND_SIZE)); *send_len = 0; - if (!skip_pipe_ready_check) - { /* Wait till connection pipe is ready for sending */ - assert(max_pipe_ready_wait->tv_sec == 0); /* all callers pass sub-second timeout. We take advantage of this fact - * to avoid division while computing wait_val */ - assert(max_pipe_ready_wait->tv_usec >= 0 && max_pipe_ready_wait->tv_usec < MICROSEC_IN_SEC); -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - FD_ZERO(&output_fds); - FD_SET(sock_fd, &output_fds); -#else - poll_fdlist[0].fd = sock_fd; - poll_fdlist[0].events = POLLOUT; - poll_nfds = 1; - poll_timeout = max_pipe_ready_wait->tv_usec / 1000; /* convert to millisecs */ -#endif - /* the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because EAGAIN is also - * being checked */ - for (timeout = *max_pipe_ready_wait, eintr_cnt = eagain_cnt = 0; -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - -1 == (status = select(sock_fd + 1, NULL, &output_fds, NULL, &timeout)) -#else - -1 == (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout)) -#endif - && (EINTR == errno || EAGAIN == errno); ) - { - if (EINTR == errno) - { - wait_val = (0 == eintr_cnt) ? (max_pipe_ready_wait->tv_usec >> 1) : (wait_val >> 1); - if (++eintr_cnt > REPL_COMM_MAX_INTR_CNT) - { /* assume timeout and give up. Note, this may result in a sleep different from intended. - * But, we can live with it as there is no impact on the user */ - status = 0; - break; - } - timeout.tv_sec = 0; - timeout.tv_usec = (gtm_tv_usec_t)wait_val; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT - poll_timeout = wait_val / 1000; /* convert to millisecs */ -#endif - REPL_DPRINT5("repl_send: select interrupted, changing timeout from tv_sec %ld tv_usec %ld to " - "tv_sec %ld tv_usec %ld\n", 0, (wait_val << 1), timeout.tv_sec, timeout.tv_usec); - } else - { /* resource starved system; relinquish the processor in the hope that we may get the required - * resources the next time around */ - if (0 == ++eagain_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL) - repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be " - "resource starved; EAGAIN returned from repl_send/select %d times\n", eagain_cnt); - rel_quant(); - } -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - FD_SET(sock_fd, &output_fds); /* Linux/gcc does not like this in the iterator */ -#endif - } - } else - status = 1; /* assume connection pipe is ready for sending */ - if (0 < status) - { /* Ready for sending */ - /* - * the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because other errno - * values are being checked. - */ + if (0 < (io_ready = fd_ioready(sock_fd, FALSE, timeout))) + { /* Trace last REPL_SEND_SIZE_TRACE_SIZE sizes of what was sent */ repl_send_size_trace[repl_send_size_trace_pos++] = send_size; repl_send_size_trace_pos %= ARRAYSIZE(repl_send_size_trace); /* Trace last REPL_SEND_TRACE_BUFF_SIZE bytes sent. */ - if (send_size > REPL_SEND_TRACE_BUFF_SIZE) + assert(0 < send_size); + REPL_TRACE_BUFF(repl_send_trace_buff, repl_send_trace_buff_pos, buff, send_size, REPL_SEND_TRACE_BUFF_SIZE); + /* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because other errno + * values are being checked. + */ + while (0 > (bytes_sent = send(sock_fd, (char *)buff, send_size, 0))) { - /* if the message size > our buffer just copy the last our buffer-size-worth starting from the - * beginning of our buffer and reset pos to the beginning of our buffer. - */ - memcpy(repl_send_trace_buff, buff + send_size - REPL_SEND_TRACE_BUFF_SIZE, REPL_SEND_TRACE_BUFF_SIZE); - repl_send_trace_buff_pos = 0; - } - else - { - space_to_end = REPL_SEND_TRACE_BUFF_SIZE - repl_send_trace_buff_pos; - if (send_size > space_to_end) - { - memcpy(repl_send_trace_buff + repl_send_trace_buff_pos, buff, space_to_end); - memcpy(repl_send_trace_buff, buff + space_to_end, send_size - space_to_end); - } - else - { - memcpy(repl_send_trace_buff + repl_send_trace_buff_pos, buff, send_size); - } - repl_send_trace_buff_pos = (repl_send_trace_buff_pos + send_size) % REPL_SEND_TRACE_BUFF_SIZE; - } - if (0 < send_size) - { - for (ewouldblock_cnt = emsgsize_cnt = 0; - (((bytes_sent = send(sock_fd, (char *)buff, send_size, 0)) < 0) - && (EINTR == errno || EMSGSIZE == errno || EWOULDBLOCK == errno)); ) - { - if (EINTR == errno) - continue; - assert(EMSGSIZE != errno); /* since we use blocking sockets, we don't expect to see EMSGSIZE */ - if (EMSGSIZE == errno) - { /* Reduce the send size if possible */ - if (send_size > REPL_COMM_MIN_SEND_SIZE) - { - if ((send_size >> 1) <= REPL_COMM_MIN_SEND_SIZE) - send_size = REPL_COMM_MIN_SEND_SIZE; - else - send_size >>= 1; - } - if (0 == ++emsgsize_cnt % REPL_COMM_LOG_EMSGSIZE_INTERVAL) - repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System " - "appears to be clogged; EMSGSIZE returned from send " - "%d times\n", emsgsize_cnt); - } else + save_errno = ERRNO; + assert((EMSGSIZE != save_errno) && (EWOULDBLOCK != save_errno)); + if (EINTR == save_errno) + continue; + if (EMSGSIZE == save_errno) + { /* Reduce the send size if possible */ + if (send_size > REPL_COMM_MIN_SEND_SIZE) { - if (0 == ++ewouldblock_cnt % REPL_COMM_LOG_EWDBLCK_INTERVAL) - repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System " - "appears to be running slow; EWOULDBLOCK returned from " - "send %d times\n", ewouldblock_cnt); - rel_quant(); /* we hope the cause for blocking would have cleared by the time - * we get scheduled next time around */ + if ((send_size >> 1) <= REPL_COMM_MIN_SEND_SIZE) + send_size = REPL_COMM_MIN_SEND_SIZE; + else + send_size >>= 1; } - } - } else - bytes_sent = 0; + if (0 == ++emsgsize_cnt % REPL_COMM_LOG_EMSGSIZE_INTERVAL) + { + repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be " + "clogged; EMSGSIZE returned from send %d times\n", emsgsize_cnt); + } + } else if (EWOULDBLOCK == save_errno) + { + if (0 == ++ewouldblock_cnt % REPL_COMM_LOG_EWDBLCK_INTERVAL) + { + repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be " + "running slow; EWOULDBLOCK returned from send %d times\n", ewouldblock_cnt); + } + rel_quant(); /* Relinquish our quanta in the hope that things get cleared next time around */ + } else + break; + } if (0 <= bytes_sent) { *send_len = (int)bytes_sent; REPL_DPRINT2("repl_send: returning with send_len %ld\n", bytes_sent); - return (SS_NORMAL); + return SS_NORMAL; } repl_errno = EREPL_SEND; - return (ERRNO); - } else if (0 == status) - return (SS_NORMAL); + return save_errno; + } else if (!io_ready) + return SS_NORMAL; + save_errno = ERRNO; repl_errno = EREPL_SELECT; - return (ERRNO); + return save_errno; } -int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_data_avail_check, struct timeval *max_data_avail_wait) -{ /* On entry *recv_len is the maximum length to be received. - * On exit, *recv_len will contain the number of bytes received. - */ - int status, max_recv_len, eintr_cnt, eagain_cnt; +int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, int timeout) +{ + int status, max_recv_len, eintr_cnt, eagain_cnt, io_ready, save_errno; ssize_t bytes_recvd; - long wait_val; - fd_set input_fds; - struct timeval timeout; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT - long poll_timeout; - unsigned long poll_nfds; - struct pollfd poll_fdlist[1]; -#endif - int space_to_end; if (!repl_recv_trace_buff) repl_recv_trace_buff = malloc(REPL_RECV_TRACE_BUFF_SIZE); @@ -277,70 +257,15 @@ int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_da */ assert(FD_INVALID != sock_fd); max_recv_len = *recv_len; - /* VMS returns SYSTEM-F-INVBUFLEN if max_recv_len is larger than the hard limit VMS_MAX_TCP_SEND_SIZE (64K - 1 on some - * impelementations, 64K - 512 on some others). Although VMS_MAX_TCP_RECV_SIZE may be larger than repl_max_recv_buffsize, - * we have empirically noticed recv() returning with repl_max_recv_buffsize or fewer bytes. + /* VMS returns SYSTEM-F-INVBUFLEN if send_size is larger than the hard limit VMS_MAX_TCP_RECV_SIZE (64K - 1 on some + * impelementations, 64K - 512 on some others). VMS_MAX_TCP_RECV_SIZE may be larger than repl_max_send_buffsize, and + * empirically we have noticed send() successfully sending repl_max_send_buffsize or more bytes. */ - VMS_ONLY(max_recv_len = MIN(max_recv_len, VMS_MAX_TCP_RECV_SIZE);) - REPL_DPRINT3("repl_recv: called with max_recv_len %d, limiting max_recv_len to %d\n", *recv_len, max_recv_len); + VMS_ONLY(max_recv_len = MIN(max_recv_len, VMS_MAX_TCP_RECV_SIZE)); *recv_len = 0; - if (!skip_data_avail_check) + if (0 < (io_ready = fd_ioready(sock_fd, TRUE, timeout))) { - assert(max_data_avail_wait->tv_sec == 0); /* all callers pass sub-second timeout. We take advantage of this fact - * to avoid division while computing wait_val */ - assert(max_data_avail_wait->tv_usec >= 0 && max_data_avail_wait->tv_usec < MICROSEC_IN_SEC); -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - FD_ZERO(&input_fds); - FD_SET(sock_fd, &input_fds); -#else - poll_fdlist[0].fd = sock_fd; - poll_fdlist[0].events = POLLIN; - poll_nfds = 1; - poll_timeout = max_data_avail_wait->tv_usec / 1000; /* convert to millisecs */ -#endif - /* the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because EAGAIN is also - * being checked */ - for (timeout = *max_data_avail_wait, eintr_cnt = eagain_cnt = 0; -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - -1 == (status = select(sock_fd + 1, &input_fds, NULL, NULL, &timeout)) -#else - -1 == (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout)) -#endif - && (EINTR == errno || EAGAIN == errno); ) - { - if (EINTR == errno) - { - wait_val = (0 == eintr_cnt) ? (max_data_avail_wait->tv_usec >> 1) : (wait_val >> 1); - if (++eintr_cnt > REPL_COMM_MAX_INTR_CNT) - { /* assume timeout and give up. Note, this may result in a sleep different from intended. - * But, we can live with it as there is no impact on the user */ - status = 0; - break; - } - timeout.tv_sec = 0; - timeout.tv_usec = (gtm_tv_usec_t)wait_val; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT - poll_timeout = wait_val / 1000; /* convert to millisecs */ -#endif - REPL_DPRINT5("repl_recv: select interrupted, changing timeout from tv_sec %ld tv_usec %ld to " - "tv_sec %ld tv_usec %ld\n", 0, (wait_val << 1), timeout.tv_sec, timeout.tv_usec); - } else - { /* resource starved system; relinquish the processor in the hope that we may get the required - * resources the next time around */ - if (0 == ++eagain_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL) - repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be " - "resource starved; EAGAIN returned from select %d times\n", eagain_cnt); - rel_quant(); - } -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - FD_SET(sock_fd, &input_fds); /* Linux/gcc does not like this in the iterator */ -#endif - } - } else - status = 1; /* assume data is available, consequence is recv() may block if data is not available */ - if (0 < status) - { /* Data available on the pipe */ - while (0 > (bytes_recvd = recv(sock_fd, (char *)buff, max_recv_len, 0)) && EINTR == errno) + while (0 > (bytes_recvd = recv(sock_fd, (char *)buff, max_recv_len, 0)) && EINTR == ERRNO) ; if (0 < bytes_recvd) { @@ -350,49 +275,34 @@ int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_da repl_recv_size_trace[repl_recv_size_trace_pos++] = bytes_recvd; repl_recv_size_trace_pos %= ARRAYSIZE(repl_recv_size_trace); /* Trace last REPL_RECV_TRACE_BUFF_SIZE bytes received. */ - if (bytes_recvd > REPL_RECV_TRACE_BUFF_SIZE) - { - /* if the message size > our buffer just copy the last our buffer-size-worth starting from the - * beginning of our buffer and reset pos to the beginning of our buffer. - */ - memcpy(repl_recv_trace_buff, buff + bytes_recvd - REPL_RECV_TRACE_BUFF_SIZE, + REPL_TRACE_BUFF(repl_recv_trace_buff, repl_recv_trace_buff_pos, buff, bytes_recvd, REPL_RECV_TRACE_BUFF_SIZE); - repl_recv_trace_buff_pos = 0; - } - else - { - space_to_end = REPL_RECV_TRACE_BUFF_SIZE - repl_recv_trace_buff_pos; - if (bytes_recvd > space_to_end) - { - memcpy(repl_recv_trace_buff + repl_recv_trace_buff_pos, buff, space_to_end); - memcpy(repl_recv_trace_buff, buff + space_to_end, bytes_recvd - space_to_end); - } - else - { - memcpy(repl_recv_trace_buff + repl_recv_trace_buff_pos, buff, bytes_recvd); - } - repl_recv_trace_buff_pos = (repl_recv_trace_buff_pos + bytes_recvd) % - REPL_RECV_TRACE_BUFF_SIZE; - } - return (SS_NORMAL); + return (SS_NORMAL); /* always process the received buffer before dealing with any errno */ } - if (0 == bytes_recvd) - { /* Connection reset */ - errno = ECONNRESET; - } else if (EWOULDBLOCK == errno) - { /* NOTE: Although we use non blocking sockets, it is possible to get EWOULDBLOCK error status if receive - * timeout has been set and the timeout expired before data was received (from man recv on RH 8 Linux). Some - * systems return ETIMEDOUT for the timeout condition. */ + save_errno = ERRNO; + if (0 == bytes_recvd) /* Connection reset */ + save_errno = errno = ECONNRESET; + else if (ETIMEDOUT == save_errno) + { + repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: network may be down;" + " socket recv() returned ETIMEDOUT\n"); + } else if (EWOULDBLOCK == save_errno) + { /* NOTE: Although we use blocking sockets, it is possible to get EWOULDBLOCK error status if receive timeout + * has been set and the timeout expired before data was received (from man recv on RH 8 Linux). Some systems + * return ETIMEDOUT for the timeout condition. + */ + assert(EWOULDBLOCK != save_errno); repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: network I/O failed to complete; " "socket recv() returned EWOULDBLOCK\n"); - errno = ETIMEDOUT; /* will be treated as a bad connection and the connection closed */ + save_errno = errno = ETIMEDOUT; /* will be treated as a bad connection and the connection closed */ } repl_errno = EREPL_RECV; - return (ERRNO); - } else if (0 == status) - return (SS_NORMAL); + return save_errno; + } else if (!io_ready) + return SS_NORMAL; + save_errno = ERRNO; repl_errno = EREPL_SELECT; - return (ERRNO); + return save_errno; } int repl_close(int *sock_fd) @@ -427,11 +337,11 @@ int get_recv_sock_buff_size(int sockfd, int *recv_buffsize) static int set_sock_buff_size(int sockfd, int buflen, int which_buf) { int status; -#ifndef sun +# ifndef sun size_t optlen; -#else +# else int optlen; -#endif +# endif optlen = SIZEOF(buflen); status = setsockopt(sockfd, SOL_SOCKET, which_buf, (void *)&buflen, (GTM_SOCKLEN_TYPE)optlen); return (0 == status) ? 0 : ERRNO; @@ -449,47 +359,55 @@ int set_recv_sock_buff_size(int sockfd, int buflen) void repl_log_conn_info(int sock_fd, FILE *log_fp) { - struct sockaddr_in local, remote; + struct sockaddr_storage local, remote; + struct sockaddr *local_sa_ptr, *remote_sa_ptr; GTM_SOCKLEN_TYPE len; int save_errno; - size_t errlen; - char *errptr, local_ip[16], remote_ip[16]; - in_port_t local_port, remote_port; - error_def(ERR_GETSOCKNAMERR); - error_def(ERR_TEXT); + char *errptr, local_ip[SA_MAXLEN], remote_ip[SA_MAXLEN]; + char port_buffer[NI_MAXSERV]; + char local_port_buffer[NI_MAXSERV], remote_port_buffer[NI_MAXSERV]; + int errcode; len = SIZEOF(local); - if (0 == getsockname(sock_fd, (struct sockaddr *)&local, (GTM_SOCKLEN_TYPE *)&len)) + local_sa_ptr = (struct sockaddr *)&local; + remote_sa_ptr = (struct sockaddr *)&remote; + if (0 == getsockname(sock_fd, local_sa_ptr, (GTM_SOCKLEN_TYPE *)&len)) { - local_port = ntohs(local.sin_port); - strcpy(local_ip, inet_ntoa(local.sin_addr)); + /* translate internal address to numeric ip address */ + GETNAMEINFO(local_sa_ptr, len, local_ip, SA_MAXLEN, local_port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); + if (0 != errcode) + { + repl_log(log_fp, TRUE, TRUE, "Error getting local name info: %s\n", gai_strerror(errcode)); + strcpy(local_port_buffer, "*UNKNOWN*"); + strcpy(local_ip, "*UNKNOWN*"); + } } else { save_errno = errno; errptr = (char *)STRERROR(save_errno); - errlen = strlen(errptr); - gtm_putmsg(VARLSTCNT(9) ERR_GETSOCKNAMERR, 3, save_errno, errlen, errptr, ERR_TEXT, 2, - LEN_AND_LIT("LOCAL")); - - local_port = (unsigned short)-1; + repl_log(log_fp, TRUE, TRUE, "Error getting local name: %s\n", errptr); + strcpy(local_port_buffer, "*UNKNOWN*"); strcpy(local_ip, "*UNKNOWN*"); } len = SIZEOF(remote); - if (0 == getpeername(sock_fd, (struct sockaddr *)&remote, (GTM_SOCKLEN_TYPE *)&len)) + if (0 == getpeername(sock_fd, remote_sa_ptr, (GTM_SOCKLEN_TYPE *)&len)) { - remote_port = ntohs(remote.sin_port); - strcpy(remote_ip, inet_ntoa(remote.sin_addr)); + GETNAMEINFO(remote_sa_ptr, len, remote_ip, SA_MAXLEN, remote_port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); + if (0 != errcode) + { + repl_log(log_fp, TRUE, TRUE, "Error getting remote name info: %s\n", gai_strerror(errcode)); + strcpy(remote_port_buffer, "*UNKNOWN*"); + strcpy(remote_ip, "*UNKNOWN*"); + } } else { save_errno = errno; errptr = (char *)STRERROR(save_errno); - errlen = strlen(errptr); - gtm_putmsg(VARLSTCNT(9) ERR_GETSOCKNAMERR, 3, save_errno, errlen, errptr, ERR_TEXT, 2, - LEN_AND_LIT("REMOTE")); - remote_port = (unsigned short)-1; + repl_log(log_fp, TRUE, TRUE, "Error getting remote name: %s\n", errptr); + strcpy(remote_port_buffer, "*UNKNOWN*"); strcpy(remote_ip, "*UNKNOWN*"); } - repl_log(log_fp, TRUE, TRUE, "Connection information:: Local: %s:%d Remote: %s:%d\n", local_ip, local_port, - remote_ip, remote_port); + repl_log(log_fp, TRUE, TRUE, "Connection information:: Local: %s:%s Remote: %s:%s\n", local_ip, local_port_buffer, + remote_ip, remote_port_buffer); return; } diff --git a/sr_port/repl_comm.h b/sr_port/repl_comm.h index 42900d2..ec8bc54 100644 --- a/sr_port/repl_comm.h +++ b/sr_port/repl_comm.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,11 +27,11 @@ * b. when repl_send() fails, in which case sent_len contains the number of bytes successfully sent, and tosend_len is the * length that we failed to send. */ -#define REPL_SEND_LOOP(SOCK_FD, BUFF, LEN, SKIP_PIPE_READY_CHECK, TIMEOUT) \ -assert(LEN > 0);\ -for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_len = (LEN); \ - SS_NORMAL == (status = repl_send(SOCK_FD, msg_ptr, &sent_this_iter, SKIP_PIPE_READY_CHECK, TIMEOUT)) \ - && ((sent_len += sent_this_iter), (tosend_len -= sent_this_iter), (tosend_len > 0)); \ +#define REPL_SEND_LOOP(SOCK_FD, BUFF, LEN, TIMEOUT) \ +assert(LEN > 0); \ +for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_len = (LEN); \ + SS_NORMAL == (status = repl_send(SOCK_FD, msg_ptr, &sent_this_iter, TIMEOUT)) \ + && ((sent_len += sent_this_iter), (tosend_len -= sent_this_iter), (tosend_len > 0)); \ msg_ptr += sent_this_iter, sent_this_iter = tosend_len) /* Use REPL_RECV_LOOP when the length of the msg to be recieved is already known @@ -48,10 +48,10 @@ for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_le * b. when repl_recv() fails, in which case recvd_len contains the number of bytes successfully received, and torecv_len is the * length that we failed to receive. */ -#define REPL_RECV_LOOP(SOCK_FD, BUFF, LEN, SKIP_DATA_AVAIL_CHECK, TIMEOUT) \ -for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_len = (LEN); \ - (SS_NORMAL == (status = repl_recv(SOCK_FD, msg_ptr, &recvd_this_iter, SKIP_DATA_AVAIL_CHECK, TIMEOUT))) \ - && ((recvd_len += recvd_this_iter), (torecv_len -= recvd_this_iter), (torecv_len > 0)); \ +#define REPL_RECV_LOOP(SOCK_FD, BUFF, LEN, TIMEOUT) \ +for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_len = (LEN); \ + (SS_NORMAL == (status = repl_recv(SOCK_FD, msg_ptr, &recvd_this_iter, TIMEOUT))) \ + && ((recvd_len += recvd_this_iter), (torecv_len -= recvd_this_iter), (torecv_len > 0)); \ msg_ptr += recvd_this_iter, recvd_this_iter = torecv_len) #define REPL_COMM_MAX_INTR_CNT 3 /* # of iterations we'll let select() be interrupted before we give up and assume timeout */ @@ -67,11 +67,14 @@ for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_ #define VMS_MAX_TCP_SEND_SIZE VMS_MAX_TCP_IO_SIZE #define VMS_MAX_TCP_RECV_SIZE VMS_MAX_TCP_IO_SIZE +#define GTMSOURCE_IDLE_POLL_WAIT 100 /* 100ms sleep in case nothing sent to the other side */ +#define REPL_POLL_WAIT (MILLISECS_IN_SEC - 1) /* Maximum time (in ms) for select()/poll() to timeout */ +#define REPL_POLL_NOWAIT 0 /* Forces poll()/select() to return immediately */ + /* Replication communcation subsystem function prototypes */ -int repl_send(int sock_fd, unsigned char *buff, int *send_len, boolean_t skip_pipe_ready_check, - struct timeval *max_pipe_ready_wait); -int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_data_avail_check, - struct timeval *max_data_avail_wait); +int fd_ioready(int sock_fd, boolean_t pollin, int timeout); +int repl_send(int sock_fd, unsigned char *buff, int *send_len, int timeout); +int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, int timeout); int repl_close(int *sock_fd); int get_send_sock_buff_size(int sockfd, int *buflen); int get_recv_sock_buff_size(int sockfd, int *buflen); diff --git a/sr_port/repl_ctl.h b/sr_port/repl_ctl.h index 5a0eaf9..aa2439b 100644 --- a/sr_port/repl_ctl.h +++ b/sr_port/repl_ctl.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,13 +15,14 @@ #ifdef GTM_CRYPT #include "gtmcrypt.h" /* for gtmcrypt_key_t type used in repl_ctl_element */ #endif -enum +typedef enum { JNL_FILE_UNREAD, JNL_FILE_OPEN, JNL_FILE_CLOSED, - JNL_FILE_EMPTY -}; /* jnl_file_state */ + JNL_FILE_EMPTY, + JNL_FILE_STATES +} jnl_file_state; typedef enum { @@ -46,6 +47,11 @@ typedef struct { uint4 buffremaining; /* Remaining buffer space */ unsigned char *base_buff; /* Actual malloced buffer start : Not necessarily "gtm_fs_block_size" aligned */ unsigned char *base; /* "gtm_fs_block_size" aligned buffer start */ +# ifdef DEBUG + uint4 save_readaddr; /* copy of readaddr before repl_read_file updates it */ + uint4 save_dskaddr; /* copy of dskaddr noted down, in repl_read_file, from shared memory */ + uint4 save_buffremaining; /* copy of buffremaining before repl_read_file updates it */ +# endif } repl_buff_desc; #define REPL_BLKSIZE(x) ((x)->fc->jfh->alignsize) diff --git a/sr_port/repl_filter.c b/sr_port/repl_filter.c index d793e73..c91897d 100644 --- a/sr_port/repl_filter.c +++ b/sr_port/repl_filter.c @@ -218,7 +218,8 @@ assert(SIZEOF(unsigned short) == SIZEOF(((struct_jrec_tcom *)NULL)->num_participants)); \ assert((unsigned short)num_participants); \ /* Below is a case of loss of precision but that's okay since we don't expect num_participants \ - * to exceed the unsigned short limit */ \ + * to exceed the unsigned short limit + */ \ *((unsigned short *)cb) = num_participants; \ cb += SIZEOF(unsigned short); \ /* Initialize jnl_tid from tmp_jnl_tid */ \ @@ -394,24 +395,29 @@ enum NON_REPLIC_JREC_TRIG /* This update was done inside of a trigger */ }; +/* Although V6.0-000 bumped up the journal format version from V22 to V23, there are no changes between the + * two's journal format structures. The reason for increasing the journal version + */ GBLDEF intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] = { - IF_22TO17, /* Convert from jnl ver V22 to jnl ver V17 */ - IF_22TO17, /* Convert from jnl ver V22 to jnl ver V18 */ - IF_22TO19, /* Convert from jnl ver V22 to jnl ver V19 */ - IF_22TO19, /* Convert from jnl ver V22 to jnl ver V20 */ - IF_22TO21, /* Convert from jnl ver V22 to jnl ver V21 */ - IF_22TO22 /* Convert from jnl ver V22 to jnl ver V22 */ + IF_22TO17, /* Convert from filter format V22 to V17 (i.e., from jnl ver V23 to V17) */ + IF_22TO17, /* Convert from filter format V22 to V17 (i.e., from jnl ver V23 to V18) */ + IF_22TO19, /* Convert from filter format V22 to V19 (i.e., from jnl ver V23 to V19) */ + IF_22TO19, /* Convert from filter format V22 to V19 (i.e., from jnl ver V23 to V20) */ + IF_22TO21, /* Convert from filter format V22 to V21 (i.e., from jnl ver V23 to V21) */ + IF_22TO22, /* Convert from filter format V22 to V22 (i.e., from jnl ver V23 to V22) */ + IF_22TO22 /* Convert from filter format V22 to V22 (i.e., from jnl ver V23 to V23) */ }; GBLDEF intlfltr_t repl_filter_old2cur[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1] = { - IF_17TO22, /* Convert from jnl ver V17 to jnl ver V22 */ - IF_17TO22, /* Convert from jnl ver V18 to jnl ver V22 */ - IF_19TO22, /* Convert from jnl ver V19 to jnl ver V22 */ - IF_19TO22, /* Convert from jnl ver V20 to jnl ver V22 */ - IF_21TO22, /* Convert from jnl ver V21 to jnl ver V22 */ - IF_22TO22 /* Convert from jnl ver V22 to jnl ver V22 */ + IF_17TO22, /* Convert from filter format V17 to V22 (i.e., from jnl ver V17 to V23) */ + IF_17TO22, /* Convert from filter format V17 to V22 (i.e., from jnl ver V18 to V23) */ + IF_19TO22, /* Convert from filter format V19 to V22 (i.e., from jnl ver V19 to V23) */ + IF_19TO22, /* Convert from filter format V19 to V22 (i.e., from jnl ver V20 to V23) */ + IF_21TO22, /* Convert from filter format V21 to V22 (i.e., from jnl ver V21 to V23) */ + IF_22TO22, /* Convert from filter format V22 to V22 (i.e., from jnl ver V22 to V23) */ + IF_22TO22 /* Convert from filter format V22 to V22 (i.e., from jnl ver V23 to V23) */ }; GBLREF unsigned int jnl_source_datalen, jnl_dest_maxdatalen; @@ -462,16 +468,16 @@ void jnl_extr_init(void) static void repl_filter_close_all_pipes(void) { - int close_res; + int close_res; if (FD_INVALID != repl_srv_filter_fd[READ_END]) - F_CLOSE(repl_srv_filter_fd[READ_END], close_res); /* resets "repl_srv_filter_fd[READ_END]" to FD_INVALID */ + F_CLOSE(repl_srv_filter_fd[READ_END], close_res); /* resets "repl_srv_filter_fd[READ_END]" to FD_INVALID */ if (FD_INVALID != repl_srv_filter_fd[WRITE_END]) - F_CLOSE(repl_srv_filter_fd[WRITE_END], close_res); /* resets "_CLOSE(repl_srv_filter_fd[WRITE_END]" to FD_INVALID */ + F_CLOSE(repl_srv_filter_fd[WRITE_END], close_res); /* resets "_CLOSE(repl_srv_filter_fd[WRITE_END]" to FD_INVALID */ if (FD_INVALID != repl_filter_srv_fd[READ_END]) - F_CLOSE(repl_filter_srv_fd[READ_END], close_res); /* resets "repl_filter_srv_fd[READ_END]" to FD_INVALID */ + F_CLOSE(repl_filter_srv_fd[READ_END], close_res); /* resets "repl_filter_srv_fd[READ_END]" to FD_INVALID */ if (FD_INVALID != repl_filter_srv_fd[WRITE_END]) - F_CLOSE(repl_filter_srv_fd[WRITE_END], close_res); /* resets "repl_filter_srv_fd[WRITE_END]" to FD_INVALID */ + F_CLOSE(repl_filter_srv_fd[WRITE_END], close_res); /* resets "repl_filter_srv_fd[WRITE_END]" to FD_INVALID */ } @@ -595,9 +601,9 @@ int repl_filter_init(char *filter_cmd) static int repl_filter_send(seq_num tr_num, unsigned char *tr, int tr_len, boolean_t first_send) { /* Send the transaction tr_num in buffer tr of len tr_len to the filter */ - ssize_t extr_len, sent_len; + ssize_t extr_len, sent_len; static ssize_t send_len; - char first_rectype, *extr_end; + char first_rectype, *extr_end; static char *send_ptr; if (TRUE == first_send) @@ -650,9 +656,9 @@ static int repl_filter_send(seq_num tr_num, unsigned char *tr, int tr_len, boole static int repl_filter_recv_line(char *line, int *line_len, int max_line_len, boolean_t send_done) { /* buffer input read from repl_filter_srv_fd[READ_END], return one line at a time; line separator is '\n' */ - int save_errno; - int status; - ssize_t l_len, r_len, buff_remaining ; + int save_errno; + int status; + ssize_t l_len, r_len, buff_remaining ; muextract_type exttype; fd_set input_fds; #ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT @@ -660,7 +666,7 @@ static int repl_filter_recv_line(char *line, int *line_len, int max_line_len, bo unsigned long poll_nfds; struct pollfd poll_fdlist[1]; #endif - struct timeval repl_filter_poll_interval; + struct timeval repl_filter_poll_interval; for (; ;) { @@ -696,7 +702,8 @@ static int repl_filter_recv_line(char *line, int *line_len, int max_line_len, bo if (0 < (buff_remaining = srv_buff_end - srv_read_end)) { /* since it is possible that this read could happen twice in this loop (no newline found) then - do a select/poll unless this is the first time and we know the previous select/poll is still valid. */ + * do a select/poll unless this is the first time and we know the previous select/poll is still valid. + */ if (FALSE == select_valid) { while(1) /* select/poll until ok to read or timeout */ @@ -806,7 +813,6 @@ static int repl_filter_recv(seq_num tr_num, unsigned char *tr, int *tr_len, bool } } - /* if not NULL record */ if ((NEED_TCOMMIT == recv_state) || (!is_nontp && !is_null && ('0' != extr_rec[0] || '0' != extr_rec[1]))) { @@ -820,6 +826,8 @@ static int repl_filter_recv(seq_num tr_num, unsigned char *tr, int *tr_len, bool GTMASSERT; /* why didn't we pre-allocate enough memory? */ return status; } + /* We don't want a null transaction inside a tp so get rid of it */ + if ('0' == extr_rec[0] && '0' == extr_rec[1]) continue; memcpy(recv_extract_buff + extr_len, extr_rec, extr_reclen); extr_len += extr_reclen; rec_cnt++; @@ -830,10 +838,11 @@ static int repl_filter_recv(seq_num tr_num, unsigned char *tr, int *tr_len, bool tcom_len = extr_reclen; rec_cnt--; } - /* if mini-transaction or fenced transaction not filtered out then convert it and - check for correct journal sequence number */ - /* if it is filtered out then take the else clause */ - if (is_nontp && ('0' != extr_rec[0] || '0' != extr_rec[1])) rec_cnt = 1; + /* If mini-transaction or fenced transaction not filtered out, then convert it and check for correct journal seq number. + * If it is filtered out, then take the else clause. + */ + if (is_nontp && (('0' != extr_rec[0]) || ('0' != extr_rec[1]))) + rec_cnt = 1; if (0 < rec_cnt) { extr_ptr = recv_extract_buff; @@ -854,23 +863,23 @@ static int repl_filter_recv(seq_num tr_num, unsigned char *tr, int *tr_len, bool } } extr_ptr[extr_len] = '\0'; /* terminate with null for ext2jnlcvt */ - if ((NULL == (tr_end = ext2jnlcvt(extr_ptr, extr_len, (jnl_record *)tr))) || (save_jnl_seqno != GET_JNL_SEQNO(tr)) + if ((NULL == (tr_end = ext2jnlcvt(extr_ptr, extr_len, (jnl_record *)tr, save_jnl_seqno, save_strm_seqno))) + || (save_jnl_seqno != GET_JNL_SEQNO(tr)) || (save_strm_seqno != GET_STRM_SEQNO(tr))) return (repl_errno = EREPL_FILTERBADCONV); *tr_len = (int4)(tr_end - (char *)&tr[0]); /* TCOM record for non TP converted to TP must have the same seqno as the original non TP record */ if (TRUE == unwrap_nontp && 1 < rec_cnt) - { - /* tr_end points past the tcom record so need to back up the length of the tcom record */ + { /* tr_end points past the tcom record so need to back up the length of the tcom record */ tcom_ptr = tr_end - TCOM_RECLEN; if (QWNE(save_jnl_seqno, ((struct_jrec_tcom *)tcom_ptr)->token_seq.jnl_seqno) || QWNE(save_strm_seqno, ((struct_jrec_tcom *)tcom_ptr)->strm_seqno)) return (repl_errno = EREPL_FILTERBADCONV); } } else /* 0 == rec_cnt */ - { /* Transaction filtered out, put a JRT_NULL record; the prefix.{pini_addr,time,tn} fields are not filled in as they are - * not relevant on the secondary - */ + { /* Transaction filtered out, put a JRT_NULL record; the prefix.{pini_addr,time,tn} fields are not filled in as they + * are not relevant on the secondary + */ QWASSIGN(null_jnlrec.jnl_seqno, save_jnl_seqno); QWASSIGN(null_jnlrec.strm_seqno, save_strm_seqno); memcpy(tr, (char *)&null_jnlrec, NULL_RECLEN); @@ -885,12 +894,12 @@ static int repl_filter_recv(seq_num tr_num, unsigned char *tr, int *tr_len, bool int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) { - int status; - boolean_t try_send = TRUE; - boolean_t try_recv = TRUE; - boolean_t send_done = FALSE; - boolean_t recv_done = FALSE; - boolean_t first_send = TRUE; + int status; + boolean_t try_send = TRUE; + boolean_t try_recv = TRUE; + boolean_t send_done = FALSE; + boolean_t recv_done = FALSE; + boolean_t first_send = TRUE; fd_set output_fds; fd_set input_fds; #ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT @@ -898,11 +907,11 @@ int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) unsigned long poll_nfds; struct pollfd poll_fdlist[1]; #endif - struct timeval repl_filter_poll_interval; + struct timeval repl_filter_poll_interval; /* */ recv_state = FIRST_RECV; - while (FALSE == send_done || FALSE == recv_done) + while ((FALSE == send_done) || (FALSE == recv_done)) { if ((FALSE == send_done) && (TRUE == try_send)) { @@ -945,7 +954,6 @@ int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) } status = repl_filter_send(tr_num, tr, *tr_len, first_send); first_send = FALSE; - /* MORE_TO_TRANSFER means more to transfer */ if (MORE_TO_TRANSFER == status) { try_recv = TRUE; @@ -955,15 +963,13 @@ int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) if (SS_NORMAL != status) return (status); else - { - /* send completed successfully */ + { /* send completed successfully */ send_done = TRUE; try_recv = TRUE; } } if ((FALSE == recv_done) && (TRUE == try_recv)) - { - /* if send is not done then do a select first */ + { /* if send is not done then do a select first */ if (FALSE == send_done) { repl_filter_poll_interval.tv_sec = 0; @@ -979,7 +985,7 @@ int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) #endif #ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT status = select(repl_filter_srv_fd[READ_END] + 1, &input_fds, NULL, NULL, - &repl_filter_poll_interval); + &repl_filter_poll_interval); #else status = poll(&poll_fdlist[0], poll_nfds, poll_timeout); #endif @@ -1002,7 +1008,6 @@ int repl_filter(seq_num tr_num, unsigned char *tr, int *tr_len, int bufsize) } status = repl_filter_recv(tr_num, tr, tr_len, send_done); - /* MORE_TO_TRANSFER means more to transfer */ if (MORE_TO_TRANSFER == status) { if (FALSE == send_done) @@ -1077,7 +1082,7 @@ void repl_check_jnlver_compat(UNIX_ONLY(boolean_t same_endianness)) assert(JNL_VER_EARLIEST_REPL <= REMOTE_JNL_VER); if (JNL_VER_EARLIEST_REPL > REMOTE_JNL_VER) rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, - LEN_AND_LIT("Dual/Multi site replication not supported between these two GT.M versions")); + LEN_AND_LIT("Dual/Multi site replication not supported between these two GT.M versions")); # ifdef UNIX else if ((V18_JNL_VER > REMOTE_JNL_VER) && !same_endianness) { /* cross-endian replication is supported only from V5.3-003 onwards. Issue error and shutdown. */ @@ -1093,7 +1098,7 @@ void repl_check_jnlver_compat(UNIX_ONLY(boolean_t same_endianness)) } static void upgrd_V19_hasht_xecute_string_to_V22(uchar_ptr_t jb, uchar_ptr_t cb, jnl_string *keystr, char *xecute_val_ptr, - uint4 *conv_reclen) + 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 @@ -1125,8 +1130,7 @@ static void upgrd_V19_hasht_xecute_string_to_V22(uchar_ptr_t jb, uchar_ptr_t cb, /* add 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. - */ + * -8 needed because "strm_seqno" is absent in source. */ *xecute_val_ptr++ = ' '; /* add the much needed */ memcpy(xecute_val_ptr, srcptr, valstrlen); /* copy the actual xecute string */ xecute_val_ptr += valstrlen; @@ -1190,7 +1194,7 @@ static void upgrd_V19_hasht_xecute_string_to_V22(uchar_ptr_t jb, uchar_ptr_t cb, * that JRT_ZTRIG records are allowed here. JRT_ZTRIG is very similar to a JRT_KILL record * in that it has a "struct_jrec_upd" layout and only the key/node (no value). * - * V22 format + * V22/V23 format * ----------- * struct_jrec_upd layout is as follows. * offset = 0000 [0x0000] size = 0024 [0x0018] ----> prefix @@ -1216,7 +1220,7 @@ static void upgrd_V19_hasht_xecute_string_to_V22(uchar_ptr_t jb, uchar_ptr_t cb, * offset = 0044 [0x002c] size = 0004 [0x0004] ----> suffix */ -/* Convert a transaction from jnl version 17 or 18 (V5.0-000 through V5.3-004A) to 22 (V5.5-000 onwards) +/* Convert a transaction from jnl version 17 or 18 (V5.0-000 through V5.3-004A) to 22/23 (V5.5-000 onwards) * Differences between the two versions: * ------------------------------------ * (a) struct_jrec_upd in V22 is 16 bytes more than V17 (8 byte strm_seqno, 4 byte update_num and 2 byte num_participants field). @@ -1319,7 +1323,7 @@ int jnl_v17TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return(status); } -/* Convert a transaction from jnl version 22 (V5.5-000 onwards) to 17 or 18 (V5.0-000 through V5.3-004A) +/* Convert a transaction from jnl version 22/23 (V5.5-000 onwards) to 17 or 18 (V5.0-000 through V5.3-004A) * For differences between the two versions, see the comment in jnl_v17TOv22. In addition, take care of the following. * (a) Since the remote side (V17) does NOT support triggers, skip ^#t, ZTWORM and ZTRIG journal records & reset nodeflags (if set). * If the entire transaction consists of skipped records, send a NULL record instead. @@ -1404,8 +1408,7 @@ int jnl_v22TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui if (IS_TUPD(rectype)) tupd_num++; else if (IS_UUPD(rectype) && promote_uupd_to_tupd) - { - /* The previous TUPD record was not replicated since it was a TZTWORM/TZTRIG record and + { /* The previous TUPD record was not replicated since it was a TZTWORM/TZTRIG record and * hence promote this UUPD to TUPD. Since the update process on the secondary will not care * about the num_participants field in the TUPD records (it cares about the num_participants * field only in the TCOM record), it is okay not to initialize the num_participants field @@ -1488,7 +1491,7 @@ int jnl_v22TOv17(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return(status); } -/* Convert a transaction from jnl version 19 or 20 (V5.4-000 through V5.4-001) to 22 (V5.5-000 onwards) +/* Convert a transaction from jnl version 19 or 20 (V5.4-000 through V5.4-001) to 22/23 (V5.5-000 onwards) * Differences between the two versions: * ------------------------------------ * (a) struct_jrec_upd, struct_jrec_tcom and struct_jrec_null in V22 is 8 bytes more than V19 (8 byte strm_seqno). @@ -1695,7 +1698,7 @@ int jnl_v19TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return(status); } -/* Convert a transaction from jnl version 22 (V5.5-000 onwards) to 19 or 20 (V5.4-000 through V5.4-001) +/* Convert a transaction from jnl version 22/23 (V5.5-000 onwards) to 19 or 20 (V5.4-000 through V5.4-001) * For differences between the two versions, see the comment in jnl_v19TOv22. In addition, take care of the following. * a) Skip ZTRIG records unconditionally as V19 (trigger enabled or not does not matter) does not support them. * b) If the remote side does NOT support triggers, then skip ^#t or ZTWORM journal records. @@ -1919,7 +1922,7 @@ int jnl_v22TOv19(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return status; } -/* Convert a transaction from jnl version 21 (V5.4-002 through V5.4-002B) to 22 (V5.5-000 onwards) +/* Convert a transaction from jnl version 21 (V5.4-002 through V5.4-002B) to 22/23 (V5.5-000 onwards) * Differences between the two versions: * ------------------------------------ * (a) struct_jrec_upd, struct_jrec_tcom and struct_jrec_null in V22 is 8 bytes more than V21 due to 8 byte strm_seqno. @@ -2102,7 +2105,7 @@ int jnl_v21TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return(status); } -/* Convert a transaction from jnl version 22 (V5.5-000 onwards) to 21 (V5.4-002 through V5.4-002B) +/* Convert a transaction from jnl version 22/23 (V5.5-000 onwards) to 21 (V5.4-002 through V5.4-002B) * For differences between the two versions, see the comment in jnl_v19TOv22. In addition, take care of the following. * (a) If the remote side does NOT support triggers, then skip ^#t or ZTWORM or ZTRIG journal records. * If the entire transaction consists of skipped records, send a NULL record instead. @@ -2266,7 +2269,8 @@ int jnl_v22TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui status = -1; } else { /* Create NULL record. Since the null record format is same for V17 and V21, it is safe to use the - * below macro. Note: Side-effect: cb is incremented by below macro */ + * below macro. Note: Side-effect: cb is incremented by below macro + */ INITIALIZE_V17_NULL_RECORD(prefix, cb, this_upd_seqno); } } @@ -2275,7 +2279,7 @@ int jnl_v22TOv21(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui return status; } -/* Convert a transaction from jnl version 22 (V5.5-000 onwards) to 22 (V5.5-000 onwards) +/* Convert a transaction from jnl version 22/23 (V5.5-000 onwards) to 22/23 (V5.5-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 or ZTWORM or ZTRIG journal records & reset nodeflags (if set). @@ -2290,7 +2294,7 @@ int jnl_v22TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui jrec_prefix *prefix; seq_num this_upd_seqno, this_strm_seqno; uint4 trigupd_type = NO_TRIG_JREC; - boolean_t promote_uupd_to_tupd, receiver_supports_triggers; + boolean_t promote_uupd_to_tupd, remote_supports_triggers; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -2300,11 +2304,15 @@ int jnl_v22TOv22(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; - assert(is_src_server); + /* The following assert ensures that filtering is initiated by the responsible party and in the expected direction, for the + * same function can be used for both V23->V22 and V23->V23 replication. In the case of V23->V22 it can be either the source + * or the receiver doing the filtering, so assert accordingly. + */ + assert(is_src_server || (LOCAL_JNL_VER > REMOTE_JNL_VER)); /* 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. */ - receiver_supports_triggers = REMOTE_TRIGGER_SUPPORT; + remote_supports_triggers = REMOTE_TRIGGER_SUPPORT; while (JREC_PREFIX_SIZE <= jlen) { assert(0 == ((UINTPTR_T)jb % SIZEOF(uint4))); @@ -2321,10 +2329,10 @@ int jnl_v22TOv22(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_V22 >= rectype); + assert(JRT_MAX_V23 >= rectype); if (IS_TUPD(rectype)) promote_uupd_to_tupd = FALSE; - if (!receiver_supports_triggers && (IS_ZTRIG(rectype) || IS_ZTWORM(rectype))) + if (!remote_supports_triggers && (IS_ZTRIG(rectype) || IS_ZTWORM(rectype))) { /* $ZTWORMHOLE jnl record cannot be handled by secondary which does not support triggers so skip converting. * If this is a TUPD rectype (actually JRT_TZTWORM/JRT_TZTRIG) then the next UUPD has to be promoted to a * TUPD type to account for the balance in TUPD and TCOM records @@ -2343,7 +2351,7 @@ int jnl_v22TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui { assert((jb == jstart) && (cb == cstart)); GET_JREC_UPD_TYPE((jb + FIXED_UPD_RECLEN), trigupd_type); - if (receiver_supports_triggers) + if (remote_supports_triggers) { if (NON_REPLIC_JREC_TRIG == trigupd_type) { @@ -2370,7 +2378,7 @@ int jnl_v22TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui } memcpy(cb, jb, conv_reclen); mumps_node_ptr = cb + FIXED_UPD_RECLEN; - if (!receiver_supports_triggers) + if (!remote_supports_triggers) ((jnl_string *)mumps_node_ptr)->nodeflags = 0; NULLSUBSC_TRANSFORM_IF_NEEDED(mumps_node_ptr + SIZEOF(jnl_str_len_t)); if (IS_TUPD(rectype)) @@ -2411,7 +2419,7 @@ int jnl_v22TOv22(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, ui { /* No conversion happened. Currently this is possible ONLY if the remote side does not support triggers and * all the records are trigger related records (^#t or ZTRIG or ZTWORM). Need to send NULL record instead. */ - assert(!receiver_supports_triggers); + assert(!remote_supports_triggers); GTMTRIG_ONLY( if (!(TREF(replgbl)).trig_replic_suspect_seqno) (TREF(replgbl)).trig_replic_suspect_seqno = this_upd_seqno; diff --git a/sr_port/repl_filter.h b/sr_port/repl_filter.h index 6751319..d0be232 100644 --- a/sr_port/repl_filter.h +++ b/sr_port/repl_filter.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,7 +19,12 @@ #define FILTERSTART_ERR -1 #define FILTER_CMD_ARG_DELIM_TOKENS " \t" -#define MAX_EXTRACT_BUFSIZ 1 * 1024 * 1024 +#ifdef UNIX +# define MAX_EXTRACT_BUFSIZ 10 * MAX_LOGI_JNL_REC_SIZE /* Since we might need up to 9X + 11 + * of MAX_LOGI_JNL_REC_SIZE */ +#else +# define MAX_EXTRACT_BUFSIZ 1 * 1024 * 1024 +#endif #define NO_FILTER 0 #define INTERNAL_FILTER 0x00000001 @@ -56,6 +61,7 @@ typedef int (*intlfltr_t)(uchar_ptr_t, uint4 *, uchar_ptr_t, uint4 *, uint4); * V19 V20 GT.M V5.4-001 64K journal file header change in Unix but V20 change for VMS too; No jnlrec format change * V21 V21 GT.M V5.4-002 Added replicated ZTRIGGER jnl record type * 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 */ typedef enum @@ -76,6 +82,7 @@ typedef enum REPL_JNL_V20, /* enum corresponding to journal format V20 */ REPL_JNL_V21, /* enum corresponding to journal format V21 */ REPL_JNL_V22, /* enum corresponding to journal format V22 */ + REPL_JNL_V23, /* enum corresponding to journal format V23 */ REPL_JNL_MAX } repl_jnl_t; @@ -134,18 +141,19 @@ GBLREF intlfltr_t repl_filter_cur2old[JNL_VER_THIS - JNL_VER_EARLIEST_REPL + 1]; #define V20_JNL_VER 20 #define V21_JNL_VER 21 #define V22_JNL_VER 22 +#define V23_JNL_VER 23 #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 */ -#define V21_NULL_RECLEN 40 /* size of a JRT_NULL record in V21/V22 jnl format */ -#define V22_NULL_RECLEN 48 /* size of a JRT_NULL record in V22 jnl format */ +#define V21_NULL_RECLEN 40 /* size of a JRT_NULL record in V21 jnl format */ +#define V22_NULL_RECLEN 48 /* size of a JRT_NULL record in V22/V23 jnl format */ #define V19_UPDATE_NUM_OFFSET 32 /* offset of "update_num" member in struct_jrec_upd structure in V19 jnl format */ #define V19_MUMPS_NODE_OFFSET 40 /* offset of "mumps_node" member in struct_jrec_upd structure in V19 jnl format */ #define V19_TCOM_FILLER_SHORT_OFFSET 32 /* offset of "filler_short" in struct_jrec_tcom structure in V19 jnl format */ #define V19_NULL_FILLER_OFFSET 32 /* offset of "filler" in struct_jrec_nullstructure in V19 jnl format */ -#define V22_MUMPS_NODE_OFFSET 48 /* offset of "mumps_node" member in struct_jrec_upd structure in V22 jnl format */ +#define V22_MUMPS_NODE_OFFSET 48 /* offset of "mumps_node" member in struct_jrec_upd struct in V22/V23 jnl format */ typedef struct { @@ -172,9 +180,9 @@ void repl_filter_error(seq_num filter_seqno, int why); GBLREF unsigned char jnl_ver, remote_jnl_ver; GBLREF boolean_t secondary_side_trigger_support; # define LOCAL_JNL_VER jnl_ver -# define LOCAL_TRIGGER_SUPPORT (DBG_ASSERT(is_rcvr_server) secondary_side_trigger_support) +# define LOCAL_TRIGGER_SUPPORT secondary_side_trigger_support # define REMOTE_JNL_VER remote_jnl_ver -# define REMOTE_TRIGGER_SUPPORT (DBG_ASSERT(is_src_server) secondary_side_trigger_support) +# define REMOTE_TRIGGER_SUPPORT secondary_side_trigger_support # define REMOTE_NULL_SUBS_XFORM (TREF(replgbl)).null_subs_xform # define REMOTE_IS_CROSS_ENDIAN FALSE # endif @@ -236,8 +244,8 @@ void repl_filter_error(seq_num filter_seqno, int why); rts_error(VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, &FILTER_SEQNO); \ else if (EREPL_INTLFILTER_MULTILINEXECUTE == repl_errno) \ rts_error(VARLSTCNT(3) ERR_REPLNOMULTILINETRG, 1, &FILTER_SEQNO); \ - else \ - GTMASSERT; \ + else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */ \ + assertpro(FALSE); \ } #else # define INT_FILTER_RTS_ERROR(FILTER_SEQNO) \ @@ -246,8 +254,8 @@ void repl_filter_error(seq_num filter_seqno, int why); rts_error(VARLSTCNT(1) ERR_REPLRECFMT); \ else if (EREPL_INTLFILTER_REPLGBL2LONG == repl_errno) \ rts_error(VARLSTCNT(1) ERR_REPLGBL2LONG); \ - else \ - GTMASSERT; \ + else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */ \ + assertpro(FALSE); \ } #endif #endif diff --git a/sr_port/repl_log.h b/sr_port/repl_log.h index dfe74f6..f3ec202 100644 --- a/sr_port/repl_log.h +++ b/sr_port/repl_log.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc.* + * Copyright 2001, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,8 +14,7 @@ typedef enum { - REPL_GENERAL_LOG, - REPL_STATISTICS_LOG + REPL_GENERAL_LOG } repl_log_file_t ; #define NULL_DEVICE "/dev/null" @@ -25,8 +24,7 @@ typedef enum int repl_log_fd2fp(FILE **fp, int fd); int repl_log(FILE *fp, boolean_t stamptime, boolean_t flush, char *fmt, ...); -int repl_log_init(repl_log_file_t log_type, int *log_fd, int *stats_fd, char *log, - char *stats_log); +int repl_log_init(repl_log_file_t log_type, int *log_fd, char *log); #define LOGTRNUM_INTERVAL 1000 /* default interval (jnlseqno count) at which source/receiver/upd log */ diff --git a/sr_port/resolve_ref.c b/sr_port/resolve_ref.c index 96e7425..c0ee025 100644 --- a/sr_port/resolve_ref.c +++ b/sr_port/resolve_ref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,11 +35,11 @@ error_def(ERR_ACTLSTTOOLONG); int resolve_ref(int errknt) { - triple *curtrip, *tripref, *chktrip; + triple *curtrip, *tripref, *chktrip, *ref, *y; tbp *tripbp; mline *mxl; mlabel *mlbx; - oprtype *opnd; + oprtype *opnd, *j, *k; int actcnt; DCL_THREADGBL_ACCESS; @@ -50,6 +50,73 @@ int resolve_ref(int errknt) walktree((mvar *)mlabtab, resolve_lab, (char *)&errknt); } else { + if (!run_time && (cmd_qlf.qlf & CQ_DYNAMIC_LITERALS)) + { /* OC_LIT --> OC_LITC wherever OC_LIT is actually used, i.e. not a dead end */ + dqloop(&t_orig, exorder, curtrip) + { + switch (curtrip->opcode) + { /* Do a few literal optimizations typically done later in alloc_reg. It's convenient to + * check for OC_LIT parameters here, before we start sliding OC_LITC opcodes in the way. + */ + case OC_NOOP: + case OC_PARAMETER: + case OC_LITC: /* possibly already inserted in bx_boolop */ + continue; + case OC_STO: /* see counterpart in alloc_reg.c */ + if ((cmd_qlf.qlf & CQ_INLINE_LITERALS) + && (TRIP_REF == curtrip->operand[1].oprclass) + && (OC_LIT == curtrip->operand[1].oprval.tref->opcode)) + { + curtrip->opcode = OC_STOLITC; + continue; + } + break; + case OC_EQU: /* see counterpart in alloc_reg.c */ + if ((TRIP_REF == curtrip->operand[0].oprclass) + && (OC_LIT == curtrip->operand[0].oprval.tref->opcode) + && (0 == curtrip->operand[0].oprval.tref->operand[0].oprval.mlit->v.str.len)) + { + curtrip->operand[0] = curtrip->operand[1]; + curtrip->operand[1].oprclass = NO_REF; + curtrip->opcode = OC_EQUNUL; + continue; + } else if ((TRIP_REF == curtrip->operand[1].oprclass) + && (OC_LIT == curtrip->operand[1].oprval.tref->opcode) + && (0 == curtrip->operand[1].oprval.tref->operand[0].oprval.mlit->v.str.len)) + { + curtrip->operand[1].oprclass = NO_REF; + curtrip->opcode = OC_EQUNUL; + continue; + } + break; + } + for (j = curtrip->operand, y = curtrip; j < ARRAYTOP(y->operand); ) + { /* Iterate over all parameters of the current triple */ + k = j; + while (INDR_REF == k->oprclass) + k = k->oprval.indr; + if (TRIP_REF == k->oprclass) + { + tripref = k->oprval.tref; + if (OC_PARAMETER == tripref->opcode) + { + y = tripref; + j = y->operand; + continue; + } + if (OC_LIT == tripref->opcode) + { /* Insert an OC_LITC to relay the OC_LIT result to curtrip */ + ref = maketriple(OC_LITC); + ref->src = tripref->src; + ref->operand[0] = put_tref(tripref); + dqins(curtrip->exorder.bl, exorder, ref); + *k = put_tref(ref); + } + } + j++; + } + } + } COMPDBG(PRINTF(" ************************************* Begin resolve_ref scan ******************************\n");); dqloop(&t_orig, exorder, curtrip) { diff --git a/sr_port/rtnlaboff2entryref.c b/sr_port/rtnlaboff2entryref.c index 9c177f9..bc53bb6 100644 --- a/sr_port/rtnlaboff2entryref.c +++ b/sr_port/rtnlaboff2entryref.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include /* Format the given routine, label and offset into user presentable label+offset^routine string, * return end of formatted output + 1. Does not check for buffer overflow, it's caller's diff --git a/sr_port/s2n.c b/sr_port/s2n.c index 90e0ed8..688d7e9 100644 --- a/sr_port/s2n.c +++ b/sr_port/s2n.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,8 +14,8 @@ #include "arit.h" #include "stringpool.h" -#define DIGIT(x) ( x >='0' && x <= '9' ) -#define NUM_MASK ( MV_NM | MV_INT | MV_NUM_APPROX ) +#define DIGIT(x) ((x >='0') && (x <= '9')) +#define NUM_MASK (MV_NM | MV_INT | MV_NUM_APPROX) error_def(ERR_NUMOFLOW); @@ -24,9 +24,9 @@ LITREF int4 ten_pwr[]; char *s2n (mval *u) { - char *c, *d, *w, *eos; - int i, j, k, x, y, z, sign, zero, expdigits; - boolean_t digit, dot, exp, exneg, tail, dotseen, isdot; + boolean_t digit, dot, dotseen, exp, exneg, isdot, tail; + char *c, *d, *eos, *w; + int expdigits, i, j, k, sign, x, y, z, zero; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -35,21 +35,21 @@ char *s2n (mval *u) GTMASSERT; c = u->str.addr; if (0 == u->str.len) - { + { /* Substitute pre-converted NULL/0 value */ TREF(s2n_intlit) = 1; *u = literal_null; return c; } - eos = u->str.addr + u->str.len; + eos = u->str.addr + u->str.len; /* End of string marker */ sign = 0; while (c < eos && (('-'== *c) || ('+' == *c))) - sign += (('-' == *c++) ? 1 : 2); - for (zero = 0; (c < eos) && ('0'== *c ); zero++, c++) + sign += (('-' == *c++) ? 1 : 2); /* Sign is odd: negative, even: positive */ + for (zero = 0; (c < eos) && ('0'== *c ); zero++, c++) /* Eliminate leading zeroes */ ; dot = ((c < eos) && ('.' == *c)); if (dot) c++; - for (y = 0; (c < eos) && ('0' == *c ); c++, y--) + for (y = 0; (c < eos) && ('0' == *c ); c++, y--) /* Eliminate leading zeroes of possible fractional part */ ; z = u->m[0] = u->m[1] = 0; /* R0 */ d = c + 9; @@ -81,7 +81,8 @@ char *s2n (mval *u) u->m[1] *= 10; i++; } else - { i = 0; + { + i = 0; u->m[1] = (u->m[1] * 10) + (*c - '0'); } } /* R2 */ @@ -107,8 +108,7 @@ char *s2n (mval *u) ; } tail = (c != eos) || (dot && (('0' == *(c - 1)) || ('.' == *(c - 1)))); - dotseen = FALSE; - for ( ; (c < eos) && ((isdot = ('.' == *c)) || DIGIT(*c)); c++) + for (dotseen = dot; (c < eos) && (((isdot = ('.' == *c)) && !dot) || DIGIT(*c)); c++) { dotseen = (dotseen || isdot); if (!dotseen) @@ -117,7 +117,7 @@ char *s2n (mval *u) digit = (0 != z) || (0 != y) || (0 != zero); x = 0; exp = ('E' == *c) && digit; - if (exp && (c+1 < eos)) + if (exp && ((c + 1) < eos)) { c++; exneg = ('-' == *c); @@ -171,7 +171,7 @@ char *s2n (mval *u) ? (MV_NM | MV_NUM_APPROX) : MV_NM; } } - assert(u->m[1] < MANT_HI); + assert(MANT_HI > u->m[1]); } else { u->mvtype |= (MV_NM | MV_INT | MV_NUM_APPROX); diff --git a/sr_port/sec_shr_map_build.c b/sr_port/sec_shr_map_build.c index cd6f80a..7e11964 100644 --- a/sr_port/sec_shr_map_build.c +++ b/sr_port/sec_shr_map_build.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,14 +20,21 @@ #include "gdsbml.h" #include "probe.h" #include "sec_shr_map_build.h" +#include "min_max.h" int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr, cw_set_element *cs, trans_num ctn, int bplmap) { - boolean_t busy, recycled; uint4 setbit; unsigned char *ptr; - sgmnt_data_ptr_t csd; uint4 bitnum, ret, prev; +#ifdef UNIX + uint4 (*bml_func)(); +#else /* gtmsecshr on VMS uses a very minimal set of modules so we dont want to pull in bml_*() functions there + * and hence avoid using function pointers + */ + uint4 bml_func; + uint4 bml_busy = 1, bml_free = 2, bml_recycled = 3; +#endif #ifdef DEBUG int4 prev_bitnum, actual_cnt = 0; #endif @@ -41,22 +48,23 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr, assert(FALSE); return FALSE; } - busy = (cs->reference_cnt > 0); - if (!busy) + /* The following PROBE's are needed before DETERMINE_BML_FUNC, as the macro uses these pointers. */ + if (!GTM_PROBE(SIZEOF(sgmnt_addrs), csa, READ)) { - if (!GTM_PROBE(SIZEOF(sgmnt_addrs), csa, READ)) - { - assert(FALSE); - return FALSE; - } - csd = csa->hdr; - if (!GTM_PROBE(SIZEOF(sgmnt_data), csd, READ)) - { - assert(FALSE); - return FALSE; - } - recycled = csd->db_got_to_v5_once ? TRUE : FALSE; + assert(FALSE); + return FALSE; } + if (!(GTM_PROBE(NODE_LOCAL_SIZE_DBS, csa->nl, WRITE))) + { + assert(FALSE); + return FALSE; + } + if (!GTM_PROBE(SIZEOF(sgmnt_data), csa->hdr, READ)) + { + assert(FALSE); + return FALSE; + } + DETERMINE_BML_FUNC(bml_func, cs, csa); DEBUG_ONLY(prev_bitnum = -1;) for (;;) { @@ -82,7 +90,7 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr, return FALSE; } setbit &= 7; - if (busy) + if (bml_busy == bml_func) { *ptr &= ~(3 << setbit); /* mark block as BUSY (00) */ DEBUG_ONLY(actual_cnt++); @@ -93,7 +101,7 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr, if (!prev) actual_cnt--; ) - if (recycled) + if (bml_recycled == bml_func) *ptr |= (3 << setbit); /* mark block as RECYCLED (11) */ else { /* mark block as FREE (01) */ diff --git a/sr_port/secshr_db_clnup.c b/sr_port/secshr_db_clnup.c index 2f02006..b1bbf68 100644 --- a/sr_port/secshr_db_clnup.c +++ b/sr_port/secshr_db_clnup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,6 +70,8 @@ #ifdef GTM_SNAPSHOT #include "db_snapshot.h" #endif +#include "muextr.h" +#include "mupip_reorg.h" /* This section documents DOs and DONTs about code used by GTMSECSHR on Alpha VMS. Any module linked into GTMSECSHR (see * secshrlink.axp for the current list) must follow certain rules as GTMSECSHR provides user-defined system services @@ -130,7 +132,7 @@ #else # define SALVAGE_UNIX_LATCH_DBCRIT(X, is_exiting, wcblocked) \ { /* "wcblocked" is relevant only if X is the database crit semaphore. In this case, BEFORE salvaging crit, \ - * (but AFTER ensuring the previous holder pid is dead) we need to set csa->hdr->wc_blocked to TRUE to \ + * (but AFTER ensuring the previous holder pid is dead) we need to set cnl->wc_blocked to TRUE to \ * ensure whoever grabs crit next does a cache-recovery. This is necessary in case previous holder of crit \ * had set some cr->in_cw_set to a non-zero value. Not doing cache recovery could cause incorrect GTMASSERTs \ * in PIN_CACHE_RECORD macro in t_end/tp_tend. \ @@ -153,8 +155,8 @@ } /* The SALVAGE_UNIX_LATCH macro needs to do exactly the same thing as done by the SALVAGE_UNIX_LATCH_DBCRIT \ - * macro except that we dont need any special set of wcblocked to TRUE. So we pass in a dummy variable \ - * (instead of csa->hdr->wc_blocked) to be set to TRUE in case the latch is salvaged. \ + * macro except that we dont need any special set of wc_blocked to TRUE. So we pass in a dummy variable \ + * (instead of cnl->wc_blocked) to be set to TRUE in case the latch is salvaged. \ */ \ #define SALVAGE_UNIX_LATCH(X, is_exiting) \ { \ @@ -224,7 +226,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) boolean_t tp_update_underway = FALSE; /* set to TRUE if TP commit was in progress or complete */ boolean_t non_tp_update_underway = FALSE; /* set to TRUE if non-TP commit was in progress or complete */ boolean_t update_underway = FALSE; /* set to TRUE if either TP or non-TP commit was underway */ - boolean_t set_wc_blocked = FALSE; /* set to TRUE if csd->wc_blocked needs to be set */ + boolean_t set_wc_blocked = FALSE; /* set to TRUE if cnl->wc_blocked needs to be set */ boolean_t dont_reset_data_invalid; /* set to TRUE in case cr->data_invalid was TRUE in phase2 */ int max_bts; unsigned int lcnt; @@ -259,7 +261,11 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) snapshot_context_ptr_t lcl_ss_ctx; cache_rec_ptr_t snapshot_cr; ) +# ifdef UNIX + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; +# endif if (NULL == get_next_gdr_addrs) return; /* @@ -290,7 +296,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) * the logic for determining whether it is a ROLL-BACK or a ROLL-FORWARD needs to also be in secshr_db_clnup. * If it is determined that a ROLL-FORWARD needs to be done, secshr_db_clnup takes care of it by itself. * But if a ROLL-BACK needs to be done, then secshr_db_clnup DOES NOT invoke t_commit_cleanup. - * Instead it sets csd->wc_blocked to TRUE thereby ensuring the next process that gets CRIT does a cache recovery + * Instead it sets cnl->wc_blocked to TRUE thereby ensuring the next process that gets CRIT does a cache recovery * which will take care of doing more than the ROLL-BACK that t_commit_cleanup would have otherwise done. * * The logic for determining if it is a ROLL-BACK or ROLL-FORWARD is explained below. @@ -1029,8 +1035,8 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) * rely on precomputed value csa->backup_in_prog since it is not initialized * if (cw_depth == 0) (see t_end.c). Hence using cnl->nbb explicitly in check. * However, for snapshots we can rely on csa as it is computed under - * if (update_trans). Use cs->was_free to ensure that FREE blocks are not - * back'ed up either by secshr_db_clnup or wcs_recover. + * if (update_trans). Use cs->blk_prior_state's free status to ensure that FREE + * blocks are not back'ed up either by secshr_db_clnup or wcs_recover. */ if ((SNAPSHOTS_IN_PROG(csa) || (BACKUP_NOT_IN_PROGRESS != cnl->nbb)) && (NULL != cs->old_block)) @@ -1067,7 +1073,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) # endif /* wcs_recover need not copy before images of FREE blocks * to the backup buffer */ - if (!cs->was_free) + if (!WAS_FREE(cs->blk_prior_state)) cr->twin = GDS_ANY_ABS2REL(csa, cs->old_block); } else { /* We have to finish phase2 update. @@ -1083,7 +1089,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) blk_hdr_ptr = (blk_hdr_ptr_t)cs->old_block; assert(GDS_ANY_REL2ABS(csa, cr->buffaddr) == (sm_uc_ptr_t)blk_hdr_ptr); - if (!cs->was_free && (cr->blk >= cnl->nbb) + if (!WAS_FREE(cs->blk_prior_state) && (cr->blk >= cnl->nbb) && (0 == csa->shmpool_buffer->failed) && (blk_hdr_ptr->tn < csa->shmpool_buffer->backup_tn) && (blk_hdr_ptr->tn >= csa->shmpool_buffer->inc_backup_tn)) @@ -1172,7 +1178,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) blk_ptr = (sm_uc_ptr_t)GDS_ANY_REL2ABS(csa, cr->buffaddr); } else { /* access method is MM */ - blk_ptr = (sm_uc_ptr_t)csa->acc_meth.mm.base_addr + csd->blk_size * cs->blk; + blk_ptr = MM_BASE_ADDR(csa) + (off_t)csd->blk_size * cs->blk; if (!GTM_PROBE(csd->blk_size, blk_ptr, WRITE)) { SECSHR_ACCOUNTING(7); @@ -1181,7 +1187,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) SECSHR_ACCOUNTING(cs->blk); SECSHR_ACCOUNTING((INTPTR_T)blk_ptr); SECSHR_ACCOUNTING(csd->blk_size); - SECSHR_ACCOUNTING((INTPTR_T)csa->acc_meth.mm.base_addr); + SECSHR_ACCOUNTING((INTPTR_T)(MM_BASE_ADDR(csa))); assert(FALSE); continue; } @@ -1579,6 +1585,10 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) CAREFUL_INCR_KIP(csd, csa, *kip_csa_addrs); *need_kip_incr_addrs = FALSE; } +# ifdef UNIX + if (MUSWP_INCR_ROOT_CYCLE == TREF(in_mu_swap_root_state)) + cnl->root_search_cycle++; +# endif } } /* if (NULL != first_cw_set) */ /* If the process is about to exit AND any kills are in progress (bitmap freeup phase of kill), mark @@ -1614,6 +1624,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) */ if (kip_csa_usable && (NULL != si->kill_set_head) && (NULL != si->kip_csa)) { + assert(csa == si->kip_csa); CAREFUL_DECR_KIP(csd, csa, si->kip_csa); CAREFUL_INCR_ABANDONED_KILLS(csd, csa); } else @@ -1624,8 +1635,9 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) (GTM_PROBE(SIZEOF(*kip_csa_addrs), kip_csa_addrs, WRITE)) ? TRUE : FALSE; assert(kip_csa_usable); - if (kip_csa_usable && (NULL != *kip_csa_addrs)) + if (kip_csa_usable && (NULL != *kip_csa_addrs) && (csa == *kip_csa_addrs)) { + assert(0 < (*kip_csa_addrs)->hdr->kill_in_prog); CAREFUL_DECR_KIP(csd, csa, *kip_csa_addrs); CAREFUL_INCR_ABANDONED_KILLS(csd, csa); } @@ -1696,7 +1708,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) * so set wc_blocked. This case is folded into phase2 cleanup case below. * if set_wc_blocked is TRUE, need to clean up queues after phase2 commits. */ - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); if (csa->now_crit) { wcblocked_ptr = WCBLOCKED_NOW_CRIT_LIT; @@ -1734,7 +1746,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) csd->trans_hist.early_tn = csd->trans_hist.curr_tn; } assert(csd->trans_hist.early_tn == csd->trans_hist.curr_tn); - if (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE)) + if (GTM_PROBE(CRIT_SPACE(NUM_CRIT_ENTRY(csd)), csa->critical, WRITE)) { /* ONLINE ROLLBACK can come here holding crit ONLY due to commit errors but NOT during * process exiting as secshr_db_clnup during process exiting is always preceded by @@ -1780,7 +1792,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) SECSHR_ACCOUNTING((INTPTR_T)cnl); SECSHR_ACCOUNTING(NODE_LOCAL_SIZE_DBS); SECSHR_ACCOUNTING((INTPTR_T)csa->critical); - SECSHR_ACCOUNTING(CRIT_SPACE); + SECSHR_ACCOUNTING(CRIT_SPACE(NUM_CRIT_ENTRY(csd))); assert(FALSE); } } @@ -1816,11 +1828,11 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) } #ifdef UNIX /* All releases done now. Double check latch is really cleared */ - if (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE)) + if (GTM_PROBE(CRIT_SPACE(NUM_CRIT_ENTRY(csd)), csa->critical, WRITE)) { /* as long as csa->hold_onto_crit is FALSE, we should have released crit if we held it at entry */ assert(!csa->now_crit || csa->hold_onto_crit); - SALVAGE_UNIX_LATCH_DBCRIT(&csa->critical->semaphore, is_exiting, csa->hdr->wc_blocked); + SALVAGE_UNIX_LATCH_DBCRIT(&csa->critical->semaphore, is_exiting, cnl->wc_blocked); SALVAGE_UNIX_LATCH(&csa->critical->crashcnt_latch, is_exiting); SALVAGE_UNIX_LATCH(&csa->critical->prochead.latch, is_exiting); SALVAGE_UNIX_LATCH(&csa->critical->freehead.latch, is_exiting); @@ -1835,8 +1847,6 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) SECSHR_PROBE_REGION(reg); /* SECSHR_PROBE_REGION sets csa */ if (csa->now_crit) { - assert(NORMAL_TERMINATION != secshr_state); /* for normal termination we should not - * have been holding the journal pool crit lock */ jpl = (jnlpool_ctl_ptr_t)((sm_uc_ptr_t)csa->critical - JNLPOOL_CTL_SIZE); /* see jnlpool_init() for * relationship between * critical and jpl */ @@ -1878,10 +1888,20 @@ void secshr_db_clnup(enum secshr_db_state secshr_state) * commit flow */ } } +#ifdef DEBUG + else if (jpl->early_write_addr > jpl->write_addr) + { /* PRO code will do the right thing by overwriting that exact space in the jnlpool with + * the current transaction's journal records. For dbg though, it is better if + * secshr_db_clnup (which is invoked as part of exit handling) does the cleanup. + */ + assert(!update_underway); + jpl->early_write_addr = jpl->write_addr; + } +#endif } cnl = csa->nl; if ((GTM_PROBE(NODE_LOCAL_SIZE_DBS, cnl, WRITE)) && - (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE))) + (GTM_PROBE(JNLPOOL_CRIT_SPACE, csa->critical, WRITE))) { /* ONLINE ROLLBACK can come here holding crit ONLY due to commit errors but NOT during * process exiting as secshr_db_clnup during process exiting is always preceded by diff --git a/sr_port/send_msg.h b/sr_port/send_msg.h index 9c0e13b..52e4962 100644 --- a/sr_port/send_msg.h +++ b/sr_port/send_msg.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,12 @@ #ifndef SEND_MSG_included #define SEND_MSG_included -void send_msg(UNIX_ONLY(int arg_count) VMS_ONLY(int msg_id_arg), ...); +#if defined(UNIX) +void send_msg(int arg_count, ...); +void send_msg_csa(void *csa, int arg_count, ...); /* Use CSA_ARG(CSA) for portability */ +#elif defined(VMS) +void send_msg(int msg_id_arg, ...); +#define send_msg_csa send_msg +#endif #endif /* SEND_MSG_included */ diff --git a/sr_port/set_jnl_info.c b/sr_port/set_jnl_info.c index 3dffe45..afbb6d0 100644 --- a/sr_port/set_jnl_info.c +++ b/sr_port/set_jnl_info.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,7 +35,7 @@ void set_jnl_info(gd_region *reg, jnl_create_info *jnl_info) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; - uint4 align_autoswitch; + uint4 align_autoswitch, autoswitch_increase; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; @@ -50,13 +50,14 @@ void set_jnl_info(gd_region *reg, jnl_create_info *jnl_info) assert(csd->jnl_buffer_size); assert(csd->epoch_interval); jnl_info->csd = csd; + jnl_info->csa = csa; /* note that csd->jnl_deq can be 0 since a zero journal extension size is accepted */ jnl_info->status = jnl_info->status2 = SS_NORMAL; jnl_info->no_rename = jnl_info->no_prev_link = FALSE; UNIX_ONLY( if ((JNL_MIN_ALIGNSIZE * DISK_BLOCK_SIZE) > csd->alignsize) - { /* Possible if a pre-V54001 journaled db (which allows alignsize to be as low as 16K) is used - * with V54001 and higher (where minimum allowed alignsize is 128K). Fix fileheader to be + { /* Possible due to the smaller JNL_MIN_ALIGNSIZE used in previous (pre-V60000) versions + * as opposed to the current alignsize of 2MB. Fix fileheader to be * at least minimum (i.e. an on-the-fly upgrade of the db file header). */ csd->alignsize = (JNL_MIN_ALIGNSIZE * DISK_BLOCK_SIZE); @@ -89,7 +90,6 @@ void set_jnl_info(gd_region *reg, jnl_create_info *jnl_info) ) jnl_info->alloc = csd->jnl_alq; jnl_info->extend = csd->jnl_deq; - jnl_info->autoswitchlimit = csd->autoswitchlimit; /* ensure autoswitchlimit is aligned to the nearest extension boundary * since set_jnl_info only uses already established allocation/extension/autoswitchlimit values, * as long as the establisher (MUPIP SET JOURNAL/MUPIP CREATE) ensures that autoswitchlimit is aligned @@ -99,6 +99,16 @@ void set_jnl_info(gd_region *reg, jnl_create_info *jnl_info) * but now with autoswitchlimit being aligned at an extension boundary, they can * compare their journal requirements directly against the autoswitchlimit. */ + align_autoswitch = ALIGNED_ROUND_DOWN(csd->autoswitchlimit, csd->jnl_alq, csd->jnl_deq); + if (align_autoswitch != csd->autoswitchlimit) + { /* round down specified autoswitch to be aligned at a journal extension boundary */ + assert(align_autoswitch < csd->autoswitchlimit || !csd->jnl_deq); + autoswitch_increase = ((0 < csd->jnl_deq) ? csd->jnl_deq : DISK_BLOCK_SIZE); + while (JNL_AUTOSWITCHLIMIT_MIN > align_autoswitch) + align_autoswitch += autoswitch_increase; + csd->autoswitchlimit = align_autoswitch; + } + jnl_info->autoswitchlimit = csd->autoswitchlimit; assert(jnl_info->autoswitchlimit == ALIGNED_ROUND_DOWN(jnl_info->autoswitchlimit, jnl_info->alloc, jnl_info->extend)); jnl_info->blks_to_upgrd = csd->blks_to_upgrd; /* will be copied over to EPOCH record in newly created journal */ jnl_info->free_blocks = csd->trans_hist.free_blocks; /* will be copied over to EPOCH record in newly created journal */ diff --git a/sr_port/setzdir.c b/sr_port/setzdir.c index ca26409..a0d3888 100644 --- a/sr_port/setzdir.c +++ b/sr_port/setzdir.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,25 +17,26 @@ #include "gtm_limits.h" #include +#include "have_crit.h" #include "setzdir.h" UNSUPPORTED_PLATFORM_CHECK static char directory_buffer[GTM_MAX_DIR_LEN]; -void setzdir(mval *newdir, mval *full_path_of_newdir) -{ /* newdir is the directory to change to; NULL to set full_path_of_newdir to current working directory. - * If full_path_of_newdir is non NULL, return the full path of the new directory in full_path_of_newdir. - * NOTE : the full path of directory is stored in a static buffer which might get overwritten by the next call to setzdir. - * Callers should save return value if needed. */ +error_def(ERR_SETZDIR); +error_def(ERR_SYSCALL); +error_def(ERR_TEXT); +void setzdir(mval *newdir, mval *full_path_of_newdir) +{ /* newdir is the directory to change to; NULL to set full_path_of_newdir to current working directory. + * If full_path_of_newdir is non NULL, return the full path of the new directory in full_path_of_newdir. + * NOTE : the full path of directory is stored in a static buffer which might get overwritten by the next call to setzdir. + * Callers should save return value if needed. + */ char directory[GTM_MAX_DIR_LEN], *getcwd_res, *err_str; uint4 length, status; - error_def(ERR_SETZDIR); - error_def(ERR_SYSCALL); - error_def(ERR_TEXT); - assert(NULL != newdir || NULL != full_path_of_newdir); if (NULL != newdir) { @@ -44,27 +45,29 @@ void setzdir(mval *newdir, mval *full_path_of_newdir) memcpy(directory, newdir->str.addr, newdir->str.len); directory[newdir->str.len] = '\0'; if (-1 == CHDIR(directory)) - { /* On VMS, chdir(directory, 0) [actually, any non 1 value] is supposed to restore the process startup cwd at exit - * (see help cc run). We've noticed that it doesn't behave the way it has been documented in the mumps executable. - * Vinaya, 08/22/2001 */ + { /* On VMS, chdir(directory, 0) [actually, any non 1 value] is supposed to restore the process startup cwd at + * exit (see help cc run). We've noticed that it doesn't behave the way it has been documented in the mumps + * executable. Vinaya, 08/22/2001. + */ err_str = STRERROR(errno); rts_error(VARLSTCNT(8) ERR_SETZDIR, 2, newdir->str.len, newdir->str.addr, ERR_TEXT, 2, LEN_AND_STR(err_str)); } } /* We need to find the full path of the current working directory because newdir might be a relative path, in which case - * $ZDIR will show up as a relative path */ + * $ZDIR will show up as a relative path. + */ if (NULL != full_path_of_newdir) { - if (NULL != GETCWD(directory_buffer, SIZEOF(directory_buffer), getcwd_res)) + GETCWD(directory_buffer, SIZEOF(directory_buffer), getcwd_res); + if (NULL != getcwd_res) { length = USTRLEN(directory_buffer); UNIX_ONLY(directory_buffer[length++] = '/';) } else { err_str = STRERROR(errno); - rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, ERR_TEXT, 2, - LEN_AND_STR(err_str)); + rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, ERR_TEXT, 2, LEN_AND_STR(err_str)); } full_path_of_newdir->mvtype = MV_STR; full_path_of_newdir->str.addr = directory_buffer; diff --git a/sr_port/show_source_line.c b/sr_port/show_source_line.c index ff6e2cc..5a59c96 100644 --- a/sr_port/show_source_line.c +++ b/sr_port/show_source_line.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,16 +31,20 @@ error_def(ERR_ARROWNTDSP); #define MAXLINESIZEFORDISPLAY 1023 -void show_source_line(char* buf, ssize_t buflen, boolean_t warn) +void show_source_line(boolean_t warn) { - char *b, *b_top, *c, *c_top; - int chlen, chwidth; - unsigned int ch, line_chwidth = 0; - boolean_t unable_to_complete_arrow = FALSE; - mstr msgstr; + char *b, *b_top, *c, *c_top, *buf; + char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)]; + ssize_t buflen; + int chlen, chwidth; + unsigned int ch, line_chwidth = 0; + boolean_t unable_to_complete_arrow = FALSE; + mstr msgstr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + buf = source_line_buff; + buflen = SIZEOF(source_line_buff); b_top = buf + buflen - STR_LIT_LEN(ARROW) - 1; /* allow room for arrow and string terminator */ for (c = (char *)source_buffer, b = buf, c_top = c + TREF(last_source_column) - 1; c < c_top;) { diff --git a/sr_port/show_source_line.h b/sr_port/show_source_line.h index 9ce830e..513cbe9 100644 --- a/sr_port/show_source_line.h +++ b/sr_port/show_source_line.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,6 +14,6 @@ #define ARROW "^-----" -void show_source_line(char* buf, ssize_t buflen, boolean_t warn); +void show_source_line(boolean_t warn); #endif /* SHOW_SOURCE_LINE_INCLUDED */ diff --git a/sr_port/shrink_trips.c b/sr_port/shrink_trips.c index 6e03203..5667a13 100644 --- a/sr_port/shrink_trips.c +++ b/sr_port/shrink_trips.c @@ -20,7 +20,7 @@ #include "gtmdbglvl.h" #include "cdbg_dump.h" #include -#include "rtnhdr.h" +#include #include "obj_file.h" #if defined(USHBIN_SUPPORTED) || defined(VMS) diff --git a/sr_port/skan_offset.c b/sr_port/skan_offset.c index 3d4505c..d9f7641 100644 --- a/sr_port/skan_offset.c +++ b/sr_port/skan_offset.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,14 +29,15 @@ GBLREF block_id patch_curr_blk; GBLREF sgmnt_addrs *cs_addrs; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF int patch_rec_counter; sm_uc_ptr_t skan_offset (sm_uc_ptr_t bp, bool over_run) { sm_uc_ptr_t b_top, rp, r_top, rp_targ, key_top; char util_buff[MAX_UTIL_LEN]; - unsigned char cc; + unsigned short cc; + int tmp_cmpc; short int size, rec_size; uint4 offset; @@ -90,10 +91,11 @@ sm_uc_ptr_t skan_offset (sm_uc_ptr_t bp, bool over_run) if (!*key_top++ && !*key_top++) break; } - if (((rec_hdr_ptr_t) rp)->cmpc > patch_comp_count) + EVAL_CMPC2((rec_hdr_ptr_t)rp, tmp_cmpc); + if (tmp_cmpc > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t) rp)->cmpc; + cc = tmp_cmpc; size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; diff --git a/sr_port/skan_rnum.c b/sr_port/skan_rnum.c index cac0f29..9cb2909 100644 --- a/sr_port/skan_rnum.c +++ b/sr_port/skan_rnum.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,13 +29,14 @@ GBLREF block_id patch_curr_blk; GBLREF sgmnt_addrs *cs_addrs; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; -GBLREF unsigned char patch_comp_count; +GBLREF unsigned short patch_comp_count; GBLREF int patch_rec_counter; sm_uc_ptr_t skan_rnum(sm_uc_ptr_t bp, bool over_run) { char util_buff[MAX_UTIL_LEN]; - unsigned char cc; + unsigned short cc; + int tmp_cmpc; sm_uc_ptr_t b_top, rp, r_top, key_top; short int size, rec_size; int4 record; @@ -80,10 +81,11 @@ sm_uc_ptr_t skan_rnum(sm_uc_ptr_t bp, bool over_run) if (!*key_top++ && !*key_top++) break; } - if (((rec_hdr_ptr_t) rp)->cmpc > patch_comp_count) + EVAL_CMPC2((rec_hdr_ptr_t)rp, tmp_cmpc); + if (tmp_cmpc > patch_comp_count) cc = patch_comp_count; else - cc = ((rec_hdr_ptr_t) rp)->cmpc; + cc = tmp_cmpc; size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; diff --git a/sr_port/sleep_cnt.h b/sr_port/sleep_cnt.h index e86f06a..9f996e9 100644 --- a/sr_port/sleep_cnt.h +++ b/sr_port/sleep_cnt.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,9 +9,12 @@ * * ****************************************************************/ +#ifndef SLEEP_CNT_H_INCLUDED +#define SLEEP_CNT_H_INCLUDED + #include "min_max.h" -/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function +/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function (BYPASSOK - sleep()) causes problems with GT.M's timers on some platforms. Specifically, the sleep() function causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least). This leads to lost timer pops and has the potential for system hangs. The proper long sleep mechanism @@ -39,13 +42,16 @@ #define JNL_FLUSH_PROG_FACTOR 2 #define JNL_FLUSH_PROG_TRIES (JNL_MAX_FLUSH_TRIES * JNL_FLUSH_PROG_FACTOR) #define MAX_LCK_TRIES SLEEP_ONE_MIN /* vms only: wait in mu_rndwn_file */ -#define MAX_FSYNC_WAIT_CNT (2 * SLEEP_ONE_MIN) /* 2 mins of total wait for fsync, before GTMASSERTing */ -#define MAX_TQREAD_WAIT (4 * BUF_OWNER_STUCK) /* 4 mins of total wait for t_qread, before GTMASSERTing */ +#define FSYNC_WAIT_TIME (2 * SLEEP_ONE_MIN) /* 2 mins of wait for fsync between JNLFSYNCSTUCK complaints */ +#define FSYNC_WAIT_HALF_TIME SLEEP_ONE_MIN /* 1 min of wait for fsync between DEBUG JNLFSYNCSTUCK complaints */ #define PHASE2_COMMIT_SLEEP MAXSLPTIME /* 10 msec inter-iteration sleep wait for active phase2 commits */ #define PHASE2_COMMIT_WAIT SLEEP_ONE_MIN #define PHASE2_COMMIT_WAIT_HTBT 8 /* = 8 heartbeats (each 8 seconds) = 64 seconds wait (used in Unix) */ +#define SLEEP_INSTFREEZEWAIT 100 /* 100-msec wait between re-checks of instance freeze status */ +#define SLEEP_IORETRYWAIT 500 /* 500-msec wait between retries of the same write operation */ + #define SLEEP_JNLQIOLOCKWAIT 1 /* 1-msec wait */ #define MAXJNLQIOLOCKWAIT 4000 /* 4sec = 4000 1-msec waits to see if io_in_prog lock is free in wcs_flu */ @@ -76,3 +82,5 @@ * the remaining crs. The value of 4 minutes was chosen because that is what t_qread currently has as its * maximum wait for reading a block from disk into the global buffer. */ #define MAX_WAIT_FOR_RIP 4 + +#endif diff --git a/sr_port/sorts_after.c b/sr_port/sorts_after.c index 577c059..962ce9d 100644 --- a/sr_port/sorts_after.c +++ b/sr_port/sorts_after.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,10 +43,30 @@ long sorts_after (mval *lhs, mval *rhs) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + if (!TREF(local_coll_nums_as_strings)) + { /* If numbers collate normally (ahead of strings), check if either of the operands is a number */ + if (MV_IS_CANONICAL(lhs)) + { /* lhs is a number */ + if (MV_IS_CANONICAL(rhs)) + { /* Both lhs and rhs are numbers */ + return numcmp(lhs, rhs); + } + /* lhs is a number, but rhs is a string; return false unless rhs is null */ + return (0 == rhs->str.len) ? 1 : -1; + } + /* lhs is a string */ + if (MV_IS_CANONICAL(rhs)) + { /* lhs is a string, but rhs is a number; return true unless lhs is null */ + return (0 != lhs->str.len) ? 1 : -1; + } + } + /* In case either lhs or rhs is not of type MV_STR, force them to be, as we are only doing string + * comparisons beyond this point. + */ + MV_FORCE_STR(lhs); + MV_FORCE_STR(rhs); if (TREF(local_collseq)) { - MV_FORCE_STR(lhs); /* just in case lhs is not of type MV_STR, force it to be as do_xform uses the str part */ - MV_FORCE_STR(rhs); /* just in case rhs is not of type MV_STR, force it to be as do_xform uses the str part */ ALLOC_XFORM_BUFF(lhs->str.len); tmstr1.len = TREF(max_lcl_coll_xform_bufsiz); tmstr1.addr = TREF(lcl_coll_xform_buff); @@ -60,18 +80,6 @@ long sorts_after (mval *lhs, mval *rhs) cmp = memcmp(tmstr1.addr, tmstr2.addr, length1 <= length2 ? length1 : length2); return cmp != 0 ? cmp : length1 - length2; } - if (MV_IS_CANONICAL(lhs)) - { /* lhs is a number */ - if (MV_IS_CANONICAL(rhs)) /* Both lhs and rhs are numbers */ - return numcmp(lhs, rhs); - /* lhs is a number, but rhs is a string; return false unless rhs is null */ - return (0 == rhs->str.len) ? 1 : -1; - } - /* lhs is a string */ - if (MV_IS_CANONICAL(rhs)) - { /* lhs is a string, but rhs is a number; return true unless lhs is null */ - return (0 != lhs->str.len) ? 1 : -1; - } - /* lhs and rhs are both strings */ + /* Do a regular string comparison if no collation options are specified */ return memvcmp(lhs->str.addr, lhs->str.len, rhs->str.addr, rhs->str.len); } diff --git a/sr_port/stack_frame.h b/sr_port/stack_frame.h index ef6eeca..116d226 100644 --- a/sr_port/stack_frame.h +++ b/sr_port/stack_frame.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,11 +28,6 @@ #include "hashtab_mname.h" -typedef struct saved_for_indx_array_struct -{ - mval *saved_for_indx[1]; -} saved_for_indx; - typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */ { struct rhead_struct *rvector; /* routine header */ @@ -76,7 +71,8 @@ typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */ unsigned short type; unsigned char flags; bool dollar_test; - saved_for_indx *for_ctrl_stack; /* anchor for array of FOR control variable indices */ + /*uint4 glvn_indx;*/ /* state of glvn pool at frame creation time. For use when gtmpcat is changed. */ + unsigned char *for_ctrl_stack;/* NOTE: temporarily using this field for glvn_indx so that gtmpcat works */ mval *ret_value; } stack_frame; @@ -92,6 +88,8 @@ typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */ #define SFT_ZINTR (1 << 8) /* 0x0100 $zinterrupt frame */ #define SFT_TRIGR (1 << 9) /* 0x0200 Trigger base frame */ +#define SFT_ZINTR_OFF ~(SFT_ZINTR) /* Mask to turn off SFF_ZINTR */ + /* The following definition identifies a frame that is running a line of code - either in a routine or what amounts to an XECUTE * it excludes frames dealing with @ indirection and frames generated for various nefarious internal purposes. * As of this writing, it's used in op_unwind to identify a frame that should receive a relocated for_ctrl_stack created by an @ @@ -108,17 +106,18 @@ typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */ * cause the getframe macro to invoke error_return() for further error processing. */ #define SFF_UNW_SYMVAL (1 << 5) /* 0x20 Unwound a symval in this stackframe (relevant to tp_restart) */ -#define SFF_TRIGR_CALLD (1 << 6) /* 0x40 This frame initiated a trigger call - checked by MUM_TSTART to prevent error - * returns to the frame which would cause a restart of error handling. - */ +#define SFF_IMPLTSTART_CALLD (1 << 6) /* 0x40 This frame initiated a trigger call or spanning node transaction + * - checked by MUM_TSTART to prevent error returns to the frame + * which would cause a restart of error handling. + */ -#define SFF_INDCE_OFF ~(SFF_INDCE) /* Mask to turn off SFF_INDCE */ -#define SFF_ZTRAP_ERR_OFF ~(SFF_ZTRAP_ERR) /* Mask to turn off SFF_ZTRAP_ERR */ -#define SFF_DEV_ACT_ERR_OFF ~(SFF_DEV_ACT_ERR) /* Mask to turn off SFF_DEV_ACT_ERR */ -#define SFF_CI_OFF ~(SFF_CI) /* Mask to turn off SFF_CI */ -#define SFF_ETRAP_ERR_OFF ~(SFF_ETRAP_ERR) /* Mask to turn off SFF_ETRAP_ERR */ -#define SFF_UNW_SYMVAL_OFF ~(SFF_UNW_SYMVAL) /* Mask to turn off SFF_UNW_SYMVAL */ -#define SFF_TRIGR_CALLD_OFF ~(SFF_TRIGR_CALLD) /* Mask to turn off SFF_TRIGR_CALLD */ +#define SFF_INDCE_OFF ~(SFF_INDCE) /* Mask to turn off SFF_INDCE */ +#define SFF_ZTRAP_ERR_OFF ~(SFF_ZTRAP_ERR) /* Mask to turn off SFF_ZTRAP_ERR */ +#define SFF_DEV_ACT_ERR_OFF ~(SFF_DEV_ACT_ERR) /* Mask to turn off SFF_DEV_ACT_ERR */ +#define SFF_CI_OFF ~(SFF_CI) /* Mask to turn off SFF_CI */ +#define SFF_ETRAP_ERR_OFF ~(SFF_ETRAP_ERR) /* Mask to turn off SFF_ETRAP_ERR */ +#define SFF_UNW_SYMVAL_OFF ~(SFF_UNW_SYMVAL) /* Mask to turn off SFF_UNW_SYMVAL */ +#define SFF_IMPLTSTART_CALLD_OFF ~(SFF_IMPLTSTART_CALLD) /* Mask to turn off SFF_IMPLTSTART_CALLD */ #define ADJUST_FRAME_POINTER(fptr, shift) \ { \ @@ -134,50 +133,6 @@ typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */ } \ } -/* the following macro ensures there's an array of FOR pointers and frees any old entry that's about to get overlaid */ -#define MANAGE_FOR_INDX(FPTR, LEVEL, NEW_INDX) \ -{ \ - assert(NULL != NEW_INDX); \ - if (NULL == FPTR->for_ctrl_stack) \ - { \ - FPTR->for_ctrl_stack = (saved_for_indx *)malloc(SIZEOF(mval *) * MAX_FOR_STACK); \ - memset(FPTR->for_ctrl_stack, 0, SIZEOF(mval *) * MAX_FOR_STACK); \ - } else \ - FREE_INDX_AND_CLR_SIBS(FPTR, LEVEL, NEW_INDX); \ - assert(NULL == FPTR->for_ctrl_stack->saved_for_indx[LEVEL]); \ - FPTR->for_ctrl_stack->saved_for_indx[LEVEL] = NEW_INDX; \ -} - -/* the following macro runs the FOR pointer array, freeing anything it finds before freeing the array - * in theory it could work down the array, but since the above macro needs FREE_INDX_AND_CLR_SIBS to work up, this does too - */ -#define FREE_SAVED_FOR_INDX(FPTR) \ -{ \ - uint4 Level; \ - \ - assert(NULL != FPTR->for_ctrl_stack); \ - for (Level = 1; Level < MAX_FOR_STACK; Level++) /* level 0 never holds a pointer */ \ - FREE_INDX_AND_CLR_SIBS(FPTR, Level, NULL); \ - free((char *)FPTR->for_ctrl_stack); \ -} - -/* the following macro, currentl only used by the above 2 macros, - * deals with the possibility of the same control variable at multiple nesting levels and clears higher nesting levels - */ -#define FREE_INDX_AND_CLR_SIBS(FPTR, LEVEL, NEW_INDX) \ -{ \ - uint4 Lvl; \ - mval *Ptr; \ - \ - if (NULL != (Ptr = FPTR->for_ctrl_stack->saved_for_indx[LEVEL])) /* NOTE assignment */ \ - { \ - free((char *)Ptr); \ - for (Lvl = 1; Lvl < MAX_FOR_STACK; Lvl++) /* level 0 never holds a pointer */ \ - if (Ptr == FPTR->for_ctrl_stack->saved_for_indx[Lvl]) \ - FPTR->for_ctrl_stack->saved_for_indx[Lvl] = (mval *)(Lvl < LEVEL ? NEW_INDX : NULL); \ - } \ -} - void new_stack_frame(rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr); void new_stack_frame_sp(rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr); int4 symbinit(void); diff --git a/sr_port/startup.h b/sr_port/startup.h index ffb2bbc..720985c 100644 --- a/sr_port/startup.h +++ b/sr_port/startup.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,7 +25,7 @@ struct startup_vector unsigned char *gtm_main_inaddr; int4 user_stack_size; int4 user_spawn_flag; - int4 user_indrcache_size; + int4 user_indrcache_size; /* defunct */ int4 user_strpl_size; int4 user_io_timer; int4 user_write_filter; diff --git a/sr_port/stp_gcol_src.h b/sr_port/stp_gcol_src.h index 6f4b331..c0e817a 100644 --- a/sr_port/stp_gcol_src.h +++ b/sr_port/stp_gcol_src.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,7 @@ #include "lv_val.h" #include "subscript.h" #include "mdq.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "stp_parms.h" @@ -54,6 +54,8 @@ #include "alias.h" #include "gtmimagename.h" #include "srcline.h" +#include "opcode.h" +#include "glvn_pool.h" #ifndef STP_MOVE GBLDEF int indr_stp_low_reclaim_passes = 0; @@ -144,8 +146,8 @@ error_def(ERR_STPEXPFAIL); * gives compiler warnings in HPUX Itanium since source is 2-byte aligned whereas destination \ * is 8-byte aligned. The void * in between makes the compiler forget the 2-byte alignment. \ */ \ - UNIX_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_mvtype);) \ - VMS_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_len);) \ + UNIX_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_mvtype)); \ + VMS_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_len)); \ } \ } @@ -344,7 +346,6 @@ error_def(ERR_STPEXPFAIL); #else #define DBGSTPGCOL(x) #endif - static void expand_stp(unsigned int new_size) /* BYPASSOK */ { if (retry_if_expansion_fails) @@ -456,7 +457,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */ int *low_reclaim_passes; int *incr_factor; int killcnt; - long stp_incr, space_needed_rounded_up; + long stp_incr; ht_ent_objcode *tabent_objcode, *topent; ht_ent_mname *tabent_mname, *topent_mname; ht_ent_addr *tabent_addr, *topent_addr; @@ -471,6 +472,8 @@ void stp_gcol(int space_asked) /* BYPASSOK */ tp_var *restore_ent; boolean_t non_mandatory_expansion, exp_gt_spc_needed, first_expansion_try; routine_source *rsptr; + glvn_pool_entry *slot, *top; + int i, n; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -577,6 +580,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */ mv_parse_tree_collect((mvar *)mlabtab); MVAL_STPG_ADD(&(TREF(director_mval))); MVAL_STPG_ADD(&(TREF(window_mval))); + MVAL_STPG_ADD(&(TREF(indirection_mval))); # endif } else { @@ -679,7 +683,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */ if (NULL != (symtab = mvs->mv_st_cont.mvs_stab)) { /* if initalization of the table was successful */ for (lv_blk_ptr = symtab->lv_first_block; NULL != lv_blk_ptr; - lv_blk_ptr = lv_blk_ptr->next) + lv_blk_ptr = lv_blk_ptr->next) { for (lvp = (lv_val *)LV_BLK_GET_BASE(lv_blk_ptr), lvlimit = LV_BLK_GET_FREE(lv_blk_ptr, lvp); @@ -699,11 +703,11 @@ void stp_gcol(int space_asked) /* BYPASSOK */ } } for (lv_blk_ptr = symtab->lvtreenode_first_block; NULL != lv_blk_ptr; - lv_blk_ptr = lv_blk_ptr->next) + lv_blk_ptr = lv_blk_ptr->next) { for (node = (lvTreeNode *)LV_BLK_GET_BASE(lv_blk_ptr), - node_limit = LV_BLK_GET_FREE(lv_blk_ptr, node); - node < node_limit; node++) + node_limit = LV_BLK_GET_FREE(lv_blk_ptr, node); + node < node_limit; node++) { /* node could be actively in use or free (added to the symval's * lvtreenode_flist). Ignore the free ones. Those should have @@ -747,7 +751,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */ continue; case MVST_NVAL: /* The var_name field is only present in a debug build */ - DEBUG_ONLY(MSTR_STPG_ADD(&mvs->mv_st_cont.mvs_nval.name.var_name);) + DEBUG_ONLY(MSTR_STPG_ADD(&mvs->mv_st_cont.mvs_nval.name.var_name)); continue; # ifdef GTM_TRIGGER case MVST_TRIGR: @@ -791,25 +795,6 @@ void stp_gcol(int space_asked) /* BYPASSOK */ # endif break; } - if (NULL != sf->for_ctrl_stack) - { - mm = (mval **)sf->for_ctrl_stack->saved_for_indx; - for (mmtop = (mval **)((char *)mm + (MAX_FOR_STACK * SIZEOF(mval *))); ++mm < mmtop;) - { - if (NULL != *mm) - { - m = (mval *)((char *)mm + SIZEOF(mval) - + SIZEOF(mname_entry) + SIZEOF(mident_fixed)); - lv_subs = *(intszofptr_t *)m; - for (m = (mval *)((char *)m + SIZEOF(intszofptr_t) + SIZEOF(lv_val)); - 0 < --lv_subs; m++) - { - assert(MV_DEFINED(m)); - MVAL_STPG_ADD(m); - } - } - } - } assert(sf->temps_ptr); if (sf->temps_ptr >= (unsigned char *)sf) continue; @@ -822,6 +807,12 @@ void stp_gcol(int space_asked) /* BYPASSOK */ MVAL_STPG_ADD(m); } } + if (NULL != TREF(glvn_pool_ptr)) + { /* Protect everything in the glvn pool. */ + m = (TREF(glvn_pool_ptr))->mval_stack; + for (mtop = m + (TREF(glvn_pool_ptr))->mval_top; m < mtop; m++) + MVAL_STPG_ADD(m); + } if (NULL != alias_retarg) { /* An alias return value is in-flight - process it */ assert(alias_retarg->mvtype & MV_ALIASCONT); @@ -846,7 +837,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */ } } space_before_compact = stringpool.top - stringpool.free; /* Available space before compaction */ - DEBUG_ONLY(blklen = stringpool.free - stringpool.base;) + DEBUG_ONLY(blklen = stringpool.free - stringpool.base); stringpool.free = stringpool.base; if (topstr != array) { @@ -901,11 +892,17 @@ void stp_gcol(int space_asked) /* BYPASSOK */ * occurrences of the stringpool filling up, and compaction not reclaiming enough space. * In such cases, if the stringpool is expanded, we create more room, resulting in fewer calls * to stp_gcol. + * + * Note it is not uncommon for space_needed to be a negative value. That can occur in here if we + * recovered enough space from the GC to satisfy the immediate need but we have identified that + * so little space is still available that we are best served by expanding the stringpool so as to + * prevent another almost immediate need for another GC. This is also known as a non-mandatory + * expansion. Assert that if space_needed is negative, we have a non-mandatory expansion. */ + assert((0 <= space_needed) || non_mandatory_expansion); strpool_base = stringpool.base; /* Grow stringpool geometrically */ stp_incr = (stringpool.top - stringpool.base) * *incr_factor / STP_NUM_INCRS; - space_needed_rounded_up = ROUND_UP(space_needed, OS_PAGE_SIZE); first_expansion_try = TRUE; while (first_expansion_try || (retry_if_expansion_fails && expansion_failed)) { @@ -925,19 +922,25 @@ void stp_gcol(int space_asked) /* BYPASSOK */ stp_incr = (stringpool.top - stringpool.base) * *incr_factor / STP_NUM_INCRS; } else /* if we are already at the lowest incr_factor half our way down */ - if (stp_incr > space_needed_rounded_up) + if (stp_incr > space_needed) stp_incr = stp_incr / 2; } first_expansion_try = FALSE; - stp_incr = ROUND_UP(stp_incr, OS_PAGE_SIZE); if (stp_incr < space_needed) - stp_incr = space_needed_rounded_up; + stp_incr = space_needed; /* If we are asking for more than is actually needed we want to try again if we do not get it. */ - retry_if_expansion_fails = (stp_incr > space_needed_rounded_up); - expansion_failed = FALSE; /* will be set to TRUE by condition handler if can't get memory */ - assert(stp_incr + stringpool.top - stringpool.base >= space_needed + blklen); - DBGSTPGCOL((stderr, "incr_factor=%i stp_incr=%i space_needed=%i\n", *incr_factor, stp_incr, - space_needed_rounded_up)); + retry_if_expansion_fails = (stp_incr > space_needed); + /* If this is a non-mandatory expansion (which also means space_needed is likely negative but this is + * not *always* the case) and stp_incr has come down to less than the size of a page, then there's really + * no point in continuing this loop - probably all the way to stp_incr = 0. But for a non-mandatory + * expansion, leaving early carries no significiant penalty - especially since we're already operating + * on the the edge. + */ + if (non_mandatory_expansion && (0 == stp_incr)) + break; /* stp_incr can't get smaller - give up and use what we have */ + expansion_failed = FALSE; /* will be set to TRUE by condition handler if can't get memory */ + assert((stp_incr + stringpool.top - stringpool.base) >= (space_needed + blklen)); + DBGSTPGCOL((stderr, "incr_factor=%i stp_incr=%i space_needed=%i\n", *incr_factor, stp_incr, space_needed)); expand_stp((unsigned int)(stp_incr + stringpool.top - stringpool.base)); } if (strpool_base != stringpool.base) /* expanded successfully */ @@ -952,10 +955,11 @@ void stp_gcol(int space_asked) /* BYPASSOK */ /* Adjust incr_factor */ if (*incr_factor < STP_NUM_INCRS) *incr_factor = *incr_factor + 1; } else - { /* could not expand during forced expansion */ + { /* Could not expand during forced expansion */ assert(non_mandatory_expansion && stop_non_mandatory_expansion); if (space_after_compact < space_needed) - rts_error(VARLSTCNT(3) ERR_STPEXPFAIL, 1, stp_incr + stringpool.top - stringpool.base); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STPEXPFAIL, 1, + (stp_incr + stringpool.top - stringpool.base)); } *low_reclaim_passes = 0; } else diff --git a/sr_port/str2gvargs.c b/sr_port/str2gvargs.c index 993f299..0203756 100644 --- a/sr_port/str2gvargs.c +++ b/sr_port/str2gvargs.c @@ -25,7 +25,7 @@ #include "gtm_utf8.h" #endif #ifdef GTM_TRIGGER -#include "rtnhdr.h" +#include #include "gv_trigger.h" #endif diff --git a/sr_port/stringpool.h b/sr_port/stringpool.h index 2e00253..7c8456d 100644 --- a/sr_port/stringpool.h +++ b/sr_port/stringpool.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,7 @@ typedef struct } spdesc; void stp_expand_array(void); -void stp_gcol(int space_needed); +void stp_gcol(int space_needed); /* BYPASSOK */ void stp_move(char *from, char *to); void stp_init(unsigned int size); void s2pool(mstr *a); @@ -36,8 +36,8 @@ GBLREF spdesc stringpool; #define IS_STP_SPACE_AVAILABLE_PRO(SPC) ((stringpool.free + SPC) <= stringpool.top) #define IS_IN_STRINGPOOL(PTR, LEN) \ - ((((unsigned char *)PTR + (int)(LEN)) < stringpool.top) && ((unsigned char *)PTR >= stringpool.base)) -#define INVOKE_STP_GCOL(SPC) stp_gcol(SPC); + ((((unsigned char *)PTR + (int)(LEN)) <= stringpool.top) && ((unsigned char *)PTR >= stringpool.base)) +#define INVOKE_STP_GCOL(SPC) stp_gcol(SPC); /* BYPASSOK */ #ifdef DEBUG GBLREF boolean_t stringpool_unusable; diff --git a/sr_port/stx_error.c b/sr_port/stx_error.c index 743c110..d452430 100644 --- a/sr_port/stx_error.c +++ b/sr_port/stx_error.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,9 +33,6 @@ GBLREF bool dec_nofac; GBLREF boolean_t run_time; GBLREF char cg_phase; GBLREF io_pair io_curr_device, io_std_device; -#ifdef UNIX -GBLREF va_list last_va_list_ptr; /* set by util_format */ -#endif error_def(ERR_ACTLSTTOOLONG); error_def(ERR_BADCASECODE); @@ -49,7 +46,6 @@ error_def(ERR_CEUSRERROR); error_def(ERR_FMLLSTMISSING); error_def(ERR_FMLLSTPRESENT); error_def(ERR_FOROFLOW); -error_def(ERR_INVCMD); error_def(ERR_INVDLRCVAL); error_def(ERR_LABELMISSING); error_def(ERR_SRCLIN); @@ -72,8 +68,8 @@ void stx_error(int in_error, ...) va_start(args, in_error); /* In case of a IS_STX_WARN type of parsing error, we resume parsing so it is important NOT to reset * the following global variables - * a) saw_side_effect - * b) shift_side_effects + * a) saw_side_effect + * b) shift_side_effects * c) source_error_found */ is_stx_warn = (CGP_PARSE == cg_phase) && IS_STX_WARN(in_error) GTMTRIG_ONLY( && !TREF(trigger_compile)); @@ -86,8 +82,9 @@ void stx_error(int in_error, ...) * See IS_STX_WARN macro definition for details. */ if (is_stx_warn) - { - ins_errtriple(in_error); + { /* merrors.msg defines INVCMD as a warning but compiler conditions can turn it into an error */ + if (ERR_INVCMD != in_error) /* if INVCMD has morphed into an error, it won't match here */ + ins_errtriple(in_error); return; } if (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)) @@ -101,7 +98,7 @@ void stx_error(int in_error, ...) arg3 = va_arg(args, VA_ARG_TYPE); arg4 = va_arg(args, VA_ARG_TYPE); va_end(args); - rts_error(VARLSTCNT(6) in_error, cnt, arg1, arg2, arg3, arg4); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) in_error, cnt, arg1, arg2, arg3, arg4); } else if ((ERR_LABELMISSING == in_error) || (ERR_FMLLSTMISSING == in_error) || (ERR_ACTLSTTOOLONG == in_error) @@ -113,20 +110,20 @@ void stx_error(int in_error, ...) arg1 = va_arg(args, VA_ARG_TYPE); arg2 = va_arg(args, VA_ARG_TYPE); va_end(args); - rts_error(VARLSTCNT(4) in_error, cnt, arg1, arg2); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) in_error, cnt, arg1, arg2); } else if ((ERR_CEUSRERROR == in_error) || (ERR_INVDLRCVAL == in_error) || (ERR_FOROFLOW == in_error)) { cnt = va_arg(args, VA_ARG_TYPE); assert(cnt == 1); arg1 = va_arg(args, VA_ARG_TYPE); va_end(args); - rts_error(VARLSTCNT(3) in_error, cnt, arg1); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) in_error, cnt, arg1); } else { va_end(args); - rts_error(VARLSTCNT(1) in_error); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) in_error); } - } else if (CGP_PARSE == cg_phase && ERR_INVCMD != in_error) + } else if ((CGP_PARSE == cg_phase) && (ERR_INVCMD != in_error)) /* if INVCMD has morphed into an error, won't match here */ ins_errtriple(in_error); assert(!run_time); /* From here on down, should never go ahead with printing compile-error while in run_time */ flush_pio(); @@ -155,8 +152,7 @@ void stx_error(int in_error, ...) warn = FALSE; /* if listing is going to $P, don't double output */ if (ERR_BADCHAR == in_error) { - memset(buf, ' ', LISTTAB); - show_source_line(&buf[LISTTAB], SIZEOF(buf), warn); + show_source_line(warn); cnt = va_arg(args, VA_ARG_TYPE); assert(cnt == 4); arg1 = va_arg(args, VA_ARG_TYPE); @@ -168,8 +164,6 @@ void stx_error(int in_error, ...) dec_err(VARLSTCNT(6) in_error, 4, arg1, arg2, arg3, arg4); dec_err(VARLSTCNT(4) ERR_SRCNAM, 2, source_name_len, source_file_name); } - if (list) - list_line(buf); arg1 = arg2 = arg3 = arg4 = 0; } else if ((ERR_LABELMISSING == in_error) || (ERR_FMLLSTMISSING == in_error) @@ -188,8 +182,7 @@ void stx_error(int in_error, ...) } } else { - memset(buf, ' ', LISTTAB); - show_source_line(&buf[LISTTAB], SIZEOF(buf), warn); + show_source_line(warn); if (warn) { if ((ERR_CEUSRERROR != in_error) && (ERR_INVDLRCVAL != in_error) && (ERR_FOROFLOW != in_error)) @@ -202,8 +195,6 @@ void stx_error(int in_error, ...) dec_err(VARLSTCNT(3) in_error, 1, arg1); } } - if (list) - list_line(buf); arg1 = arg2 = 0; } va_end(args); @@ -217,7 +208,7 @@ void stx_error(int in_error, ...) # ifdef UNIX cnt = va_arg(args, VA_ARG_TYPE); c = util_format(msgbuf, args, LIT_AND_LEN(buf), (int)cnt); - va_end(last_va_list_ptr); /* set by util_format */ + va_end(TREF(last_va_list_ptr)); /* set by util_format */ # else c = util_format(msgbuf, args, LIT_AND_LEN(buf)); # endif diff --git a/sr_port/symb_line.c b/sr_port/symb_line.c index 6d4c0c8..e24aee6 100644 --- a/sr_port/symb_line.c +++ b/sr_port/symb_line.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #define OFFSET_LEN 5 diff --git a/sr_port/symbinit.c b/sr_port/symbinit.c index 0eaa87c..adc2780 100644 --- a/sr_port/symbinit.c +++ b/sr_port/symbinit.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" /* this includes lv_val.h which also includes hashtab_mname.h and hashtab.h */ #include "stack_frame.h" #include "mdq.h" diff --git a/sr_port/t_begin.c b/sr_port/t_begin.c index 9dfef15..dfd627d 100644 --- a/sr_port/t_begin.c +++ b/sr_port/t_begin.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,6 +41,10 @@ GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF jnl_gbls_t jgbl; GBLREF volatile int4 fast_lock_count; GBLREF sgm_info *first_sgm_info; +GBLREF boolean_t need_kip_incr; +GBLREF boolean_t mu_reorg_process; + +error_def(ERR_MMREGNOACCESS); void t_begin(uint4 err, uint4 upd_trans) /* err --> error code for current gvcst_routine */ { @@ -53,8 +57,16 @@ void t_begin(uint4 err, uint4 upd_trans) /* err --> error code for current gvcs /* any changes to the initialization in the two lines below might need a similar change in T_BEGIN_xxx_NONTP_OR_TP macros */ assert(INTRPT_OK_TO_INTERRUPT == intrpt_ok_state); update_trans = upd_trans; + assert(!update_trans || !need_kip_incr); /* should not begin an update transaction with a non-zero value of this + * variable as it will then cause csd->kill_in_prog to be incorrectly + * incremented for the current transaction. + */ t_err = err; - + if ((NULL == cs_addrs->db_addrs[0]) && (dba_mm == cs_addrs->hdr->acc_meth)) + { + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_MMREGNOACCESS, 4, REG_LEN_STR(cs_addrs->region), + DB_LEN_STR(cs_addrs->region)); + } /* If we use a clue then we must consider the oldest tn in the search history to be the start tn for this transaction */ /* start_tn manipulation for TP taken care of in tp_hist */ if (cs_addrs->critical) @@ -71,6 +83,11 @@ void t_begin(uint4 err, uint4 upd_trans) /* err --> error code for current gvcs for (s = &gv_target->hist.h[0]; s->blk_num; s++) { histtn = s->tn; + /* Assert that we have a NULL cse in case of a non-zero clue as this will otherwise confuse t_end.c. + * The only exception is reorg in which case we nullify the clue AFTER the t_begin call (in mu_reorg.c, + * mu_swap_root.c, mu_truncate.c) but BEFORE the gvcst_search call so the clue does not get used. + */ + assert(mu_reorg_process || (NULL == s->cse)); if (start_tn > histtn) start_tn = histtn; } diff --git a/sr_port/t_begin_crit.c b/sr_port/t_begin_crit.c index 6c6d26c..e42d725 100644 --- a/sr_port/t_begin_crit.c +++ b/sr_port/t_begin_crit.c @@ -65,19 +65,8 @@ void t_begin_crit(uint4 err) /* err - error code for current gvcst_routine */ update_trans = UPDTRNS_DB_UPDATED_MASK; was_crit = cs_addrs->now_crit; assert(!was_crit || cs_addrs->hold_onto_crit); -# ifdef GTM_TRUNCATE - /* Sync private and shared copies of total_blks. We do this here in order to avoid the following scenario, in which - * t_end attempts a restart due to a truncate that happened before t_begin_crit: - * 1. db_init happens (csa->total_blks = 200, csa->ti->total_blks = 200) - * 2. truncate happens (csa->total_blks = 200, csa->ti->total_blks = 100) - * 3. enter t_begin_crit (csa->total_blks = 200, csa->ti->total_blks = 100) - * 4. go to t_end, try to restart since 200 > 100... assert goes off since t_tries = CDB_STAGNATE. - */ - if (dba_mm != cs_addrs->hdr->acc_meth) - cs_addrs->total_blks = cs_addrs->ti->total_blks; -# endif if (!was_crit) - { /* We are going to grab_crit. If csd->wc_blocked is set to TRUE, we will end up calling wcs_recover as part of + { /* We are going to grab_crit. If csa->nl->wc_blocked is set to TRUE, we will end up calling wcs_recover as part of * grab_crit. Set variable to indicate it is ok to do so even though t_tries is CDB_STAGNATE since we are not * in the middle of any transaction. */ diff --git a/sr_port/t_busy2free.c b/sr_port/t_busy2free.c index 41bc7a9..9f15dfb 100644 --- a/sr_port/t_busy2free.c +++ b/sr_port/t_busy2free.c @@ -45,9 +45,12 @@ void t_busy2free(srch_blk_status *blkhist) cse->blk = blkhist->blk_num; cse->old_block = blkhist->buffaddr; old_block = (blk_hdr_ptr_t)cse->old_block; - cse->was_free = FALSE; /* t_busy2free operates on BUSY blocks and hence cse->was_free is set to FALSE unconditionally */ + /* t_busy2free operates on BUSY blocks and hence cse->blk_prior_state's free and recycled status is always set to FALSE */ + BIT_CLEAR_FREE(cse->blk_prior_state); + BIT_CLEAR_RECYCLED(cse->blk_prior_state); cse->blk_checksum = 0; csa = cs_addrs; + assert(dba_bg == csa->hdr->acc_meth); assert(NULL != old_block); jbbp = (JNL_ENABLED(csa) && csa->jnl_before_image) ? csa->jnl->jnl_buff : NULL; if ((NULL != jbbp) && (old_block->tn < jbbp->epoch_tn)) diff --git a/sr_port/t_commit_cleanup.c b/sr_port/t_commit_cleanup.c index 5655c26..7ad138d 100644 --- a/sr_port/t_commit_cleanup.c +++ b/sr_port/t_commit_cleanup.c @@ -41,23 +41,24 @@ #include "send_msg.h" #include "have_crit.h" -GBLREF unsigned char cw_set_depth; -GBLREF cw_set_element cw_set[]; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF sgmnt_data_ptr_t cs_data; -GBLREF gd_region *gv_cur_region; -GBLREF unsigned int t_tries; -GBLREF uint4 dollar_tlevel; -GBLREF sgm_info *first_sgm_info; GBLREF cache_rec_ptr_t cr_array[((MAX_BT_DEPTH * 2) - 1) * 2]; /* Maximum number of blocks that can be in transaction */ GBLREF unsigned int cr_array_index; -GBLREF boolean_t unhandled_stale_timer_pop; -GBLREF jnlpool_addrs jnlpool; -GBLREF uint4 process_id; -GBLREF jnlpool_ctl_ptr_t jnlpool_ctl, temp_jnlpool_ctl; -GBLREF gv_namehead *gv_target; -GBLREF uint4 update_trans; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data_ptr_t cs_data; +GBLREF cw_set_element cw_set[]; +GBLREF unsigned char cw_set_depth; +GBLREF uint4 dollar_trestart; +GBLREF uint4 dollar_tlevel; +GBLREF sgm_info *first_sgm_info; GBLREF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */ +GBLREF gd_region *gv_cur_region; +GBLREF gv_namehead *gv_target; +GBLREF jnlpool_addrs jnlpool; +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl, temp_jnlpool_ctl; +GBLREF uint4 process_id; +GBLREF unsigned int t_tries; +GBLREF boolean_t unhandled_stale_timer_pop; +GBLREF uint4 update_trans; #ifdef UNIX GBLREF jnl_gbls_t jgbl; #endif @@ -105,10 +106,11 @@ boolean_t t_commit_cleanup(enum cdb_sc status, int signal) gd_region *xactn_err_region, *jpl_reg = NULL; cache_rec_ptr_t *tp_cr_array; DEBUG_ONLY(unsigned int lcl_t_tries;) + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(cdb_sc_normal != status); xactn_err_region = gv_cur_region; - /* see comments in secshr_db_clnup for the commit logic flow as a sequence of steps in t_end and tp_tend and how * t_commit_cleanup() and secshr_db_clnup() complement each other (one does the rollback and one the roll forward) * update_underway is set to TRUE to indicate the commit is beyond rollback. It is set only if we hold crit on the region. @@ -158,7 +160,7 @@ boolean_t t_commit_cleanup(enum cdb_sc status, int signal) * at a point where the transaction can be rolled backwards (update_underway = FALSE), we release crit before going * to the error trap thereby avoiding any unintended crit hangs. */ - release_crit = (0 == signal) ? NEED_TO_RELEASE_CRIT(t_tries) : TRUE; + release_crit = (0 == signal) ? NEED_TO_RELEASE_CRIT(t_tries, status) : TRUE; if ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) { csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; diff --git a/sr_port/t_create.c b/sr_port/t_create.c index e4179d6..47193e8 100644 --- a/sr_port/t_create.c +++ b/sr_port/t_create.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,15 @@ #include "tp.h" #include "t_create.h" +#define TP_ALLOCATION_CLUE_INCREMENT 1 /* This is the default value. Defined below (under a #ifdef) is another value + * Enable below #ifdef/#endif block if you want that value instead. + */ +#ifdef TP_ALLOCATION_CLUE_BUMP_BY_512 +#define TP_ALLOCATION_CLUE_INCREMENT 512 /* Change this to some other number if you want a different bump to the + * tp allocation clue each time it is used. + */ +#endif + GBLREF cw_set_element cw_set[]; GBLREF sgmnt_data_ptr_t cs_data; GBLREF unsigned char cw_set_depth; @@ -61,11 +70,15 @@ block_index t_create ( { if (!tp_allocation_clue) { - tp_allocation_clue = gtm_tp_allocation_clue + 1; - hint = tp_allocation_clue; + tp_allocation_clue = gtm_tp_allocation_clue + 1; /* + 1 so we dont start out with 0 value for "hint" */ + hint = tp_allocation_clue; /* this is copied over to cse->blk which is asserted + * in gvcst_put as never being 0. + */ } else { - hint = ++tp_allocation_clue; + tp_allocation_clue += TP_ALLOCATION_CLUE_INCREMENT; + hint = tp_allocation_clue; + /* What if hint becomes greater than total_blks. Should we wrap back to 0? */ if (tp_allocation_clue < 0) GTMASSERT; } @@ -73,9 +86,9 @@ block_index t_create ( assert(gv_target); cse->blk_target = gv_target; } - cse->mode = gds_t_create; cse->blk_checksum = 0; + assert(hint); /* various callers (particularly gvcst_put) rely on gds_t_create cse to have a non-zero "blk" */ cse->blk = hint; cse->upd_addr = upd_addr; cse->ins_off = ins_off; @@ -91,6 +104,12 @@ block_index t_create ( cse->low_tlevel = NULL; cse->high_tlevel = NULL; cse->ondsk_blkver = GDSVCURR; + assert (NULL != gv_target); /* t_create is called by gvcst kill/put,mu split/swap_blk, where gv_target can't be NULL */ + /* For uninitialized gv_target, initialize the in_tree status as IN_DIR_TREE, which later may be modified by t_write */ + if (0 == gv_target->root) + BIT_SET_DIR_TREE(cse->blk_prior_state); + else + (DIR_ROOT == gv_target->root) ? BIT_SET_DIR_TREE(cse->blk_prior_state) : BIT_SET_GV_TREE(cse->blk_prior_state); if (!dollar_tlevel) return(cw_set_depth++); else diff --git a/sr_port/t_end.c b/sr_port/t_end.c index fea1c0e..abc5b51 100644 --- a/sr_port/t_end.c +++ b/sr_port/t_end.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,11 +50,13 @@ #include "cws_insert.h" #include "min_max.h" #include "gtmimagename.h" +#include "anticipatory_freeze.h" #ifdef UNIX #include "gtmrecv.h" #include "deferred_signal_handler.h" #include "repl_instance.h" +#include "format_targ_key.h" #endif /* Include prototypes */ @@ -85,6 +87,7 @@ #include "shmpool.h" #include "bml_status_check.h" #include "is_proc_alive.h" +#include "muextr.h" GBLREF bool rc_locked; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; @@ -94,7 +97,7 @@ GBLREF boolean_t block_saved; GBLREF uint4 update_trans; GBLREF cw_set_element cw_set[]; /* create write set. */ GBLREF gd_region *gv_cur_region; -GBLREF gv_namehead *gv_target; +GBLREF gv_namehead *gv_target, *gv_target_list; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF uint4 dollar_tlevel; @@ -127,6 +130,8 @@ GBLREF inctn_opcode_t inctn_opcode; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLREF boolean_t block_is_free; GBLREF boolean_t gv_play_duplicate_kills; +GBLREF boolean_t pool_init; +GBLREF gv_key *gv_currkey; #ifdef GTM_TRIGGER GBLREF boolean_t skip_dbtriggers; /* see gbldefs.c for description of this global */ #endif @@ -138,6 +143,7 @@ GBLREF int4 strm_index; GBLREF boolean_t mupip_jnl_recover; #endif +error_def(ERR_GBLOFLOW); error_def(ERR_GVKILLFAIL); error_def(ERR_GVPUTFAIL); error_def(ERR_JNLFILOPN); @@ -178,13 +184,21 @@ if (history) \ } \ } +#define BUSY2FREE 0x00000001 +#define RECYCLED2FREE 0x00000002 +#define FREE_DIR_DATA 0x00000004 /* denotes the block to be freed is a data block in directory tree */ + +#define SAVE_2FREE_IMAGE(MODE, FREE_SEEN, CSD) \ + (((gds_t_busy2free == MODE) && (!CSD->db_got_to_v5_once || (FREE_SEEN & FREE_DIR_DATA))) \ + || (gds_t_recycled2free == MODE)) + trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) { srch_hist *hist; bt_rec_ptr_t bt; boolean_t blk_used; cache_rec cr_save; - cache_rec_ptr_t cr; + cache_rec_ptr_t cr, backup_cr; cw_set_element *cs, *cs_top, *cs1; enum cdb_sc status; int int_depth, tmpi; @@ -196,8 +210,8 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) node_local_ptr_t cnl; sgm_info *dummysi = NULL; /* needed as a dummy parameter for {mm,bg}_update */ srch_blk_status *t1; - trans_num valid_thru, tnque_earliest_tn, dbtn, blktn, temp_tn, epoch_tn, old_block_tn; - unsigned char cw_depth, cw_bmp_depth; + trans_num valid_thru, oldest_hist_tn, dbtn, blktn, temp_tn, epoch_tn, old_block_tn; + unsigned char cw_depth, cw_bmp_depth, buff[MAX_ZWR_KEY_SZ], *end; jnldata_hdr_ptr_t jnl_header; uint4 total_jnl_rec_size, tmp_cumul_jnl_rec_len, tmp_cw_set_depth, prev_cw_set_depth; DEBUG_ONLY(unsigned int tot_jrec_size;) @@ -207,18 +221,22 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) boolean_t supplementary = FALSE; /* this variable is initialized ONLY if "replication" is TRUE. */ seq_num strm_seqno, next_strm_seqno; # endif + sm_uc_ptr_t blk_ptr, backup_blk_ptr; + int blkid; boolean_t is_mm; boolean_t read_before_image; /* TRUE if before-image journaling or online backup in progress * This is used to read before-images of blocks whose cs->mode is gds_t_create */ boolean_t write_inctn = FALSE; /* set to TRUE in case writing an inctn record is necessary */ - boolean_t decremented_currtn, retvalue, busy2free_seen, recompute_cksum, cksum_needed; - boolean_t recycled2free_seen; - boolean_t in_mu_truncate = FALSE; + boolean_t decremented_currtn, retvalue, recompute_cksum, cksum_needed; + unsigned int free_seen; /* free_seen denotes the block is going to be set free rather than recycled */ + boolean_t in_mu_truncate = FALSE, jnlpool_crit_acquired = FALSE; + boolean_t was_crit; blk_hdr_ptr_t old_block; unsigned int bsiz, crindex; jnl_tm_t save_gbl_jrec_time; enum gds_t_mode mode; uint4 prev_cr_array_index; + uint4 com_csum; # ifdef DEBUG boolean_t ready2signal_gvundef_lcl; enum cdb_sc prev_status; @@ -229,8 +247,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) int n_blks_validated; boolean_t before_image_needed, lcl_ss_in_prog = FALSE, reorg_ss_in_prog = FALSE; boolean_t ss_need_to_restart, new_bkup_started; + gv_namehead *gvnh; # ifdef GTM_TRIGGER uint4 cycle; +# endif +# ifdef GTM_SNAPSHOT + snapshot_context_ptr_t lcl_ss_ctx; # endif DCL_THREADGBL_ACCESS; @@ -252,8 +274,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) cnl = csa->nl; is_mm = (dba_mm == csd->acc_meth); # ifdef GTM_TRUNCATE - in_mu_truncate = (cnl != NULL && process_id == cnl->trunc_pid); + DEBUG_ONLY(in_mu_truncate = (cnl != NULL && process_id == cnl->trunc_pid);) # endif + TREF(rlbk_during_redo_root) = FALSE; status = cdb_sc_normal; /* The only cases where we set csa->hold_onto_crit to TRUE are the following : * (a) jgbl.onlnrlbk @@ -278,9 +301,10 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert(0 == cr_array_index); assert(!gv_cur_region->read_only || !update_trans); cr_array_index = 0; /* be safe and reset it in PRO even if it is not zero */ - if (csd->wc_blocked || (is_mm && (csa->total_blks != csa->ti->total_blks))) - { /* If blocked, or we have MM and file has been extended, force repair */ + if (cnl->wc_blocked || (is_mm && (csa->total_blks != csa->ti->total_blks))) + { /* If blocked, or we have MM and file has been extended, force repair */ status = cdb_sc_helpedout; /* force retry with special status so philanthropy isn't punished */ + assert((CDB_STAGNATE > t_tries) || !is_mm || (csa->total_blks == csa->ti->total_blks)); goto failed_skip_revert; } else { @@ -297,6 +321,29 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) n_blks_validated = 0; VALIDATE_CYCLE(is_mm, hist1); /* updates n_blks_validated */ VALIDATE_CYCLE(is_mm, hist2); /* updates n_blks_validated */ + assert(cdb_sc_normal == status); +# ifdef UNIX + if (MISMATCH_ROOT_CYCLES(csa, cnl)) + { /* If a root block has moved, we might have started the read from the wrong root block, in which + * case we cannot trust the entire search. Need to redo root search. + */ + was_crit = csa->now_crit; + if (!was_crit) + grab_crit(gv_cur_region); + status = cdb_sc_gvtrootmod2; + if (MISMATCH_ONLN_RLBK_CYCLES(csa, cnl)) + { + assert(!mupip_jnl_recover); + status = ONLN_RLBK_STATUS(csa, cnl); + SYNC_ONLN_RLBK_CYCLES; + SYNC_ROOT_CYCLES(NULL); + } else + SYNC_ROOT_CYCLES(csa); + if (!was_crit && !csa->hold_onto_crit) + rel_crit(gv_cur_region); + goto failed_skip_revert; + } +# endif /* Assert that if gtm_gvundef_fatal is non-zero, then we better not be about to signal a GVUNDEF */ assert(!TREF(gtm_gvundef_fatal) || !ready2signal_gvundef_lcl); if (csa->now_crit && !csa->hold_onto_crit) @@ -311,26 +358,36 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) return csa->ti->curr_tn; } } - busy2free_seen = FALSE; - recycled2free_seen = FALSE; + assert((gds_t_committed < gds_t_busy2free) && (n_gds_t_op > gds_t_busy2free)); + assert((gds_t_committed < gds_t_recycled2free) && (n_gds_t_op > gds_t_recycled2free)); + assert((gds_t_committed < gds_t_write_root) && (n_gds_t_op > gds_t_write_root)); + free_seen = 0; cw_depth = cw_set_depth; cw_bmp_depth = cw_depth; - if (0 != cw_set_depth) + if ((0 != cw_set_depth) && (gds_t_writemap == cw_set[cw_set_depth - 1].mode)) { - if (gds_t_writemap == cw_set[0].mode) + if (1 == cw_set_depth) { cw_depth = 0; cw_bmp_depth = 0; - } else if ((gds_t_busy2free == cw_set[0].mode) && (gds_t_writemap == cw_set[1].mode)) + } else if (gds_t_busy2free == cw_set[0].mode) { + assert(TREF(in_gvcst_bmp_mark_free)); + free_seen |= BUSY2FREE; + if (CSE_LEVEL_DRT_LVL0_FREE == cw_set[0].level) + { /* the block is in fact a level-0 block in the directory tree */ + assert(MUSWP_FREE_BLK == TREF(in_mu_swap_root_state)); + free_seen |= FREE_DIR_DATA; + } + assert(2 == cw_set_depth); cw_depth = 0; - busy2free_seen = TRUE; cw_bmp_depth = 1; - } else if ((gds_t_recycled2free == cw_set[0].mode) && (gds_t_writemap == cw_set[1].mode)) - { - assert(process_id == cnl->trunc_pid && in_mu_truncate); /* In phase 1 of MUPIP REORG -TRUNCATE */ - cw_depth = 1; - recycled2free_seen = TRUE; + } else if (gds_t_recycled2free == cw_set[0].mode) + { /* in phase 1 of MUPIP REORG -TRUNCATE, and we need to free a recycled block */ + assert(in_mu_truncate); + free_seen |= RECYCLED2FREE; + assert(2 == cw_set_depth); + cw_depth = 0; cw_bmp_depth = 1; } } @@ -343,15 +400,17 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) */ SS_INIT_IF_NEEDED(csa, cnl); } else - csa->snapshot_in_prog = FALSE; - lcl_ss_in_prog = SNAPSHOTS_IN_PROG(csa); /* store in local variable to avoid pointer access */ - reorg_ss_in_prog = (mu_reorg_process && lcl_ss_in_prog); /* store in local variable if both snapshots and MUPIP REORG - * are in progress */ + CLEAR_SNAPSHOTS_IN_PROG(csa); # endif if (0 != cw_depth) { /* Caution : since csa->backup_in_prog and read_before_image are initialized below * only if (cw_depth), these variables should be used below only within an if (cw_depth). */ +# ifdef GTM_SNAPSHOT + lcl_ss_in_prog = SNAPSHOTS_IN_PROG(csa); /* store in local variable to avoid pointer access */ + reorg_ss_in_prog = (mu_reorg_process && lcl_ss_in_prog); /* store in local variable if both snapshots and MUPIP + * REORG are in progress */ +# endif assert(SIZEOF(bsiz) == SIZEOF(old_block->bsiz)); assert(update_trans); csa->backup_in_prog = (BACKUP_NOT_IN_PROGRESS != cnl->nbb); @@ -374,16 +433,31 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } else { GET_CDB_SC_CODE(cs->blk, status); /* code is set in status */ +# ifdef UNIX + if (is_mm && (cdb_sc_gbloflow == status)) + { + assert(NULL != gv_currkey); + if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) + end = &buff[MAX_ZWR_KEY_SZ - 1]; + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, + ERR_GVIS, 2, end - buff, buff); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, + ERR_GVIS, 2, end - buff, buff); + } +# endif } goto failed_skip_revert; } - cs->was_free = !blk_used; + assert(!is_mm || (cs->blk < csa->total_blks)); + assert((CDB_STAGNATE > t_tries) || (cs->blk < csa->ti->total_blks)); + blk_used ? BIT_SET_RECYCLED_AND_CLEAR_FREE(cs->blk_prior_state) + : BIT_CLEAR_RECYCLED_AND_SET_FREE(cs->blk_prior_state); BEFORE_IMAGE_NEEDED(read_before_image, cs, csa, csd, cs->blk, before_image_needed); if (!before_image_needed) cs->old_block = NULL; else { - block_is_free = cs->was_free; + block_is_free = WAS_FREE(cs->blk_prior_state); cs->old_block = t_qread(cs->blk, (sm_int_ptr_t)&cs->cycle, &cs->cr); old_block = (blk_hdr_ptr_t)cs->old_block; if (NULL == old_block) @@ -391,7 +465,8 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) status = (enum cdb_sc)rdfail_detail; goto failed_skip_revert; } - if (!cs->was_free && (NULL != jbbp) && (old_block->tn < jbbp->epoch_tn)) + ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)cs->old_block, csa); + if (!WAS_FREE(cs->blk_prior_state) && (NULL != jbbp) && (old_block->tn < jbbp->epoch_tn)) { /* Compute CHECKSUM for writing PBLK record before getting crit. * It is possible that we are reading a block that is actually marked free in * the bitmap (due to concurrency issues at this point). Therefore we might be @@ -418,14 +493,14 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert((CDB_STAGNATE > t_tries) || (cs->blk < csa->ti->total_blks)); cs->mode = gds_t_acquired; assert(GDSVCURR == cs->ondsk_blkver); - } else if (reorg_ss_in_prog && cs->was_free) + } else if (reorg_ss_in_prog && WAS_FREE(cs->blk_prior_state)) { assert((gds_t_acquired == cs->mode) && (NULL == cs->old_block)); /* If snapshots are in progress, we might want to read the before images of the FREE blocks also. * Since mu_swap_blk mimics a small part of t_end, it sets cse->mode to gds_t_acquired and hence * will not read the before images of the FREE blocks in t_end. To workaround this, set - * cse->was_free to TRUE so that in t_end, this condition can be used to read the before images of - * the FREE blocks if needed. + * cse->blk_prior_state's free status to TRUE so that in t_end, this condition can be used to read + * the before images of the FREE blocks if needed. */ BEFORE_IMAGE_NEEDED(read_before_image, cs, csa, csd, cs->blk, before_image_needed); if (before_image_needed) @@ -438,6 +513,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) status = (enum cdb_sc)rdfail_detail; goto failed_skip_revert; } + ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)cs->old_block, csa); } } } @@ -450,13 +526,13 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) tmp_cw_set_depth = cw_map_depth ? cw_map_depth : cw_set_depth; TOTAL_NONTPJNL_REC_SIZE(total_jnl_rec_size, non_tp_jfb_ptr, csa, tmp_cw_set_depth); /* For a non-tp update maximum journal space we may need is total size of - * 1) space for maximum CDB_CW_SET_SIZE PBLKs, that is, MAX_JNL_REC_SIZE * CDB_CW_SET_SIZE + * 1) space for maximum CDB_CW_SET_SIZE PBLKs, that is, MAX_MAX_NONTP_JNL_REC_SIZE * CDB_CW_SET_SIZE * 2) space for a logical record itself, that is, MAX_LOGI_JNL_REC_SIZE and * 3) overhead records (MIN_TOTAL_NONTPJNL_REC_SIZE + JNL_FILE_TAIL_PRESERVE) * This requirement is less than the minimum autoswitchlimit size (JNL_AUTOSWITCHLIMIT_MIN) as asserted below. * Therefore we do not need any check to issue JNLTRANS2BIG error like is being done in tp_tend.c */ - assert((CDB_CW_SET_SIZE * MAX_JNL_REC_SIZE + MAX_LOGI_JNL_REC_SIZE + + assert((CDB_CW_SET_SIZE * MAX_MAX_NONTP_JNL_REC_SIZE + MAX_LOGI_JNL_REC_SIZE + MIN_TOTAL_NONTPJNL_REC_SIZE + JNL_FILE_TAIL_PRESERVE) <= (JNL_AUTOSWITCHLIMIT_MIN * DISK_BLOCK_SIZE)); DEBUG_ONLY(tot_jrec_size = MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size)); assert(tot_jrec_size <= csd->autoswitchlimit); @@ -470,7 +546,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert(jgbl.gbl_jrec_time); } block_saved = FALSE; - ESTABLISH_RET(t_ch, 0); + ESTABLISH_NOUNWIND(t_ch); /* avoid hefty setjmp call, which is ok since we never unwind t_ch */ assert(!csa->hold_onto_crit || csa->now_crit); if (!csa->now_crit) { @@ -478,8 +554,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) { /* Get more space if needed. This is done outside crit so that * any necessary IO has a chance of occurring outside crit. * The available space must be double-checked inside crit. */ - if (!is_mm && (cnl->wc_in_free < (int4)(cw_set_depth + 1)) - && !wcs_get_space(gv_cur_region, cw_set_depth + 1, NULL)) + if (!is_mm && !WCS_GET_SPACE(gv_cur_region, cw_set_depth + 1, NULL)) assert(FALSE); /* wcs_get_space should have returned TRUE unconditionally in this case */ for (;;) { @@ -511,6 +586,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) goto failed; } } + com_csum = 0; /* We should never proceed to update a frozen database. Only exception is DSE */ assert(!update_trans || !csd->freeze || IS_DSE_IMAGE); # ifdef UNIX @@ -519,25 +595,27 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) * here in the forward phase */ assert(!csd->file_corrupt || mupip_jnl_recover); - if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) - { /* A concurrent Online Rollback occurred. Restart to be safe. */ - assert(!mupip_jnl_recover); - /* Note: We don't assert that CDB_STAGNATE > t_tries because we can detect an online rollback even in the final - * retry. - */ - status = cdb_sc_onln_rlbk1; - if (csa->db_onln_rlbkd_cycle != csa->nl->db_onln_rlbkd_cycle) - status = cdb_sc_onln_rlbk2; /* database was rolled back to a different logical state */ - SYNC_ONLN_RLBK_CYCLES; + if (MISMATCH_ROOT_CYCLES(csa, cnl)) + { + status = cdb_sc_gvtrootmod2; + if (MISMATCH_ONLN_RLBK_CYCLES(csa, cnl)) + { + assert(!mupip_jnl_recover); + status = ONLN_RLBK_STATUS(csa, cnl); + SYNC_ONLN_RLBK_CYCLES; + if (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process) + SYNC_ROOT_CYCLES(NULL); + } else + SYNC_ROOT_CYCLES(csa); goto failed; } /* We should never proceed to commit if the global variable - only_reset_clues_if_onln_rlbk - is TRUE AND if the prior * retry was due to ONLINE ROLLBACK. This way, we ensure that, whoever set the global variable knows to handle ONLINE * ROLLBACK and resets it before returning control to the application. */ - DEBUG_ONLY(prev_status = (0 < t_tries) ? t_fail_hist[t_tries - 1] : cdb_sc_normal); + DEBUG_ONLY(prev_status = LAST_RESTART_CODE); assert((cdb_sc_normal == prev_status) || ((cdb_sc_onln_rlbk1 != prev_status) && (cdb_sc_onln_rlbk2 != prev_status)) - || (!TREF(only_reset_clues_if_onln_rlbk))); + || (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process)); # endif if (is_mm && ((csa->hdr != csd) || (csa->total_blks != csa->ti->total_blks))) { /* If MM, check if wcs_mm_recover was invoked as part of the grab_crit done above OR if @@ -546,18 +624,6 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) status = cdb_sc_helpedout; /* force retry with special status so philanthropy isn't punished */ goto failed; } -# ifdef GTM_TRUNCATE - assert(csa->total_blks); - if (csa->ti->total_blks < csa->total_blks) - { - /* File has been truncated since this process entered t_end or last called gdsfilext. I.e., the file is smaller - * than its last known size and we might have allocated blocks beyond csa->ti->total_blks. Restart. */ - assert(dba_mm != csd->acc_meth); - assert(CDB_STAGNATE > t_tries); /* On the final retry, should have crit and truncate can't happen */ - status = cdb_sc_truncate; - goto failed; - } -# endif assert(!cw_depth || update_trans); # ifdef GTM_TRIGGER if (!skip_dbtriggers) @@ -648,14 +714,13 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } } /* in crit, ensure cache-space is available. the out-of-crit check done above might not have been enough */ - if (!is_mm && (cnl->wc_in_free < (int4)(cw_set_depth + 1)) - && !wcs_get_space(gv_cur_region, cw_set_depth + 1, NULL)) + if (!is_mm && !WCS_GET_SPACE(gv_cur_region, cw_set_depth + 1, NULL)) { - assert(csd->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ + assert(cnl->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_hist); - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); goto failed; } if (inctn_invalid_op != inctn_opcode) @@ -690,7 +755,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert(csd == csa->hdr); valid_thru = dbtn = csa->ti->curr_tn; if (!is_mm) - tnque_earliest_tn = ((th_rec_ptr_t)((sm_uc_ptr_t)csa->th_base + csa->th_base->tnque.fl))->tn; + oldest_hist_tn = OLDEST_HIST_TN(csa); if (update_trans) valid_thru++; n_blks_validated = 0; @@ -712,7 +777,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) bt = bt_get(t1->blk_num); if (NULL == bt) { - if (t1->tn <= tnque_earliest_tn) + if (t1->tn <= oldest_hist_tn) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_losthist; @@ -735,7 +800,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) if (cr->blk != bt->blk) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_crbtmismatch1); status = cdb_sc_crbtmismatch; goto failed; @@ -779,9 +844,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } if ((cache_rec_ptr_t)CR_NOTVALID == cr) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_hist); - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); goto failed; } if ((NULL == cr) || (cr->cycle != t1->cycle) @@ -790,7 +855,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) if ((NULL != cr) && (NULL != bt) && (cr->blk != bt->blk)) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_crbtmismatch2); status = cdb_sc_crbtmismatch; goto failed; @@ -806,18 +871,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) cs = t1->cse; if (cs) { - if (n_gds_t_op > cs->mode && gds_t_recycled2free != cs->mode) /* don't pass histories... */ + if (n_gds_t_op > cs->mode) { assert(update_trans); - assert(gds_t_busy2free > gds_t_committed); - assert(gds_t_busy2free < n_gds_t_op); - assert(gds_t_write_root > gds_t_committed); - assert(gds_t_write_root < n_gds_t_op); - assert(gds_t_recycled2free > gds_t_committed); - assert(gds_t_recycled2free < n_gds_t_op); - assert((gds_t_committed > cs->mode) - || (busy2free_seen && (gds_t_busy2free == cs->mode)) - || (recycled2free_seen && gds_t_recycled2free == cs->mode)); PIN_CACHE_RECORD(cr, cr_array, cr_array_index); /* If cs->mode is gds_t_busy2free, then the corresponding cache-record needs * to be pinned to write the before-image right away but this cse is not going @@ -827,8 +883,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) * that the cache-record corresponding to the gds_t_busy2free cse is always the * first one in the cr_array. */ + assert((gds_t_committed > cs->mode) + || (gds_t_busy2free == cs->mode) || (gds_t_recycled2free == cs->mode)); assert((gds_t_busy2free != cs->mode) || (1 == cr_array_index)); assert((gds_t_recycled2free != cs->mode) || (1 == cr_array_index)); + assert((gds_t_busy2free != cs->mode) || (free_seen & BUSY2FREE)); + assert((gds_t_recycled2free != cs->mode) || (free_seen & RECYCLED2FREE)); } t1->cse = NULL; /* reset for next transaction */ } @@ -845,7 +905,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) * resetting the clue just before doing the next gvcst_search. The mu_reorg* routines already take care of this reset * (in fact, this is asserted in gvcst_search too). So we can allow invalid clues here in that special case. */ - if (!mu_reorg_process && (NULL != gv_target) && gv_target->clue.end && !in_mu_truncate) + if (!mu_reorg_process && (NULL != gv_target) && gv_target->clue.end) /* gv_target can be NULL in case of DSE MAPS etc. */ DEBUG_GVT_CLUE_VALIDATE(gv_target); /* Validate that gvt has valid first_rec, clue & last_rec fields */ # endif @@ -882,7 +942,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) bt = bt_get(cs->blk); if (NULL == bt) { - if (cs->tn <= tnque_earliest_tn) + if (cs->tn <= oldest_hist_tn) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_lostbmlhist; @@ -911,7 +971,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) if (cr->blk != bt->blk) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_crbtmismatch3); status = cdb_sc_crbtmismatch; goto failed; @@ -920,9 +980,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } if ((cache_rec_ptr_t)CR_NOTVALID == cr) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_bitmap_nullbt); - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); goto failed; } if ((NULL == cr) || (cr->cycle != cs->cycle) || @@ -953,7 +1013,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } } assert(csd == csa->hdr); - assert(!need_kip_incr || update_trans); + assert(!need_kip_incr || update_trans UNIX_ONLY(|| TREF(in_gvcst_redo_root_search))); + /* At this point if the transaction has no updates, we are done with validation (all possibilities of "goto failed") + * and so we need to assert that donot_commit better be set to FALSE at this point. For transaction with updates, + * there are a few more "goto failed" usages below so we will do this check separately after those usages. + */ + assert(update_trans || !TREF(donot_commit)); /* We should never commit a transaction that was determined restartable */ if (update_trans) { if (cw_depth && read_before_image && !is_mm) @@ -964,11 +1029,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) { /* have already read old block for creates before we got crit, make sure * cache record still has correct block. if not, reset "cse" fields to * point to correct cache-record. this is ok to do since we only need the - * prior content of the block (for online backup or before-image journaling) - * and did not rely on it for constructing the transaction. Restart if - * block is not present in cache now or is being read in currently. + * prior content of the block (for online backup or before-image journaling + * or online integ) and did not rely on it for constructing the transaction. + * Restart if block is not present in cache now or is being read in currently. */ - if ((gds_t_acquired == cs->mode || gds_t_recycled2free == cs->mode) && (NULL != cs->old_block)) + assert((gds_t_busy2free != cs->mode) && (gds_t_recycled2free != cs->mode)); + if ((gds_t_acquired == cs->mode) && (NULL != cs->old_block)) { assert(read_before_image == ((JNL_ENABLED(csa) && csa->jnl_before_image) || csa->backup_in_prog @@ -976,9 +1042,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) cr = db_csh_get(cs->blk); if ((cache_rec_ptr_t)CR_NOTVALID == cr) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_jnl_cwset); - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); goto failed; } /* It is possible that cr->in_cw_set is non-zero in case a concurrent MUPIP REORG @@ -1006,7 +1072,8 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) * while doing the bm_getfree, if we got a free block, then no need to compute checksum * as we would NOT be writing before images of free blocks to journal files */ - cksum_needed = (!cs->was_free && (NULL != jbbp) && (old_block_tn < jbbp->epoch_tn)); + cksum_needed = (!WAS_FREE(cs->blk_prior_state) && (NULL != jbbp) + && (old_block_tn < jbbp->epoch_tn)); if ((cs->cr != cr) || (cs->cycle != cr->cycle)) { /* Block has relocated in the cache. Adjust pointers to new location. */ cs->cr = cr; @@ -1066,66 +1133,59 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) || (ERR_GVPUTFAIL == t_err) && gvdupsetnoop /* exception case (a) */ || (ERR_JRTNULLFAIL == t_err) /* exception case (d) */ || (ERR_GVKILLFAIL == t_err) && gv_play_duplicate_kills); /* exception case (b) */ - if (REPL_ALLOWED(csa) && is_replicator && (inctn_invalid_op == inctn_opcode)) + if (REPL_ALLOWED(csa) && (NULL != jnlpool_ctl)) { - replication = TRUE; - jpl = jnlpool_ctl; - tjpl = temp_jnlpool_ctl; repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; - /* No concurrent online rollbacks can happen at this point due to grab_crit (done above). So, the jnlpool - * should be in sync. There is one exception though. If this is GT.CM GNP Server and the last client - * disconnected, the server invokes gtcmd_rundown which in-turn invokes gds_rundown thereby running down - * all active databases at this point but leaves the journal pool up and running. Now, if an online rollback - * is attempted, it increments the onln_rlbk_cycle in the journal pool, but repl_csa->onln_rlbk_cycle is not - * synced yet. So, the grab_crit done above will NOT detect a concurrent online rollback and it doesn't need - * to because the rollback happened AFTER the rundown. So, in this case sync the repl_csa->onln_rlbk_cycle - * with the journal pool cycle (now that we have crit). Also, assert that this is the only case we know of - * for the cycles to be out-of-sync. This is all needed in DBG only, as in PRO jnlpool_ctl->onln_rlbk_cycle - * is used only by the replication servers (which GT.CM is not) and so even if it continues with an - * out-of-sync repl_csa->onln_rlbk_cycle, t_end logic does the right thing. - * Note: The below assert is better kept in the GRAB_LOCK macro but is not currently done because image_type - * variable is needed which is of type enum gtmImageTypes which is NOT available wherever GRAB_LOCK is used. - * Until we move the GRAB_LOCK macro to a separate header, keep the assert here. - */ - UNIX_ONLY( - assert((repl_csa->onln_rlbk_cycle == jnlpool_ctl->onln_rlbk_cycle) || IS_GTCM_GNP_SERVER_IMAGE); - DEBUG_ONLY(repl_csa->onln_rlbk_cycle = jnlpool_ctl->onln_rlbk_cycle); - ) if (!repl_csa->hold_onto_crit) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); assert(repl_csa->now_crit); - tjpl->write_addr = jpl->write_addr; - tjpl->write = jpl->write; - tjpl->jnl_seqno = jpl->jnl_seqno; + jnlpool_crit_acquired = TRUE; # ifdef UNIX - if (INVALID_SUPPL_STRM != strm_index) - { /* Need to also update supplementary stream seqno */ - supplementary = TRUE; - assert(0 <= strm_index); - /* assert(strm_index < ARRAYSIZE(tjpl->strm_seqno)); */ - strm_seqno = jpl->strm_seqno[strm_index]; - ASSERT_INST_FILE_HDR_HAS_HISTREC_FOR_STRM(strm_index); - } else - supplementary = FALSE; -# endif - INT8_ONLY(assert(tjpl->write == tjpl->write_addr % tjpl->jnlpool_size)); - assert(jgbl.cumul_jnl_rec_len); - tmp_cumul_jnl_rec_len = (uint4)(jgbl.cumul_jnl_rec_len + SIZEOF(jnldata_hdr_struct)); - tjpl->write += SIZEOF(jnldata_hdr_struct); - if (tjpl->write >= tjpl->jnlpool_size) + /* With jnlpool lock held, check instance freeze, and retry if set. */ + if (jnlpool.jnlpool_ctl->freeze) { - assert(tjpl->write == tjpl->jnlpool_size); - tjpl->write = 0; + status = cdb_sc_instancefreeze; + goto failed; + } +# endif + if (is_replicator && (inctn_invalid_op == inctn_opcode)) + { + jpl = jnlpool_ctl; + tjpl = temp_jnlpool_ctl; + replication = TRUE; + tjpl->write_addr = jpl->write_addr; + tjpl->write = jpl->write; + tjpl->jnl_seqno = jpl->jnl_seqno; +# ifdef UNIX + if (INVALID_SUPPL_STRM != strm_index) + { /* Need to also update supplementary stream seqno */ + supplementary = TRUE; + assert(0 <= strm_index); + /* assert(strm_index < ARRAYSIZE(tjpl->strm_seqno)); */ + strm_seqno = jpl->strm_seqno[strm_index]; + ASSERT_INST_FILE_HDR_HAS_HISTREC_FOR_STRM(strm_index); + } else + supplementary = FALSE; +# endif + INT8_ONLY(assert(tjpl->write == tjpl->write_addr % tjpl->jnlpool_size)); + assert(jgbl.cumul_jnl_rec_len); + tmp_cumul_jnl_rec_len = (uint4)(jgbl.cumul_jnl_rec_len + SIZEOF(jnldata_hdr_struct)); + tjpl->write += SIZEOF(jnldata_hdr_struct); + if (tjpl->write >= tjpl->jnlpool_size) + { + assert(tjpl->write == tjpl->jnlpool_size); + tjpl->write = 0; + } + assert(jpl->early_write_addr == jpl->write_addr); + jpl->early_write_addr = jpl->write_addr + tmp_cumul_jnl_rec_len; + /* Source server does not read in crit. It relies on early_write_addr, the transaction + * data, lastwrite_len, write_addr being updated in that order. To ensure this order, + * we have to force out early_write_addr to its coherency point now. If not, the source + * server may read data that is overwritten (or stale). This is true only on + * architectures and OSes that allow unordered memory access + */ + SHM_WRITE_MEMORY_BARRIER; } - assert(jpl->early_write_addr == jpl->write_addr); - jpl->early_write_addr = jpl->write_addr + tmp_cumul_jnl_rec_len; - /* Source server does not read in crit. It relies on early_write_addr, the transaction - * data, lastwrite_len, write_addr being updated in that order. To ensure this order, - * we have to force out early_write_addr to its coherency point now. If not, the source - * server may read data that is overwritten (or stale). This is true only on - * architectures and OSes that allow unordered memory access - */ - SHM_WRITE_MEMORY_BARRIER; } assert(cw_set_depth < CDB_CW_SET_SIZE); ASSERT_CURR_TN_EQUALS_EARLY_TN(csa, dbtn); @@ -1181,7 +1241,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) * across multiple generation journal files. */ if (SS_NORMAL != (jnl_status = jnl_flush(jpc->region))) { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during t_end"), jnl_status); assert((!JNL_ENABLED(csd)) && (JNL_ENABLED(csa))); @@ -1203,10 +1263,11 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) { if ((jbp->next_epoch_time <= jgbl.gbl_jrec_time) UNCONDITIONAL_EPOCH_ONLY(|| TRUE)) { /* Flush the cache. Since we are in crit, defer syncing epoch */ - if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT)) + if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT + | WCSFLU_SPEEDUP_NOBEFORE)) { SET_WCS_FLU_FAIL_STATUS(status, csd); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_end_jnl_wcsflu); goto failed; } @@ -1225,18 +1286,28 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } else { if (SS_NORMAL != jpc->status) - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), - jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region), jpc->status); else - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region)); } } assert(!TREF(donot_commit)); /* We should never commit a transaction that was determined restartable */ - assert(TN_NOT_SPECIFIED > MAX_TN_V5); /* Ensure TN_NOT_SPECIFIED isn't a valid TN number */ + assert(TN_NOT_SPECIFIED > MAX_TN_V6); /* Ensure TN_NOT_SPECIFIED isn't a valid TN number */ blktn = (TN_NOT_SPECIFIED == ctn) ? dbtn : ctn; csa->ti->early_tn = dbtn + 1; if (JNL_ENABLED(csa)) { + /* At this point we know tn,pini_addr and jrec_time; so calculate the checksum for the transaction once + reuse it for all the updates + */ + if(!com_csum) + { + ADJUST_CHECKSUM_TN(INIT_CHECKSUM_SEED, &dbtn, com_csum); + ADJUST_CHECKSUM(com_csum, csa->jnl->pini_addr, com_csum); + ADJUST_CHECKSUM(com_csum, jgbl.gbl_jrec_time, com_csum); + } DEBUG_ONLY(save_gbl_jrec_time = jgbl.gbl_jrec_time;) if (jbp->before_images) { /* do not write PBLKs if MUPIP REORG UPGRADE/DOWNGRADE with -NOSAFEJNL */ @@ -1246,24 +1317,26 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) for (cs = cw_set, cs_top = cs + cw_set_depth; cs < cs_top; ++cs) { /* PBLK computations for FREE blocks are not needed */ - if (cs->was_free) + if (WAS_FREE(cs->blk_prior_state)) continue; /* write out before-update journal image records */ mode = cs->mode; if (gds_t_committed < mode) - { /* There are two possibilities at this point. + { /* There are three possibilities at this point. * a) gds_t_write_root : In this case no need to write PBLK. * b) gds_t_busy2free : This is set by gvcst_bmp_mark_free to indicate * that a block has to be freed right away instead of taking it * through the RECYCLED state. This should be done only if * csd->db_got_to_v5_once has not yet become TRUE. Once it is * TRUE, block frees will write PBLK only when the block is reused. + * An exception is when the block is a level-0 block in directory + * tree, we always write PBLK immediately. + * c) gds_t_recycled2free: Need to write PBLK */ assert((gds_t_write_root == mode) || (gds_t_busy2free == mode) || (gds_t_recycled2free == mode)); - if ((gds_t_write_root == mode) - || (gds_t_busy2free == mode) && csd->db_got_to_v5_once) - continue; + if (!SAVE_2FREE_IMAGE(mode, free_seen, csd)) + continue; } old_block = (blk_hdr_ptr_t)cs->old_block; ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)old_block, csa); @@ -1316,7 +1389,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) (sm_uc_ptr_t)old_block); } # endif - jnl_write_pblk(csa, cs, old_block); + jnl_write_pblk(csa, cs, old_block, com_csum); cs->jnl_freeaddr = jbp->freeaddr; } DEBUG_ONLY( @@ -1331,7 +1404,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert(1 == cw_set_depth); /* only one block at a time */ assert(!replication); cs = cw_set; - jnl_write_aimg_rec(csa, cs); + jnl_write_aimg_rec(csa, cs, com_csum); } else if (write_inctn) { assert(!replication); @@ -1367,9 +1440,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) } else if (!jgbl.forw_phase_recovery) jnl_fence_ctl.token = seq_num_zero; /* In case of forw-phase of recovery, token would have been set by mur_output_record */ - jnl_write_logical(csa, non_tp_jfb_ptr); + jnl_write_logical(csa, non_tp_jfb_ptr, com_csum); } else - jnl_write_ztp_logical(csa, non_tp_jfb_ptr); + jnl_write_ztp_logical(csa, non_tp_jfb_ptr, com_csum); /* Ensure jgbl.gbl_jrec_time did not get reset by any of the jnl writing functions */ assert(save_gbl_jrec_time == jgbl.gbl_jrec_time); } else if (replication) @@ -1384,9 +1457,41 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) if (supplementary) jnl_fence_ctl.strm_seqno = SET_STRM_INDEX(strm_seqno, strm_index); ) - jnl_write_logical(csa, non_tp_jfb_ptr); + jnl_write_logical(csa, non_tp_jfb_ptr, com_csum); } else - jnl_write_ztp_logical(csa, non_tp_jfb_ptr); + jnl_write_ztp_logical(csa, non_tp_jfb_ptr, com_csum); + } + if (free_seen) + { /* Write to snapshot and backup file for busy2free and recycled2free mode. These modes only appear in + * mupip reorg -truncate or v4-v5 upgrade, neither of which can occur with MM. + */ + assert(!is_mm); + cs = &cw_set[0]; + if (SAVE_2FREE_IMAGE(cs->mode, free_seen, csd)) + { + blkid = cs->blk; + assert(!IS_BITMAP_BLK(blkid) && (blkid == cr_array[0]->blk)); + csa->backup_in_prog = (BACKUP_NOT_IN_PROGRESS != cnl->nbb); + cr = cr_array[0]; + backup_cr = cr; + blk_ptr = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); + backup_blk_ptr = blk_ptr; + BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, block_saved, + dummysi->backup_block_saved); +# ifdef GTM_SNAPSHOT + if (SNAPSHOTS_IN_PROG(csa)) + { /* we write the before-image to snapshot file only for FAST_INTEG and not for + * regular integ because the block is going to be marked free at this point + * and in case of a regular integ a before image will be written to the snapshot + * file eventually when the free block gets reused. So the before-image writing + * effectively gets deferred but does happen. + */ + lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx); + if (lcl_ss_ctx && FASTINTEG_IN_PROG(lcl_ss_ctx)) + WRITE_SNAPSHOT_BLOCK(cs_addrs, cr, NULL, blkid, lcl_ss_ctx); + } +# endif + } } if (replication) { @@ -1424,11 +1529,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) { mode = cs->mode; assert((gds_t_write_root != mode) || ((cs - cw_set) + 1 == cw_depth)); + assert((gds_t_committed > mode) || + (gds_t_busy2free == mode) || (gds_t_recycled2free == mode) || (gds_t_write_root == mode)); cs->old_mode = (int4)mode; /* note down before being reset to gds_t_committed */ - assert(gds_t_committed < gds_t_write_root); - assert(gds_t_committed < gds_t_busy2free); - assert((n_gds_t_op != mode) && (gds_t_committed != mode)); - assert((kill_t_write != mode) && (kill_t_create != mode)); if (gds_t_committed > mode) { DEBUG_ONLY( @@ -1500,7 +1603,8 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) /* signal secshr_db_clnup/t_commit_cleanup, roll-back is no longer possible */ update_trans |= UPDTRNS_TCOMMIT_STARTED_MASK; assert(cdb_sc_normal == status); - assert(!csd->freeze || IS_DSE_IMAGE); /* should never increment curr_tn on a frozen database except if DSE */ + /* should never increment curr_tn on a frozen database except if DSE */ + assert(!(csd->freeze UNIX_ONLY(|| (replication && jnlpool.jnlpool_ctl->freeze))) || IS_DSE_IMAGE); INCREMENT_CURR_TN(csd); csa->t_commit_crit = T_COMMIT_CRIT_PHASE2; /* set this BEFORE releasing crit but AFTER incrementing curr_tn */ /* If db is journaled, then db header is flushed periodically when writing the EPOCH record, @@ -1509,32 +1613,26 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) assert(!JNL_ENABLED(csa) || (jbp == csa->jnl->jnl_buff)); if ((!JNL_ENABLED(csa) || !JNL_HAS_EPOCH(jbp)) && !(csd->trans_hist.curr_tn & (HEADER_UPDATE_COUNT - 1))) fileheader_sync(gv_cur_region); + UNIX_ONLY(assert((MUSWP_INCR_ROOT_CYCLE != TREF(in_mu_swap_root_state)) || need_kip_incr)); if (need_kip_incr) /* increment kill_in_prog */ { INCR_KIP(csd, csa, kip_csa); need_kip_incr = FALSE; +# ifdef UNIX + if (MUSWP_INCR_ROOT_CYCLE == TREF(in_mu_swap_root_state)) + { /* Increment root_search_cycle to let other processes know that they should redo_root_search. */ + assert((0 != cw_map_depth) && !TREF(in_gvcst_redo_root_search)); + csa->nl->root_search_cycle++; + } +# endif } start_tn = dbtn; /* start_tn temporarily used to store currtn (for bg_update_phase2) before releasing crit */ - } - if (!is_mm && busy2free_seen) - { - assert((gds_t_busy2free == cw_set[0].mode) && cr_array_index && (cw_set[0].blk == cr_array[0]->blk)); - assert(process_id == cr_array[0]->in_cw_set); - UNPIN_CACHE_RECORD(cr_array[0]); /* need to do this BEFORE releasing crit as we have no other lock on this buffer */ - } else if (recycled2free_seen) - { - assert(gds_t_recycled2free == cw_set[0].mode); - assert(!is_mm); - if (read_before_image) - { - assert(cr_array_index == 2); - assert(cw_set[0].blk = cr_array[1]->blk); - assert(process_id == cr_array[1]->in_cw_set); - UNPIN_CACHE_RECORD(cr_array[1]); - } else - { - assert(cr_array_index == 1); - /* Never pinned it in the first place */ + if (free_seen) + { /* need to do below BEFORE releasing crit as we have no other lock on this buffer */ + VMS_ONLY(assert((BUSY2FREE == free_seen) && (2 <= cr_array_index) && (cr_array_index <= 3))); + UNIX_ONLY(assert(2 == cr_array_index)); /* Unlike VMS, no chance to pin a twin for bitmap update */ + assert((2 == cw_set_depth) && (process_id == cr_array[0]->in_cw_set)); + UNPIN_CACHE_RECORD(cr_array[0]); } } if (!csa->hold_onto_crit) @@ -1571,8 +1669,11 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn) jpl->write_addr += jnl_header->jnldata_len; assert(jpl->early_write_addr == jpl->write_addr); jpl->jnl_seqno = tjpl->jnl_seqno; - if (!repl_csa->hold_onto_crit) - rel_lock(jnlpool.jnlpool_dummy_reg); + } + if (jnlpool_crit_acquired) + { + assert((NULL != jnlpool_ctl) && repl_csa->now_crit && REPL_ALLOWED(csa)); + rel_lock(jnlpool.jnlpool_dummy_reg); } /* If BG, check that we have not pinned any more buffers than we are updating */ DBG_CHECK_PINNED_CR_ARRAY_CONTENTS(is_mm, cr_array, cr_array_index, csd->bplmap); @@ -1646,7 +1747,7 @@ skip_cr_array: if (REPL_ALLOWED(csa) && IS_DSE_IMAGE) { temp_tn = dbtn + 1; - send_msg(VARLSTCNT(6) ERR_NOTREPLICATED, 4, &temp_tn, LEN_AND_LIT("DSE"), process_id); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_NOTREPLICATED, 4, &temp_tn, LEN_AND_LIT("DSE"), process_id); } INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_readwrite, 1); INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_blkread, n_blks_validated); @@ -1660,6 +1761,7 @@ skip_cr_array: /* "secshr_db_clnup/t_commit_cleanup" assume an active non-TP transaction if cw_set_depth is non-zero * or if update_trans is set to T_COMMIT_STARTED. Now that the transaction is complete, reset these fields. */ + DEBUG_ONLY(jgbl.cumul_index = jgbl.cu_jnl_index = 0;) /* symmetrical with TP and makes op_tstart checks happy */ cw_set_depth = 0; update_trans = 0; CWS_RESET; @@ -1678,12 +1780,29 @@ failed_skip_revert: RESTORE_CURRTN_IF_NEEDED(csa, write_inctn, decremented_currtn); retvalue = t_commit_cleanup(status, 0); /* we expect to get a return value indicating update was NOT underway */ assert(!retvalue); /* if it was, then we would have done a "goto skip_cr_array:" instead */ - if (NULL != gv_target) /* gv_target can be NULL in case of DSE MAPS command etc. */ - gv_target->clue.end = 0; + if ((NULL != hist1) && (NULL != (gvnh = hist1->h[0].blk_num ? hist1->h[0].blk_target : NULL))) + gvnh->clue.end = 0; + if ((NULL != hist2) && (NULL != (gvnh = hist2->h[0].blk_num ? hist2->h[0].blk_target : NULL))) + gvnh->clue.end = 0; +# ifdef DEBUG + /* Ensure we dont have t1->cse set for any gv_targets that also have their clue non-zero. + * As this can cause following transactions to rely on out-of-date information and do wrong things. + * (e.g. in t_end of the following transaction, we will see t1->cse non-NULL and conclude the buffer + * needs to be pinned when actually it is not necessary). + */ + for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh) + { + if (gvnh->clue.end) + { + for (t1 = &gvnh->hist.h[0]; t1->blk_num; t1++) + assert(NULL == t1->cse); + } + } +# endif /* t_commit_cleanup releases crit as long as the transition is from 2nd to 3rd retry or 3rd to 3rd retry. The only exception * is if hold_onto_crit is set to TRUE in which case t_commit_cleanup honors it. Assert accordingly. */ - assert(!csa->now_crit || !NEED_TO_RELEASE_CRIT(t_tries) || csa->hold_onto_crit); + assert(!csa->now_crit || !NEED_TO_RELEASE_CRIT(t_tries, status) || csa->hold_onto_crit); DEFERRED_EXIT_HANDLING_CHECK; /* now that all crits are released, check if deferred signal/exit handling needs to be done */ t_retry(status); /* in the retry case, we do not do a CWS_RESET as cw_stagnate is used only in the diff --git a/sr_port/t_end.h b/sr_port/t_end.h index 76b7528..46b9ba6 100644 --- a/sr_port/t_end.h +++ b/sr_port/t_end.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #ifndef T_END_DEFINED #define T_END_DEFINED -#define TN_NOT_SPECIFIED (MAX_TN_V5 + 1) +#define TN_NOT_SPECIFIED (MAX_TN_V6 + 1) trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn); #endif diff --git a/sr_port/t_end_sysops.c b/sr_port/t_end_sysops.c index a639fd6..fb44ef8 100644 --- a/sr_port/t_end_sysops.c +++ b/sr_port/t_end_sysops.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2007, 2012 Fidelity Information Services, Inc * + * Copyright 2007, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -57,6 +57,7 @@ #include "repl_sp.h" /* for F_CLOSE (used by JNL_FD_CLOSE) */ #include "have_crit.h" #include "gt_timer.h" +#include "anticipatory_freeze.h" #if defined(VMS) #include "efn.h" @@ -106,6 +107,7 @@ #endif error_def(ERR_DBFILERR); +error_def(ERR_FREEBLKSLOW); error_def(ERR_GBLOFLOW); UNIX_ONLY(error_def(ERR_TEXT);) error_def(ERR_WCBLOCKED); @@ -123,44 +125,40 @@ error_def(ERR_WCBLOCKED); assert((ctn > csd->desired_db_format_tn) || ((ctn == csd->desired_db_format_tn) && (1 == ctn))); \ cr->ondsk_blkver = csd->desired_db_format; \ } -/* check for online backup - ATTN: this part of code is similar to that in mm_update */ -#define BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, nontp_block_saved, tp_block_saved, ctn)\ -{ \ - boolean_t read_before_image; \ - trans_num bkup_blktn; \ - shmpool_buff_hdr_ptr_t sbufh_p; \ - \ - DEBUG_ONLY(read_before_image = \ - ((JNL_ENABLED(csa) && csa->jnl_before_image) || csa->backup_in_prog || SNAPSHOTS_IN_PROG(csa));) \ - assert(!read_before_image || (NULL == cs->old_block) || (backup_blk_ptr == cs->old_block)); \ - assert(csd == cs_data); /* backup_block uses cs_data hence this check */ \ - if ((blkid >= cnl->nbb) && (NULL != cs->old_block)) \ - { \ - sbufh_p = csa->shmpool_buffer; \ - if (0 == sbufh_p->failed) \ - { \ - bkup_blktn = ((blk_hdr_ptr_t)(backup_blk_ptr))->tn; \ - if ((bkup_blktn < sbufh_p->backup_tn) && (bkup_blktn >= sbufh_p->inc_backup_tn)) \ - { \ - assert(backup_cr->blk == blkid); \ - assert(cs->old_block == backup_blk_ptr); \ - /* to write valid before-image, ensure buffer is protected against preemption */ \ - assert(process_id == backup_cr->in_cw_set); \ - backup_block(csa, blkid, backup_cr, NULL); \ - if (!dollar_tlevel) \ - nontp_block_saved = TRUE; \ - else \ - tp_block_saved = TRUE; \ - } \ - } \ - } \ -} #if defined(UNIX) #define MAX_CYCLES 2 NOPIO_ONLY(GBLREF boolean_t *lseekIoInProgress_flags;) void wcs_stale(TID tid, int4 hd_len, gd_region **region); +#define DO_FAST_INTEG_CHECK(old_block, cs_addrs, cs, lcl_ss_ctx, blkid, write_to_snapshot_file) \ +{ \ + /* For fast integ, do NOT write the data block in global variable tree to snapshot file */ \ + blk_hdr *blk_hdr_ptr; \ + boolean_t is_in_gv_tree; \ + \ + /* level-0 block in DIR tree was already processed */ \ + assert((CSE_LEVEL_DRT_LVL0_FREE != cs->level) || (gds_t_writemap == cs->mode)); \ + assert(blkid < lcl_ss_ctx->total_blks); \ + blk_hdr_ptr = (blk_hdr_ptr_t)old_block; \ + if (WAS_FREE(cs->blk_prior_state)) \ + write_to_snapshot_file = FALSE; \ + else if (WAS_RECYCLED(cs->blk_prior_state)) \ + write_to_snapshot_file = (blk_hdr_ptr->levl > 0); \ + else \ + { \ + is_in_gv_tree = (IN_GV_TREE == (cs->blk_prior_state & KEEP_TREE_STATUS)); \ + write_to_snapshot_file = !((0 == blk_hdr_ptr->levl) && is_in_gv_tree); \ + } \ + /* If we decide not to write this block to snapshot file, then mark it as written in the snapshot file anyways because: \ + * (a) For free and recycled blocks, we prevent writing the before-image later when this block becomes busy \ + * (b) For busy blocks, level-0 block in GV tree may change level after swapping with another block. So, by marking it \ + * in the shadow bitmap, we prevent writing the before-image later. \ + */ \ + if (!write_to_snapshot_file && !ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)) \ + ss_set_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid); \ +} + #elif defined(VMS) GBLREF short astq_dyn_avail; void wcs_stale(gd_region *reg); @@ -206,25 +204,26 @@ void fileheader_sync(gd_region *reg) # if defined(UNIX) size_t flush_len, sync_size, rounded_flush_len; int4 save_errno; - unix_db_info *gds_info; + unix_db_info *udi; # elif defined(VMS) file_control *fc; int4 flush_len; - vms_gds_info *gds_info; + vms_gds_info *udi; # endif - gds_info = FILE_INFO(reg); - csa = &gds_info->s_addrs; + udi = FILE_INFO(reg); + csa = &udi->s_addrs; csd = csa->hdr; assert(csa->now_crit); /* only way high water mark code works is if in crit */ /* Adding lock code to it would remove this restriction */ + assert(!reg->read_only); assert(0 == memcmp(csd->label, GDS_LABEL, GDS_LABEL_SZ - 1)); cnl = csa->nl; gvstats_rec_cnl2csd(csa); /* Periodically transfer statistics from database shared-memory to file-header */ high_blk = cnl->highest_lbm_blk_changed; cnl->highest_lbm_blk_changed = -1; /* Reset to initial value */ flush_len = SGMNT_HDR_LEN; - if (0 <= high_blk) /* If not negative, flush at least one map block */ + if (0 <= high_blk) /* If not negative, flush at least one master map block */ flush_len += ((high_blk / csd->bplmap / DISK_BLOCK_SIZE / BITS_PER_UCHAR) + 1) * DISK_BLOCK_SIZE; if (csa->do_fullblockwrites) { /* round flush_len up to full block length. This is safe since we know that @@ -242,48 +241,14 @@ void fileheader_sync(gd_region *reg) fc->op_pos = 1; dbfilop(fc); # elif defined(UNIX) - if (dba_mm != csd->acc_meth) + DB_LSEEKWRITE(csa, udi->fn, udi->fd, 0, (sm_uc_ptr_t)csd, flush_len, save_errno); + if (0 != save_errno) { - LSEEKWRITE(gds_info->fd, 0, (sm_uc_ptr_t)csd, flush_len, save_errno); - if (0 != save_errno) - { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno); - } - return; - } else - { - UNTARGETED_MSYNC_ONLY( - cti = csa->ti; - if (cti->last_mm_sync != cti->curr_tn) - { - sync_size = (size_t)ROUND_UP((size_t)csa->db_addrs[0] + flush_len, MSYNC_ADDR_INCS) - - (size_t)csa->db_addrs[0]; - if (-1 == msync((caddr_t)csa->db_addrs[0], sync_size, MS_ASYNC)) - { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, - RTS_ERROR_TEXT("Error during file msync for fileheader"), errno); - } - cti->last_mm_sync = cti->curr_tn; /* save when did last full sync */ - } - ) - TARGETED_MSYNC_ONLY( - if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)ROUND_UP(flush_len, MSYNC_ADDR_INCS), MS_ASYNC)) - { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync for fileheader"), errno); - } - ) - REGULAR_MSYNC_ONLY( - LSEEKWRITE(gds_info->fd, 0, csa->db_addrs[0], flush_len, save_errno); - if (0 != save_errno) - { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno); - } - ) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno); } # endif + return; } /* update a bitmap */ @@ -332,6 +297,10 @@ void bm_update(cw_set_element *cs, sm_uc_ptr_t lclmap, boolean_t is_mm) { bit_clear(blkid / bplmap, MM_ADDR(csd)); change_bmm = TRUE; + if ((0 == csd->extension_size) /* no extension and less than a bit map or less than 1/32 (3.125%) */ + && ((BLKS_PER_LMAP > cti->free_blocks) || ((cti->total_blks >> 5) > cti->free_blocks))) + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_FREEBLKSLOW, 4, cti->free_blocks, cti->total_blks, + DB_LEN_STR(gv_cur_region)); } } else if (0 > reference_cnt) { /* blocks were freed up in this bitmap. check if local bitmap became non-full as a result. if so update mastermap */ @@ -389,166 +358,23 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn, cw_set_element *cs_ptr, *nxt; off_chain chain; sm_uc_ptr_t chain_ptr, db_addr[2]; - GTM_SNAPSHOT_ONLY( - snapshot_context_ptr_t lcl_ss_ctx; - ) +# ifdef GTM_SNAPSHOT + boolean_t write_to_snapshot_file; + snapshot_context_ptr_t lcl_ss_ctx; +# endif # if defined(VMS) unsigned int status; io_status_block_disk iosb; # endif -# if defined(UNIX) -# if !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC) - /* The earlier_dirty and mmblkr arrays should be declared as - * boolean_t earlier_dirty[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, MSYNC_ADDR_INCS) + 1] - * but MSYNC_ADDR_INCS is based on OS_PAGE_SIZE which reduces to a function call and therefore can't be - * used for an array declaration. The alternative is to use a value that is larger than what will be needed. - * Since DISK_BLOCK_SIZE will always be smaller than OS_PAGE_SIZE and the array isn't very large anyway, use - * DISK_BLOCK_SIZE instead. This assumption is checked with an assert. - */ - boolean_t earlier_dirty[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1]; - mmblk_rec_ptr_t mmblkr[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1]; - uint4 indx; - int4 lcnt, ocnt, n, blk, blk_first_piece, blk_last_piece; - uint4 max_ent; -# if defined(TARGETED_MSYNC) - sm_uc_ptr_t desired_first, desired_last; -# else - unix_db_info *udi; - int4 save_errno; -# endif -# endif -# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(cs_addrs->now_crit); assert((gds_t_committed > cs->mode) && (gds_t_noop < cs->mode)); INCR_DB_CSH_COUNTER(cs_addrs, n_bgmm_updates, 1); blkid = cs->blk; assert((0 <= blkid) && (blkid < cs_addrs->ti->total_blks)); - db_addr[0] = cs_addrs->acc_meth.mm.base_addr + (sm_off_t)cs_data->blk_size * (blkid); - -# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC) - if (0 < cs_data->defer_time) - { - TARGETED_MSYNC_ONLY( - desired_first = db_addr[0]; - desired_last = desired_first + (sm_off_t)(cs_data->blk_size) - 1; - blk_first_piece = DIVIDE_ROUND_DOWN(desired_first - cs_addrs->db_addrs[0], MSYNC_ADDR_INCS); - blk_last_piece = DIVIDE_ROUND_DOWN(desired_last - cs_addrs->db_addrs[0], MSYNC_ADDR_INCS); - ) - REGULAR_MSYNC_ONLY( - blk_first_piece = blkid; - blk_last_piece = blkid; - ) - assert(DISK_BLOCK_SIZE <= MSYNC_ADDR_INCS); - assert((DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1) >= (blk_last_piece - blk_first_piece)); - for (blk = blk_first_piece, indx = 0; blk <= blk_last_piece; blk++, indx++) - { - mmblkr[indx] = (mmblk_rec_ptr_t)db_csh_get(blk); - earlier_dirty[indx] = FALSE; - - if (NULL == mmblkr[indx]) - { - mmblk_rec_ptr_t hdr, cur_mmblkr, start_mmblkr, q0; - - max_ent = cs_addrs->hdr->n_bts; - cur_mmblkr = (mmblk_rec_ptr_t)GDS_REL2ABS(cs_addrs->nl->cur_lru_cache_rec_off); - hdr = cs_addrs->acc_meth.mm.mmblk_state->mmblk_array + (blk % cs_addrs->hdr->bt_buckets); - start_mmblkr = cs_addrs->acc_meth.mm.mmblk_state->mmblk_array + cs_addrs->hdr->bt_buckets; - - for (lcnt = 0; lcnt <= (MAX_CYCLES * max_ent); ) - { - cur_mmblkr++; - assert(cur_mmblkr <= (start_mmblkr + max_ent)); - if (cur_mmblkr >= start_mmblkr + max_ent) - cur_mmblkr = start_mmblkr; - if (cur_mmblkr->refer) - { - lcnt++; - cur_mmblkr->refer = FALSE; - continue; - } - if ((blk_first_piece <= cur_mmblkr->blk) && (blk_last_piece >= cur_mmblkr->blk)) - { /* If we've already claimed and locked this cache record for another OS block - * in the current DB block; or we'll be finding it soon, we need to keep looking. - */ - lcnt++; - continue; - } - if (0 != cur_mmblkr->dirty) - wcs_get_space(gv_cur_region, 0, (cache_rec_ptr_t)cur_mmblkr); - cur_mmblkr->blk = blk; - q0 = (mmblk_rec_ptr_t)((sm_uc_ptr_t)cur_mmblkr + cur_mmblkr->blkque.fl); - shuffqth((que_ent_ptr_t)q0, (que_ent_ptr_t)hdr); - cs_addrs->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cur_mmblkr); - - earlier_dirty[indx] = FALSE; - mmblkr[indx] = cur_mmblkr; - /* Here we cannot call LOCK_NEW_BUFF_FOR_UPDATE directly, because in wcs_wtstart - * csr->dirty is reset before it releases the LOCK in the buffer. - * To avoid this very small window followings are needed. - */ - for (ocnt = 1; ; ocnt++) - { - LOCK_BUFF_FOR_UPDATE(mmblkr[indx], n, &cs_addrs->nl->db_latch); - if (!OWN_BUFF(n)) - { - if (BUF_OWNER_STUCK < ocnt) - { - assert(FALSE); - if (0 == mmblkr[indx]->dirty) - { - LOCK_NEW_BUFF_FOR_UPDATE(mmblkr[indx]); - break; - } else - return cdb_sc_comfail; - } - if (WRITER_STILL_OWNS_BUFF(mmblkr[indx], n)) - wcs_sleep(ocnt); - } else - { - break; - } - } - break; - } - assert(lcnt <= (MAX_CYCLES * max_ent)); - } else if ((mmblk_rec_ptr_t)CR_NOTVALID == mmblkr[indx]) - { /* ------------- yet to write recovery mechanisms if hashtable is corrupt ------*/ - /* ADD CODE LATER */ - GTMASSERT; - } else - { /* See comment (few lines above) about why LOCK_NEW_BUFF_FOR_UPDATE cannot be called here */ - for (ocnt = 1; ; ocnt++) - { - LOCK_BUFF_FOR_UPDATE(mmblkr[indx], n, &cs_addrs->nl->db_latch); - if (!OWN_BUFF(n)) - { - if (BUF_OWNER_STUCK < ocnt) - { - assert(FALSE); - if (0 == mmblkr[indx]->dirty) - { - LOCK_NEW_BUFF_FOR_UPDATE(mmblkr[indx]); - break; - } else - return cdb_sc_comfail; - } - if (WRITER_STILL_OWNS_BUFF(mmblkr[indx], n)) - wcs_sleep(ocnt); - } else - { - break; - } - } - - if (0 != mmblkr[indx]->dirty) - earlier_dirty[indx] = TRUE; - else - earlier_dirty[indx] = FALSE; - } - } - } -# endif + db_addr[0] = MM_BASE_ADDR(cs_addrs) + (sm_off_t)cs_data->blk_size * (blkid); /* check for online backup -- ATTN: this part of code is similar to the BG_BACKUP_BLOCK macro */ if ((blkid >= cs_addrs->nl->nbb) && (NULL != cs->old_block) && (0 == cs_addrs->shmpool_buffer->failed) @@ -562,16 +388,25 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn, si->backup_block_saved = TRUE; } # ifdef GTM_SNAPSHOT - lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx); if (SNAPSHOTS_IN_PROG(cs_addrs) && (NULL != cs->old_block)) - WRITE_SNAPSHOT_BLOCK(cs_addrs, NULL, db_addr[0], blkid, lcl_ss_ctx); - /* If snapshots are in progress then the current block better be before imaged in the snapshot file. The - * only exception is when the current database transaction number is greater than the snapshot transaction - * number in which case the block's before image is not expected to be written to the snapshot file - */ - assert(!SNAPSHOTS_IN_PROG(cs_addrs) - || (cs_data->trans_hist.curr_tn > lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn) - || (ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid))); + { + lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx); + assert(lcl_ss_ctx); + if (blkid < lcl_ss_ctx->total_blks) + { + if (FASTINTEG_IN_PROG(lcl_ss_ctx)) + { + DO_FAST_INTEG_CHECK(db_addr[0], cs_addrs, cs, lcl_ss_ctx, blkid, write_to_snapshot_file); + } else + write_to_snapshot_file = TRUE; + if (write_to_snapshot_file) + WRITE_SNAPSHOT_BLOCK(cs_addrs, NULL, db_addr[0], blkid, lcl_ss_ctx); + assert(!FASTINTEG_IN_PROG(lcl_ss_ctx) || !write_to_snapshot_file + || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)); + assert(FASTINTEG_IN_PROG(lcl_ss_ctx) || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid) + || ((blk_hdr_ptr_t)(db_addr[0]))->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn); + } + } # endif if (gds_t_writemap == cs->mode) { @@ -662,73 +497,8 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn, if (SS$_NOTMODIFIED != status) /* don't expect notmodified, but no harm to go on */ return cdb_sc_comfail; } -# elif defined(UNTARGETED_MSYNC) - if (cs_addrs->ti->last_mm_sync != cs_addrs->ti->curr_tn) - { /* msync previous transaction as part of updating first block in the current transaction */ - if (-1 == msync((caddr_t)cs_addrs->db_addrs[0], - (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0]), MS_SYNC)) - { - assert(FALSE); - return cdb_sc_comfail; - } - cs_addrs->ti->last_mm_sync = cs_addrs->ti->curr_tn; /* Save when did last full sync */ - } -# elif defined(TARGETED_MSYNC) - caddr_t start; - - start = (caddr_t)ROUND_DOWN2((sm_off_t)db_addr[0], MSYNC_ADDR_INCS); - if (-1 == msync(start, - (size_t)ROUND_UP((sm_off_t)((caddr_t)db_addr[0] - start) + cs_data->blk_size, MSYNC_ADDR_INCS), MS_SYNC)) - { - assert(FALSE); - return cdb_sc_comfail; - } -# elif !defined(NO_MSYNC) - udi = FILE_INFO(gv_cur_region); - LSEEKWRITE(udi->fd, (db_addr[0] - (sm_uc_ptr_t)cs_data), db_addr[0], cs_data->blk_size, save_errno); - if (0 != save_errno) - { - gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during MM Block Write"), save_errno); - assert(FALSE); - return cdb_sc_comfail; - } # endif } -# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC) - if (0 < cs_data->defer_time) - { - int4 n; - - for (blk = blk_first_piece, indx = 0; blk <= blk_last_piece; blk++, indx++) - { - mmblkr[indx]->dirty = cs_addrs->ti->curr_tn; - mmblkr[indx]->refer = TRUE; - - if (FALSE == earlier_dirty[indx]) - { - ADD_ENT_TO_ACTIVE_QUE_CNT(&cs_addrs->nl->wcs_active_lvl, &cs_addrs->nl->wc_var_lock); - DECR_CNT(&cs_addrs->nl->wc_in_free, &cs_addrs->nl->wc_var_lock); - if (INTERLOCK_FAIL == INSQTI((que_ent_ptr_t)&mmblkr[indx]->state_que, - (que_head_ptr_t)&cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active)) - { - assert(FALSE); - return cdb_sc_comfail; - } - } - RELEASE_BUFF_UPDATE_LOCK(mmblkr[indx], n, &cs_addrs->nl->db_latch); - if (WRITER_BLOCKED_BY_PROC(n)) - { /* it's off the active queue, so put it back at the head */ - if (INTERLOCK_FAIL == INSQHI((que_ent_ptr_t)&mmblkr[indx]->state_que, - (que_head_ptr_t)&cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active)) - { - assert(FALSE); - return cdb_sc_comfail; - } - } - } - } -# endif return cdb_sc_normal; } @@ -766,6 +536,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) sm_off_t backup_cr_off; uint4 in_cw_set; # endif + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; csa = cs_addrs; /* Local access copies */ csd = csa->hdr; @@ -780,7 +553,10 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) assertpro((0 <= blkid) && (blkid < csa->ti->total_blks)); INCR_DB_CSH_COUNTER(csa, n_bgmm_updates, 1); bt = bt_put(gv_cur_region, blkid); +#ifdef UNIX GTM_WHITE_BOX_TEST(WBTEST_BG_UPDATE_BTPUTNULL, bt, NULL); + GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_DBDANGER, bt, NULL); +#endif if (NULL == bt) { assert(gtm_white_box_test_case_enabled); @@ -820,7 +596,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) } ) BG_TRACE_PRO(wcb_t_end_sysops_nocr_invcr); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_nocr_invcr"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_nocr_invcr"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } @@ -831,7 +607,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_cr_invcr); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_cr_invcr"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_cr_invcr"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } else if (-1 != cr->read_in_progress) @@ -845,7 +621,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) if (!read_finished) { BG_TRACE_PRO(wcb_t_end_sysops_rip_wait); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_rip_wait"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_rip_wait"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } @@ -868,26 +644,27 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) assert(LATCH_CLEAR == WRITE_LATCH_VAL(cr)); LOCK_NEW_BUFF_FOR_UPDATE(cr); /* not on the active queue and this process is crit */ ) - UNIX_ONLY( - /* Since the only case where the write interlock is not clear in Unix is a two-instruction window - * (described in the above comment), we dont expect the lock-not-clear situation to be frequent. - * Hence, for performance reasons we do the check before invoking the wcs_write_in_progress_wait function - * (instead of moving the if check into the function which would mean an unconditional function call). - */ - if (LATCH_CLEAR != WRITE_LATCH_VAL(cr)) +# ifdef UNIX + /* Since the only case where the write interlock is not clear in Unix is a two-instruction window + * (described in the above comment), we dont expect the lock-not-clear situation to be frequent. + * Hence, for performance reasons we do the check before invoking the wcs_write_in_progress_wait function + * (instead of moving the if check into the function which would mean an unconditional function call). + */ + if (LATCH_CLEAR != WRITE_LATCH_VAL(cr)) + { + write_finished = wcs_write_in_progress_wait(cnl, cr, WBTEST_BG_UPDATE_DIRTYSTUCK1); + if (!write_finished) { - write_finished = wcs_write_in_progress_wait(cnl, cr, WBTEST_BG_UPDATE_DIRTYSTUCK1); - if (!write_finished) - { - assert(gtm_white_box_test_case_enabled); - BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck1); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck1"), - process_id, &ctn, DB_LEN_STR(gv_cur_region)); - return cdb_sc_cacheprob; - } - } else - LOCK_NEW_BUFF_FOR_UPDATE(cr); /* writer has released interlock and this process is crit */ - ) + assert(gtm_white_box_test_case_enabled); + BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck1); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, + 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck1"), process_id, &ctn, + DB_LEN_STR(gv_cur_region)); + return cdb_sc_cacheprob; + } + } else + LOCK_NEW_BUFF_FOR_UPDATE(cr); /* writer has released interlock and this process is crit */ +# endif assert(LATCH_SET <= WRITE_LATCH_VAL(cr)); BG_TRACE(new_buff); cr->bt_index = GDS_ABS2REL(bt); @@ -913,8 +690,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_intend_wait); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_intend_wait"), - process_id, &ctn, DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, + 6, LEN_AND_LIT("wcb_t_end_sysops_intend_wait"), + process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } } @@ -935,8 +713,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck2); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck2"), - process_id, &ctn, DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, + 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck2"), + process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } } @@ -984,8 +763,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) } ) BG_TRACE_PRO(wcb_t_end_sysops_dirty_invcr); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirty_invcr"), - process_id, &ctn, DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, + 6, LEN_AND_LIT("wcb_t_end_sysops_dirty_invcr"), + process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } assert(NULL != cr1); @@ -1020,7 +800,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_wtfini_fail); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_wtfini_fail"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; @@ -1046,7 +826,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { status = sys$dclast(wcs_wtstart, gv_cur_region, 0); if (SS$_NORMAL != status) - send_msg(VARLSTCNT(6) ERR_DBFILERR, 2, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), 0, status); wcs_sleep(lcnt); } @@ -1058,7 +838,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_twin_stuck); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_twin_stuck"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; @@ -1145,7 +925,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_t_end_sysops_dirtyripwait); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirtyripwait"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; @@ -1193,8 +973,8 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) assert((gds_t_acquired != mode) || (NULL != cs->old_block) || (GDSVCURR == cs->ondsk_blkver)); desired_db_format = csd->desired_db_format; /* assert that appropriate inctn journal records were written at the beginning of the commit in t_end */ - assert((inctn_blkupgrd_fmtchng != inctn_opcode) || (GDSV4 == cr->ondsk_blkver) && (GDSV5 == desired_db_format)); - assert((inctn_blkdwngrd_fmtchng != inctn_opcode) || (GDSV5 == cr->ondsk_blkver) && (GDSV4 == desired_db_format)); + assert((inctn_blkupgrd_fmtchng != inctn_opcode) || (GDSV4 == cr->ondsk_blkver) && (GDSV6 == desired_db_format)); + assert((inctn_blkdwngrd_fmtchng != inctn_opcode) || (GDSV6 == cr->ondsk_blkver) && (GDSV4 == desired_db_format)); assert(!(JNL_ENABLED(csa) && csa->jnl_before_image) || !mu_reorg_nosafejnl || (inctn_blkupgrd != inctn_opcode) || (cr->ondsk_blkver == desired_db_format)); assert(!mu_reorg_upgrd_dwngrd_in_prog || (gds_t_acquired != mode)); @@ -1212,7 +992,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) { /* Some sort of state change in the block format is occuring */ switch(desired_db_format) { - case GDSV5: + case GDSV6: /* V4 -> V5 transition */ if (gds_t_write_recycled != mode) DECR_BLKS_TO_UPGRD(csa, csd, 1); @@ -1223,7 +1003,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) INCR_BLKS_TO_UPGRD(csa, csd, 1); break; default: - GTMASSERT; + assertpro(FALSE); } } assert((gds_t_writemap != mode) || dse_running /* generic dse_running variable is used for caller = dse_maps */ @@ -1274,7 +1054,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si) backup_blk_ptr = (sm_uc_ptr_t)GDS_REL2ABS(backup_cr->buffaddr); assert(gds_t_write_root != mode); } - BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, block_saved, si->backup_block_saved, ctn); + BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, block_saved, si->backup_block_saved); /* Update cr->ondsk_blkver to reflect the current desired_db_format. */ SET_ONDSK_BLKVER(cr, csd, ctn); # endif @@ -1316,14 +1096,17 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect node_local_ptr_t cnl; enum gds_t_mode mode; cache_que_heads_ptr_t cache_state; +#ifdef GTM_SNAPSHOT + boolean_t write_to_snapshot_file; + snapshot_context_ptr_t lcl_ss_ctx; +#endif # if defined(VMS) gv_namehead *targ; srch_blk_status *blk_hist; # endif - GTM_SNAPSHOT_ONLY( - snapshot_context_ptr_t lcl_ss_ctx = NULL; - ) + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; mode = cs->mode; cr = cs->cr; /* Make sure asserts that were valid before letting go of this cache-record in phase1 are still so */ @@ -1370,22 +1153,31 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect */ backup_cr = cr; backup_blk_ptr = blk_ptr; - if (!cs->was_free) /* dont do before image write for backup for FREE blocks */ - BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, block_saved, si->backup_block_saved, ctn); + if (!WAS_FREE(cs->blk_prior_state)) /* dont do before image write for backup for FREE blocks */ + BG_BACKUP_BLOCK(csa, csd, cnl, cr, cs, blkid, backup_cr, backup_blk_ptr, block_saved, si->backup_block_saved); # endif /* Update cr->ondsk_blkver to reflect the current desired_db_format. */ SET_ONDSK_BLKVER(cr, csd, ctn); # ifdef GTM_SNAPSHOT - lcl_ss_ctx = SS_CTX_CAST(csa->ss_ctx); - if (SNAPSHOTS_IN_PROG(csa) && (NULL != cs->old_block)) - WRITE_SNAPSHOT_BLOCK(csa, cr, NULL, blkid, lcl_ss_ctx); - /* If snapshots are in progress then the current block better be before imaged in the snapshot file. The - * only exception is when the current database transaction number is greater than the snapshot transaction - * number in which case the block's before image is not expected to be written to the snapshot file - */ - assert(!SNAPSHOTS_IN_PROG(csa) - || (csd->trans_hist.curr_tn > lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn) - || (ss_chk_shdw_bitmap(csa, SS_CTX_CAST(csa->ss_ctx), cs->blk))); + if (SNAPSHOTS_IN_PROG(cs_addrs) && (NULL != cs->old_block)) + { + lcl_ss_ctx = SS_CTX_CAST(csa->ss_ctx); + assert(lcl_ss_ctx); + if (blkid < lcl_ss_ctx->total_blks) + { + if (FASTINTEG_IN_PROG(lcl_ss_ctx)) + { + DO_FAST_INTEG_CHECK(blk_ptr, csa, cs, lcl_ss_ctx, blkid, write_to_snapshot_file); + } else + write_to_snapshot_file = TRUE; + if (write_to_snapshot_file) + WRITE_SNAPSHOT_BLOCK(csa, cr, NULL, blkid, lcl_ss_ctx); + assert(!FASTINTEG_IN_PROG(lcl_ss_ctx) || !write_to_snapshot_file + || ss_chk_shdw_bitmap(csa, lcl_ss_ctx, blkid)); + assert(FASTINTEG_IN_PROG(lcl_ss_ctx) || ss_chk_shdw_bitmap(csa, lcl_ss_ctx, blkid) + || ((blk_hdr_ptr_t)(blk_ptr))->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn); + } + } # endif SET_DATA_INVALID(cr); /* data_invalid should be set signaling intent to update contents of a valid block */ if (gds_t_writemap == mode) @@ -1496,7 +1288,7 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_bg_update_lckfail1); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail1"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail1"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } @@ -1530,11 +1322,24 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect { assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO(wcb_bg_update_lckfail2); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail2"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail2"), process_id, &ctn, DB_LEN_STR(gv_cur_region)); return cdb_sc_cacheprob; } } +# ifdef VMS + if (cr->backup_cr_off && (gds_t_write == mode)) /* update landed in a different cache-record (twin) */ + { /* If valid clue and this block is in it, need to update buffer address */ + targ = (!dollar_tlevel ? gv_target : cs->blk_target); + if ((NULL != targ) && (0 != targ->clue.end)) + { + blk_hist = &targ->hist.h[cs->level]; + blk_hist->buffaddr = blk_ptr; + blk_hist->cr = cr; + blk_hist->cycle = cr->cycle; /* must do this before unpinning the cache-record */ + } + } +# endif /* A concurrent process reading this block will wait for in_tend to become FALSE and then proceed with its * database operation. Later it will reach t_end/tp_tend doing validations at which point it will need to set in_cw_set. * It expects in_cw_set to be 0 at that point. Therefore in_cw_set needs to be reset to 0 BEFORE resetting in_tend. @@ -1546,19 +1351,6 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect SHM_WRITE_MEMORY_BARRIER; assert(process_id == cr->in_tend); /* should still be valid */ cr->in_tend = 0; - VMS_ONLY( - if (cr->backup_cr_off && (gds_t_write == mode)) /* update landed in a different cache-record (twin) */ - { /* If valid clue and this block is in it, need to update buffer address */ - targ = (!dollar_tlevel ? gv_target : cs->blk_target); - if ((NULL != targ) && (0 != targ->clue.end)) - { - blk_hist = &targ->hist.h[cs->level]; - blk_hist->buffaddr = blk_ptr; - blk_hist->cr = cr; - blk_hist->cycle = cr->cycle; - } - } - ) VERIFY_QUEUE_LOCK(&cache_state->cacheq_active, &cnl->db_latch); cs->old_mode = -cs->old_mode; /* negate it back to indicate phase2 is complete for this cse (used by secshr_db_clnup) */ assert(0 < cs->old_mode); @@ -1749,43 +1541,23 @@ void wcs_stale(gd_region *reg) BG_TRACE_PRO_ANY(csa, stale); switch (acc_meth) { - case dba_bg: - /* Flush at least some of our cache */ - UNIX_ONLY(wcs_wtstart(reg, 0);) - VMS_ONLY(wcs_wtstart(reg);) - /* If there is no dirty buffer left in the active queue, then no need for new timer */ - if (0 == csa->acc_meth.bg.cache_state->cacheq_active.fl) - need_new_timer = FALSE; - break; - -# if defined(UNIX) - case dba_mm: -# if defined(UNTARGETED_MSYNC) - if (csa->ti->last_mm_sync != csa->ti->curr_tn) - { - boolean_t was_crit; - - was_crit = csa->now_crit; - if (FALSE == was_crit) - grab_crit(reg); - msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), - MS_SYNC); - csa->ti->last_mm_sync = csa->ti->curr_tn; /* Save when did last full sync */ - if (FALSE == was_crit) - rel_crit(reg); - need_new_timer = FALSE; /* All sync'd up -- don't need another one */ - } -# else - /* note that wcs_wtstart is called for TARGETED_MSYNC or FILE_IO */ - wcs_wtstart(reg, 0); - assert(csd == csa->hdr); - if (0 == csa->acc_meth.mm.mmblk_state->mmblkq_active.fl) + case dba_bg: + /* Flush at least some of our cache */ + UNIX_ONLY(wcs_wtstart(reg, 0);) + VMS_ONLY(wcs_wtstart(reg);) + /* If there is no dirty buffer left in the active queue, then no need for new timer */ + if (0 == csa->acc_meth.bg.cache_state->cacheq_active.fl) + need_new_timer = FALSE; + break; +# if defined(UNIX) + case dba_mm: + wcs_wtstart(reg, 0); + assert(csd == csa->hdr); need_new_timer = FALSE; + break; # endif - break; -# endif - default: - break; + default: + break; } } else { diff --git a/sr_port/t_qread.c b/sr_port/t_qread.c index c187524..1678027 100644 --- a/sr_port/t_qread.c +++ b/sr_port/t_qread.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,16 +47,15 @@ #include "add_inter.h" #include "wbox_test_init.h" #include "memcoherency.h" - +#include "wcs_flu.h" /* for SET_CACHE_FAIL_STATUS macro */ #ifdef UNIX +# ifdef GTM_CRYPT +# include "gtmcrypt.h" +# endif #include "io.h" /* needed by gtmsecshr.h */ #include "gtmsecshr.h" /* for continue_proc */ #endif #include "wcs_phase2_commit_wait.h" - -#ifdef GTM_CRYPT -#include "gtmcrypt.h" -#endif #include "gtm_c_stack_trace.h" GBLDEF srch_blk_status *first_tp_srch_status; /* the first srch_blk_status for this block in this transaction */ @@ -96,7 +95,15 @@ GBLREF boolean_t mupip_jnl_recover; (first_tp_srch_status)->cycle = (newcycle); \ (first_tp_srch_status)->buffaddr = (sm_uc_ptr_t)GDS_REL2ABS((newcr)->buffaddr); +#define REL_CRIT_IF_NEEDED(CSA, REG, WAS_CRIT, HOLD_ONTO_CRIT) \ +{ /* If currently have crit, but didn't have it upon entering, release crit now. */ \ + assert(!WAS_CRIT || CSA->now_crit); \ + if ((WAS_CRIT != CSA->now_crit) && !HOLD_ONTO_CRIT) \ + rel_crit(REG); \ +} + error_def(ERR_BUFOWNERSTUCK); +error_def(ERR_CRYPTBADCONFIG); error_def(ERR_DBFILERR); error_def(ERR_DYNUPGRDFAIL); error_def(ERR_GVPUTFAIL); @@ -115,7 +122,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out register sgmnt_addrs *csa; register sgmnt_data_ptr_t csd; enum db_ver ondsk_blkver; - int4 dummy_errno; + int4 dummy_errno, gtmcrypt_errno; boolean_t already_built, is_mm, reset_first_tp_srch_status, set_wc_blocked, sleep_invoked; ht_ent_int4 *tabent; srch_blk_status *blkhist; @@ -123,7 +130,13 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out sm_uc_ptr_t buffaddr; uint4 stuck_cnt = 0; boolean_t lcl_blk_free; + node_local_ptr_t cnl; +# ifdef GTM_CRYPT + gd_segment *seg; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; lcl_blk_free = block_is_free; block_is_free = FALSE; /* Reset to FALSE so that if t_qread fails below, we don't have an incorrect state of this var */ first_tp_srch_status = NULL; @@ -269,11 +282,13 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out } } } - if ((blk >= csa->ti->total_blks) || (blk < 0)) - { /* requested block out of range; could occur because of a concurrency conflict */ - if ((&FILE_INFO(gv_cur_region)->s_addrs != csa) || (csd != cs_data)) - GTMASSERT; - assert(FALSE == csa->now_crit); + if ((uint4)blk >= (uint4)csa->ti->total_blks) + { /* Requested block out of range; could occur because of a concurrency conflict. mm_read and dsk_read assume blk is + * never negative or greater than the maximum possible file size. If a concurrent REORG truncates the file, t_qread + * can proceed despite blk being greater than total_blks. But dsk_read handles this fine; see comments below. + */ + assert((&FILE_INFO(gv_cur_region)->s_addrs == csa) && (csd == cs_data)); + assert(!csa->now_crit); rdfail_detail = cdb_sc_blknumerr; return (sm_uc_ptr_t)NULL; } @@ -284,14 +299,17 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out return (sm_uc_ptr_t)(mm_read(blk)); } # ifdef GTM_CRYPT - /* If database is encrypted, check if encryption initialization went fine for this database. If not, - * do not let process proceed as it could now potentially get a peek at the desired data from the - * decrypted shared memory global buffers (read in from disk by other processes) without having to go to disk. - * If DSE, allow for a special case where it is trying to dump a local bitmap block. In this case, DSE - * can continue to run fine (even if encryption initialization failed) since bitmap blocks are unencrypted. - */ - if (csa->encrypt_init_status && (!dse_running || !IS_BITMAP_BLK(blk))) - GC_RTS_ERROR(csa->encrypt_init_status, gv_cur_region->dyn.addr->fname); + if ((GTMCRYPT_INVALID_KEY_HANDLE == csa->encr_key_handle) && !IS_BITMAP_BLK(blk)) + { /* A non-GT.M process is attempting to read a non-bitmap block but doesn't have a valid encryption key handle. This + * is an indication that the process encountered an error during db_init and reported it with a -W- severity. But, + * since the block it is attempting to read can be in the unencrypted shared memory, we cannot let it access it + * without a valid handle. So, issue an rts_error + */ + assert(!IS_GTM_IMAGE); /* GT.M would have error'ed out in db_init */ + gtmcrypt_errno = SET_REPEAT_MSG_MASK(SET_CRYPTERR_MASK(ERR_CRYPTBADCONFIG)); + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); + } # endif assert(dba_bg == csd->acc_meth); assert(!first_tp_srch_status || !first_tp_srch_status->cr @@ -300,7 +318,8 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out bt = NULL; was_crit = csa->now_crit; ocnt = 0; - set_wc_blocked = FALSE; /* to indicate whether csd->wc_blocked was set to TRUE by us */ + cnl = csa->nl; + set_wc_blocked = FALSE; /* to indicate whether cnl->wc_blocked was set to TRUE by us */ hold_onto_crit = csa->hold_onto_crit; /* note down in local to avoid csa-> dereference in multiple usages below */ do { @@ -316,7 +335,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out assert(clustered); wait_for_block_flush(bt, blk); /* try for no other node currently writing the block */ } - if (csd->flush_trigger <= csa->nl->wcs_active_lvl && FALSE == gv_cur_region->read_only) + if ((csd->flush_trigger <= cnl->wcs_active_lvl) && (FALSE == gv_cur_region->read_only)) JNL_ENSURE_OPEN_WCS_WTSTART(csa, gv_cur_region, 0, dummy_errno); /* a macro that dclast's "wcs_wtstart" and checks for errors etc. */ grab_crit(gv_cur_region); @@ -333,9 +352,9 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out cr = db_csh_getn(blk); if (CR_NOTVALID == (sm_long_t)cr) { - assert(csd->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ + assert(cnl->wc_blocked); /* only reason we currently know wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); - SET_TRACEABLE_VAR(cs_data->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_qread_db_csh_getn_invalid_blk); set_wc_blocked = TRUE; break; @@ -355,7 +374,8 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out assert(0 == cr->dirty); assert(cr->read_in_progress >= 0); CR_BUFFER_CHECK(gv_cur_region, csa, csd, cr); - if (SS_NORMAL != (status = dsk_read(blk, GDS_REL2ABS(cr->buffaddr), &ondsk_blkver, lcl_blk_free))) + buffaddr = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); + if (SS_NORMAL != (status = dsk_read(blk, buffaddr, &ondsk_blkver, lcl_blk_free))) { /* buffer does not contain valid data, so reset blk to be empty */ cr->cycle++; /* increment cycle for blk number changes (for tp_hist and others) */ cr->blk = CR_BLKEMPTY; @@ -378,21 +398,45 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out if (was_crit) { assert(FALSE); - rts_error(VARLSTCNT(5) status, 3, blk, DB_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) status, 3, blk, + DB_LEN_STR(gv_cur_region)); } else { rdfail_detail = cdb_sc_lostcr; return (sm_uc_ptr_t)NULL; } } - if (-1 == status) - { - /* could have been concurrent truncate, and we read a blk >= csa->ti->total_blks */ - /* restart */ + if ((-1 == status) && !was_crit) + { /* LSEEKREAD and, consequently, dsk_read return -1 in case pread is unable to fetch + * a full database block's length of data. This can happen if the requested read is + * past the end of the file, which can happen if a concurrent truncate occurred + * after the blk >= csa->ti->total_blks comparison above. Allow for this scenario + * by restarting. However, if we've had crit the whole time, no truncate could have + * happened. -1 indicates a problem with the file, so fall through to DBFILERR. + */ rdfail_detail = cdb_sc_truncate; return (sm_uc_ptr_t)NULL; - } else - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); + } +# ifdef GTM_CRYPT + else if (IS_CRYPTERR_MASK(status)) + { + seg = gv_cur_region->dyn.addr; + GTMCRYPT_REPORT_ERROR(status, rts_error, seg->fname_len, seg->fname); + } +# endif + else + { /* A DBFILERR can be thrown for two possible reasons: + * (1) LSEEKREAD returned an unexpected error due to a filesystem problem; or + * (2) csa/cs_addrs/csd/cs_data are out of sync, and we're trying to read a block + * number for one region from another region with fewer total_blks. + * We suspect the former is what happened in GTM-7623. Apparently the latter + * has been an issue before, too. If either occurs again in pro, this assertpro + * distinguishes the two possibilities. + */ + assertpro((&FILE_INFO(gv_cur_region)->s_addrs == csa) && (csd == cs_data)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), + status); + } } disk_blk_read = TRUE; assert(0 <= cr->read_in_progress); @@ -408,18 +452,18 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out { /* keep the parantheses for the if (although single line) since the following is a macro */ RESET_FIRST_TP_SRCH_STATUS(first_tp_srch_status, cr, *cycle); } - return (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); + return buffaddr; } else if (!was_crit && (BAD_LUCK_ABOUNDS > ocnt)) { assert(!hold_onto_crit); assert(TRUE == csa->now_crit); - assert(csa->nl->in_crit == process_id); + assert(cnl->in_crit == process_id); rel_crit(gv_cur_region); } } if (CR_NOTVALID == (sm_long_t)cr) { - SET_TRACEABLE_VAR(cs_data->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_qread_db_csh_get_invalid_blk); set_wc_blocked = TRUE; break; @@ -442,8 +486,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out { if (0 > cr->read_in_progress) { /* it's not being read */ - if (clustered && (0 == cr->bt_index) && - (cr->tn < ((th_rec *)((uchar_ptr_t)csa->th_base + csa->th_base->tnque.fl))->tn)) + if (clustered && (0 == cr->bt_index) && (cr->tn < OLDEST_HIST_TN(csa))) { /* can't rely on the buffer */ cr->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */ cr->blk = CR_BLKEMPTY; @@ -469,8 +512,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out ) if (cr->blk != blk) break; - if ((was_crit != csa->now_crit) && !hold_onto_crit) - rel_crit(gv_cur_region); + REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit); assert(was_crit == csa->now_crit); /* Check if "cr" is locked for phase2 update by a concurrent process. Before doing so, need to * do a read memory barrier to ensure we read a consistent state. Otherwise, we could see @@ -501,7 +543,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out * final retry in which case it is better to wait here as we dont want to end up in a * situation where "recompute_upd_array" indicates that a restart is necessary. */ - if (dollar_tlevel && gv_target->noisolation && (ERR_GVPUTFAIL == t_err) + if (dollar_tlevel && (gv_target && gv_target->noisolation) && (ERR_GVPUTFAIL == t_err) && (CDB_STAGNATE > t_tries)) /* do not skip wait in case of final retry */ { /* We know that the only caller in this case would be the function "gvcst_search". * If the input cr and cycle match corresponding fields of gv_target->hist.h[0], @@ -525,10 +567,18 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out blocking_pid = 0; /* do not sleep in the for loop below */ } } - if (blocking_pid && !wcs_phase2_commit_wait(csa, cr)) - { /* Timed out waiting for cr->in_tend to become non-zero. Restart. */ - rdfail_detail = cdb_sc_phase2waitfail; - return NULL; + if (blocking_pid) + { + if (TREF(tqread_nowait) && ((sm_int_ptr_t)&gv_target->hist.h[0].cycle == cycle)) + { /* We're an update helper. Don't waste time waiting on a leaf blk */ + rdfail_detail = cdb_sc_tqreadnowait; + return (sm_uc_ptr_t)NULL; + } + if (!wcs_phase2_commit_wait(csa, cr)) + { /* Timed out waiting for cr->in_tend to become non-zero. Restart. */ + rdfail_detail = cdb_sc_phase2waitfail; + return (sm_uc_ptr_t)NULL; + } } } if (reset_first_tp_srch_status) @@ -560,14 +610,15 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out } else if (cr->read_in_progress >= 0) { BG_TRACE_PRO(t_qread_buf_owner_stuck); - if (0 != (blocking_pid = cr->r_epid)) + blocking_pid = cr->r_epid; + if ((0 != blocking_pid) && (process_id != blocking_pid)) { if (FALSE == is_proc_alive(blocking_pid, cr->image_count)) { /* process gone: release that process's lock */ assert(0 == cr->bt_index); if (cr->bt_index) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_qread_bad_bt_index1); set_wc_blocked = TRUE; break; @@ -580,39 +631,50 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out { if (!hold_onto_crit) rel_crit(gv_cur_region); - send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region)); - send_msg(VARLSTCNT(9) ERR_BUFOWNERSTUCK, 7, process_id, blocking_pid, - cr->blk, cr->blk, (lcnt / BUF_OWNER_STUCK), - cr->read_in_progress, cr->rip_latch.u.parts.latch_pid); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2, + DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_BUFOWNERSTUCK, 7, process_id, + blocking_pid, cr->blk, cr->blk, (lcnt / BUF_OWNER_STUCK), + cr->read_in_progress, cr->rip_latch.u.parts.latch_pid); stuck_cnt++; GET_C_STACK_FROM_SCRIPT("BUFOWNERSTUCK", process_id, blocking_pid, stuck_cnt); - if (MAX_TQREAD_WAIT <= lcnt) /* max wait of 4 mins */ - GTMASSERT; /* Kickstart the process taking a long time in case it was suspended */ UNIX_ONLY(continue_proc(blocking_pid)); } } else - { /* process stopped before could set r_epid */ + { /* process stopped before could set r_epid OR + * Process is waiting on the lock held by itself. + * Process waiting on the lock held by itself is an out-of-design + * situation that we dont how it can occur hence the following assert + * but know how to handle so we dont have to gtmassert in pro. + */ + assert(process_id != blocking_pid); assert(0 == cr->bt_index); if (cr->bt_index) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_t_qread_bad_bt_index2); set_wc_blocked = TRUE; break; } cr->cycle++; /* increment cycle for blk number changes (for tp_hist) */ cr->blk = CR_BLKEMPTY; - RELEASE_BUFF_READ_LOCK(cr); /* cr->r_epid already zero - no need to set */ + cr->r_epid = 0; /* If the process itself is lock holder, r_epid is non-zero */ + RELEASE_BUFF_READ_LOCK(cr); if (cr->read_in_progress < -1) /* race: process released since if r_epid */ LOCK_BUFF_FOR_READ(cr, dummy); } } - if ((was_crit != csa->now_crit) && !hold_onto_crit) - rel_crit(gv_cur_region); + REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit); } else { + if (TREF(tqread_nowait) && ((sm_int_ptr_t)&gv_target->hist.h[0].cycle == cycle)) + { /* We're an update helper. Don't waste time waiting on a leaf blk; move on to useful work */ + REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit); + rdfail_detail = cdb_sc_tqreadnowait; + return (sm_uc_ptr_t)NULL; + } BG_TRACE_PRO_ANY(csa, t_qread_ripsleep_cnt); if (!sleep_invoked) /* Count # of blks for which we ended up sleeping on the read */ BG_TRACE_PRO_ANY(csa, t_qread_ripsleep_nblks); @@ -620,7 +682,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out sleep_invoked = TRUE; } } - if (set_wc_blocked) /* cannot use csd->wc_blocked here as we might not necessarily have crit */ + if (set_wc_blocked) /* cannot use cnl->wc_blocked here as we might not necessarily have crit */ break; ocnt++; assert((0 == was_crit) || (1 == was_crit)); @@ -636,10 +698,9 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out if (!csa->now_crit && !hold_onto_crit) grab_crit(gv_cur_region); } while (TRUE); - assert(set_wc_blocked && (csd->wc_blocked || !csa->now_crit)); - rdfail_detail = cdb_sc_cacheprob; - if ((was_crit != csa->now_crit) && !hold_onto_crit) - rel_crit(gv_cur_region); + assert(set_wc_blocked && (cnl->wc_blocked || !csa->now_crit)); + SET_CACHE_FAIL_STATUS(rdfail_detail, csd); + REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit); assert(was_crit == csa->now_crit); return (sm_uc_ptr_t)NULL; } diff --git a/sr_port/t_retry.c b/sr_port/t_retry.c index 3f31d7c..1a13d4c 100644 --- a/sr_port/t_retry.c +++ b/sr_port/t_retry.c @@ -11,6 +11,10 @@ #include "mdef.h" +#if defined(VMS) && defined(DEBUG) +#include +#endif + #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" @@ -41,20 +45,33 @@ #include "wcs_backoff.h" #include "tp_restart.h" #include "gtm_ctype.h" /* for ISALPHA_ASCII */ +#include "anticipatory_freeze.h" +#include "wcs_recover.h" +#include "wbox_test_init.h" #ifdef GTM_TRIGGER #include "gtm_trigger_trc.h" #endif #ifdef UNIX -#include "wcs_recover.h" #include "gvcst_protos.h" #include "gtmimagename.h" -#include "wbox_test_init.h" -#endif -#ifdef ENABLE_EXTENDED_RESTART_TRACE_HIST -#include "repl_msg.h" -#include "gtmsource.h" #include "caller_id.h" #endif +#ifdef DEBUG +#include "repl_msg.h" +#include "gtmsource.h" +#endif + +/* In mu_reorg if we are in gvcst_bmp_mark_free, we actually have a valid gv_target. Find its root before the next iteration + * in mu_reorg. + */ +#define WANT_REDO_ROOT_SEARCH \ + ( (NULL != gv_target) \ + && (DIR_ROOT != gv_target->root) \ + && !redo_root_search_done \ + && !TREF(in_gvcst_redo_root_search) \ + && !mu_reorg_upgrd_dwngrd_in_prog \ + && (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process) \ + ) GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; @@ -67,6 +84,7 @@ GBLREF tp_frame *tp_pointer; GBLREF trans_num start_tn; GBLREF unsigned char cw_set_depth, cw_map_depth, t_fail_hist[CDB_MAX_TRIES]; GBLREF boolean_t mu_reorg_process; +GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; GBLREF unsigned int t_tries; GBLREF uint4 t_err; GBLREF jnl_gbls_t jgbl; @@ -77,15 +95,17 @@ GBLREF boolean_t skip_INVOKE_RESTART; #endif #ifdef DEBUG -GBLDEF unsigned char t_fail_hist_dbg[32]; +GBLDEF unsigned char t_fail_hist_dbg[T_FAIL_HIST_DBG_SIZE]; GBLDEF unsigned int t_tries_dbg; GBLREF sgm_info *sgm_info_ptr; +GBLREF boolean_t mupip_jnl_recover; #endif #ifdef UNIX GBLREF boolean_t is_updproc; GBLREF boolean_t need_kip_incr; GBLREF sgmnt_addrs *kip_csa; +GBLREF jnlpool_addrs jnlpool; #endif #ifdef UNIX @@ -106,17 +126,18 @@ void t_retry(enum cdb_sc failure) short tl; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; + node_local_ptr_t cnl; # ifdef DEBUG unsigned int tries; # endif boolean_t skip_invoke_restart; boolean_t redo_root_search_done = FALSE; + unsigned int local_t_tries; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; # ifdef GTM_TRIGGER skip_invoke_restart = skip_INVOKE_RESTART; /* note down global value in local variable */ - skip_INVOKE_RESTART = FALSE; /* reset global variable to default state as soon as possible */ GTMTRIG_ONLY(DBGTRIGR((stderr, "t_retry: entered\n"))); # else skip_invoke_restart = FALSE; /* no triggers so set local variable to default state */ @@ -127,16 +148,12 @@ void t_retry(enum cdb_sc failure) * until the final retry which is why we accept this way of invoking t_retry. Assert accordingly. */ assert((cdb_sc_normal != failure) || mu_reorg_process); - /* The only reason online rollback ends up restarting is if some process set wc_blocked outside crit or the prior - * transaction had commit errors and secshr_db_clnup set wc_blocked to TRUE. But, that's possible only if white box test - * cases to induce Phase 1 and Phase 2 commit errors are set. So, assert accordingly - */ - UNIX_ONLY(assert(!jgbl.onlnrlbk || WB_COMMIT_ERR_ENABLED)); t_fail_hist[t_tries] = (unsigned char)failure; if (mu_reorg_process) CWS_RESET; DEBUG_ONLY(TREF(donot_commit) = FALSE;) csa = cs_addrs; + cnl = csa ? csa->nl : NULL; /* making sure we do not try to dereference a NULL pointer */ if (!dollar_tlevel) { # ifdef DEBUG @@ -146,21 +163,35 @@ void t_retry(enum cdb_sc failure) t_fail_hist_dbg[t_tries_dbg++] = (unsigned char)failure; TRACE_TRANS_RESTART(failure); # endif - SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, failure); /* set wc_blocked if cache related status */ +# ifdef UNIX + if (cdb_sc_instancefreeze == failure) + { + assert(REPL_ALLOWED(csa->hdr)); /* otherwise, a cdb_sc_instancefreeze retry would not have been signalled */ + WAIT_FOR_REPL_INST_UNFREEZE(csa); + } +# endif + /* Even though rollback and recover operate standalone, there are certain kind of restarts that can still happen + * either due to whitebox test cases or stomping on our own buffers causing cdb_sc_lostcr/cdb_sc_rmisalign. Assert + * accordingly + */ + assert(!mupip_jnl_recover || WB_COMMIT_ERR_ENABLED || (CDB_STAGNATE > t_tries)); + SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, cnl, failure); /* set wc_blocked if cache related status */ + TREF(prev_t_tries) = t_tries; + TREF(rlbk_during_redo_root) = FALSE; switch(t_tries) { case 0: - INCR_GVSTATS_COUNTER(csa, csa->nl, n_nontp_retries_0, 1); + INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_retries_0, 1); break; case 1: - INCR_GVSTATS_COUNTER(csa, csa->nl, n_nontp_retries_1, 1); + INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_retries_1, 1); break; case 2: - INCR_GVSTATS_COUNTER(csa, csa->nl, n_nontp_retries_2, 1); + INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_retries_2, 1); break; default: assert(3 == t_tries); - INCR_GVSTATS_COUNTER(csa, csa->nl, n_nontp_retries_3, 1); + INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_retries_3, 1); break; } if (csa->critical) @@ -168,7 +199,7 @@ void t_retry(enum cdb_sc failure) /* If the restart code is something that should not increment t_tries, handle that by decrementing t_tries * for these special codes just before incrementing it unconditionally. Note that this should be done ONLY IF * t_tries is CDB_STAGNATE or higher and not for lower values as otherwise it can cause livelocks (e.g. - * because csa->hdr->wc_blocked is set to TRUE, it is possible we end up restarting with cdb_sc_helpedout + * because cnl->wc_blocked is set to TRUE, it is possible we end up restarting with cdb_sc_helpedout * without even doing a cache-recovery (due to the fast path in t_end that does not invoke grab_crit in case * of read-only transactions). In this case, not incrementing t_tries causes us to eternally retry * the transaction with no one eventually grabbing crit and doing the cache-recovery). @@ -188,16 +219,19 @@ void t_retry(enum cdb_sc failure) * (b) cdb_sc_jnlclose : journaling might get turned off in the final retry INSIDE crit while trying to * flush journal buffer or during extending the journal file (due to possible disk issues) in which * case we come here with t_tries = CDB_STAGNATE. - * (c) cdb_sc_helpedout : csd->wc_blocked being TRUE as well as file extension in MM (both of which is + * (c) cdb_sc_helpedout : cnl->wc_blocked being TRUE as well as file extension in MM (both of which is * caused due to another process) can happen in final retry with failure status set to cdb_sc_helpedout * (d) cdb_sc_needcrit : See GTM-7004 for how this is possible and why only a max of one such restart * per non-TP transaction is possible. * (e) cdb_sc_onln_rlbk[1,2] : See comment below as to why we allow online rollback related restarts even * in the final retry. + * (f) cdb_sc_instancefreeze : Instance freeze detected while crit held. + * (g) cdb_sc_gvtrootmod2 : Similar to (e). */ if ((cdb_sc_jnlstatemod == failure) || (cdb_sc_jnlclose == failure) || (cdb_sc_helpedout == failure) || (cdb_sc_needcrit == failure) || (cdb_sc_onln_rlbk1 == failure) - || (cdb_sc_onln_rlbk2 == failure)) + || (cdb_sc_onln_rlbk2 == failure) || (cdb_sc_instancefreeze == failure) + || (cdb_sc_gvtrootmod2 == failure)) { /* t_tries should never be greater than t_tries_dbg. The only exception is if this is DSE or online * rollback operates with t_tries = CDB_STAGNATE and restarts if wc_blocked is set outside crit. @@ -207,7 +241,7 @@ void t_retry(enum cdb_sc failure) assert((t_tries <= t_tries_dbg) UNIX_ONLY(|| (csa->hold_onto_crit && WB_COMMIT_ERR_ENABLED))); /* Assert that the same kind of restart code can never occur more than once once we go to the * final retry. The only exception is cdb_sc_helpedout which can happen due to other processes - * setting csd->wc_blocked to TRUE without holding crit. + * setting cnl->wc_blocked to TRUE without holding crit. */ assert(failure == t_fail_hist_dbg[t_tries_dbg - 1]); DEBUG_ONLY( @@ -222,17 +256,21 @@ void t_retry(enum cdb_sc failure) DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = TRUE;) if (!csa->hold_onto_crit) grab_crit(gv_cur_region); -# ifdef UNIX - if (csa->hdr->wc_blocked) + else if (cnl->wc_blocked) { /* Possible ONLY for online rollback or DSE that grabs crit during startup and never grabs again. * In such cases grab_crit (such as above) is skipped. As a result wcs_recover is also skipped. * To avoid this, do wcs_recover if wc_blocked is TRUE. But, that's possible only if white box test * cases to induce Phase 1 and Phase 2 errors are set. So, assert accordingly. */ - assert(csa->hold_onto_crit && WB_COMMIT_ERR_ENABLED); + assert(WB_COMMIT_ERR_ENABLED); wcs_recover(gv_cur_region); + /* Note that if a concurrent Phase 2 error sets wc_blocked to TRUE anytime between now + * and the wc_blocked check at the top of t_end, we'll end up restarting and doing wcs_recover + * on the next restart. + */ } - if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) +# ifdef UNIX + if (MISMATCH_ROOT_CYCLES(csa, cnl)) { /* We came in to handle a different restart code in the penultimate retry and grab_crit before going * to final retry. As part of grabbing crit, we detected an online rollback. Although we could treat * this as just an online rollback restart and handle it by syncing cycles, but by doing so, we will @@ -246,12 +284,16 @@ void t_retry(enum cdb_sc failure) * proceeds smoothly. */ RESET_ALL_GVT_CLUES; - gvcst_redo_root_search(); - redo_root_search_done = TRUE; + cw_set_depth = 0; + cw_map_depth = 0; + if (WANT_REDO_ROOT_SEARCH) + { + gvcst_redo_root_search(); + redo_root_search_done = TRUE; + } } # endif assert(csa->now_crit); - CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region); DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;) csd = cs_data; if (CDB_STAGNATE == t_tries) @@ -267,31 +309,43 @@ void t_retry(enum cdb_sc failure) assert((failure != cdb_sc_helpedout) && (failure != cdb_sc_jnlclose) && (failure != cdb_sc_jnlstatemod) && (failure != cdb_sc_bkupss_statemod) && (failure != cdb_sc_inhibitkills)); - assert(csa->now_crit); + local_t_tries = t_tries; if (!csa->hold_onto_crit) + { rel_crit(gv_cur_region); + t_tries = 0; + } if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; if (cdb_sc_gbloflow == failure) - rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + } if (IS_DOLLAR_INCREMENT) { assert(ERR_GVPUTFAIL == t_err); t_err = ERR_GVINCRFAIL; /* print more specific error message */ } - UNIX_ONLY(send_msg(VARLSTCNT(9) t_err, 2, t_tries, t_fail_hist, + UNIX_ONLY(send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) t_err, 2, local_t_tries, t_fail_hist, ERR_GVIS, 2, end-buff, buff, ERR_GVFAILCORE)); +#ifdef DEBUG + /* Core is not needed. We intentionally create this error. */ + if (!gtm_white_box_test_case_enabled) +#endif UNIX_ONLY(gtm_fork_n_core()); - VMS_ONLY(send_msg(VARLSTCNT(8) t_err, 2, t_tries, t_fail_hist, + VMS_ONLY(send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist, ERR_GVIS, 2, end-buff, buff)); - rts_error(VARLSTCNT(8) t_err, 2, t_tries, t_fail_hist, ERR_GVIS, 2, end-buff, buff); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist, ERR_GVIS, 2, end-buff, + buff); } } - if ((cdb_sc_blockflush == failure) && !CCP_SEGMENT_STATE(csa->nl, CCST_MASK_HAVE_DIRTY_BUFFERS)) + CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region); + if ((cdb_sc_blockflush == failure) && !CCP_SEGMENT_STATE(cnl, CCST_MASK_HAVE_DIRTY_BUFFERS)) { assert(csa->hdr->clustered); CCP_FID_MSG(gv_cur_region, CCTR_FLUSHLK); - ccp_userwait(gv_cur_region, CCST_MASK_HAVE_DIRTY_BUFFERS, 0, csa->nl->ccp_cycle); + ccp_userwait(gv_cur_region, CCST_MASK_HAVE_DIRTY_BUFFERS, 0, cnl->ccp_cycle); } cw_set_depth = 0; cw_map_depth = 0; @@ -300,19 +354,6 @@ void t_retry(enum cdb_sc failure) */ GTMTRIG_ONLY(csa->db_trigger_cycle = csa->hdr->db_trigger_cycle); GTMTRIG_ONLY(DBGTRIGR((stderr, "t_retry: csa->db_trigger_cycle updated to %d\n", csa->db_trigger_cycle))); -# ifdef GTM_TRUNCATE - /* t_end restarts any transaction that may have acquired blocks beyond total_blks when a concurrent truncate - * occurred. The private copy csa->total_blks can be interpreted as the upper bound for acquired blocks. - * Resync private and shared copies of total_blks here to cover the next retry. We do this here instead of - * in t_end before bm_getfree because mu_swap_blk can acquire its own blocks. Essentially, truncate - * detection spans from the syncing of total_blks here (or db_init or tp_set_sgm) to when total_blks are checked - * in t_end. - * csa->total_blks can increase (see gdsfilext) - * csa->ti->total_blks can increase (gdsfilext) or decrease (mu_truncate) - */ - if (dba_mm != csa->hdr->acc_meth) - csa->total_blks = csa->ti->total_blks; -# endif start_tn = csa->ti->curr_tn; /* Note: If gv_target was NULL before the start of a transaction and the only operations done inside the transaction * are trigger deletions causing bitmap free operations which got restarted due to a concurrent update, we can @@ -323,9 +364,10 @@ void t_retry(enum cdb_sc failure) # ifdef UNIX if ((cdb_sc_onln_rlbk1 == failure) || (cdb_sc_onln_rlbk2 == failure)) { /* restarted due to online rollback */ - RESET_ALL_GVT_CLUES; - if (!TREF(only_reset_clues_if_onln_rlbk)) - { + if (!redo_root_search_done) + RESET_ALL_GVT_CLUES; + if (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process) + { /* Handle cleanup beyond just resetting clues */ if (cdb_sc_onln_rlbk2 == failure) { if (IS_MCODE_RUNNING || TREF(issue_DBROLLEDBACK_anyways)) @@ -341,17 +383,14 @@ void t_retry(enum cdb_sc failure) * KILL. So, assert that kip_csa is still NULL */ assert(NULL == kip_csa); - need_kip_incr = FALSE; /* reset so the next transaction does not see stale values */ - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_DBROLLEDBACK); } } - if ((NULL != gv_target) && (DIR_ROOT != gv_target->root)) - { - assert(!redo_root_search_done); /* assert we dont invoke this twice inside t_retry */ + assert(!redo_root_search_done); + if (WANT_REDO_ROOT_SEARCH) gvcst_redo_root_search(); - } if (is_updproc) - rts_error(VARLSTCNT(1) ERR_REPLONLNRLBK); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_REPLONLNRLBK); } # ifdef DEBUG else @@ -377,6 +416,22 @@ void t_retry(enum cdb_sc failure) if (!redo_root_search_done && (NULL != gv_target) && (DIR_ROOT != gv_target->root)) gvcst_redo_root_search(); } + if (cdb_sc_gvtrootmod2 == failure) + { + if (!redo_root_search_done) + RESET_ALL_GVT_CLUES; + /* It is possible for a read-only transaction to release crit after detecting gvtrootmod2, during which time + * yet another root block could have moved. In that case, the MISMATCH_ROOT_CYCLES check would have + * already done the redo_root_search. + */ + assert(!redo_root_search_done || !update_trans); + if (WANT_REDO_ROOT_SEARCH) + { /* Note: An online rollback can occur DURING gvcst_redo_root_search, which can remove gbls from db, + * leading to gv_target->root being 0, even though failure code is not cdb_sc_onln_rlbk2 + */ + gvcst_redo_root_search(); + } + } # endif } else { /* for TP, do the minimum; most of the logic is in tp_retry, because it is also invoked directly from t_commit */ @@ -384,10 +439,10 @@ void t_retry(enum cdb_sc failure) assert((NULL == csa) || (NULL != csa->hdr)); /* both csa and csa->hdr should be NULL or non-NULL. */ if (NULL != csa) { - SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, failure); - TP_RETRY_ACCOUNTING(csa, csa->nl, failure); - } else /* csa can be NULL if retry in op_lock2 (cdb_sc_needlock) or if cur_reg is not open yet (cdb_sc_needcrit) */ - assert((CDB_STAGNATE == t_tries) && ((cdb_sc_needlock == failure) || (cdb_sc_needcrit == failure))); + SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, cnl, failure); + TP_RETRY_ACCOUNTING(csa, cnl); + } else /* csa can be NULL if cur_reg is not open yet (cdb_sc_needcrit) */ + assert((CDB_STAGNATE == t_tries) && (cdb_sc_needcrit == failure)); if (NULL != gv_target) { if (cdb_sc_blkmod != failure) diff --git a/sr_port/t_write.c b/sr_port/t_write.c index 37bf4e8..e6a6a0d 100644 --- a/sr_port/t_write.c +++ b/sr_port/t_write.c @@ -43,6 +43,8 @@ GBLREF unsigned int t_tries; GBLREF boolean_t horiz_growth; GBLREF int4 prev_first_off, prev_next_off; GBLREF boolean_t mu_reorg_process; +GBLREF boolean_t dse_running; +GBLREF jnl_gbls_t jgbl; cw_set_element *t_write ( srch_blk_status *blkhist, /* Search History of the block to be written. Currently the @@ -193,11 +195,18 @@ cw_set_element *t_write ( /* the buffer in shared memory holding the GDS block contents currently does not have in its block header the * on-disk format of that block. if it had, we could have easily copied that over to the cw-set-element. * until then, we have to use the cache-record's field "ondsk_blkver". but the cache-record is available only in BG. - * thankfully, in MM, we do not allow GDSV4 type blocks, so we can safely assign GDSV5 (or GDSVCURR) to this field. + * thankfully, in MM, we do not allow GDSV4 type blocks, so we can safely assign GDSV6 (or GDSVCURR) to this field. */ cr = blkhist->cr; assert((NULL != cr) || (dba_mm == csa->hdr->acc_meth)); cse->ondsk_blkver = (NULL == cr) ? GDSVCURR : cr->ondsk_blkver; + /* For uninitialized gv_target, initialize the in_tree status as IN_DIR_TREE */ + assert (NULL != gv_target || dse_running || jgbl.forw_phase_recovery); + if (NULL == gv_target || 0 == gv_target->root) + BIT_SET_DIR_TREE(cse->blk_prior_state); + else + (DIR_ROOT == gv_target->root)? BIT_SET_DIR_TREE(cse->blk_prior_state) : + BIT_SET_GV_TREE(cse->blk_prior_state); } else { /* we did not create a new cse. assert the integrity of few fields filled in when this cse was created */ assert(cse->blk == blk); @@ -219,7 +228,9 @@ cw_set_element *t_write ( cse->index = index; cse->reference_cnt = 0; cse->level = level; - cse->was_free = FALSE; /* t_write operates on BUSY blocks and hence cse->was_free is set to FALSE unconditionally */ + /* t_write operates on BUSY blocks and hence cse->blk_prior_state's free_status is set to FALSE unconditionally */ + BIT_CLEAR_FREE(cse->blk_prior_state); + BIT_CLEAR_RECYCLED(cse->blk_prior_state); if (horiz_growth) cse->first_copy = TRUE; else diff --git a/sr_port/t_write_map.c b/sr_port/t_write_map.c index 737b07b..9a57501 100644 --- a/sr_port/t_write_map.c +++ b/sr_port/t_write_map.c @@ -77,8 +77,10 @@ void t_write_map ( cs->blk_checksum = 0; cs->blk = blkhist->blk_num; assert((cs->blk < csa->ti->total_blks) GTM_TRUNCATE_ONLY(|| (CDB_STAGNATE > t_tries))); - cs->old_block = blkhist->buffaddr; - cs->was_free = FALSE; /* t_write_map operates on BUSY blocks and hence cs->was_free is set to FALSE unconditionally */ + cs->old_block = blkhist->buffaddr; + /* t_write_map operates on BUSY blocks and hence cs->blk_prior_state's free_status is set to FALSE unconditionally */ + BIT_CLEAR_FREE(cs->blk_prior_state); + BIT_CLEAR_RECYCLED(cs->blk_prior_state); old_block = (blk_hdr_ptr_t)cs->old_block; assert(NULL != old_block); jbbp = (JNL_ENABLED(csa) && csa->jnl_before_image) ? csa->jnl->jnl_buff : NULL; @@ -95,7 +97,7 @@ void t_write_map ( /* the buffer in shared memory holding the GDS block contents currently does not have in its block header the * on-disk format of that block. if it had, we could have easily copied that over to the cw-set-element. * until then, we have to use the cache-record's field "ondsk_blkver". but the cache-record is available only in BG. - * thankfully, in MM, we do not allow GDSV4 type blocks, so we can safely assign GDSV5 (or GDSVCURR) to this field. + * thankfully, in MM, we do not allow GDSV4 type blocks, so we can safely assign GDSV6 (or GDSVCURR) to this field. */ assert((NULL != cr) || (dba_mm == csa->hdr->acc_meth)); cs->ondsk_blkver = (NULL == cr) ? GDSVCURR : cr->ondsk_blkver; diff --git a/sr_port/tab_gvstats_rec.h b/sr_port/tab_gvstats_rec.h index 4e37718..4d9df6f 100644 --- a/sr_port/tab_gvstats_rec.h +++ b/sr_port/tab_gvstats_rec.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2008, 2010 Fidelity Information Services, Inc * + * Copyright 2008, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,3 +50,17 @@ TAB_GVSTATS_REC(n_tp_cnflct_retries_2, "TC2", "# of Tp Conflict retries [2] TAB_GVSTATS_REC(n_tp_cnflct_retries_3, "TC3", "# of Tp Conflict retries [3] ") TAB_GVSTATS_REC(n_tp_cnflct_retries_4, "TC4", "# of Tp Conflict retries [4] ") TAB_GVSTATS_REC(n_ztrigger , "ZTR", "# of ZTRigger operations ") +TAB_GVSTATS_REC(n_db_flush , "DFL", "# of Database FLushes ") +TAB_GVSTATS_REC(n_db_fsync , "DFS", "# of Database FSyncs ") +TAB_GVSTATS_REC(n_jnl_flush , "JFL", "# of Journal FLushes ") +TAB_GVSTATS_REC(n_jnl_fsync , "JFS", "# of Journal FSyncs ") +TAB_GVSTATS_REC(n_jbuff_bytes , "JBB", "# of Bytes written to Journal Buffer ") +TAB_GVSTATS_REC(n_jfile_bytes , "JFB", "# of Bytes written to Journal File ") +TAB_GVSTATS_REC(n_jfile_writes , "JFW", "# of Journal File Writes ") +TAB_GVSTATS_REC(n_jrec_logical , "JRL", "# of Logical Journal Records ") +TAB_GVSTATS_REC(n_jrec_pblk , "JRP", "# of Pblk Journal Records ") +TAB_GVSTATS_REC(n_jrec_epoch_regular , "JRE", "# of Regular Epoch Journal Records ") +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 ") diff --git a/sr_port/tcp_open.c b/sr_port/tcp_open.c index ed49293..7cf6e49 100644 --- a/sr_port/tcp_open.c +++ b/sr_port/tcp_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,11 +32,12 @@ #include #include "gtm_time.h" #include "gtm_socket.h" +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_string.h" #include "gtm_ctype.h" #include "gtm_stdio.h" -#include "gtm_netdb.h" #include "copy.h" #include "gt_timer.h" @@ -62,85 +63,83 @@ const char *hstrerror(int err); GBLREF tcp_library_struct tcp_routines; +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); error_def(ERR_INVADDRSPEC); error_def(ERR_IPADDRREQ); error_def(ERR_SETSOCKOPTERR); -error_def(ERR_SOCKINIT); -error_def(ERR_SYSCALL); error_def(ERR_SOCKACPT); +error_def(ERR_SOCKINIT); error_def(ERR_SOCKLISTEN); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */ { boolean_t no_time_left = FALSE, error_given = FALSE; char temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1]; - char *from, *to, *errptr, *temp_ch, *adptr; + char *from, *to, *errptr, *temp_ch; + char ipname[SA_MAXLEN]; int match, sock, sendbufsize, ii, on = 1, temp_1 = -2; GTM_SOCKLEN_TYPE size; int4 rv, msec_timeout; - struct sockaddr_in sin; - in_addr_t temp_sin_addr; + struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *remote_ai_head, hints; + char port_buffer[NI_MAXSERV], *brack_pos; + + int host_len, addr_len, port_len; char msg_buffer[1024]; mstr msg_string; ABS_TIME cur_time, end_time; fd_set tcp_fd; - struct sockaddr_in peer; + struct sockaddr_storage peer; short retry_num; int save_errno, errlen; const char *terrptr; + int errcode; + boolean_t af; - temp_sin_addr = 0; msg_string.len = SIZEOF(msg_buffer); msg_string.addr = msg_buffer; - memset((char *)&sin, 0, SIZEOF(struct sockaddr_in)); /* ============================= initialize structures ============================== */ if (NULL != host) { - temp_ch = host; - while(ISDIGIT_ASCII(*temp_ch) || ('.' == *temp_ch)) - temp_ch++; - if ('\0' != *temp_ch) + host_len = strlen(host); + if ('[' == host[0]) { - adptr = iotcp_name2ip(host); - if (NULL == adptr) + brack_pos = memchr(host, ']', SA_MAXLEN); + if (NULL == brack_pos || (&host[1] == brack_pos)) { -# if !defined(__hpux) && !defined(__MVS__) - terrptr = HSTRERROR(h_errno); - rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(terrptr)); -# else - /* Grumble grumble HPUX and z/OS don't have hstrerror() */ - rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); -# endif + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); + return -1; + } + addr_len = brack_pos - &(host[1]); + memcpy(addr, &host[1], addr_len); + if ('\0' != *(brack_pos + 1)) + { /* not allowed to have special symbols other than [ and ] */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return -1; } - SPRINTF(addr, "%s", adptr); } else - SPRINTF(addr, "%s", host); - - if ((unsigned int)-1 == (temp_sin_addr = tcp_routines.aa_inet_addr(addr))) - { - gtm_putmsg(VARLSTCNT(1) ERR_INVADDRSPEC); - assert(FALSE); - return -1; + { /* IPv4 address only */ + addr_len = strlen(host); + if (0 == addr_len) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); + return -1; + } + memcpy(addr, &host[0], addr_len); } - } - if (passive) - /* We can only listen on our own system */ - sin.sin_addr.s_addr = INADDR_ANY; - else - { - if (0 == temp_sin_addr) - { /* If no address was specified */ - gtm_putmsg(VARLSTCNT(1) ERR_IPADDRREQ); - assert(FALSE); + addr[addr_len] = '\0'; + CLIENT_HINTS(hints); + port_len = 0; + I2A(port_buffer, port_len, port); + port_buffer[port_len]='\0'; + if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_head))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return -1; } - /* Set where to send the connection attempt */ - sin.sin_addr.s_addr = temp_sin_addr; } - sin.sin_port = GTM_HTONS(port); - sin.sin_family = AF_INET; /* ============================== do the connection ============================== */ if (passive) @@ -148,15 +147,31 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / struct timeval utimeout, save_utimeout; int lsock; - lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); + af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); + lsock = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP); if (-1 == lsock) { - save_errno = errno; - errptr = (char *)STRERROR(save_errno); - errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); - assert(FALSE); + af = AF_INET; + if (-1 == (lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) + { + save_errno = errno; + errptr = (char *)STRERROR(save_errno); + errlen = STRLEN(errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); + assert(FALSE); + return -1; + } + } + SERVER_HINTS(hints, af); + /* We can only listen on our own system */ + port_len = 0; + I2A(port_buffer, port_len, port); + port_buffer[port_len]='\0'; + if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return -1; + } /* allow multiple connections to the same IP address */ if (-1 == tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on))) @@ -165,19 +180,20 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / (void)tcp_routines.aa_close(lsock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, - RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr); assert(FALSE); return -1; } - if (-1 == tcp_routines.aa_bind(lsock, (struct sockaddr *)&sin, SIZEOF(struct sockaddr))) + if (-1 == tcp_routines.aa_bind(lsock, ai_ptr->ai_addr, ai_ptr->ai_addrlen)) { save_errno = errno; (void)tcp_routines.aa_close(lsock); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, - RTS_ERROR_LITERAL("bind()"), CALLFROM, save_errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("bind()"), CALLFROM, save_errno); return -1; } + freeaddrinfo(ai_ptr); /* establish a queue of length MAX_CONN_PENDING for incoming connections */ if (-1 == tcp_routines.aa_listen(lsock, MAX_CONN_PENDING)) { @@ -185,7 +201,7 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / (void)tcp_routines.aa_close(lsock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); assert(FALSE); return -1; } @@ -197,15 +213,14 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / utimeout.tv_sec = timeout; utimeout.tv_usec = 0; } - while(1) + FD_ZERO(&tcp_fd); + while (TRUE) { - while(1) + while (TRUE) { - /* - * the check for EINTR below is valid and should not be converted to an EINTR - * wrapper macro, since it might be a timeout. + /* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro + * since it might be a timeout. */ - FD_ZERO(&tcp_fd); FD_SET(lsock, &tcp_fd); save_utimeout = utimeout; rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, @@ -234,110 +249,46 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / } else if (0 > rv) { (void)tcp_routines.aa_close(lsock); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, - RTS_ERROR_LITERAL("select()"), CALLFROM, save_errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("select()"), CALLFROM, save_errno); assert(FALSE); return -1; } - size = SIZEOF(struct sockaddr_in); - sock = tcp_routines.aa_accept(lsock, &peer, &size); - save_errno = errno; - if (-1 == sock) + size = SIZEOF(struct sockaddr_storage); + sock = tcp_routines.aa_accept(lsock, (struct sockaddr*)(&peer), &size); + if (FD_INVALID == sock) { + save_errno = errno; # ifdef __hpux - /* ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just - * after a SYN before an accept call. Normally this is not fatal and is just a transient state. - * Hence exiting just after a single error of this kind should not be done. So retry in case - * of HP-UX and ENOBUFS error. - */ if (ENOBUFS == save_errno) - { - retry_num = 0; - while (HPUX_MAX_RETRIES > retry_num) - { /* In case of succeeding with select in first go, accept will still get 5ms time - * difference. - */ - SHORT_SLEEP(5); - for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++) - { - utimeout.tv_sec = 0; - utimeout.tv_usec = HPUX_SEL_TIMEOUT; - FD_ZERO(&tcp_fd); - FD_SET(lsock, &tcp_fd); - rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, - (void *)0, &utimeout); - save_errno = errno; - if (0 < rv) - break; - else - SHORT_SLEEP(5); - } - if (0 > rv) - { - (void)tcp_routines.aa_close(lsock); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, - RTS_ERROR_LITERAL("select()"), - CALLFROM, save_errno); - assert(FALSE); - return -1; - } - if (0 == rv) - { - (void)tcp_routines.aa_close(lsock); - util_out_print("Select timed out.\n", TRUE); - assert(FALSE); - return -1; - } - sock = tcp_routines.aa_accept(lsock, &peer, &size); - save_errno = errno; - if ((-1 == sock) && (ENOBUFS == save_errno)) - retry_num++; - else - break; - } - } - if (-1 == sock) + continue; # endif - { - (void)tcp_routines.aa_close(lsock); - errptr = (char *)STRERROR(save_errno); - errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); - assert(FALSE); - return -1; - } + (void)tcp_routines.aa_close(lsock); + errptr = (char *)STRERROR(save_errno); + errlen = STRLEN(errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); + assert(FALSE); + return -1; + } + GETNAMEINFO((struct sockaddr*)(&peer), size, temp_addr, SA_MAXLEN + 1, NULL, 0, NI_NUMERICHOST, errcode); + if (0 != errcode) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return -1; } - SPRINTF(&temp_addr[0], "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr)); # ifdef DEBUG_ONLINE PRINTF("Connection is from : %s\n", &temp_addr[0]); # endif - /* Check if connection is from whom we want it to be from. Note that this is not a robust check - (potential for multiple IP addrs for a resolved name but workarounds for this exist so not a lot - of effort has been expended here at this time. Especially since the check is easily spoofed with - raw sockets anyway. It is more for the accidental "oops" type check than serious security.. - */ - if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr)))) - break; - else - { /* Connection not from expected host */ - (void)tcp_routines.aa_close(sock); - if (NO_M_TIMEOUT != timeout) - { - sys_get_curr_time(&cur_time); - cur_time = sub_abs_time(&end_time, &cur_time); - utimeout.tv_sec = ((cur_time.at_sec > 0) ? cur_time.at_sec : 0); - } - if (!error_given) - { - util_out_print("Connection from !AD rejected and ignored (expected from !AD)", TRUE, - LEN_AND_STR(&temp_addr[0]), LEN_AND_STR(&addr[0])); - error_given = TRUE; - } - } + break; + /* previously there is following check here + * if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr)))) + * However, temp_sin_addr is always 0 on server side, and addr(local address) shoud not equal to + * temp_addr(remote address), so the entire check should be removed + */ } (void)tcp_routines.aa_close(lsock); } else - { + { /* client side (connection side) */ if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); @@ -350,47 +301,44 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / { if (1 != temp_1) tcp_routines.aa_close(sock); - sock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); - if (-1 == sock) + assert(NULL != remote_ai_head); + for (remote_ai_ptr = remote_ai_head; NULL != remote_ai_ptr; remote_ai_ptr = remote_ai_ptr->ai_next) + { + sock = tcp_routines.aa_socket(remote_ai_ptr->ai_family, remote_ai_ptr->ai_socktype, + remote_ai_ptr->ai_protocol); + if (FD_INVALID != sock) + break; + } + if (FD_INVALID == sock) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); assert(FALSE); return -1; } /* Allow multiple connections to the same IP address */ - if (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on))) + if (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on))) { save_errno = errno; (void)tcp_routines.aa_close(sock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); - gtm_putmsg(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, - RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, + LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr); assert(FALSE); return -1; } - temp_1 = tcp_routines.aa_connect(sock, (struct sockaddr *)(&sin), SIZEOF(sin)); + temp_1 = tcp_routines.aa_connect(sock, remote_ai_ptr->ai_addr, remote_ai_ptr->ai_addrlen); save_errno = errno; - /* - * the check for EINTR below is valid and should not be converted to an EINTR - * wrapper macro, because other error conditions are checked, and a retry is not - * immediately performed. - */ - if ((0 > temp_1) && (ECONNREFUSED != save_errno) && (EINTR != save_errno)) + /* tcp_routines.aa_connect == gtm_connect should have handled EINTR. Assert that */ + assert((0 <= temp_1) || (EINTR != save_errno)); + if ((0 > temp_1) && (ECONNREFUSED != save_errno)) { (void)tcp_routines.aa_close(sock); - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, - RTS_ERROR_LITERAL("connect()"), CALLFROM, save_errno); - assert(FALSE); - return -1; - } - if ((0 > temp_1) && (EINTR == save_errno)) - { - (void)tcp_routines.aa_close(sock); - util_out_print("Interrupted.", TRUE); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("connect()"), CALLFROM, save_errno); assert(FALSE); return -1; } @@ -404,6 +352,7 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) / SHORT_SLEEP(NAP_LENGTH); /* Sleep for NAP_LENGTH ms */ } while ((FALSE == no_time_left) && (0 > temp_1)); + freeaddrinfo(remote_ai_head); if (0 > temp_1) /* out of time */ { tcp_routines.aa_close(sock); diff --git a/sr_port/toktyp.h b/sr_port/toktyp.h index 063279e..95bad8b 100644 --- a/sr_port/toktyp.h +++ b/sr_port/toktyp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2006 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,7 +61,8 @@ #define TK_EXPONENT 48 #define TK_SORTS_AFTER 49 #define TK_NSORTS_AFTER 50 -#define TK_SQLFIELDNAME 51 +#define TK_ATHASH 51 +#define TK_SQLFIELDNAME 52 #define NUM_ASCII_CHARS 128 #define NUM_CHARS 256 /* number of single-byte characters (includes ASCII and non-ASCII) */ diff --git a/sr_port/tp.h b/sr_port/tp.h index e6db1e9..d0681f4 100644 --- a/sr_port/tp.h +++ b/sr_port/tp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -160,15 +160,25 @@ typedef struct sgm_info_struct uint4 tot_jrec_size; /* maximum journal space needs for this transaction */ } sgm_info; +/* Define macros to reflect the size of cw_index and next_off in the off_chain structure. + * If the structure layout changes, these formulas might need corresponding adjustment. + * Note that ideally we should be using SIZEOF(off_chain) * 8 instead of 32 in the NEXT_OFF_MAX_BITS definition + * (currently commented due to a gengtmdeftypes issue). But that introduces a cyclic dependency causing a compiler error. + */ +#define CW_INDEX_MAX_BITS 15 +/* Remove the next line and uncomment the following line once gengtmdeftypes is fixed to allow expressions in bitfield members */ +#define NEXT_OFF_MAX_BITS 16 +/* #define NEXT_OFF_MAX_BITS (32 - CW_INDEX_MAX_BITS - 1) */ + typedef struct { #ifdef BIGENDIAN unsigned flag : 1; - unsigned cw_index : 15; - unsigned next_off : 16; + unsigned cw_index : CW_INDEX_MAX_BITS; + unsigned next_off : NEXT_OFF_MAX_BITS; #else - unsigned next_off : 16; - unsigned cw_index : 15; + unsigned next_off : NEXT_OFF_MAX_BITS; + unsigned cw_index : CW_INDEX_MAX_BITS; unsigned flag : 1; #endif } off_chain; @@ -308,13 +318,34 @@ typedef struct tp_region_struct for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh) \ { \ gvnh->clue.end = 0; \ - assert((NULL != gvnh->gd_csa) || (reorg_gv_target == gvnh)); \ if (gvnh->gd_csa && (gvnh != gvnh->gd_csa->dir_tree)) \ + { \ + assert ((DIR_ROOT != gvnh->root) || (gvnh == reorg_gv_target)); \ gvnh->root = 0; \ + } \ /* Cleanup any block-split info (of created block #) in gvtarget histories */ \ TP_CLEANUP_GVNH_SPLIT_IF_NEEDED(gvnh, 0); \ } \ } +# define RESET_ALL_GVT_CLUES_REG(CSA) \ +{ \ + GBLREF gv_namehead *gv_target_list; \ + GBLREF gv_namehead *reorg_gv_target; \ + \ + gv_namehead *gvnh; \ + \ + assert(NULL != CSA); \ + for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh) \ + { \ + if (CSA == gvnh->gd_csa) \ + { /* Only reset info for globals in CSA. */ \ + gvnh->clue.end = 0; \ + if (gvnh != gvnh->gd_csa->dir_tree) \ + gvnh->root = 0; \ + TP_CLEANUP_GVNH_SPLIT_IF_NEEDED(gvnh, 0); \ + } \ + } \ +} #endif typedef struct ua_list_struct @@ -343,8 +374,8 @@ GBLREF int4 tp_fail_n; GBLREF int4 tp_fail_level; GBLREF trans_num tp_fail_histtn[], tp_fail_bttn[]; -#ifdef ENABLE_EXTENDED_RESTART_TRACE_HIST - +#define TRANS_RESTART_HIST_ARRAY_SZ 512 /* See comment (6) in gtm_threadgbl_defs.h as to why this is not inside #ifdef DEBUG */ +#ifdef DEBUG /* The following structure stores information pertaining to the most recent invocation of t_retry OR tp_restart. Maintain a 512 * element array per-process to track the recent t_retry and tp_restart invocations. Instead of keeping track of dollar_tlevel, * keep track of the current csa which is always Non-NULL for Non-TP. For TP, csa can be NULL but store it as NULL in the history @@ -353,6 +384,7 @@ GBLREF trans_num tp_fail_histtn[], tp_fail_bttn[]; typedef struct trans_restart_hist_struct { uint4 t_tries; + uint4 dollar_tlevel; enum cdb_sc retry_code; caddr_t call_from; union @@ -363,8 +395,6 @@ typedef struct trans_restart_hist_struct sgmnt_addrs *csa; /* NULL if TP, Non-NULL if Non-TP */ } trans_restart_hist_t; -# define TRANS_RESTART_HIST_ARRAY_SZ 512 - # define TRACE_TRANS_RESTART(RETRY_CODE) \ { \ GBLREF jnlpool_addrs jnlpool; \ @@ -381,6 +411,7 @@ typedef struct trans_restart_hist_struct curidx = TREF(trans_restart_hist_index) = 0; \ this_restart_hist = (TADR(trans_restart_hist_array) + curidx); \ this_restart_hist->t_tries = t_tries; \ + this_restart_hist->dollar_tlevel = dollar_tlevel; \ this_restart_hist->retry_code = RETRY_CODE; \ this_restart_hist->call_from = (caddr_t)caller_id(); \ if (NULL != jnlpool.jnlpool_ctl) \ @@ -391,7 +422,7 @@ typedef struct trans_restart_hist_struct } #else # define TRACE_TRANS_RESTART(RETRY_CODE) -#endif +#endif /* DEBUG */ #define TP_TRACE_HIST(X, Y) \ { \ @@ -406,7 +437,7 @@ typedef struct trans_restart_hist_struct } \ } -#define TP_TRACE_HIST_MOD(X, Y, n, csd, histtn, bttn, level) \ +#define TP_TRACE_HIST_MOD(X, Y, N, CSD, HISTTN, BTTN, LEVEL) \ { \ DCL_THREADGBL_ACCESS; \ \ @@ -416,22 +447,22 @@ typedef struct trans_restart_hist_struct tp_fail_hist_reg[t_tries] = gv_cur_region; \ t_fail_hist_blk[t_tries] = ((block_id)X); \ tp_fail_hist[t_tries] = (gv_namehead *)(((int)X & ~(-BLKS_PER_LMAP)) ? Y : NULL); \ - (csd)->tp_cdb_sc_blkmod[(n)]++; \ - tp_fail_n = (n); \ - tp_fail_level = (level); \ - tp_fail_histtn[t_tries] = (histtn); \ - tp_fail_bttn[t_tries] = (bttn); \ + (CSD)->tp_cdb_sc_blkmod[(N)]++; \ + tp_fail_n = (N); \ + tp_fail_level = (LEVEL); \ + tp_fail_histtn[t_tries] = (HISTTN); \ + tp_fail_bttn[t_tries] = (BTTN); \ } \ } -#define ASSERT_IS_WITHIN_TP_HIST_ARRAY_BOUNDS(first_tp_srch_status, sgm_info_ptr) \ +#define ASSERT_IS_WITHIN_TP_HIST_ARRAY_BOUNDS(FIRST_TP_SRCH_STATUS, SGM_INFO_PTR) \ { \ - assert(NULL == (first_tp_srch_status) \ - || ((first_tp_srch_status) >= (sgm_info_ptr)->first_tp_hist \ - && (first_tp_srch_status) < (sgm_info_ptr)->last_tp_hist)); \ + assert(NULL == (FIRST_TP_SRCH_STATUS) \ + || ((FIRST_TP_SRCH_STATUS) >= (SGM_INFO_PTR)->first_tp_hist \ + && (FIRST_TP_SRCH_STATUS) < (SGM_INFO_PTR)->last_tp_hist)); \ } -#define SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, status) \ +#define SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(CSA, CNL, STATUS) \ { /* set wc_blocked if final retry and cache related failure status */ \ if (CDB_STAGNATE <= t_tries) \ { \ @@ -439,67 +470,50 @@ typedef struct trans_restart_hist_struct GBLREF boolean_t is_lchar_wcs_code[]; \ boolean_t is_wcs_code = FALSE; \ \ - if (ISALPHA_ASCII(status)) \ - { \ - if (status > 'Z') \ - is_wcs_code = is_lchar_wcs_code[status - 'a']; \ - else \ - is_wcs_code = is_uchar_wcs_code[status - 'A']; \ - } \ + if (ISALPHA_ASCII(STATUS)) \ + is_wcs_code = (STATUS > 'Z') \ + ? is_lchar_wcs_code[STATUS - 'a'] \ + : is_uchar_wcs_code[STATUS - 'A']; \ if (is_wcs_code) \ { \ - SET_TRACEABLE_VAR(csa->hdr->wc_blocked, TRUE); \ - BG_TRACE_PRO_ANY(csa, wc_blocked_wcs_cdb_sc_final_retry); \ + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); \ + BG_TRACE_PRO_ANY(CSA, wc_blocked_wcs_cdb_sc_final_retry); \ } \ } \ } -#define TP_RETRY_ACCOUNTING(csa, cnl, status) \ +#define TP_RETRY_ACCOUNTING(CSA, CNL) \ { \ GBLREF uint4 dollar_trestart; \ \ switch (dollar_trestart) \ { \ case 0: \ - INCR_GVSTATS_COUNTER(csa, cnl, n_tp_cnflct_retries_0, 1); \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_tp_cnflct_retries_0, 1); \ break; \ case 1: \ - INCR_GVSTATS_COUNTER(csa, cnl, n_tp_cnflct_retries_1, 1); \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_tp_cnflct_retries_1, 1); \ break; \ case 2: \ - INCR_GVSTATS_COUNTER(csa, cnl, n_tp_cnflct_retries_2, 1); \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_tp_cnflct_retries_2, 1); \ break; \ case 3: \ - INCR_GVSTATS_COUNTER(csa, cnl, n_tp_cnflct_retries_3, 1); \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_tp_cnflct_retries_3, 1); \ break; \ default: \ - INCR_GVSTATS_COUNTER(csa, cnl, n_tp_cnflct_retries_4, 1); \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_tp_cnflct_retries_4, 1); \ break; \ } \ } #define PREV_OFF_INVALID -1 -/* JNL_FILE_TAIL_PRESERVE macro indicates maximum number of bytes to ensure allocated at the end of the journal file - * to store the journal records that will be written whenever the journal file gets closed. - * (i) Any process closing the journal file needs to write at most one PINI, one EPOCH, one PFIN and one EOF record - * In case of wcs_recover extra INCTN will be written - * (ii) We may need to give room for twice the above space to accommodate the EOF writing by a process that closes the journal - * and the EOF writing by the first process that reopens it and finds no space left and switches to a new journal. - * (iii) We may need to write one ALIGN record at the most since the total calculated from (i) and (ii) above is - * less than the minimum alignsize that we support (asserted before using JNL_FILE_TAIL_PRESERVE in macros below) - * The variable portion of this ALIGN record can get at the most equal to the maximum of the sizes of the - * PINI/EPOCH/PFIN/EOF record. (We know PINI_RECLEN is maximum of EPOCH_RECLEN, PFIN_RECLEN, EOF_RECLEN) - */ -#define JNL_FILE_TAIL_PRESERVE (MIN_ALIGN_RECLEN + (PINI_RECLEN + EPOCH_RECLEN + INCTN_RECLEN + \ - PFIN_RECLEN + EOF_RECLEN) * 2 + PINI_RECLEN) - -#define TOTAL_TPJNL_REC_SIZE(total_jnl_rec_size, si, csa) \ +#define TOTAL_TPJNL_REC_SIZE(TOTAL_JNL_REC_SIZE, SI, CSA) \ { \ - DEBUG_ONLY(si->tmp_cw_set_depth = si->cw_set_depth;) /* save a copy to check later in "tp_tend" */ \ - total_jnl_rec_size = si->total_jnl_rec_size; \ - if (csa->jnl_before_image) \ - total_jnl_rec_size += (si->cw_set_depth * csa->pblk_align_jrecsize); \ + DEBUG_ONLY(SI->tmp_cw_set_depth = SI->cw_set_depth;) /* save a copy to check later in "tp_tend" */ \ + TOTAL_JNL_REC_SIZE = SI->total_jnl_rec_size; \ + if (CSA->jnl_before_image) \ + TOTAL_JNL_REC_SIZE += (SI->cw_set_depth * CSA->pblk_align_jrecsize); \ /* Since we have already taken into account an align record per journal record and since the size of \ * an align record will be < (size of the journal record written + fixed-size of align record) \ * we can be sure we won't need more than twice the computed space. \ @@ -507,7 +521,7 @@ typedef struct trans_restart_hist_struct * in case journal file close is needed \ */ \ assert(JNL_FILE_TAIL_PRESERVE < (JNL_MIN_ALIGNSIZE * DISK_BLOCK_SIZE)); \ - si->total_jnl_rec_size = total_jnl_rec_size = (total_jnl_rec_size * 2) + (uint4)JNL_FILE_TAIL_PRESERVE; \ + SI->total_jnl_rec_size = TOTAL_JNL_REC_SIZE = (TOTAL_JNL_REC_SIZE * 2) + (uint4)JNL_FILE_TAIL_PRESERVE; \ } #define MIN_TOTAL_NONTPJNL_REC_SIZE (PINI_RECLEN + MIN_ALIGN_RECLEN + INCTN_RECLEN + MIN_ALIGN_RECLEN) @@ -515,14 +529,14 @@ typedef struct trans_restart_hist_struct /* This macro gives a pessimistic estimate on the total journal record size needed. * The side effect is that we might end up with a journal file extension when it was actually not needed. */ -#define TOTAL_NONTPJNL_REC_SIZE(total_jnl_rec_size, non_tp_jfb_ptr, csa, tmp_cw_set_depth) \ +#define TOTAL_NONTPJNL_REC_SIZE(TOTAL_JNL_REC_SIZE, NON_TP_JFB_PTR, CSA, TMP_CW_SET_DEPTH) \ { \ - total_jnl_rec_size = (non_tp_jfb_ptr->record_size + (uint4)MIN_TOTAL_NONTPJNL_REC_SIZE); \ - if (csa->jnl_before_image) \ + TOTAL_JNL_REC_SIZE = (NON_TP_JFB_PTR->record_size + (uint4)MIN_TOTAL_NONTPJNL_REC_SIZE); \ + if (CSA->jnl_before_image) \ /* One PBLK record for each gds block changed by the transaction */ \ - total_jnl_rec_size += (tmp_cw_set_depth * csa->pblk_align_jrecsize); \ + TOTAL_JNL_REC_SIZE += (TMP_CW_SET_DEPTH * CSA->pblk_align_jrecsize); \ if (write_after_image) \ - total_jnl_rec_size += (uint4)MIN_AIMG_RECLEN + csa->hdr->blk_size + (uint4)MIN_ALIGN_RECLEN; \ + TOTAL_JNL_REC_SIZE += (uint4)MIN_AIMG_RECLEN + CSA->hdr->blk_size + (uint4)MIN_ALIGN_RECLEN; \ /* Since we have already taken into account an align record per journal record and since the size of \ * an align record will be < (size of the journal record written + fixed-size of align record) \ * we can be sure we won't need more than twice the computed space. \ @@ -530,29 +544,29 @@ typedef struct trans_restart_hist_struct * in case journal file close is needed \ */ \ assert(JNL_FILE_TAIL_PRESERVE < (JNL_MIN_ALIGNSIZE * DISK_BLOCK_SIZE)); \ - total_jnl_rec_size = total_jnl_rec_size * 2 + (uint4)JNL_FILE_TAIL_PRESERVE; \ + TOTAL_JNL_REC_SIZE = TOTAL_JNL_REC_SIZE * 2 + (uint4)JNL_FILE_TAIL_PRESERVE; \ } -#define INVALIDATE_CLUE(cse) \ +#define INVALIDATE_CLUE(CSE) \ { \ off_chain macro_chain; \ \ - assert(cse->blk_target); \ - cse->blk_target->clue.end = 0; \ - macro_chain = *(off_chain *)&cse->blk_target->root; \ + assert(CSE->blk_target); \ + CSE->blk_target->clue.end = 0; \ + macro_chain = *(off_chain *)&CSE->blk_target->root; \ if (macro_chain.flag) \ - cse->blk_target->root = 0; \ + CSE->blk_target->root = 0; \ } /* freeup killset starting from the link 'ks' */ -#define FREE_KILL_SET(si, ks) \ +#define FREE_KILL_SET(KS) \ { \ kill_set *macro_next_ks; \ - for (; ks; ks = macro_next_ks) \ + for (; KS; KS = macro_next_ks) \ { \ - macro_next_ks = ks->next_kill_set; \ - free(ks); \ + macro_next_ks = KS->next_kill_set; \ + free(KS); \ } \ } @@ -631,17 +645,18 @@ typedef struct trans_restart_hist_struct /* freeup gbl_tlvl_info_list starting from the link 'gti' */ -#define FREE_GBL_TLVL_INFO(gti) \ +#define FREE_GBL_TLVL_INFO(GTI) \ { \ int macro_cnt; \ - for (macro_cnt = 0; gti; gti = gti->next_global_tlvl_info) \ + \ + for (macro_cnt = 0; GTI; GTI = GTI->next_global_tlvl_info) \ macro_cnt++; \ if (macro_cnt) \ free_last_n_elements(global_tlvl_info_list, macro_cnt); \ } #ifdef GTM_TRIGGER -#define INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(INCREMENTAL, COMMIT) \ +#define TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(INCREMENTAL, COMMIT) \ { \ GBLREF boolean_t dollar_ztrigger_invoked; \ GBLREF trans_num local_tn; \ @@ -652,7 +667,11 @@ typedef struct trans_restart_hist_struct cw_set_element *cse; \ sgmnt_addrs *csa; \ sgm_info *si; \ + gvt_trigger_t *gvt_trigger; \ + DEBUG_ONLY(boolean_t matched_one_gvnh;) \ + DCL_THREADGBL_ACCESS; \ \ + SETUP_THREADGBL_ACCESS; \ if (dollar_ztrigger_invoked) \ { /* There was at least one region where a $ZTRIGGER() was invoked. */ \ dollar_ztrigger_invoked = FALSE; \ @@ -674,23 +693,23 @@ typedef struct trans_restart_hist_struct { \ /* Now that the transaction is rolled back/restarted, invalidate gvt->gvt_trigger->gv_trigger_cycle \ * (by resetting it to zero) for all gvt read/updated in this transaction. Note that even though we \ - * reset db_trigger_cycle (to -1) for non-incremental rollbacks/restarts and increment db_dztrigger_cycle\ + * reset db_trigger_cycle for non-incremental rollbacks/restarts and increment db_dztrigger_cycle \ * for incremental rollbacks we still need to reset gv_trigger_cycle as otherwise gvtr_init will find \ - * that gv_trigger_cycle has NOT changed since it was updated last and will NOT do any trigger reads \ + * that gv_trigger_cycle has NOT changed since it was updated last and will NOT do any trigger reads. \ */ \ for (gvnh = gvt_tp_list; NULL != gvnh; gvnh = gvnh->next_tp_gvnh) \ { \ assert(gvnh->read_local_tn == local_tn); \ - if (NULL != gvnh->gvt_trigger) \ - ((gvt_trigger_t *)(gvnh->gvt_trigger))->gv_trigger_cycle = 0; \ + if (NULL != (gvt_trigger = gvnh->gvt_trigger)) \ + gvt_trigger->gv_trigger_cycle = 0; \ if (!INCREMENTAL) \ { /* 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-read triggers \ + * 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. \ */ \ gvnh->db_dztrigger_cycle = 0; \ - gvnh->db_trigger_cycle = (uint4)-1; \ + gvnh->db_trigger_cycle = 0; \ } \ } \ } \ @@ -719,9 +738,7 @@ typedef struct trans_restart_hist_struct if (NULL != cse) \ csa->incr_db_trigger_cycle = FALSE; \ } else \ - { \ assert(!csa->incr_db_trigger_cycle); \ - } \ if (csa->db_dztrigger_cycle) \ csa->db_dztrigger_cycle++; /* so that future updates in this TN re-read triggers */ \ } \ @@ -741,9 +758,39 @@ typedef struct trans_restart_hist_struct } \ } \ } \ + /* If gvt_triggers_read_this_tn is TRUE and INCREMENTAL is TRUE, we are in an incremental commit or rollback. \ + * In either case, we dont need to worry about resetting gv_target's trigger cycles as we will do this when the \ + * outermost commit or rollback (or a restart) occurs. The key is that even if a gv_target gets used in a nested \ + * tstart/tcommit that gets incrementally rolled back, it is still part of the gvt_tp_list and hence we can wait \ + * to clean the cycle fields at restart/commit/non-incremental-rollback time. In case of a commit, no need to reset \ + * the gv_trigger_cycle, db_dztrigger_cycle and db_trigger_cycle fields of gvnh as those are valid going forward. \ + */ \ + if (TREF(gvt_triggers_read_this_tn) && !INCREMENTAL) \ + { \ + if (!COMMIT) \ + { /* There was at least one GVT where ^#t records were read and this is a complete \ + * (i.e. non-incremental) transaction restart or rollback. In this case, reset cycle fields \ + * in corresponding gv_target to force re-reads of ^#t records of this gvt (if any) in next retry. \ + */ \ + DEBUG_ONLY(matched_one_gvnh = TRUE;) \ + for (gvnh = gvt_tp_list; NULL != gvnh; gvnh = gvnh->next_tp_gvnh) \ + { \ + assert(gvnh->read_local_tn == local_tn); \ + if (gvnh->trig_read_tn != local_tn) \ + continue; \ + DEBUG_ONLY(matched_one_gvnh = FALSE;) \ + if (NULL != (gvt_trigger = gvnh->gvt_trigger)) \ + gvt_trigger->gv_trigger_cycle = 0; \ + gvnh->db_dztrigger_cycle = 0; \ + gvnh->db_trigger_cycle = 0; \ + } \ + assert(!matched_one_gvnh); /* we expect at least one gvnh with trig_read_tn == local_tn */ \ + } \ + TREF(gvt_triggers_read_this_tn) = FALSE; \ + } \ } # ifdef DEBUG -# define ASSERT_ZTRIGGER_CYCLE_RESET \ +# 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 \ @@ -757,9 +804,9 @@ typedef struct trans_restart_hist_struct assert(0 == si->tp_csa->db_dztrigger_cycle); \ } # else -# define ASSERT_ZTRIGGER_CYCLE_RESET -# endif -#endif +# define TP_ASSERT_ZTRIGGER_CYCLE_RESET +# endif /* #ifdef DEBUG */ +#endif /* #ifdef GTM_TRIGGER */ #ifdef VMS /* The error below has special handling in a few condition handlers because it not so much signals an error @@ -769,9 +816,9 @@ typedef struct trans_restart_hist_struct code in mdb_condition_handler). The number of extra parameters need to be 2 more than the largest number of parameters for an rts_error in tp_restart(). */ -#define INVOKE_RESTART rts_error(VARLSTCNT(6) ERR_TPRETRY, 4, 0, 0, 0, 0, 0, 0, 0, 0); +#define INVOKE_RESTART rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TPRETRY, 4, 0, 0, 0, 0, 0, 0, 0, 0); #else -#define INVOKE_RESTART rts_error(VARLSTCNT(1) ERR_TPRETRY); +#define INVOKE_RESTART rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TPRETRY); #endif /* the following macros T_BEGIN_READ_NONTP_OR_TP and T_BEGIN_SETORKILL_NONTP_OR_TP are similar except for one difference @@ -780,35 +827,35 @@ typedef struct trans_restart_hist_struct * otherwise been had the two macros been merged and this is used in database code where performance is a concern. */ /* the macro below uses "dollar_tlevel", "t_err" and "sgm_info_ptr" */ -#define T_BEGIN_SETORKILL_NONTP_OR_TP(err_code) \ +#define T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_CODE) \ { \ GBLREF sgm_info *sgm_info_ptr; \ GBLREF sgmnt_addrs *cs_addrs; \ GBLREF uint4 t_err; \ \ if (!dollar_tlevel) \ - t_begin(err_code, UPDTRNS_DB_UPDATED_MASK); \ + t_begin(ERR_CODE, UPDTRNS_DB_UPDATED_MASK); \ else \ { \ - t_err = err_code; \ + t_err = ERR_CODE; \ assert((NULL != sgm_info_ptr) && (cs_addrs->sgm_info_ptr == sgm_info_ptr)); \ sgm_info_ptr->update_trans |= UPDTRNS_DB_UPDATED_MASK; \ } \ } /* the macro below uses "dollar_tlevel", "t_err" */ -#define T_BEGIN_READ_NONTP_OR_TP(err_code) \ +#define T_BEGIN_READ_NONTP_OR_TP(ERR_CODE) \ { \ GBLREF uint4 t_err; \ GBLREF sgm_info *sgm_info_ptr; \ GBLREF sgmnt_addrs *cs_addrs; \ \ if (!dollar_tlevel) \ - t_begin(err_code, 0); \ + t_begin(ERR_CODE, 0); \ else \ { \ assert((NULL != sgm_info_ptr) && (cs_addrs->sgm_info_ptr == sgm_info_ptr)); \ - t_err = err_code; \ + t_err = ERR_CODE; \ } \ } @@ -844,32 +891,47 @@ GBLREF unsigned int t_tries; \ assert(dollar_tlevel); \ assert(CDB_STAGNATE == t_tries); \ - /* In case of journal recovery, it operates at t_tries=CDB_STAGNATE but we should not adjust t_tries \ - * in that case and it is ok to not print the TPNOTACID message in that case. Since we have standalone \ - * access, we dont expect anyone else to interfere with us and cause a restart anyways. \ + /* mupip_jnl_recovery operates with t_tries=CDB_STAGNATE so we should not adjust t_tries \ + * In that case, because we have standalone access, we dont expect anyone else to interfere with us \ + * and cause a restart, but if they do, TPNOTACID_CHECK (below) gives a TPNOTACID message. \ */ \ if (!mupip_jnl_recover) \ + { \ + assert(CDB_STAGNATE <= dollar_trestart); \ + assert(dollar_trestart >= TREF(tp_restart_dont_counts)); \ t_tries = CDB_STAGNATE - 1; \ + DEBUG_ONLY(if (0 == TREF(tp_restart_dont_counts))) \ + DEBUG_ONLY((TREF(tp_restart_dont_counts))++); /* can live with one too many */ \ + DEBUG_ONLY(if (0 < TREF(tp_restart_dont_counts))) \ + DEBUG_ONLY((TREF(tp_restart_dont_counts)) = -(TREF(tp_restart_dont_counts))); \ + } \ } +#define TPNOTACID_DEFAULT_TIME 2 /* default (in seconds)for tpnotacidtime */ +#define TPNOTACID_MAX_TIME 30 /* maximum (in seconds)for tpnotacidtime */ +#define TPTIMEOUT_MAX_TIME 60 /* maximum (inseconds) for dollar_zmaxtptime - enforced in gtm_env_init, not in op_svput */ + #define TPNOTACID_CHECK(CALLER_STR) \ { \ + GBLREF boolean_t mupip_jnl_recover; \ mval zpos; \ \ if (IS_TP_AND_FINAL_RETRY) \ { \ TP_REL_CRIT_ALL_REG; \ + assert(!mupip_jnl_recover); \ TP_FINAL_RETRY_DECREMENT_T_TRIES_IF_OK; \ getzposition(&zpos); \ - gtm_putmsg(VARLSTCNT(6) ERR_TPNOTACID, 4, LEN_AND_LIT(CALLER_STR), zpos.str.len, zpos.str.addr); \ - send_msg(VARLSTCNT(6) ERR_TPNOTACID, 4, LEN_AND_LIT(CALLER_STR), zpos.str.len, zpos.str.addr); \ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TPNOTACID, 4, LEN_AND_LIT(CALLER_STR), zpos.str.len, \ + zpos.str.addr); \ } \ } /* Any retry transition where the destination state is the 3rd retry, we don't want to release crit, i.e. for 2nd to 3rd retry * transition or 3rd to 3rd retry transition. Therefore we need to release crit only if (CDB_STAGNATE - 1) > t_tries. */ -#define NEED_TO_RELEASE_CRIT(T_TRIES) ((CDB_STAGNATE - 1) > T_TRIES) +#define NEED_TO_RELEASE_CRIT(T_TRIES, STATUS) (((CDB_STAGNATE - 1) > T_TRIES) \ + UNIX_ONLY(|| cdb_sc_instancefreeze == STATUS)) void tp_get_cw(cw_set_element *cs, int depth, cw_set_element **cs1); void tp_clean_up(boolean_t rollback_flag); diff --git a/sr_port/tp_clean_up.c b/sr_port/tp_clean_up.c index 7581ae7..140aae5 100644 --- a/sr_port/tp_clean_up.c +++ b/sr_port/tp_clean_up.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,27 +33,28 @@ #include "have_crit.h" #include "min_max.h" #ifdef GTM_TRIGGER -#include "rtnhdr.h" -#include "gv_trigger.h" /* for INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */ +#include +#include "gv_trigger.h" /* for TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */ #endif -GBLREF jnl_fence_control jnl_fence_ctl; -GBLREF sgm_info *sgm_info_ptr, *first_sgm_info; -GBLREF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */ -GBLREF ua_list *curr_ua, *first_ua; -GBLREF char *update_array, *update_array_ptr; -GBLREF block_id tp_allocation_clue; -GBLREF uint4 update_array_size, cumul_update_array_size; -GBLREF gd_region *gv_cur_region; -GBLREF sgmnt_addrs *cs_addrs; -GBLREF gv_namehead *gv_target_list, *gvt_tp_list; -GBLREF trans_num local_tn; GBLREF sgmnt_data_ptr_t cs_data; -GBLREF buddy_list *global_tlvl_info_list; -GBLREF global_tlvl_info *global_tlvl_info_head; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF ua_list *curr_ua, *first_ua; +GBLREF uint4 dollar_trestart; +GBLREF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */ GBLREF jnl_gbls_t jgbl; -GBLREF int process_exiting; +GBLREF jnl_fence_control jnl_fence_ctl; +GBLREF trans_num local_tn; +GBLREF global_tlvl_info *global_tlvl_info_head; +GBLREF buddy_list *global_tlvl_info_list; GBLREF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */ +GBLREF gd_region *gv_cur_region; +GBLREF gv_namehead *gv_target_list, *gvt_tp_list; +GBLREF sgm_info *sgm_info_ptr, *first_sgm_info; +GBLREF int process_exiting; +GBLREF block_id tp_allocation_clue; +GBLREF char *update_array, *update_array_ptr; +GBLREF uint4 update_array_size, cumul_update_array_size; #ifdef VMS GBLREF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */ #endif @@ -160,7 +161,7 @@ void tp_clean_up(boolean_t rollback_flag) /* Cleanup any block-split info (of created block #) in gvtarget histories */ TP_CLEANUP_GVNH_SPLIT_IF_NEEDED(gvnh, 0); } - GTMTRIG_ONLY(INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(FALSE, FALSE)); + GTMTRIG_ONLY(TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(FALSE, FALSE)); # ifdef DEBUG if (!process_exiting) { /* Ensure that we did not miss out on resetting clue for any gvtarget. @@ -179,11 +180,17 @@ void tp_clean_up(boolean_t rollback_flag) } # endif local_tn++; /* to effectively invalidate first_tp_srch_status of all gv_targets */ + tp_allocation_clue = gtm_tp_allocation_clue; /* Reset clue to what it was at beginning of transaction */ } else { - GTMTRIG_ONLY(INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(FALSE, TRUE)); + GTMTRIG_ONLY(TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(FALSE, TRUE)); + gtm_tp_allocation_clue = tp_allocation_clue; /* Update tp allocation clue for next transaction to skip + * past values used in this transaction now that this one + * is successfully committed. + */ } - GTMTRIG_ONLY(ASSERT_ZTRIGGER_CYCLE_RESET;) /* for all regions, we better have csa->db_dztrigger_cycle = 0*/ + 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*/ for (si = first_sgm_info; si != NULL; si = next_si) { TP_TEND_CHANGE_REG(si); @@ -192,7 +199,7 @@ void tp_clean_up(boolean_t rollback_flag) { if (NULL != (ks = si->kill_set_head)) { - FREE_KILL_SET(si, ks); + FREE_KILL_SET(ks); si->kill_set_tail = NULL; si->kill_set_head = NULL; } @@ -287,7 +294,7 @@ void tp_clean_up(boolean_t rollback_flag) } } else { - t1->buffaddr = cs_addrs->acc_meth.mm.base_addr + t1->buffaddr = MM_BASE_ADDR(cs_addrs) + (sm_off_t)cs_data->blk_size * cseblk; assert(NULL == t1->cr); } @@ -304,8 +311,7 @@ void tp_clean_up(boolean_t rollback_flag) blk_target->root = cseblk; t1->blk_num = cseblk; if (is_mm) - t1->buffaddr = - cs_addrs->acc_meth.mm.base_addr + t1->buffaddr = MM_BASE_ADDR(cs_addrs) + (sm_off_t)cs_data->blk_size * cseblk; else { @@ -389,7 +395,7 @@ void tp_clean_up(boolean_t rollback_flag) { /* check that gv_target->root falls within total blocks range */ csa = gvnh->gd_csa; assert(NULL != csa); - assert(gvnh->root < csa->ti->total_blks); + NON_GTM_TRUNCATE_ONLY(assert(gvnh->root < csa->ti->total_blks)); assert(!IS_BITMAP_BLK(gvnh->root)); } if (gvnh->clue.end) @@ -423,7 +429,6 @@ void tp_clean_up(boolean_t rollback_flag) CWS_RESET; /* reinitialize the hashtable before restarting/committing the TP transaction */ } /* if (any database work in the transaction) */ VMS_ONLY(tp_has_kill_t_cse = FALSE;) - tp_allocation_clue = gtm_tp_allocation_clue + 1; 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 diff --git a/sr_port/tp_cw_list.c b/sr_port/tp_cw_list.c index 7122257..26985c6 100644 --- a/sr_port/tp_cw_list.c +++ b/sr_port/tp_cw_list.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,23 +32,26 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF boolean_t is_updproc; GBLREF boolean_t mupip_jnl_recover; +error_def(ERR_TRANS2BIG); + void tp_cw_list(cw_set_element **cs) { - cw_set_element *last_cse, *tempcs, *prev_last; - - error_def(ERR_TRANS2BIG); + cw_set_element *last_cse, *tempcs, *prev_last; + boolean_t is_bg; + sgmnt_data_ptr_t csd; /* Don't allow a single transaction to use more cw_set_elements than half of the global buffers or - * more than 32K cw_set_elements. This because the "cw_index" field in "off_chain" structure is 15-bits. + * more than 32K cw_set_elements. This because the "cw_index" field in "off_chain" structure is CW_INDEX_MAX_BITS-bits. */ - if (dba_bg == cs_addrs->hdr->acc_meth) - if (sgm_info_ptr->cw_set_depth + 2 >= (cs_addrs->hdr->n_bts >> 1) || - sgm_info_ptr->cw_set_depth + 2 > (32 * 1024)) - { /* catch the case where MUPIP recover or update process gets into this situation */ - assert(!mupip_jnl_recover && !is_updproc); - rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region)); - } - + csd = cs_addrs->hdr; + is_bg = (dba_bg == csd->acc_meth); + assert(is_bg || (dba_mm == csd->acc_meth)); + if ((sgm_info_ptr->cw_set_depth + 2 > (1 << CW_INDEX_MAX_BITS)) + || (is_bg && ((sgm_info_ptr->cw_set_depth + 2) >= (csd->n_bts >> 1)))) + { /* catch the case where MUPIP recover or update process gets into this situation */ + assert(!mupip_jnl_recover && !is_updproc); + rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region)); + } tempcs = (cw_set_element *)get_new_element(sgm_info_ptr->cw_set_list, 1); /* secshr_db_clnup relies on the cw_set_element (specifically the "mode" field) being initialized to a value * that is not "gds_t_committed". This needs to be done before setting sgm_info_ptr->first_cw_set. */ diff --git a/sr_port/tp_hist.c b/sr_port/tp_hist.c index 29f9c5d..963118e 100644 --- a/sr_port/tp_hist.c +++ b/sr_port/tp_hist.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,12 +35,8 @@ #ifdef UNIX #include "repl_msg.h" /* needed for gtmsource.h */ #include "gtmsource.h" /* needed for SYNC_ONLN_RLBK_CYCLES */ -#include "tp_grab_crit.h" #endif -#define MMBLK_OFFSET(BLK) \ - (cs_addrs->db_addrs[0] + (cs_addrs->hdr->start_vbn - 1) * DISK_BLOCK_SIZE + (off_t)(cs_addrs->hdr->blk_size * (BLK))) - #define REPOSITION_PTR(ptr, type, delta, begin, end) \ { \ assert((sm_uc_ptr_t)(ptr) >= (sm_uc_ptr_t)(begin)); \ @@ -190,13 +186,13 @@ enum cdb_sc tp_hist(srch_hist *hist1) /* Assert that cr->in_tend is never equal to our process_id since at this point we should * never have locked a buffer for phase2 commit. The only exception is if the previous * transaction by this process had a commit-time error and secshr_db_clnup finished the - * transaction and had set csd->wc_blocked to TRUE. It is possible in that case no process + * transaction and had set csa->nl->wc_blocked to TRUE. It is possible in that case no process * has yet done a cache-recovery by the time we come to tp_hist as part of the next transaction * in which case cr->in_tend could still be pointing to our process_id. Note that - * csd->wc_blocked could be changing concurrently so need to note it down in a local variable - * BEFORE checking the value of cr->in_tend. + * csa->nl->wc_blocked could be changing concurrently so need to note it down in a local + * variable BEFORE checking the value of cr->in_tend. */ - DEBUG_ONLY(wc_blocked = cs_addrs->hdr->wc_blocked;) + DEBUG_ONLY(wc_blocked = cs_addrs->nl->wc_blocked;) assert((NULL == cr) || (process_id != cr->in_tend) || wc_blocked); if (TP_IS_CDB_SC_BLKMOD(cr, t2)) { @@ -268,31 +264,6 @@ enum cdb_sc tp_hist(srch_hist *hist1) # endif } } -# ifdef UNIX - if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) - { - status = cdb_sc_onln_rlbk1; - if (csa->db_onln_rlbkd_cycle != csa->nl->db_onln_rlbkd_cycle) - status = cdb_sc_onln_rlbk2; /* database taken back to a different logical state */ - /* We want to sync the online rollback cycles ONLY under crit. So, grab_crit and sync the - * cycles. While tp_grab_crit would have been a better choice, the reason we don't use - * tp_grab_crit here is because if we don't sync cycles because we don't hold crit but - * do invoke t_retry which increments $zonlnrlbk and on the subsequent retry we remain - * unlucky in getting crit, we will end up incrementing $zonlnrlbk more than once for a - * single online rollback event. In the worst case we will have $zonlnrlbk=3 which from - * the user perspective is incorrect. So, sync the cycles the first time we detect the - * online rollback - */ - assert(!csa->hold_onto_crit); - was_crit = csa->now_crit; - if (!was_crit) - grab_crit(gv_cur_region); - SYNC_ONLN_RLBK_CYCLES; - if (!was_crit) - rel_crit(gv_cur_region); - break; - } -# endif /* Although t1->first_tp_srch_status (i.e. t2) is used for doing blkmod check, * we need to use BOTH t1 and t1->first_tp_srch_status to do the cdb_sc_lostcr check. * @@ -316,7 +287,8 @@ enum cdb_sc tp_hist(srch_hist *hist1) if ((t1 != t2) && t1->cr) { assert(((sm_long_t)GDS_REL2ABS(t1->cr->buffaddr) == (sm_long_t)t1->buffaddr) - UNIX_ONLY(|| (0 != csa->nl->onln_rlbk_pid))); + UNIX_ONLY(|| (0 != csa->nl->onln_rlbk_pid) + || MISMATCH_ROOT_CYCLES(csa, csa->nl))); if (t1->cycle != t1->cr->cycle) { assert(CDB_STAGNATE > t_tries); @@ -328,7 +300,8 @@ enum cdb_sc tp_hist(srch_hist *hist1) if (cr) { assert(((sm_long_t)GDS_REL2ABS(cr->buffaddr) == (sm_long_t)t2->buffaddr) - UNIX_ONLY( || (0 != csa->nl->onln_rlbk_pid))); + UNIX_ONLY( || (0 != csa->nl->onln_rlbk_pid) + || MISMATCH_ROOT_CYCLES(csa, csa->nl))); if (t2->cycle != cr->cycle) { assert(CDB_STAGNATE > t_tries); @@ -369,7 +342,8 @@ enum cdb_sc tp_hist(srch_hist *hist1) delete_hashtab_int4(si->blks_in_use,(uint4 *)&blk); si->num_of_blks--; assert(si->num_of_blks == si->tp_hist_size); - rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRANS2BIG, 2, + REG_LEN_STR(gv_cur_region)); } /* Either history has a clue or not. * If yes, then it could have been constructed in an earlier @@ -458,7 +432,8 @@ enum cdb_sc tp_hist(srch_hist *hist1) for (t1 = hist->h; HIST_TERMINATOR != (blk = t1->blk_num); t1++) { t2 = t1->first_tp_srch_status ? t1->first_tp_srch_status : t1; - assert((t2->tn <= t1->tn) UNIX_ONLY(|| (0 != csa->nl->onln_rlbk_pid))); + assert((t2->tn <= t1->tn) UNIX_ONLY(|| (0 != csa->nl->onln_rlbk_pid) + || MISMATCH_ROOT_CYCLES(csa, csa->nl))); /* Take this time to also check that gv_targets match between t1 and t2. * If they dont, the restart should be detected in tp_tend. * Set the flag donot_commit to catch the case this does not restart. @@ -469,9 +444,38 @@ enum cdb_sc tp_hist(srch_hist *hist1) } # endif } +# ifdef UNIX + if (MISMATCH_ROOT_CYCLES(csa, csa->nl)) + { /* We want to sync the online rollback cycles ONLY under crit. So, grab_crit and sync the + * cycles. While grab_crit_immediate would have been a better choice, the reason we don't use + * grab_crit_immediate here is because if we don't sync cycles because we don't hold crit but + * do invoke t_retry which increments $zonlnrlbk and on the subsequent retry we remain + * unlucky in getting crit, we will end up incrementing $zonlnrlbk more than once for a + * single online rollback event. In the worst case we will have $zonlnrlbk=3 which from + * the user perspective is incorrect. So, sync the cycles the first time we detect the + * online rollback + */ + assert(!csa->hold_onto_crit); + was_crit = csa->now_crit; + if (!was_crit) + grab_crit(gv_cur_region); + status = cdb_sc_gvtrootmod2; + if (MISMATCH_ONLN_RLBK_CYCLES(csa, csa->nl)) + { + assert(!mupip_jnl_recover); + status = ONLN_RLBK_STATUS(csa, csa->nl); + SYNC_ONLN_RLBK_CYCLES; + SYNC_ROOT_CYCLES(NULL); + } else + SYNC_ROOT_CYCLES(csa); + if (!was_crit) + rel_crit(gv_cur_region); + } +# endif /* If validation has succeeded, assert that if gtm_gvundef_fatal is non-zero, then we better not signal a GVUNDEF */ assert((cdb_sc_normal != status) || !TREF(gtm_gvundef_fatal) || !ready2signal_gvundef_lcl); - ADD_TO_GVT_TP_LIST(gvt); /* updates gvt->read_local_tn & adds gvt to gvt_tp_list : both only if needed */ + ADD_TO_GVT_TP_LIST(gvt, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* updates gvt->read_local_tn & adds gvt to gvt_tp_list + * (all only if needed) */ CWS_RESET; return status; } diff --git a/sr_port/tp_incr_clean_up.c b/sr_port/tp_incr_clean_up.c index 70d9574..febf9d5 100644 --- a/sr_port/tp_incr_clean_up.c +++ b/sr_port/tp_incr_clean_up.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,8 +28,8 @@ #include "longset.h" /* also needed for cws_insert.h */ #include "cws_insert.h" /* for cw_stagnate_reinitialized */ #ifdef GTM_TRIGGER -#include "rtnhdr.h" -#include "gv_trigger.h" /* for INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */ +#include +#include "gv_trigger.h" /* for TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED macro */ #endif GBLREF sgm_info *first_sgm_info; @@ -203,9 +203,7 @@ void tp_incr_clean_up(uint4 newlevel) } DEBUG_ONLY(if (!si->update_trans) DBG_CHECK_SI_BUDDY_LIST_IS_REINITIALIZED(si);) } - GTMTRIG_ONLY( - INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(TRUE, FALSE); - ) + GTMTRIG_ONLY(TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(TRUE, FALSE);) /* After an incremental rollback, it is possible that some gv_targets now have a block-split history that reflects * a created block number that is no longer relevant due to the rollback. Fix those as needed. */ @@ -370,12 +368,12 @@ void rollbk_sgm_tlvl_info(uint4 newlevel, sgm_info *si) ks->used = tli->tlvl_kill_used; si->kill_set_tail = ks; temp_kill_set = ks->next_kill_set; - FREE_KILL_SET(si, temp_kill_set); + FREE_KILL_SET(temp_kill_set); ks->next_kill_set = NULL; } else { temp_kill_set = si->kill_set_head; - FREE_KILL_SET(si, temp_kill_set); + FREE_KILL_SET(temp_kill_set); si->kill_set_head = si->kill_set_tail = NULL; } FREE_JFB_INFO_IF_NEEDED(csa, si, tli, FALSE); @@ -411,7 +409,7 @@ void rollbk_sgm_tlvl_info(uint4 newlevel, sgm_info *si) { /* there was nothing at the beginning of transaction level (newlevel + 1) */ assert(tli == si->tlvl_info_head); temp_kill_set = si->kill_set_head; - FREE_KILL_SET(si, temp_kill_set); + FREE_KILL_SET(temp_kill_set); si->kill_set_head = si->kill_set_tail = NULL; FREE_JFB_INFO_IF_NEEDED(csa, si, tli, TRUE); reinitialize_hashtab_int4(si->blks_in_use); diff --git a/sr_port/tp_restart.c b/sr_port/tp_restart.c index 93767ab..140aad3 100644 --- a/sr_port/tp_restart.c +++ b/sr_port/tp_restart.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "error.h" #include "iosp.h" /* for declaration of SS_NORMAL */ #include "jnl.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "hashtab_int4.h" /* needed for tp.h */ @@ -55,11 +55,12 @@ #include "wbox_test_init.h" #include "gtmimagename.h" #include "have_crit.h" +#include "anticipatory_freeze.h" #ifdef GTM_TRIGGER #include "gv_trigger.h" #include "gtm_trigger.h" #endif -#ifdef ENABLE_EXTENDED_RESTART_TRACE_HIST +#ifdef DEBUG #include "caller_id.h" #endif @@ -95,6 +96,7 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data *cs_data; GBLREF symval *curr_symval; GBLREF trans_num tstart_local_tn; /* copy of global variable "local_tn" at op_tstart time */ +GBLREF boolean_t mupip_jnl_recover; #ifdef VMS GBLREF struct chf$signal_array *tp_restart_fail_sig; GBLREF boolean_t tp_restart_fail_sig_used; @@ -116,7 +118,6 @@ error_def(ERR_REPLONLNRLBK); #endif error_def(ERR_TLVLZERO); error_def(ERR_TPFAIL); -error_def(ERR_TPLOCKRESTMAX); error_def(ERR_TPRESTART); error_def(ERR_TPRETRY); error_def(ERR_TRESTLOC); @@ -155,7 +156,6 @@ CONDITION_HANDLER(tp_restart_ch) int tp_restart(int newlevel, boolean_t handle_errors_internally) { unsigned char *cp; - short top; unsigned int hist_index; tp_frame *tf; mv_stent *mvc; @@ -164,11 +164,11 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) sgmnt_addrs *csa; int4 num_closed = 0; boolean_t tp_tend_status; + boolean_t reset_clues_done = FALSE; mstr gvname_mstr, reg_mstr; gd_region *restart_reg, *reg; int tprestart_rc; enum cdb_sc status; - UNIX_ONLY(boolean_t issue_REPLONLNRLBK;) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -202,11 +202,6 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) rts_error(VARLSTCNT(1) ERR_TLVLZERO); return 0; /* for the compiler only -- never executed */ } -# ifdef DEBUG - if (TREF(tp_restart_dont_counts) >= dollar_trestart) - TREF(tp_restart_dont_counts) = dollar_trestart; -# endif - # ifdef GTM_TRIGGER DBGTRIGR((stderr, "tp_restart: Entry state: %d\n", tprestart_state)); if (TPRESTART_STATE_NORMAL == tprestart_state) @@ -245,11 +240,12 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) } } status = t_fail_hist[t_tries]; - /* The only reason online rollback ends up restarting is if some process set wc_blocked outside crit or the prior - * transaction had commit errors and secshr_db_clnup set wc_blocked to TRUE. But, that's possible only if white box - * test cases to induce Phase 1 and Phase 2 commit errors are set. So, assert accordingly + TREF(prev_t_tries) = t_tries; + /* Even though rollback and recover operate standalone, there are certain kind of restarts that can still happen due + * to white box test cases. Assert accordingly. */ - UNIX_ONLY(assert(!jgbl.onlnrlbk || WB_COMMIT_ERR_ENABLED)); + assert(!mupip_jnl_recover || WB_COMMIT_ERR_ENABLED || + (WBTEST_TP_HIST_CDB_SC_BLKMOD == gtm_white_box_test_case_number)); if (TREF(tprestart_syslog_delta) && (((TREF(tp_restart_count))++ < TREF(tprestart_syslog_limit)) || (0 == ((TREF(tp_restart_count) - TREF(tprestart_syslog_limit)) % TREF(tprestart_syslog_delta))))) { @@ -338,15 +334,17 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) assert(dba_mm == csa->hdr->acc_meth); wcs_recover(sgm_info_ptr->gv_cur_region); } - DEBUG_ONLY((TREF(tp_restart_dont_counts))++); if (CDB_STAGNATE > t_tries) { t_tries++; break; } +# ifdef DEBUG + if (0 <= TREF(tp_restart_dont_counts)) /* skip increment on negative from TPNOTACID */ + (TREF(tp_restart_dont_counts))++; +# endif /* WARNING - fallthrough !!! */ case cdb_sc_needcrit: - case cdb_sc_needlock: /* Here when a final (4th) attempt has failed with a need for crit in some routine. The * assumption is that the previous attempt failed somewhere before transaction end * therefore tp_reg_list did not have a complete list of regions necessary to complete the @@ -370,8 +368,8 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) } DEBUG_ONLY( /* The journal pool crit lock is currently obtained only inside commit logic at - * which point we will never signal a cdb_sc_needcrit or cdb_sc_needlock restart - * code. So no need to verify if we need to release crit there. Assert this though. + * which point we will never signal a cdb_sc_needcrit restart code. + * So no need to verify if we need to release crit there. Assert this though. */ if ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) { @@ -380,23 +378,6 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) } ) /* If retry due to M-locks, sleep so needed locks have a chance to get released */ - if (cdb_sc_needlock == status) - { /* Since we are in the final retry and holding crit on at least one database, we want - * to limit the # of times this transaction can restart due to a failed M-lock - * attempt as a restart entails wasted work while holding crit on the db and - * preventing others from accessing the same. - */ - if (TREF(tp_restart_needlock_tn) != tstart_local_tn) - { - TREF(tp_restart_needlock_cnt) = 0; /* Restart counting */ - TREF(tp_restart_needlock_tn) = tstart_local_tn; - } - (TREF(tp_restart_needlock_cnt))++; - assert(MAX_TP_FINAL_RETRY_MLOCKRESTART_CNT >= TREF(tp_restart_needlock_cnt)); - if (MAX_TP_FINAL_RETRY_MLOCKRESTART_CNT <= TREF(tp_restart_needlock_cnt)) - rts_error(VARLSTCNT(3) ERR_TPLOCKRESTMAX, 1, MAX_TP_FINAL_RETRY_MLOCKRESTART_CNT); - wcs_backoff(dollar_trestart * TP_DEADLOCK_FACTOR); - } break; /* Journaling might get turned off in the final retry INSIDE crit while trying to flush journal buffer or * during extending the journal file (due to possible disk issues) in which case we will come here with @@ -416,13 +397,22 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) */ case cdb_sc_onln_rlbk1: case cdb_sc_onln_rlbk2: + case cdb_sc_instancefreeze: + case cdb_sc_gvtrootmod2: # endif case cdb_sc_optrestart: if (CDB_STAGNATE <= t_tries) { t_tries--; - DEBUG_ONLY((TREF(tp_restart_dont_counts))++); +# ifdef DEBUG + if (0 <= TREF(tp_restart_dont_counts)) /* skip increment on negative from TPNOTACID */ + (TREF(tp_restart_dont_counts))++; +# endif } +# ifdef UNIX + if (cdb_sc_instancefreeze == status) + WAIT_FOR_REPL_INST_UNFREEZE_NOCSA; +# endif /* fall through */ default: if (CDB_STAGNATE < ++t_tries) @@ -497,7 +487,7 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) * unconditionally */ # ifdef UNIX - if (cs_addrs_list && (cs_addrs_list->onln_rlbk_cycle != cs_addrs_list->nl->onln_rlbk_cycle)) + if (cs_addrs_list && MISMATCH_ONLN_RLBK_CYCLES(cs_addrs_list, cs_addrs_list->nl)) { /* We came in to handle a different restart code in the penultimate retry and grab_crit before going * to final retry. As part of grabbing crit, we detected an online rollback. Although we could treat * this as just an online rollback restart and handle it by syncing cycles, but by doing so, we will @@ -511,6 +501,7 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) * proceeds smoothly in the final retry. */ RESET_ALL_GVT_CLUES; + reset_clues_done = TRUE; } # endif DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE); @@ -524,10 +515,19 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) TP_CHANGE_REG_IF_NEEDED(reg); MM_DBFILEXT_REMAP_IF_NEEDED(cs_addrs, gv_cur_region); } +# ifdef UNIX + csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs; + if (MISMATCH_ROOT_CYCLES(csa, csa->nl) && !reset_clues_done) + { + RESET_ALL_GVT_CLUES; + reset_clues_done = TRUE; + } +# endif } } # ifdef GTM_TRIGGER - } + } else + status = LAST_RESTART_CODE; DBGTRIGR((stderr, "tp_restart: past initial normal state processing\n")); # endif /* The below code to determine the roll-back point depends on tp_frame sized blocks being pushed on the TP @@ -537,7 +537,6 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) tf = (tp_frame *)(tpstackbase - (newlevel * SIZEOF(tp_frame))); assert(NULL != tf); assert(tpstacktop < (unsigned char *)tf); - UNIX_ONLY(issue_REPLONLNRLBK = FALSE); # ifdef GTM_TRIGGER if (TPRESTART_STATE_NORMAL == tprestart_state) { /* Only if normal tp_restart call - else we've already done this for this tp_restart */ @@ -555,16 +554,19 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) */ # ifdef UNIX assert(cdb_sc_normal != status); - if ((cdb_sc_onln_rlbk1 == status) || (cdb_sc_onln_rlbk2 == status)) - { /* restarted due to online rollback */ - RESET_ALL_GVT_CLUES; - assert(!TREF(only_reset_clues_if_onln_rlbk)); - if (IS_MCODE_RUNNING) - { - assert(!is_updproc); - (TREF(dollar_zonlnrlbk))++; - } - issue_REPLONLNRLBK = is_updproc; + switch (status) + { + case cdb_sc_gvtrootmod2: /* restarted due to MUPIP REORG moving root blocks */ + RESET_ALL_GVT_CLUES; + break; + case cdb_sc_onln_rlbk1: /* restarted due to online rollback */ + case cdb_sc_onln_rlbk2: + RESET_ALL_GVT_CLUES; + if (IS_MCODE_RUNNING && (cdb_sc_onln_rlbk2 == status)) + (TREF(dollar_zonlnrlbk))++; + break; + default: + break; } # endif # ifdef GTM_TRIGGER @@ -580,40 +582,35 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) */ GTMTRIG_ONLY(DBGTRIGR((stderr, "tp_restart: Beginning state 0/1 processing (state %d)\n", tprestart_state))); tp_unwind(newlevel, RESTART_INVOCATION, &tprestart_rc); + assert(dollar_tlevel == newlevel); /* tp_unwind would have set this */ assert(tf == tp_pointer); /* Needs to be true for now. Revisit when can restart to other than newlevel == 1 */ gd_header = tp_pointer->gd_header; gv_target = tp_pointer->orig_gv_target; gv_cur_region = tp_pointer->gd_reg; TP_CHANGE_REG(gv_cur_region); - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; - dollar_tlevel = newlevel; - top = gv_currkey->top; - /* ensure proper alignment before dereferencing tp_pointer->orig_key->end */ - assert(0 == (((unsigned long)tp_pointer->orig_key) % SIZEOF(tp_pointer->orig_key->end))); - memcpy(gv_currkey, tp_pointer->orig_key, SIZEOF(*tp_pointer->orig_key) + tp_pointer->orig_key->end); - gv_currkey->top = top; - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + COPY_KEY(gv_currkey, tp_pointer->orig_key); + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); # ifdef GTM_TRIGGER - /* Maintenance of SFF_TRIGR_CALLD stack frame flag: + /* Maintenance of SFF_IMPLTSTART_CALLD stack frame flag: * - Set by gtm_trigger when trigger base frame is created. Purpose to prevent MUM_TSTART from restarting * a frame making a call-in to a trigger (flag is checked in MUM_TSTART macro) because the mpc in the * stack frame is not the return point to the frame, which is only available in the C stack. * - Both TP restart and error handling unwinds can use MUM_TSTART to restart frame. * - TP restart changes the mpc to the proper address (where TSTART was done) before invoking MUM_TSTART. We allow - * this by shutting the SFF_TRIGR_CALLD flag off when mpc is changed. + * this by shutting the SFF_IMPLTSTART_CALLD flag off when mpc is changed. * - For TSTARTs done implcitly by triggers, MUM_TSTART would break things so we do not turn off the flag * for that type. */ if (!tp_pointer->implicit_tstart) - { /* SFF_TRIGR_CALLD validation: + { /* SFF_IMPLTSTART_CALLD validation: * - This is not a trigger-initiated implicit TSTART. * - If the flag is is not on, no further checks. Turning off flag is unconditional for best performance. * - If flag is on, verify the address in the stack frame is in fact being modified so it points to * a TSTART instead of the (currently) trigger call point. */ - assert(!(tp_pointer->fp->flags & SFF_TRIGR_CALLD) || (tp_pointer->fp->mpc != tp_pointer->restart_pc)); - tp_pointer->fp->flags &= SFF_TRIGR_CALLD_OFF; - DBGTRIGR((stderr, "tp_restart: Removing SFF_TRIGR_CALLD in frame 0x"lvaddr"\n", tp_pointer->fp)); + assert(!(tp_pointer->fp->flags & SFF_IMPLTSTART_CALLD) || (tp_pointer->fp->mpc != tp_pointer->restart_pc)); + tp_pointer->fp->flags &= SFF_IMPLTSTART_CALLD_OFF; + DBGTRIGR((stderr, "tp_restart: Removing SFF_IMPLTSTART_CALLD in frame 0x"lvaddr"\n", tp_pointer->fp)); } # endif tp_pointer->fp->mpc = tp_pointer->restart_pc; @@ -684,8 +681,8 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) * this frame, op_xnew creates a NEW symtab just for this frame. But when this code * unwound back to the TSTART, we also unwound the l_symtab this frame was using. So here * we verify this frame is a simple call frame from the previous and restore the use of its - * l_symtab if so. If not, GTMASSERT. Note the outer SFF_UWN_SYMVAL check keeps us from having - * non-existant l_symtab issues which is possible when we are MUPIP. + * l_symtab if so. If not, assertpro/GTMASSERT2. Note the outer SFF_UWN_SYMVAL check keeps + * us from having non-existant l_symtab issues which is possible when we are MUPIP. */ if ((frame_pointer->rvector == frame_pointer->old_frame_pointer->rvector) && (frame_pointer->vartab_ptr == frame_pointer->old_frame_pointer->vartab_ptr)) @@ -693,7 +690,7 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) frame_pointer->l_symtab = frame_pointer->old_frame_pointer->l_symtab; frame_pointer->flags &= SFF_UNW_SYMVAL_OFF; /* No need to clear symtab now */ } else - GTMASSERT; + assertpro(FALSE); } else { /* Otherwise the l_symtab needs to be cleared so its references get re-resolved to *this* symtab */ memset(frame_pointer->l_symtab, 0, frame_pointer->vartab_len * SIZEOF(ht_ent_mname *)); @@ -721,15 +718,24 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally) return 0; /* for the compiler only -- never executed */ } ++dollar_trestart; +# ifdef DEBUG + if (0 > TREF(tp_restart_dont_counts)) /* negative is a flag from TPNOTACID - do increment here */ + { + TREF(tp_restart_dont_counts) = -TREF(tp_restart_dont_counts); + (TREF(tp_restart_dont_counts))++; + } + assert(0 <= TREF(tp_restart_dont_counts)); /* NOTE: should tp_restart_dont_counts wrap, asserts will fail */ assert(dollar_trestart >= TREF(tp_restart_dont_counts)); assert(MAX_TRESTARTS > (dollar_trestart - TREF(tp_restart_dont_counts))); /* a magic number limit for restarts */ +# endif if (!dollar_trestart) /* in case of a wrap */ dollar_trestart--; UNIX_ONLY( /* Now that we are done with all the cleanup related to this restart, issue rts_error if we are update process. * updproc_ch knows to handle this SIGNAL. */ - if (issue_REPLONLNRLBK) + assert(cdb_sc_normal != status); + if (is_updproc && ((cdb_sc_onln_rlbk1 == status) || (cdb_sc_onln_rlbk2 == status))) rts_error(VARLSTCNT(1) ERR_REPLONLNRLBK); ) if (handle_errors_internally) diff --git a/sr_port/tp_set_sgm.c b/sr_port/tp_set_sgm.c index 46911b2..6a3f0c6 100644 --- a/sr_port/tp_set_sgm.c +++ b/sr_port/tp_set_sgm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,6 +39,8 @@ GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; +error_def(ERR_MMREGNOACCESS); + void tp_set_sgm(void) { sgm_info *si; @@ -49,6 +51,9 @@ void tp_set_sgm(void) si = csa->sgm_info_ptr; assert(si->tp_csa == csa); assert(si->tp_csd == cs_data); + assert(csa->hdr == cs_data); + if ((NULL == csa->db_addrs[0]) && (dba_mm == cs_data->acc_meth)) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MMREGNOACCESS, 4, REG_LEN_STR(csa->region), DB_LEN_STR(csa->region)); if (!si->tp_set_sgm_done) { si->next_sgm_info = first_sgm_info; @@ -63,11 +68,6 @@ void tp_set_sgm(void) GTMTRIG_ONLY(csa->db_trigger_cycle = csa->hdr->db_trigger_cycle); GTMTRIG_ONLY(DBGTRIGR((stderr, "tp_set_sgm: Updating csa->db_trigger_cycle to %d\n", csa->db_trigger_cycle))); -# ifdef GTM_TRUNCATE - /* see t_retry for comment */ - if (dba_mm != csa->hdr->acc_meth) - csa->total_blks = csa->ti->total_blks; -# endif si->tp_set_sgm_done = TRUE; assert(0 == si->update_trans); } diff --git a/sr_port/tp_tend.c b/sr_port/tp_tend.c index 9f44daa..99182d8 100644 --- a/sr_port/tp_tend.c +++ b/sr_port/tp_tend.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -78,6 +78,9 @@ #include "have_crit.h" #include "bml_status_check.h" #include "gtmimagename.h" +#ifdef DEBUG +#include "anticipatory_freeze.h" /* needed for IS_REPL_INST_FROZEN macro */ +#endif #ifdef UNIX #include "gtmrecv.h" @@ -123,6 +126,7 @@ GBLREF uint4 process_id; #ifdef UNIX GBLREF recvpool_addrs recvpool; GBLREF int4 strm_index; +GBLREF uint4 update_trans; #endif #ifdef VMS GBLREF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */ @@ -172,12 +176,14 @@ boolean_t tp_crit_all_regions() { int lcnt; boolean_t x_lock; - tp_region *tr, *tr_last; - sgmnt_addrs *tmpcsa; + tp_region *tr; + sgmnt_addrs *tmpcsa, *frozen_csa; sgm_info *tmpsi; sgmnt_data_ptr_t tmpcsd; gd_region *reg; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(dollar_tlevel); /* This function is in tp_tend because its technique and structures should be maintained in parallel with tp_tend. * The following section grabs crit in all regions touched by the transaction. We use a different @@ -204,22 +210,30 @@ boolean_t tp_crit_all_regions() } ) assert(!tmpcsa->hold_onto_crit); - grab_crit(reg); + if (!tmpcsa->now_crit) + grab_crit(reg); assert(!(tmpsi->update_trans & ~UPDTRNS_VALID_MASK)); if (tmpcsd->freeze && tmpsi->update_trans) { tr = tr->fPtr; /* Increment so we release the lock we actually got */ x_lock = FALSE; + frozen_csa = tmpcsa; break; } } if (x_lock) break; - tr_last = tr; - for (tr = tp_reg_list; tr_last != tr; tr = tr->fPtr) - rel_crit(tr->reg); + for (tr = tp_reg_list; NULL != tr; tr = tr->fPtr) + { /* We may already have crit, if we're entering the final retry or an extra retry. So we need to + * release crit on all before waiting for freezes. + */ + reg = tr->reg; + tmpcsa = &FILE_INFO(reg)->s_addrs; + if (tmpcsa->now_crit) + rel_crit(tr->reg); + } /* Wait for region to be unfrozen before re-grabbing crit on ALL regions */ - WAIT_FOR_REGION_TO_UNFREEZE(tmpcsa, tmpcsd); + WAIT_FOR_REGION_TO_UNFREEZE(frozen_csa, tmpcsd); } /* for (;;) */ return TRUE; } @@ -241,12 +255,12 @@ boolean_t tp_tend() jnl_buffer_ptr_t jbp; jnl_format_buffer *jfb; sgm_info *si, *si_last, *tmpsi, *si_not_validated; - tp_region *tr, *tr_last; + tp_region *tr; sgmnt_addrs *csa, *repl_csa = NULL; sgmnt_data_ptr_t csd; node_local_ptr_t cnl; srch_blk_status *t1; - trans_num ctn, tnque_earliest_tn, epoch_tn, old_block_tn; + trans_num ctn, oldest_hist_tn, epoch_tn, old_block_tn; trans_num valid_thru; /* buffers touched by this transaction will be valid thru this tn */ enum cdb_sc status; gd_region *save_gv_cur_region; @@ -274,6 +288,7 @@ boolean_t tp_tend() ) # endif boolean_t ss_need_to_restart, new_bkup_started; + uint4 com_csum; DEBUG_ONLY( int tmp_jnl_participants; uint4 upd_num; @@ -303,6 +318,8 @@ boolean_t tp_tend() TP_CHANGE_REG_IF_NEEDED(tr->reg); csa = cs_addrs; 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)); @@ -311,11 +328,10 @@ boolean_t tp_tend() sgm_info_ptr = si; *prev_tp_si_by_ftok = si; prev_tp_si_by_ftok = &si->next_tp_si_by_ftok; - if ((csd->wc_blocked) || /* If blocked, or.. */ - ((dba_mm == csd->acc_meth) && /* we have MM and.. */ - (csa->total_blks != csd->trans_hist.total_blks))) /* and file has been extended */ - { /* Force repair */ + if ((cnl->wc_blocked) || (is_mm && (csa->total_blks != csd->trans_hist.total_blks))) + { /* If blocked, or we have MM and file has been extended, force repair */ status = cdb_sc_helpedout; /* special status to prevent punishing altruism */ + assert((CDB_STAGNATE > t_tries) || !is_mm || (csa->total_blks == csd->trans_hist.total_blks)); TP_TRACE_HIST(CR_BLKEMPTY, NULL); goto failed_skip_revert; } @@ -324,8 +340,8 @@ boolean_t tp_tend() * (b) If we are in the final retry and we don't hold crit on some region. * (c) If we are in the final retry and we hold crit on a frozen region that we want to update. * This is possible if: - * (1) We did a tp_grab_crit through one of the gvcst_* routines when we first encountered the region - * in the TP transaction and it wasn't locked down although it was frozen then. + * (1) We did a grab_crit_immediate() through one of the gvcst_* routines when we first encountered the + * region in the TP transaction and it wasn't locked down although it was frozen then. * (2) tp_crit_all_regions notices that at least one of the participating regions did ONLY READs, it * will not wait for any freeze on THAT region to complete before grabbing crit. Later, in the * final retry, if THAT region did an update which caused op_tcommit to invoke bm_getfree -> @@ -347,7 +363,7 @@ boolean_t tp_tend() : (!csa->now_crit || region_is_frozen)) { assert(!csa->hold_onto_crit); - send_msg(VARLSTCNT(8) ERR_DLCKAVOIDANCE, 6, DB_LEN_STR(tr->reg), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DLCKAVOIDANCE, 6, DB_LEN_STR(tr->reg), &csd->trans_hist.curr_tn, t_tries, dollar_trestart, csa->now_crit); /* The only possible case we know of is (c). assert to that effect. Use local variable region_is_frozen * instead of csd->freeze as it could be concurrently changed even though we hold crit (freeze holding @@ -373,7 +389,7 @@ boolean_t tp_tend() * logic gets crit anyways and so will salvage the lock and do the necessary recovery and issue * DBFLCORRP if it notices that csd->file_corrupt is TRUE. */ - if ((si->start_tn == csd->trans_hist.early_tn) UNIX_ONLY(&& (0 == csa->nl->onln_rlbk_pid))) + if ((si->start_tn == csd->trans_hist.early_tn) UNIX_ONLY(&& (0 == cnl->onln_rlbk_pid))) { /* read with no change to the transaction history. ensure we haven't overrun * our history buffer and we have reasonable values for first and last */ assert(si->last_tp_hist - si->first_tp_hist <= si->tp_hist_size); @@ -383,14 +399,12 @@ boolean_t tp_tend() } else { do_validation = TRUE; - is_mm = (dba_mm == cs_data->acc_meth); /* We are still out of crit if this is not our last attempt. If so, run the region list and check * that we have sufficient free blocks for our update. If not, get them now while we can. * We will repeat this check later in crit but it will hopefully have little or nothing to do. * bypass 1st check if already in crit -- check later */ - if (!csa->now_crit && !is_mm && (csa->nl->wc_in_free < si->cw_set_depth + 1) - && !wcs_get_space(gv_cur_region, si->cw_set_depth + 1, NULL)) + if (!csa->now_crit && !is_mm && !WCS_GET_SPACE(gv_cur_region, si->cw_set_depth + 1, NULL)) assert(FALSE); /* wcs_get_space should have returned TRUE unconditionally in this case */ if (JNL_ENABLED(csa)) { /* compute the total journal record size requirements before grab_crit. @@ -403,13 +417,14 @@ boolean_t tp_tend() /* check if current TP transaction's jnl size needs are greater than max jnl file size */ if (si->tot_jrec_size > csd->autoswitchlimit) /* can't fit in current transaction's journal records into one journal file */ - rts_error(VARLSTCNT(6) ERR_JNLTRANS2BIG, 4, si->tot_jrec_size, + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_JNLTRANS2BIG, 4, si->tot_jrec_size, JNL_LEN_STR(csd), csd->autoswitchlimit); } if (REPL_ALLOWED(csa)) { assert(JNL_ENABLED(csa) || REPL_WAS_ENABLED(csa)); replication = TRUE; + repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; jnl_participants++; } else if (JNL_ENABLED(csa)) { @@ -437,7 +452,8 @@ boolean_t tp_tend() 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(VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(save_gv_cur_region)); + rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, + DB_LEN_STR(save_gv_cur_region)); } if (!do_validation) { @@ -491,7 +507,7 @@ boolean_t tp_tend() * file being operated on, the obtains will always occurr in a consistent manner. Therefore, we * will grab crit on each file with wait since deadlock should not be able to occurr. */ - ESTABLISH_RET(t_ch, FALSE); + ESTABLISH_NOUNWIND(t_ch); /* avoid hefty setjmp call, which is ok since we never unwind t_ch */ for (lcnt = 0; ; lcnt++) { x_lock = TRUE; /* Assume success */ @@ -502,6 +518,7 @@ boolean_t tp_tend() sgm_info_ptr = si; TP_TEND_CHANGE_REG(si); csa = cs_addrs; + cnl = csa->nl; csd = cs_data; assert(!si->cr_array_index); DEBUG_ONLY( @@ -524,13 +541,13 @@ boolean_t tp_tend() if (TREF(tprestart_syslog_delta)) n_blkmods = n_pvtmods = 0; /* If we already hold crit (possible if we are in the final retry), do not invoke grab_crit as it will - * invoke wcs_recover unconditionally if csd->wc_blocked is set to TRUE. In that case, we want to + * invoke wcs_recover unconditionally if cnl->wc_blocked is set to TRUE. In that case, we want to * restart with a helped out code because the cache recovery will most likely result in a restart of * the current transaction which we want to avoid if we are in the final retry. */ if (!csa->now_crit) grab_crit(gv_cur_region); - else if (csd->wc_blocked) + else if (cnl->wc_blocked) { status = cdb_sc_helpedout; goto failed; @@ -542,19 +559,6 @@ boolean_t tp_tend() status = cdb_sc_helpedout; /* force retry with special status so philanthropy isn't punished */ goto failed; } -# ifdef GTM_TRUNCATE - assert(csa->total_blks); - if (csa->ti->total_blks < csa->total_blks) - { - /* File has been truncated since this process entered op_tcommit or last called gdsfilext on csa. - * I.e., the file is smaller than its last known size and we might have allocated blocks - * beyond csa->ti->total_blks. Restart. */ - assert(dba_mm != csd->acc_meth); - assert(CDB_STAGNATE > t_tries); /* On the final retry, should have crit and truncate can't happen */ - status = cdb_sc_truncate; - goto failed; - } -# endif /* Note that even though we ensured that regions are not frozen outside of crit, it is still possible * that they become frozen just before we grab crit. In this case (should be rare though) release * crit on ALL regions that we have grabbed uptil this point and wait for the freeze to be removed. @@ -566,30 +570,24 @@ boolean_t tp_tend() } CHECK_TN(csa, csd, csd->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */ if (!is_mm) - tnque_earliest_tn = ((th_rec_ptr_t)((sm_uc_ptr_t)csa->th_base + csa->th_base->tnque.fl))->tn; + oldest_hist_tn = OLDEST_HIST_TN(csa); # ifdef UNIX /* We never expect to come here with file_corrupt set to TRUE (in case of an online rollback) because * grab_crit done above will make sure of that. The only exception is RECOVER/ROLLBACK itself coming * here in the forward phase */ assert(!csd->file_corrupt || mupip_jnl_recover); - /* only_reset_clues_if_onln_rlbk is set ONLY for gvcst_bmp_mark_free which operates completely in non-tp - * and so we should never come here. This also ensures that we never try to commit a TP transaction when - * this flag is set - */ - assert(!TREF(only_reset_clues_if_onln_rlbk)); - if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) - { /* A concurrent Online Rollback occurred. Restart to be safe. */ - assert(!mupip_jnl_recover); - /* Note: We don't assert that CDB_STAGNATE > t_tries because we can detect an online rollback even - * in the final retry. - */ - status = cdb_sc_onln_rlbk1; - if (csa->db_onln_rlbkd_cycle != csa->nl->db_onln_rlbkd_cycle) - status = cdb_sc_onln_rlbk2; /* database was rolled back to a different logical state */ - SYNC_ONLN_RLBK_CYCLES; - if ((CDB_STAGNATE - 1) == t_tries) - release_crit = TRUE; + if (MISMATCH_ROOT_CYCLES(csa, cnl)) + { + status = cdb_sc_gvtrootmod2; + if (MISMATCH_ONLN_RLBK_CYCLES(csa, cnl)) + { + assert(!mupip_jnl_recover); + status = ONLN_RLBK_STATUS(csa, cnl); + SYNC_ONLN_RLBK_CYCLES; + SYNC_ROOT_CYCLES(NULL); + } else + SYNC_ROOT_CYCLES(csa); goto failed; } # endif @@ -641,6 +639,7 @@ boolean_t tp_tend() { csa = tmpsi->tp_csa; csd = csa->hdr; + cnl = csa->nl; csa->jnl_state = csd->jnl_state; csa->jnl_before_image = csd->jnl_before_image; /* jnl_file_lost causes a jnl_state transition from jnl_open to jnl_closed @@ -661,7 +660,7 @@ boolean_t tp_tend() /* Flag retry, if other mupip activities like BACKUP, INTEG or FREEZE are in progress. * If in final retry, go ahead with kill. BACKUP/INTEG/FREEZE will wait for us to be done. */ - if ((NULL != si->kill_set_head) && (0 < csa->nl->inhibit_kills) && (CDB_STAGNATE > t_tries)) + if ((NULL != si->kill_set_head) && (0 < cnl->inhibit_kills) && (CDB_STAGNATE > t_tries)) { status = cdb_sc_inhibitkills; goto failed; @@ -673,9 +672,9 @@ boolean_t tp_tend() { ss_need_to_restart = new_bkup_started = FALSE; GTM_SNAPSHOT_ONLY( - CHK_AND_UPDATE_SNAPSHOT_STATE_IF_NEEDED(csa, csa->nl, ss_need_to_restart); + CHK_AND_UPDATE_SNAPSHOT_STATE_IF_NEEDED(csa, cnl, ss_need_to_restart); ) - CHK_AND_UPDATE_BKUP_STATE_IF_NEEDED(csa->nl, csa, new_bkup_started); + CHK_AND_UPDATE_BKUP_STATE_IF_NEEDED(cnl, csa, new_bkup_started); if (ss_need_to_restart || (new_bkup_started && !(JNL_ENABLED(csa) && csa->jnl_before_image))) { @@ -697,26 +696,23 @@ boolean_t tp_tend() { /* in crit, ensure cache-space is available. * the out-of-crit check done above might not be enough */ - if (csa->nl->wc_in_free < si->cw_set_depth + 1) + if (!WCS_GET_SPACE(gv_cur_region, si->cw_set_depth + 1, NULL)) { - if (!wcs_get_space(gv_cur_region, si->cw_set_depth + 1, NULL)) - { - assert(csd->wc_blocked); /* only reason we currently know - * why wcs_get_space could fail */ - assert(gtm_white_box_test_case_enabled); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); - BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_wcsgetspace); - status = cdb_sc_cacheprob; - TP_TRACE_HIST(CR_BLKEMPTY, NULL); - goto failed; - } + assert(cnl->wc_blocked); /* only reason we currently know + * why wcs_get_space could fail */ + assert(gtm_white_box_test_case_enabled); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); + BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_wcsgetspace); + SET_CACHE_FAIL_STATUS(status, csd); + TP_TRACE_HIST(CR_BLKEMPTY, NULL); + goto failed; } VMS_ONLY( - if (csd->clustered && !CCP_SEGMENT_STATE(csa->nl, CCST_MASK_HAVE_DIRTY_BUFFERS)) + if (csd->clustered && !CCP_SEGMENT_STATE(cnl, CCST_MASK_HAVE_DIRTY_BUFFERS)) { CCP_FID_MSG(gv_cur_region, CCTR_FLUSHLK); ccp_userwait(gv_cur_region, CCST_MASK_HAVE_DIRTY_BUFFERS, - NULL, csa->nl->ccp_cycle); + NULL, cnl->ccp_cycle); } ) } @@ -751,17 +747,17 @@ boolean_t tp_tend() ctn = csd->trans_hist.curr_tn; assert(csd->trans_hist.early_tn == ctn); if (SS_NORMAL != jpc->status) - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), jpc->status); else - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); } if (DISK_BLOCKS_SUM(jbp->freeaddr, si->total_jnl_rec_size) > jbp->filesize) { /* Moved here to prevent jnlrecs split across multiple generation journal files. */ if (SS_NORMAL != (jnl_status = jnl_flush(jpc->region))) { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush in tp_tend"), jnl_status); assert((!JNL_ENABLED(csd)) && JNL_ENABLED(csa)); @@ -799,12 +795,13 @@ boolean_t tp_tend() */ save_dont_reset_gbl_jrec_time = jgbl.dont_reset_gbl_jrec_time; jgbl.dont_reset_gbl_jrec_time = TRUE; - if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT)) + if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_IN_COMMIT + | WCSFLU_SPEEDUP_NOBEFORE)) { assert(csd == csa->hdr); jgbl.dont_reset_gbl_jrec_time = save_dont_reset_gbl_jrec_time; SET_WCS_FLU_FAIL_STATUS(status, csd); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_jnl_wcsflu); TP_TRACE_HIST(CR_BLKEMPTY, NULL); goto failed; @@ -906,7 +903,7 @@ boolean_t tp_tend() PRO_ONLY(goto failed;) } } - } else if (t1->tn <= tnque_earliest_tn) + } else if (t1->tn <= oldest_hist_tn) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_losthist; @@ -930,7 +927,7 @@ boolean_t tp_tend() if ((NULL != cr) && (cr->blk != bt->blk)) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_crbtmismatch1); status = cdb_sc_crbtmismatch; TP_TRACE_HIST(t1->blk_num, t1->blk_target); @@ -939,9 +936,9 @@ boolean_t tp_tend() } if ((cache_rec_ptr_t)CR_NOTVALID == cr) { - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_t1); - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); TP_TRACE_HIST(t1->blk_num, t1->blk_target); goto failed; } @@ -955,7 +952,7 @@ boolean_t tp_tend() if ((NULL != cr) && (NULL != bt) && (cr->blk != bt->blk)) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_crbtmismatch2); status = cdb_sc_crbtmismatch; TP_TRACE_HIST(t1->blk_num, t1->blk_target); @@ -1044,7 +1041,7 @@ boolean_t tp_tend() TP_TRACE_HIST(tp_blk, NULL); goto failed; } - } else if (cse->tn <= tnque_earliest_tn) + } else if (cse->tn <= oldest_hist_tn) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_lostbmlhist; @@ -1057,9 +1054,9 @@ boolean_t tp_tend() cr = db_csh_get(tp_blk); if ((cache_rec_ptr_t)CR_NOTVALID == cr) { - status = cdb_sc_cacheprob; + SET_CACHE_FAIL_STATUS(status, csd); TP_TRACE_HIST(tp_blk, NULL); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_bitmap); goto failed; } @@ -1069,7 +1066,7 @@ boolean_t tp_tend() if (cr->blk != bt->blk) { assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_crbtmismatch3); status = cdb_sc_crbtmismatch; TP_TRACE_HIST(tp_blk, NULL); @@ -1110,8 +1107,8 @@ boolean_t tp_tend() if ((cache_rec_ptr_t)CR_NOTVALID == cr) { TP_TRACE_HIST(cse->blk, cse->blk_target); - status = cdb_sc_cacheprob; - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_CACHE_FAIL_STATUS(status, csd); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_tp_tend_jnl_cwset); goto failed; } @@ -1138,7 +1135,8 @@ boolean_t tp_tend() assert((cse->cr != cr) || (cse->old_block == (sm_uc_ptr_t)old_block)); old_block_tn = old_block->tn; /* Need checksums if before imaging and if a PBLK record is going to be written. */ - cksum_needed = (!cse->was_free && (NULL != jbp) && (old_block_tn < jbp->epoch_tn)); + cksum_needed = (!WAS_FREE(cse->blk_prior_state) && (NULL != jbp) + && (old_block_tn < jbp->epoch_tn)); if ((cse->cr != cr) || (cse->cycle != cr->cycle)) { /* Block has relocated in the cache. Adjust pointers to new location. */ cse->cr = cr; @@ -1237,6 +1235,8 @@ boolean_t tp_tend() WAIT_FOR_REGION_TO_UNFREEZE(csa, csd); assert(CDB_STAGNATE > t_tries); } /* for (;;) */ + /* At this point, we are done with validation and so we need to assert that donot_commit is set to FALSE */ + assert(!TREF(donot_commit)); /* We should never commit a transaction that was determined restartable */ /* Validate the correctness of the calculation of # of replication/journaled regions inside & outside of crit */ assert(tmp_jnl_participants == jnl_participants); assert(cdb_sc_normal == status); @@ -1244,9 +1244,16 @@ boolean_t tp_tend() { jpl = jnlpool_ctl; tjpl = temp_jnlpool_ctl; - repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; if (!repl_csa->hold_onto_crit) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); +# ifdef UNIX + if (jnlpool.jnlpool_ctl->freeze) + { + status = cdb_sc_instancefreeze; /* break the possible deadlock by signalling a restart */ + TP_TRACE_HIST(CR_BLKEMPTY, NULL); + goto failed; + } +# endif tjpl->write_addr = jpl->write_addr; tjpl->write = jpl->write; tjpl->jnl_seqno = jpl->jnl_seqno; @@ -1308,7 +1315,6 @@ boolean_t tp_tend() /* the following section writes journal records in all regions */ DEBUG_ONLY(save_gbl_jrec_time = jgbl.gbl_jrec_time;) DEBUG_ONLY(tmp_jnl_participants = 0;) - assert(!TREF(donot_commit)); /* We should never commit a transaction that was determined restartable */ # ifdef DEBUG /* Check that upd_num in jnl records got set in increasing order (not necessarily contiguous) within each region. * This is true for GT.M and journal recovery. Take the chance to also check that jnl_head & update_trans are in sync. @@ -1390,6 +1396,7 @@ boolean_t tp_tend() replay_jnl_participants = jnl_participants; } else replay_jnl_participants = jgbl.mur_jrec_participants; + /* In case of journal recovery, token would be initialized to a non-zero value */ for (si = first_tp_si_by_ftok; (NULL != si); si = si->next_tp_si_by_ftok) { @@ -1402,6 +1409,7 @@ boolean_t tp_tend() ctn = csd->trans_hist.curr_tn; ASSERT_CURR_TN_EQUALS_EARLY_TN(csa, ctn); csd->trans_hist.early_tn = ctn + 1; + com_csum = 0; /* Write non-logical records (PBLK) if applicable */ if (JNL_ENABLED(csa)) { @@ -1416,13 +1424,19 @@ boolean_t tp_tend() assert(jgbl.gbl_jrec_time >= jbp->prev_jrec_time); if (0 == jpc->pini_addr) jnl_put_jrt_pini(csa); + if(!com_csum) + { + ADJUST_CHECKSUM_TN(INIT_CHECKSUM_SEED, &ctn, com_csum); + ADJUST_CHECKSUM(com_csum, jpc->pini_addr, com_csum); + ADJUST_CHECKSUM(com_csum, jgbl.gbl_jrec_time, com_csum); + } if (jbp->before_images) { epoch_tn = jbp->epoch_tn; /* store in a local variable as it is used in a loop below */ for (cse = si->first_cw_set; NULL != cse; cse = cse->next_cw_set) { /* Write out before-update journal image records */ TRAVERSE_TO_LATEST_CSE(cse); - if (cse->was_free) + if (WAS_FREE(cse->blk_prior_state)) continue; old_block = (blk_hdr_ptr_t)cse->old_block; ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)old_block, csa); @@ -1467,7 +1481,7 @@ boolean_t tp_tend() DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csd, (sm_uc_ptr_t)old_block); } # endif - jnl_write_pblk(csa, cse, old_block); + jnl_write_pblk(csa, cse, old_block, com_csum); cse->jnl_freeaddr = jbp->freeaddr; } else cse->jnl_freeaddr = 0; @@ -1506,7 +1520,7 @@ boolean_t tp_tend() DEBUG_ONLY(++tmp_jnl_participants;) do { - jnl_write_logical(csa, jfb); + jnl_write_logical(csa, jfb, com_csum); jfb = jfb->next; } while (NULL != jfb); } @@ -1549,6 +1563,7 @@ boolean_t tp_tend() cs_addrs = csa; cs_data = csa->hdr; /* Note tcom_record.jnl_tid was set in op_tstart or updproc */ + tcom_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&tcom_record, SIZEOF(struct_jrec_tcom)); JNL_WRITE_APPROPRIATE(csa, jpc, JRT_TCOM, (jnl_record *)&tcom_record, NULL, NULL); DEBUG_ONLY(tmp_jnl_participants++;) } @@ -1684,7 +1699,8 @@ boolean_t tp_tend() assert(!(UPDTRNS_TCOMMIT_STARTED_MASK & update_trans)); si->update_trans = update_trans | UPDTRNS_TCOMMIT_STARTED_MASK; csa->t_commit_crit = T_COMMIT_CRIT_PHASE2; /* set this BEFORE releasing crit */ - assert(!csd->freeze); /* should never increment curr_tn on a frozen database */ + /* should never increment curr_tn on a frozen database */ + assert(!(csd->freeze UNIX_ONLY(|| (replication && IS_REPL_INST_FROZEN)))); INCREMENT_CURR_TN(csd); # ifdef GTM_TRIGGER if (csa->incr_db_trigger_cycle) @@ -1838,7 +1854,7 @@ failed: si_not_validated = si; si_last = (NULL == si_not_validated) ? NULL : si_not_validated->next_tp_si_by_ftok; /* Free up all pinnned cache-records and release crit */ - release_crit = (NEED_TO_RELEASE_CRIT(t_tries) UNIX_ONLY(&& !jgbl.onlnrlbk)); + release_crit = (NEED_TO_RELEASE_CRIT(t_tries, status) UNIX_ONLY(&& !jgbl.onlnrlbk)); for (si = first_tp_si_by_ftok; (si_last != si); si = si->next_tp_si_by_ftok) { assert(si->tp_csa->now_crit); @@ -1853,6 +1869,13 @@ failed: rel_crit(si->gv_cur_region); } } +#ifdef UNIX + if (replication && repl_csa->now_crit && release_crit) + { /* The only restart that is possible once we acquired the journal pool lock is due to instance freeze */ + assert(cdb_sc_instancefreeze == status); + rel_lock(jnlpool.jnlpool_dummy_reg); + } +#endif /* Check that we DONT own crit/commit on ANY region. The only exception is online mupip journal rollback/recovery * which holds crit for the entire process lifetime. */ @@ -1941,8 +1964,8 @@ skip_failed: failed_skip_revert: assert(cdb_sc_normal != status); t_fail_hist[t_tries] = status; - SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, status); - TP_RETRY_ACCOUNTING(csa, csa->nl, status); + SET_WC_BLOCKED_FINAL_RETRY_IF_NEEDED(csa, cnl, status); + TP_RETRY_ACCOUNTING(csa, cnl); first_tp_si_by_ftok = NULL; /* Signal t_commit_cleanup/secshr_db_clnup that TP transaction is NOT underway */ return FALSE; } @@ -1963,6 +1986,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) int4 blk_size, blk_fill_size, cur_blk_size, blk_seg_cnt, delta ; int4 n, new_rec_size, next_rec_shrink; int4 rec_cmpc, target_key_size; + int tmp_cmpc; uint4 segment_update_array_size; key_cum_value *kv, *kvhead; mstr value; @@ -2008,7 +2032,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) cse->old_block = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); cse->ondsk_blkver = cr->ondsk_blkver; /* old_block needs to be repointed to the NEW buffer but the fact that this block was free does not change in this - * entire function. So cse->was_free can stay as it is. + * entire function. So cse->blk_prior_state's free_status can stay as it is. */ bh->buffaddr = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); } @@ -2051,7 +2075,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) } else { GET_USHORT(rec_size, &rp->rsiz); - rec_cmpc = rp->cmpc; + rec_cmpc = EVAL_CMPC(rp); if ((sm_uc_ptr_t)rp + rec_size > (sm_uc_ptr_t)buffaddr + cur_blk_size) { assert(CDB_STAGNATE > t_tries); @@ -2091,7 +2115,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), bh->curr_rec.offset - SIZEOF(blk_hdr)); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; - curr_rec_hdr->cmpc = bh->prev_rec.match; + SET_CMPC(curr_rec_hdr, bh->prev_rec.match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - bh->prev_rec.match, unsigned char); memcpy(cp1, pKey->base + bh->prev_rec.match, target_key_size - bh->prev_rec.match); @@ -2111,7 +2135,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) { BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = rec_size - next_rec_shrink; - next_rec_hdr->cmpc = bh->curr_rec.match; + SET_CMPC(next_rec_hdr, bh->curr_rec.match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); next_rec_shrink += SIZEOF(rec_hdr); } @@ -2163,7 +2187,7 @@ enum cdb_sc recompute_upd_array(srch_blk_status *bh, cw_set_element *cse) * not on cse->new_buff. Therefore we need to PIN the corresponding cache-record in tp_tend. So reset cse->new_buff. */ cse->new_buff = NULL; - if (!cse->was_free && (NULL != cse->old_block) && JNL_ENABLED(csa) && csa->jnl_before_image) + if (!WAS_FREE(cse->blk_prior_state) && (NULL != cse->old_block) && JNL_ENABLED(csa) && csa->jnl_before_image) { old_block = (blk_hdr_ptr_t)cse->old_block; assert(old_block->bsiz <= csa->hdr->blk_size); @@ -2237,7 +2261,8 @@ boolean_t reallocate_bitmap(sgm_info *si, cw_set_element *bml_cse) return FALSE; cse->blk = bml + free_bit; assert(cse->blk < total_blks); - cse->was_free = !blk_used; + blk_used ? BIT_SET_RECYCLED_AND_CLEAR_FREE(cse->blk_prior_state) + : BIT_CLEAR_RECYCLED_AND_SET_FREE(cse->blk_prior_state); /* re-point before-images into cse->old_block if necessary; if not available restart by returning FALSE */ BEFORE_IMAGE_NEEDED(read_before_image, cse, csa, csd, cse->blk, before_image_needed); if (!before_image_needed) @@ -2262,7 +2287,7 @@ boolean_t reallocate_bitmap(sgm_info *si, cw_set_element *bml_cse) cse->cycle = cr->cycle; cse->old_block = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr); old_block = (blk_hdr_ptr_t)cse->old_block; - if (!cse->was_free && (NULL != jbp)) + if (!WAS_FREE(cse->blk_prior_state) && (NULL != jbp)) { assert(old_block->bsiz <= csd->blk_size); if (old_block->tn < jbp->epoch_tn) @@ -2303,7 +2328,7 @@ boolean_t reallocate_bitmap(sgm_info *si, cw_set_element *bml_cse) /* since bitmap block got modified, copy latest "ondsk_blkver" status from cache-record to bml_cse */ assert((NULL != bml_cse->cr) || is_mm); old_block = (blk_hdr_ptr_t)bml_cse->old_block; - assert(!bml_cse->was_free); /* Bitmap blocks are never of type gds_t_acquired or gds_t_create */ + assert(!WAS_FREE(bml_cse->blk_prior_state)); /* Bitmap blocks are never of type gds_t_acquired or gds_t_create */ if (NULL != jbp) { /* recompute CHECKSUM for the modified bitmap block before-image */ if (old_block->tn < jbp->epoch_tn) diff --git a/sr_port/tp_timeout.c b/sr_port/tp_timeout.c index fda77ae..20d2999 100644 --- a/sr_port/tp_timeout.c +++ b/sr_port/tp_timeout.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -86,7 +86,7 @@ char asccurtime[10]; \ size_t len; \ now = time(NULL); \ - tm_struct = localtime(&now); \ + GTM_LOCALTIME(tm_struct, &now); \ STRFTIME(asccurtime, SIZEOF(asccurtime), TIME_EXT_FMT, tm_struct, len); \ DBGTPTDFRL(x); \ } diff --git a/sr_port/tp_unwind.c b/sr_port/tp_unwind.c index 68cc97b..8e426ff 100644 --- a/sr_port/tp_unwind.c +++ b/sr_port/tp_unwind.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,7 @@ #include "gtm_stdio.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "tp_frame.h" @@ -41,11 +41,17 @@ #include "tp.h" #include "tp_restart.h" #ifdef UNIX -#include "deferred_signal_handler.h" +# include "deferred_signal_handler.h" #endif #ifdef GTM_TRIGGER -#include "gv_trigger.h" -#include "gtm_trigger.h" +# include "gv_trigger.h" +# include "gtm_trigger.h" +# include "gt_timer.h" +# include "wbox_test_init.h" +#endif +#ifdef DEBUG +# include "gtmio.h" +# include "gtm_stdio.h" #endif GBLREF stack_frame *frame_pointer; @@ -56,10 +62,36 @@ GBLREF unsigned char *tp_sp, *tpstackbase, *tpstacktop; GBLREF mlk_pvtblk *mlk_pvt_root; GBLREF uint4 dollar_tlevel; GBLREF symval *curr_symval; +GBLREF uint4 process_id; +GBLREF sgmnt_addrs *csa; #ifdef GTM_TRIGGER GBLREF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */ #endif +/* Define whitebox test case as a macro only for a debug build */ +#ifdef DEBUG +# define TPUNWND_WBOX_TEST \ +{ \ + if (WBTEST_ENABLED(WBTEST_TRIGR_TPRESTART_MSTOP)) \ + { /* For this white box test, we're going to send ourselves a SIGTERM termination signal at a specific point \ + * in the processing to make sure it succeeds without exploding during rundown. To test the condition GTM-7811 \ + * fixes, where TPUNWND_WBOX_TEST is seen, move the reset for dollar_tlevel from before the ENABLE_INTERRUTPS \ + * macro to after the TPUNWND_WBOX_TEST, rebuild and re-run test to see it explode. \ + */ \ + kill(process_id, SIGTERM); \ + hiber_start(20 * 1000); /* Wait up to 20 secs - don't use wait_any as the heartbeat timer \ + * will kill this wait in 0-7 seconds or so. \ + */ \ + /* We sent, we waited, wait expired - weird - funky condition is for identification purposes (to identify the \ + * actual assert). We should be dead or dying, not trying to resume. \ + */ \ + assertpro(WBTEST_TRIGR_TPRESTART_MSTOP == 0); \ + } \ +} +#else +# define TPUNWND_WBOX_TEST +#endif + error_def(ERR_STACKUNDERFLO); error_def(ERR_TPRETRY); @@ -78,18 +110,20 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t /* We are about to clean up structures. Defer MUPIP STOP/signal handling until function end. */ DEFER_INTERRUPTS(INTRPT_IN_TP_UNWIND); - - DBGRFCT((stderr, "\ntp_unwind: Beginning TP unwind process\n")); - restore_lv = (invocation_type == RESTART_INVOCATION); + /* Unwind the requested TP levels */ +# if defined(DEBUG_REFCNT) || defined(DEBUG_ERRHND) + DBGFPF((stderr, "\ntp_unwind: Beginning TP unwind process\n")); +# endif + restore_lv = (RESTART_INVOCATION == invocation_type); lvscan = &first_lvscan; lvscan->next = NULL; lvscan->elemcnt = 0; - assert(tp_sp <= tpstackbase && tp_sp > tpstacktop); - assert(tp_pointer <= (tp_frame *)tpstackbase && tp_pointer > (tp_frame *)tpstacktop); + assert((tp_sp <= tpstackbase) && (tp_sp > tpstacktop)); + assert((tp_pointer <= (tp_frame *)tpstackbase) && (tp_pointer > (tp_frame *)tpstacktop)); for (tl = dollar_tlevel; tl > newlevel; --tl) { DBGRFCT((stderr, "\ntp_unwind: Unwinding level %d -- tp_pointer: 0x"lvaddr"\n", tl, tp_pointer)); - assert(NULL != tp_pointer); + assertpro(NULL != tp_pointer); for (restore_ent = tp_pointer->vars; NULL != restore_ent; restore_ent = tp_pointer->vars) { /*********************************************************************************/ @@ -115,9 +149,10 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t # ifdef GTM_TRIGGER if (0 != rc) { + dollar_tlevel = tl; /* Record fact if we unwound some tp_frames */ ENABLE_INTERRUPTS(INTRPT_IN_TP_UNWIND); /* drive any MUPIP STOP/signals deferred * while in this function */ - dollar_tlevel = tl; /* Record fact if we unwound some tp_frames */ + TPUNWND_WBOX_TEST; /* Debug-only wbox-test to simulate SIGTERM */ INVOKE_RESTART; } # endif @@ -165,23 +200,25 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t tp_pointer->vars = restore_ent->next; free(restore_ent); } - if (tp_pointer->fp == frame_pointer && mv_chain->mv_st_type == MVST_TPHOLD && msp == (unsigned char *)mv_chain) + if ((tp_pointer->fp == frame_pointer) && (MVST_TPHOLD == mv_chain->mv_st_type) + && (msp == (unsigned char *)mv_chain)) POP_MV_STENT(); if (NULL == tp_pointer->old_tp_frame) tp_sp = tpstackbase; else tp_sp = (unsigned char *)tp_pointer->old_tp_frame; if (tp_sp > tpstackbase) - rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO); if (tp_pointer->tp_save_all_flg) --tp_pointer->sym->tp_save_all; if ((NULL != (tp_pointer = tp_pointer->old_tp_frame)) /* Note assignment */ - && ((tp_pointer < (tp_frame *)tp_sp) || (tp_pointer > (tp_frame *)tpstackbase) + && ((tp_pointer < (tp_frame *)tp_sp) || (tp_pointer > (tp_frame *)tpstackbase) || (tp_pointer < (tp_frame *)tpstacktop))) - rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO); } if ((0 != newlevel) && restore_lv) { /* Restore current context (without releasing) */ + assertpro(NULL != tp_pointer); DBGRFCT((stderr, "\n\n** tp_unwind: Newlevel (%d) != 0 loop processing\n", newlevel)); for (restore_ent = tp_pointer->vars; NULL != restore_ent; restore_ent = restore_ent->next) { @@ -198,9 +235,10 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t # ifdef GTM_TRIGGER if (0 != rc) { + dollar_tlevel = tl; /* Record fact if we unwound some levels */ ENABLE_INTERRUPTS(INTRPT_IN_TP_UNWIND); /* drive any MUPIP STOP/signals deferred while * in this function */ - dollar_tlevel = tl; /* Record fact if we unwound some levels */ + TPUNWND_WBOX_TEST; /* Debug-only wbox-test to simulate SIGTERM */ INVOKE_RESTART; } # endif @@ -242,7 +280,7 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t } } assert(0 == lvscan->elemcnt); /* verify no elements queued that were not scanned */ - rollback_locks = (invocation_type != COMMIT_INVOCATION); + rollback_locks = (COMMIT_INVOCATION != invocation_type); for (prior = &mlk_pvt_root, mlkp = *prior; NULL != mlkp; mlkp = *prior) { if (mlkp->granted) @@ -265,11 +303,11 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t mlkp->zalloc = oldlock->zalloc; } } - if (NULL != oldlock && oldlock->tplevel == newlevel) + if ((NULL != oldlock) && (oldlock->tplevel == newlevel)) { /* Remove lock reference from level being unwound to, * now that any {level,zalloc} state information has been restored. */ - assert(NULL == oldlock->next || oldlock->next->tplevel < newlevel); + assert((NULL == oldlock->next) || (oldlock->next->tplevel < newlevel)); mlkp->tp = oldlock->next; /* update root reference pointer */ free(oldlock); } else @@ -315,7 +353,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc */ if (curr_symval != tp_pointer->sym) { /* Unwind as many stackframes as are necessary up to the max */ - while(curr_symval != tp_pointer->sym && frame_pointer < tp_pointer->fp) + while((curr_symval != tp_pointer->sym) && (frame_pointer < tp_pointer->fp)) { # ifdef GTM_TRIGGER if (SFT_TRIGR & frame_pointer->type) @@ -335,15 +373,14 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc if (curr_symval != tp_pointer->sym) { /* Unwind as many mv_stents as are necessary up to the max */ mvc = mv_chain; - while(curr_symval != tp_pointer->sym && mvc < tp_pointer->mvc) + while((curr_symval != tp_pointer->sym) && (mvc < tp_pointer->mvc)) { unw_mv_ent(mvc); mvc = (mv_stent *)(mvc->mv_st_next + (char *)mvc); } mv_chain = mvc; /* Final check */ - if (curr_symval != tp_pointer->sym) - GTMASSERT; + assertpro(curr_symval == tp_pointer->sym); } } var_cloned = curr_lv->tp_var->var_cloned; @@ -361,7 +398,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc * it is no longer used) and replace with desired previous lv_val whose use count * was incremented when it was saved. */ - if (curr_lv != (inuse_lv = (lv_val *)tabent->value)) + if (curr_lv != (inuse_lv = (lv_val *)tabent->value)) /* Note assignment */ { if (inuse_lv) DECR_BASE_REF_RQ(tabent, inuse_lv, FALSE); @@ -403,16 +440,8 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc assert(0 < curr_lv->stats.trefcnt); /* No need to copy "stats" as curr_lv is more uptodate */ assert(0 < curr_lv->stats.crefcnt); assert(8 == (OFFSETOF(lv_val, tp_var) - OFFSETOF(lv_val, has_aliascont))); - /* lv_val->has_aliascont/lvmon_mark all initialized in one shot. - * Note: We use "qw_num *" instead of "uint8 *" below because the former works on 32-bit platforms too. - * On 64-bit platforms, this is 1 8-byte move instead of 2 4-byte moves (the latter means more instructions). - * Even though lvmon_mark is maintained only if DEBUG_ALIAS is #defined, we do the copy here unconditionally - * because on 64-bit platforms, a 4-byte copy (of just has_aliascont) is the same as an 8-byte copy - * (of has_aliascont and lvmon_mark). On 32-bit platforms, it saves us one copy but we dont worry about it much. - */ - GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(&curr_lv->has_aliascont));) - NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(&curr_lv->has_aliascont));) - *(RECAST(qw_num *)&curr_lv->has_aliascont) = *(RECAST(qw_num *)&save_lv->has_aliascont); + curr_lv->has_aliascont = save_lv->has_aliascont; + DBGALS_ONLY(curr_lv->lvmon_mark = save_lv->has_aliascont); assert(save_lv->tp_var == curr_lv->tp_var); /* no need to copy this field */ /* save_lv -> curr_lv Copy done */ /* Some fixup may need to be done if the variable was cloned (and thus moved around) */ @@ -422,7 +451,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc assert(LVT_PARENT(lvt_child) == ((lvTreeNode *)curr_lv->tp_var->save_value)); LV_CHILD(save_lv) = NULL; /* now that curr_lv->tp_var->var_cloned has been reset */ LVT_PARENT(lvt_child) = (lvTreeNode *)curr_lv; - if (curr_lv->has_aliascont && NULL != lvscan_anchor) + if (curr_lv->has_aliascont && (NULL != lvscan_anchor)) { /* Some ref counts need to be restored for arrays this tree points to -- but only if the * array contains pointers (alias containers). */ @@ -442,7 +471,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc *lvscan_anchor = newlvscan; lvscan = newlvscan; } - assert(ARY_SCNCNTNR_MAX >= elemindx && 0 <= elemindx); + assert((ARY_SCNCNTNR_MAX >= elemindx) && (0 <= elemindx)); lvscan->ary_scncntnr[elemindx] = curr_lv; } } diff --git a/sr_port/trace_table_types.h b/sr_port/trace_table_types.h index cba6b5d..febc307 100644 --- a/sr_port/trace_table_types.h +++ b/sr_port/trace_table_types.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011 Fidelity Information Services, Inc * + * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,3 +39,4 @@ TRACETYPE(SOCKRFL, RSTGC, "", "buffer_start", "stp_free", "") /* Ditto, value TRACETYPE(SOCKRFL, BEGIN, "chars_read", "buffer_start", "stp_free", "") /* Main line code values start of processing */ TRACETYPE(SOCKRFL, OUTOFBAND, "bytes_read", "chars_read", "buffer_start", "") /* Out-of-band recognized - interrupted */ TRACETYPE(SOCKRFL, EXPBUFGC, "bytes_read", "stp_free", "old_stp_free", "max_bufflen") /* Buffer expansion */ +TRACETYPE(SOCKRFL, RDSTATUS, "read_status", "out_of_band", "out_of_time", "") /* Read results */ diff --git a/sr_port/trans_code.c b/sr_port/trans_code.c index fd62aee..fc8ae78 100644 --- a/sr_port/trans_code.c +++ b/sr_port/trans_code.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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" #ifdef UNIX -#include "io.h" +# include "io.h" #endif - #include "error.h" #include "indir_enum.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "stack_frame.h" #include "stringpool.h" @@ -39,8 +38,8 @@ #include "gdskill.h" #include "jnl.h" #ifdef GTM_TRIGGER -#include "gv_trigger.h" -#include "gtm_trigger.h" +# include "gv_trigger.h" +# include "gtm_trigger.h" #endif #define POP_SPECIFIED ((ztrap_form & ZTRAP_POP) && (level2go = MV_FORCE_INTD(&ztrap_pop2level))) /* note: assignment */ @@ -56,9 +55,7 @@ GBLREF mval dollar_etrap; GBLREF unsigned char *msp, *stackwarn, *stacktop; GBLREF mv_stent *mv_chain; GBLREF unsigned char *restart_pc, *restart_ctxt; -#ifdef UNIX GBLREF io_desc *gtm_err_dev; -#endif error_def(ERR_ASSERT); error_def(ERR_CTRAP); @@ -134,13 +131,13 @@ CONDITION_HANDLER(trans_code_ch) START_CH; /* Treat $ZTRAP (and DEVICE exception action) as the target entryref for an implicit GOTO */ - if (DUMPABLE || /* fatal error; we test for STACKOFLOW as part of DUMPABLE test */ - (int)ERR_STACKCRIT == SIGNAL || /* successfully compiled ${Z,E}TRAP code but encountered STACK error while attempting - * to push new frame, OR, STACK error while executing $ZTRAP entryref - */ - !(ztrap_form & ZTRAP_ENTRYREF) || /* user doesn't want ENTRYREF form for $ZTRAP */ - !(ztrap_form & ZTRAP_CODE) || /* error during $ZTRAP ENTRYREF processing */ - IS_ETRAP) /* error compiling $ETRAP code */ + if (DUMPABLE /* fatal error; we test for STACKOFLOW as part of DUMPABLE test */ + || (int)ERR_STACKCRIT == SIGNAL /* Successfully compiled ${Z,E}TRAP code but encountered STACK error while + * attempting to push new frame, OR, STACK error while executing $ZTRAP entryref + */ + || !(ztrap_form & ZTRAP_ENTRYREF) /* User doesn't want ENTRYREF form for $ZTRAP */ + || !(ztrap_form & ZTRAP_CODE) /* Error during $ZTRAP ENTRYREF processing */ + || IS_ETRAP) /* Error compiling $ETRAP code */ { NEXTCH; } @@ -165,13 +162,19 @@ CONDITION_HANDLER(trans_code_ch) TREF(trans_code_pop) = push_mval(&dummy); } op_commarg(TREF(trans_code_pop), indir_goto); -#ifdef UNIX if (NULL != gtm_err_dev) { - remove_rms(gtm_err_dev); + if ((gtmsocket == gtm_err_dev->type) && gtm_err_dev->newly_created) + { + assert(gtm_err_dev->state != dev_open); + iosocket_destroy(gtm_err_dev); + } +# ifdef UNIX + if (gtmsocket != gtm_err_dev->type) + remove_rms(gtm_err_dev); +# endif gtm_err_dev = NULL; } -#endif trans_code_finish(); UNWIND(NULL, NULL); } @@ -206,17 +209,22 @@ void trans_code(void) dummy.mvtype = MV_STR; dummy.str = *err_act; TREF(trans_code_pop) = push_mval(&dummy); - ESTABLISH(trans_code_ch); op_commarg(TREF(trans_code_pop), ((ztrap_form & ZTRAP_CODE) || IS_ETRAP) ? indir_linetail : indir_goto); REVERT; -# ifdef UNIX if (NULL != gtm_err_dev) { - remove_rms(gtm_err_dev); +# ifdef UNIX + if (gtmsocket != gtm_err_dev->type) + remove_rms(gtm_err_dev); +# endif + if ((gtmsocket == gtm_err_dev->type) && gtm_err_dev->newly_created) + { + assert(gtm_err_dev->state != dev_open); + iosocket_destroy(gtm_err_dev); + } gtm_err_dev = NULL; } -# endif trans_code_finish(); return; } diff --git a/sr_port/trans_code_cleanup.c b/sr_port/trans_code_cleanup.c index 12473a9..29d0041 100644 --- a/sr_port/trans_code_cleanup.c +++ b/sr_port/trans_code_cleanup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "stringpool.h" #include "objlabel.h" @@ -35,9 +35,6 @@ GBLREF io_desc *active_device; GBLREF boolean_t ztrap_explicit_null; error_def(ERR_STACKCRIT); -error_def(ERR_ERRWZTRAP); -error_def(ERR_ERRWETRAP); -error_def(ERR_ERRWIOEXC); void trans_code_cleanup(void) { @@ -106,6 +103,7 @@ void trans_code_cleanup(void) } else if ((ERR_ERRWZBRK == errmsg) || (ERR_ERRWEXC == errmsg)) { /* For typical exceptions in ZBREAK and ZSTEP, get back to direct mode */ dm_setup(); + fp = frame_pointer; /* Let code at end see direct mode is current frame */ break; } else { /* The only known way to be here is if the command is a command given in direct mode as @@ -133,11 +131,19 @@ void trans_code_cleanup(void) IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(fp); fp->mpc = CODE_ADDRESS(pseudo_ret); fp->ctxt = GTM_CONTEXT(pseudo_ret); - fp->flags &= SFF_TRIGR_CALLD_OFF; /* Frame enterable now with mpc reset */ - GTMTRIG_ONLY(DBGTRIGR((stderr, "trans_code_cleanup: turning off SFF_TRIGR_CALLD in frame 0x"lvaddr"\n", + fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ + GTMTRIG_ONLY(DBGTRIGR((stderr, "trans_code_cleanup: turning off SFF_IMPLTSTART_CALLD in frame 0x"lvaddr"\n", frame_pointer))); } TREF(transform) = TRUE; + /* Only put error on console if frame we unwind to is a direct mode frame */ if (0 != errmsg) - dec_err(VARLSTCNT(1) errmsg); + { + ecode_set(errmsg); /* Add error with trap indicator to $ECODE */ + UNIX_ONLY(if (fp->type & SFT_DM)) /* Bypass check for VMS and just push error out */ + { + UNIX_ONLY(PRN_ERROR); /* Can only appear in condition handler in VMS */ + dec_err(VARLSTCNT(1) errmsg); + } + } } diff --git a/sr_port/tripinit.c b/sr_port/tripinit.c index 886b6a2..1b464c0 100644 --- a/sr_port/tripinit.c +++ b/sr_port/tripinit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,9 +45,19 @@ void tripinit(void) mcavailptr = mcavailbase; mcavail = mcavailptr->size; memset(&mcavailptr->data[0], 0, mcavail); - TREF(expr_depth) = 0; TREF(expr_start) = TREF(expr_start_orig) = NULL; TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE; + if (NULL == TREF(side_effect_base)) + { + TREF(side_effect_depth) = INITIAL_SIDE_EFFECT_DEPTH; + TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * INITIAL_SIDE_EFFECT_DEPTH); + memset((char *)TREF(side_effect_base), 0, SIZEOF(boolean_t) * INITIAL_SIDE_EFFECT_DEPTH); + TREF(expr_depth) = 0; + } else + { + while (TREF(expr_depth)) + DECREMENT_EXPR_DEPTH; /* in case of prior errors */ + } mlitmax = mlmax = mvmax = 0; mlabtab = NULL; mvartab = NULL; diff --git a/sr_port/underr.c b/sr_port/underr.c index f855d00..246969b 100644 --- a/sr_port/underr.c +++ b/sr_port/underr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,15 +16,16 @@ #include "lv_val.h" #include "undx.h" -GBLDEF bool undef_inhibit = 0; +GBLREF bool undef_inhibit; LITREF mval literal_null; +error_def(ERR_UNDEF); + mval *underr (mval *start, ...) { mident_fixed name; unsigned char *end; va_list var; - error_def(ERR_UNDEF); va_start (var, start); if (start && undef_inhibit) diff --git a/sr_port/unw_mv_ent.c b/sr_port/unw_mv_ent.c index f2f0778..5a5b474 100644 --- a/sr_port/unw_mv_ent.c +++ b/sr_port/unw_mv_ent.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -18,7 +18,7 @@ #include "gtm_string.h" #include "lv_val.h" -#include "rtnhdr.h" +#include #include "error.h" #include "mv_stent.h" #include "find_mvstent.h" /* for zintcmd_active */ @@ -366,7 +366,7 @@ void unw_mv_ent(mv_stent *mv_st_ent) if (NULL != mv_st_ent->mv_st_cont.mvs_zintdev.io_ptr) { /* This mv_stent has not been processed yet */ rm_ptr = (d_rm_struct *)(mv_st_ent->mv_st_cont.mvs_zintdev.io_ptr->dev_sp); - assert(rm_ptr->pipe || rm_ptr->fifo); + assert(rm_ptr->pipe || rm_ptr->fifo || rm_ptr->follow); rm_ptr->mupintr = FALSE; rm_ptr->pipe_save_state.who_saved = pipewhich_invalid; mv_st_ent->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; @@ -465,10 +465,18 @@ void unw_mv_ent(mv_stent *mv_st_ent) dollar_ztrap = mv_st_ent->mv_st_cont.mvs_trigr.dollar_ztrap_save; ztrap_explicit_null = mv_st_ent->mv_st_cont.mvs_trigr.ztrap_explicit_null_save; } - assert(ctxt >= mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save); + CHECKHIGHBOUND(mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save); + CHECKLOWBOUND(mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save); ctxt = mv_st_ent->mv_st_cont.mvs_trigr.ctxt_save; - assert(((0 == gtm_trigger_depth) && (ch_at_trigger_init == ctxt->ch)) - || (0 < gtm_trigger_depth) && (&mdb_condition_handler == ctxt->ch)); + /* 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))))))); 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 ea07d51..74e1ecc 100644 --- a/sr_port/unw_retarg.c +++ b/sr_port/unw_retarg.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mv_stent.h" #include "tp_frame.h" @@ -32,6 +32,8 @@ #include "compiler.h" #include "parm_pool.h" #include "get_ret_targ.h" +#include "opcode.h" +#include "glvn_pool.h" GBLREF void (*unw_prof_frame_ptr)(void); GBLREF stack_frame *frame_pointer, *zyerr_frame; @@ -159,6 +161,7 @@ int unw_retarg(mval *src, boolean_t alias_return) if (is_tracing_on) (*unw_prof_frame_ptr)(); msp = (unsigned char *)frame_pointer + SIZEOF(stack_frame); + DRAIN_GLVN_POOL_IF_NEEDED; PARM_ACT_UNSTACK_IF_NEEDED; 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", diff --git a/sr_port/unwind_nocounts.c b/sr_port/unwind_nocounts.c index 5d0a3db..0a13cfb 100644 --- a/sr_port/unwind_nocounts.c +++ b/sr_port/unwind_nocounts.c @@ -13,7 +13,7 @@ #include "gtm_stdio.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "tp_frame.h" #include "op.h" diff --git a/sr_port/updhelper_init.c b/sr_port/updhelper_init.c index 5c39fb5..9700a55 100644 --- a/sr_port/updhelper_init.c +++ b/sr_port/updhelper_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2006 Fidelity Information Services, Inc. * + * Copyright 2005, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -93,6 +93,14 @@ GBLREF recvpool_addrs recvpool; GBLREF upd_helper_entry_ptr_t helper_entry; GBLREF uint4 process_id; GBLREF boolean_t is_updhelper; +#ifdef UNIX +GBLREF boolean_t jnlpool_init_needed; +#endif + +error_def(ERR_NOTALLDBOPN); +error_def(ERR_RECVPOOLSETUP); +error_def(ERR_REPLWARN); +error_def(ERR_TEXT); void updhelper_init(recvpool_user who) { @@ -103,11 +111,6 @@ void updhelper_init(recvpool_user who) char proc_name[PROC_NAME_MAXLEN + 1], *proc_prefix; struct dsc$descriptor_s proc_name_desc; #endif - error_def(ERR_RECVPOOLSETUP); - error_def(ERR_TEXT); - error_def(ERR_NOTALLDBOPN); - error_def(ERR_REPLWARN); - is_updhelper = TRUE; getjobnum(); VMS_ONLY(recvpool_init(UPD_HELPER_READER, FALSE, FALSE);) @@ -134,6 +137,7 @@ void updhelper_init(recvpool_user who) break; } } + OPERATOR_LOG_MSG; if (helper == helper_top) { /* did not find my entry possibly due to startup directly from command line as opposed to the desired via-rcvr server */ rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, @@ -142,6 +146,7 @@ void updhelper_init(recvpool_user who) helper_entry = helper; gvinit(); + UNIX_ONLY(jnlpool_init_needed = TRUE); if (!region_init(FALSE)) gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN); return; diff --git a/sr_port/updhelper_reader.c b/sr_port/updhelper_reader.c index 10c2403..977cf5c 100644 --- a/sr_port/updhelper_reader.c +++ b/sr_port/updhelper_reader.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc. * + * Copyright 2005, 2013 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -79,7 +79,7 @@ #endif #ifdef GTM_TRIGGER -#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ +#include /* for rtn_tabent in gv_trigger.h */ #include "gv_trigger.h" #include "tp_set_sgm.h" #endif @@ -108,6 +108,9 @@ GBLREF boolean_t disk_blk_read; LITREF mval literal_hasht; static uint4 last_pre_read_offset; +error_def(ERR_DBCCERR); +error_def(ERR_ERRCALL); + int updhelper_reader(void) { uint4 pre_read_offset; @@ -168,9 +171,9 @@ boolean_t updproc_preread(void) unsigned char buff[MAX_ZWR_KEY_SZ], *end; uint4 write, write_wrap; #endif + DCL_THREADGBL_ACCESS; - error_def(ERR_DBCCERR); - error_def(ERR_ERRCALL); + SETUP_THREADGBL_ACCESS; maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1; upd_proc_local = recvpool.upd_proc_local; recvpool_ctl = recvpool.recvpool_ctl; @@ -218,7 +221,8 @@ boolean_t updproc_preread(void) } if (0 == retries) { - gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, LIT_AND_LEN("Pre-reader"), ERR_ERRCALL, 3, CALLFROM); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DBCCERR, 2, LIT_AND_LEN("Pre-reader"), + ERR_ERRCALL, 3, CALLFROM); return FALSE; } #ifdef REPL_DEBUG @@ -335,6 +339,7 @@ boolean_t updproc_preread(void) && (key_len == keystr->length)) /* If the shared copy changed underneath us, what we copied over is potentially a bad record */ { + TREF(tqread_nowait) = FALSE; /* don't screw up gvcst_root_search */ UPD_GV_BIND_NAME_APPROPRIATE(gd_header, mname, lcl_key, key_len); /* if ^#t do special processing */ /* the above would have set gv_target and gv_cur_region appropriately */ @@ -355,7 +360,11 @@ boolean_t updproc_preread(void) gv_currkey->end = key_len; disk_blk_read = FALSE; DEBUG_ONLY(num_helped++); + TREF(tqread_nowait) = TRUE; + assert(!csa->now_crit); status = gvcst_search(gv_currkey, NULL); + assert(!csa->now_crit); + TREF(tqread_nowait) = FALSE; /* reset as soon as possible */ if (cdb_sc_normal != status) { /* If gvcst_search returns abnormal status, no need to retry since * we are a pre-reader but we need to reset clue to avoid fast-path @@ -365,11 +374,11 @@ boolean_t updproc_preread(void) * non-NULL. But this is not necessarily guaranteed for example if * gvcst_search returns abnormal status due to t_qread returning * NULL (due in turn to the function "wcs_phase2_commit_wait" - * detecting csd->wc_blocked is TRUE and deciding to restart). In - * this case buffaddr will be set to NULL while cr will be non-NULL - * causing srch_status to be inconsistent. Resetting the clue would - * cause this to be freshly initialized next time gvcst_search for - * this gv_target is called. + * detecting csa->nl->wc_blocked is TRUE and deciding to restart). + * In this case buffaddr will be set to NULL while cr will be + * non-NULL causing srch_status to be inconsistent. Resetting the + * clue would cause this to be freshly initialized next time + * gvcst_search for this gv_target is called. */ gv_target->clue.end = 0; } diff --git a/sr_port/updproc.c b/sr_port/updproc.c index e4d0028..da2456c 100644 --- a/sr_port/updproc.c +++ b/sr_port/updproc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -60,7 +60,7 @@ #include "repl_inst_dump.h" /* for "repl_dump_histinfo" prototype */ #endif #ifdef GTM_TRIGGER -#include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */ +#include /* for rtn_tabent in gv_trigger.h */ #include "gv_trigger.h" #include "targ_alloc.h" #endif @@ -99,8 +99,8 @@ #include "error_trap.h" #include "tp_frame.h" #include "gvcst_jrt_null.h" /* for gvcst_jrt_null prototype */ +#include "preemptive_db_clnup.h" -#define MAX_IDLE_HARD_SPINS 1000 /* Fail-safe count to avoid hanging CPU in tight loop while it's idle */ #define UPDPROC_WAIT_FOR_READJNLSEQNO 100 /* ms */ #define UPDPROC_WAIT_FOR_STARTJNLSEQNO 100 /* ms */ @@ -167,60 +167,90 @@ error_def(ERR_TRIGDEFNOSYNC); error_def(ERR_UPDREPLSTATEOFF); /* The below logic does "jnl_ensure_open" and other pre-requisites. This code is very similar to t_end.c */ -#define DO_JNL_ENSURE_OPEN(CSA, JPC) \ -{ \ - jnl_buffer_ptr_t jbp; \ - uint4 jnl_status; \ - \ - assert(CSA = &FILE_INFO(gv_cur_region)->s_addrs); /* so we can use gv_cur_region below */ \ - assert(JPC == CSA->jnl); \ - SET_GBL_JREC_TIME; /* needed for jnl_put_jrt_pini() */ \ - jbp = JPC->jnl_buff; \ - /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order \ - * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write \ - * journal records (if it decides to switch to a new journal file). \ - */ \ - ADJUST_GBL_JREC_TIME(jgbl, jbp); \ - /* Make sure timestamp of this seqno is >= timestamp of previous seqno. Note: The below \ - * macro invocation should be done AFTER the ADJUST_GBL_JREC_TIME call as the below resets \ - * jpl->prev_jnlseqno_time. Doing it the other way around would mean the reset will happen \ - * with a potentially lower value than the final adjusted time written in the jnl record. \ - */ \ - ADJUST_GBL_JREC_TIME_JNLPOOL(jgbl, jnlpool_ctl); \ - if (JNL_ENABLED(CSA)) \ - { \ - jnl_status = jnl_ensure_open(); \ - if (0 == jnl_status) \ - { \ - if (0 == JPC->pini_addr) \ - jnl_put_jrt_pini(CSA); \ - } else \ - { \ - if (SS_NORMAL != JPC->status) \ - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \ - DB_LEN_STR(gv_cur_region), JPC->status); \ - else \ - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \ - DB_LEN_STR(gv_cur_region)); \ - } \ - } \ +#define DO_JNL_ENSURE_OPEN(CSA, JPC) \ +{ \ + jnl_buffer_ptr_t jbp; \ + uint4 jnl_status; \ + \ + assert(CSA = &FILE_INFO(gv_cur_region)->s_addrs); /* so we can use gv_cur_region below */ \ + assert(JPC == CSA->jnl); \ + SET_GBL_JREC_TIME; /* needed for jnl_put_jrt_pini() */ \ + jbp = JPC->jnl_buff; \ + /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order \ + * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write \ + * journal records (if it decides to switch to a new journal file). \ + */ \ + ADJUST_GBL_JREC_TIME(jgbl, jbp); \ + /* Make sure timestamp of this seqno is >= timestamp of previous seqno. Note: The below \ + * macro invocation should be done AFTER the ADJUST_GBL_JREC_TIME call as the below resets \ + * jpl->prev_jnlseqno_time. Doing it the other way around would mean the reset will happen \ + * with a potentially lower value than the final adjusted time written in the jnl record. \ + */ \ + ADJUST_GBL_JREC_TIME_JNLPOOL(jgbl, jnlpool_ctl); \ + if (JNL_ENABLED(CSA)) \ + { \ + jnl_status = jnl_ensure_open(); \ + if (0 == jnl_status) \ + { \ + if (0 == JPC->pini_addr) \ + jnl_put_jrt_pini(CSA); \ + } else \ + { \ + if (SS_NORMAL != JPC->status) \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \ + DB_LEN_STR(gv_cur_region), JPC->status); \ + else \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \ + DB_LEN_STR(gv_cur_region)); \ + } \ + } \ } #ifdef UNIX -# define UPDPROC_ONLN_RLBK_CLNUP(REG) \ -{ \ - sgmnt_addrs *csa; \ - \ - assert(0 != have_crit(CRIT_HAVE_ANY_REG)); \ - csa = &FILE_INFO(REG)->s_addrs; \ - assert(csa->now_crit); \ - SYNC_ONLN_RLBK_CYCLES; \ - if (REG == jnlpool.jnlpool_dummy_reg) \ - rel_lock(REG); \ - else \ - rel_crit(REG); \ - RESET_ALL_GVT_CLUES; \ - rts_error(VARLSTCNT(1) ERR_REPLONLNRLBK); /* transfers control back to updproc_ch */ \ +# define UPDPROC_ONLN_RLBK_CLNUP(REG) \ +{ \ + sgmnt_addrs *csa; \ + \ + assert(0 != have_crit(CRIT_HAVE_ANY_REG)); \ + csa = &FILE_INFO(REG)->s_addrs; \ + assert(csa->now_crit); \ + SYNC_ONLN_RLBK_CYCLES; \ + if (REG == jnlpool.jnlpool_dummy_reg) \ + rel_lock(REG); \ + else \ + rel_crit(REG); \ + RESET_ALL_GVT_CLUES; \ + /* transfers control back to updproc_ch */ \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLONLNRLBK); \ +} + +/* Receiver eventually sees the upd_proc_local->onln_rlbk_flag being set, drains the replication pipe, closes the connection and + * restarts. But, before that it also resets recvpool_ctl->jnl_seqno to 0. So, wait until recvpool_ctl->jnl_seqno is reset to 0 + * to be sure that receiver server did acknowledge the upd_proc_local->onln_rlbk_flag. + */ +#define WAIT_FOR_ZERO_RECVPOOL_JNL_SEQNO \ +{ \ + repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Waiting for receiver server to reset recvpool_ctl->jnl_seqno\n"); \ + while (recvpool_ctl->jnl_seqno) \ + { \ + SHORT_SLEEP(UPDPROC_WAIT_FOR_STARTJNLSEQNO); \ + if (SHUTDOWN == upd_proc_local->upd_proc_shutdown) \ + { \ + updproc_end(); \ + return SS_NORMAL; \ + } \ + } \ +} + +#define LOG_ONLINE_ROLLBACK_EVENT \ +{ \ + repl_log(updproc_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n"); \ + repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : %llu\n", jnlpool.jnlpool_ctl->jnl_seqno); \ + repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Update process Read Seqno : %llu\n", \ + upd_proc_local->read_jnl_seqno); \ + assert(recvpool_ctl->jnl_seqno); \ + repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Receive Pool Seqno : %llu\n", \ + recvpool_ctl->jnl_seqno); \ } #endif @@ -240,7 +270,7 @@ CONDITION_HANDLER(updproc_ch) INT8_PRINT(recvpool.upd_proc_local->read_jnl_seqno), INT8_PRINTX(recvpool.upd_proc_local->read_jnl_seqno)); /* This is a kludge. We can come here from 2 places. - * ( i) From a call to t_retry which does a rts_error(ERR_TPRETRY). + * ( i) From a call to t_retry which does a rts_error(ERR_TPRETRY) * (ii) From updproc_actions() where immediately after op_tcommit we detect that dollar_tlevel is non-zero. * In the first case, we need to do a tp_restart. In the second, op_tcommit would have already done it for us. * The way we detect the second case is from the value of first_sgm_info since it is NULLified in tp_restart. @@ -288,6 +318,8 @@ CONDITION_HANDLER(updproc_ch) # ifdef UNIX else if (ERR_REPLONLNRLBK == SIGNAL) { + preemptive_db_clnup(SEVERITY); + assert(INVALID_GV_TARGET == reset_gv_target); set_onln_rlbk_flg = TRUE; UNWIND(NULL, NULL); } @@ -312,6 +344,7 @@ int updproc(void) struct dsc$descriptor_s proc_name_desc; # endif upd_proc_local_ptr_t upd_proc_local; + sgmnt_addrs *repl_csa; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -324,7 +357,7 @@ int updproc(void) proc_name_desc.dsc$b_dtype = DSC$K_DTYPE_T; proc_name_desc.dsc$b_class = DSC$K_CLASS_S; if (SS$_NORMAL != (status = sys$setprn(&proc_name_desc))) - rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to change update process name"), status); # else /* In the update process, we want every replicated update from an originating instances to end up in a replicated region @@ -344,8 +377,13 @@ int updproc(void) NON_GTMTRIG_ONLY(skip_dbtriggers = TRUE;) memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool)); /* For util_base_ch and mupip_exit */ if (updproc_init(&gld_db_files, &start_jnl_seqno) == UPDPROC_EXISTS) /* we got the global directory header already */ - rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process already exists")); + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, + ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process already exists")); + } + OPERATOR_LOG_MSG; /* Initialization of all the relevant global datastructures and allocation for TP */ + repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; mu_gv_stack_init(); upd_proc_local = recvpool.upd_proc_local; recvpool_ctl = recvpool.recvpool_ctl; @@ -393,6 +431,18 @@ int updproc(void) recvpool.upd_helper_ctl->pre_read_offset = 0; } } + if (repl_csa->onln_rlbk_cycle != jnlpool_ctl->onln_rlbk_cycle) + { /* A concurrent online rollback. Handle it */ + LOG_ONLINE_ROLLBACK_EVENT; + assert(!repl_csa->now_crit && !set_onln_rlbk_flg); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); + SYNC_ONLN_RLBK_CYCLES; + rel_lock(jnlpool.jnlpool_dummy_reg); + upd_proc_local->onln_rlbk_flg = TRUE; /* let receiver know about the online rollback */ + WAIT_FOR_ZERO_RECVPOOL_JNL_SEQNO; + upd_proc_local->read = 0; + recvpool_ctl->jnl_seqno = jnl_seqno; + } } /* Ensure all updates done by the receiver server BEFORE setting * upd_proc_local->read_jnl_seqno are visible once we see the updated read_jnl_seqno. @@ -419,7 +469,7 @@ int updproc(void) repl_log(updproc_log_fp, TRUE, TRUE, "JNLSEQNO of last transaction written to journal pool = "INT8_FMT" "INT8_FMTX"\n", INT8_PRINT(jnlpool_ctl->jnl_seqno), INT8_PRINTX(jnlpool_ctl->jnl_seqno)); - rts_error(VARLSTCNT(1) ERR_SECONDAHEAD); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SECONDAHEAD); } # else /* The SECONDAHEAD check is performed in the receiver server after it has connected with the source @@ -441,32 +491,9 @@ int updproc(void) { /* A concurrent online rollback happened which drove the updproc_ch and called us. Need to let the receiver * server know about it and set up the sequence numbers */ - start_jnl_seqno = jnlpool_ctl->jnl_seqno; - repl_log(updproc_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n"); - repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : %llu\n", start_jnl_seqno); - repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Update process Read Seqno : %llu\n", - upd_proc_local->read_jnl_seqno); - repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Receive Pool Seqno : %llu\n", - recvpool_ctl->jnl_seqno); - - assert(recvpool_ctl->jnl_seqno); - upd_proc_local->onln_rlbk_flg = TRUE; - /* receiver server eventually sees the above flag, drains the replication pipe, closes the connection and - * restarts. But, before that it sets recvpool_ctl->jnl_seqno to 0. We wait until receiver server resets - * this field. This way, when we go back to the beginning of the for loop to set recvpool_ctl->jnl_seqno - * to start_jnl_seqno, our update will not be lost. - */ - repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Waiting for receiver server to reset " - "recvpool_ctl->jnl_seqno\n"); - while (recvpool_ctl->jnl_seqno) - { - SHORT_SLEEP(UPDPROC_WAIT_FOR_STARTJNLSEQNO); - if (SHUTDOWN == upd_proc_local->upd_proc_shutdown) - { - updproc_end(); - return(SS_NORMAL); - } - } + LOG_ONLINE_ROLLBACK_EVENT; + upd_proc_local->onln_rlbk_flg = TRUE; /* let receiver know about the online rollback */ + WAIT_FOR_ZERO_RECVPOOL_JNL_SEQNO; set_onln_rlbk_flg = FALSE; /* Since we are going to start afresh, do a OP_TROLLBACK if we are in TP. This brings the global variables * dollar_tlevel, dollar_trestart all to a known state thereby erasing any history of lingering TP artifacts @@ -477,6 +504,7 @@ int updproc(void) assert(!dollar_tlevel); assert(!dollar_trestart); } + start_jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno; /* needed when we go back to the beginning of the loop */ } else # endif if (!updproc_continue) @@ -506,32 +534,29 @@ void updproc_actions(gld_dbname_list *gld_db_files) jnl_string *keystr; mstr mname; char *key, *keytop; + gv_key *gv_failed_key = NULL, *gv_failed_key_ptr; + unsigned char *endBuff, fmtBuff[MAX_ZWR_KEY_SZ]; enum upd_bad_trans_type bad_trans_type; recvpool_ctl_ptr_t recvpool_ctl; upd_proc_local_ptr_t upd_proc_local; gtmrecv_local_ptr_t gtmrecv_local; upd_helper_ctl_ptr_t upd_helper_ctl; - sgmnt_addrs *csa, *repl_csa; + sgmnt_addrs *csa, *repl_csa, *tmpcsa = NULL; sgmnt_data_ptr_t csd; char gv_mname[MAX_KEY_SZ]; unsigned char buff[MAX_ZWR_KEY_SZ], *end, scan_char, next_char; boolean_t log_switched = FALSE; # ifdef UNIX boolean_t suppl_root_primary, suppl_propagate_primary; + repl_histinfo histinfo; + repl_old_triple_jnl_t *input_old_triple; + repl_histrec_jnl_ptr_t input_histjrec; + uint4 expected_rec_len; # endif jnl_private_control *jpc; gld_dbname_list *curr; gd_region *save_reg; - int4 wtstart_errno; - boolean_t buffers_flushed; - uint4 idle_flush_count = 0; /* Number of times buffers were flushed without an intermediate sleep */ uint4 write_wrap, cntr, last_nullsubs, last_subs, keyend; - UNIX_ONLY( - repl_histinfo histinfo; - repl_old_triple_jnl_ptr_t input_old_triple; - repl_histrec_jnl_ptr_t input_histjrec; - uint4 expected_rec_len; - ) # ifdef GTM_TRIGGER uint4 nodeflags; boolean_t primary_has_trigdef, secondary_has_trigdef; @@ -646,63 +671,16 @@ void updproc_actions(gld_dbname_list *gld_db_files) */ assert((0 == recvpool.recvpool_ctl->jnl_seqno) || (jnl_seqno <= recvpool.recvpool_ctl->jnl_seqno)); /* the 0 == check takes care of the startup case where jnl_seqno is 0 in the recvpool_ctl */ - /* If any dirty buffers, write them out since nothing else is happening now. - * wcs_wtstart only writes a few buffer a call and putting the call in a loop would flush the - * entire dirty buffer set, but there is no need for a loop around the call since we're already in - * the main updproc loop and this is the only place it really sleeps. */ - save_reg = gv_cur_region; - /* Make sure cs_addrs and cs_data are in sync with gv_cur_region before TP_CHANGE_REG changes them */ - assert((NULL == gv_cur_region) || (cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs)); - assert((NULL == gv_cur_region) || (cs_data == cs_addrs->hdr)); - buffers_flushed = FALSE; - for (curr = gld_db_files; NULL != curr; curr = curr->next) - { - TP_CHANGE_REG(curr->gd); - if (cs_addrs->nl->wcs_active_lvl && (FALSE == gv_cur_region->read_only)) - { - DCLAST_WCS_WTSTART(gv_cur_region, 0, wtstart_errno); - /* DCLAST_WCS_WTSTART macro does not set the wtstart_errno variable in VMS. But in - * any case, we do not support database file extensions with MM on VMS. So we could - * never get a ERR_GBLOFLOW error there. Therefore the file extension check below is - * done only in Unix. - */ -# ifdef UNIX - if ((dba_mm == cs_data->acc_meth) && (ERR_GBLOFLOW == wtstart_errno)) - { - assert(!cs_addrs->hold_onto_crit); - grab_crit(gv_cur_region); - if (cs_addrs->onln_rlbk_cycle != cs_addrs->nl->onln_rlbk_cycle) - UPDPROC_ONLN_RLBK_CLNUP(gv_cur_region); /* No return */ - wcs_recover(gv_cur_region); - rel_crit(gv_cur_region); - } -# endif - buffers_flushed = TRUE; - } - } - TP_CHANGE_REG(save_reg); - /* To avoid a potential infinite cpu-bound loop if the wcs_active_lvl field is bogus and wcs_wtstart() - * returns immediately, we count the number of times a buffer flush has (potentially) occurred. When - * this count gets to an arbitrarily "large" value or there were no buffers to flush, we will sleep - * and start the count over again. If there are more than the "large" number of dirty buffers to flush, - * this logic only causes an extra benign sleep whenever the count is "large". */ - if (buffers_flushed && (MAX_IDLE_HARD_SPINS > idle_flush_count)) - idle_flush_count++; - else - { - idle_flush_count = 0; - SHORT_SLEEP(10); - } + SHORT_SLEEP(10); # ifdef UNIX if (!upd_proc_local->onln_rlbk_flg && (repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle)) { /* A concurrent online rollback happened. Start afresh */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */ } /* else onln_rlbk_flag is already set and the receiver should take the next appropriate action */ # endif continue; } - idle_flush_count = 0; /* The update process reads "recvpool_ctl->write" first and assumes that all data in the receive pool * that it then reads (upto the "write" offset) is valid. In order for this assumption to hold good, the * receiver server needs to do a write memory barrier after updating the receive pool data but before @@ -882,7 +860,7 @@ void updproc_actions(gld_dbname_list *gld_db_files) rel_crit(gv_cur_region); } TP_CHANGE_REG(save_reg); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY) + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); if (repl_csa->onln_rlbk_cycle != jnlpool_ctl->onln_rlbk_cycle) UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */ jnlpool_ctl->strm_seqno[histinfo.strm_index] = strm_seqno; @@ -895,7 +873,7 @@ void updproc_actions(gld_dbname_list *gld_db_files) assert(jnlpool.jnlpool_ctl->upd_disabled || (strm_index == histinfo.strm_index)); } /* Now that we have constructed the history, add it to the instance file. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY) + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); if (repl_csa->onln_rlbk_cycle != jnlpool_ctl->onln_rlbk_cycle) UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */ repl_inst_histinfo_add(&histinfo); @@ -1025,21 +1003,26 @@ void updproc_actions(gld_dbname_list *gld_db_files) } if (upd_good_record == bad_trans_type) { - UNIX_ONLY( - if (suppl_propagate_primary) +# ifdef UNIX + if (suppl_propagate_primary) + { + rec_strm_seqno = GET_STRM_SEQNO(rec); + strm_index = GET_STRM_INDEX(rec_strm_seqno); + rec_strm_seqno = GET_STRM_SEQ60(rec_strm_seqno); + strm_seqno = jnlpool_ctl->strm_seqno[strm_index]; + /* In the event of a concurrent ONLINE ROLLBACK, it is likely that the strm_seqno is less than + * rec_strm_seqno. In that case, do not issue STRMSEQMISMTCH error as that would be incorrect. + * Instead, continue and eventually, either the update process or the transaction processing logic + * will detect the online rollback and take appropriate action. + */ + if ((rec_strm_seqno != strm_seqno) && (repl_csa->onln_rlbk_cycle == jnlpool_ctl->onln_rlbk_cycle)) { - rec_strm_seqno = GET_STRM_SEQNO(rec); - strm_index = GET_STRM_INDEX(rec_strm_seqno); - rec_strm_seqno = GET_STRM_SEQ60(rec_strm_seqno); - strm_seqno = jnlpool_ctl->strm_seqno[strm_index]; - if (rec_strm_seqno != strm_seqno) - { - assert(FALSE); - rts_error(VARLSTCNT(5) ERR_STRMSEQMISMTCH, 3, - strm_index, &rec_strm_seqno, &strm_seqno); - } + assert(FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_STRMSEQMISMTCH, 3, + strm_index, &rec_strm_seqno, &strm_seqno); } - ) + } +# endif if (JRT_NULL == rectype) { /* Play the NULL transaction into the database and journal files */ save_reg = gv_cur_region; @@ -1108,7 +1091,7 @@ void updproc_actions(gld_dbname_list *gld_db_files) * the journal seqno on the secondary database will get out-of-sync with that of * the primary database. */ - gtm_putmsg(VARLSTCNT(6) ERR_UPDREPLSTATEOFF, 4, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_UPDREPLSTATEOFF, 4, mname.len, mname.addr, DB_LEN_STR(gv_cur_region)); /* Shut down the update process normally */ upd_proc_local->upd_proc_shutdown = SHUTDOWN; @@ -1120,6 +1103,7 @@ void updproc_actions(gld_dbname_list *gld_db_files) if (gv_currkey->end + 1 > gv_cur_region->max_key_size) { bad_trans_type = upd_bad_key_size; + tmpcsa = csa; assert(gtm_white_box_test_case_enabled && (WBTEST_UPD_PROCESS_ERROR == gtm_white_box_test_case_number)); } else @@ -1200,10 +1184,11 @@ void updproc_actions(gld_dbname_list *gld_db_files) else { assert(IS_SET(rectype)); - if (keystr->length + 1 + val_mv.str.len + SIZEOF(rec_hdr) > + if (VMS_ONLY(keystr->length + 1 + SIZEOF(rec_hdr) +) val_mv.str.len > gv_cur_region->max_rec_size) { bad_trans_type = upd_bad_val_size; + tmpcsa = csa; assert(gtm_white_box_test_case_enabled && (WBTEST_UPD_PROCESS_ERROR == gtm_white_box_test_case_number)); } else @@ -1228,9 +1213,9 @@ void updproc_actions(gld_dbname_list *gld_db_files) trigdef_inst = "replicating"; no_trigdef_inst = "originating"; } - send_msg(VARLSTCNT(9) ERR_TRIGDEFNOSYNC, 7, mname.len, mname.addr, - LEN_AND_STR(trigdef_inst), LEN_AND_STR(no_trigdef_inst), - &jnl_seqno); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_TRIGDEFNOSYNC, 7, + mname.len, mname.addr, LEN_AND_STR(trigdef_inst), + LEN_AND_STR(no_trigdef_inst), &jnl_seqno); } } # endif @@ -1269,7 +1254,9 @@ void updproc_actions(gld_dbname_list *gld_db_files) */ assert(0 == have_crit(CRIT_HAVE_ANY_REG)); if (dollar_tlevel) - { + { /* Copy gv_currkey into temp variable before TROLLBACK overwrites the current variable. */ + gv_failed_key = (gv_key *)malloc(SIZEOF(gv_key) + gv_currkey->end); + memcpy(gv_failed_key, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); repl_log(updproc_log_fp, TRUE, TRUE, "OP_TROLLBACK IS CALLED -->Bad trans :: dollar_tlevel = %ld\n", dollar_tlevel); OP_TROLLBACK(0); /* this should also release crit (if any) on all regions in TP */ @@ -1291,26 +1278,53 @@ void updproc_actions(gld_dbname_list *gld_db_files) temp_read = 0; temp_write = 0; upd_rec_seqno = tupd_num = tcom_num = 0; - /* Throw an error if bad_trans comes for the same sequence number */ + /* KEY2BIG and REC2BIG are cases for which we need to make sure it is not a transmission hiccup before we + * go ahead and do the rts_error(GVSUBOFLOW) or rts_error(REC2BIG). That is the reason we give those two + * errors a second chance. Other errors are handled by either throwing an rts_error or asking for an + * unconditional re-transmission (as opposed to only two attempts for GVSUBOFLOW and REC2BIG). By asking for + * a re-transmission we increase our confidence level that this is a configuration issue (with smaller + * keysize on the secondary) and proceed with an rts_error if we see the same symptom. It is possible we + * might have two successive transmissions having the exact same corruption, but that is highly unlikely. + */ if (last_errored_seqno == jnl_seqno) { last_errored_seqno = 0; switch(bad_trans_type) { - case upd_bad_key_size: - ISSUE_GVSUBOFLOW_ERROR(gv_currkey); + case upd_bad_key_size: /* Not using ISSUE_GVSUBOFLOW_ERROR in order to free gv_failed_key */ + gv_failed_key_ptr = ((NULL == gv_failed_key) ? gv_currkey : gv_failed_key); + /* Assert that input key to format_targ_key is double null terminated */ + assert(KEY_DELIMITER == gv_failed_key_ptr->base[gv_failed_key_ptr->end]); + /* Note: might update "endBuff" */ + endBuff = format_targ_key(fmtBuff, ARRAYSIZE(fmtBuff), gv_failed_key_ptr, TRUE); + GV_SET_LAST_SUBSCRIPT_INCOMPLETE(fmtBuff, endBuff); + if (NULL != gv_failed_key) /* Free memory if it has been used */ + free(gv_failed_key); + assert(NULL != tmpcsa); + rts_error_csa(CSA_ARG(tmpcsa) VARLSTCNT(6) ERR_GVSUBOFLOW, 0, + ERR_GVIS, 2, endBuff - fmtBuff, fmtBuff); break; case upd_bad_val_size: - if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) + if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, + ((NULL == gv_failed_key) ? gv_currkey : gv_failed_key), TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, - gv_currkey->end + 1 + val_mv.str.len + SIZEOF(rec_hdr), + if (NULL != gv_failed_key) /* Free memory if it has been used */ + free(gv_failed_key); + 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), ERR_GVIS, 2, end - buff, buff); break; } } else + { + gv_currkey->base[0] = KEY_DELIMITER; last_errored_seqno = jnl_seqno; + /* Free memory on the first unsuccessful attempt if gv_failed_key has been previously used */ + if (NULL != gv_failed_key) + free(gv_failed_key); + } continue; } if (incr_seqno) @@ -1336,14 +1350,19 @@ void updproc_actions(gld_dbname_list *gld_db_files) { /* Now that the update process has played an incoming seqno, we expect it to have incremented * the corresponding jnl_seqno and strm_seqno fields in the current instance's journal pool * as well. Not doing so will cause the source and receiver instances to go out of sync. - * We know of 3 ways in which this can occur and all of them have already been handled. + * We know of 4 ways in which this can occur and all of them have already been handled. * 1) UPDREPLSTATEOFF error. * 2) error_on_jnl_file_lost = JNL_FILE_LOST_ERRORS; * 3) Duplicate KILL is journaled and increments seqno even though it does not touch db. - * Therefore if we find any out-of-sync situation at this point, we should stop right away - * and get a core dump for further analysis. So GTMASSERT. + * 4) A concurrent online rollback on this instance + * First 3 cases are not expected in a typical update process. But, the 4th case is expected in a + * typical run. So, as long as the out-of-sync is due to the first 3 cases, stop right away and get + * a core dump for further analysis. In case of an online rollback, it is okay for us to continue + * to the next iteration which will eventually detect the online rollback (as part of commit or + * before that in the idle wait loop) and take appropriate action. */ - if (upd_proc_local->read_jnl_seqno != jnlpool_ctl_seqno) + if ((upd_proc_local->read_jnl_seqno != jnlpool_ctl_seqno) + UNIX_ONLY(&& (repl_csa->onln_rlbk_cycle == jnlpool_ctl->onln_rlbk_cycle))) { repl_log(updproc_log_fp, TRUE, TRUE, "JNLSEQNO last updated by update process = "INT8_FMT" "INT8_FMTX"\n", diff --git a/sr_port/updproc_end.c b/sr_port/updproc_end.c index 4d82197..c214371 100644 --- a/sr_port/updproc_end.c +++ b/sr_port/updproc_end.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -62,11 +62,13 @@ #include "repl_log.h" #ifdef UNIX #include "mutex.h" +#include "anticipatory_freeze.h" #endif #include "gtm_event_log.h" #include "mupip_exit.h" #include "read_db_files_from_gld.h" #include "updproc.h" +#include "have_crit.h" GBLREF gd_region *gv_cur_region; GBLREF recvpool_addrs recvpool; @@ -80,13 +82,17 @@ GBLREF FILE *updproc_log_fp; void updproc_stop(boolean_t exit) { int4 status; - int fclose_res, idx; + int fclose_res, idx, save_errno; seq_num log_seqno, log_seqno1, jnlpool_seqno, jnlpool_strm_seqno[MAX_SUPPL_STRMS]; sgmnt_addrs *repl_csa; UNIX_ONLY( int4 strm_idx; + DCL_THREADGBL_ACCESS; ) + UNIX_ONLY( + SETUP_THREADGBL_ACCESS; + ) call_on_signal = NULL; /* Don't reenter on error */ if (pool_init) { @@ -114,23 +120,23 @@ void updproc_stop(boolean_t exit) # endif repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Update process Read Seqno : %llu\n", log_seqno1); repl_log(updproc_log_fp, TRUE, TRUE, "REPL INFO - Current Receive Pool Seqno : %llu\n", log_seqno); - /* nullify jnlpool_ctl before detaching from jnlpool since if it is the other way, we might be interrupted - * by the periodic timer routines and end up in jnl_write_epoch_rec() routine that dereferences jnlpool_ctl - * since it is non-NULL although it has been detached from and is no longer valid memory. - */ - jnlpool_ctl = NULL; -#ifdef UNIX - mutex_cleanup(jnlpool.jnlpool_dummy_reg); - SHMDT(jnlpool.jnlpool_ctl); -#elif defined(VMS) +# ifdef UNIX + if (!ANTICIPATORY_FREEZE_AVAILABLE) + { + mutex_cleanup(jnlpool.jnlpool_dummy_reg); + JNLPOOL_SHMDT(status, save_errno); + if (0 > status) + repl_log(stderr, TRUE, TRUE, "Error detaching from jnlpool : %s\n", STRERROR(save_errno)); + } +# elif defined(VMS) + jnlpool_ctl = jnlpool.jnlpool_ctl = NULL; if (SS$_NORMAL != (status = detach_shm(jnlpool.shm_range))) repl_log(stderr, TRUE, TRUE, "Error detaching from jnlpool : %s\n", REPL_STR_ERROR); if (SS$_NORMAL != (status = signoff_from_gsec(jnlpool.shm_lockid))) repl_log(stderr, TRUE, TRUE, "Error dequeueing lock on jnlpool global section : %s\n", REPL_STR_ERROR); -#else -#error Unsupported Platform -#endif - jnlpool.jnlpool_ctl = NULL; +# else +# error Unsupported Platform +# endif pool_init = FALSE; } recvpool.upd_proc_local->upd_proc_shutdown = NORMAL_SHUTDOWN; diff --git a/sr_port/updproc_init.c b/sr_port/updproc_init.c index 8815b73..eecd1d0 100644 --- a/sr_port/updproc_init.c +++ b/sr_port/updproc_init.c @@ -46,6 +46,10 @@ GBLREF boolean_t pool_init; GBLREF gd_addr *gd_header; GBLREF recvpool_addrs recvpool; +#ifdef UNIX +GBLREF jnlpool_addrs jnlpool; +GBLREF FILE *updproc_log_fp; +#endif error_def(ERR_RECVPOOLSETUP); error_def(ERR_TEXT); @@ -54,6 +58,7 @@ error_def(ERR_UPDATEFILEOPEN); int updproc_init(gld_dbname_list **gld_db_files , seq_num *start_jnl_seqno) { mval v; + int save_errno; uint4 log_file_len; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; @@ -71,13 +76,20 @@ int updproc_init(gld_dbname_list **gld_db_files , seq_num *start_jnl_seqno) */ if (0 != grab_sem_immediate(RECV, UPD_PROC_COUNT_SEM)) { + save_errno = errno; if (REPL_SEM_NOT_GRABBED) - return(UPDPROC_EXISTS); + return UPDPROC_EXISTS; else rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Receive pool semop error"), REPL_SEM_ERRNO); + RTS_ERROR_LITERAL("Receive pool semop error"), UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO)); } jnlpool_init((jnlpool_user)GTMPROC, (boolean_t)FALSE, (boolean_t *)NULL); +# ifdef UNIX + repl_log(updproc_log_fp, TRUE, TRUE, "Attached to existing jnlpool with shmid = [%d] and semid = [%d]\n", + jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid); + repl_log(updproc_log_fp, TRUE, TRUE, "Attached to existing recvpool with shmid = [%d] and semid = [%d]\n", + jnlpool.repl_inst_filehdr->recvpool_shmid, jnlpool.repl_inst_filehdr->recvpool_semid); +# endif gvinit(); /* get the desired global directory and update the gd_map */ *gld_db_files = read_db_files_from_gld(gd_header);/* read all the database files to be opened in this global directory */ if (!updproc_open_files(gld_db_files, start_jnl_seqno)) /* open and initialize all regions */ diff --git a/sr_port/updproc_open_files.c b/sr_port/updproc_open_files.c index c201ba6..2cea8ed 100644 --- a/sr_port/updproc_open_files.c +++ b/sr_port/updproc_open_files.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -168,7 +168,7 @@ boolean_t updproc_open_files(gld_dbname_list **gld_db_files, seq_num *start_jnl_ * loops instead of one is because we don't want to do gvcst_init while holding the journal pool lock as the former * acquires ftok and access control semaphores and holding the journal pool lock is a potential recipe for deadlocks */ - UNIX_ONLY(GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY)); + UNIX_ONLY(grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY)); for (curr = *gld_db_files; NULL != curr; curr = curr->next) { reg = curr->gd; diff --git a/sr_port/urx.h b/sr_port/urx.h index ca26cca..81e0e41 100644 --- a/sr_port/urx.h +++ b/sr_port/urx.h @@ -31,7 +31,7 @@ typedef struct urx_labref_type /* urx_addr_type and associated prototypes can vary by chip or platform */ #include "urxsp.h" -#include "rtnhdr.h" /* Can be removed when all azl* routines are fixed */ +#include /* Can be removed when all azl* routines are fixed */ urx_rtnref *urx_putrtn(char *rtn, int rtnlen, urx_rtnref *anchor); void urx_free(urx_rtnref *anchor); diff --git a/sr_port/urx_add.c b/sr_port/urx_add.c index ae95163..6520986 100644 --- a/sr_port/urx_add.c +++ b/sr_port/urx_add.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "urx.h" GBLREF urx_rtnref urx_anchor; diff --git a/sr_port/urx_addlab.c b/sr_port/urx_addlab.c index 2b42261..7273531 100644 --- a/sr_port/urx_addlab.c +++ b/sr_port/urx_addlab.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "urx.h" urx_labref **urx_addlab (urx_labref **anchor, urx_labref *lp) diff --git a/sr_port/urx_addrtn.c b/sr_port/urx_addrtn.c index 61952a6..abfff36 100644 --- a/sr_port/urx_addrtn.c +++ b/sr_port/urx_addrtn.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "urx.h" urx_rtnref *urx_addrtn(urx_rtnref *rp_start, urx_rtnref *rp) diff --git a/sr_port/urx_free.c b/sr_port/urx_free.c index 6aa6422..f54a5a3 100644 --- a/sr_port/urx_free.c +++ b/sr_port/urx_free.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" /* for urx.h */ +#include /* for urx.h */ #include "urx.h" void urx_free (urx_rtnref *anchor) diff --git a/sr_port/urx_getlab.c b/sr_port/urx_getlab.c index 7ef8d6a..195c6c0 100644 --- a/sr_port/urx_getlab.c +++ b/sr_port/urx_getlab.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" /* for urx.h */ +#include /* for urx.h */ #include "urx.h" bool urx_getlab (char *lab, int lablen, urx_rtnref *rtn, urx_labref **lp0p, urx_labref **lp1p) diff --git a/sr_port/urx_getrtn.c b/sr_port/urx_getrtn.c index ded6191..1b689c3 100644 --- a/sr_port/urx_getrtn.c +++ b/sr_port/urx_getrtn.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" /* for urx.h */ +#include /* for urx.h */ #include "urx.h" bool urx_getrtn (char *rtn, int rtnlen, urx_rtnref **rp0p, urx_rtnref **rp1p, urx_rtnref *anchor) diff --git a/sr_port/urx_putlab.c b/sr_port/urx_putlab.c index abfc95b..44d0f4a 100644 --- a/sr_port/urx_putlab.c +++ b/sr_port/urx_putlab.c @@ -12,7 +12,7 @@ #include "mdef.h" #include #include "gtm_string.h" -#include "rtnhdr.h" /* For urx.h */ +#include /* For urx.h */ #include "urx.h" void urx_putlab (char *lab, int lablen, urx_rtnref *rtn, char *addr) diff --git a/sr_port/urx_putrtn.c b/sr_port/urx_putrtn.c index 044b89b..cfea34c 100644 --- a/sr_port/urx_putrtn.c +++ b/sr_port/urx_putrtn.c @@ -12,7 +12,7 @@ #include "mdef.h" #include #include "gtm_string.h" -#include "rtnhdr.h" /* needed by urx.h */ +#include /* needed by urx.h */ #include "urx.h" urx_rtnref *urx_putrtn (char *rtn, int rtnlen, urx_rtnref *anchor) diff --git a/sr_port/urx_resolve.c b/sr_port/urx_resolve.c index 9cab053..3a58def 100644 --- a/sr_port/urx_resolve.c +++ b/sr_port/urx_resolve.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "urx.h" GBLDEF urx_rtnref urx_anchor; diff --git a/sr_port/util.h b/sr_port/util.h index 978d0d3..fa8ce82 100644 --- a/sr_port/util.h +++ b/sr_port/util.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,7 +36,7 @@ boolean_t util_is_log_open(void); typedef struct { - unsigned int req_code : 08; + unsigned int req_code : 8; unsigned int target : 24; uint4 mess_code; char text[OPER_LOG_SIZE]; @@ -51,10 +51,51 @@ void util_out_write(unsigned char *addr, unsigned int len); 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, ...); -/* util_out_save() and util_out_restore() are UNIX only - called from the UNIX send_msg() */ -void util_out_save(void); -void util_out_restore(void); +#ifdef DEBUG +void util_out_syslog_dump(void); + +#define UTIL_OUT_SYSLOG_INTERVAL 50 #endif +#endif + +/* This value determines how many levels of nesting are allowed for protection of util_outbuff. */ +#define UTIL_OUTBUFF_STACK_SIZE 3 + +/* Save the current va_list and repoint util_outbuff_ptr to the next chunk of util_outbuff, + * so that if an interrupt handler invokes util_out_print, the buffer under construction is + * left intact. In theory, we should not need more than two buffer chunks, but in pro we + * will allow to utilize a third one just to provide more protection against overwrites of + * under-construction messages. + */ +#define SAVE_UTIL_OUT_BUFFER(UTIL_OUT_SAVE_PTR, VA_LIST_SAVE_PTR, COPY_SAVED) \ +{ \ + if (TREF(util_outbuff_ptr) < (TADR(util_outbuff) + \ + OUT_BUFF_SIZE * (UTIL_OUTBUFF_STACK_SIZE - 1))) \ + { \ + (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; \ + COPY_SAVED = TRUE; \ + } else \ + assert(FALSE); \ +} + +/* Repoint util_outbuff_ptr to the previous chunk of util_outbuff, so that the construction + * of the buffer that was saved there could be finished safely, and also restore the + * corresponding va_list. + */ +#define RESTORE_UTIL_OUT_BUFFER(UTIL_OUT_SAVE_PTR, VA_LIST_SAVE_PTR, COPY_SAVED) \ +{ \ + if (COPY_SAVED) \ + { \ + assert(TREF(util_outbuff_ptr) > TADR(util_outbuff)); \ + (TREF(util_outbuff_ptr)) -= OUT_BUFF_SIZE; \ + TREF(util_outptr) = UTIL_OUT_SAVE_PTR; \ + VAR_COPY(TREF(last_va_list_ptr), VA_LIST_SAVE_PTR); \ + COPY_SAVED = FALSE; \ + } \ +} #define OUT_BUFF_SIZE 2048 #define NOFLUSH 0 diff --git a/sr_port/util_base_ch.c b/sr_port/util_base_ch.c index 0a6f7b4..b7ef1db 100644 --- a/sr_port/util_base_ch.c +++ b/sr_port/util_base_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,7 +27,7 @@ #include "gtmimagename.h" #include "lke.h" #include "dpgbldir.h" -#include "preemptive_ch.h" +#include "preemptive_db_clnup.h" #include "util.h" GBLREF boolean_t need_core; @@ -83,7 +83,7 @@ CONDITION_HANDLER(util_base_ch) } } if (IS_MUPIP_IMAGE) - preemptive_ch(SEVERITY); /* for other utilities, preemptive_ch() is called from util_ch() */ + preemptive_db_clnup(SEVERITY); /* for other utilities, preemptive_db_clnup() is called from util_ch() */ UNIX_ONLY( if ((DUMPABLE) && !SUPPRESS_DUMP) { diff --git a/sr_port/util_ch.c b/sr_port/util_ch.c index d243050..062f119 100644 --- a/sr_port/util_ch.c +++ b/sr_port/util_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include #include "error.h" -#include "preemptive_ch.h" +#include "preemptive_db_clnup.h" #include "util.h" GBLREF VSIG_ATOMIC_T util_interrupt; @@ -36,7 +36,7 @@ CONDITION_HANDLER(util_ch) PRN_ERROR; if (SIGNAL == ERR_CTRLC) { - preemptive_ch(ERROR); /* bluff about SEVERITY, just so gv_target will be reset in preemptive_ch */ + preemptive_db_clnup(ERROR); /* bluff about SEVERITY, just so gv_target will be reset in preemptive_db_clnup */ assert(util_interrupt); util_interrupt = 0; UNWIND(NULL, NULL); @@ -45,7 +45,7 @@ CONDITION_HANDLER(util_ch) CONTINUE; } else { - preemptive_ch(SEVERITY); + preemptive_db_clnup(SEVERITY); UNWIND(NULL, NULL); } } diff --git a/sr_port/view_routines.c b/sr_port/view_routines.c index 400a8bd..3f9d6aa 100644 --- a/sr_port/view_routines.c +++ b/sr_port/view_routines.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "gtm_caseconv.h" #include "stringpool.h" diff --git a/sr_port/viewtab.h b/sr_port/viewtab.h index 5fe1bac..14a5665 100644 --- a/sr_port/viewtab.h +++ b/sr_port/viewtab.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,10 +16,13 @@ VIEWTAB("0", VTP_NULL, VTK_GDSCERT0, MV_STR), VIEWTAB("1", VTP_NULL, VTK_GDSCERT1, MV_STR), VIEWTAB("BADCHAR", VTP_NULL, VTK_BADCHAR, MV_NM), VIEWTAB("BREAKMSG", VTP_NULL | VTP_VALUE, VTK_BREAKMSG, MV_NM), +VIEWTAB("DBFLUSH", VTP_DBREGION | VTP_NULL, VTK_DBFLUSH, MV_STR), +VIEWTAB("DBSYNC", VTP_DBREGION | VTP_NULL, VTK_DBSYNC, MV_STR), VIEWTAB("DEBUG1", VTP_VALUE | VTP_NULL, VTK_DEBUG1, MV_STR), VIEWTAB("DEBUG2", VTP_VALUE | VTP_NULL, VTK_DEBUG2, MV_STR), VIEWTAB("DEBUG3", VTP_VALUE | VTP_NULL, VTK_DEBUG3, MV_STR), VIEWTAB("DEBUG4", VTP_VALUE | VTP_NULL, VTK_DEBUG4, MV_STR), +VIEWTAB("EPOCH", VTP_DBREGION | VTP_NULL, VTK_EPOCH, MV_STR), VIEWTAB("FILL_FACTOR", VTP_VALUE | VTP_NULL, VTK_FILLFACTOR, MV_NM), VIEWTAB("FLUSH", VTP_DBREGION | VTP_NULL, VTK_FLUSH, MV_STR), VIEWTAB("FREEBLOCKS", VTP_DBREGION, VTK_BLFREE, MV_NM), @@ -47,6 +50,10 @@ VIEWTAB("JNLTRANSACTION", VTP_NULL, VTK_JNLTRANSACTION, MV_NM), VIEWTAB("JNLWAIT", VTP_NULL, VTK_JNLWAIT, MV_STR), VIEWTAB("JOBPID", VTP_VALUE | VTP_NULL, VTK_JOBPID, MV_STR), VIEWTAB("LABELS", VTP_VALUE | VTP_NULL, VTK_LABELS, MV_NM), +VIEWTAB("LOGTPRESTART", VTP_VALUE | VTP_NULL, VTK_LOGTPRESTART, MV_NM), +#ifdef DEBUG +VIEWTAB("LVDMP", VTP_LVN, VTK_LVDMP, MV_NM), +#endif VIEWTAB("LVDUPCHECK", VTP_NULL | VTP_VALUE, VTK_LVDUPCHECK, MV_STR), /* nodoc : felt unnecessary in all known cases */ #ifdef DEBUG_ALIAS VIEWTAB("LVMONOUT", VTP_NULL, VTK_LVMONOUT, MV_NM), /* nodoc : code debugging feature */ @@ -63,10 +70,14 @@ VIEWTAB("NEVERLVNULLSUBS", VTP_NULL, VTK_NEVERLVNULLSUBS, MV_NM), VIEWTAB("NOBADCHAR", VTP_NULL, VTK_NOBADCHAR, MV_NM), VIEWTAB("NOFULL_BOOLEAN", VTP_NULL, VTK_NOFULLBOOL, MV_STR), VIEWTAB("NOISOLATION", VTP_NULL | VTP_DBKEYLIST, VTK_NOISOLATION, MV_NM), +VIEWTAB("NOLOGTPRESTART", VTP_NULL, VTK_NOLOGTPRESTART, MV_NM), 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("RCHITS", VTP_NULL, VTK_RCHITS, MV_NM), VIEWTAB("RCMISSES", VTP_NULL, VTK_RCMISSES, MV_NM), VIEWTAB("RCSIZE", VTP_NULL, VTK_RCSIZE, MV_NM), diff --git a/sr_port/wake_alarm.c b/sr_port/wake_alarm.c index 4b3b10e..c5002cc 100644 --- a/sr_port/wake_alarm.c +++ b/sr_port/wake_alarm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,7 @@ GBLREF bool out_of_time; void wake_alarm(void) -{ out_of_time = TRUE; +{ + out_of_time = TRUE; GT_WAKE; } diff --git a/sr_port/wbox_test_init.h b/sr_port/wbox_test_init.h index d91afd5..4e8b996 100644 --- a/sr_port/wbox_test_init.h +++ b/sr_port/wbox_test_init.h @@ -1,7 +1,7 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -71,7 +71,7 @@ typedef enum { WBTEST_JNL_FILE_OPEN_FAIL, /* 43 : Unix only. Journal file open always return ERR_JNLFILOPN */ WBTEST_FAIL_ON_SHMGET, /* 44 : Unix only. Cause db_init() to fail on shmget */ WBTEST_EXTEND_JNL_FSYNC, /* 45 : enter a long loop upon trying to do jnl_fsync */ - WBTEST_CMP_SOLVE_TIMEOUT, /* 46 : !!! UNUSED !!! */ + WBTEST_TRIGR_TPRESTART_MSTOP, /* 46 : Trigger being restarted gets a MUPIP STOP - shouldn't fail */ WBTEST_SENDTO_EPERM, /* 47 : Will sleep in grab_crit depending on gtm_white_box_test_case_number */ WBTEST_ALLOW_ARBITRARY_FULLY_UPGRADED, /* 48 : Allows csd->fully_upgraded to take arbitrary values (via DSE) and prevents * assert in mur_process_intrpt_recov.c */ @@ -80,28 +80,77 @@ typedef enum { WBTEST_JNL_SWITCH_EXPECTED, /* 51 : We expect an automatic journal file switch in jnl_file_open */ WBTEST_SYSCONF_WRAPPER, /* 52 : Will sleep in SYSCONF wrapper to let us verify that first two MUPIP STOPs * are indeed deferred in the interrupt-deferred zone, but the third isn't */ - WBTEST_DEFERRED_TIMERS, /* 53 : Will enter a long loop upon specific WRITE or MUPIP STOP command */ + WBTEST_DEFERRED_TIMERS, /* 53 : Will enter a long loop upon specific WRITE or MUPIP STOP command */ WBTEST_BREAKMPC, /* 54 : Breaks the mpc of the previous frame putting 0xdeadbeef in it */ - WBTEST_CRASH_TRUNCATE_1, /* 55 : Issue a kill -9 before 1st fsync */ - WBTEST_CRASH_TRUNCATE_2, /* 56 : Issue a kill -9 after 1st fsync */ - WBTEST_CRASH_TRUNCATE_3, /* 57 : Issue a kill -9 after reducing csa->ti->total_blks, before FTRUNCATE */ - WBTEST_CRASH_TRUNCATE_4, /* 58 : Issue a kill -9 after FTRUNCATE, before 2nd fsync */ - WBTEST_CRASH_TRUNCATE_5 /* 58 : Issue a kill -9 after after 2nd fsync */ + WBTEST_CRASH_TRUNCATE_1, /* 55 : Issue a kill -9 before 1st fsync */ + WBTEST_CRASH_TRUNCATE_2, /* 56 : Issue a kill -9 after 1st fsync */ + WBTEST_CRASH_TRUNCATE_3, /* 57 : Issue a kill -9 after reducing csa->ti->total_blks, before FTRUNCATE */ + WBTEST_CRASH_TRUNCATE_4, /* 58 : Issue a kill -9 after FTRUNCATE, before 2nd fsync */ + WBTEST_CRASH_TRUNCATE_5, /* 59 : Issue a kill -9 after after 2nd fsync */ + WBTEST_HOLD_SEM_BYPASS, /* 60 : Hold access and FTOK semaphores so that LKE/DSE can bypass it. */ + WBTEST_UTIL_OUT_BUFFER_PROTECTION, /* 61 : Start a timer that would mess with util_out buffers by frequently + * printing long messages via util_out_print */ + WBTEST_SET_WC_BLOCKED, /* 62 : Set the wc_blocked when searching the tree to start wcs_recover process*/ + WBTEST_CLOSE_JNLFILE, /* 63 : Set the journal file state to close when reading journal files to + * trigger repl_warn message */ + WBTEST_WCS_FLU_IOERR, /* 64 : Force an I/O error (other than ENOSPC) when wcs_wtstart is invoked from + * wcs_flu */ + WBTEST_WCS_WTSTART_IOERR, /* 65 : Force an I/O error (other than ENOSPC) within wcs_wtstart */ + WBTEST_HOLD_CRIT_TILL_LCKALERT, /* 66 : Grab and hold crit until 15 seconds past what triggers a lock alert message + * which should invoke a mutex salvage */ + WBTEST_OPER_LOG_MSG, /* 67 : send message to operator log */ + WBTEST_UNUSED_1, /* 68 : */ + /* Begin ANTIFREEZE related white box test cases */ + WBTEST_ANTIFREEZE_JNLCLOSE, /* 69 : */ + WBTEST_ANTIFREEZE_DBBMLCORRUPT, /* 70 : */ + WBTEST_ANTIFREEZE_DBDANGER, /* 71 : */ + WBTEST_ANTIFREEZE_DBFSYNCERR, /* 72 : */ + WBTEST_ANTIFREEZE_GVDATAFAIL, /* 73 : */ + WBTEST_ANTIFREEZE_GVGETFAIL, /* 74 : */ + WBTEST_ANTIFREEZE_GVINCRPUTFAIL, /* 75 : */ + WBTEST_ANTIFREEZE_GVKILLFAIL, /* 76 : */ + WBTEST_ANTIFREEZE_GVORDERFAIL, /* 77 : */ + WBTEST_ANTIFREEZE_GVQUERYFAIL, /* 78 : */ + WBTEST_ANTIFREEZE_GVQUERYGETFAIL, /* 79 : */ + WBTEST_ANTIFREEZE_GVZTRIGFAIL, /* 80 : */ + WBTEST_ANTIFREEZE_OUTOFSPACE, /* 81 : */ + /* End ANTIFREEZE related white box test cases */ + WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP, /* 82 : Send SIGTSTP to self if wcs_timers is 0 */ + WBTEST_CONCBKUP_RUNNING, /* 83 : Sleep in mupip_backup to test concurrent BACKUPs */ + WBTEST_LONGSLEEP_IN_REPL_SHUTDOWN, /* 84 : Sleep in Source/Receiver shutdown logic to ensure sem/shm is not removed */ + WBTEST_FORCE_WCS_GET_SPACE, /* 85 : Simulate state in which nearly all global buffers are dirty, forcing + * wcs_get_space to be called before committing an update */ + /* Begin HugeTLB tests */ + WBTEST_HUGETLB_DLOPEN, /* 86 : Fail dlopen(libhugetlbfs.so) */ + WBTEST_HUGETLB_DLSYM, /* 87 : Fail dlsym(shmget) */ + WBTEST_FSYNC_SYSCALL_FAIL, /* 88 : Force error from fsync() */ + WBTEST_HUGE_ALLOC, /* 89 : Force ZALLOCSTOR, ZREALSTOR, and ZUSEDSTOR to be values exceeding + * the capacity of four-byte ints */ + WBTEST_MMAP_SYSCALL_FAIL, /* 90 : Force mmap() to return an error */ + WBTEST_TAMPER_HOSTNAME, /* 91 : Change host name in db_init to call condition handler */ + WBTEST_RECOVER_ENOSPC, /* 92 : Cause ENOSPC error on Xth write to test return status on error */ + WBTEST_WCS_FLU_FAIL, /* 93 : Simulates a failure in wcs_flu */ + WBTEST_PREAD_SYSCALL_FAIL, /* 94 : Simulate pread() error in dsk_read */ + WBTEST_HOLD_CRIT_ENABLED, /* 95 : Enable $view("PROBECRIT","REGION") command to cold crit */ + WBTEST_HOLD_FTOK_UNTIL_BYPASS /* 96 : Hold the ftok semaphore until another process comes and bypasses + * it*/ + /* 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. + */ } wbtest_code_t; #ifdef DEBUG +/* Make sure to setenv gtm_white_box_test_case_count if you are going to use GTM_WHITE_BOX_TEST */ #define GTM_WHITE_BOX_TEST(input_test_case_num, lhs, rhs) \ { \ - if (gtm_white_box_test_case_enabled) \ + if (gtm_white_box_test_case_enabled && (gtm_white_box_test_case_number == input_test_case_num)) \ { \ - if (gtm_white_box_test_case_number == input_test_case_num) \ + gtm_wbox_input_test_case_count++; \ + if (gtm_white_box_test_case_count == gtm_wbox_input_test_case_count) \ { \ - gtm_wbox_input_test_case_count++; \ - if (gtm_white_box_test_case_count == gtm_wbox_input_test_case_count) \ - { \ - lhs = rhs; \ - gtm_wbox_input_test_case_count = 0; \ - } \ + lhs = rhs; \ + gtm_wbox_input_test_case_count = 0; \ } \ } \ } @@ -110,6 +159,7 @@ typedef enum { #endif #ifdef DEBUG +#define WBTEST_ENABLED(WBTEST_NUMBER) (gtm_white_box_test_case_enabled && (WBTEST_NUMBER == gtm_white_box_test_case_number)) #define ENABLE_WBTEST_ABANDONEDKILL \ { \ int sleep_counter; \ @@ -127,9 +177,18 @@ typedef enum { #define WB_PHASE1_COMMIT_ERR (WBTEST_BG_UPDATE_BTPUTNULL == gtm_white_box_test_case_number) #define WB_PHASE2_COMMIT_ERR (WBTEST_BG_UPDATE_PHASE2FAIL == gtm_white_box_test_case_number) #define WB_COMMIT_ERR_ENABLED (WB_PHASE1_COMMIT_ERR || WB_PHASE2_COMMIT_ERR) /* convoluted definition to simplify usage */ +#define WBTEST_ASSIGN_ONLY(WBTEST_NUMBER, LHS, RHS) \ +{ \ + if (WBTEST_ENABLED(WBTEST_NUMBER)) \ + { \ + LHS = RHS; \ + } \ +} #else +#define WBTEST_ENABLED(WBTEST_NUMBER) FALSE #define ENABLE_WBTEST_ABANDONEDKILL #define WB_COMMIT_ERR_ENABLED +#define WBTEST_ASSIGN_ONLY(WBTEST_NUMBER, LHS, RHS) #endif #endif diff --git a/sr_port/wcs_backoff.c b/sr_port/wcs_backoff.c index bf7b9f1..cb7182a 100644 --- a/sr_port/wcs_backoff.c +++ b/sr_port/wcs_backoff.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,10 +12,13 @@ #include "mdef.h" #include "sleep_cnt.h" -#include +#ifdef VMS +# include +#endif +#include "gtm_stdlib.h" #include "gt_timer.h" #ifdef UNIX -#include "random.h" +# include "random.h" #endif #include "wcs_backoff.h" @@ -30,12 +33,10 @@ void wcs_backoff(unsigned int sleepfactor) * if (count) wcs_backoff(count); */ -#if defined(VMS) - float mth$random(); - uint4 lib$day(); - int4 day; -#endif - +# if defined(VMS) + int4 day; + double randfloat; +# endif static int4 seed = 0; uint4 sleep_ms; @@ -44,19 +45,25 @@ void wcs_backoff(unsigned int sleepfactor) return; if (sleepfactor > MAXSLPTIME) sleepfactor = MAXSLPTIME; - -#ifdef UNIX - if (seed == 0) +# ifdef UNIX + if (0 == seed) { init_rand_table(); seed = 1; } sleep_ms = ((uint4)(get_rand_from_table() % sleepfactor)); -#else - if (seed == 0) /* Seed random number generator */ +# elif defined(VMS) + if (0 == seed) /* Seed random number generator */ + { lib$day(&day, 0, &seed); - sleep_ms = ((uint4)(sleepfactor * mth$random(&seed))); -#endif + seed *= process_id; + srandom(seed); + } + randfloat = ((double)random()) / RAND_MAX; + sleep_ms = ((uint4)(sleepfactor * randfloat)); +# else +# error "Unsupported platform" +# endif if (0 == sleep_ms) return; /* We have no wait this time */ if (1000 > sleep_ms) /* Use simpler sleep for shorties */ diff --git a/sr_port/wcs_flu.h b/sr_port/wcs_flu.h index f933384..0139104 100644 --- a/sr_port/wcs_flu.h +++ b/sr_port/wcs_flu.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,28 +32,35 @@ boolean_t wcs_flu(uint4 options); #define SET_WCS_FLU_FAIL_STATUS(status, csd) \ { /* Reasons we currently know why wcs_flu can fail (when called from t_end or tp_tend) is if \ - * a) wcs_flu avoided invoking wcs_recover because csd->wc_blocked is already set to TRUE. \ - * (this is possible only if cache-recoveries are induced by white-box testing). \ + * a) wcs_flu avoided invoking wcs_recover because cnl->wc_blocked is already set \ + * to TRUE (this is possible only if cache-recoveries are induced by white-box \ + * testing). \ * OR b) if wcs_flu encountered errors in the "jnl_flush" call. The only way we know this \ * out-of-design situation can happen is if journal buffer fields are tampered \ - * with by white-box testing. In this case csd->wc_blocked need not be TRUE. \ + * with by white-box testing. In this case cnl->wc_blocked need not be TRUE. \ * In either case, white-box testing should be true. Assert accordingly. \ */ \ assert(gtm_white_box_test_case_enabled); \ assert(CDB_STAGNATE >= t_tries); \ - if ((dba_bg == csd->acc_meth) && (CDB_STAGNATE <= t_tries)) \ + SET_CACHE_FAIL_STATUS(status, csd); \ +} + +#define SET_CACHE_FAIL_STATUS(status, csd) \ +{ \ + if ((CDB_STAGNATE <= t_tries) && (dba_bg == csd->acc_meth)) \ { /* We are in final retry but have to restart because some other process encountered \ * an error in phase2 of commit and has set wc_blocked to TRUE causing us (in-crit \ * process) not to be able to flush the cache. We do not want to increase t_tries in \ * this case as that will cause us to error out of the transaction. Instead treat this \ * like a helped out case. This will cause us to retry the transaction and as part of \ - * that we will perform a cache-recovery that should reset csd->wc_blocked to FALSE. \ + * that we'll perform a cache-recovery that should reset cnl->wc_blocked to FALSE. \ * This should cause the wcs_flu() done in the next retry to succeed unless yet another \ * process set wc_blocked to TRUE as part of its phase2 commit. In the worst case we \ * could restart as many times as there are processes concurrently running phase2 \ * commits. Since we dont release crit throughout this final-retry restart loop, we \ * are guaranteed not to do infinite retries. \ */ \ + assert(gtm_white_box_test_case_enabled && WB_PHASE2_COMMIT_ERR); \ status = (enum cdb_sc)cdb_sc_helpedout; \ } else \ status = (enum cdb_sc)cdb_sc_cacheprob; \ diff --git a/sr_port/wcs_get_space.h b/sr_port/wcs_get_space.h index f80a808..66d4ffe 100644 --- a/sr_port/wcs_get_space.h +++ b/sr_port/wcs_get_space.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,6 +21,19 @@ typedef struct wcs_conflict_trace_struct } wcs_conflict_trace_t; #endif +/* Ensure that at least DB_CSH_RDPOOL_SZ buffers are not dirty by the time an update transaction completes. This guarantees + * a minimum number of buffers are available at all times. Macro should be used whenever second arg is non-zero. + * WBTEST_FORCE_WCS_GET_SPACE forces wcs_get_space to be called, regardless of wc_in_free. + */ +#define WCS_GET_SPACE(REG, NEEDED, CR) \ +( \ + ( \ + (cnl->wc_in_free >= ((int4)(NEEDED) + DB_CSH_RDPOOL_SZ)) \ + DEBUG_ONLY( && !(gtm_white_box_test_case_enabled && (WBTEST_FORCE_WCS_GET_SPACE == gtm_white_box_test_case_number))) \ + ) \ + || wcs_get_space(REG, (NEEDED) + DB_CSH_RDPOOL_SZ, CR) \ +) + bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr); #endif diff --git a/sr_port/wcs_mm_recover.h b/sr_port/wcs_mm_recover.h index b15b002..3db0560 100644 --- a/sr_port/wcs_mm_recover.h +++ b/sr_port/wcs_mm_recover.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,7 @@ { \ if (csa->total_blks != csa->ti->total_blks) \ wcs_mm_recover(reg); \ - assert(csa->total_blks == csa->ti->total_blks); \ + assert(!csa->now_crit || (csa->total_blks == csa->ti->total_blks)); \ } #define CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg) \ diff --git a/sr_port/wcs_phase2_commit_wait.c b/sr_port/wcs_phase2_commit_wait.c index 8d866e5..c722f12 100644 --- a/sr_port/wcs_phase2_commit_wait.c +++ b/sr_port/wcs_phase2_commit_wait.c @@ -205,7 +205,7 @@ boolean_t wcs_phase2_commit_wait(sgmnt_addrs *csa, cache_rec_ptr_t cr) assert(!was_crit || !value); return TRUE; } - if (!was_crit && csd->wc_blocked) + if (!was_crit && cnl->wc_blocked) { /* Some other process could be doing cache-recovery at this point and if it takes more than * a minute, we will time out for no reason. No point proceeding with this transaction * anyway as we are bound to restart. Do that right away. Caller knows to restart. @@ -325,12 +325,12 @@ boolean_t wcs_phase2_commit_wait(sgmnt_addrs *csa, cache_rec_ptr_t cr) /* If called from wcs_recover(), we dont want to assert(FALSE) as it is possible (in case of STOP/IDs) that * cnl->wcs_phase2_commit_pidcnt is non-zero even though there is no process in phase2 of commit. In this case * wcs_recover will call wcs_verify which will clear the flag unconditionally and proceed with normal activity. - * So should not assert. If the caller is wcs_recover, then we expect csd->wc_blocked so be non-zero. Assert + * So should not assert. If the caller is wcs_recover, then we expect cnl->wc_blocked so be non-zero. Assert * that. If we are called from wcs_flu via ONLINE ROLLBACK, then wc_blocked will NOT be set. Instead, wcs_flu * will return with a failure status back to ROLLBACK which will invoke wcs_recover and that will take care of * resetting cnl->wcs_phase2_commit_pidcnt. But, ONLINE ROLLBACK called in a crash situation is done only with * whitebox test cases. So, assert accordingly. */ - assert(csd->wc_blocked || (WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number)); + assert(cnl->wc_blocked || (WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number)); return FALSE; } diff --git a/sr_port/wcs_recover.c b/sr_port/wcs_recover.c index 725f000..e922f62 100644 --- a/sr_port/wcs_recover.c +++ b/sr_port/wcs_recover.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -103,16 +103,15 @@ GBLREF boolean_t in_mu_rndwn_file; error_def(ERR_BUFRDTIMEOUT); error_def(ERR_DBADDRALIGN); error_def(ERR_DBADDRANGE); -error_def(ERR_DBCCERR); error_def(ERR_DBCNTRLERR); error_def(ERR_DBCRERR); error_def(ERR_DBDANGER); error_def(ERR_DBFILERR); -error_def(ERR_ERRCALL); error_def(ERR_INVALIDRIP); error_def(ERR_GBLOFLOW); error_def(ERR_GVIS); error_def(ERR_STOPTIMEOUT); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); void wcs_recover(gd_region *reg) @@ -179,12 +178,12 @@ void wcs_recover(gd_region *reg) assert((CDB_STAGNATE > t_tries) || TREF(ok_to_call_wcs_recover) || process_exiting); assert(csa->now_crit || csd->clustered); CHECK_TN(csa, csd, csd->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */ - SIGNAL_WRITERS_TO_STOP(csd); /* to stop all active writers */ + SIGNAL_WRITERS_TO_STOP(cnl); /* to stop all active writers */ WAIT_FOR_WRITERS_TO_STOP(cnl, lcnt, MAXWTSTARTWAIT); /* if the wait loop above hits the limit, or cnl->intent_wtstart goes negative, it is ok to proceed since * wcs_verify (invoked below) reports and clears cnl->intent_wtstart and cnl->in_wtstart. */ - assert(!TREF(donot_write_inctn_in_wcs_recover) || in_mu_rndwn_file UNIX_ONLY(|| jgbl.onlnrlbk)); + assert(!TREF(donot_write_inctn_in_wcs_recover) || in_mu_rndwn_file UNIX_ONLY(|| jgbl.onlnrlbk) || jgbl.mur_extract); assert(!in_mu_rndwn_file || (0 == cnl->wcs_phase2_commit_pidcnt)); assert(!csa->wcs_pidcnt_incremented); /* we should never have come here with a phase2 commit pending for ourself */ /* Wait for any pending phase2 commits to finish */ @@ -201,7 +200,7 @@ void wcs_recover(gd_region *reg) if (wcs_verify(reg, TRUE, TRUE)) /* expect_damage is TRUE, in_wcs_recover is TRUE */ { /* if it passes verify, then recover can't help ??? what to do */ BG_TRACE_PRO_ANY(csa, wc_blocked_wcs_verify_passed); - send_msg(VARLSTCNT(4) ERR_DBCNTRLERR, 2, DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBCNTRLERR, 2, DB_LEN_STR(reg)); } if (gtmDebugLevel) verifyAllocatedStorage(); @@ -247,13 +246,13 @@ void wcs_recover(gd_region *reg) old_block = (INTPTR_T)GDS_ANY_REL2ABS(csa, cr->twin); if (!IS_PTR_IN_RANGE(old_block, bp_lo, bp_top)) { - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, old_block, RTS_ERROR_TEXT("bkup_before_image_range"), bp_lo, bp_top); assert(FALSE); continue; } else if (!IS_PTR_ALIGNED(old_block, bp_lo, csd->blk_size)) { - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("bkup_before_image_align"), old_block, bp_lo, csd->blk_size); assert(FALSE); continue; @@ -266,26 +265,28 @@ void wcs_recover(gd_region *reg) /* Do other checks to validate before-image buffer */ if (cr_alt == cr) { - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("bkup_before_image_cr_same"), cr_alt, FALSE, CALLFROM); assert(FALSE); continue; } else if (cr->blk != cr_alt->blk) { - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("bkup_before_image_blk"), cr_alt->blk, cr->blk, CALLFROM); assert(FALSE); continue; } else if (!cr_alt->in_cw_set) { - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, cr_alt->blk, - RTS_ERROR_TEXT("bkup_before_image_in_cw_set"), cr_alt->in_cw_set, TRUE, CALLFROM); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, + cr_alt->blk, RTS_ERROR_TEXT("bkup_before_image_in_cw_set"), + cr_alt->in_cw_set, TRUE, CALLFROM); assert(FALSE); continue; } else if (cr_alt->stopped) { - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, cr_alt->blk, - RTS_ERROR_TEXT("bkup_before_image_stopped"), cr_alt->stopped, FALSE, CALLFROM); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, + cr_alt->blk, RTS_ERROR_TEXT("bkup_before_image_stopped"), + cr_alt->stopped, FALSE, CALLFROM); assert(FALSE); continue; } @@ -360,7 +361,7 @@ void wcs_recover(gd_region *reg) r_epid = cr->r_epid; if (cr->read_in_progress < -1) { - send_msg(VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(reg)); INTERLOCK_INIT(cr); cr->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */ cr->blk = CR_BLKEMPTY; @@ -388,9 +389,9 @@ void wcs_recover(gd_region *reg) GTMASSERT; /* process still active but not playing fair or cache is corrupted */ GET_C_STACK_FROM_SCRIPT("BUFRDTIMEOUT", process_id, r_epid, TWICE); - send_msg(VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id, cr->blk, cr, r_epid, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id, cr->blk, cr, r_epid, DB_LEN_STR(reg)); - send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized")); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized")); INTERLOCK_INIT(cr); cr->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */ cr->blk = CR_BLKEMPTY; @@ -427,8 +428,10 @@ void wcs_recover(gd_region *reg) GTMASSERT; if (0 != epid) { /* process still active, but not playing fair */ - send_msg(VARLSTCNT(5) ERR_STOPTIMEOUT, 3, epid, DB_LEN_STR(reg)); - send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized")); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_STOPTIMEOUT, 3, epid, + DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("Buffer forcibly seized")); cr->epid = 0; } continue; @@ -575,6 +578,19 @@ void wcs_recover(gd_region *reg) ADD_ENT_TO_ACTIVE_QUE_CNT(&cnl->wcs_active_lvl, &cnl->wc_var_lock); continue; } +#if defined(DEBUG) && defined(UNIX) + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_DBDANGER == gtm_white_box_test_case_number)) + { + gtm_wbox_input_test_case_count++; + /* 50 has no special meaning. Just to trigger this somewhere in the middle once. */ + if (50 == gtm_wbox_input_test_case_count) + { + cr->blk = 0; + cr->dirty = 1; + cr->data_invalid = 1; + } + } +#endif if ((CR_BLKEMPTY == cr->blk) || (0 == cr->dirty) VMS_ONLY(|| ((0 != cr->iosb.cond) && (0 == cr->bt_index)))) { /* cache record has no valid buffer attached, or its contents are in the database, * or it has a more recent twin so we don't even have to care how its write terminated */ @@ -602,7 +618,8 @@ void wcs_recover(gd_region *reg) * In Unix, no rebuild would have been attempted since no kernel extension routine currently available. * In either case, we do not want to discard this buffer so send a warning to the user and proceed. */ - send_msg(VARLSTCNT(7) ERR_DBDANGER, 5, cr->data_invalid, cr->data_invalid, DB_LEN_STR(reg), cr->blk); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBDANGER, 5, cr->data_invalid, cr->data_invalid, + DB_LEN_STR(reg), cr->blk); cr->data_invalid = 0; } if (cr->in_tend) @@ -795,7 +812,7 @@ void wcs_recover(gd_region *reg) INCREMENT_CURR_TN(csd); } csa->wbuf_dqd = 0; /* reset this so the wcs_wtstart below will work */ - SIGNAL_WRITERS_TO_RESUME(csd); + SIGNAL_WRITERS_TO_RESUME(cnl); in_wcs_recover = FALSE; if (!reg->read_only) { @@ -811,57 +828,65 @@ void wcs_recover(gd_region *reg) return; } -#ifdef UNIX - #ifdef MM_FILE_EXT_OK void wcs_mm_recover(gd_region *reg) { - int mm_prot; + int save_errno; + gtm_uint64_t mmap_sz; INTPTR_T status; struct stat stat_buf; - sm_uc_ptr_t old_base[2]; - sigset_t savemask; - boolean_t need_to_restore_mask = FALSE, was_crit; + sm_uc_ptr_t old_db_addrs[2], mmap_retaddr; + boolean_t was_crit, read_only; unix_db_info *udi; + const char *syscall = "munmap()"; + VMS_ONLY(assert(FALSE)); assert(&FILE_INFO(reg)->s_addrs == cs_addrs); assert(cs_addrs->hdr == cs_data); - if (!(was_crit = cs_addrs->now_crit) && !(cs_addrs->hdr->clustered)) + assert(!cs_addrs->hdr->clustered); + assert(!cs_addrs->hold_onto_crit || cs_addrs->now_crit); + if (!(was_crit = cs_addrs->now_crit)) grab_crit(gv_cur_region); - SET_TRACEABLE_VAR(cs_addrs->hdr->wc_blocked, FALSE); - if (cs_addrs->total_blks == cs_addrs->ti->total_blks) - { - /* I am the one who actually did the extension, don't need to remap again */ + SET_TRACEABLE_VAR(cs_addrs->nl->wc_blocked, FALSE); + assert((NULL != cs_addrs->db_addrs[0]) || process_exiting); + if ((cs_addrs->total_blks == cs_addrs->ti->total_blks) || (NULL == cs_addrs->db_addrs[0])) + { /* I am the one who actually did the extension, don't need to remap again OR an munmap/mmap failed and we are in + * shutdown logic + */ if (!was_crit) rel_crit(gv_cur_region); return; } - mm_prot = cs_addrs->read_write ? (PROT_READ | PROT_WRITE) : PROT_READ; - /* Block SIGALRM to ensure cs_data and cs_addrs are always in-sync / No IO in this period */ - sigprocmask(SIG_BLOCK, &blockalrm, &savemask); - old_base[0] = cs_addrs->db_addrs[0]; - old_base[1] = cs_addrs->db_addrs[1]; - status = (INTPTR_T)munmap((caddr_t)old_base[0], (size_t)(old_base[1] - old_base[0])); + old_db_addrs[0] = cs_addrs->db_addrs[0]; + old_db_addrs[1] = cs_addrs->db_addrs[1]; + cs_addrs->db_addrs[0] = NULL; + status = (INTPTR_T)munmap((caddr_t)old_db_addrs[0], (size_t)(old_db_addrs[1] - old_db_addrs[0])); if (-1 != status) { udi = FILE_INFO(gv_cur_region); FSTAT_FILE(udi->fd, &stat_buf, status); - status = (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, (size_t)stat_buf.st_size, - mm_prot, GTM_MM_FLAGS, udi->fd, (off_t)0)); + mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(cs_data); + CHECK_LARGEFILE_MMAP(gv_cur_region, mmap_sz); /* can issue rts_error MMFILETOOLARGE */ + read_only = gv_cur_region->read_only; + syscall = "mmap()"; + status = (sm_long_t)(mmap_retaddr = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(cs_data), read_only)); + GTM_WHITE_BOX_TEST(WBTEST_MMAP_SYSCALL_FAIL, status, -1); } if (-1 == status) { - sigprocmask(SIG_SETMASK, &savemask, NULL); + save_errno = errno; + WBTEST_ASSIGN_ONLY(WBTEST_MMAP_SYSCALL_FAIL, save_errno, ENOMEM); if (!was_crit) rel_crit(gv_cur_region); - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); + assert(WBTEST_ENABLED(WBTEST_MMAP_SYSCALL_FAIL)); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + LEN_AND_STR(syscall), CALLFROM, save_errno); } - /* In addition to updating the internal map values, gds_map_moved also updates cs_data to point to the remapped file */ - gds_map_moved(cs_addrs->db_addrs[0], old_base[0], old_base[1], (off_t)stat_buf.st_size); + gds_map_moved(mmap_retaddr, old_db_addrs[0], old_db_addrs[1], mmap_sz); /* updates cs_addrs->db_addrs[1] */ + cs_addrs->db_addrs[0] = mmap_retaddr; cs_addrs->total_blks = cs_addrs->ti->total_blks; if (!was_crit) rel_crit(gv_cur_region); - sigprocmask(SIG_SETMASK, &savemask, NULL); return; } #else /* !MM_FILE_EXT_OK */ @@ -869,29 +894,13 @@ void wcs_mm_recover(gd_region *reg) { unsigned char *end, buff[MAX_ZWR_KEY_SZ]; - if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) - end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); - return; -} -#endif -#elif defined(VMS) -/* wcs_mm_recover is not yet implemented on VMS */ -void wcs_mm_recover(gd_region *reg) -{ - unsigned char *end, buff[MAX_ZWR_KEY_SZ]; - assert(&FILE_INFO(reg)->s_addrs == cs_addrs); - assert(cs_addrs->now_crit); assert(cs_addrs->hdr == cs_data); - if (!cs_addrs->hold_onto_crit) - rel_crit(gv_cur_region); + if (cs_addrs->now_crit && !cs_addrs->hold_onto_crit) + rel_crit(reg); if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff); return; } - -#else -# error UNSUPPORTED PLATFORM #endif diff --git a/sr_port/wcs_verify.c b/sr_port/wcs_verify.c index 3fae091..1284bf8 100644 --- a/sr_port/wcs_verify.c +++ b/sr_port/wcs_verify.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,10 +33,28 @@ /* global refs/defs */ /* defines */ -#define FAKE_DIRTY ((trans_num)(-1)) +#define FAKE_DIRTY ((trans_num)(-1)) +#ifdef UNIX +#define SEND_MSG_CSA(...) send_msg_csa(CSA_ARG(csa) __VA_ARGS__) /* to avoid formatting various send_msg calls */ +#else +#define SEND_MSG_CSA send_msg +#endif GBLREF uint4 process_id; +error_def(ERR_DBADDRALIGN); +error_def(ERR_DBADDRANGE); +error_def(ERR_DBADDRANGE8); +error_def(ERR_DBCLNUPINFO); +error_def(ERR_DBCRERR); +error_def(ERR_DBCRERR8); +error_def(ERR_DBFHEADERR4); +error_def(ERR_DBFHEADERR8); +error_def(ERR_DBFHEADERRANY); +error_def(ERR_DBQUELINK); +error_def(ERR_DBWCVERIFYEND); +error_def(ERR_DBWCVERIFYSTART); + boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_is_wcs_recover) { /* This routine verifies the shared memory structures used to manage the buffers of the bg access method. * Changes to those structures or the way that they are managed may require changes to this routine @@ -48,7 +66,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i uint4 cnt, lcnt ; ssize_t offset ; - trans_num max_tn ; + trans_num max_tn, tmp_8byte; INTPTR_T bp_lo, bp_top, bp, cr_base, cr_top, bt_top_off, bt_base_off; sm_uc_ptr_t bptmp; boolean_t ret; @@ -68,30 +86,18 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i trans_num dummy_tn; int4 in_wtstart, intent_wtstart, wcs_phase2_commit_pidcnt; - error_def(ERR_DBFHEADERR4); - error_def(ERR_DBFHEADERR8); - error_def(ERR_DBADDRANGE); - error_def(ERR_DBADDRANGE8); - error_def(ERR_DBADDRALIGN); - error_def(ERR_DBQUELINK); - error_def(ERR_DBCRERR); - error_def(ERR_DBCRERR8); - error_def(ERR_DBCLNUPINFO); - error_def(ERR_DBWCVERIFYSTART); - error_def(ERR_DBWCVERIFYEND); - csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; cnl = csa->nl; ret = TRUE; - send_msg(VARLSTCNT(7) ERR_DBWCVERIFYSTART, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn); + SEND_MSG_CSA(VARLSTCNT(7) ERR_DBWCVERIFYSTART, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn); /* while some errors terminate loops, as of this writing, no errors are treated as terminal */ if ((csa->now_crit == FALSE) && (csd->clustered == FALSE)) { assert(expect_damage); assert(!csa->hold_onto_crit); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("now_crit"), csa->now_crit, TRUE); + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("now_crit"), csa->now_crit, TRUE); grab_crit(reg); /* what if it has it but lost track of it ??? should there be a crit reset ??? */ } if (dba_mm != csd->acc_meth) @@ -101,7 +107,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("bt_header_off"), cnl->bt_header_off, offset); cnl->bt_header_off = offset; } @@ -109,7 +115,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("bt_header"), csa->bt_header, (sm_uc_ptr_t)csd + cnl->bt_header_off); csa->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->bt_header_off); } @@ -118,7 +124,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("th_base_off"), cnl->th_base_off, offset + SIZEOF(bt->blkque)); cnl->th_base_off = (offset + SIZEOF(bt->blkque)); } @@ -126,7 +132,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("th_base"), csa->th_base, (sm_uc_ptr_t)csd + cnl->th_base_off); csa->th_base = (th_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->th_base_off); } @@ -135,7 +141,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("bt_base_off"), cnl->bt_base_off, offset); cnl->bt_base_off = offset; } @@ -143,7 +149,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("bt_base"), csa->bt_base, (sm_uc_ptr_t)csd + cnl->bt_base_off); csa->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->bt_base_off); } @@ -153,7 +159,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("csa->ti"), (sm_uc_ptr_t)csa->ti, (sm_uc_ptr_t)&csd->trans_hist); csa->ti = &csd->trans_hist; } @@ -165,7 +171,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("cache_off"), cnl->cache_off, -CACHE_CONTROL_SIZE(csd)); cnl->cache_off = -CACHE_CONTROL_SIZE(csd); } @@ -173,7 +179,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("cache_state"), csa->acc_meth.bg.cache_state, (sm_uc_ptr_t)csd + cnl->cache_off); csa->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)csd + cnl->cache_off); } @@ -181,7 +187,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("bt_buckets"), csd->bt_buckets, getprime(n_bts)); csd->bt_buckets = getprime(n_bts); } @@ -189,19 +195,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i if (JNL_ALLOWED(csd)) { if (NULL == csa->jnl) - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("csa->jnl"), csa->jnl, (UINTPTR_T)-1); else if (NULL == csa->jnl->jnl_buff) - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("csa->jnl->jnl_buff"), csa->jnl->jnl_buff, (UINTPTR_T)-1); else { - jnl_buff_expected = ((sm_uc_ptr_t)(cnl) + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE); + jnl_buff_expected = ((sm_uc_ptr_t)(cnl) + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE); if (csa->jnl->jnl_buff != (jnl_buffer_ptr_t)jnl_buff_expected) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("csa->jnl->jnl_buff_expected"), csa->jnl->jnl_buff, jnl_buff_expected); csa->jnl->jnl_buff = (jnl_buffer_ptr_t)jnl_buff_expected; } @@ -219,19 +225,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { /* if wcs_recover is caller, it would have waited for the following fields to become 0. * if called from DSE CACHE -VERIFY, none of these are guaranteed. So do these checks only for first case. */ - if (FALSE == csd->wc_blocked) + if (FALSE == cnl->wc_blocked) { /* in UNIX this blocks the writer */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), - RTS_ERROR_TEXT("wc_blocked"), csd->wc_blocked, TRUE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + RTS_ERROR_TEXT("wc_blocked"), cnl->wc_blocked, TRUE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); } in_wtstart = cnl->in_wtstart; /* store value in local variable in case the following assert fails */ if (0 != in_wtstart) { /* caller should outwait active writers */ ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("in_wtstart"), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("in_wtstart"), in_wtstart, 0); assert(expect_damage); cnl->in_wtstart = 0; @@ -241,7 +247,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i if (0 != intent_wtstart) { /* Two situations are possible. * a) A wcs_wtstart() call is concurrently in progress and that the process has just now - * incremented intent_wtstart. It will notice csd->wc_blocked to be TRUE and + * incremented intent_wtstart. It will notice cnl->wc_blocked to be TRUE and * decrement intent_wtstart right away and return. So we dont need to do anything. * b) A wcs_wtstart() call had previously increment intent_wtstart but got shot before it could * get a chance to decrement the field. In this case, we need to clear the field to @@ -254,7 +260,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i * happens first. The INCR_INTENT_WTSTART macro has a double increment to take care of this * case. */ - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("intent_wtstart"), intent_wtstart, 0); cnl->intent_wtstart = 0; SHM_WRITE_MEMORY_BARRIER; @@ -263,7 +269,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i if (0 != wcs_phase2_commit_pidcnt) { /* caller should outwait active committers */ ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("wcs_phase2_commit_pidcnt"), wcs_phase2_commit_pidcnt, 0); assert(expect_damage); cnl->wcs_phase2_commit_pidcnt = 0; @@ -275,7 +281,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("th_base->blk"), th->blk, BT_QUEHEAD); th->blk = BT_QUEHEAD; } @@ -289,7 +295,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), th_prev, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), th_prev, -1, RTS_ERROR_TEXT("th->tnque"), bt, bt_lo, SIZEOF(bt_rec)); break; } @@ -297,7 +303,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th_prev, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th_prev, -1, bt, RTS_ERROR_TEXT("th->tnque"), bt_lo, bt_hi); break; } @@ -305,8 +311,9 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, RTS_ERROR_TEXT("tnque.bl"), - (UINTPTR_T)th->tnque.bl, (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th); + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, + RTS_ERROR_TEXT("tnque.bl"), (UINTPTR_T)th->tnque.bl, + (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th); } if (th->tn != 0) { @@ -314,8 +321,9 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), - th, th->blk, max_tn, RTS_ERROR_TEXT("tnque transaction number"), 1, th->tn); + tmp_8byte = 1; + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), th, th->blk, &max_tn, + RTS_ERROR_TEXT("tnque transaction number"), &tmp_8byte, &th->tn); } /* ideally, the following max_tn assignment should have been in the else part of the above if. but * the issue with doing that is if there is a sequence of non-decreasing transaction numbers @@ -330,7 +338,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th, th->blk, th->blk, RTS_ERROR_TEXT("th->blk"), 0, csd->trans_hist.total_blks); } if (((int)(th->cache_index) != CR_NOTVALID) && @@ -338,21 +346,21 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th, th->blk, th->cache_index, RTS_ERROR_TEXT("th->cache_index"), cr_base, cr_top); } if (th->flushing != FALSE) /* ??? this is a gt.cx item that may require more synchronization at the top */ { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("th->flushing"), th->flushing, FALSE); } if (0 == th->tnque.fl) { /* No point proceeding to next iteration of loop as "th + th->tnque.fl" will be the same as "th" */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, RTS_ERROR_TEXT("tnque.fl"), (UINTPTR_T)th->tnque.fl, (UINTPTR_T)-1); break; } @@ -361,21 +369,21 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("tnque entries"), n_bts - cnt, n_bts - 1); } else if ((th == csa->th_base) && ((th_rec_ptr_t)((sm_uc_ptr_t)th + th->tnque.bl) != th_prev)) { /* at this point "th" is csa->th_base and its backlink does not point to the last entry in the th queue */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, RTS_ERROR_TEXT("tnque th_base"), (UINTPTR_T)th->tnque.bl, (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th); } if (max_tn > csd->trans_hist.curr_tn) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), - RTS_ERROR_TEXT("MAX(th_base->tn)"), max_tn, csd->trans_hist.curr_tn); + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg), + RTS_ERROR_TEXT("MAX(th_base->tn)"), &max_tn, &csd->trans_hist.curr_tn); } /* loop through bt blkques */ blkque_array = malloc(n_bts * SIZEOF(boolean_t)); @@ -386,7 +394,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("queue head bt->blk"), bt0->blk, BT_QUEHEAD); bt0->blk = BT_QUEHEAD; } @@ -398,7 +406,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt_prev, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt_prev, -1, RTS_ERROR_TEXT("bt->blkque"), bt, bt_lo, SIZEOF(bt_rec)); break; } @@ -406,7 +414,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), bt_prev, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), bt_prev, -1, bt, RTS_ERROR_TEXT("bt->blkque"), bt_lo, bt_hi); break; } @@ -414,7 +422,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("bt->blkque.bl"), (UINTPTR_T)bt->blkque.bl, (sm_uc_ptr_t)bt_prev - (sm_uc_ptr_t)bt); } @@ -424,7 +432,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("bt hash"), (bt0 - csa->bt_header), (UINTPTR_T)(bt->blk % csd->bt_buckets)); } @@ -436,19 +444,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), bt, bt->blk, cr, RTS_ERROR_TEXT("bt->cache_index"), cr_lo, cr_hi); } else if (CR_NOT_ALIGNED(cr, cr_lo)) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("bt->cache_index"), cr, cr_lo, SIZEOF(cache_rec)); } else if (cr->blk != bt->blk) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, bt->blk, RTS_ERROR_TEXT("bt block"), cr->blk, bt->blk, CALLFROM); } @@ -459,7 +467,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { /* No point proceeding to next iteration as "bt + bt->blkque.fl" will be the same as "bt" */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("bt->blkque.fl"), (UINTPTR_T)bt->blkque.fl, (UINTPTR_T)-1); break; } @@ -468,13 +476,13 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("btque entries"), n_bts + 1 - cnt, n_bts + 1); } else if ((bt == bt0) && ((bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->blkque.bl) != bt_prev)) { /* at this point "bt" is bt0 and its backlink does not point to last entry in the bt0'th queue */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("btque bt_base"), (UINTPTR_T)bt->blkque.bl, (sm_uc_ptr_t)bt_prev - (sm_uc_ptr_t)bt); } @@ -486,7 +494,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk, RTS_ERROR_TEXT("bt blkque hash"), (UINTPTR_T)-1, (UINTPTR_T)(bt->blk % csd->bt_buckets)); } } @@ -506,7 +514,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i "secshr_max_index exceeded. max_index = %d [0x%08x] : ops_index = %d [0x%08x]", SECSHR_OPS_ARRAY_SIZE, SECSHR_OPS_ARRAY_SIZE, cnl->secshr_ops_index, cnl->secshr_ops_index); - send_msg(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string)); + SEND_MSG_CSA(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string)); cnl->secshr_ops_index = SECSHR_OPS_ARRAY_SIZE; } for (i = 0; (i + 1) < cnl->secshr_ops_index; i += (int4)cnl->secshr_ops_array[i]) @@ -517,7 +525,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i SPRINTF(secshr_string_delta, " : [0x%08lx]", cnl->secshr_ops_array[lcnt]); strcat(secshr_string, secshr_string_delta); } - send_msg(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string)); + SEND_MSG_CSA(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string)); } cnl->secshr_ops_index = 0; } @@ -530,15 +538,16 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, cr->blk, RTS_ERROR_TEXT("cr->blk"), 0, csd->trans_hist.total_blks); } if (cr->tn > csd->trans_hist.curr_tn) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), - cr, cr->blk, cr->tn, RTS_ERROR_TEXT("cr->tn"), 0, csd->trans_hist.curr_tn); + tmp_8byte = 0; + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), + cr, cr->blk, &cr->tn, RTS_ERROR_TEXT("cr->tn"), &tmp_8byte, &csd->trans_hist.curr_tn); } if (0 != cr->bt_index) { @@ -546,14 +555,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, cr->bt_index, RTS_ERROR_TEXT("cr->bt_index"), bt_base_off, bt_top_off); } else if (!IS_PTR_ALIGNED(cr->bt_index, bt_base_off, SIZEOF(bt_rec))) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->bt_index"), cr->bt_index, bt_base_off, SIZEOF(bt_rec)); } else @@ -563,7 +572,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr block"), cr->blk, bt->blk, CALLFROM); } @@ -573,33 +582,33 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, cr->buffaddr, RTS_ERROR_TEXT("cr->buffaddr"), bp_lo, bp_top); } else if (!IS_PTR_ALIGNED(cr->buffaddr, bp_lo, csd->blk_size)) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp_lo, csd->blk_size); } else if (cr->buffaddr != bp) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp, CALLFROM); } if (cr->in_tend) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->in_tend"), cr->in_tend, FALSE, CALLFROM); } if (cr->data_invalid) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->data_invalid"), cr->data_invalid, FALSE, CALLFROM); } if (cr->r_epid != 0) @@ -608,7 +617,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->r_epid"), cr->r_epid, 0, CALLFROM); } } else if ((-1 == cr->read_in_progress) && !caller_is_wcs_recover && (CR_BLKEMPTY != cr->blk) @@ -631,10 +640,10 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("Block certification result"), FALSE, TRUE, CALLFROM); - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("Block certification result buffer"), bptmp, csa->lock_addrs[0], CALLFROM); } @@ -643,7 +652,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->in_cw_set"), (uint4)cr->in_cw_set, 0, CALLFROM); } assert(!JNL_ALLOWED(csd) || (NULL != csa->jnl) && (NULL != csa->jnl->jnl_buff)); @@ -654,7 +663,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, (uint4)cr->jnl_addr, RTS_ERROR_TEXT("cr->jnl_addr"), 0, csa->jnl->jnl_buff->freeaddr); } @@ -662,14 +671,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->jnl_addr"), (uint4)cr->jnl_addr, 0, CALLFROM); } if ((WRITE_LATCH_VAL(cr) < LATCH_CLEAR) || (WRITE_LATCH_VAL(cr) > LATCH_CONFLICT)) { /* the message would read cr->interlock.semaphore although in Unix it means cr->interlock.latch */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, WRITE_LATCH_VAL(cr), RTS_ERROR_TEXT("cr->interlock.semaphore"), LATCH_CLEAR, LATCH_CONFLICT); } @@ -679,7 +688,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->rip_latch"), cr->rip_latch.u.parts.latch_pid, 0, CALLFROM); } if (cr->iosb.cond != 0) @@ -694,17 +703,17 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); dummy_tn = (trans_num)TRUE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM); - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->cr->iosb"), cr->iosb.cond, 0, CALLFROM); } if (0 == cr->epid) { assert(expect_damage); - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->epid"), cr->epid, -1, CALLFROM); - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->iosb"), cr->iosb.cond, 0, CALLFROM); } } @@ -713,7 +722,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = (trans_num)TRUE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM); } if (cr->twin != 0) @@ -723,19 +732,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk, cr_tmp, RTS_ERROR_TEXT("cr->twin"), cr_lo, cr_hi); } else if (CR_NOT_ALIGNED(cr_tmp, cr_lo)) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->twin"), cr_tmp, cr_lo, SIZEOF(cache_rec)); } else if (cr != (cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, cr_tmp->twin)) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_tmp, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_tmp, cr->blk, RTS_ERROR_TEXT("cr->twin->twin"), GDS_ANY_REL2ABS(csa, cr_tmp->twin), cr, CALLFROM); } @@ -746,21 +755,21 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->twin"), cr->twin, 0, CALLFROM); } if (0 != cr->image_count) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->image_count"), cr->image_count, 0, CALLFROM); } if ((0 != cr->epid) && caller_is_wcs_recover) { /* if called from DSE CACHE -VERIFY, we do not wait for concurrent writers to finish */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->epid"), cr->epid, 0, CALLFROM); } #endif @@ -768,14 +777,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->wip_stopped"), cr->wip_stopped, FALSE, CALLFROM); } if (FALSE != cr->stopped) { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->stopped"), cr->stopped, FALSE, CALLFROM); } } @@ -786,7 +795,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr0, cr0->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr0, cr0->blk, RTS_ERROR_TEXT("queue head cr->blk"), cr0->blk, BT_QUEHEAD, CALLFROM); cr0->blk = BT_QUEHEAD; } @@ -798,7 +807,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr0, -1, cr, RTS_ERROR_TEXT("cr->blkque"), cr_lo, cr_hi); break; } @@ -806,7 +815,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr0, -1, RTS_ERROR_TEXT("cr->blkque"), cr, cr_lo, SIZEOF(cache_rec)); break; } @@ -814,7 +823,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->blkque.bl"), (UINTPTR_T)cr->blkque.bl, (sm_uc_ptr_t)cr_prev - (sm_uc_ptr_t)cr); } @@ -822,7 +831,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr hash"), cr0 - cr_qbase, cr->blk % csd->bt_buckets, CALLFROM); if (caller_is_wcs_recover && !cr->stopped) { /* if cr->stopped is TRUE, then the buffer was created by secshr_db_clnup(), @@ -856,7 +865,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { /* No point proceeding to next iteration as "cr + cr->blkque.fl" will be the same as "cr" */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr->blkque.fl"), (UINTPTR_T)cr->blkque.fl, (UINTPTR_T)-1); break; } @@ -865,13 +874,13 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr_qbase, 0, RTS_ERROR_TEXT("crque entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)(n_bts)); } else if ((cr == cr0) && ((cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.bl) != cr_prev)) { /* at this point "cr" is cr0 and its backlink does not point to last entry in the cr0'th queue */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("crque cr_base"), (UINTPTR_T)cr->blkque.bl, (sm_uc_ptr_t)cr_prev - (sm_uc_ptr_t)cr); } @@ -883,7 +892,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("cr blkque hash"), -1, cr->blk % csd->bt_buckets, CALLFROM); if (caller_is_wcs_recover && !cr->stopped) /* see comment above ("cr hash") for similar handling */ { @@ -898,7 +907,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_active"), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_active"), que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl)); } /* loop through the active queue */ @@ -912,7 +921,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1, cr, RTS_ERROR_TEXT("active cstt->state_que"), cr_lo, cr_hi); break; } @@ -920,7 +929,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1, RTS_ERROR_TEXT("active cstt->state_que"), cr, cr_lo, SIZEOF(cache_rec)); break; } @@ -928,7 +937,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, RTS_ERROR_TEXT("active queue.bl"), (UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt); } @@ -937,7 +946,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = (trans_num)TRUE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk, RTS_ERROR_TEXT("active cr->dirty"), &cstt->dirty, &dummy_tn, CALLFROM); } if (((0 != cstt->flushed_dirty_tn) && (cstt->dirty <= cstt->flushed_dirty_tn)) @@ -946,7 +955,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = cstt->flushed_dirty_tn + 1; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), cstt + SIZEOF(que_head), cstt->blk, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), cstt + SIZEOF(que_head), cstt->blk, &cstt->dirty, RTS_ERROR_TEXT("active dirty (tn)"), &dummy_tn, &csd->trans_hist.curr_tn); } /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues @@ -958,7 +967,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { /* No point proceeding to next iteration as "cstt + cstt->state_que.fl" will be same as "cstt" */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, RTS_ERROR_TEXT("active queue.fl"), (UINTPTR_T)cstt->state_que.fl, (UINTPTR_T)-1); break; } @@ -967,14 +976,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("active queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts); } else if ((cstt == (cache_state_rec_ptr_t)que_head) && ((cache_state_rec_ptr_t)((sm_uc_ptr_t)cstt + cstt->state_que.bl) != cstt_prev)) { /* at this point "cstt" is active que_head and its backlink does not point to last entry in active queue */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"), (UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt); } @@ -984,7 +993,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_wip"), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_wip"), que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl)); } #ifdef VMS @@ -997,7 +1006,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1, cr, RTS_ERROR_TEXT("wip cstt->state_que"), cr_lo, cr_hi); break; } @@ -1005,7 +1014,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1, + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1, RTS_ERROR_TEXT("wip cstt->state_que"), cr, cr_lo, SIZEOF(cache_rec)); break; } @@ -1013,7 +1022,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, RTS_ERROR_TEXT("wip queue.bl"), (UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt); } @@ -1022,7 +1031,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i * { * assert(expect_damage); * ret = FALSE; - * send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), + * SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), * cr, cstt->blk, RTS_ERROR_TEXT("wip cr->epid"), cstt->epid, -1, CALLFROM); * } */ @@ -1031,7 +1040,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = (trans_num)TRUE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk, RTS_ERROR_TEXT("wip cr->dirty"), &cstt->dirty, &dummy_tn, CALLFROM); } if (((0 != cstt->flushed_dirty_tn) && (cstt->dirty <= cstt->flushed_dirty_tn)) @@ -1040,8 +1049,9 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = cstt->flushed_dirty_tn + 1; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), (int)cstt + SIZEOF(que_head), cstt->blk, - &cstt->dirty, RTS_ERROR_TEXT("wip dirty (tn)"), &dummy_tn, &csd->trans_hist.curr_tn); + SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), (int)cstt + SIZEOF(que_head), + cstt->blk, &cstt->dirty, RTS_ERROR_TEXT("wip dirty (tn)"), &dummy_tn, + &csd->trans_hist.curr_tn); } /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues * and so it is ok to do the FAKE_DIRTY check. but otherwise it is not. @@ -1052,7 +1062,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk, RTS_ERROR_TEXT("wip queue.fl"), (UINTPTR_T)cstt->state_que.fl, (UINTPTR_T)-1); break; } @@ -1061,14 +1071,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("wip queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts); } else if ((cstt == (cache_state_rec_ptr_t)que_head) && ((cache_state_rec_ptr_t)((sm_uc_ptr_t)cstt + cstt->state_que.bl) != cstt_prev)) { /* at this point "cstt" is wip que_head and its backlink does not point to last entry in the wip queue */ assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"), (UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt); } #else @@ -1076,7 +1086,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("wip queue head fl"), (UINTPTR_T)que_head->fl, (UINTPTR_T)0); que_head->fl = 0; } @@ -1084,7 +1094,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i { assert(expect_damage); ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), + SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("wip queue head bl"), (UINTPTR_T)que_head->bl, (UINTPTR_T)0); que_head->bl = 0; } @@ -1105,222 +1115,15 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i assert(expect_damage); ret = FALSE; dummy_tn = (trans_num)FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk, + SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk, RTS_ERROR_TEXT("non-state cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM); } } } } - } else - { -# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC) - mbr_lo = (mmblk_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets; - mbr_hi = mbr_lo + n_bts; - /* loop through the mbr blkques */ - for (mbr0 = (mmblk_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array, mbr_qbase = mbr0; mbr0 < mbr_lo; mbr0++) - { - if (mbr0->blk != BT_QUEHEAD) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr0, mbr0->blk, - RTS_ERROR_TEXT("queue head mbr->blk"), mbr0->blk, BT_QUEHEAD, CALLFROM); - mbr0->blk = BT_QUEHEAD; - } - for (mbr_prev = mbr0, mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr0 + mbr0->blkque.fl), cnt = n_bts + 1; - (mbr != mbr0) && (cnt > 0); - mbr_prev = mbr, cnt--, mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.fl)) - { - if (MBR_NOT_IN_RANGE(mbr, mbr_lo, mbr_hi)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), - mbr0, -1, mbr, RTS_ERROR_TEXT("mbr->blkque"), mbr_lo, mbr_hi); - break; - } - if (MBR_NOT_ALIGNED(mbr, mbr_lo)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), - mbr0, -1, RTS_ERROR_TEXT("mbr->blkque"), mbr, mbr_lo, SIZEOF(mmblk_rec)); - break; - } - if ((mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.bl) != mbr_prev) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("mbr->blkque.bl"), (UINTPTR_T)mbr->blkque.bl, - (sm_uc_ptr_t)mbr_prev - (sm_uc_ptr_t)mbr); - } - if (((int)(mbr->blk) != MBR_BLKEMPTY) && ((mbr_qbase + (mbr->blk % csd->bt_buckets)) != mbr0)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("mbr hash"), mbr0 - mbr_qbase, mbr->blk % csd->bt_buckets, - CALLFROM); - } - (*blkque_array)[mbr - mbr_lo] = TRUE; /* note: mbr's blkque hash validity is already checked */ - if (0 == mbr->blkque.fl) - { /* Don't proceed to next iteration as "mbr + mbr->blkque.fl" will be the same as "mbr" */ - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("mbr->blkque.fl"), (UINTPTR_T)mbr->blkque.fl, (UINTPTR_T)-1); - break; - } - } - if (cnt == 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), - mbr_qbase, 0, RTS_ERROR_TEXT("mbrque entries"), (UINTPTR_T)(n_bts + 1), - (UINTPTR_T)(n_bts)); - } else if ((mbr == mbr0) && ((mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.bl) != mbr_prev)) - { /* at this point "mbr" is mbr0 and its backlink does not point to last entry in the mbr0'th queue */ - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("mbrque mbr_base"), (UINTPTR_T)mbr->blkque.bl, - (sm_uc_ptr_t)mbr_prev - (sm_uc_ptr_t)mbr); - } - } - /* scan all mbrs looking for non-empty mbr->blks whose mbrs were not in any blkque */ - for (mbr = mbr_lo; mbr < mbr_hi; mbr++) - { - if ((FALSE == (*blkque_array)[mbr - mbr_lo]) && ((int)(mbr->blk) != MBR_BLKEMPTY)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("mbr blkque hash"), -1, mbr->blk % csd->bt_buckets, CALLFROM); - } - } - que_head = &csa->acc_meth.mm.mmblk_state->mmblkq_active; - if ((sm_long_t)que_head % SIZEOF(que_head->fl) != 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("mmblkq_active"), - que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl)); - } - /* loop through the active queue */ - for (mbstt_prev = (mmblk_state_rec_ptr_t)que_head, - mbstt = (mmblk_state_rec_ptr_t)((sm_uc_ptr_t)que_head + que_head->fl), cnt = n_bts; - (mbstt != (mmblk_state_rec_ptr_t)que_head) && (cnt > 0); - mbstt_prev = mbstt, cnt--, mbstt = (mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.fl)) - { - mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbstt - SIZEOF(mbr->blkque)); - if (MBR_NOT_IN_RANGE((mmblk_rec_ptr_t)mbr, mbr_lo, mbr_hi)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1, - mbr, RTS_ERROR_TEXT("active mbstt->state_que"), mbr_lo, mbr_hi); - break; - } - if (MBR_NOT_ALIGNED(mbr, mbr_lo)) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1, - RTS_ERROR_TEXT("active mbstt->state_que"), mbr, mbr_lo, SIZEOF(mmblk_rec)); - break; - } - if ((mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.bl) != mbstt_prev) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, mbstt->blk, - RTS_ERROR_TEXT("active queue.bl"), (UINTPTR_T)mbstt->state_que.bl, - (sm_uc_ptr_t)mbstt_prev - (sm_uc_ptr_t)mbstt); - } - if (0 == mbstt->dirty) - { - assert(expect_damage); - ret = FALSE; - dummy_tn = (trans_num)TRUE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), mbr, mbstt->blk, - RTS_ERROR_TEXT("active mbr->dirty"), &mbstt->dirty, &dummy_tn, CALLFROM); - } - /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues - * and so it is ok to do the FAKE_DIRTY check. but otherwise it is not. - */ - if (caller_is_wcs_recover) - mbstt->dirty = FAKE_DIRTY; /* change the flag to indicate it was found in a state queue */ - if (0 == mbstt->state_que.fl) - { /* No point proceeding to next iteration as "mbstt + mbstt->state_que.fl" will be same as "mbstt" */ - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, mbstt->blk, - RTS_ERROR_TEXT("active queue.fl"), (UINTPTR_T)mbstt->state_que.fl, (UINTPTR_T)-1); - break; - } - } - if (cnt == 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), - que_head, 0, RTS_ERROR_TEXT("active queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts); - } else if ((mbstt == (mmblk_state_rec_ptr_t)que_head) - && ((mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.bl) != mbstt_prev)) - { /* at this point "mbstt" is active que_head and its backlink does not point to last entry in active queue */ - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, 0, RTS_ERROR_TEXT("active queue base"), - (UINTPTR_T)mbstt->state_que.bl, (sm_uc_ptr_t)mbstt_prev - (sm_uc_ptr_t)mbstt); - } - - /* loop through the wip queue */ - que_head = &csa->acc_meth.mm.mmblk_state->mmblkq_wip; - if ((sm_long_t)que_head % SIZEOF(que_head->fl) != 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("mmblkq_wip"), - que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl)); - } - if (que_head->fl != 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), - que_head, 0, RTS_ERROR_TEXT("wip queue head fl"), (UINTPTR_T)que_head->fl, (UINTPTR_T)0); - que_head->fl = 0; - } - if (que_head->bl != 0) - { - assert(expect_damage); - ret = FALSE; - send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), - que_head, 0, RTS_ERROR_TEXT("wip queue head bl"), (UINTPTR_T)que_head->bl, (UINTPTR_T)0); - que_head->bl = 0; - } - /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues - * and so it is ok to do the FAKE_DIRTY check. but otherwise it is not. - */ - if (caller_is_wcs_recover) - { /* loop through the mmblk_recs again to look for lost dirties */ - for (mbr = mbr_lo, cnt = n_bts; cnt > 0; mbr++, cnt--) - { - if (0 != mbr->dirty) - { - assert(expect_damage); - ret = FALSE; - dummy_tn = (trans_num)FALSE; - send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), mbr, mbr->blk, - RTS_ERROR_TEXT("non-state mbr->dirty"), &mbr->dirty, &dummy_tn, CALLFROM); - } - } - } -# endif } - send_msg(VARLSTCNT(7) ERR_DBWCVERIFYEND, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn); - if (NULL != blkque_array) free(blkque_array); + SEND_MSG_CSA(VARLSTCNT(7) ERR_DBWCVERIFYEND, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn); + if (NULL != blkque_array) + free(blkque_array); return ret; } diff --git a/sr_port/wrtcatopt.c b/sr_port/wrtcatopt.c index a29e851..9347d82 100644 --- a/sr_port/wrtcatopt.c +++ b/sr_port/wrtcatopt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,7 +26,7 @@ void wrtcatopt(triple *r, triple ***lpx, triple **lptop) assert(r->operand[1].oprclass == TRIP_REF); assert(r->operand[0].oprval.tref->opcode == OC_ILIT); ref = r->operand[1].oprval.tref; - r->operand[0].oprclass = r->operand[1].oprclass = 0; + r->operand[0].oprclass = r->operand[1].oprclass = NO_REF; r->opcode = OC_NOOP; for (;;) { @@ -39,13 +39,13 @@ void wrtcatopt(triple *r, triple ***lpx, triple **lptop) else { wrtcatopt(ref->operand[0].oprval.tref, lpx, lptop); - ref->operand[0].oprclass = 0; + ref->operand[0].oprclass = NO_REF; ref->opcode = OC_NOOP; } if (ref->operand[1].oprclass == 0) break; assert(ref->operand[1].oprclass == TRIP_REF); - ref->operand[1].oprclass = 0; + ref->operand[1].oprclass = NO_REF; ref = ref->operand[1].oprval.tref; } } diff --git a/sr_port/xcmd.mpt b/sr_port/xcmd.mpt index ff3152e..9fbedd6 100644 --- a/sr_port/xcmd.mpt +++ b/sr_port/xcmd.mpt @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2010 Fidelity Information Services, Inc. ; +; Copyright 2012 Fidelity Information Services, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -8,8 +8,83 @@ ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -%XCMD ; utility to execute a shell command and return a non-zero status on error + ; Utility to execute a shell command and return a non-zero status on error ; - set $ztrap="" - xecute $zcmdline +%XCMD ; Usage: mumps -run %XCMD '' + ; + set $ETRAP="goto CLIERR^%XCMD" + do ; protect %XCMD's error handler + . new $ETRAP set $ETRAP="goto CLIERR^%XCMD" + . xecute $zcmdline quit + +CLIERR + for i=1:1:$length($zstatus,",") quit:i>$length($zstatus,",") do + . if $piece($zstatus,",",i)?1(1"%",1"-")3.U1"-"1U1"-".E do ; split on GTM error format + . . write:$data(lasti) $piece($zstatus,",",lasti,i-1),! + . . set lasti=i + write $piece($zstatus,",",$get(lasti,3),i),! + zhalt +$piece($zstatus,",",1) + quit + + ; Perform a given command on every line of input + ; +LOOP ; Usage: mumps -run LOOP^%XCMD [--before=||] [--after=||] --xec=|| + set $ETRAP="do LOOPERR^%XCMD" + new %cli,%l,%NR,%xcmd + set %cli=$zcmdline + for quit:'$$trimleadingstr(.%cli,"--") do ; process command line options + . if $$trimleadingstr(.%cli,"after=") set %xcmd("after")=$$trimleadingdelimstr(.%cli) + . else if $$trimleadingstr(.%cli,"before=") set %xcmd("before")=$$trimleadingdelimstr(.%cli) + . else if $$trimleadingstr(.%cli,"xec=") set %xcmd("xec")=$$trimleadingdelimstr(.%cli) + . else set $ecode=",U254," + . if $$trimleadingstr(.%cli," ") + set:'$length($get(%xcmd("xec"))) $ecode=",U253," + set:$length(%cli) $ecode=",U252," + kill %cli + do ; protect %XCMD's error handler + . new $ETRAP set $ETRAP="do LOOPERR^%XCMD" + . do cmd($get(%xcmd("before")),0,"") + . for %NR=1:1 read %l quit:$zeof do cmd(%xcmd("xec"),%NR,%l) + . do cmd($get(%xcmd("after")),%NR,%l) + quit + +cmd(cmd,%NR,%l) + quit:$length(cmd)=0 + new %xcmd + xecute cmd + quit + +LOOPERR + ; attempt to trap internal errors + set uecode=$piece($ecode,",",2),uemsg=$text(@uecode) + if $length(uemsg) write $text(+0),@$piece(uemsg,";",2),! zhalt +$extract(uecode,2,$length(uecode)) + use $principal + write $zstatus,! + zhalt 1 + quit + + ; Remove and optionally return leading delimited string from str +trimleadingdelimstr(str) + new delim,substr + set delim=$extract(str,1) + set substr=$piece(str,delim,2) + set str=$extract(str,$length(substr)+3,$length(str)) + quit:$quit substr quit + + ; Remove and optionally return first piece of s with space as piece separator +trimleadingpiece(str) + new tmp + set tmp=$piece(str," ",1) + set str=$piece(str," ",2,$length(str," ")) + quit:$quit tmp quit + + ; Return s without leading $length(x) characters; return 1/0 if called as function +trimleadingstr(str,x) + if x=$extract(str,1,$length(x)) set str=$extract(str,$length(x)+1,$length(str)) quit:$quit 1 quit + else quit:$quit 0 quit + +; Error message texts +U252 ;"-F-UNRECCMD Unrecognized commands starting with "_%cli +U253 ;"-F-EMPTYXEC String to Xecute with --xec is required but not provided" +U254 ;"-F-ILLEGALCMD Illegal command line option(s) starting with --"_%cli diff --git a/sr_port/xfer.h b/sr_port/xfer.h index 765390f..0ec34f6 100644 --- a/sr_port/xfer.h +++ b/sr_port/xfer.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -199,14 +199,14 @@ XFER(xf_trestart, opp_trestart), XFER(xf_tstart, opp_tstart), XFER(xf_exp, op_exp), XFER(xf_fnget2, op_fnget2), -XFER(xf_indget, opp_indget), +XFER(xf_dummy, op_fnget2), /* left to prevent massive slide - reuse at next opportunity */ XFER(xf_fnname, op_fnname), XFER(xf_indfnname, opp_indfnname), XFER(xf_fnlvprvname, op_fnlvprvname), XFER(xf_gvo2, op_gvo2), XFER(xf_fnlvnameo2, op_fnlvnameo2), XFER(xf_fno2, op_fno2), -XFER(xf_indo2, opp_indo2), +XFER(xf_indo2, op_indo2), XFER(xf_get_msf, op_get_msf), XFER(xf_dt_get, op_dt_get), XFER(xf_dt_store, op_dt_store), @@ -226,7 +226,7 @@ XFER(xf_fgnlookup, op_fgnlookup), XFER(xf_sorts_after, op_sorts_after), XFER(xf_fnzqgblmod, op_fnzqgblmod), XFER(xf_fngvget1, op_fngvget1), -XFER(xf_fngvget2, op_fngvget2), +XFER(xf_fnget1, op_fnget1), XFER(xf_setp1, op_setp1), XFER(xf_setextract, op_setextract), XFER(xf_inddevparms, opp_inddevparms), @@ -281,8 +281,25 @@ XFER(xf_zwritesvn, op_zwritesvn), #ifdef UNIX XFER(xf_ztrigger, op_ztrigger), /* Restrict to UNIX, not GTM_TRIGGER since is in ttt.txt which cannot be #ifdef'd out */ #endif -XFER(xf_rfrshindx, op_rfrshindx), -XFER(xf_savputindx, op_savputindx), -XFER(xf_forfreeindx, op_forfreeindx), -XFER(xf_fornestlvl, op_fornestlvl), -XFER(xf_zhalt, op_zhalt) +XFER(xf_zhalt, op_zhalt), +XFER(xf_fnzwrite, op_fnzwrite), +XFER(xf_igetdst, op_igetdst), +XFER(xf_indget1, op_indget1), +XFER(xf_glvnpop, op_glvnpop), +XFER(xf_glvnslot, op_glvnslot), +XFER(xf_indsavglvn, opp_indsavglvn), +XFER(xf_indsavlvn, opp_indsavlvn), +XFER(xf_rfrshlvn, op_rfrshlvn), +XFER(xf_savgvn, op_savgvn), +XFER(xf_savlvn, op_savlvn), +XFER(xf_shareslot, op_shareslot), +XFER(xf_stoglvn, op_stoglvn), +XFER(xf_rfrshgvn, op_rfrshgvn), +XFER(xf_indfnname2, op_indfnname2), +XFER(xf_indget2, op_indget2), +XFER(xf_indmerge2, op_indmerge2), +#ifdef UNIX +XFER(xf_fnzpeek, op_fnzpeek), +#endif +XFER(xf_litc, op_litc), +XFER(xf_stolitc, op_stolitc) diff --git a/sr_port/zbreak.h b/sr_port/zbreak.h index 57ee227..1da6f58 100644 --- a/sr_port/zbreak.h +++ b/sr_port/zbreak.h @@ -12,7 +12,7 @@ #ifndef ZBREAK_H_INCLUDED #define ZBREAK_H_INCLUDED -#include "zbreaksp.h" +#include #include "cache.h" typedef struct diff --git a/sr_port/zlput_rname.c b/sr_port/zlput_rname.c index 363b6b0..3a84593 100644 --- a/sr_port/zlput_rname.c +++ b/sr_port/zlput_rname.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,8 @@ #include "mdef.h" #include "gtm_string.h" -#include "rtnhdr.h" +#include "cmd_qlf.h" +#include #include "stack_frame.h" #include "hashtab_mname.h" #include "fix_pages.h" @@ -188,47 +189,45 @@ bool zlput_rname (rhdtyp *hdr) tabent->value = NULL; } } - NON_USHBIN_ONLY( - hdr->old_rhead_ptr = (int4)old_rhead; - if (!old_rhead->old_rhead_ptr) - { - fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead) - + (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len)); - } - ) - USHBIN_ONLY( - if (!old_rhead->shlib_handle) - { /* Migrate text literals pointing into text area we are about to throw away into the stringpool. - We also can release the read-only releasable segment as it is no longer needed. +# ifndef USHBIN_SUPPORTED + hdr->old_rhead_ptr = (int4)old_rhead; + if (!old_rhead->old_rhead_ptr) + { + fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead) + + (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len)); + } +# else /* USHBIN_SUPPORTED */ + if (!old_rhead->shlib_handle) + { /* Migrate text literals pointing into text area we are about to throw away into the stringpool. + We also can release the read-only releasable segment as it is no longer needed. + */ + stp_move((char *)old_rhead->literal_text_adr, + (char *)(old_rhead->literal_text_adr + old_rhead->literal_text_len)); + if (tabent) + { /* There was (at one time) a $TEXT source section for this routine. We may have just + released it but whether the source was for the routine just replaced or for an earlier + replacement, the key for that segment is pointing into the readonly storage we + are just about to release. Replace the key with the current one for this routine. */ - stp_move((char *)old_rhead->literal_text_adr, - (char *)(old_rhead->literal_text_adr + old_rhead->literal_text_len)); - if (tabent) - { /* There was (at one time) a $TEXT source section for this routine. We may have just - released it but whether the source was for the routine just replaced or for an earlier - replacement, the key for that segment is pointing into the readonly storage we - are just about to release. Replace the key with the current one for this routine. - */ - assert(MSTR_EQ(&tabent->key.var_name, rtn_name)); - tabent->key.var_name = *rtn_name; /* Update key with newly saved mident */ - } - zlmov_lnames(old_rhead); /* copy the label names from literal pool to malloc'd area */ - GTM_TEXT_FREE(old_rhead->ptext_adr); - /* Reset the routine header pointers to the sections we just freed up. - * NOTE: literal_text_adr shouldn't be reset as it points to the label area malloc'd - * in zlmov_lnames() */ - old_rhead->ptext_adr = old_rhead->ptext_end_adr = NULL; - old_rhead->lnrtab_adr = NULL; + assert(MSTR_EQ(&tabent->key.var_name, rtn_name)); + tabent->key.var_name = *rtn_name; /* Update key with newly saved mident */ } - urx_remove(old_rhead); - free(old_rhead->literal_adr); /* Release the read-write releasable segments */ - old_rhead->literal_adr = NULL; - old_rhead->vartab_adr = NULL; - - free(old_rhead->linkage_adr); /* Release the old linkage section */ - old_rhead->linkage_adr = NULL; - hdr->old_rhead_adr = old_rhead; - ) + zlmov_lnames(old_rhead); /* copy the label names from literal pool to malloc'd area */ + GTM_TEXT_FREE(old_rhead->ptext_adr); + /* Reset the routine header pointers to the sections we just freed up. + * NOTE: literal_text_adr shouldn't be reset as it points to the label area malloc'd + * in zlmov_lnames() */ + old_rhead->ptext_adr = old_rhead->ptext_end_adr = NULL; + old_rhead->lnrtab_adr = NULL; + } + urx_remove(old_rhead); + free(RW_REL_START_ADR(old_rhead)); /* Release the read-write releasable segments */ + old_rhead->literal_adr = NULL; + old_rhead->vartab_adr = NULL; + free(old_rhead->linkage_adr); /* Release the old linkage section */ + old_rhead->linkage_adr = NULL; + hdr->old_rhead_adr = old_rhead; +# endif mid->rt_name = *rtn_name; } mid->rt_adr= hdr; diff --git a/sr_port/zr_find.c b/sr_port/zr_find.c index e24bcbe..0347a94 100644 --- a/sr_port/zr_find.c +++ b/sr_port/zr_find.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "zbreak.h" zbrk_struct *zr_find(z_records *zrecs, zb_code *addr) diff --git a/sr_port/zr_get_free.c b/sr_port/zr_get_free.c index 2b735b7..b5b0b6a 100644 --- a/sr_port/zr_get_free.c +++ b/sr_port/zr_get_free.c @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "zbreak.h" zbrk_struct *zr_get_free(z_records *zrecs, zb_code *addr) diff --git a/sr_port/zr_init.c b/sr_port/zr_init.c index cfd0fe0..ba1a359 100644 --- a/sr_port/zr_init.c +++ b/sr_port/zr_init.c @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include "rtnhdr.h" +#include #include "zbreak.h" void zr_init(z_records *zrecs, int4 count) diff --git a/sr_port/zr_put_free.c b/sr_port/zr_put_free.c index af4ceb7..ee2ef02 100644 --- a/sr_port/zr_put_free.c +++ b/sr_port/zr_put_free.c @@ -14,7 +14,7 @@ #include "gtm_string.h" #include "cache.h" -#include "rtnhdr.h" +#include #include "zbreak.h" #include "inst_flush.h" #include "private_code_copy.h" diff --git a/sr_port/zr_remove.c b/sr_port/zr_remove.c index 1eb27a2..5278e73 100644 --- a/sr_port/zr_remove.c +++ b/sr_port/zr_remove.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "zbreak.h" #include "break.h" #include "gtmmsg.h" diff --git a/sr_port/zshow.h b/sr_port/zshow.h index 07a09aa..a98bbc8 100644 --- a/sr_port/zshow.h +++ b/sr_port/zshow.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,11 +12,12 @@ #ifndef ZSHOW_H #define ZSHOW_H -#define ZSHOW_DEVICE 1 -#define ZSHOW_GLOBAL 2 -#define ZSHOW_LOCAL 3 -#define ZSHOW_NOPARM -1 -#define ZSHOW_ALL "IVBDLGSC" +#define ZSHOW_DEVICE 1 +#define ZSHOW_GLOBAL 2 +#define ZSHOW_LOCAL 3 +#define ZSHOW_BUFF_ONLY 4 +#define ZSHOW_NOPARM -1 +#define ZSHOW_ALL "IVBDLGSC" #define CLEANUP_ZSHOW_BUFF \ { \ @@ -90,7 +91,7 @@ void zshow_zcalls(zshow_out *output); void zshow_gvstats(zshow_out *output); void zshow_zwrite(zshow_out *output); boolean_t zwr2format(mstr *src, mstr *des); -int zwrkeylength(char* ptr, int len); +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 mval_write(zshow_out *output, mval *v, boolean_t flush); void mval_nongraphic(zshow_out *output, char *cp, int len, int num); diff --git a/sr_port/zshow_output.c b/sr_port/zshow_output.c index ab59e4c..02f4a62 100644 --- a/sr_port/zshow_output.c +++ b/sr_port/zshow_output.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,7 @@ #include "error.h" #include "lv_val.h" #include "subscript.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "mlkdef.h" #include "zshow.h" @@ -75,17 +75,17 @@ void zshow_output(zshow_out *out, const mstr *str) out->size = MAXSTR_BUFF_ALLOC(str->len, out->buff, buff_len); out->ptr = out->buff + buff_len; } + if (!process_exiting) + { /* Only if not exiting in case we are called from mdb_condition_handler + * with stack overflow */ + PUSH_MV_STENT(MVST_MVAL); + mv = &mv_chain->mv_st_cont.mvs_mval; + } else + mv = &lmv; + mv->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before value gets initialized below */ switch (out->type) { case ZSHOW_DEVICE: - if (!process_exiting) - { /* Only if not exiting in case we are called from mdb_condition_handler - * with stack overflow */ - PUSH_MV_STENT(MVST_MVAL); - mv = &mv_chain->mv_st_cont.mvs_mval; - } else - mv = &lmv; - mv->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before value gets initialized below */ if (str) { len = str->len; @@ -169,19 +169,8 @@ void zshow_output(zshow_out *out, const mstr *str) out->displen = 0; out->line_num++; } - if (!process_exiting) - { - POP_MV_STENT(); - } break; case ZSHOW_LOCAL: - if (!process_exiting) - { - PUSH_MV_STENT(MVST_MVAL); - mv = &mv_chain->mv_st_cont.mvs_mval; - } else - mv = &lmv; - mv->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before value gets initialized below */ if (out->code) { if (out->code != out->curr_code) @@ -290,8 +279,6 @@ void zshow_output(zshow_out *out, const mstr *str) out->line_num++; } } - if (!process_exiting) - POP_MV_STENT(); break; case ZSHOW_GLOBAL: if (!out->len) @@ -301,13 +288,6 @@ void zshow_output(zshow_out *out, const mstr *str) if (out->len < MIN_DATASIZE) rts_error(VARLSTCNT(1) ERR_ZSHOWGLOSMALL); } - if (!process_exiting) - { - PUSH_MV_STENT(MVST_MVAL); - mv = &mv_chain->mv_st_cont.mvs_mval; - } else - mv = &lmv; - mv->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before value gets initialized below */ if (out->code && out->code != out->curr_code) { gv_currkey->end = out->out_var.gv.end; @@ -396,15 +376,27 @@ void zshow_output(zshow_out *out, const mstr *str) out->ptr = out->buff; out->line_num++; } - if (!process_exiting) + break; + case ZSHOW_BUFF_ONLY: + /* This code is meant to print to a buffer so it DOES NOT bother setting the other fields of output. + * Only beginning and ending pointers because those are the only fields we need + */ + if (str) { - POP_MV_STENT(); + len = str->len; + strptr = str->addr; + memcpy(out->ptr, str->addr, len); + out->ptr += len; } break; default: GTMASSERT; break; } + if (!process_exiting) + { + POP_MV_STENT(); + } out->curr_code = out->code; out->flush = 0; } diff --git a/sr_port/zshow_params.h b/sr_port/zshow_params.h index b54d28e..d7ef7f7 100644 --- a/sr_port/zshow_params.h +++ b/sr_port/zshow_params.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2008 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,13 +24,16 @@ zshow_command, zshow_conv, zshow_ctra, zshow_dele, +zshow_dest, zshow_ebcd, zshow_edit, +zshow_empterm, zshow_exce, zshow_exte, zshow_field, zshow_fil, zshow_fixed, +zshow_follow, zshow_host, zshow_ichset, zshow_independent, @@ -38,9 +41,12 @@ zshow_inse, zshow_lab, zshow_leng, zshow_nocene, +zshow_nodest, zshow_noecho, zshow_noedit, +zshow_noempterm, zshow_noesca, +zshow_nofollow, zshow_nohost, zshow_noinse, zshow_nopast, diff --git a/sr_port/zshow_stack.c b/sr_port/zshow_stack.c index bd3f3cc..ad81d17 100644 --- a/sr_port/zshow_stack.c +++ b/sr_port/zshow_stack.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,7 +13,7 @@ #include "gtm_string.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "mlkdef.h" #include "zshow.h" @@ -60,8 +60,10 @@ void zshow_stack(zshow_out *output) # endif break; /* Endpoint.. */ } - if (!(fp->type & SFT_COUNT) || (fp->type & SFT_ZINTR)) - { + if (!(fp->type & SFT_COUNT) || ((fp->type & SFT_ZINTR) && (fp->flags & SFF_INDCE))) + { /* SFT_ZINTR is normally indirect but if the frame has been replaced by non-indirect frame via ZGOTO or GOTO + * then do not include it in the indirect list here. + */ if (nfp < &nocount_frames[MAX_INDR_PER_COUNTED]) /* If room in array, save indirect frame type */ *nfp++ = fp->type; diff --git a/sr_port/zshow_svn.c b/sr_port/zshow_svn.c index fb855de..9096fd2 100644 --- a/sr_port/zshow_svn.c +++ b/sr_port/zshow_svn.c @@ -26,7 +26,7 @@ #include "gdscc.h" #include "io.h" #include "jnl.h" -#include "rtnhdr.h" +#include #include "stack_frame.h" #include "svnames.h" #include "mlkdef.h" @@ -142,7 +142,6 @@ GBLREF uint4 dollar_zjob; GBLREF mval dollar_zstatus; GBLREF mval dollar_zstep; GBLREF mval dollar_zsource; -GBLREF int dollar_zmaxtptime; GBLREF int4 dollar_zsystem; GBLREF int4 dollar_zeditor; GBLREF uint4 dollar_tlevel; @@ -527,7 +526,7 @@ void zshow_svn(zshow_out *output, int one_sv) break; /* CAUTION: fall through */ case SV_ZMAXTPTIME: - MV_FORCE_MVAL(&var, dollar_zmaxtptime); + MV_FORCE_MVAL(&var, TREF(dollar_zmaxtptime)); ZS_VAR_EQU(&x, zmaxtptime_text); mval_write(output, &var, TRUE); if (SV_ALL != one_sv) diff --git a/sr_port/zshow_zbreaks.c b/sr_port/zshow_zbreaks.c index e97c3c3..6a60584 100644 --- a/sr_port/zshow_zbreaks.c +++ b/sr_port/zshow_zbreaks.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "zbreak.h" #include "zshow.h" diff --git a/sr_port/ztrap_form_init.c b/sr_port/ztrap_form_init.c index e83fb9f..e838a4f 100644 --- a/sr_port/ztrap_form_init.c +++ b/sr_port/ztrap_form_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,15 +25,18 @@ GBLREF int ztrap_form; +error_def(ERR_LOGTOOLONG); +error_def(ERR_TRNLOGFAIL); + +/* Initialize ztrap_form appropriately. Note this routine is not resident in gtm_env_init() because it raises errors + * and error handling is not set up yet in gtm_env_init(). + */ void ztrap_form_init(void) { int4 status; mstr val, tn; char buf[1024], *buf_ptr = &buf[0]; - error_def(ERR_LOGTOOLONG); - error_def(ERR_TRNLOGFAIL); - ztrap_form = ZTRAP_CODE; /* default */ val.addr = ZTRAP_FORM; val.len = STR_LIT_LEN(ZTRAP_FORM); diff --git a/sr_port/ztrap_save_ctxt.c b/sr_port/ztrap_save_ctxt.c index 5afd87d..a79c78f 100644 --- a/sr_port/ztrap_save_ctxt.c +++ b/sr_port/ztrap_save_ctxt.c @@ -11,7 +11,7 @@ #include "mdef.h" -#include "rtnhdr.h" +#include #include "mv_stent.h" #include "mvalconv.h" #include "dollar_zlevel.h" diff --git a/sr_port/zwr2format.c b/sr_port/zwr2format.c index d866c04..c721552 100644 --- a/sr_port/zwr2format.c +++ b/sr_port/zwr2format.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -186,15 +186,27 @@ boolean_t zwr2format(mstr *src, mstr *des) return TRUE; } -/* Routine to compute the length of the KEY in ZWR format */ -int zwrkeylength(char* ptr, int len) +/* Routine to compute the length of the KEY, length of the VALUE and Offset of VALUE in ZWR format. + * This function takes 2 inputs and returns 5 piece of information. + * INPUT: + * ptr : starting address of the zwr format string. + * len : length of the zwr format string. + * OUTPUT: + * lenght of the key + * val_off : offset of the value(Right hand side of the '=' sign). + * val_len : length of the value(Length of the value present on right hand side of '=' sign). + * val_off1 : offset inside the value of spanning node present. + * val_len1 : length of data (of spanning node) present in the block. + */ +int zwrkeyvallen(char* ptr, int len, char **val_off, int *val_len, int *val_off1, int *val_len1) { - int keylength, keystate; + int keylength, keystate, off, *tmp; unsigned ch, chtmp; - boolean_t keepgoing; + boolean_t keepgoing, extfmt; keylength = 0; /* determine length of key */ keystate = 0; + ptr = (extfmt = ('$' == ptr[keylength]) ? 1 : 0) ? ptr + 4 : ptr; /*In extract first 4 chars are '$', 'z', 'e' and '(' */ keepgoing = TRUE; while ((keylength < len) && keepgoing) /* slightly different here from go_load since we can get kill records too */ { @@ -206,8 +218,11 @@ int zwrkeylength(char* ptr, int len) { keylength--; keepgoing = FALSE; - } - else if ('(' == ch) /* start of subscripts */ + } else if (',' == ch) + { + keylength--; + keepgoing = FALSE; + } else if ('(' == ch) /* start of subscripts */ keystate = 1; break; case 1: /* in subscripts area, but out of "..." or $C(...) */ @@ -277,5 +292,32 @@ int zwrkeylength(char* ptr, int len) break; } } + + if (extfmt) + { + off = keylength + 1; /* to point to second exp in $ext format */ + tmp = val_off1; + *tmp = 0; + while (TRUE) + { + ch = ptr[off++]; + if (')' == ch) + break; + if (',' == ch) + { + tmp = val_len1; + *tmp = 0; + continue; + } + *tmp = (10 * (*tmp)) + ch - 48; + } + *val_off = ptr + off + SIZEOF(char); /* SIZEOF(char) is used to make adjustment for '=' sign */ + *val_len = len - (off + SIZEOF(char) + 4); /* The prefix '$ze(' account for 4 chars */ + } + else + { + *val_off = ptr + (keylength + SIZEOF(char)); /* SIZEOF(char) is used to make adjustment for '=' sign */ + *val_len = len - (keylength + SIZEOF(char)); /* SIZEOF(char) is used to make adjustment for '=' sign */ + } return keylength; } diff --git a/sr_port_cm/gtcmd_cst_init.c b/sr_port_cm/gtcmd_cst_init.c index 589b8ef..98bb047 100644 --- a/sr_port_cm/gtcmd_cst_init.c +++ b/sr_port_cm/gtcmd_cst_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,32 +26,29 @@ #include "targ_alloc.h" #include "dpgbldir.h" -#define DIR_ROOT 1 - GBLREF int4 gv_keysize; GBLREF gv_key *gv_currkey; GBLREF gv_key *gv_altkey; GBLREF short gtcm_ast_avail; +error_def(CMERR_CMEXCDASTLM); + void gtcmd_cst_init(cm_region_head *ptr) { - gv_namehead *g; - gv_key *temp_key; gd_region *reg; sgmnt_addrs *csa; - error_def(CMERR_CMEXCDASTLM); - reg = ptr->reg; if (VMS_ONLY(gtcm_ast_avail > 0) UNIX_ONLY(TRUE)) gvcst_init(reg); else rts_error(VARLSTCNT(1) CMERR_CMEXCDASTLM); VMS_ONLY(gtcm_ast_avail--); - GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(reg->max_key_size)); +# ifdef DEBUG + assert(gv_keysize >= DBKEYSIZE(reg->max_key_size)); csa = &FILE_INFO(reg)->s_addrs; - assert(NULL == csa->dir_tree); - SET_CSA_DIR_TREE(csa, reg->max_key_size, reg); + assert(NULL != csa->dir_tree); +# endif init_hashtab_mname(ptr->reg_hash, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE); cm_add_gdr_ptr(reg); } diff --git a/sr_port_cm/gtcmd_rundown.c b/sr_port_cm/gtcmd_rundown.c index 4a68506..c3a81a5 100644 --- a/sr_port_cm/gtcmd_rundown.c +++ b/sr_port_cm/gtcmd_rundown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,6 +38,8 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF jnl_gbls_t jgbl; +error_def(ERR_NOTALLDBRNDWN); + #ifdef VMS GBLREF short gtcm_ast_avail; #endif @@ -52,6 +54,7 @@ void gtcmd_rundown(connection_struct *cnx, bool clean_exit) jnl_buffer_ptr_t jbp; int refcnt; boolean_t was_crit; + int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ for (ptr = cnx->region_root; ptr;) { @@ -100,7 +103,7 @@ void gtcmd_rundown(connection_struct *cnx, bool clean_exit) VMS_ONLY(gtcm_ast_avail++); if (JNL_ALLOWED(cs_data)) jpc->pini_addr = 0; - gds_rundown(); + UNIX_ONLY(rundown_status |=) gds_rundown(); gd_ht_kill(region->reg_hash, TRUE); /* TRUE to free up the table and the gv_targets it holds too */ FREE_CSA_DIR_TREE(cs_addrs); cm_del_gdr_ptr(gv_cur_region); @@ -114,4 +117,7 @@ void gtcmd_rundown(connection_struct *cnx, bool clean_exit) ptr = ptr->next; free(last); } + + if (EXIT_NRM != rundown_status) + rts_error(VARLSTCNT(1) ERR_NOTALLDBRNDWN); } diff --git a/sr_port_cm/gtcmtr_initreg.c b/sr_port_cm/gtcmtr_initreg.c index e60b697..ec8261b 100644 --- a/sr_port_cm/gtcmtr_initreg.c +++ b/sr_port_cm/gtcmtr_initreg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,10 @@ GBLREF connection_struct *curr_entry; +error_def(ERR_UNIMPLOP); +error_def(ERR_TEXT); +error_def(ERR_GVIS); + bool gtcmtr_initreg(void) { cm_region_head *region; @@ -33,14 +37,18 @@ bool gtcmtr_initreg(void) unsigned short temp_short; unsigned char buff[MAX_ZWR_KEY_SZ], *end; - error_def(ERR_UNIMPLOP); - error_def(ERR_TEXT); - error_def(ERR_GVIS); - assert(*curr_entry->clb_ptr->mbf == CMMS_S_INITREG); region = gtcmd_ini_reg(curr_entry); gtcm_add_region(curr_entry,region); + if (region->reg->max_rec_size > 32767) + { + rts_error(VARLSTCNT(10) ERR_UNIMPLOP, 0, + ERR_TEXT, 2, + LEN_AND_LIT("Client does not support spanning nodes"), + ERR_TEXT, 2, DB_LEN_STR(region->reg)); + } + if (region->reg->max_rec_size + CM_BUFFER_OVERHEAD > curr_entry->clb_ptr->mbl) { free(curr_entry->clb_ptr->mbf); diff --git a/sr_port_cm/gtcmtr_put.c b/sr_port_cm/gtcmtr_put.c index aa6d22e..ee32e1b 100644 --- a/sr_port_cm/gtcmtr_put.c +++ b/sr_port_cm/gtcmtr_put.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -95,9 +95,9 @@ bool gtcmtr_put(void) { if ((end = format_targ_key(&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; - rts_error(VARLSTCNT(11) ERR_REC2BIG, 4, n + v.str.len + SIZEOF(rec_hdr), + rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, n + v.str.len + SIZEOF(rec_hdr), (int4)gv_cur_region->max_rec_size, REG_LEN_STR(gv_cur_region), - 0, ERR_GVIS, 2, end - buff, buff); + ERR_GVIS, 2, end - buff, buff); } gvcst_put(&v); if (JNL_ALLOWED(cs_addrs)) diff --git a/sr_port_cm/gvcmy_open.c b/sr_port_cm/gvcmy_open.c index 52213fd..d686ed9 100644 --- a/sr_port_cm/gvcmy_open.c +++ b/sr_port_cm/gvcmy_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,6 +43,13 @@ GBLREF spdesc stringpool; +error_def(ERR_BADSRVRNETMSG); +error_def(ERR_INVNETFILNM); +error_def(ERR_LOGTOOLONG); +error_def(ERR_NETDBOPNERR); +error_def(ERR_SYSCALL); + + #define GTCM_ENVVAR_PFX "GTCM_" #define GTCM_ENVVAR_PFXLEN (SIZEOF(GTCM_ENVVAR_PFX) - 1) @@ -66,12 +73,6 @@ void gvcmy_open(gd_region *reg, parse_blk *pb) VMS_ONLY($DESCRIPTOR(task, "GTCMSVR");) UNIX_ONLY(MSTR_DEF(task, 0, NULL);) - error_def(ERR_BADSRVRNETMSG); - error_def(ERR_INVNETFILNM); - error_def(ERR_LOGTOOLONG); - error_def(ERR_NETDBOPNERR); - error_def(ERR_SYSCALL); - ESTABLISH(gvcmy_open_ch); #ifdef VMS if (!nb->nam$b_node) @@ -209,7 +210,7 @@ void gvcmy_open(gd_region *reg, parse_blk *pb) /* From level 210 (GT.M V5), server will send null subscript collation info into CMMS_S_INITREG message */ reg->dyn.addr->cm_blk = clb_ptr; reg->dyn.addr->acc_meth = dba_cm; - reg->open = TRUE; + SET_REGION_OPEN_TRUE(reg, WAS_OPEN_FALSE); clb_ptr->mbl = li->buffer_size; if (clb_ptr->mbl < CM_MINBUFSIZE) clb_ptr->mbl = CM_MINBUFSIZE; diff --git a/sr_port_cm/gvcmz_bunch.c b/sr_port_cm/gvcmz_bunch.c index 1c7773b..3f45a6a 100644 --- a/sr_port_cm/gvcmz_bunch.c +++ b/sr_port_cm/gvcmz_bunch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -34,11 +34,11 @@ GBLREF gv_key *gv_currkey; GBLREF spdesc stringpool; typedef struct bunch_rec_struct { - unsigned char rn; - unsigned char len; - unsigned char cc; - unsigned char prv; - unsigned char base[1]; + unsigned char rn; + unsigned short len; + unsigned short cc; + unsigned short prv; + unsigned char base[1]; } bunch_rec; void gvcmz_bunch(mval *v) @@ -46,7 +46,8 @@ void gvcmz_bunch(mval *v) struct CLB *lnk; link_info *usr; unsigned char *buffptr, *bufftop, *insert_record, *msgptr; - unsigned char cc, len, i, *new_key, *rec_key; + unsigned char *new_key, *rec_key; + unsigned short cc, len, i; signed char is_gt; bool overlay; unsigned short newrec_len, oldrec_len, tmp_short; diff --git a/sr_unix/append_time_stamp.c b/sr_unix/append_time_stamp.c index 48ec375..7599ce6 100644 --- a/sr_unix/append_time_stamp.c +++ b/sr_unix/append_time_stamp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2007 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,31 +13,26 @@ #include #include "gtm_string.h" -#include "gtm_stat.h" #include "gtm_time.h" #include "gtm_rename.h" + #include "eintr_wrappers.h" #include "iosp.h" -#define TIME_EXT_FMT "_%Y%j%H%M%S" /* .yearjuliendayhoursminutesseconds */ - -/* This appends timestamp from file (fn) last modified status time. Result is returned in same string fn. - * Return SS_NORMAL for success */ -uint4 append_time_stamp(char *fn, int fn_len, int *app_len, uint4 *ustatus) +/* Append the formatted timestamp to the file name (fn); *fn_len contains the current length of the filename and at exit from this + * function, it is updated to reflect the new length. + */ +uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now) { - struct stat stat_buf; struct tm *tm_struct; - int status; - size_t tt; + time_t tt_now; + size_t tm_str_len; - *ustatus = SS_NORMAL; - STAT_FILE(fn, &stat_buf, status); - if (-1 == status) /* if file fn does not exist */ - return errno; - assert(0 < MAX_FN_LEN - fn_len - 1); - tm_struct = localtime(&(stat_buf.st_ctime)); - STRFTIME(&fn[fn_len], MAX_FN_LEN - fn_len - 1, TIME_EXT_FMT, tm_struct, tt); - *app_len = (int)tt; + assert(0 < MAX_FN_LEN - *fn_len - 1); + tt_now = (time_t)now; + GTM_LOCALTIME(tm_struct, &tt_now); + STRFTIME(&fn[*fn_len], MAX_FN_LEN - *fn_len - 1, JNLSWITCH_TM_FMT, tm_struct, tm_str_len); + *fn_len += (int)tm_str_len; return SS_NORMAL; } diff --git a/sr_unix/auto_zlink.h b/sr_unix/auto_zlink.h index 8e2efde..6cfd5de 100644 --- a/sr_unix/auto_zlink.h +++ b/sr_unix/auto_zlink.h @@ -12,7 +12,7 @@ #ifndef AUTO_ZLINK_INCLUDED #define AUTO_ZLINK_INCLUDED -#include "auto_zlink_sp.h" +#include rhdtyp *auto_zlink(mach_inst *pc, lnr_tabent ***line); diff --git a/sr_unix/badd.txt b/sr_unix/badd.txt index e82f0ad..49eb4a1 100644 --- a/sr_unix/badd.txt +++ b/sr_unix/badd.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2011, 2012 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -11,8 +11,9 @@ # Do not add any blank lines after this comment pro: TTTGEN.m%-r--r----- README.txt +dse%-r--r----- custom_errors_sample.txt gdehelp.dat%-r--r----- gdedefaults -gtm_descript.h%-r-xr-x--- gtm +gtm_common_defs.h%-r-xr-x--- gtm gtmcshrc.gtc%-r-xr-x--- gtmbase gtmhelp.dat%-r-xr-x--- gtmcshrc gtmsecshr%-r-xr-x--- gtmprofile @@ -28,4 +29,10 @@ zzz_insert%-r--r----- source.tar pro/utf8: TTTGEN.m -> ../TTTGEN.m%lrwxrwxrwx README.txt -> ../README.txt +dse -> ../dse%lrwxrwxrwx custom_errors_sample.txt -> ../custom_errors_sample.txt +gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr +gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir lke -> ../lke%-r-xr-x--- libgtmutil.so + +pro/utf8/gtmsecshrdir: +zzz_insert%-r-s------ gtmsecshr diff --git a/sr_unix/bdelete.txt b/sr_unix/bdelete.txt index 3160c05..20fd7ac 100644 --- a/sr_unix/bdelete.txt +++ b/sr_unix/bdelete.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2011 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -16,7 +16,6 @@ GENDASH.o GENOUT.o GTMDefinedTypesInit.m GTMDefinedTypesInit.o -GTMHELP.o GTMHLPLD.o LOADOP.o LOADVX.o @@ -51,7 +50,6 @@ gtmcrypt_interface.h gtmcrypt_pk_ref.h gtmcrypt_ref.h gtmcrypt_sym_ref.h -gtmxc_types.h install.sh ld_verbose.out libgtmcrypt.dll @@ -69,7 +67,6 @@ GENDASH.o GENOUT.o GTMDefinedTypesInit.m -> ../GTMDefinedTypesInit.m GTMDefinedTypesInit.o -GTMHELP.o GTMHLPLD.o LOADOP.o LOADVX.o @@ -83,6 +80,8 @@ configure -> ../configure dbcertify -> ../dbcertify gtmhelp.dmp -> ../gtmhelp.dmp gtminstall -> ../gtminstall +gtmsecshr -> ../gtmsecshr +gtmsecshrdir -> ../gtmsecshrdir lowerc_cp -> ../lowerc_cp map -> ../map mumps.gld -> ../mumps.gld diff --git a/sr_unix/bin_load.c b/sr_unix/bin_load.c index 4f92920..9e8af6b 100644 --- a/sr_unix/bin_load.c +++ b/sr_unix/bin_load.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,11 +39,14 @@ #include "gtmmsg.h" #include "gtm_utf8.h" #ifdef GTM_CRYPT +#include "io.h" #include "gtmcrypt.h" #endif #include #include "gv_trigger.h" #include "gvcst_protos.h" /* for gvcst_root_search in GV_BIND_NAME_AND_ROOT_SEARCH macro */ +#include "format_targ_key.h" +#include "zshow.h" GBLREF bool mupip_DB_full; GBLREF bool mu_ctrly_occurred; @@ -56,6 +59,10 @@ GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; GBLREF int4 gv_keysize; GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_addrs *cs_addrs; +#ifdef GTM_CRYPT +GBLREF io_pair io_curr_device; +#endif error_def(ERR_CORRUPT); error_def(ERR_GVIS); @@ -68,31 +75,98 @@ error_def(ERR_COLLTYPVERSION); error_def(ERR_COLLATIONUNDEF); error_def(ERR_OLDBINEXTRACT); error_def(ERR_LOADINVCHSET); +error_def(ERR_LDSPANGLOINCMP); #define BIN_PUT 0 #define BIN_BIND 1 #define ERR_COR 2 +#define BIN_KILL 3 + #ifdef GTM_CRYPT -#define EMPTY_GTMCRYPT_HASH16 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" -#define EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH16 EMPTY_GTMCRYPT_HASH16 -#define EMPTY_GTMCRYPT_HASH EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH32 -#define GC_BIN_LOAD_ERR(crypt_status) \ -{ \ - if (0 != crypt_status) \ - { \ - GC_GTM_PUTMSG(crypt_status, NULL); \ - mupip_error_occurred = TRUE; \ - if (NULL != tmp_gvkey) \ - { \ - free(tmp_gvkey); \ - tmp_gvkey = NULL; \ - } \ - return; \ - } \ +# define EMPTY_GTMCRYPT_HASH16 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" +# define EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH16 EMPTY_GTMCRYPT_HASH16 +# define EMPTY_GTMCRYPT_HASH EMPTY_GTMCRYPT_HASH32 EMPTY_GTMCRYPT_HASH32 + +# define GC_BIN_LOAD_ERR(GTMCRYPT_ERRNO) \ +{ \ + io_log_name *io_log; \ + \ + if (0 != GTMCRYPT_ERRNO) \ + { \ + io_log = io_curr_device.in->name; \ + GTMCRYPT_REPORT_ERROR(GTMCRYPT_ERRNO, gtm_putmsg, io_log->len, io_log->dollar_io); \ + mupip_error_occurred = TRUE; \ + if (NULL != tmp_gvkey) \ + { \ + free(tmp_gvkey); \ + tmp_gvkey = NULL; \ + } \ + return; \ + } \ } #endif -static readonly unsigned char gt_lit[] = "LOAD TOTAL"; +#define DEFAULT_SN_HOLD_BUFF_SIZE MAX_IO_BLOCK_SIZE + +#define KILL_INCMP_SN_IF_NEEDED \ +{ \ + if (!sn_incmp_gbl_already_killed) \ + { \ + COPY_KEY(sn_savekey, gv_currkey); \ + COPY_KEY(gv_currkey, sn_gvkey); \ + bin_call_db(BIN_KILL, 0, 0); \ + COPY_KEY(gv_currkey, sn_savekey); \ + sn_incmp_gbl_already_killed = TRUE; \ + } \ +} + +#define DISPLAY_INCMP_SN_MSG \ +{ \ + file_offset = file_offset_base + ((unsigned char *)rp - ptr_base); \ + if (file_offset != last_sn_error_offset) \ + { \ + last_sn_error_offset = file_offset; \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDSPANGLOINCMP); \ + util_out_print("!_!_at File offset : [0x!XL]", TRUE, file_offset); \ + if (sn_gvkey->end && expected_sn_chunk_number) \ + { \ + sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, sn_gvkey, TRUE); \ + util_out_print("!_!_Expected Spanning Global variable : !AD", TRUE, \ + sn_key_str_end - &sn_key_str[0], sn_key_str); \ + } \ + sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE); \ + util_out_print("!_!_Global variable from record: !AD", TRUE, \ + sn_key_str_end - &sn_key_str[0], sn_key_str); \ + } \ +} + +#define DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK \ +{ \ + util_out_print("!_!_File offset : [0x!XL]", TRUE, file_offset_base + ((unsigned char *)rp - ptr_base)); \ + util_out_print("!_!_Rest of Block :", TRUE); \ + zwr_out_print((char *)rp, btop - (unsigned char *)rp); \ + util_out_print(0, TRUE); \ +} + +#define DISPLAY_CURRKEY \ +{ \ + sn_key_str_end = format_targ_key(&sn_key_str[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE); \ + util_out_print("!_!_Key: !AD", TRUE, sn_key_str_end - &sn_key_str[0], sn_key_str); \ +} + +#define DISPLAY_VALUE(STR) \ +{ \ + util_out_print(STR, TRUE); \ + zwr_out_print(v.str.addr, v.str.len); \ + util_out_print(0, TRUE); \ +} + +#define DISPLAY_PARTIAL_SN_HOLD_BUFF \ +{ \ + util_out_print("!_!_Partial Value :", TRUE); \ + zwr_out_print(sn_hold_buff, sn_hold_buff_pos); \ + util_out_print(0, TRUE); \ +} /* starting extract file format 3, we have an extra record for each gvn, that contains the * collation information of the database at the time of extract. This record is transparent @@ -102,32 +176,70 @@ static readonly unsigned char gt_lit[] = "LOAD TOTAL"; */ void bin_call_db(int, INTPTR_T, INTPTR_T); +void zwr_out_print(char * buff, int len); + +#define ZWR_BASE_STRIDE 1024 +#define UOP_BASE_STRIDE 1024 + +void zwr_out_print(char * buff, int bufflen) +{ + char zwrbuff[ZWR_BASE_STRIDE * MAX_ZWR_EXP_RATIO], savechar; + int zwrlen; + int buffpos, left, stride; + int uopbuffpos, uopleft, uopstride; + + buffpos = 0; + while (left = bufflen - buffpos) + { + if (buffpos) + FPRINTF(stderr,"_"); + stride = (left > ZWR_BASE_STRIDE) ? ZWR_BASE_STRIDE : left; + format2zwr((sm_uc_ptr_t)(buff + buffpos), stride, (unsigned char *) zwrbuff, &zwrlen); + uopbuffpos = 0; + while (uopleft = zwrlen - uopbuffpos) + { + uopstride = (uopleft > UOP_BASE_STRIDE) ? UOP_BASE_STRIDE : uopleft; + savechar = *(zwrbuff + uopstride); + *(zwrbuff + uopstride) = '\0'; + FPRINTF(stderr,"%s", zwrbuff + uopbuffpos); + *(zwrbuff + uopstride) = savechar; + uopbuffpos += uopstride; + } + buffpos += stride; + } + FPRINTF(stderr,"\n"); +} void bin_load(uint4 begin, uint4 end) { - unsigned char *ptr, *cp1, *cp2, *btop, *gvkey_char_ptr, *tmp_ptr, *tmp_key_ptr, *c, *ctop; - unsigned char hdr_lvl, src_buff[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ], - cmpc_str[MAX_KEY_SZ + 1], dup_key_str[MAX_KEY_SZ + 1]; - unsigned char *end_buff; - unsigned short rec_len, next_cmpc; - int len; - int current, last, length, max_blk_siz, max_key, status; - uint4 iter, max_data_len, max_subsc_len, key_count; - ssize_t rec_count, global_key_count, subsc_len,extr_std_null_coll; - boolean_t need_xlation, new_gvn, utf8_extract; - rec_hdr *rp, *next_rp; - mval v, tmp_mval; - mstr mstr_src, mstr_dest; - collseq *extr_collseq, *db_collseq, *save_gv_target_collseq; - coll_hdr extr_collhdr, db_collhdr; - gv_key *tmp_gvkey = NULL; /* null-initialize at start, will be malloced later */ - char std_null_coll[BIN_HEADER_NUMSZ + 1]; + 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], + cmpc_str[MAX_KEY_SZ + 1], dup_key_str[MAX_KEY_SZ + 1], sn_key_str[MAX_KEY_SZ + 1], *sn_key_str_end; + unsigned char *end_buff; + unsigned short rec_len, next_cmpc, numsubs; + 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; + 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; + mval v, tmp_mval; + mstr mstr_src, mstr_dest; + collseq *extr_collseq, *db_collseq, *save_gv_target_collseq; + coll_hdr extr_collhdr, db_collhdr; + gv_key *tmp_gvkey = NULL; /* null-initialize at start, will be malloced later */ + gv_key *sn_gvkey = NULL; /* null-initialize at start, will be malloced later */ + gv_key *sn_savekey = NULL; /* null-initialize at start, will be malloced later */ + char std_null_coll[BIN_HEADER_NUMSZ + 1], *sn_hold_buff = NULL, *sn_hold_buff_temp = NULL; # ifdef GTM_CRYPT - gtmcrypt_key_t *encr_key_handles; - char *inbuf; - int4 index; - int req_dec_blk_size, init_status, crypt_status; - muext_hash_hdr_ptr_t hash_array = NULL; + gtmcrypt_key_t *encr_key_handles; + char *inbuf; + int4 index; + int in_len, gtmcrypt_errno; + muext_hash_hdr_ptr_t hash_array = NULL; # endif DCL_THREADGBL_ACCESS; @@ -135,18 +247,22 @@ void bin_load(uint4 begin, uint4 end) assert(4 == SIZEOF(coll_hdr)); gvinit(); v.mvtype = MV_STR; - len = file_input_bin_get((char **)&ptr); + len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base); hdr_lvl = EXTR_HEADER_LEVEL(ptr); - if (!(((('4' == hdr_lvl) || ('5' == hdr_lvl)) && (BIN_HEADER_SZ == len)) || (('4' > hdr_lvl) && (V3_BIN_HEADER_SZ == len)))) + if (!(((('4' == hdr_lvl) || ('5' == hdr_lvl)) && (V5_BIN_HEADER_SZ == len)) || + (('6' == hdr_lvl) && (BIN_HEADER_SZ == len)) || + (('7' == hdr_lvl) && (BIN_HEADER_SZ == len)) || + (('4' > hdr_lvl) && (V3_BIN_HEADER_SZ == len)))) { - rts_error(VARLSTCNT(1) ERR_LDBINFMT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } /* expecting the level in a single character */ assert(' ' == *(ptr + SIZEOF(BIN_HEADER_LABEL) - 3)); - if (0 != memcmp(ptr, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || ('2' > hdr_lvl) || *(BIN_HEADER_VERSION) < hdr_lvl) + if (0 != memcmp(ptr, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || ('2' > hdr_lvl) || + *(BIN_HEADER_VERSION_ENCR) < hdr_lvl) { /* ignore the level check */ - rts_error(VARLSTCNT(1) ERR_LDBINFMT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } /* check if extract was generated in UTF-8 mode */ @@ -154,9 +270,9 @@ void bin_load(uint4 begin, uint4 end) if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode)) { /* extract CHSET doesn't match $ZCHSET */ if (utf8_extract) - rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); else - rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); mupip_exit(ERR_LDBINFMT); } if ('4' >= hdr_lvl) @@ -173,57 +289,66 @@ void bin_load(uint4 begin, uint4 end) new_gvn = FALSE; if (hdr_lvl > '3') { - memcpy(std_null_coll, ptr + BIN_HEADER_NULLCOLLOFFSET, BIN_HEADER_NUMSZ); - std_null_coll[BIN_HEADER_NUMSZ] = '\0'; + if (hdr_lvl > '5') + { + memcpy(std_null_coll, ptr + BIN_HEADER_NULLCOLLOFFSET, BIN_HEADER_NUMSZ); + std_null_coll[BIN_HEADER_NUMSZ] = '\0'; + } + else + { + memcpy(std_null_coll, ptr + V5_BIN_HEADER_NULLCOLLOFFSET, V5_BIN_HEADER_NUMSZ); + std_null_coll[V5_BIN_HEADER_NUMSZ] = '\0'; + } extr_std_null_coll = STRTOUL(std_null_coll, NULL, 10); if (0 != extr_std_null_coll && 1!= extr_std_null_coll) { - rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupted null collation field in header"), - ERR_LDBINFMT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, + RTS_ERROR_TEXT("Corrupted null collation field in header"), ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } } else extr_std_null_coll = 0; # ifdef GTM_CRYPT - if ('5' <= hdr_lvl) + if ('7' <= hdr_lvl) { int i, num_indexes; - len = file_input_bin_get((char **)&ptr); + len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base); hash_array = (muext_hash_hdr *)malloc(len); /* store hashes of all the files used during extract into muext_hash_hdr structure */ memcpy((char *)hash_array, ptr, len); num_indexes = len / GTMCRYPT_HASH_LEN; encr_key_handles = (gtmcrypt_key_t *)malloc(SIZEOF(gtmcrypt_key_t) * num_indexes); - INIT_PROC_ENCRYPTION(crypt_status); - GC_BIN_LOAD_ERR(crypt_status); + INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno); + GC_BIN_LOAD_ERR(gtmcrypt_errno); for (index = 0; index < num_indexes; index++) { if (0 == memcmp(hash_array[index].gtmcrypt_hash, EMPTY_GTMCRYPT_HASH, GTMCRYPT_HASH_LEN)) continue; - GTMCRYPT_GETKEY(hash_array[index].gtmcrypt_hash, encr_key_handles[index], crypt_status); - GC_BIN_LOAD_ERR(crypt_status); + GTMCRYPT_GETKEY(NULL, hash_array[index].gtmcrypt_hash, encr_key_handles[index], gtmcrypt_errno); + GC_BIN_LOAD_ERR(gtmcrypt_errno); } } # endif if ('2' < hdr_lvl) { - len = file_input_bin_get((char **)&ptr); + len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base); if (SIZEOF(coll_hdr) != len) { - rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"), ERR_LDBINFMT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"), + ERR_LDBINFMT); mupip_exit(ERR_LDBINFMT); } extr_collhdr = *((coll_hdr *)(ptr)); new_gvn = TRUE; } else - gtm_putmsg(VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0'); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0'); if (begin < 2) begin = 2; for (iter = 2; iter < begin; iter++) { - if (!(len = file_input_bin_get((char **)&ptr))) + if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base))) { - gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin); util_out_print("Error reading record number: !UL\n", TRUE, iter); mupip_error_occurred = TRUE; return; @@ -244,6 +369,10 @@ void bin_load(uint4 begin, uint4 end) need_xlation = FALSE; assert(NULL == tmp_gvkey); /* GVKEY_INIT macro relies on this */ GVKEY_INIT(tmp_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* tmp_gvkey will point to malloced memory after this */ + assert(NULL == sn_gvkey); /* GVKEY_INIT macro relies on this */ + GVKEY_INIT(sn_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* sn_gvkey will point to malloced memory after this */ + assert(NULL == sn_savekey); /* GVKEY_INIT macro relies on this */ + GVKEY_INIT(sn_savekey, DBKEYSIZE(MAX_KEY_SZ)); /* sn_gvkey will point to malloced memory after this */ for (; !mupip_DB_full ;) { if (++rec_count > end) @@ -255,15 +384,13 @@ void bin_load(uint4 begin, uint4 end) if (mu_ctrlc_occurred) { util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE, - LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len); + 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); mu_gvis(); util_out_print(0, TRUE); mu_ctrlc_occurred = FALSE; } - /* reset the stringpool for every record in order to avoid garbage collection */ - stringpool.free = stringpool.base; - if (!(len = file_input_bin_get((char **)&ptr)) || mupip_error_occurred) + if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base)) || mupip_error_occurred) break; else if (len == SIZEOF(coll_hdr)) { @@ -275,15 +402,15 @@ void bin_load(uint4 begin, uint4 end) } rp = (rec_hdr*)(ptr); # ifdef GTM_CRYPT - if ('5' <= hdr_lvl) + if ('7' <= hdr_lvl) { /* Getting index value from the extracted file. It indicates which database file this record belongs to */ GET_LONG(index, ptr); if (-1 != index) /* Indicates that the record is encrypted. */ { - req_dec_blk_size = len - SIZEOF(int4); + in_len = len - SIZEOF(int4); inbuf = (char *)(ptr + SIZEOF(int4)); - GTMCRYPT_DECODE_FAST(encr_key_handles[index], inbuf, req_dec_blk_size, NULL, crypt_status); - GC_BIN_LOAD_ERR(crypt_status); + GTMCRYPT_DECRYPT(NULL, encr_key_handles[index], inbuf, in_len, NULL, gtmcrypt_errno); + GC_BIN_LOAD_ERR(gtmcrypt_errno); } rp = (rec_hdr*)(ptr + SIZEOF(int4)); } @@ -305,11 +432,11 @@ void bin_load(uint4 begin, uint4 end) db_collhdr.nct = gv_target->nct; } GET_USHORT(rec_len, &rp->rsiz); - if (rp->cmpc != 0 || v.str.len > rec_len || mupip_error_occurred) + if (EVAL_CMPC(rp) != 0 || v.str.len > rec_len || mupip_error_occurred) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); - util_out_print(0, TRUE); + DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK; continue; } if (new_gvn) @@ -325,14 +452,15 @@ void bin_load(uint4 begin, uint4 end) { if (!do_verify(extr_collseq, extr_collhdr.act, extr_collhdr.ver)) { - gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, extr_collhdr.act, - extr_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2, + extr_collhdr.act, extr_collhdr.ver, ERR_GVIS, 2, + gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLTYPVERSION); } } else { - gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, extr_collhdr.act, - ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, + extr_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLATIONUNDEF); } } @@ -342,13 +470,14 @@ void bin_load(uint4 begin, uint4 end) { if (!do_verify(db_collseq, db_collhdr.act, db_collhdr.ver)) { - gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, db_collhdr.act, - db_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2, + db_collhdr.act, db_collhdr.ver, ERR_GVIS, 2, + gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLTYPVERSION); } } else { - gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); mupip_exit(ERR_COLLATIONUNDEF); } @@ -365,11 +494,11 @@ void bin_load(uint4 begin, uint4 end) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); - util_out_print(0, TRUE); + DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK; break; } cp1 = (unsigned char*)(rp + 1); - cp2 = gv_currkey->base + rp->cmpc; + cp2 = gv_currkey->base + EVAL_CMPC(rp); current = 1; for (;;) { @@ -380,9 +509,12 @@ void bin_load(uint4 begin, uint4 end) if (cp1 > (unsigned char *)rp + rec_len || cp2 > (unsigned char *)gv_currkey + gv_currkey->top) { + gv_currkey->end = cp2 - gv_currkey->base - 1; + gv_currkey->base[gv_currkey->end] = 0; + gv_currkey->base[gv_currkey->end - 1] = 0; bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); - util_out_print(0, TRUE); + DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK; break; } } @@ -399,7 +531,7 @@ void bin_load(uint4 begin, uint4 end) next_rp = (rec_hdr *)((unsigned char*)rp + rec_len); if ((unsigned char*)next_rp < btop) { - next_cmpc = next_rp->cmpc; + next_cmpc = EVAL_CMPC(next_rp); assert(next_cmpc <= gv_currkey->end); memcpy(cmpc_str, gv_currkey->base, next_cmpc); } else @@ -464,27 +596,185 @@ void bin_load(uint4 begin, uint4 end) { bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); mu_gvis(); - util_out_print(0, TRUE); + DISPLAY_FILE_OFFSET_OF_RECORD_AND_REST_OF_BLOCK; continue; } - if (max_subsc_len < (gv_currkey->end + 1)) + /* + * Spanning node-related variables and their usage: + * + * expected_sn_chunk_number: 0 - looking for spanning nodes (regular nodes are OK, too) + * !0 - number of the next chunk needed (implies we are building + * a spanning node's value) + * + * While building a spanning node's value: + * numsubs: the number of chunks needed to build the spanning node's value + * gblsize: the expected size of the completed value + * sn_chunk_number: The chunk number of the chunk from the current record from the extract + * + * Managing the value + * sn_hold_buff: buffer used to accumulate the spanning node's value + * sn_hold_buff_size: Allocated size of buffer + * sn_hold_buff_pos: amount of the buffer used; where to place the next chunk + * sn_hold_buff_temp: used when we have to increase the size of the buffer + * + * Controlling the placing of the key,value in the database: + * ok_to_put: means we are ready to place the key,value in the database, i.e., we have the full value + * (either of the spanning node or a regular node). + * putting_a_sn: we are placing a spanning node in the database, i.e, use the key from sn_gvkey and + * the value from sn_hold_buff. + */ + CHECK_HIDDEN_SUBSCRIPT(gv_currkey,is_hidden_subscript); + if (!is_hidden_subscript && (max_subsc_len < (gv_currkey->end + 1))) max_subsc_len = gv_currkey->end + 1; v.str.addr = (char*)cp1; v.str.len =INTCAST(rec_len - (cp1 - (unsigned char *)rp)); - if (max_data_len < v.str.len) - max_data_len = v.str.len; - bin_call_db(BIN_PUT, (INTPTR_T)&v, 0); - if (mupip_error_occurred) - { - if (!mupip_DB_full) - { - bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); - util_out_print(0, TRUE); - } - break; + if (expected_sn_chunk_number && !is_hidden_subscript) + { /* we were expecting a chunk of an spanning node and we did not get one */ + DISPLAY_INCMP_SN_MSG; + util_out_print("!_!_Expected chunk number : !UL but found a non-spanning node", TRUE, + expected_sn_chunk_number + 1); + if (sn_hold_buff_pos) + DISPLAY_PARTIAL_SN_HOLD_BUFF; + KILL_INCMP_SN_IF_NEEDED; + sn_hold_buff_pos = 0; + expected_sn_chunk_number = 0; + ok_to_put = TRUE; + putting_a_sn = FALSE; + numsubs = 0; + } + if (is_hidden_subscript) + { /* it's a chunk and we were expecting one */ + sn_chunk_number = SPAN_GVSUBS2INT((span_subs *) &(gv_currkey->base[gv_currkey->end - 4])); + if (!expected_sn_chunk_number && is_hidden_subscript && sn_chunk_number) + { /* we not expecting a payload chunk (as opposed to a control record) but we got one */ + DISPLAY_INCMP_SN_MSG; + util_out_print("!_!_Not expecting a spanning node chunk but found chunk : !UL", TRUE, + sn_chunk_number + 1); + if (v.str.len) + DISPLAY_VALUE("!_!_Errant Chunk :"); + continue; + } + if (0 == sn_chunk_number) + { /* first spanning node chunk, get ctrl info */ + if (0 != expected_sn_chunk_number) + { + DISPLAY_INCMP_SN_MSG; + util_out_print("!_!_Expected chunk number : !UL but found chunk number : !UL", TRUE, + expected_sn_chunk_number + 1, sn_chunk_number + 1); + if (sn_hold_buff_pos) + DISPLAY_PARTIAL_SN_HOLD_BUFF; + KILL_INCMP_SN_IF_NEEDED; + } + /* start building a new spanning node */ + sn_gvkey->end = gv_currkey->end - (SPAN_SUBS_LEN + 1); + memcpy(sn_gvkey->base, gv_currkey->base, sn_gvkey->end); + sn_gvkey->base[sn_gvkey->end] = 0; + sn_gvkey->prev = gv_currkey->prev; + sn_gvkey->top = gv_currkey->top; + GET_NSBCTRL(v.str.addr, numsubs, gblsize); + /* look for first payload chunk */ + expected_sn_chunk_number = 1; + sn_hold_buff_pos = 0; + ok_to_put = FALSE; + sn_incmp_gbl_already_killed = FALSE; + } else + { /* we only need to compare the key before the hidden subscripts */ + if ((expected_sn_chunk_number == sn_chunk_number) + && (sn_gvkey->end == gv_currkey->end - (SPAN_SUBS_LEN + 1)) + && !memcmp(sn_gvkey->base,gv_currkey->base, sn_gvkey->end) + && ((sn_hold_buff_pos + v.str.len) <= gblsize)) + { + if (NULL == sn_hold_buff) + { + sn_hold_buff_size = DEFAULT_SN_HOLD_BUFF_SIZE; + sn_hold_buff = (char *)malloc(DEFAULT_SN_HOLD_BUFF_SIZE); + } + if ((sn_hold_buff_pos + v.str.len) > sn_hold_buff_size) + { + sn_hold_buff_size = sn_hold_buff_size * 2; + sn_hold_buff_temp = (char *)malloc(sn_hold_buff_size); + memcpy(sn_hold_buff_temp, sn_hold_buff, sn_hold_buff_pos); + free (sn_hold_buff); + sn_hold_buff = sn_hold_buff_temp; + } + memcpy(sn_hold_buff + sn_hold_buff_pos, v.str.addr, v.str.len); + sn_hold_buff_pos += v.str.len; + if (expected_sn_chunk_number == numsubs) + { + if (sn_hold_buff_pos != gblsize) + { /* we don't have the expected size even though */ + /* we have all the expected chunks. */ + DISPLAY_INCMP_SN_MSG; + util_out_print("!_!_Expected size : !UL actual size : !UL", TRUE, + gblsize, sn_hold_buff_pos); + if (sn_hold_buff_pos) + DISPLAY_PARTIAL_SN_HOLD_BUFF; + KILL_INCMP_SN_IF_NEEDED; + expected_sn_chunk_number = 0; + ok_to_put = FALSE; + sn_hold_buff_pos = 0; + } + else + { + expected_sn_chunk_number = 0; + ok_to_put = TRUE; + putting_a_sn = TRUE; + } + + }else + expected_sn_chunk_number++; + }else + { + DISPLAY_INCMP_SN_MSG; + if ((sn_hold_buff_pos + v.str.len) <= gblsize) + util_out_print("!_!_Expected chunk number : !UL but found chunk number : !UL", /*BYPASSOK*/ + TRUE, expected_sn_chunk_number + 1, sn_chunk_number + 1); + else + util_out_print("!_!_Global value too large: expected size : !UL actual size : !UL chunk number : !UL", TRUE, /*BYPASSOK*/ + gblsize, sn_hold_buff_pos + v.str.len, sn_chunk_number + 1); + if (sn_hold_buff_pos) + DISPLAY_PARTIAL_SN_HOLD_BUFF; + if (v.str.len) + DISPLAY_VALUE("!_!_Errant Chunk :"); + KILL_INCMP_SN_IF_NEEDED; + sn_hold_buff_pos = 0; + expected_sn_chunk_number = 0; + } + } + } else + ok_to_put = TRUE; + if (ok_to_put) + { + if (putting_a_sn) + { + gv_currkey->base[gv_currkey->end - (SPAN_SUBS_LEN + 1)] = 0; + gv_currkey->end -= (SPAN_SUBS_LEN + 1); + v.str.addr = sn_hold_buff; + v.str.len = sn_hold_buff_pos; + } + if (max_data_len < v.str.len) + max_data_len = v.str.len; + bin_call_db(BIN_PUT, (INTPTR_T)&v, 0); + if (mupip_error_occurred) + { + if (!mupip_DB_full) + { + bin_call_db(ERR_COR, (INTPTR_T)rec_count, (INTPTR_T)global_key_count); + file_offset = file_offset_base + ((unsigned char *)rp - ptr_base); + util_out_print("!_!_at File offset : [0x!XL]", TRUE, file_offset); + DISPLAY_CURRKEY; + DISPLAY_VALUE("!_!_Value :"); + } + break; + } + if (putting_a_sn) + putting_a_sn = FALSE; + else + { + key_count++; + global_key_count++; + } } - key_count++; - global_key_count++; } } GTMCRYPT_ONLY( @@ -492,13 +782,16 @@ void bin_load(uint4 begin, uint4 end) free(hash_array); ) free(tmp_gvkey); + free(sn_gvkey); + 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, max_data_len); util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (rec_count - 1) : 0); if (mu_ctrly_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_LOADCTRLY); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LOADCTRLY); mupip_exit(ERR_MUNOFINISH); } } @@ -519,7 +812,9 @@ void bin_call_db(int routine, INTPTR_T parm1, INTPTR_T parm2) GV_BIND_NAME_AND_ROOT_SEARCH((gd_addr *)parm1, (mstr *)parm2); break; case ERR_COR: - rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, parm1, parm2); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_CORRUPT, 2, parm1, parm2); + case BIN_KILL: + gvcst_kill(FALSE); break; } REVERT; diff --git a/sr_unix/build.sh b/sr_unix/build.sh index a30277d..e4ed958 100644 --- a/sr_unix/build.sh +++ b/sr_unix/build.sh @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2009, 2011 Fidelity Information Services, Inc # +# Copyright 2009, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -10,14 +10,17 @@ # # ################################################################# -if [ $# -lt 1 ]; then - echo "Usage: $0 " - echo "encryption_library:" - echo "gcrypt: Build the plugin with libgcrypt" - echo "openssl: Build the plugin with OpenSSL" - echo "build_type:" - echo "d|D: Build the plugin with debug information" - echo "p|P: Build the plugin without debug information" +if [ $# -lt 2 ]; then + echo "Usage: $0 ENCRYPTION_LIB BUILD_TYPE [ALGORITHM]" + echo "ENCRYPTION_LIB is either gcrypt or openssl" + echo " gcrypt : Build the plugin with libgcrypt" + echo " openssl: Build the plugin with OpenSSL" + echo "BUILD_TYPE is either [p|P] or [d|D]" + echo " d|D : Build the plugin with debug information" + echo " p|P : Build the plugin without debug information" + echo "ALGORITHM is either AES256CFB (default) or BLOWFISHCFB" + echo " AES256CFB : Build the plugin with AES (CFB mode) with 256-bit encryption" + echo " BLOWFISHCFB : Build the plugin with BLOWFISH (CFB mode) with 256-bit encryption" exit 1 fi @@ -26,9 +29,16 @@ if [ -z "$gtm_dist" ]; then exit 1 fi +encryption_lib=$1 +build_type=$2 +if [ $# -eq 3 ]; then + algorithm="$3" +else + algorithm="AES256CFB" # default +fi +algorithm_option="-DUSE_$algorithm" # Clean up existing artifacts \rm -f *.o 2>/dev/null -\rm -f *.so 2>/dev/null hostos=`uname -s` machtype=`uname -m` @@ -48,7 +58,7 @@ bld_status=0 ext=".so" # Set debug/optimization options if needed. -if [ "d" = $2 -o "D" = $2 ]; then +if [ "d" = $build_type -o "D" = $build_type ]; then dbg_enable="1" options_optimize="-DDEBUG -g" else @@ -65,16 +75,17 @@ if [ $is64bit_gtm -eq 1 ] ; then else options_libpath="-L /usr/local/lib32 -L /usr/local/lib -L /usr/lib32 -L /usr/lib -L /lib32 -L /lib" fi -# -I $gtm_dist needed for main_pragma.h +# -I $gtm_dist needed for main_pragma.h, gtmxc_types.h and gtm_common_defs.h options_incpath="-I /usr/local/include/ -I /usr/include -I $builddir -I $gtm_dist" +base_libname="libgtmcrypt" # Common CC options for various platforms if [ "AIX" = "$hostos" ] ; then - cc_common="-c -qchars=signed -qsrcmsg -qmaxmem=8192 -D_BSD=43 -D_LARGE_FILES -D_TPARM_COMPAT -D_AIO_AIX_SOURCE -DCOMPAT_43" + cc_common="-c -qchars=signed -qsrcmsg -qmaxmem=8192 -D_BSD=43 -D_LARGE_FILES -D_TPARM_COMPAT -D_AIO_AIX_SOURCE" cc_common="$cc_common -qro -qroconst -D_USE_IRS -q64" ld_common="-q64 -brtl" - aix_loadmap_option="-bcalls:$builddir/libgtmcrypt.so.map -bmap:$builddir/libgtmcrypt.so.map" - aix_loadmap_option="$aix_loadmap_option -bxref:$builddir/libgtmcrypt.so.map" + aix_loadmap_option="-bcalls:$builddir/$base_libname.so.map -bmap:$builddir/$base_libname.so.map" + aix_loadmap_option="$aix_loadmap_option -bxref:$builddir/$base_libname.so.map" ld_shl_options="-q64 -Wl,-G -bexpall -bnoentry -bh:4 $aix_loadmap_option" # Reference implementation on AIX requires OpenSSL. Adjust library and include paths accordingly. options_libpath="-L /usr/local/ssl/lib $options_libpath" @@ -84,13 +95,16 @@ elif [ "HP-UX" = "$hostos" -a "ia64" = "$machtype" ] ; then cc_common="$cc_common -D_LARGEFILE64_SOURCE +W2550" ld_common="-Wl,-m +DD64" ld_shl_options="+DD64 -Wl,-b,-B,symbolic" + options_libpath="-L /opt/openssl/lib/hpux64 $options_libpath" + options_incpath="-L /opt/openssl/include $options_incpath" # Additional DEBUG-ONLY options on HP-UX if [ ! -z "$dbg_enable" ] ; then options_optimize="$options_optimize +ESdbgasm" ; fi elif [ "SunOS" = "$hostos" ] ; then cc_common="-KPIC -c -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DSUNOS -DSHADOWPW -m64" ld_common="-Wl,-m,-64 -m64 -xarch=generic" ld_shl_options="-m64 -xarch=generic -G -z combreloc" - options_libpath="$options_libpath -L /usr/lib/sparcv9" + options_libpath="-L /usr/lib/sparcv9 -L /usr/local/ssl/lib $options_libpath" + options_incpath="-I /usr/local/ssl/include $options_incpath" elif [ "Linux" = "$hostos" ] ; then cc_common="-c -ansi -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=600 -fsigned-char -fPIC" ld_common="-Wl,-M" @@ -119,17 +133,19 @@ elif [ "OS/390" = "$hostos" ] ; then ld_shl_options="-q64 -W l,DLL,XPLINK" ext=".dll" fi -gtmcrypt_libname="libgtmcrypt$ext" +generic_libname=$base_libname$ext +specific_libname=${base_libname}_${encryption_lib}_${algorithm}${ext} +if [ -f $builddir/$specific_libname ]; then \rm -f $specific_libname ; fi # Needed shared libraries for building encryption plugin crypto_libs="-lgpgme -lgpg-error" -if [ "openssl" = "$1" ] ; then +if [ "openssl" = "$encryption_lib" ] ; then crypto_libs="$crypto_libs -lcrypto" - cc_options="$cc_common $options_optimize $options_incpath -DUSE_OPENSSL" -elif [ "gcrypt" = "$1" ] ; then + cc_options="$cc_common $options_optimize $options_incpath -DUSE_OPENSSL $algorithm_option" +elif [ "gcrypt" = "$encryption_lib" ] ; then crypto_libs="$crypto_libs -lgcrypt" - cc_options="$cc_common $options_optimize $options_incpath -DUSE_GCRYPT" + cc_options="$cc_common $options_optimize $options_incpath -DUSE_GCRYPT $algorithm_option" else - echo "Unsupported encryption library : $1" + echo "Unsupported encryption library : $encryption_lib" exit 1 fi @@ -140,18 +156,10 @@ bld_status=`expr $bld_status + $?` $cc $cc_options $builddir/gtmcrypt_dbk_ref.c bld_status=`expr $bld_status + $?` -$ld $ld_common $ld_shl_options -o $builddir/$gtmcrypt_libname $builddir/gtmcrypt_ref.o $builddir/gtmcrypt_pk_ref.o \ - $builddir/gtmcrypt_dbk_ref.o $options_libpath $crypto_libs > $builddir/$gtmcrypt_libname.map +$ld $ld_common $ld_shl_options -o $builddir/$specific_libname $builddir/gtmcrypt_ref.o $builddir/gtmcrypt_pk_ref.o \ + $builddir/gtmcrypt_dbk_ref.o $options_libpath $crypto_libs > $builddir/$generic_libname.map bld_status=`expr $bld_status + $?` -cat > $builddir/gtmcrypt.tab << tabfile -getpass:char* getpass^GETPASS(I:gtm_int_t) -tabfile -cat > $builddir/gpgagent.tab << tabfile -$builddir/$gtmcrypt_libname -unmaskpwd: xc_status_t gc_pk_mask_unmask_passwd_interlude(I:xc_string_t*,O:xc_string_t*[512],I:xc_int_t) -tabfile - # Compile maskpass.c $cc $cc_options $builddir/maskpass.c $ld $ld_common -o $builddir/maskpass $builddir/maskpass.o $options_libpath $crypto_libs > $builddir/maskpass.map diff --git a/sr_unix/buildaux.csh b/sr_unix/buildaux.csh index 7e50eba..511f172 100644 --- a/sr_unix/buildaux.csh +++ b/sr_unix/buildaux.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2011 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -523,58 +523,87 @@ if ( $buildaux_dbcertify == 1 ) then endif endif -#create the plugin directory, copy the files and set it up so that buildplugin can build the needed libraries -#Do these only for the below mentioned platforms. All the remaining platforms will run GT.M without encryption +# Create the plugin directory, copy the files and set it up so that build.sh can build the needed libraries. if ($buildaux_gtmcrypt == 1) then - set encrypt_supported = `$gtm_tools/check_encrypt_support.sh` - if ("TRUE" == $encrypt_supported) then + set supported_list = `$gtm_tools/check_encrypt_support.sh mail` + if ("FALSE" != "$supported_list") then # Do it only on the platforms where encryption is supported set plugin_build_type="" switch ($2) - case "[bB]*": - set plugin_build_type="p" - breaksw - case "[pP]*": - set plugin_build_type="p" - breaksw - default: - set plugin_build_type="d" - breaksw + case "[bB]*": + set plugin_build_type="p" + breaksw + case "[pP]*": + set plugin_build_type="p" + breaksw + default: + set plugin_build_type="d" + breaksw endsw rm -rf $gtm_dist/plugin/gtmcrypt rm -rf $gtm_dist/plugin/ mkdir -p $gtm_dist/plugin/gtmcrypt >&! /dev/null setenv gtm_dist_plugin $gtm_dist/plugin/gtmcrypt cp -pf $gtm_src/gtmcrypt_*ref.c $gtm_src/maskpass.c $gtm_dist_plugin >&! /dev/null - cp -pf $gtm_inc/gtmcrypt_*ref.h $gtm_inc/gtmcrypt_interface.h $gtm_inc/gtmxc_types.h $gtm_dist_plugin >&! /dev/null + cp -pf $gtm_inc/gtmcrypt_*ref.h $gtm_inc/gtmcrypt_interface.h $gtm_dist_plugin >&! /dev/null cp -pf $gtm_tools/build.sh $gtm_tools/install.sh $gtm_tools/add_db_key.sh $gtm_dist_plugin >&! /dev/null cp -pf $gtm_tools/encrypt_sign_db_key.sh $gtm_tools/gen_keypair.sh $gtm_dist_plugin >&! /dev/null cp -pf $gtm_tools/gen_sym_hash.sh $gtm_tools/gen_sym_key.sh $gtm_dist_plugin >&! /dev/null cp -pf $gtm_tools/import_and_sign_key.sh $gtm_tools/pinentry-gtm.sh $gtm_dist_plugin >&! /dev/null + cp -pf $gtm_tools/show_install_config.sh $gtm_dist_plugin >&! /dev/null cp -pf $gtm_pct/pinentry.m $gtm_dist_plugin >&! /dev/null chmod +x $gtm_dist_plugin/*.sh pushd $gtm_dist_plugin >&! /dev/null - set bstat = 0 - if ( $HOSTOS == "AIX") then - #For AIX we will be building the encryption library with openssl support. - sh -x $gtm_dist_plugin/build.sh openssl $plugin_build_type >&! $gtm_map/gtmcryptbuild.map - set bstat = $status; - else - sh -x $gtm_dist_plugin/build.sh gcrypt $plugin_build_type >&! $gtm_map/gtmcryptbuild.map - set bstat = $status; + # For, non-AIX platforms, move the libgcrypt entry to the end of $supported_list. This way, build.sh will always + # build maskpass with libgcrypt dependency rather than libcrypto dependency on non-AIX platforms. + if ($HOSTOS != "AIX") then + set supported_list_reorder = `echo $supported_list | sed 's/gcrypt//;s/$/ gcrypt/'` + set supported_list = `echo $supported_list_reorder` endif - cat $gtm_map/gtmcryptbuild.map - if (0 != $bstat || ! -x $gtm_dist_plugin/libgtmcrypt$gt_ld_shl_suffix || ! -x $gtm_dist_plugin/maskpass ) then - set buildaux_status = `expr $buildaux_status + 1` - echo "buildaux-E-libgtmcrypt, failed to build gtmcrypt and/or helper scripts \ - (see ${dollar_sign}gtm_map/gtmcryptbuild.map)" >> $gtm_log/error.`basename $gtm_exe`.log - else - $gtm_dist_plugin/install.sh >&! $gtm_map/gtmcryptinstall.map - if (0 != $status) then - set buildaux_status = `expr $buildaux_status + 1` - echo "buildaux-E-libgtmcrypt, failed to install gtmcrypt and/or helper scripts \ - (see ${dollar_sign}gtm_map/gtmcryptinstall.map)" >> $gtm_log/error.`basename $gtm_exe`.log + # 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 #########" + sh -x $gtm_dist_plugin/build.sh $supported_lib $plugin_build_type $algorithm + set bstat = $status + echo "" + if (0 != $bstat) then + set buildaux_status = `expr $buildaux_status + 1` + echo "buildaux-E-libgtmcrypt, failed to build gtmcrypt and/or helper scripts. See 'map' \ + files in ${dollar_sign}gtm_dist/plugin/gtmcrypt for more details" \ + >> $gtm_log/error.`basename $gtm_exe`.log + endif + end + end + if ($gtm_verno =~ V[4-8]*) then + # For production builds don't do any randomizations. + set algorithm = "AES256CFB" + if ($HOSTOS == "AIX") then + set encryption_lib = "openssl" + else + set encryption_lib = "gcrypt" endif - cat $gtm_map/gtmcryptinstall.map + 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. + set rand = `$gtm_dist/mumps -run %XCMD 'write 1+$random('$#supported_list')'` + 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 + set algorithms = ("AES256CFB" "AES256CFB" "BLOWFISHCFB") + set rand = `$gtm_dist/mumps -run %XCMD 'write 1+$random('$#algorithms')'` + set algorithm = $algorithms[$rand] + endif + endif + $gtm_dist_plugin/install.sh $encryption_lib $algorithm + if (0 != $status) then + set buildaux_status = `expr $buildaux_status + 1` + echo "buildaux-E-libgtmcrypt, failed to install libgtmcrypt and/or helper scripts" \ + >> $gtm_log/error.`basename $gtm_exe`.log endif popd >&! /dev/null endif diff --git a/sr_unix/callintogtmxfer.c b/sr_unix/callintogtmxfer.c index 141a74e..ea620a2 100644 --- a/sr_unix/callintogtmxfer.c +++ b/sr_unix/callintogtmxfer.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,8 +20,10 @@ #include "gt_timer.h" typedef int (*int_fptr)(); -GBLREF int jnlpool_detach(); +/* Note the malloc and free calls below are turned into gtm_malloc/gtm_free respectively by the #defines for those names + * in mdefsp.h. + */ GBLDEF int (*callintogtm_vectortable[])()= { (int_fptr)hiber_start, @@ -30,7 +32,6 @@ GBLDEF int (*callintogtm_vectortable[])()= (int_fptr)cancel_timer, (int_fptr)malloc, (int_fptr)free, - (int_fptr)jnlpool_detach, (int_fptr)-1L }; @@ -44,20 +45,24 @@ GBLDEF int (*callintogtm_vectortable[])()= GBLDEF unsigned char gtmvectortable_address[MAX_ADDR_SIZE]; GBLDEF unsigned char gtmvectortable_env[MAX_ADDR_ENV_SIZE]; +error_def(ERR_SYSCALL); + void init_callin_functable(void) { unsigned char *env_top, *address_top; uint4 address_len; + int save_errno; address_top = GTM64_ONLY(i2ascl)NON_GTM64_ONLY(i2asc)(gtmvectortable_address, (UINTPTR_T)(&callintogtm_vectortable[0])); *address_top = '\0'; address_len = (uint4)(address_top - >mvectortable_address[0]); env_top = >mvectortable_env[0]; - memcpy(env_top, GTM_CALLIN_START_ENV, strlen(GTM_CALLIN_START_ENV)); + 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)) { - rts_error(VARLSTCNT(1) errno); + save_errno = errno; + rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("putenv"), CALLFROM, save_errno); } } diff --git a/sr_unix/check_encrypt_support.sh b/sr_unix/check_encrypt_support.sh index 80bc2d2..2edf663 100644 --- a/sr_unix/check_encrypt_support.sh +++ b/sr_unix/check_encrypt_support.sh @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2009, 2011 Fidelity Information Services, Inc # +# Copyright 2009, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -9,148 +9,189 @@ # the license, please stop and do not read further. # # # ################################################################# -########################################################################################### -# -# check_encrypt_support.sh - Checks if encryption library and executables required for -# building encryption plugin are available -# Returns : -# TRUE - if ksh, gpg, crypt headers and libraries are available -# FALSE - if not all of them are available i.e the host does not support encryption -########################################################################################### + +################################################################# +# # +# check_encrypt_support.sh - Checks if headers, libraries # +# and executables required for # +# building encryption plugin # +# are available # +# Returns - If encryption is supported, returns either # +# "libgcrypt" or "openssl" or "libgcrypt openssl# +# FALSE, otherwise. # +################################################################# + +################################# +# Helper functions # +################################# +check_files() +{ + # Check if a given list of files with a given list of extensions is + # present in a given list of search paths + srch_path=$1 + srch_files=$2 + srch_ext=$3 + missing="" + ret=0 + for each_file in $srch_files + do + flag=0 + for each_path in $srch_path + do + for each_ext in $srch_ext + do + if [ -f $each_path/$each_file$each_ext ]; then flag=1 break ; fi + done + # The below takes care of files whose extensions are already determined by the caller + if [ -f $each_path/$each_file ]; then flag=1 break; fi + done + if [ $flag -eq 0 ]; then + missing="$missing $each_file" + ret=1 + fi + done + return $ret +} + +send_mail() +{ + msg=$1 + echo $encrypt_dist_servers | grep -w $hostname > /dev/null + if [ $? -eq 0 ]; then + msg="Please setup the required dependencies for this distribution server.\n\n$msg" + msg="$msg\nAt least one of Libgcrypt or OpenSSL dependencies must be met." + sub="ENCRYPTSUPPORTED-E-ERROR : Distribution server $hostname will not build encryption plugin" + fi + echo "$encrypt_other_servers $encrypt_desktops" | grep -w $hostname > /dev/null + if [ $? -eq 0 ]; then + msg="This system supports encryption but does not have the required dependencies setup\n\n.$msg" + msg="$msg\nAt least one of Libgcrypt or OpenSSL dependencies must be met." + sub="ENCRYPTSUPPORTED-W-WARNING : Server $hostname will not build encryption plugin" + fi + printf "$msg" | mailx -s "$sub" gglogs +} + +################################# +# Helper functions ends # +################################# hostos=`uname -s` -# We know we don't support these platforms -if [ "OSF1" = "$hostos" -o \( "HP-UX" = "$hostos" -a "ia64" != `uname -m` \) ]; then - echo "FALSE" - exit 0 -fi - -lib_search_path="/usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /lib64 /lib /usr/local/ssl/lib /usr/lib/x86_64-linux-gnu" -lib_search_path="$lib_search_path /lib/x86_64-linux-gnu" -include_search_path="/usr/include /usr/local/include /usr/local/include/gpgme" -bin_search_path="/usr/bin /usr/local/bin /bin" - -sym_headers="gcrypt.h gcrypt-module.h" -req_lib_files="libgpg-error libgpgme" -lib_ext="so" -if [ "AIX" = "$hostos" ]; then - sym_headers="openssl/evp.h openssl/sha.h openssl/blowfish.h" - req_lib_files="libcrypto $req_lib_files" - lib_ext="$lib_ext a" -else - req_lib_files="libgcrypt $req_lib_files" -fi -if [ "OS/390" = "$hosotos" ]; then - lib_ext="dll" -fi -req_inc_files="gpgme.h gpg-error.h $sym_headers" -req_bin_files="gpg ksh" - -found_headers="TRUE" -found_libs="TRUE" -found_bins="TRUE" - -whatsmissing="" - -for each_lib in $req_lib_files -do - find_flag=0 - for each_lib_path in $lib_search_path - do - for each_ext in $lib_ext - do - if [ -f $each_lib_path/$each_lib.$each_ext ]; then - find_flag=1 - break - fi - done - done - if [ $find_flag -eq 0 ]; then - found_libs="FALSE" - whatsmissing="$whatsmissing library $each_lib is missing \n" - fi -done -for each_header in $req_inc_files -do - find_flag=0 - for each_path in $include_search_path - do - if [ -f $each_path/$each_header ]; then - find_flag=1 - break - fi - done - if [ $find_flag -eq 0 ]; then - found_headers="FALSE" - whatsmissing="$whatsmissing include file $each_header is missing \n" - fi -done - -for each_bin in $req_bin_files -do - find_flag=0 - for each_path in $bin_search_path - do - if [ -x $each_path/$each_bin ]; then - find_flag=1 - break - fi - done - if [ $find_flag -eq 0 ]; then - found_bins="FALSE" - whatsmissing="$whatsmissing executable $each_bin is missing \n" - fi -done - +hostname=`uname -n | awk -F. '{print $1}'` +machtype=`uname -m` server_list="$cms_tools/server_list" - -if [ -f $server_list ];then - hostname=`uname -n | awk -F. '{print $1}'` +this_host_noencrypt="FALSE" +if [ -f $server_list ]; then eval `/usr/local/bin/tcsh -efc " source $server_list; echo non_encrypt_machines=\'\\\$non_encrypt_machines\'; echo encrypt_desktops=\'\\\$encrypt_desktops\'; echo encrypt_dist_servers=\'\\\$encrypt_dist_servers\'; echo encrypt_other_servers=\'\\\$encrypt_other_servers\'; - " || echo echo ERROR \; exit 1` - if [ $found_headers = "TRUE" -a $found_libs = "TRUE" -a $found_bins = "TRUE" ];then - # We want to keep at least one server without support for encryption. So if it send a warning if it is not the case. - echo $non_encrypt_machines | grep -w $hostname > /dev/null - if [ $? -eq 0 ]; then - errmsg="This system should not supports encryption, but it does.\n" - printf "$errmsg" | mailx -s \ - "ENCRYPTSUPPORTED-W-WARNING : Server $hostname will build encryption plugin (but should not)" \ - gglogs - fi - echo "TRUE" - else - # These are distribution servers that support encryption. If can't build encryption plugin send error. - echo $encrypt_dist_servers | grep -w $hostname > /dev/null - if [ $? -eq 0 ]; then - errmsg="Please setup the required dependencies for this distribution server:\n" - errmsg="$errmsg$whatsmissing" - printf "$errmsg" | mailx -s \ - "ENCRYPTSUPPORTED-E-ERROR : Distribution server $hostname will not build encryption plugin" \ - gglogs - fi - # There are machines that can support encryption. If can't build encryption plugin send warning. - encrypt_machines="$encrypt_other_servers $encrypt_desktops" - echo $encrypt_machines | grep -w $hostname > /dev/null - if [ $? -eq 0 ]; then - errmsg="This system supports encryption but does not have the required dependencies setup:\n" - errmsg="$errmsg$whatsmissing" - printf "$errmsg" | mailx -s \ - "ENCRYPTSUPPORTED-W-WARNING : Server $hostname will not build encryption plugin" \ - gglogs - fi - echo "FALSE" - fi -else - if [ $found_headers = "TRUE" -a $found_libs = "TRUE" -a $found_bins = "TRUE" ];then - echo "TRUE" - else - echo "FALSE" + " || echo echo ERROR \; exit 1` + echo $non_encrypt_machines | grep -w $hostname > /dev/null + if [ $? -eq 0 ]; then + this_host_noencrypt="TRUE" fi fi -exit 0 +if [ "OSF1" = "$hostos" -o \( "HP-UX" = "$hostos" -a "ia64" != "$machtype" \) -o "TRUE" = "$this_host_noencrypt" ]; then + echo "FALSE" + exit 0 +fi + +lib_search_path="/usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /lib64 /lib /usr/local/ssl/lib /usr/lib/x86_64-linux-gnu" +lib_search_path="$lib_search_path /usr/lib/i386-linux-gnu /lib/x86_64-linux-gnu /lib/i386-linux-gnu /opt/openssl/0.9.8/lib/hpux64" +include_search_path="/usr/include /usr/local/include /usr/local/include/gpgme /usr/local/ssl/include /opt/openssl/0.9.8/include" +bin_search_path="/usr/bin /usr/local/bin /bin" + +mandate_headers="gpgme.h gpg-error.h" +mandate_libs="libgpg-error libgpgme" +mandate_bins="gpg" +gcrypt_headers="gcrypt.h gcrypt-module.h" +gcrypt_libs="libgcrypt" +openssl_headers="openssl/evp.h openssl/sha.h openssl/blowfish.h" +openssl_libs="libcrypto" +lib_ext=".so" +if [ "AIX" = "$hostos" ]; then + lib_ext="$lib_ext .a" +elif [ "OS/390" = "$hosotos" ]; then + lib_ext=".dll" +fi + +# ------------------------------------------------------ # +# Mandatory checks # +# ------------------------------------------------------ # +found_mandates="TRUE" +check_files "$include_search_path" "$mandate_headers" "" +if [ $? -eq 1 ]; then + found_mandates="FALSE" + mandate_missing_list="Mandatory header files - $missing - are missing" +fi + +check_files "$lib_search_path" "$mandate_libs" "$lib_ext" +if [ $? -eq 1 ]; then + found_mandates="FALSE" + mandate_missing_list="$mandate_missing_list\nMandatory library files - $missing - are missing" +fi + +check_files "$bin_search_path" "$mandate_bins" "" +if [ $? -eq 1 ]; then + found_mandates="FALSE" + mandate_missing_list="$mandate_missing_list\nMandatory executables - $missing - are missing" +fi + + +# ------------------------------------------------------ # +# Check for libgcrypt # +# ------------------------------------------------------ # +found_gcrypt="TRUE" +check_files "$include_search_path" "$gcrypt_headers" "" +if [ $? -eq 1 ]; then + found_gcrypt="FALSE" + gcrypt_missing_list="\nLibgcrypt header files - $missing - are missing" +fi + +check_files "$lib_search_path" "$gcrypt_libs" "$lib_ext" +if [ $? -eq 1 ]; then + found_gcrypt="FALSE" + gcrypt_missing_list="$gcrypt_missing_list\nLibgcrypt library files - $missing - are missing" +fi + +# ------------------------------------------------------ # +# Check for OpenSSL # +# ------------------------------------------------------ # +found_openssl="TRUE" +check_files "$include_search_path" "$openssl_headers" "" +if [ $? -eq 1 ]; then + found_openssl="FALSE" + openssl_missing_list="\nOpenSSL header files - $missing - are missing" +fi + +check_files "$lib_search_path" "$openssl_libs" "$lib_ext" +if [ $? -eq 1 ]; then + found_openssl="FALSE" + openssl_missing_list="$openssl_missing_list\nOpenSSL library files - $missing - are missing\n" +fi + +# ------------------------------------------------------ # +# Figure out supported list # +# ------------------------------------------------------ # +mail_msg="" +supported_list="" +if [ "TRUE" = $found_mandates ] ; then + if [ "TRUE" = "$found_gcrypt" ]; then supported_list="$supported_list gcrypt" ; fi + if [ "TRUE" = "$found_openssl" ]; then supported_list="$supported_list openssl" ; fi + if [ "" != "$supported_list" ] ; then + echo $supported_list + exit 0 + fi +fi +# Some of the dependencies are unmet. +mail_msg="$mandate_missing_list \n \n $gcrypt_missing_list \n \n $openssl_missing_list" +if [ "mail" = "$1" ]; then + if [ -f $server_list ]; then + send_mail "$mail_msg" + fi +fi +echo "FALSE" +exit 1 diff --git a/sr_unix/check_unicode_support.csh b/sr_unix/check_unicode_support.csh index 18def7d..a59ef7c 100644 --- a/sr_unix/check_unicode_support.csh +++ b/sr_unix/check_unicode_support.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2010 Fidelity Information Services, Inc # +# Copyright 2007, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -19,17 +19,17 @@ ########################################################################################### set found_icu = 0 -set utflocale = `locale -a | grep -i en_us | grep -i utf | grep '8$'` +set utflocale = `locale -a | grep -i en_us | grep -i utf | grep '8$' | head -n 1` if ("OS/390" == $HOSTOS) then # z/OS has both en_US.UTF-8 and En_US.UTF-8 with both .xplink and .lp64 suffixes - we need .lp64 - set utflocale = `locale -a | grep En_US.UTF-8.lp64 | sed 's/.lp64$//'` + set utflocale = `locale -a | grep En_US.UTF-8.lp64 | sed 's/.lp64$//' | head -n 1` endif # This _could_ not work on new platforms or newly installed supported platforms. # It should be manually tested using this command : # ssh ls -l {/usr/local,/usr,}/lib{64,,32}/libicuio.{a,so,sl} -foreach libdir ( {/usr/local,/usr,}/lib{64,,32}/libicuio.{a,so,sl} ) +foreach libdir ( {/usr/local,/usr,}/lib{64,/x86_64-linux-gnu,,32,/i386-linux-gnu}/libicuio.{a,so,sl} ) # 36 is the least version GT.M supports for ICU. # We have to get the numeric value from the ICU library. On non-AIX platforms, this can be done by # first getting the library to which libicuio.so is pointing to (this is always TRUE, in the sense diff --git a/sr_unix/clear_cache_array.c b/sr_unix/clear_cache_array.c index 1d834fe..0096d88 100644 --- a/sr_unix/clear_cache_array.c +++ b/sr_unix/clear_cache_array.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2012 Fidelity Information Services, Inc * + * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -65,51 +65,43 @@ void clear_cache_array(sgmnt_addrs *csa, sgmnt_data_ptr_t csd, gd_region* reg, u SETUP_THREADGBL_ACCESS; /* If called from db_init, assure we've grabbed the access semaphor and are the only process attached to the database. - * Otherwise, we should have crit when called from wcs_recover or mu_truncate. */ + * Otherwise, we should have crit when called from wcs_recover or mu_truncate. + */ udi = FILE_INFO(reg); assert((udi->grabbed_access_sem && (1 == (semval = semctl(udi->semid, 1, GETVAL)))) || csa->now_crit); hash_hdr = (cache_rec_ptr_t)csa->acc_meth.bg.cache_state->cache_array; cr_lo = hash_hdr + csd->bt_buckets; cr_top = cr_lo + csd->n_bts; cnl = csa->nl; - /* CLear all the cached blocks(FREE AND RECYCLED) - * that are greater than the post-truncate total_blks - * Done in crit, near the end of truncate. - */ + /* Last thing we did was wcs_flu, so no buffers should have been dirtied in the meantime. */ + assert(0 == cnl->wcs_active_lvl); for (cr = cr_lo; cr < cr_top; cr++) { - if (CR_BLKEMPTY != cr->blk && cr->blk >= new_total) - { - if ((0 == cr->dirty) - VMS_ONLY(|| ((0 != cr->iosb.cond) && (0 == cr->bt_index)))) - { /* cache record has no valid buffer attached, or its contents - * are in the database, or it has a more recent twin so we don't - * even have to care how its write terminated - */ - cr->cycle++; - if (CR_BLKEMPTY != cr->blk) + assert(0 == cr->dirty); + if ((CR_BLKEMPTY != cr->blk) && (new_total <= cr->blk)) + { /* Invalidate this cache record. */ + cr->cycle++; + if (CR_BLKEMPTY != cr->blk) + { + bt = bt_get(cr->blk); + if (NULL != bt) { - bt = bt_get(cr->blk); - if (bt) - bt->cache_index = CR_NOTVALID; + bt->cache_index = CR_NOTVALID; + bt->blk = BT_NOTVALID; } - cr->blk = BT_NOTVALID; /* -1 */ - /* when cr->blk is empty, ensure no bt points to this cache-record */ - cr->bt_index = 0; /* offset to bt_rec */ - cr->data_invalid = 0; /* process_id */ - cr->dirty = 0; - cr->flushed_dirty_tn = 0; /* value of dirty at the time of flush */ - cr->in_tend = 0; - /* release of a shmpool reformat block if the current cache record is pointing to it */ - SHMPOOL_FREE_CR_RFMT_BLOCK(reg, csa, cr); - WRITE_LATCH_VAL(cr) = LATCH_CLEAR; - VMS_ONLY(cr->iosb.cond = 0;) - cr->jnl_addr = 0; - cr->refer = FALSE; - cr->stopped = FALSE; - /* increment number of write cache records in free queue */ - cnl->wc_in_free++; } + cr->blk = CR_BLKEMPTY; + /* when cr->blk is empty, ensure no bt points to this cache-record */ + cr->bt_index = 0; /* offset to bt_rec */ + cr->data_invalid = 0; /* process_id */ + cr->flushed_dirty_tn = 0; /* value of dirty at the time of flush */ + cr->in_tend = 0; + /* release of a shmpool reformat block if the current cache record is pointing to it */ + SHMPOOL_FREE_CR_RFMT_BLOCK(reg, csa, cr); + WRITE_LATCH_VAL(cr) = LATCH_CLEAR; + cr->jnl_addr = 0; + cr->refer = FALSE; + assert(!cr->stopped); } } } diff --git a/sr_unix/cli_lex.c b/sr_unix/cli_lex.c index 898c105..4840889 100644 --- a/sr_unix/cli_lex.c +++ b/sr_unix/cli_lex.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,6 +47,13 @@ GBLREF boolean_t gtm_utf8_mode; #define CLI_ISSPACE(CHAR) ISSPACE_ASCII(CHAR) #endif +/* Don't use toupper() because, with Turkish unicode settings, toupper('i') does not have well-defined behavior. On some platforms + * it returns back 'i' itself. This is because, in Turkish, the actual uppercase version of 'i' is 'I' with a dot on top, which is + * not an ascii character. Thus cli_strupper would incorrectly convert some qualifiers, resulting in CLIERR errors. For example it + * would convert "-dynamic_literals" to "-DYNAMiC_LiTERALS" or "-warnings" to "-WARNiNGS". + */ +#define CLI_TOUPPER(C) (('a' <= (C) && (C) <= 'z') ? ((C) + ('A' - 'a')) : (C)) + static int tok_string_extract(void) { int token_len; @@ -204,7 +211,7 @@ void cli_strupper(char *sp) int c; while (c = *sp) - *sp++ = IS_ASCII(c) ? TOUPPER(c) : c; + *sp++ = IS_ASCII(c) ? CLI_TOUPPER(c) : c; } /* @@ -221,7 +228,7 @@ int cli_is_hex(char *p) if (('+' == *p) || ('-' == *p)) p++; - if (('0' == *p) && ('X' == TOUPPER(*(p + 1)))) + if (('0' == *p) && ('X' == CLI_TOUPPER(*(p + 1)))) { p = p + 2; } @@ -338,7 +345,7 @@ static int tok_extract (void) token_len = 1; } else if (ch) /* only if something there */ { - /* smw if quotable, need to unicode isspace */ + /* smw if quotable, need to unicode isspace (BYPASSOK) */ /* '-' is not a token separator */ while(ch && !CLI_ISSPACE(ch) && ch != '=') diff --git a/sr_unix/cmidefsp.h b/sr_unix/cmidefsp.h index f933e82..bf22284 100644 --- a/sr_unix/cmidefsp.h +++ b/sr_unix/cmidefsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -59,6 +59,8 @@ typedef mstr cmi_descriptor; #include #include "gtm_unistd.h" +#include "gtm_netdb.h" +#include "gtm_socket.h" /* for sockaddr_storage */ typedef struct { @@ -84,7 +86,7 @@ typedef struct clb_stat_struct * Individual link connections doubly linked list */ -#include +#include "gtm_inet.h" #ifdef __MVS__ /* need fd_set */ #include @@ -92,26 +94,27 @@ typedef struct clb_stat_struct struct CLB { - que_ent cqe; /* forward/backward links */ - struct NTD *ntd; /* back pointer to ntd */ - cmi_descriptor nod; /* node */ - cmi_descriptor tnd; /* taskname */ - struct sockaddr_in peer; /* peer */ - int mun; /* endpoint's file descriptor */ - void *usr; /* client specific storage */ - qio_iosb ios; /* used for tracking inprocess I/O */ - unsigned short cbl; /* number of bytes read */ - unsigned short mbl; /* max size buffer */ - unsigned char *mbf; /* pointer to buffer */ - unsigned char urgdata; /* buffer for urgent data */ - int fd_async; /* TRUE --> fd is in async mode */ - int deferred_event; /* TRUE --> deferred event signaled */ - cmi_reason_t deferred_reason; /* reason for deferred event */ - cmi_status_t deferred_status; /* status for deferred event */ - int sta; /* CM_ state */ - int prev_sta; /* CM_ state before URG WRITE, to be restored after URG WRITE completes */ - void (*err)(struct CLB *); /* link status error callback - not used */ - void (*ast)(struct CLB *); /* I/O call back for async read/write */ + que_ent cqe; /* forward/backward links */ + struct NTD *ntd; /* back pointer to ntd */ + cmi_descriptor nod; /* node */ + cmi_descriptor tnd; /* taskname */ + struct sockaddr_storage peer_sas; /* peer */ + struct addrinfo peer_ai; /* peer */ + int mun; /* endpoint's file descriptor */ + void *usr; /* client specific storage */ + qio_iosb ios; /* used for tracking inprocess I/O */ + unsigned short cbl; /* number of bytes read */ + unsigned short mbl; /* max size buffer */ + unsigned char *mbf; /* pointer to buffer */ + unsigned char urgdata; /* buffer for urgent data */ + int fd_async; /* TRUE --> fd is in async mode */ + int deferred_event; /* TRUE --> deferred event signaled */ + cmi_reason_t deferred_reason; /* reason for deferred event */ + cmi_status_t deferred_status; /* status for deferred event */ + int sta; /* CM_ state */ + int prev_sta; /* CM_ state before URG WRITE, to be restored after URG WRITE completes */ + void (*err)(struct CLB *); /* link status error callback - not used */ + void (*ast)(struct CLB *); /* I/O call back for async read/write */ struct clb_stat_struct stt; }; @@ -215,8 +218,7 @@ cmi_status_t cmj_write_start(struct CLB *lnk); cmi_status_t cmj_write_urg_start(struct CLB *lnk); void cmj_write_interrupt(struct CLB *lnk, int signo); void cmj_init_clb(struct NTD *tsk, struct CLB *lnk); -cmi_status_t cmj_resolve_nod_tnd(cmi_descriptor *nod, cmi_descriptor *tnd, struct sockaddr_in *inp); -cmi_status_t cmj_getsockaddr(cmi_descriptor *tnd, struct sockaddr_in *inp); +cmi_status_t cmj_getsockaddr(cmi_descriptor *nod, cmi_descriptor *tnd, struct addrinfo **ai_ptr); cmi_status_t cmi_write_urg(struct CLB *c, unsigned char data); cmi_status_t cmi_init( cmi_descriptor *tnd, diff --git a/sr_unix/cms_load.csh b/sr_unix/cms_load.csh index 27137aa..03e6daa 100755 --- a/sr_unix/cms_load.csh +++ b/sr_unix/cms_load.csh @@ -1,7 +1,7 @@ #! /usr/local/bin/tcsh ################################################################# # # -# Copyright 2001, 2011 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -54,7 +54,7 @@ set dir_structure = "inc pct src tools log $build_types" set gtm_src_types = "c m64 s msg" set gtm_inc_types = "h max mac si" set gtm_pct_types = "mpt m hlp" -set gtm_tools_types = "gtc sed awk sh csh list txt exp mk ksh" +set gtm_tools_types = "gtc sed awk sh csh list txt exp mk ksh cmake tab in" ##################################################################################### @@ -102,7 +102,7 @@ if (-e $dst_ver) then /bin/ps $psopt | grep "$dst_top_dir/$dst_ver/" | grep -vE "grep|$0" exit 1 endif - if ($dst_ver =~ V3* || $dst_ver =~ V4* || $dst_ver =~ V5* || $dst_ver == "V990") then + if ($dst_ver =~ V3* || $dst_ver =~ V4* || $dst_ver =~ V5* || $dst_ver =~ V6* || $dst_ver == "V990") then set move_args = "compulsory" endif # to use this script to update released versions, you must diff --git a/sr_unix/comlist.csh b/sr_unix/comlist.csh index 0139c73..1dbd4c3 100644 --- a/sr_unix/comlist.csh +++ b/sr_unix/comlist.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2012 Fidelity Infromation Services, Inc # +# Copyright 2001, 2013 Fidelity Infromation Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -32,7 +32,9 @@ echo "Start of $0 `date`" echo "" -echo "Built on $HOST" +set uname_out = `uname -a` + +echo "Built on $HOST : $uname_out" echo "" echo "arguments: '$1' '$2' '$3' '$4'" @@ -80,94 +82,6 @@ unalias ls rm set comlist_start_directory = `pwd` -switch ( $gtm_verno ) - - -case "V990": - # V990 is designated "most recent on the main line of descent in CMS" - # and should be protected from inadvertent change. - set comlist_chmod_protect = 1 - breaksw - -case "V99*": - # Other V9.9 releases are provided for the "private" use of developers to - # modify as they see fit for test purposes and should allow modification. - set comlist_chmod_protect = 0 - breaksw - -default: - # Anything else should be a configured release (i.e., should correspond to - # a CMS release class) and should be protected against inadvertent change. - set comlist_chmod_protect = 1 - breaksw - -endsw - -set mach_type = `uname -m` - -if ( $comlist_chmod_protect == 1 ) then - # Change the permissions on all of the source files to prevent inadvertent - # modification by developers. - set comlist_chmod_conf = 755 - set comlist_chmod_src = 444 - -else - # Change the permissions on all of the source files to allow modification by developers. - set comlist_chmod_conf = 775 - set comlist_chmod_src = 664 - -endif - - -# Change the permissions on the root directory for this version to allow -# others in this group (i.e., developers) to create new subdirectories. This -# is usually done for running tests or creating readme.txt files, although -# there may be other reasons. -chmod 775 $gtm_ver - - - -# Change the permissions on the configured directories for this version to -# prevent inadvetent modification (creation / deletion of files) by developers -# or allow modification as appropriate. -cd $gtm_ver -chmod $comlist_chmod_conf bta dbg pro inc pct src tools gtmsrc.csh - -chmod 775 log - - - -# Change permisions on all source files to prevent inadvertent modification of -# source files corresponding to configured releases and allowing modification -# for development and test releases. -cd $gtm_inc -chmod $comlist_chmod_src * - - -cd $gtm_pct -chmod $comlist_chmod_src * - - -# In $gtm_src, use xargs because this directory has so many files that the -# command line expansion overflows the command length limits on some Unix -# implementations. -cd $gtm_src -/bin/ls | xargs -n25 chmod $comlist_chmod_src - -cd $gtm_tools -chmod $comlist_chmod_src * - -if ( $comlist_chmod_protect == 1 ) then - chmod 555 *sh # make the shell scripts executable, but protect against inadvertent modification - -else - chmod 775 *sh # make the shell scripts exectuable and allow modification - -endif - -# Remove old error log. -rm $gtm_log/error.`basename $gtm_exe`.log - # Verify arguments: set p1 = "$1" set p2 = "$2" @@ -224,6 +138,102 @@ if (0 != $comlist_status) then goto comlist.END endif +switch ( $gtm_verno ) + +case "V990": + # V990 is designated "most recent on the main line of descent in CMS" + # and should be protected from inadvertent change. + set comlist_chmod_protect = 1 + breaksw + +case "V9*": + # Other V9 releases are provided for the "private" use of developers to + # modify as they see fit for test purposes and should allow modification. + set comlist_chmod_protect = 0 + breaksw + +default: + # Anything else should be a configured release (i.e., should correspond to + # a CMS release class) and should be protected against inadvertent change. + set comlist_chmod_protect = 1 + breaksw + +endsw + +set mach_type = `uname -m` + +if ( $comlist_chmod_protect == 1 ) then + # Change the permissions on all of the source files to prevent inadvertent + # modification by developers. + set comlist_chmod_conf = 755 + set comlist_chmod_src = 444 + +else + # Change the permissions on all of the source files to allow modification by developers. + set comlist_chmod_conf = 775 + set comlist_chmod_src = 664 + +endif + + +if !(-o $gtm_ver) then + echo "COMLIST-E-NOTOWNER. $USER is not owner of $gtm_ver cannot coninue" + goto comlist.END +endif + +# Change the permissions on the root directory for this version to allow +# others in this group (i.e., developers) to create new subdirectories. This +# is usually done for running tests or creating readme.txt files, although +# there may be other reasons. +chmod 775 $gtm_ver + + + +# Change the permissions on the configured directories for this version to +# prevent inadvetent modification (creation / deletion of files) by developers +# or allow modification as appropriate. +cd $gtm_ver +chmod $comlist_chmod_conf inc pct src tools gtmsrc.csh + +chmod 775 log +if !(-w $gtm_exe) then + echo "COMLIST-E-PERMISSON : There is no write permission to $gtm_exe. Exiting" + exit +endif + + +# Change permisions on all source files to prevent inadvertent modification of +# source files corresponding to configured releases and allowing modification +# for development and test releases. +cd $gtm_inc +chmod $comlist_chmod_src * + + +cd $gtm_pct +chmod $comlist_chmod_src * + + +# In $gtm_src, use xargs because this directory has so many files that the +# command line expansion overflows the command length limits on some Unix +# implementations. +cd $gtm_src +/bin/ls | xargs -n25 chmod $comlist_chmod_src + +cd $gtm_tools +chmod $comlist_chmod_src * + +if ( $comlist_chmod_protect == 1 ) then + chmod 555 *sh # make the shell scripts executable, but protect against inadvertent modification + +else + chmod 775 *sh # make the shell scripts exectuable and allow modification + +endif + +# Remove old error log. +rm $gtm_log/error.`basename $gtm_exe`.log + + echo "" echo "Assembler-related aliases:" echo "" @@ -295,6 +305,7 @@ chmod +x {lowerc,gtminstall}* cp $gtm_tools/*.gtc . mv configure{.gtc,} +cp $gtm_inc/gtm_common_defs.h . cp $gtm_inc/gtmxc_types.h . cp $gtm_inc/gtm_descript.h . cp $gtm_inc/gtm_sizeof.h . @@ -484,8 +495,18 @@ endif if ( $?gt_as_use_prebuilt == 0 ) then # Finally assemble any sources originally in native dialect so they # can supersede any conflicting non-native dialect sources: - foreach asm (${gs[1]}/*${gt_as_src_suffix}) - $shell $gtm_tools/gt_as.csh $asm + @ asm_batch_size=25 + @ asm_batch_tail = ${asm_batch_size} + 1 + set asmlist=(`echo ${gs[1]}/*${gt_as_src_suffix}`) + while ($#asmlist) + if (${#asmlist} > ${asm_batch_size}) then + set asmsublist=(${asmlist[1-${asm_batch_size}]}) + set asmlist=(${asmlist[${asm_batch_tail}-]}) + else + set asmsublist=(${asmlist}) + set asmlist=() + endif + $shell $gtm_tools/gt_as.csh ${asmsublist} end else cp -p $gtm_vrt/$gt_as_use_prebuilt/*.o . @@ -646,40 +667,77 @@ rm -f GTMDefinedTypesInit.m >& /dev/null echo "Generating GTMDefinedTypesInit.m" if ($?work_dir) then if (-e $work_dir/tools/cms_tools/gengtmdeftypes.csh) then + echo "Using gengtmdeftypes.csh from $work_dir" $work_dir/tools/cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log + @ savestatus = $status else $cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log + @ savestatus = $status endif else $cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log -endif -if ((0 != $status) || (! -e GTMDefinedTypesInit.m)) then @ savestatus = $status - if (`expr $gtm_verno \>= V900`) @ comlist_status = $savestatus # note no errors for development versions - echo "gengtmdeftypes.csh failed to create GTMDefinedTypesInit.m - see log in $gtm_obj/gengtmdeftypes.log" >> \ - $gtm_log/error.`basename $gtm_exe`.log +endif +if ((0 != $savestatus) || (! -e GTMDefinedTypesInit.m)) then + set errmsg = "COMLIST-E-FAIL gengtmdeftypes.csh failed to create GTMDefinedTypesInit.m " + set errmsg = "$errmsg - see log in $gtm_obj/gengtmdeftypes.log" + if (`expr $gtm_verno \< V900`) then + @ comlist_status = $savestatus # No errors for development - this fails the build + else + echo "Warning: Build of $gtm_verno on $HOST, $errmsg" | \ + mailx -s "${HOST}: Build for $gtm_verno failed to create GTMDefinedTypes.m" $USER + endif + echo $errmsg >> $gtm_log/error.`basename $gtm_exe`.log endif if (-e GTMDefinedTypesInit.m) then # Need a different name for each build type as they can be different cp -f GTMDefinedTypesInit.m $gtm_pct/GTMDefinedTypesInit${bldtype}.m + setenv LC_CTYPE C + setenv gtm_chset M ./mumps GTMDefinedTypesInit.m - if (0 != $status) then - if (`expr $gtm_verno \>= V900`) @ comlist_status = $status - echo "Failed to compile $gtm_exe/GTMDefinedTypes.m" >> $gtm_log/error.`basename $gtm_exe`.log + @ savestatus = $status + if (0 != $savestatus) then + set errmsg = "COMLIST-E-FAIL Failed to compile generated $gtm_exe/GTMDefinedTypes.m" + if (`expr $gtm_verno \< V900`) then + @ comlist_status = $savestatus + else + echo "Warning: During build of $gtm_verno on $HOST, ${errmsg}" | \ + mailx -s "${HOST}: Compile for GTMDefinedTypes.m failed during build of $gtm_verno" $USER + endif + echo "${errmsg}" >> $gtm_log/error.`basename $gtm_exe`.log endif - # If we have a utf8 dir (created by buildaux.csh called from buildbdp.csh above), add a link to it for GTMDefinedTypesInit.m - if (-e $gtm_dist/utf8) then + # If we have a utf8 dir (created by buildaux.csh called from buildbdp.csh above), add a link to it for + # GTMDefinedTypesInit.m and compile it in UTF8 mode + source $gtm_tools/set_library_path.csh + source $gtm_tools/check_unicode_support.csh + if (-e $gtm_dist/utf8 && ("TRUE" == "$is_unicode_support")) then if (! -e $gtm_dist/utf8/GTMDefinedTypesInit.m) then ln -s $gtm_dist/GTMDefinedTypesInit.m $gtm_dist/utf8/GTMDefinedTypesInit.m endif pushd utf8 + # Switch to UTF8 mode + if ( "OS/390" == $HOSTOS ) setenv gtm_chset_locale $utflocale # LC_CTYPE not picked up right + setenv LC_CTYPE $utflocale + unsetenv LC_ALL + setenv gtm_chset UTF-8 # switch to "UTF-8" mode # mumps executable not yet linked to utf8 dir so access it in parent directory ../mumps GTMDefinedTypesInit.m - if (0 != $status) then - if (`expr $gtm_verno \>= V900`) @ comlist_status = $status - echo "Failed to compile $gtm_exe/GTMDefinedTypes.m" >> $gtm_log/error.`basename $gtm_exe`.log + @ savestatus = $status + if (0 != $savestatus) then + set errmsg = "COMLIST_E-FAIL Failed to compile generated $gtm_exe/utf8/GTMDefinedTypes.m" + if (`expr $gtm_verno \< V900`) then + @ comlist_status = $savestatus + else + echo "Warning: During build of $gtm_verno on $HOST, ${errmsg}" | \ + mailx -s "${HOST}: Compile for utf8/GTMDefinedTypes.m failed during build of $gtm_verno" \ + $USER + endif + echo "${errmsg}" >> $gtm_log/error.`basename $gtm_exe`.log endif popd + setenv LC_CTYPE C + unsetenv gtm_chset # switch back to "M" mode + if ( "OS/390" == $HOSTOS ) unsetenv gtm_chset_locale endif endif @@ -690,40 +748,27 @@ exit GDE_in1 if (0 != $status) @ comlist_status = $status -# Create the GT.M help database file. -setenv gtmgbldir $gtm_dist/gtmhelp.gld -gde < /dev/null +chgrp $bingroup tmp_owngrp 2> /dev/null if [ 0 != "$?" ] ; then - $echo $binuser is not a valid group name - exiting! + $echo $bingroup is not a valid group name - exiting! rm tmp_owngrp exit 1 fi @@ -168,7 +172,7 @@ fi $echo "Should execution of GT.M be restricted to this group? (y or n) \c" read resp if [ "$resp" = "Y" -o "$resp" = "y" ] ; then - group=$binuser + group=$bingroup fi rm tmp_owngrp @@ -191,7 +195,7 @@ if [ -d $gtmdist ]; then if [ "$resp" = "Y" -o "$resp" = "y" ] ; then chmod 0755 $gtmdist chown $owner $gtmdist - chgrp $binuser $gtmdist + chgrp $bingroup $gtmdist else exit fi @@ -205,7 +209,7 @@ else mkdir -p $gtmdist/plugin/r $gtmdist/plugin/o chmod 0755 $gtmdist chown $owner $gtmdist - chgrp $binuser $gtmdist + chgrp $bingroup $gtmdist else exit fi @@ -238,8 +242,9 @@ if [ -d "utf8" ]; then else is64bit_gtm=`file mumps | grep "64-bit" | wc -l` fi +# please keep in sync with sr_unix/set_library_path.csh if [ $is64bit_gtm -eq 1 ] ; then - library_path="/usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /usr/lib/x86_64-linux-gnu /lib64 /lib /usr/local/ssl/lib" + library_path="/usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib /usr/lib/x86_64-linux-gnu /lib64 /lib /usr/local/ssl/lib" #BYPASSOK line length else library_path="/usr/local/lib32 /usr/local/lib /usr/lib32 /usr/lib /usr/lib/i386-linux-gnu /lib32 /lib" fi @@ -346,7 +351,7 @@ if [ -d "utf8" ]; then fi fi # Look for locale - utflocale=`locale -a | grep -i .utf | sed 's/.lp64$//' | grep '8$' | head -n1` + utflocale=`locale -a | grep -i .utf | sed 's/.lp64$//' | grep '8$' | head -n 1` if [ "$utflocale" = "" ] ; then $echo "WARNING: UTF8 locale not found. Not installing UTF-8 support." fi @@ -423,6 +428,14 @@ if [ -f $file ]; then fi fi +# Install custom_errors_sample.txt if it is applicable +file=custom_errors_sample.txt +if [ -f $file ]; then + cp $file $gtmdist + if [ "$doutf8" -ne 0 ]; then + ln -s ../$file $gtmdist/utf8/$file + fi +fi # Install the .cshrc and .profile files cp gdedefaults gtmprofile gtmprofile_preV54000 gtm gtmcshrc $gtmdist chmod 0444 $gtmdist/gdedefaults @@ -456,17 +469,17 @@ done for i in $binaries do if [ $arch = "sun" -o $arch = "linux" ]; then - install -g $binuser -o $owner -m 644 $i $gtmdist + install -g $bingroup -o $owner -m 644 $i $gtmdist elif [ $arch = "ibm" ]; then - /usr/bin/install -f $gtmdist -M 644 -O $owner -G $binuser $i + /usr/bin/install -f $gtmdist -M 644 -O $owner -G $bingroup $i elif [ -x /usr/sbin/install ]; then - /usr/sbin/install -f $gtmdist -m 644 -u $owner -g $binuser $i $gtmdist + /usr/sbin/install -f $gtmdist -m 644 -u $owner -g $bingroup $i $gtmdist elif [ $arch = "zos" ]; then cp $i $gtmdist/ chmod 644 $gtmdist/$i - chown $user:$binuser $gtmdist/$i + chown $user:$bingroup $gtmdist/$i else - install -f $gtmdist -m 644 -u $owner -g $binuser $i $gtmdist + install -f $gtmdist -m 644 -u $owner -g $bingroup $i $gtmdist fi # strip $gtmdist/$i >/dev/null 2>&1 done @@ -501,17 +514,18 @@ gtmcryptbldfiles="install.sh build.sh" gtmcryptbinaries="maskpass" # Gtmcrypt shared library -gtmcryptsharedlib="libgtmcrypt$ext" +gtmcryptsharedlibs="libgtmcrypt_openssl_BLOWFISHCFB$ext libgtmcrypt_openssl_AES256CFB$ext" +gtmcryptsharedlibs="$gtmcryptsharedlibs libgtmcrypt_gcrypt_AES256CFB$ext libgtmcrypt$ext" # Gtmcrypt scripts gtmcryptscripts="add_db_key.sh gen_sym_key.sh encrypt_sign_db_key.sh gen_keypair.sh pinentry-gtm.sh" -gtmcryptscripts="$gtmcryptscripts import_and_sign_key.sh gen_sym_hash.sh" +gtmcryptscripts="$gtmcryptscripts import_and_sign_key.sh gen_sym_hash.sh show_install_config.sh" # Gtmcrypt related M file gtmcryptmfile="pinentry.m" # Gtmcrypt source files -gtmcryptsrcfiles="gtmcrypt_ref.c gtmcrypt_ref.h gtmcrypt_interface.h gtmxc_types.h maskpass.c" +gtmcryptsrcfiles="gtmcrypt_ref.c gtmcrypt_ref.h gtmcrypt_interface.h maskpass.c" gtmcryptsrcfiles="$gtmcryptsrcfiles gtmcrypt_dbk_ref.c gtmcrypt_dbk_ref.h gtmcrypt_pk_ref.c gtmcrypt_pk_ref.h" gtmcryptsrcfiles="$gtmcryptsrcfiles gtmcrypt_sym_ref.h $gtmcryptbldfiles $gtmcryptmfile" @@ -525,10 +539,10 @@ if [ -d "$plugin_gtmcrypt" ]; then mkdir -p $gtmdist/plugin/gtmcrypt chmod 0755 $gtmdist/plugin chown $owner $gtmdist/plugin - chgrp $binuser $gtmdist/plugin + chgrp $bingroup $gtmdist/plugin chmod 0755 $gtmdist/plugin/gtmcrypt chown $owner $gtmdist/plugin/gtmcrypt/ - chgrp $binuser $gtmdist/plugin/gtmcrypt + chgrp $bingroup $gtmdist/plugin/gtmcrypt #Install the plugin related scripts @@ -537,49 +551,62 @@ if [ -d "$plugin_gtmcrypt" ]; then cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt/$i chmod 0755 $gtmdist/$plugin_gtmcrypt/$i chown $owner $gtmdist/$plugin_gtmcrypt/$i - chgrp $binuser $gtmdist/$plugin_gtmcrypt/$i + chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$i done # Install the plugin binaries for i in $gtmcryptbinaries do if [ $arch = "sun" -o $arch = "linux" ]; then - install -g $binuser -o $owner -m 755 $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt + install -g $bingroup -o $owner -m 755 $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt elif [ $arch = "ibm" ]; then - /usr/bin/install -f $gtmdist/$plugin_gtmcrypt -M 755 -O $owner -G $binuser $plugin_gtmcrypt/$i + /usr/bin/install -f $gtmdist/$plugin_gtmcrypt -M 755 -O $owner -G $bingroup $plugin_gtmcrypt/$i elif [ $arch = "zos" ]; then cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt chmod 755 $gtmdist/$plugin_gtmcrypt/$i - chown $user:$binuser $gtmdist/$plugin_gtmcrypt/$i + chown $user:$bingroup $gtmdist/$plugin_gtmcrypt/$i elif [ -x /usr/sbin/install ]; then - /usr/sbin/install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $binuser \ + /usr/sbin/install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $bingroup \ $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt else - install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $binuser \ + install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $bingroup \ $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt fi done - # Install the plugin shared library - if [ $arch = "sun" -o $arch = "linux" ]; then - install -g $binuser -o $owner -m 755 $plugin/$gtmcryptsharedlib $gtmdist/$plugin - elif [ $arch = "ibm" ]; then - /usr/bin/install -f $gtmdist/$plugin -M 755 -O $owner -G $binuser $plugin/$gtmcryptsharedlib - elif [ $arch = "zos" ]; then - cp $plugin/$gtmcryptsharedlib $gtmdist/$plugin - chmod 755 $gtmdist/$plugin/$gtmcryptsharedlib - chown $user:$binuser $gtmdist/$plugin/$gtmcryptsharedlib - elif [ -x /usr/sbin/install ]; then - /usr/sbin/install -f $gtmdist/$plugin -m 755 -u $owner -g $binuser $plugin/$gtmcryptsharedlib $gtmdist/$plugin - else - install -f $gtmdist/$plugin -m 755 -u $owner -g $binuser $plugin/$gtmcryptsharedlib $gtmdist/$plugin + # Install the different flavors of encryption plugin (OpenSSL and Gcrypt) + for i in $gtmcryptsharedlibs + do + # Install only files (and not symlinks) that exist + # CMake builds generate only one library - GCRYPT with AES256CFB + if [ -L $plugin/$i -o ! -f $plugin/$i ]; then + continue + elif [ $arch = "sun" -o $arch = "linux" ]; then + install -g $bingroup -o $owner -m 755 $plugin/$i $gtmdist/$plugin + elif [ $arch = "ibm" ]; then + /usr/bin/install -f $gtmdist/$plugin -M 755 -O $owner -G $bingroup $plugin/$i + elif [ $arch = "zos" ]; then + cp $plugin/$i $gtmdist/$plugin + chmod 755 $gtmdist/$plugin/$i + chown $user:$bingroup $gtmdist/$plugin/$i + elif [ -x /usr/sbin/install ]; then + /usr/sbin/install -f $gtmdist/$plugin -m 755 -u $owner -g $bingroup $plugin/$i $gtmdist/$plugin + else + install -f $gtmdist/$plugin -m 755 -u $owner -g $bingroup $plugin/$i $gtmdist/$plugin + fi + done + + # Install the Symbolic link only if one exists (tarball has it, CMake builds do not) + if [ -L $plugin/libgtmcrypt$ext ]; then + currentlink=`ls -l $plugin/libgtmcrypt$ext | awk '{print $NF}'` + ln -s $currentlink $gtmdist/$plugin/libgtmcrypt$ext fi - # Install the plugin related M file - cp $plugin_gtmcrypt/$gtmcryptmfile $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile - chmod 0644 $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile - chown $owner $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile - chgrp $binuser $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile + # Install the plugin related M file + cp $plugin_gtmcrypt/$gtmcryptmfile $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile + chmod 0644 $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile + chown $owner $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile + chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile # Install other plugin files for i in $gtmcryptofiles @@ -587,7 +614,7 @@ if [ -d "$plugin_gtmcrypt" ]; then cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt chmod 0644 $gtmdist/$plugin_gtmcrypt/$i chown $owner $gtmdist/$plugin_gtmcrypt/$i - chgrp $binuser $gtmdist/$plugin_gtmcrypt/$i + chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$i done # Install gpgagent.tab @@ -596,10 +623,10 @@ if [ -d "$plugin_gtmcrypt" ]; then cat $plugin/gpgagent.tab | sed 1d >> $gtmdist/$plugin/gpgagent.tab # Tar the source files - (cd $plugin_gtmcrypt; chmod 0644 $gtmcryptsrcfiles; chown $owner $gtmcryptsrcfiles; chgrp $binuser $gtmcryptsrcfiles) - (cd $plugin_gtmcrypt; chmod 0555 $gtmcryptbldfiles; chown $owner $gtmcryptbldfiles; chgrp $binuser $gtmcryptbldfiles) + (cd $plugin_gtmcrypt; chmod 0644 $gtmcryptsrcfiles; chown $owner $gtmcryptsrcfiles; chgrp $bingroup $gtmcryptsrcfiles) + (cd $plugin_gtmcrypt; chmod 0555 $gtmcryptbldfiles; chown $owner $gtmcryptbldfiles; chgrp $bingroup $gtmcryptbldfiles) (cd $plugin_gtmcrypt; tar -cvf source.tar $gtmcryptsrcfiles >/dev/null 2>&1; mv source.tar $gtmdist/$plugin_gtmcrypt) - (cd $gtmdist/$plugin_gtmcrypt; chmod 0644 source.tar; chown $owner source.tar; chgrp $binuser source.tar) + (cd $gtmdist/$plugin_gtmcrypt; chmod 0644 source.tar; chown $owner source.tar; chgrp $bingroup source.tar) fi # Install GDE, GTMHELP, and all the percent routines @@ -614,6 +641,10 @@ if [ "$doutf8" -ne 0 ]; then if [ -d $file ]; then continue fi + # Skip gtmsecshr/dir + if [ "$file" = "gtmsecshr" -o "$file" = "gtmsecshrdir" ]; then + continue + fi # Install .o files base="`basename $file .o`" if [ "$base" != "$file" ]; then @@ -673,38 +704,39 @@ export gtm_chset # Now work on UTF-8 mode if [ "$doutf8" -ne 0 ]; then + # Enclose UTF-8 operations inside a subshell. This avoids changing the current M mode execution ( - # Ensure we ARE in UTF-8 mode - utflocale=`locale -a | grep -i en_us | grep -i utf | grep '8$'` - if [ $arch = "zos" ]; then - utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1` - fi + # Ensure we ARE in UTF-8 mode + utflocale=`locale -a | grep -i en_us | grep -i utf | grep '8$' | head -n 1` + if [ $arch = "zos" ]; then + utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1` + fi - if [ $utflocale = "" ]; then - utflocale="C" - fi - if [ $arch != "zos" ]; then - # don't set LC_CTYPE to avoid random error messages from EBCDIC utilities - LC_CTYPE=$utflocale - export LC_CTYPE - else - gtm_chset_locale=$utflocale - export gtm_chset_locale - fi - unset LC_ALL - gtm_chset="UTF-8" - export gtm_chset - if [ $arch = "ibm" ]; then - export LIBPATH=$save_icu_libpath - elif [ $arch = "zos" ]; then - # on z/OS LIBPATH is the only library search path so we should preserve it - export LIBPATH=${save_icu_libpath}:${LIBPATH} - else - LD_LIBRARY_PATH=$save_icu_libpath - export LD_LIBRARY_PATH - fi - (gtm_dist=$gtmdist/utf8; export gtm_dist; cd $gtm_dist; ./mumps -noignore *.m; $echo $?>>$gtmdist/compstat; \ - if [ $is64bit_gtm -eq 1 -o "linux" != $arch ] ; then $ldcmd $ldflags -o libgtmutil$ext *.o ; fi ) + if [ $utflocale = "" ]; then + utflocale="C" + fi + if [ $arch != "zos" ]; then + # don't set LC_CTYPE to avoid random error messages from EBCDIC utilities + LC_CTYPE=$utflocale + export LC_CTYPE + else + gtm_chset_locale=$utflocale + export gtm_chset_locale + fi + unset LC_ALL + gtm_chset="UTF-8" + export gtm_chset + if [ $arch = "ibm" ]; then + export LIBPATH=$save_icu_libpath + elif [ $arch = "zos" ]; then + # on z/OS LIBPATH is the only library search path so we should preserve it + export LIBPATH=${save_icu_libpath}:${LIBPATH} + else + LD_LIBRARY_PATH=$save_icu_libpath + export LD_LIBRARY_PATH + fi + (gtm_dist=$gtmdist/utf8; export gtm_dist; cd $gtm_dist; ./mumps -noignore *.m; $echo $?>>$gtmdist/compstat; \ + if [ $is64bit_gtm -eq 1 -o "linux" != $arch ] ; then $ldcmd $ldflags -o libgtmutil$ext *.o ; fi ) ) fi @@ -718,8 +750,10 @@ chmod 0644 $gtmdist/*.m chmod 0644 $gtmdist/*.o chown $owner $gtmdist/*.m chown $owner $gtmdist/*.o -chgrp $binuser $gtmdist/*.m -chgrp $binuser $gtmdist/*.o +chown $owner $gtmdist/*.txt +chgrp $bingroup $gtmdist/*.m +chgrp $bingroup $gtmdist/*.o +chgrp $bingroup $gtmdist/*.txt if [ "$doutf8" -ne 0 ]; then chmod 0644 $gtmdist/utf8/*.m @@ -727,14 +761,16 @@ if [ "$doutf8" -ne 0 ]; then chown $owner $gtmdist/utf8 chown $owner $gtmdist/utf8/*.m chown $owner $gtmdist/utf8/*.o - chgrp $binuser $gtmdist/utf8/*.m - chgrp $binuser $gtmdist/utf8/*.o + chown $owner $gtmdist/utf8/*.txt + chgrp $bingroup $gtmdist/utf8/*.m + chgrp $bingroup $gtmdist/utf8/*.o + chgrp $bingroup $gtmdist/utf8/*.txt fi if [ "$dogtmcrypt" -ne 0 ]; then chmod 0644 $gtmdist/plugin/gtmcrypt/*.m chown $owner $gtmdist/plugin/gtmcrypt/*.m - chgrp $binuser $gtmdist/plugin/gtmcrypt/*.m + chgrp $bingroup $gtmdist/plugin/gtmcrypt/*.m fi gtm_dist=$gtmdist @@ -747,28 +783,6 @@ else fi export gtmroutines -# Create the global directories for the help databases. - -gtmgbldir=$gtmdist/gtmhelp.gld -export gtmgbldir - -cat < /dev/null 2>&1 strip $tgtmsecshrdir/gtmsecshr > /dev/null 2>&1 +if [ -d $gtmdist/utf8 ]; then + + # Delete the gtmsecshr symlink + if [ -f $gtmdist/utf8/gtmsecshr -o -h $gtmdist/utf8/gtmsecshr ]; then + rm -f $gtmdist/utf8/gtmsecshr + fi + ln $gtmdist/gtmsecshr $gtmdist/utf8/gtmsecshr || \ + echo ln $gtmdist/gtmsecshr $gtmdist/utf8/gtmsecshr + + # Delete the gtmsecshrdir symlink + if [ -f $gtmdist/utf8/gtmsecshrdir -o -h $gtmdist/utf8/gtmsecshrdir ]; then + rm -f $gtmdist/utf8/gtmsecshrdir + fi + mkdir -p $gtmdist/utf8/gtmsecshrdir + chmod 0500 $gtmdist/utf8/gtmsecshrdir + ln $gtmdist/gtmsecshrdir/gtmsecshr $gtmdist/utf8/gtmsecshrdir/gtmsecshr || \ + echo ln $gtmdist/gtmsecshrdir/gtmsecshr $gtmdist/utf8/gtmsecshrdir/gtmsecshr + +fi + # change group ownership of wrapper if group restricted # also remove user privileges for wrapper if group changed if [ "$group" != "" ] ; then @@ -900,8 +929,8 @@ read resp if [ "$resp" = "Y" -o "$resp" = "y" ] ; then \rm -rf $binaries $pathmods $rscripts $nscripts $dirs configure \ *.gtc gtm* gde* GDE*.o _*.m _*.o mumps.dat mumps.gld geteuid $other_object_files $csh_script_files lowerc_cp\ - esnecil *.hlp core *.h libgtmrpc.a *.m gdehelp.* COPYING README.txt - \rm -rf GETPASS.o plugin PINENTRY.o GTMHELP.o + esnecil *.hlp core *.h libgtmrpc.a *.m *help.dat *help.gld COPYING README.txt + \rm -rf GETPASS.o plugin PINENTRY.o GTMHELP.o custom_errors_sample.txt if [ -d utf8 ]; then \rm -rf utf8 fi diff --git a/sr_unix/continue_handler.c b/sr_unix/continue_handler.c index 04902c2..c8cca0a 100644 --- a/sr_unix/continue_handler.c +++ b/sr_unix/continue_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,34 +12,48 @@ #include #include +#ifdef GTM_PTHREAD +# include +#endif +#include "gtm_syslog.h" +#include "gtm_limits.h" #include "gtmsiginfo.h" #include "io.h" #include "send_msg.h" #include "setterm.h" #include "continue_handler.h" +#include "gtmsecshr.h" GBLREF volatile int suspend_status; GBLREF io_pair io_std_device; +GBLREF uint4 process_id; + +error_def(ERR_REQ2RESUME); void continue_handler(int sig, siginfo_t *info, void *context) { gtmsiginfo_t sig_info; + DCL_THREADGBL_ACCESS; - error_def(ERR_REQ2RESUME); - - assert(SIGCONT == sig); + SETUP_THREADGBL_ACCESS; + FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); + /* Count how many times we get a continue-process signal (in DEBUG) */ + DEBUG_ONLY(DBGGSSHR((LOGFLAGS, "continue_handler: pid %d, continue_proc_cnt bumped from %d to %d\n", + process_id, TREF(continue_proc_cnt), TREF(continue_proc_cnt) + 1))); + DEBUG_ONLY((TREF(continue_proc_cnt))++); + assert(SIGCONT == sig); extract_signal_info(sig, info, context, &sig_info); switch(suspend_status) { case NOW_SUSPEND: /* Don't bother checking if user info is available. If info isn't available, - the value zero will be printed for pid and uid. Note that the following - message was previously put out even when the process was not suspended but - with the changes in spin locks that send continue messages "just in case", - I thought it better to restrict this message to when the process was actually - suspended and being continued. SE 7/01 - */ + * the value zero will be printed for pid and uid. Note that the following + * message was previously put out even when the process was not suspended but + * with the changes in spin locks that send continue messages "just in case", + * I thought it better to restrict this message to when the process was actually + * suspended and being continued. SE 7/01 + */ send_msg(VARLSTCNT(4) ERR_REQ2RESUME, 2, sig_info.send_pid, sig_info.send_uid); if (NULL != io_std_device.in && tt == io_std_device.in->type) setterm(io_std_device.in); diff --git a/sr_unix/continue_proc.c b/sr_unix/continue_proc.c index 005e057..29214f1 100644 --- a/sr_unix/continue_proc.c +++ b/sr_unix/continue_proc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,7 @@ #include #include +#include "gtm_limits.h" #include "io.h" #include "gtmsecshr.h" @@ -23,13 +24,19 @@ error_def(ERR_NOSUCHPROC); int continue_proc(pid_t pid) { - if (0 == kill(pid, SIGCONT)) - return(0); - else if (ESRCH == errno) + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + DEBUG_ONLY(if (!TREF(gtm_usesecshr))) /* Cause debug builds to talk to gtmsecshr more often */ { - send_msg(VARLSTCNT(5) ERR_NOSUCHPROC, 3, pid, RTS_ERROR_LITERAL("continue")); - return(ESRCH); - } else - assert(EINVAL != errno); - return(send_mesg2gtmsecshr(CONTINUE_PROCESS, pid, (char *)NULL, 0)); + if (0 == kill(pid, SIGCONT)) + return 0; + else if (ESRCH == errno) + { + send_msg(VARLSTCNT(5) ERR_NOSUCHPROC, 3, pid, RTS_ERROR_LITERAL("continue")); + return ESRCH; + } else + assert(EINVAL != errno); + } + return send_mesg2gtmsecshr(CONTINUE_PROCESS, pid, NULL, 0); } diff --git a/sr_unix/crit_wake.c b/sr_unix/crit_wake.c index c1167ce..63fb0c7 100644 --- a/sr_unix/crit_wake.c +++ b/sr_unix/crit_wake.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,8 +10,11 @@ ****************************************************************/ #include "mdef.h" + #include #include +#include "gtm_limits.h" + #include "io.h" #include "gtmsecshr.h" #include "secshr_client.h" @@ -31,8 +34,18 @@ int crit_wake (sm_uint_ptr_t pid) return(ESRCH); } else assert(EINVAL != errno); +# ifdef NOT_CURRENTLY_USED + /* The code segment below basically disabled M LOCK wakeup via gtmsecshr (via send_mesg2gtmsecshr() call below). The + * requisite gtmsecshr support is temporarily also being #ifdef'd out until the M LOCK wakeup mechanism used to wakeup + * processes with different userids can be run outside of crit. At that point, this code will be re-enabled without + * the crit-check below once again allowing improved wakeup times for differing userids without waiting for a 100ms + * poll timer to expire. + */ /* if you are in crit don't send, the other process's timer will wake it up any way */ if (0 != have_crit(CRIT_HAVE_ANY_REG)) return 0; return send_mesg2gtmsecshr(WAKE_MESSAGE, *pid, (char *)NULL, 0); +# else + return 0; +# endif } diff --git a/sr_unix/ctrlc_handler.c b/sr_unix/ctrlc_handler.c index cf74c15..583c641 100644 --- a/sr_unix/ctrlc_handler.c +++ b/sr_unix/ctrlc_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,10 @@ #include #include +#ifdef GTM_PTHREAD +# include +#endif + #include "ctrlc_handler.h" #include "std_dev_outbndset.h" @@ -21,8 +25,9 @@ void ctrlc_handler(int sig) int4 ob_char; int save_errno; - if (sig == SIGINT) + if (SIGINT == sig) { + FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); save_errno = errno; ob_char = 3; std_dev_outbndset(ob_char); diff --git a/sr_unix/db_ipcs_reset.c b/sr_unix/db_ipcs_reset.c index bf5a76c..d341e30 100644 --- a/sr_unix/db_ipcs_reset.c +++ b/sr_unix/db_ipcs_reset.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,6 +39,7 @@ #include "db_ipcs_reset.h" #include "jnl.h" #include "do_semop.h" +#include "anticipatory_freeze.h" GBLREF uint4 process_id; GBLREF ipcs_mesg db_ipcs; @@ -65,7 +66,9 @@ boolean_t db_ipcs_reset(gd_region *reg) gd_region *temp_region; char sgmnthdr_unaligned[SGMNT_HDR_LEN + 8], *sgmnthdr_8byte_aligned; sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(reg); temp_region = gv_cur_region; /* save gv_cur_region wherever there is scope for it to be changed */ gv_cur_region = reg; /* dbfilop needs gv_cur_region */ @@ -93,6 +96,7 @@ boolean_t db_ipcs_reset(gd_region *reg) return FALSE; } LSEEKREAD(udi->fd, (off_t)0, csd, SGMNT_HDR_LEN, status); + csa->hdr = csd; /* needed for DB_LSEEKWRITE when instance is frozen */ if (0 != status) { gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); @@ -102,7 +106,7 @@ boolean_t db_ipcs_reset(gd_region *reg) return FALSE; } assert((udi->semid == csd->semid) || (INVALID_SEMID == csd->semid)); - semval = semctl(udi->semid, 1, GETVAL); /* Get the counter semaphore's value */ + semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL); /* Get the counter semaphore's value */ assert(1 <= semval); if (1 < semval) { @@ -110,14 +114,14 @@ boolean_t db_ipcs_reset(gd_region *reg) assert(!reg->read_only); /* ONLINE ROLLBACK must be a read/write process */ if (!reg->read_only) { - if (0 != (save_errno = do_semop(udi->semid, 1, -1, SEM_UNDO))) + if (0 != (save_errno = do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO))) { gtm_putmsg(VARLSTCNT(8) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("db_ipcs_reset - write semaphore release"), save_errno); return FALSE; } - assert(1 == (semval = semctl(udi->semid, 0, GETVAL))); - if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO))) + assert(1 == (semval = semctl(udi->semid, DB_CONTROL_SEM, GETVAL))); + if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO))) { gtm_putmsg(VARLSTCNT(8) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("db_ipcs_reset - access control semaphore release"), save_errno); @@ -134,13 +138,13 @@ boolean_t db_ipcs_reset(gd_region *reg) * BEFORE removing the semaphore as otherwise the waiting process in db_init will notice the semaphore removal * first and will read the file header and can potentially notice the stale semid/shmid values. */ - if (!reg->read_only) + if (!reg->read_only DEBUG_ONLY(&& !TREF(gtm_usesecshr))) { csd->semid = INVALID_SEMID; csd->shmid = INVALID_SHMID; csd->gt_sem_ctime.ctime = 0; csd->gt_shm_ctime.ctime = 0; - LSEEKWRITE(udi->fd, (off_t)0, csd, SGMNT_HDR_LEN, status); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, csd, SGMNT_HDR_LEN, status); if (0 != status) { gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); @@ -156,12 +160,13 @@ boolean_t db_ipcs_reset(gd_region *reg) db_ipcs.gt_sem_ctime = 0; db_ipcs.gt_shm_ctime = 0; if (!get_full_path((char *)DB_STR_LEN(reg), db_ipcs.fn, (unsigned int *)&db_ipcs.fn_len, - MAX_TRANS_NAME_LEN, &ustatus)) + GTM_PATH_MAX, &ustatus)) { gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, DB_LEN_STR(reg), ustatus); return FALSE; } db_ipcs.fn[db_ipcs.fn_len] = 0; + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa); if (0 != (status = send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0))) { gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); @@ -180,6 +185,7 @@ boolean_t db_ipcs_reset(gd_region *reg) } } udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; CLOSEFILE_RESET(udi->fd, status); /* resets "udi->fd" to FD_INVALID */ if (0 != status) gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); diff --git a/sr_unix/db_snapshot.h b/sr_unix/db_snapshot.h index 71d6f69..6395772 100644 --- a/sr_unix/db_snapshot.h +++ b/sr_unix/db_snapshot.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,10 @@ #define SNAPSHOT_HDR_LABEL "SNAPSHOTV1" +#define SET_FAST_INTEG(X) ((X)->proc_property |= 0x0001) +#define SET_NORM_INTEG(X) ((X)->proc_property &= 0xfffe) +#define FASTINTEG_IN_PROG(X) ((X)->proc_property & 0x0001) + /* Possible states when snapshot is being init'ed */ typedef enum { @@ -60,7 +64,7 @@ typedef struct util_snapshot_struct { unsigned char *master_map; sgmnt_data_ptr_t header; - uint4 native_size; + gtm_uint64_t native_size; } util_snapshot_t; typedef struct snapshot_context_struct @@ -77,6 +81,10 @@ typedef struct snapshot_context_struct int4 shadow_vbn; char shadow_file[GTM_PATH_MAX]; ss_proc_status cur_state; + /* the property of process triggering snapshot. At present only last bit is used to indicate property of integ process: + * 0x0000: Normal Integ, 0x0001:Fast Integ + */ + uint4 proc_property; } snapshot_context_t; typedef struct snapshot_filehdr_struct diff --git a/sr_unix/dbcertify_dbfilop.c b/sr_unix/dbcertify_dbfilop.c index 90fa1b8..024a276 100644 --- a/sr_unix/dbcertify_dbfilop.c +++ b/sr_unix/dbcertify_dbfilop.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2010 Fidelity Information Services, LLC. * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,6 +38,14 @@ #include "is_file_identical.h" #include "error.h" #include "dbcertify.h" +#include "jnl.h" +#include "anticipatory_freeze.h" + +error_def(ERR_DBFILOPERR); +error_def(ERR_DBOPNERR); +error_def(ERR_DBPREMATEOF); +error_def(ERR_SYSCALL); +error_def(ERR_TEXT); void dbcertify_dbfilop(phase_static_area *psa) { @@ -46,12 +54,6 @@ void dbcertify_dbfilop(phase_static_area *psa) int4 save_errno; int fstat_res; - error_def(ERR_DBFILOPERR); - error_def(ERR_DBOPNERR); - error_def(ERR_DBPREMATEOF); - error_def(ERR_SYSCALL); - error_def(ERR_TEXT); - /* assert((dba_mm == psa->fc->file_type) || (dba_bg == psa->fc->file_type)); not always set in unix */ udi = (unix_db_info *)psa->fc->file_info; switch(psa->fc->op) @@ -80,7 +82,7 @@ void dbcertify_dbfilop(phase_static_area *psa) psa->fc->op_pos, psa->fc->op_len))); GTM64_ONLY(DBC_DEBUG(("DBC_DEBUG: -- Writing database op_pos = %ld op_len = %d\n", psa->fc->op_pos, psa->fc->op_len))); - LSEEKWRITE(udi->fd, + DB_LSEEKWRITE(NULL, NULL, udi->fd, (off_t)(psa->fc->op_pos - 1) * DISK_BLOCK_SIZE, psa->fc->op_buff, psa->fc->op_len, diff --git a/sr_unix/dbcertify_deferred_signal_handler.c b/sr_unix/dbcertify_deferred_signal_handler.c index 1605bec..146b958 100644 --- a/sr_unix/dbcertify_deferred_signal_handler.c +++ b/sr_unix/dbcertify_deferred_signal_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2010 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,9 +33,9 @@ #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "gdsblkops.h" +#include "have_crit.h" #include "dbcertify.h" -GBLREF VSIG_ATOMIC_T forced_exit; GBLREF int4 exi_condition; GBLREF int forced_exit_err; GBLREF uint4 process_id; @@ -45,16 +45,16 @@ GBLREF boolean_t exit_handler_active; LITREF gtmImageName gtmImageNames[]; +error_def(ERR_KILLBYSIG); +error_def(ERR_KILLBYSIGUINFO); +error_def(ERR_KILLBYSIGSINFO1); +error_def(ERR_KILLBYSIGSINFO2); +error_def(ERR_KILLBYSIGSINFO3); + void dbcertify_deferred_signal_handler(void) { - error_def(ERR_KILLBYSIG); - error_def(ERR_KILLBYSIGUINFO); - error_def(ERR_KILLBYSIGSINFO1); - error_def(ERR_KILLBYSIGSINFO2); - error_def(ERR_KILLBYSIGSINFO3); - - /* To avoid nested calls to this routine, we set forced_exit to FALSE at the very beginning */ - forced_exit = FALSE; + /* To avoid nested calls to this routine, we advance the status of forced_exit. */ + SET_FORCED_EXIT_STATE_ALREADY_EXITING; if (exit_handler_active) { @@ -68,36 +68,38 @@ void dbcertify_deferred_signal_handler(void) /* note can't use switch here because ERR_xxx are not defined as constants */ if (ERR_KILLBYSIG == forced_exit_err) { - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); } else if (ERR_KILLBYSIGUINFO == forced_exit_err) { - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, - signal_info.signal, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, + signal_info.signal, signal_info.send_pid, signal_info.send_uid); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.send_pid, signal_info.send_uid); } else if (ERR_KILLBYSIGSINFO1 == forced_exit_err) { - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr); } else if (ERR_KILLBYSIGSINFO2 == forced_exit_err) { - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr); } else if (ERR_KILLBYSIGSINFO3 == forced_exit_err) { - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.bad_vadr); } else { - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); } /* Drive the exit handler to terminate */ exit(-exi_condition); diff --git a/sr_unix/dbcertify_signal_handler.c b/sr_unix/dbcertify_signal_handler.c index f92cee6..d28368d 100644 --- a/sr_unix/dbcertify_signal_handler.c +++ b/sr_unix/dbcertify_signal_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2012 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,7 +53,6 @@ GBLDEF siginfo_t exi_siginfo; GBLDEF gtm_sigcontext_t exi_context; -GBLREF VSIG_ATOMIC_T forced_exit; GBLREF int4 forced_exit_err; GBLREF int4 exi_condition; GBLREF enum gtmImageTypes image_type; @@ -133,15 +132,15 @@ 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) && (psa_gbl->dbc_critical || exit_handler_active)) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ return; } exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); dont_want_core = TRUE; break; case SIGQUIT: /* Handle SIGQUIT specially which we ALWAYS want to defer if possible as it is always sent */ @@ -169,9 +168,9 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context) GTMASSERT; } /* 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) && (psa_gbl->dbc_critical || exit_handler_active)) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ return; } @@ -179,32 +178,36 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context) switch(signal_info.infotype) { case GTMSIGINFO_NONE: - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, sig); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, sig); break; case GTMSIGINFO_USER: - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.send_pid, signal_info.send_uid); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, + GTMIMAGENAMETXT(image_type), process_id, sig, + signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, + GTMIMAGENAMETXT(image_type), process_id, sig, + signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, + GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, + GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); break; } break; @@ -212,15 +215,15 @@ 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) && (psa_gbl->dbc_critical || exit_handler_active)) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ return; } exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); dont_want_core = TRUE; break; #endif @@ -230,47 +233,51 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context) { case GTMSIGINFO_NONE: exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, sig); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, + GTMIMAGENAMETXT(image_type), process_id, sig); break; case GTMSIGINFO_USER: /* 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) && (psa_gbl->dbc_critical || exit_handler_active)) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ need_core = TRUE; gtm_fork_n_core(); /* Generate "virgin" core while we can */ return; } exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.send_pid, signal_info.send_uid); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, + GTMIMAGENAMETXT(image_type), process_id, sig, + signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, + GTMIMAGENAMETXT(image_type), process_id, sig, + signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, + GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: exit_state = EXIT_IMMED; - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, + GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr); break; default: exit_state = EXIT_IMMED; @@ -278,8 +285,8 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context) } if (0 != signal_info.sig_err) { - send_msg(VARLSTCNT(1) signal_info.sig_err); - gtm_putmsg(VARLSTCNT(1) signal_info.sig_err); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) signal_info.sig_err); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) signal_info.sig_err); } break; } /* switch (sig) */ diff --git a/sr_unix/dbfilop.c b/sr_unix/dbfilop.c index a10762c..b548d0c 100644 --- a/sr_unix/dbfilop.c +++ b/sr_unix/dbfilop.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,9 +33,17 @@ #include "iosp.h" #include "is_file_identical.h" #include "dbfilop.h" +#include "anticipatory_freeze.h" +#include "jnl.h" GBLREF gd_region *gv_cur_region; +error_def(ERR_DBFILOPERR); +error_def(ERR_DBNOTGDS); +error_def(ERR_DBOPNERR); +error_def(ERR_DBPREMATEOF); +error_def(ERR_TEXT); +ZOS_ONLY(error_def(ERR_BADTAG);) uint4 dbfilop(file_control *fc) { @@ -46,13 +54,6 @@ uint4 dbfilop(file_control *fc) sgmnt_data_ptr_t csd; ZOS_ONLY(int realfiletag;) - error_def(ERR_DBFILOPERR); - error_def(ERR_DBNOTGDS); - error_def(ERR_DBOPNERR); - error_def(ERR_DBPREMATEOF); - error_def(ERR_TEXT); - ZOS_ONLY(error_def(ERR_BADTAG);) - /* assert((dba_mm == fc->file_type) || (dba_bg == fc->file_type)); not always set in unix */ udi = (unix_db_info *)fc->file_info; switch(fc->op) @@ -88,7 +89,7 @@ uint4 dbfilop(file_control *fc) || (0 == ((sgmnt_data_ptr_t)fc->op_buff)->acc_meth))) GTMASSERT; assert((1 != fc->op_pos) || fc->op_len <= SIZEOF_FILE_HDR(fc->op_buff)); - LSEEKWRITE(udi->fd, + DB_LSEEKWRITE(&udi->s_addrs, udi->fn, udi->fd, (off_t)(fc->op_pos - 1) * DISK_BLOCK_SIZE, fc->op_buff, fc->op_len, @@ -111,7 +112,8 @@ uint4 dbfilop(file_control *fc) return ERR_DBOPNERR; #ifdef __MVS__ if (-1 == gtm_zos_tag_to_policy(udi->fd, TAG_BINARY, &realfiletag)) - TAG_POLICY_SEND_MSG((char_ptr_t)gv_cur_region->dyn.addr->fname, errno, realfiletag, TAG_BINARY); + TAG_POLICY_SEND_MSG((char_ptr_t)gv_cur_region->dyn.addr->fname, errno, + realfiletag, TAG_BINARY); #endif set_gdid_from_stat(&udi->fileid, &stat_buf); udi->raw = (S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode)); diff --git a/sr_unix/dbinit_ch.c b/sr_unix/dbinit_ch.c index 4e29918..f2a2f53 100644 --- a/sr_unix/dbinit_ch.c +++ b/sr_unix/dbinit_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,7 @@ #include "gdsfhead.h" #include "error.h" #include "filestruct.h" +#include "gvcst_protos.h" #include "jnl.h" #include "do_semop.h" #include "mmseg.h" @@ -36,30 +37,36 @@ #include "have_crit.h" GBLREF gd_region *db_init_region; -GBLREF boolean_t sem_incremented; CONDITION_HANDLER(dbinit_ch) { - unix_db_info *udi; - gd_segment *seg; - sgmnt_addrs *csa; - int rc, lcl_new_dbinit_ipc; - START_CH; if (SUCCESS == SEVERITY || INFO == SEVERITY) { PRN_ERROR; CONTINUE; } + db_init_err_cleanup(FALSE); + NEXTCH +} + +void db_init_err_cleanup(boolean_t retry_dbinit) +{ + unix_db_info *udi; + gd_segment *seg; + sgmnt_addrs *csa; + int rc, lcl_new_dbinit_ipc; + + assert(NULL != db_init_region); seg = db_init_region->dyn.addr; udi = NULL; if (NULL != seg->file_cntl) udi = FILE_INFO(db_init_region); if (NULL != udi) { - if (FD_INVALID != udi->fd) + if (FD_INVALID != udi->fd && !retry_dbinit) CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ - assert(FD_INVALID == udi->fd); + assert(FD_INVALID == udi->fd || retry_dbinit); csa = &udi->s_addrs; # ifdef GTM_CRYPT if (NULL != csa->encrypted_blk_contents) @@ -68,11 +75,10 @@ CONDITION_HANDLER(dbinit_ch) csa->encrypted_blk_contents = NULL; } # endif - if (NULL != csa->hdr) + if ((NULL != csa->hdr) && (dba_mm == db_init_region->dyn.addr->acc_meth)) { - if (dba_mm == db_init_region->dyn.addr->acc_meth) - munmap((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0])); - csa->hdr = (sgmnt_data_ptr_t)NULL; + assert((NULL != csa->db_addrs[1]) && (csa->db_addrs[1] > csa->db_addrs[0])); + munmap((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0])); } if (NULL != csa->jnl) { @@ -84,48 +90,45 @@ CONDITION_HANDLER(dbinit_ch) shmdt((caddr_t)csa->nl); csa->nl = (node_local_ptr_t)NULL; } - lcl_new_dbinit_ipc = TREF(new_dbinit_ipc); - if (lcl_new_dbinit_ipc) + if (udi->new_shm && (INVALID_SHMID != udi->shmid)) { - if ((lcl_new_dbinit_ipc & NEW_DBINIT_SHM_IPC_MASK) && (INVALID_SHMID != udi->shmid)) - { - shm_rmid(udi->shmid); - udi->shmid = INVALID_SHMID; - } - if ((lcl_new_dbinit_ipc & NEW_DBINIT_SEM_IPC_MASK) && (INVALID_SEMID != udi->semid)) - { - sem_rmid(udi->semid); - udi->semid = INVALID_SEMID; - udi->grabbed_access_sem = FALSE; - } - TREF(new_dbinit_ipc) = 0; + shm_rmid(udi->shmid); + udi->shmid = INVALID_SHMID; + udi->new_shm = FALSE; } - if (sem_incremented) + if (udi->new_sem && (INVALID_SEMID != udi->semid)) { - if (INVALID_SEMID != udi->semid) - { - if (FALSE == db_init_region->read_only) - do_semop(udi->semid, 1, -1, SEM_UNDO); /* decrement the read-write sem */ - do_semop(udi->semid, 0, -1, SEM_UNDO); /* release the startup-shutdown sem */ - } - sem_incremented = FALSE; + sem_rmid(udi->semid); + udi->semid = INVALID_SEMID; + udi->new_sem = FALSE; + udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; + } + if (udi->counter_acc_incremented) + { + assert((INVALID_SEMID != udi->semid) && !db_init_region->read_only); + do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT); /* decrement the read-write sem */ + udi->counter_acc_incremented = FALSE; + } + if (udi->grabbed_access_sem) + { + do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO | IPC_NOWAIT); /* release the startup-shutdown sem */ + udi->grabbed_access_sem = FALSE; } - if (udi->grabbed_ftok_sem) - ftok_sem_release(db_init_region, TRUE, TRUE); - if (!IS_GTCM_GNP_SERVER_IMAGE) /* gtcm_gnp_server reuses file_cntl */ + ftok_sem_release(db_init_region, udi->counter_ftok_incremented, TRUE); + else if (udi->counter_ftok_incremented) + do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT); + udi->counter_ftok_incremented =FALSE; + udi->grabbed_ftok_sem = FALSE; + if (!IS_GTCM_GNP_SERVER_IMAGE && !retry_dbinit) /* gtcm_gnp_server reuses file_cntl */ { free(seg->file_cntl->file_info); free(seg->file_cntl); seg->file_cntl = NULL; } } - /* Reset intrpt_ok_state to OK_TO_INTERRUPT in case we got called (due to an rts_error) with intrpt_ok_state - * being set to INTRPT_IN_GVCST_INIT. - * We should actually be calling RESTORE_INTRPT_OK_STATE macro but since we don't have access to local variable - * save_intrpt_ok_state, set intrpt_ok_state directly. - */ - assert((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) || (INTRPT_IN_GVCST_INIT == intrpt_ok_state)); - intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; - NEXTCH; + /* Enable interrupts in case we are here with intrpt_ok_state == INTRPT_IN_GVCST_INIT due to an rts error. */ + if (!retry_dbinit) + ENABLE_INTERRUPTS(INTRPT_IN_GVCST_INIT); } diff --git a/sr_unix/dec_err.c b/sr_unix/dec_err.c index b89f35f..d5537b6 100644 --- a/sr_unix/dec_err.c +++ b/sr_unix/dec_err.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,7 +19,6 @@ #include "gtmmsg.h" GBLREF bool dec_nofac; -GBLREF va_list last_va_list_ptr; void dec_err(uint4 argcnt, ...) { @@ -29,7 +28,9 @@ void dec_err(uint4 argcnt, ...) const err_msg *em; char msgbuff[2048]; mstr msgstr; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; util_out_print(0, RESET, 0); /* reset the buffer */ VAR_START(var, argcnt); assert (argcnt >= 1); @@ -37,11 +38,7 @@ void dec_err(uint4 argcnt, ...) ec = err_check(err); em = NULL; if (ec) - { - assert((err & FACMASK(ec->facnum)) && (MSGMASK(err, ec->facnum) <= ec->msg_cnt)); - j = MSGMASK(err, ec->facnum); - em = ec->fst_msg + j - 1; - } + GET_MSG_INFO(err, ec, em); msgstr.addr = msgbuff; msgstr.len = SIZEOF(msgbuff); gtm_getmsg(err, &msgstr); @@ -58,7 +55,7 @@ void dec_err(uint4 argcnt, ...) } else count = 0; util_out_print_vaparm(msgstr.addr, FLUSH, var, count); - va_end(last_va_list_ptr); + va_end(TREF(last_va_list_ptr)); } va_end(var); } diff --git a/sr_unix/deferred_signal_handler.c b/sr_unix/deferred_signal_handler.c index 8899665..5d61b3c 100644 --- a/sr_unix/deferred_signal_handler.c +++ b/sr_unix/deferred_signal_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,7 +31,6 @@ #include "io.h" #endif -GBLREF VSIG_ATOMIC_T forced_exit; GBLREF int4 exi_condition; GBLREF void (*call_on_signal)(); GBLREF int forced_exit_err; @@ -57,8 +56,8 @@ void deferred_signal_handler(void) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - /* To avoid nested calls to this routine, we set forced_exit to FALSE at the very beginning */ - forced_exit = FALSE; + /* To avoid nested calls to this routine, progress the forced_exit state. */ + SET_FORCED_EXIT_STATE_ALREADY_EXITING; if (exit_handler_active) { @@ -72,40 +71,42 @@ void deferred_signal_handler(void) /* note can't use switch here because ERR_xxx are not defined as constants */ if (ERR_KILLBYSIG == forced_exit_err) { - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), + process_id, signal_info.signal); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), + process_id, signal_info.signal); } else if (ERR_KILLBYSIGUINFO == forced_exit_err) { - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.send_pid, signal_info.send_uid); } else if (ERR_KILLBYSIGSINFO1 == forced_exit_err) { - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr); } else if (ERR_KILLBYSIGSINFO2 == forced_exit_err) { - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.int_iadr); } else if (ERR_KILLBYSIGSINFO3 == forced_exit_err) { - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal, signal_info.bad_vadr); } else if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt) { /* No HALT messages if quiet halt is requested */ - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); } assert(OK_TO_INTERRUPT); /* Signal intent to exit BEFORE driving condition handlers. This avoids checks that will otherwise fail (for example - * if mdb_condition_handler/preemptive_ch gets called below, that could invoke the RESET_GV_TARGET macro which in turn + * if mdb_condition_handler/preemptive_db_clnup gets called below, that could invoke the RESET_GV_TARGET macro which in turn * would assert that gv_target->gd_csa is equal to cs_addrs. This could not be true in case we were in mainline code * that was interrupted by the flush timer for a different region which in turn was interrupted by an external signal * that would drive us to exit. Setting the "process_exiting" variable causes those csa checks to pass. diff --git a/sr_unix/dircompare.m.txt b/sr_unix/dircompare.m.txt index fb3359f..a0fd6b1 100644 --- a/sr_unix/dircompare.m.txt +++ b/sr_unix/dircompare.m.txt @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2011 Fidelity Information Services, Inc ; +; Copyright 2011, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -9,30 +9,50 @@ ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; dircompare -; mumps -r dircompare , where filename -; is the output of ls -lR -; of pro in either the build directory or the install directory. -; If the deletefilename is NOP then there are no delete entries. -; If the addfilename is NOP then there are no add entries. -; If the deletedirectory is NOP then there are no deldirectory entries. -; The first few lines of the three files are the copyright lines. Other comment lines may be included after -; the copyright lines and all are eaten before the data is read into the database. No spaces are allowed between the comments -; lines. -; The format of the deletefile is shown below. Its purpose is to delete files from the list of permissions and files -; which are written to standard output. -; The format of the addfile is shown below. Its purpose is to add files to the list of permissions and files -; which are written to standard output. To add files before an existing entry, the tryadd function is used. +; The purpose of this routine is to take the ls -lR output of the regular +; GT.M development directory and massage it to look like what we expect from +; the installed directory +; +; mumps -r dircompare +; +; is the output of ls -lR of pro in either the build directory or the install directory +; For each of the following NOP indicates that there are none +; - delete entries - aka files missing from PRO +; - added entries - aka files added on to of PRO +; - deleted directories - aka dirs missing from PRO +; +; The first few lines of the three files are the copyright lines. Other +; comment lines may be included after ; the copyright lines and all are eaten +; before the data is read into the database. No spaces are allowed between the +; comments lines. +; +; +; The format of the deletefile is shown below. +; Its purpose is to delete files from the list of permissions and files which +; are written to standard output. +; +; +; The format of the addfile is shown below. +; Its purpose is to add files to the list of permissions and files which are +; written to standard output. To add files before an existing entry, the tryadd +; function is used. +; ; To add files after the last file in a directory, the same format is used in the addfile, but the filename must be ; after the last entry (i.e. must not exist). The tryinsert function adds files to the end of a directory. It ; assumes that at least one file exists in the directory. An example of both forms is given prior to the loadadd function. - +; +; +; The format of the deldirfile is shown below. +; dircompare ; set etrap so we get debug info and exit mumps - set $etrap="use $P write $zstatus,!,""Error line: "" zprint @$zposition halt" + set $etrap="use $P write $zstatus,!,""Error line: "" zprint @$zposition s x=$zjobexam() halt" ; read the delete file into global memory kill ^delentries kill ^addentries kill ^deldirentries + kill ^debug + ; Parse command line if 4'=$LENGTH($ZCMDLINE," ") do . write "Usage: dircompare ",! halt set infile=$PIECE($ZCMDLINE," ",1) @@ -53,15 +73,17 @@ dircompare set (directorydelete,nonewline)=1 open infile:(readonly) use infile:exception="GOTO EOF" - for read dirname,x do; read a directory and eat the next line which is size info; ; terminated by exception="GOTO EOF" + for read dirname,x do ; read a directory and eat the next line which is size info; ; terminated by exception="GOTO EOF" + . set ^debug($i(readdirloop))=dirname . if $DATA(^deldirentries(dirname)) set directorydelete=1 ; flag directory to delete . else do .. use $P .. if 'nonewline write ! .. write dirname,! - .. set (^addmatch,directorydelete,nonewline)=0 + .. set (directorydelete,nonewline)=0 + . set ^debug(readdirloop,dirname,"state")=$select(directorydelete=1:"delete me",1:"use me") . for use infile read x do quit:""=x - .. if ""=x do quit; if it is a blank line then tryinsert + .. if ""=x do quit ; if it is a blank line then tryinsert ... ;in case a file(s) need(s) to be added to the end of the directory ... if $DATA(^addentries(dirname)) do tryinsert(dirname) .. if directorydelete quit @@ -81,6 +103,8 @@ dircompare EOF if ('directorydelete&$DATA(^addentries(dirname))) do tryinsert(dirname) + for set unused=$order(^addentries($get(unused))) quit:unused="" do + . use $p write !,unused,! do tryinsert(unused) close infile halt @@ -89,18 +113,28 @@ trydelete(dirname,filename) tryadd(dirname,filename,infile) set ret=0 - if $DATA(^addentries(dirname,filename)),$increment(^addmatch) do + if $DATA(^addentries(dirname,filename)) do . use $P - . for j=1:1:^addentries(dirname,filename) write ^addentries(dirname,filename,j),! + . for j=1:1:^addentries(dirname,filename) do + . . write ^addentries(dirname,filename,j),! + . . set ^debug(readdirloop,dirname,$i(action))=$R + . set ^addentries(dirname)=$increment(^addentries(dirname),-j) + . kill ^addentries(dirname,filename) + . if $data(^addentries(dirname))<10 kill ^addentries(dirname) . use infile . quit quit tryinsert(dirname) set nummatch=^addentries(dirname) - if nummatch>^addmatch&$DATA(^addentries(dirname,"zzz_insert")) do + if $DATA(^addentries(dirname,"zzz_insert")) do . use $P - . for j=1:1:^addentries(dirname,"zzz_insert") write ^addentries(dirname,"zzz_insert",j),! + . for j=1:1:^addentries(dirname,"zzz_insert") do + . . write ^addentries(dirname,"zzz_insert",j),! + . . set ^debug(readdirloop,dirname,$i(action))=$R + . set ^addentries(dirname)=$increment(^addentries(dirname),-j) + . kill ^addentries(dirname,"zzz_insert") + . if $data(^addentries(dirname))<10 kill ^addentries(dirname) . use infile quit @@ -174,10 +208,14 @@ loaddelete(fdelete) close fdelete quit -; loadadd(fadd) - fadd is the name of the add file to load +; loadadd(fadd) +; - fadd is the name of the add file to load +; ; assume addfile starts with a directory name follwed by a colon and has a blank line before each subdirectory ; assumes the last line is not blank. It is ok to have a directory with no entries under it +; ; the field separators must be a % +; ; the add entries start with a existing file before which the following permission and file will be inserted ; The exception to this rule is if the file or files is to be entered after the last entry in a directory ; In this case, you must use the file name zzz_insert which will not match any file in the directory @@ -258,15 +296,24 @@ loaddeldir(fdeldir) use $P quit +; Ensure that the routine uses a file as input only once and that the target file exists +; f - is the name of a local which was just set by the CLI parser uniquefile(f) - new fn,ok - set ok=1 - set same=0 - for fn="infile","deletefile","addfile","deletedirfile" do - . if f'=fn,$DATA(@fn),@f=@fn set ok=0 write !,f," and ",fn," files (",@f,") can't be the same",! set same=1 quit - if same quit ok - if ""=$ZSEARCH(@f) set ok=0 write !,f," file: ",@f," does not exist",! - quit ok + new fn,status,same + set status=1 + for fn="infile","deletefile","addfile","deldirfile" do + . ; Skip when f and fn point to the same local + . quit:f=fn + . ; If the local (fn points to) DOES NOT exist in memory, quit + . quit:$data(@fn)=0 + . ; The local (fn points to) exists in memory, quit if f and fn DO NOT point to the same file + . quit:@f'=@fn + . set status=0,same=1 + . write !,f," and ",fn," files (",@f,") can't be the same",! + . quit + if $data(same) quit status + if ""=$ZSEARCH(@f) set status=0 write !,f," file: ",@f," does not exist",! + quit status getext(file) ; return the extension of the filename or null if none diff --git a/sr_unix/disk_block_available.c b/sr_unix/disk_block_available.c index 649bd9b..5b7a518 100644 --- a/sr_unix/disk_block_available.c +++ b/sr_unix/disk_block_available.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,10 +42,11 @@ #endif +#include "have_crit.h" #include "eintr_wrappers.h" #include "disk_block_available.h" -int4 disk_block_available(int fd, GTM_BAVAIL_TYPE *ret, boolean_t fill_unix_holes) +int4 disk_block_available(int fd, gtm_uint64_t *ret, boolean_t fill_unix_holes) { struct stat fstat_buf; struct statvfs fstatvfs_buf; @@ -54,13 +55,13 @@ int4 disk_block_available(int fd, GTM_BAVAIL_TYPE *ret, boolean_t fill_unix_hole FSTATVFS_FILE(fd, &fstatvfs_buf, status); if (-1 == status) return errno; - *ret = (GTM_BAVAIL_TYPE)((fstatvfs_buf.f_frsize / DISK_BLOCK_SIZE) * fstatvfs_buf.f_bavail); + *ret = (gtm_uint64_t)((fstatvfs_buf.f_frsize / DISK_BLOCK_SIZE) * fstatvfs_buf.f_bavail); if (fill_unix_holes) { FSTAT_FILE(fd, &fstat_buf, status); if (-1 == status) return errno; - *ret -= (GTM_BAVAIL_TYPE)(DEV_BSIZE / DISK_BLOCK_SIZE + *ret -= (gtm_uint64_t)(DEV_BSIZE / DISK_BLOCK_SIZE * (DIVIDE_ROUND_UP(fstat_buf.st_size, DEV_BSIZE) - fstat_buf.st_blocks)); } return 0; diff --git a/sr_unix/disk_block_available.h b/sr_unix/disk_block_available.h index 3ecfd49..ae144d0 100644 --- a/sr_unix/disk_block_available.h +++ b/sr_unix/disk_block_available.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 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 DISK_BLOCK_AVAILABLE_INCLUDED #define DISK_BLOCK_AVAILABLE_INCLUDED -int4 disk_block_available(int fd, GTM_BAVAIL_TYPE *ret, boolean_t fill_unix_holes); +int4 disk_block_available(int fd, gtm_uint64_t *ret, boolean_t fill_unix_holes); #endif /* DISK_BLOCK_AVAILABLE_INCLUDED */ diff --git a/sr_unix/do_semop.c b/sr_unix/do_semop.c index 67ac443..d43cce0 100644 --- a/sr_unix/do_semop.c +++ b/sr_unix/do_semop.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,9 +11,10 @@ #include "mdef.h" -#include "gtm_ipc.h" -#include #include +#include +#include "gtm_stdlib.h" +#include "gtm_ipc.h" #include "gtm_fcntl.h" #include "do_semop.h" diff --git a/sr_unix/dollarh.c b/sr_unix/dollarh.c index 867261d..3a010d8 100644 --- a/sr_unix/dollarh.c +++ b/sr_unix/dollarh.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,47 +11,44 @@ #include "mdef.h" -#include #include "gtm_time.h" #include #include "dollarh.h" #include "gtmimagename.h" - -GBLREF boolean_t run_time; -GBLREF boolean_t blocksig_initialized; -GBLREF sigset_t block_sigsent; +#include "have_crit.h" void dollarh(time_t intime, uint4 *days, time_t *seconds) { uint4 tdays; int isdst; struct tm *ttime; - sigset_t savemask; + time_t mktime_ret; #ifdef DEBUG static uint4 old_days = 0, old_seconds = 0; static time_t old_intime = 0; static int old_isdst; #endif - /* When dollarh() is processing and a signal occurs, the signal processing can eventually lead to nested system time + /* The comment below is now obsolete as GTM-6802 took care of protecting time-related functions from nested + * invocations, making the presence of sigprocmasks unnecessary. If several years pass without more incidents + * of time-caused hangs, remove the comment. (SOPINI, 2013/02/20) + * + * When dollarh() is processing and a signal occurs, the signal processing can eventually lead to nested system time * routine calls. If a signal arrives during a system time call (__tzset() in linux) we end up in a generic signal * handler which invokes syslog which in turn tries to call the system time routine (__tz_convert() in linux) which * seems to get suspended presumably waiting for the same interlock that __tzset() has already obtained. A work around * is to block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) during the function and then restore them * at the end. [C9D06-002271] [C9I03-002967]. */ - assert(blocksig_initialized); /* the set of blocking signals should be initialized at process startup */ - if (blocksig_initialized) /* In pro, dont take chances and handle case where it is not initialized */ - sigprocmask(SIG_BLOCK, &block_sigsent, &savemask); - ttime = localtime(&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 UCT other than hourly */ *seconds = (time_t)(ttime->tm_hour * HOUR) + (ttime->tm_min * MINUTE) + ttime->tm_sec; isdst = ttime->tm_isdst; - ttime = gmtime(&intime); /* represent intime as UCT */ - ttime->tm_isdst = isdst; /* use localtime() to tell mktime whether daylight savings needs to be applied */ - tdays = (uint4)((intime + (time_t)difftime(intime, mktime(ttime))) / ONEDAY) + DAYS; /* adjust relative to UTC */ + GTM_GMTIME(ttime, &intime); /* represent intime as UCT */ + 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 */ - if (blocksig_initialized) - sigprocmask(SIG_SETMASK, &savemask, NULL); /* 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, diff --git a/sr_unix/dse.c b/sr_unix/dse.c index 88c937a..7ba0a4a 100644 --- a/sr_unix/dse.c +++ b/sr_unix/dse.c @@ -13,6 +13,7 @@ #include "main_pragma.h" #include +#include #include "gtm_inet.h" #include "mlkdef.h" @@ -68,10 +69,14 @@ #include "wbox_test_init.h" #include "gtmio.h" #include "have_crit.h" +#include "gt_timers_add_safe_hndlrs.h" +#include "continue_handler.h" #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" +#include "gtm_conv.h" +GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ #endif GBLREF gd_region *gv_cur_region; @@ -100,7 +105,6 @@ static void display_prompt(void); static readonly char prompt[]="DSE> "; error_def(ERR_CTRLC); - int main(int argc, char *argv[]) { DCL_THREADGBL_ACCESS; @@ -115,8 +119,9 @@ int main(int argc, char *argv[]) op_open_ptr = op_open; patch_curr_blk = get_dir_root(); err_init(util_base_ch); + UNICODE_ONLY(gtm_strToTitle_ptr = >m_strToTitle); GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ - sig_init(generic_signal_handler, dse_ctrlc_handler, suspsigs_handler); + sig_init(generic_signal_handler, dse_ctrlc_handler, suspsigs_handler, continue_handler); atexit(util_exit_handler); SET_LATCH_GLOBAL(&defer_latch, LOCK_AVAILABLE); get_page_size(); @@ -125,7 +130,9 @@ int main(int argc, char *argv[]) getjobname(); INVOKE_INIT_SECSHR_ADDRS; getzdir(); + gtm_chk_dist(argv[0]); prealloc_gt_timers(); + gt_timers_add_safe_hndlrs(); initialize_pattern_table(); gvinit(); region_init(FALSE); @@ -135,7 +142,7 @@ int main(int argc, char *argv[]) util_out_print("Region!_!AD!/", TRUE, REG_LEN_STR(gv_cur_region)); cli_lex_setup(argc, argv); CREATE_DUMMY_GBLDIR(gd_header, original_header, gv_cur_region, gd_map, gd_map_top); - gtm_chk_dist(argv[0]); + OPERATOR_LOG_MSG; # ifdef DEBUG if ((gtm_white_box_test_case_enabled && (WBTEST_SEMTOOLONG_STACK_TRACE == gtm_white_box_test_case_number) )) { @@ -144,6 +151,9 @@ int main(int argc, char *argv[]) csa = &FILE_INFO(gv_cur_region)->s_addrs; cnl = csa->nl; cnl->wbox_test_seq_num = 1; /*Signal the first step and wait here*/ + /* The signal to the shell. MUPIP must not start BEFORE DSE */ + util_out_print("DSE is ready. MUPIP can start. Note: This message is a part of WBTEST_SEMTOOLONG_STACK_TRACE test. " + "It will not appear in PRO version.", TRUE); while (2 != cnl->wbox_test_seq_num) /*Wait for another process to get hold of the semaphore and signal next step*/ LONG_SLEEP(10); } diff --git a/sr_unix/dse_cmd.c b/sr_unix/dse_cmd.c index 1773ff5..2c2a81d 100644 --- a/sr_unix/dse_cmd.c +++ b/sr_unix/dse_cmd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,6 +37,7 @@ #include "dse_exit.h" #include "util_spawn.h" +#include "util_help.h" #include "dse_cmd_disallow.h" /************************************************************* @@ -109,7 +110,7 @@ static readonly CLI_ENTRY never_always_allowexisting[] = { static readonly CLI_ENTRY db_vers[] = { { "V4", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - { "V5", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { "V6", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, }; static readonly CLI_ENTRY dse_cfhead_qual[] = { @@ -163,6 +164,7 @@ static readonly CLI_ENTRY dse_cfhead_qual[] = { { "ONLINE_NBB", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, { "OVERRIDE", 0, 0, 0, 0, 0, 0, VAL_N_A, 0, 0, 0, 0 }, { "PRE_READ_TRIGGER_FACTOR", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, VAL_DCM }, +{ "QDBRUNDOWN", 0, 0, 0, 0, 0, 0, VAL_N_A, 0, NEG, 0, 0 }, { "RC_SRV_COUNT", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, VAL_DCM }, { "RECORD_MAX_SIZE", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, VAL_DCM }, { "REFERENCE_COUNT", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, VAL_DCM }, @@ -366,7 +368,7 @@ GBLDEF CLI_ENTRY dse_cmd_ary[] = { { "EVALUATE", dse_eval, dse_eval_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, { "EXIT", dse_exit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, { "FIND", dse_f_blk, dse_find_qual, 0, 0, cli_disallow_dse_find, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, -{ "HELP", dse_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, +{ "HELP", util_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, { "INTEGRIT", dse_integ, dse_integrit_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, { "MAPS", dse_maps, dse_map_qual, 0, 0, cli_disallow_dse_maps, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, { "OPEN", dse_open, dse_open_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, diff --git a/sr_unix/dse_help.c b/sr_unix/dse_help.c index abf60ea..cb7dc40 100644 --- a/sr_unix/dse_help.c +++ b/sr_unix/dse_help.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,6 +21,7 @@ void dse_help(void) { + /* This function is a STUB to avoid editting sr_port/dse.h */ } void dse_version(void) diff --git a/sr_unix/dse_open.c b/sr_unix/dse_open.c index 2ab9af9..11d3e15 100644 --- a/sr_unix/dse_open.c +++ b/sr_unix/dse_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -66,16 +66,29 @@ void dse_open (void) int4 save_errno; mval val; - mval pars; + mval open_pars, use_pars; mstr chset_mstr; int cnt; + static readonly unsigned char open_params_list[] = { (unsigned char)iop_newversion, (unsigned char)iop_m, + (unsigned char)iop_nowrap, (unsigned char)iop_eol }; + /*set iop_width=1MB(1*1024*1024)*/ + static readonly unsigned char use_params_list[] = + { + (unsigned char)iop_width, +# ifdef BIGENDIAN + (unsigned char)0x0, (unsigned char)0x10, (unsigned char)0x0, (unsigned char)0x0 +# else + (unsigned char)0x0, (unsigned char)0x0, (unsigned char)0x10, (unsigned char)0x0 +# endif + }; + if (cli_present("FILE") == CLI_PRESENT) { if (CLOSED_FMT != dse_dmp_format) @@ -95,14 +108,17 @@ void dse_open (void) patch_ofile[cli_len] = 0; patch_len = cli_len; - pars.mvtype = MV_STR; - pars.str.len = SIZEOF(open_params_list); - pars.str.addr = (char *)open_params_list; val.mvtype = MV_STR; val.str.len = patch_len; val.str.addr = (char *)patch_ofile; - (*op_open_ptr)(&val, &pars, 0, NULL); - op_use(&val, &pars); + open_pars.mvtype = MV_STR; + open_pars.str.len = SIZEOF(open_params_list); + open_pars.str.addr = (char *)open_params_list; + (*op_open_ptr)(&val, &open_pars, 0, NULL); + use_pars.mvtype = MV_STR; + use_pars.str.len = SIZEOF(use_params_list); + use_pars.str.addr = (char *)use_params_list; + op_use(&val, &use_pars); if (CLI_PRESENT == cli_present("OCHSET")) { diff --git a/sr_unix/dsk_read.c b/sr_unix/dsk_read.c index e3c5163..13f40e2 100644 --- a/sr_unix/dsk_read.c +++ b/sr_unix/dsk_read.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,12 +39,24 @@ #include "min_max.h" #include "gtmimagename.h" #include "memcoherency.h" +#include "gdskill.h" +#include "gdscc.h" +#include "jnl.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF volatile int4 fast_lock_count; GBLREF boolean_t dse_running; +GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; +GBLREF unsigned int t_tries; +GBLREF uint4 dollar_tlevel; +GBLREF sgm_info *sgm_info_ptr; +GBLREF sgmnt_addrs *kip_csa; +GBLREF jnl_gbls_t jgbl; error_def(ERR_DYNUPGRDFAIL); @@ -56,10 +68,12 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea sm_uc_ptr_t save_buff = NULL, enc_save_buff; boolean_t fully_upgraded, buff_is_modified_after_lseekread; int bsiz; - DEBUG_ONLY( - blk_hdr_ptr_t blk_hdr_val; - static int in_dsk_read; - ) +# ifdef DEBUG + unsigned int effective_t_tries; + boolean_t killinprog; + blk_hdr_ptr_t blk_hdr_val; + static int in_dsk_read; +# endif /* It is possible that the block that we read in from disk is a V4 format block. The database block scanning routines * (gvcst_*search*.c) that might be concurrently running currently assume all global buffers (particularly the block * headers) are V5 format. They are not robust enough to handle a V4 format block. Therefore we do not want to @@ -72,12 +86,14 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea */ static sm_uc_ptr_t read_reformat_buffer; static int read_reformat_buffer_len; - GTMCRYPT_ONLY( - int req_dec_blk_size; - int crypt_status; - boolean_t is_encrypted; - ) +# ifdef GTM_CRYPT + int in_len, gtmcrypt_errno; + char *in, *out; + boolean_t is_encrypted; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; /* Note: Even in snapshots, only INTEG requires dsk_read to read FREE blocks. The assert below should be modified * if we later introduce a scheme where we can figure out as to who started the snapshots and assert accordingly */ @@ -133,32 +149,25 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea size, save_errno); assert((0 == save_errno) GTM_TRUNCATE_ONLY(|| (-1 == save_errno))); + WBTEST_ASSIGN_ONLY(WBTEST_PREAD_SYSCALL_FAIL, save_errno, EIO); # ifdef GTM_CRYPT if (is_encrypted && (0 == save_errno)) { bsiz = (int)((blk_hdr_ptr_t)enc_save_buff)->bsiz; - req_dec_blk_size = MIN(cs_data->blk_size, bsiz) - SIZEOF(blk_hdr); + in_len = MIN(cs_data->blk_size, bsiz) - SIZEOF(blk_hdr); buff_is_modified_after_lseekread = TRUE; /* Do not do encryption/decryption if block is FREE */ - if (!blk_free && (IS_BLK_ENCRYPTED(((blk_hdr_ptr_t)enc_save_buff)->levl, req_dec_blk_size))) - { - /* The below assert cannot be moved before BLOCK_REQUIRE_ENCRYPTION check done above as tmp_ptr could - * potentially point to a V4 block in which case the assert might fail when a V4 block is casted to - * a V5 block header. + if (!blk_free && (IS_BLK_ENCRYPTED(((blk_hdr_ptr_t)enc_save_buff)->levl, in_len))) + { /* Due to concurrency conflicts, we are potentially reading a free block even though blk_free is + * FALSE. Go ahead and safely "decrypt" such a block, even though it contains no valid contents. + * We expect GTMCRYPT_DECRYPT to return success even if it is presented with garbage data. */ - assert((bsiz <= cs_data->blk_size) && (bsiz >= SIZEOF(blk_hdr))); ASSERT_ENCRYPTION_INITIALIZED; memcpy(buff, enc_save_buff, SIZEOF(blk_hdr)); - GTMCRYPT_DECODE_FAST(cs_addrs->encr_key_handle, - (char *)enc_save_buff + SIZEOF(blk_hdr), - req_dec_blk_size, - (char *)buff + SIZEOF(blk_hdr), - crypt_status); - if (0 != crypt_status) - { - GC_RTS_ERROR(crypt_status, gv_cur_region->dyn.addr->fname); - return crypt_status; - } + in = (char *)(enc_save_buff + SIZEOF(blk_hdr)); + out = (char *)(buff + SIZEOF(blk_hdr)); + GTMCRYPT_DECRYPT(cs_addrs, cs_addrs->encr_key_handle, in, in_len, out, gtmcrypt_errno); + save_errno = gtmcrypt_errno; } else memcpy(buff, enc_save_buff, size); } @@ -180,7 +189,7 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea if (GDSVCURR != tmp_ondskblkver) PRINTF("DSK_READ: Block %d being dynamically upgraded on read\n", blk); ) - assert((GDSV5 == tmp_ondskblkver) || (NULL != save_buff)); /* never read a V4 block directly into cache */ + assert((GDSV6 == tmp_ondskblkver) || (NULL != save_buff)); /* never read a V4 block directly into cache */ if (NULL != ondsk_blkver) *ondsk_blkver = tmp_ondskblkver; /* a bitmap block should never be short of space for a dynamic upgrade. assert that. */ @@ -206,15 +215,25 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea */ SHM_WRITE_MEMORY_BARRIER; } - DEBUG_ONLY( - in_dsk_read--; - 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. - */ - blk_hdr_val = (NULL != save_buff) ? (blk_hdr_ptr_t)save_buff : (blk_hdr_ptr_t)buff; - GDS_BLK_HDR_CHECK(cs_data, blk_hdr_val, fully_upgraded); - } - ) +# ifdef DEBUG + in_dsk_read--; + /* 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) + */ + 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))); + 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. + */ + blk_hdr_val = (NULL != save_buff) ? (blk_hdr_ptr_t)save_buff : (blk_hdr_ptr_t)buff; + GDS_BLK_HDR_CHECK(cs_data, blk_hdr_val, fully_upgraded); + } +# endif return save_errno; } diff --git a/sr_unix/dsk_write.c b/sr_unix/dsk_write.c index 47eb61e..2f927be 100644 --- a/sr_unix/dsk_write.c +++ b/sr_unix/dsk_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,8 @@ #include "gtmio.h" #include "gds_blk_downgrade.h" #include "gdsbml.h" +#include "jnl.h" +#include "anticipatory_freeze.h" GBLREF sm_uc_ptr_t reformat_buffer; GBLREF int reformat_buffer_len; @@ -91,7 +93,7 @@ int dsk_write(gd_region *reg, block_id blk, cache_rec_ptr_t cr) assert(size <= csd->blk_size - SIZEOF(blk_hdr) + SIZEOF(v15_blk_hdr)); size = (size + 1) & ~1; assert(SIZEOF(v15_blk_hdr) <= size); - } else DEBUG_ONLY(if (GDSV5 == cr->ondsk_blkver)) + } else DEBUG_ONLY(if (GDSV6 == cr->ondsk_blkver)) { size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1; assert(SIZEOF(blk_hdr) <= size); @@ -112,11 +114,9 @@ int dsk_write(gd_region *reg, block_id blk, cache_rec_ptr_t cr) assert(size <= csd->blk_size); if (udi->raw) size = ROUND_UP(size, DISK_BLOCK_SIZE); /* raw I/O must be a multiple of DISK_BLOCK_SIZE */ - LSEEKWRITE(udi->fd, + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (DISK_BLOCK_SIZE * (csd->start_vbn - 1) + (off_t)blk * csd->blk_size), - buff, - size, - save_errno); + buff, size, save_errno); DEBUG_ONLY(reformat_buffer_in_use--;) assert(0 == reformat_buffer_in_use); --fast_lock_count; diff --git a/sr_unix/dsk_write_nocache.c b/sr_unix/dsk_write_nocache.c index 4535195..6de961f 100644 --- a/sr_unix/dsk_write_nocache.c +++ b/sr_unix/dsk_write_nocache.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2009 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,10 +28,12 @@ #include "gtmio.h" #include "gds_blk_downgrade.h" #include "add_inter.h" +#include "anticipatory_freeze.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #include "min_max.h" +#include "jnl.h" GBLREF sm_uc_ptr_t reformat_buffer; GBLREF int reformat_buffer_len; @@ -51,7 +53,9 @@ int dsk_write_nocache(gd_region *reg, block_id blk, sm_uc_ptr_t buff, enum db_ve sgmnt_data_ptr_t csd; sm_uc_ptr_t save_buff; # ifdef GTM_CRYPT - int req_enc_blk_size, this_blk_size, crypt_status; + int in_len, this_blk_size, gtmcrypt_errno; + char *in, *out; + gd_segment *seg; # endif udi = (unix_db_info *)(reg->dyn.addr->file_cntl->file_info); @@ -83,7 +87,7 @@ int dsk_write_nocache(gd_region *reg, block_id blk, sm_uc_ptr_t buff, enum db_ve /* Represents a block state change from V5 -> V4 */ INCR_BLKS_TO_UPGRD(csa, csd, 1); assert(SIZEOF(v15_blk_hdr) <= size); - } else DEBUG_ONLY(if (GDSV5 == ondsk_blkver)) + } else DEBUG_ONLY(if (GDSV6 == ondsk_blkver)) { size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1; assert(SIZEOF(blk_hdr) <= size); @@ -105,24 +109,25 @@ int dsk_write_nocache(gd_region *reg, block_id blk, sm_uc_ptr_t buff, enum db_ve { this_blk_size = ((blk_hdr_ptr_t)buff)->bsiz; assert((this_blk_size <= csd->blk_size) && (this_blk_size >= SIZEOF(blk_hdr))); - req_enc_blk_size = MIN(csd->blk_size, this_blk_size) - SIZEOF(blk_hdr); - if (BLK_NEEDS_ENCRYPTION(((blk_hdr_ptr_t)buff)->levl, req_enc_blk_size)) + in_len = MIN(csd->blk_size, this_blk_size) - SIZEOF(blk_hdr); + if (BLK_NEEDS_ENCRYPTION(((blk_hdr_ptr_t)buff)->levl, in_len)) { ASSERT_ENCRYPTION_INITIALIZED; assert(csa->encrypted_blk_contents); memcpy(csa->encrypted_blk_contents, buff, SIZEOF(blk_hdr)); - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, - (char *)(buff + SIZEOF(blk_hdr)), - req_enc_blk_size, - (csa->encrypted_blk_contents + SIZEOF(blk_hdr)), - crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, reg->dyn.addr->fname); + out = csa->encrypted_blk_contents + SIZEOF(blk_hdr); + in = (char *)(buff + SIZEOF(blk_hdr)); + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, in, in_len, out, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + seg = reg->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + } buff = (unsigned char *)csa->encrypted_blk_contents; } } # endif - LSEEKWRITE(udi->fd, + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (DISK_BLOCK_SIZE * (csd->start_vbn - 1) + (off_t)blk * csd->blk_size), buff, size, diff --git a/sr_unix/err_init.c b/sr_unix/err_init.c index 7228abf..b9b6558 100644 --- a/sr_unix/err_init.c +++ b/sr_unix/err_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,35 +10,115 @@ ****************************************************************/ #include "mdef.h" + +#include #include +#include +#include "unistd.h" +#include "gtm_stdlib.h" +#include "gtm_stdio.h" + #include "invocation_mode.h" #include "gtmimagename.h" #include "error.h" +#include "send_msg.h" + +#define COREDUMPFILTERFN "/proc/%i/coredump_filter" +#define FILTERPARMSIZE (8 + 1) +#define FILTERENABLEBITS 0x00000073 /* Represents bits 0, 1, 4, 5, 6 */ GBLREF enum gtmImageTypes image_type; +error_def(ERR_SYSCALL); + +/* 1. Allocate a basic initial condition handler stack that can be expanded later if necessary. + * 2. On Linux, make sure bits 0,1, 4, 5, and 6 are set in /proc/PID/coredump_filter so dumps the sections that GT.M + * cores need to have in them. + */ void err_init(void (*x)()) -{ /* Due to nested callins, we allocate bigger condition handlers stack for mumps and other trigger capable - images than for non-trigger capable utilities */ - - int size; - - switch(image_type) - { - case GTM_IMAGE: -#ifdef GTM_TRIGGER - case MUPIP_IMAGE: - case GTCM_SERVER_IMAGE: - case GTCM_GNP_SERVER_IMAGE: -#endif - size = MAX_MUMPS_HANDLERS; - break; - default: - size = MAX_HANDLERS; - } - chnd = (condition_handler*)malloc(size * SIZEOF(condition_handler)); +{ + chnd = (condition_handler *)malloc((CONDSTK_INITIAL_INCR + CONDSTK_RESERVE) * SIZEOF(condition_handler)); chnd[0].ch_active = FALSE; + chnd[0].save_active_ch = NULL; active_ch = ctxt = &chnd[0]; ctxt->ch = x; - chnd_end = &chnd[size]; /* chnd_end is the end of the condition handler stack */ + chnd_end = &chnd[CONDSTK_INITIAL_INCR]; /* chnd_end is the end of the condition handler stack */ + chnd_incr = CONDSTK_INITIAL_INCR * 2; +# ifdef __linux__ + /* Read the coredump_filter value from /proc for this process, update the value if necessary so we have the proper + * flags set to get the info we (and gtmpcat) need to properly process a core file. Note any errors we encounter just + * send a message to the operator log and return as nothing here should prevent GT.M from running. + * + * Note "man 5 core" on x86-64 Linux (Ubuntu 12.04) notes that the /proc/PID/coredump_filter file is only provided when + * the Linux kernel is built with the CONFIG_ELF_CORE configuration option. This *seems* to control whether or not the + * kernel supports the ELF loader or not. To date, all Linux flavors GT.M supports use ELF so we regard this as largely + * mandatory though in the future it may happen that GT.M works yet runs with something other than ELF. In that case, + * we'd need to change the below to avoid the operator log messages every time GT.M initializes. + */ + { + int rc; + unsigned int filterbits; + char procfn[SIZEOF(COREDUMPFILTERFN) + MAX_DIGITS_IN_INT]; /* File name of file to update */ + char filter[FILTERPARMSIZE], *filterend; /* Value read in & written out */ + char *rcc; + FILE *filterstrm; /* filter stream file block */ + + /* Note use simple basic methods since this early in initialization not everything is necessarily setup to + * be able to properly use the *print*() wrapper functions. + */ + rc = snprintf(procfn, SIZEOF(procfn), COREDUMPFILTERFN, getpid()); + if (0 > rc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sprintf()"), CALLFROM, rc); + return; + } + filterstrm = fopen(procfn, "r"); + if (NULL == filterstrm) + { + rc = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fopen()"), CALLFROM, rc); + return; + } + rcc = fgets(filter, SIZEOF(filter), filterstrm); + if (NULL == rcc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM, rc); + return; + } + rc = fclose(filterstrm); + if (0 > rc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fclose()"), CALLFROM, rc); + return; + } + filterend = filter + SIZEOF(filter); + filterbits = (unsigned int)strtol(filter, &filterend, 16); + if (FILTERENABLEBITS != (filterbits & FILTERENABLEBITS)) + { /* At least one flag was missing - reset them */ + filterbits = filterbits | FILTERENABLEBITS; + filterstrm = fopen(procfn, "w"); + if (NULL == filterstrm) + { + rc = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fopen()"), + CALLFROM, rc); + return; + } + rc = fprintf(filterstrm, "0x%08x", filterbits); + if (0 > rc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf"), + CALLFROM, rc); + return; + } + fclose(filterstrm); + if (0 > rc) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fclose()"), + CALLFROM, rc); + return; + } + } + } +# endif } diff --git a/sr_unix/errorsp.h b/sr_unix/errorsp.h index 0a2de02..a9f0cbd 100644 --- a/sr_unix/errorsp.h +++ b/sr_unix/errorsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,22 +15,40 @@ #include #include "gtm_stdio.h" +#include "have_crit.h" #ifdef __MVS__ # define GTMCORENAME "gtmcore" #endif -/* Define maximum condition handlers. For utilities that do not use triggers (dse, lke, and such) we - only need a basic number of condition handlers. But if triggers are supported, not only the GT.M - runtime but MUPIP and the GTCM servers too need to be able to nest which means several triggers - per allowed level plus extra handlers for that last level. -*/ -#define MAX_HANDLERS 15 /* should be enough for dse/lke etc. */ -#ifdef GTM_TRIGGER -# define MAX_MUMPS_HANDLERS (MAX_HANDLERS + 20 + 15 + (GTM_TRIGGER_DEPTH_MAX * 2)) /* Allow for callins plus many trigr lvls */ +/* Condition handler stack definitions: + * + * Global: chnd - Base of condition handler stack. + * chnd_end - Top of condition handler stack. + * chnd_incr - Increment for next expansion. + * ctxt - Top condition handler stack currently in use. + * active_ch - Top of the inactive (i.e. available for invocation) condition handler stack. + * + * Note that START_CH used at the top of every condition handler defined "current_ch" as a stack variable + * (i.e. "automatic" variable in some lingos). The current_ch var in a given (C) frame always points to the + * condition handler entry active for that frame because active_ch can change in a nested handler situation. + * Note also that current_ch has the form of an index into the condition handler array because the stack + * can be extended via re-allocation. + * + * Condition handler stack starts off at a modest CONDSTK_INITIAL_INCR frames. If needed, (to cover trigger + * and/or spanning node stack frames which nest handlers), it can expand up to MAX_CON + * + * Note, if ever call-ins fully support TP processing such that each trigger frame could have it's own callin + * in addition to the other handlers for each trigger frame, the maximums may need to be re-visited. + */ +#ifdef DEBUG +# define CONDSTK_INITIAL_INCR 2 /* Low initial limit for DEBUG to exercise extensions */ #else -# define MAX_MUMPS_HANDLERS (MAX_HANDLERS + 20) /* to allow upto 10 nested callin lvls */ +# define CONDSTK_INITIAL_INCR 8 /* Initial increment value used when expanding condition handler stack */ #endif +#define CONDSTK_MAX_INCR 128 /* Increment doubles each time expanded till hits this level */ +#define CONDSTK_MAX_STACK 512 /* Actual max is approx 504 due to arithmetic progression */ +#define CONDSTK_RESERVE 3 /* Reserve 2 frames for when process_exiting */ #define CONDITION_HANDLER(name) ch_ret_type name(int arg) @@ -40,29 +58,31 @@ typedef void ch_ret_type; typedef struct condition_handler_struct { - struct condition_handler_struct *save_active_ch; - boolean_t ch_active; - ch_ret_type (*ch)(); - jmp_buf jmp; + struct condition_handler_struct *save_active_ch; /* -> Previous active condition handler */ + boolean_t ch_active; /* True when *THIS* condition handler is active (not usable) */ + ch_ret_type (*ch)(); /* Condition handler address */ + jmp_buf jmp; /* setjmp/longjmp buffer associated with ESTABLISH point */ } condition_handler; /* The values below usually expand as GBLREF. If CHEXPAND is defined, they will - expand as GBLDEF instead (as it does in err_init.c) */ + * expand as GBLDEF instead (as it does in gbldefs.c). + */ #ifdef CHEXPAND # define GBLEXP GBLDEF #else # define GBLEXP GBLREF #endif GBLEXP condition_handler *chnd, *ctxt, *active_ch, *chnd_end; -GBLEXP int4 severity; +GBLEXP int severity, chnd_incr; /* Don't do these GBLREFs if doing above GBLDEFs as this means we are in gbldefs.c where the below - are also defined so a REF is likely to cause problems */ + * are also defined so a REF is likely to cause problems. + */ #ifndef CHEXPAND GBLREF int4 error_condition; -GBLREF char util_outbuff[]; GBLREF err_ctl merrors_ctl; GBLREF void (*restart)(); +GBLREF int process_exiting; #endif #define WARNING 0 @@ -73,8 +93,8 @@ GBLREF void (*restart)(); #define SEV_MSK 7 #define IS_GTM_ERROR(err) ((err & FACMASK(merrors_ctl.facnum)) && (MSGMASK(err, merrors_ctl.facnum) <= merrors_ctl.msg_cnt)) -#define CHECKHIGHBOUND(hptr) assert(chnd_end > hptr); -#define CHECKLOWBOUND(hptr) assert(hptr >= (&chnd[0] - 1)); +#define CHECKHIGHBOUND(hptr) assert(hptr < (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) +#define CHECKLOWBOUND(hptr) assert(hptr >= (&chnd[0] - 1)) /* Low check for chnd - 1 in case last handler setup new handler */ #define SIGNAL error_condition #define SEVERITY severity @@ -112,7 +132,7 @@ void ch_trace_point() {return;} * two flavors depending on if triggers are enabled or not. */ #ifdef GTM_TRIGGER -/* Note the 2nd assert makes sure we are NOT returning to a trigger-invoking frame which does not have a valid msp to +/* Note the 3rd assert makes sure we are NOT returning to a trigger-invoking frame which does not have a valid msp to * support a return since a call to op_gvput or op_kill does not save a return addr in the M stackframe but only in the C * stackframe. But if proc_act_type is non-zero we set an error frame flag and getframe instead detours to * error_return which deals with the module appropriately. @@ -123,10 +143,12 @@ void ch_trace_point() {return;} \ assert(!process_exiting); \ CHTRACEPOINT; \ - for ( ;ctxt > &chnd[0] && ctxt->ch != &mdb_condition_handler; ctxt--) ; \ - assert(ctxt->ch == &mdb_condition_handler && FALSE == ctxt->save_active_ch->ch_active); \ + for ( ;(ctxt > &chnd[0]) && (ctxt->ch != &mdb_condition_handler); ctxt--); \ + CHECKLOWBOUND(ctxt); \ + assert((ctxt->ch == &mdb_condition_handler) \ + && (FALSE == ctxt->save_active_ch->ch_active)); \ /* Absolutely critical that this *never* occur hence assertpro() */ \ - assertpro(!(SFF_TRIGR_CALLD & frame_pointer->flags) || (0 != proc_act_type) \ + assertpro(!(SFF_IMPLTSTART_CALLD & frame_pointer->flags) || (0 != proc_act_type) \ || (SFF_ETRAP_ERR & frame_pointer->flags)); \ DBGEHND((stderr, "MUM_TSTART: Frame 0x"lvaddr" dispatched\n", frame_pointer)); \ ctxt->ch_active = FALSE; \ @@ -140,8 +162,10 @@ void ch_trace_point() {return;} \ assert(!process_exiting); \ CHTRACEPOINT; \ - for ( ;ctxt > &chnd[0] && ctxt->ch != &mdb_condition_handler; ctxt--) ; \ - assert(ctxt->ch == &mdb_condition_handler && FALSE == ctxt->save_active_ch->ch_active); \ + for ( ;ctxt > &chnd[0] && ctxt->ch != &mdb_condition_handler; ctxt--); \ + CHECKLOWBOUND(ctxt); \ + assert((ctxt->ch == &mdb_condition_handler) \ + && (FALSE == ctxt->save_active_ch->ch_active)); \ DBGEHND((stderr, "MUM_TSTART: Frame 0x"lvaddr" dispatched\n", frame_pointer)); \ ctxt->ch_active = FALSE; \ restart = mum_tstart; \ @@ -150,67 +174,66 @@ void ch_trace_point() {return;} } #endif +#define GTM_ASM_ESTABLISH { /* So named because gtm_asm_establish does exactly this */ \ + CHTRACEPOINT; \ + ctxt++; \ + if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) \ + condstk_expand(); \ + CHECKHIGHBOUND(ctxt); \ + ctxt->save_active_ch = active_ch; \ + ctxt->ch_active = FALSE; \ + active_ch = ctxt; \ + } +#define ESTABLISH_NOJMP(x) { \ + GTM_ASM_ESTABLISH; \ + ctxt->ch = x; \ + } -#define ESTABLISH_RET(x,ret) { \ - CHTRACEPOINT; \ - ctxt++; \ - CHECKHIGHBOUND(ctxt); \ - ctxt->save_active_ch = active_ch; \ - ctxt->ch_active = FALSE; \ - active_ch = ctxt; \ - ctxt->ch = x; \ - if (setjmp(ctxt->jmp) == -1) \ - { \ - REVERT; \ - return ret; \ - } \ +#define ESTABLISH_NOUNWIND(x) ESTABLISH_NOJMP(x) +#define ESTABLISH_RET(x, ret) { \ + ESTABLISH_NOJMP(x); \ + if (setjmp(ctxt->jmp) == -1) \ + { \ + REVERT; \ + return ret; \ + } \ } #ifdef __cplusplus /* must specify return value (if any) for C++ */ -#define ESTABLISH(x,ret) { \ - CHTRACEPOINT; \ - ctxt++; \ - CHECKHIGHBOUND(ctxt); \ - ctxt->save_active_ch = active_ch; \ - ctxt->ch_active = FALSE; \ - active_ch = ctxt; \ - ctxt->ch = x; \ - if (setjmp(ctxt->jmp) == -1) \ - { \ - REVERT; \ - return ret; \ - } \ - } +# define ESTABLISH(x, ret) ESTABLISH_RET(x, ret) #else -#define ESTABLISH(x) { \ - CHTRACEPOINT; \ - ctxt++; \ - CHECKHIGHBOUND(ctxt); \ - ctxt->save_active_ch = active_ch; \ - ctxt->ch_active = FALSE; \ - active_ch = ctxt; \ - ctxt->ch = x; \ - if (setjmp(ctxt->jmp) == -1) \ - { \ - REVERT; \ - return; \ - } \ +# define ESTABLISH(x) { \ + ESTABLISH_NOJMP(x); \ + if (setjmp(ctxt->jmp) == -1) \ + { \ + REVERT; \ + return; \ + } \ + } +# define ESTABLISH_NORET(x, did_long_jump) \ + { \ + did_long_jump = FALSE; \ + ESTABLISH_NOJMP(x); \ + if (setjmp(ctxt->jmp) == -1) \ + did_long_jump = TRUE; \ } #endif -#define REVERT { \ - CHTRACEPOINT; \ - active_ch = ctxt->save_active_ch; \ - ctxt--; \ - CHECKLOWBOUND(ctxt); \ +#define REVERT { \ + CHTRACEPOINT; \ + active_ch = ctxt->save_active_ch; \ + CHECKHIGHBOUND(active_ch); \ + CHECKLOWBOUND(active_ch); \ + ctxt--; \ + CHECKLOWBOUND(ctxt); \ } -#define CONTINUE { \ - CHTRACEPOINT; \ - active_ch++; \ - CHECKHIGHBOUND(active_ch); \ - current_ch->ch_active = FALSE; \ - return; \ +#define CONTINUE { \ + CHTRACEPOINT; \ + active_ch++; \ + CHECKHIGHBOUND(active_ch); \ + chnd[current_ch].ch_active = FALSE; \ + return; \ } #define DRIVECH(x) { \ @@ -239,33 +262,51 @@ void ch_trace_point() {return;} } \ } -#define NEXTCH { \ - CHTRACEPOINT; \ - current_ch->ch_active = FALSE; \ - DRIVECH(arg); \ - return; \ - } - -#define UNWIND(dummy1, dummy2) { \ - GBLREF int process_exiting; \ - GBLREF boolean_t ok_to_UNWIND_in_exit_handling; \ - \ - assert(!process_exiting || ok_to_UNWIND_in_exit_handling); \ +#define NEXTCH { \ CHTRACEPOINT; \ - current_ch->ch_active = FALSE; \ - active_ch++; \ - CHECKHIGHBOUND(active_ch); \ - ctxt = active_ch; \ - longjmp(active_ch->jmp, -1); \ + chnd[current_ch].ch_active = FALSE; \ + DRIVECH(arg); \ + /* If ever DRIVECH does a CONTINUE and returns back to us, we \ + * need to do a CONTINUE as well so we re-establish ourselves \ + * on the condition handler stack. This cancels out the \ + * START_CH (done before the NEXTCH invocation) which would \ + * have removed us from the condition handler stack. This way \ + * we restore the condition handler stack to what it was at \ + * entry into the current condition handler before returning \ + * on a successfully handled condition. Assert that we should \ + * never have been in a DUMPABLE state if DRIVECH returned. \ + */ \ + assert(!DUMPABLE); \ + CONTINUE; \ } -#define START_CH condition_handler *current_ch; \ +/* Should never unwind a condition handler established with ESTABLISH_NOUNWIND. Currently t_ch and dbinit_ch are the only ones. */ +#define UNWINDABLE(unw_ch) ((&t_ch != unw_ch->ch) && (&dbinit_ch != unw_ch->ch)) +#define UNWIND(dummy1, dummy2) { \ + GBLREF int process_exiting; \ + GBLREF boolean_t ok_to_UNWIND_in_exit_handling; \ + \ + assert(!process_exiting || ok_to_UNWIND_in_exit_handling); \ + /* When we hit an error in the midst of commit, t_ch/t_commit_cleanup should be invoked \ + * and clean it up before any condition handler on the stack unwinds. \ + */ \ + assert(0 == have_crit(CRIT_IN_COMMIT)); \ + CHTRACEPOINT; \ + chnd[current_ch].ch_active = FALSE; \ + active_ch++; \ + CHECKHIGHBOUND(active_ch); \ + ctxt = active_ch; \ + assert(UNWINDABLE(active_ch)); \ + longjmp(active_ch->jmp, -1); \ + } + +#define START_CH int current_ch; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ CHTRACEPOINT; \ - current_ch = active_ch; \ - current_ch->ch_active = TRUE; \ + current_ch = (active_ch - chnd); \ + active_ch->ch_active = TRUE; \ active_ch--; \ CHECKLOWBOUND(active_ch); \ DBGEHND((stderr, "%s: Condition handler entered at line %d - arg: %d SIGNAL: %d\n", \ @@ -297,11 +338,19 @@ void stop_image_no_core(void); EXIT(-exi_condition); \ } -#define PROCDIE(x) _exit(x) +#define PROCDIE(x) _exit(x) /* No exit handler, no cleanup, just die */ #define EXIT(x) { \ exit(x); \ } +error_def(ERR_ASSERT); +error_def(ERR_GTMASSERT); +error_def(ERR_GTMASSERT2); +error_def(ERR_GTMCHECK); +error_def(ERR_MEMORY); +error_def(ERR_STACKOFLOW); +error_def(ERR_OUTOFSPACE); + #define DUMP (SIGNAL == (int)ERR_ASSERT \ || SIGNAL == (int)ERR_GTMASSERT \ || SIGNAL == (int)ERR_GTMASSERT2 \ @@ -322,11 +371,12 @@ unsigned char *set_zstatus(mstr *src, int arg, unsigned char **ctxtp, boolean_t #define EXIT_HANDLER(x) -#define SEND_CALLERID(callee) send_msg(VARLSTCNT(5) ERR_CALLERID, 3, LEN_AND_STR((callee)), caller_id()); +#define SEND_CALLERID(callee) send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_CALLERID, 3, LEN_AND_STR((callee)), caller_id()); #define PRINT_CALLERID util_out_print(" -- generated from 0x!XJ.", NOFLUSH, caller_id()) #define UNIX_EXIT_STATUS_MASK 0xFF void err_init(void (*x)()); +void condstk_expand(void); void gtm_dump(void); void gtm_dump_core(void); void gtm_fork_n_core(void); @@ -357,5 +407,16 @@ CONDITION_HANDLER(gtm_trigger_complink_ch); CONDITION_HANDLER(op_fnztrigger_ch); CONDITION_HANDLER(trigger_tpwrap_ch); #endif +CONDITION_HANDLER(gvcst_redo_root_search_ch); +CONDITION_HANDLER(gvcst_data_ch); +CONDITION_HANDLER(gvcst_get_ch); +CONDITION_HANDLER(gvcst_kill_ch); +CONDITION_HANDLER(gvcst_order_ch); +CONDITION_HANDLER(gvcst_put_ch); +CONDITION_HANDLER(gvcst_query_ch); +CONDITION_HANDLER(gvcst_queryget_ch); +CONDITION_HANDLER(gvcst_zprevious_ch); +CONDITION_HANDLER(op_fnzpeek_ch); +CONDITION_HANDLER(op_fnzpeek_getpool_ch); #endif diff --git a/sr_unix/extract_signal_info.c b/sr_unix/extract_signal_info.c index dde025c..ce5607d 100644 --- a/sr_unix/extract_signal_info.c +++ b/sr_unix/extract_signal_info.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,35 +33,40 @@ #include "gtmsiginfo.h" +/* GCC on HPPA does not have SI_USER defined */ +#if !defined(SI_USER) && defined(__GNUC__) +# define SI_USER 0 +#endif + /* OS/390 (R7) does not define SI_USER but for code expansions purposes, define the value it uses in its place */ #if !defined(SI_USER) && defined(__MVS__) # define SI_USER 0 #endif +error_def(ERR_SIGACCERR); +error_def(ERR_SIGADRALN); +error_def(ERR_SIGADRERR); +error_def(ERR_SIGBADSTK); +error_def(ERR_SIGCOPROC); +error_def(ERR_SIGFLTDIV); +error_def(ERR_SIGFLTINV); +error_def(ERR_SIGFLTOVF); +error_def(ERR_SIGFLTRES); +error_def(ERR_SIGFLTUND); +error_def(ERR_SIGILLADR); +error_def(ERR_SIGILLOPC); +error_def(ERR_SIGILLOPN); +error_def(ERR_SIGILLTRP); +error_def(ERR_SIGINTDIV); +error_def(ERR_SIGINTOVF); +error_def(ERR_SIGMAPERR); +error_def(ERR_SIGOBJERR); +error_def(ERR_SIGPRVOPC); +error_def(ERR_SIGPRVREG); + void extract_signal_info(int sig, siginfo_t *info, gtm_sigcontext_t *context, gtmsiginfo_t *gtmsi) { - error_def(ERR_SIGILLOPC); - error_def(ERR_SIGILLOPN); - error_def(ERR_SIGILLADR); - error_def(ERR_SIGILLTRP); - error_def(ERR_SIGPRVOPC); - error_def(ERR_SIGPRVREG); - error_def(ERR_SIGCOPROC); - error_def(ERR_SIGBADSTK); - error_def(ERR_SIGADRALN); - error_def(ERR_SIGADRERR); - error_def(ERR_SIGOBJERR); - error_def(ERR_SIGINTDIV); - error_def(ERR_SIGINTOVF); - error_def(ERR_SIGFLTDIV); - error_def(ERR_SIGFLTOVF); - error_def(ERR_SIGFLTUND); - error_def(ERR_SIGFLTRES); - error_def(ERR_SIGFLTINV); - error_def(ERR_SIGMAPERR); - error_def(ERR_SIGACCERR); - memset(gtmsi, 0, SIZEOF(*gtmsi)); gtmsi->signal = sig; if (NULL != info) @@ -90,7 +95,7 @@ void extract_signal_info(int sig, siginfo_t *info, gtm_sigcontext_t *context, gt gtmsi->infotype |= GTMSIGINFO_BADR; if (NULL != context) { -#ifndef __ia64 +#if !defined(__ia64) && !defined(__GNUC__) if (0 == (context->uc_mcontext.ss_flags & SS_NARROWISINVALID)) { /* Interrupt location is in narrow area */ diff --git a/sr_unix/exttab_parse.c b/sr_unix/exttab_parse.c index 938adfc..d3f4e2c 100644 --- a/sr_unix/exttab_parse.c +++ b/sr_unix/exttab_parse.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,37 +41,54 @@ #define TABLEN 8 #define POINTER_SIZE 6 -static int ext_source_line_num; -static int ext_source_line_len; -static int ext_source_column; -static char ext_source_line[MAX_SRC_LINE]; -static char *ext_table_file_name; -static boolean_t star_found; +STATICDEF int ext_source_line_num; +STATICDEF int ext_source_line_len; +STATICDEF int ext_source_column; +STATICDEF char ext_source_line[MAX_SRC_LINE]; +STATICDEF char *ext_table_file_name; +STATICDEF boolean_t star_found; + +STATICFNDCL void *get_memory(size_t n); +STATICFNDCL char *exttab_scan_space(char *c); +STATICFNDCL char *scan_ident(char *c); +STATICFNDCL char *scan_labelref(char *c); +STATICFNDCL enum gtm_types scan_keyword(char **c); +STATICFNDCL int scan_array_bound(char **b,int curr_type); +STATICFNDCL char *read_table(char *b, int l, FILE *f); +STATICFNDCL void put_mstr(mstr *src, mstr *dst); +STATICFNDCL uint4 array_to_mask(boolean_t ar[MAX_ACTUALS], int n); +STATICFNDCL void ext_stx_error(int in_error, ...); -static void ext_stx_error(int in_error, ...); -static int scan_array_bound(char **b, int curr_type); const int parm_space_needed[] = { 0, 0, SIZEOF(void *), - SIZEOF(xc_int_t), - SIZEOF(xc_uint_t), - SIZEOF(xc_long_t), - SIZEOF(xc_ulong_t), - SIZEOF(xc_float_t), - SIZEOF(xc_double_t), - SIZEOF(xc_int_t *) + SIZEOF(xc_int_t), - SIZEOF(xc_uint_t *) + SIZEOF(xc_uint_t), - SIZEOF(xc_long_t *) + SIZEOF(xc_long_t), - SIZEOF(xc_ulong_t *) + SIZEOF(xc_ulong_t), - SIZEOF(xc_string_t *) + SIZEOF(xc_string_t), - SIZEOF(xc_float_t *) + SIZEOF(xc_float_t), - SIZEOF(xc_char_t *), - SIZEOF(xc_char_t **) + SIZEOF(xc_char_t *), - SIZEOF(xc_double_t *) + SIZEOF(xc_double_t), - SIZEOF(xc_pointertofunc_t), - SIZEOF(xc_pointertofunc_t *) + SIZEOF(xc_pointertofunc_t) + SIZEOF(gtm_int_t), + SIZEOF(gtm_uint_t), + SIZEOF(gtm_long_t), + SIZEOF(gtm_ulong_t), + SIZEOF(gtm_float_t), + SIZEOF(gtm_double_t), + SIZEOF(gtm_int_t *) + SIZEOF(gtm_int_t), + SIZEOF(gtm_uint_t *) + SIZEOF(gtm_uint_t), + SIZEOF(gtm_long_t *) + SIZEOF(gtm_long_t), + SIZEOF(gtm_ulong_t *) + SIZEOF(gtm_ulong_t), + SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t), + SIZEOF(gtm_float_t *) + SIZEOF(gtm_float_t), + SIZEOF(gtm_char_t *), + SIZEOF(gtm_char_t **) + SIZEOF(gtm_char_t *), + SIZEOF(gtm_double_t *) + SIZEOF(gtm_double_t), + SIZEOF(gtm_pointertofunc_t), + SIZEOF(gtm_pointertofunc_t *) + SIZEOF(gtm_pointertofunc_t), + SIZEOF(gtm_int_t *) + SIZEOF(gtm_int_t), + SIZEOF(gtm_int_t *) + SIZEOF(gtm_int_t), + SIZEOF(gtm_long_t *) + SIZEOF(gtm_long_t), + SIZEOF(gtm_float_t *) + SIZEOF(gtm_float_t), + SIZEOF(gtm_double_t *) + SIZEOF(gtm_double_t), + SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t), + SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t), + SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t) }; error_def(ERR_CIDIRECTIVE); @@ -111,8 +128,8 @@ error_def(ERR_ZCUNAVAIL); error_def(ERR_ZCUNTYPE); error_def(ERR_ZCUSRRTN); -/* manage local get_memory'ed space (the space is never returned) */ -static void *get_memory(size_t n) +/* Manage local get_memory'ed space (the space is never returned) */ +STATICFNDEF void *get_memory(size_t n) { void *x; static void *heap_base = 0; @@ -139,19 +156,19 @@ static void *get_memory(size_t n) return x; } -/* skip white space */ -static char *scan_space(char *c) +/* Skip white space */ +STATICFNDEF char *exttab_scan_space(char *c) { for ( ; ISSPACE_ASCII(*c); c++, ext_source_column++) ; return c; } -/* if this is an identifier (alphameric and underscore), then - return the address after the end of the identifier. - Otherwise, return zero - */ -static char *scan_ident(char *c) +/* If this is an identifier (alphameric and underscore), then + * return the address after the end of the identifier. + * Otherwise, return zero + */ +STATICFNDEF char *scan_ident(char *c) { char *b; @@ -161,11 +178,11 @@ static char *scan_ident(char *c) return (b == c) ? 0 : b; } -/* if this is a label (alphameric, underscore, caret, and percent (C9E12-002681)), then - return the address after the end of the label. - Otherwise, return zero - */ -static char *scan_labelref(char *c) +/* If this is a label (alphameric, underscore, caret, and percent (C9E12-002681)), then + * return the address after the end of the label. + * Otherwise, return zero. + */ +STATICFNDEF char *scan_labelref(char *c) { char *b = c; @@ -174,65 +191,72 @@ static char *scan_labelref(char *c) return (b == c) ? 0 : b; } -static enum xc_types scan_keyword(char **c) +STATICFNDEF enum gtm_types scan_keyword(char **c) { const static struct { char nam[MAX_NAM_LEN]; - enum xc_types typ[MAXIMUM_STARS + 1]; /* one entry for each level of indirection eg [1] is type* */ + enum gtm_types typ[MAXIMUM_STARS + 1]; /* One entry for each level of indirection eg [1] is type* */ } xctab[] = { - /* typename type type * type ** */ + /* typename type type * type ** */ - {"void", xc_void, xc_notfound, xc_notfound }, + {"void", gtm_void, gtm_notfound, gtm_notfound }, - {"gtm_int_t", xc_int, xc_int_star, xc_notfound }, - {"xc_int_t", xc_int, xc_int_star, xc_notfound }, - {"int", xc_int, xc_int_star, xc_notfound }, + {"gtm_int_t", gtm_int, gtm_int_star, gtm_notfound }, + {"gtm_jboolean_t", gtm_jboolean, gtm_notfound, gtm_notfound }, + {"gtm_jint_t", gtm_jint, gtm_notfound, gtm_notfound }, + {"xc_int_t", gtm_int, gtm_int_star, gtm_notfound }, + {"int", gtm_int, gtm_notfound, gtm_notfound }, - {"gtm_uint_t", xc_uint, xc_uint_star, xc_notfound }, - {"xc_uint_t", xc_uint, xc_uint_star, xc_notfound }, - {"uint", xc_uint, xc_uint_star, xc_notfound }, + {"gtm_uint_t", gtm_uint, gtm_uint_star, gtm_notfound }, + {"xc_uint_t", gtm_uint, gtm_uint_star, gtm_notfound }, + {"uint", gtm_uint, gtm_uint_star, gtm_notfound }, - {"gtm_long_t", xc_long, xc_long_star, xc_notfound }, - {"xc_long_t", xc_long, xc_long_star, xc_notfound }, - {"long", xc_long, xc_long_star, xc_notfound }, + {"gtm_long_t", gtm_long, gtm_long_star, gtm_notfound }, + {"gtm_jlong_t", gtm_jlong, gtm_notfound, gtm_notfound }, + {"xc_long_t", gtm_long, gtm_long_star, gtm_notfound }, + {"long", gtm_long, gtm_long_star, gtm_notfound }, - {"gtm_ulong_t", xc_ulong, xc_ulong_star, xc_notfound }, - {"xc_ulong_t", xc_ulong, xc_ulong_star, xc_notfound }, - {"ulong", xc_ulong, xc_ulong_star, xc_notfound }, + {"gtm_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound }, + {"xc_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound }, + {"ulong", gtm_ulong, gtm_ulong_star, gtm_notfound }, - {"gtm_status_t", xc_status, xc_notfound, xc_notfound }, - {"xc_status_t", xc_status, xc_notfound, xc_notfound }, + {"gtm_status_t", gtm_status, gtm_notfound, gtm_notfound }, + {"xc_status_t", gtm_status, gtm_notfound, gtm_notfound }, - {"gtm_char_t", xc_notfound, xc_char_star, xc_char_starstar }, - {"xc_char_t", xc_notfound, xc_char_star, xc_char_starstar }, - {"char", xc_notfound, xc_char_star, xc_char_starstar }, + {"gtm_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar }, + {"gtm_jstring_t", gtm_jstring, gtm_notfound, gtm_notfound }, + {"gtm_jbyte_array_t", gtm_jbyte_array, gtm_notfound, gtm_notfound }, + {"gtm_jbig_decimal_t", gtm_jbig_decimal, gtm_notfound, gtm_notfound }, + {"xc_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar }, + {"char", gtm_notfound, gtm_char_star, gtm_char_starstar }, - {"gtm_string_t", xc_notfound, xc_string_star, xc_notfound }, - {"xc_string_t", xc_notfound, xc_string_star, xc_notfound }, - {"string", xc_notfound, xc_string_star, xc_notfound }, + {"gtm_string_t", gtm_notfound, gtm_string_star, gtm_notfound }, + {"xc_string_t", gtm_notfound, gtm_string_star, gtm_notfound }, + {"string", gtm_notfound, gtm_string_star, gtm_notfound }, - {"gtm_float_t", xc_float, xc_float_star, xc_notfound }, - {"xc_float_t", xc_float, xc_float_star, xc_notfound }, - {"float", xc_float, xc_float_star, xc_notfound }, + {"gtm_float_t", gtm_float, gtm_float_star, gtm_notfound }, + {"gtm_jfloat_t", gtm_jfloat, gtm_notfound, gtm_notfound }, + {"xc_float_t", gtm_float, gtm_float_star, gtm_notfound }, + {"float", gtm_float, gtm_float_star, gtm_notfound }, - {"gtm_double_t", xc_double, xc_double_star, xc_notfound }, - {"xc_double_t", xc_double, xc_double_star, xc_notfound }, - {"double", xc_double, xc_double_star, xc_notfound }, + {"gtm_double_t", gtm_double, gtm_double_star, gtm_notfound }, + {"gtm_jdouble_t", gtm_jdouble, gtm_notfound, gtm_notfound }, + {"xc_double_t", gtm_double, gtm_double_star, gtm_notfound }, + {"double", gtm_double, gtm_double_star, gtm_notfound }, - {"gtm_pointertofunc_t", xc_pointertofunc, xc_pointertofunc_star, xc_notfound }, - {"xc_pointertofunc_t", xc_pointertofunc, xc_pointertofunc_star, xc_notfound } + {"gtm_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound }, + {"xc_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound } }; - char *b = *c; char *d; int len, i, star_count; - b = scan_space(b); + b = exttab_scan_space(b); d = scan_ident(b); if (!d) - return xc_notfound; + return gtm_notfound; len = (int)(d - b); for (i = 0 ; i < SIZEOF(xctab) / SIZEOF(xctab[0]) ; i++) { @@ -242,29 +266,28 @@ static enum xc_types scan_keyword(char **c) /* scan stars */ for (star_count = 0; (MAXIMUM_STARS >= star_count); star_count++, d++) { - d = scan_space(d); + d = exttab_scan_space(d); if ('*' != *d) break; star_found = TRUE; } assert(star_count <= MAXIMUM_STARS); - *c = scan_space(d); + *c = exttab_scan_space(d); return xctab[i].typ[star_count]; } } - return xc_notfound; + return gtm_notfound; } -static int scan_array_bound(char **b,int curr_type) +STATICFNDEF int scan_array_bound(char **b,int curr_type) { char number[MAX_DIGITS_IN_INT]; char *c; - char *line; int index; const static int default_pre_alloc_value[] = { - 0, /* Unknown Type */ + 0, /* unknown Type */ 0, /* void */ 0, /* status */ 0, /* int */ @@ -275,20 +298,28 @@ static int scan_array_bound(char **b,int curr_type) 0, /* double */ 1, /* pointer to int */ 1, /* pointer to unsigned int */ - 1, /* Pointer to long */ - 1, /* Pointer to unsigned long */ - 1, /* Pointer to string */ - 1, /* Pointer to float */ - 100, /* Pointer to char */ - 1, /* Pointer to pointer of char */ - 1, /* Pointer to double */ - 1, /* Pointer to function */ - 1 /* Pointer to pointer to function */ + 1, /* pointer to long */ + 1, /* pointer to unsigned long */ + 1, /* pointer to string */ + 1, /* pointer to float */ + 100, /* pointer to char */ + 1, /* pointer to pointer of char */ + 1, /* pointer to double */ + 1, /* pointer to function */ + 1, /* pointer to pointer to function */ + 1, /* java int */ + 1, /* java int */ + 1, /* java long */ + 1, /* java float */ + 1, /* java double */ + 1, /* java string */ + 1, /* java byte array */ + 1 /* java big decimal */ }; c = *b; - /* already found '[' */ - for (index=0, c++; ']' != *c; c++) + /* Already found '[' */ + for (index = 0, c++; ']' != *c; c++) { if ('\0' != *c) { @@ -299,7 +330,7 @@ static int scan_array_bound(char **b,int curr_type) } else ext_stx_error(ERR_ZCCSQRBR, ext_table_file_name); } - c++; /* skip ']' */ + c++; /* Skip ']' */ *b = c; if (0 == index) return default_pre_alloc_value[curr_type]; @@ -307,9 +338,10 @@ static int scan_array_bound(char **b,int curr_type) return ATOI(number); } -static char *read_table(char *b, int l, FILE *f) +STATICFNDEF char *read_table(char *b, int l, FILE *f) { char *t; + int fclose_res; ext_source_column = 0; FGETS(b, l, f, t); @@ -317,15 +349,14 @@ static char *read_table(char *b, int l, FILE *f) { if (0 != ferror(f)) { - int fclose_res; FCLOSE(f, fclose_res); /* Expand error message */ - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); } else assert(feof(f) != 0); } else { - /* unfortunately, fgets does not strip the NL, we will do it for it */ + /* Unfortunately, fgets does not strip the NL, we will do it for it */ for (ext_source_line_len = 0; *t ; t++) { ext_source_line[ext_source_line_len++] = *t; @@ -340,11 +371,11 @@ static char *read_table(char *b, int l, FILE *f) return t; } -/* utility routine to store static mstr's which will remain for the duration of the process - * These mstr's will have a trailing null attached so that UNIX system routines can operate - * on them directly as const char *'s +/* Utility routine to store static mstr's which will remain for the duration of the process + * These mstr's will have a trailing null attached so that UNIX system routines can operate + * on them directly as const char *'s */ -static void put_mstr(mstr *src, mstr *dst) +STATICFNDEF void put_mstr(mstr *src, mstr *dst) { char *cp; ssize_t n; @@ -360,8 +391,8 @@ static void put_mstr(mstr *src, mstr *dst) return; } -/* utility to convert an array of bool's to a bit mask */ -static uint4 array_to_mask(boolean_t ar[MAX_ACTUALS], int n) +/* Utility to convert an array of bool's to a bit mask */ +STATICFNDEF uint4 array_to_mask(boolean_t ar[MAX_ACTUALS], int n) { uint4 mask = 0; int i; @@ -374,8 +405,8 @@ static uint4 array_to_mask(boolean_t ar[MAX_ACTUALS], int n) return mask; } -/* Note: need condition handler to clean-up allocated structures and close intput file in the event of an error */ -struct extcall_package_list *exttab_parse(mval *package) +/* Note: Need condition handler to clean-up allocated structures and close intput file in the event of an error */ +struct extcall_package_list *exttab_parse(mval *package) { int parameter_alloc_values[MAX_ACTUALS], parameter_count, ret_pre_alloc_val, i, fclose_res; int len, keywordlen; @@ -383,12 +414,13 @@ struct extcall_package_list *exttab_parse(mval *package) mstr callnam, rtnnam, clnuprtn; mstr val, trans; void_ptr_t pakhandle; - enum xc_types ret_tok, parameter_types[MAX_ACTUALS], pr; + enum gtm_types ret_tok, parameter_types[MAX_ACTUALS], pr; char str_buffer[MAX_TABLINE_LEN], *tbp, *end; char str_temp_buffer[MAX_TABLINE_LEN]; FILE *ext_table_file_handle; struct extcall_package_list *pak; struct extcall_entry_list *entry_ptr; + /* First, construct package name environment variable */ memcpy(str_buffer, PACKAGE_ENV_PREFIX, SIZEOF(PACKAGE_ENV_PREFIX)); tbp = &str_buffer[SIZEOF(PACKAGE_ENV_PREFIX) - 1]; @@ -406,21 +438,21 @@ struct extcall_package_list *exttab_parse(mval *package) if (NULL == ext_table_file_name) { /* Environment variable for the package not found */ - rts_error(VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer)); } ext_table_file_handle = Fopen(ext_table_file_name, "r"); if (NULL == ext_table_file_handle) { /* Package's external call table could not be found */ - rts_error(VARLSTCNT(4) ERR_ZCCTOPN, 2, LEN_AND_STR(ext_table_file_name)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTOPN, 2, LEN_AND_STR(ext_table_file_name)); } ext_source_line_num = 0; - /* pick-up name of shareable library */ + /* Pick-up name of shareable library */ tbp = read_table(LIT_AND_LEN(str_buffer), ext_table_file_handle); if (NULL == tbp) { /* External call table is a null file */ - rts_error(VARLSTCNT(4) ERR_ZCCTNULLF, 2, package->str.len, package->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTNULLF, 2, package->str.len, package->str.addr); } STRNCPY_STR(str_temp_buffer, str_buffer, MAX_TABLINE_LEN); val.addr = str_temp_buffer; @@ -435,13 +467,13 @@ struct extcall_package_list *exttab_parse(mval *package) if (SS_LOG2LONG == TRANS_LOG_NAME(&val, &trans, str_buffer, SIZEOF(str_buffer), dont_sendmsg_on_log2long)) { /* Env variable expansion in the pathname caused buffer overflow */ - rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.len, val.addr, SIZEOF(str_buffer) - 1); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.len, val.addr, SIZEOF(str_buffer) - 1); } pakhandle = fgn_getpak(str_buffer, INFO); if (NULL == pakhandle) { /* Unable to obtain handle to the shared library */ - rts_error(VARLSTCNT(4) ERR_ZCUNAVAIL, 2, package->str.len, package->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCUNAVAIL, 2, package->str.len, package->str.addr); } pak = get_memory(SIZEOF(*pak)); pak->first_entry = 0; @@ -450,17 +482,17 @@ struct extcall_package_list *exttab_parse(mval *package) pak->package_clnup_rtn = NULL; len = STRLEN("GTMSHLIBEXIT"); /* At this point, we have a valid package, pointed to by pak */ -#ifdef DEBUG_EXTCALL +# ifdef DEBUG_EXTCALL FPRINTF(stderr, "GT.M external call opened package name: %s\n", pak->package_name.addr); -#endif +# endif for (;;) { star_found = FALSE; tbp = read_table(LIT_AND_LEN(str_buffer), ext_table_file_handle); if (NULL == tbp) break; - tbp = scan_space(str_buffer); - /* empty line? */ + tbp = exttab_scan_space(str_buffer); + /* Empty line? */ if (!*tbp) continue; /* No, must be entryref or keyword */ @@ -468,7 +500,7 @@ struct extcall_package_list *exttab_parse(mval *package) if (!end) ext_stx_error(ERR_ZCENTNAME, ext_table_file_name); keywordlen = end - tbp; - end = scan_space(end); + end = exttab_scan_space(end); if ('=' == *end) { /* Keyword before '=' has a string of size == STRLEN("GTMSHLIBEXIT") */ if (keywordlen == len) @@ -476,7 +508,7 @@ struct extcall_package_list *exttab_parse(mval *package) if (0 == MEMCMP_LIT(tbp, "GTMSHLIBEXIT")) { /* Skip past the '=' char */ - tbp = scan_space(end + 1); + tbp = exttab_scan_space(end + 1); if (*tbp) { /* We have a cleanup routine name */ clnuprtn.addr = tbp; @@ -501,37 +533,45 @@ struct extcall_package_list *exttab_parse(mval *package) } rtnnam.addr = tbp; rtnnam.len = INTCAST(end - tbp); - tbp = scan_space(end); + tbp = exttab_scan_space(end); if (':' != *tbp++) ext_stx_error(ERR_ZCCOLON, ext_table_file_name); - /* get return type */ + /* Get return type */ ret_tok = scan_keyword(&tbp); - /* check for legal return type */ + /* Check for legal return type */ switch (ret_tok) { - case xc_status: - case xc_void: - case xc_int: - case xc_uint: - case xc_long: - case xc_ulong: - case xc_char_star: - case xc_float_star: - case xc_string_star: - case xc_int_star: - case xc_uint_star: - case xc_long_star: - case xc_ulong_star: - case xc_double_star: - case xc_char_starstar: - case xc_pointertofunc: - case xc_pointertofunc_star: + case gtm_status: + case gtm_void: + case gtm_int: + case gtm_uint: + case gtm_long: + case gtm_ulong: + case gtm_char_star: + case gtm_float_star: + case gtm_string_star: + case gtm_int_star: + case gtm_uint_star: + case gtm_long_star: + case gtm_ulong_star: + case gtm_double_star: + case gtm_char_starstar: + case gtm_pointertofunc: + case gtm_pointertofunc_star: + case gtm_jboolean: + case gtm_jint: + case gtm_jlong: + case gtm_jfloat: + case gtm_jdouble: + case gtm_jstring: + case gtm_jbyte_array: + case gtm_jbig_decimal: break; default: ext_stx_error(ERR_ZCRTNTYP, ext_table_file_name); } - got_status = (ret_tok == xc_status); - /* get call name */ + got_status = (ret_tok == gtm_status); + /* Get call name */ if ('[' == *tbp) { if (star_found) @@ -539,7 +579,8 @@ struct extcall_package_list *exttab_parse(mval *package) else ext_stx_error(ERR_ZCPREALLVALPAR, ext_table_file_name); /* We should allow the pre-allocated value upto to the maximum string size (MAX_STRLEN) plus 1 for the - * extra terminating NULL. Negative values would have been caught by scan_array_bound() above */ + * extra terminating NULL. Negative values would have been caught by scan_array_bound() above. + */ if (ret_pre_alloc_val > MAX_STRLEN + 1) ext_stx_error(ERR_ZCPREALLVALINV, ext_table_file_name); } else @@ -552,19 +593,19 @@ struct extcall_package_list *exttab_parse(mval *package) ext_stx_error(ERR_ZCRCALLNAME, ext_table_file_name); callnam.addr = tbp; callnam.len = INTCAST(end - tbp); - tbp = scan_space(end); - tbp = scan_space(tbp); + tbp = exttab_scan_space(end); + tbp = exttab_scan_space(tbp); for (parameter_count = 0;(MAX_ACTUALS > parameter_count) && (')' != *tbp); parameter_count++) { star_found = FALSE; - /* must have comma if this is not the first parameter, otherwise '(' */ + /* Must have comma if this is not the first parameter, otherwise '(' */ if (((0 == parameter_count)?'(':',') != *tbp++) ext_stx_error(ERR_ZCRPARMNAME, ext_table_file_name); - tbp = scan_space(tbp); - /* special case: () is ok */ + tbp = exttab_scan_space(tbp); + /* Special case: () is ok */ if ((0 == parameter_count) && (*tbp == ')')) break; - /* looking for an I, an O or an IO */ + /* Looking for an I, an O or an IO */ is_input[parameter_count] = is_output[parameter_count] = FALSE; if ('I' == *tbp) { @@ -579,11 +620,11 @@ struct extcall_package_list *exttab_parse(mval *package) if (((FALSE == is_input[parameter_count]) && (FALSE == is_output[parameter_count])) ||(':' != *tbp++)) ext_stx_error(ERR_ZCRCALLNAME, ext_table_file_name); - /* scanned colon--now get type */ + /* Scanned colon--now get type */ pr = scan_keyword(&tbp); - if (xc_notfound == pr) + if (gtm_notfound == pr) ext_stx_error(ERR_ZCUNTYPE, ext_table_file_name); - if (xc_status == pr) + if (gtm_status == pr) { /* Only one type "status" allowed per call */ if (got_status) @@ -599,12 +640,13 @@ struct extcall_package_list *exttab_parse(mval *package) else ext_stx_error(ERR_ZCPREALLVALPAR, ext_table_file_name); /* We should allow the pre-allocated value upto to the maximum string size (MAX_STRLEN) plus 1 for - * the extra terminating NULL. Negative values would have been caught by scan_array_bound() above */ + * the extra terminating NULL. Negative values would have been caught by scan_array_bound() above. + */ if (parameter_alloc_values[parameter_count] > MAX_STRLEN + 1) ext_stx_error(ERR_ZCPREALLVALINV, ext_table_file_name); } else parameter_alloc_values[parameter_count] = -1; - tbp = scan_space(tbp); + tbp = exttab_scan_space(tbp); } entry_ptr = get_memory(SIZEOF(*entry_ptr)); entry_ptr->next_entry = pak->first_entry; @@ -620,70 +662,80 @@ struct extcall_package_list *exttab_parse(mval *package) for (i = 0 ; i < parameter_count; i++) { entry_ptr->parms[i] = parameter_types[i]; + assert(gtm_void != parameter_types[i]); entry_ptr->parmblk_size += parm_space_needed[parameter_types[i]]; entry_ptr->param_pre_alloc_size[i] = parameter_alloc_values[i]; } put_mstr(&rtnnam, &entry_ptr->entry_name); put_mstr(&callnam, &entry_ptr->call_name); - /* the reason for passing INFO severity is that PROFILE has several routines listed in + /* The reason for passing INFO severity is that PROFILE has several routines listed in * the external call table that are not in the shared library. PROFILE folks would * rather see info/warning messages for such routines at shared library open time, * than error out. These unimplemented routines, they say were not being called from * the application and wouldn't cause any application failures. If we fail to open * the shared libary, or we fail to locate a routine that is called from the - * application, we issue rts_error message (in extab_parse.c) */ + * application, we issue rts_error message (in extab_parse.c). + */ entry_ptr->fcn = fgn_getrtn(pak->package_handle, &entry_ptr->call_name, INFO); -#ifdef DEBUG_EXTCALL +# ifdef DEBUG_EXTCALL FPRINTF(stderr, " package entry point: %s, address: %x\n", entry_ptr->entry_name.addr, entry_ptr->fcn); -#endif +# endif } FCLOSE(ext_table_file_handle, fclose_res); return pak; } -callin_entry_list* citab_parse (void) +callin_entry_list* citab_parse (void) { int parameter_count, i, fclose_res; uint4 inp_mask, out_mask, mask; mstr labref, callnam; - enum xc_types ret_tok, parameter_types[MAX_ACTUALS], pr; + enum gtm_types ret_tok, parameter_types[MAX_ACTUALS], pr; char str_buffer[MAX_TABLINE_LEN], *tbp, *end; FILE *ext_table_file_handle; - callin_entry_list *entry_ptr, *save_entry_ptr = 0; + callin_entry_list *entry_ptr = NULL, *save_entry_ptr = NULL; ext_table_file_name = GETENV(CALLIN_ENV_NAME); if (!ext_table_file_name) /* environment variable not set */ - rts_error(VARLSTCNT(4) ERR_CITABENV, 2, LEN_AND_STR(CALLIN_ENV_NAME)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CITABENV, 2, LEN_AND_STR(CALLIN_ENV_NAME)); ext_table_file_handle = Fopen(ext_table_file_name, "r"); if (!ext_table_file_handle) /* call-in table not found */ - rts_error(VARLSTCNT(11) ERR_CITABOPN, 2, LEN_AND_STR(ext_table_file_name), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_CITABOPN, 2, LEN_AND_STR(ext_table_file_name), ERR_SYSCALL, 5, LEN_AND_LIT("fopen"), CALLFROM, errno); ext_source_line_num = 0; while (read_table(LIT_AND_LEN(str_buffer), ext_table_file_handle)) { - if (!*(tbp = scan_space(str_buffer))) + if (!*(tbp = exttab_scan_space(str_buffer))) continue; if (!(end = scan_ident(tbp))) ext_stx_error(ERR_CIRCALLNAME, ext_table_file_name); callnam.addr = tbp; callnam.len = INTCAST(end - tbp); - tbp = scan_space(end); + tbp = exttab_scan_space(end); if (':' != *tbp++) ext_stx_error(ERR_COLON, ext_table_file_name); ret_tok = scan_keyword(&tbp); /* return type */ switch (ret_tok) /* return type valid ? */ { - case xc_void: - case xc_char_star: - case xc_int_star: - case xc_uint_star: - case xc_long_star: - case xc_ulong_star: - case xc_float_star: - case xc_double_star: - case xc_string_star: + case gtm_void: + case gtm_char_star: + case gtm_int_star: + case gtm_uint_star: + case gtm_long_star: + case gtm_ulong_star: + case gtm_float_star: + case gtm_double_star: + case gtm_string_star: + case gtm_jboolean: + case gtm_jint: + case gtm_jlong: + case gtm_jfloat: + case gtm_jdouble: + case gtm_jstring: + case gtm_jbyte_array: + case gtm_jbig_decimal: break; default: ext_stx_error(ERR_CIRTNTYP, ext_table_file_name); @@ -693,7 +745,7 @@ callin_entry_list* citab_parse (void) labref.len = INTCAST(end - tbp); else ext_stx_error(ERR_CIENTNAME, ext_table_file_name); - tbp = scan_space(end); + tbp = exttab_scan_space(end); inp_mask = out_mask = 0; for (parameter_count = 0; (*tbp && ')' != *tbp); parameter_count++) { @@ -702,7 +754,7 @@ callin_entry_list* citab_parse (void) /* must have comma if this is not the first parameter, otherwise '(' */ if (((0 == parameter_count)?'(':',') != *tbp++) ext_stx_error(ERR_CIRPARMNAME, ext_table_file_name); - tbp = scan_space(tbp); + tbp = exttab_scan_space(tbp); if ((0 == parameter_count) && (*tbp == ')')) /* special case () */ break; /* looking for an I, a O or an IO */ @@ -713,29 +765,37 @@ callin_entry_list* citab_parse (void) ext_stx_error(ERR_CIDIRECTIVE, ext_table_file_name); switch ((pr = scan_keyword(&tbp))) /* valid param type? */ { - case xc_int: - case xc_uint: - case xc_long: - case xc_ulong: - case xc_float: - case xc_double: + case gtm_int: + case gtm_uint: + case gtm_long: + case gtm_ulong: + case gtm_float: + case gtm_double: if (out_mask & mask) ext_stx_error(ERR_CIPARTYPE, ext_table_file_name); /* fall-thru */ - case xc_char_star: - case xc_int_star: - case xc_uint_star: - case xc_long_star: - case xc_ulong_star: - case xc_float_star: - case xc_double_star: - case xc_string_star: + case gtm_char_star: + case gtm_int_star: + case gtm_uint_star: + case gtm_long_star: + case gtm_ulong_star: + case gtm_float_star: + case gtm_double_star: + case gtm_string_star: + case gtm_jboolean: + case gtm_jint: + case gtm_jlong: + case gtm_jfloat: + case gtm_jdouble: + case gtm_jstring: + case gtm_jbyte_array: + case gtm_jbig_decimal: break; default: ext_stx_error(ERR_CIUNTYPE, ext_table_file_name); } parameter_types[parameter_count] = pr; - tbp = scan_space(tbp); + tbp = exttab_scan_space(tbp); } if (!*tbp) ext_stx_error(ERR_CIRPARMNAME, ext_table_file_name); @@ -756,7 +816,7 @@ callin_entry_list* citab_parse (void) return entry_ptr; } -static void ext_stx_error(int in_error, ...) +STATICFNDEF void ext_stx_error(int in_error, ...) { va_list args; char *ext_table_name; @@ -781,5 +841,5 @@ static void ext_stx_error(int in_error, ...) dec_err(VARLSTCNT(6) ERR_EXTSRCLIN, 4, ext_source_line_len, ext_source_line, b - &buf[0], &buf[0]); dec_err(VARLSTCNT(6) ERR_EXTSRCLOC, 4, ext_source_column, ext_source_line_num, LEN_AND_STR(ext_table_name)); - rts_error(VARLSTCNT(1) in_error); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) in_error); } diff --git a/sr_unix/fgncalsp.h b/sr_unix/fgncalsp.h index 3b6881c..e13f387 100644 --- a/sr_unix/fgncalsp.h +++ b/sr_unix/fgncalsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -66,51 +66,60 @@ struct extcall_package_list clnupfptr package_clnup_rtn; }; -enum xc_types +enum gtm_types { - xc_notfound, - xc_void, - xc_status, - xc_int, - xc_uint, - xc_long, - xc_ulong, - xc_float, - xc_double, - xc_int_star, - xc_uint_star, - xc_long_star, - xc_ulong_star, - xc_string_star, - xc_float_star, - xc_char_star, - xc_char_starstar, - xc_double_star, - xc_pointertofunc, - xc_pointertofunc_star + gtm_notfound, + gtm_void, + gtm_status, + gtm_int, + gtm_uint, + gtm_long, + gtm_ulong, + gtm_float, + gtm_double, + gtm_int_star, + gtm_uint_star, + gtm_long_star, + gtm_ulong_star, + gtm_string_star, + gtm_float_star, + gtm_char_star, + gtm_char_starstar, + gtm_double_star, + gtm_pointertofunc, + gtm_pointertofunc_star, + gtm_jboolean, + gtm_jint, + gtm_jlong, + gtm_jfloat, + gtm_jdouble, + gtm_jstring, + gtm_jbyte_array, + gtm_jbig_decimal }; -enum callintogtm_fncs { - xc_hiber_start, - xc_hiber_start_any, - xc_start_timer, - xc_cancel_timer, - xc_gtm_malloc, - xc_gtm_free, - xc_unknown_function +enum callintogtm_fncs +{ + gtmfunc_hiber_start, + gtmfunc_hiber_start_any, + gtmfunc_start_timer, + gtmfunc_cancel_timer, + gtmfunc_gtm_malloc, + gtmfunc_gtm_free, + gtmfunc_unknown_function }; /* There is one of these for each external routine. Each is owned by a package. */ struct extcall_entry_list { struct extcall_entry_list *next_entry; - enum xc_types return_type; /* function return value */ + enum gtm_types return_type; /* function return value */ int ret_pre_alloc_val; /* amount of space to be pre-allocated for the return type */ uint4 input_mask; /* is it an input parameter lsb = 1st parm */ uint4 output_mask; /* is it an output parameter lsb = 1st parm */ int parmblk_size; /* size in bytes of parameter block to be allocated for call*/ int argcnt; /* number of arguments */ - enum xc_types *parms; /* pointer to parameter array */ + enum gtm_types *parms; /* pointer to parameter array */ int *param_pre_alloc_size; /* amount of space to be pre-allocated for the parameters */ fgnfnc fcn; /* address of runtime routine */ mstr entry_name; /* name of M entryref */ @@ -126,8 +135,8 @@ typedef struct callin_entry_list uint4 input_mask; /* input parameter? LSB = 1st parm */ uint4 output_mask; /* output parameter? LSB = 1st parm */ unsigned short argcnt; /* number of arguments */ - enum xc_types return_type; - enum xc_types *parms; /* parameter types */ + enum gtm_types return_type; + enum gtm_types *parms; /* parameter types */ struct callin_entry_list *next_entry; } callin_entry_list; diff --git a/sr_unix/file_head_write.c b/sr_unix/file_head_write.c index 42e18a3..c61ce83 100644 --- a/sr_unix/file_head_write.c +++ b/sr_unix/file_head_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,10 +28,17 @@ #include "eintr_wrappers.h" #include "file_head_write.h" #include "gtmmsg.h" +#include "jnl.h" +#include "anticipatory_freeze.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif +error_def(ERR_DBFILOPERR); +error_def(ERR_DBNOTGDS); +error_def(ERR_TEXT); +ZOS_ONLY(error_def(ERR_BADTAG);) + /* * This is a plain way to write file header to database. * User needs to take care of concurrency issue etc. @@ -45,11 +52,6 @@ boolean_t file_head_write(char *fn, sgmnt_data_ptr_t header, int4 len) int save_errno, fd, header_size; ZOS_ONLY(int realfiletag;) - error_def(ERR_DBFILOPERR); - error_def(ERR_DBNOTGDS); - error_def(ERR_TEXT); - ZOS_ONLY(error_def(ERR_BADTAG);) - header_size = (int)SIZEOF_FILE_HDR(header); assert(SGMNT_HDR_LEN == len || header_size == len); OPENFILE(fn, O_RDWR, fd); @@ -63,7 +65,7 @@ boolean_t file_head_write(char *fn, sgmnt_data_ptr_t header, int4 len) if (-1 == gtm_zos_tag_to_policy(fd, TAG_BINARY, &realfiletag)) TAG_POLICY_GTM_PUTMSG(fn, errno, realfiletag, TAG_BINARY); #endif - LSEEKWRITE(fd, 0, header, len, save_errno); + DB_LSEEKWRITE(NULL, NULL, fd, 0, header, len, save_errno); if (0 != save_errno) { gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno); diff --git a/sr_unix/file_input.c b/sr_unix/file_input.c index c889071..487996f 100644 --- a/sr_unix/file_input.c +++ b/sr_unix/file_input.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,8 @@ #define BUFF_SIZE 65535 GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace); -GBLREF io_pair io_curr_device; +GBLREF uint4 dollar_tlevel; +GBLREF io_pair io_curr_device; error_def(ERR_LOADFILERR); error_def(ERR_PREMATEOF); @@ -40,6 +41,7 @@ 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 char *load_fn_ptr; static int load_fn_len; static readonly unsigned char open_params_list[] = @@ -78,6 +80,7 @@ void file_input_init(char *fn, short fn_len) load_fn_ptr = fn; load_fn_len = fn_len; buff1_ptr = buff1; + buff1_ptr_file_offset = 0; buff1_end = buff1; REVERT; return; @@ -96,7 +99,7 @@ void file_input_close(void) op_close(&val, &pars); } -int file_input_bin_get(char **in_ptr) +int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base) { char *ptr; int rd_cnt, rd_len, s1; @@ -138,6 +141,8 @@ int file_input_bin_get(char **in_ptr) } *in_ptr = buff1_ptr; buff1_ptr += s1; + *file_offset = buff1_ptr_file_offset; + *buff_base = buff1; REVERT; return s1; } @@ -155,6 +160,7 @@ int file_input_bin_read(void) assert(NULL != d_rm); assert(BUFF_SIZE - s1); buff1_end = buff1 + s1; + buff1_ptr_file_offset += (buff1_ptr - buff1); buff1_ptr = buff1; DOREADRL(d_rm->fildes, buff1_end, BUFF_SIZE - s1, rdlen); # ifdef DEBUG_FO_BIN @@ -167,17 +173,18 @@ int file_input_bin_read(void) int file_input_get(char **in_ptr) { - char *ptr; - int rd_len, ret_len, s1; + char *ptr, *tmp_ptr; + int rd_len, s1; mval val; + static unsigned int mbuff_len = BUFF_SIZE; + unsigned int new_mbuff_len, ret_len; + static char *mbuff = buff1; ESTABLISH_RET(mupip_load_ch, 0); - buff1_ptr = buff1_end = buff1; ret_len = 0; for (;;) - { - /* do untimed reads */ - op_read(&val, NO_M_TIMEOUT); + { /* one-time only reads if in TP to avoid TPNOTACID, otherwise use untimed reads */ + op_read(&val, dollar_tlevel ? 0: NO_M_TIMEOUT); rd_len = val.str.len; if ((0 == rd_len) && io_curr_device.in->dollar.zeof) { @@ -186,17 +193,32 @@ int file_input_get(char **in_ptr) rts_error(VARLSTCNT(1) ERR_PREMATEOF); return -1; } - ret_len += rd_len; - if (SIZEOF(buff1) < ret_len) + if (mbuff_len < ret_len + rd_len) { - REVERT; - return -1; + new_mbuff_len = MAX(ret_len,(2 * mbuff_len)); + tmp_ptr = (char *)malloc(new_mbuff_len); + if (NULL == tmp_ptr) + { + REVERT; + return -1; + } + if (mbuff != buff1) + { + memcpy(tmp_ptr, mbuff, (ret_len)); + free (mbuff); + } + else + memcpy(tmp_ptr, buff1, (ret_len)); + + mbuff = tmp_ptr; + mbuff_len = new_mbuff_len; + } - memcpy(buff1_end, val.str.addr, rd_len); - buff1_end = buff1_end + rd_len; + memcpy((unsigned char *) (mbuff + ret_len), val.str.addr, rd_len); + ret_len += rd_len; if ( !(io_curr_device.in->dollar.x) ) { - *in_ptr = buff1_ptr; + *in_ptr = mbuff; REVERT; return ret_len; } diff --git a/sr_unix/file_input.h b/sr_unix/file_input.h index 589dc9a..99101e9 100644 --- a/sr_unix/file_input.h +++ b/sr_unix/file_input.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,7 +14,7 @@ void file_input_init(char *fn, short fn_len); void file_input_close(void); -int file_input_bin_get(char **in_ptr); +int file_input_bin_get(char **in_ptr, ssize_t *file_offset, char **buff_base); int file_input_bin_read(void); int file_input_get(char **in_ptr); diff --git a/sr_unix/filestruct.h b/sr_unix/filestruct.h index 7cb82cb..55893c4 100644 --- a/sr_unix/filestruct.h +++ b/sr_unix/filestruct.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -29,8 +29,12 @@ typedef struct unix_db_info_struct int shmid; time_t gt_shm_ctime; int ftok_semid; + boolean_t new_shm; + boolean_t new_sem; boolean_t grabbed_ftok_sem; boolean_t grabbed_access_sem; + boolean_t counter_acc_incremented; + boolean_t counter_ftok_incremented; key_t key; bool raw; } unix_db_info; diff --git a/sr_unix/fork_init.h b/sr_unix/fork_init.h index 8aea125..d14a369 100644 --- a/sr_unix/fork_init.h +++ b/sr_unix/fork_init.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011, 2012 Fidelity Information Services, Inc.* + * Copyright 2011, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,8 @@ #ifndef _FORK_INIT_H #define _FORK_INIT_H +#include "have_crit.h" + /* This macro takes care of safely clearing the timer queue and resetting the * timer-related globals when we need to fork-off a process. Please note that * it is unnecessary to use this macro when the fork is immediately followed @@ -20,11 +22,19 @@ * situations, append BYPASSOK comment directives to the lines with fork * instances. */ + #define FORK_CLEAN(pid) \ { \ - pid = fork(); \ + FORK(pid); \ if (0 == pid) \ clear_timers(); \ } +#define FORK(pid) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM) \ + pid = fork(); \ + ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM) \ +} + #endif diff --git a/sr_unix/ftok.c b/sr_unix/ftok.c index d523db1..97f74f5 100644 --- a/sr_unix/ftok.c +++ b/sr_unix/ftok.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,7 @@ FPRINTF(stderr, "\nUsage:\n"); \ FPRINTF(stderr, "\t%s [%s] ... \n\n", argv[0], ID_PREFIX); \ FPRINTF(stderr, "Reports IPC Key(s) (using id 1, or ) of ... \n\n"); \ - exit(1); \ + exit(EXIT_FAILURE); \ } int main (int argc, char *argv[]) diff --git a/sr_unix/ftok_sems.c b/sr_unix/ftok_sems.c index 1699fac..3e4b050 100644 --- a/sr_unix/ftok_sems.c +++ b/sr_unix/ftok_sems.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,7 +58,6 @@ GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; -GBLREF boolean_t sem_incremented; GBLREF gd_region *ftok_sem_reg; GBLREF int4 exi_condition; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; @@ -106,7 +105,7 @@ error_def(ERR_TEXT); return TRUE; \ } -boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t *retstat) +boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t *retstat, boolean_t *bypass) { int status = SS_NORMAL, save_errno; int ftok_sopcnt, sem_pid; @@ -145,7 +144,11 @@ boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t SET_GTM_SOP_ARRAY(ftok_sop, ftok_sopcnt, TRUE, (SEM_UNDO | IPC_NOWAIT)); /* First try is always IPC_NOWAIT */ SEMOP(ftokid, ftok_sop, ftok_sopcnt, status, NO_WAIT); if (-1 != status) + { + udi->counter_ftok_incremented = TRUE; RETURN_SUCCESS(reg); + } + assert(EINTR != errno); save_errno = errno; if (EAGAIN == save_errno) { /* someone else is holding it */ @@ -155,15 +158,21 @@ boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t if (-1 != sem_pid) RETURN_SEMWAIT_FAILURE(retstat, 0, op_invalid_sem_syscall, ERR_SEMWT2LONG, 0, sem_pid); save_errno = errno; /* fall-through */ - } else if (do_blocking_semop(ftokid, ftok_sop, ftok_sopcnt, gtm_ftok_sem, start_hrtbt_cntr, retstat)) + } else if (do_blocking_semop(ftokid, gtm_ftok_sem, start_hrtbt_cntr, retstat, reg, bypass)) { - RETURN_SUCCESS(reg); + if (*bypass) + { + udi->counter_ftok_incremented = TRUE; + return TRUE; + } else + RETURN_SUCCESS(reg); } else if (!SEM_REMOVED(retstat->save_errno)) return FALSE; /* retstat will already have the necessary error information */ - save_errno = errno; /* some other error. Fall-through */ + save_errno = retstat->save_errno; /* some other error. Fall-through */ } if (SEM_REMOVED(save_errno)) continue; + assert(EINTR != save_errno); RETURN_SEMWAIT_FAILURE(retstat, save_errno, op_semctl_or_semop, 0, ERR_CRITSEMFAIL, 0); } assert(FALSE); @@ -195,7 +204,7 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole boolean_t shared_mem_available; int4 lcl_ftok_ops_index; struct sembuf ftok_sop[3]; - const char *msgstr = NULL; + char *msgstr; boolean_t stacktrace_issued = FALSE; DCL_THREADGBL_ACCESS; @@ -242,13 +251,11 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole SET_GTM_SOP_ARRAY(ftok_sop, ftok_sopcnt, incr_cnt, (SEM_UNDO | IPC_NOWAIT)); assert(mupip_jnl_recover || incr_cnt); /* First try is always non-blocking */ - do - { - status = semop(udi->ftok_semid, ftok_sop, ftok_sopcnt); - } while ((-1 == status) && (EINTR == errno)); /* EINTR is possible if heartbeat_timer is enabled at this point */ + SEMOP(udi->ftok_semid, ftok_sop, ftok_sopcnt, status, NO_WAIT); if (-1 != status) { SENDMSG_SEMOP_SUCCESS_IF_NEEDED(stacktrace_issued, gtm_ftok_sem); + udi->counter_ftok_incremented = incr_cnt; RETURN_SUCCESS(reg); } save_errno = errno; @@ -256,7 +263,7 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno); if (EAGAIN == save_errno) { /* Someone else is holding it */ - sem_pid = semctl(udi->ftok_semid, 0, GETPID); + sem_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID); if (-1 != sem_pid) { ftok_sop[0].sem_flg = ftok_sop[1].sem_flg = ftok_sop[2].sem_flg = SEM_UNDO; /* blocking calls */ @@ -273,13 +280,14 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole if (-1 != status) /* success ? */ { SENDMSG_SEMOP_SUCCESS_IF_NEEDED(stacktrace_issued, gtm_ftok_sem); + udi->counter_ftok_incremented = incr_cnt; CANCEL_TIMER_AND_RETURN_SUCCESS(reg); } save_errno = errno; if (EINTR == save_errno) { /* Timer popped. If not, we would have continued in the do..while loop */ assert(TREF(semwait2long)); - sem_pid = semctl(udi->ftok_semid, 0, GETPID); + sem_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID); if (-1 != sem_pid) { stuck_cnt++; @@ -353,11 +361,11 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate) udi = FILE_INFO(reg); csa = &udi->s_addrs; assert(!csa->now_crit); - /* The following two asserts are to ensure we never hold more than one FTOK semaphore at any point in time. - * The only exception is if we were MUPIP STOPped (or kill -3ed) while having ftok_sem lock on one region and we - * came to rundown code that invoked ftok_sem_lock() on a different region. Hence the process_exiting check below. - * In the pro version, we will do the right thing by returning TRUE right away if udi->grabbed_ftok_sem is TRUE. - * This is because incr_cnt is FALSE always (asserted below too). + /* The following two asserts are to ensure we never hold more than one FTOK semaphore at any point in time. The only + * exception is if we were MUPIP STOPped (or kill -3ed) while having ftok_sem lock on one region and we came to rundown code + * that invoked ftok_sem_lock() on a different region. Hence the process_exiting check below. In the pro version, we will + * do the right thing by returning TRUE right away if udi->grabbed_ftok_sem is TRUE. This is + * because incr_cnt is FALSE always (asserted below too). */ assert(!udi->grabbed_ftok_sem || (FALSE != process_exiting)); assert((NULL == ftok_sem_reg) || (FALSE != process_exiting)); @@ -366,14 +374,14 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate) ftok_sopcnt = 0; if (!udi->grabbed_ftok_sem) { /* Guarantee no one else accesses database file header while we update semid/shmid fields in the file header */ - ftok_sop[0].sem_num = 0; ftok_sop[0].sem_op = 0; /* Wait for 0 (unlocked) */ - ftok_sop[1].sem_num = 0; ftok_sop[1].sem_op = 1; /* Then lock it */ + ftok_sop[0].sem_num = DB_CONTROL_SEM; ftok_sop[0].sem_op = 0; /* Wait for 0 (unlocked) */ + ftok_sop[1].sem_num = DB_CONTROL_SEM; ftok_sop[1].sem_op = 1; /* Then lock it */ ftok_sopcnt = 2; } else if (!incr_cnt) return TRUE; if (incr_cnt) { - ftok_sop[ftok_sopcnt].sem_num = 1; ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */ + ftok_sop[ftok_sopcnt].sem_num = DB_COUNTER_SEM; ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */ ftok_sopcnt++; } ftok_sop[0].sem_flg = ftok_sop[1].sem_flg = ftok_sop[2].sem_flg = SEM_UNDO | IPC_NOWAIT; @@ -404,9 +412,8 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate) ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno); } } - udi->grabbed_ftok_sem = TRUE; - ftok_sem_reg = reg; - return TRUE; + udi->counter_ftok_incremented = TRUE; + RETURN_SUCCESS(reg); } /* @@ -419,11 +426,10 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate) */ boolean_t ftok_sem_incrcnt(gd_region *reg) { - int semflag, save_errno, status; + int save_errno, status; unix_db_info *udi; sgmnt_addrs *csa; - struct sembuf ftok_sop[3]; - int ftok_sopcnt; + struct sembuf ftok_sop; assert(NULL != reg); assert(NULL == ftok_sem_reg); /* assert that we never hold more than one FTOK semaphore at any point in time */ @@ -431,18 +437,16 @@ boolean_t ftok_sem_incrcnt(gd_region *reg) csa = &udi->s_addrs; assert(!csa->now_crit); assert(INVALID_SEMID != udi->ftok_semid); - semflag = SEM_UNDO; - ftok_sopcnt = 0; - ftok_sop[ftok_sopcnt].sem_num = 1; - ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */ - ftok_sop[ftok_sopcnt].sem_flg = SEM_UNDO; - ftok_sopcnt++; - SEMOP(udi->ftok_semid, ftok_sop, ftok_sopcnt, status, NO_WAIT); + ftok_sop.sem_num = DB_COUNTER_SEM; + ftok_sop.sem_op = 1; /* increment counter */ + ftok_sop.sem_flg = SEM_UNDO; + SEMOP(udi->ftok_semid, (&ftok_sop), 1, status, NO_WAIT); if (-1 == status) /* We couldn't get it in one shot -- see if we already have it */ { save_errno = errno; ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno); } + udi->counter_ftok_incremented = TRUE; return TRUE; } @@ -481,7 +485,7 @@ boolean_t ftok_sem_release(gd_region *reg, boolean_t decr_cnt, boolean_t immedi semflag = SEM_UNDO | (immediate ? IPC_NOWAIT : 0); if (decr_cnt) { - if (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL))) + if (-1 == (ftok_semval = semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))) { save_errno = errno; GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi); @@ -498,15 +502,17 @@ boolean_t ftok_sem_release(gd_region *reg, boolean_t decr_cnt, boolean_t immedi udi->ftok_semid = INVALID_SEMID; ftok_sem_reg = NULL; udi->grabbed_ftok_sem = FALSE; + udi->counter_ftok_incremented = FALSE; return TRUE; } - if (0 != (save_errno = do_semop(udi->ftok_semid, 1, -1, semflag))) + if (0 != (save_errno = do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, semflag))) { GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi); ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno); } + udi->counter_ftok_incremented = FALSE; } - if (0 != (save_errno = do_semop(udi->ftok_semid, 0, -1, semflag))) + if (0 != (save_errno = do_semop(udi->ftok_semid, DB_CONTROL_SEM, -1, semflag))) { GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi); ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno); diff --git a/sr_unix/ftok_sems.h b/sr_unix/ftok_sems.h index a1fe790..9bdaded 100644 --- a/sr_unix/ftok_sems.h +++ b/sr_unix/ftok_sems.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,12 +14,12 @@ #include "gtm_semutils.h" -boolean_t ftok_sem_get2(gd_region *reg, uint4 stacktrace_on_wait, semwait_status_t *retstat); +boolean_t ftok_sem_get2(gd_region *reg, uint4 stacktrace_on_wait, semwait_status_t *retstat, boolean_t *bypass); boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boolean_t immediate); boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate); boolean_t ftok_sem_incrcnt(gd_region *reg); boolean_t ftok_sem_release(gd_region *reg, boolean_t decr_cnt, boolean_t immediate); -#define MAX_SEMGET_RETRIES 4 +#define MAX_SEMGET_RETRIES 100 #endif /* FTOK_SEMS_INCLUDED */ diff --git a/sr_unix/gbldirnam.h b/sr_unix/gbldirnam.h index a24c349..f34b3de 100644 --- a/sr_unix/gbldirnam.h +++ b/sr_unix/gbldirnam.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,5 +12,5 @@ #define GDE_LABEL_SIZE 13 #define GDE_LABEL_NUM 1 /* Note, GDE_LABEL_LITERAL must be maintained in gdeinit.m if changes are made here */ -#define GDE_LABEL_LITERAL GTM64_ONLY("GTCGBDUNX107") NON_GTM64_ONLY("GTCGBDUNX007") +#define GDE_LABEL_LITERAL GTM64_ONLY("GTCGBDUNX108") NON_GTM64_ONLY("GTCGBDUNX008") #define DEF_GDR_EXT "*.gld" diff --git a/sr_unix/gdeget.m b/sr_unix/gdeget.m index 7e66444..14ccbf8 100644 --- a/sr_unix/gdeget.m +++ b/sr_unix/gdeget.m @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2006, 2011 Fidelity Information Services, Inc ; +; Copyright 2006, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -25,8 +25,13 @@ LOAD s mach=$p($zver," ",4) s seghasencrflag=FALSE if ($e(label,0,9)="GTCGBDUNX"),$e(label,$l(label)-1,99)>5 s seghasencrflag=TRUE - s reghasv543fields=FALSE - if ($e(label,0,9)="GTCGBDUNX"),$e(label,$l(label)-1,99)>6 s reghasv543fields=TRUE + s reghasv550fields=FALSE + if ($e(label,0,9)="GTCGBDUNX"),$e(label,$l(label)-1,99)>6 s reghasv550fields=TRUE + s reghasv600fields=FALSE + if ($e(label,0,9)="GTCGBDUNX"),$e(label,$l(label)-1,99)>7 s reghasv600fields=TRUE + set v550=0 + i (label="GTCGBDUNX007")!(label="GTCGBDUNX107") s label=hdrlab,v550=1,update=1 ;autoconvert + i (v550=1) n SIZEOF d v550init set v542=0 i (label="GTCGBLDIR009")!(label="GTCGBDUNX006")!(label="GTCGBDUNX106") s label=hdrlab,v542=1,update=1 ;autoconvert i (v542=1) n SIZEOF d v542init @@ -114,21 +119,28 @@ LOAD ; templates k tmpreg,tmpseg d cretmps - i (reghasv543fields=TRUE) d tmpreg("ALIGNSIZE") + i (reghasv550fields=TRUE) d tmpreg("ALIGNSIZE") f s="ALLOCATION" d tmpreg(s) - i (reghasv543fields=TRUE) d tmpreg("AUTOSWITCHLIMIT") + i (reghasv550fields=TRUE) d tmpreg("AUTOSWITCHLIMIT") f s="BEFORE_IMAGE","BUFFER_SIZE" d tmpreg(s) + i tmpreg("BUFFER_SIZE")y s verified=0 zm gdeerr("RECSIZIS"):x,gdeerr("REGIS"):REGION,gdeerr("RECTOOBIG"):s:f:y,gdeerr("SEGIS"):am:SEGMENT +key2blk: ;bs:block size, y:supportable max key size, f:size of reserved bytes, ks:key size + s y=bs-f-SIZEOF("blk_hdr")-len("min_val")-SIZEOF("rec_hdr")-len("bstar_rec")-len("hide_subs") + i ks>y s verified=0 zm gdeerr("KEYSIZIS"):ks,gdeerr("KEYFORBLK"):bs:y,gdeerr("REGIS"):REGION q buf2blk: i REGION="TEMPLATE","USER"[am,am'=tmpacc q i "USER"[am s verified=0 zm gdeerr("NOJNL"):am,gdeerr("REGIS"):REGION,gdeerr("SEGIS"):am:SEGMENT - s y=s/256 - i y>x s verified=0 zm gdeerr("BUFSIZIS"):x,gdeerr("REGIS"):REGION,gdeerr("BUFTOOSMALL"):s:y,gdeerr("SEGIS"):am:SEGMENT q mmbichk: i REGION="TEMPLATE",am="MM",tmpacc'="MM" q i am="MM" s verified=0 zm gdeerr("MMNOBEFORIMG"),gdeerr("REGIS"):REGION,gdeerr("SEGIS"):am:SEGMENT @@ -131,25 +130,34 @@ allocchk(rquals) . s rquals("ALLOCATION")=asl . zm gdeerr("JNLALLOCGROW"):alloc:asl:"region":REGION q +prefix(str1,str2) ;check whether str1 is a prefix of str2 + n len1,len2 + s len1=$l(str1),len2=$l(str2) + q:(len1>len2)!'len1 0 + i ($e(str2,1,len1)=str1) q 1 + q 0 ;----------------------------------------------------------------------------------------------------------------------------------- ; called from GDEADD.M and GDECHANG.M RQUALS(rquals) i '$d(verified) n verified s verified=1 + s len("min_val")=4 ;size for value field in index block + s len("bstar_rec")=8 ;size for bstar record + s len("hide_subs")=8 ;size for hidden subscript s s="" f s s=$o(rquals(s)) q:'$l(s) d regelm i $d(rquals("FILE_NAME")),$zl(rquals("FILE_NAME"))>(SIZEOF("file_spec")-1) s verified=0 i zm $$info(gdeerr("VALTOOLONG")):rquals("FILE_NAME"):SIZEOF("file_spec")-1:"Journal filename",gdeerr("REGIS"):REGION - s s="KEY_SIZE",s=$s($d(rquals(s)):rquals(s),$d(regs(REGION,s)):regs(REGION,s),1:tmpreg(s)) + s ks="KEY_SIZE",ks=$s($d(rquals(ks)):rquals(ks),$d(regs(REGION,ks)):regs(REGION,ks),1:tmpreg(ks)) s x="RECORD_SIZE",x=$s($d(rquals(x)):rquals(x),$d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x)) - i s+4>x s verified=0 zm gdeerr("KEYSIZIS"):s,gdeerr("KEYTOOBIG"):x:x-4,gdeerr("REGIS"):REGION d allocchk(.rquals) - i REGION="TEMPLATE" s s=tmpseg(tmpacc,"BLOCK_SIZE"),f=tmpseg(tmpacc,"RESERVED_BYTES") + i REGION="TEMPLATE" s bs=tmpseg(tmpacc,"BLOCK_SIZE"),f=tmpseg(tmpacc,"RESERVED_BYTES") e s s="DYNAMIC_SEGMENT",s=$s($d(rquals(s)):rquals(s),$d(regs(REGION,s)):regs(REGION,s),1:0) e q:'$d(segs(s)) verified n SEGMENT,am d - . s SEGMENT=s,am=segs(s,"ACCESS_METHOD"),s=$g(segs(s,"BLOCK_SIZE")),f=$g(segs(s,"RESERVED_BYTES")) - i am'="USER" d rec2blk + . s SEGMENT=s,am=segs(s,"ACCESS_METHOD"),bs=$g(segs(s,"BLOCK_SIZE")),f=$g(segs(s,"RESERVED_BYTES")) + i minreg("KEY_SIZE")'>ks d + . i am'="USER" d key2blk ;GTM-6941 s x="JOURNAL" i '$s('$d(rquals(x)):tmpreg(x),1:rquals(x)) q verified s x="BUFFER_SIZE",x=$s($d(rquals(x)):rquals(x),$d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x)) d buf2blk @@ -158,22 +166,26 @@ RQUALS(rquals) ; SQUALS(am,squals) i '$d(verified) n verified s verified=1 + s len("min_val")=4 ;size for value field in index block + s len("bstar_rec")=8 ;size for bstar record + s len("hide_subs")=8 ;size for hidden subscript n s s s="" f s s=$o(squals(s)) q:'$l(s) i $l(squals(s)) d segelm - s s="BLOCK_SIZE" - i $d(squals(s)),squals(s)#512 s x=squals(s),squals(s)=x\512+1*512 - i zm gdeerr("BLKSIZ512"):x:squals(s),gdeerr("SEGIS"):am:SEGMENT + n bs s bs="BLOCK_SIZE" + i $d(squals(bs)),squals(bs)#512 s x=squals(bs),squals(bs)=x\512+1*512 + i zm gdeerr("BLKSIZ512"):x:squals(bs),gdeerr("SEGIS"):am:SEGMENT s s="WINDOW_SIZE" i SEGMENT="TEMPLATE" s x=tmpreg("RECORD_SIZE") d segreg q verified n REGION s REGION="" - f s REGION=$o(regs(REGION)) q:'$l(REGION) i regs(REGION,"DYNAMIC_SEGMENT")=SEGMENT s s=regs(REGION,"RECORD_SIZE") d segreg + f s REGION=$o(regs(REGION)) q:'$l(REGION) i regs(REGION,"DYNAMIC_SEGMENT")=SEGMENT s bs=regs(REGION,"RECORD_SIZE") d segreg q verified segreg: i am'="USER" d - . s s="BLOCK_SIZE",s=$s($d(squals(s)):squals(s),$d(segs(SEGMENT,s)):segs(SEGMENT,s),1:tmpseg(am,s)) - . s f="RESERVED_BYTES",f=$s($d(squals(f)):squals(f),$d(segs(SEGMENT,s)):seg(SEGMENT,f),1:tmpseg(am,f)) + . s bs="BLOCK_SIZE",bs=$s($d(squals(bs)):squals(bs),$d(segs(SEGMENT,bs)):segs(SEGMENT,bs),1:tmpseg(am,bs)) + . s f="RESERVED_BYTES",f=$s($d(squals(f)):squals(f),$d(segs(SEGMENT,f)):segs(SEGMENT,f),1:tmpseg(am,f)) . s x="RECORD_SIZE",x=$s($d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x)) - . d rec2blk + . s ks="KEY_SIZE",ks=$s($d(regs(REGION,ks)):regs(REGION,ks),1:tmpreg(ks)) + . d key2blk ;GTM-6941 i '$s(SEGMENT="TEMPLATE":tmpreg("JOURNAL"),1:regs(REGION,"JOURNAL")) q s x=$s(SEGMENT="TEMPLATE":tmpreg("BUFFER_SIZE"),1:regs(REGION,"BUFFER_SIZE")) d buf2blk i nommbi,$s(SEGMENT="TEMPLATE":tmpreg("BEFORE_IMAGE"),1:regs(REGION,"BEFORE_IMAGE")) d mmbichk @@ -189,3 +201,15 @@ TRQUALS(rquals) TSQUALS(am,squals) n REGION,SEGMENT s (REGION,SEGMENT)="TEMPLATE" q $$SQUALS(am,.squals) + +;----------------------------------------------------------------------------------------------------------------------------------- +; called from GDEADD.M, GDECHANG.M and GDETEMPL.M, [GTM-7184] +NQUALS(rquals) + n nullsub s nullsub=rquals("NULL_SUBSCRIPTS") + i ($$prefix(nullsub,"NEVER")!$$prefix(nullsub,"FALSE")) s rquals("NULL_SUBSCRIPTS")=0 + e d + . i ($$prefix(nullsub,"ALWAYS")!$$prefix(nullsub,"TRUE")) s rquals("NULL_SUBSCRIPTS")=1 + . e d + . . i ($$prefix(nullsub,"EXISTING")) s rquals("NULL_SUBSCRIPTS")=2 + q + diff --git a/sr_unix/gds_file_size.c b/sr_unix/gds_file_size.c index 851c782..8e4ffba 100644 --- a/sr_unix/gds_file_size.c +++ b/sr_unix/gds_file_size.c @@ -27,7 +27,7 @@ error_def(ERR_DBFILOPERR); -unsigned int gds_file_size(file_control *fc) +gtm_uint64_t gds_file_size(file_control *fc) { unix_db_info *udi; int fstat_res; @@ -38,5 +38,5 @@ unsigned int gds_file_size(file_control *fc) if (-1 == fstat_res) rts_error(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(udi->fn), errno); assert(0 == stat_buf.st_size % DISK_BLOCK_SIZE); - return (unsigned int)(stat_buf.st_size / DISK_BLOCK_SIZE); + return (gtm_uint64_t)(stat_buf.st_size / DISK_BLOCK_SIZE); } diff --git a/sr_unix/gds_rundown.c b/sr_unix/gds_rundown.c index 97a836e..8db5389 100644 --- a/sr_unix/gds_rundown.c +++ b/sr_unix/gds_rundown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,7 +33,6 @@ #include "gdsblk.h" #include "gt_timer.h" #include "jnl.h" -#include "interlock.h" #include "error.h" #include "iosp.h" #include "gdsbgtr.h" @@ -68,37 +67,22 @@ #include "gtmimagename.h" #include "gtmio.h" #include "have_crit.h" -#include "wcs_clean_dbsync.h" #include "is_proc_alive.h" #include "shmpool.h" #include "db_snapshot.h" -#include "tp_grab_crit.h" #include "ss_lock_facility.h" +#include "anticipatory_freeze.h" +#include "wcs_clean_dbsync.h" +#include "interlock.h" +#include "gds_rundown_err_cleanup.h" #ifndef GTM_SNAPSHOT # error "Snapshot facility not available on this platform" #endif -#define CANCEL_DB_TIMERS(region, csa, cancelled_timer, cancelled_dbsync_timer) \ -{ \ - if (csa->timer) \ - { \ - cancel_timer((TID)region); \ - if (NULL != csa->nl) \ - DECR_CNT(&csa->nl->wcs_timers, &csa->nl->wc_var_lock); \ - cancelled_timer = TRUE; \ - csa->timer = FALSE; \ - } \ - if (csa->dbsync_timer) \ - { \ - CANCEL_DBSYNC_TIMER(csa); \ - cancelled_dbsync_timer = TRUE; \ - } \ -} - GBLREF VSIG_ATOMIC_T forced_exit; GBLREF boolean_t mupip_jnl_recover; -GBLREF boolean_t created_core, need_core, dont_want_core, is_src_server, is_updproc; +GBLREF boolean_t is_src_server, is_updproc; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; @@ -108,9 +92,14 @@ GBLREF jnl_process_vector *prc_vec; GBLREF jnl_process_vector *originator_prc_vec; GBLREF jnl_gbls_t jgbl; GBLREF boolean_t dse_running; +GBLREF int num_additional_processors; +GBLREF jnlpool_addrs jnlpool; +GBLREF int process_exiting; +GBLREF boolean_t ok_to_UNWIND_in_exit_handling; LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; +LITREF gtmImageName gtmImageNames[]; error_def(ERR_ASSERT); error_def(ERR_CRITSEMFAIL); @@ -125,15 +114,16 @@ error_def(ERR_IPCNOTDEL); error_def(ERR_JNLFLUSH); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); +error_def(ERR_RESRCINTRLCKBYPAS); error_def(ERR_RNDWNSEMFAIL); error_def(ERR_STACKOFLOW); error_def(ERR_TEXT); error_def(ERR_WCBLOCKED); error_def(ERR_STACKOFLOW); -void gds_rundown(void) +int4 gds_rundown(void) { - boolean_t cancelled_dbsync_timer, cancelled_timer, have_standalone_access, ipc_deleted, skip_database_rundown; + boolean_t cancelled_dbsync_timer, cancelled_timer, have_standalone_access, ipc_deleted, err_caught; boolean_t is_cur_process_ss_initiator, remove_shm, vermismatch, we_are_last_user, we_are_last_writer, is_mm; now_t now; /* for GET_CUR_TIME macro */ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */ @@ -153,7 +143,11 @@ void gds_rundown(void) shm_snapshot_t *ss_shm_ptr; uint4 ss_pid, onln_rlbk_pid, holder_pid; boolean_t was_crit; + boolean_t safe_mode; /* Do not flush or take down shared memory. */ + boolean_t bypassed_ftok = FALSE, bypassed_access = FALSE, may_bypass_ftok, inst_is_frozen; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; jnl_status = 0; reg = gv_cur_region; /* Local copy */ @@ -167,7 +161,7 @@ void gds_rundown(void) * and should be done eventually. */ if (dba_cm == reg->dyn.addr->acc_meth) - return; + return EXIT_NRM; udi = FILE_INFO(reg); csa = &udi->s_addrs; @@ -177,25 +171,28 @@ void gds_rundown(void) { change_reg(); gvusr_rundown(); - return; + return EXIT_NRM; + } + /* If the process has standalone access, it has udi->grabbed_access_sem set to TRUE at this point. Note that down in a local + * variable as the udi->grabbed_access_sem is set to TRUE even for non-standalone access below and hence we can't rely on + * that later to determine if the process had standalone access or not when it entered this function. We need to guarantee + * that none else access database file header when semid/shmid fields are reset. We already have created ftok semaphore in + * db_init or, mu_rndwn_file and did not remove it. So just lock it. We do it in blocking mode. + */ + have_standalone_access = udi->grabbed_access_sem; /* process holds standalone access */ + ESTABLISH_NORET(gds_rundown_ch, err_caught); + if (err_caught) + { + gds_rundown_err_cleanup(have_standalone_access); + ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN); + REVERT; + DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = FALSE); + return EXIT_ERR; } - ESTABLISH(gds_rundown_ch); assert(reg->open); /* if we failed to open, dbinit_ch should have taken care of proper clean up */ assert(!reg->opening); /* see comment above */ - switch(csd->acc_meth) - { /* Pass mm and bg through */ - case dba_bg: - is_mm = FALSE; - break; - case dba_mm: - is_mm = TRUE; - break; - case dba_usr: - assert(FALSE); - default: - REVERT; - return; - } + assert((dba_bg == csd->acc_meth) || (dba_mm == csd->acc_meth)); + is_mm = (dba_bg != csd->acc_meth); assert(!csa->hold_onto_crit || (csa->now_crit && jgbl.onlnrlbk)); /* If we are online rollback, we should already be holding crit and should release it only at the end of this module. This * is usually done by noting down csa->now_crit in a local variable (was_crit) and using it whenever we are about to @@ -209,6 +206,7 @@ void gds_rundown(void) cancelled_dbsync_timer = FALSE; CANCEL_DB_TIMERS(reg, csa, cancelled_timer, cancelled_dbsync_timer); we_are_last_user = FALSE; + inst_is_frozen = IS_REPL_INST_FROZEN && REPL_ALLOWED(csa->hdr); if (!csa->persistent_freeze) region_freeze(reg, FALSE, FALSE, FALSE); if (!was_crit) @@ -217,14 +215,6 @@ void gds_rundown(void) mutex_cleanup(reg); } DEFER_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN); - /* If the process has standalone access, it has udi->grabbed_access_sem set to TRUE at this point. Note that down - * in a local variable as the udi->grabbed_access_sem is set to TRUE even for non-standalone access below and hence - * we can't rely on that later to determine if the process had standalone access or not when it entered this function. - * We need to guarantee that none else access database file header when semid/shmid fields are reset. - * We already have created ftok semaphore in db_init or, mu_rndwn_file and did not remove it. - * So just lock it. We do it in blocking mode. - */ - have_standalone_access = udi->grabbed_access_sem; /* process holds standalone access */ /* The only process that can invoke gds_rundown while holding access control semaphore is RECOVER/ROLLBACK. All the others * (like MUPIP SET -FILE/MUPIP EXTEND would have invoked db_ipcs_reset() before invoking gds_rundown (from * mupip_exit_handler). The only exception is when these processes encounter a terminate signal and they reach @@ -236,63 +226,120 @@ void gds_rundown(void) */ onln_rlbk_pid = csa->nl->onln_rlbk_pid; assert(!have_standalone_access || mupip_jnl_recover || !onln_rlbk_pid || !is_proc_alive(onln_rlbk_pid, 0)); - skip_database_rundown = FALSE; if (!have_standalone_access) { + if (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL))) /* Check # of processes counted on FTOK. */ + { + save_errno = errno; + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get ftok_semval"), CALLFROM, errno); + } + /* If csa->timer was true, this process may flush buffers, so it must follow regular protocol.*/ + may_bypass_ftok = CAN_BYPASS(ftok_semval, cancelled_timer, inst_is_frozen); /* Do we need a blocking wait? */ /* We need to guarantee that no one else access database file header when semid/shmid fields are reset. * We already have created ftok semaphore in db_init or mu_rndwn_file and did not remove it. So just - * lock it. We do it in blocking mode. + * lock it. */ - if (!ftok_sem_lock(reg, FALSE, FALSE)) - rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); - FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_lock, process_id); - sop[0].sem_num = 0; sop[0].sem_op = 0; /* Wait for 0 */ - sop[1].sem_num = 0; sop[1].sem_op = 1; /* Lock */ + if (!ftok_sem_lock(reg, FALSE, may_bypass_ftok)) + { + if (may_bypass_ftok) + { + /* We did a non-blocking wait. It's ok to proceed without locking */ + bypassed_ftok = TRUE; + holder_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID); + if ((uint4)-1 == holder_pid) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get holder_pid"), + CALLFROM, errno); + if (!IS_GTM_IMAGE) /* MUMPS processes should not flood syslog with bypass messages. */ + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10, + LEN_AND_STR(gtmImageNames[image_type].imageName), process_id, LEN_AND_LIT("FTOK"), + REG_LEN_STR(reg), DB_LEN_STR(reg), holder_pid); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("FTOK bypassed at rundown")); + } + + } else + { /* We did a blocking wait but something bad happened. */ + FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_lock, process_id); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); + } + } + sop[0].sem_num = DB_CONTROL_SEM; sop[0].sem_op = 0; /* Wait for 0 */ + sop[1].sem_num = DB_CONTROL_SEM; sop[1].sem_op = 1; /* Lock */ sopcnt = 2; sop[0].sem_flg = sop[1].sem_flg = SEM_UNDO | IPC_NOWAIT; /* Don't wait the first time thru */ SEMOP(udi->semid, sop, sopcnt, status, NO_WAIT); - if (-1 == status) /* We couldn't get it in one shot -- see if we already have it */ + if (0 != status) { save_errno = errno; - holder_pid = semctl(udi->semid, 0, GETPID); - if (holder_pid == process_id) - { - send_msg(VARLSTCNT(5) MAKE_MSG_INFO(ERR_CRITSEMFAIL), 2, - DB_LEN_STR(reg), - ERR_RNDWNSEMFAIL); - REVERT; - ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN); - return; /* Already in rundown for this region */ - } - if (EAGAIN != save_errno) - { - assert(FALSE); - rts_error(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("gds_rundown first semop/semctl"), save_errno); - } + /* Check # of processes counted on access sem. */ + if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL))) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get semval"), CALLFROM, errno); + /* If csa->timer was true, this process may flush buffers so it must follow regular protocol.*/ + bypassed_access = CAN_BYPASS(semval, cancelled_timer, inst_is_frozen) || onln_rlbk_pid || csd->file_corrupt; /* Before attempting again in the blocking mode, see if the holding process is an online rollback. * If so, it is likely we won't get the access control semaphore anytime soon. In that case, we * are better off skipping rundown and continuing with sanity cleanup and exit. */ - skip_database_rundown = (onln_rlbk_pid || csd->file_corrupt); - if (!skip_database_rundown) - { + holder_pid = semctl(udi->semid, DB_CONTROL_SEM, GETPID); + if ((uint4)-1 == holder_pid) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get holder_pid"), CALLFROM, errno); + if (!bypassed_access) + { /* We couldn't get it in one shot-- see if we already have it */ + if (holder_pid == process_id) + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) MAKE_MSG_INFO(ERR_CRITSEMFAIL), 2, DB_LEN_STR(reg), + ERR_RNDWNSEMFAIL); + REVERT; + ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN); + assert(FALSE); + return EXIT_ERR; + } + if (EAGAIN != save_errno) + { + assert(FALSE); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"), + CALLFROM, save_errno); + } sop[0].sem_flg = sop[1].sem_flg = SEM_UNDO; /* Try again - blocking this time */ SEMOP(udi->semid, sop, 2, status, FORCED_WAIT); if (-1 == status) /* We couldn't get it at all.. */ - rts_error(VARLSTCNT(5) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), errno); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"), + CALLFROM, errno); + } else if (!IS_GTM_IMAGE) + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10, + LEN_AND_STR(gtmImageNames[image_type].imageName), process_id, + LEN_AND_LIT("access control"), REG_LEN_STR(reg), DB_LEN_STR(reg), holder_pid); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("Access control bypassed at rundown")); } + udi->grabbed_access_sem = !bypassed_access; } - udi->grabbed_access_sem = !skip_database_rundown; } /* else we we hold the access control semaphore and therefore have standalone access. We do not release it now - we * release it later in mupip_exit_handler.c. Since we already hold the access control semaphore, we don't need the * ftok semaphore and trying it could cause deadlock */ + /* If we bypassed any of the semaphores, activate safe mode. + * Also, if the replication instance is frozen and this db has replication turned on (which means + * no flushes of dirty buffers to this db can happen while the instance is frozen) activate safe mode. + */ + safe_mode = bypassed_access || bypassed_ftok || inst_is_frozen; /* At this point we are guaranteed no one else is doing a db_init/rundown as we hold the access control semaphore */ assert(csa->ref_cnt); /* decrement private ref_cnt before shared ref_cnt decrement. */ csa->ref_cnt--; /* Currently journaling logic in gds_rundown() in VMS relies on this order to detect last writer */ assert(!csa->ref_cnt); --csa->nl->ref_cnt; + if (memcmp(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1)) { /* VERMISMATCH condition. Possible only if DSE */ assert(dse_running); @@ -302,20 +349,27 @@ void gds_rundown(void) if (-1 == shmctl(udi->shmid, IPC_STAT, &shm_buf)) { save_errno = errno; - rts_error(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("gds_rundown shmctl"), save_errno); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown shmctl"), CALLFROM, save_errno); } else - we_are_last_user = (1 == shm_buf.shm_nattch) && !vermismatch; - assert(!have_standalone_access || we_are_last_user || jgbl.onlnrlbk); /* recover => one user except ONLINE ROLLBACK */ - if (-1 == (semval = semctl(udi->semid, 1, GETVAL))) - rts_error(VARLSTCNT(5) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), errno); - we_are_last_writer = (1 == semval) && (FALSE == reg->read_only) && !vermismatch;/* There's one writer left and I am it */ - assert(!we_are_last_writer || !skip_database_rundown); - assert(!we_are_last_user || !skip_database_rundown); - assert(!(have_standalone_access && !reg->read_only) || we_are_last_writer - || jgbl.onlnrlbk); /* recover + R/W region => one writer except ONLINE ROLLBACK */ - if (!have_standalone_access && (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL)))) - rts_error(VARLSTCNT(5) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), errno); + we_are_last_user = (1 == shm_buf.shm_nattch) && !vermismatch && !safe_mode; + /* recover => one user except ONLINE ROLLBACK, or standalone with frozen instance */ + assert(!have_standalone_access || we_are_last_user || jgbl.onlnrlbk || inst_is_frozen); + if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL))) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get semval"), CALLFROM, errno); + /* There's one writer left and I am it */ + assert(reg->read_only || semval >= 0); + we_are_last_writer = (1 == semval) && (FALSE == reg->read_only) && !vermismatch && !safe_mode; + assert(!we_are_last_writer || !safe_mode); + assert(!we_are_last_user || !safe_mode); + /* recover + R/W region => one writer except ONLINE ROLLBACK, or standalone with frozen instance, leading to safe_mode */ + assert(!(have_standalone_access && !reg->read_only) || we_are_last_writer || jgbl.onlnrlbk + || inst_is_frozen); + GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_JNLCLOSE, we_are_last_writer, 1); /* Assume we are the last writer to invoke wcs_flu */ + if (!have_standalone_access && (-1 == (ftok_semval = semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)))) + rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get ftok_semval"), CALLFROM, errno); if (NULL != csa->ss_ctx) ss_destroy_context(csa->ss_ctx); /* SS_MULTI: If multiple snapshots are supported, then we have to run through each of the snapshots */ @@ -346,7 +400,7 @@ void gds_rundown(void) { /* If we had an orphaned block and were interrupted, set wc_blocked so we can invoke wcs_recover. Do it ONLY * if there is NO concurrent online rollback running (as we need crit to set wc_blocked) */ - if (csa->wbuf_dqd) + if (csa->wbuf_dqd && !is_mm) { /* If we had an orphaned block and were interrupted, mupip_exit_handler will invoke secshr_db_clnup which * will clear this field and so we should never come to gds_rundown with a non-zero wbuf_dqd. The only * exception is if we are recover/rollback in which case gds_rundown (from mur_close_files) is invoked @@ -355,20 +409,15 @@ void gds_rundown(void) * the moment we apply the first PBLK, we stop all interrupts and hence can never be interrupted in * wcs_wtstart or wcs_get_space. Assert accordingly. */ - assert(mupip_jnl_recover && !jgbl.onlnrlbk && !skip_database_rundown); + assert(mupip_jnl_recover && !jgbl.onlnrlbk && !safe_mode); if (!was_crit) grab_crit(reg); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); + SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wcb_gds_rundown); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_gds_rundown"), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_gds_rundown"), process_id, &csa->ti->curr_tn, DB_LEN_STR(reg)); csa->wbuf_dqd = 0; wcs_recover(reg); - if (is_mm) - { - assert(FALSE); - csd = csa->hdr; - } BG_TRACE_PRO_ANY(csa, lost_block_recovery); if (!was_crit) rel_crit(reg); @@ -378,20 +427,13 @@ void gds_rundown(void) /* If we are the last writing user, then everything must be flushed */ if (we_are_last_writer) { /* Time to flush out all of our buffers */ + assert(!safe_mode); if (is_mm) { - if (csa->total_blks != csa->ti->total_blks) /* do remap if file had been extended */ - { - if (!was_crit) - grab_crit(reg); - wcs_mm_recover(reg); - csd = csa->hdr; - if (!was_crit) - rel_crit(reg); - } + MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg); csa->nl->remove_shm = TRUE; } - if (csd->wc_blocked && jgbl.onlnrlbk) + if (csa->nl->wc_blocked && jgbl.onlnrlbk) { /* if the last update done by online rollback was not committed in the normal code-path but was * completed by secshr_db_clnup, wc_blocked will be set to TRUE. But, since online rollback never * invokes grab_crit (since csa->hold_onto_crit is set to TRUE), wcs_recover is never invoked. This @@ -415,7 +457,7 @@ void gds_rundown(void) */ assert(csd == csa->hdr); assert(0 == memcmp(csd->label, GDS_LABEL, GDS_LABEL_SZ - 1)); - } else if (((cancelled_timer && (0 > csa->nl->wcs_timers)) || cancelled_dbsync_timer) && !skip_database_rundown) + } else if (((cancelled_timer && (0 > csa->nl->wcs_timers)) || cancelled_dbsync_timer) && !safe_mode) { /* cancelled pending db or jnl flush timers - flush database and journal buffers to disk */ if (!was_crit) grab_crit(reg); @@ -447,7 +489,7 @@ void gds_rundown(void) COMPSWAP_UNLOCK(&jbp->io_in_prog_latch, process_id, 0, LOCK_AVAILABLE, 0); } if ((((NOJNL != jpc->channel) && !JNL_FILE_SWITCHED(jpc)) - || we_are_last_writer && (0 != csa->nl->jnl_file.u.inode)) && !skip_database_rundown) + || we_are_last_writer && (0 != csa->nl->jnl_file.u.inode)) && !safe_mode) { /* We need to close the journal file cleanly if we have the latest generation journal file open * or if we are the last writer and the journal file is open in shared memory (not necessarily * by ourselves e.g. the only process that opened the journal got shot abnormally) @@ -473,11 +515,14 @@ void gds_rundown(void) * play it safe in PRO and write a PINI record if not written already. */ assert(!jbp->before_images || is_mm - || !we_are_last_writer || 0 != jpc->pini_addr); - if (we_are_last_writer && 0 == jpc->pini_addr) - jnl_put_jrt_pini(csa); - if (0 != jpc->pini_addr) - jnl_put_jrt_pfin(csa); + || !we_are_last_writer || (0 != jpc->pini_addr || jgbl.mur_extract)); + if (!jgbl.mur_extract) + { + if (we_are_last_writer && 0 == jpc->pini_addr) + jnl_put_jrt_pini(csa); + if (0 != jpc->pini_addr) + jnl_put_jrt_pfin(csa); + } /* If not the last writer and no pending flush timer left, do jnl flush now */ if (!we_are_last_writer && (0 > csa->nl->wcs_timers)) { @@ -488,8 +533,8 @@ void gds_rundown(void) assert(jbp->fsync_dskaddr == jbp->dskaddr); } else { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), - ERR_TEXT, 2, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, + JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush in gds_rundown"), jnl_status); assert(NOJNL == jpc->channel);/* jnl file lost has been triggered */ @@ -502,7 +547,8 @@ void gds_rundown(void) } jnl_file_close(reg, we_are_last_writer, FALSE); } else - send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(reg)); } if (!was_crit) rel_crit(reg); @@ -523,28 +569,22 @@ void gds_rundown(void) fileheader_sync(reg); if (!was_crit) rel_crit(reg); - if (FALSE == is_mm) + if (!is_mm) { - if (-1 == fsync(udi->fd)) /* Sync it all */ + GTM_DB_FSYNC(csa, udi->fd, rc); /* Sync it all */ + if (-1 == rc) { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file sync at close"), errno); } } else { /* Now do final MM file sync before exit */ -# if !defined(TARGETED_MSYNC) && !defined(NO_MSYNC) - if (-1 == fsync(udi->fd)) /* Sync it all */ + assert(csa->ti->total_blks == csa->total_blks); + if (-1 == MSYNC((caddr_t)csa->db_addrs[0], (caddr_t)csa->db_addrs[1])) { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file sync at close"), errno); - } -# else - if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC)) - { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync at close"), errno); } -# endif } } } /* end if (!reg->read_only && !csa->nl->donotflush_dbjnl) */ @@ -562,43 +602,25 @@ void gds_rundown(void) memcpy(db_ipcs.fn, reg->dyn.addr->fname, reg->dyn.addr->fname_len); db_ipcs.fn[reg->dyn.addr->fname_len] = 0; /* request gtmsecshr to flush. read_only cannot flush itself */ + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa); if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0)) - rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("gtmsecshr failed to update database file header")); } /* Done with file now, close it */ CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ if (-1 == rc) { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error during file close"), errno); } /* Unmap storage if mm mode but only the part that is not the fileheader (so shows up in dumps) */ - if (is_mm) + if (is_mm && (NULL != csa->db_addrs[0])) { - munmap_len = (sm_long_t)((csa->db_addrs[1] - csa->db_addrs[0]) - ROUND_UP(SIZEOF_FILE_HDR(csa->hdr), - MSYNC_ADDR_INCS)); - if (munmap_len > 0) - { - munmap((caddr_t)(csa->db_addrs[0] + ROUND_UP(SIZEOF_FILE_HDR(csa->hdr), MSYNC_ADDR_INCS)), - (size_t)(munmap_len)); -# ifdef DEBUG_DB64 - rel_mmseg((caddr_t)csa->db_addrs[0]); -# endif - } - } - /* If we had skipped flushing journal and database buffers due to a concurrent online rollback, increment the counter - * indicating that in the shared memory so that online rollback can report the # of such processes when it shuts down. - */ - if (skip_database_rundown) /* indicates flushing was skipped */ - csa->nl->dbrndwn_skip_cnt++; - /* If we are online rollback, report the # of processes that skipped rundown because we were holding the access control - * semaphore - */ - if (jgbl.onlnrlbk && csa->nl->dbrndwn_skip_cnt) - { - send_msg(VARLSTCNT(3) ERR_RNDWNSKIPCNT, 1, csa->nl->dbrndwn_skip_cnt); - csa->nl->dbrndwn_skip_cnt = 0; + assert(csa->db_addrs[1] > csa->db_addrs[0]); + munmap_len = (sm_long_t)(csa->db_addrs[1] - csa->db_addrs[0]); + if (0 < munmap_len) + munmap((caddr_t)(csa->db_addrs[0]), (size_t)(munmap_len)); } /* Detach our shared memory while still under lock so reference counts will be correct for the next process to run down * this region. In the process also get the remove_shm status from node_local before detaching. @@ -607,15 +629,26 @@ void gds_rundown(void) */ remove_shm = !vermismatch && (csa->nl->remove_shm || csa->nl->donotflush_dbjnl); rel_crit(reg); /* Since we are about to detach from the shared memory, release crit and reset onln_rlbk_pid */ + /* If we had skipped flushing journal and database buffers due to a concurrent online rollback, increment the counter + * indicating that in the shared memory so that online rollback can report the # of such processes when it shuts down. + * The same thing is done for both FTOK and access control semaphores when there are too many MUMPS processes. + */ + if (safe_mode) /* indicates flushing was skipped */ + { + if (bypassed_access) csa->nl->dbrndwn_access_skip++; /* Access semaphore can be bypassed during online rollback */ + if (bypassed_ftok) csa->nl->dbrndwn_ftok_skip++; + } if (jgbl.onlnrlbk) { /* We are done with online rollback on this region Indicate to other processes by setting the onln_rlbk_pid to 0 */ csa->hold_onto_crit = FALSE; csa->nl->onln_rlbk_pid = 0; } + GTM_WHITE_BOX_TEST(WBTEST_HOLD_SEM_BYPASS, csa->nl->wbox_test_seq_num, 0); status = shmdt((caddr_t)csa->nl); csa->nl = NULL; /* dereferencing nl after detach is not right, so we set it to NULL so that we can test before dereference*/ if (-1 == status) - send_msg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error during shmdt"), errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, + LEN_AND_LIT("Error during shmdt"), errno); REMOVE_CSA_FROM_CSADDRSLIST(csa); /* remove "csa" from list of open regions (cs_addrs_list) */ reg->open = FALSE; /* If file is still not in good shape, die here and now before we get rid of our storage */ @@ -629,120 +662,84 @@ void gds_rundown(void) { ipc_deleted = TRUE; if (0 != shm_rmid(udi->shmid)) - rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to remove shared memory")); } else if (is_src_server || is_updproc) { - gtm_putmsg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); - send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); } else - send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id); /* mupip recover/rollback don't release the semaphore here, but do it later in db_ipcs_reset (invoked from * mur_close_files()) */ if (!have_standalone_access) { if (0 != sem_rmid(udi->semid)) - rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to remove semaphore")); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; } } else { - assert(!have_standalone_access || jgbl.onlnrlbk); - if (!jgbl.onlnrlbk) + assert(!have_standalone_access || jgbl.onlnrlbk || safe_mode); + if (!jgbl.onlnrlbk && !have_standalone_access) { /* If we were writing, get rid of our writer access count semaphore */ if (!reg->read_only) - if (0 != (save_errno = do_semop(udi->semid, 1, -1, SEM_UNDO))) - rts_error(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("gds_rundown write semaphore release"), save_errno); + { + if (0 != (save_errno = do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown access control semaphore decrement"), + CALLFROM, save_errno); + udi->counter_acc_incremented = FALSE; + } + assert(safe_mode || !bypassed_access); /* Now remove the rundown lock */ - if (!skip_database_rundown) - { /* Do it only if we skipped getting the access control semaphore above */ - if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO))) - rts_error(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), - ERR_TEXT, 2, RTS_ERROR_TEXT("gds_rundown rundown semaphore release"), save_errno); + if (!bypassed_access) + { + if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, + RTS_ERROR_TEXT("gds_rundown access control semaphore release"), + CALLFROM, save_errno); udi->grabbed_access_sem = FALSE; } } /* else access control semaphore will be released in db_ipcs_reset */ } if (!have_standalone_access) { - if (!ftok_sem_release(reg, !have_standalone_access, FALSE)) - rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); - FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_release, process_id); + if (bypassed_ftok) + { + if (0 != (save_errno = do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, SEM_UNDO))) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); + } else if (!ftok_sem_release(reg, TRUE, FALSE)) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); + FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_release, process_id); + } + udi->grabbed_ftok_sem = FALSE; + udi->counter_ftok_incremented = FALSE; } ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN); if (!ipc_deleted) { GET_CUR_TIME; if (is_src_server) - gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, LEN_AND_LIT("Source server"), REG_LEN_STR(reg)); if (is_updproc) - gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, LEN_AND_LIT("Update process"), REG_LEN_STR(reg)); if (mupip_jnl_recover && (!jgbl.onlnrlbk || !we_are_last_user)) { - gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(reg)); - send_msg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr, LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(reg)); } } REVERT; -} - -CONDITION_HANDLER(gds_rundown_ch) -{ - pid_t sem_pid; - int semop_res; - unix_db_info *udi; - sgmnt_addrs *csa; - boolean_t cancelled_timer, cancelled_dbsync_timer, have_standalone_access; - - START_CH; - /* To get as virgin a state as possible in the core, take the core now if we - * would be doing so anyway. This will set created_core so it doesn't happen again. - */ - if (DUMPABLE && !SUPPRESS_DUMP) - { - need_core = TRUE; - gtm_fork_n_core(); - } - udi = FILE_INFO(gv_cur_region); - csa = &udi->s_addrs; - /* We got here on an error and are going to close the region. Cancel any pending flush timer for this region by this task*/ - CANCEL_DB_TIMERS(gv_cur_region, csa, cancelled_timer, cancelled_dbsync_timer); - /* release the access control semaphore, if you hold it */ - have_standalone_access = udi->grabbed_access_sem; - if (udi->grabbed_access_sem) - { - if (csa->now_crit) /* Might hold crit if wcs_flu or other failure */ - { - assert(!csa->hold_onto_crit || jgbl.onlnrlbk); - if (NULL != csa->nl) - rel_crit(gv_cur_region); /* also sets csa->now_crit to FALSE */ - else - csa->now_crit = FALSE; - } - sem_pid = semctl(udi->semid, 0, GETPID); - assert(sem_pid == process_id); - if (0 != (semop_res = do_semop(udi->semid, 0, -1, SEM_UNDO | IPC_NOWAIT))) - gtm_putmsg(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(gv_cur_region), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error releasing access semaphore"), semop_res); - udi->grabbed_access_sem = FALSE; - - } - if (udi->grabbed_ftok_sem) - { - assert(!have_standalone_access); - ftok_sem_release(gv_cur_region, !have_standalone_access, TRUE); - } - gv_cur_region->open = FALSE; - csa->nl = NULL; - REMOVE_CSA_FROM_CSADDRSLIST(csa); /* remove "csa" from list of open regions (cs_addrs_list) */ - PRN_ERROR; - gtm_putmsg(VARLSTCNT(4) ERR_DBRNDWN, 2, REG_LEN_STR(gv_cur_region)); - UNWIND(NULL, NULL); + return EXIT_NRM; } diff --git a/sr_unix/gdsfilext.c b/sr_unix/gdsfilext.c index b326eac..29e9192 100644 --- a/sr_unix/gdsfilext.c +++ b/sr_unix/gdsfilext.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,6 @@ #include #include "gtm_unistd.h" #include -#include "gtm_statvfs.h" /* for GTM_BAVAIL_TYPE */ #include "buddy_list.h" #include "gdsroot.h" @@ -41,6 +40,7 @@ #include "gdsblk.h" /* needed for gds_blk_downgrade.h */ #include "gds_blk_downgrade.h" /* for IS_GDS_BLK_DOWNGRADE_NEEDED macro */ #include "wbox_test_init.h" +#include "anticipatory_freeze.h" /* Include prototypes */ #include "bit_set.h" #include "disk_block_available.h" @@ -51,13 +51,26 @@ #include "gtmimagename.h" #include "gtmdbglvl.h" #include "min_max.h" +#include "repl_msg.h" +#include "gtmsource.h" +#include "error.h" -#define GDSFILEXT_CLNUP { if (need_to_restore_mask) \ - sigprocmask(SIG_SETMASK, &savemask, NULL); \ - if (!was_crit) \ - rel_crit(gv_cur_region); \ - cs_addrs->extending = FALSE; \ - } +#define GDSFILEXT_CLNUP \ +{ \ + if (!was_crit) \ + rel_crit(gv_cur_region); \ +} + +#define ISSUE_WAITDSKSPACE(TO_WAIT, WAIT_PERIOD, MECHANISM) \ +{ \ + uint4 seconds; \ + \ + seconds = TO_WAIT + (CDB_STAGNATE - t_tries) * WAIT_PERIOD; \ + MECHANISM(CSA_ARG(cs_addrs) VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id, seconds, DB_LEN_STR(gv_cur_region), ERR_TEXT,\ + 2, LEN_AND_LIT("Please make more disk space available or shutdown GT.M to avoid data loss"), ENOSPC); \ +} + +#define SUSPICIOUS_EXTEND (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks) GBLREF sigset_t blockalrm; GBLREF sgmnt_addrs *cs_addrs; @@ -74,68 +87,79 @@ GBLREF jnl_gbls_t jgbl; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLREF boolean_t gtm_dbfilext_syslog_disable; /* control whether db file extension message is logged or not */ GBLREF uint4 gtmDebugLevel; +GBLREF jnlpool_addrs jnlpool; error_def(ERR_DBFILERR); error_def(ERR_DBFILEXT); error_def(ERR_DSKSPACEFLOW); error_def(ERR_JNLFLUSH); +error_def(ERR_NOSPACEEXT); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); error_def(ERR_TOTALBLKMAX); error_def(ERR_WAITDSKSPACE); OS_PAGE_SIZE_DECLARE -uint4 gdsfilext (uint4 blocks, uint4 filesize) +uint4 gdsfilext(uint4 blocks, uint4 filesize, boolean_t trans_in_prog) { - sm_uc_ptr_t old_base[2]; - boolean_t was_crit, need_to_restore_mask = FALSE; - char *buff; - int mm_prot, result, save_errno, status; - uint4 new_bit_maps, bplmap, map, new_blocks, new_total, max_tot_blks; + sm_uc_ptr_t old_base[2], mmap_retaddr; + boolean_t was_crit, is_mm; + char buff[DISK_BLOCK_SIZE]; + int result, save_errno, status; + uint4 new_bit_maps, bplmap, map, new_blocks, new_total, max_tot_blks, old_total; uint4 jnl_status, to_wait, to_msg, wait_period; - GTM_BAVAIL_TYPE avail_blocks; - sgmnt_data_ptr_t tmp_csd; + gtm_uint64_t avail_blocks, mmap_sz; off_t new_eof; trans_num curr_tn; unix_db_info *udi; - sigset_t savemask; inctn_opcode_t save_inctn_opcode; int4 prev_extend_blks_to_upgrd; jnl_private_control *jpc; jnl_buffer_ptr_t jbp; + cache_rec_ptr_t cr; + DCL_THREADGBL_ACCESS; + assert(!IS_DSE_IMAGE); assert((cs_addrs->nl == NULL) || (process_id != cs_addrs->nl->trunc_pid)); /* mu_truncate shouldn't extend file... */ + assert(!process_exiting); + DEBUG_ONLY(old_base[0] = old_base[1] = NULL); + assert(!gv_cur_region->read_only); udi = FILE_INFO(gv_cur_region); + is_mm = (dba_mm == cs_addrs->hdr->acc_meth); # if !defined(MM_FILE_EXT_OK) - if (!udi->grabbed_access_sem && (dba_mm == cs_addrs->hdr->acc_meth)) + if (!udi->grabbed_access_sem && is_mm) return (uint4)(NO_FREE_SPACE); /* should this be changed to show extension not allowed ? */ # endif - /* Both blocks and total blocks are unsigned ints so make sure we aren't asking for huge numbers that will overflow and end up doing silly things. */ - assert((blocks <= (MAXTOTALBLKS(cs_data) - cs_data->trans_hist.total_blks)) || - (gtm_white_box_test_case_enabled && (WBTEST_FILE_EXTEND_ERROR == gtm_white_box_test_case_number))); - + assert((blocks <= (MAXTOTALBLKS(cs_data) - cs_data->trans_hist.total_blks)) || WBTEST_ENABLED(WBTEST_FILE_EXTEND_ERROR)); if (!blocks) return (uint4)(NO_FREE_SPACE); /* should this be changed to show extension not enabled ? */ bplmap = cs_data->bplmap; - /* new total of non-bitmap blocks will be number of current, non-bitmap blocks, plus new blocks desired - There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks - and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this - manner as every non-bitmap block must have an associated bitmap) - Current number of bitmaps is (total number of current blocks + bplmap - 1) / bplmap. - Subtract current number of bitmaps from number needed for expanded database to get number of new bitmaps needed. - */ + /* New total of non-bitmap blocks will be number of current, non-bitmap blocks, plus new blocks desired + * There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks + * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this + * manner as every non-bitmap block must have an associated bitmap) + * Current number of bitmaps is (total number of current blocks + bplmap - 1) / bplmap. + * Subtract current number of bitmaps from number needed for expanded database to get number of new bitmaps needed. + */ new_bit_maps = DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks - DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap) + blocks, bplmap - 1) - DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap); new_blocks = blocks + new_bit_maps; assert(0 < (int)new_blocks); + if (new_blocks + cs_data->trans_hist.total_blks > MAXTOTALBLKS(cs_data)) + { + assert(FALSE); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_TOTALBLKMAX); + return (uint4)(NO_FREE_SPACE); + } if (0 != (save_errno = disk_block_available(udi->fd, &avail_blocks, FALSE))) { - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); } else { if (!(gtmDebugLevel & GDL_IgnoreAvailSpace)) @@ -145,14 +169,21 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) avail_blocks = avail_blocks / (cs_data->blk_size / DISK_BLOCK_SIZE); if ((blocks * EXTEND_WARNING_FACTOR) > avail_blocks) { - send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, DB_LEN_STR(gv_cur_region), - (uint4)(avail_blocks - ((new_blocks <= avail_blocks) ? new_blocks : 0))); if (blocks > (uint4)avail_blocks) - return (uint4)(NO_FREE_SPACE); + { + SETUP_THREADGBL_ACCESS; + if (!ANTICIPATORY_FREEZE_ENABLED(cs_addrs)) + return (uint4)(NO_FREE_SPACE); + else + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4, + DB_LEN_STR(gv_cur_region), new_blocks, (uint4)avail_blocks); + } else + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, DB_LEN_STR(gv_cur_region), + (uint4)(avail_blocks - ((new_blocks <= avail_blocks) ? new_blocks : 0))); } } } - cs_addrs->extending = TRUE; + /* From here on, we need to use GDSFILEXT_CLNUP before returning to the caller */ was_crit = cs_addrs->now_crit; assert(!cs_addrs->hold_onto_crit || was_crit); /* If we are coming from mupip_extend (which gets crit itself) we better have waited for any unfreezes to occur. @@ -170,7 +201,7 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) */ assert(!was_crit || !cs_data->freeze || (dollar_tlevel && (CDB_STAGNATE <= t_tries))); /* - * If we are in the final retry and already hold crit, it is possible that csd->wc_blocked is also set to TRUE + * If we are in the final retry and already hold crit, it is possible that csa->nl->wc_blocked is also set to TRUE * (by a concurrent process in phase2 which encountered an error in the midst of commit and secshr_db_clnup * finished the job for it). In this case we do NOT want to invoke wcs_recover as that will update the "bt" * transaction numbers without correspondingly updating the history transaction numbers (effectively causing @@ -182,40 +213,42 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) for ( ; ; ) { grab_crit(gv_cur_region); - if (!cs_data->freeze) + if (!cs_data->freeze && !IS_REPL_INST_FROZEN) break; rel_crit(gv_cur_region); - while (cs_data->freeze) + while (cs_data->freeze || IS_REPL_INST_FROZEN) hiber_start(1000); } - } else if (cs_data->freeze && dollar_tlevel) + } else if ((cs_data->freeze || IS_REPL_INST_FROZEN) && dollar_tlevel) { /* We don't want to continue with file extension as explained above. Hence return with an error code which * op_tcommit will recognize (as a cdb_sc_needcrit type of restart) and restart accordingly. */ assert(CDB_STAGNATE <= t_tries); + GDSFILEXT_CLNUP; return (uint4)(FINAL_RETRY_FREEZE_PROG); } assert(cs_addrs->ti->total_blks == cs_data->trans_hist.total_blks); - if (cs_data->trans_hist.total_blks != filesize) - { - /* somebody else has already extended it, since we are in crit, this is trust-worthy - * however, in case of MM, we still need to remap the database */ - assert((cs_data->trans_hist.total_blks > filesize) GTM_TRUNCATE_ONLY( || (dba_mm != cs_addrs->hdr->acc_meth))); + old_total = cs_data->trans_hist.total_blks; + if (old_total != filesize) + { /* Somebody else has already extended it, since we are in crit, this is trust-worthy. However, in case of MM, + * we still need to remap the database + */ + assert((old_total > filesize) GTM_TRUNCATE_ONLY( || !is_mm)); /* For BG, someone else could have truncated or extended - we have no idea */ GDSFILEXT_CLNUP; return (SS_NORMAL); } - if (IS_GTM_IMAGE && (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks)) + if (trans_in_prog && SUSPICIOUS_EXTEND) { - if (FALSE == was_crit) + if (!was_crit) { - rel_crit(gv_cur_region); + GDSFILEXT_CLNUP; return (uint4)(EXTEND_SUSPECT); } - /* If free_blocks counter is not ok, then correct it. Do the check again. If still fails, then GTMASSERT. */ - if (is_free_blks_ctr_ok() || - (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks)) - GTMASSERT; /* held crit through bm_getfree into gdsfilext and still didn't get it right */ + /* If free_blocks counter is not ok, then correct it. Do the check again. If still fails, then it means we held + * crit through bm_getfree into gdsfilext and still didn't get it right. + */ + assertpro(!is_free_blks_ctr_ok() && !SUSPICIOUS_EXTEND); } if (JNL_ENABLED(cs_data)) { @@ -232,125 +265,90 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) if (jnl_status) { GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region)); return (uint4)(NO_FREE_SPACE); /* should have better return status */ } } - if (dba_mm == cs_addrs->hdr->acc_meth) + if (is_mm) { -#if defined(UNTARGETED_MSYNC) - status = msync((caddr_t)cs_addrs->db_addrs[0], (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0]), MS_SYNC); -#else cs_addrs->nl->mm_extender_pid = process_id; status = wcs_wtstart(gv_cur_region, 0); cs_addrs->nl->mm_extender_pid = 0; - if (0 != cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active.fl) - GTMASSERT; - status = 0; -#endif - if (0 == status) - { - /* Block SIGALRM for the duration when cs_data and cs_addrs are out of sync */ - sigprocmask(SIG_BLOCK, &blockalrm, &savemask); - need_to_restore_mask = TRUE; - tmp_csd = cs_data; - cs_data = (sgmnt_data_ptr_t)malloc(SIZEOF(*cs_data)); - memcpy((sm_uc_ptr_t)cs_data, (uchar_ptr_t)tmp_csd, SIZEOF(*cs_data)); - status = munmap((caddr_t)cs_addrs->db_addrs[0], (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0])); - } else - tmp_csd = NULL; + assertpro(SS_NORMAL == status); + old_base[0] = cs_addrs->db_addrs[0]; + old_base[1] = cs_addrs->db_addrs[1]; + cs_addrs->db_addrs[0] = NULL; /* don't rely on it until the mmap below */ + status = munmap((caddr_t)old_base[0], (size_t)(old_base[1] - old_base[0])); if (0 != status) { - if (tmp_csd) - { - free(cs_data); - cs_data = tmp_csd; - } + save_errno = errno; GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), + ERR_SYSCALL, 5, LEN_AND_LIT("munmap()"), CALLFROM, save_errno); return (uint4)(NO_FREE_SPACE); } - cs_addrs->hdr = cs_data; - cs_addrs->ti = &cs_data->trans_hist; - } - if (new_blocks + cs_data->trans_hist.total_blks > MAXTOTALBLKS(cs_data)) - { - GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(1) ERR_TOTALBLKMAX); - return (uint4)(NO_FREE_SPACE); + } else + { /* Due to concurrency issues, it is possible some process had issued a disk read of the GDS block# corresponding + * to "old_total" right after a truncate wrote a 512-byte block of zeros on disk (to signal end of the db file). + * If so, the global buffer containing this block needs to be invalidated now as part of the extend. If not, it is + * possible the EOF block on disk is now going to be overwritten by a properly initialized bitmap block (as part + * of the gdsfilext below) while the global buffer continues to have an incorrect copy of that bitmap block and + * this in turn would cause XXXX failures due to a bad bitmap block in shared memory. (GTM-7519) + */ + cr = db_csh_get((block_id)old_total); + if ((NULL != cr) && ((cache_rec_ptr_t)CR_NOTVALID != cr)) + { + assert((0 == cr->dirty) && (0 == cr->bt_index) && !cr->stopped); + cr->cycle++; + cr->blk = CR_BLKEMPTY; + } } CHECK_TN(cs_addrs, cs_data, cs_data->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */ - new_total = cs_data->trans_hist.total_blks + new_blocks; + new_total = old_total + new_blocks; new_eof = ((off_t)(cs_data->start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)new_total * cs_data->blk_size); - buff = (char *)malloc(DISK_BLOCK_SIZE); - memset(buff, 0, DISK_BLOCK_SIZE); - LSEEKWRITE(udi->fd, new_eof, buff, DISK_BLOCK_SIZE, save_errno); + DB_LSEEKWRITE(cs_addrs, udi->fn, udi->fd, new_eof, buff, DISK_BLOCK_SIZE, save_errno); if ((ENOSPC == save_errno) && IS_GTM_IMAGE) { - /* try to write it every second, and send message to operator - * log every 1/20 of cs_data->wait_disk_space - */ + /* Attempt to write every second, and send message to operator every 1/20 of cs_data->wait_disk_space */ wait_period = to_wait = DIVIDE_ROUND_UP(cs_data->wait_disk_space, CDB_STAGNATE + 1); to_msg = (to_wait / 8) ? (to_wait / 8) : 1; /* send around 8 messages during 1 wait_period */ while ((to_wait > 0) && (ENOSPC == save_errno)) { if ((to_wait == cs_data->wait_disk_space) || (to_wait % to_msg == 0)) - { - send_msg(VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id, - to_wait + (CDB_STAGNATE - t_tries) * wait_period, DB_LEN_STR(gv_cur_region), - ERR_TEXT, 2, - RTS_ERROR_TEXT("Please make more disk space available or shutdown GT.M to avoid data loss"), - save_errno); - gtm_putmsg(VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id, - to_wait + (CDB_STAGNATE - t_tries) * wait_period, DB_LEN_STR(gv_cur_region), - ERR_TEXT, 2, - RTS_ERROR_TEXT("Please make more disk space available or shutdown GT.M to avoid data loss"), - save_errno); - } - if (!was_crit) - rel_crit(gv_cur_region); + ISSUE_WAITDSKSPACE(to_wait, wait_period, send_msg_csa); hiber_start(1000); to_wait--; - if (!was_crit) - grab_crit(gv_cur_region); LSEEKWRITE(udi->fd, new_eof, buff, DISK_BLOCK_SIZE, save_errno); } } - free(buff); if (0 != save_errno) { GDSFILEXT_CLNUP; - if (ENOSPC == save_errno) - return (uint4)(NO_FREE_SPACE); - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + if (ENOSPC != save_errno) + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno); return (uint4)(NO_FREE_SPACE); } + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_1)) + { + LONG_SLEEP(600); + assert(FALSE); + } /* Ensure the EOF and metadata get to disk BEFORE any bitmap writes. Otherwise, the file size could no longer reflect * a proper extent and subsequent invocations of gdsfilext could corrupt the database. */ - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_1 == gtm_white_box_test_case_number)) - { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ - } - ) - GTM_FSYNC(udi->fd, status); + GTM_DB_FSYNC(cs_addrs, udi->fd, status); assert(0 == status); if (0 != status) { GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync()"), CALLFROM, errno); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync1()"), CALLFROM, status); return (uint4)(NO_FREE_SPACE); } - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_2 == gtm_white_box_test_case_number)) - { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ - } - ) - + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_2)) + { + LONG_SLEEP(600); + assert(FALSE); /* Should be killed before that */ + } DEBUG_ONLY(prev_extend_blks_to_upgrd = cs_data->blks_to_upgrd;) /* inctn_detail.blks_to_upgrd_delta holds the increase in "csd->blks_to_upgrd" due to the file extension */ inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta = @@ -372,7 +370,7 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) jnl_status = jnl_flush(gv_cur_region); if (SS_NORMAL != jnl_status) { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data), + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during gdsfilext"), jnl_status); assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */ @@ -384,13 +382,13 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) } if (new_bit_maps) { - for (map = ROUND_UP(cs_data->trans_hist.total_blks, bplmap); map < new_total; map += bplmap) + for (map = ROUND_UP(old_total, bplmap); map < new_total; map += bplmap) { DEBUG_ONLY(new_bit_maps--;) if (SS_NORMAL != (status = bml_init(map))) { GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); return (uint4)(NO_FREE_SPACE); } } @@ -399,56 +397,30 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) /* Ensures that if at all the file header write goes to disk before the crash, the bitmap blocks are all * guaranteed to be initialized and synced to disk as well. */ - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_3 == gtm_white_box_test_case_number)) - { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ - } - ) - - GTM_FSYNC(udi->fd, status); + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_3)) + { + LONG_SLEEP(600); + assert(FALSE); /* Should be killed before that */ + } + GTM_DB_FSYNC(cs_addrs, udi->fd, status); assert(0 == status); if (0 != status) { GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync()"), CALLFROM, errno); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync2()"), CALLFROM, status); return (uint4)(NO_FREE_SPACE); } - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_4 == gtm_white_box_test_case_number)) - { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ - } - ) + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_4)) + { + LONG_SLEEP(600); + assert(FALSE); /* Should be killed before that */ + } assert(cs_data->blks_to_upgrd == (inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta + prev_extend_blks_to_upgrd)); - if (dba_mm == cs_addrs->hdr->acc_meth) - { /* On 32 bit aix, is it possible we can have now increased the file size past what we can map ? */ - mm_prot = cs_addrs->read_write ? (PROT_READ | PROT_WRITE) : PROT_READ; - old_base[0] = cs_addrs->db_addrs[0]; - old_base[1] = cs_addrs->db_addrs[1]; - if (-1 == ((sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, (size_t)new_eof, mm_prot, - GTM_MM_FLAGS, udi->fd, (off_t)0)))) - { - GDSFILEXT_CLNUP; - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), errno); - return (uint4)(NO_FREE_SPACE); - } - free(cs_data); /* note current assumption that cs_data has not changed since memcpy above */ - /* In addition to updating the internal map values, gds_map_moved sets cs_data to point to the remapped file */ - gds_map_moved(cs_addrs->db_addrs[0], old_base[0], old_base[1], new_eof); - cs_addrs->total_blks = new_total; /* Local copy to test if file has extended */ - } -# ifdef GTM_TRUNCATE - /* Used with BG to detect concurrent truncates in t_end and tp_tend */ - cs_addrs->total_blks = MAX(cs_addrs->total_blks, new_total); -# endif assert(0 < (int)blocks); assert(0 < (int)(cs_addrs->ti->free_blocks + blocks)); cs_addrs->ti->free_blocks += blocks; - blocks = cs_data->trans_hist.total_blks; - cs_addrs->ti->total_blks = new_total; + cs_addrs->total_blks = cs_addrs->ti->total_blks = new_total; + blocks = old_total; if (blocks / bplmap * bplmap != blocks) { bit_set(blocks / bplmap, MM_ADDR(cs_data)); /* Mark old last local map as having space */ @@ -464,24 +436,43 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize) INCREMENT_CURR_TN(cs_data); } /* white box test for interrupted file extension */ - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_5 == gtm_white_box_test_case_number)) - { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ - } - ) + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_5)) + { + LONG_SLEEP(600); + assert(FALSE); /* Should be killed before that */ + } fileheader_sync(gv_cur_region); /* white box test for interrupted file extension */ - DEBUG_ONLY( - if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_6 == gtm_white_box_test_case_number)) + if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_6)) + { + LONG_SLEEP(600); + assert(FALSE); /* Should be killed before that */ + } + if (is_mm) + { + assert((NULL != old_base[0]) && (NULL != old_base[1])); + mmap_sz = new_eof - BLK_ZERO_OFF(cs_data); /* Don't mmap the file header and master map */ + CHECK_LARGEFILE_MMAP(gv_cur_region, mmap_sz); /* can issue rts_error MMFILETOOLARGE */ + status = (sm_long_t)(mmap_retaddr = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(cs_data), FALSE)); + GTM_WHITE_BOX_TEST(WBTEST_MMAP_SYSCALL_FAIL, status, -1); + if (-1 == status) { - LONG_SLEEP(600); - assert(FALSE); /* Should be killed before that */ + save_errno = errno; + WBTEST_ASSIGN_ONLY(WBTEST_MMAP_SYSCALL_FAIL, save_errno, ENOMEM); + GDSFILEXT_CLNUP; + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), + ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, save_errno); + return (uint4)(NO_FREE_SPACE); } - ) + /* In addition to updating the internal map values, gds_map_moved sets cs_data to point to the remapped file */ + gds_map_moved(mmap_retaddr, old_base[0], old_base[1], mmap_sz); /* updates cs_addrs->db_addrs[1] */ + cs_addrs->db_addrs[0] = mmap_retaddr; + assert(cs_addrs->db_addrs[0] < cs_addrs->db_addrs[1]); + } GDSFILEXT_CLNUP; + INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_db_extends, 1); if (!gtm_dbfilext_syslog_disable) - send_msg(VARLSTCNT(7) ERR_DBFILEXT, 5, DB_LEN_STR(gv_cur_region), blocks, new_total, &curr_tn); + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_DBFILEXT, 5, DB_LEN_STR(gv_cur_region), blocks, new_total, + &curr_tn); return (SS_NORMAL); } diff --git a/sr_unix/gdsfilext_nojnl.c b/sr_unix/gdsfilext_nojnl.c index eb95bf4..afc646d 100644 --- a/sr_unix/gdsfilext_nojnl.c +++ b/sr_unix/gdsfilext_nojnl.c @@ -39,6 +39,7 @@ #include "gtmimagename.h" #include "gdsfilext_nojnl.h" #include "gtmio.h" +#include "anticipatory_freeze.h" #include "sleep_cnt.h" #include "wcs_sleep.h" @@ -48,7 +49,6 @@ #include "shmpool.h" error_def(ERR_DBFILERR); - /* Minimal file extend. Called (at the moment) from mur_back_process.c when processing JRT_TRUNC record. * We want to avoid jnl and other interferences of gdsfilext. */ @@ -60,8 +60,10 @@ int gdsfilext_nojnl(gd_region* reg, uint4 new_total, uint4 old_total) off_t offset; char *newmap; uint4 ii; + unix_db_info *udi; - csa = &FILE_INFO(reg)->s_addrs; + udi = FILE_INFO(reg); + csa = &udi->s_addrs; csd = csa->hdr; assert(old_total < new_total); assert(new_total <= MAXTOTALBLKS(csd)); @@ -69,7 +71,6 @@ int gdsfilext_nojnl(gd_region* reg, uint4 new_total, uint4 old_total) if (0 != status) { send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); - /* if (ENOSPC == status)? wait for more space? */ return status; } /* initialize the bitmap tn's to 0. */ @@ -79,7 +80,7 @@ int gdsfilext_nojnl(gd_region* reg, uint4 new_total, uint4 old_total) for (ii = ROUND_UP(old_total, BLKS_PER_LMAP); ii < new_total; ii += BLKS_PER_LMAP) { offset = (off_t)(csd->start_vbn - 1) * DISK_BLOCK_SIZE + (off_t)ii * csd->blk_size; - LSEEKWRITE(FILE_INFO(reg)->fd, offset, newmap, csd->blk_size, status); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, offset, newmap, csd->blk_size, status); if (0 != status) { send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status); diff --git a/sr_unix/gen_sym_hash.sh b/sr_unix/gen_sym_hash.sh index 915ddfa..1977620 100644 --- a/sr_unix/gen_sym_hash.sh +++ b/sr_unix/gen_sym_hash.sh @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2010 Fidelity Information Services, Inc # +# Copyright 2010, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -25,13 +25,22 @@ # please verify that UNIQ_ENC_PARAM_STRING in gtmcrypt_ref.h # and encr_param_string in this module match. +if [ $# -lt 1 ]; then + $ECHO "Usage: $0 " ; exit 1 +fi hostos=`uname -s` +basedir=`dirname $0` # try to get a predictable which if [ "OS/390" = "$hostos" ] ; then which=whence ; elif [ -x "/usr/bin/which" ] ; then which=/usr/bin/which else which=which fi +if [ ! -x $basedir/show_install_config.sh ]; then + echo "Cannot find show_install_config.sh in $basedir. Exiting" + exit 1 +fi +algorithm=`$basedir/show_install_config.sh | awk '/^ALGORITHM/ {print $NF}'` # temporary file if [ -x "`$which mktemp 2>&1`" ] ; then tmp_file=`mktemp` else tmp_file=/tmp/`basename $0`_$$.tmp ; fi @@ -41,17 +50,11 @@ trap 'rm -rf $tmp_file ; stty sane ; exit 1' HUP INT QUIT TERM TRAP ECHO=/bin/echo ECHO_OPTIONS="" -if [ "Linux" = $hostos ] ; then ECHO_OPTIONS="-e" ; encr_param_string="AES256CFB" ; -elif [ "AIX" = "$hostos" ]; then encr_param_string="BLOWFISHCFB" -else encr_param_string="AES256CFB" -fi +if [ "Linux" = $hostos ] ; then ECHO_OPTIONS="-e" ; fi; -if [ $# -lt 1 ]; then - $ECHO "Usage: `basename $0` encrypted symmetric key file" ; exit 1 -fi encrypted_key_file="$1" -$ECHO $ECHO_OPTIONS $encr_param_string\\c >$tmp_file +$ECHO $ECHO_OPTIONS $algorithm\\c >$tmp_file # Identify GnuPG - it is required if [ -x "`$which gpg 2>&1`" ] ; then gpg=gpg diff --git a/sr_unix/gen_xfer_desc.cmake b/sr_unix/gen_xfer_desc.cmake index a9e1d2d..62a4a16 100644 --- a/sr_unix/gen_xfer_desc.cmake +++ b/sr_unix/gen_xfer_desc.cmake @@ -1,3 +1,13 @@ +################################################################# +# # +# Copyright 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. # +# # +################################################################# set(I "") foreach(i ${includes}) list(APPEND I "-I${i}") @@ -21,10 +31,58 @@ file(STRINGS tmp_xfer_2.c lines REGEX "MY_XF") string(REGEX REPLACE "(MY_XF|,)" "" names "${lines}") file(REMOVE tmp_xfer_1.c tmp_xfer_2.c) +if("${arch}" MATCHES "ia64") + # Guess what! Its possible for xfer_table to be initialized by functions others than + # then the ones in xfer.h. So append those names explicitly here + list(APPEND names + op_fnzreverse + op_zst_st_over + op_zst_fet_over + op_zstzb_fet_over + op_zstzb_st_over + opp_zstepret + opp_zstepretarg + op_zstepfetch + op_zstepstart + op_zstzbfetch + op_zstzbstart + opp_zst_over_ret + opp_zst_over_retarg + op_fetchintrrpt + op_startintrrpt + op_forintrrpt + op_mprofextexfun + op_mprofextcall + op_mprofcalll + op_mprofcallb + op_mprofcallw + op_mprofcallspl + op_mprofcallspb + op_mprofcallspw + op_mprofexfun + op_mprofforlcldow + op_mprofforlcldol + op_mprofforlcldob + op_mprofforchk1 + op_mproflinefetch + op_mproflinestart + ) +endif() + file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/sources.list" sources) +# On X86_64, the calling convention for variable length functions defines that the register $RAX +# (ie the lower 8 bytes of this register actually) will contain the # of floating point arguments passed to that function. +# $RAX is not an argument register normally and so is typically unused (and also is not expected to be preserved across calls). +# since none of the XFER functions actually take double/float arguments, but some are variable length functions, +# the generated code should set the $RAX register to the value '0'. +# Theoretically this register can be set to 0 all the time during a function call. +# But to optimize the number of generated instructions, identify which XFER function is actually a var arg function +# And if the logic to identify it falls thru, blindly assume its a VAR_ARG function. +# Hence the logic below might incorrectly mark a few functions like op_sub, op_fnzascii as C_VAR_ARGS. But that is okay. + set(ftypes "") -#set(defines "") +set(defines "\n/* Defines used in resetting xfer_table_desc on transfer table changes */\n") foreach(name ${names}) set(ftype "") if(";${sources};" MATCHES ";([^;]*/${name}\\.s);") @@ -38,26 +96,32 @@ foreach(name ${names}) endif() endif() if(NOT ftype) - set(ftype GTM_C_VAR_ARGS_RTN) + set(ftype "GTM_C_VAR_ARGS_RTN") foreach(src ${sources}) if("${src}" MATCHES "\\.s$") file(STRINGS "${src}" sig REGEX "^${name}") if(sig) - set(ftype GTM_ASM_RTN) + set(ftype "GTM_ASM_RTN") break() endif() endif() endforeach() endif() - set(ftypes "${ftypes}${ftype}, /* ${name} */ \\\n") - #set(defines "${defines}#define ${name}_FUNCTYPE ${ftype}\n") # TODO for ia64 + set(ftypes "${ftypes}${ftype}, /* ${name} abc */ \\\n") + set(defines "${defines}#define ${name}_FUNCTYPE ${ftype}\n") endforeach() +if("${arch}" MATCHES "ia64") +else() + # Not IA64? reset defines + set(defines "") +endif() + file(WRITE xfer_desc.i "/* Generated by gen_xfer_desc.cmake */ #define GTM_C_RTN 1 #define GTM_ASM_RTN 2 #define GTM_C_VAR_ARGS_RTN 3 #define DEFINE_XFER_TABLE_DESC char xfer_table_desc[] = \\ { \\ -${ftypes}0} - \n") +${ftypes}0}\n +${defines}") diff --git a/sr_unix/generic_signal_handler.c b/sr_unix/generic_signal_handler.c index 93cd39f..9fbb3ed 100644 --- a/sr_unix/generic_signal_handler.c +++ b/sr_unix/generic_signal_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,9 @@ #include "gtm_inet.h" #include +#ifdef GTM_PTHREAD +# include +#endif #include "gtm_stdio.h" #include "error.h" @@ -37,17 +40,26 @@ #include "gtmmsg.h" #include "gtmio.h" #include "have_crit.h" +#include "util.h" -#define DEFER_EXIT_PROCESSING ((EXIT_PENDING_TOLERANT >= exit_state) && \ +#define DEFER_EXIT_PROCESSING ((EXIT_PENDING_TOLERANT >= exit_state) && \ (exit_handler_active || !OK_TO_INTERRUPT)) + +/* Combine send_msg and gtm_putmsg into one macro to conserve space. */ +#define SEND_AND_PUT_MSG(...) \ +{ \ + if (OK_TO_SEND_MSG) \ + send_msg_csa(CSA_ARG(NULL) __VA_ARGS__); \ + gtm_putmsg_csa(CSA_ARG(NULL) __VA_ARGS__); \ +} + /* These fields are defined as globals not because they are used globally but * so they will be easily retrievable even in 'pro' cores. */ -GBLDEF siginfo_t exi_siginfo; +GBLDEF siginfo_t exi_siginfo; -GBLDEF gtm_sigcontext_t exi_context; +GBLDEF gtm_sigcontext_t exi_context; -GBLREF VSIG_ATOMIC_T forced_exit; GBLREF int4 forced_exit_err; GBLREF int4 exi_condition; GBLREF boolean_t dont_want_core; @@ -75,12 +87,12 @@ error_def(ERR_KRNLKILL); void generic_signal_handler(int sig, siginfo_t *info, void *context) { - boolean_t exit_now; gtm_sigcontext_t *context_ptr; - void (*signal_routine)(); + void (*signal_routine)(); DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); /* Save parameter value in global variables for easy access in core */ dont_want_core = FALSE; /* (re)set in case we recurse */ created_core = FALSE; /* we can deal with a second core if needbe */ @@ -126,29 +138,33 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) switch(sig) { case SIGTERM: - forced_exit_err = (IS_GTMSECSHR_IMAGE ? ERR_GTMSECSHRSHUTDN : ERR_FORCEDHALT); - /* If nothing pending AND we have crit or in wcs_wtstart() or already in exit processing, wait to - * invoke shutdown. wcs_wtstart() manipulates the active queue that a concurrent process in crit - * in bt_put() might be waiting for. interrupting it can cause deadlocks (see C9C11-002178). - */ - if (DEFER_EXIT_PROCESSING) + if (!IS_GTMSECSHR_IMAGE) { - forced_exit = TRUE; - exit_state++; /* Make exit pending, may still be tolerant though */ - assert(!IS_GTMSECSHR_IMAGE); - if (exit_handler_active && !gtm_quiet_halt) + forced_exit_err = ERR_FORCEDHALT; + /* If nothing pending AND we have crit or in wcs_wtstart() or already in exit processing, wait to + * invoke shutdown. wcs_wtstart() manipulates the active queue that a concurrent process in crit + * in bt_put() might be waiting for. interrupting it can cause deadlocks (see C9C11-002178). + */ + if (DEFER_EXIT_PROCESSING) { - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + SET_FORCED_EXIT_STATE; + exit_state++; /* Make exit pending, may still be tolerant though */ + assert(!IS_GTMSECSHR_IMAGE); + if (exit_handler_active && !gtm_quiet_halt) + SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); + return; } - return; - } - exit_state = EXIT_IMMED; - SET_PROCESS_EXITING_TRUE; /* set this BEFORE cancelling timers as wcs_phase2_commit_wait relies on this */ - if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt) - { - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + exit_state = EXIT_IMMED; + SET_PROCESS_EXITING_TRUE; /* Set this BEFORE cancelling timers as wcs_phase2_commit_wait + * relies on this. + */ + if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt) + SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); + } else + { /* Special case for gtmsecshr - no deferral just exit */ + forced_exit_err = ERR_GTMSECSHRSHUTDN; + if (OK_TO_SEND_MSG) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); } dont_want_core = TRUE; break; @@ -179,7 +195,7 @@ void generic_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 (DEFER_EXIT_PROCESSING) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ assert(!IS_GTMSECSHR_IMAGE); return; @@ -189,32 +205,24 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) switch(signal_info.infotype) { case GTMSIGINFO_NONE: - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); + SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), + process_id, sig); break; case GTMSIGINFO_USER: - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); + SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); + SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); + SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); + SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.bad_vadr); break; } break; @@ -224,15 +232,14 @@ void generic_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 (DEFER_EXIT_PROCESSING) { - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ assert(!IS_GTMSECSHR_IMAGE); return; } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(1) forced_exit_err); - gtm_putmsg(VARLSTCNT(1) forced_exit_err); + SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err); dont_want_core = TRUE; break; # endif @@ -243,8 +250,8 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) case GTMSIGINFO_NONE: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); - gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig); + SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), + process_id, sig); break; case GTMSIGINFO_USER: /* This signal was SENT to us so it can wait until we are out of crit to cause an exit */ @@ -253,7 +260,7 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) if (DEFER_EXIT_PROCESSING) { assert(!IS_GTMSECSHR_IMAGE); - forced_exit = TRUE; + SET_FORCED_EXIT_STATE; exit_state++; /* Make exit pending, may still be tolerant though */ need_core = TRUE; gtm_fork_n_core(); /* Generate "virgin" core while we can */ @@ -261,34 +268,26 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) } exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.send_pid, signal_info.send_uid); + SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.send_pid, signal_info.send_uid); break; case GTMSIGINFO_ILOC + GTMSIGINFO_BADR: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); + SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.int_iadr, signal_info.bad_vadr); break; case GTMSIGINFO_ILOC: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.int_iadr); + SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.int_iadr); break; case GTMSIGINFO_BADR: exit_state = EXIT_IMMED; SET_PROCESS_EXITING_TRUE; - send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); - gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), - process_id, sig, signal_info.bad_vadr); + SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type), + process_id, sig, signal_info.bad_vadr); break; default: exit_state = EXIT_IMMED; @@ -297,12 +296,14 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context) } if (0 != signal_info.sig_err) { - send_msg(VARLSTCNT(1) signal_info.sig_err); - gtm_putmsg(VARLSTCNT(1) signal_info.sig_err); + SEND_AND_PUT_MSG(VARLSTCNT(1) signal_info.sig_err); } break; } /* switch (sig) */ - cancel_timer(0); /* Don't want any interruptions */ + /* Stop the timers but do not cancel them. This allows the timer structures to appear in the core where gtmpcat can + * extract them allowing us to see what was going on. + */ + sys_canc_timer(); FFLUSH(stdout); if (!dont_want_core) { diff --git a/sr_unix/get_full_path.c b/sr_unix/get_full_path.c index 386bfde..11781a6 100644 --- a/sr_unix/get_full_path.c +++ b/sr_unix/get_full_path.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,32 +11,41 @@ #include "mdef.h" +#include #include #include "gtm_unistd.h" #include "gtm_string.h" +#include "gtm_limits.h" #include "gdsroot.h" #include "gdsbt.h" +#include "have_crit.h" -/* gets the full path name for a given file name. Prepends the CWD, even if the file does not exist */ +error_def(ERR_FILENAMETOOLONG); +/* Gets the full path name for a given file name. Prepends the CWD, even if the file does not exist. */ boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, unsigned int *full_len, int max_len, uint4 *status) { char *cptr, *c1; - char cwdbuf[MAX_FN_LEN + 1]; + char cwdbuf[GTM_PATH_MAX]; int cwd_len; int i, length; char *getcwd_res; - error_def(ERR_FILENAMETOOLONG); if ('/' == *orig_fn) - { - /* The original path is already complete */ + { /* The original path is already complete */ + if (max_len < orig_len) + { + *status = ERR_FILENAMETOOLONG; + return FALSE; + + } length = orig_len; memcpy(full_fn, orig_fn, length); } else { - if (NULL == GETCWD(cwdbuf, SIZEOF(cwdbuf), getcwd_res)) + GETCWD(cwdbuf, SIZEOF(cwdbuf), getcwd_res); + if (NULL == getcwd_res) { *status = errno; return FALSE; @@ -55,7 +64,7 @@ boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, uns for (c1 = &cwdbuf[cwd_len - 1]; i > 0; --i) while ('/' != *c1) --c1; - if ((length = (int)((c1 - cwdbuf) + orig_len - (cptr - orig_fn))) + 1 > max_len) + if ((length = (int)((c1 - cwdbuf) + orig_len - (cptr - orig_fn))) + 1 > max_len) /* Warning - assignment */ { *status = ERR_FILENAMETOOLONG; return FALSE; @@ -66,7 +75,7 @@ boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, uns { if ('.' == *cptr && '/' == (*(cptr + 1))) cptr += 2; - if ((length = (int)(cwd_len + 1 + orig_len - (cptr - orig_fn))) + 1 > max_len) + if ((length = (int)(cwd_len + 1 + orig_len - (cptr - orig_fn))) + 1 > max_len) /* Warning - assignment */ { *status = ERR_FILENAMETOOLONG; return FALSE; diff --git a/sr_unix/getjobnum.c b/sr_unix/getjobnum.c index 16de8e6..fba06d1 100644 --- a/sr_unix/getjobnum.c +++ b/sr_unix/getjobnum.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,16 +10,17 @@ ****************************************************************/ #include "mdef.h" + #include "gtm_unistd.h" #include "getjobnum.h" -GBLDEF uint4 user_id; - GBLREF uint4 process_id; -GBLREF uint4 image_count; /* not used in UNIX but defined to preserve VMS compatibility */ void getjobnum(void) { + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; process_id = getpid(); - user_id = (uint4)getuid(); + TREF(user_id) = (uint4)getuid(); } diff --git a/sr_unix/go_load.c b/sr_unix/go_load.c index f98123f..d72e8e8 100644 --- a/sr_unix/go_load.c +++ b/sr_unix/go_load.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,20 +32,30 @@ #include "load.h" #include "mu_gvis.h" #include "mupip_put_gvdata.h" +#include "mupip_put_gvn_fragment.h" #include "str2gvkey.h" #include "gtmmsg.h" #include "gtm_utf8.h" #include #include "gv_trigger.h" -GBLREF bool mupip_error_occurred; -GBLREF bool mu_ctrly_occurred; -GBLREF bool mu_ctrlc_occurred; -GBLREF spdesc stringpool; -GBLREF gv_key *gv_currkey; +GBLREF bool mupip_error_occurred; +GBLREF bool mu_ctrly_occurred; +GBLREF bool mu_ctrlc_occurred; +GBLREF spdesc stringpool; +GBLREF gv_key *gv_currkey; +GBLREF sgmnt_addrs *cs_addrs; -#define GO_PUT_SUB 0 -#define GO_PUT_DATA 1 +error_def(ERR_LOADCTRLY); +error_def(ERR_LOADEOF); +error_def(ERR_LOADFILERR); +error_def(ERR_LOADINVCHSET); +error_def(ERR_MUNOFINISH); +error_def(ERR_TRIGDATAIGNORE); + +#define GO_PUT_SUB 0 +#define GO_PUT_DATA 1 +#define GO_SET_EXTRACT 2 #define DEFAULT_MAX_REC_SIZE 3096 #define ISSUE_TRIGDATAIGNORE_IF_NEEDED(KEYLENGTH, PTR, HASHT_GBL) \ { \ @@ -54,13 +64,12 @@ GBLREF gv_key *gv_currkey; */ \ if ((HASHT_GBL = IS_GVKEY_HASHT_FULL_GBLNAME(KEYLENGTH, PTR)) && !hasht_ignored) \ { \ - gtm_putmsg(VARLSTCNT(4) ERR_TRIGDATAIGNORE, 2, KEYLENGTH, PTR); \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGDATAIGNORE, 2, KEYLENGTH, PTR); \ hasht_ignored = TRUE; \ } \ } -static readonly unsigned char gt_lit[] = "LOAD TOTAL"; -void go_call_db(int routine, char *parm1, int parm2); +void go_call_db(int routine, char *parm1, int parm2, int val_off1, int val_len1); void go_load(uint4 begin, uint4 end) { @@ -70,13 +79,9 @@ void go_load(uint4 begin, uint4 end) mstr src, des; unsigned char *rec_buff, ch; boolean_t utf8_extract, format_error = FALSE, hasht_ignored = FALSE, hasht_gbl = FALSE; - - error_def(ERR_LOADCTRLY); - error_def(ERR_LOADEOF); - error_def(ERR_LOADFILERR); - error_def(ERR_MUNOFINISH); - error_def(ERR_LOADINVCHSET); - error_def(ERR_TRIGDATAIGNORE); + char *val_off; + int val_len, val_off1, val_len1; + boolean_t is_setextract; gvinit(); @@ -98,9 +103,9 @@ void go_load(uint4 begin, uint4 end) if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode)) { /* extract CHSET doesn't match $ZCHSET */ if (utf8_extract) - gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8")); else - gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M")); mupip_error_occurred = TRUE; free(rec_buff); return; @@ -126,7 +131,7 @@ void go_load(uint4 begin, uint4 end) len = file_input_get(&ptr); if (len < 0) /* The IO device has signalled an end of file */ { - gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin); mupip_error_occurred = TRUE; } if (mupip_error_occurred) @@ -150,7 +155,7 @@ void go_load(uint4 begin, uint4 end) if (mu_ctrlc_occurred) { util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE, - LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len); + 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); mu_gvis(); util_out_print(0, TRUE); @@ -169,20 +174,29 @@ void go_load(uint4 begin, uint4 end) break; ptr++; } - stringpool.free = stringpool.base; if (0 == len) continue; if (MU_FMT_GO != fmt) { - /* Determine the ZWR key length. -1 (SIZEOF(=)) is needed since ZWR allows '^x(1,2)='*/ - keylength = zwrkeylength(ptr, len - 1); + /* Determine if the ZWR has $extract format */ + if ('$' == *ptr) + { + keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, &val_off1, &val_len1); + ptr = ptr + 4; /* Skip first 4 character '$','z','e','(' */ + is_setextract = TRUE; + } else + { + /* Determine the ZWR key length. -1 (SIZEOF(=)) is needed since ZWR allows '^x(1,2)='*/ + keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, NULL, NULL); + is_setextract = FALSE; + } ISSUE_TRIGDATAIGNORE_IF_NEEDED(keylength, ptr, hasht_gbl); if (hasht_gbl) { hasht_gbl = FALSE; continue; } - go_call_db(GO_PUT_SUB, ptr, keylength); + go_call_db(GO_PUT_SUB, ptr, keylength, 0, 0); if (mupip_error_occurred) { mu_gvis(); @@ -193,8 +207,8 @@ void go_load(uint4 begin, uint4 end) assert(keylength < len - 1); if (max_subsc_len < (gv_currkey->end + 1)) max_subsc_len = gv_currkey->end + 1; - src.len = len - keylength - 1; - src.addr = (char *)(ptr + keylength + 1); + src.len = val_len; + src.addr = val_off; des.len = 0; if (src.len > max_rec_size) { @@ -211,8 +225,8 @@ void go_load(uint4 begin, uint4 end) } if (max_data_len < des.len) max_data_len = des.len; - stringpool.free = stringpool.base; - go_call_db(GO_PUT_DATA, (char *)rec_buff, des.len); + (is_setextract) ? go_call_db(GO_SET_EXTRACT, des.addr, des.len, val_off1, val_len1) + : go_call_db(GO_PUT_DATA, (char *)rec_buff, des.len, 0, 0); if (mupip_error_occurred) { mu_gvis(); @@ -232,7 +246,7 @@ void go_load(uint4 begin, uint4 end) hasht_gbl = FALSE; continue; } - go_call_db(GO_PUT_SUB, ptr, len); + go_call_db(GO_PUT_SUB, ptr, len, 0, 0); if (mupip_error_occurred) { mu_gvis(); @@ -258,7 +272,7 @@ void go_load(uint4 begin, uint4 end) stringpool.free = stringpool.base; if (max_data_len < len) max_data_len = len; - go_call_db(GO_PUT_DATA, ptr, len); + go_call_db(GO_PUT_DATA, ptr, len, 0, 0); if (mupip_error_occurred) { mu_gvis(); @@ -273,7 +287,7 @@ void go_load(uint4 begin, uint4 end) file_input_close(); if (mu_ctrly_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_LOADCTRLY); + 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, @@ -283,7 +297,7 @@ void go_load(uint4 begin, uint4 end) mupip_exit(ERR_LOADFILERR); } -void go_call_db(int routine, char *parm1, int parm2) +void go_call_db(int routine, char *parm1, int parm2, int val_off1, int val_len1) { /* In order to duplicate the VMS functionality, which is to trap all errors in mupip_load_ch * and continue in go_load after they occur, it is necessary to call these routines from a @@ -296,7 +310,10 @@ void go_call_db(int routine, char *parm1, int parm2) str2gvkey_gvfunc(parm1, parm2); break; case GO_PUT_DATA: - mupip_put_gvdata(parm1 , parm2); + mupip_put_gvdata(parm1, parm2); + break; + case GO_SET_EXTRACT: + mupip_put_gvn_fragment(parm1, parm2, val_off1, val_len1); break; } REVERT; diff --git a/sr_unix/golevel.c b/sr_unix/golevel.c index 38194c5..74fa095 100644 --- a/sr_unix/golevel.c +++ b/sr_unix/golevel.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,6 +22,9 @@ GBLREF stack_frame *frame_pointer; +error_def(ERR_ZGOTOTOOBIG); +error_def(ERR_ZGOTOLTZERO); + #ifdef GTM_TRIGGER void golevel(int4 level, boolean_t unwtrigrframe) #else @@ -31,15 +34,12 @@ void golevel(int4 level) stack_frame *fp, *fpprev; int4 unwframes, unwlevels, prevlvl; - error_def(ERR_ZGOTOTOOBIG); - error_def(ERR_ZGOTOLTZERO); - if (0 > level) - rts_error(VARLSTCNT(1) ERR_ZGOTOLTZERO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO); unwlevels = dollar_zlevel() - level; if (0 > unwlevels) /* Couldn't get to the level we were trying to unwind to */ - rts_error(VARLSTCNT(1) ERR_ZGOTOTOOBIG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG); unwframes = 0; for (fp = frame_pointer; NULL != fp; fp = fpprev) { @@ -60,7 +60,7 @@ void golevel(int4 level) } unwframes++; if (SFT_TRIGR & fp->type) - { /* Unwinding a trigger base frame leave a null frame_pointer so allow us to jump over the + { /* Unwinding a trigger base frame leaves a null frame_pointer so allow us to jump over the * base frame to the rich stack beneath.. */ assert(NULL == fpprev); diff --git a/sr_unix/grab_crit.c b/sr_unix/grab_crit.c index a627aa8..37c89b3 100644 --- a/sr_unix/grab_crit.c +++ b/sr_unix/grab_crit.c @@ -36,6 +36,7 @@ #endif #include "gtmimagename.h" #include "error.h" +#include "anticipatory_freeze.h" GBLREF volatile int4 crit_count; GBLREF short crash_count; @@ -89,7 +90,6 @@ void grab_crit(gd_region *reg) * Not following the protocol (obtaining lock on journal pool AFTER obtaining crit on database region), * can lead to potential deadlocks */ - assert((jnlpool.jnlpool_dummy_reg && jnlpool.jnlpool_dummy_reg->open) || jgbl.onlnrlbk); jnlpool_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; assert(!jnlpool_csa->now_crit); } @@ -139,9 +139,12 @@ void grab_crit(gd_region *reg) TREF(grabbing_crit) = NULL; crit_count = 0; } - if (csd->file_corrupt && !mupip_jnl_recover) + /* Commands/Utilties that plays with the file_corrupt flags (DSE/MUPIP SET -PARTIAL_RECOV_BYPASS/RECOVER/ROLLBACK) should + * NOT issue DBFLCORRP. Use skip_file_corrupt_check global variable for this purpose + */ + if (csd->file_corrupt && !TREF(skip_file_corrupt_check)) rts_error(VARLSTCNT(4) ERR_DBFLCORRP, 2, DB_LEN_STR(reg)); - if (csd->wc_blocked) + if (cnl->wc_blocked) wcs_recover(reg); return; } diff --git a/sr_unix/grab_lock.c b/sr_unix/grab_lock.c index c781246..22b8dba 100644 --- a/sr_unix/grab_lock.c +++ b/sr_unix/grab_lock.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,12 +27,17 @@ #include "gtmsource.h" #include "repl_instance.h" #include "jnl.h" +#include "gtmimagename.h" /* for IS_GTCM_GNP_SERVER_IMAGE */ +#include "anticipatory_freeze.h" +#include "util.h" /* for OUT_BUFF_SIZE */ GBLREF volatile int4 crit_count; GBLREF uint4 process_id; GBLREF node_local_ptr_t locknl; GBLREF jnlpool_addrs jnlpool; GBLREF jnl_gbls_t jgbl; +GBLREF boolean_t is_src_server; +GBLREF boolean_t jnlpool_init_needed; error_def(ERR_DBCCERR); error_def(ERR_CRITRESET); @@ -44,26 +49,35 @@ error_def(ERR_TEXT); * mutex_spin_parms_struct, and node_local in shared memory. Initialize the fields as in * jnlpool_init(). Pass the address of the dummy region as argument to this function. */ -void grab_lock(gd_region *reg) +boolean_t grab_lock(gd_region *reg, boolean_t is_blocking_wait, uint4 onln_rlbk_action) { unix_db_info *udi; - sgmnt_addrs *csa; + sgmnt_addrs *csa; enum cdb_sc status; mutex_spin_parms_ptr_t mutex_spin_parms; + char scndry_msg[OUT_BUFF_SIZE]; +# ifdef DEBUG + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; +# endif udi = FILE_INFO(reg); csa = &udi->s_addrs; assert(!csa->hold_onto_crit); + assert(!csa->now_crit); if (!csa->now_crit) { assert(0 == crit_count); crit_count++; /* prevent interrupts */ - DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */ - mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE); - /* This assumes that mutex_spin_parms_t is located immediately after the crit structures */ + DEBUG_ONLY(locknl = csa->nl); /* for DEBUG_ONLY LOCK_HIST macro */ + mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE); + /* This assumes that mutex_spin_parms_t is located immediately after the crit structures */ /* As of 10/07/98, crashcnt field in mutex_struct is not changed by any function for the dummy region */ - status = mutex_lockw(reg, mutex_spin_parms, 0); - DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */ + if (is_blocking_wait) + status = mutex_lockw(reg, mutex_spin_parms, 0); + else + status = mutex_lockwim(reg, mutex_spin_parms, 0); + DEBUG_ONLY(locknl = NULL); /* restore "locknl" to default value */ if (status != cdb_sc_normal) { crit_count = 0; @@ -73,10 +87,12 @@ void grab_lock(gd_region *reg) rts_error(VARLSTCNT(4) ERR_CRITRESET, 2, REG_LEN_STR(reg)); case cdb_sc_dbccerr: rts_error(VARLSTCNT(4) ERR_DBCCERR, 2, REG_LEN_STR(reg)); + case cdb_sc_nolock: + return FALSE; default: GTMASSERT; } - return; + return FALSE; } /* There is only one case we know of when csa->nl->in_crit can be non-zero and that is when a process holding * crit gets kill -9ed and another process ends up invoking "secshr_db_clnup" which in turn clears the @@ -87,14 +103,42 @@ void grab_lock(gd_region *reg) csa->nl->in_crit = process_id; CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */ crit_count = 0; - } - if (jnlpool.repl_inst_filehdr->file_corrupt && !jgbl.onlnrlbk) - { /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until the rollback command is - * re-run to bring the journal pool/file and instance file to a consistent state. + if (jnlpool.repl_inst_filehdr->file_corrupt && !jgbl.onlnrlbk) + { /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until the rollback + * command is re-run to bring the journal pool/file and instance file to a consistent state. + */ + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE"); + /* No need to do rel_lock before rts_error (mupip_exit_handler will do it for us) */ + rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), ERR_TEXT, 2, LEN_AND_STR(scndry_msg)); + } + /* If ASSERT_NO_ONLINE_ROLLBACK, then no concurrent online rollbacks can happen at this point. So, the jnlpool + * should be in in sync. There are two exceptions. If this is GT.CM GNP Server and the last client disconnected, the + * server invokes gtcmd_rundown which in-turn invokes gds_rundown thereby running down all active databases at this + * point but leaves the journal pool up and running. Now, if an online rollback is attempted, it increments the + * onln_rlbk_cycle in the journal pool, but csa->onln_rlbk_cycle is not synced yet. So, the grab_crit done in t_end + * will NOT detect a concurrent online rollback and it doesn't need to because the rollback happened AFTER the + * rundown. Assert that this is the only case we know of for the cycles to be out-of-sync. In PRO + * jnlpool_ctl->onln_rlbk_cycle is used only by the replication servers (which GT.CM is not) and so even if it + * continues with an out-of-sync csa->onln_rlbk_cycle, t_end logic does the right thing. The other exception is if + * GT.M initialized journal pool while opening database (belonging to a different instance) in gvcst_init (for + * anticipatory freeze) followed by an online rollback which increments the jnlpool_ctl->onln_rlbk_cycle but leaves + * the repl_csa->onln_rlbk_cycle out-of-sync. At this point, if a replicated database is open for the first time, + * we'll reach t_end to commit the update but will end up failing the below assert due to the out-of-sync + * onln_rlbk_cycle. So, assert accordingly. Note : even though the cycles are out-of-sync they are not an issue for + * GT.M because it always relies on the onln_rlbk_cycle from csa->nl and not from repl_csa. But, we don't remove the + * assert as it is valuable for replication servers (Source, Receiver and Update Process). */ - /* No need to do rel_lock before rts_error (mupip_exit_handler will do it for us) */ - rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), - ERR_TEXT, 2, LEN_AND_LIT("file_corrupt field in instance file header is set to TRUE")); + assert((ASSERT_NO_ONLINE_ROLLBACK != onln_rlbk_action) + || (csa->onln_rlbk_cycle == jnlpool.jnlpool_ctl->onln_rlbk_cycle) || IS_GTCM_GNP_SERVER_IMAGE + || (jnlpool_init_needed && ANTICIPATORY_FREEZE_AVAILABLE)); + if ((HANDLE_CONCUR_ONLINE_ROLLBACK == onln_rlbk_action) + && (csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle)) + { + assert(is_src_server); + SYNC_ONLN_RLBK_CYCLES; + gtmsource_onln_rlbk_clnup(); /* side-effect : sets gtmsource_state */ + rel_lock(reg); /* caller knows to disconnect and re-establish the connection */ + } } - return; + return TRUE; } diff --git a/sr_unix/gt_as.csh b/sr_unix/gt_as.csh index a4a3bc0..61b8940 100644 --- a/sr_unix/gt_as.csh +++ b/sr_unix/gt_as.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2009 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -34,23 +34,53 @@ endif alias gt_as_local "$comlist_gt_as" -set platform_name = `uname | sed 's/-//g' | sed 's,/,,' | tr '[A-Z]' '[a-z]'` +set os = `uname` +set platform_name = ${os:gs/-//:s,/,,:al} set mach_type = `uname -m` -if ( "ia64" == $mach_type && "linux" == $platform_name ) then - set lfile = `basename $1`:r - set file = $lfile:r +set asmlist=($*) +set cmdfile="$gtm_log/gt_as_$$__batch.csh" +set background="&" +if ($HOST:r:r:r =~ {snail,turtle,lespaul,pfloyd,strato}) set background="" - gt_cpp -E $1 > ${gtm_obj}/${file}_cpp.s - gt_as_local ${gtm_obj}/${file}_cpp.s -o ${gtm_obj}/${file}.o - \rm ${gtm_obj}/${file}_cpp.s -else if ( "os390" == $platform_name ) then - set file = `basename $1` - set file = $file:r +echo 'alias gt_as_local "$comlist_gt_as"' >> $cmdfile - gt_as_local $1 - if ( -e $gtm_obj/${file}.dbg ) chmod ugo+r $gtm_obj/${file}.dbg +foreach asm ($asmlist) + set outfile="$gtm_log/gt_as_$$_${asm:t:r}.out" + set redir=">& $outfile" + if ( "ia64" == $mach_type && "linux" == $platform_name ) then + set file=$asm:t:r:r + set sfile="${gtm_obj}/${file}_cpp.s" + set ofile="${gtm_obj}/${file}.o" + echo "(eval 'gt_cpp -E $asm' > $sfile ; eval 'gt_as_local $sfile -o $ofile' ; /bin/rm $sfile)" \ + "$redir $background" >> $cmdfile + else if ( "os390" == $platform_name ) then + set file=$asm:t:r + set dbgfile="${gtm_obj}/${file}.dbg" + echo "(eval 'gt_as_local $asm' ; if ( -e $dbgfile ) chmod ugo+r $dbgfile) $redir $background" >> $cmdfile + else + echo "eval 'gt_as_local $asm' $redir $background" >> $cmdfile + endif +end + +echo "wait" >> $cmdfile + +set cmdout="$gtm_log/gt_as_$$__batch.out" +source $cmdfile >& $cmdout + +set stat=$status + +foreach asm ($asmlist) + set outfile="$gtm_log/gt_as_$$_${asm:t:r}.out" + /bin/cat $outfile + /bin/rm $outfile +end + +if ($stat) then + /bin/cat $cmdout else - gt_as_local $1 + /bin/rm $cmdfile + /bin/rm $cmdout endif +exit 0 diff --git a/sr_unix/gt_cc.csh b/sr_unix/gt_cc.csh index eaf34cf..ac730bd 100644 --- a/sr_unix/gt_cc.csh +++ b/sr_unix/gt_cc.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2010 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -31,9 +31,39 @@ if ( $?comlist_gt_cc == "0" ) then exit 1 endif -alias gt_cc_local "$comlist_gt_cc" +alias gt_cc_local "comlist_gt_cc" -foreach i ($*) - echo $i - gt_cc_local $i +set cfilelist=($*) +set cmdfile="$gtm_log/gt_cc_$$__batch.csh" +set background="&" +if ($HOST:r:r:r =~ {snail,turtle}) set background="" + +echo 'alias gt_cc_local "$comlist_gt_cc"' >> $cmdfile + +foreach cfile ($cfilelist) + set outfile="$gtm_log/gt_cc_$$_${cfile:t:r}.out" + set redir=">& $outfile" + echo "(echo $cfile ; eval 'gt_cc_local $cfile') $redir $background" >> $cmdfile end + +echo "wait" >> $cmdfile + +set cmdout="$gtm_log/gt_cc_$$__batch.out" +source $cmdfile >& $cmdout + +set stat=$status + +foreach cfile ($cfilelist) + set outfile="$gtm_log/gt_cc_$$_${cfile:t:r}.out" + /bin/cat $outfile + /bin/rm $outfile +end + +if ($stat) then + /bin/cat $cmdout +else + /bin/rm $cmdfile + /bin/rm $cmdout +endif + +exit 0 diff --git a/sr_unix/gt_timer.h b/sr_unix/gt_timer.h index f932e9c..29bb4ee 100644 --- a/sr_unix/gt_timer.h +++ b/sr_unix/gt_timer.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,7 @@ #include typedef INTPTR_T TID; /* Timer ID type */ +typedef void (*timer_hndlr)(); /* Timer handler type */ /* Gtm timer package uses ABS_TIME structure to carry * the time information in operating system independent @@ -82,14 +83,23 @@ typedef struct st_timer_alloc struct st_timer_alloc *next; } st_timer_alloc; +#define MAX_TIMER_HNDLRS 10 /* Max # of safe timer handlers */ #define GT_WAKE +/* 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) + */ +#define SLACKTIME 10 + int4 abs_time_comp(ABS_TIME *atp1, ABS_TIME *atp2); void add_int_to_abs_time(ABS_TIME *atps, int4 ival, ABS_TIME *atpd); void cancel_timer(TID tid); void clear_timers(void); void hiber_start(uint4 hiber); void hiber_start_wait_any(uint4 hiber); +void gtm_start_timer(TID tid, int4 time_to_expir, void(* handler)(), int4 data_length, void *handler_data); void start_timer(TID tid, int4 time_to_expir, void(* handler)(), int4 data_length, void *handler_data); ABS_TIME sub_abs_time(ABS_TIME *atp1, ABS_TIME *atp2); void sys_get_curr_time(ABS_TIME *atp); @@ -98,17 +108,20 @@ void set_blocksig(void); void check_for_timer_pops(void); GT_TIMER *find_timer_intr_safe(TID tid, GT_TIMER **tprev); void check_for_deferred_timers(void); +void add_safe_timer_handler(int safetmr_cnt, ...); +void sys_canc_timer(void); STATICFNDCL void hiber_wake(TID tid, int4 hd_len, int4 **waitover_flag); STATICFNDCL void gt_timers_alloc(void); -STATICFNDCL void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata); +STATICFNDCL void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, + void *hdata, boolean_t safe_timer); STATICFNDCL void sys_settimer (TID tid, ABS_TIME *time_to_expir, void (*handler)()); STATICFNDCL void start_first_timer(ABS_TIME *curr_time); STATICFNDCL void timer_handler(int why); STATICFNDCL GT_TIMER *find_timer(TID tid, GT_TIMER **tprev); -STATICFNDCL void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata); +STATICFNDCL void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, + void *hdata, boolean_t safe_timer); STATICFNDCL void remove_timer(TID tid); -STATICFNDCL void sys_canc_timer(void); STATICFNDCL void uninit_all_timers(void); STATICFNDCL void cancel_all_timers(void); STATICFNDCL void init_timers(void); diff --git a/sr_unix/gt_timers.c b/sr_unix/gt_timers.c index dcb8f4e..123e9d7 100644 --- a/sr_unix/gt_timers.c +++ b/sr_unix/gt_timers.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,68 +43,66 @@ #include "mdef.h" #include +#include +#include +#ifdef GTM_PTHREAD +# include +#endif +#include #include "gtm_time.h" #include "gtm_string.h" -#include +#include "gtmimagename.h" #if (defined(__ia64) && defined(__linux__)) || defined(__MVS__) -#include "gtm_unistd.h" +# include "gtm_unistd.h" #endif /* __ia64 && __linux__ or __MVS__ */ - #include "gt_timer.h" #include "wake_alarm.h" -#include "heartbeat_timer.h" -#include "semwt2long_handler.h" -#include "secshr_client.h" - #ifdef DEBUG -#include "wbox_test_init.h" -#include "io.h" +# include "wbox_test_init.h" +# include "io.h" #endif - #if defined(mips) && !defined(_SYSTYPE_SVR4) -#include +# include #else -#include +# include #endif - #ifndef __MVS__ -#include +# include #endif #include "send_msg.h" #include "eintr_wrappers.h" #include "gtmio.h" #include "have_crit.h" - +#include "util.h" +#include "sleep.h" #if defined(__osf__) -#define HZ CLK_TCK +# define HZ CLK_TCK #elif defined(__MVS__) -#define HZ gtm_zos_HZ +# define HZ gtm_zos_HZ STATICDEF int gtm_zos_HZ = 100; /* see prealloc_gt_timers below */ #endif #ifdef ITIMER_REAL -#define BSD_TIMER +# define BSD_TIMER #else /* check def of time() including arg - see below; should be time_t * (from sys/types.h) and traditionally unsigned long */ -#ifndef __osf__ +# ifndef __osf__ int4 time(); -#endif -#endif - -/* 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) - */ -#ifndef SLACKTIME -# define SLACKTIME 10 +# endif #endif #define TIMER_BLOCK_SIZE 64 /* # of timer entries allocated initially as well as at every expansion */ #define GT_TIMER_EXPAND_TRIGGER 8 /* if the # of timer entries in the free queue goes below this, allocate more */ #define GT_TIMER_INIT_DATA_LEN 8 +#define MAX_TIMER_POP_TRACE_SZ 32 + +#define ADD_SAFE_HNDLR(HNDLR) \ +{ \ + assert((ARRAYSIZE(safe_handlers) - 1) > safe_handlers_cnt); \ + safe_handlers[safe_handlers_cnt++] = HNDLR; \ +} #ifdef BSD_TIMER STATICDEF struct itimerval sys_timer, old_sys_timer; @@ -122,30 +120,48 @@ 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 and timers popped, correspondingly */ -STATICDEF TID *deferred_tids; +STATICDEF int safe_timer_cnt, timer_pop_cnt; /* Number of safe timers in queue/popped */ +STATICDEF TID *deferred_tids; -STATICDEF void (*safe_handlers[])() = {hiber_wake, wake_alarm, semwt2long_handler, client_timer_handler, heartbeat_timer, NULL}; +STATICDEF timer_hndlr safe_handlers[MAX_TIMER_HNDLRS + 1]; /* +1 for NULL to terminate list, or can use safe_handlers_cnt */ +STATICDEF int safe_handlers_cnt; STATICDEF boolean_t stolen_timer = FALSE; /* only complain once, used in check_for_timer_pops() */ STATICDEF char *whenstolen[] = {"check_for_timer_pops", "check_for_timer_pops first time"}; /* for check_for_timer_pops */ -GBLREF boolean_t blocksig_initialized; /* set to TRUE when blockalrm and block_sigsent are initialized */ -GBLREF sigset_t blockalrm; -GBLREF sigset_t block_sigsent; -GBLREF boolean_t heartbeat_started; +#ifdef DEBUG +STATICDEF int trc_timerpop_idx; +STATICDEF GT_TIMER trc_timerpop_array[MAX_TIMER_POP_TRACE_SZ]; + +# define TRACE_TIMER_POP(TIMER_INFO) \ +{ \ + memcpy(&trc_timerpop_array[trc_timerpop_idx], TIMER_INFO, SIZEOF(GT_TIMER)); \ + trc_timerpop_idx = (trc_timerpop_idx + 1) % MAX_TIMER_POP_TRACE_SZ; \ +} +#endif + /* Flag signifying timer is active. Especially useful when the timer handlers get nested. This has not been moved to a * threaded framework because we do not know how timers will be used with threads. */ GBLDEF volatile boolean_t timer_active = FALSE; GBLDEF volatile int4 timer_stack_count = 0; GBLDEF volatile boolean_t timer_in_handler = FALSE; -GBLREF int4 outofband; -GBLREF int process_exiting; -GBLDEF void (*wcs_clean_dbsync_fptr)(); /* Reference to wcs_clean_dbsync() to be used * in gt_timers.c */ -GBLDEF void (*wcs_stale_fptr)(); /* Reference to wcs_stale() to be used in gt_timers.c */ +GBLDEF void (*wcs_clean_dbsync_fptr)(); /* Reference to wcs_clean_dbsync() to be used in gt_timers.c. */ +GBLDEF void (*wcs_stale_fptr)(); /* Reference to wcs_stale() to be used in gt_timers.c. */ GBLDEF boolean_t deferred_timers_check_needed; /* Indicator whether check_for_deferred_timers() should be called - upon leaving deferred zone */ + * upon leaving deferred zone. */ + +GBLREF boolean_t blocksig_initialized; /* Set to TRUE when blockalrm, block_ttinout, and block_sigsent are + * initialized. */ +GBLREF sigset_t blockalrm; +GBLREF sigset_t block_ttinout; +GBLREF sigset_t block_sigsent; +GBLREF boolean_t heartbeat_started; +GBLREF void (*heartbeat_timer_ptr)(void); /* Initialized only in gtm_startup(). */ +GBLREF int4 error_condition; +GBLREF int4 outofband; +GBLREF int process_exiting; + error_def(ERR_TIMERHANDLER); /* Called when a hiber_start timer pops. Set flag so a given timer will wake up (not go back to sleep). */ @@ -155,12 +171,13 @@ STATICFNDEF void hiber_wake(TID tid, int4 hd_len, int4 **waitover_flag) } /* Preallocate some memory for timers. */ -STATICFNDEF void gt_timers_alloc(void) +void gt_timers_alloc(void) { int4 gt_timer_cnt; GT_TIMER *timeblk, *timeblks; st_timer_alloc *new_alloc; + /* Allocate timer blocks putting each timer on the free queue */ assert(1 > timer_stack_count); timeblk_hdrlen = OFFSETOF(GT_TIMER, hd_data[0]); timeblk = timeblks = (GT_TIMER *)malloc((timeblk_hdrlen + GT_TIMER_INIT_DATA_LEN) * TIMER_BLOCK_SIZE); @@ -179,7 +196,22 @@ STATICFNDEF void gt_timers_alloc(void) num_timers_free += TIMER_BLOCK_SIZE; } -/* Do the initialization of block_sigsent and blockalrm, and set blocksig_initialized to TRUE, so +void add_safe_timer_handler(int safetmr_cnt, ...) +{ + int i; + va_list var; + timer_hndlr tmrhndlr; + + VAR_START(var, safetmr_cnt); + for (i = 1; i <= safetmr_cnt; i++) + { + tmrhndlr = va_arg(var, timer_hndlr); + ADD_SAFE_HNDLR(tmrhndlr); + } + va_end(var); +} + +/* Do the initialization of blockalrm, block_ttinout and block_sigsent, and set blocksig_initialized to TRUE, so * that we can later block signals when there is a need. This function should be called very early * in the main() routines of modules that wish to do their own interrupt handling. */ @@ -187,7 +219,9 @@ void set_blocksig(void) { sigemptyset(&blockalrm); sigaddset(&blockalrm, SIGALRM); - + sigemptyset(&block_ttinout); + sigaddset(&block_ttinout, SIGTTIN); + sigaddset(&block_ttinout, SIGTTOU); sigemptyset(&block_sigsent); sigaddset(&block_sigsent, SIGINT); sigaddset(&block_sigsent, SIGQUIT); @@ -223,17 +257,24 @@ void prealloc_gt_timers(void) * If more timer blocks are needed, we will allocate them as needed. */ gt_timers_alloc(); /* Allocate timers */ + /* 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. + * + * First step, fill in the safe timers contained within this module which are always available. + */ + ADD_SAFE_HNDLR(&hiber_wake); /* Resident in this module */ + ADD_SAFE_HNDLR(&hiber_start_wait_any); /* Resident in this module */ + ADD_SAFE_HNDLR(&wake_alarm); /* Standalone module containing on one global reference */ } /* Get current clock time. Fill-in the structure with the absolute time of system clock. * Arguments: atp - pointer to structure of absolute time */ -void sys_get_curr_time (ABS_TIME *atp) +void sys_get_curr_time(ABS_TIME *atp) { # ifdef BSD_TIMER struct timeval tv; struct timezone tz; - struct tm *dtp; /* getclock or clock_gettime perhaps to avoid tz just to ignore */ gettimeofday(&tv, &tz); @@ -246,30 +287,42 @@ void sys_get_curr_time (ABS_TIME *atp) } /* Start hibernating by starting a timer and waiting for it. */ -void hiber_start (uint4 hiber) +void hiber_start(uint4 hiber) { int4 waitover; int4 *waitover_addr; TID tid; sigset_t savemask; - if (1 <= timer_stack_count) /* timer services are unavailable from within a timer handler */ - GTMASSERT; + assertpro(1 > timer_stack_count); /* timer services are unavailable from within a timer handler */ sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */ - waitover = FALSE; /* when OUR timer pops, it will set this flag */ - waitover_addr = &waitover; - tid = (TID)waitover_addr; /* unique id of this timer */ - start_timer_int((TID)tid, hiber, hiber_wake, SIZEOF(waitover_addr), &waitover_addr); - /* we will loop here until OUR timer pops and sets OUR flag */ - do + /* sigsuspend() sets the signal mask to 'savemask' and waits for an ALARM signal. If the SIGALRM is a member of savemask, + * this process will never receive SIGALRM, and it will hang indefinitely. One such scenario would be if we interrupted a + * timer handler with kill -15, thus getting all timer setup reset by generic_signal_handler, and the gtm_exit_handler + * ended up invoking hiber_start (when starting gtmsecshr server, for instance). In such situations rely on something other + * than GT.M timers. + */ + if (sigismember(&savemask, SIGALRM)) { - sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */ - if (outofband) + NANOSLEEP(hiber); + } else + { + waitover = FALSE; /* when OUR timer pops, it will set this flag */ + waitover_addr = &waitover; + tid = (TID)waitover_addr; /* unique id of this timer */ + start_timer_int((TID)tid, hiber, hiber_wake, SIZEOF(waitover_addr), &waitover_addr, TRUE); + /* we will loop here until OUR timer pops and sets OUR flag */ + do { - cancel_timer(tid); - break; - } - } while(FALSE == waitover); + assert(!sigismember(&savemask, SIGALRM)); + sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */ + if (outofband) + { + cancel_timer(tid); + break; + } + } while(FALSE == waitover); + } sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */ } @@ -280,18 +333,46 @@ void hiber_start_wait_any(uint4 hiber) if (1000 > hiber) { - SHORT_SLEEP(hiber); /* note: some platforms call hiber_start */ + SHORT_SLEEP(hiber); /* note: some platforms call hiber_start */ return; } - if (1 <= timer_stack_count) /* timer services are unavailable from within a timer handler */ - GTMASSERT; + assertpro(1 > timer_stack_count); /* timer services are unavailable from within a timer handler */ sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal and set new timer */ - start_timer_int((TID)hiber_start_wait_any, hiber, NULL, 0, NULL); - sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */ + /* 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 + * 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. + */ + assert(!sigismember(&savemask, SIGALRM)); + start_timer_int((TID)hiber_start_wait_any, hiber, NULL, 0, NULL, TRUE); + sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */ cancel_timer((TID)hiber_start_wait_any); /* cancel timer block before reenabling */ 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. + * Arguments: tid - timer id + * time_to_expir - time to expiration in msecs + * handler - pointer to handler routine + * hdata_len - length of handler data next arg + * hdata - data to pass to handler (if any) + */ +void gtm_start_timer(TID tid, + int4 time_to_expir, + void (*handler)(), + int4 hdata_len, + void *hdata) +{ + if (0 >= time_to_expir) + time_to_expir = SLACKTIME; + start_timer(tid, time_to_expir, handler, hdata_len, hdata); +} + /* Start the timer. If timer chain is empty or this is the first timer to expire, actually start the system timer. * Arguments: tid - timer id * time_to_expir - time to expiration in msecs @@ -305,19 +386,41 @@ void start_timer(TID tid, int4 hdata_len, void *hdata) { - sigset_t savemask; + sigset_t savemask; + boolean_t safe_timer = FALSE, safe_to_add = FALSE; + int i; - if (0 >= time_to_expir) - GTMASSERT; + assertpro(0 < time_to_expir); /* Callers should verify non-zero time */ + if (NULL == handler) + { + safe_to_add = TRUE; + safe_timer = TRUE; + } else if ((wcs_clean_dbsync_fptr == handler) || (wcs_stale_fptr == handler)) + safe_to_add = TRUE; + else + { + for (i = 0; NULL != safe_handlers[i]; i++) + if (safe_handlers[i] == handler) + { + safe_to_add = TRUE; + safe_timer = TRUE; + break; + } + } + if (!safe_to_add && (process_exiting || (INTRPT_OK_TO_INTERRUPT != intrpt_ok_state))) + { + assert(WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)); + return; + } sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */ - start_timer_int(tid, time_to_expir, handler, hdata_len, hdata); + start_timer_int(tid, time_to_expir, handler, hdata_len, hdata, safe_timer); sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */ } /* Internal version of start_timer that does not protect itself, assuming this has already been done. * Otherwise does as explained above in start_timer. */ -STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata) +STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata, boolean_t safe_timer) { ABS_TIME at; @@ -340,7 +443,7 @@ 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(); - add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata); /* Link new timer into timer chain */ + add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata, safe_timer); /* Put new timer in the queue. */ if ((timeroot->tid == tid) || !timer_active) start_first_timer(&at); } @@ -381,7 +484,9 @@ void cancel_timer(TID tid) sys_get_curr_time(&at); if (tid == 0) { - assert(process_exiting); /* wcs_phase2_commit_wait relies on this flag being set BEFORE cancelling all timers */ + assert(process_exiting || IS_GTMSECSHR_IMAGE); /* wcs_phase2_commit_wait relies on this flag being set BEFORE + * cancelling all timers. But secshr doesn't have it. + */ cancel_all_timers(); uninit_all_timers(); timer_stack_count = 0; @@ -499,30 +604,42 @@ STATICFNDEF void start_first_timer(ABS_TIME *curr_time) */ STATICFNDEF void timer_handler(int why) { - int4 cmp; + int4 cmp, save_error_condition; GT_TIMER *tpop, *tpop_prev = NULL; ABS_TIME at; - sigset_t savemask; int save_errno, timer_defer_cnt, offset; TID *deferred_tid; boolean_t tid_found; - DEBUG_ONLY(ABS_TIME pseudo_at;) + char *save_util_outptr; + va_list save_last_va_list_ptr; + boolean_t util_copy_saved = FALSE; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + 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. + */ + FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIGALRM); + } # ifdef DEBUG - tpop = find_timer((TID)heartbeat_timer, &tpop); - assert(process_exiting || (((NULL != tpop) && heartbeat_started) || ((NULL == tpop) && !heartbeat_started))); + if (IS_GTM_IMAGE) + { + tpop = find_timer((TID)heartbeat_timer_ptr, &tpop); + assert(process_exiting || (((NULL != tpop) && heartbeat_started) || ((NULL == tpop) && !heartbeat_started))); + } # endif if (0 < timer_stack_count) return; timer_stack_count++; deferred_timers_check_needed = FALSE; save_errno = errno; + save_error_condition = error_condition; /* aka SIGNAL */ timer_active = FALSE; /* timer has popped; system timer not active anymore */ sys_get_curr_time(&at); tpop = (GT_TIMER *)timeroot; timer_defer_cnt = 0; /* reset the deferred timer count, since we are in timer_handler */ + SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); while (tpop) /* fire all handlers that expired */ { cmp = abs_time_comp(&at, (ABS_TIME *)&tpop->expir_time); @@ -531,7 +648,7 @@ STATICFNDEF void timer_handler(int why) /* A timer might pop while we are in the non-zero intrpt_ok_state zone, which could cause collisions. Instead, * we will defer timer events and drive them once the deferral is removed, unless the timer is safe. */ - if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (FALSE == process_exiting) || tpop->safe) + if (((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (FALSE == process_exiting)) || (tpop->safe)) { if (NULL != tpop_prev) tpop_prev->next = tpop->next; @@ -547,7 +664,7 @@ STATICFNDEF void timer_handler(int why) # ifdef DEBUG if (gtm_white_box_test_case_enabled && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number) - && ((void *)tpop->handler != (void*)&heartbeat_timer)) + && ((void *)tpop->handler != (void*)heartbeat_timer_ptr)) { DBGFPF((stderr, "TIMER_HANDLER: handled a timer\n")); timer_pop_cnt++; @@ -558,6 +675,7 @@ STATICFNDEF void timer_handler(int why) timer_in_handler = FALSE; if (!tpop->safe) /* if safe, avoid a system call */ sys_get_curr_time(&at); /* refresh current time if called a handler */ + DEBUG_ONLY(TRACE_TIMER_POP(tpop)); } tpop->next = (GT_TIMER *)timefree; /* put timer block on the free chain */ timefree = tpop; @@ -613,11 +731,17 @@ STATICFNDEF void timer_handler(int why) break; } } + RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); if (((FALSE == process_exiting) && (INTRPT_OK_TO_INTERRUPT == intrpt_ok_state)) || (0 < safe_timer_cnt)) start_first_timer(&at); else if ((NULL != timeroot) || (0 < timer_defer_cnt)) deferred_timers_check_needed = TRUE; - errno = save_errno; /* restore mainline errno */ + /* Restore mainline error_condition global variable. This way any gtm_putmsg or rts_errors that occurred inside + * interrupt code do not affect the error_condition global variable that mainline code was relying on. + * For example, not doing this restore caused the update process (in updproc_ch) to issue a GTMASSERT (GTM-7526). + */ + error_condition = save_error_condition; + errno = save_errno; /* restore mainline errno by similar reasoning as mainline error_condition */ timer_stack_count--; } @@ -625,14 +749,14 @@ STATICFNDEF void timer_handler(int why) * Arguments: tid - timer id * tprev - address of pointer to previous node * Return: pointer to timer in the chain, or 0 if timer is not found - * NOTE: tprev is set to the link previous to the tid link + * Note: tprev is set to the link previous to the tid link */ STATICFNDEF GT_TIMER *find_timer(TID tid, GT_TIMER **tprev) { GT_TIMER *tc; - tc = (GT_TIMER*)timeroot; - *tprev = 0; + tc = (GT_TIMER *)timeroot; + *tprev = NULL; while (tc) { if (tc->tid == tid) @@ -650,13 +774,14 @@ STATICFNDEF GT_TIMER *find_timer(TID tid, GT_TIMER **tprev) * handler - pointer to handler routine * hdata_len - length of data to follow * hdata - data to pass to timer rtn if any + * safe_timer - timer's handler is in safe_handlers array */ -STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata) +STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, + void *hdata, boolean_t safe_timer) { GT_TIMER *tp, *tpp, *ntp, *lastntp; int4 cmp, i; st_timer_alloc *new_alloc; - boolean_t safe_to_add = FALSE; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -697,28 +822,13 @@ STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*ha } ntp->tid = tid; ntp->handler = handler; - ntp->safe = FALSE; - if (NULL == handler) + if (safe_timer) { ntp->safe = TRUE; safe_timer_cnt++; assert(0 < safe_timer_cnt); } else - { - for (i = 0; NULL != safe_handlers[i]; i++) - if (safe_handlers[i] == handler) - { - ntp->safe = TRUE; /* known to just set flags, etc. */ - safe_timer_cnt++; - break; - } - } - if (ntp->safe || (wcs_clean_dbsync_fptr == handler) || (wcs_stale_fptr == handler)) - safe_to_add = TRUE; - if ((INTRPT_OK_TO_INTERRUPT != intrpt_ok_state) && !safe_to_add) - GTMASSERT; - if (process_exiting && !safe_to_add) - GTMASSERT; + ntp->safe = FALSE; ntp->hd_len = hdata_len; if (0 < hdata_len) memcpy(ntp->hd_data, hdata, hdata_len); @@ -750,7 +860,7 @@ STATICFNDEF void remove_timer(TID tid) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - if (tp = find_timer(tid, &tprev)) + if (tp = find_timer(tid, &tprev)) /* Warning: assignment */ { if (tprev) tprev->next = tp->next; @@ -767,8 +877,11 @@ STATICFNDEF void remove_timer(TID tid) } } -/* System call to cancel timer. */ -STATICFNDEF void sys_canc_timer() +/* System call to cancel timer. Not static because can be called from generic_signal_handler() to stop timers + * from popping yet preserve the blocks so gtmpcat can pick them out of the core. Note that once we exit, + * timers are cleared at the top of the exit handler. + */ +void sys_canc_timer() { # ifdef BSD_TIMER struct itimerval zero; @@ -782,7 +895,7 @@ STATICFNDEF void sys_canc_timer() } /* Cancel all timers. - * NOTE: The timer signal must be blocked prior to entry + * Note: The timer signal must be blocked prior to entry */ STATICFNDEF void cancel_all_timers(void) { @@ -826,9 +939,9 @@ STATICFNDEF void init_timers() (SIG_IGN != prev_alrm_handler.sa_handler) && /* as set by sig_init */ (SIG_DFL != prev_alrm_handler.sa_handler)) /* utils, compile */ { - send_msg(VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler, LEN_AND_LIT("init_timers")); - rts_error(VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler, LEN_AND_LIT("init_timers")); assert(FALSE); } @@ -891,9 +1004,9 @@ void check_for_timer_pops() } if (stolenwhen) { - send_msg(VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler, LEN_AND_STR(whenstolen[stolenwhen - 1])); - rts_error(VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler, LEN_AND_STR(whenstolen[stolenwhen - 1])); assert(FALSE); /* does not return here */ } diff --git a/sr_unix/gtm.gtc b/sr_unix/gtm.gtc index c66604a..ca4808f 100644 --- a/sr_unix/gtm.gtc +++ b/sr_unix/gtm.gtc @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2010 Fidelity Information Services, Inc # +# Copyright 2010,2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -19,6 +19,10 @@ else find . -name \*.mjl_\* -mtime +$gtm_retention -exec rm -vf {} \; ) if [ 0 = $# ] ; then $gtm_dist/mumps -direct + elif [ "-help" = "$1" -o "-h" = "$1" -o "-?" = "$1" ] ; then + echo "gtm -dir[ect] to enter direct mode (halt returns to shell)" + echo "gtm -run to start executing at an entryref" + echo "gtm -help / gtm -h / gtm -? to display this text" else $gtm_dist/mumps $* fi diff --git a/sr_unix/gtm_bintim.c b/sr_unix/gtm_bintim.c index 6882c40..f360afc 100644 --- a/sr_unix/gtm_bintim.c +++ b/sr_unix/gtm_bintim.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,6 +50,7 @@ #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" /* jnl_proc_time needs this. jnl.h needs some of the above */ +#include "have_crit.h" #include "gtm_bintim.h" #define monthalphas "abcdefgjlmnoprstuvyABCDEFGJLMNOPRSTUVY" @@ -58,110 +59,97 @@ static int getmon(char *month); int gtm_bintim(char *toscan, jnl_proc_time *timep) { - time_t now, mktime_ret; - struct tm time_tm, *now_tm; - int num, sec, min, hour, day, year; - int len = STRLEN(toscan), matched = 0; - char month[256]; - - num = SSCANF(toscan, "%d %d", &day, &hour); - if (2 == num) - { /* delta time format. note: this is the same code as in VMS gtm_bintim.c */ - num = SSCANF(toscan, "%d %d:%d:%d%n", &day, &hour, &min, &sec, &matched); - if (matched < len) - { - num = SSCANF(toscan, "%d %d:%d:%d:%*d%n", &day, &hour, &min, &sec, - &matched); - if (matched < len) - { - sec = 0; - num = SSCANF(toscan, "%d %d:%d%n", &day, &hour, &min, &matched); - if (matched < len) - return -1; - } - } - *timep = - (day*86400 + hour*3600 + min*60 + sec); - return 0; - } else /* absolute time format */ - { - *month = '\0'; - now = time((time_t *) 0); - now_tm = localtime(&now); - num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d%n", &day, month, &year, - &hour, &min, &sec, &matched); - - if (matched < len) - { - num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d:%*d%n", &day, month, - &year, &hour, &min, &sec, &matched); - - if (matched < len) - { - sec = 0; - num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d%n", &day, month, &year, - &hour, &min, &matched); + time_t now, mktime_ret; + struct tm time_tm, *now_tm; + int num, sec, min, hour, day, year; + int len = STRLEN(toscan), matched = 0; + char month[256]; + num = SSCANF(toscan, "%d %d", &day, &hour); + if (2 == num) + { /* delta time format. note: this is the same code as in VMS gtm_bintim.c */ + num = SSCANF(toscan, "%d %d:%d:%d%n", &day, &hour, &min, &sec, &matched); if (matched < len) { - hour = min = sec = 0; - num = SSCANF(toscan, "%d-%[" monthalphas "]-%d%n", &day, month, &year, - &matched); - if (matched < len) - { - day = now_tm->tm_mday; - year = now_tm->tm_year + 1900; - num = SSCANF(toscan, "-- %d:%d:%d%n", &hour, &min, &sec, - &matched); + num = SSCANF(toscan, "%d %d:%d:%d:%*d%n", &day, &hour, &min, &sec, &matched); if (matched < len) { - num = SSCANF(toscan, "-- %d:%d:%d:%*d%n", &hour, &min, - &sec, &matched); - if (matched < len) - { sec = 0; - num = SSCANF(toscan, "-- %d:%d%n", &hour, &min, - &matched); + num = SSCANF(toscan, "%d %d:%d%n", &day, &hour, &min, &matched); if (matched < len) - return -1; - } + return -1; } - } } - } + *timep = -((day * 86400) + (hour * 3600) + (min * 60) + sec); + return 0; + } else /* absolute time format */ + { + *month = '\0'; + now = time((time_t *) 0); + GTM_LOCALTIME(now_tm, &now); + num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d%n", &day, month, &year, &hour, &min, &sec, &matched); + if (matched < len) + { + num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d:%*d%n", + &day, month, &year, &hour, &min, &sec, &matched); + if (matched < len) + { + sec = 0; + num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d%n", &day, month, &year, &hour, &min, &matched); + if (matched < len) + { + hour = min = sec = 0; + num = SSCANF(toscan, "%d-%[" monthalphas "]-%d%n", &day, month, &year, &matched); + if (matched < len) + { + day = now_tm->tm_mday; + year = now_tm->tm_year + 1900; + num = SSCANF(toscan, "-- %d:%d:%d%n", &hour, &min, &sec, &matched); + if (matched < len) + { + num = SSCANF(toscan, "-- %d:%d:%d:%*d%n", &hour, &min, &sec, &matched); + if (matched < len) + { + sec = 0; + num = SSCANF(toscan, "-- %d:%d%n", &hour, &min, &matched); + if (matched < len) + return -1; + } + } + } + } + } + } + time_tm.tm_sec = sec; + time_tm.tm_min = min; + time_tm.tm_hour = hour; + if (*month) + time_tm.tm_mon = getmon(month); + else + time_tm.tm_mon = now_tm->tm_mon; + time_tm.tm_mday = day; + time_tm.tm_year = year-1900; + time_tm.tm_isdst = -1; + GTM_MKTIME(mktime_ret, &time_tm); + if ((time_t)-1 == mktime_ret) + return -1; + *timep = (jnl_proc_time)mktime_ret; + return 0; } - time_tm.tm_sec = sec; - time_tm.tm_min = min; - time_tm.tm_hour = hour; - if (*month) - time_tm.tm_mon = getmon(month); - else - time_tm.tm_mon = now_tm->tm_mon; - time_tm.tm_mday = day; - time_tm.tm_year = year-1900; - time_tm.tm_isdst = -1; - - mktime_ret = mktime(&time_tm); - if ((time_t)-1 == mktime_ret) - return -1; - *timep = (jnl_proc_time)mktime_ret; - return 0; - } } static int getmon(char *month) { - char *p; - int i; - static char *m[] = { "jan", "feb", "mar", "apr", "may", "jun", - "jul", "aug", "sep", "oct", "nov", "dec" }; + char *p; + int i; + static char *m[] = { "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" }; - for(p=month; *p; p++) - if (ISUPPER(*p)) - *p = TOLOWER(*p); - - for(i=0; i<12; i++) - if (!strcmp(month,m[i])) - return i; - - return -1; + for (p = month; *p; p++) + if (ISUPPER_ASCII(*p)) + *p = TOLOWER(*p); + for (i = 0; i < 12; i++) + if (!strcmp(month,m[i])) + return i; + return -1; } diff --git a/sr_unix/gtm_c_stack_trace_semop.c b/sr_unix/gtm_c_stack_trace_semop.c index 562f1ec..1843b12 100644 --- a/sr_unix/gtm_c_stack_trace_semop.c +++ b/sr_unix/gtm_c_stack_trace_semop.c @@ -1,6 +1,6 @@ /**************************************************************** * * -* Copyright 2011 Fidelity Information Services, Inc * +* Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,6 +15,11 @@ #include "gtm_c_stack_trace.h" #include "gtm_c_stack_trace_semop.h" #include "semwt2long_handler.h" +#include "wbox_test_init.h" +#include "gt_timer.h" +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" GBLREF uint4 process_id; #ifdef DEBUG @@ -68,8 +73,8 @@ int try_semop_get_c_stack(int semid, struct sembuf sops[], int nsops) { GET_C_STACK_FROM_SCRIPT("SEMOP_INFO", process_id, semop_pid, stuckcnt); /* Got stack trace signal the first process to continue */ - GTM_WHITE_BOX_TEST(WBTEST_SEMTOOLONG_STACK_TRACE, \ - cnl->wbox_test_seq_num, 3); + GTM_WHITE_BOX_TEST(WBTEST_SEMTOOLONG_STACK_TRACE, + cnl->wbox_test_seq_num, 3); } else if (-1 == semop_pid) { rc = -1; diff --git a/sr_unix/gtm_compare_dir.csh b/sr_unix/gtm_compare_dir.csh index 10e6f9a..7fec051 100644 --- a/sr_unix/gtm_compare_dir.csh +++ b/sr_unix/gtm_compare_dir.csh @@ -1,7 +1,7 @@ #!/usr/local/bin/tcsh ################################################################# # # -# Copyright 2011 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -22,13 +22,18 @@ exit GDE_EOF mupip create >& /dev/null cp $gtm_tools/dircompare.m.txt ./dircompare.m -mumps -r dircompare $2/build.dir $3 $4 $5 > bout -mumps -r dircompare $2/install.dir NOP NOP $5 > iout +echo "setenv gtm_dist $gtm_dist" >&! repeat +echo "setenv gtmroutines '$gtmroutines'" >>& repeat +echo "setenv gtmgbldir mumps.gld" >>& repeat +echo "$gtm_dist/mumps -r dircompare $2/build.dir $3 $4 $5" >>& repeat +echo "$gtm_dist/mumps -r dircompare $2/install.dir NOP NOP $5" >>& repeat +$gtm_dist/mumps -r dircompare $2/build.dir $3 $4 $5 > dev.out +$gtm_dist/mumps -r dircompare $2/install.dir NOP NOP $5 > install.out if ($6 == "os390") then # we expect 4 diff lines at the beginning on zos so account for them - diff bout iout | tail -n +5 > diff.out + diff dev.out install.out | tail -n +5 > diff.out else - diff bout iout > diff.out + diff dev.out install.out > diff.out endif set numdiff=`wc -l < diff.out` echo diff --git a/sr_unix/gtm_compile.c b/sr_unix/gtm_compile.c index d9b539d..ebf3230 100644 --- a/sr_unix/gtm_compile.c +++ b/sr_unix/gtm_compile.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,8 +39,11 @@ #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" +#include "gt_timers_add_safe_hndlrs.h" +#include "zco_init.h" GBLREF command_qualifier glb_cmd_qlf, cmd_qlf; +GBLREF IN_PARMS *cli_lex_in_ptr; GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase,*stacktop,*stackwarn,*msp; GBLREF mv_stent *mv_chain; @@ -50,12 +53,14 @@ GBLREF spdesc rts_stringpool, stringpool; int gtm_compile (void) { - int status; - unsigned short len; - char source_file_string[MAX_FBUFF + 1]; - char obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1], ceprep_file[MAX_FBUFF + 1]; - unsigned char *mstack_ptr; - void gtm_ret_code(); + int status; + unsigned short len; + char source_file_string[MAX_FBUFF + 1]; + char obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1], ceprep_file[MAX_FBUFF + 1]; + unsigned char *mstack_ptr; + void gtm_ret_code(); + command_qualifier save_qlf; + mstr orig_cmdstr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -65,7 +70,6 @@ int gtm_compile (void) io_init(TRUE); getjobnum(); getzdir(); - prealloc_gt_timers(); run_time = FALSE; TREF(compile_time) = TRUE; mstack_ptr = (unsigned char *)malloc(USER_STACK_SIZE); @@ -90,15 +94,25 @@ int gtm_compile (void) LVVAL_INIT((TREF(zsearch_dir1)), curr_symval); LVVAL_INIT((TREF(zsearch_dir2)), curr_symval); /* command qualifier processing stuff */ - cmd_qlf.object_file.str.addr = obj_file; - cmd_qlf.object_file.str.len = MAX_FBUFF; - cmd_qlf.list_file.str.addr = list_file; - cmd_qlf.list_file.str.len = MAX_FBUFF; - cmd_qlf.ceprep_file.str.addr = ceprep_file; - cmd_qlf.ceprep_file.str.len = MAX_FBUFF; - get_cmd_qlf(&cmd_qlf); + zco_init(); + assert(cli_lex_in_ptr); + save_qlf = glb_cmd_qlf; + /* Save the original MUMPS command line qualifers. These are processed after, and take precedence over, $ZCOMPILE. */ + orig_cmdstr.len = strlen(cli_lex_in_ptr->in_str) - strlen("MUMPS "); + orig_cmdstr.addr = (char *)malloc(orig_cmdstr.len); + memcpy(orig_cmdstr.addr, cli_lex_in_ptr->in_str + strlen("MUMPS "), orig_cmdstr.len); + INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, MAX_FBUFF); + zl_cmd_qlf(&(TREF(dollar_zcompile)), &cmd_qlf); /* Initialize $ZCOMPILE as default command qualifiers */ + glb_cmd_qlf = cmd_qlf; + INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, MAX_FBUFF); + zl_cmd_qlf(&orig_cmdstr, &cmd_qlf); /* Next, process MUMPS command line qualifers */ + free(orig_cmdstr.addr); + glb_cmd_qlf = save_qlf; + /* end command qualifier processing stuff */ initialize_pattern_table(); ce_init(); /* initialize compiler escape processing */ + prealloc_gt_timers(); + gt_timers_add_safe_hndlrs(); /* Not sure why compiler needs timers but .. */ TREF(dollar_zcstatus) = SS_NORMAL; len = MAX_FBUFF; for (status = cli_get_str("INFILE", source_file_string, &len); @@ -109,6 +123,7 @@ int gtm_compile (void) len = MAX_FBUFF; } print_exit_stats(); + SET_PROCESS_EXITING_TRUE; /* needed by remove_rms($principal) to avoid closing that */ io_rundown(NORMAL_RUNDOWN); - return (SS_NORMAL == TREF(dollar_zcstatus)) ? SS_NORMAL : -1; + return (SS_NORMAL == TREF(dollar_zcstatus)) ? SS_NORMAL : 1; } diff --git a/sr_unix/gtm_conv.c b/sr_unix/gtm_conv.c index 81d204b..b51b072 100644 --- a/sr_unix/gtm_conv.c +++ b/sr_unix/gtm_conv.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,71 +17,15 @@ #include "gtm_utf8.h" #include "gtm_conv.h" -LITDEF mstr chset_names[CHSET_MAX_IDX_ALL] = -{ /* Supported character set (CHSET) codes for the 3-argument form of $ZCONVERT. - * NOTE: Update the *_CHSET_LEN macros below if new CHSETs are added. - */ - {1, 1, "M"}, /* "M" should be the first CHSET (0th index of "chset_names" array). verify_chset() callers rely on this. - * $ZCONVERT doesn't support M, but I/O does */ - {5, 5, "UTF-8"}, - {6, 6, "UTF-16"}, - {8, 8, "UTF-16LE"}, - {8, 8, "UTF-16BE"}, - {5, 5, "ASCII"}, - {6, 6, "EBCDIC"}, - {6, 6, "BINARY"} -}; -#define MIN_CHSET_LEN 1 /* minimum length of CHSET names */ -#define MAX_CHSET_LEN 8 /* maximum length of CHSET names */ - -/* This array holds the ICU converter handles corresponding to the respective - * CHSET name in the table chset_names[] - */ -GBLDEF UConverter *chset_desc[CHSET_MAX_IDX]; -GBLDEF casemap_t casemaps[MAX_CASE_IDX] = -{ /* Supported case mappings and their disposal conversion routines for both $ZCHSET modes. - * Note: since UTF-8 disposal functions for "U" and "L" are ICU "function pointers" rather - * rather than their direct addresses, they are initialized in gtm_utf8_init() instead - */ - {"U", &lower_to_upper, NULL }, - {"L", &upper_to_lower, NULL }, - {"T", NULL, >m_strToTitle} -}; - -GBLREF spdesc stringpool; +GBLREF spdesc stringpool; +GBLREF UConverter *chset_desc[CHSET_MAX_IDX]; +GBLREF casemap_t casemaps[MAX_CASE_IDX]; +LITREF mstr chset_names[CHSET_MAX_IDX_ALL]; LITREF unsigned char lower_to_upper_table[]; -error_def(ERR_ICUERROR); error_def(ERR_MAXSTRLEN); -/* Routine to verify given parameter against supported CHSETs. - * Valid arguments (case-insensitive): - * "M", "UTF-8", "UTF-16", "UTF-16LE" and "UTF-16BE" - * Returns - * -1 (if invalid argument) or - * 0 (if "M") or - * non-zero index to an entry of chset_names[] (if valid) - */ -int verify_chset(const mstr *parm) -{ - const mstr *vptr, *vptr_top; - char mode[MAX_CHSET_LEN]; - - if ((MIN_CHSET_LEN > parm->len) || (MAX_CHSET_LEN < parm->len)) - return -1; /* Parameter is smaller or larger than any possible CHSET */ - /* Make a translated copy of the parm */ - lower_to_upper((unsigned char *)mode, (unsigned char *)parm->addr, parm->len); - /* See if any of our possibilities match */ - for (vptr = chset_names, vptr_top = vptr + CHSET_MAX_IDX_ALL; vptr < vptr_top; ++vptr) - { - if (parm->len == vptr->len && - 0 == memcmp(mode, vptr->addr, vptr->len)) - return (int)(vptr - chset_names); /* return the index */ - } - return -1; -} - /* Routine to verify given parameter against supported case conversion codes. * Valid arguments (case-insensitive): * "U", "L" and "T" @@ -114,50 +58,6 @@ int32_t gtm_strToTitle(UChar *dst, int32_t dstlen, const UChar *src, int32_t src return u_strToTitle(dst, dstlen, src, srclen, NULL, locale, status); } -void callback_stop(const void* context, UConverterToUnicodeArgs *args, const char *codeUnits, - int32_t length, UConverterCallbackReason reason, UErrorCode *pErrorCode) -{ - /* EMPTY BODY: - * By not resetting the pErrorCode, this routine returns to ICU routine directing - * it to stop and return immediately - */ -} - -UConverter* get_chset_desc(const mstr* chset) -{ - int chset_indx; - UErrorCode status; - - if ((0 >= (chset_indx = verify_chset(chset))) || (CHSET_MAX_IDX <= chset_indx)) - return NULL; - if (NULL == chset_desc[chset_indx]) - { - status = U_ZERO_ERROR; - chset_desc[chset_indx] = ucnv_open(chset_names[chset_indx].addr, &status); - if (U_FAILURE(status)) - rts_error(VARLSTCNT(3) ERR_ICUERROR, 1, status); /* strange and unexpected ICU unhappiness */ - /* Initialize the callback for illegal/invalid characters, so that conversion - * stops at the first illegal character rather than continuing with replacement */ - status = U_ZERO_ERROR; - ucnv_setToUCallBack(chset_desc[chset_indx], &callback_stop, NULL, NULL, NULL, &status); - if (U_FAILURE(status)) - rts_error(VARLSTCNT(3) ERR_ICUERROR, 1, status); /* strange and unexpected ICU unhappiness */ - } - return chset_desc[chset_indx]; -} - -/* Startup initializations of conversion data */ -void gtm_conv_init(void) -{ - assert(gtm_utf8_mode); - /* Implicitly created CHSET descriptor for UTF-8 */ - get_chset_desc(&chset_names[CHSET_UTF8]); - assert(NULL != chset_desc[CHSET_UTF8]); - /* initialize the case conversion disposal functions */ - casemaps[0].u = u_strToUpper; - casemaps[1].u = u_strToLower; -} - int gtm_conv(UConverter* from, UConverter* to, mstr *src, char* dstbuff, int* bufflen) { char *dstptr, *dstbase, *srcptr; diff --git a/sr_unix/gtm_conv.h b/sr_unix/gtm_conv.h index 155585f..4cd2060 100644 --- a/sr_unix/gtm_conv.h +++ b/sr_unix/gtm_conv.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,9 @@ #define MAX_CASE_IDX 3 /* maximum number of case conversions supported */ #define MAX_ZCONVBUFF (8 * 1024) /* temporary buffer size used in case conversion */ +#define MIN_CHSET_LEN 1 /* minimum length of CHSET names */ +#define MAX_CHSET_LEN 8 /* maximum length of CHSET names */ + int verify_chset(const mstr *parm); int verify_case(const mstr *parm); UConverter* get_chset_desc(const mstr *chset); @@ -23,11 +26,11 @@ int gtm_conv(UConverter* from, UConverter* to, mstr* src, char* dstbuff, int* bu typedef void (*m_casemap_t)(uchar_ptr_t, uchar_ptr_t, int4); typedef int32_t (*u_casemap_t)(UChar *dest, int32_t destCapacity, const UChar *src, - int32_t srcLength, const char *locale, UErrorCode *pErrorCode); + int32_t srcLength, const char *locale, UErrorCode *pErrorCode); /* An interlude routine for title case to have the same signature as u_strToUpper/u_strToLower */ int32_t gtm_strToTitle(UChar *dest, int32_t destCapacity, const UChar *src, int32_t srcLength, - const char *locale, UErrorCode *pErrorCode); + const char *locale, UErrorCode *pErrorCode); /* descriptor for case mapping */ typedef struct @@ -39,6 +42,6 @@ typedef struct /* Call back function for ICU to stop at illegal/invalid characters and return with error */ void callback_stop(const void* context, UConverterToUnicodeArgs *args, const char *codeUnits, - int32_t length, UConverterCallbackReason reason, UErrorCode *pErrorCode); + int32_t length, UConverterCallbackReason reason, UErrorCode *pErrorCode); #endif /* GTM_CONV_H */ diff --git a/sr_unix/gtm_dump_core.c b/sr_unix/gtm_dump_core.c index 0a3af39..10905fe 100644 --- a/sr_unix/gtm_dump_core.c +++ b/sr_unix/gtm_dump_core.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -54,7 +54,7 @@ void gtm_dump_core(void) SPRINTF(&newname[0], "core%d", suffix); /* Make new file name */ status = Stat(&newname[0], &fs1); /* This file exist ? */ if (0 != status) - status = rename("core", &newname[0]); /* No, attempt the rename */ + status = RENAME("core", &newname[0]); /* No, attempt the rename */ else status = -1; /* Yes, reset status for another iteration */ } @@ -66,5 +66,5 @@ void gtm_dump_core(void) sigprocmask(SIG_UNBLOCK, &unblock_sigquit, NULL); kill(getpid(), SIGQUIT); sleep(60); /* In case of async kill */ - _exit(1); + _exit(EXIT_FAILURE); } diff --git a/sr_unix/gtm_env_init_sp.c b/sr_unix/gtm_env_init_sp.c index 367c356..145d5e8 100644 --- a/sr_unix/gtm_env_init_sp.c +++ b/sr_unix/gtm_env_init_sp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2004, 2011 Fidelity Information Services, Inc * + * Copyright 2004, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,14 +46,32 @@ #include "jnl.h" #include "replgbl.h" #include "gtm_semutils.h" +#ifdef __linux__ +#include "hugetlbfs_overrides.h" +#endif #define DEFAULT_NON_BLOCKED_WRITE_RETRIES 10 /* default number of retries */ #ifdef __MVS__ # define PUTENV_BPXK_MDUMP_PREFIX "_BPXK_MDUMP=" #endif - +#ifdef DEBUG +/* Note the var below is NOT located in gtm_logicals because it is DEBUG-only which would screw-up + * regresion test v53003/D9I10002703. + */ +# 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" +#endif #define DEFAULT_MUPIP_TRIGGER_ETRAP "IF $ZJOBEXAM()" +/* Only for this function, define MAX_TRANS_NAME_LEN to be equal to GTM_PATH_MAX as some of the environment variables can indicate + * path to files which is limited by GTM_PATH_MAX. + */ +#ifdef MAX_TRANS_NAME_LEN +#undef MAX_TRANS_NAME_LEN +#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; @@ -63,6 +81,8 @@ GBLREF boolean_t gtm_quiet_halt; GBLREF int gtm_non_blocked_write_retries; /* number for retries for non_blocked write to pipe */ GBLREF char *gtm_core_file; GBLREF char *gtm_core_putenv; +GBLREF mval dollar_etrap; +GBLREF mval dollar_ztrap; ZOS_ONLY(GBLREF char *gtm_utf8_locale_object;) ZOS_ONLY(GBLREF boolean_t gtm_tag_utf8_as_ascii;) GTMTRIG_ONLY(GBLREF mval gtm_trigger_etrap;) @@ -75,17 +95,19 @@ LITDEF mval default_mupip_trigger_etrap = DEFINE_MVAL_LITERAL(MV_STR, 0 , 0 , (S static readonly nametabent editing_params[] = { {7, "EDITING"}, + {7, "EMPTERM"}, {6, "INSERT"}, {9, "NOEDITING"}, + {9, "NOEMPTERM"}, {8, "NOINSERT"} }; - static readonly unsigned char editing_index[27] = { - 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, - 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4 + 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6 }; +static readonly unsigned char init_break[1] = {'B'}; void gtm_env_init_sp(void) { /* Unix only environment initializations */ @@ -98,6 +120,9 @@ void gtm_env_init_sp(void) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; +# ifdef HUGETLB_SUPPORTED + libhugetlbfs_init(); +# endif # ifdef __MVS__ /* For now OS/390 only. Eventually, this will be added to all UNIX platforms along with the * capability to specify the desired directory to put a core file in. @@ -174,13 +199,19 @@ void gtm_env_init_sp(void) case 0: /* EDITING */ gtm_principal_editing_defaults |= TT_EDITING; break; - case 1: /* INSERT */ + case 1: /* EMPTERM */ + gtm_principal_editing_defaults |= TT_EMPTERM; + break; + case 2: /* INSERT */ gtm_principal_editing_defaults &= ~TT_NOINSERT; break; - case 2: /* NOEDITING */ + case 3: /* NOEDITING */ gtm_principal_editing_defaults &= ~TT_EDITING; break; - case 3: /* NOINSERT */ + case 4: /* NOEMPTERM */ + gtm_principal_editing_defaults &= ~TT_EMPTERM; + break; + case 5: /* NOINSERT */ gtm_principal_editing_defaults |= TT_NOINSERT; break; } @@ -261,4 +292,62 @@ void gtm_env_init_sp(void) TREF(dbinit_max_hrtbt_delta) = (ROUND_UP2(hrtbt_cntr_delta, 8)) / 8; else TREF(dbinit_max_hrtbt_delta) = hrtbt_cntr_delta; + /* Initialize variable that controls the location of GT.M custom errors file (used for anticipatory freeze) */ + val.addr = GTM_CUSTOM_ERRORS; + val.len = SIZEOF(GTM_CUSTOM_ERRORS) - 1; + if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) + { + assert(GTM_PATH_MAX > trans.len); + (TREF(gtm_custom_errors)).addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */ + (TREF(gtm_custom_errors)).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_custom_errors)).addr, buf, trans.len); + ((TREF(gtm_custom_errors)).addr)[trans.len] = '\0'; + } + } + /* Initialize which ever error trap we are using (ignored in the utilities except the update process) */ + val.addr = GTM_ETRAP; + val.len = SIZEOF(GTM_ETRAP) - 1; + if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) + { + if (MAX_SRCLINE >= trans.len) + { /* Only set $ETRAP if the length is usable (may be NULL) */ + dollar_etrap.str.addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */ + memcpy(dollar_etrap.str.addr, trans.addr, trans.len); + *(dollar_etrap.str.addr + trans.len + 1) = '\0'; + dollar_etrap.str.len = trans.len; + dollar_etrap.mvtype = MV_STR; + } + } else if (0 == dollar_etrap.mvtype) + { /* If didn't setup $ETRAP, set default $ZTRAP instead */ + dollar_ztrap.mvtype = MV_STR; + dollar_ztrap.str.len = SIZEOF(init_break); + dollar_ztrap.str.addr = (char *)init_break; + } +# 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. + */ + val.addr = GTM_USESECSHR; + val.len = SIZEOF(GTM_USESECSHR) - 1; + TREF(gtm_usesecshr) = logical_truth_value(&val, FALSE, &is_defined); + if (!is_defined) + TREF(gtm_usesecshr) = FALSE; + /* DEBUG-only option to enable/disable anticipatory freeze fake ENOSPC testing */ + val.addr = GTM_TEST_FAKE_ENOSPC; + val.len = SIZEOF(GTM_TEST_FAKE_ENOSPC) - 1; + TREF(gtm_test_fake_enospc) = logical_truth_value(&val, FALSE, &is_defined); + if (!is_defined) + TREF(gtm_test_fake_enospc) = FALSE; +# endif +# ifdef GTMDBGFLAGS_ENABLED + val.addr = GTMDBGFLAGS; + val.len = SIZEOF(GTMDBGFLAGS) - 1; + TREF(gtmdbgflags) = trans_numeric(&val, &is_defined, TRUE); + val.addr = GTMDBGFLAGS_FREQ; + val.len = SIZEOF(GTMDBGFLAGS_FREQ) - 1; + TREF(gtmdbgflags_freq) = trans_numeric(&val, &is_defined, TRUE); +# endif } diff --git a/sr_unix/gtm_exit_handler.c b/sr_unix/gtm_exit_handler.c index ea7a223..477a11b 100644 --- a/sr_unix/gtm_exit_handler.c +++ b/sr_unix/gtm_exit_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -79,14 +79,6 @@ void gtm_exit_handler(void) cancel_timer(0); /* Cancel all timers - No unpleasant surprises */ ESTABLISH(lastchance1); secshr_db_clnup(NORMAL_TERMINATION); - if (pool_init) - { - rel_lock(jnlpool.jnlpool_dummy_reg); - mutex_cleanup(jnlpool.jnlpool_dummy_reg); - SHMDT(jnlpool.jnlpool_ctl); - jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; - pool_init = FALSE; - } if (dollar_tlevel) OP_TROLLBACK(0); zcall_halt(); diff --git a/sr_unix/gtm_fd_trace.c b/sr_unix/gtm_fd_trace.c index 601a495..5f85764 100644 --- a/sr_unix/gtm_fd_trace.c +++ b/sr_unix/gtm_fd_trace.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009 Fidelity Information Services, Inc * + * Copyright 2009, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -65,6 +65,9 @@ GBLDEF int4 fd_ops_array_index = -1; GBLDEF int4 fd_ops_array_num_wraps = 0; /* to get an idea how many total files were opened/closed */ GBLDEF fd_trace fd_ops_array[FD_OPS_ARRAY_SIZE]; /* space for FD_TRACE macro to record info */ +error_def(ERR_CLOSEFAIL); +error_def(ERR_CALLERID); + /* Determine on what platforms and build types we want to get caller_id information. In pro builds, invoke caller_id only on * those platforms where caller_id is lightweight (i.e. caller_id.s exists). Thankfully AIX (necessary for D9I11-002714) * falls in this category. For debug builds, invoke caller_id unconditionally since performance is not a big concern. @@ -149,13 +152,14 @@ int gtm_pipe1(int pipefd[2]) return status; } -int gtm_socket(int domain, int type, int protocol) +int gtm_socket(int family, int type, int protocol) { int fd; - fd = socket(domain, type, protocol); - FD_TRACE(fd_ops_socket, fd, 0); - assert(-1 != fd); + fd = socket(family, type, protocol); + if (-1 != fd) + FD_TRACE(fd_ops_socket, fd, 0); + /* it is possible that fd will be -1 if the address family is not supported */ return fd; } @@ -164,15 +168,12 @@ int gtm_close(int fd) int status; int save_errno; - error_def(ERR_CLOSEFAIL); - error_def(ERR_CALLERID); - status = close(fd); save_errno = errno; FD_TRACE(fd_ops_close, fd, status); if ((-1 == status) && (EINTR != save_errno)) { - send_msg(VARLSTCNT(4) ERR_CLOSEFAIL, 1, fd, save_errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, fd, save_errno); SEND_CALLERID("gtm_close()"); assert(FALSE); } diff --git a/sr_unix/gtm_fork_n_core.c b/sr_unix/gtm_fork_n_core.c index 5afd471..31b0911 100644 --- a/sr_unix/gtm_fork_n_core.c +++ b/sr_unix/gtm_fork_n_core.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,6 +42,7 @@ #include "gdsfhead.h" #include "filestruct.h" #include "dpgbldir.h" +#include "fork_init.h" GBLREF boolean_t created_core; /* core file was created */ GBLREF unsigned int core_in_progress; @@ -135,7 +136,7 @@ DEBUG_ONLY( struct rlimit rlim;) status = stat(newname, &fs1); /* This file exist ? */ if (0 != status) - status = rename(oldname, newname); /* No, attempt the rename */ + status = RENAME(oldname, newname); /* No, attempt the rename */ else status = -1; /* Yes, reset status for another iteration */ } @@ -150,8 +151,8 @@ DEBUG_ONLY( struct rlimit rlim;) { if (1 == core_in_progress) { /* only report once */ - send_msg(VARLSTCNT(1) ERR_COREINPROGRESS, 0); - gtm_putmsg(VARLSTCNT(1) ERR_COREINPROGRESS, 0); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COREINPROGRESS, 0); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COREINPROGRESS, 0); } return; } @@ -165,14 +166,14 @@ DEBUG_ONLY( struct rlimit rlim;) /* block SIGALRM signal */ sigprocmask(SIG_BLOCK, &blockalrm, &savemask); - childid = fork(); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */ + FORK(childid); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */ if (childid) { if (-1 == childid) { /* restore interrupt handler */ sigaction(SIGINT, &intr, 0); sigprocmask(SIG_SETMASK, &savemask, NULL); - gtm_putmsg(VARLSTCNT(3) ERR_NOFORKCORE, 0, errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_NOFORKCORE, 0, errno); return; /* Fork failed, no core done */ } WAITPID(childid, &status, 0, waitrc); @@ -189,29 +190,6 @@ DEBUG_ONLY( struct rlimit rlim;) created_core = TRUE; } else { - for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) - { - for (reg = addr_ptr->regions, r_top = reg + addr_ptr->n_regions; reg < r_top; reg++) - { - if (reg->open && !reg->was_open && (dba_mm == reg->dyn.addr->acc_meth)) - { /* Because most OSs don't include mapped memory in the core file, copy file header - * to temporary location that'll show up in the core. - */ - csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs; - tmp_csd = csa->hdr; - if ((NULL != tmp_csd) && (MM_MALLOC_ALREADY_TRIED != csa->mm_core_hdr)) - { - csa->mm_core_hdr = MM_MALLOC_ALREADY_TRIED; - csd = (sgmnt_data_ptr_t)malloc(SIZEOF(*csd)); - if (NULL != csd) - { - memcpy((sm_uc_ptr_t)csd, (uchar_ptr_t)tmp_csd, SIZEOF(*csd)); - csa->mm_core_hdr = csd; - } - } - } - } - } DUMP_CORE; /* This will (should) not return */ _exit(-1); /* Protection to kill fork'd process with no rundown by exit handler(s) */ } diff --git a/sr_unix/gtm_getmsg.c b/sr_unix/gtm_getmsg.c index 79fa421..af837df 100644 --- a/sr_unix/gtm_getmsg.c +++ b/sr_unix/gtm_getmsg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,7 @@ GBLREF bool dec_nofac; #define ERR_TAG "ENO" -void gtm_getmsg (int4 msgnum, mstr *msgbuf) +void gtm_getmsg(int4 msgnum, mstr *msgbuf) { short int m_len, faclen, taglen, j, sever; char *cp; @@ -33,11 +33,9 @@ void gtm_getmsg (int4 msgnum, mstr *msgbuf) const err_ctl *ctl; ctl = err_check(msgnum); - if (ctl != 0) + if (NULL != ctl) { - assert((msgnum & FACMASK(ctl->facnum)) && (MSGMASK(msgnum, ctl->facnum) <= ctl->msg_cnt)); - j = MSGMASK(msgnum, ctl->facnum); - msg = ctl->fst_msg + j - 1; + GET_MSG_INFO(msgnum, ctl, msg); msgp = msg->msg; tag = (char_ptr_t)msg->tag; fac = ctl->facname; diff --git a/sr_unix/gtm_icu.c b/sr_unix/gtm_icu.c index 589e1e4..5847bd9 100644 --- a/sr_unix/gtm_icu.c +++ b/sr_unix/gtm_icu.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ #include #endif +#define GTMIO_MINIMAL /* If gtmio.h is pulled in for tracing, don't include stuff that causes redefined errors */ #include "error.h" #include "io.h" #include "iosp.h" @@ -87,7 +88,7 @@ typedef uint8_t UVersionInfo[MAX_ICU_VERSION_LENGTH]; /* Declare enumerators for all functions */ #define ICU_DEF(x) x##_, enum { -#include "gtm_icu.h" +#include "gtm_icu.h" /* BYPASSOK */ icu_func_n /* total number of ICU functions used */ }; #undef ICU_DEF @@ -96,7 +97,7 @@ icu_func_n /* total number of ICU functions used */ #define ICU_DEF(x) #x, LITDEF char* icu_fname[] = { -#include "gtm_icu.h" +#include "gtm_icu.h" /* BYPASSOK */ NULL }; #undef ICU_DEF @@ -109,7 +110,7 @@ NULL #define ICU_DEF(x) &x##_ptr, GBLDEF icu_func_t *icu_fptr[] = { -#include "gtm_icu.h" +#include "gtm_icu.h" /* BYPASSOK */ NULL }; #undef ICU_DEF diff --git a/sr_unix/gtm_ipc.h b/sr_unix/gtm_ipc.h index f7c810d..87c26f6 100644 --- a/sr_unix/gtm_ipc.h +++ b/sr_unix/gtm_ipc.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Serivces, Inc * + * Copyright 2001, 2012 Fidelity Information Serivces, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,9 +20,20 @@ #define MEGA_BOUND (1024 * 1024) #endif -#define FTOK gtm_ftok +#define FTOK gtm_ftok #define FTOK_OLD ftok +#define JNLPOOL_SHMDT(RC, SAVE_ERRNO) \ +{ \ + SAVE_ERRNO = 0; /* clear any left-over value */ \ + assert(NULL != jnlpool_ctl); \ + DEFER_INTERRUPTS(INTRPT_IN_SHMDT); \ + RC = SHMDT(jnlpool.jnlpool_ctl); \ + SAVE_ERRNO = errno; \ + jnlpool_ctl = jnlpool.jnlpool_ctl = NULL; \ + ENABLE_INTERRUPTS(INTRPT_IN_SHMDT); \ +} + key_t gtm_ftok(const char *path, int id); #endif diff --git a/sr_unix/gtm_logicals.h b/sr_unix/gtm_logicals.h index c28d1b2..94a8a01 100644 --- a/sr_unix/gtm_logicals.h +++ b/sr_unix/gtm_logicals.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,32 +10,34 @@ ****************************************************************/ /* gtm_logicals.h - Environment variables used by GT.M. */ - +/* within each group, the entries are in alpha order of the third column */ /* -------------------------- Common to Unix and VMS -------------------------- */ #define GTM_DIST_LOG "$gtm_dist" /* Database */ #define GTM_GBLDIR "$gtmgbldir" -#define GTM_ENV_XLATE "$gtm_env_translate" -#define GTM_GVDUPSETNOOP "$gtm_gvdupsetnoop" -#define GTM_GVUNDEF_FATAL "$gtm_gvundef_fatal" -#define GTM_GDSCERT "$gtm_gdscert" #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_GVUNDEF_FATAL "$gtm_gvundef_fatal" #define GTM_TP_ALLOCATION_CLUE "$gtm_tp_allocation_clue" +#define GTM_TPNOTACIDTIME "$gtm_tpnotacidtime" #define GTM_TPRESTART_LOG_DELTA "$gtm_tprestart_log_delta" #define GTM_TPRESTART_LOG_LIMIT "$gtm_tprestart_log_first" -#define GTM_FULLBLOCKWRITES "$gtm_fullblockwrites" +#define GTM_ZMAXTPTIME "$gtm_zmaxtptime" /* White-box testing */ +#define GTM_WHITE_BOX_TEST_CASE_COUNT "$gtm_white_box_test_case_count" #define GTM_WHITE_BOX_TEST_CASE_ENABLE "$gtm_white_box_test_case_enable" #define GTM_WHITE_BOX_TEST_CASE_NUMBER "$gtm_white_box_test_case_number" -#define GTM_WHITE_BOX_TEST_CASE_COUNT "$gtm_white_box_test_case_count" /* Indirection-cache */ -#define GTM_MAX_INDRCACHE_MEMORY "$gtm_max_indrcache_memory" #define GTM_MAX_INDRCACHE_COUNT "$gtm_max_indrcache_count" +#define GTM_MAX_INDRCACHE_MEMORY "$gtm_max_indrcache_memory" /* MUPIP BACKUP */ #define GTM_BAK_TEMPDIR_LOG_NAME "$gtm_baktmpdir" @@ -53,39 +55,38 @@ /* GTM processing versus M standard */ /* (see gtm_local_collate above) */ #define GTM_STDXKILL "$gtm_stdxkill" -#define GTM_LVNULLSUBS "$gtm_lvnullsubs" /* Miscellaneous */ -#define GTM_DEBUG_LEVEL_ENVLOG "$gtmdbglvl" -#define GTM_PRINCIPAL "$gtm_principal" -#define GTM_ZINTERRUPT "$gtm_zinterrupt" -#define SYSID "$gtm_sysid" #define ZCOMPILE "$gtmcompile" +#define GTM_DEBUG_LEVEL_ENVLOG "$gtmdbglvl" #define GTM_ZROUTINES "$gtmroutines" -#define ZYERROR "$gtm_zyerror" -#define ZTRAP_FORM "$gtm_ztrap_form" -#define ZTRAP_NEW "$gtm_ztrap_new" -#define ZDATE_FORM "$gtm_zdate_form" +#define GTM_BOOLEAN "$gtm_boolean" #define DISABLE_ALIGN_STRINGS "$gtm_disable_alignstr" #define GTM_MAX_SOCKETS "$gtm_max_sockets" #define GTM_MEMORY_RESERVE "$gtm_memory_reserve" -#define GTM_ZQUIT_ANYWAY "$gtm_zquit_anyway" #define GTM_NOUNDEF "$gtm_noundef" +#define GTM_PRINCIPAL "$gtm_principal" #define GTM_PROMPT "$gtm_prompt" -#define GTM_BOOLEAN "$gtm_boolean" -#define GTM_PROCSTUCKEXEC "$gtm_procstuckexec" -#define GTM_TRACE_GROUPS "$gtm_trace_groups" -#define GTM_TRACE_TABLE_SIZE "$gtm_trace_table_size" -#define GTM_MPROF_TESTING "$gtm_trace_gbl_name" +#define GTM_SIDE_EFFECT "$gtm_side_effects" +#define SYSID "$gtm_sysid" +#define GTM_MPROF_TESTING "$gtm_trace_gbl_name" +#define GTM_TRACE_GROUPS "$gtm_trace_groups" +#define GTM_TRACE_TABLE_SIZE "$gtm_trace_table_size" +#define ZDATE_FORM "$gtm_zdate_form" +#define GTM_ZINTERRUPT "$gtm_zinterrupt" +#define GTM_ZQUIT_ANYWAY "$gtm_zquit_anyway" +#define ZTRAP_FORM "$gtm_ztrap_form" +#define ZTRAP_NEW "$gtm_ztrap_new" +#define ZYERROR "$gtm_zyerror" /* -------------------------- Unix only -------------------------- */ /* 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" +#define GTM_TRIGGER_ETRAP "$gtm_trigger_etrap" +#define GTM_SNAPTMPDIR "$gtm_snaptmpdir" +#define GTM_DB_STARTUP_MAX_WAIT "$gtm_db_startup_max_wait" /* Replication */ #define GTM_REPL_INSTANCE "$gtm_repl_instance" @@ -94,7 +95,8 @@ #define GTM_ZLIB_CMP_LEVEL "$gtm_zlib_cmp_level" #define GTM_EVENT_LOG_LIB_ENV "$gtm_event_log_libpath" #define GTM_EVENT_LOG_RTN_ENV "$gtm_event_log_rtn" -#define GTM_JNL_RELEASE_TIMEOUT "$gtm_jnl_release_timeout" +#define GTM_JNL_RELEASE_TIMEOUT "$gtm_jnl_release_timeout" +#define GTM_CUSTOM_ERRORS "$gtm_custom_errors" /* Unicode */ #define GTM_CHSET_ENV "$gtm_chset" @@ -107,9 +109,17 @@ #define GTM_ICU_VERSION "$gtm_icu_version" /* Miscellaneous */ -#define GTM_LOG_ENV "$gtm_log" -#define GTM_PRINCIPAL_EDITING "$gtm_principal_editing" -#define GTM_QUIET_HALT "$gtm_quiet_halt" -#define GTM_NON_BLOCKED_WRITE_RETRIES "$gtm_non_blocked_write_retries" -#define GTM_NOCENABLE "$gtm_nocenable" #define GTM_ERROR_ON_JNL_FILE_LOST "$gtm_error_on_jnl_file_lost" +#define GTM_ETRAP "$gtm_etrap" +#define GTM_LOG_ENV "$gtm_log" +#define GTM_LVNULLSUBS "$gtm_lvnullsubs" +#define GTM_NOCENABLE "$gtm_nocenable" +#define GTM_NON_BLOCKED_WRITE_RETRIES "$gtm_non_blocked_write_retries" +#define GTM_PRINCIPAL_EDITING "$gtm_principal_editing" +#define GTM_PROCSTUCKEXEC "$gtm_procstuckexec" +#define GTM_QUIET_HALT "$gtm_quiet_halt" +#define GTM_EXTRACT_NOCOL "$gtm_extract_nocol" +#define GTMDBGFLAGS "$gtmdbgflags" +#define GTMDBGFLAGS_FREQ "$gtmdbgflags_freq" +#define GTM_MAX_STORALLOC "$gtm_max_storalloc" +#define GTM_IPV4_ONLY "$gtm_ipv4_only" diff --git a/sr_unix/gtm_main.c b/sr_unix/gtm_main.c index 42079f1..f91086f 100644 --- a/sr_unix/gtm_main.c +++ b/sr_unix/gtm_main.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,6 +43,7 @@ #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" +#include "gtm_conv.h" #endif #ifdef GTM_CRYPT #include "gtmci.h" @@ -55,6 +56,9 @@ GBLREF char cli_token_buf[]; GBLREF char cli_err_str[]; GBLREF CLI_ENTRY mumps_cmd_ary[]; GTMTRIG_DBG_ONLY(GBLREF ch_ret_type (*ch_at_trigger_init)();) +#ifdef UNICODE_SUPPORTED +GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ +#endif GBLDEF CLI_ENTRY *cmd_ary = &mumps_cmd_ary[0]; /* Define cmd_ary to be the MUMPS specific cmd table */ GBLREF boolean_t skip_dbtriggers; @@ -66,25 +70,28 @@ GBLREF boolean_t skip_dbtriggers; * array passed to the main program is an array of 64-bit pointers. Thus the C program needs to declare argv[] * as an array of 64-bit pointers and needs to do the same for any pointer it sets to an element of argv[]. */ -#pragma pointer_size (save) -#pragma pointer_size (long) +# pragma pointer_size (save) +# pragma pointer_size (long) #endif - GBLDEF char **gtmenvp; - -int gtm_main (int argc, char **argv, char **envp) - -#ifdef __osf__ -#pragma pointer_size (restore) +#ifdef GTM_CRYPT +error_def(ERR_CRYPTDLNOOPEN); +error_def(ERR_CRYPTDLNOOPEN2); +error_def(ERR_CRYPTINIT); +error_def(ERR_CRYPTINIT2); +#endif +int gtm_main (int argc, char **argv, char **envp) +#ifdef __osf__ +# pragma pointer_size (restore) #endif - { char *ptr; int eof, parse_ret; - GTMCRYPT_ONLY( - char *gtm_passwd; - int init_status; - ) +# ifdef GTM_CRYPT + char *gtm_passwd; + const char *gtmcrypt_errlit = "during GT.M startup"; + int gtmcrypt_errno; +# endif DCL_THREADGBL_ACCESS; GTM_THREADGBL_INIT; @@ -95,6 +102,7 @@ int gtm_main (int argc, char **argv, char **envp) gtm_wcswidth_fnptr = gtm_wcswidth; gtm_env_init(); /* read in all environment variables */ err_init(stop_image_conditional_core); + UNICODE_ONLY(gtm_strToTitle_ptr = >m_strToTitle); GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ cli_lex_setup(argc, argv); /* put the arguments into buffer, then clean up the token buffer @@ -138,9 +146,19 @@ int gtm_main (int argc, char **argv, char **envp) && (NULL != (gtm_passwd = (char *)getenv(GTM_PASSWD))) && (0 == strlen(gtm_passwd))) { - INIT_PROC_ENCRYPTION(init_status); - if (0 != init_status) - GC_RTS_ERROR(init_status, NULL); + INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + { + CLEAR_CRYPTERR_MASK(gtmcrypt_errno); + assert(!IS_REPEAT_MSG_MASK(gtmcrypt_errno)); + assert((ERR_CRYPTDLNOOPEN == gtmcrypt_errno) || (ERR_CRYPTINIT == gtmcrypt_errno)); + if (ERR_CRYPTDLNOOPEN == gtmcrypt_errno) + gtmcrypt_errno = ERR_CRYPTDLNOOPEN2; + else if (ERR_CRYPTINIT == gtmcrypt_errno) + gtmcrypt_errno = ERR_CRYPTINIT2; + gtmcrypt_errno = SET_CRYPTERR_MASK(gtmcrypt_errno); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, STRLEN(gtmcrypt_errlit), gtmcrypt_errlit); + } } # endif dm_start(); diff --git a/sr_unix/gtm_permissions.h b/sr_unix/gtm_permissions.h index 8750c96..e7b2a7a 100644 --- a/sr_unix/gtm_permissions.h +++ b/sr_unix/gtm_permissions.h @@ -12,7 +12,7 @@ #ifndef GTM_PERMISSIONS #define GTM_PERMISSIONS -#include "mdefsp.h" +#include enum perm_target_types { diff --git a/sr_unix/gtm_pipe.c b/sr_unix/gtm_pipe.c index d9d0bb1..6227f7d 100644 --- a/sr_unix/gtm_pipe.c +++ b/sr_unix/gtm_pipe.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,6 +35,7 @@ #include "gtm_pipe.h" #include "eintr_wrappers.h" #include "gtmio.h" +#include "fork_init.h" GBLDEF uint4 pipe_child; @@ -46,13 +47,13 @@ int gtm_pipe(char *command, pipe_type pt) parent = (int)pt; child = 1 - parent; - if (0 > pipe(pfd)) { PERROR("pipe : "); return -2; } - if (-1 == (child_pid = fork())) /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */ + FORK(child_pid); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */ + if (-1 == child_pid) { PERROR("fork : "); return -1; @@ -61,21 +62,17 @@ int gtm_pipe(char *command, pipe_type pt) CLOSEFILE_RESET(pfd[parent], rc); /* resets "pfd[parent]" to FD_INVALID */ DUP2(pfd[child], child, dup2_res); CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ - /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(0), which calls exit_handler. - * So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release semaphores, - * which we should not release until parent exists. So we just call _exit(0). Add the do nothing if to - * keep compiler happy since exiting anyway. + /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(EXIT_SUCCESS), which calls + * exit_handler. So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release + * semaphores, which we should not release until parent exists. So we just call _exit(EXIT_SUCCESS). Add the do + * nothing if to keep compiler happy since exiting anyway. */ - if (-1 == SYSTEM(command)); - _exit(0); /* just exit from here */ + rc = SYSTEM(command); + _exit(EXIT_SUCCESS); /* just exit from here */ } else { /* parent process */ pipe_child = child_pid; CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */ return pfd[parent]; } - - assert(FALSE); - /* It should never get here, just to keep compiler happy. */ - return -3; } diff --git a/sr_unix/gtm_putmsg.c b/sr_unix/gtm_putmsg.c index 8b97539..1cf9280 100644 --- a/sr_unix/gtm_putmsg.c +++ b/sr_unix/gtm_putmsg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,17 +17,41 @@ #include "gtmmsg.h" #include "gtm_putmsg_list.h" #include "gtmimagename.h" +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "filestruct.h" +#include "repl_msg.h" +#include "gtmsource.h" +#include "anticipatory_freeze.h" + +GBLREF gd_region *gv_cur_region; +GBLREF jnlpool_addrs jnlpool; /* WARNING: For chained error messages, all messages MUST be followed by an fao count; * ======= zero MUST be specified if there are no parameters. */ void gtm_putmsg(int argcnt, ...) +{ + va_list var; + sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL; + VAR_START(var, argcnt); + gtm_putmsg_list(csa, argcnt, var); + va_end(var); + util_out_print("",TRUE); +} + +void gtm_putmsg_csa(void *csa, int argcnt, ...) { va_list var; VAR_START(var, argcnt); - gtm_putmsg_list(argcnt, var); + gtm_putmsg_list(csa, argcnt, var); va_end(var); util_out_print("",TRUE); } @@ -35,8 +59,21 @@ void gtm_putmsg(int argcnt, ...) void gtm_putmsg_noflush(int argcnt, ...) { va_list var; + sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; + csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL; VAR_START(var, argcnt); - gtm_putmsg_list(argcnt, var); + gtm_putmsg_list(csa, argcnt, var); + va_end(var); +} + +void gtm_putmsg_noflush_csa(void *csa, int argcnt, ...) +{ + va_list var; + + VAR_START(var, argcnt); + gtm_putmsg_list(csa, argcnt, var); va_end(var); } diff --git a/sr_unix/gtm_putmsg_list.c b/sr_unix/gtm_putmsg_list.c index 6ace432..f17fab5 100644 --- a/sr_unix/gtm_putmsg_list.c +++ b/sr_unix/gtm_putmsg_list.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,16 +20,17 @@ #include "util_out_print_vaparm.h" #include "gtmmsg.h" #include "gtm_putmsg_list.h" -#include "gtmimagename.h" /* needed for IS_GTM_IMAGE macro */ -#include "gtmio.h" /* needed for FFLUSH macro */ +#include "gtmimagename.h" /* needed for IS_GTM_IMAGE macro */ +#include "gtmio.h" /* needed for FFLUSH macro */ #include "io.h" +/* database/replication related includes due to anticipatory freeze */ +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "filestruct.h" +#include "anticipatory_freeze.h" /* for SET_ANTICIPATORY_FREEZE_IF_NEEDED */ GBLREF boolean_t donot_fflush_NULL; -GBLREF va_list last_va_list_ptr; - -#define NOFLUSH 0 -#define FLUSH 1 -#define RESET 2 /* * ---------------------------------------------------------------------------------------- @@ -38,77 +39,62 @@ GBLREF va_list last_va_list_ptr; * ---------------------------------------------------------------------------------------- */ -void gtm_putmsg_list(int arg_count, va_list var) +void gtm_putmsg_list(void *csa, int arg_count, va_list var) { - int i, msg_id, fao_actual, fao_count, dummy; + int i, msg_id, fao_actual, fao_count, dummy, freeze_msg_id; char msg_buffer[1024]; mstr msg_string; - boolean_t first_error; const err_msg *msg; const err_ctl *ctl; + boolean_t freeze_needed = FALSE; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; /* Before starting to write to stderr, make sure all other buffered streams are flushed. * This way we avoid out-of-order logging issues with multiple streams mapping to the same file * e.g. stdout/stderr could both end up in the same file. We do this now only for the utilities * (and not mumps) since the implications of that change (is it safe or not) are not yet clear. */ - if (!IS_GTM_IMAGE && !donot_fflush_NULL) - FFLUSH(NULL); + if (!IS_GTMSECSHR_IMAGE) + { /* Note gtmsecshr does no stdout/stderr IO - everything goes to operator log so this doesn't apply */ + if (!IS_GTM_IMAGE && !donot_fflush_NULL) + FFLUSH(NULL); + util_out_print(NULL, RESET); + flush_pio(); + } assert(0 < arg_count); - util_out_print(NULL, RESET); - first_error = TRUE; - flush_pio(); - - for (;;) + for (; ; ) { msg_id = va_arg(var, int); + CHECK_IF_FREEZE_ON_ERROR_NEEDED(csa, msg_id, freeze_needed, freeze_msg_id); --arg_count; - if (NULL == (ctl = err_check(msg_id))) msg = NULL; else - { - assert(0 != (msg_id & FACMASK(ctl->facnum)) && MSGMASK(msg_id, ctl->facnum) <= ctl->msg_cnt); - - msg = ctl->fst_msg + MSGMASK(msg_id, ctl->facnum) - 1; - } - - if (first_error) - { - first_error = FALSE; - error_condition = msg_id; - severity = NULL == msg ? ERROR : SEVMASK(msg_id); - } - + GET_MSG_INFO(msg_id, ctl, msg); msg_string.addr = msg_buffer; msg_string.len = sizeof msg_buffer; gtm_getmsg(msg_id, &msg_string); - if (NULL == msg) { util_out_print(msg_string.addr, NOFLUSH, msg_id); - if (0 < arg_count) { /* -------------------------- * Print the message to date * -------------------------- */ - util_out_print(NULL, FLUSH); - /* --------------------------------------- * Chained error; scan off the fao count * (it should be zero) * --------------------------------------- */ - i = va_arg(var, int); --arg_count; assert(0 == i); } - } - else + } else { if (0 < arg_count) { @@ -118,33 +104,27 @@ void gtm_putmsg_list(int arg_count, va_list var) fao_count = fao_actual < msg->parm_count ? fao_actual : msg->parm_count; if (MAX_FAO_PARMS < fao_count) fao_count = MAX_FAO_PARMS; - } - else - { + } else fao_actual = fao_count = 0; - } - util_out_print_vaparm(msg_string.addr, NOFLUSH, var, fao_count); va_end(var); /* needed before used as dest in copy */ - VAR_COPY(var, last_va_list_ptr); /* How much we unwound */ + VAR_COPY(var, TREF(last_va_list_ptr)); /* How much we unwound */ arg_count -= fao_count; - /* ------------------------------ * Skim off any extra parameters * ------------------------------ */ - for (i = fao_count; i < fao_actual; ++i) { dummy = va_arg(var, int); --arg_count; } - va_end(last_va_list_ptr); + va_end(TREF(last_va_list_ptr)); } - if (0 == arg_count) break; - - util_out_print("!/", NOFLUSH); + if (!IS_GTMSECSHR_IMAGE) + util_out_print("!/", NOFLUSH); } + FREEZE_INSTANCE_IF_NEEDED(csa, freeze_needed, freeze_msg_id); } diff --git a/sr_unix/gtm_rename.c b/sr_unix/gtm_rename.c index b0fd9b5..8232481 100644 --- a/sr_unix/gtm_rename.c +++ b/sr_unix/gtm_rename.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003 Sanchez Computer Associates, Inc. * + * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,7 @@ #include "mdef.h" #include + #include "gtm_stdio.h" #include "gtm_rename.h" #include "iosp.h" diff --git a/sr_unix/gtm_semutils.c b/sr_unix/gtm_semutils.c index 2e49793..f48d24f 100644 --- a/sr_unix/gtm_semutils.c +++ b/sr_unix/gtm_semutils.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011 Fidelity Information Services, Inc * + * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,58 +26,124 @@ #include #include /* for kill(), SIGTERM, SIGQUIT */ +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" #include "eintr_wrapper_semop.h" #include "gtm_sem.h" #include "gtm_c_stack_trace.h" #include "gtm_semutils.h" +#include "gtmimagename.h" +#include "do_semop.h" GBLREF uint4 process_id; GBLREF volatile uint4 heartbeat_counter; error_def(ERR_CRITSEMFAIL); error_def(ERR_SEMWT2LONG); +error_def(ERR_RESRCWAIT); +error_def(ERR_RESRCINTRLCKBYPAS); +error_def(ERR_TEXT); #define FULLTIME(MAX_HRTBT_DELTA, START_HRTBT_CNTR) (MAX_HRTBT_DELTA - 1 == (heartbeat_counter - START_HRTBT_CNTR)) #define HALFTIME(MAX_HRTBT_DELTA, START_HRTBT_CNTR) (MAX_HRTBT_DELTA / 2 == (heartbeat_counter - START_HRTBT_CNTR)) #define STACKTRACE_TIME(MAX_HRTBT_DELTA, START_HRTBT_CNTR) (HALFTIME(MAX_HRTBT_DELTA, START_HRTBT_CNTR) || \ FULLTIME(MAX_HRTBT_DELTA, START_HRTBT_CNTR)) #define USER_SPECIFIED_TIME_EXPIRED(MAX_HRTBT_DELTA, START_HRTBT_CNTR) (MAX_HRTBT_DELTA <= (heartbeat_counter - START_HRTBT_CNTR)) +#define IS_ACCESS_SEM (gtm_access_sem == semtype) +#define IS_FTOK_SEM (gtm_ftok_sem == semtype) -boolean_t do_blocking_semop(int semid, struct sembuf *sop, int sopcnt, enum gtm_semtype semtype, uint4 start_hrtbt_cntr, - semwait_status_t *retstat) + +boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrtbt_cntr, + semwait_status_t *retstat, gd_region *reg, boolean_t *bypass) { boolean_t need_stacktrace, indefinite_wait; - const char *msgstr = NULL; - int status = SS_NORMAL, save_errno, sem_pid; + char *msgstr; + int status = SS_NORMAL, save_errno, sem_pid, semval, i, sopcnt; uint4 loopcnt = 0, max_hrtbt_delta, lcl_hrtbt_cntr, stuck_cnt = 0; - boolean_t stacktrace_issued = FALSE; + boolean_t stacktrace_issued = FALSE, is_editor; /* This is LKE or DSE editor image */ + struct sembuf sop[3]; + char *sem_names[2] = {"FTOK", "access control"}; /* based on gtm_semtype enum order */ + DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - sop[0].sem_flg = sop[1].sem_flg = sop[2].sem_flg = SEM_UNDO; + assert(IS_FTOK_SEM || IS_ACCESS_SEM); + /* Access control semaphore should not be increased when the process is readonly */ + SET_GTM_SOP_ARRAY(sop, sopcnt, IS_FTOK_SEM || !reg->read_only, (SEM_UNDO | IPC_NOWAIT)); + is_editor = (IS_DSE_IMAGE || IS_LKE_IMAGE); max_hrtbt_delta = TREF(dbinit_max_hrtbt_delta); assert(NO_SEMWAIT_ON_EAGAIN != max_hrtbt_delta); if (indefinite_wait = (INDEFINITE_WAIT_ON_EAGAIN == max_hrtbt_delta)) max_hrtbt_delta = DEFAULT_DBINIT_MAX_HRTBT_DELTA; - need_stacktrace = (DEFAULT_DBINIT_MAX_HRTBT_DELTA <= max_hrtbt_delta); + need_stacktrace = (DEFAULT_DBINIT_MAX_HRTBT_DELTA <= max_hrtbt_delta) && !is_editor; if (!need_stacktrace) { /* Since the user specified wait time is less than the default wait, wait that time without any stack trace */ - do + if (is_editor) + { /* Editors are able to bypass after 3 seconds of wait. IPC_NOWAIT smeop every second. + * The semaphore value must be at least 2 to make sure the shared memeory is already created. + */ + if (-1 == (semval = semctl(semid, 1, GETVAL))) /* semval = number of process attached */ + RETURN_SEMWAIT_FAILURE(retstat, errno, op_semctl, ERR_CRITSEMFAIL, 0, 0); + if (semval > 1) + { + if (-1 == (sem_pid = semctl(semid, 0, GETPID))) + RETURN_SEMWAIT_FAILURE(retstat, errno, op_semctl, ERR_CRITSEMFAIL, 0, 0); + gtm_putmsg(VARLSTCNT(10) ERR_RESRCWAIT, 8, LEN_AND_STR(sem_names[semtype]), REG_LEN_STR(reg), + DB_LEN_STR(reg), sem_pid, semid); + i = 0; + do + { + SEMOP(semid, sop, sopcnt, status, NO_WAIT); + save_errno = errno; + LONG_SLEEP(1); + i++; + } while ((-1 == status) && (EAGAIN == save_errno) && (i < MAX_BYPASS_WAIT_SEC)); + if (-1 != status) + return TRUE; + assert(EINTR != save_errno); + if (EAGAIN == save_errno) + { + *bypass = TRUE; + save_errno = 0; + send_msg(VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10, + LEN_AND_STR((IS_LKE_IMAGE ? "LKE" : "DSE")), process_id, + LEN_AND_STR(sem_names[semtype]), REG_LEN_STR(reg), DB_LEN_STR(reg), sem_pid); + /* If this is a readonly access, we don't increment access semaphore's counter. See + * SET_GTM_SOP_ARRAY definition in gtm_semutils.h and how it is called from db_init(). + */ + if (IS_FTOK_SEM || !reg->read_only) + { + /* Increase the counter semaphore. */ + save_errno = do_semop(semid, 1, 1, SEM_UNDO); + if (save_errno == 0) + return TRUE; + *bypass = FALSE; /* Semaphore removed when attempting to bypass. Abort bypass. */ + } else + return TRUE; + } + } + } + if (!is_editor || (semval < 2)) { - status = semop(semid, sop, sopcnt); - } while ((-1 == status) && (EINTR == errno) && !USER_SPECIFIED_TIME_EXPIRED(max_hrtbt_delta, start_hrtbt_cntr)); - if (-1 != status) - return TRUE; - save_errno = errno; - if (EINTR == save_errno) - { /* someone else is holding it and we are done waiting */ + /* Do not bypass. (We are not LKE/DSE OR) OR (There are less than 2 processes inside) */ + sop[0].sem_flg = sop[1].sem_flg = sop[2].sem_flg = SEM_UNDO; /* Enable blocking wait. */ + do + { + status = semop(semid, sop, sopcnt); + save_errno = errno; + } while ((-1 == status) && (EINTR == errno) && !USER_SPECIFIED_TIME_EXPIRED(max_hrtbt_delta, + start_hrtbt_cntr)); + if (-1 != status) + return TRUE; + /* someone else is holding it and we are done waiting */ sem_pid = semctl(semid, 0, GETPID); if (-1 != sem_pid) RETURN_SEMWAIT_FAILURE(retstat, 0, op_invalid_sem_syscall, ERR_SEMWT2LONG, 0, sem_pid); - save_errno = errno; } } else { + sop[0].sem_flg = sop[1].sem_flg = sop[2].sem_flg = SEM_UNDO; /* Enable blocking wait. */ lcl_hrtbt_cntr = heartbeat_counter; while (!USER_SPECIFIED_TIME_EXPIRED(max_hrtbt_delta, start_hrtbt_cntr)) { @@ -105,7 +171,7 @@ boolean_t do_blocking_semop(int semid, struct sembuf *sop, int sopcnt, enum gtm_ * elapsed, get the stack trace at half-time and at the penultimate heartbeat. */ stuck_cnt++; - if (gtm_ftok_sem == semtype) + if (IS_FTOK_SEM) msgstr = (1 == stuck_cnt) ? "SEMWT2LONG_FTOK_INFO" : "SEMWT2LONG_FTOK"; else msgstr = (1 == stuck_cnt) ? "SEMWT2LONG_ACCSEM_INFO" : "SEMWT2LONG_ACCSEM"; diff --git a/sr_unix/gtm_semutils.h b/sr_unix/gtm_semutils.h index bc6f5c7..fefc96b 100644 --- a/sr_unix/gtm_semutils.h +++ b/sr_unix/gtm_semutils.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011 Fidelity Information Services, Inc * + * Copyright 2011, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,9 +17,13 @@ #define DEFAULT_DBINIT_MAX_HRTBT_DELTA 12 #define NO_SEMWAIT_ON_EAGAIN 0 #define INDEFINITE_WAIT_ON_EAGAIN (uint4) -1 +#define MAX_BYPASS_WAIT_SEC 3 #define MAX_C_STACK_TRACES_FOR_SEMWAIT 2 +#define DB_CONTROL_SEM 0 +#define DB_COUNTER_SEM 1 + error_def(ERR_CRITSEMFAIL); error_def(ERR_DBFILERR); error_def(ERR_FTOKERR); @@ -48,7 +52,7 @@ enum gtm_semtype typedef struct semwait_status_struct { int line_no; - int save_errno; + int save_errno; /* This value must be checked/assigned only errors. May not be 0 on success. */ int status1; int status2; int sem_pid; @@ -56,8 +60,8 @@ typedef struct semwait_status_struct enum sem_syscalls op; } semwait_status_t; -boolean_t do_blocking_semop(int semid, struct sembuf *sop, int sopcnt, enum gtm_semtype semtype, uint4 start_hrtbt_cntr, - semwait_status_t *status); +boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrtbt_cntr, + semwait_status_t *status, gd_region *reg, boolean_t *bypass); #define SENDMSG_SEMOP_SUCCESS_IF_NEEDED(STACKTRACE_ISSUED, SEMTYPE) \ { \ @@ -157,11 +161,11 @@ boolean_t do_blocking_semop(int semid, struct sembuf *sop, int sopcnt, enum gtm_ /* Typically, multiple statements are not specified in a single line. However, each of the 2 lines below represent \ * "one" semaphore operation and hence an acceptible exception to the coding guidelines. \ */ \ - SOP[0].sem_num = 0; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \ - SOP[1].sem_num = 0; SOP[1].sem_op = 1; /* Then lock it */ \ + SOP[0].sem_num = DB_CONTROL_SEM; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \ + SOP[1].sem_num = DB_CONTROL_SEM; SOP[1].sem_op = 1; /* Then lock it */ \ if (INCR_CNT) \ { \ - SOP[2].sem_num = 1; SOP[2].sem_op = 1; /* Increment counter semaphore */ \ + SOP[2].sem_num = DB_COUNTER_SEM; SOP[2].sem_op = 1; /* Increment counter semaphore */ \ SOPCNT = 3; \ } else \ SOPCNT = 2; \ diff --git a/sr_unix/gtm_startup.c b/sr_unix/gtm_startup.c index ca0e0c0..60d3bcb 100644 --- a/sr_unix/gtm_startup.c +++ b/sr_unix/gtm_startup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,7 +70,6 @@ #include "error_trap.h" /* for ecode_init() prototype */ #include "zyerror_init.h" #include "ztrap_form_init.h" -#include "ztrap_new_init.h" #include "zdate_form_init.h" #include "dollar_system_init.h" #include "sig_init.h" @@ -90,6 +89,9 @@ #include "cenable.h" #include "gtmimagename.h" #include "mprof.h" +#include "heartbeat_timer.h" +#include "gt_timers_add_safe_hndlrs.h" +#include "continue_handler.h" GBLDEF void (*restart)() = &mum_tstart; #ifdef __MVS__ @@ -108,7 +110,6 @@ GBLREF unsigned char *fgncal_stack; GBLREF mv_stent *mv_chain; GBLREF xfer_entry_t xfer_table[]; GBLREF mval dollar_system; -GBLREF mval dollar_ztrap; GBLREF mval dollar_zstatus; GBLREF bool compile_time; GBLREF spdesc stringpool; @@ -133,8 +134,10 @@ GBLREF casemap_t casemaps[]; GBLREF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */ GBLREF ch_ret_type (*ht_rhash_ch)(); /* Function pointer to hashtab_rehash_ch */ GBLREF ch_ret_type (*jbxm_dump_ch)(); /* Function pointer to jobexam_dump_ch */ +GBLREF ch_ret_type (*stpgc_ch)(); /* Function pointer to stp_gcol_ch */ GBLREF enum gtmImageTypes image_type; GBLREF int init_xfer_table(void); +GBLREF void (*heartbeat_timer_ptr)(void); OS_PAGE_SIZE_DECLARE @@ -152,7 +155,6 @@ void gtm_startup(struct startup_vector *svec) { unsigned char *mstack_ptr; void gtm_ret_code(); - static readonly unsigned char init_break[1] = {'B'}; int4 lct; int i; static char other_mode_buf[] = "OTHER"; @@ -167,6 +169,8 @@ void gtm_startup(struct startup_vector *svec) cache_table_relobjs = &cache_table_rebuild; ht_rhash_ch = &hashtab_rehash_ch; jbxm_dump_ch = &jobexam_dump_ch; + heartbeat_timer_ptr = &heartbeat_timer; + stpgc_ch = &stp_gcol_ch; rtn_fst_table = rtn_names = (rtn_tabent *)svec->rtn_start; rtn_names_end = rtn_names_top = (rtn_tabent *)svec->rtn_end; if (svec->user_stack_size < 4096) @@ -191,14 +195,6 @@ void gtm_startup(struct startup_vector *svec) else if (svec->user_strpl_size > STP_MAXINITSIZE) svec->user_strpl_size = STP_MAXINITSIZE; stp_init(svec->user_strpl_size); - if (svec->user_indrcache_size > MAX_INDIRECTION_NESTING || svec->user_indrcache_size < MIN_INDIRECTION_NESTING) - svec->user_indrcache_size = MIN_INDIRECTION_NESTING; - TREF(ind_result_array) = (mval **)malloc(SIZEOF(mval *) * svec->user_indrcache_size); - TREF(ind_source_array) = (mval **)malloc(SIZEOF(mval *) * svec->user_indrcache_size); - TREF(ind_result_sp) = TREF(ind_result_array); - TREF(ind_result_top) = TREF(ind_result_sp) + svec->user_indrcache_size; - TREF(ind_source_sp) = TREF(ind_source_array); - TREF(ind_source_top) = TREF(ind_source_sp) + svec->user_indrcache_size; rts_stringpool = stringpool; TREF(compile_time) = FALSE; /* assert that is_replicator and run_time is properly set by gtm_imagetype_init invoked at process entry */ @@ -253,11 +249,14 @@ void gtm_startup(struct startup_vector *svec) LVVAL_INIT((TREF(zsearch_dir2)), curr_symval); /* Initialize global pointer to control-C handler. Also used in iott_use */ ctrlc_handler_ptr = &ctrlc_handler; + if (!IS_MUPIP_IMAGE) + { + sig_init(generic_signal_handler, ctrlc_handler_ptr, suspsigs_handler, continue_handler); + atexit(gtm_exit_handler); + } io_init(IS_MUPIP_IMAGE); /* starts with nocenable for GT.M runtime, enabled for MUPIP */ if (!IS_MUPIP_IMAGE) { - sig_init(generic_signal_handler, ctrlc_handler_ptr, suspsigs_handler); - atexit(gtm_exit_handler); cenable(); /* cenable unless the environment indicates otherwise - 2 steps because this can report errors */ } jobinterrupt_init(); @@ -274,16 +273,12 @@ void gtm_startup(struct startup_vector *svec) (TREF(dollar_zmode)).str.len = SIZEOF(other_mode_buf) -1; } svec->frm_ptr = (unsigned char *)frame_pointer; - dollar_ztrap.mvtype = MV_STR; - dollar_ztrap.str.len = SIZEOF(init_break); - dollar_ztrap.str.addr = (char *)init_break; dollar_zstatus.mvtype = MV_STR; dollar_zstatus.str.len = 0; dollar_zstatus.str.addr = NULL; ecode_init(); zyerror_init(); ztrap_form_init(); - ztrap_new_init(); zdate_form_init(svec); dollar_system_init(svec); init_callin_functable(); @@ -307,7 +302,8 @@ void gtm_startup(struct startup_vector *svec) } } else TREF(local_collseq) = 0; - prealloc_gt_timers(); /* Preallocate some timer blocks. */ + prealloc_gt_timers(); + gt_timers_add_safe_hndlrs(); for (i = 0; FNPC_MAX > i; i++) { /* Initialize cache structure for $Piece function */ (TREF(fnpca)).fnpcs[i].pcoffmax = &(TREF(fnpca)).fnpcs[i].pstart[FNPC_ELEM_MAX]; diff --git a/sr_unix/gtm_startup_chk.c b/sr_unix/gtm_startup_chk.c index 5a4e73b..d327451 100644 --- a/sr_unix/gtm_startup_chk.c +++ b/sr_unix/gtm_startup_chk.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,7 +39,9 @@ #include "is_file_identical.h" #include "gtm_startup_chk.h" #include "gtmimagename.h" +#include "have_crit.h" +GBLREF char gtm_dist[GTM_PATH_MAX]; LITREF gtmImageName gtmImageNames[]; error_def(ERR_DISTPATHMAX); @@ -51,7 +53,6 @@ error_def(ERR_IMAGENAME); int gtm_chk_dist(char *image) { - char *ptr1; char pre_buff[MAX_FBUFF]; char *prefix; int prefix_len; @@ -59,14 +60,17 @@ int gtm_chk_dist(char *image) int status; char mbuff[MAX_FBUFF + 1]; parse_blk pblk; + char *dist; - if (NULL != (ptr1 = (char *)GETENV(GTM_DIST))) + if (NULL != (dist = (char *)GETENV(GTM_DIST))) { assert(IS_VALID_IMAGE && (n_image_types > image_type)); /* assert image_type is initialized */ - if ((GTM_PATH_MAX - 2) <= (STRLEN(ptr1) + gtmImageNames[image_type].imageNameLen)) - rts_error(VARLSTCNT(3) ERR_DISTPATHMAX, 1, GTM_PATH_MAX - gtmImageNames[image_type].imageNameLen - 2); + if ((GTM_PATH_MAX - 2) <= (STRLEN(dist) + gtmImageNames[image_type].imageNameLen)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_DISTPATHMAX, 1, + GTM_PATH_MAX - gtmImageNames[image_type].imageNameLen - 2); } else - rts_error(VARLSTCNT(1) ERR_GTMDISTUNDEF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMDISTUNDEF); + memcpy(gtm_dist, dist, STRLEN(dist)); memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = mbuff; pblk.buff_size = MAX_FBUFF; @@ -76,16 +80,16 @@ int gtm_chk_dist(char *image) /* strings returned in pblk are not null terminated */ status = parse_file(>m_name, &pblk); if (!(status & 1)) - rts_error(VARLSTCNT(5) ERR_FILEPARSE, 2, gtm_name.len, gtm_name.addr, status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, gtm_name.len, gtm_name.addr, status); assert(NULL != pblk.l_name); if ((!(pblk.fnb & F_HAS_DIR) && !pblk.b_dir) || (DIR_SEPARATOR != pblk.l_dir[0])) { - if (NULL == GETCWD(pre_buff, MAX_FBUFF, prefix)) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, - LEN_AND_LIT("getcwd"), CALLFROM, errno); + GETCWD(pre_buff, MAX_FBUFF, prefix); + if (NULL == prefix) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, errno); prefix_len = STRLEN(prefix); if (MAX_FBUFF < prefix_len + pblk.b_esl + 1) - rts_error(VARLSTCNT(3) ERR_MAXGTMPATH, 1, MAX_FBUFF - pblk.b_name); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXGTMPATH, 1, MAX_FBUFF - pblk.b_name); if (DIR_SEPARATOR != prefix[prefix_len - 1]) { prefix[prefix_len] = DIR_SEPARATOR; @@ -100,6 +104,6 @@ int gtm_chk_dist(char *image) prefix[pblk.b_dir] = 0; } if (IS_GTM_IMAGE && memcmp(pblk.l_name, GTM_IMAGE_NAME, GTM_IMAGE_NAMELEN)) - rts_error(VARLSTCNT(6) ERR_IMAGENAME, 4, LEN_AND_LIT(GTM_IMAGE_NAME), pblk.b_name, pblk.l_name); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IMAGENAME, 4, LEN_AND_LIT(GTM_IMAGE_NAME), pblk.b_name, pblk.l_name); return 0; } diff --git a/sr_unix/gtm_statvfs.h b/sr_unix/gtm_statvfs.h index 4875ec6..2497427 100644 --- a/sr_unix/gtm_statvfs.h +++ b/sr_unix/gtm_statvfs.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,14 +16,11 @@ #include #define STATVFS(pathname,fsinfo,statvfs_res) (statvfs_res = statvfs(pathname, fsinfo)) -#define FSTATVFS(filedesc,fstatvfsinfo,fstatvfs_res) (fstatvfs_res = fstatvfs(filedesc, fstatvfsinfo)) - -#if (defined(__osf__) && defined(__alpha)) || defined(__ia64) -#define GTM_BAVAIL_TYPE unsigned long -#elif defined(__linux__) && defined(__USE_FILE_OFFSET64) -#define GTM_BAVAIL_TYPE unsigned long long int -#else -#define GTM_BAVAIL_TYPE uint4 -#endif +#define FSTATVFS(filedesc,fstatvfsinfo,fstatvfs_res) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_FSTAT); \ + fstatvfs_res = fstatvfs(filedesc, fstatvfsinfo); \ + ENABLE_INTERRUPTS(INTRPT_IN_FSTAT); \ +} #endif diff --git a/sr_unix/gtm_stdio.h b/sr_unix/gtm_stdio.h index c26ebba..3b63fbd 100644 --- a/sr_unix/gtm_stdio.h +++ b/sr_unix/gtm_stdio.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,7 +22,16 @@ #include -#define FDOPEN fdopen +/* 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. + */ +#define FDOPEN(VAR, FILE_DES, MODE) \ +{ \ + DEFER_INTERRUPTS(INTRPT_IN_FDOPEN); \ + VAR = fdopen(FILE_DES, MODE); \ + ENABLE_INTERRUPTS(INTRPT_IN_FDOPEN); \ +} + #define FGETS(strg, n, strm, fgets_res) (fgets_res = fgets(strg,n,strm)) #define Fopen fopen #define GETS(buffer, gets_res) syntax error diff --git a/sr_unix/gtm_syslog.h b/sr_unix/gtm_syslog.h index daef709..b6ac34b 100644 --- a/sr_unix/gtm_syslog.h +++ b/sr_unix/gtm_syslog.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,5 +17,6 @@ #define OPENLOG openlog #define SYSLOG syslog +#define CLOSELOG closelog #endif diff --git a/sr_unix/gtm_test_install.csh b/sr_unix/gtm_test_install.csh index 8e7b668..4719f8a 100644 --- a/sr_unix/gtm_test_install.csh +++ b/sr_unix/gtm_test_install.csh @@ -1,272 +1,291 @@ -#!/usr/local/bin/tcsh -################################################################# -# # -# Copyright 2011 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. # -# # -################################################################# -echo "" -echo "------------------------------------------------------------------------" -set arch = `grep arch $gtm_ver/pro/arch.gtc | awk -F= '{print $2}' | tr -d '\"'` -cd $1 -source ./gtmcshrc -setenv gtmgbldir mumps.gld -gde exit -mupip create -gtm << \EOF >&! gtm_test_install.out -set ^X=1 -set x=2 -write $ORDER(^%),! -zwrite -zwrite ^X -halt -\EOF -gtm << EOF >>&! gtm_test_install.out -zhelp - -zwrite ^X -halt -EOF -cat << EOF -Please run zhelp manually: -cd `pwd` -source ./gtmcshrc -gtm -zhelp -EOF - -mkdir test_gtm -cd test_gtm - -# create sim.m -cat > sim.m <>&! $save_gtm_dist/gtm_test_install.out -grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out - -#get version number - -setenv gtmver `ls -d V*` - -# get journal output -cd $gtmver/g - -setenv gtm_dist $save_gtm_dist - -$gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out -(setenv gtmgbldir $gtm_dist/test_gtm/mumps.gld; $gtm_dist/mupip integ -reg "*" >& integ.out) -# output the change lines -echo "" >>&! $gtm_dist/gtm_test_install.out -echo "Global changes in the gtm.mjl file:" >>&! $gtm_dist/gtm_test_install.out -grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $gtm_dist/gtm_test_install.out -cat integ.out >>&! $gtm_dist/gtm_test_install.out - -cd $gtm_dist - -# keep the utf8 libicu search code below in synch with configure.gtc! - -set is64bit_gtm = `file mumps | grep 64 | wc -l` - -if ( $is64bit_gtm == 1 ) then - set library_path = "/usr/local/lib64 /usr/local/lib /usr/lib /usr/lib32" -else - set library_path = "/usr/local/lib /usr/lib /usr/lib32" -endif - -set is64bit_icu = 0 -# Set the appropriate extensions for ICU libraries depending on the platforms -set icu_ext = ".so" -if ( $arch == "ibm" ) then - set icu_ext = ".a" -else if ( $arch == "hp" ) then - set icu_ext = ".sl" -endif - -# Check the presence of gtm_icu_version -set gtm_icu_version_set = "FALSE" -if ($?gtm_icu_version) then - if ("" != $gtm_icu_version) then - set gtm_icu_version_set = "TRUE" - endif -endif - -foreach libpath ($library_path) - set icu_lib_found = 0 - if ( "FALSE" == "$gtm_icu_version_set" && ( -f "$libpath/libicuio$icu_ext" ) ) then - set icu_lib_found = 1 - # Find the actual version'ed library to which libicuio.{so,sl,a} points to - set icu_versioned_lib = `ls -l $libpath/libicuio$icu_ext | awk '{print $NF}'` - # Find out vital parameters - if ( "$arch" == "ibm" || "$arch" == "zos" ) then - # From the version'ed library(eg. libicuio36.0.a) extract out - # 36.0.a - set full_icu_ver_string = `echo $icu_versioned_lib | sed 's/libicuio//g'` - # Extract 36 from 36.0.a - set majmin=`echo $full_icu_ver_string | cut -f 1 -d '.'` - else - set full_icu_ver_string=`echo $icu_versioned_lib | sed 's/libicuio\.//g'` - set majmin=`echo $full_icu_ver_string | cut -f 2 -d '.'` - endif - else if ( "TRUE" == "$gtm_icu_version_set" ) then - set majmin = `echo $gtm_icu_version | sed 's/\.//'` - if ( -f "$libpath/libicuio$majmin$icu_ext" || -f "$libpath/libicuio$icu_ext.$majmin" ) then - set icu_lib_found = 1 - else - set icu_lib_found = 0 - endif - - endif - if ( $icu_lib_found ) then - # Figure out the object mode(64 bit or 32 bit) of ICU libraries on the target machine - if ( "linux" == "$arch" || "sun" == "$arch" || "solaris" == $arch ) then - set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$icu_ext.$majmin 2>/dev/null" | awk '{print $NF}'` - set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "64-bit" | wc -l"` - else if ( "hp" == "$arch" ) then - set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$icu_ext.$majmin 2>/dev/null" | awk '{print $NF}'` - set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "IA64" | wc -l"` - else if ( "ibm" == "$arch" ) then - set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$majmin$icu_ext 2>/dev/null" | awk '{print $NF}'` - set is64bit_icu = `sh -c "nm -X64 $libpath/$icu_full_ver_lib 2>/dev/null | head -n 1 | wc -l"` - else if ( "zos" == "$arch" ) then - set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$majmin$icu_ext 2>/dev/null" | awk '{print $NF}'` - set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "amode=64" | wc -l"` - endif - # Make sure both GTM and ICU are in sync with object mode compatibility (eg both are 32 bit/64 bit) - if ( ( "$is64bit_gtm" == 1 ) && ( "$is64bit_icu" != 0 ) ) then - set found_icu = 1 - else if ( ( "$is64bit_gtm" != 1 ) && ( "$is64bit_icu" == 0 ) ) then - set found_icu = 1 - else - set found_icu = 0 - endif - if ( "$found_icu" == 1 && "$majmin" >= 36 ) then - set save_icu_libpath = $libpath - set majorver = `expr $majmin / 10` - set minorver = `expr $majmin % 10` - setenv gtm_icu_version "$majorver.$minorver" - break - endif - endif -end -set msg2 = `ls -al * | grep -v \> | grep w- | wc -l` -@ msg2 = $msg2 - 8 -if ( $msg2 ) then - echo "Number of writeable lines = $msg2" >>&! gtm_test_install.out -endif - -setenv gtm_dist . - -gtm << EOF >>&! gtm_test_install.out -write \$zchset -EOF - -setenv gtm_dist utf8 - -if ( -d utf8) then - setenv LD_LIBRARY_PATH $libpath - setenv LIBPATH $libpath - setenv gtm_chset utf-8 - set utflocale = `locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1` - if ( "OS/390" == `uname` ) then - setenv gtm_chset_locale $utflocale - else - setenv LC_ALL $utflocale - endif - -gtm << EOF >>&! gtm_test_install.out -write \$zchset -EOF - - setenv gtm_dist $save_gtm_dist/utf8 - setenv gtmroutines ". $save_gtm_dist/utf8" - - mkdir test_gtm_utf8 - cd test_gtm_utf8 - cp ../test_gtm/sim.m . - - # set to test directory - setenv gtmdir $save_gtm_dist/test_gtm_utf8 - # make gtm set the utf locale - unsetenv LC_CTYPE - ../gtm -r sim >& gtm.out - # get $ZCHSET - echo "" >>&! $save_gtm_dist/gtm_test_install.out - grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out - # get journal output - cd V*/g - - $save_gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out - (setenv gtmgbldir $save_gtm_dist/test_gtm/mumps.gld; $save_gtm_dist/mupip integ -reg "*" >& integ.out) - # output the change lines - echo "" >>&! $save_gtm_dist/gtm_test_install.out - echo "Global changes in the gtm.mjl file:" >>&! $save_gtm_dist/gtm_test_install.out - grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $save_gtm_dist/gtm_test_install.out - cat integ.out >>&! $save_gtm_dist/gtm_test_install.out - cd $save_gtm_dist - -else - -cat <>&! gtm_test_install.out - -GTM> -UTF-8 -GTM> - -ZCHSET= UTF-8 - -Global changes in the gtm.mjl file: -^a="1" -^b="2" - - -Integ of region DEFAULT - -No errors detected by integ. - -Type Blocks Records % Used Adjacent - -Directory 2 3 0.756 NA -Index 2 2 0.585 2 -Data 2 2 0.585 2 -Free 4994 NA NA NA -Total 5000 7 NA 4 -EOF -endif - -# strip off the copyright lines -tail -n +11 $gtm_tools/gtm_test_install.txt > gtm_test_install.txt -# remove white space at end of created output so it looks like version after ftpput is run -echo ':%s/[ ][ ]*$//g :wall\! :q ' | vim -n gtm_test_install.out >& /dev/null - -\diff gtm_test_install.txt gtm_test_install.out >& /dev/null -if ($status) then - echo "---------" - echo "GTM_TEST_INSTALL-E-ERROR the output is not as expected." - \diff gtm_test_install.txt gtm_test_install.out - set exitstat = 1 - echo "---------" -else - echo "The test succeeded, the output is in "`pwd`/gtm_test_install.out - set exitstat = 0 -endif - -echo "------------------------------------------------------------------------" -exit $exitstat +#!/usr/local/bin/tcsh +################################################################# +# # +# Copyright 2011, 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. # +# # +################################################################# +echo "" +echo "------------------------------------------------------------------------" +set arch = `grep arch $gtm_ver/pro/arch.gtc | awk -F= '{print $2}' | tr -d '\"'` +cd $1 +# Source the installed GT.M's configuration +source ./gtmcshrc +setenv gtmgbldir mumps.gld +gde exit +mupip create +gtm << \EOF >&! gtm_test_install.out +set ^X=1 +set x=2 +write $ORDER(^%),! +zwrite +zwrite ^X +halt +\EOF +gtm << EOF >>&! gtm_test_install.out +zhelp + +zwrite ^X +halt +EOF + + +mkdir test_gtm +cd test_gtm + +# create sim.m +cat > sim.m <>&! $save_gtm_dist/gtm_test_install.out +grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out + +#get version number + +setenv gtmver `ls -d V*` + +# get journal output +cd $gtmver/g + +setenv gtm_dist $save_gtm_dist + +$gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out +env gtmgbldir=$gtm_dist/test_gtm/mumps.gld $gtm_dist/mupip integ -reg "*" >& integ.out +# output the change lines +echo "" >>&! $gtm_dist/gtm_test_install.out +echo "Global changes in the gtm.mjl file:" >>&! $gtm_dist/gtm_test_install.out +grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $gtm_dist/gtm_test_install.out +cat integ.out >>&! $gtm_dist/gtm_test_install.out + +cd $gtm_dist + +# keep the utf8 libicu search code below in synch with configure.gtc! + +set is64bit_gtm = `file mumps | grep 64 | wc -l` + +# please keep in sync with sr_unix/set_library_path.csh +if ( $is64bit_gtm == 1 ) then + set library_path = "/usr/local/lib64 /usr/local/lib /usr/lib64 /usr/lib/x86_64-linux-gnu /usr/lib" +else + set library_path = " /usr/local/lib /usr/lib32 /usr/lib/i386-linux-gnu /usr/lib" +endif + +set is64bit_icu = 0 +# Set the appropriate extensions for ICU libraries depending on the platforms +set icu_ext = ".so" +if ( $arch == "ibm" ) then + set icu_ext = ".a" +else if ( $arch == "hp" ) then + set icu_ext = ".sl" +endif + +# Check the presence of gtm_icu_version +set gtm_icu_version_set = "FALSE" +if ($?gtm_icu_version) then + if ("" != $gtm_icu_version) then + set gtm_icu_version_set = "TRUE" + endif +endif + +foreach libpath ($library_path) + set icu_lib_found = 0 + if ( "FALSE" == "$gtm_icu_version_set" && ( -f "$libpath/libicuio$icu_ext" ) ) then + set icu_lib_found = 1 + # Find the actual version'ed library to which libicuio.{so,sl,a} points to + set icu_versioned_lib = `ls -l $libpath/libicuio$icu_ext | awk '{print $NF}'` + # Find out vital parameters + if ( "$arch" == "ibm" || "$arch" == "zos" ) then + # From the version'ed library(eg. libicuio36.0.a) extract out + # 36.0.a + set full_icu_ver_string = `echo $icu_versioned_lib | sed 's/libicuio//g'` + # Extract 36 from 36.0.a + set majmin=`echo $full_icu_ver_string | cut -f 1 -d '.'` + else + set full_icu_ver_string=`echo $icu_versioned_lib | sed 's/libicuio\.//g'` + set majmin=`echo $full_icu_ver_string | cut -f 2 -d '.'` + endif + else if ( "TRUE" == "$gtm_icu_version_set" ) then + set majmin = `echo $gtm_icu_version | sed 's/\.//'` + if ( -f "$libpath/libicuio$majmin$icu_ext" || -f "$libpath/libicuio$icu_ext.$majmin" ) then + set icu_lib_found = 1 + else + set icu_lib_found = 0 + endif + + endif + if ( $icu_lib_found ) then + # Figure out the object mode(64 bit or 32 bit) of ICU libraries on the target machine + if ( "linux" == "$arch" || "sun" == "$arch" || "solaris" == $arch ) then + set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$icu_ext.$majmin 2>/dev/null" | awk '{print $NF}'` + set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "64-bit" | wc -l"` + else if ( "hp" == "$arch" ) then + set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$icu_ext.$majmin 2>/dev/null" | awk '{print $NF}'` + set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "IA64" | wc -l"` + else if ( "ibm" == "$arch" ) then + set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$majmin$icu_ext 2>/dev/null" | awk '{print $NF}'` + set is64bit_icu = `sh -c "nm -X64 $libpath/$icu_full_ver_lib 2>/dev/null | head -n 1 | wc -l"` + else if ( "zos" == "$arch" ) then + set icu_full_ver_lib = `sh -c "ls -l $libpath/libicuio$majmin$icu_ext 2>/dev/null" | awk '{print $NF}'` + set is64bit_icu = `sh -c "file $libpath/$icu_full_ver_lib 2>/dev/null | grep "amode=64" | wc -l"` + endif + # Make sure both GTM and ICU are in sync with object mode compatibility (eg both are 32 bit/64 bit) + if ( ( "$is64bit_gtm" == 1 ) && ( "$is64bit_icu" != 0 ) ) then + set found_icu = 1 + else if ( ( "$is64bit_gtm" != 1 ) && ( "$is64bit_icu" == 0 ) ) then + set found_icu = 1 + else + set found_icu = 0 + endif + if ( "$found_icu" == 1 && "$majmin" >= 36 ) then + set save_icu_libpath = $libpath + set majorver = `expr $majmin / 10` + set minorver = `expr $majmin % 10` + setenv gtm_icu_version "$majorver.$minorver" + break + endif + endif +end +# No files are supposed to have write permissions enabled. However part of the kit install +# test leaves a few files writeable. The list of known writeable files is: +# .: +# -rw-r--r-- 1 root root 1387 Jul 10 11:54 gtm_test_install.out +# -rw-rw-rw- 1 root root 366080 Jul 10 11:54 mumps.dat +# -rw-r--r-- 1 root root 1536 Jul 10 11:54 mumps.gld +# test_gtm: +# -rw-r--r-- 1 root root 670 Jul 10 11:54 gtm.out +# -rw-r--r-- 1 root root 1536 Jul 10 11:54 mumps.gld +# -rw-r--r-- 1 root root 88 Jul 10 11:54 sim.m +# -rw-r--r-- 1 root root 869 Jul 10 11:54 sim.o +set msg2 = `ls -al * | grep -v \> | grep w- | wc -l` +@ msg2 = $msg2 - 7 +if ( $msg2 ) then + echo "Number of writeable lines = $msg2" >>&! gtm_test_install.out + ls -al * | grep -v \> | grep w- >>&! gtm_test_install.out +endif + +setenv gtm_dist . + +gtm << EOF >>&! gtm_test_install.out +write \$zchset +EOF + +setenv gtm_dist utf8 + +if ( -d utf8) then + setenv LD_LIBRARY_PATH $libpath + setenv LIBPATH $libpath + setenv gtm_chset utf-8 + set utflocale = `locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1` + if ( "OS/390" == `uname` ) then + setenv gtm_chset_locale $utflocale + else + setenv LC_ALL $utflocale + endif + +gtm << EOF >>&! gtm_test_install.out +write \$zchset +EOF + + setenv gtm_dist $save_gtm_dist/utf8 + setenv gtmroutines ". $save_gtm_dist/utf8" + + mkdir test_gtm_utf8 + cd test_gtm_utf8 + cp ../test_gtm/sim.m . + + # set to test directory + setenv gtmdir $save_gtm_dist/test_gtm_utf8 + # make gtm set the utf locale + unsetenv LC_CTYPE + ../gtm -r sim >& gtm.out + + # get $ZCHSET + echo "" >>&! $save_gtm_dist/gtm_test_install.out + grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out + # test gtmsecshr with an alternate user + set XCMD='do ^GTMHELP("",$ztrnlnm("gtm_dist")_"/gtmhelp.gld")' + su - gtmtest1 -c "env LD_LIBRARY_PATH=$libpath LC_ALL=$LC_ALL gtm_chset=UTF-8 gtm_dist=$gtm_dist gtmroutines='$gtmroutines' $gtm_dist/mumps -run %XCMD '${XCMD:q}' < /dev/null" > gtmtest.out #BYPASSOK line length + # if we see the 'Topic? ' prompt, all is well + grep -q '^Topic. $' gtmtest.out + if ( $status ) cat gtmtest.out >>&! $save_gtm_dist/gtm_test_install.out + # get journal output + cd V*/g + + $save_gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out + env gtmgbldir=$save_gtm_dist/test_gtm/mumps.gld $save_gtm_dist/mupip integ -reg "*" >& integ.out + + # output the change lines + echo "" >>&! $save_gtm_dist/gtm_test_install.out + echo "Global changes in the gtm.mjl file:" >>&! $save_gtm_dist/gtm_test_install.out + awk -F\\ '/=/{print ($NF)}' gtm.mjf >>&! $save_gtm_dist/gtm_test_install.out + cat integ.out >>&! $save_gtm_dist/gtm_test_install.out + $gtm_dist/gtmsecshr >>&! $save_gtm_dist/gtm_test_install.out + cd $save_gtm_dist + +else + # BEGIN - Fake the UTF-8 mode run for platforms that don't support it +cat <>&! gtm_test_install.out + +GTM> +UTF-8 +GTM> + +ZCHSET= UTF-8 + +Global changes in the gtm.mjl file: +^a="1" +^b="2" + + +Integ of region DEFAULT + +No errors detected by integ. + +Type Blocks Records % Used Adjacent + +Directory 2 3 0.756 NA +Index 2 2 0.585 2 +Data 2 2 0.585 2 +Free 4994 NA NA NA +Total 5000 7 NA 4 +EOF + # END - Fake the UTF-8 mode run for platforms that don't support it +endif + +# strip off the copyright lines +tail -n +11 $gtm_tools/gtm_test_install.txt > gtm_test_install.txt +# remove white space at end of created output so it looks like version after ftpput is run +echo ':%s/[ ][ ]*$//g :wall\! :q ' | vim -n gtm_test_install.out >& /dev/null + +\diff gtm_test_install.txt gtm_test_install.out >& /dev/null +if ($status) then + echo "---------" + echo "GTM_TEST_INSTALL-E-ERROR the output is not as expected." + \diff gtm_test_install.txt gtm_test_install.out + set exitstat = 1 + echo "---------" +else + echo "The test succeeded, the output is in "`pwd`/gtm_test_install.out + set exitstat = 0 +endif + +echo "------------------------------------------------------------------------" +exit $exitstat diff --git a/sr_unix/gtm_text_alloc.c b/sr_unix/gtm_text_alloc.c index aa36d3a..1d218e6 100644 --- a/sr_unix/gtm_text_alloc.c +++ b/sr_unix/gtm_text_alloc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2007, 2012 Fidelity Information Services, Inc * + * Copyright 2007, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,14 +10,14 @@ ****************************************************************/ /* Storage manager for mmap() allocated storage used for executable code. - Uses power-of-two "buddy" system as described by Knuth. Allocations up to - size - SIZEOF(header) are managed by the buddy system. Larger - sizes are only "tracked" and then released via munmap() when they are freed. - - The algorithms used in this module are very similar to those used in - gtm_malloc.c with some changes and fewer of the generation options - since this is a more special purpose type allocation mechanism. -*/ + * Uses power-of-two "buddy" system as described by Knuth. Allocations up to + * size - SIZEOF(header) are managed by the buddy system. Larger + * sizes are only "tracked" and then released via munmap() when they are freed. + * + * The algorithms used in this module are very similar to those used in + * gtm_malloc.c with some changes and fewer of the generation options + * since this is a more special purpose type allocation mechanism. + */ #include "mdef.h" @@ -45,30 +45,32 @@ GBLREF int process_exiting; /* Process is on it's way out */ GBLREF volatile int4 fast_lock_count; /* Stop stale/epoch processing while we have our parts exposed */ GBLREF uint4 gtmDebugLevel; +GBLREF size_t gtm_max_storalloc; /* Max value for $ZREALSTOR or else memory error is raised */ OS_PAGE_SIZE_DECLARE #ifdef COMP_GTA /* Only build this routine if it is going to be called */ /* This module is built in two different ways: (1) For z/OS the allocation and free routines will just call - __malloc31() and free() respectively since mmap() on z/OS does not support the necessary features as of this - writing (12/2008). (2) For all other platforms that use this module (Linux and Tru64 builds currently), the - module will expand with the mmap code. [SE 12/2008] -*/ + * __malloc31() and free() respectively since mmap() on z/OS does not support the necessary features as of this + * writing (12/2008). (2) For all other platforms that use this module (Linux and Tru64 builds currently), the + * module will expand with the mmap code. [SE 12/2008] + */ /* The MAXTWO is set to pagesize and MINTWO to 5 sizes below that. Our systems have page - sizes of 16K, 8K, and 4K. -*/ + * sizes of 16K, 8K, and 4K. + */ #define MAXTWO gtm_os_page_size #define MINTWO TwoTable[0] /* Computed by gtaSmInit() */ #define MAXINDEX 5 /* Fields to help instrument our algorithm */ -GBLREF ssize_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */ -GBLREF ssize_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */ -GBLREF ssize_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */ +GBLREF size_t totalRmalloc; /* Total storage allocated through malloc() */ +GBLREF size_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */ +GBLREF size_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */ +GBLREF size_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */ static int totalAllocs; /* Total alloc requests */ static int totalFrees; /* Total free requests */ -static ssize_t rAllocMax; /* Maximum value of totalRalloc */ +static size_t rAllocMax; /* Maximum value of totalRallocGta */ static int allocCnt[MAXINDEX + 2]; /* Alloc count satisfied by each queue size */ static int freeCnt[MAXINDEX + 2]; /* Free count for element in each queue size */ static int elemSplits[MAXINDEX + 2]; /* Times a given queue size block was split */ @@ -110,19 +112,19 @@ static uint4 TwoTable[MAXINDEX + 2]; #include "obj_file.h" /* This function is meant as a temporary replacement for the gtm_text_alloc code that uses mmap. - ABS 2008/12 - It is deficient in two regards: - 1) It abuses textElem - the abuse stems from account needs. It was hoped that we could simply - abuse textElem to hold the actual length of memory allocated and then use the size of textElem - as the offset to the original start of memory address that was malloc'ed. However, the - userStart of memory needs to be SECTION_ALIGN_BOUNDARY byte aligned. - action: don't use textElem - 2) SECTION_ALIGN_BOUNDARY is 16 bytes in 64bit world. Since __malloc31 is returning 8 byte - aligned memory, we really only needed a pad of 8 bytes. But that left no real mechanism to - return to the original start of memory. So we have a pad of 24 bytes. The first 8 bytes point - back to the start of memory. If the next 8 bytes are 16 byte aligned that is returned to the - caller. If not, then we store the start of memory there and return the next 8 bytes. This allows - us to free() the correct address. - action: remove SECTION_ALIGN_BOUNDARY as a restriction for all 64bit platforms except IA64 + * ABS 2008/12 - It is deficient in two regards: + * 1) It abuses textElem - the abuse stems from account needs. It was hoped that we could simply + * abuse textElem to hold the actual length of memory allocated and then use the size of textElem + * as the offset to the original start of memory address that was malloc'ed. However, the + * userStart of memory needs to be SECTION_ALIGN_BOUNDARY byte aligned. + * action: don't use textElem + * 2) SECTION_ALIGN_BOUNDARY is 16 bytes in 64bit world. Since __malloc31 is returning 8 byte + * aligned memory, we really only needed a pad of 8 bytes. But that left no real mechanism to + * return to the original start of memory. So we have a pad of 24 bytes. The first 8 bytes point + * back to the start of memory. If the next 8 bytes are 16 byte aligned that is returned to the + * caller. If not, then we store the start of memory there and return the next 8 bytes. This allows + * us to free() the correct address. + * action: remove SECTION_ALIGN_BOUNDARY as a restriction for all 64bit platforms except IA64 */ void *gtm_text_alloc(size_t size) { @@ -150,21 +152,19 @@ void *gtm_text_alloc(size_t size) INCR_SUM(totalAllocGta, tSize); INCR_SUM(totalUsedGta, tSize); INCR_CNTR(totalAllocs); - SET_MAX(rAllocMax, totalUsedGta); + SET_MAX(rAllocMax, totalRallocGta); TRACE_TXTALLOC(aligned, tSize); return (void *)aligned; } - save_errno = errno; if (ENOMEM == save_errno) { assert(FALSE); - rts_error(VARLSTCNT(5) ERR_MEMORY, 2, tSize, CALLERID, save_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, tSize, CALLERID, save_errno); } /* On non-allocate related error, give more general error and GTMASSERT */ - gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("gtm_text_alloc()"), CALLFROM, - save_errno, 0, - ERR_TEXT, 3, LEN_AND_LIT("Storage call made from"), CALLERID); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("gtm_text_alloc()"), CALLFROM, + save_errno, 0, ERR_TEXT, 3, LEN_AND_LIT("Storage call made from"), CALLERID); GTMASSERT; } @@ -195,6 +195,12 @@ void gtm_text_free(void *addr) # define TEXT_ALLOC(rsize, addr) \ { \ int save_errno; \ + if ((0 < gtm_max_storalloc) && ((rsize + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \ + { /* Boundary check for $gtm_max_storalloc (if set) */ \ + --gtaSmDepth; \ + --fast_lock_count; \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, ERR_MALLOCMAXUNIX); \ + } \ addr = mmap(NULL, rsize, (PROT_READ + PROT_WRITE + PROT_EXEC), (MAP_PRIVATE + MAP_ANONYMOUS), -1, 0); \ if (MAP_FAILED == addr) \ { \ @@ -204,12 +210,11 @@ void gtm_text_free(void *addr) if (ENOMEM == save_errno) \ { \ assert(FALSE); \ - rts_error(VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, save_errno); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, save_errno); \ } \ /* On non-allocate related error, give more general error and GTMASSERT */ \ - gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, \ - save_errno, 0, \ - ERR_CALLERID, 3, LEN_AND_LIT("TEXT_ALLOC"), CALLERID); \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, \ + save_errno, 0, ERR_CALLERID, 3, LEN_AND_LIT("TEXT_ALLOC"), CALLERID); \ GTMASSERT; \ } \ } @@ -222,18 +227,17 @@ void gtm_text_free(void *addr) --gtaSmDepth; \ --fast_lock_count; \ save_errno = errno; \ - gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("munmap"), CALLFROM, \ - save_errno, 0, \ - ERR_CALLERID, 3, LEN_AND_LIT("TEXT_FREE"), CALLERID); \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("munmap"), CALLFROM, \ + save_errno, 0, ERR_CALLERID, 3, LEN_AND_LIT("TEXT_FREE"), CALLERID); \ GTMASSERT; \ } \ } - #define STE_FP(p) p->userStorage.links.fPtr #define STE_BP(p) p->userStorage.links.bPtr /* Following are values used in queueIndex in a storage element. Note that both - values must be less than zero for the current code to function correctly. */ + * values must be less than zero for the current code to function correctly. + */ #define QUEUE_ANCHOR -1 #define REAL_ALLOC -2 @@ -244,7 +248,8 @@ void gtm_text_free(void *addr) #endif /* Define "routines" to enqueue and dequeue storage elements. Use define so we don't - have to depend on each implementation's compiler inlining to get efficient code here */ + * have to depend on each implementation's compiler inlining to get efficient code here. + */ #define ENQUEUE_STOR_ELEM(idx, elem) \ { \ textElem *qHdr, *fElem; \ @@ -284,7 +289,7 @@ GBLREF readonly struct static uint4 TwoTable[MAXINDEX + 2]; static textElem freeStorElemQs[MAXINDEX + 1]; /* Need full element as queue anchor for dbl-linked - list since ptrs not at top of element */ + * list since ptrs not at top of element */ static volatile int4 gtaSmDepth; /* If we get nested... */ static boolean_t gtaSmInitialized; /* Initialized indicator */ @@ -300,17 +305,19 @@ error_def(ERR_SYSCALL); error_def(ERR_MEMORYRECURSIVE); error_def(ERR_CALLERID); error_def(ERR_TEXT); +error_def(ERR_MALLOCMAXUNIX); /* Initialize the storage manangement system. Things to initialize: - - - Initialize size2Index table. This table is used to convert a malloc request size - to a storage queue index. - - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we - build a circular queue. This allows elements to be added and removed without - end-of-queue special casing. The queue anchor element is easily recognized because - it's queue index size will be set to a special value. - - Initialize debug mode. See if gtm_debug_level environment variable is set and - retrieve it's value if yes. */ + * + * - Initialize size2Index table. This table is used to convert a malloc request size + * to a storage queue index. + * - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we + * build a circular queue. This allows elements to be added and removed without + * end-of-queue special casing. The queue anchor element is easily recognized because + * it's queue index size will be set to a special value. + * - Initialize debug mode. See if gtm_debug_level environment variable is set and + * retrieve it's value if yes. + */ void gtaSmInit(void) { char *ascNum; @@ -318,11 +325,10 @@ void gtaSmInit(void) int i, sizeIndex, twoSize; /* WARNING!! Since this is early initialization, the assert(s) below are not well behaved if they do - indeed trip. The best that can be hoped for is they give a condition handler exhausted error on - GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices - are setup nor (potentially) most of the GTM runtime. - */ - + * indeed trip. The best that can be hoped for is they give a condition handler exhausted error on + * GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices + * are setup nor (potentially) most of the GTM runtime. + */ /* Initialize the TwoTable fields for our given page size */ TwoTable[MAXINDEX + 1] = 0xFFFFFFFF; for (sizeIndex = MAXINDEX, twoSize = gtm_os_page_size; 0 <= sizeIndex; --sizeIndex, twoSize >>= 1) @@ -331,7 +337,6 @@ void gtaSmInit(void) TwoTable[sizeIndex] = twoSize; assert(TwoTable[sizeIndex] < TwoTable[sizeIndex + 1]); } - /* Need to initialize the fwd/bck ptrs in the anchors to point to themselves */ for (uStor = &freeStorElemQs[0], i = 0; i <= MAXINDEX; ++i, ++uStor) { @@ -342,12 +347,13 @@ void gtaSmInit(void) } /* Recursive routine used to obtain an element on a given size queue. If no - elements of that size are available, we recursively call ourselves to get - an element of the next larger queue which we will then split in half to - get the one we need and place the remainder back on the free queue of its - new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of - storage, carve it up into the largest block size we handle and process as - before. */ + * elements of that size are available, we recursively call ourselves to get + * an element of the next larger queue which we will then split in half to + * get the one we need and place the remainder back on the free queue of its + * new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of + * storage, carve it up into the largest block size we handle and process as + * before. + */ textElem *gtaFindStorElem(int sizeIndex) { unsigned char *uStorAlloc; @@ -381,9 +387,7 @@ textElem *gtaFindStorElem(int sizeIndex) uStor->state = TextFree; sizeIndex = MAXINDEX; } - assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); - uStor->queueIndex = sizeIndex; /* This is now a smaller block */ return uStor; } @@ -396,12 +400,11 @@ int getSizeIndex(size_t size) testSize = MAXTWO; sizeIndex = MAXINDEX; - /* Theory here is to hunt for first significant bit. Then if there is more to the word, bump back - to previous queue size. Note that in the following loop, the sizeIndex can go negative if the - value of size is less than MINTWO (which is queue index 0) but since we guarantee there will be a - remainder, we will increment back to 0. */ - + * to previous queue size. Note that in the following loop, the sizeIndex can go negative if the + * value of size is less than MINTWO (which is queue index 0) but since we guarantee there will be a + * remainder, we will increment back to 0. + */ while (0 == (testSize & size)) { --sizeIndex; /* Try next smaller queue */ @@ -410,10 +413,8 @@ int getSizeIndex(size_t size) else /* Else leave loop with last valid testSize */ break; } - if (0 != (size & (testSize - 1))) /* Is there a remainder? */ ++sizeIndex; /* .. if yes, round up a size */ - return sizeIndex; } @@ -427,7 +428,8 @@ void *gtm_text_alloc(size_t size) boolean_t reentered; /* Note that this if is also structured for maximum fallthru. The else will - be near the end of this entry point */ + * be near the end of this entry point. + */ if (gtaSmInitialized) { hdrSize = OFFSETOF(textElem, userStorage); /* Size of textElem header */ @@ -442,7 +444,7 @@ void *gtm_text_alloc(size_t size) { --gtaSmDepth; assert(FALSE); - rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } INCR_CNTR(totalAllocs); if (0 != size) @@ -495,17 +497,14 @@ void gtm_text_free(void *addr) return; if (!gtaSmInitialized) /* Storage must be init'd before can free anything */ GTMASSERT; - ++fast_lock_count; ++gtaSmDepth; /* Recursion indicator */ - if (1 < gtaSmDepth) { --gtaSmDepth; assert(FALSE); - rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } - INCR_CNTR(totalFrees); if ((unsigned char *)addr != &NullStruct.nullStr[0]) { @@ -561,10 +560,10 @@ void gtm_text_free(void *addr) #endif /* not __MVS__ */ /* Routine to print the end-of-process info -- either allocation statistics or malloc trace dump. - Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one - time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily - be changed to use util_out_print instead of FPRINTF -*/ + * Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one + * time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily + * be changed to use util_out_print instead of FPRINTF + */ void printAllocInfo(void) { textElem *eHdr, *uStor; diff --git a/sr_unix/gtm_trigger.c b/sr_unix/gtm_trigger.c index 696d4f1..1856e63 100644 --- a/sr_unix/gtm_trigger.c +++ b/sr_unix/gtm_trigger.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,6 +19,7 @@ #include +#include "cmd_qlf.h" #include "compiler.h" #include "error.h" #include @@ -299,6 +300,10 @@ STATICFNDEF int gtm_trigger_invoke(void) REVERT; assert(frame_pointer->type & SFT_TRIGR); assert(0 <= gtm_trigger_depth); + CHECKHIGHBOUND(ctxt); + CHECKLOWBOUND(ctxt); + CHECKHIGHBOUND(active_ch); + CHECKLOWBOUND(active_ch); return rc; } @@ -450,7 +455,7 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink) mv_chain->mv_st_cont.mvs_msav.v = dollar_zsource; mv_chain->mv_st_cont.mvs_msav.addr = &dollar_zsource; TREF(trigger_compile) = TRUE; /* Set flag so compiler knows this is a special trigger compile */ - op_zcompile(&zcompprm, FALSE); /* Compile but don't require a .m file extension */ + 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)) { /* Someone err'd.. */ @@ -538,7 +543,8 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm) { /* Create new trigger base frame first that back-stops stack unrolling and return to us */ if (GTM_TRIGGER_DEPTH_MAX < (gtm_trigger_depth + 1)) /* Verify we won't nest too deep */ rts_error(VARLSTCNT(3) ERR_MAXTRIGNEST, 1, GTM_TRIGGER_DEPTH_MAX); - DBGTRIGR((stderr, "gtm_trigger: PUSH: frame_pointer 0x%016lx ctxt value: 0x%016lx\n", frame_pointer, ctxt)); + DBGTRIGR((stderr, "gtm_trigger: Invoking new trigger at frame_pointer 0x%016lx ctxt value: 0x%016lx\n", + frame_pointer, ctxt)); /* Protect against interrupts while we have only a trigger base frame on the stack */ DEFER_INTERRUPTS(INTRPT_IN_TRIGGER_NOMANS_LAND); /* The current frame invoked a trigger. We cannot return to it for a TP restart or other reason unless @@ -547,8 +553,8 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm) * command (KILL, SET or ZTRIGGER) was entered. Set flag in the frame to prevent MUM_TSTART unless the frame gets * reset. */ - frame_pointer->flags |= SFF_TRIGR_CALLD; /* Do not return to this frame via MUM_TSTART */ - DBGTRIGR((stderr, "gtm_trigger: Setting SFF_TRIGR_CALLD in frame 0x"lvaddr"\n", frame_pointer)); + frame_pointer->flags |= SFF_IMPLTSTART_CALLD; /* Do not return to this frame via MUM_TSTART */ + DBGTRIGR((stderr, "gtm_trigger: Setting SFF_IMPLTSTART_CALLD in frame 0x"lvaddr"\n", frame_pointer)); base_frame(trigdsc->rtn_desc.rt_adr); /* Finish base frame initialization - reset mpc/context to return to us without unwinding base frame */ frame_pointer->type |= SFT_TRIGR; @@ -616,8 +622,17 @@ 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 - assert(((0 == gtm_trigger_depth) && (ch_at_trigger_init == ctxt->ch)) - || ((0 < gtm_trigger_depth) && (&mdb_condition_handler == ctxt->ch))); + /* 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. + */ + 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))))))); 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) @@ -736,6 +751,12 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm) { /* Unwind a trigger level to restart level or to next trigger boundary */ gtm_trigger_fini(FALSE, FALSE); /* Get rid of this trigger level - we won't be returning */ DBGTRIGR((stderr, "gtm_trigger: dm_start returned rethrow code - rethrowing ERR_TPRETRY\n")); + /* The bottommost mdb_condition handler better not be catching this restart if we did an implicit + * tstart. mdb_condition_handler will try to unwind further, and the process will inadvertently exit. + */ + assert((&mdb_condition_handler != ch_at_trigger_init) + || ((&mdb_condition_handler == ctxt->ch) && (&mdb_condition_handler == chnd[1].ch) + && (!tp_pointer->implicit_tstart || (&chnd[1] < ctxt)))); INVOKE_RESTART; } else { /* It is possible we are restarting a transaction that never got around to creating a base @@ -751,9 +772,9 @@ int gtm_trigger(gv_trigger_t *trigdsc, gtm_trigger_parms *trigprm) { /* Unusual case of trigger that died in no-mans-land before trigger base frame established. * Remove the "do not return to me" flag only on non-error unwinds */ assert(tp_pointer->implicit_tstart); - assert(SFF_TRIGR_CALLD & frame_pointer->flags); - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; - DBGTRIGR((stderr, "gtm_trigger: turning off SFF_TRIGR_CALLD (1) in frame 0x"lvaddr"\n", + assert(SFF_IMPLTSTART_CALLD & frame_pointer->flags); + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; + DBGTRIGR((stderr, "gtm_trigger: turning off SFF_IMPLTSTART_CALLD (1) in frame 0x"lvaddr"\n", frame_pointer)); DBGTRIGR((stderr, "gtm_trigger: unwinding no-base-frame trigger for TP restart\n")); } @@ -799,15 +820,15 @@ void gtm_trigger_fini(boolean_t forced_unwind, boolean_t fromzgoto) /* Unwind the trigger base frame */ op_unwind(); /* restore frame_pointer stored at msp (see base_frame.c) */ - frame_pointer = *(stack_frame**)msp; - msp += SIZEOF(stack_frame *); /* Remove frame save pointer from stack */ + frame_pointer = *(stack_frame**)msp; + msp += SIZEOF(stack_frame *); /* Remove frame save pointer from stack */ if (!forced_unwind) { /* Remove the "do not return to me" flag only on non-error unwinds. Note this flag may have already been * turned off by an earlier tp_restart if this is not an implicit_tstart situation. */ - assert(!tp_pointer->implicit_tstart || (SFF_TRIGR_CALLD & frame_pointer->flags)); - frame_pointer->flags &= SFF_TRIGR_CALLD_OFF; - DBGTRIGR((stderr, "gtm_trigger_fini: turning off SFF_TRIGR_CALLD (2) in frame 0x"lvaddr"\n", frame_pointer)); + assert(!tp_pointer->implicit_tstart || (SFF_IMPLTSTART_CALLD & frame_pointer->flags)); + frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; + DBGTRIGR((stderr, "gtm_trigger_fini: turning off SFF_IMPLTSTART_CALLD (2) in frame 0x"lvaddr"\n", frame_pointer)); } else { /* Error unwind, make sure certain cleanups are done */ # ifdef DEBUG @@ -828,7 +849,8 @@ void gtm_trigger_fini(boolean_t forced_unwind, boolean_t fromzgoto) OP_TROLLBACK(-1); /* We just unrolled the implicitly started TSTART so unroll what it did */ } } - DBGTRIGR((stderr, "gtm_trigger: POP: frame_pointer 0x%016lx ctxt value: 0x%016lx\n", frame_pointer, ctxt)); + DBGTRIGR((stderr, "gtm_trigger: Unwound to trigger invoking frame: frame_pointer 0x%016lx ctxt value: 0x%016lx\n", + frame_pointer, ctxt)); /* Re-allow interruptions now that our base frame is gone */ if (forced_unwind) { /* Since we are being force-unwound, we don't know the state of things except that it it should be either @@ -954,7 +976,7 @@ void gtm_trigger_cleanup(gv_trigger_t *trigdsc) stp_move((char *)rtnhdr->literal_text_adr, (char *)(rtnhdr->literal_text_adr + rtnhdr->literal_text_len)); GTM_TEXT_FREE(rtnhdr->ptext_adr); /* R/O releasable section */ - free(rtnhdr->literal_adr); /* R/W releasable section part 1 */ + free(RW_REL_START_ADR(rtnhdr)); /* R/W releasable section part 1 */ free(rtnhdr->linkage_adr); /* R/W releasable section part 2 */ free(rtnhdr->labtab_adr); /* Usually non-releasable but triggers don't have labels so * this is just cleaning up a dangling null malloc diff --git a/sr_unix/gtm_trigger_trc.h b/sr_unix/gtm_trigger_trc.h index def4235..c199339 100644 --- a/sr_unix/gtm_trigger_trc.h +++ b/sr_unix/gtm_trigger_trc.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,12 +16,15 @@ * gtm_trigger.h, these have been moved out to this supplemental header file with no * pre-reqs. * Debugging macros for triggers. In open code so are always defined (at least as null). - * Uncomment below define to enable debugging macros (and set GTM_TRIGGER of course) + * Uncomment below include and define to enable debugging macros (and set GTM_TRIGGER of course) */ +/* #include "have_crit.h" for DBGFPF/FFLUSH/INTRPT_IN_FFLUSH */ /* #define DEBUG_TRIGR */ #if defined(DEBUG_TRIGR) && defined(GTM_TRIGGER) # define DBGTRIGR(x) DBGFPF(x) # define DBGTRIGR_ONLY(x) x +# include "gtm_stdio.h" +# include "gtmio.h" #else # define DBGTRIGR(x) # define DBGTRIGR_ONLY(x) diff --git a/sr_unix/gtm_unlink_all.c b/sr_unix/gtm_unlink_all.c index 132f420..0b00753 100644 --- a/sr_unix/gtm_unlink_all.c +++ b/sr_unix/gtm_unlink_all.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011, 2012 Fidelity Information Services, Inc * + * Copyright 2011, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,6 +15,7 @@ #include "error_trap.h" #include "golevel.h" #include "cache.h" +#include "cmd_qlf.h" #include "hashtab.h" #include "hashtab_objcode.h" #include "hashtab_mname.h" @@ -95,7 +96,10 @@ void gtm_unlink_all(void) /* Step 3: re-Initialize $ECODE, $REFERENCE, and $TEST */ NULLIFY_DOLLAR_ECODE; /* Clears $ECODE and results returned for $STACK */ if (NULL != gv_currkey) - gv_currkey->end = 0; /* Clears $REFERENCE */ + { /* Clears $REFERENCE */ + gv_currkey->end = 0; + gv_currkey->base[0] = KEY_DELIMITER; + } dollar_truth = FALSE; /* aka $TEST */ /* Step 4: Remove all triggers */ # ifdef GTM_TRIGGER @@ -153,7 +157,7 @@ void gtm_unlink_all(void) if (NULL == rtnhdr->shlib_handle) /* We can only release this section if this is not a shared library */ GTM_TEXT_FREE(rtnhdr->ptext_adr); /* R/O releasable section */ - free(rtnhdr->literal_adr); /* R/W releasable section part 1 */ + free(RW_REL_START_ADR(rtnhdr)); /* R/W releasable section part 1 */ free(rtnhdr->linkage_adr); /* R/W releasable section part 2 */ free(rtnhdr->labtab_adr); /* Usually non-releasable but not in this case */ /* Run the chain of old (replaced) versions freeing them also */ diff --git a/sr_unix/gtmci.c b/sr_unix/gtmci.c index 9eb6b27..0f66971 100644 --- a/sr_unix/gtmci.c +++ b/sr_unix/gtmci.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,9 @@ #include #include "gtm_stdio.h" #include +#ifdef GTM_PTHREAD +# include +#endif #include "gtm_stdlib.h" #include "gtm_string.h" #include "cli.h" @@ -53,12 +56,17 @@ #ifdef UNICODE_SUPPORTED # include "gtm_icu_api.h" # include "gtm_utf8.h" +# include "gtm_conv.h" +GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ #endif #include "hashtab.h" #include "hashtab_str.h" #include "compiler.h" #include "gt_timer.h" #include "have_crit.h" +#include "callg.h" +#include "min_max.h" +#include "gtm_limits.h" GBLREF parmblk_struct *param_list; GBLREF stack_frame *frame_pointer; @@ -73,17 +81,79 @@ GBLREF mval dollar_zstatus; GBLREF unsigned char *fgncal_stack; GBLREF uint4 dollar_tlevel; GBLREF int process_exiting; +#ifdef GTM_PTHREAD +GBLREF boolean_t gtm_jvm_process; +GBLREF pthread_t gtm_main_thread_id; +GBLREF boolean_t gtm_main_thread_id_set; +#endif +GBLREF char gtm_dist[GTM_PATH_MAX]; GTMTRIG_DBG_ONLY(GBLREF ch_ret_type (*ch_at_trigger_init)();) +LITREF gtmImageName gtmImageNames[]; +error_def(ERR_ACTLSTTOOLONG); error_def(ERR_CALLINAFTERXIT); error_def(ERR_CIMAXLEVELS); error_def(ERR_CINOENTRY); error_def(ERR_CIRCALLNAME); error_def(ERR_CITPNESTED); error_def(ERR_INVGTMEXIT); +error_def(ERR_JOBLABOFF); error_def(ERR_MAXACTARG); error_def(ERR_MAXSTRLEN); +#define REVERT_AND_RETURN \ +{ \ + REVERT; /* gtmci_ch */ \ + TREF(in_gtmci) = FALSE; \ + return 0; \ +} + +/* When passing arguments from Java, ensure that the expected types match the actual ones. If not, + * use the arg_types array to pass back the information needed for a detailed error message. + */ +#define CHECK_FOR_TYPE_MISMATCH(INDEX, EXP_TYPE, ACT_TYPE) \ +{ \ + if (EXP_TYPE != ACT_TYPE) \ + { \ + arg_types[3] = ACT_TYPE; \ + arg_types[2] = EXP_TYPE; \ + arg_types[1] = INDEX; \ + arg_types[0] = -1; \ + REVERT_AND_RETURN; \ + } \ +} + +/* When passing arguments from Java, ensure that the either of the expected types matches the actual one. + * If not, use the arg_types array to pass back the information needed for a detailed error message. + */ +#define CHECK_FOR_TYPES_MISMATCH(INDEX, EXP_TYPE1, EXP_TYPE2, ACT_TYPE) \ +{ \ + if ((EXP_TYPE1 != ACT_TYPE) && (EXP_TYPE2 != ACT_TYPE)) \ + { \ + arg_types[4] = ACT_TYPE; \ + arg_types[3] = EXP_TYPE1; \ + arg_types[2] = EXP_TYPE2; \ + arg_types[1] = INDEX; \ + arg_types[0] = -1; \ + REVERT_AND_RETURN; \ + } \ +} + +/* When returning a typed value, ensure that the declared type matches the expected one. If not, + * use the arg_types array to pass back the information needed for a detailed error message. + */ +#define CHECK_FOR_RET_TYPE_MISMATCH(INDEX, EXP_TYPE, ACT_TYPE) \ +{ \ + if ((0 == INDEX) && (EXP_TYPE != ACT_TYPE)) \ + { \ + arg_types[3] = ACT_TYPE; \ + arg_types[2] = EXP_TYPE; \ + arg_types[1] = 0; \ + arg_types[0] = -1; \ + REVERT_AND_RETURN; \ + } \ +} + static callin_entry_list* get_entry(const char* call_name) { /* Lookup in a hashtable for entry corresponding to routine name */ ht_ent_str *callin_entry; @@ -98,6 +168,327 @@ static callin_entry_list* get_entry(const char* call_name) return (callin_entry ? callin_entry->value : NULL); } +int gtm_is_main_thread() +{ +# ifdef GTM_PTHREAD + if (!gtm_main_thread_id_set) + return -1; + if (pthread_equal(gtm_main_thread_id, pthread_self())) + return 1; + return 0; +# else + return -1; +# endif +} + +/* Java-specific version of call-in handler. */ +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) +{ + callin_entry_list *entry; + mstr label, routine; + int has_return, i, len; + rhdtyp *base_addr; + uint4 inp_mask, out_mask, mask; + mval arg_mval, *arg_ptr; + enum gtm_types arg_type; + gtm_string_t *mstr_parm; + parmblk_struct param_blk; + void op_extcall(), op_extexfun(), flush_pio(void); + volatile int *save_var_on_cstack_ptr; /* Volatile to match global var type */ + int status; + boolean_t added; + stringkey symkey; + ht_ent_str *syment; + intrpt_state_t old_intrpt_state; + char **arg_blob_ptr; + int *java_arg_type; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + set_blocksig(); + added = FALSE; + /* A prior invocation of gtm_exit would have set process_exiting = TRUE. Use this to disallow gtm_ci to be + * invoked after a gtm_exit + */ + if (process_exiting) + { + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); + return ERR_CALLINAFTERXIT; + } + TREF(in_gtmci) = TRUE; + if (!gtm_startup_active || !(frame_pointer->flags & SFF_CI)) + { + if ((status = gtm_init()) != 0) + { + TREF(in_gtmci) = FALSE; + return status; + } + } + GTM_PTHREAD_ONLY(assert(gtm_main_thread_id_set && pthread_equal(gtm_main_thread_id, pthread_self()))); + ESTABLISH_RET(gtmci_ch, mumps_status); + if (msp < fgncal_stack) /* Unwind all arguments left on the stack by previous gtm_cij. */ + fgncal_unwind(); + if (!c_rtn_name) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CIRCALLNAME); + if (!TREF(ci_table)) /* Load the call-in table only once from env variable GTMCI. */ + { + TREF(ci_table) = citab_parse(); + if (!TREF(callin_hashtab)) + { + TREF(callin_hashtab) = (hash_table_str *)malloc(SIZEOF(hash_table_str)); + (TREF(callin_hashtab))->base = NULL; + /* Need to initialize hash table. */ + init_hashtab_str(TREF(callin_hashtab), CALLIN_HASHTAB_SIZE, + HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE); + assert((TREF(callin_hashtab))->base); + } + for (entry = TREF(ci_table); NULL != entry; entry = entry->next_entry) + { /* Loop over the list and populate the hash table. */ + symkey.str.addr = entry->call_name.addr; + symkey.str.len = entry->call_name.len; + COMPUTE_HASH_STR(&symkey); + added = add_hashtab_str(TREF(callin_hashtab), &symkey, entry, &syment); + assert(added); + assert(syment->value == entry); + } + } + if (!(entry = get_entry(c_rtn_name))) /* c_rtn_name not found in the table. */ + 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)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF); + memset(¶m_blk, 0, SIZEOF(param_blk)); + param_blk.rtnaddr = (void *)base_addr; + /* lnr_entry below is a pointer to the code offset for this label from the + * beginning of text base(on USHBIN platforms) or from the beginning of routine + * header (on NON_USHBIN platforms). + * On NON_USHBIN platforms -- 2nd argument to EXTCALL is this pointer + * On USHBIN -- 2nd argument to EXTCALL is the pointer to this pointer (&lnr_entry) + */ + /* Assign the address for line number entry storage, so that the adjacent address holds has_parms value. */ + param_blk.labaddr = &(TREF(lab_proxy)).LABENT_LNR_OFFSET; + if (MAX_ACTUALS < entry->argcnt) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXACTARG); + if (entry->argcnt < count) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ACTLSTTOOLONG, 2, (int)label.len, label.addr); + param_blk.argcnt = count; + has_return = (gtm_void != entry->return_type); + if (has_return) + { /* Create mval slot for return value */ + MV_INIT(&arg_mval); + param_blk.retaddr = (void *)push_lvval(&arg_mval); + arg_blob_ptr = &arg_blob[0] + GTM64_ONLY(1) NON_GTM64_ONLY(2); + java_arg_type = arg_types + 1; + } else + { + param_blk.retaddr = 0; + arg_blob_ptr = &arg_blob[0]; + java_arg_type = arg_types; + } + inp_mask = entry->input_mask; + out_mask = entry->output_mask; + *io_vars_mask = out_mask; + if (*has_ret_value != has_return) + { + *has_ret_value = has_return; + REVERT_AND_RETURN; + } + *has_ret_value = has_return; + for (i = 0, mask = ~inp_mask; i < count; ++i, mask >>= 1, java_arg_type++, arg_blob_ptr += GTM64_ONLY(1) NON_GTM64_ONLY(2)) + { /* Copy the arguments' values into mval containers. Since some arguments might be declared as output-only, + * we need to go over all of them unconditionally, but only do the copying for the ones that are used for + * the input direction (I or IO). The integer values passed to CHECK_FOR_TYPE_MISMATCH as a second argument + * indicate the types to expect according to the call-in table definition, and are in correspondence with the + * constants declared in GTMContainerType class in gtmji.jar: 0 for GTMBoolean, 1 for GTMInteger, and so on. + */ + arg_mval.mvtype = MV_XZERO; + switch (entry->parms[i]) + { + case gtm_jboolean: + CHECK_FOR_TYPE_MISMATCH(i + 1, 0, *java_arg_type); + if (!(mask & 1)) + i2mval(&arg_mval, *(int *)arg_blob_ptr); + break; + case gtm_jint: + CHECK_FOR_TYPE_MISMATCH(i + 1, 1, *java_arg_type); + if (!(mask & 1)) + i2mval(&arg_mval, *(int *)arg_blob_ptr); + break; + case gtm_jlong: + CHECK_FOR_TYPE_MISMATCH(i + 1, 2, *java_arg_type); + if (!(mask & 1)) + i82mval(&arg_mval, *(gtm_int64_t *)arg_blob_ptr); + break; + case gtm_jfloat: + CHECK_FOR_TYPE_MISMATCH(i + 1, 3, *java_arg_type); + if (!(mask & 1)) + float2mval(&arg_mval, *(float *)arg_blob_ptr); + break; + case gtm_jdouble: + CHECK_FOR_TYPE_MISMATCH(i + 1, 4, *java_arg_type); + if (!(mask & 1)) + double2mval(&arg_mval, *(double *)arg_blob_ptr); + break; + case gtm_jstring: + CHECK_FOR_TYPES_MISMATCH(i + 1, 7, 5, *java_arg_type); + if (!(mask & 1)) + { + mstr_parm = *(gtm_string_t **)arg_blob_ptr; + arg_mval.mvtype = MV_STR; + if (MAX_STRLEN < (uint4)mstr_parm->length) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); + arg_mval.str.len = (mstr_len_t)mstr_parm->length; + arg_mval.str.addr = mstr_parm->address; + s2pool(&arg_mval.str); + } + break; + case gtm_jbyte_array: + CHECK_FOR_TYPES_MISMATCH(i + 1, 8, 6, *java_arg_type); + if (!(mask & 1)) + { + mstr_parm = *(gtm_string_t **)arg_blob_ptr; + arg_mval.mvtype = MV_STR; + if (MAX_STRLEN < (uint4)mstr_parm->length) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); + arg_mval.str.len = (mstr_len_t)mstr_parm->length; + arg_mval.str.addr = mstr_parm->address; + s2pool(&arg_mval.str); + } + break; + case gtm_jbig_decimal: + CHECK_FOR_TYPE_MISMATCH(i + 1, 9, *java_arg_type); + if (!(mask & 1)) + { + mstr_parm = *(gtm_string_t **)arg_blob_ptr; + arg_mval.mvtype = MV_STR; + if (MAX_STRLEN < (uint4)mstr_parm->length) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); + arg_mval.str.len = (mstr_len_t)mstr_parm->length; + arg_mval.str.addr = mstr_parm->address; + s2pool(&arg_mval.str); + } + break; + default: /* Indicate an invalid type. */ + arg_types[1] = i + 1; + arg_types[0] = -2; + REVERT_AND_RETURN; + } + param_blk.args[i] = push_lvval(&arg_mval); + } + param_blk.mask = out_mask; + param_blk.ci_rtn = (!has_return && param_blk.argcnt <= 0) + ? (void (*)())CODE_ADDRESS_TYPE(op_extcall) + : (void (*)())CODE_ADDRESS_TYPE(op_extexfun); + /* The params block needs to be saved and restored across multiple GT.M environments. So, instead of storing it + * explicitely, setting the global param_list to point to local param_blk will do the job. + */ + param_list = ¶m_blk; + old_intrpt_state = intrpt_ok_state; + intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; /* Reset interrupt state for the new M session. */ + save_var_on_cstack_ptr = var_on_cstack_ptr; + var_on_cstack_ptr = NULL; /* Reset var_on_cstack_ptr for the new M environment. */ + assert(frame_pointer->flags & SFF_CI); + frame_pointer->mpc = frame_pointer->ctxt = PTEXT_ADR(frame_pointer->rvector); + REVERT; /* Revert gtmci_ch. */ + + ESTABLISH_RET(stop_image_conditional_core, mumps_status); + dm_start(); /* Kick off execution. */ + REVERT; + + intrpt_ok_state = old_intrpt_state; /* Restore the old interrupt state. */ + var_on_cstack_ptr = save_var_on_cstack_ptr; /* Restore the old environment's var_on_cstack_ptr. */ + if (1 != mumps_status) + { + TREF(in_gtmci) = FALSE; + /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1, + * it is either the unhandled error code propaged by $ZT/$ET (from mdb_condition_handler) + * or zero on returning from ZGOTO 0 (ci_ret_code_quit). + */ + return mumps_status; + } + ESTABLISH_RET(gtmci_ch, mumps_status); + /* Convert mval args designated for output-only or input-output use to C types. */ + arg_blob_ptr = &arg_blob[0]; + for (i = 0; i <= count; ++i, arg_blob_ptr += GTM64_ONLY(1) NON_GTM64_ONLY(2)) + { + if (0 == i) /* Special case for return value. */ + { + if (!has_return) + { + arg_blob_ptr -= GTM64_ONLY(1) NON_GTM64_ONLY(2); + continue; + } + arg_ptr = &((lv_val *)(param_blk.retaddr))->v; + mask = 1; + arg_type = entry->return_type; + } else + { + arg_ptr = ¶m_blk.args[i - 1]->v; + mask = out_mask; + arg_type = entry->parms[i - 1]; + out_mask >>= 1; + } + /* Do not process parameters that are either input-only(I) or output(O/IO) + * parameters that are not modified by the M routine. + */ + if ((mask & 1) && MV_DEFINED(arg_ptr)) + { /* Process all output (O/IO) parameters modified by the M routine */ + switch (arg_type) + { + case gtm_jboolean: + CHECK_FOR_RET_TYPE_MISMATCH(i, 0, *arg_types); + *(gtm_int_t *)arg_blob_ptr = mval2double(arg_ptr) ? 1 : 0; + break; + case gtm_jint: + CHECK_FOR_RET_TYPE_MISMATCH(i, 1, *arg_types); + *(gtm_int_t *)arg_blob_ptr = mval2i(arg_ptr); + break; + case gtm_jlong: + CHECK_FOR_RET_TYPE_MISMATCH(i, 2, *arg_types); + *(gtm_int64_t *)arg_blob_ptr = mval2i8(arg_ptr); + break; + case gtm_jfloat: + CHECK_FOR_RET_TYPE_MISMATCH(i, 3, *arg_types); + *(gtm_float_t *)arg_blob_ptr = mval2double(arg_ptr); + break; + case gtm_jdouble: + CHECK_FOR_RET_TYPE_MISMATCH(i, 4, *arg_types); + *(gtm_double_t *)arg_blob_ptr = mval2double(arg_ptr); + break; + case gtm_jstring: + CHECK_FOR_RET_TYPE_MISMATCH(i, 7, *arg_types); + MV_FORCE_STR(arg_ptr); + (*(gtm_string_t **)arg_blob_ptr)->address = arg_ptr->str.addr; + (*(gtm_string_t **)arg_blob_ptr)->length = arg_ptr->str.len; + if (((unsigned char *)arg_ptr->str.addr + arg_ptr->str.len) == stringpool.top) /*BYPASSOK*/ + { /* Since the ci_gateway.c code temporarily switches the character following the + * string's content in memory to '\n' (for generation of a proper Unicode string), + * ensure that this character is in the stringpool and not elsewhere. + */ + ENSURE_STP_FREE_SPACE(1); + } + break; + case gtm_jbyte_array: + CHECK_FOR_RET_TYPE_MISMATCH(i, 8, *arg_types); + MV_FORCE_STR(arg_ptr); + (*(gtm_string_t **)arg_blob_ptr)->address = arg_ptr->str.addr; + (*(gtm_string_t **)arg_blob_ptr)->length = arg_ptr->str.len; + break; + case gtm_jbig_decimal: /* We currently do not support output for big decimal. */ + break; + default: + GTMASSERT; + } + } + } + REVERT; + TREF(in_gtmci) = FALSE; + return 0; +} + int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle, va_list temp_var) { va_list var; @@ -106,11 +497,10 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle int has_return, i; rhdtyp *base_addr; uint4 inp_mask, out_mask, mask; - uint4 *lnr_entry; mval arg_mval, *arg_ptr; - enum xc_types arg_type; + enum gtm_types arg_type; gtm_string_t *mstr_parm; - char *xc_char_ptr; + char *gtm_char_ptr; parmblk_struct param_blk; void op_extcall(), op_extexfun(), flush_pio(void); volatile int *save_var_on_cstack_ptr; /* Volatile to match global var type */ @@ -130,18 +520,24 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle */ if (process_exiting) { - gtm_putmsg(VARLSTCNT(1) ERR_CALLINAFTERXIT); - send_msg(VARLSTCNT(1) ERR_CALLINAFTERXIT); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); return ERR_CALLINAFTERXIT; } + TREF(in_gtmci) = TRUE; if (!gtm_startup_active || !(frame_pointer->flags & SFF_CI)) { if ((status = gtm_init()) != 0) + { + TREF(in_gtmci) = FALSE; return status; + } } ESTABLISH_RET(gtmci_ch, mumps_status); if (msp < fgncal_stack) /* unwind all arguments left on the stack by previous gtm_ci */ fgncal_unwind(); + if (!c_rtn_name) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CIRCALLNAME); if (!TREF(ci_table)) /* load the call-in table only once from env variable GTMCI */ { TREF(ci_table) = citab_parse(); @@ -164,19 +560,18 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle assert(syment->value == entry); } } - if (!c_rtn_name) - rts_error(VARLSTCNT(1) ERR_CIRCALLNAME); if (NULL == callin_handle) { if (!(entry = get_entry(c_rtn_name))) /* c_rtn_name not found in the table */ - rts_error(VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name)); if (populate_handle) callin_handle = entry; } else 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 */ - job_addr(&routine, &label, 0, (char **)&base_addr, NULL); + if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF); memset(¶m_blk, 0, SIZEOF(param_blk)); param_blk.rtnaddr = (void *)base_addr; /* lnr_entry below is a pointer to the code offset for this label from the @@ -184,19 +579,20 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle * header (on NON_USHBIN platforms). * On NON_USHBIN platforms -- 2nd argument to EXTCALL is this pointer * On USHBIN -- 2nd argument to EXTCALL is the pointer to this pointer (&lnr_entry) + * + * Assign the address for line number entry storage, so that the adjacent address holds has_parms value. */ - /* Assign the address for line number entry storage, so that the adjacent address holds has_parms value. */ param_blk.labaddr = &(TREF(lab_proxy)).LABENT_LNR_OFFSET; param_blk.argcnt = entry->argcnt; if (MAX_ACTUALS < param_blk.argcnt) - rts_error(VARLSTCNT(1) ERR_MAXACTARG); - has_return = (xc_void == entry->return_type) ? 0 : 1; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXACTARG); + has_return = (gtm_void == entry->return_type) ? 0 : 1; if (has_return) { /* Create mval slot for return value */ param_blk.retaddr = (void *)push_lvval(&arg_mval); va_arg(var, void *); /* advance va_arg */ } else - param_blk.retaddr = 0; + param_blk.retaddr = NULL; inp_mask = entry->input_mask; out_mask = entry->output_mask; for (i = 0, mask = ~inp_mask; i < entry->argcnt; ++i, mask >>= 1) @@ -206,125 +602,127 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle */ arg_mval.mvtype = MV_XZERO; if (mask & 1) - { /* output-only(O) params : advance va_arg pointer */ + { /* Output-only(O) params : advance va_arg pointer */ switch (entry->parms[i]) { - case xc_int: + case gtm_int: va_arg(var, gtm_int_t); break; - case xc_uint: + case gtm_uint: va_arg(var, gtm_uint_t); break; - case xc_long: + case gtm_long: va_arg(var, gtm_long_t); break; - case xc_ulong: + case gtm_ulong: va_arg(var, gtm_ulong_t); break; - case xc_int_star: + case gtm_int_star: va_arg(var, gtm_int_t *); break; - case xc_uint_star: + case gtm_uint_star: va_arg(var, gtm_uint_t *); break; - case xc_long_star: + case gtm_long_star: va_arg(var, gtm_long_t *); break; - case xc_ulong_star: + case gtm_ulong_star: va_arg(var, gtm_ulong_t *); break; - case xc_float: - case xc_double: + case gtm_float: + case gtm_double: va_arg(var, gtm_double_t); break; - case xc_float_star: + case gtm_float_star: va_arg(var, gtm_float_t *); break; - case xc_double_star: + case gtm_double_star: va_arg(var, gtm_double_t *); break; - case xc_char_star: + case gtm_char_star: va_arg(var, gtm_char_t *); break; - case xc_string_star: + case gtm_string_star: va_arg(var, gtm_string_t *); break; default: va_end(var); - GTMASSERT; + assertpro(FALSE); } } else { /* I/IO params: create mval for each native type param */ switch (entry->parms[i]) { - case xc_int: + case gtm_int: i2mval(&arg_mval, va_arg(var, gtm_int_t)); break; - case xc_uint: + case gtm_uint: i2usmval(&arg_mval, va_arg(var, gtm_uint_t)); break; - case xc_long: -#ifdef GTM64 - l2mval(&arg_mval, (long)va_arg(var, gtm_long_t)); -#else + case gtm_long: +# ifdef GTM64 + i82mval(&arg_mval, (gtm_int64_t)va_arg(var, gtm_long_t)); +# else i2mval(&arg_mval, (int)va_arg(var, gtm_long_t)); -#endif +# endif break; - case xc_ulong: -#ifdef GTM64 - ul2mval(&arg_mval, (unsigned long)va_arg(var, gtm_ulong_t)); -#else + case gtm_ulong: +# ifdef GTM64 + ui82mval(&arg_mval, (gtm_uint64_t)va_arg(var, gtm_ulong_t)); +# else i2usmval(&arg_mval, (int)va_arg(var, gtm_ulong_t)); -#endif +# endif break; - case xc_int_star: + case gtm_int_star: i2mval(&arg_mval, *va_arg(var, gtm_int_t *)); break; - case xc_uint_star: + case gtm_uint_star: i2usmval(&arg_mval, *va_arg(var, gtm_uint_t *)); break; - case xc_long_star: -#ifdef GTM64 - l2mval(&arg_mval, (long)*va_arg(var, gtm_long_t *)); -#else + case gtm_long_star: +# ifdef GTM64 + i82mval(&arg_mval, (gtm_int64_t)*va_arg(var, gtm_long_t *)); +# else i2mval(&arg_mval, (int)*va_arg(var, gtm_long_t *)); -#endif +# endif break; - case xc_ulong_star: -#ifdef GTM64 - ul2mval(&arg_mval, (unsigned long)*va_arg(var, gtm_ulong_t *)); -#else + case gtm_ulong_star: +# ifdef GTM64 + ui82mval(&arg_mval, (gtm_uint64_t)*va_arg(var, gtm_ulong_t *)); +# else i2usmval(&arg_mval, (int)*va_arg(var, gtm_ulong_t *)); -#endif +# endif break; - case xc_float: /* fall through */ - case xc_double: + case gtm_float: + float2mval(&arg_mval, (gtm_float_t)va_arg(var, gtm_double_t)); + break; + case gtm_double: double2mval(&arg_mval, va_arg(var, gtm_double_t)); break; - case xc_float_star: - double2mval(&arg_mval, *va_arg(var, gtm_float_t *)); + case gtm_float_star: + float2mval(&arg_mval, *va_arg(var, gtm_float_t *)); break; - case xc_double_star: + case gtm_double_star: double2mval(&arg_mval, *va_arg(var, gtm_double_t *)); break; - case xc_char_star: + case gtm_char_star: arg_mval.mvtype = MV_STR; arg_mval.str.addr = va_arg(var, gtm_char_t *); arg_mval.str.len = STRLEN(arg_mval.str.addr); if (MAX_STRLEN < arg_mval.str.len) { va_end(var); - rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); } s2pool(&arg_mval.str); break; - case xc_string_star: + case gtm_string_star: mstr_parm = va_arg(var, gtm_string_t *); arg_mval.mvtype = MV_STR; if (MAX_STRLEN < (uint4)mstr_parm->length) { va_end(var); - rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); } arg_mval.str.len = (mstr_len_t)mstr_parm->length; arg_mval.str.addr = mstr_parm->address; @@ -332,7 +730,7 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle break; default: va_end(var); - GTMASSERT; /* should have been caught by citab_parse */ + assertpro(FALSE); /* should have been caught by citab_parse */ } } param_blk.args[i] = push_lvval(&arg_mval); @@ -342,9 +740,9 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle param_blk.ci_rtn = (!has_return && param_blk.argcnt <= 0) ? (void (*)())CODE_ADDRESS_TYPE(op_extcall) : (void (*)())CODE_ADDRESS_TYPE(op_extexfun); - /* the params block needs to be stored & restored across multiple + /* The params block needs to be stored & restored across multiple * gtm environments. So instead of storing explicitely, setting the - * global param_list to point to local param_blk will do the job + * global param_list to point to local param_blk will do the job. */ param_list = ¶m_blk; old_intrpt_state = intrpt_ok_state; @@ -362,17 +760,19 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle intrpt_ok_state = old_intrpt_state; /* restore the old interrupt state */ var_on_cstack_ptr = save_var_on_cstack_ptr; /* restore the old environment's var_on_cstack_ptr */ if (1 != mumps_status) - { /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1, + { + TREF(in_gtmci) = FALSE; + /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1, * it is either the unhandled error code propaged by $ZT/$ET (from mdb_condition_handler) - * or zero on returning from ZGOTO 0 (ci_ret_code_quit) + * or zero on returning from ZGOTO 0 (ci_ret_code_quit). */ return mumps_status; } ESTABLISH_RET(gtmci_ch, mumps_status); - /* convert mval args passed by reference to C types */ + /* Convert mval args passed by reference to C types */ for (i = 0; i <= entry->argcnt; ++i) { - if (0 == i) /* special case for return value */ + if (0 == i) /* Special case for return value */ { if (!has_return) continue; @@ -393,79 +793,81 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle { switch (arg_type) { - case xc_int_star: + case gtm_int_star: va_arg(temp_var, gtm_int_t *); break; - case xc_uint_star: + case gtm_uint_star: va_arg(temp_var, gtm_uint_t *); break; - case xc_long_star: + case gtm_long_star: va_arg(temp_var, gtm_long_t *); break; - case xc_ulong_star: + case gtm_ulong_star: va_arg(temp_var, gtm_ulong_t *); break; - case xc_float_star: + case gtm_float_star: va_arg(temp_var, gtm_float_t *); break; - case xc_double_star: + case gtm_double_star: va_arg(temp_var, gtm_double_t *); break; - case xc_char_star: + case gtm_char_star: va_arg(temp_var, gtm_char_t *); break; - case xc_string_star: + case gtm_string_star: va_arg(temp_var, gtm_string_t *); break; - case xc_int: + case gtm_int: va_arg(temp_var, gtm_int_t); break; - case xc_uint: + case gtm_uint: va_arg(temp_var, gtm_uint_t); break; - case xc_long: + case gtm_long: va_arg(temp_var, gtm_long_t); break; - case xc_ulong: + case gtm_ulong: va_arg(temp_var, gtm_ulong_t); break; - case xc_float: - case xc_double: + case gtm_float: + case gtm_double: va_arg(temp_var, gtm_double_t); break; default: va_end(temp_var); - GTMASSERT; + assertpro(FALSE); } } else { /* Process all output (O/IO) parameters modified by the M routine */ switch (arg_type) { - case xc_int_star: + case gtm_int_star: *va_arg(temp_var, gtm_int_t *) = mval2i(arg_ptr); break; - case xc_uint_star: + case gtm_uint_star: *va_arg(temp_var, gtm_uint_t *) = mval2ui(arg_ptr); break; - case xc_long_star: - *va_arg(temp_var, gtm_long_t *) = mval2i(arg_ptr); + case gtm_long_star: + *va_arg(temp_var, gtm_long_t *) = + GTM64_ONLY(mval2i8(arg_ptr)) NON_GTM64_ONLY(mval2i(arg_ptr)); break; - case xc_ulong_star: - *va_arg(temp_var, gtm_ulong_t *) = mval2ui(arg_ptr); + case gtm_ulong_star: + *va_arg(temp_var, gtm_ulong_t *) = + GTM64_ONLY(mval2ui8(arg_ptr)) NON_GTM64_ONLY(mval2ui(arg_ptr)); break; - case xc_float_star: + case gtm_float_star: *va_arg(temp_var, gtm_float_t *) = mval2double(arg_ptr); break; - case xc_double_star: + case gtm_double_star: *va_arg(temp_var, gtm_double_t *) = mval2double(arg_ptr); break; - case xc_char_star: - xc_char_ptr = va_arg(temp_var, gtm_char_t *); + case gtm_char_star: + gtm_char_ptr = va_arg(temp_var, gtm_char_t *); MV_FORCE_STR(arg_ptr); - memcpy(xc_char_ptr, arg_ptr->str.addr, arg_ptr->str.len); - xc_char_ptr[arg_ptr->str.len] = 0; /* trailing null */ + memcpy(gtm_char_ptr, arg_ptr->str.addr, arg_ptr->str.len); + gtm_char_ptr[arg_ptr->str.len] = 0; /* trailing null */ break; - case xc_string_star: + case gtm_string_star: mstr_parm = va_arg(temp_var, gtm_string_t *); MV_FORCE_STR(arg_ptr); mstr_parm->length = arg_ptr->str.len; @@ -473,18 +875,19 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle break; default: va_end(temp_var); - GTMASSERT; + assertpro(FALSE); } } } va_end(temp_var); REVERT; + TREF(in_gtmci) = FALSE; return 0; } int gtm_ci(const char *c_rtn_name, ...) { - va_list var; + va_list var; VAR_START(var, c_rtn_name); return gtm_ci_exec(c_rtn_name, NULL, FALSE, var); @@ -493,16 +896,25 @@ int gtm_ci(const char *c_rtn_name, ...) /* Functionality is same as that of gtmci but accepts a struct containing information about the routine. */ int gtm_cip(ci_name_descriptor* ci_info, ...) { - va_list var; + va_list var; VAR_START(var, ci_info); return gtm_ci_exec(ci_info->rtn_name.address, ci_info->handle, TRUE, var); } +#ifdef GTM_PTHREAD +int gtm_jinit() +{ + gtm_jvm_process = TRUE; + return gtm_init(); +} +#endif + int gtm_init() { rhdtyp *base_addr; unsigned char *transfer_addr; + char *dist; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -516,16 +928,19 @@ int gtm_init() */ if (process_exiting) { - gtm_putmsg(VARLSTCNT(1) ERR_CALLINAFTERXIT); - send_msg(VARLSTCNT(1) ERR_CALLINAFTERXIT); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT); return ERR_CALLINAFTERXIT; } + if (!TREF(in_gtmci)) + return 0; if (!gtm_startup_active) { /* call-in invoked from C as base. GT.M hasn't been started up yet. */ gtm_imagetype_init(GTM_IMAGE); gtm_wcswidth_fnptr = gtm_wcswidth; gtm_env_init(); /* read in all environment variables */ err_init(stop_image_conditional_core); + UNICODE_ONLY(gtm_strToTitle_ptr = >m_strToTitle); GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ cli_lex_setup(0, NULL); /* Initialize msp to the maximum so if errors occur during GT.M startup below, @@ -540,6 +955,14 @@ int gtm_init() invocation_mode = MUMPS_CALLIN; init_gtm(); gtm_savetraps(); /* nullify default $ZTRAP handling */ + if (NULL != (dist = (char *)GETENV(GTM_DIST))) + { + assert(IS_VALID_IMAGE && (n_image_types > image_type)); /* assert image_type is initialized */ + if ((GTM_PATH_MAX - 2) <= (STRLEN(dist) + gtmImageNames[image_type].imageNameLen)) + dist = NULL; + else + memcpy(gtm_dist, dist, STRLEN(dist)); + } assert(gtm_startup_active); assert(frame_pointer->flags & SFF_CI); TREF(gtmci_nested_level) = 1; @@ -551,13 +974,13 @@ int gtm_init() fgncal_stack = msp; /* generate CIMAXLEVELS error if gtmci_nested_level > CALLIN_MAX_LEVEL */ if (CALLIN_MAX_LEVEL < TREF(gtmci_nested_level)) - rts_error(VARLSTCNT(3) ERR_CIMAXLEVELS, 1, TREF(gtmci_nested_level)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CIMAXLEVELS, 1, TREF(gtmci_nested_level)); /* Disallow call-ins within a TP boundary since TP restarts are not supported * currently across nested call-ins. When we implement TP restarts across call-ins, * this error needs be changed to a Warning or Notification */ if (dollar_tlevel) - rts_error(VARLSTCNT(1) ERR_CITPNESTED); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CITPNESTED); base_addr = make_cimode(); transfer_addr = PTEXT_ADR(base_addr); gtm_init_env(base_addr, transfer_addr); @@ -586,7 +1009,7 @@ int gtm_exit() assert(NULL != frame_pointer); /* Do not allow gtm_exit() to be invoked from external calls */ if (!(SFF_CI & frame_pointer->flags) || !(MUMPS_CALLIN & invocation_mode) || (1 < TREF(gtmci_nested_level))) - rts_error(VARLSTCNT(1) ERR_INVGTMEXIT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVGTMEXIT); /* Now get rid of the whole M stack - end of GT.M environment */ while (NULL != frame_pointer) { diff --git a/sr_unix/gtmci_ch.c b/sr_unix/gtmci_ch.c index b5cc546..823f915 100644 --- a/sr_unix/gtmci_ch.c +++ b/sr_unix/gtmci_ch.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,6 +47,7 @@ CONDITION_HANDLER(gtmci_ch) src_line.len = 0; src_line.addr = &src_buf[0]; set_zstatus(&src_line, SIGNAL, NULL, FALSE); + TREF(in_gtmci) = FALSE; if (msp < fgncal_stack) /* restore stack to the last marked position */ fgncal_unwind(); mumps_status = SIGNAL; diff --git a/sr_unix/gtmcrypt.h b/sr_unix/gtmcrypt.h index 2ecd59e..b628213 100644 --- a/sr_unix/gtmcrypt.h +++ b/sr_unix/gtmcrypt.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,24 +26,38 @@ #include "gtmmsg.h" #include "gtmci.h" #include "wbox_test_init.h" +#include "error.h" /* for MAKE_MSG_WARNING macro */ -typedef xc_status_t (*gtmcrypt_init_t)(int); -typedef xc_status_t (*gtmcrypt_close_t)(); -typedef xc_status_t (*gtmcrypt_hash_gen_t)(gtmcrypt_key_t, xc_string_t *); -typedef xc_status_t (*gtmcrypt_encode_t)(gtmcrypt_key_t, xc_string_t *, xc_string_t *); -typedef xc_status_t (*gtmcrypt_decode_t)(gtmcrypt_key_t, xc_string_t *, xc_string_t *); -typedef xc_status_t (*gtmcrypt_getkey_by_name_t)(xc_string_t *, gtmcrypt_key_t *); -typedef xc_status_t (*gtmcrypt_getkey_by_hash_t)(xc_string_t *, gtmcrypt_key_t *); -typedef char* (*gtmcrypt_strerror_t)(); +#define MAX_GTMCRYPT_ERR_STRLEN 2048 /* Should be kept in sync with the one in gtmcrypt_ref.h */ + +typedef xc_status_t (*gtmcrypt_init_t)(int); +typedef xc_status_t (*gtmcrypt_close_t)(); +typedef xc_status_t (*gtmcrypt_hash_gen_t)(gtmcrypt_key_t, xc_string_t *); +typedef xc_status_t (*gtmcrypt_encrypt_t)(gtmcrypt_key_t, xc_string_t *, xc_string_t *); +typedef xc_status_t (*gtmcrypt_decrypt_t)(gtmcrypt_key_t, xc_string_t *, xc_string_t *); +typedef xc_status_t (*gtmcrypt_getkey_by_name_t)(xc_string_t *, gtmcrypt_key_t *); +typedef xc_status_t (*gtmcrypt_getkey_by_hash_t)(xc_string_t *, gtmcrypt_key_t *); +typedef char* (*gtmcrypt_strerror_t)(); GBLREF gtmcrypt_init_t gtmcrypt_init_fnptr; GBLREF gtmcrypt_close_t gtmcrypt_close_fnptr; GBLREF gtmcrypt_hash_gen_t gtmcrypt_hash_gen_fnptr; -GBLREF gtmcrypt_encode_t gtmcrypt_encode_fnptr; -GBLREF gtmcrypt_decode_t gtmcrypt_decode_fnptr; +GBLREF gtmcrypt_encrypt_t gtmcrypt_encrypt_fnptr; +GBLREF gtmcrypt_decrypt_t gtmcrypt_decrypt_fnptr; GBLREF gtmcrypt_getkey_by_name_t gtmcrypt_getkey_by_name_fnptr; GBLREF gtmcrypt_getkey_by_hash_t gtmcrypt_getkey_by_hash_fnptr; GBLREF gtmcrypt_strerror_t gtmcrypt_strerror_fnptr; +GBLREF boolean_t gtmcrypt_initialized; +LITREF char gtmcrypt_repeat_msg[]; + +error_def(ERR_CRYPTDLNOOPEN); +error_def(ERR_CRYPTDLNOOPEN2); +error_def(ERR_CRYPTHASHGENFAILED); +error_def(ERR_CRYPTINIT); +error_def(ERR_CRYPTKEYFETCHFAILED); +error_def(ERR_CRYPTKEYFETCHFAILEDNF); +error_def(ERR_CRYPTNOPSWDINTP); +error_def(ERR_CRYPTOPFAILED); /* The standard shared library suffix for HPUX on HPPA is .sl. * On HPUX/IA64, the standard suffix was changed to .so (to match other Unixes) but for @@ -63,114 +77,64 @@ GBLREF gtmcrypt_strerror_t gtmcrypt_strerror_fnptr; #define GTMCRYPT_INIT_FNAME "gtmcrypt_init" #define GTMCRYPT_CLOSE_FNAME "gtmcrypt_close" #define GTMCRYPT_HASH_GEN_FNAME "gtmcrypt_hash_gen" -#define GTMCRYPT_ENCODE_FNAME "gtmcrypt_encode" -#define GTMCRYPT_DECODE_FNAME "gtmcrypt_decode" +#define GTMCRYPT_ENCRYPT_FNAME "gtmcrypt_encrypt" +#define GTMCRYPT_DECRYPT_FNAME "gtmcrypt_decrypt" #define GTMCRYPT_GETKEY_BY_NAME "gtmcrypt_getkey_by_name" #define GTMCRYPT_GETKEY_BY_HASH "gtmcrypt_getkey_by_hash" #define GTMCRYPT_STRERROR "gtmcrypt_strerror" #define GTM_PASSWD "gtm_passwd" -/* Global variable GBLDEF'ed in gbldefs.c */ -GBLREF int4 gtmcrypt_init_state; -/* Possible states for encryption library */ -typedef enum -{ - GTMCRYPT_UNINITIALIZED, /* This is when, so far in the code, gtmcrypt_setup or gtmcrypt_init hasn't been called */ - GTMCRYPT_INITIALIZED, /* This is the state when both dlopen and gtmcrypt_init has successfully passed */ -} gtmcrypt_init_values; -void gtmcrypt_entry(void); +#define GTMCRYPT_INVALID_KEY_HANDLE -1 /* Should be kept in sync with INVALID_HANDLE in gtmcrypt_ref.h */ + +uint4 gtmcrypt_entry(void); /* =====================================================================================================*/ /* Error Reporting Macros */ /* =====================================================================================================*/ -/* Call the plugin's strerror equivalent to get the last error message */ -#define GC_GET_ERR_STRING(err) \ -{ \ - assert(NULL != gtmcrypt_strerror_fnptr); \ - err = (*gtmcrypt_strerror_fnptr)(); \ -} +#define CRYPTERR_MASK 0x10000000 +#define REPEAT_MSG_MASK 0x20000000 -/* ERR_CRYPTKEYFETCHFAILED is a unique error that has to be handled a bit differently. Whenever GT.M calls the plugin - * to get the encryption key for a give hash, the plugin is not aware of the filename for which the hash was - * passed. Also, GT.M itself might not be aware of the filenames in cases like bin_load. To handle this case, - * GC_GTM_PUTMSG and GC_RTS_ERROR will explicitly carry the filename for which the current operation - * is being done. In case GT.M cannot figure out the filename, it will pass NULL. The following constructs the - * appropriate error message in the event that the filename is present and for the case where GT.M has passed - * NULL. */ +#define IS_CRYPTERR_MASK(ERRID) ((ERRID) & CRYPTERR_MASK) +#define IS_REPEAT_MSG_MASK(ERRID) ((ERRID) & REPEAT_MSG_MASK) +#define SET_CRYPTERR_MASK(ERRID) ((ERRID) | CRYPTERR_MASK) +#define SET_REPEAT_MSG_MASK(ERRID) ((ERRID) | REPEAT_MSG_MASK) +#define CLEAR_CRYPTERR_MASK(ERRID) (ERRID = ((ERRID) & ~CRYPTERR_MASK)) +#define CLEAR_REPEAT_MSG_MASK(ERRID) (ERRID = ((ERRID) & ~REPEAT_MSG_MASK)) -#define GC_GTM_PUTMSG(err_id, FNAME) \ +#define GTMCRYPT_REPORT_ERROR(ERRID, MECHANISM, LEN, PTR) \ { \ - char *err; \ - GBLREF char dl_err[]; \ + GBLREF char dl_err[]; \ \ - error_def(ERR_CRYPTKEYFETCHFAILED); \ - error_def(ERR_CRYPTKEYFETCHFAILEDNF); \ - error_def(ERR_CRYPTINIT); \ - error_def(ERR_CRYPTDLNOOPEN); \ + int errid; \ + const char *errptr; \ \ - if (ERR_CRYPTDLNOOPEN != err_id) \ + errid = ERRID; \ + assert(IS_CRYPTERR_MASK(errid)); \ + CLEAR_CRYPTERR_MASK(errid); \ + if (IS_REPEAT_MSG_MASK(errid)) \ + errptr = >mcrypt_repeat_msg[0]; \ + else if ((ERR_CRYPTDLNOOPEN == errid) || (ERR_CRYPTDLNOOPEN2 == errid) \ + || (MAKE_MSG_WARNING(ERR_CRYPTDLNOOPEN2) == errid) || (MAKE_MSG_WARNING(ERR_CRYPTDLNOOPEN) == errid)) \ { \ - GC_GET_ERR_STRING(err); \ - if (ERR_CRYPTKEYFETCHFAILED == err_id) \ - { \ - if (NULL != FNAME) \ - gtm_putmsg(VARLSTCNT(6) ERR_CRYPTKEYFETCHFAILED, 4, LEN_AND_STR(FNAME), LEN_AND_STR(err)); \ - else \ - gtm_putmsg(VARLSTCNT(4) ERR_CRYPTKEYFETCHFAILEDNF, 2, LEN_AND_STR(err)); \ - } else \ - gtm_putmsg(VARLSTCNT(4) err_id, 2, LEN_AND_STR(err)); \ + errptr = (const char *) &dl_err[0]; \ } else \ - gtm_putmsg(VARLSTCNT(4) ERR_CRYPTDLNOOPEN, 2, LEN_AND_STR(dl_err)); \ -} - -/* Fetch the last error string from the encryption plugin. If the error is ERR_KEYFETCHFAILED, we need to - * handle them a bit differently as described above. This macro should be called whenever GT.M wants to do - * rts_error. */ -#define GC_RTS_ERROR(err_id, FNAME) \ -{ \ - char *err; \ - GBLREF char dl_err[]; \ - \ - error_def(ERR_CRYPTKEYFETCHFAILED); \ - error_def(ERR_CRYPTKEYFETCHFAILEDNF); \ - error_def(ERR_CRYPTINIT); \ - error_def(ERR_CRYPTDLNOOPEN); \ - \ - if (ERR_CRYPTDLNOOPEN != err_id) \ { \ - GC_GET_ERR_STRING(err); \ - if (ERR_CRYPTKEYFETCHFAILED == err_id) \ - { \ - if (NULL != FNAME) \ - rts_error(VARLSTCNT(6) ERR_CRYPTKEYFETCHFAILED, 4, LEN_AND_STR(FNAME), LEN_AND_STR(err)); \ - else \ - rts_error(VARLSTCNT(4) ERR_CRYPTKEYFETCHFAILEDNF, 2, LEN_AND_STR(err)); \ - } else \ - rts_error(VARLSTCNT(4) err_id, 2, LEN_AND_STR(err)); \ - } else \ - rts_error(VARLSTCNT(4) ERR_CRYPTDLNOOPEN, 2, LEN_AND_STR(dl_err)); \ + DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + errptr = (const char *) (*gtmcrypt_strerror_fnptr)(); \ + ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + } \ + CLEAR_REPEAT_MSG_MASK(errid); \ + MECHANISM(VARLSTCNT(6) errid, 4, LEN, PTR, LEN_AND_STR(errptr)); \ } -/* Following are the error identifiers visible to the GT.M user. Depending on the operation performed, - * mark the appropriate status. */ -#define GC_MARK_STATUS(status, RC, ERR_ID) \ -{ \ - error_def(ERR_CRYPTDLNOOPEN); \ - error_def(ERR_CRYPTINIT); \ - error_def(ERR_CRYPTKEYFETCHFAILED); \ - error_def(ERR_CRYPTOPFAILED); \ - error_def(ERR_CRYPTHASHGENFAILED); \ - \ - RC = (0 != status) ? ERR_ID : 0; \ -} /* =====================================================================================================*/ /* Utility Macros */ /* =====================================================================================================*/ -/* Package the required addresses in various xc_string_t which can be used by various decode, encode macros */ +/* Helper macro to package the address and length in a xc_string_t type */ #define PACKAGE_XCSTRING(xcstring, buf, buflen) \ { \ xcstring.address = buf; \ @@ -186,257 +150,219 @@ void gtmcrypt_entry(void); #define BLOCK_REQUIRE_ENCRYPTION(FLAG, LEVL, BSIZ) (FLAG && IS_BLK_ENCRYPTED(LEVL, BSIZ)) -#define ENCR_INITIALIZED (GTMCRYPT_INITIALIZED == gtmcrypt_init_state) -#define ENCR_WBOX_ENABLED (gtm_white_box_test_case_enabled \ - && (WBTEST_ENCRYPT_INIT_ERROR == gtm_white_box_test_case_number)) +#define ENCR_INITIALIZED gtmcrypt_initialized +#define ENCR_WBOX_ENABLED (gtm_white_box_test_case_enabled \ + && (WBTEST_ENCRYPT_INIT_ERROR == gtm_white_box_test_case_number)) #define ASSERT_ENCRYPTION_INITIALIZED assert(ENCR_INITIALIZED || ENCR_WBOX_ENABLED) -#define GTMCRYPT_COPY_HASH(src, dst) \ +#define PROMPT_PASSWD(PTR) (IS_MUMPS_IMAGE \ + && (NULL != (PTR = (char *)getenv(GTM_PASSWD))) \ + && (0 == strlen(PTR))) \ + + +#define GTMCRYPT_COPY_HASH(SRC, DST) \ { \ - memcpy(dst->encryption_hash, src->encryption_hash, GTMCRYPT_HASH_LEN); \ - dst->is_encrypted = src->is_encrypted; \ + memcpy(DST->encryption_hash, SRC->encryption_hash, GTMCRYPT_HASH_LEN); \ + DST->is_encrypted = SRC->is_encrypted; \ } \ +/* General Note : All macros below (execpt GTMCRYPT_CLOSE) takes in CSA as their first parameter. Currently, most macros don't + * use CSA, but is supplied by the caller anyways in case later a need to arises to reference CSA. + */ #define ALLOC_BUFF_GET_ENCR_KEY(CSA, HASH, ALLOC_SIZE, RC) \ { \ - assert(0 < ALLOC_SIZE && NULL != CSA); \ + assert((0 < ALLOC_SIZE) && (NULL != CSA)); \ RC = 0; \ - GTMCRYPT_GETKEY(HASH, CSA->encr_key_handle, RC); \ + GTMCRYPT_GETKEY(CSA, HASH, CSA->encr_key_handle, RC); \ if (0 == RC) \ (CSA)->encrypted_blk_contents = (char *)malloc(ALLOC_SIZE); \ } -#define INIT_DB_ENCRYPTION(fname, CSA, CSD, RC) \ +/* Database specific initialization - gets the encryption key corresponding to the HASH (SHA-512 currently) found in the database + * file header and allocates a buffer large enough to encrypt/decrypt database block sizes. + */ +#define INIT_DB_ENCRYPTION(CSA, CSD, RC) \ { \ GBLREF stack_frame *frame_pointer; \ GBLREF uint4 dollar_tlevel; \ - char *ptr, *key_hash = CSD->encryption_hash; \ - boolean_t call_ci_ret_code_quit = FALSE, prompt_passwd = FALSE; \ + char *ptr, *key_hash; \ + boolean_t call_ci_ret_code_quit, prompt_passwd; \ \ - error_def(ERR_CRYPTNOPSWDINTP); \ RC = 0; \ - /* If we are in a TP transaction and the environment is setup in such a way that we will be doing a gtm_ci call \ - * then let's error out as gtm_ci doesn't work inside a TP transaction */ \ - prompt_passwd = PROMPT_PASSWD; \ + prompt_passwd = PROMPT_PASSWD(ptr); \ if (prompt_passwd && dollar_tlevel) \ - rts_error(VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \ - /* Make sure we are not in gtm_ci already. */ \ - assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); \ - /* The below macro eventually calls gtmcrypt_getkey_by_hash to get the encryption key for the database based on \ - * the hash in the database file header. It could be possible that initially the user had a wrong password and \ - * tried accessing a global which might have landed in db_init and would have successfully done encryption \ - * initialization. But later call to this macro would have failed since the password turned out to be wrong and \ - * the encryption library failed to do the decryption. Now, after setting the password to a null string, the user \ - * now tries to access the global again which will reach this macro again but now the call to gtmcrypt_getkey_by_hash \ - * will call gtm_ci for prompting password. Hence before calling the encryption library, make a note if we had \ - * to do ci_ret_code_quit below. */ \ + { /* GT.M call-ins don't support TP transactions (see gtm_ci_exec) */ \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \ + } \ + assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); /* ensures not already in gtm_ci */ \ + /* ALLOC_BUFF_GET_ENCR_KEY eventually invokes gtmcrypt_getkey_by_hash to obtain the encryption key for the concerned \ + * database. At this point encryption initialization is already done (as part of INIT_PROC_ENCRYPTION) even if the \ + * user had entered a wrong password. But, the wrong password isn't validated until the actual encryption/decryption \ + * happens (which is now). If user fixes the wrong-password situation by setting gtm_passwd to null-string and once \ + * again accesses the database, we'd come back here; but this time, gtmcrypt_getkey_by_hash will end up invoking \ + * gtm_ci (to obtain the password) and so a corresponding ci_ret_code_quit must be done. Make a note of this so we \ + * can accordingly invoke ci_ret_code_quit (after gtmcrypt_getkey_by_hash) \ + */ \ call_ci_ret_code_quit = (prompt_passwd && !(frame_pointer->flags & SFF_CI)); \ + key_hash = CSD->encryption_hash; \ ALLOC_BUFF_GET_ENCR_KEY(CSA, key_hash, (CSD->blk_size + SIZEOF(int4)), RC); \ if (call_ci_ret_code_quit) \ ci_ret_code_quit(); \ } -#define PROMPT_PASSWD (IS_MUMPS_IMAGE \ - && (NULL != (ptr = (char *)getenv(GTM_PASSWD))) \ - && (0 == strlen(ptr))) - /* =====================================================================================================*/ /* Plugin Related Macros */ /* =====================================================================================================*/ -/* INIT_PROC_ENCRYPTION is called whenever GT.M wants to initialize the encryption library and it's related - * modules. The context in which the caller calls INIT_PROC_ENCRYPTION might force non encryption related - * tasks (like MUPIP JOURNAL -SHOW=HEADER -NOVERIFY -FORWARD) to error out in case the below macro fails. To - * avoid this, we note down the error status and the corresponding error string in global variable. This way, - * any task requiring the actual encryption (MUPIP INTEG -FILE) will verify if the global error code is holding - * a non zero value and error out accordingly. */ -#define INIT_PROC_ENCRYPTION(RC) \ +/* Process specific initialization - dlopen libgtmcrypt.so and invoke gtmcrypt_init() */ +#define INIT_PROC_ENCRYPTION(CSA, RC) \ { \ - GBLREF int4 gbl_encryption_ecode; \ GBLREF stack_frame *frame_pointer; \ GBLREF uint4 dollar_tlevel; \ - boolean_t call_ci_ret_code_quit = FALSE, prompt_passwd = FALSE; \ + boolean_t call_ci_ret_code_quit, prompt_passwd; \ + char *ptr; \ \ - error_def(ERR_CRYPTNOPSWDINTP); \ - error_def(ERR_CRYPTINIT); \ RC = 0; \ - gbl_encryption_ecode = 0; \ - if (GTMCRYPT_UNINITIALIZED == gtmcrypt_init_state) \ + if (!gtmcrypt_initialized) \ { \ - gtmcrypt_entry(); \ - /* If in the above call, dlopen failed for some reason, then gbl_encryption_ecode will be set to \ - * ERR_CRYPTDLNOOPEN. Also, the dlopen error message will be stored in dl_err. */ \ - RC = gbl_encryption_ecode; \ - if (0 == gbl_encryption_ecode) \ - { \ - char *ptr; \ - boolean_t has_prompted_passwd; \ - \ - /* dlopen on the encryption library succeeded. */ \ + if (0 == (RC = gtmcrypt_entry())) \ + { /* dlopen succeeded */ \ assert(NULL != gtmcrypt_init_fnptr); \ - /* If we are in a TP transaction and the environment is setup in such a way that we will be doing a \ - * gtm_ci call then let's error out as gtm_ci doesn't work inside a TP transaction */ \ - prompt_passwd = PROMPT_PASSWD; \ - if (prompt_passwd && dollar_tlevel) \ - rts_error(VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \ - /* Make sure we are not in gtm_ci already. */ \ - assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); \ - /* The call to gtmcrypt_init below will try to call gtm_ci on finding that password is set to \ - * empty string and if the calling process is MUMPS. Make a note of the condition under which we \ - * would be calling ci_ret_code_quit. */ \ - call_ci_ret_code_quit = (prompt_passwd && !(frame_pointer->flags & SFF_CI)); \ - /* Call the encryption library's init routine. Also, pass a boolean indicating whether \ - * the library should do the password prompting(for MUMPS) or not(for MUPIP, DSE, etc.)*/ \ - xc_status_t init_ret_status = (*gtmcrypt_init_fnptr)(IS_MUMPS_IMAGE); \ - /* Unwind the stack frames if necessary. */ \ - if (call_ci_ret_code_quit) \ - ci_ret_code_quit(); \ - /* If the call failed, we have to indicate the caller that an error happened. Also, we \ - * will mark the gbl_encryption_ecode to ERR_CRYPTINIT. */ \ - if (0 != init_ret_status) \ - RC = gbl_encryption_ecode = ERR_CRYPTINIT; \ - else \ - { \ - /* Everything went on smoothly. So indicate that we don't need to do the init \ - * again. */ \ - gtmcrypt_init_state = GTMCRYPT_INITIALIZED; \ - gbl_encryption_ecode = RC = 0; \ + assert(NULL != gtmcrypt_getkey_by_hash_fnptr); \ + assert(NULL != gtmcrypt_getkey_by_name_fnptr); \ + assert(NULL != gtmcrypt_hash_gen_fnptr); \ + assert(NULL != gtmcrypt_encrypt_fnptr); \ + assert(NULL != gtmcrypt_decrypt_fnptr); \ + assert(NULL != gtmcrypt_strerror_fnptr); \ + assert(NULL != gtmcrypt_close_fnptr); \ + prompt_passwd = PROMPT_PASSWD(ptr); \ + if (prompt_passwd && dollar_tlevel) \ + { /* GT.M call-ins don't support TP transactions (see gtm_ci_exec)*/ \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \ } \ - } \ + assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); /* ensures not already in gtm_ci */ \ + /* If password is set to empty string, gtmcrypt_init (called below) invokes gtm_ci to obtain the \ + * password at runtime (if we are MUMPS) in which case ci_ret_code_quit() needs to be invoked. Make \ + * a note of this so we can accordingly invoke ci_ret_code_quit (after gtmcrypt_init) \ + */ \ + call_ci_ret_code_quit = (prompt_passwd && !(frame_pointer->flags & SFF_CI)); \ + /* IS_MUMPS_IMAGE below tells the plugin to prompt for password (if not already provided in env) */ \ + DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + xc_status_t init_ret_status = (*gtmcrypt_init_fnptr)(IS_MUMPS_IMAGE); \ + ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + if (call_ci_ret_code_quit) \ + ci_ret_code_quit(); /* Unwind stack frames */ \ + if (0 != init_ret_status) \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTINIT); \ + else \ + gtmcrypt_initialized = TRUE; /* No more per-process initialization needed */ \ + } else \ + RC = SET_CRYPTERR_MASK(RC); \ } \ } -/* GTMCRYPT_GETKEY is mostly called when the caller wants to get the encryption key well before the actual - * encryption or decryption happens. As mentioned above the context in which GTMCRYPT_GETKEY is called - * might force the non encryption related tasks to error out. So we follow a similar approach as mentioned above. */ -#define GTMCRYPT_GETKEY(hash, key_handle, RC) \ +/* Given a cryptographic hash (currently SHA-512), the below function retrieves a handle to the symmetric key corresponding to + * the hash. This function is always called before attempting an encrypt or decrypt operation. + */ +#define GTMCRYPT_GETKEY(CSA, hash, key_handle, RC) \ { \ - xc_string_t xc_hash; \ - xc_status_t status; \ - GBLREF int4 gbl_encryption_ecode; \ + xc_string_t xc_hash; \ + xc_status_t status; \ \ - error_def(ERR_CRYPTKEYFETCHFAILED); \ - /* Call the encryption library only if we are clean from the last encryption \ - * call. We find this from gbl_encryption_ecode. */ \ - RC = gbl_encryption_ecode; \ - if (0 == RC) \ + key_handle = GTMCRYPT_INVALID_KEY_HANDLE; \ + if (gtmcrypt_initialized) \ { \ PACKAGE_XCSTRING(xc_hash, hash, GTMCRYPT_HASH_LEN); \ - assert(NULL != gtmcrypt_getkey_by_hash_fnptr); \ - status = (*gtmcrypt_getkey_by_hash_fnptr)(&xc_hash, &key_handle); \ - RC = gbl_encryption_ecode = (0 != status) ? ERR_CRYPTKEYFETCHFAILED : 0; \ - } \ + DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + if (0 != (status = (*gtmcrypt_getkey_by_hash_fnptr)(&xc_hash, &key_handle))) \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTKEYFETCHFAILED); \ + else \ + RC = 0; \ + ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + } else \ + RC = SET_REPEAT_MSG_MASK((SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED))); \ } -#define GTMCRYPT_HASH_CHK(hash, RC) \ +#define GTMCRYPT_HASH_CHK(CSA, hash, RC) \ { \ gtmcrypt_key_t handle; \ \ - GTMCRYPT_GETKEY(hash, handle, RC); \ + GTMCRYPT_GETKEY(CSA, hash, handle, RC); \ } -/* DSE CHANGE -FILE -ENCRYPTION_HASH will call the GTMCRYPT_HASH_GEN macro to reset the encryption hash in the database file - * header. But, before doing so, it would have encountered an error in db_init but instead of reporting the error in db_init, it - * stores the error code in gbl_encryption_ecode. But the GTMCRYPT_HASH_GEN macro cannot proceed if it finds that the error code is - * non-zero. The below GTMCRYPT_RESET_ERR macro will reset this global error code back to zero so that GTMCRYPT_HASH_GEN can - * proceed. However, we don't want to reset the error if the initialization failed because of a dlopen error as this would mean - * that we won't have the function pointers to encryption library APIs properly initialized which would be used by GTMCRYPT_HASH_GEN - * when we should ideally be reporting an error. */ -#define GTMCRYPT_RESET_HASH_MISMATCH_ERR \ -{ \ - GBLREF int4 gbl_encryption_ecode; \ - \ - error_def(ERR_CRYPTDLNOOPEN); \ - if (0 != gbl_encryption_ecode && (ERR_CRYPTDLNOOPEN != gbl_encryption_ecode)) \ - gbl_encryption_ecode = 0; \ -} - -#define GTMCRYPT_HASH_GEN(filename, filename_len, hash, RC) \ +#define GTMCRYPT_HASH_GEN(CSA, filename, filename_len, hash, RC) \ { \ xc_status_t status; \ xc_string_t xc_filename, xc_hash; \ gtmcrypt_key_t handle; \ - GBLREF int4 gbl_encryption_ecode; \ \ - error_def(ERR_CRYPTDLNOOPEN); \ - RC = gbl_encryption_ecode; \ - if (0 == RC || (ERR_CRYPTDLNOOPEN != RC)) \ + if (gtmcrypt_initialized) \ { \ PACKAGE_XCSTRING(xc_filename, filename, filename_len); \ PACKAGE_XCSTRING(xc_hash, hash, GTMCRYPT_HASH_LEN); \ - assert(NULL != gtmcrypt_getkey_by_name_fnptr); \ - status = (*gtmcrypt_getkey_by_name_fnptr)(&xc_filename, &handle); \ - GC_MARK_STATUS(status, RC, ERR_CRYPTKEYFETCHFAILED); \ - if (0 == RC) \ + DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + if (0 == (status = (*gtmcrypt_getkey_by_name_fnptr)(&xc_filename, &handle))) \ { \ - assert(NULL != gtmcrypt_hash_gen_fnptr); \ - status = (*gtmcrypt_hash_gen_fnptr)(handle, &xc_hash); \ - GC_MARK_STATUS(status, RC, ERR_CRYPTHASHGENFAILED); \ - if (0 == RC) \ + if (0 == (status = (*gtmcrypt_hash_gen_fnptr)(handle, &xc_hash))) \ + { \ memcpy(hash, xc_hash.address, GTMCRYPT_HASH_LEN); \ - } \ - } \ + RC = 0; \ + } else \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTHASHGENFAILED); \ + } else \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTKEYFETCHFAILED); \ + ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ + } else \ + RC = SET_REPEAT_MSG_MASK((SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED))); \ } -#define GTMCRYPT_ENCODE_FAST(key_handle, inbuf, inbuf_len, outbuf, RC) \ +#define GTMCRYPT_ENCRYPT(CSA, key_handle, inbuf, inbuf_len, outbuf, RC) \ { \ - GBLREF volatile int4 fast_lock_count; \ xc_string_t unencrypted_block, encrypted_block; \ xc_status_t status; \ - int save_fast_lock_count; \ - GBLREF int4 gbl_encryption_ecode; \ \ - RC = gbl_encryption_ecode; \ - if (0 == RC) \ + if (gtmcrypt_initialized && (GTMCRYPT_INVALID_KEY_HANDLE != key_handle)) \ { \ PACKAGE_XCSTRING(unencrypted_block, inbuf, inbuf_len); \ PACKAGE_XCSTRING(encrypted_block, outbuf, inbuf_len); \ - assert(NULL != gtmcrypt_encode_fnptr); \ - save_fast_lock_count = fast_lock_count; \ DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ - fast_lock_count++; \ - status = (*gtmcrypt_encode_fnptr)(key_handle, \ - &unencrypted_block, \ - &encrypted_block); \ + if (0 == (status = (*gtmcrypt_encrypt_fnptr)(key_handle, &unencrypted_block, &encrypted_block))) \ + RC = 0; \ + else \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED); \ ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ - GC_MARK_STATUS(status, RC, ERR_CRYPTOPFAILED); \ - fast_lock_count = save_fast_lock_count; \ - } \ + } else \ + RC = SET_REPEAT_MSG_MASK((SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED))); \ } -#define GTMCRYPT_DECODE_FAST(key_handle, inbuf, inbuf_len, outbuf, RC) \ +#define GTMCRYPT_DECRYPT(CSA, key_handle, inbuf, inbuf_len, outbuf, RC) \ { \ - GBLREF volatile int4 fast_lock_count; \ xc_string_t unencrypted_block, encrypted_block; \ xc_status_t status; \ - int save_fast_lock_count; \ - GBLREF int4 gbl_encryption_ecode; \ \ - RC = gbl_encryption_ecode; \ - if (0 == RC) \ + if (gtmcrypt_initialized && (GTMCRYPT_INVALID_KEY_HANDLE != key_handle)) \ { \ PACKAGE_XCSTRING(encrypted_block, inbuf, inbuf_len); \ PACKAGE_XCSTRING(unencrypted_block, outbuf, inbuf_len); \ - assert(NULL != gtmcrypt_decode_fnptr); \ - save_fast_lock_count = fast_lock_count; \ - fast_lock_count++; \ DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ - status = (*gtmcrypt_decode_fnptr)(key_handle, \ - &encrypted_block, \ - &unencrypted_block); \ + if (0 == (status = (*gtmcrypt_decrypt_fnptr)(key_handle, &encrypted_block, &unencrypted_block))) \ + RC = 0; \ + else \ + RC = SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED); \ ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ - GC_MARK_STATUS(status, RC, ERR_CRYPTOPFAILED); \ - fast_lock_count = save_fast_lock_count; \ - } \ + } else \ + RC = SET_REPEAT_MSG_MASK((SET_CRYPTERR_MASK(ERR_CRYPTOPFAILED))); \ } #define GTMCRYPT_CLOSE \ { \ - if (GTMCRYPT_INITIALIZED == gtmcrypt_init_state) \ + if (gtmcrypt_initialized) \ { \ + DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ (*gtmcrypt_close_fnptr)(); \ - gtmcrypt_init_state = GTMCRYPT_UNINITIALIZED; \ + gtmcrypt_initialized = FALSE; \ + ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \ } \ } diff --git a/sr_unix/gtmcrypt_dbk_ref.c b/sr_unix/gtmcrypt_dbk_ref.c index d618ec1..517051c 100644 --- a/sr_unix/gtmcrypt_dbk_ref.c +++ b/sr_unix/gtmcrypt_dbk_ref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,180 +11,132 @@ #define _FILE_OFFSET_BITS 64 /* Needed to compile gpgme client progs also with large file support */ -#include -#include -#include -#include +#include /* BYPASSOK -- Plugin doesn't have access to gtm_* header files */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include #include -#include #include #include /* gpgme functions */ #include /* gcry*_err_t */ #include "gtmxc_types.h" /* xc_string, xc_status_t and other callin interfaces xc_fileid */ #include "gtmcrypt_interface.h" /* Function prototypes for gtmcrypt*.* functions */ #include "gtmcrypt_ref.h" +#include "gtmcrypt_sym_ref.h" #include "gtmcrypt_dbk_ref.h" #include "gtmcrypt_pk_ref.h" -#include "gtmcrypt_sym_ref.h" -int num_entries; -db_key_map *db_map_root; -db_key_map **fast_lookup_entry; -extern char err_string[ERR_STRLEN]; -extern int can_prompt_passwd; +#define NEWLINE 0x0A -/* Cleanup the db key entries and also remove the plain text passwd stored there */ +GBLDEF int num_entries; +GBLREF int can_prompt_passwd; +GBLDEF gtm_dbkeys_tbl *tbl_head; +GBLDEF gtm_dbkeys_tbl **fast_lookup_entry; + +/* Free up the linked list of database-symmetric key association AFTER scrubbing off the contents of the raw symmetric key and + * its corresponding hash + */ void gc_dbk_scrub_entries() { - db_key_map *temp, *temp1; + gtm_dbkeys_tbl *cur, *temp; - temp = GC_DBK_GET_FIRST_ENTRY(); - /* Walk through the linked list and free each member of the structure.*/ - while (NULL != temp) + cur = tbl_head; + while (NULL != cur) { # ifdef USE_GCRYPT - if (temp->encr_key_handle) - gcry_cipher_close(temp->encr_key_handle); - if (temp->decr_key_handle) - gcry_cipher_close(temp->decr_key_handle); + if (!cur->symmetric_key_dirty) + { + if (cur->encr_key_handle) + gcry_cipher_close(cur->encr_key_handle); + if (cur->decr_key_handle) + gcry_cipher_close(cur->decr_key_handle); + } # endif - temp1 = GC_DBK_GET_NEXT_ENTRY(temp); - GC_FREE_DB_KEY_MAP(temp); /* Note, this will memset the key_string to 0 before free'ing */ - temp = temp1; + temp = cur->next; + GC_FREE_TBL_ENTRY(cur); /* Note, this will memset the symmetric_key to 0 before free'ing */ + cur = temp; } if (NULL != fast_lookup_entry) GC_FREE(fast_lookup_entry); -} - -/* Find out whether the db key file is modified since last time */ -xc_status_t gc_dbk_is_db_key_file_modified() -{ - struct stat stat_info; - char *gtm_dbkeys; - int status; - static time_t last_modified = 0; - - GC_GETENV(gtm_dbkeys, GTM_DBKEYS, status); - if (GC_FAILURE == status) - { - GC_ENV_UNSET_ERROR(GTM_DBKEYS); - return GC_FAILURE; - } - if (0 != stat(gtm_dbkeys, &stat_info) || (last_modified != stat_info.st_mtime)) - { - last_modified = stat_info.st_mtime; - return TRUE; - } - return FALSE; + num_entries = 0; } /* Given a xc_fileid, containing a unique description of the dat file, the function searches for it's * entry in the linked list. On unsuccessful search, returns NULL. */ -db_key_map* gc_dbk_get_entry_by_fileid(xc_fileid_ptr_t fileid) +gtm_dbkeys_tbl* gc_dbk_get_entry_by_fileid(xc_fileid_ptr_t fileid) { - db_key_map *cur = db_map_root; + gtm_dbkeys_tbl *cur = tbl_head; while (NULL != cur) { - if (!cur->fileid_dirty && (!cur->sym_key_dirty) && (gtm_is_file_identical_fptr(fileid, (cur->fileid)))) + if (!cur->fileid_dirty && (!cur->symmetric_key_dirty) && (gtm_is_file_identical_fptr(fileid, cur->fileid))) break; - cur = (db_key_map *)cur->next; + cur = (gtm_dbkeys_tbl *)cur->next; } return cur; } -/* Given a hash of the symmetric key, the function searches for the entry in the linked list that matches with the - * given hash - */ -db_key_map* gc_dbk_get_entry_by_hash(xc_string_t *hash) +/* Given a hash, the function returns the entry in the linked list that matches with the given hash. Otherwise, NULL is returned */ +gtm_dbkeys_tbl* gc_dbk_get_entry_by_hash(xc_string_t *hash) { - db_key_map *cur = db_map_root; - - assert(hash); - assert(hash->length); + gtm_dbkeys_tbl *cur = tbl_head; + assert(hash && (hash->length == GTMCRYPT_HASH_LEN)); while (NULL != cur) { - if (hash->length == cur->hash.length && (0 == memcmp(hash->address, cur->hash.address, hash->length))) + if ((hash->length == GTMCRYPT_HASH_LEN) && (0 == memcmp(hash->address, cur->symmetric_key_hash, GTMCRYPT_HASH_LEN))) break; - cur = (db_key_map *)cur->next; + cur = cur->next; } return cur; } -dbkeyfile_line_type gc_dbk_get_line_info (char *buf, char *data) +xc_status_t gc_dbk_fill_gtm_dbkeys_fname(char *fname) { - dbkeyfile_line_type line_type = ERROR_LINE_INFO; + char *ptr; + int status; + struct stat stat_buf; - if (!memcmp(buf, DAT_LINE_INDICATOR, DAT_LINE_INDICATOR_SIZE)) + if (ptr = getenv(GTM_DBKEYS)) { - strcpy(data, &buf[DAT_LINE_INDICATOR_SIZE]); /* The rest of the line is a file name */ - if ('\n' == data[strlen(data) - 1]) data[strlen(data) - 1] = '\0'; - line_type = DAT_LINE_INFO; - } else if (!memcmp(buf, KEY_LINE_INDICATOR, KEY_LINE_INDICATOR_SIZE)) - { - strcpy(data, &buf[KEY_LINE_INDICATOR_SIZE]); /* The rest of the line is a file name */ - if ('\n' == data[strlen(data) - 1]) data[strlen(data) - 1] = '\0'; - line_type = KEY_LINE_INFO; - } - return line_type; -} - -xc_status_t gc_dbk_load_gtm_dbkeys(FILE **gtm_dbkeys) -{ - char *ptr, dbkeys_filename[GTM_PATH_MAX]; - int status; - FILE *dbkeys_fp; - struct stat stat_buf; - - GC_GETENV(ptr, GTM_DBKEYS, status); - if (GC_SUCCESS == status) - { - if (0 == strlen(ptr)) + if (0 == STRLEN(ptr)) { - snprintf(err_string, ERR_STRLEN, "%s", "Environment variable gtm_dbkeys set to empty string"); + UPDATE_ERROR_STRING(ENV_EMPTY_ERROR, GTM_DBKEYS); return GC_FAILURE; - } - if (0 == stat(ptr, &stat_buf)) /* See if the environment variable points to a proper path */ + } else if (0 == stat(ptr, &stat_buf)) /* See if the environment variable points to a proper path */ { if (S_ISDIR(stat_buf.st_mode)) /* if directory */ - snprintf(dbkeys_filename, GTM_PATH_MAX, "%s/%s", ptr, DOT_GTM_DBKEYS); - else if (S_ISREG(stat_buf.st_mode)) /* if file */ - snprintf(dbkeys_filename, GTM_PATH_MAX, "%s", ptr); - else { - snprintf(err_string, ERR_STRLEN, "Unknown file type : %s", ptr); + SNPRINTF(fname, GTM_PATH_MAX, "%s/%s", ptr, DOT_GTM_DBKEYS); + } else if (S_ISREG(stat_buf.st_mode)) /* if file */ + { + SNPRINTF(fname, GTM_PATH_MAX, "%s", ptr); + } else + { + UPDATE_ERROR_STRING("%s is neither a directory nor a regular file", ptr); return GC_FAILURE; } - } else /* error if env variable present but couldn't stat */ - { - snprintf(err_string, ERR_STRLEN, "Cannot find DB keys file - %s", ptr); + } else if (ENOENT == errno) + { /* File doesn't exist */ + UPDATE_ERROR_STRING("Cannot find DB keys file - %s", ptr); + return GC_FAILURE; + } else + { /* Some other error */ + UPDATE_ERROR_STRING("Cannot find DB keys file - %s. %s", ptr, strerror(errno)); return GC_FAILURE; } - } else /* if env variable is undefined, then look for $HOME/.gtm_dbkeys */ + } else if (ptr = getenv(HOME)) { - GC_GETENV(ptr, "HOME", status); - snprintf(dbkeys_filename, GTM_PATH_MAX, "%s/%s", ptr, DOT_GTM_DBKEYS); - if (0 != stat(dbkeys_filename, &stat_buf)) - { - snprintf(err_string, - ERR_STRLEN, - "Environment variable gtm_dbkeys undefined. Cannot find %s/.gtm_dbkeys", - ptr); - return GC_FAILURE; - } - } - /* At this point we would have at least one form of the gtm_dbkeys in dbkeys_filename */ - status = GC_SUCCESS; - if (NULL != (dbkeys_fp = fopen(dbkeys_filename, "r"))) - *gtm_dbkeys = dbkeys_fp; - else + SNPRINTF(fname, GTM_PATH_MAX, "%s/%s", ptr, DOT_GTM_DBKEYS); + } else { - snprintf(err_string, ERR_STRLEN, "Cannot open DB keys file - %s", dbkeys_filename); - status = GC_FAILURE; + UPDATE_ERROR_STRING("Neither $"GTM_DBKEYS "nor $"HOME " is defined"); + return GC_FAILURE; } - return status; + return GC_SUCCESS; } /* Initialize the linked list with minimal things. For each pair of entries in the db key file, load the * file names into the linked list and validate the format of the entries. Returns error if the format is @@ -193,227 +145,228 @@ xc_status_t gc_dbk_load_gtm_dbkeys(FILE **gtm_dbkeys) */ xc_status_t gc_dbk_load_entries_from_file() { - FILE *dbkeys_fp = NULL; - db_key_map *node = NULL; - int current_state; - int start = TRUE, count = 0, status, all_done = FALSE; - int looking_for_dat_entry = 1, looking_for_key_entry = 2; - int line_no = 0; - char *prefix = "Error parsing database key file"; - char buf[GTM_PATH_MAX], data[GTM_PATH_MAX]; - dbkeyfile_line_type line_type; - /* Check for $gtm_dbkeys */ - if (0 != gc_dbk_load_gtm_dbkeys(&dbkeys_fp)) - return GC_FAILURE; + FILE *gtm_dbkeys_fp; + int current_state, count, status, space_cnt, line_no = 0, line_type, filename_len; + int looking_for_dat_entry = 1, looking_for_key_entry = 2, buflen, save_errno; + const char *prefix = "Error parsing database key file"; + char buf[LINE_MAX], gtm_dbkeys_fname[GTM_PATH_MAX]; + struct stat stat_info; + static time_t last_modified = 0; + gtm_dbkeys_tbl *node = NULL; + if (GC_SUCCESS != gc_dbk_fill_gtm_dbkeys_fname(>m_dbkeys_fname[0])) + return GC_FAILURE; + if (0 != stat(gtm_dbkeys_fname, &stat_info)) + { + save_errno = errno; + if (ENOENT == save_errno) + { + UPDATE_ERROR_STRING("Cannot find DB keys file - %s", gtm_dbkeys_fname); + } else + UPDATE_ERROR_STRING("Cannot find DB keys file - %s. %s", gtm_dbkeys_fname, strerror(save_errno)); + return GC_FAILURE; + } + if (last_modified == stat_info.st_mtime) + return GC_SUCCESS;/* Nothing changed since we last read it. So, return success */ + last_modified = stat_info.st_mtime; + if (NULL == (gtm_dbkeys_fp = fopen(gtm_dbkeys_fname, "r"))) + { + save_errno = errno; + UPDATE_ERROR_STRING("Cannot open DB keys file - %s. %s", gtm_dbkeys_fname, strerror(save_errno)); + return GC_FAILURE; + } /* Read the file and parse the contents and fill a mapping table */ /* Note the format of this dbkeys will be like this - - dat - key - dat - key - */ - /* To start with we are looking for a dat entry */ - current_state = looking_for_dat_entry; - GC_DBK_SET_FIRST_ENTRY(NULL); - while (!feof(dbkeys_fp)) + * dat + * key + * dat + * key + */ + current_state = looking_for_dat_entry; /* To start with we are looking for a database entry */ + if (tbl_head) { - - memset(buf, 0, GTM_PATH_MAX); - memset(data, 0, GTM_PATH_MAX); - - /* Skip past empty lines */ - while (1) + gc_dbk_scrub_entries(); /* free up the existing linked list as we are about to create a fresh one */ + tbl_head = NULL; + } + while (!feof(gtm_dbkeys_fp)) + { + if (NULL == fgets(buf, LINE_MAX, gtm_dbkeys_fp)) + break; + line_no++; + buflen = STRLEN(buf); + if (NEWLINE != buf[buflen - 1]) + { /* last character in the read buffer is not a newline implying that the line contains more than + * LINE_MAX characters. + */ + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. Entry at line: %d longer than %ld characters", prefix, line_no, LINE_MAX); + return GC_FAILURE; + } + buf[buflen - 1] = '\0'; /* strip off the newline at the end */ + space_cnt = 0; + while (isspace(buf[space_cnt])) /* BYPASSOK -- don't have access to gtm_ctype.h */ + space_cnt++; /* go past any whitespace characters */ + assert(space_cnt <= (buflen - 1)); + if ((0 == space_cnt) && ('\0' != buf[0])) { - if (!fgets(buf, GTM_PATH_MAX, dbkeys_fp)) + if (0 == memcmp(buf, DATABASE_LINE_INDICATOR, DATABASE_LINE_INDICATOR_SIZE)) { - /* If EOF is reached but the line_no din't move beyond 0, it means we have no entries - * in the db key file. */ - if (0 == line_no) - { - fclose(dbkeys_fp); - snprintf(err_string, - ERR_STRLEN, - "%s. %s", - prefix, - "No entries found in DB keys file."); - return GC_FAILURE; - } - /* At the end if we are looking for a key entry, then the last dat entry is unmatched*/ - if (current_state == looking_for_key_entry) - { - fclose(dbkeys_fp); - snprintf(err_string, - ERR_STRLEN, - "%s. No matching KEY entry found for DAT entry at line: %d", - prefix, - line_no); - return GC_FAILURE; - } - all_done = TRUE; - break; + filename_len = buflen - DATABASE_LINE_INDICATOR_SIZE; + line_type = DATABASE_LINE_INFO; } - if (buf[0] != '\0' && (buf[0] != '\n')) /* Non-Empty line */ + else if (0 == memcmp(buf, SYMMETRIC_KEY_LINE_INDICATOR, SYMMETRIC_KEY_LINE_INDICATOR_SIZE)) { - buf[strlen(buf) - 1] = '\0'; - break; + filename_len = buflen - SYMMETRIC_KEY_LINE_INDICATOR_SIZE; + line_type = SYMMETRIC_KEY_LINE_INFO; } else - line_no++; - } - if (all_done) break; - /* Figure out what kind of line are we going to deal with. */ - line_type = gc_dbk_get_line_info(buf, data); + line_type = -1; + } else if (space_cnt < (buflen - 1)) + line_type = -1; /* line doesn't consist entirely of spaces (but only has leading spaces) */ + else + continue; /* skip this line as it consists entirely of spaces -- blank line */ switch(line_type) { - case DAT_LINE_INFO: - line_no++; - /* We should have seen a key before seeing the next dat file */ - if (current_state == looking_for_key_entry && (FALSE == start)) + case DATABASE_LINE_INFO: + if (current_state == looking_for_key_entry) { - fclose(dbkeys_fp); - snprintf(err_string, - ERR_STRLEN, - "%s. At line %d: No matching KEY entry found for %s", - prefix, - line_no, - buf); + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. At line %d: Found DAT entry, expecting KEY entry", prefix, + line_no); + return GC_FAILURE; } - /* Now that we have seen a dat file, we will now be looking for a key entry */ + GC_ALLOCATE_TBL_ENTRY(node); + memcpy(node->database_fn, &buf[DATABASE_LINE_INDICATOR_SIZE], filename_len + 1); + assert('\0' == node->database_fn[filename_len]); + node->database_fn_len = filename_len; + node->next = tbl_head; + tbl_head = node; current_state = looking_for_key_entry; - start = FALSE; - GC_NEW_DB_KEYMAP(node); - GC_COPY_TO_XC_STRING(&node->db_name, data, strlen(data)); - node->next = (struct db_key_map*) db_map_root; - GC_DBK_SET_FIRST_ENTRY(node); break; - case KEY_LINE_INFO: - line_no++; - /* We should have seen a dat file before seeing a key file */ - if (!node && (current_state == looking_for_dat_entry)) + case SYMMETRIC_KEY_LINE_INFO: + if (current_state == looking_for_dat_entry) { - fclose(dbkeys_fp); - snprintf(err_string, - ERR_STRLEN, - "%s. At line %d: No matching DAT entry found for %s", - prefix, - line_no, - buf); + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. At line %d: Found KEY entry, expecting DAT entry", prefix, + line_no); return GC_FAILURE; } - /* Now that we have seen a key file, we will now be looking for a dat entry */ + assert(NULL != node); + memcpy(node->symmetric_key_fn, &buf[SYMMETRIC_KEY_LINE_INDICATOR_SIZE], filename_len + 1); + assert('\0' == node->symmetric_key_fn[filename_len]); + num_entries++; /* one set of entries processed */ current_state = looking_for_dat_entry; - num_entries++; - GC_COPY_TO_XC_STRING(&node->key_filename, data, strlen(data)); break; default: - line_no++; - fclose(dbkeys_fp); - snprintf(err_string, - ERR_STRLEN, - "%s. At line %d: %s does not start with 'dat '/'key '", - prefix, - line_no, - buf); + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. At line %d: %s does not start with 'dat '/'key '", prefix, line_no, buf); return GC_FAILURE; } } - GC_MALLOC(fast_lookup_entry, (SIZEOF(fast_lookup_entry) * num_entries), db_key_map*); - node = GC_DBK_GET_FIRST_ENTRY(); + if (!feof(gtm_dbkeys_fp)) + { + save_errno = errno; + UPDATE_ERROR_STRING("Error while reading from database key file. %s", strerror(save_errno)); + return GC_FAILURE; + } else if (0 == line_no) + { /* EOF reached, but did not go past the first line -- no entries in database key file */ + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. No entries found in DB keys file.", prefix); + return GC_FAILURE; + } else if (current_state == looking_for_key_entry) + { /* last database file entry has no matching symmetric key file entry */ + fclose(gtm_dbkeys_fp); + UPDATE_ERROR_STRING("%s. No matching KEY entry found for DAT entry at line: %d", prefix, line_no); + return GC_FAILURE; + } + GC_MALLOC(fast_lookup_entry, (SIZEOF(fast_lookup_entry) * num_entries), gtm_dbkeys_tbl*); + node = tbl_head; + count = 0; while (NULL != node) { node->index = count; fast_lookup_entry[count] = node; count++; - node = GC_DBK_GET_NEXT_ENTRY(node); + node = node->next; } assert(count == num_entries); - fclose(dbkeys_fp); + fclose(gtm_dbkeys_fp); return GC_SUCCESS; } xc_status_t gc_dbk_fill_sym_key_and_hash(xc_fileid_ptr_t req_fileid, char *req_hash) { - db_key_map *cur; - int status, concerns_current_file; - xc_fileid_ptr_t db_fileid; + gtm_dbkeys_tbl *cur; + int status, concerns_current_file, skip_entry, plain_text_length; + xc_fileid_ptr_t db_fileid; + xc_string_t filename; - cur = GC_DBK_GET_FIRST_ENTRY(); + cur = tbl_head; while (NULL != cur) { db_fileid = NULL; - if (TRUE == cur->fileid_dirty) + if (cur->fileid_dirty) { - if (TRUE == gtm_filename_to_id_fptr(&(cur->db_name), &db_fileid)) + filename.length = cur->database_fn_len; + filename.address = cur->database_fn; + if (TRUE == gtm_filename_to_id_fptr(&filename, &db_fileid)) { cur->fileid_dirty = FALSE; cur->fileid = db_fileid; } } - if (TRUE == cur->sym_key_dirty) /* Need to fill sym key value */ + if (cur->symmetric_key_dirty) /* Need to fill sym key value */ { + skip_entry = FALSE; /* Before decrypting the key, let's see if the gtm_passwd in the environment has changed since * the last time we read from the environment. This way if the user had originally entered a wrong - * password and if he is in MUMPS and changes the password through a external call then we should - * be using the new password rather than the old one which might still be hanging in the environment. */ + * password and if he/she is in MUMPS and changes the password through an external call then we should + * be using the new password rather than the old one which might still be hanging in the environment. + */ gc_pk_crypt_prompt_passwd_if_needed(can_prompt_passwd); - GC_PK_GET_DECRYPTED_KEY(cur->key_string, status); - - /* If we failed because of a gtm_passwd being wrong we wouldn't want to continue any further although it - * might not concern for the current file. */ - if (GPG_ERR_BAD_PASSPHRASE == status) - return GC_FAILURE; - + status = gc_pk_get_decrypted_key(cur->symmetric_key_fn, cur->symmetric_key, &plain_text_length); concerns_current_file = (NULL != req_fileid && (gtm_is_file_identical_fptr(cur->fileid, req_fileid))); - /* Eventhough we may have an encountered error in the above decryption, we report only when it is concerned - * with the current dat file being used. For other files, we silently ignore the error, with a hope that by - * the time the database file is accessed, db key file would have been updated appropriately by the user. - */ - if (0 != status && concerns_current_file) - return GC_FAILURE; - - /* It could be possible that the decryption din't return any error but plain_text_length happens to - * be zero. So, we verify it and return error in case the length is zero. Again we make sure that we return - * the error only when it concerned with the current dat file. - */ - if (0 == cur->key_string.length && concerns_current_file) - { - snprintf(err_string, ERR_STRLEN, "Symmetric key %s found to be empty", cur->key_filename.address); - return GC_FAILURE; - } - - /* If we fall through here, it means that we have encountered an error for a database which is not of - * concern at this moment. So, we continue with the next database. */ if (0 != status) { - cur = GC_DBK_GET_NEXT_ENTRY(cur); - continue; + /* If we failed because of wrong we password OR we are processing an entry that concerns the file + * for which we are called for, don't continue any further + */ + if ((GPG_ERR_BAD_PASSPHRASE == status) || concerns_current_file) + return GC_FAILURE; + skip_entry = TRUE; + } else if (0 == plain_text_length) + { /* It's possible that the decryption didn't encounter error but the plain text length is 0 */ + if (concerns_current_file) + { + UPDATE_ERROR_STRING("Symmetric key %s found to be empty", cur->symmetric_key_fn); + return GC_FAILURE; + } + skip_entry = TRUE; + } + if (!skip_entry) + { /* Everything is fine, compute the hash for the key */ + GC_PK_COMPUTE_HASH(cur->symmetric_key_hash, cur->symmetric_key); + GC_SYM_CREATE_HANDLES(cur); + cur->symmetric_key_dirty = FALSE; + if (concerns_current_file + || (NULL != req_hash && (0 == memcmp(cur->symmetric_key_hash, req_hash, GTMCRYPT_HASH_LEN)))) + { /* Processed the entry for which the function was called or found a matching hash. Return */ + return GC_SUCCESS; + } } - - /* If everything is fine, compute the hash for the key */ - GC_PK_COMPUTE_HASH(cur->hash, cur->key_string); - GC_SYM_CREATE_HANDLES(cur); - cur->sym_key_dirty = FALSE; - - /* If we have found a matching entry for the hash/fileid that we requested for, return immediately with - * GC_SUCCESS */ - if (concerns_current_file - || (NULL != req_hash && (0 == memcmp(cur->hash.address, req_hash, GTMCRYPT_HASH_LEN)))) - return GC_SUCCESS; } - cur = GC_DBK_GET_NEXT_ENTRY(cur); + cur = cur->next; } return GC_SUCCESS; } -void gc_dbk_get_hash(db_key_map *entry, xc_string_t *hash) +void gc_dbk_get_hash(gtm_dbkeys_tbl *entry, xc_string_t *hash) { - /*Make sure the reference block that is being passed is already allocated */ assert(hash->address); assert(NULL != entry); - memcpy(hash->address, entry->hash.address, GTMCRYPT_HASH_LEN); + memcpy(hash->address, entry->symmetric_key_hash, GTMCRYPT_HASH_LEN); hash->length = GTMCRYPT_HASH_LEN; } diff --git a/sr_unix/gtmcrypt_dbk_ref.h b/sr_unix/gtmcrypt_dbk_ref.h index db87684..238b6c4 100644 --- a/sr_unix/gtmcrypt_dbk_ref.h +++ b/sr_unix/gtmcrypt_dbk_ref.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,106 +12,99 @@ #ifndef GTMCRYPT_DBK_REF_H #define GTMCRYPT_DBK_REF_H -typedef struct +#define DATABASE_LINE_INFO 0 +#define SYMMETRIC_KEY_LINE_INFO 1 +#define DATABASE_LINE_INDICATOR "dat " +#define SYMMETRIC_KEY_LINE_INDICATOR "key " +#define DATABASE_LINE_INDICATOR_SIZE (SIZEOF(DATABASE_LINE_INDICATOR) - 1) +#define SYMMETRIC_KEY_LINE_INDICATOR_SIZE (SIZEOF(SYMMETRIC_KEY_LINE_INDICATOR) - 1) +#ifdef LINE_MAX +#undef LINE_MAX +#endif +#define LINE_MAX (GTM_PATH_MAX + DATABASE_LINE_INDICATOR_SIZE + 2) /* 2 is just for safety */ + + +typedef struct gtm_dbkeys_tbl_struct { - xc_string_t db_name, key_filename; /* name of the database and corresponding key found in the db key file */ - xc_string_t key_string, hash; /* plain text key and it's hash */ - xc_fileid_ptr_t fileid; /* if valid, unique file id representation of the database path */ - int fileid_dirty, sym_key_dirty; /* indicates if the db and the key file are valid accessible path */ - int index; /* A positive integer (initialized to -1) indicating the ith entry in the db key - * file. This value is returned to the caller and subsequently passed to the - * plugin to get the key for the corresponding database. */ - struct db_key_map *next; /* Pointer to the next entry in the linked list */ - crypt_key_t encr_key_handle, decr_key_handle; /* Pointer to the actual key handles typedef'ed to the underlying - * encryption library. */ -}db_key_map; + struct gtm_dbkeys_tbl_struct *next; + int fileid_dirty; + int symmetric_key_dirty; + int index; + int database_fn_len; + char database_fn[GTM_PATH_MAX + 1]; + char symmetric_key_fn[GTM_PATH_MAX + 1]; + unsigned char symmetric_key[SYMMETRIC_KEY_MAX + 1]; + unsigned char symmetric_key_hash[GTMCRYPT_HASH_LEN + 1]; + xc_fileid_ptr_t fileid; + crypt_key_t encr_key_handle; + crypt_key_t decr_key_handle; +} gtm_dbkeys_tbl; -void gc_dbk_scrub_entries(void); -xc_status_t gc_dbk_is_db_key_file_modified(void); -db_key_map* gc_dbk_get_entry_by_fileid(xc_fileid_ptr_t fileid); -db_key_map* gc_dbk_get_entry_by_hash(xc_string_t *hash); -dbkeyfile_line_type gc_dbk_get_line_info (char *buf, char *data); -xc_status_t gc_dbk_load_gtm_dbkeys(FILE **gtm_dbkeys); -xc_status_t gc_dbk_load_entries_from_file(void); -xc_status_t gc_dbk_fill_sym_key_and_hash(xc_fileid_ptr_t req_fileid, char *req_hash); -void gc_dbk_get_hash(db_key_map *entry, xc_string_t *hash); + +void gc_dbk_scrub_entries(void); +gtm_dbkeys_tbl* gc_dbk_get_entry_by_fileid(xc_fileid_ptr_t fileid); +gtm_dbkeys_tbl* gc_dbk_get_entry_by_hash(xc_string_t *hash); +xc_status_t gc_dbk_fill_gtm_dbkeys_fname(char *fname); +xc_status_t gc_dbk_load_entries_from_file(void); +xc_status_t gc_dbk_fill_sym_key_and_hash(xc_fileid_ptr_t req_fileid, char *req_hash); +void gc_dbk_get_hash(gtm_dbkeys_tbl *entry, xc_string_t *hash); -#define GC_FREE_DB_KEY_MAP(X) \ -{ \ - GC_FREE((X)->db_name.address); \ - GC_FREE((X)->key_filename.address); \ - memset((X)->key_string.address, 0, GTM_KEY_MAX);\ - GC_FREE((X)->key_string.address); \ - GC_FREE((X)->hash.address); \ - gtm_xcfileid_free_fptr((X)->fileid); \ - GC_FREE(X); \ +#define GC_FREE_TBL_ENTRY(X) \ +{ \ + gtm_xcfileid_free_fptr((X)->fileid); \ + memset((X)->symmetric_key, 0, SYMMETRIC_KEY_MAX); \ + memset((X)->symmetric_key_hash, 0, GTMCRYPT_HASH_LEN); \ + GC_FREE(X); \ } -#define GC_NEW_DB_KEYMAP(X) \ -{ \ - GC_MALLOC(X, SIZEOF(db_key_map), db_key_map); \ - memset(X, 0, SIZEOF(db_key_map)); \ - GC_MALLOC(X->db_name.address, GTM_PATH_MAX, char); \ - memset((X)->db_name.address, 0, GTM_PATH_MAX); \ - GC_MALLOC(X->key_filename.address, GTM_PATH_MAX, char); \ - memset((X)->key_filename.address, 0, GTM_PATH_MAX); \ - GC_MALLOC(X->key_string.address, GTM_PATH_MAX, char); \ - memset((X)->key_string.address, 0, GTM_KEY_MAX); \ - GC_MALLOC(X->hash.address, GTMCRYPT_HASH_LEN, char); \ - memset((X)->hash.address, 0, GTMCRYPT_HASH_LEN); \ - (X)->fileid_dirty = TRUE; \ - (X)->sym_key_dirty = TRUE; \ - (X)->fileid = NULL; \ - (X)->index = 0; \ +#define GC_ALLOCATE_TBL_ENTRY(X) \ +{ \ + GC_MALLOC((X), SIZEOF(gtm_dbkeys_tbl), gtm_dbkeys_tbl); \ + (X)->fileid_dirty = TRUE; \ + (X)->symmetric_key_dirty = TRUE; \ + (X)->fileid = NULL; \ + (X)->index = 0; \ } -#define GC_DBK_LOAD_KEY_FILE \ -{ \ - if (0 != gc_dbk_load_entries_from_file()) \ - return GC_FAILURE; \ -} - -/* After the preliminary search, if we haven't found our entry in the in-memory linked list for the - * given hash/fileid, we try reloading the db key file(if it has been changed since last time) and then - * we re-organize our in-memory linked list and try to search again. +/* After the preliminary search, if we haven't found our entry in the in-memory linked list for the given hash/fileid, we try + * reloading the db key file (just in case it has been changed since last time) and re-organize our in-memory linked list */ -#define GC_DBK_RELOAD_IF_NEEDED(entry, RC, fileid, req_hash) \ -{ \ - if (NULL == entry) \ - { \ - if (TRUE == gc_dbk_is_db_key_file_modified()) \ - GC_DBK_LOAD_KEY_FILE; \ - RC = gc_dbk_fill_sym_key_and_hash(fileid, req_hash); \ - } \ +#define GC_DBK_RELOAD_IF_NEEDED(entry, RC, fileid, req_hash) \ +{ \ + if (NULL == entry) \ + { \ + if (0 != gc_dbk_load_entries_from_file()) \ + return GC_FAILURE; \ + RC = gc_dbk_fill_sym_key_and_hash(fileid, req_hash); \ + } \ } -#define GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, ret) \ -{ \ - int idx; \ - \ - idx = (int)handle; \ - if (idx < 0 || (idx > num_entries)) \ - { \ - snprintf(err_string, ERR_STRLEN, "%s", "Encryption handle corrupted."); \ - entry = NULL; \ - return ret; \ - } else \ - entry = (db_key_map *)fast_lookup_entry[idx]; \ +#define GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, ret) \ +{ \ + GBLREF int num_entries; \ + GBLREF gtm_dbkeys_tbl **fast_lookup_entry; \ + \ + int idx; \ + \ + idx = (int)handle; \ + if (idx < 0 || (idx > num_entries)) \ + { \ + UPDATE_ERROR_STRING("Encryption handle corrupted."); \ + entry = NULL; \ + return ret; \ + } else \ + entry = (gtm_dbkeys_tbl *)fast_lookup_entry[idx]; \ } -#define GC_DBK_FILENAME_TO_ID(filename, fileid) \ -{ \ - if (TRUE != gtm_filename_to_id_fptr(filename, &fileid)) \ - { \ - snprintf(err_string, ERR_STRLEN, "database file %s not found", filename->address); \ - return GC_FAILURE; \ - } \ +#define GC_DBK_FILENAME_TO_ID(filename, fileid) \ +{ \ + if (TRUE != gtm_filename_to_id_fptr(filename, &fileid)) \ + { \ + UPDATE_ERROR_STRING("Database file %s not found", filename->address); \ + return GC_FAILURE; \ + } \ } -#define GC_DBK_SET_FIRST_ENTRY(cur) db_map_root = (db_key_map *)cur -#define GC_DBK_GET_FIRST_ENTRY() db_map_root -#define GC_DBK_GET_NEXT_ENTRY(cur) (db_key_map *) cur->next - #endif /* GTMCRYPT_DBK_REF_H */ diff --git a/sr_unix/gtmcrypt_entry.c b/sr_unix/gtmcrypt_entry.c index 2421e71..7ad8860 100644 --- a/sr_unix/gtmcrypt_entry.c +++ b/sr_unix/gtmcrypt_entry.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,9 +12,10 @@ #include "mdef.h" #include "gtm_string.h" -#include "gtm_limits.h" +#include "gtm_limits.h" /* for GTM_PATH_MAX */ #include +#include #include "lv_val.h" /* needed for "fgncal.h" */ #include "fgncal.h" /* needed for COPY_DLLERR_MSG() */ @@ -23,72 +24,95 @@ #include "gtm_stdlib.h" #include "real_len.h" #include "gtmcrypt.h" +#include "iosp.h" /* for SS_NORMAL */ +#include "trans_log_name.h" #ifndef GTM_DIST #define GTM_DIST "gtm_dist" #endif +#define GTM_CRYPT_PLUGIN "$gtm_crypt_plugin" +#define MAX_GTMCRYPT_PLUGIN_STR_LEN (SIZEOF(GTMCRYPT_LIBNAME) * 4) +#define PLUGIN_DIR_NAME "plugin" GBLREF char dl_err[MAX_ERRSTR_LEN]; -GBLREF int4 gbl_encryption_ecode; +error_def(ERR_CRYPTDLNOOPEN); +error_def(ERR_GTMDISTUNDEF); -void gtmcrypt_entry() +uint4 gtmcrypt_entry() { - char *libname, err_msg[MAX_ERRSTR_LEN]; - void_ptr_t handle; - char_ptr_t err_str; - char *gtmcryptlib_fname[] = { - GTMCRYPT_INIT_FNAME, - GTMCRYPT_CLOSE_FNAME, - GTMCRYPT_HASH_GEN_FNAME, - GTMCRYPT_ENCODE_FNAME, - GTMCRYPT_DECODE_FNAME, - GTMCRYPT_GETKEY_BY_NAME, - GTMCRYPT_GETKEY_BY_HASH, - GTMCRYPT_STRERROR - }; - void **gtmcryptlib_fptr[] = { - (void **)>mcrypt_init_fnptr, - (void **)>mcrypt_close_fnptr, - (void **)>mcrypt_hash_gen_fnptr, - (void **)>mcrypt_encode_fnptr, - (void **)>mcrypt_decode_fnptr, - (void **)>mcrypt_getkey_by_name_fnptr, - (void **)>mcrypt_getkey_by_hash_fnptr, - (void **)>mcrypt_strerror_fnptr - }; - int findx; - int num_dlsyms = SIZEOF(gtmcryptlib_fptr) / SIZEOF(gtmcryptlib_fptr[0]); /* number of functions in library */ - void *fptr; - char *gtm_dist_path; - char libpath[GTM_PATH_MAX]; + void_ptr_t handle, fptr; + char_ptr_t err_str, env_ptr, libname_ptr, libpath_ptr; + char *gtmcryptlib_fname[] = { + GTMCRYPT_INIT_FNAME, + GTMCRYPT_CLOSE_FNAME, + GTMCRYPT_HASH_GEN_FNAME, + GTMCRYPT_ENCRYPT_FNAME, + GTMCRYPT_DECRYPT_FNAME, + GTMCRYPT_GETKEY_BY_NAME, + GTMCRYPT_GETKEY_BY_HASH, + GTMCRYPT_STRERROR + }; + void **gtmcryptlib_fptr[] = { + (void **)>mcrypt_init_fnptr, + (void **)>mcrypt_close_fnptr, + (void **)>mcrypt_hash_gen_fnptr, + (void **)>mcrypt_encrypt_fnptr, + (void **)>mcrypt_decrypt_fnptr, + (void **)>mcrypt_getkey_by_name_fnptr, + (void **)>mcrypt_getkey_by_hash_fnptr, + (void **)>mcrypt_strerror_fnptr + }; + int findx, num_dlsyms, plugin_dir_len, save_errno; + char libpath[GTM_PATH_MAX], buf[MAX_GTMCRYPT_PLUGIN_STR_LEN], plugin_dir_path[GTM_PATH_MAX]; + char resolved_libpath[GTM_PATH_MAX], resolved_gtmdist[GTM_PATH_MAX]; + mstr trans, env_var = {0, SIZEOF(GTM_CRYPT_PLUGIN) - 1, GTM_CRYPT_PLUGIN}; - error_def(ERR_CRYPTDLNOOPEN); - error_def(ERR_GTMDISTUNDEF); - if (NULL == (gtm_dist_path = getenv(GTM_DIST))) + if (NULL == (env_ptr = getenv(GTM_DIST))) rts_error(VARLSTCNT(1) ERR_GTMDISTUNDEF); - - memset(libpath, 0, GTM_PATH_MAX); - SNPRINTF(libpath, GTM_PATH_MAX, "%s/%s/%s", gtm_dist_path, "plugin", GTMCRYPT_LIBNAME); - - gbl_encryption_ecode = 0; - handle = dlopen(libpath, GTMCRYPT_LIBFLAGS); + if (NULL == realpath(env_ptr, &resolved_gtmdist[0])) + { + save_errno = errno; + SNPRINTF(dl_err, MAX_ERRSTR_LEN, "Failed to find symbolic link for %s. %s", env_ptr, STRERROR(save_errno)); + return ERR_CRYPTDLNOOPEN; + } + SNPRINTF(plugin_dir_path, GTM_PATH_MAX, "%s/%s", resolved_gtmdist, PLUGIN_DIR_NAME); + plugin_dir_len = STRLEN(plugin_dir_path); + if ((SS_NORMAL != TRANS_LOG_NAME(&env_var, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)) || (0 >= trans.len)) + { /* Either $gtm_crypt_plugin is not defined in the environment variable OR it is set to null-string. Fall-back to + * using libgtmcrypt.so + */ + libname_ptr = GTMCRYPT_LIBNAME; + } else + libname_ptr = &buf[0]; /* value of $gtm_crypt_plugin */ + SNPRINTF(libpath, GTM_PATH_MAX, "%s/%s", plugin_dir_path, libname_ptr); + if (NULL == realpath(&libpath[0], &resolved_libpath[0])) + { + save_errno = errno; + SNPRINTF(dl_err, MAX_ERRSTR_LEN, "Failed to find symbolic link for %s. %s", libpath, STRERROR(save_errno)); + return ERR_CRYPTDLNOOPEN; + } + /* Symbolic link found. dlopen resolved_libpath */ + if (0 != memcmp(&resolved_libpath[0], plugin_dir_path, plugin_dir_len)) + { /* resolved_path doesn't contain $gtm_dist/plugin as the prefix */ + SNPRINTF(dl_err, MAX_ERRSTR_LEN, "Symbolic link for %s must be relative to %s", libpath, plugin_dir_path); + return ERR_CRYPTDLNOOPEN; + } + handle = dlopen(&resolved_libpath[0], GTMCRYPT_LIBFLAGS); if (NULL == handle) { COPY_DLLERR_MSG(err_str, dl_err); - gbl_encryption_ecode = ERR_CRYPTDLNOOPEN; /* library initialization failed */ - return; + return ERR_CRYPTDLNOOPEN; } - + num_dlsyms = ARRAYSIZE(gtmcryptlib_fptr); /* number of functions to be dlsym'ed */ for(findx = 0; findx < num_dlsyms; ++findx) { fptr = (void *)dlsym(handle, gtmcryptlib_fname[findx]); if (NULL == fptr) { COPY_DLLERR_MSG(err_str, dl_err); - gbl_encryption_ecode = ERR_CRYPTDLNOOPEN; /* library initialization failed */ - return; + return ERR_CRYPTDLNOOPEN; } *gtmcryptlib_fptr[findx] = fptr; } - return; + return 0; } diff --git a/sr_unix/gtmcrypt_interface.h b/sr_unix/gtmcrypt_interface.h index 22f52dc..2fdf64d 100644 --- a/sr_unix/gtmcrypt_interface.h +++ b/sr_unix/gtmcrypt_interface.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,8 +15,8 @@ xc_status_t gtmcrypt_init(int); xc_status_t gtmcrypt_close(void); xc_status_t gtmcrypt_hash_gen(gtmcrypt_key_t, xc_string_t *); -xc_status_t gtmcrypt_encode(gtmcrypt_key_t, xc_string_t *, xc_string_t *); -xc_status_t gtmcrypt_decode(gtmcrypt_key_t, xc_string_t *, xc_string_t *); +xc_status_t gtmcrypt_encrypt(gtmcrypt_key_t, xc_string_t *, xc_string_t *); +xc_status_t gtmcrypt_decrypt(gtmcrypt_key_t, xc_string_t *, xc_string_t *); xc_status_t gtmcrypt_getkey_by_hash(xc_string_t *, gtmcrypt_key_t *); xc_status_t gtmcrypt_getkey_by_name(xc_string_t *, gtmcrypt_key_t *); char *gtmcrypt_strerror(void); diff --git a/sr_unix/gtmcrypt_pk_ref.c b/sr_unix/gtmcrypt_pk_ref.c index d4e4d08..87f769e 100644 --- a/sr_unix/gtmcrypt_pk_ref.c +++ b/sr_unix/gtmcrypt_pk_ref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,12 +11,12 @@ #define _FILE_OFFSET_BITS 64 /* Needed to compile gpgme client progs also with large file support */ -#include -#include -#include -#include +#include /* BYPASSOK -- Plugin doesn't have access to gtm_* header files */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ #include -#include #include #include #include @@ -27,15 +27,13 @@ #include "gtmxc_types.h" /* xc_string, xc_status_t and other callin interfaces xc_fileid */ #include "gtmcrypt_interface.h" /* Function prototypes for gtmcrypt*.* functions */ #include "gtmcrypt_ref.h" -#include "gtmcrypt_pk_ref.h" #include "gtmcrypt_sym_ref.h" +#include "gtmcrypt_pk_ref.h" -static char *gtm_passwd; -static char *gtm_passwd_env; -int can_prompt_passwd; -gpgme_ctx_t pk_crypt_ctx; - -extern char err_string[ERR_STRLEN]; +STATICDEF char *gtm_passwd; +STATICDEF char *gtm_passwd_env; +GBLDEF int can_prompt_passwd; +GBLDEF gpgme_ctx_t pk_crypt_ctx; #ifdef __sparc /* for some reason sun does not provide a prototype */ int setenv(const char* name, const char *value, int overwrite); @@ -61,74 +59,66 @@ int setenv(const char* name, const char *value, int overwrite); int gc_pk_mask_unmask_passwd(char *in, char *out, int len) { - char *ptr; char tmp[GTM_PASSPHRASE_MAX], mumps_ex[GTM_PATH_MAX], tobehashed[GTM_PASSPHRASE_MAX], hash[GTMCRYPT_HASH_LEN]; - int passwd_len, ilen, status, i; + char *ptr, *mmap_addrs; + int passwd_len, ilen, status, i, save_errno, fd, have_hash; struct stat stat_info; - int fd; - char *p; - int have_hash; have_hash = FALSE; passwd_len = len < GTM_PASSPHRASE_MAX ? len : GTM_PASSPHRASE_MAX; - GC_GETENV(ptr, "gtm_obfuscation_key", status); - if (GC_SUCCESS == status) + if (ptr = getenv(GTM_OBFUSCATION_KEY)) { fd = open(ptr, O_RDONLY); - if (fd != -1) - if (fstat(fd, &stat_info) != -1) - if (S_ISREG(stat_info.st_mode)) - { - p = mmap(0,stat_info.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (p != MAP_FAILED) - { -# ifdef USE_OPENSSL - EVP_Digest(p, stat_info.st_size, (unsigned char *)hash, NULL, EVP_sha512(), NULL); -# elif defined USE_GCRYPT - GC_SYM_INIT; - gcry_md_hash_buffer(GCRY_MD_SHA512, hash, p, stat_info.st_size ); -# endif - have_hash = TRUE; - munmap(p, stat_info.st_size); - } - } - close(fd); + if ((-1 != fd) && (-1 != fstat(fd, &stat_info)) && S_ISREG(stat_info.st_mode)) + { /* File pointed by $gtm_obfuscation_key exists and is a regular file */ + mmap_addrs = mmap(0,stat_info.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (MAP_FAILED != mmap_addrs) + { +# ifdef USE_OPENSSL + EVP_Digest(mmap_addrs, stat_info.st_size, (unsigned char *)hash, NULL, EVP_sha512(), NULL); +# elif defined USE_GCRYPT + GC_SYM_INIT; + gcry_md_hash_buffer(GCRY_MD_SHA512, hash, mmap_addrs, stat_info.st_size ); +# endif + have_hash = TRUE; + munmap(mmap_addrs, stat_info.st_size); + } + close(fd); + } } - if (!have_hash) { memset(tobehashed, 0, passwd_len); memset(mumps_ex, 0, GTM_PATH_MAX); - GC_GETENV(ptr, "USER", status); - if (GC_SUCCESS != status) + if (!(ptr = getenv(USER))) { - GC_ENV_UNSET_ERROR("USER"); + UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, USER); return GC_FAILURE; } else { strncpy(tobehashed, ptr, passwd_len); - GC_GETENV(ptr, "gtm_dist", status); - if (GC_SUCCESS != status) + if (!(ptr = getenv(GTM_DIST))) { - GC_ENV_UNSET_ERROR("gtm_dist"); + UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, GTM_DIST); return GC_FAILURE; } else { - sprintf(mumps_ex, "%s/%s", ptr, "mumps"); + SNPRINTF(mumps_ex, GTM_PATH_MAX, "%s/%s", ptr, "mumps"); if (0 == stat(mumps_ex, &stat_info)) { - sprintf(tmp, "%ld", (long) stat_info.st_ino); - ilen = (int)strlen(tmp); + SNPRINTF(tmp, GTM_PASSPHRASE_MAX, "%ld", (long) stat_info.st_ino); + ilen = (int)STRLEN(tmp); if (ilen < passwd_len) strncpy(tobehashed + (passwd_len - ilen), tmp, ilen); else strncpy(tobehashed, tmp, passwd_len); } else { - sprintf(err_string, "Cannot find MUMPS executable in %s", ptr); + save_errno = errno; + UPDATE_ERROR_STRING("Cannot find MUMPS executable in %s - %s", ptr, strerror(save_errno)); return GC_FAILURE; } # ifdef USE_OPENSSL @@ -160,7 +150,7 @@ int gc_pk_mask_unmask_passwd_interlude(int nparm, gtm_string_t *in, gtm_string_t void gc_pk_scrub_passwd() { /* Nullify the key strings, so that any generated cores will not contain the unencrypted keys */ - memset(gtm_passwd, 0, strlen(gtm_passwd)); + memset(gtm_passwd, 0, STRLEN(gtm_passwd)); /* Free gtm_passwd and gtm_passwd_env variables */ if (NULL != gtm_passwd) GC_FREE(gtm_passwd); @@ -181,11 +171,11 @@ void gc_pk_crypt_load_gtmci_env() const char *gtmcrypt_tab_file = "gtmcrypt.tab"; /* Name of the tab file */ static char gtmcrypt_tab_path[TAB_NAME_MAX]; /* Needs to be in scope always */ - gtm_dist_value = getenv("gtm_dist"); + gtm_dist_value = getenv(GTM_DIST); assert(NULL != gtm_dist_value); - assert(0 != strlen(gtm_dist_value)); + assert(0 != STRLEN(gtm_dist_value)); - sprintf(gtmcrypt_tab_path, "%s/%s/%s", gtm_dist_value, "plugin/gtmcrypt", gtmcrypt_tab_file); + SNPRINTF(gtmcrypt_tab_path, TAB_NAME_MAX, "%s/%s/%s", gtm_dist_value, "plugin/gtmcrypt", gtmcrypt_tab_file); setenv(GTMCI, gtmcrypt_tab_path, TRUE); } @@ -196,30 +186,25 @@ void gc_pk_crypt_load_gtmci_env() xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) { - /* Name of the mumps password routine that will be called. */ - const char *password_routine = "getpass"; - /* Points to the value that was held in GTMCI prior to modification. */ - char *save_gtmci, tgtm_passwd[GTM_PASSPHRASE_MAX]; - char *lgtm_passwd; + const char *password_routine = "getpass"; /* Name of the mumps password routine that will be called. */ + char *save_gtmci; /* Points to the value that was held in GTMCI prior to modification. */ + char *lgtm_passwd, tgtm_passwd[GTM_PASSPHRASE_MAX]; int status, len; gtm_int_t pass_len = GTM_PASSPHRASE_MAX; can_prompt_passwd = prompt_passwd; - GC_GETENV(lgtm_passwd, GTM_PASSWD, status); - /* This is an error condition. We have hit a encrypted database but the env doesn't have gtm_passwd set. */ - if (0 != status) + if (!(lgtm_passwd = getenv(GTM_PASSWD))) { - GC_ENV_UNSET_ERROR(GTM_PASSWD); + UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, GTM_PASSWD); return GC_FAILURE; } - /* If the masked password in the environment is same as we have in memory then it means that the password * has not been changed and so the actual value in the gtm_passwd is still good to use. */ if (NULL != gtm_passwd_env && (0 == strcmp(gtm_passwd_env, lgtm_passwd))) return GC_SUCCESS; /* If the password is set to an appropriate value, then we know for sure it's in it's masked form. So, we unmask it * and set it in the global variable and return to the caller. */ - if (0 < (len = (int)strlen(lgtm_passwd))) + if (0 < (len = (int)STRLEN(lgtm_passwd))) { if (gtm_passwd) GC_FREE(gtm_passwd); @@ -236,7 +221,7 @@ xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) * the one in the memory */ if (NULL != gtm_passwd_env) GC_FREE(gtm_passwd_env); - GC_MALLOC(gtm_passwd_env, strlen(lgtm_passwd) + 1, char); + GC_MALLOC(gtm_passwd_env, STRLEN(lgtm_passwd) + 1, char); strcpy(gtm_passwd_env, lgtm_passwd); } return status; @@ -245,10 +230,9 @@ xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) /* If we are here, it means that the caller of the plugin library was not MUMPS (may be MUPIP, DSE and LKE). * For the utility programs, we expect the password to be set in the environment to an appropriate masked * form. If not, it's an error and we return the appropriate error message. */ - strcpy(err_string, PASSWD_EMPTY); + UPDATE_ERROR_STRING(ENV_EMPTY_ERROR ". %s", GTM_PASSWD, "Password prompting not allowed for utilities"); return GC_FAILURE; } - /* Only if the gtm_passwd is set to empty string, we prompt the user for password */ GC_MALLOC(gtm_passwd, GTM_PASSPHRASE_MAX, char); memset(gtm_passwd, 0, GTM_PASSPHRASE_MAX); @@ -257,7 +241,7 @@ xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) status = gtm_ci_fptr(password_routine, gtm_passwd, pass_len); if (0 != status) { - gtm_zstatus_fptr(err_string, ERR_STRLEN); + gtm_zstatus_fptr(gtmcrypt_err_string, MAX_GTMCRYPT_ERR_STRLEN); return GC_FAILURE; } /* Restore the GTMCI variable */ @@ -265,10 +249,10 @@ xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) setenv(GTMCI, save_gtmci, 1); /* After applying a minimal encryption, we set it to the environment variable */ - GC_MALLOC(lgtm_passwd, strlen(gtm_passwd) * 2 + 1, char); - gc_pk_mask_unmask_passwd(gtm_passwd, tgtm_passwd, (int)strlen(gtm_passwd)); - GC_HEX(tgtm_passwd, lgtm_passwd, strlen(gtm_passwd) * 2); - setenv("gtm_passwd", lgtm_passwd, TRUE); /* Note that we currently do not free 'gtm_passwd', even if it was + GC_MALLOC(lgtm_passwd, STRLEN(gtm_passwd) * 2 + 1, char); + gc_pk_mask_unmask_passwd(gtm_passwd, tgtm_passwd, (int)STRLEN(gtm_passwd)); + GC_HEX(tgtm_passwd, lgtm_passwd, STRLEN(gtm_passwd) * 2); + setenv(GTM_PASSWD, lgtm_passwd, TRUE); /* Note that we currently do not free 'gtm_passwd', even if it was * allocated above, as it needs to be in the env buffer */ return GC_SUCCESS; @@ -277,7 +261,6 @@ xc_status_t gc_pk_crypt_prompt_passwd_if_needed(int prompt_passwd) /* This function is called whenever gpg needs the passphrase with which the secret key is encrypted. In this case, the passphrase * is obtained from the ENVIRONMENT VARIABLE - $gtm_passwd or by invoking the mumps engine during the "gtmcrypt_init()". * In either ways, it's guaranteed that when this function is called, the passphrase is already set in the global variable. - * In either ways, it's guaranteed that when this function is called, the passphrase is already set in the global variable. */ int gc_pk_crypt_passphrase_callback(void *opaque, const char *uid_hint, const char *passphrase_info, int last_was_bad, @@ -289,9 +272,9 @@ int gc_pk_crypt_passphrase_callback(void *opaque, const char *uid_hint, /* This is just being cautious. We would have thrown the appropriate error message * if gtm_passwd have been zero length'ed one. */ - assert(0 != strlen(gtm_passwd)); - write_ret = write(fd, gtm_passwd, strlen(gtm_passwd)); - if (strlen(gtm_passwd) == write_ret) + assert(0 != STRLEN(gtm_passwd)); + write_ret = write(fd, gtm_passwd, STRLEN(gtm_passwd)); + if (STRLEN(gtm_passwd) == write_ret) { write_ret = write(fd, "\n", 1); if (1 == write_ret) @@ -305,17 +288,16 @@ int gc_pk_crypt_passphrase_callback(void *opaque, const char *uid_hint, * also return the number of bytes actually read from the structure. */ -int gc_pk_crypt_retrieve_plain_text(gpgme_data_t plain_data, char *plain_text) +int gc_pk_crypt_retrieve_plain_text(gpgme_data_t plain_data, unsigned char *plain_text) { int ret; assert(NULL != plain_text); /* Clear the temporary buffer */ - memset(plain_text, 0, GTM_KEY_MAX); - + memset(plain_text, 0, SYMMETRIC_KEY_MAX); gpgme_data_seek(plain_data, 0, SEEK_SET); - ret = (int)gpgme_data_read(plain_data, plain_text, GTM_KEY_MAX); + ret = (int)gpgme_data_read(plain_data, plain_text, SYMMETRIC_KEY_MAX); return ret; } @@ -336,18 +318,18 @@ int gc_pk_scrub_plaintext_keys_from_c_stack() * should contain the fully qualified path of the encrypted database key file. Also, plain text is supposed to be allocated with * sufficient space to hold the decrypted text. */ -gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, char *plain_text, int *plain_text_length) +gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, unsigned char *plain_text, int *plain_text_length) { gpgme_error_t err; gpgme_data_t cipher_data = NULL, plain_data = NULL; xc_status_t ret_status; gpg_err_code_t ecode; - char null_buffer[GTM_KEY_MAX]; + char null_buffer[SYMMETRIC_KEY_MAX]; assert(NULL != cipher_file); assert(NULL != plain_text); assert(NULL != pk_crypt_ctx); - assert(0 != strlen(cipher_file)); + assert(0 != STRLEN(cipher_file)); /* Convert the cipher content in the cipher file into * in-memory content. This in-memory content is stored @@ -372,21 +354,21 @@ gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, char *plain_text, switch(ecode) { case GPG_ERR_BAD_PASSPHRASE: - snprintf(err_string, ERR_STRLEN, "%s", "Incorrect password"); + UPDATE_ERROR_STRING("Incorrect password or error while obtaining password"); break; case GPG_ERR_ENOENT: - snprintf(err_string, ERR_STRLEN, "encryption key file %s not found", cipher_file); + UPDATE_ERROR_STRING("Encryption key file %s not found", cipher_file); break; default: - snprintf(err_string, ERR_STRLEN, "%s", gpgme_strerror(err)); + UPDATE_ERROR_STRING("%s", gpgme_strerror(err)); break; } } if (NULL != plain_data) { /* scrub plaintext data before releasing it */ - assert(GTM_KEY_MAX == SIZEOF(null_buffer)); - memset(null_buffer, 0, GTM_KEY_MAX); - gpgme_data_write(plain_data, null_buffer, GTM_KEY_MAX); + assert(SYMMETRIC_KEY_MAX == SIZEOF(null_buffer)); + memset(null_buffer, 0, SYMMETRIC_KEY_MAX); + gpgme_data_write(plain_data, null_buffer, SYMMETRIC_KEY_MAX); gpgme_data_release(plain_data); } if (NULL != cipher_data) @@ -396,45 +378,34 @@ gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, char *plain_text, int gc_pk_gpghome_has_permissions() { - char filename[GTM_PATH_MAX], *tmp_ptr = NULL; - int gnupghome_set, status, fd; + char pathname[GTM_PATH_MAX], *ptr; + int gnupghome_set, perms; /* See if GNUPGHOME is set in the environment */ - GC_GETENV(tmp_ptr, GNUPGHOME, status); - if (GC_SUCCESS != status) - { + if (!(ptr = getenv(GNUPGHOME))) + { /* $GNUPGHOME is not set, use $HOME/.gnupg as the GPG home directory */ gnupghome_set = FALSE; - GC_GETENV(tmp_ptr, "HOME", status); - if (GC_SUCCESS != status) + if (!(ptr = getenv(HOME))) { - GC_ENV_UNSET_ERROR("HOME"); + UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, HOME); return GC_FAILURE; } - /* If GNUPGHOME is not set, we choose the filename as $HOME/.gnupg */ - snprintf(filename, GTM_PATH_MAX, "%s/%s", tmp_ptr, DOT_GNUPG); + SNPRINTF(pathname, GTM_PATH_MAX, "%s/%s", ptr, DOT_GNUPG); } else { gnupghome_set = TRUE; - /* If GNUPGHOME is set, then we choose the path pointed by GNUPGHOME as the - * directory containing the public keys and private keys whose permissions we are - * interested in. */ - strcpy(filename, tmp_ptr); + strcpy(pathname, ptr); } - /* At this point, we are sure that the filename is pointing to the appropriate directory containing the public/private - * keys. If not, then we had encountered an error and would have returned back to the caller. */ - if (-1 != (fd = open(filename, O_RDONLY))) - { - close(fd); + if (-1 != (perms = access(pathname, R_OK | X_OK))) return GC_SUCCESS; - } - /* If we don't have appropriate read permissions then we report the error accordingly. */ - if (EACCES == errno) + else if (EACCES == errno) { if (gnupghome_set) - snprintf(err_string, ERR_STRLEN, "%s", "No read permissions on $GNUPGHOME"); - else - snprintf(err_string, ERR_STRLEN, "%s", "No read permissions on $HOME/.gnupg"); - } - close(fd); + { + UPDATE_ERROR_STRING("No read permissions on $%s", GNUPGHOME); + } else + UPDATE_ERROR_STRING("No read permissions on $%s/%s", HOME, DOT_GNUPG); + } else /* some other error */ + UPDATE_ERROR_STRING("Cannot stat on %s - %d", pathname, errno); return GC_FAILURE; } diff --git a/sr_unix/gtmcrypt_pk_ref.h b/sr_unix/gtmcrypt_pk_ref.h index 816cfa6..4e48943 100644 --- a/sr_unix/gtmcrypt_pk_ref.h +++ b/sr_unix/gtmcrypt_pk_ref.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,8 +22,8 @@ int gc_pk_crypt_passphrase_callback(void *opaque, const char *passphrase_info, int last_was_bad, int fd); -int gc_pk_crypt_retrieve_plain_text(gpgme_data_t plain_data, char *plain_text); -gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, char *plain_text, int *plain_text_length); +int gc_pk_crypt_retrieve_plain_text(gpgme_data_t plain_data, unsigned char *plain_text); +gpgme_error_t gc_pk_get_decrypted_key(const char *cipher_file, unsigned char *plain_text, int *plain_text_length); int gc_pk_mask_unmask_passwd(char *in, char *out, int len); void gc_pk_scrub_passwd(void); void gc_pk_crypt_load_gtmci_env(void); @@ -33,7 +33,8 @@ int gc_pk_gpghome_has_permissions(void); /* Public key cryptography related macros */ #define GC_PK_INIT \ { \ - gpgme_error_t err; \ + gpgme_error_t err; \ + GBLREF gpgme_ctx_t pk_crypt_ctx; \ \ gpgme_check_version(NULL); /* This initializes the gpgme engine. */ \ err = gpgme_new(&pk_crypt_ctx); \ @@ -45,70 +46,46 @@ int gc_pk_gpghome_has_permissions(void); gpgme_set_passphrase_cb(pk_crypt_ctx, \ (gpgme_passphrase_cb_t) gc_pk_crypt_passphrase_callback, \ NULL); \ - memset(err_string, 0, ERR_STRLEN); \ } \ } \ if (err) \ { \ pk_crypt_ctx = NULL; \ - snprintf(err_string, \ - ERR_STRLEN, \ - "Error initializing GpgME: %s/%s", \ - gpgme_strsource(err), \ - gpgme_strerror(err)); \ + UPDATE_ERROR_STRING("Error initializing GpgME: %s/%s", gpgme_strsource(err), gpgme_strerror(err)); \ return GC_FAILURE; \ } \ } -#define GC_PK_PROMPT_PASSWD(prompt_passwd) \ -{ \ - if (0 != gc_pk_crypt_prompt_passwd_if_needed(prompt_passwd)) \ - return GC_FAILURE; \ +#define GC_PK_PROMPT_PASSWD(prompt_passwd) \ +{ \ + if (0 != gc_pk_crypt_prompt_passwd_if_needed(prompt_passwd)) \ + return GC_FAILURE; \ } -#define GC_PK_GET_DECRYPTED_KEY(key_string, status) \ -{ \ - int plain_text_length; \ - char decrypted_key[GTM_KEY_MAX]; \ - \ - memset(decrypted_key, 0, GTM_KEY_MAX); \ - status = gc_pk_get_decrypted_key(cur->key_filename.address, decrypted_key, &plain_text_length); \ - \ - if (0 == status) \ - { \ - memcpy(key_string.address, decrypted_key, plain_text_length); \ - key_string.length = plain_text_length; \ - memset(decrypted_key, 0, GTM_KEY_MAX); \ - } \ -} - -#define GC_PK_APPEND_UNIQ_STRING(in_buff, key_string) \ -{ \ - memcpy(in_buff, (key_string).address, (key_string).length); \ - memcpy(in_buff + (key_string).length, UNIQ_ENC_PARAM_STRING, UNIQ_ENC_PARAM_LEN); \ +#define GC_PK_APPEND_UNIQ_STRING(in_buff, symmetric_key) \ +{ \ + memcpy(in_buff, symmetric_key, SYMMETRIC_KEY_MAX); \ + memcpy(in_buff + SYMMETRIC_KEY_MAX, UNIQ_ENC_PARAM_STRING, UNIQ_ENC_PARAM_LEN); \ } #ifdef USE_OPENSSL -#define GC_PK_COMPUTE_HASH(hash, key_string) \ -{ \ - char in_buff[HASH_INPUT_BUFF_LEN]; \ - \ - GC_PK_APPEND_UNIQ_STRING(in_buff, key_string); \ - EVP_Digest(in_buff, HASH_INPUT_BUFF_LEN, (unsigned char *)((hash).address), NULL, \ - EVP_sha512(), NULL); \ - (hash).length = GTMCRYPT_HASH_LEN; \ - memset(in_buff, 0, HASH_INPUT_BUFF_LEN); \ +#define GC_PK_COMPUTE_HASH(symmetric_key_hash, symmetric_key) \ +{ \ + unsigned char in_buff[HASH_INPUT_BUFF_LEN]; \ + \ + GC_PK_APPEND_UNIQ_STRING(in_buff, symmetric_key); \ + EVP_Digest(in_buff, HASH_INPUT_BUFF_LEN, symmetric_key_hash, NULL, EVP_sha512(), NULL); \ + memset(in_buff, 0, HASH_INPUT_BUFF_LEN); \ } #else -#define GC_PK_COMPUTE_HASH(hash, key_string) \ -{ \ - char in_buff[HASH_INPUT_BUFF_LEN]; \ - \ - GC_PK_APPEND_UNIQ_STRING(in_buff, key_string); \ - GC_SYM_INIT; \ - gcry_md_hash_buffer(GCRY_MD_SHA512, (hash).address, in_buff, HASH_INPUT_BUFF_LEN); \ - (hash).length = GTMCRYPT_HASH_LEN; \ - memset(in_buff, 0, HASH_INPUT_BUFF_LEN); \ +#define GC_PK_COMPUTE_HASH(symmetric_key_hash, symmetric_key) \ +{ \ + unsigned char in_buff[HASH_INPUT_BUFF_LEN]; \ + \ + GC_PK_APPEND_UNIQ_STRING(in_buff, symmetric_key); \ + GC_SYM_INIT; \ + gcry_md_hash_buffer(GCRY_MD_SHA512, symmetric_key_hash, in_buff, HASH_INPUT_BUFF_LEN); \ + memset(in_buff, 0, HASH_INPUT_BUFF_LEN); \ } #endif diff --git a/sr_unix/gtmcrypt_ref.c b/sr_unix/gtmcrypt_ref.c index 26bd314..9cf336d 100644 --- a/sr_unix/gtmcrypt_ref.c +++ b/sr_unix/gtmcrypt_ref.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,13 +11,13 @@ #define _FILE_OFFSET_BITS 64 /* Needed to compile gpgme client progs also with large file support */ -#include -#include -#include -#include +#include /* BYPASSOK -- Plugin doesn't have access to gtm_* header files */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ +#include /* BYPASSOK -- see above */ #include #include -#include #include #include /* gpgme functions */ #include /* gcry*_err_t */ @@ -25,76 +25,61 @@ #include "gtmcrypt_interface.h" /* Function prototypes for gtmcrypt*.* functions */ #include "gtmcrypt_ref.h" +#include "gtmcrypt_sym_ref.h" #include "gtmcrypt_dbk_ref.h" #include "gtmcrypt_pk_ref.h" -#include "gtmcrypt_sym_ref.h" #ifdef __MVS__ -#define GTM_DIST "gtm_dist" #define GTMSHR_IMAGENAME "libgtmshr.dll" #endif -char err_string[ERR_STRLEN]; -int gtmcrypt_inited = FALSE, num_entries; -db_key_map *db_map_root; -db_key_map **fast_lookup_entry = NULL; - -extern gpgme_ctx_t pk_crypt_ctx; - -/* ==================================================================================== */ -/* Plugin API implementations */ -/* ==================================================================================== */ - -char* gtmcrypt_strerror() -{ - return err_string; -} - -/* Initialize the encryption environment. Note: If any of the following macros fail, the error return happens within the macro. */ +GBLDEF int gtmcrypt_inited; +GBLDEF char gtmcrypt_err_string[MAX_GTMCRYPT_ERR_STRLEN]; xc_status_t gc_init_interface(int prompt_passwd) -{ -/* - * zOS is special when it comes to dynamic linking. - * (1). Building DLL with UNRESOLVED symbols - * ========================================= - * Unlike other Unix platforms, on zOS DLL cannot be built having unresolved symbols and expecting them to get resolved - * by the loader. - * In this particular scenario we have symbols gtm_malloc, gtm_is_file_identical, gtm_free, gtm_filename_to_id and - * gtm_xcfileid_free that are part of mupip executable. - * As an workaround we are using function pointers to call into the interface functions so that we don't have an link-time - * errors. - * At runtime we do an dlopen with NULL which returns handle to global space and dlsym sets the function pointers to point to - * the correct functions at runtime. - * - * (2). DLSYM on symbols that are already resolved from another DLL - * ================================================================ - * When mumps calls into libgtmcrypt it has above mentioned symbols already resolved from libgtmshr.dll. - * On zOS, when we try to DLSYM using the handle returned by DLOPEN(NULL,..), DLSYM crashes while trying to find symbols - * that are already loaded from another DLL(libgtmshr.dll). - * As an work around we dlopen libgtmshr.dll when called from MUMPS. - */ -#ifdef __MVS__ - void *handle = NULL; - const char *gtm_dist; - char gtmshr_file[GTM_PATH_MAX]; - - gtm_dist = getenv(GTM_DIST); - - snprintf(gtmshr_file, GTM_PATH_MAX, "%s/%s", gtm_dist, GTMSHR_IMAGENAME); - -/* - * prompt_passwd = TRUE implies plugin is invoked from MUMPS. We need to dlopen libgtmshr when invoked from MUMPS. - * Please refer comment 2) above. - */ - if (prompt_passwd) - handle = dlopen(gtmshr_file, GC_FLAGS); - else - handle = dlopen(NULL, GC_FLAGS); +{ /* zOS is special when it comes to dynamic linking. + * (1). Building DLL with UNRESOLVED symbols + * ========================================= + * Unlike other Unix platforms, on zOS DLL cannot be built having unresolved symbols and expecting them to get resolved + * by the loader. + * In this particular scenario we have symbols gtm_malloc, gtm_is_file_identical, gtm_free, gtm_filename_to_id and + * gtm_xcfileid_free that are part of mupip executable. + * As an workaround we are using function pointers to call into the interface functions so that we don't have an link-time + * errors. + * At runtime we do an dlopen with NULL which returns handle to global space and dlsym sets the function pointers to point + * to the correct functions at runtime. + * + * (2). DLSYM on symbols that are already resolved from another DLL + * ================================================================ + * When mumps calls into libgtmcrypt it has above mentioned symbols already resolved from libgtmshr.dll. + * On zOS, when we try to DLSYM using the handle returned by DLOPEN(NULL,..), DLSYM crashes while trying to find symbols + * that are already loaded from another DLL(libgtmshr.dll). + * As an work around we dlopen libgtmshr.dll when called from MUMPS. + */ +# ifdef __MVS__ + void *handle = NULL; + const char *gtm_dist, *dlerr_ptr; + char gtmshr_file[GTM_PATH_MAX]; + int dir_len; + if (!(gtm_dist = getenv(GTM_DIST))) + UPDATE_ERROR_STRING(ENV_UNDEF_ERROR, GTM_DIST); + dir_len = STRLEN(gtm_dist); + memcpy(>mshr_file[0], gtm_dist, dir_len); + gtmshr_file[dir_len] = DIR_SEPARATOR; + MEMCPY_LIT(>mshr_file[dir_len + 1], GTMSHR_IMAGENAME); + gtmshr_file[dir_len + STR_LIT_LEN(GTMSHR_IMAGENAME) + 1] = '\0'; + /* prompt_passwd = TRUE implies plugin is invoked from MUMPS. We need to dlopen libgtmshr when invoked from MUMPS. + * Please refer comment (2) above. + */ + handle = dlopen(prompt_passwd ? gtmshr_file : NULL, GC_FLAGS); if (NULL == handle) { - snprintf(err_string, ERR_STRLEN, "%s", "Unable to resolve GT.M interface functions"); + if (NULL == (dlerr_ptr = dlerror())) + { + UPDATE_ERROR_STRING("Unable to resolve GT.M interface functions. Unknown system error"); + } else + UPDATE_ERROR_STRING("Unable to resolve GT.M interface functions. %s", dlerr_ptr); return GC_FAILURE; } DLSYM_ERR_AND_EXIT(gtm_is_file_identical_fptr_t, gtm_is_file_identical_fptr, GTM_IS_FILE_IDENTICAL_FUNC); @@ -104,7 +89,7 @@ xc_status_t gc_init_interface(int prompt_passwd) DLSYM_ERR_AND_EXIT(gtm_ci_fptr_t, gtm_ci_fptr, GTM_CI_FUNC); DLSYM_ERR_AND_EXIT(gtm_zstatus_fptr_t, gtm_zstatus_fptr, GTM_ZSTATUS_FUNC); DLSYM_ERR_AND_EXIT(gtm_xcfileid_free_fptr_t, gtm_xcfileid_free_fptr, GTM_XCFILEID_FREE_FUNC); -#else +# else gtm_is_file_identical_fptr = >m_is_file_identical; gtm_malloc_fptr = >m_malloc; gtm_free_fptr = >m_free; @@ -112,30 +97,42 @@ xc_status_t gc_init_interface(int prompt_passwd) gtm_ci_fptr = >m_ci; gtm_zstatus_fptr = >m_zstatus; gtm_xcfileid_free_fptr = >m_xcfileid_free; -#endif +# endif return GC_SUCCESS; } -xc_status_t gtmcrypt_init(int prompt_passwd) +/* ==================================================================================== */ +/* Plugin API implementations */ +/* ==================================================================================== */ + +char* gtmcrypt_strerror() { + return gtmcrypt_err_string; +} + + +xc_status_t gtmcrypt_init(int prompt_passwd) +{ /* Initialize the encryption environment. If any of the following macros fail, the error return happens within the macro. */ if (GC_SUCCESS != gc_init_interface(prompt_passwd)) return GC_FAILURE; - GC_IF_INITED_RETURN; + if (gtmcrypt_inited) + return GC_SUCCESS; GC_PK_INIT; GC_PK_PROMPT_PASSWD(prompt_passwd) - GC_SET_INITED; + gtmcrypt_inited = TRUE; return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_getkey_by_name(xc_string_t *filename, gtmcrypt_key_t *handle) { - xc_fileid_ptr_t fileid = NULL; - db_key_map *entry; - xc_status_t status = GC_SUCCESS; + xc_fileid_ptr_t fileid = NULL; + gtm_dbkeys_tbl *entry; + xc_status_t status = GC_SUCCESS; GC_VERIFY_INITED; *handle = INVALID_HANDLE; + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ GC_DBK_FILENAME_TO_ID(filename, fileid); entry = gc_dbk_get_entry_by_fileid(fileid); /* If the load below failed, don't continue */ @@ -145,10 +142,7 @@ xc_status_t gtmcrypt_getkey_by_name(xc_string_t *filename, gtmcrypt_key_t *handl entry = gc_dbk_get_entry_by_fileid(fileid); if (NULL == entry) { - snprintf(err_string, - ERR_STRLEN, - "database file %s missing in DB keys file or does not exist", - filename->address); + UPDATE_ERROR_STRING("Database file %s missing in DB keys file or does not exist", filename->address); return GC_FAILURE; } *handle = entry->index; @@ -159,16 +153,17 @@ xc_status_t gtmcrypt_getkey_by_name(xc_string_t *filename, gtmcrypt_key_t *handl /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_getkey_by_hash(xc_string_t *hash, gtmcrypt_key_t *handle) { - db_key_map *entry; + gtm_dbkeys_tbl *entry; xc_status_t status = GC_SUCCESS; - int i, err_caused_by_gpg; - char save_err[ERR_STRLEN], hex_buff[GTMCRYPT_HASH_HEX_LEN + 1]; + int err_caused_by_gpg; + char save_err[MAX_GTMCRYPT_ERR_STRLEN], hex_buff[GTMCRYPT_HASH_HEX_LEN + 1]; char *gpg_msg = "Verify encrypted key file and your GNUPGHOME settings"; char *correct_key_msg = "Verify encryption key in DB keys file"; char *alert_msg; *handle = INVALID_HANDLE; GC_VERIFY_INITED; + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ entry = gc_dbk_get_entry_by_hash(hash); /* If the load below failed, don't continue */ GC_DBK_RELOAD_IF_NEEDED(entry, status, NULL, hash->address); @@ -176,23 +171,21 @@ xc_status_t gtmcrypt_getkey_by_hash(xc_string_t *hash, gtmcrypt_key_t *handle) { entry = gc_dbk_get_entry_by_hash(hash); if (NULL == entry) - { - /* If the lookup still failed, then verify if we have right permissions on - * GNUPGHOME or $HOME/.gnupg (if GNUPGHOME is unset). If not, then the below - * function will store the appropriate error message in err_string and - * so we can return GC_FAILURE.*/ + { /* Lookup still failed. Verify if we have right permissions on GNUPGHOME or $HOME/.gnupg + * (if GNUPGHOME is unset). If not, then the below function will store the appropriate + * error message in err_string and so return GC_FAILURE. + */ if (GC_SUCCESS != gc_pk_gpghome_has_permissions()) return GC_FAILURE; - err_caused_by_gpg = ('\0' != err_string[0]); + err_caused_by_gpg = ('\0' != gtmcrypt_err_string[0]); alert_msg = (err_caused_by_gpg ? gpg_msg : correct_key_msg); - /* Save the previous error message if any */ - strcpy(save_err, err_string); - for (i = 0; i < GTMCRYPT_HASH_HEX_LEN; i+=2) - sprintf(hex_buff + i, "%02X", (unsigned char)(hash->address[i/2])); + GC_HEX(hash->address, hex_buff, GTMCRYPT_HASH_HEX_LEN); if (err_caused_by_gpg) - snprintf(err_string, ERR_STRLEN, "Expected hash - %s - %s. %s", hex_buff, save_err, alert_msg); - else - snprintf(err_string, ERR_STRLEN, "Expected hash - %s. %s", hex_buff, alert_msg); + { + strcpy(save_err, gtmcrypt_err_string); + UPDATE_ERROR_STRING("Expected hash - %s - %s. %s", hex_buff, save_err, alert_msg); + } else + UPDATE_ERROR_STRING("Expected hash - %s. %s", hex_buff, alert_msg); return GC_FAILURE; } *handle = entry->index; @@ -203,40 +196,43 @@ xc_status_t gtmcrypt_getkey_by_hash(xc_string_t *hash, gtmcrypt_key_t *handle) /* Note: If any of the following macros fail, the error return happens within the macro. */ xc_status_t gtmcrypt_hash_gen(gtmcrypt_key_t handle, xc_string_t *hash) { - db_key_map *entry; + gtm_dbkeys_tbl *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); gc_dbk_get_hash(entry, hash); return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ -xc_status_t gtmcrypt_encode(gtmcrypt_key_t handle, xc_string_t *unencrypted_block, xc_string_t *encrypted_block) +xc_status_t gtmcrypt_encrypt(gtmcrypt_key_t handle, xc_string_t *unencrypted_block, xc_string_t *encrypted_block) { crypt_key_t key_handle; - db_key_map *entry; + gtm_dbkeys_tbl *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); key_handle = entry->encr_key_handle; - GC_SYM_ENCODE(key_handle, unencrypted_block, encrypted_block); + GC_SYM_ENCRYPT(key_handle, unencrypted_block, encrypted_block); return GC_SUCCESS; } /* Note: If any of the following macros fail, the error return happens within the macro. */ -xc_status_t gtmcrypt_decode(gtmcrypt_key_t handle, xc_string_t *encrypted_block, xc_string_t *unencrypted_block) +xc_status_t gtmcrypt_decrypt(gtmcrypt_key_t handle, xc_string_t *encrypted_block, xc_string_t *unencrypted_block) { crypt_key_t key_handle; - db_key_map *entry; + gtm_dbkeys_tbl *entry; GC_VERIFY_INITED; assert(INVALID_HANDLE != handle); + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ GC_DBK_GET_ENTRY_FROM_HANDLE(handle, entry, GC_FAILURE); key_handle = entry->decr_key_handle; - GC_SYM_DECODE(key_handle, encrypted_block, unencrypted_block); + GC_SYM_DECRYPT(key_handle, encrypted_block, unencrypted_block); return GC_SUCCESS; } @@ -244,8 +240,9 @@ xc_status_t gtmcrypt_decode(gtmcrypt_key_t handle, xc_string_t *encrypted_block, xc_status_t gtmcrypt_close() { GC_VERIFY_INITED; + gtmcrypt_err_string[0] = '\0'; /* discard any previously recorded error messages */ gc_pk_scrub_passwd(); gc_dbk_scrub_entries(); - GC_CLEAR_INITED; + gtmcrypt_inited = FALSE; return GC_SUCCESS; } diff --git a/sr_unix/gtmcrypt_ref.h b/sr_unix/gtmcrypt_ref.h index ea659d5..8139372 100644 --- a/sr_unix/gtmcrypt_ref.h +++ b/sr_unix/gtmcrypt_ref.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,98 +11,13 @@ #ifndef GTMCRYPT_REF_H #define GTMCRYPT_REF_H -#ifdef USE_OPENSSL -# include -# include -# include -#elif defined USE_GCRYPT -# include -#else -# error "Unsupported encryption library. Reference implementation currently supports openssl and gcrypt" +#if !defined(DEBUG) && defined(assert) +# undef assert +# define assert(x) #endif -#ifndef DEBUG - #undef assert - #define assert(x) -#endif - -/* Any change done to the below macro should be reflected in mdef.h and vice versa */ -/* Note: sizeof returns a "unsigned long" type by default. In expressions involving 32-bit quantities, -* using sizeof causes a compiler warning for every 64->32 bit auto cast (zOS compiler for now). -* Hence typecasting the return to "int" on zOS (to avoid warning) in most common sizeof usages. -* Whenever SIZEOF needs to be used in expressions involving 64-bit pointer quantities, use ((INTPTR_T)SIZEOF(...)). -* Whenever SIZEOF needs to be used in expressions involving 64-bit integer quantities, use ((long)SIZEOF(...)). -*/ -#if defined(__MVS__) -# define SIZEOF(X) ((int)(sizeof(X))) /* BYPASSOK */ -#else -# define SIZEOF(X) ((long)sizeof(X)) /* BYPASSOK */ -#endif - -typedef enum -{ - ERROR_LINE_INFO = -1, - DAT_LINE_INFO, - KEY_LINE_INFO -} dbkeyfile_line_type; - -typedef enum -{ - LOOKING_FOR_DAT_ENTRY = 1, - LOOKING_FOR_KEY_ENTRY, - NUM_STATES -} dbkeyfile_states; -#ifdef USE_OPENSSL -typedef EVP_CIPHER_CTX crypt_key_t; -#else -typedef gcry_cipher_hd_t crypt_key_t; -#endif - -#define TAB_NAME_MAX 512 -#define GTM_PASSPHRASE_MAX 512 -#define GC_ENCRYPT 1 -#define GC_DECRYPT 0 -#define GC_FAILURE 1 -#define GC_SUCCESS 0 -#define TRUE 1 -#define FALSE 0 -#define GNUPGHOME "GNUPGHOME" -#define DOT_GNUPG ".gnupg" -#define GTM_PASSWD "gtm_passwd" -#define GTM_DBKEYS "gtm_dbkeys" -#define DOT_GTM_DBKEYS "."GTM_DBKEYS -#define PASSWD_EMPTY "Environment variable gtm_passwd set to empty string. Password prompting not allowed for utilities" -#define GTM_PATH_MAX 1024 -#define GTM_KEY_MAX 32 -#define GTMCRYPT_HASH_LEN 64 -#define GTMCRYPT_HASH_HEX_LEN GTMCRYPT_HASH_LEN * 2 -#define DAT_LINE_INDICATOR "dat " -#define KEY_LINE_INDICATOR "key " -#define DAT_LINE_INDICATOR_SIZE (SIZEOF(DAT_LINE_INDICATOR) - 1) -#define KEY_LINE_INDICATOR_SIZE (SIZEOF(KEY_LINE_INDICATOR) - 1) -#define INVALID_HANDLE -1 -#define GTMCI "GTMCI" -#define ERR_STRLEN 2048 - -#ifdef USE_GCRYPT -#define IV_LEN 16 -#define ALGO GCRY_CIPHER_AES256 -#define MODE GCRY_CIPHER_MODE_CFB -/* This string uniquely identifies the encryption algorithm and its parameters. - * It will be appended to the encryption key and the combination will be hashed (with SHA512). - * This hash will be used verify that the same algorithm (including parameters) and key are used to - * open the database file as were used to create the database file. */ -#define UNIQ_ENC_PARAM_STRING "AES256CFB" -#define FLAGS 0 -static char iv[IV_LEN]; -static int gcry_already_inited = FALSE; -#else -#define ALGO EVP_bf_cfb64() -#define UNIQ_ENC_PARAM_STRING "BLOWFISHCFB" -#endif -#define UNIQ_ENC_PARAM_LEN SIZEOF(UNIQ_ENC_PARAM_STRING) - 1 -#define HASH_INPUT_BUFF_LEN UNIQ_ENC_PARAM_LEN + GTM_KEY_MAX - +#include "gtm_common_defs.h" /* To import common macros implemented by GT.M */ +#include "gtm_sizeof.h" /* for SIZEOF */ /* ==================================================================================== */ /* Legend to namespaces used - @@ -113,14 +28,61 @@ static int gcry_already_inited = FALSE; */ /* ==================================================================================== */ -/* ==================================================================================== */ -/* Generic macros and functions related to this plugin */ -/* ==================================================================================== */ -#define GC_MIN_STATIC_BLOCK_SIZE 4096 /* Have a good size block, so that we dont keep reallocating */ -#define GC_ROUNDUP(x, y) ((x / y) * y) + ((x % y) ? y : 0) +/* The value 1023 for PATH_MAX is derived using pathconf("path", _PC_PATH_MAX) on z/OS and + * we figure other POSIX platforms are at least as capable if they don't define PATH_MAX. + * Since we can't afford to call a function on each use of PATH_MAX/GTM_PATH_MAX, this + * value is hardcoded here. + * + * Note on Linux (at least), PATH_MAX is actually defined in . We would include + * that here unconditionally but on AIX, param.h includes limits.h. Note that regardless of where + * it gets defined, PATH_MAX needs to be defined prior to including stdlib.h. This is because in a + * pro build, at least Linux verifies the 2nd parm of realpath() is PATH_MAX bytes or more. + * Since param.h sets PATH_MAX to 4K on Linux, this can cause structures defined as GTM_PATH_MAX + * to raise an error when used in the 2nd argument of realpath(). + * Note : The definition of PATH_MAX and GTM_PATH_MAX is borrowed from gtm_limits.h. Change in one + * should be reflected in the other. + */ +#ifndef PATH_MAX +# ifdef __linux__ +# include +# else +# define PATH_MAX 1023 +# endif +#endif +/* Now define our version which includes space for a terminating NULL byte */ +#define GTM_PATH_MAX PATH_MAX + 1 +#define TAB_NAME_MAX 512 +#define GTM_PASSPHRASE_MAX 512 +#define GC_ENCRYPT 1 +#define GC_DECRYPT 0 +#define GC_FAILURE 1 +#define GC_SUCCESS 0 +#define DOT_GTM_DBKEYS ".gtm_dbkeys" +#define DOT_GNUPG ".gnupg" +#define SYMMETRIC_KEY_MAX 32 +#define GTMCRYPT_HASH_LEN 64 +#define GTMCRYPT_HASH_HEX_LEN GTMCRYPT_HASH_LEN * 2 +#define INVALID_HANDLE -1 +#define GTMCI "GTMCI" +#define MAX_GTMCRYPT_ERR_STRLEN 2048 + +#define GC_MIN_STATIC_BLOCK_SIZE 4096 /* Have a good size block, so that we dont keep reallocating */ #define GC_FLAGS (RTLD_NOW | RTLD_GLOBAL) +/* Some environment variables that encryption plugin cares about */ +#define GNUPGHOME "GNUPGHOME" +#define GTM_PASSWD "gtm_passwd" +#define GTM_OBFUSCATION_KEY "gtm_obfuscation_key" +#define GTM_DBKEYS "gtm_dbkeys" +#define HOME "HOME" +#define USER "USER" +#define GTM_DIST "gtm_dist" + +#define ENV_UNDEF_ERROR "Environment variable %s not set" +#define ENV_EMPTY_ERROR "Environment variable %s set to empty string" + +/* Define function pointers to the functions that the encryption plugin imports from libgtmshr.so at runtime */ #define GTM_MALLOC_FUNC "gtm_malloc" #define GTM_FREE_FUNC "gtm_free" #define GTM_FILENAME_TO_ID_FUNC "gtm_filename_to_id" @@ -129,117 +91,118 @@ static int gcry_already_inited = FALSE; #define GTM_IS_FILE_IDENTICAL_FUNC "gtm_is_file_identical" #define GTM_XCFILEID_FREE_FUNC "gtm_xcfileid_free" -xc_status_t gc_init_interface(int prompt_passwd); +typedef void * (*gtm_malloc_fptr_t)(size_t); +typedef void (*gtm_free_fptr_t)(void *); +typedef xc_status_t (*gtm_filename_to_id_fptr_t)(xc_string_t *, xc_fileid_ptr_t *); +typedef xc_status_t (*gtm_ci_fptr_t)(const char *c_rtn_name, ...); +typedef void (*gtm_zstatus_fptr_t)(char *msg, int len); +typedef xc_status_t (*gtm_is_file_identical_fptr_t)(xc_fileid_ptr_t, xc_fileid_ptr_t); +typedef void (*gtm_xcfileid_free_fptr_t)(xc_fileid_ptr_t); -typedef void * (*gtm_malloc_fptr_t)(size_t); -typedef void (*gtm_free_fptr_t)(void *); -typedef xc_status_t (*gtm_filename_to_id_fptr_t)(xc_string_t *, xc_fileid_ptr_t *); -typedef xc_status_t (*gtm_ci_fptr_t)(const char *c_rtn_name, ...); -typedef void (*gtm_zstatus_fptr_t)(char *msg, int len); -typedef xc_status_t (*gtm_is_file_identical_fptr_t)(xc_fileid_ptr_t, xc_fileid_ptr_t); -typedef void (*gtm_xcfileid_free_fptr_t)(xc_fileid_ptr_t); +GBLDEF gtm_malloc_fptr_t gtm_malloc_fptr; +GBLDEF gtm_free_fptr_t gtm_free_fptr; +GBLDEF gtm_filename_to_id_fptr_t gtm_filename_to_id_fptr; +GBLDEF gtm_ci_fptr_t gtm_ci_fptr; +GBLDEF gtm_zstatus_fptr_t gtm_zstatus_fptr; +GBLDEF gtm_is_file_identical_fptr_t gtm_is_file_identical_fptr; +GBLDEF gtm_xcfileid_free_fptr_t gtm_xcfileid_free_fptr; -gtm_malloc_fptr_t gtm_malloc_fptr; -gtm_free_fptr_t gtm_free_fptr; -gtm_filename_to_id_fptr_t gtm_filename_to_id_fptr; -gtm_ci_fptr_t gtm_ci_fptr; -gtm_zstatus_fptr_t gtm_zstatus_fptr; -gtm_is_file_identical_fptr_t gtm_is_file_identical_fptr; -gtm_xcfileid_free_fptr_t gtm_xcfileid_free_fptr; +xc_status_t gc_init_interface(int prompt_passwd); /* function that sets up the above function pointers */ -#define DLSYM_ERR_AND_EXIT(fptr_type, fptr, func_name) \ -{ \ - fptr = (fptr_type)dlsym(handle, func_name); \ - if (NULL == fptr) \ - { \ - snprintf(err_string, ERR_STRLEN, "Enable to resolve %s ", func_name); /* BYPASSOK */ \ - return GC_FAILURE; \ - } \ +GBLREF char gtmcrypt_err_string[MAX_GTMCRYPT_ERR_STRLEN]; /* most recent error that the plugin encountered */ + +#define SNPRINTF(SRC, LEN, ...) \ +{ \ + int rc; \ + \ + do \ + { \ + rc = snprintf(SRC, LEN, __VA_ARGS__); /* BYPASSOK */ \ + } while ((-1 == rc) && (EINTR == errno)); /* EINTR-safe */ \ } -#define GC_MALLOC(blk, len, type) \ -{ \ - blk = (type *)gtm_malloc_fptr(len); \ - assert (blk); \ +#define SPRINTF(SRC, ...) \ +{ \ + int rc; \ + \ + do \ + { \ + rc = sprintf(SRC, __VA_ARGS__); /* BYPASSOK */ \ + } while ((-1 == rc) && (EINTR == errno)); /* EINTR-safe */ \ +} + +#define UPDATE_ERROR_STRING(...) \ +{ \ + SNPRINTF(gtmcrypt_err_string, MAX_GTMCRYPT_ERR_STRLEN, __VA_ARGS__); \ +} + +#define DLSYM_ERR_AND_EXIT(fptr_type, fptr, func_name) \ +{ \ + char *dlerr_ptr; \ + \ + fptr = (fptr_type)dlsym(handle, func_name); \ + if (NULL == fptr) \ + { \ + if (NULL == (dlerr_ptr = dlerror())) \ + { \ + UPDATE_ERROR_STRING("Unable to resolve symbol %s. Unknown system error", func_name); \ + } else \ + UPDATE_ERROR_STRING("Unable to resolve symbol %s. %s", func_name, dlerr_ptr); \ + return GC_FAILURE; \ + } \ +} + +#define GC_MALLOC(blk, len, type) \ +{ \ + blk = (type *)gtm_malloc_fptr(len); \ + assert(blk); \ } #define GC_FREE(blk) gtm_free_fptr(blk) -#define GC_COPY_TO_XC_STRING(X, STR, N) \ -{ \ - memcpy((X)->address, STR, N); \ - (X)->length = N; \ -} - - /* Following makes sure that at no point we are in the encryption library without gtmcrypt_init getting called * prior to the current call */ -#define GC_VERIFY_INITED \ -{ \ - if (!gtmcrypt_inited) \ - { \ - snprintf(err_string, ERR_STRLEN, "%s", "Encryption library has not been initialized"); /* BYPASSOK */ \ - return GC_FAILURE; \ - } \ +#define GC_VERIFY_INITED \ +{ \ + if (!gtmcrypt_inited) \ + { \ + UPDATE_ERROR_STRING("Encryption library has not been initialized"); \ + return GC_FAILURE; \ + } \ } -#define GC_IF_INITED_RETURN \ -{ \ - /* Check if init has happened already */ \ - if (gtmcrypt_inited) \ - return GC_SUCCESS; \ -} - -#define GC_SET_INITED gtmcrypt_inited = TRUE; - -#define GC_CLEAR_INITED gtmcrypt_inited = FALSE; - #define GC_INT(H) ((H >= 'A' && H <= 'F') ? ((H - 'A') + 10) : (H - '0')) -#define GC_UNHEX(a, b, len) \ -{ \ - int i; \ - for (i = 0; i < len; i+=2) \ - b[i/2] = (unsigned char)(GC_INT(a[i]) * 16 + GC_INT(a[i + 1])); \ +#define GC_UNHEX(a, b, len) \ +{ \ + int i; \ + for (i = 0; i < len; i += 2) \ + b[i/2] = (unsigned char)(GC_INT(a[i]) * 16 + GC_INT(a[i + 1])); \ } -#define GC_HEX(a, b, len) \ -{ \ - int i; \ - for (i = 0; i < len; i+=2) \ - sprintf(b + i, "%02X", (unsigned char)a[i/2]); /* BYPASSOK */ \ +#define GC_HEX(a, b, len) \ +{ \ + int i; \ + for (i = 0; i < len; i += 2) \ + SPRINTF(b + i, "%02X", (unsigned char)a[i / 2]); \ } -#define GC_GETENV(ptr, key, RC) \ -{ \ - RC = GC_SUCCESS; \ - if (NULL == (ptr = (char *)getenv(key))) \ - RC = GC_FAILURE; \ -} - -#define GC_ENV_UNSET_ERROR(key) \ -{ \ - snprintf(err_string, ERR_STRLEN, "Environment variable %s not set", key); /* BYPASSOK */ \ -} - -/* Allocate a single block, and try reusing the same everytime this macro is called */ +/* Allocate a single block, and reuse everytime this macro is called */ #ifdef USE_OPENSSL -#define GC_GET_STATIC_BLOCK(out, block_len) \ -{ \ - static char *blk = (char *)NULL; \ - static int allocated_len = GC_MIN_STATIC_BLOCK_SIZE; \ - if (blk == NULL || (block_len > allocated_len)) \ - { \ - if (blk) \ - GC_FREE(blk); \ - allocated_len = (block_len > allocated_len) ? \ - GC_ROUNDUP(block_len, GC_MIN_STATIC_BLOCK_SIZE) : \ - allocated_len; \ - GC_MALLOC(blk, allocated_len, char); \ - } \ - out = blk; \ +#define GC_GET_STATIC_BLOCK(out, block_len) \ +{ \ + static char *blk = (char *)NULL; \ + static int allocated_len = GC_MIN_STATIC_BLOCK_SIZE; \ + if (blk == NULL || (block_len > allocated_len)) \ + { \ + if (blk) \ + GC_FREE(blk); \ + allocated_len = (block_len > allocated_len) ? ROUND_UP(block_len, GC_MIN_STATIC_BLOCK_SIZE) : allocated_len; \ + GC_MALLOC(blk, allocated_len, char); \ + } \ + out = blk; \ } #endif #endif /* GTMCRYPT_REF_H */ diff --git a/sr_unix/gtmcrypt_sym_ref.h b/sr_unix/gtmcrypt_sym_ref.h index e5bdd78..a895c37 100644 --- a/sr_unix/gtmcrypt_sym_ref.h +++ b/sr_unix/gtmcrypt_sym_ref.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,164 +11,179 @@ #ifndef GTMCRYPT_SYM_REF_H #define GTMCRYPT_SYM_REF_H + +#ifdef USE_OPENSSL +# include +# include +# include +# include +# if defined(USE_AES256CFB) +# define ALGO EVP_aes_256_cfb128() +# define UNIQ_ENC_PARAM_STRING "AES256CFB" +# elif defined(USE_BLOWFISHCFB) +# define ALGO EVP_bf_cfb64() +# define UNIQ_ENC_PARAM_STRING "BLOWFISHCFB" +# else +# error "Unsupported Algorithm for OpenSSL" +# endif +typedef EVP_CIPHER_CTX crypt_key_t; +#elif defined USE_GCRYPT +# include +# if defined(USE_AES256CFB) +# define IV_LEN 16 +# define ALGO GCRY_CIPHER_AES256 +# define MODE GCRY_CIPHER_MODE_CFB +# define UNIQ_ENC_PARAM_STRING "AES256CFB" +# define FLAGS 0 +# else +# error "Unsupported Algorithm for Libgcrypt" +# endif +STATICDEF int gcry_already_inited; +STATICDEF char iv[IV_LEN]; +typedef gcry_cipher_hd_t crypt_key_t; +#else +# error "Unsupported encryption library. Reference implementation currently supports OpenSSL and Libgcrypt" +#endif /* USE_GCRYPT */ + +#define UNIQ_ENC_PARAM_LEN SIZEOF(UNIQ_ENC_PARAM_STRING) - 1 +#define HASH_INPUT_BUFF_LEN UNIQ_ENC_PARAM_LEN + SYMMETRIC_KEY_MAX + /* ==================================================================================== */ /* Macros and functions for symmetric encryption tasks */ /* ==================================================================================== */ #ifdef USE_OPENSSL -#define GC_SYM_CREATE_HANDLES(cur_entry) \ -{ \ - int ecode; \ - unsigned char *key = (unsigned char *)(cur_entry->key_string.address); \ - \ - EVP_CIPHER_CTX_init(&(cur_entry->encr_key_handle)); \ - ecode = EVP_CipherInit(&(cur_entry->encr_key_handle), ALGO, key, NULL, GC_ENCRYPT); \ - GC_SYM_ERROR(ecode, GC_FAILURE); \ - \ - EVP_CIPHER_CTX_init(&(cur_entry->decr_key_handle)); \ - ecode = EVP_CipherInit(&(cur_entry->decr_key_handle), ALGO, key, NULL, GC_DECRYPT); \ - GC_SYM_ERROR(ecode, GC_FAILURE); \ +#define GC_SYM_CREATE_HANDLES(cur_entry) \ +{ \ + int ecode; \ + unsigned char *key = cur_entry->symmetric_key; \ + \ + EVP_CIPHER_CTX_init(&(cur_entry->encr_key_handle)); \ + ecode = EVP_CipherInit(&(cur_entry->encr_key_handle), ALGO, key, NULL, GC_ENCRYPT); \ + GC_SYM_ERROR(ecode, GC_FAILURE); \ + \ + EVP_CIPHER_CTX_init(&(cur_entry->decr_key_handle)); \ + ecode = EVP_CipherInit(&(cur_entry->decr_key_handle), ALGO, key, NULL, GC_DECRYPT); \ + GC_SYM_ERROR(ecode, GC_FAILURE); \ } -#define GC_SYM_ERROR(err, return_value) \ -{ \ - if (!err) \ - { \ - ERR_error_string_n(err, err_string, ERR_STRLEN); \ - return return_value; \ - } \ +#define GC_SYM_ERROR(err, return_value) \ +{ \ + if (!err) \ + { \ + ERR_error_string_n(err, gtmcrypt_err_string, MAX_GTMCRYPT_ERR_STRLEN); \ + return return_value; \ + } \ } #else -#define GC_SYM_CREATE_HANDLES(cur_entry) \ -{ \ - gcry_error_t err; \ - char *key = cur_entry->key_string.address; \ - size_t keylen = cur_entry->key_string.length; \ - \ - GC_SYM_INIT; \ - err = gcry_cipher_open(&(cur_entry->encr_key_handle), ALGO, MODE, FLAGS); \ - if (!err) \ - err = gcry_cipher_setkey(cur_entry->encr_key_handle, key, keylen); \ - GC_SYM_ERROR(err, GC_FAILURE); \ - err = gcry_cipher_open(&(cur_entry->decr_key_handle), ALGO, MODE, FLAGS); \ - if (!err) \ - err = gcry_cipher_setkey(cur_entry->decr_key_handle, key, keylen); \ - GC_SYM_ERROR(err, GC_FAILURE); \ +#define GC_SYM_CREATE_HANDLES(cur_entry) \ +{ \ + gcry_error_t err; \ + unsigned char *key = cur_entry->symmetric_key; \ + \ + GC_SYM_INIT; \ + err = gcry_cipher_open(&(cur_entry->encr_key_handle), ALGO, MODE, FLAGS); \ + if (!err) \ + err = gcry_cipher_setkey(cur_entry->encr_key_handle, key, SYMMETRIC_KEY_MAX); \ + GC_SYM_ERROR(err, GC_FAILURE); \ + err = gcry_cipher_open(&(cur_entry->decr_key_handle), ALGO, MODE, FLAGS); \ + if (!err) \ + err = gcry_cipher_setkey(cur_entry->decr_key_handle, key, SYMMETRIC_KEY_MAX); \ + GC_SYM_ERROR(err, GC_FAILURE); \ } -#define GC_SYM_ERROR(err, return_value) \ -{ \ - if (GPG_ERR_NO_ERROR != err) \ - { \ - snprintf(err_string, ERR_STRLEN, "%s", gcry_strerror(err)); \ - return return_value; \ - } \ +#define GC_SYM_ERROR(err, return_value) \ +{ \ + if (GPG_ERR_NO_ERROR != err) \ + { \ + UPDATE_ERROR_STRING("%s", gcry_strerror(err)); \ + return return_value; \ + } \ } #endif #ifdef USE_GCRYPT /* Initialization and error handling functions defined only for libgcrypt. * OpenSSL doesn't neeed them. */ -#define GC_SYM_INIT \ -{ \ - gcry_error_t err; \ - char *ver; \ - \ - if (!gcry_already_inited) \ - { \ - memset(iv, 0, IV_LEN); \ - if (!gcry_check_version(GCRYPT_VERSION)) \ - { \ - snprintf(err_string, \ - ERR_STRLEN, \ - "libgcrypt version mismatch. %s or higher is required", \ - GCRYPT_VERSION); \ - return GC_FAILURE; \ - } \ - if (!(err = gcry_control(GCRYCTL_DISABLE_SECMEM, 0))) \ - if (!(err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0))) \ - gcry_already_inited = TRUE; \ - GC_SYM_ERROR(err, GC_FAILURE); \ - } \ +#define GC_SYM_INIT \ +{ \ + gcry_error_t err; \ + char *ver; \ + \ + if (!gcry_already_inited) \ + { \ + memset(iv, 0, IV_LEN); \ + if (!gcry_check_version(GCRYPT_VERSION)) \ + { \ + UPDATE_ERROR_STRING("libgcrypt version mismatch. %s or higher is required", GCRYPT_VERSION); \ + return GC_FAILURE; \ + } \ + if (!(err = gcry_control(GCRYCTL_DISABLE_SECMEM, 0))) \ + if (!(err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0))) \ + gcry_already_inited = TRUE; \ + GC_SYM_ERROR(err, GC_FAILURE); \ + } \ } #endif #ifdef USE_OPENSSL -#define GC_SYM_COMMON(key_handle, in_block, out_block, flag) \ -{ \ - int block_len, is_inplace, ecode, tmp_len; \ - int out_len; \ - char *static_out_blk; \ - unsigned char *in = NULL, *out = NULL; \ - \ - assert(in_block->address); \ - assert(0 != in_block->length); \ - in = (unsigned char *)in_block->address; \ - block_len = in_block->length; \ - out = (unsigned char *)out_block->address; \ - if (NULL == out_block->address) \ - { \ - GC_GET_STATIC_BLOCK(static_out_blk, block_len); \ - out = (unsigned char *)static_out_blk; \ - is_inplace = TRUE; \ - } else \ - is_inplace = FALSE; \ - ecode = EVP_CipherUpdate(&key_handle, out, &out_len, in, block_len); \ - if (ecode) \ - ecode = EVP_CipherFinal(&key_handle, out + out_len, &tmp_len); \ - GC_SYM_ERROR(ecode, GC_FAILURE); \ - if (is_inplace) \ - memcpy(in, out, block_len); \ +#define GC_SYM_COMMON(key_handle, in_block, out_block, flag) \ +{ \ + int block_len, is_inplace, ecode, tmp_len; \ + int out_len; \ + char *static_out_blk; \ + unsigned char *in = NULL, *out = NULL; \ + \ + assert(in_block->address); \ + assert(0 != in_block->length); \ + in = (unsigned char *)in_block->address; \ + block_len = in_block->length; \ + out = (unsigned char *)out_block->address; \ + if (NULL == out_block->address) \ + { \ + GC_GET_STATIC_BLOCK(static_out_blk, block_len); \ + out = (unsigned char *)static_out_blk; \ + is_inplace = TRUE; \ + } else \ + is_inplace = FALSE; \ + ecode = EVP_CipherUpdate(&key_handle, out, &out_len, in, block_len); \ + if (ecode) \ + ecode = EVP_CipherFinal(&key_handle, out + out_len, &tmp_len); \ + GC_SYM_ERROR(ecode, GC_FAILURE); \ + if (is_inplace) \ + memcpy(in, out, block_len); \ } #else /* USE_GCRYPT */ -#define GC_SYM_COMMON(key_handle, in_block, out_block, flag) \ -{ \ - int is_inplace = 0; \ - size_t blen; \ - gcry_error_t err; \ - \ - assert(in_block->address); \ - assert(0 != in_block->length); \ - blen = in_block->length; \ - if (NULL == out_block->address) \ - is_inplace = TRUE; \ - \ - GC_SYM_INIT; \ - gcry_cipher_setiv(key_handle, iv, IV_LEN); \ - if (is_inplace) \ - { \ - if (flag == GC_ENCRYPT) \ - { \ - err = gcry_cipher_encrypt(key_handle, in_block->address, blen, NULL, 0);\ - GC_SYM_ERROR(err, GC_FAILURE); \ - } else \ - { \ - err = gcry_cipher_decrypt(key_handle, in_block->address, blen, NULL, 0);\ - GC_SYM_ERROR(err, GC_FAILURE); \ - } \ - } else \ - { \ - if (flag == GC_ENCRYPT) \ - { \ - err = gcry_cipher_encrypt(key_handle, \ - out_block->address, \ - blen, \ - in_block->address, \ - blen); \ - GC_SYM_ERROR(err, GC_FAILURE); \ - } else \ - { \ - err = gcry_cipher_decrypt(key_handle, \ - out_block->address, \ - blen, \ - in_block->address, \ - blen); \ - GC_SYM_ERROR(err, GC_FAILURE); \ - } \ - } \ +#define GC_SYM_COMMON(key_handle, in_block, out_block, flag) \ +{ \ + size_t inlen, outlen; \ + char *in, *out; \ + gcry_error_t err; \ + \ + inlen = in_block->length; \ + in = in_block->address; \ + assert(in && inlen); \ + if (NULL == out_block->address) \ + { /* IN-PLACE encryption/decryption. Adjust pointers accordingly */ \ + out = in; \ + outlen = inlen; \ + in = NULL; \ + inlen = 0; \ + } else \ + { \ + out = out_block->address; \ + outlen = inlen; \ + } \ + GC_SYM_INIT; \ + gcry_cipher_setiv(key_handle, iv, IV_LEN); \ + if (GC_ENCRYPT == flag) \ + err = gcry_cipher_encrypt(key_handle, out, outlen, in, inlen); \ + else \ + err = gcry_cipher_decrypt(key_handle, out, outlen, in, inlen); \ + GC_SYM_ERROR(err, GC_FAILURE); \ } #endif -#define GC_SYM_DECODE(key_handle, encrypted_block, unencrypted_block) \ +#define GC_SYM_DECRYPT(key_handle, encrypted_block, unencrypted_block) \ GC_SYM_COMMON(key_handle, encrypted_block, unencrypted_block, GC_DECRYPT) -#define GC_SYM_ENCODE(key_handle, unencrypted_block, encrypted_block) \ +#define GC_SYM_ENCRYPT(key_handle, unencrypted_block, encrypted_block) \ GC_SYM_COMMON(key_handle, unencrypted_block, encrypted_block, GC_ENCRYPT) #endif /* GTMCRYPT_SYM_REF_H */ diff --git a/sr_unix/gtminstall.sh b/sr_unix/gtminstall.sh index f5bd1c1..302b71d 100644 --- a/sr_unix/gtminstall.sh +++ b/sr_unix/gtminstall.sh @@ -1,7 +1,7 @@ #!/bin/sh - ################################################################# # # -# Copyright 2011 Fidelity Information Services, Inc # +# Copyright 2011, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # diff --git a/sr_unix/gtminstall_Solaris.sh b/sr_unix/gtminstall_Solaris.sh index 5672029..fbbde5e 100644 --- a/sr_unix/gtminstall_Solaris.sh +++ b/sr_unix/gtminstall_Solaris.sh @@ -1,7 +1,7 @@ #!/usr/xpg4/bin/sh - ################################################################# # # -# Copyright 2011 Fidelity Information Services, Inc # +# Copyright 2011, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -419,8 +419,10 @@ fi tmp=`head -1 configure | cut -f 1` if [ "#!/bin/sh" != "$tmp" ] ; then echo "#!/bin/sh" >configure.sh + cat configure >>configure.sh +else + cp configure configure.sh fi -cat configure >>configure.sh chmod +x configure.sh # Stop here if this is a dry run diff --git a/sr_unix/gtmio.h b/sr_unix/gtmio.h index 5aab776..e1cf0ec 100644 --- a/sr_unix/gtmio.h +++ b/sr_unix/gtmio.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,17 +43,22 @@ #ifndef GTMIO_Included #define GTMIO_Included -#include -#include "gtm_stat.h" -#include "gtm_unistd.h" -#include "gtm_fcntl.h" -#include "eintr_wrappers.h" -#include "min_max.h" +#ifndef GTMIO_MINIMAL /* Avoid pulling in includes that make gtm_icu.c uncompilable */ +# include +# include "gtm_stat.h" +# include "gtm_unistd.h" +# include "gtm_fcntl.h" +# include "eintr_wrappers.h" +# include "min_max.h" +# include "wbox_test_init.h" +#endif #ifdef __linux__ #include #endif +error_def(ERR_PREMATEOF); + #ifdef KEEP_zOS_EBCDIC #define DOWRITE_A __write_a #define DOREAD_A __read_a @@ -657,13 +662,15 @@ } \ FCNTL3(FDESC, F_SETFL, FLAGS, tfcntl_res); \ if (0 > tfcntl_res) \ - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, \ + 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); \ *BLOCKED_IN = TRUE; \ if (PIPE_ZERO_TIMEOUT) \ { \ TOFLAG = FALSE; \ /* Set a timer for 1 sec so atomic read x:0 will still work on \ - loaded systems but timeout on incomplete reads. Any characters \ + loaded systems but timeout on incomplete reads. \ + Any characters \ read to this point will be returned. */ \ *MSEC_TIMEOUT = timeout2msec(1); \ start_timer(TIMER_ID, *MSEC_TIMEOUT, wake_alarm, 0, NULL); \ @@ -773,12 +780,12 @@ #define DOLLAR_DEVICE_SET(DEVPTR,STATUS) \ { \ len = SIZEOF(ONE_COMMA) - 1; \ - memcpy(DEVPTR->dollar_device, ONE_COMMA, len); \ + memcpy(DEVPTR->dollar.device, ONE_COMMA, len); \ errptr = (char *)STRERROR(STATUS); \ /* make sure there is room for the 1, and the null at the end */ \ - errlen = MIN(STRLEN(errptr), SIZEOF(DEVPTR->dollar_device) - SIZEOF(ONE_COMMA)); \ - memcpy(&DEVPTR->dollar_device[len], errptr, errlen); \ - DEVPTR->dollar_device[len + errlen] = '\0'; \ + errlen = MIN(STRLEN(errptr), SIZEOF(DEVPTR->dollar.device) - SIZEOF(ONE_COMMA)); \ + memcpy(&DEVPTR->dollar.device[len], errptr, errlen); \ + DEVPTR->dollar.device[len + errlen] = '\0'; \ } #define DOLLAR_DEVICE_WRITE(DEVPTR,STATUS) \ @@ -790,7 +797,7 @@ if (EAGAIN == STATUS) \ { \ len = SIZEOF(ONE_COMMA_UNAVAILABLE); \ - memcpy(DEVPTR->dollar_device, ONE_COMMA_UNAVAILABLE, len); \ + memcpy(DEVPTR->dollar.device, ONE_COMMA_UNAVAILABLE, len); \ } else \ DOLLAR_DEVICE_SET(DEVPTR,STATUS); \ } @@ -833,24 +840,28 @@ #define DO_FILE_READ(CHANNEL, OFFSET, READBUFF, LEN, STATUS1, STATUS2) \ { \ - error_def(ERR_PREMATEOF); \ - \ STATUS2 = SS_NORMAL; \ LSEEKREAD(CHANNEL, OFFSET, READBUFF, LEN, STATUS1); \ if (-1 == STATUS1) \ STATUS1 = ERR_PREMATEOF; \ } -#define DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \ +#define DB_DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \ { \ - error_def(ERR_PREMATEOF); \ - \ STATUS2 = SS_NORMAL; \ - LSEEKWRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1); \ + DB_LSEEKWRITE(NULL, NULL, CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1); \ if (-1 == STATUS1) \ STATUS1 = ERR_PREMATEOF; \ } +#define JNL_DO_FILE_WRITE(CSA, JNL_FN, CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \ +{ \ + STATUS2 = SS_NORMAL; \ + JNL_LSEEKWRITE(CSA, JNL_FN, CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1); \ + if (-1 == STATUS1) \ + STATUS1 = ERR_PREMATEOF; \ +} + typedef struct { int fd; diff --git a/sr_unix/gtmprofile.gtc b/sr_unix/gtmprofile.gtc index af451a5..04c9caf 100644 --- a/sr_unix/gtmprofile.gtc +++ b/sr_unix/gtmprofile.gtc @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2010, 2012 Fidelity Information Services, Inc.# +# Copyright 2010, 2013 Fidelity Information Services, Inc.# # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -89,7 +89,7 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then # Note that if UTF-8 mode cannot be properly set, GT.M remains configured for M mode if [ "zos" = $arch ] ; then # for z/OS make sure the en_US.UTF-8 locale is available and set $gtm_chset_locale if it is - utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1` + utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1` if [ "`echo $gtm_chset|tr utf UTF`" = "UTF-8" -a -d $gtm_dist/utf8 -a $utflocale = en_US.UTF-8 ] ; then gtm_chset_locale=$utflocale; export gtm_chset_locale if [ "`echo Halt | gtm_prompt='GTM>' $gtm_dist/utf8/mumps -dir | tail -n 1`" = 'GTM>' ] ; then @@ -239,12 +239,16 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then # Other useful environment variables # System administrators - add, delete or modify GT.M environment variables here as appropriate for your installation + if [ -z "$gtm_etrap" ] ; then + gtm_etrap='Write:(0=$STACK) "Error occurred: ",$ZStatus,!' ; export gtm_etrap + fi if [ -z "$gtm_principal_editing" ] ; then gtm_principal_editing="EDITING" ; export gtm_principal_editing fi if [ -z "$gtm_repl_instance" ] ; then gtm_repl_instance=$gtmdir/$gtmver/g/gtm.repl ; export gtm_repl_instance - else gtm_repl_instance=`echo $gtm_repl_instance | sed "s;$old_gtmver;$gtmver;"` + elif [ -n "$old_gtmver" ] ; then + gtm_repl_instance=`echo $gtm_repl_instance | sed "s;$old_gtmver;$gtmver;"` fi if [ -z "$gtm_retention" ] ; then gtm_retention=42 ; export gtm_retention diff --git a/sr_unix/gtmrecv.c b/sr_unix/gtmrecv.c index 89069cd..0a78f83 100644 --- a/sr_unix/gtmrecv.c +++ b/sr_unix/gtmrecv.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -80,6 +80,7 @@ GBLREF jnlpool_addrs jnlpool; GBLREF IN_PARMS *cli_lex_in_ptr; GBLREF uint4 mutex_per_process_init_pid; +error_def(ERR_INITORRESUME); error_def(ERR_MUPCLIERR); error_def(ERR_NORESYNCSUPPLONLY); error_def(ERR_NORESYNCUPDATERONLY); @@ -105,18 +106,18 @@ int gtmrecv(void) uint4 gtmrecv_pid; int idx, semval, status, save_upd_status, upd_start_status, upd_start_attempts; char print_msg[1024], tmpmsg[1024]; - recvpool_user pool_user = GTMRECV; pid_t pid, procgp; - int exit_status, waitpid_res; + int exit_status, waitpid_res, save_errno; int log_init_status; int updresync_instfile_fd; /* fd of the instance file name specified in -UPDATERESYNC= */ boolean_t cross_endian; + int null_fd, rc; call_on_signal = gtmrecv_sigstop; ESTABLISH_RET(gtmrecv_ch, SS_NORMAL); memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool)); if (-1 == gtmrecv_get_opt()) - rts_error(VARLSTCNT(1) ERR_MUPCLIERR); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR); if (gtmrecv_options.start || gtmrecv_options.shut_down) { jnlpool_init(GTMRECEIVE, (boolean_t)FALSE, (boolean_t *)NULL); @@ -130,14 +131,15 @@ int gtmrecv(void) */ if (gtmrecv_options.updateresync && jnlpool.repl_inst_filehdr->num_histinfo && !(jnlpool.repl_inst_filehdr->is_supplementary && !jnlpool.jnlpool_ctl->upd_disabled)) - rts_error(VARLSTCNT(1) ERR_UPDSYNC2MTINS); /* replication instance file is NOT empty. Issue error */ + /* replication instance file is NOT empty. Issue error */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UPDSYNC2MTINS); if (gtmrecv_options.noresync) { /* If -NORESYNC was specified on a non-supplementary receiver instance, issue an error */ if (!jnlpool.repl_inst_filehdr->is_supplementary) - rts_error(VARLSTCNT(1) ERR_NORESYNCSUPPLONLY); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NORESYNCSUPPLONLY); /* If -NORESYNC was specified on a receiver instance where updates are disabled, issue an error */ if (jnlpool.jnlpool_ctl->upd_disabled) - rts_error(VARLSTCNT(1) ERR_NORESYNCUPDATERONLY); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NORESYNCUPDATERONLY); } } if (gtmrecv_options.shut_down) @@ -154,7 +156,7 @@ int gtmrecv(void) } else repl_log(stdout, FALSE, TRUE, "Signalling immediate shutdown\n"); } - recvpool_init(pool_user, gtmrecv_options.start && 0 != gtmrecv_options.listen_port); + recvpool_init(GTMRECV, gtmrecv_options.start && 0 != gtmrecv_options.listen_port); /* * When gtmrecv_options.start is TRUE, shm field recvpool.recvpool_ctl->fresh_start is updated in "recvpool_init" * recvpool.recvpool_ctl->fresh_start == TRUE ==> fresh start, and @@ -164,214 +166,230 @@ int gtmrecv(void) upd_proc_local = recvpool.upd_proc_local; gtmrecv_local = recvpool.gtmrecv_local; upd_helper_ctl = recvpool.upd_helper_ctl; - if (GTMRECV == pool_user) + if (gtmrecv_options.start) { - if (gtmrecv_options.start) + if (0 == gtmrecv_options.listen_port /* implies (updateonly || helpers only) */ + || !recvpool_ctl->fresh_start) { - if (0 == gtmrecv_options.listen_port /* implies (updateonly || helpers only) */ - || !recvpool_ctl->fresh_start) + if (SRV_ALIVE == (status = is_recv_srv_alive()) && 0 != gtmrecv_options.listen_port) { - if (SRV_ALIVE == (status = is_recv_srv_alive()) && 0 != gtmrecv_options.listen_port) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Receiver Server already exists")); - } else if (SRV_DEAD == status && 0 == gtmrecv_options.listen_port) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Receiver server does not exist. Start it first")); - } else if (SRV_ERR == status) - { - status = errno; - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Receiver server semaphore error"), status); - } - if (gtmrecv_options.updateonly) - { - status = gtmrecv_start_updonly() - UPDPROC_STARTED; - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - gtmrecv_exit(status); - } - if (gtmrecv_options.helpers && 0 == gtmrecv_options.listen_port) - { /* start helpers only */ - status = gtmrecv_start_helpers(gtmrecv_options.n_readers, gtmrecv_options.n_writers); - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - gtmrecv_exit(status - NORMAL_SHUTDOWN); - } - } - if (gtmrecv_options.updateresync && ('\0' != gtmrecv_options.updresync_instfilename[0])) - { /* -UPDATERESYNC= was specified. - * Note: -UPDATERESYNC without a value is treated as -UPDATERESYNC="" hence the above check. - */ - OPENFILE(gtmrecv_options.updresync_instfilename, O_RDONLY, updresync_instfile_fd); - if (FD_INVALID == updresync_instfile_fd) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(5) ERR_REPLINSTOPEN, 2, - LEN_AND_STR(gtmrecv_options.updresync_instfilename), errno); - } - LSEEKREAD(updresync_instfile_fd, 0, &updresync_inst_hdr, SIZEOF(updresync_inst_hdr), status); - if (0 != status) - { /* Encountered an error reading the full file header */ - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Input file does not even have a full instance file header")); - } - /* Check if it is the right version */ - if (memcmp(updresync_inst_hdr.label, GDS_REPL_INST_LABEL, GDS_REPL_INST_LABEL_SZ - 1)) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(10) ERR_UPDSYNCINSTFILE, 0, - ERR_REPLINSTFMT, 6, LEN_AND_STR(gtmrecv_options.updresync_instfilename), - GDS_REPL_INST_LABEL_SZ - 1, GDS_REPL_INST_LABEL, - GDS_REPL_INST_LABEL_SZ - 1, updresync_inst_hdr.label); - } - /* Check endianness match. If not, fields have to be endian converted before examining them. */ - cross_endian = (GTM_IS_LITTLE_ENDIAN != updresync_inst_hdr.is_little_endian); - /* At the time of this writing, the only minor version supported is 1. - * Whenever this gets updated, we need to add code to do the online upgrade. - * Add an assert as a reminder to do this. - */ - assert(1 == SIZEOF(updresync_inst_hdr.replinst_minorver)); /* so no endian conversion needed */ - assert(1 == updresync_inst_hdr.replinst_minorver); - /* Check if cleanly shutdown */ - if (cross_endian) - { - assert(4 == SIZEOF(updresync_inst_hdr.crash)); /* so need to use GTM_BYTESWAP_32 */ - updresync_inst_hdr.crash = GTM_BYTESWAP_32(updresync_inst_hdr.crash); - } - if (updresync_inst_hdr.crash) - { /* The instance file cannot be used for updateresync if it was not cleanly shutdown */ - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Input instance file was not cleanly shutdown")); - } - if (cross_endian) - { - assert(4 == SIZEOF(updresync_inst_hdr.is_supplementary)); /* so need GTM_BYTESWAP_32 */ - updresync_inst_hdr.is_supplementary = GTM_BYTESWAP_32(updresync_inst_hdr.is_supplementary); - assert(8 == SIZEOF(updresync_inst_hdr.jnl_seqno)); /* so need to use GTM_BYTESWAP_64 */ - updresync_inst_hdr.jnl_seqno = GTM_BYTESWAP_64(updresync_inst_hdr.jnl_seqno); - assert(4 == SIZEOF(updresync_inst_hdr.num_histinfo)); /* so need to use GTM_BYTESWAP_32 */ - updresync_inst_hdr.num_histinfo = GTM_BYTESWAP_32(updresync_inst_hdr.num_histinfo); - } - if (jnlpool.repl_inst_filehdr->is_supplementary && !updresync_inst_hdr.is_supplementary) - { /* Do one check for non-supplementary -> supplementary connection using -updateresync. - * This is because this use of -updateresync is different than the other connection usages. - */ - if (!updresync_inst_hdr.jnl_seqno) - { /* The instance file cannot be used for updateresync if it has a ZERO seqno */ - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Non-supplementary input instance file cannot be used" - " on supplementary instance when it is empty (has seqno of 0)")); - } - } - /* else similar checks of the jnl_seqno and num_histinfo for other types of connections (i.e. - * non-supplementary -> non-supplementary, supplementary -> supplementary) will be done later in - * "repl_inst_get_updresync_histinfo" only when there is a need to scan the input instance file - * for any history record. - */ - updresync_inst_hdr.num_histinfo--; /* needed to get at the last history record */ - if (cross_endian) - ENDIAN_CONVERT_REPL_INST_UUID(&updresync_inst_hdr.lms_group_info); - if (IS_REPL_INST_UUID_NULL(updresync_inst_hdr.lms_group_info)) - { /* The input instance has a NULL LMS group. Cannot be used to fill in current instance */ - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Input instance file has NULL LMS group")); - } - if (updresync_inst_hdr.is_supplementary) - { /* The input instance file is supplementary. Allow it only if the current instance is - * supplementary and is not a root primary. - */ - if (!jnlpool.repl_inst_filehdr->is_supplementary) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - LEN_AND_LIT("Input instance file must be non-supplementary" - " to match current instance")); - assert(FALSE); - } - if (!jnlpool.jnlpool_ctl->upd_disabled) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - LEN_AND_LIT("Input instance file must be non-supplementary" - " as current instance is a supplementary root primary")); - } - } else if (jnlpool.repl_inst_filehdr->is_supplementary && jnlpool.jnlpool_ctl->upd_disabled) - { /* The input instance file is non-supplementary. Allow it only if the current instance is - * non-supplementary or if it is a supplementary root primary. - */ - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - LEN_AND_LIT("Input instance file must be supplementary" - " to match current instance")); - } - if (!jnlpool.repl_inst_filehdr->is_supplementary || jnlpool.jnlpool_ctl->upd_disabled) - { - if (gtmrecv_options.resume_specified) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, - LEN_AND_LIT("RESUME allowed only on root primary supplementary instance")); - } - if (gtmrecv_options.reuse_specified) - { - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, - LEN_AND_LIT("REUSE allowed only on root primary supplementary instance")); - } - } - } -# ifndef REPL_DEBUG_NOBACKGROUND - FORK_CLEAN(pid); - if (0 < pid) + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Receiver Server already exists")); + } else if (SRV_DEAD == status && 0 == gtmrecv_options.listen_port) { - REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid); - while (0 == (semval = get_sem_info(RECV, RECV_SERV_COUNT_SEM, SEM_INFO_VAL)) && - is_proc_alive(pid, 0)) - { - /* To take care of reassignment of PIDs, the while condition should be && with the - * condition (PPID of pid == process_id) - */ - REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid); - SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); - WAITPID(pid, &exit_status, WNOHANG, waitpid_res); /* Release defunct child if dead */ - } - if (0 <= semval) - rel_sem(RECV, RECV_SERV_OPTIONS_SEM); - gtmrecv_exit(1 == semval ? SRV_ALIVE : SRV_DEAD); - } else if (0 > pid) + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Receiver server does not exist. Start it first")); + } else if (SRV_ERR == status) { status = errno; - rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Unable to fork"), status); + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Receiver server semaphore error"), status); } -# endif - } else if (gtmrecv_options.shut_down) - { if (gtmrecv_options.updateonly) - gtmrecv_exit(gtmrecv_endupd() - NORMAL_SHUTDOWN); - if (gtmrecv_options.helpers) - gtmrecv_exit(gtmrecv_end_helpers(FALSE) - NORMAL_SHUTDOWN); - gtmrecv_exit(gtmrecv_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN); - } else if (gtmrecv_options.changelog) - gtmrecv_exit(gtmrecv_changelog() - NORMAL_SHUTDOWN); - else if (gtmrecv_options.checkhealth) - gtmrecv_exit(gtmrecv_checkhealth() - NORMAL_SHUTDOWN); - else if (gtmrecv_options.showbacklog) - gtmrecv_exit(gtmrecv_showbacklog() - NORMAL_SHUTDOWN); - else - gtmrecv_exit(gtmrecv_statslog() - NORMAL_SHUTDOWN); - } /* (pool_user != GTMRECV) */ + { + status = gtmrecv_start_updonly() - UPDPROC_STARTED; + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + gtmrecv_exit(status); + } + if (gtmrecv_options.helpers && 0 == gtmrecv_options.listen_port) + { /* start helpers only */ + status = gtmrecv_start_helpers(gtmrecv_options.n_readers, gtmrecv_options.n_writers); + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + gtmrecv_exit(status - NORMAL_SHUTDOWN); + } + } + if (gtmrecv_options.updateresync && ('\0' != gtmrecv_options.updresync_instfilename[0])) + { /* -UPDATERESYNC= was specified. + * Note: -UPDATERESYNC without a value is treated as -UPDATERESYNC="" hence the above check. + */ + OPENFILE(gtmrecv_options.updresync_instfilename, O_RDONLY, updresync_instfile_fd); + if (FD_INVALID == updresync_instfile_fd) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLINSTOPEN, 2, + LEN_AND_STR(gtmrecv_options.updresync_instfilename), errno); + } + LSEEKREAD(updresync_instfile_fd, 0, &updresync_inst_hdr, SIZEOF(updresync_inst_hdr), status); + if (0 != status) + { /* Encountered an error reading the full file header */ + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Input file does not even have a full instance file header")); + } + /* Check if it is the right version */ + if (memcmp(updresync_inst_hdr.label, GDS_REPL_INST_LABEL, GDS_REPL_INST_LABEL_SZ - 1)) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UPDSYNCINSTFILE, 0, + ERR_REPLINSTFMT, 6, LEN_AND_STR(gtmrecv_options.updresync_instfilename), + GDS_REPL_INST_LABEL_SZ - 1, GDS_REPL_INST_LABEL, + GDS_REPL_INST_LABEL_SZ - 1, updresync_inst_hdr.label); + } + /* Check endianness match. If not, fields have to be endian converted before examining them. */ + cross_endian = (GTM_IS_LITTLE_ENDIAN != updresync_inst_hdr.is_little_endian); + /* At the time of this writing, the only minor version supported is 1. + * Whenever this gets updated, we need to add code to do the online upgrade. + * Add an assert as a reminder to do this. + */ + assert(1 == SIZEOF(updresync_inst_hdr.replinst_minorver)); /* so no endian conversion needed */ + assert(1 == updresync_inst_hdr.replinst_minorver); + /* Check if cleanly shutdown */ + if (cross_endian) + { + assert(4 == SIZEOF(updresync_inst_hdr.crash)); /* so need to use GTM_BYTESWAP_32 */ + updresync_inst_hdr.crash = GTM_BYTESWAP_32(updresync_inst_hdr.crash); + } + if (updresync_inst_hdr.crash) + { /* The instance file cannot be used for updateresync if it was not cleanly shutdown */ + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Input instance file was not cleanly shutdown")); + } + if (cross_endian) + { + assert(4 == SIZEOF(updresync_inst_hdr.is_supplementary)); /* so need GTM_BYTESWAP_32 */ + updresync_inst_hdr.is_supplementary = GTM_BYTESWAP_32(updresync_inst_hdr.is_supplementary); + assert(8 == SIZEOF(updresync_inst_hdr.jnl_seqno)); /* so need to use GTM_BYTESWAP_64 */ + updresync_inst_hdr.jnl_seqno = GTM_BYTESWAP_64(updresync_inst_hdr.jnl_seqno); + assert(4 == SIZEOF(updresync_inst_hdr.num_histinfo)); /* so need to use GTM_BYTESWAP_32 */ + updresync_inst_hdr.num_histinfo = GTM_BYTESWAP_32(updresync_inst_hdr.num_histinfo); + } + if (jnlpool.repl_inst_filehdr->is_supplementary && !updresync_inst_hdr.is_supplementary) + { /* Do one check for non-supplementary -> supplementary connection using -updateresync. + * This is because this use of -updateresync is different than the other connection usages. + */ + if (!updresync_inst_hdr.jnl_seqno) + { /* The instance file cannot be used for updateresync if it has a ZERO seqno */ + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Non-supplementary input instance file cannot be used" + " on supplementary instance when it is empty (has seqno of 0)")); + } + } + /* else similar checks of the jnl_seqno and num_histinfo for other types of connections (i.e. + * non-supplementary -> non-supplementary, supplementary -> supplementary) will be done later in + * "repl_inst_get_updresync_histinfo" only when there is a need to scan the input instance file + * for any history record. + */ + updresync_inst_hdr.num_histinfo--; /* needed to get at the last history record */ + if (cross_endian) + ENDIAN_CONVERT_REPL_INST_UUID(&updresync_inst_hdr.lms_group_info); + if (IS_REPL_INST_UUID_NULL(updresync_inst_hdr.lms_group_info)) + { /* The input instance has a NULL LMS group. Cannot be used to fill in current instance */ + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Input instance file has NULL LMS group")); + } + if (updresync_inst_hdr.is_supplementary) + { /* The input instance file is supplementary. Allow it only if the current instance is + * supplementary and is not a root primary. + */ + if (!jnlpool.repl_inst_filehdr->is_supplementary) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + LEN_AND_LIT("Input instance file must be non-supplementary" + " to match current instance")); + assert(FALSE); + } + if (!jnlpool.jnlpool_ctl->upd_disabled) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + LEN_AND_LIT("Input instance file must be non-supplementary" + " as current instance is a supplementary root primary")); + } + } else if (jnlpool.repl_inst_filehdr->is_supplementary) + { + if (jnlpool.jnlpool_ctl->upd_disabled) + { /* The input instance file is non-supplementary. Allow it only if the current + * instance is non-supplementary or if it is a supplementary root primary. + */ + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + LEN_AND_LIT("Input instance file must be supplementary" + " to match current instance")); + } + if (!gtmrecv_options.resume_specified && !gtmrecv_options.initialize_specified) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INITORRESUME); + } + } + if (!jnlpool.repl_inst_filehdr->is_supplementary || jnlpool.jnlpool_ctl->upd_disabled) + { + if (gtmrecv_options.resume_specified) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, + LEN_AND_LIT("RESUME allowed only on root primary supplementary instance")); + } + if (gtmrecv_options.reuse_specified) + { + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, + LEN_AND_LIT("REUSE allowed only on root primary supplementary instance")); + } + } + } +# ifndef REPL_DEBUG_NOBACKGROUND + FORK_CLEAN(pid); + if (0 < pid) + { + REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid); + while (0 == (semval = get_sem_info(RECV, RECV_SERV_COUNT_SEM, SEM_INFO_VAL)) && + is_proc_alive(pid, 0)) + { + /* To take care of reassignment of PIDs, the while condition should be && with the + * condition (PPID of pid == process_id) + */ + REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid); + SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); + WAITPID(pid, &exit_status, WNOHANG, waitpid_res); /* Release defunct child if dead */ + } + if (0 <= semval) + rel_sem(RECV, RECV_SERV_OPTIONS_SEM); + gtmrecv_exit(1 == semval ? SRV_ALIVE : SRV_DEAD); + } else if (0 > pid) + { + status = errno; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to fork"), status); + } +# endif + } else if (gtmrecv_options.shut_down) + { + if (gtmrecv_options.updateonly) + gtmrecv_exit(gtmrecv_endupd() - NORMAL_SHUTDOWN); + if (gtmrecv_options.helpers) + gtmrecv_exit(gtmrecv_end_helpers(FALSE) - NORMAL_SHUTDOWN); + gtmrecv_exit(gtmrecv_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN); + } else if (gtmrecv_options.changelog) + gtmrecv_exit(gtmrecv_changelog() - NORMAL_SHUTDOWN); + else if (gtmrecv_options.checkhealth) + gtmrecv_exit(gtmrecv_checkhealth() - NORMAL_SHUTDOWN); + else if (gtmrecv_options.showbacklog) + gtmrecv_exit(gtmrecv_showbacklog() - NORMAL_SHUTDOWN); + else + gtmrecv_exit(gtmrecv_statslog() - NORMAL_SHUTDOWN); + /* Point stdin to /dev/null */ + OPENFILE("/dev/null", O_RDONLY, null_fd); + if (0 > null_fd) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0); + FCNTL3(null_fd, F_DUPFD, 0, rc); + if (0 > rc) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0); + CLOSEFILE(null_fd, rc); + if (0 > rc) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0); assert(!holds_sem[RECV][RECV_POOL_ACCESS_SEM]); assert(holds_sem[RECV][RECV_SERV_OPTIONS_SEM]); is_rcvr_server = TRUE; process_id = getpid(); + OPERATOR_LOG_MSG; /* Reinvoke secshr related initialization with the child's pid */ INVOKE_INIT_SECSHR_ADDRS; /* Initialize mutex socket, memory semaphore etc. before any "grab_lock" is done by this process on the journal pool. @@ -433,11 +451,11 @@ int gtmrecv(void) upd_proc_local->log_interval = gtmrecv_options.upd_log_interval; upd_helper_ctl->start_helpers = FALSE; upd_helper_ctl->start_n_readers = upd_helper_ctl->start_n_writers = 0; - log_init_status = repl_log_init(REPL_GENERAL_LOG, >mrecv_log_fd, NULL, gtmrecv_options.log_file, NULL); + log_init_status = repl_log_init(REPL_GENERAL_LOG, >mrecv_log_fd, gtmrecv_options.log_file); assert(SS_NORMAL == log_init_status); repl_log_fd2fp(>mrecv_log_fp, gtmrecv_log_fd); if (-1 == (procgp = setsid())) - rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receiver server error in setsid"), errno); gtm_event_log_init(); gtmrecv_local->recv_serv_pid = process_id; @@ -452,14 +470,21 @@ int gtmrecv(void) process_id, jnlpool.repl_inst_filehdr->inst_info.this_instname); sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg)); repl_log(gtmrecv_log_fp, TRUE, TRUE, print_msg); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Attached to existing jnlpool with shmid = [%d] and semid = [%d]\n", + jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid); gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg); if (recvpool_ctl->fresh_start) + { QWASSIGNDW(recvpool_ctl->jnl_seqno, 0); /* Update process will initialize this to a non-zero value */ - else + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Created recvpool with shmid = [%d] and semid = [%d]\n", + jnlpool.repl_inst_filehdr->recvpool_shmid, jnlpool.repl_inst_filehdr->recvpool_semid); + } else { /* Coming up after a crash, reset Update process read. This is done by setting gtmrecv_local->restart. * This will trigger update process to reset recvpool_ctl->jnl_seqno too. */ gtmrecv_local->restart = GTMRECV_RCVR_RESTARTED; + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Attached to existing recvpool with shmid = [%d] and semid = [%d]\n", + jnlpool.repl_inst_filehdr->recvpool_shmid, jnlpool.repl_inst_filehdr->recvpool_semid); } save_upd_status = upd_proc_local->upd_proc_shutdown; for (upd_start_attempts = 0; @@ -516,11 +541,14 @@ int gtmrecv(void) * that. Do that while the parent is still waiting for our okay. */ if (!ftok_sem_incrcnt(recvpool.recvpool_dummy_reg)) - rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RECVPOOLSETUP); /* Lock the receiver server count semaphore. Its value should be atmost 1. */ if (0 > grab_sem_immediate(RECV, RECV_SERV_COUNT_SEM)) - rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool semop failure"), - REPL_SEM_ERRNO); + { + save_errno = errno; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Receive pool semop failure"), save_errno); + } # ifdef REPL_DEBUG_NOBACKGROUND rel_sem(RECV, RECV_SERV_OPTIONS_SEM); # endif diff --git a/sr_unix/gtmrecv.h b/sr_unix/gtmrecv.h index 37a0431..af3cd9e 100644 --- a/sr_unix/gtmrecv.h +++ b/sr_unix/gtmrecv.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -205,7 +205,6 @@ typedef struct typedef struct { uint4 recv_serv_pid; /* Process identification of receiver server */ - int4 primary_inet_addr; /* IP address of the primary system */ int4 lastrecvd_time; /* unused */ /* Data items used in communicating action qualifiers (show statistics, shutdown) and * qualifier values (log file, shutdown time, etc). */ @@ -329,10 +328,13 @@ typedef enum UPDPROC, UPD_HELPER_READER, UPD_HELPER_WRITER, - GTMRECV -#ifdef VMS - , GTMRECV_CHILD -#endif + GTMRECV, +# ifdef UNIX + GTMZPEEK +# endif +# ifdef VMS + GTMRECV_CHILD +# endif } recvpool_user; typedef struct @@ -355,6 +357,7 @@ typedef struct boolean_t helpers; boolean_t reuse_specified; boolean_t resume_specified; + boolean_t initialize_specified; int4 resume_strm_num; int4 n_readers; int4 n_writers; diff --git a/sr_unix/gtmrecv_end.c b/sr_unix/gtmrecv_end.c index e2ee1ce..528b93a 100644 --- a/sr_unix/gtmrecv_end.c +++ b/sr_unix/gtmrecv_end.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,6 +43,7 @@ #include "is_proc_alive.h" #include "gtmsource.h" #include "gtmio.h" +#include "have_crit.h" GBLREF uint4 process_id; GBLREF recvpool_addrs recvpool; @@ -51,9 +52,7 @@ GBLREF boolean_t gtmrecv_logstats; GBLREF int gtmrecv_listen_sock_fd; GBLREF int gtmrecv_sock_fd; GBLREF int gtmrecv_log_fd; -GBLREF int gtmrecv_statslog_fd; GBLREF FILE *gtmrecv_log_fp; -GBLREF FILE *gtmrecv_statslog_fp; GBLREF qw_num repl_recv_data_recvd; GBLREF qw_num repl_recv_data_processed; GBLREF repl_msg_ptr_t gtmrecv_msgp; @@ -65,7 +64,7 @@ GBLREF boolean_t pool_init; int gtmrecv_endupd(void) { pid_t savepid; - int exit_status; + int exit_status, status, save_errno; pid_t waitpid_res; repl_log(stdout, TRUE, TRUE, "Initiating shut down of Update Process\n"); @@ -91,12 +90,17 @@ int gtmrecv_endupd(void) /* Wait for the Update Process to detach */ if (0 == grab_sem(RECV, UPD_PROC_COUNT_SEM)) { - if(0 != (errno = rel_sem(RECV, UPD_PROC_COUNT_SEM))) - repl_log(stderr, TRUE, TRUE, "Error releasing the Update Process Count semaphore : %s\n", REPL_SEM_ERROR); + if (0 != (status = rel_sem(RECV, UPD_PROC_COUNT_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Error releasing the Update Process Count semaphore : %s\n", + STRERROR(save_errno)); + } repl_log(stdout, TRUE, TRUE, "Update Process exited\n"); } else { - repl_log(stderr, TRUE, TRUE, "Error in update proc count semaphore : %s\n", REPL_SEM_ERROR); + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Error in update proc count semaphore : %s\n", STRERROR(save_errno)); exit_status = ABNORMAL_SHUTDOWN; } return (exit_status); @@ -105,7 +109,7 @@ int gtmrecv_endupd(void) int gtmrecv_end1(boolean_t auto_shutdown) { int4 strm_idx; - int exit_status, idx; + int exit_status, idx, status, save_errno; int fclose_res, rc; seq_num log_seqno, log_seqno1, jnlpool_seqno, jnlpool_strm_seqno[MAX_SUPPL_STRMS]; uint4 savepid; @@ -118,8 +122,11 @@ int gtmrecv_end1(boolean_t auto_shutdown) /* Detach from receive pool */ recvpool.gtmrecv_local->shutdown = exit_status; recvpool.gtmrecv_local->recv_serv_pid = 0; - if (recvpool.recvpool_ctl && 0 > SHMDT(recvpool.recvpool_ctl)) - repl_log(stderr, TRUE, TRUE, "Error detaching from Receive Pool : %s\n", REPL_STR_ERROR); + if (0 > SHMDT(recvpool.recvpool_ctl)) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Error detaching from Receive Pool : %s\n", STRERROR(save_errno)); + } recvpool.recvpool_ctl = NULL; assert((NULL != jnlpool_ctl) && (jnlpool_ctl == jnlpool.jnlpool_ctl)); if (NULL != jnlpool.jnlpool_ctl) @@ -138,8 +145,9 @@ int gtmrecv_end1(boolean_t auto_shutdown) */ if (!auto_shutdown) { - if (0 > SHMDT(jnlpool.jnlpool_ctl)) - repl_log(stderr, TRUE, TRUE, "Error detaching from Journal Pool : %s\n", REPL_STR_ERROR); + JNLPOOL_SHMDT(status, save_errno); + if (0 > status) + repl_log(stderr, TRUE, TRUE, "Error detaching from Journal Pool : %s\n", STRERROR(save_errno)); jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; jnlpool.repl_inst_filehdr = NULL; jnlpool.gtmsrc_lcl_array = NULL; diff --git a/sr_unix/gtmrecv_fetchresync.c b/sr_unix/gtmrecv_fetchresync.c index fbe997b..e147167 100644 --- a/sr_unix/gtmrecv_fetchresync.c +++ b/sr_unix/gtmrecv_fetchresync.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -64,10 +64,28 @@ #define MAX_WAIT_FOR_FETCHRESYNC_CONN 60 /* max-wait in seconds to establish connection with the source server */ #define FETCHRESYNC_PRIMARY_POLL (MICROSEC_IN_SEC - 1) /* micro seconds, almost 1 second */ +#define CHECK_SEND_RECV_LOOP_ERROR(STATUS, WAIT_COUNT, MESSAGE) \ +{ \ + if (SS_NORMAL != STATUS) \ + { \ + if (EREPL_RECV == repl_errno) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \ + LEN_AND_LIT("Error in recv() for " MESSAGE), STATUS); \ + else if (EREPL_SEND == repl_errno) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \ + LEN_AND_LIT("Error in send() for " MESSAGE), STATUS); \ + else if (EREPL_SELECT == repl_errno) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \ + LEN_AND_LIT("Error in select() for " MESSAGE), STATUS); \ + } \ + if (0 >= WAIT_COUNT) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, \ + LEN_AND_LIT("Waited too long to get/send" MESSAGE " from primary. Check if primary is alive."));\ +} + GBLREF uint4 process_id; GBLREF int recvpool_shmid; GBLREF int gtmrecv_listen_sock_fd, gtmrecv_sock_fd; -GBLREF struct sockaddr_in primary_addr; GBLREF seq_num seq_num_zero; GBLREF jnl_gbls_t jgbl; GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize; @@ -100,7 +118,6 @@ CONDITION_HANDLER(gtmrecv_fetchresync_ch) int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) { - GTM_SOCKLEN_TYPE primary_addr_len; repl_resync_msg_t resync_msg; repl_msg_t msg; uchar_ptr_t msgp; @@ -109,13 +126,12 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */ int status; /* needed for REPL_{SEND,RECV}_LOOP */ fd_set input_fds; - int wait_count; + int wait_count, save_errno; char seq_num_str[32], *seq_num_ptr; pid_t rollback_pid; int rollback_status; int wait_status; time_t t1, t2; - struct timeval gtmrecv_fetchresync_max_wait, gtmrecv_fetchresync_poll, sel_timeout_val; repl_old_instinfo_msg_t old_instinfo_msg; repl_old_needinst_msg_ptr_t old_need_instinfo_msg; repl_needinst_msg_t need_instinfo_msg; @@ -124,116 +140,75 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) seq_num histinfo_seqno; short retry_num; repl_inst_hdr_ptr_t inst_hdr; + repl_logfile_info_msg_t logfile_msg; + uint4 len; + struct addrinfo primary_ai; + struct sockaddr_storage primary_sas; + struct timeval repl_poll_wait; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - repl_log(stdout, TRUE, TRUE, "Assuming primary supports multisite functionality. Connecting " - "using multisite communication protocol.\n"); + repl_log(stdout, TRUE, TRUE, + "Assuming primary supports multisite functionality. Connecting using multisite communication protocol.\n"); ESTABLISH_RET(gtmrecv_fetchresync_ch, (!SS_NORMAL)); QWASSIGN(*resync_seqno, seq_num_zero); - gtmrecv_fetchresync_max_wait.tv_sec = MAX_WAIT_FOR_FETCHRESYNC_CONN; - gtmrecv_fetchresync_max_wait.tv_usec = 0; - gtmrecv_fetchresync_poll.tv_sec = 0; - gtmrecv_fetchresync_poll.tv_usec = FETCHRESYNC_PRIMARY_POLL; gtmrecv_comm_init(port); - primary_addr_len = SIZEOF(primary_addr); + primary_ai.ai_addr = (sockaddr_ptr)&primary_sas; + primary_ai.ai_addrlen = SIZEOF(primary_sas); remote_side->proto_ver = REPL_PROTO_VER_UNINITIALIZED; repl_log(stdout, TRUE, TRUE, "Waiting for a connection...\n"); - FD_ZERO(&input_fds); - FD_SET(gtmrecv_listen_sock_fd, &input_fds); - /* Note - the following call to select checks for EINTR. The SELECT macro is not used because - * the code also checks for EAGAIN and takes action before retrying the select. - */ - t1 = time(NULL); - while ((status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, >mrecv_fetchresync_max_wait)) < 0) + while (TRUE) { - if ((EINTR == errno) || (EAGAIN == errno)) + t1 = time(NULL); + repl_poll_wait.tv_sec = MAX_WAIT_FOR_FETCHRESYNC_CONN; + repl_poll_wait.tv_usec = 0; + while ((status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &repl_poll_wait)) < 0) { - t2 = time(NULL); - if (0 >= (int)(gtmrecv_fetchresync_max_wait.tv_sec = - (MAX_WAIT_FOR_FETCHRESYNC_CONN - (int)difftime(t2, t1)))) + if ((EINTR == errno) || (EAGAIN == errno)) { - status = 0; - break; - } - gtmrecv_fetchresync_max_wait.tv_usec = 0; - FD_SET(gtmrecv_listen_sock_fd, &input_fds); - continue; - } else - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in select on listen socket"), errno); - } - if (status == 0) - { - repl_log(stdout, TRUE, TRUE, "Waited about %d seconds for connection from primary source server\n", - MAX_WAIT_FOR_FETCHRESYNC_CONN); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Waited too long to get a connection request. Check if primary is alive.")); - } - ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr, - (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd); - if (0 > gtmrecv_sock_fd) - { -# ifdef __hpux - /* ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just - after a SYN before an accept call. Normally this is not fatal and is just a transient state.Hence - exiting just after a single error of this kind should not be done. So retry in case of HP-UX and ENOBUFS error*/ - if (ENOBUFS == errno) - { - retry_num = 0; - /*In case of succeeding with select in first go, accept will still get 5ms time difference*/ - while (HPUX_MAX_RETRIES > retry_num) - { - SHORT_SLEEP(5); - FD_ZERO(&input_fds); + t2 = time(NULL); + if (0 >= (int)(repl_poll_wait.tv_sec = (MAX_WAIT_FOR_FETCHRESYNC_CONN - (int)difftime(t2, t1)))) + { + status = 0; + break; + } + repl_poll_wait.tv_usec = 0; FD_SET(gtmrecv_listen_sock_fd, &input_fds); - /* Since we use Blocking socket, check before re-trying if there is a connection to be accepted. - * Timeout of HPUX_SEL_TIMEOUT. In case the earlier connection is not available there can be - * some time gap between the time the error occured and the new client requests coming in. - */ - for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++) - { - FD_ZERO(&input_fds); - FD_SET(gtmrecv_listen_sock_fd, &input_fds); - sel_timeout_val.tv_sec = 0; - sel_timeout_val.tv_usec = HPUX_SEL_TIMEOUT; - status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, - NULL, &sel_timeout_val); - if (0 < status) - break; - else - SHORT_SLEEP(5); - } - if (0 > status) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in select on listen socket after ENOBUFS error"), errno); - else - { - ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr, - (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd); - if ((0 > gtmrecv_sock_fd) && (errno == ENOBUFS)) - retry_num++; - else - break; - } - } + continue; + } else + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error in select on listen socket"), errno); } - if (0 > gtmrecv_sock_fd) -# endif + if (status == 0) { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error accepting connection from Source Server"), errno); + repl_log(stdout, TRUE, TRUE, "Waited about %d seconds for connection from primary source server\n", + MAX_WAIT_FOR_FETCHRESYNC_CONN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Waited too long to get a connection request. Check if primary is alive.")); } + ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr, + (GTM_SOCKLEN_TYPE *)&primary_ai.ai_addrlen, gtmrecv_sock_fd); + if (FD_INVALID == gtmrecv_sock_fd) + { + save_errno = errno; +# ifdef __hpux + if (ENOBUFS == save_errno) + continue; +# endif + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, + ERR_TEXT, 2, LEN_AND_LIT("Error accepting connection from Source Server"), save_errno); + } + break; } + /* Connection established */ repl_close(>mrecv_listen_sock_fd); /* Close the listener socket */ repl_connection_reset = FALSE; if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize)) || 0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize))) { - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT("Error getting socket send/recv buffsizes"), status); - return ERR_REPLCOMM; } repl_log(stdout, TRUE, TRUE, "Connection established, using TCP send buffer size %d receive buffer size %d\n", repl_max_send_buffsize, repl_max_recv_buffsize); @@ -252,16 +227,17 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) "REPL_FETCH_RESYNC", resync_msg.resync_seqno); if (repl_connection_reset) { /* Connection got reset during the above send */ - rts_error(VARLSTCNT(1) ERR_REPLCOMM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM); return ERR_REPLCOMM; } /* Wait for REPL_RESYNC_SEQNO (if dual-site primary) or REPL_OLD_NEED_INSTANCE_INFO (if multi-site primary) - * or REPL_NEED_INSTINFO (if multi-site primary with supplementary instance support) message */ + * or REPL_NEED_INSTINFO (if multi-site primary with supplementary instance support) message + */ do { wait_count = MAX_ATTEMPTS_FOR_FETCH_RESYNC; assert(SIZEOF(msg) == MIN_REPL_MSGLEN); - REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll) + REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT) { if (0 >= wait_count) break; @@ -269,18 +245,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) " or REPL_NEED_INSTINFO or REPL_NEED_HISTINFO\n"); wait_count--; } - if (status != SS_NORMAL) - { - if (EREPL_RECV == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error receiving RESYNC JNLSEQNO. Error in recv"), status); - if (EREPL_SELECT == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error receiving RESYNC JNLSEQNO. Error in select"), status); - } - if (wait_count <= 0) - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, - LEN_AND_LIT("Waited too long to get message from primary. Check if primary is alive.")); + CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "RESYNC JNLSEQNO"); if (!remote_side->endianness_known) { remote_side->endianness_known = TRUE; @@ -309,8 +274,9 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) if (jnlpool.repl_inst_filehdr->is_supplementary) { /* Issue REPL2OLD error because this is a supplementary instance and remote side runs * on a GT.M version that does not understand the supplementary protocol */ - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_need_instinfo_msg->instname), - LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, + LEN_AND_STR(old_need_instinfo_msg->instname), + LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); } remote_side->proto_ver = old_need_instinfo_msg->proto_ver; assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver); @@ -324,7 +290,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) gtmrecv_repl_send((repl_msg_ptr_t)&old_instinfo_msg, REPL_OLD_INSTANCE_INFO, MIN_REPL_MSGLEN, "REPL_OLD_INSTANCE_INFO", MAX_SEQNO); if (old_instinfo_msg.was_rootprimary && !old_need_instinfo_msg->is_rootprimary) - rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *)old_need_instinfo_msg->instname)); break; @@ -333,27 +299,14 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) assert(SIZEOF(need_instinfo_msg) > MIN_REPL_MSGLEN); memcpy(&need_instinfo_msg, &msg, MIN_REPL_MSGLEN); msgp = (uchar_ptr_t)&need_instinfo_msg + MIN_REPL_MSGLEN; - REPL_RECV_LOOP(gtmrecv_sock_fd, msgp, - SIZEOF(need_instinfo_msg) - MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll) + REPL_RECV_LOOP(gtmrecv_sock_fd, msgp, SIZEOF(need_instinfo_msg) - MIN_REPL_MSGLEN, REPL_POLL_WAIT) { if (0 >= wait_count) break; repl_log(stdout, TRUE, TRUE, "Waiting for REPL_NEED_INSTINFO\n"); wait_count--; } - if (status != SS_NORMAL) - { - if (EREPL_RECV == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in recv REPL_NEED_INSTINFO"), status); - if (EREPL_SELECT == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in select REPL_NEED_INSTINFO"), status); - } - if (wait_count <= 0) - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, - LEN_AND_LIT("Waited too long to get message from primary." - " Check if primary is alive.")); + CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_NEED_INSTINFO"); gtmrecv_check_and_send_instinfo(&need_instinfo_msg, IS_RCVR_SRVR_FALSE); break; @@ -424,7 +377,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) if (REPL_PROTO_VER_UNINITIALIZED == remote_side->proto_ver) { /* Issue REPL2OLD error because primary is dual-site */ assert(NULL != jnlpool.repl_inst_filehdr); - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME), LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); } assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver); @@ -438,16 +391,51 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) */ break; + case REPL_LOGFILE_INFO: + /* We got only a part of this message. Get the remaining part as well */ + assert(SIZEOF(logfile_msg) > MIN_REPL_MSGLEN); + assert(MIN_REPL_MSGLEN < msg.len); + assert(remote_side->endianness_known); + msgp = (uchar_ptr_t)&logfile_msg; + memcpy(msgp, &msg, MIN_REPL_MSGLEN); + REPL_RECV_LOOP(gtmrecv_sock_fd, msgp + MIN_REPL_MSGLEN, msg.len - MIN_REPL_MSGLEN, REPL_POLL_WAIT) + { + if (0 >= wait_count) + break; + wait_count--; + } + CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_LOGFILE_INFO"); + assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msg.proto_ver); + if (remote_side->cross_endian) + { + logfile_msg.fullpath_len = GTM_BYTESWAP_32(logfile_msg.fullpath_len); + logfile_msg.pid = GTM_BYTESWAP_32(logfile_msg.pid); + } + assert('\0' == logfile_msg.fullpath[logfile_msg.fullpath_len - 1]); + repl_log(stdout, TRUE, TRUE, "Remote side source log file path is %s; Source Server PID = %d\n", + logfile_msg.fullpath, logfile_msg.pid); + /* Now send our logfile path to the source side. Since the rollback doesn't have a logfile per-se, + * send just the $PWD + */ + len = repl_logfileinfo_get(NULL, &logfile_msg, remote_side->cross_endian, (FILE *)stdout); + REPL_SEND_LOOP(gtmrecv_sock_fd, &logfile_msg, len, REPL_POLL_WAIT) + { + if (0 >= wait_count) + break; + wait_count--; + } + CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_LOGFILE_INFO"); + break; default: repl_log(stdout, TRUE, TRUE, "Message of unknown type (%d) received\n", msg.type); assert(FALSE); - rts_error(VARLSTCNT(1) ERR_REPLCOMM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM); break; } } while (!repl_connection_reset && (REPL_RESYNC_SEQNO != msg.type)); if (repl_connection_reset) { /* Connection got reset during the above send */ - rts_error(VARLSTCNT(1) ERR_REPLCOMM); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM); return ERR_REPLCOMM; } assert(remote_side->endianness_known); /* only then is remote_side->cross_endian reliable */ @@ -456,7 +444,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno) else QWASSIGN(*resync_seqno, GTM_BYTESWAP_64(*(seq_num *)&msg.msg[0])); /* Wait till connection is broken or REPL_CONN_CLOSE is received */ - REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll) + REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT) { REPL_DPRINT1("FETCH_RESYNC : Waiting for source to send CLOSE_CONN or connection breakage\n"); } diff --git a/sr_unix/gtmrecv_poll_actions.c b/sr_unix/gtmrecv_poll_actions.c index b6a6de5..e7ae58c 100644 --- a/sr_unix/gtmrecv_poll_actions.c +++ b/sr_unix/gtmrecv_poll_actions.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2008, 2012 Fidelity Information Services, Inc.* + * Copyright 2008, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,15 +47,12 @@ GBLREF repl_msg_ptr_t gtmrecv_msgp; GBLREF int gtmrecv_max_repl_msglen; -GBLREF struct timeval gtmrecv_poll_interval, gtmrecv_poll_immediate; GBLREF int gtmrecv_listen_sock_fd; GBLREF int gtmrecv_sock_fd; GBLREF boolean_t repl_connection_reset; GBLREF recvpool_addrs recvpool; GBLREF int gtmrecv_log_fd; GBLREF FILE *gtmrecv_log_fp; -GBLREF int gtmrecv_statslog_fd; -GBLREF FILE *gtmrecv_statslog_fp; GBLREF boolean_t gtmrecv_logstats; GBLREF boolean_t gtmrecv_wait_for_jnl_seqno; GBLREF boolean_t gtmrecv_bad_trans_sent; @@ -234,7 +231,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned temp_send_seqno = GTM_BYTESWAP_64(send_seqno); memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&temp_send_seqno, SIZEOF(seq_num)); } - REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT) ; /* Empty Body */ if (SS_NORMAL != status) { @@ -248,14 +245,14 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned send_badtrans = FALSE; } else if (EREPL_SEND == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. " "Error in send"), status); else { assert(EREPL_SELECT == repl_errno); - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. " "Error in select"), status); } } else @@ -324,7 +321,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned { /* Receive the header of a message */ assert(REPL_MSG_HDRLEN > *buff_unprocessed); /* so we dont pass negative length in REPL_RECV_LOOP */ REPL_RECV_LOOP(gtmrecv_sock_fd, ((unsigned char *)gtmrecv_msgp) + *buff_unprocessed, - (REPL_MSG_HDRLEN - *buff_unprocessed), FALSE, >mrecv_poll_interval) + (REPL_MSG_HDRLEN - *buff_unprocessed), REPL_POLL_WAIT) ; /* Empty Body */ if (SS_NORMAL == status) { @@ -347,8 +344,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned } if ((SS_NORMAL == status) && (0 != *buff_unprocessed || 0 == *pending_data_len) && (REPL_XOFF_ACK == msg_type)) { /* Receive the rest of the XOFF_ACK msg and signal the drain as complete */ - REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, (MIN_REPL_MSGLEN - REPL_MSG_HDRLEN), FALSE, - >mrecv_poll_interval) + REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, (MIN_REPL_MSGLEN - REPL_MSG_HDRLEN), REPL_POLL_WAIT) ; /* Empty Body */ if (SS_NORMAL == status) { @@ -373,7 +369,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned for ( ; SS_NORMAL == status && 0 < pending_msg_size; pending_msg_size -= gtmrecv_max_repl_msglen) { temp_len = (pending_msg_size < gtmrecv_max_repl_msglen)? pending_msg_size : gtmrecv_max_repl_msglen; - REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, temp_len, FALSE, >mrecv_poll_interval) + REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, temp_len, REPL_POLL_WAIT) ; /* Empty Body */ } *buff_unprocessed = 0; *pending_data_len = 0; @@ -399,13 +395,13 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned send_badtrans = FALSE; return_status = STOP_POLL; } else - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error while draining replication pipe. Error in recv"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error while draining replication pipe. Error in recv"), status); } else { assert(EREPL_SELECT == repl_errno); - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error while draining replication pipe. Error in select"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error while draining replication pipe. Error in select"), status); } } } else @@ -428,7 +424,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned bad_trans_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN); bad_trans_msg.start_seqno = GTM_BYTESWAP_64(send_seqno); } - REPL_SEND_LOOP(gtmrecv_sock_fd, &bad_trans_msg, bad_trans_msg.len, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, &bad_trans_msg, bad_trans_msg.len, REPL_POLL_NOWAIT) ; /* Empty Body */ if (SS_NORMAL == status) { @@ -453,13 +449,13 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned repl_connection_reset = TRUE; return_status = STOP_POLL; } else if (EREPL_SEND == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in send"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in send"), status); else { assert(EREPL_SELECT == repl_errno); - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in select"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in select"), status); } } send_badtrans = FALSE; @@ -548,7 +544,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned * just syncing the journal pool cycles as the databases are not opened. But, to be safe, grab * the lock and sync the cycles. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); SYNC_ONLN_RLBK_CYCLES; rel_lock(jnlpool.jnlpool_dummy_reg); return_status = STOP_POLL; @@ -575,7 +571,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned if (gtmrecv_local->changelog & REPLIC_CHANGE_LOGFILE) { repl_log(gtmrecv_log_fp, TRUE, TRUE, "Changing log file to %s\n", gtmrecv_local->log_file); - repl_log_init(REPL_GENERAL_LOG, >mrecv_log_fd, NULL, gtmrecv_local->log_file, NULL); + repl_log_init(REPL_GENERAL_LOG, >mrecv_log_fd, gtmrecv_local->log_file); repl_log_fd2fp(>mrecv_log_fp, gtmrecv_log_fd); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Change log to %s successful\n",gtmrecv_local->log_file); } @@ -587,27 +583,12 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned if (0 == *pending_data_len && !gtmrecv_logstats && gtmrecv_local->statslog) { gtmrecv_logstats = TRUE; - repl_log_init(REPL_STATISTICS_LOG, >mrecv_log_fd, >mrecv_statslog_fd, gtmrecv_local->log_file, - gtmrecv_local->statslog_file); - repl_log_fd2fp(>mrecv_statslog_fp, gtmrecv_statslog_fd); - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Starting stats log to %s\n", gtmrecv_local->statslog_file); - repl_log(gtmrecv_statslog_fp, TRUE, TRUE, "Begin statistics logging\n"); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Begin statistics logging\n"); } else if (0 == *pending_data_len && gtmrecv_logstats && !gtmrecv_local->statslog) { gtmrecv_logstats = FALSE; - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Stopping stats log\n"); /* Force all data out to the file before closing the file */ - repl_log(gtmrecv_statslog_fp, TRUE, TRUE, "End statistics logging\n"); - CLOSEFILE_RESET(gtmrecv_statslog_fd, status); /* resets "gtmrecv_statslog_fd" to FD_INVALID */ - /* We need to FCLOSE because a later open() in repl_log_init() might return the same file descriptor as the one - * that we just closed. In that case, FCLOSE done in repl_log_fd2fp() affects the newly opened file and - * FDOPEN will fail returning NULL for the file pointer. So, we close both the file descriptor and file pointer. - * Note the same problem does not occur with GENERAL LOG because the current log is kept open while opening - * the new log and hence the new file descriptor will be different (we keep the old log file open in case there - * are errors during DUPing. In such a case, we do not switch the log file, but keep the current one). - * We can FCLOSE the old file pointer later in repl_log_fd2fp() */ - FCLOSE(gtmrecv_statslog_fp, status); - gtmrecv_statslog_fp = NULL; + repl_log(gtmrecv_log_fp, TRUE, TRUE, "End statistics logging\n"); } if (0 == *pending_data_len) { diff --git a/sr_unix/gtmrecv_process.c b/sr_unix/gtmrecv_process.c index 91730a6..f0874cb 100644 --- a/sr_unix/gtmrecv_process.c +++ b/sr_unix/gtmrecv_process.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,12 +25,6 @@ #include #include -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT -#include -#endif -#ifdef VMS -#include /* Required for gtmrecv.h */ -#endif #include "gdsroot.h" #include "gdsblk.h" @@ -80,25 +74,22 @@ #include "gtmio.h" #include "repl_inst_dump.h" /* for "repl_dump_histinfo" prototype */ #include "gv_trigger_common.h" +#include "anticipatory_freeze.h" #define GTM_ZLIB_UNCMP_ERR_STR "error from zlib uncompress function " #define GTM_ZLIB_Z_MEM_ERROR_STR "Out-of-memory " GTM_ZLIB_UNCMP_ERR_STR #define GTM_ZLIB_Z_BUF_ERROR_STR "Insufficient output buffer " GTM_ZLIB_UNCMP_ERR_STR #define GTM_ZLIB_Z_DATA_ERROR_STR "Input-data-incomplete-or-corrupt " GTM_ZLIB_UNCMP_ERR_STR #define GTM_ZLIB_UNCMPLEN_ERROR_STR "Decompressed message data length %d is not equal to precompressed length %d " -#define GTM_ZLIB_UNCMP_ERR_SEQNO_STR "at seqno %llu [0x%llx]\n" +#define GTM_ZLIB_UNCMP_ERR_SEQNO_STR "at seqno "INT8_FMT" "INT8_FMTX"\n" #define GTM_ZLIB_UNCMP_ERR_SOLVE_STR "before sending REPL_CMP_SOLVE message\n" #define GTM_ZLIB_UNCMPTRANSITION_STR "Defaulting to NO decompression\n" #define RECVBUFF_REPLMSGLEN_FACTOR 8 -#define GTMRECV_POLL_INTERVAL (1000000 - 1)/* micro sec, almost 1 sec */ -#define MAX_GTMRECV_POLL_INTERVAL 1000000 /* 1 sec in micro sec */ - #define GTMRECV_WAIT_FOR_STARTJNLSEQNO 100 /* ms */ #define GTMRECV_WAIT_FOR_UPD_PROGRESS 100 /* ms */ -#define GTMRECV_WAIT_FOR_UPD_PROGRESS_US (GTMRECV_WAIT_FOR_UPD_PROGRESS * 1000) /* micro sec */ /* By having different high and low watermarks, we can reduce the # of XOFF/XON exchanges */ #define RECVPOOL_HIGH_WATERMARK_PCTG 90 /* Send XOFF when %age of receive pool space occupied goes beyond this */ @@ -117,15 +108,25 @@ #define ONLN_RLBK_VERBOSE "-verbose " #define ONLN_RLBK_QUALIFIERS "-online -rollback -backward \"*\" -fetchresync=" /* port# will be filled later */ +#if defined(__hpux) && !defined(__hppa) || defined(_AIX) +#define KEEPALIVE_PROTO_LEVEL IPPROTO_TCP +#define KEEPALIVE_TIME 5 +#define KEEPALIVE_INTVL 5 +#define KEEPALIVE_PROBES 5 +#elif defined(__linux__) +#define KEEPALIVE_PROTO_LEVEL SOL_TCP +#define KEEPALIVE_TIME 5 +#define KEEPALIVE_INTVL 5 +#define KEEPALIVE_PROBES 5 +#endif + GBLDEF repl_msg_ptr_t gtmrecv_msgp; GBLDEF int gtmrecv_max_repl_msglen; -GBLDEF struct timeval gtmrecv_poll_interval, gtmrecv_poll_immediate; GBLDEF int gtmrecv_sock_fd = FD_INVALID; GBLDEF boolean_t repl_connection_reset = TRUE; GBLDEF boolean_t gtmrecv_wait_for_jnl_seqno = FALSE; GBLDEF boolean_t gtmrecv_bad_trans_sent = FALSE; GBLDEF boolean_t gtmrecv_send_cmp2uncmp = FALSE; -GBLDEF struct sockaddr_in primary_addr; GBLDEF qw_num repl_recv_data_recvd = 0; GBLDEF qw_num repl_recv_data_processed = 0; @@ -168,9 +169,7 @@ GBLREF recvpool_addrs recvpool; GBLREF boolean_t gtmrecv_logstats; GBLREF int gtmrecv_filter; GBLREF int gtmrecv_log_fd; -GBLREF int gtmrecv_statslog_fd; GBLREF FILE *gtmrecv_log_fp; -GBLREF FILE *gtmrecv_statslog_fp; GBLREF seq_num seq_num_zero, seq_num_one, seq_num_minus_one; GBLREF unsigned char *repl_filter_buff; GBLREF int repl_filter_bufsiz; @@ -239,6 +238,14 @@ static int heartbeat_period; static boolean_t repl_cmp_solve_timer_set; #endif +#define ISSUE_REPLCOMM_ERROR(REASON, SAVE_ERRNO) \ +{ \ + if (0 != SAVE_ERRNO) \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT(REASON), SAVE_ERRNO);\ + else \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT(REASON)); \ +} + #define GTMRECV_EXPAND_CMPBUFF_IF_NEEDED(cmpmsglen) \ { \ int lclcmpmsglen; \ @@ -345,6 +352,27 @@ static boolean_t repl_cmp_solve_timer_set; } \ } +/* For cross-endian conversion to happen on the receiving side, the receiver must understand the layout of the journal + * records. To keep the endian conversion logic on both primary and secondary simple, the following scheme is used: + * (a) If primary < secondary, endian conversion will happen on primary. + * (b) If primary >= secondary, primary will apply internal filters to convert the records to secondary's format. The + * secondary on receiving them will do the necessary endian conversion before letting the update process see them. + * + * However, the above logic will cause the older versions (< V5.4-002) to NOT replicate to V5.4-002 as the endian-conversion + * by-primary is introduced only from V5.4-002 and above. Hence, allow secondary to do endian conversion for this special + * case when the primary is a GT.M version running V5.3-003 (V18_JNL_VER) to V5.4-001 (V20_JNL_VER). The lower limit is + * chosen to be V5.3-003 since that was the first version where cross-endian conversion was supported. + * + * There is one other exception. V5.5 source server (V22_JNL_VER) had a bug wherein a history record is endian-converted + * when the replication is NOT cross-endian and vice versa. In either case, do an endian conversion of the history record. + * + * The below macro takes all the above conditions into consideration to determine if the receiver server needs to do endian + * converison or not. + */ +#define ENDIAN_CONVERSION_NEEDED(IS_NEW_HISTREC, THIS_JNL_VER, REMOTE_JNL_VER, X_ENDIAN) \ + ((IS_NEW_HISTREC && (V22_JNL_VER == REMOTE_JNL_VER)) \ + || (X_ENDIAN && ((REMOTE_JNL_VER >= THIS_JNL_VER) || (V21_JNL_VER > REMOTE_JNL_VER)))) + STATICFNDEF void gtmrecv_repl_send_loop_error(int status, char *msgtypestr) { char print_msg[1024]; @@ -363,13 +391,13 @@ STATICFNDEF void gtmrecv_repl_send_loop_error(int status, char *msgtypestr) } else if (EREPL_SEND == repl_errno) { SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending %s message. Error in send : %s", - msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + msgtypestr, STRERROR(status)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg)); } else if (EREPL_SELECT == repl_errno) { SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending %s message. Error in select : %s", - msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + msgtypestr, STRERROR(status)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg)); } } @@ -395,19 +423,7 @@ STATICFNDEF int repl_tr_endian_convert(unsigned char remote_jnl_ver, uchar_ptr_t SETUP_THREADGBL_ACCESS; # endif - - /* for cross-endian conversion to happen on the receiving side, the receiver must understand the layout of the journal - * records. To keep the endian conversion logic on both primary and secondary simple, the following scheme is used: - * (a) if primary < secondary, endian conversion will happen on primary. - * (b) if primary >= secondary, primary will apply internal filters to convert the records to secondary's format. The - * secondary on receiving them will do the necessary endian conversion before letting the update process see them. - * - * However, the above logic will cause the older versions (< V5.4-002) to NOT replicate to V5.4-002 as the endian-conversion - * by-primary is introduced only from V5.4-002 and above. Hence, allow secondary to do endian conversion for this special - * case when the primary is a GT.M version running V5.3-003 (V18_JNL_VER) to V5.4-001 (V20_JNL_VER). The lower limit is - * chosen to be V5.3-003 since that was the first version where cross-endian conversion was supported. - */ - assert((remote_jnl_ver >= this_side->jnl_ver) || ((V18_JNL_VER <= remote_jnl_ver) && (V20_JNL_VER >= remote_jnl_ver))); + assert((remote_jnl_ver >= this_side->jnl_ver) || (V21_JNL_VER > remote_jnl_ver) || (V22_JNL_VER == remote_jnl_ver)); jb = jnl_buff; status = SS_NORMAL; jlen = jnl_len; @@ -455,11 +471,11 @@ STATICFNDEF int repl_tr_endian_convert(unsigned char remote_jnl_ver, uchar_ptr_t } if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) { - /* This code will need changes in case the jnl-ver changes from V22 to V24 so add an assert to + /* This code will need changes in case the jnl-ver changes from V23 to V24 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 == V22_JNL_VER); + assert(JNL_VER_THIS == V23_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). */ @@ -592,22 +608,19 @@ STATICFNDEF void do_flow_control(uint4 write_pos) memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&temp_seq_num, SIZEOF(seq_num)); xoff_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN); } - REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT) { GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); } CHECK_REPL_SEND_LOOP_ERROR(status, "REPL_XOFF"); if (gtmrecv_logstats) - repl_log(gtmrecv_statslog_fp, TRUE, TRUE, "Space used = %ld, High water mark = %d Low water mark = %d, " + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Space used = %ld, High water mark = %d Low water mark = %d, " "Updproc Read = %d, Recv Write = %d, Sent XOFF\n", space_used, recvpool_high_watermark, recvpool_low_watermark, read_pos, write_pos); repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL_XOFF sent as receive pool has %ld bytes transaction data yet to be " "processed\n", space_used); xoff_sent = TRUE; xoff_msg_log_cnt = 1; - assert(GTMRECV_WAIT_FOR_UPD_PROGRESS_US < MAX_GTMRECV_POLL_INTERVAL); - gtmrecv_poll_interval.tv_sec = 0; - gtmrecv_poll_interval.tv_usec = GTMRECV_WAIT_FOR_UPD_PROGRESS_US; } else if (space_used < recvpool_low_watermark && xoff_sent) { if (!remote_side->cross_endian) @@ -622,21 +635,19 @@ STATICFNDEF void do_flow_control(uint4 write_pos) memcpy((uchar_ptr_t)&xon_msg.msg[0], (uchar_ptr_t)&temp_seq_num, SIZEOF(seq_num)); xon_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN); } - REPL_SEND_LOOP(gtmrecv_sock_fd, &xon_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, &xon_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT) { GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); } CHECK_REPL_SEND_LOOP_ERROR(status, "REPL_XON"); if (gtmrecv_logstats) - repl_log(gtmrecv_statslog_fp, TRUE, TRUE, "Space used now = %ld, High water mark = %d, " + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Space used now = %ld, High water mark = %d, " "Low water mark = %d, Updproc Read = %d, Recv Write = %d, Sent XON\n", space_used, recvpool_high_watermark, recvpool_low_watermark, read_pos, write_pos); repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL_XON sent as receive pool has %ld bytes free space to buffer transaction " "data\n", recvpool_size - space_used); xoff_sent = FALSE; xoff_msg_log_cnt = 0; - gtmrecv_poll_interval.tv_sec = 0; - gtmrecv_poll_interval.tv_usec = GTMRECV_POLL_INTERVAL; } return; } @@ -646,34 +657,26 @@ STATICFNDEF int gtmrecv_est_conn(void) recvpool_ctl_ptr_t recvpool_ctl; upd_proc_local_ptr_t upd_proc_local; gtmrecv_local_ptr_t gtmrecv_local; - GTM_SOCKLEN_TYPE primary_addr_len; - fd_set input_fds; - int status; - const int disable_keepalive = 0; - struct linger disable_linger = {0, 0}; - struct timeval save_gtmrecv_poll_interval, sel_timeout_val; - char print_msg[1024]; + boolean_t keepalive; + GTM_SOCKLEN_TYPE optlen; + int status, keepalive_opt, optval, save_errno; int send_buffsize, recv_buffsize, tcp_r_bufsize; - short retry_num; -#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT - long poll_timeout; - unsigned long poll_nfds; - struct pollfd poll_fdlist[1]; -#endif + struct linger disable_linger = {0, 0}; + char print_msg[1024]; + struct addrinfo primary_ai; + struct sockaddr_storage primary_sas; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - /* Wait for a connection from a Source Server. - * The Receiver Server is an iterative server. - */ + /* Wait for a connection from a Source Server. The Receiver Server is an iterative server. */ recvpool_ctl = recvpool.recvpool_ctl; upd_proc_local = recvpool.upd_proc_local; gtmrecv_local = recvpool.gtmrecv_local; - + /* Create a listen socket */ gtmrecv_comm_init((in_port_t)gtmrecv_local->listen_port); - primary_addr_len = SIZEOF(primary_addr); + primary_ai.ai_addr = (sockaddr_ptr)&primary_sas; + primary_ai.ai_addrlen = SIZEOF(primary_sas); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Waiting for a connection...\n"); - /* Null initialize fields that need to be initialized only after connecting to the primary. * It is ok not to hold a lock on the journal pool while updating jnlpool_ctl fields since this will be the only * process updating those fields. @@ -681,131 +684,92 @@ STATICFNDEF int gtmrecv_est_conn(void) assert(remote_side == >mrecv_local->remote_side); remote_side->proto_ver = REPL_PROTO_VER_UNINITIALIZED; jnlpool_ctl->primary_instname[0] = '\0'; - -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - FD_ZERO(&input_fds); - FD_SET(gtmrecv_listen_sock_fd, &input_fds); - save_gtmrecv_poll_interval = gtmrecv_poll_interval; -#else - poll_fdlist[0].fd = gtmrecv_listen_sock_fd; - poll_fdlist[0].events = POLLIN; - poll_nfds = 1; - poll_timeout = gtmrecv_poll_interval.tv_usec / 1000; /* convert to millisecs */ -#endif - /* - * Note - the following while loop checks for EINTR on the select. The - * SELECT macro is not used because the FD_SET is redone before the new - * call to select (after the continue). - */ - while (0 >= -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - (status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &save_gtmrecv_poll_interval)) -#else - (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout)) -#endif - ) + while (TRUE) { -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - save_gtmrecv_poll_interval = gtmrecv_poll_interval; - FD_SET(gtmrecv_listen_sock_fd, &input_fds); -#endif - if (0 == status) - gtmrecv_poll_actions(0, 0, NULL); - else if (EINTR == errno || EAGAIN == errno) - continue; - else + while (TRUE) { - status = ERRNO; - SNPRINTF(print_msg, SIZEOF(print_msg), "Error in select on listen socket : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } - } - ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr, - (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd); - if (FD_INVALID == gtmrecv_sock_fd) - { - status = ERRNO; -#ifdef __hpux - /* ENOBUFS will normally signify a transient state. Hence retry before issuing an error*/ - if (ENOBUFS == status) - { - retry_num = 0; - while (HPUX_MAX_RETRIES > retry_num) + if (0 < (status = fd_ioready(gtmrecv_listen_sock_fd, TRUE, REPL_POLL_WAIT))) + break; + if (-1 == status) { - /*In case of succeeding with select in first go, accept will still get 5ms time difference*/ - SHORT_SLEEP(5); - for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++) - { -#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT - sel_timeout_val.tv_sec = 0; - sel_timeout_val.tv_usec = HPUX_SEL_TIMEOUT; - FD_ZERO(&input_fds); - FD_SET(gtmrecv_listen_sock_fd, &input_fds); - status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &sel_timeout_val); -#else - poll_fdlist[0].fd = gtmrecv_listen_sock_fd; - poll_fdlist[0].events = POLLIN; - poll_nfds = 1; - poll_timeout = HPUX_SEL_TIMEOUT / 1000; /* convert to millisecs */ - status = poll(&poll_fdlist[0], poll_nfds, poll_timeout); -#endif - if (0 == status) - gtmrecv_poll_actions(0, 0, NULL); - if (0 < status) - break; - else - SHORT_SLEEP(5); - } - if (0 > status) - { - status = ERRNO; - SNPRINTF(print_msg, SIZEOF(print_msg),"Error in select on listen socket after ENOBUFS : %s", - STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } - ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr, - (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd); - status = ERRNO; - if ((FD_INVALID == gtmrecv_sock_fd) && (ENOBUFS == status)) - retry_num++; - else - break; - } + save_errno = errno; + assert((EAGAIN != save_errno) && (EINTR != save_errno)); + ISSUE_REPLCOMM_ERROR("Error in select on listen socket", save_errno); + } else if (0 == status) /* timeout */ + gtmrecv_poll_actions(0, 0, NULL); } + ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr, + (GTM_SOCKLEN_TYPE *)&primary_ai.ai_addrlen, gtmrecv_sock_fd); if (FD_INVALID == gtmrecv_sock_fd) -#endif { - status = ERRNO; - SNPRINTF(print_msg, SIZEOF(print_msg), "Error accepting connection from Source Server : %s", - STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + save_errno = errno; +# ifdef __hpux + if (ENOBUFS == save_errno) + { + gtmrecv_poll_actions(0, 0, NULL); + continue; + } +# endif + ISSUE_REPLCOMM_ERROR("Error accepting connection from Source Server", save_errno); } + break; } /* Connection established */ repl_close(>mrecv_listen_sock_fd); /* Close the listener socket */ repl_connection_reset = FALSE; if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket disable linger", errno); +# ifdef REPL_DISABLE_KEEPALIVE + keepalive = FALSE; +# else + keepalive = TRUE; +# endif + if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&keepalive, + SIZEOF(keepalive))) { - status = ERRNO; - SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket disable linger : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + ISSUE_REPLCOMM_ERROR("Error with receiver server socket enable keepalive", errno); } + /* Set up the keepalive parameters + * TCP_KEEPCNT : overrides tcp_keepalive_probes + * TCP_KEEPIDLE: overrides tcp_keepalive_time + * TCP_KEEPINTVL: overrides tcp_keepalive_intvl + */ +# if defined(KEEPALIVE_PROTO_LEVEL) + keepalive_opt = KEEPALIVE_PROBES; + if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPCNT, (void*)&keepalive_opt, SIZEOF(keepalive_opt))) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_probes", errno); + keepalive_opt = KEEPALIVE_TIME; + if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPIDLE, (void*)&keepalive_opt, SIZEOF(keepalive_opt))) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_time", errno); + keepalive_opt = KEEPALIVE_INTVL; + if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPINTVL, (void*)&keepalive_opt, SIZEOF(keepalive_opt))) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_intvl", errno); +# endif + optlen = SIZEOF(optval); + if ( -1 == getsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen)) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket checking keepalive enabled or not", errno) +# if !defined(KEEPALIVE_PROTO_LEVEL) + repl_log(gtmrecv_log_fp, TRUE, TRUE, "SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF")); +# else + repl_log(gtmrecv_log_fp, TRUE, TRUE, "SO_KEEPALIVE is %s. ", (optval ? "ON" : "OFF")); -#ifdef REPL_DISABLE_KEEPALIVE - if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&disable_keepalive, - SIZEOF(disable_keepalive))) - { /* Till SIGPIPE is handled properly */ - status = ERRNO; - SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket disable keepalive : %s", - STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } -#endif + if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPCNT, &optval, &optlen)) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_probes", errno); + if (optval) + repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPCNT is %d, ", optval); + + if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPIDLE, &optval, &optlen)) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_time", errno); + if (optval) + repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPIDLE is %d, ", optval); + + if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPINTVL, &optval, &optlen)) + ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_intvl", errno); + if (optval) + repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPINTVL is %d.\n", optval); +# endif if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &send_buffsize))) - { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } + ISSUE_REPLCOMM_ERROR("Error getting socket send buffsize", errno); if (send_buffsize < GTMRECV_TCP_SEND_BUFSIZE) { if (0 != (status = set_send_sock_buff_size(gtmrecv_sock_fd, GTMRECV_TCP_SEND_BUFSIZE))) @@ -814,20 +778,15 @@ STATICFNDEF int gtmrecv_est_conn(void) { SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP send buffer size to %d : %s", GTMRECV_MIN_TCP_SEND_BUFSIZE, STRERROR(status)); - rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, + ERR_TEXT, 2, LEN_AND_STR(print_msg)); } } } if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize))) /* may have changed */ - { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } + ISSUE_REPLCOMM_ERROR("Error getting socket send buffsize", errno); if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &recv_buffsize))) - { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } + ISSUE_REPLCOMM_ERROR("Error getting socket recv buffsize", errno); if (recv_buffsize < GTMRECV_TCP_RECV_BUFSIZE) { for (tcp_r_bufsize = GTMRECV_TCP_RECV_BUFSIZE; @@ -840,14 +799,12 @@ STATICFNDEF int gtmrecv_est_conn(void) SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP receive buffer size in range [%d, %d], last " "known error : %s", GTMRECV_MIN_TCP_RECV_BUFSIZE, GTMRECV_TCP_RECV_BUFSIZE, STRERROR(status)); - rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, + ERR_TEXT, 2, LEN_AND_STR(print_msg)); } } if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize))) /* may have changed */ - { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); - } + ISSUE_REPLCOMM_ERROR("Error getting socket recv buffsize", errno); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection established, using TCP send buffer size %d receive buffer size %d\n", repl_max_send_buffsize, repl_max_recv_buffsize); repl_log_conn_info(gtmrecv_sock_fd, gtmrecv_log_fp); @@ -950,7 +907,7 @@ void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypest log_fp = (NULL == gtmrecv_log_fp) ? stdout : gtmrecv_log_fp; if (MAX_SEQNO != optional_seqno) { - repl_log(log_fp, TRUE, TRUE, "Sending %s message with seqno %llu [0x%llx]\n", msgtypestr, + repl_log(log_fp, TRUE, TRUE, "Sending %s message with seqno "INT8_FMT" "INT8_FMTX"\n", msgtypestr, optional_seqno, optional_seqno); } else repl_log(log_fp, TRUE, TRUE, "Sending %s message\n", msgtypestr); @@ -965,7 +922,7 @@ void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypest msgp->type = GTM_BYTESWAP_32(type); msgp->len = GTM_BYTESWAP_32(len); } - REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, len, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, len, REPL_POLL_NOWAIT) { GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); } @@ -981,18 +938,19 @@ 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; + boolean_t remote_side_is_supplementary, grab_lock_needed; 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; seq_num strm_jnl_seqno; - DEBUG_ONLY(sgmnt_addrs *repl_csa;) + sgmnt_addrs *repl_csa; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs); + repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; + grab_lock_needed = is_rcvr_srvr || ((NULL != jnlpool_ctl) && !repl_csa->hold_onto_crit); 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 */ @@ -1012,8 +970,8 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, */ if (is_rcvr_srvr && recvpool.gtmrecv_local->updateresync && (FD_INVALID == recvpool.gtmrecv_local->updresync_instfile_fd)) { - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Source side is >= V5.5-000 implies -UPDATERESYNC needs a value specified")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + LEN_AND_LIT("Source side is >= V5.5-000 implies -UPDATERESYNC needs a value specified")); assert(FALSE); /* we dont expect the rts_error to return control */ } /* We usually expect the LMS group info to be non-NULL on both primary and secondary. An exception is if @@ -1023,25 +981,28 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, */ assert(inst_hdr->lms_group_info.created_time || need_instinfo_msg->lms_group_info.created_time || !need_instinfo_msg->is_rootprimary); - assert((is_rcvr_srvr && (NULL != jnlpool_ctl)) || (!is_rcvr_srvr && (NULL == jnlpool_ctl)) || jgbl.onlnrlbk); + assert((is_rcvr_srvr && (NULL != jnlpool_ctl)) || (!is_rcvr_srvr && (NULL == jnlpool_ctl)) || jgbl.onlnrlbk + || (jgbl.mur_rollback && ANTICIPATORY_FREEZE_AVAILABLE)); /* If this instance is supplementary and the journal pool exists (to indicate whether updates are enabled or not * which in turn helps us know whether this is an originating instance or not) do some additional checks. */ - if (inst_hdr->is_supplementary && (NULL != jnlpool_ctl)) + if (is_rcvr_srvr && inst_hdr->is_supplementary) { + assert(NULL != jnlpool_ctl); if (!jnlpool_ctl->upd_disabled) { /* this supplementary instance was started with -UPDOK. Issue error if source is also supplementary */ if (need_instinfo_msg->is_supplementary) { - rts_error(VARLSTCNT(6) ERR_NOSUPPLSUPPL, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), - LEN_AND_STR((char *)need_instinfo_msg->instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_NOSUPPLSUPPL, 4, + LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), + LEN_AND_STR((char *)need_instinfo_msg->instname)); assert(FALSE); /* we dont expect the rts_error to return control */ } } else { /* this supplementary instance was started with -UPDNOTOK. Issue error if source is not supplementary */ if (!need_instinfo_msg->is_supplementary) { - rts_error(VARLSTCNT(6) ERR_SUPRCVRNEEDSSUPSRC, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SUPRCVRNEEDSSUPSRC, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), LEN_AND_STR((char *)need_instinfo_msg->instname)); assert(FALSE); /* we dont expect the rts_error to return control */ @@ -1049,10 +1010,12 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, } } /* Assert that if the receiver side is a root primary (i.e. has updates enabled), it better be a - * supplementary instance and have the LMS group info filled in. + * supplementary instance and have the LMS group info filled in. Exception is if this a FETCHRESYNC + * ROLLBACK run on an instance which was once primary (not necessarily a supplementary one). */ assert((NULL == jnlpool_ctl) || jnlpool_ctl->upd_disabled - || inst_hdr->is_supplementary && IS_REPL_INST_UUID_NON_NULL(inst_hdr->lms_group_info)); + || inst_hdr->is_supplementary && IS_REPL_INST_UUID_NON_NULL(inst_hdr->lms_group_info) + || jgbl.onlnrlbk || (jgbl.mur_rollback && ANTICIPATORY_FREEZE_AVAILABLE)); /* Check if primary and secondary are in same LMS group. Otherwise issue error. An exception is if the group info has * not yet been filled in after instance file creation. In that case, copy the info from primary and skip the error check. */ @@ -1064,8 +1027,9 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, */ if (!inst_hdr->is_supplementary || remote_side_is_supplementary) { - rts_error(VARLSTCNT(6) ERR_INSNOTJOINED, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), - LEN_AND_STR((char *)need_instinfo_msg->instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSNOTJOINED, 4, + LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), + LEN_AND_STR((char *)need_instinfo_msg->instname)); assert(FALSE); /* we dont expect the rts_error to return control */ } } else @@ -1075,8 +1039,9 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, if (inst_hdr->is_supplementary && !remote_side_is_supplementary) { assert(!need_instinfo_msg->is_supplementary); /* else NOSUPPLSUPPL error must have been issued */ - rts_error(VARLSTCNT(6) ERR_INSROLECHANGE, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), - LEN_AND_STR((char *)need_instinfo_msg->instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSROLECHANGE, 4, + LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), + LEN_AND_STR((char *)need_instinfo_msg->instname)); assert(FALSE); /* we dont expect the rts_error to return control */ } } @@ -1088,8 +1053,8 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, if (memcmp(&recvpool.gtmrecv_local->updresync_lms_group, &need_instinfo_msg->lms_group_info, SIZEOF(inst_hdr->lms_group_info))) { - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Specified input instance file does not have same " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + LEN_AND_LIT("Specified input instance file does not have same " "LMS Group information as source server instance")); } } @@ -1099,14 +1064,15 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, * If caller is rollback, no other process can be touching the instance file until we are done so * no need of the lock in that case. */ - if (is_rcvr_srvr) + if (grab_lock_needed) { - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); - GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); + if (is_rcvr_srvr) + GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; } inst_hdr->lms_group_info = need_instinfo_msg->lms_group_info; repl_inst_flush_filehdr(); - if (is_rcvr_srvr) + if (grab_lock_needed) rel_lock(jnlpool.jnlpool_dummy_reg); } /* If this instance is supplementary and remote side is not, then find out which stream # the non-supplementary source @@ -1124,10 +1090,11 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, * If a matching stream is found, update gtmrecv_local->strm_index to reflect this while still holding lock. * This field is checked by the -UPDATERESYNC to see if a receiver has a given stream # actively in use. */ - if (is_rcvr_srvr) + if (grab_lock_needed) { - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); - GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); + if (is_rcvr_srvr) + GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; } reuse_slot = 0; if (is_rcvr_srvr && recvpool.gtmrecv_local->updateresync && gtmrecv_options.reuse_specified) @@ -1147,7 +1114,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, if (strm_info == strm_top) { /* -REUSE specified an instance name that is not present in any of the 15 strm_group slots */ rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, LEN_AND_LIT("Instance name in REUSE does not match any of 15 slots in instance file")); } assert(reuse_slot); @@ -1184,17 +1151,18 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, strm_index = first_usable_slot; else { - if (is_rcvr_srvr) + if (grab_lock_needed) rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, LEN_AND_LIT("No empty slot found. Specify REUSE to choose one for reuse")); } } else { - if (is_rcvr_srvr) + if (grab_lock_needed) rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(6) ERR_INSUNKNOWN, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), - LEN_AND_STR((char *)need_instinfo_msg->instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSUNKNOWN, 4, + LEN_AND_STR((char *)inst_hdr->inst_info.this_instname), + LEN_AND_STR((char *)need_instinfo_msg->instname)); assert(FALSE); /* we dont expect the rts_error to return control */ } /* Since we did not find the stream in the existing instance file but did find a slot, fill that slot @@ -1215,13 +1183,13 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, { /* If -RESUME was specified, then the slot it matched must be same as slot found without its use */ assert(is_rcvr_srvr); rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS " "group is found in instance file but RESUME specifies different stream number")); } else if (reuse_slot && (reuse_slot != strm_index)) { /* If -REUSE was specified, then the slot it matched must be same as slot found without its use */ assert(is_rcvr_srvr); rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS " "group is found in instance file but REUSE specifies different instance name")); } assert(INVALID_SUPPL_STRM != strm_index); @@ -1237,10 +1205,12 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, * update process, issue error. Note: This limitation "might" be removed in the future. */ rel_lock(jnlpool.jnlpool_dummy_reg); - rts_error(VARLSTCNT(4) ERR_RCVRMANYSTRMS, 2, strm_index, recvpool.gtmrecv_local->strm_index); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RCVRMANYSTRMS, 2, + strm_index, recvpool.gtmrecv_local->strm_index); } recvpool.gtmrecv_local->strm_index = strm_index; - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Determined non-supplementary source Stream # = %d\n", strm_index); + repl_log(gtmrecv_log_fp, TRUE, TRUE, + "Determined non-supplementary source Stream # = %d\n", strm_index); assert(IS_REPL_INST_UUID_NON_NULL(need_instinfo_msg->lms_group_info)); recvpool.gtmrecv_local->remote_lms_group = need_instinfo_msg->lms_group_info; rel_lock(jnlpool.jnlpool_dummy_reg); @@ -1293,14 +1263,10 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, strm_jnl_seqno = 1; } } else - { - assert(jnlpool_ctl->strm_seqno[strm_index] - == jnlpool.repl_inst_filehdr->strm_seqno[strm_index]); strm_jnl_seqno = jnlpool_ctl->strm_seqno[strm_index]; - } assert(0 == GET_STRM_INDEX(strm_jnl_seqno)); } - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Sending Stream Seqno = %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Sending Stream Seqno = "INT8_FMT" "INT8_FMTX"\n", strm_jnl_seqno, strm_jnl_seqno); } else { @@ -1313,7 +1279,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, || (jnlpool_ctl->strm_seqno[strm_index] == inst_hdr->strm_seqno[strm_index])); strm_jnl_seqno = jnlpool.repl_inst_filehdr->strm_seqno[strm_index]; } - repl_log(stdout, TRUE, TRUE, "Sending Stream Seqno = %llu [0x%llx]\n", + repl_log(stdout, TRUE, TRUE, "Sending Stream Seqno = "INT8_FMT" "INT8_FMTX"\n", strm_jnl_seqno, strm_jnl_seqno); } } else @@ -1340,17 +1306,22 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, /*************** Send REPL_INSTINFO message ***************/ memset(&instinfo_msg, 0, SIZEOF(instinfo_msg)); memcpy(instinfo_msg.instname, inst_hdr->inst_info.this_instname, MAX_INSTNAME_LEN - 1); - if (is_rcvr_srvr) + if (grab_lock_needed) { - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); - GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); + if (is_rcvr_srvr) + GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; } instinfo_msg.was_rootprimary = (unsigned char)repl_inst_was_rootprimary(); - if (is_rcvr_srvr) + if (grab_lock_needed) rel_lock(jnlpool.jnlpool_dummy_reg); if (!is_rcvr_srvr) murgbl.was_rootprimary = instinfo_msg.was_rootprimary; instinfo_msg.strm_jnl_seqno = strm_jnl_seqno; + /* strm_jnl_seqno is not expected to be zero unless this is a non-supplementary instance (like A->B) in which case + * strm_seqno is not maintained OR the remote side is supplementary (like P->Q) in which case the two instances do + * not communicate in-terms of strm_seqno (once the handshake is established) + */ assert(strm_jnl_seqno || !inst_hdr->is_supplementary || remote_side_is_supplementary); instinfo_msg.lms_group_info = inst_hdr->lms_group_info; assert(remote_side->endianness_known); /* only then is remote_side->cross_endian reliable */ @@ -1363,17 +1334,24 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, if (repl_connection_reset || is_rcvr_srvr && gtmrecv_wait_for_jnl_seqno) return; /* Do not allow an instance which was formerly a root primary or which still - * has a non-zero value of "zqgblmod_seqno" to start up as a tertiary. + * has a non-zero value of "zqgblmod_seqno" to start up as a tertiary. The only exception is + * if this is P (supplementary instance) receiving from a non-supplementary instance. + * In that case, P can never be a root primary of the non-supplementary group and therefore + * cannot be affected by lost transactions being applied from the non-supplementary group. */ - if ((instinfo_msg.was_rootprimary || (is_rcvr_srvr && jnlpool_ctl->max_zqgblmod_seqno)) - && !need_instinfo_msg->is_rootprimary) + if ((!inst_hdr->is_supplementary || remote_side_is_supplementary) + && !need_instinfo_msg->is_rootprimary + && (instinfo_msg.was_rootprimary + || (is_rcvr_srvr && jnlpool_ctl->max_zqgblmod_seqno))) { if (is_rcvr_srvr) { - gtm_putmsg(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *) need_instinfo_msg->instname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, + LEN_AND_STR((char *) need_instinfo_msg->instname)); gtmrecv_autoshutdown(); /* should not return */ } else - rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *) need_instinfo_msg->instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, + LEN_AND_STR((char *) need_instinfo_msg->instname)); assert(FALSE); } if (is_rcvr_srvr) @@ -1402,7 +1380,8 @@ STATICFNDEF int gtmrecv_start_onln_rlbk(void) assert(0 < gtmrecv_local->listen_port); SNPRINTF(&command[cmdlen], ONLN_RLBK_CMD_MAXLEN, "%d", gtmrecv_local->listen_port); /* will add '\0' at the end */ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Executing %s\n", command); - if (0 != (status = SYSTEM((char *)command))) + status = SYSTEM(((char *)command)); + if (0 != status) { if (-1 == status) { @@ -1430,15 +1409,25 @@ STATICFNDEF int gtmrecv_start_onln_rlbk(void) */ void gtmrecv_onln_rlbk_clnup(void) { + boolean_t connection_already_reset; + assert(NULL != gtmrecv_log_fp); assert(jnlpool.jnlpool_ctl == jnlpool_ctl); - repl_log(gtmrecv_log_fp, TRUE, TRUE, "---> ONLINE ROLLBACK. Current Jnlpool Seqno : %llu\n", jnlpool_ctl->jnl_seqno); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "---> ONLINE ROLLBACK. Current Jnlpool Seqno : "INT8_FMT"\n", jnlpool_ctl->jnl_seqno); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Waiting for update process to set recvpool_ctl->onln_rlbk_flag\n"); + connection_already_reset = repl_connection_reset; + assert(!gtmrecv_wait_for_jnl_seqno); while (TRUE) { SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_PROGRESS); gtmrecv_poll_actions(data_len, buff_unprocessed, buffp); - if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno) + /* If connection was already closed before we came here (possible if receiver server closed the connection in + * response to a REPL_ROLLBACK_FIRST message) after spawning off an online rollback, then we should NOT check for + * repl_connection_reset. This way, we avoid breaking prematurely from this loop without waiting for the update + * process to acknowledge the online rollback. In this case, wait for gtmrecv_wait_for_jnl_seqno to be set to TRUE + * by gtmrecv_poll_actions. + */ + if ((!connection_already_reset && repl_connection_reset) || gtmrecv_wait_for_jnl_seqno) break; } return; @@ -1512,8 +1501,8 @@ STATICFNDEF void prepare_recvpool_for_write(int datalen, int pre_filter_write_le recvpool_ctl = recvpool.recvpool_ctl; if (datalen > recvpool_size) { /* Too large a transaction to be accommodated in the Receive Pool */ - rts_error(VARLSTCNT(7) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno, datalen, pre_filter_write_len, - RTS_ERROR_LITERAL("Receive")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno, + datalen, pre_filter_write_len, LEN_AND_LIT("Receive")); } if ((write_loc + datalen) > recvpool_size) { @@ -1606,7 +1595,7 @@ STATICFNDEF void wait_for_updproc_to_clear_backlog(void) STATICFNDEF void process_tr_buff(int msg_type) { recvpool_ctl_ptr_t recvpool_ctl; - seq_num log_seqno, recv_jnl_seqno; + seq_num log_seqno, recv_jnl_seqno, upd_seqno, diff_seqno; uint4 in_size, out_size, out_bufsiz, tot_out_size, upd_read, max_strm_histinfo; boolean_t filter_pass = FALSE, is_new_histrec, is_repl_cmpc; uchar_ptr_t save_buffp, save_filter_buff, in_buff, out_buff; @@ -1727,12 +1716,11 @@ STATICFNDEF void process_tr_buff(int msg_type) assert((write_off != write_wrap) || (0 == write_off)); assert(remote_side->jnl_ver); assert(!remote_side->cross_endian || (V18_JNL_VER <= remote_side->jnl_ver)); - if (remote_side->cross_endian - && ((remote_side->jnl_ver >= this_side->jnl_ver) || (V21_JNL_VER > remote_side->jnl_ver))) + if (ENDIAN_CONVERSION_NEEDED(is_new_histrec, this_side->jnl_ver, remote_side->jnl_ver, remote_side->cross_endian)) { if (SS_NORMAL != (status = repl_tr_endian_convert(remote_side->jnl_ver, recvpool.recvdata_base + write_off, write_len))) - rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Replicating"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Replicating"), &recvpool.upd_proc_local->read_jnl_seqno); } if (!is_new_histrec) @@ -1768,17 +1756,19 @@ STATICFNDEF void process_tr_buff(int msg_type) { assert(EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno); if (EREPL_INTLFILTER_BADREC == repl_errno) - rts_error(VARLSTCNT(1) ERR_JNLRECFMT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLRECFMT); else if (EREPL_INTLFILTER_DATA2LONG == repl_errno) - rts_error(VARLSTCNT(4) ERR_JNLSETDATA2LONG, 2, jnl_source_datalen, - jnl_dest_maxdatalen); + 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(VARLSTCNT(4) ERR_JNLNEWREC, 2, (unsigned int)jnl_source_rectype, - (unsigned int)jnl_dest_maxrectype); + 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(VARLSTCNT(1) ERR_REPLGBL2LONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG); else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno) - rts_error(VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, &recvpool_ctl->jnl_seqno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, + &recvpool_ctl->jnl_seqno); else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */ GTMASSERT; } @@ -1831,19 +1821,29 @@ STATICFNDEF void process_tr_buff(int msg_type) if (recvpool_ctl->jnl_seqno - lastlog_seqno >= log_interval) { log_seqno = recvpool_ctl->jnl_seqno; + upd_seqno = recvpool.upd_proc_local->read_jnl_seqno; + assert(log_seqno >= upd_seqno); + diff_seqno = (log_seqno - upd_seqno); trans_recvd_cnt += (log_seqno - lastlog_seqno); msg_total = repl_recv_data_recvd - buff_unprocessed; /* Don't include data not yet processed, we'll include that count in a later log */ if (NO_FILTER == gtmrecv_filter) { - repl_log(gtmrecv_log_fp, FALSE, TRUE, "REPL INFO - Seqno : %llu" - " Jnl Total : %llu Msg Total : %llu\n", log_seqno, - repl_recv_data_processed, msg_total); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Seqno : "INT8_FMT" "INT8_FMTX + " Jnl Total : "INT8_FMT" "INT8_FMTX" Msg Total : "INT8_FMT" "INT8_FMTX + " Current backlog : "INT8_FMT" "INT8_FMTX"\n", + log_seqno, log_seqno, repl_recv_data_processed, repl_recv_data_processed, + msg_total, msg_total, diff_seqno, diff_seqno); } else { - repl_log(gtmrecv_log_fp, FALSE, TRUE, "REPL INFO - Seqno : %llu Pre filter " - "total : %llu Post filter total : %llu Msg Total : %llu\n", log_seqno, - repl_recv_data_processed, repl_recv_postfltr_data_procd, msg_total); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Seqno : "INT8_FMT" "INT8_FMTX + " Pre filter total : "INT8_FMT" "INT8_FMTX" Post filter total : " + INT8_FMT" "INT8_FMTX" Msg Total : "INT8_FMT" "INT8_FMTX + " Current backlog : "INT8_FMT" "INT8_FMTX"\n", + log_seqno, log_seqno, + repl_recv_data_processed, repl_recv_data_processed, + repl_recv_postfltr_data_procd, repl_recv_postfltr_data_procd, + msg_total, msg_total, diff_seqno, diff_seqno); } /* Approximate time with an error not more than GTMRECV_HEARTBEAT_PERIOD. We use this * instead of calling time(), and expensive system call, especially on VMS. The @@ -1859,7 +1859,7 @@ STATICFNDEF void process_tr_buff(int msg_type) if ((double)GTMRECV_LOGSTATS_INTERVAL <= time_elapsed) { repl_log(gtmrecv_log_fp, TRUE, FALSE, "REPL INFO since last log : Time elapsed : " - "%00.f Tr recvd : %llu Tr bytes : %llu Msg bytes : %llu\n", + "%00.f Tr recvd : "INT8_FMT" Tr bytes : "INT8_FMT" Msg bytes : "INT8_FMT"\n", time_elapsed, trans_recvd_cnt - last_log_tr_recvd_cnt, repl_recv_data_processed - repl_recv_lastlog_data_procd, msg_total - repl_recv_lastlog_data_recvd); @@ -1879,15 +1879,15 @@ STATICFNDEF void process_tr_buff(int msg_type) { if (!filter_pass) { - repl_log(gtmrecv_statslog_fp, FALSE, FALSE, "Tr : %llu Size : %d Write : %d " - "Total : %llu\n", recvpool_ctl->jnl_seqno, write_len, + repl_log(gtmrecv_log_fp, FALSE, FALSE, "Tr : "INT8_FMT" Size : %d Write : %d " + "Total : "INT8_FMT"\n", recvpool_ctl->jnl_seqno, write_len, write_off, repl_recv_data_processed); } else { assert(!is_new_histrec); - repl_log(gtmrecv_statslog_fp, FALSE, FALSE, "Tr : %llu Pre filter Size : %d " + repl_log(gtmrecv_log_fp, FALSE, FALSE, "Tr : "INT8_FMT" Pre filter Size : %d " "Post filter Size : %d Pre filter Write : %d Post filter Write : %d " - "Pre filter Total : %llu Post filter Total : %llu\n", + "Pre filter Total : "INT8_FMT" Post filter Total : "INT8_FMT"\n", recvpool_ctl->jnl_seqno, pre_filter_write_len, write_len, pre_filter_write, write_off, repl_recv_data_processed, repl_recv_postfltr_data_procd); @@ -2082,6 +2082,8 @@ STATICFNDEF void process_tr_buff(int msg_type) /* uses and updates "write_loc" */ write_off = recvpool_ctl->write; /* Note: "last_rcvd_strm_histinfo" is automatically maintained in this case */ + /* Now that we have inserted the stream specific history records, reset flag */ + recvpool_ctl->insert_strm_histinfo = FALSE; } else { /* Maintain last_rcvd_strm_histinfo[] as well. * In addition, if insert_strm_histinfo is TRUE, it means no REPL_STRMINFO messages @@ -2193,21 +2195,22 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4 histinfo_num = recvpool.gtmrecv_local->updresync_num_histinfo_strm[strm_num]; if (INVALID_HISTINFO_NUM == histinfo_num) { /* The instance file cannot be used for updateresync if it has NO history records. */ - rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Input instance file has NO history records")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, + LEN_AND_LIT("Input instance file has NO history records")); } assert(0 <= histinfo_num); if (!recvpool.gtmrecv_local->updresync_jnl_seqno) { /* The instance file cannot be used for updateresync if it has a ZERO seqno */ - rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Input instance file has jnl_seqno of 0")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, + ERR_TEXT, 2, LEN_AND_LIT("Input instance file has jnl_seqno of 0")); } if (input_seqno > recvpool.gtmrecv_local->updresync_jnl_seqno) { /* Input seqno is greater than the max seqno in the updateresync input instance file. So can never be found. */ - SNPRINTF(print_msg, SIZEOF(print_msg), "Seqno %llu [0x%llx] cannot be found in input instance file " - " which has a max seqno of %llu [0x%llx]\n", input_seqno, input_seqno, + SNPRINTF(print_msg, SIZEOF(print_msg), "Seqno "INT8_FMT" "INT8_FMTX" cannot be found in input instance file " + " which has a max seqno of "INT8_FMT" "INT8_FMTX"\n", input_seqno, input_seqno, recvpool.gtmrecv_local->updresync_jnl_seqno, recvpool.gtmrecv_local->updresync_jnl_seqno); - rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, + ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg)); } histinfo->start_seqno = 0; do @@ -2220,14 +2223,14 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4 * error indicates to the user it is the -updateresync qualifier where the issue is so it is not a big loss. */ if (-1 == status) - rts_error(VARLSTCNT(15) ERR_UPDSYNCINSTFILE, 0, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"), + ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"), ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT("")); else - rts_error(VARLSTCNT(16) ERR_UPDSYNCINSTFILE, 0, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(16) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"), + ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"), ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""), status); } if (recvpool.gtmrecv_local->updresync_cross_endian) @@ -2237,9 +2240,11 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4 histinfo_num = (INVALID_SUPPL_STRM == strm_num) ? (histinfo_num - 1) : histinfo->prev_histinfo_num; } while (INVALID_HISTINFO_NUM != histinfo_num); /* Could not find history record in -updateresync= input instance file */ - SNPRINTF(print_msg, SIZEOF(print_msg), "Receiver side instance seqno %llu [0x%llx] is lesser than " - " any history record found in instance file", input_seqno, input_seqno); - rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg)); + SNPRINTF(print_msg, SIZEOF(print_msg), + "Receiver side instance seqno "INT8_FMT" "INT8_FMTX" is less than" + " any history record found in instance file", input_seqno, input_seqno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, + ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg)); } /* Retrieve the "index"'th history record in the instance file specified using the -UPDATERESYNC qualifier. @@ -2252,7 +2257,6 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4 */ STATICFNDEF void gtmrecv_updresync_histinfo_get(int4 index, repl_histinfo *histinfo) { - char print_msg[1024]; int fd, status; off_t offset; @@ -2267,12 +2271,12 @@ STATICFNDEF void gtmrecv_updresync_histinfo_get(int4 index, repl_histinfo *histi * error indicates to the user it is the -updateresync qualifier where the issue is so it is not a big loss. */ if (-1 == status) - rts_error(VARLSTCNT(12) ERR_UPDSYNCINSTFILE, 0, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_UPDSYNCINSTFILE, 0, + ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"), ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT("")); else - rts_error(VARLSTCNT(13) ERR_UPDSYNCINSTFILE, 0, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_UPDSYNCINSTFILE, 0, + ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"), ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""), status); } if (recvpool.gtmrecv_local->updresync_cross_endian) @@ -2297,7 +2301,7 @@ STATICFNDEF void gtmrecv_process_need_strminfo_msg(repl_needstrminfo_msg_ptr_t n need_strminfo_seqno = need_strminfo_msg->seqno; else need_strminfo_seqno = GTM_BYTESWAP_64(need_strminfo_msg->seqno); - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_STRMINFO message for seqno %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_STRMINFO message for seqno "INT8_FMT" "INT8_FMTX"\n", need_strminfo_seqno, need_strminfo_seqno); if (recvpool.gtmrecv_local->updateresync && (FD_INVALID != recvpool.gtmrecv_local->updresync_instfile_fd)) { /* The stream information that is being requested needs to be found in the -updateresync input instance file @@ -2342,7 +2346,7 @@ STATICFNDEF void gtmrecv_process_need_strminfo_msg(repl_needstrminfo_msg_ptr_t n { repl_log(gtmrecv_log_fp, TRUE, TRUE, "Searching for the desired history in the replication instance file\n"); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; /* above macro will "return" if repl_connection_reset OR gtmrecv_wait_for_jnl_seqno is set */ status = repl_inst_wrapper_histinfo_find_seqno(need_strminfo_seqno, INVALID_SUPPL_STRM, &histinfo); @@ -2409,14 +2413,14 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n assert(INVALID_SUPPL_STRM == need_histinfo_strm_num); assert(INVALID_HISTINFO_NUM == need_histinfo_num); } - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for seqno %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for seqno "INT8_FMT" "INT8_FMTX"\n", need_histinfo_seqno, need_histinfo_seqno); } else if (0 < strm_index) { /* Receiver side is supplementary but Source side is a non-supplementary instance */ assert(INVALID_SUPPL_STRM == need_histinfo_strm_num); assert(INVALID_HISTINFO_NUM == need_histinfo_num); - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for Stream %d : Seqno %llu [0x%llx]\n", - strm_index, need_histinfo_seqno, need_histinfo_seqno); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for Stream %d : Seqno " + INT8_FMT" "INT8_FMTX"\n", strm_index, need_histinfo_seqno, need_histinfo_seqno); need_histinfo_strm_num = strm_index; } else { /* Both receiver and source sides are supplementary instances */ @@ -2424,7 +2428,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n assert(INVALID_SUPPL_STRM != need_histinfo_strm_num); if (INVALID_HISTINFO_NUM == need_histinfo_num) repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for Stream %d : " - "Seqno %llu [0x%llx]\n", need_histinfo_strm_num, need_histinfo_seqno, need_histinfo_seqno); + "Seqno "INT8_FMT" "INT8_FMTX"\n", need_histinfo_strm_num, need_histinfo_seqno, need_histinfo_seqno); else repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_NEED_HISTINFO message for History Number %d\n", need_histinfo_num); @@ -2447,7 +2451,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n { /* The history record needs to be found in the receiver side instance file */ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Searching for the desired history in the replication instance file\n"); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; /* above macro will "return" if repl_connection_reset OR gtmrecv_wait_for_jnl_seqno is set */ status = repl_inst_histinfo_get(need_histinfo_num, histinfo); @@ -2474,7 +2478,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n } else { first_unprocessed_seqno = recvpool.upd_proc_local->read_jnl_seqno; - repl_log(gtmrecv_log_fp, TRUE, FALSE, "Update process has processed upto seqno %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, FALSE, "Update process has processed upto seqno "INT8_FMT" "INT8_FMTX"\n", first_unprocessed_seqno, first_unprocessed_seqno); suppl_propagate_primary = remote_side->is_supplementary; if (!suppl_propagate_primary) @@ -2482,13 +2486,12 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n else last_valid_histinfo_seqno = recvpool_ctl->last_valid_strm_histinfo[0].start_seqno; repl_log(gtmrecv_log_fp, TRUE, TRUE, - "Starting seqno of the last valid history in the receive pool is %llu [0x%llx]\n", + "Starting seqno of the last valid history in the receive pool is "INT8_FMT" "INT8_FMTX"\n", last_valid_histinfo_seqno, last_valid_histinfo_seqno); if (last_valid_histinfo_seqno >= first_unprocessed_seqno) last_unprocessed_histinfo_seqno = last_valid_histinfo_seqno; else last_unprocessed_histinfo_seqno = MAX_SEQNO; - assert(last_valid_histinfo_seqno < need_histinfo_seqno); if (last_unprocessed_histinfo_seqno && (need_histinfo_seqno > last_unprocessed_histinfo_seqno)) { /* NOTE0: The source server is requesting histinfo information for a seqno whose corresponding @@ -2537,7 +2540,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n assert(NULL != jnlpool.jnlpool_dummy_reg); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Searching for the desired history in the replication instance file\n"); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; status = repl_inst_wrapper_histinfo_find_seqno(need_histinfo_seqno, need_histinfo_strm_num, histinfo); rel_lock(jnlpool.jnlpool_dummy_reg); @@ -2581,8 +2584,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) { /* The work-horse of the Receiver Server */ boolean_t dont_reply_to_heartbeat = FALSE, is_repl_cmpc; - boolean_t uncmpfail, send_cross_endian; - char print_msg[1024]; + boolean_t uncmpfail, send_cross_endian, preserve_buffp, recvpool_prepared; gtmrecv_local_ptr_t gtmrecv_local; gtm_time4_t ack_time; int4 msghdrlen, strm_num; @@ -2609,12 +2611,13 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) seq_num request_from, recvd_jnl_seqno; sgmnt_addrs *repl_csa; uchar_ptr_t old_buffp; - uint4 recvd_start_flags; + uint4 recvd_start_flags, len; uLong cmplen; uLongf destlen; unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */ unsigned char remote_jnl_ver; upd_proc_local_ptr_t upd_proc_local; + repl_logfile_info_msg_t *logfile_msgp, logfile_msg; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -2667,7 +2670,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) assert((!jnlpool_ctl->upd_disabled && jnlpool.repl_inst_filehdr->is_supplementary) || (recvpool_ctl->jnl_seqno >= jnlpool_ctl->jnl_seqno)); assert(request_from); - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Requesting transactions from JNL_SEQNO %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Requesting transactions from JNL_SEQNO "INT8_FMT" "INT8_FMTX"\n", request_from, request_from); /* Send (re)start JNL_SEQNO to Source Server. * Note that even though we might know the endianness of the source side at this time, we still send this @@ -2680,7 +2683,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) * AND the source is cross-endian. In that case, the pre-V55000 source does not know to handle a * receiver-side-native-endian format message. So endian convert the message only in this case. */ - repl_log(gtmrecv_log_fp, TRUE, TRUE, "Sending REPL_START_JNL_SEQNO message with seqno %llu [0x%llx]\n", + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Sending REPL_START_JNL_SEQNO message with seqno "INT8_FMT" "INT8_FMTX"\n", request_from, request_from); send_cross_endian = (remote_side->endianness_known && remote_side->cross_endian && (REPL_PROTO_VER_SUPPLEMENTARY > remote_side->proto_ver)); @@ -2715,7 +2718,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) msgp->is_supplementary = jnlpool.repl_inst_filehdr->is_supplementary; msgp->len = send_cross_endian ? GTM_BYTESWAP_32(MIN_REPL_MSGLEN) : MIN_REPL_MSGLEN; msg_len = MIN_REPL_MSGLEN; - REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, msg_len, FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, msg_len, REPL_POLL_NOWAIT) { GTMRECV_POLL_ACTIONS(0, 0, NULL); } @@ -2740,12 +2743,11 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) repl_recv_lastlog_data_recvd = 0; repl_recv_lastlog_data_procd = 0; msghdrlen = REPL_MSG_HDRLEN; - while (TRUE) { recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed; while ((SS_NORMAL == (status = repl_recv(gtmrecv_sock_fd, - (buffp + buff_unprocessed), &recvd_len, FALSE, >mrecv_poll_interval))) + (buffp + buff_unprocessed), &recvd_len, REPL_POLL_WAIT))) && (0 == recvd_len)) { recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed; @@ -2754,10 +2756,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, gtmrecv_poll_interval is now 0. - * Force wait before logging any message. - */ - SHORT_SLEEP(GTMRECV_POLL_INTERVAL >> 10); /* approximate in ms */ + { /* update process is still running slow, Force wait before logging any message. */ + SHORT_SLEEP(REPL_POLL_WAIT >> 10); /* approximate in ms */ REPL_DPRINT1("Waiting for Update Process to clear recvpool space\n"); xoff_msg_log_cnt = 0; } else if (xoff_sent) @@ -2777,15 +2777,11 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) return; } else { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. " - "Error in recv : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + ISSUE_REPLCOMM_ERROR("Error in receiving from source. Error in recv", status); } } else if (EREPL_SELECT == repl_errno) { - SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. Error in select : %s", - STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg)); + ISSUE_REPLCOMM_ERROR("Error in receiving from source. Error in select", status); } } if (repl_connection_reset) @@ -2803,12 +2799,13 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) buff_unprocessed += recvd_len; repl_recv_data_recvd += (qw_num)recvd_len; if (gtmrecv_logstats) - repl_log(gtmrecv_statslog_fp, FALSE, FALSE, "Recvd : %d Total : %d\n", recvd_len, repl_recv_data_recvd); + repl_log(gtmrecv_log_fp, FALSE, FALSE, "Recvd : %d Total : %d\n", recvd_len, repl_recv_data_recvd); while (msghdrlen <= buff_unprocessed) { if (0 == data_len) { assert(0 == ((unsigned long)buffp % REPL_MSG_ALIGN)); + DEBUG_ONLY(recvpool_prepared = FALSE); if (!remote_side->endianness_known) { remote_side->endianness_known = TRUE; @@ -2876,14 +2873,21 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) } else { msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN; - buffp += REPL_MSG_HDRLEN; exp_data_len = msg_len; + if (REPL_TR_JNL_RECS == msg_type || REPL_OLD_TRIPLE == msg_type || REPL_HISTREC == msg_type) + { + /* Target buffer is the receive pool. Prepare the receive pool for write (also + * checks if the transaction will fit in). + * Note: this is a special case where PREPARE_RECVPOOL_FOR_WRITE is not invoked + * right before COPY_TO_RECVPOOL because we want to prepare the receive pool just + * once even though the actual data (coming from the other end) might come in + * different pieces. + */ + 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; - /* If the target buffer is the receive pool, prepare the receive pool for the write. - * In addition, check if transaction will fit in. - * If the target buffer is not the receive pool, we will do this check after uncompression. - */ - PREPARE_RECVPOOL_FOR_WRITE(exp_data_len, 0); } assert(0 <= buff_unprocessed); assert(0 == (msg_len % REPL_MSG_ALIGN)); @@ -2897,6 +2901,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) buffp += buffered_data_len; buff_unprocessed -= buffered_data_len; data_len -= buffered_data_len; + preserve_buffp = (0 != data_len); switch(msg_type) { case REPL_TR_JNL_RECS: @@ -2907,6 +2912,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) is_repl_cmpc = ((REPL_TR_CMP_JNL_RECS == msg_type) || (REPL_TR_CMP_JNL_RECS2 == msg_type)); if (!is_repl_cmpc) { + assert(recvpool_prepared); COPY_TO_RECVPOOL(old_buffp, buffered_data_len); /* uses and updates "write_loc" */ } else { @@ -2921,6 +2927,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno) return; } + preserve_buffp = FALSE; break; case REPL_LOSTTNCOMPLETE: @@ -2928,12 +2935,13 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) { assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_LOSTTNCOMPLETE message\n"); - if (SS_NORMAL != (status = repl_inst_reset_zqgblmod_seqno_and_tn())) - { /* only reason we know currently for the above function to fail is due + status = repl_inst_reset_zqgblmod_seqno_and_tn(); + assert(-1 == status || EXIT_ERR == status || SS_NORMAL == status); + if (-1 == status) + { /* only reason we know currently for the above function to return -1 is due * to a concurrent online rollback. In this case, we cannot continue * and need to start afresh. */ - assert(-1 == status); gtmrecv_onln_rlbk_clnup(); if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno) return; @@ -2965,7 +2973,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) (uchar_ptr_t)&heartbeat.ack_seqno[0], SIZEOF(seq_num)); ack_seqno = GTM_BYTESWAP_64(temp_ack_seqno); } - REPL_DPRINT4("HEARTBEAT received with time %ld SEQNO %llu at %ld\n", + REPL_DPRINT4("HEARTBEAT received with time %ld SEQNO "INT8_FMT" at %ld\n", ack_time, ack_seqno, time(NULL)); ack_seqno = upd_proc_local->read_jnl_seqno; if (!remote_side->cross_endian) @@ -2983,13 +2991,12 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) memcpy((uchar_ptr_t)&heartbeat.ack_seqno[0], (uchar_ptr_t)&temp_ack_seqno, SIZEOF(seq_num)); } - REPL_SEND_LOOP(gtmrecv_sock_fd, &heartbeat, MIN_REPL_MSGLEN, - FALSE, >mrecv_poll_immediate) + REPL_SEND_LOOP(gtmrecv_sock_fd, &heartbeat, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT) { GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); } CHECK_REPL_SEND_LOOP_ERROR(status, "REPL_HEARTBEAT"); - REPL_DPRINT4("HEARTBEAT sent with time %ld SEQNO %llu at %ld\n", + REPL_DPRINT4("HEARTBEAT sent with time %ld SEQNO "INT8_FMT" at %ld\n", ack_time, ack_seqno, time(NULL)); } break; @@ -3005,7 +3012,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) if (jnlpool.repl_inst_filehdr->is_supplementary) { /* Issue REPL2OLD error because this is a supplementary instance and remote * side runs a GT.M version that does not know the supplementary protocol */ - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_need_instinfo_msg->instname), LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); } @@ -3016,11 +3023,14 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) if (gtmrecv_local->updateresync && (FD_INVALID != gtmrecv_local->updresync_instfile_fd)) { - rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Source side is non-supplementary implies " + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, + ERR_TEXT, 2, + LEN_AND_LIT("Source side is non-supplementary implies " "-UPDATERESYNC needs no value specified")); } - /* Initialize the remote side protocol version from "proto_ver" field of this msg */ + /* Initialize the remote side protocol version from "proto_ver" + * field of this msg + */ remote_side->proto_ver = old_need_instinfo_msg->proto_ver; assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver); assert(REPL_PROTO_VER_SUPPLEMENTARY > remote_side->proto_ver); @@ -3028,7 +3038,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) memset(&old_instinfo_msg, 0, SIZEOF(old_instinfo_msg)); memcpy(old_instinfo_msg.instname, jnlpool.repl_inst_filehdr->inst_info.this_instname, MAX_INSTNAME_LEN - 1); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; old_instinfo_msg.was_rootprimary = (unsigned char)repl_inst_was_rootprimary(); rel_lock(jnlpool.jnlpool_dummy_reg); @@ -3043,7 +3053,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) if ((old_instinfo_msg.was_rootprimary || jnlpool_ctl->max_zqgblmod_seqno) && !old_need_instinfo_msg->is_rootprimary) { - gtm_putmsg(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *) old_need_instinfo_msg->instname)); gtmrecv_autoshutdown(); /* should not return */ assert(FALSE); @@ -3218,8 +3228,9 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) */ if (REPL_PROTO_VER_UNINITIALIZED == remote_side->proto_ver) { /* Issue REPL2OLD error because primary is dual-site */ - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME), - LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, + LEN_AND_STR(UNKNOWN_INSTNAME), + LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); } /* Assert that endianness_known and cross_endian have already been initialized. * This ensures that remote_side->cross_endian is reliable */ @@ -3234,7 +3245,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) * database file headers henceforth controls whether this instance can * be brought up as a tertiary or not. Flush changes to file on disk. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; jnlpool.repl_inst_filehdr->was_rootprimary = FALSE; repl_inst_flush_filehdr(); @@ -3264,7 +3275,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) { repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_ROLLBACK_FIRST message. " "Secondary is out of sync with the primary. " - "Secondary at %llu [0x%llx], Primary at %llu [0x%llx]. " + "Secondary at "INT8_FMT" "INT8_FMTX", Primary at "INT8_FMT" "INT8_FMTX". " "Do ROLLBACK FIRST\n", request_from, request_from, recvd_jnl_seqno, recvd_jnl_seqno); if (gtmrecv_options.autorollback) @@ -3284,22 +3295,28 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) gtmrecv_autoshutdown(); /* should not return */ assert(FALSE); } - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); - GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; /* No return */ - rel_lock(jnlpool.jnlpool_dummy_reg); /* in PRO just in case */ + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); + GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED; + /* The ONLINE ROLLBACK did not change the physical or the logical state as + * otherwise the above macro would have returned to the caller. But, since + * we have already disconnected the connection by now, we cannot resume the + * flow from this point on. So, go ahead and release the lock and shutdown + * the Receiver Server. + */ + rel_lock(jnlpool.jnlpool_dummy_reg); } else { repl_log(gtmrecv_log_fp, TRUE, TRUE, "Receiver was not started with " "-AUTOROLLBACK. Manual ROLLBACK required. Shutting down\n"); - gtmrecv_autoshutdown(); /* should not return */ } + gtmrecv_autoshutdown(); /* should not return */ assert(FALSE); break; } /* Handle REPL_WILL_RESTART_WITH_INFO case now */ assert(REPL_WILL_RESTART_WITH_INFO == msg_type); repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received REPL_WILL_RESTART_WITH_INFO message" - " with seqno %llu [0x%llx]\n", recvd_jnl_seqno, recvd_jnl_seqno); + " with seqno "INT8_FMT" "INT8_FMTX"\n", recvd_jnl_seqno, recvd_jnl_seqno); remote_side->jnl_ver = start_msg->jnl_ver; remote_jnl_ver = remote_side->jnl_ver; REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n", @@ -3324,11 +3341,12 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) remote_side->is_supplementary = start_msg->is_supplementary; remote_side->trigger_supported = (recvd_start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE; - assert((remote_jnl_ver - JNL_VER_EARLIEST_REPL) < ARRAYSIZE(repl_filter_old2cur)); - assert((remote_jnl_ver - JNL_VER_EARLIEST_REPL) < ARRAYSIZE(repl_filter_cur2old)); - if ((this_side->jnl_ver > remote_jnl_ver) - && (IF_NONE != repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL])) + if (this_side->jnl_ver > remote_jnl_ver) { + assert(JNL_VER_EARLIEST_REPL <= remote_jnl_ver); + assert((remote_jnl_ver - JNL_VER_EARLIEST_REPL) < ARRAYSIZE(repl_filter_old2cur)); + assert((remote_jnl_ver - JNL_VER_EARLIEST_REPL) < ARRAYSIZE(repl_filter_cur2old)); + assert(IF_NONE != repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL]); assert(IF_INVALID != repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL]); /* reverse transformation should exist */ assert(IF_INVALID != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]); @@ -3379,7 +3397,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) SHM_WRITE_MEMORY_BARRIER; recvpool.upd_proc_local->read_jnl_seqno = recvd_jnl_seqno; repl_log(gtmrecv_log_fp, TRUE, TRUE, "Wrote upd_proc_local->read_jnl_seqno" - " : %llu [0x%llx]\n", recvd_jnl_seqno, recvd_jnl_seqno); + " : "INT8_FMT" "INT8_FMTX"\n", recvd_jnl_seqno, recvd_jnl_seqno); /* If -NORESYNC was used in receiver startup, we dont want to use it * anymore as future such connections could cause recvpool_ctl->jnl_seqno * to be reset further backwards and will confuse the update process. @@ -3414,6 +3432,33 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) } break; + case REPL_LOGFILE_INFO: + if (0 == data_len) + { + logfile_msgp = (repl_logfile_info_msg_t *)(buffp - msg_len - REPL_MSG_HDRLEN); + assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msgp->proto_ver); + if (remote_side->cross_endian) + { + logfile_msgp->fullpath_len = GTM_BYTESWAP_32(logfile_msgp->fullpath_len); + logfile_msgp->pid = GTM_BYTESWAP_32(logfile_msgp->pid); + } + assert('\0' == logfile_msgp->fullpath[logfile_msgp->fullpath_len - 1]); + repl_log(gtmrecv_log_fp, TRUE, TRUE, "Remote side source log file path is %s; " + "Source Server PID = %d\n", + logfile_msgp->fullpath, logfile_msgp->pid); + /* Now, send our logfile path to the source side */ + assert(remote_side->endianness_known); + len = repl_logfileinfo_get(recvpool.gtmrecv_local->log_file, + &logfile_msg, + remote_side->cross_endian, + gtmrecv_log_fp); + REPL_SEND_LOOP(gtmrecv_sock_fd, &logfile_msg, len, REPL_POLL_NOWAIT) + { + GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); + } + CHECK_REPL_SEND_LOOP_ERROR(status, "REPL_LOGFILE_INFO"); + } + break; default: /* Discard the message */ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). " @@ -3428,13 +3473,16 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart) return; } assert(0 == ((unsigned long)(buffp) % REPL_MSG_ALIGN)); - if ((0 != buff_unprocessed) && (buff_start != buffp)) + if (!preserve_buffp) { - REPL_DPRINT4("Incmpl msg hdr, moving %d bytes from %lx to %lx\n", buff_unprocessed, (caddr_t)buffp, - (caddr_t)buff_start); - memmove(buff_start, buffp, buff_unprocessed); + if ((0 != buff_unprocessed) && (buff_start != buffp)) + { + REPL_DPRINT4("Incmpl msg hdr, moving %d bytes from %lx to %lx\n", buff_unprocessed, (caddr_t)buffp, + (caddr_t)buff_start); + memmove(buff_start, buffp, buff_unprocessed); + } + buffp = buff_start; } - buffp = buff_start; GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp); } } @@ -3490,7 +3538,6 @@ void gtmrecv_process(boolean_t crash_restart) * different sized messages only for a few messages types REPL_TR_JNL_RECS, REPL_OLD_TRIPLE and REPL_CMP_SOLVE. * But post-supplementary it knows to handle different sized messages for various additional message types * (including REPL_NEED_INSTINFO, REPL_INSTINFO, REPL_HISTREC). - * */ assert(MIN_REPL_MSGLEN == SIZEOF(repl_start_msg_t)); assert(MIN_REPL_MSGLEN == SIZEOF(repl_start_reply_msg_t)); @@ -3506,11 +3553,7 @@ void gtmrecv_process(boolean_t crash_restart) assert(MIN_REPL_MSGLEN < SIZEOF(repl_old_triple_msg_t)); assert(MIN_REPL_MSGLEN < SIZEOF(repl_histrec_msg_t)); assert(MIN_REPL_MSGLEN == SIZEOF(repl_heartbeat_msg_t)); - assert(GTMRECV_POLL_INTERVAL < MAX_GTMRECV_POLL_INTERVAL); - gtmrecv_poll_interval.tv_sec = 0; - gtmrecv_poll_interval.tv_usec = GTMRECV_POLL_INTERVAL; - gtmrecv_poll_immediate.tv_sec = 0; - gtmrecv_poll_immediate.tv_usec = 0; + assert(REPL_POLL_WAIT < MILLISECS_IN_SEC); recvpool_size = recvpool_ctl->recvpool_size; recvpool_high_watermark = (long)((float)RECVPOOL_HIGH_WATERMARK_PCTG / 100 * recvpool_size); recvpool_low_watermark = (long)((float)RECVPOOL_LOW_WATERMARK_PCTG / 100 * recvpool_size); diff --git a/sr_unix/gtmrecv_shutdown.c b/sr_unix/gtmrecv_shutdown.c index 50d16ba..7c923b1 100644 --- a/sr_unix/gtmrecv_shutdown.c +++ b/sr_unix/gtmrecv_shutdown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -41,6 +41,10 @@ #include "gtmmsg.h" #include "repl_msg.h" #include "gtmsource.h" +#ifdef DEBUG +#include "wbox_test_init.h" +#include "gtmio.h" +#endif #define GTMRECV_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1s */ @@ -61,7 +65,7 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status) { uint4 savepid; boolean_t shut_upd_too = FALSE, was_crit; - int status; + int status, save_errno; unix_db_info *udi; udi = (unix_db_info *)FILE_INFO(recvpool.recvpool_dummy_reg); @@ -75,9 +79,11 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status) status = grab_sem(RECV, RECV_POOL_ACCESS_SEM); if (0 > status) { - repl_log(stderr, TRUE, TRUE, - "Error grabbing receive pool control semaphore : %s. Shutdown not complete\n", REPL_SEM_ERROR); - return (ABNORMAL_SHUTDOWN); + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Error grabbing receive pool control semaphore : %s. " + "Shutdown not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); + return ABNORMAL_SHUTDOWN; } } else { /* ftok semaphore and recvpool access semaphore should already be held from the previous call to "recvpool_init" */ @@ -86,28 +92,41 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status) /* We do not want to hold the options semaphore to avoid deadlocks with receiver server startup (C9F12-002766) */ assert(!holds_sem[RECV][RECV_SERV_OPTIONS_SEM]); recvpool.gtmrecv_local->shutdown = SHUTDOWN; - /* Wait for receiver server to die. But release ftok semaphore and recvpool access control semaphore before - * waiting as the concurrently running receiver server might need these (e.g. if it is about to call the - * function "repl_inst_was_rootprimary"). + /* Wait for receiver server to die. But before that release ftok semaphore and receive pool access control + * semaphore. This way, other processes (either in this environment or a different one) don't encounter startup + * issues. However, to ensure that a concurrent argument-less rundown doesn't remove these semaphores (in case they + * are orphaned), increment the counter semaphore. */ - if (0 != rel_sem(RECV, RECV_POOL_ACCESS_SEM)) - gtm_putmsg(VARLSTCNT(7) ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in receiver server shutdown rel_sem"), - REPL_SEM_ERRNO); + if (0 != (status = incr_sem(RECV, RECV_SERV_COUNT_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not acquire Receive Pool counter semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + /* Even though we hold the FTOK and RECV_POOL_ACCESS_SEM before entering this function (as ensured by + * asserts above), it is safe to release them in case of a premature error (like this one). The caller + * doesn't rely on the semaphores being held and this function is designed to release these semaphores + * eventually anyways (after gtmrecv_ipc_cleanup()) + */ + repl_inst_ftok_sem_release(); + status = rel_sem(RECV, RECV_POOL_ACCESS_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } + if (0 != (status = rel_sem(RECV, RECV_POOL_ACCESS_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not release Receive Pool access control semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); /* see comment above for why this is okay */ + status = decr_sem(RECV, RECV_SERV_COUNT_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } repl_inst_ftok_sem_release(); - /* Wait for receiver server to shut down */ while((SHUTDOWN == recvpool.gtmrecv_local->shutdown) && (0 < (savepid = recvpool.gtmrecv_local->recv_serv_pid)) && is_proc_alive(savepid, 0)) SHORT_SLEEP(GTMRECV_WAIT_FOR_SHUTDOWN); - /* (Re)Grab the ftok semaphore and recvpool access control semaphore IN THAT ORDER (to avoid deadlocks) */ - repl_inst_ftok_sem_lock(); - status = grab_sem(RECV, RECV_POOL_ACCESS_SEM); - if (0 > status) - { - repl_log(stderr, TRUE, TRUE, - "Error regrabbing receive pool control semaphore : %s. Shutdown not complete\n", REPL_SEM_ERROR); - return (ABNORMAL_SHUTDOWN); - } exit_status = recvpool.gtmrecv_local->shutdown; if (SHUTDOWN == exit_status) { @@ -120,6 +139,39 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status) shut_upd_too = TRUE; } } + /* (Re)Grab the ftok semaphore and recvpool access control semaphore IN THAT ORDER (to avoid deadlocks) */ + repl_inst_ftok_sem_lock(); +# ifdef DEBUG + /* Sleep for a few seconds to test for concurrent argument-less RUNDOWN to ensure that the latter doesn't remove + * the RECV_POOL_ACCESS_SEM under the assumption that it is orphaned. + */ + if (gtm_white_box_test_case_enabled && (WBTEST_LONGSLEEP_IN_REPL_SHUTDOWN == gtm_white_box_test_case_number)) + { + DBGFPF((stderr, "GTMRECV_SHUTDOWN is about to start long sleep\n")); + LONG_SLEEP(10); + } +# endif + if (0 != (status = grab_sem(RECV, RECV_POOL_ACCESS_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not acquire Receive Pool access control semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); + status = decr_sem(RECV, RECV_SERV_COUNT_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } + /* Now that semaphores are acquired, decrement the counter semaphore */ + if (0 != (status = decr_sem(RECV, RECV_SERV_COUNT_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not release Receive Pool counter semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); + status = rel_sem(RECV, RECV_POOL_ACCESS_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } } if (shut_upd_too) gtmrecv_endupd(); @@ -130,19 +182,19 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status) { /* Release all semaphores */ if (!auto_shutdown) { - rel_sem_immediate( RECV, UPD_PROC_COUNT_SEM); - rel_sem_immediate( RECV, RECV_SERV_COUNT_SEM); + decr_sem(RECV, UPD_PROC_COUNT_SEM); + decr_sem(RECV, RECV_SERV_COUNT_SEM); } rel_sem_immediate( RECV, RECV_POOL_ACCESS_SEM); - } else if (NORMAL_SHUTDOWN == exit_status) - { + } else + { /* Receive Pool and Access Control Semaphores removed. Invalidate corresponding fields in file header */ assert(!udi->s_addrs.hold_onto_crit); was_crit = udi->s_addrs.now_crit; /* repl_inst_recvpool_reset inturn invokes repl_inst_flush_filehdr which expects the caller to grab journal pool * lock if journal pool is available. */ if ((NULL != jnlpool.jnlpool_ctl) && !was_crit) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); repl_inst_recvpool_reset(); if ((NULL != jnlpool.jnlpool_ctl) && !was_crit) rel_lock(jnlpool.jnlpool_dummy_reg); diff --git a/sr_unix/gtmsecshr.c b/sr_unix/gtmsecshr.c index e6c0534..415c8d7 100644 --- a/sr_unix/gtmsecshr.c +++ b/sr_unix/gtmsecshr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,6 +9,17 @@ * * ****************************************************************/ +/******************************************************************************************** + * W A R N I N G --- W A R N I N G --- W A R N I N G --- W A R N I N G --- W A R N I N G * + * * + * This routine (gtmsecshr) runs as setuid to root to perform various functions on behalf * + * of GT.M processes. Extreme care must be taken to prevent all forms of deceptive access, * + * linking with unauthorized libraries, etc. Same applies to anything it calls. * + * * + * W A R N I N G --- W A R N I N G --- W A R N I N G --- W A R N I N G --- W A R N I N G * + ********************************************************************************************/ + + #include "mdef.h" #include "main_pragma.h" @@ -18,10 +29,13 @@ #include "gtm_stat.h" #include "gtm_socket.h" #include +#include #include #if !defined(_AIX) && !defined(__linux__) && !defined(__hpux) && !defined(__CYGWIN__) && !defined(__MVS__) -#include +# include #endif +#include "gtm_syslog.h" +#include "gtm_limits.h" #include "gtm_stdlib.h" #include "gtm_sem.h" #include "gtm_string.h" @@ -33,7 +47,7 @@ #include "gtm_permissions.h" #if defined(__MVS__) -#include "gtm_zos_io.h" +# include "gtm_zos_io.h" #endif #include "cli.h" @@ -59,41 +73,45 @@ #include "generic_signal_handler.h" #include "gtmmsg.h" #include "have_crit.h" -#include "trans_log_name.h" #include "sig_init.h" #include "gtmio.h" #include "file_head_read.h" #include "file_head_write.h" -#include "suspsigs_handler.h" #include "gtm_env_init.h" /* for gtm_env_init() prototype */ #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" - +#include "hashtab.h" +#include "fork_init.h" #ifdef UNICODE_SUPPORTED -#include "gtm_icu_api.h" -#include "gtm_utf8.h" +# include "gtm_icu_api.h" +# include "gtm_utf8.h" #endif -#define TIME_FORMAT "_%Y%j%H%M%S" /* .yearjuliendayhoursminutesseconds */ +#define execname "gtmsecshr" /* this is what this executable is supposed to be called. A different name is verboten */ +#define intent_open "for open" /* FLUSH_DB_IPCS_INFO types */ +#define intent_close "for close" +#define TZLOCATOR "TZ=" +#define NEWLINE 0x0a GBLDEF CLI_ENTRY *cmd_ary = NULL; /* GTMSECSHR does not have any command tables so initialize command array to NULL */ -GBLREF int gtmsecshr_log_file; GBLREF int gtmsecshr_sockfd; GBLREF struct sockaddr_un gtmsecshr_sock_name; GBLREF int gtmsecshr_sockpath_len; GBLREF key_t gtmsecshr_key; GBLREF uint4 process_id; GBLREF boolean_t need_core; +GBLREF boolean_t first_syslog; /* Defined in util_output.c */ + +LITREF char gtm_release_name[]; +LITREF int4 gtm_release_name_len; static volatile int gtmsecshr_timer_popped; -static volatile boolean_t ready_to_switch_log_file = FALSE; -static int4 times_to_switch_log_file = 0; -static int gtmsecshr_logpath_len; static int gtmsecshr_socket_dir_len; -static char gtmsecshr_logpath[MAX_TRANS_NAME_LEN]; void clean_client_sockets(char *path); +void gtmsecshr_exit (int exit_code, boolean_t dump); +void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len); void gtmsecshr_timer_handler(void); void gtmsecshr_signal_handler(int sig, siginfo_t *info, void *context); ZOS_ONLY(boolean_t gtm_tag_error(char *filename, int realtag, int desiredtag);) @@ -106,18 +124,24 @@ error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_GTMSECSHR); +error_def(ERR_GTMSECSHRBADDIR); error_def(ERR_GTMSECSHRCHDIRF); -error_def(ERR_GTMSECSHRDEFLOG); +error_def(ERR_GTMSECSHRDMNSTARTED); error_def(ERR_GTMSECSHRFORKF); -error_def(ERR_GTMSECSHRLOGF); -error_def(ERR_GTMSECSHRLOGSWH); +error_def(ERR_GTMSECSHRGETSEMFAIL); +error_def(ERR_GTMSECSHRISNOT); +error_def(ERR_GTMSECSHRNOARG0); error_def(ERR_GTMSECSHROPCMP); error_def(ERR_GTMSECSHRRECVF); +error_def(ERR_GTMSECSHRREMFILE); +error_def(ERR_GTMSECSHRREMSEM); +error_def(ERR_GTMSECSHRREMSEMFAIL); +error_def(ERR_GTMSECSHRREMSHM); error_def(ERR_GTMSECSHRSCKSEL); +error_def(ERR_GTMSECSHRSEMGET); error_def(ERR_GTMSECSHRSENDF); -error_def(ERR_GTMSECSHRSGIDF); +error_def(ERR_GTMSECSHRSHMCONCPROC); error_def(ERR_GTMSECSHRSOCKET); -error_def(ERR_GTMSECSHRSRVF); error_def(ERR_GTMSECSHRSRVFID); error_def(ERR_GTMSECSHRSRVFIL); error_def(ERR_GTMSECSHRSSIDF); @@ -125,10 +149,11 @@ error_def(ERR_GTMSECSHRSTART); error_def(ERR_GTMSECSHRSUIDF); error_def(ERR_GTMSECSHRTMOUT); error_def(ERR_GTMSECSHRTMPPATH); -error_def(ERR_LOGTOOLONG); +error_def(ERR_GTMSECSHRUPDDBHDR); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); /* Note that this condition handler is not really properly setup as a condition handler @@ -138,6 +163,7 @@ error_def(ERR_TEXT); */ CONDITION_HANDLER(gtmsecshr_cond_hndlr) { + START_CH; gtmsecshr_exit(arg, DUMPABLE ? TRUE : FALSE); } @@ -146,8 +172,8 @@ CONDITION_HANDLER(gtmsecshr_cond_hndlr) */ void clean_client_sockets(char *path) { - char last, suffix; - int len; + char last, suffix; + int len; len = STRLEN(path); last = path[len - 1]; @@ -166,26 +192,29 @@ uint4 have_crit(uint4 crit_state) { return 0; } -/* For gtmsecshr, override this routine so no fork is done */ +/* For gtmsecshr, no forking but still allow to create a core */ void gtm_fork_n_core(void) -{ +{ /* Should we switch to an otherwise unpriv'd id of some sort and chdir to create the core + * in say $gtm_dist ? + */ + DUMP_CORE; } -int main(void) +/* Main gtmsecshr entry point. + * + * Note the functions in util_output know the caller is gtmsecshr so ALL messages flushed through it + * automatically go to syslog. There is no flat-file logging. + */ +int main(int argc, char_ptr_t argv[]) { - int serv_fail = 0; int selstat; - int loop_limit = 0; int save_errno; - int mesg_len; - int recd, sent; - int recv_len, send_len; int recv_complete, send_complete; - int num_chars_recd, num_chars_sent; + int num_chars_recd, num_chars_sent, rundir_len; int4 msec_timeout; /* timeout in milliseconds */ TID timer_id; GTM_SOCKLEN_TYPE client_addr_len; - char *recv_ptr, *send_ptr; + char *recv_ptr, *send_ptr, *rundir; fd_set wait_on_fd; struct sockaddr_un client_addr; struct timeval input_timeval; @@ -193,120 +222,89 @@ int main(void) DCL_THREADGBL_ACCESS; GTM_THREADGBL_INIT; - gtm_imagetype_init(GTMSECSHR_IMAGE); /* Side-effect : Sets skip_dbtriggers to TRUE for trigger non-supporting platforms */ + gtm_imagetype_init(GTMSECSHR_IMAGE); /* Side-effect : Sets skip_dbtriggers = TRUE if platorm lacks trigger support */ gtm_wcswidth_fnptr = NULL; - gtm_env_init(); /* read in all environment variables */ + gtm_env_init(); /* read in all environment variables */ err_init(gtmsecshr_cond_hndlr); - gtmsecshr_init(); - input_timeval.tv_sec = MAX_TIMEOUT_VALUE; - input_timeval.tv_usec = 0; + gtmsecshr_init(argv, &rundir, &rundir_len); timer_id = (TID)main; - while (!loop_limit) + while (TRUE) { + input_timeval.tv_sec = MAX_TIMEOUT_VALUE; /* Restart timeout each interation for platforms that save + * unexpired time when select exits. + */ + input_timeval.tv_usec = 0; FD_ZERO(&wait_on_fd); FD_SET(gtmsecshr_sockfd, &wait_on_fd); - gtmsecshr_timer_popped = FALSE; - if (times_to_switch_log_file > 0) - { - gtmsecshr_switch_log_file(0); - times_to_switch_log_file = 0; - } - ready_to_switch_log_file = TRUE; - SELECT(gtmsecshr_sockfd+1, (void *)&wait_on_fd, (void *)NULL, (void *)NULL, &input_timeval, selstat); - ready_to_switch_log_file = FALSE; + SELECT(gtmsecshr_sockfd+1, (void *)&wait_on_fd, NULL, NULL, &input_timeval, selstat); if (0 > selstat) - rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSCKSEL, 0, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSCKSEL, 0, errno); else if (0 == selstat) { - gtm_putmsg(VARLSTCNT(1) ERR_GTMSECSHRTMOUT); - loop_limit = 1; - gtmsecshr_exit(0,0); /* doesn't return */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRTMOUT); + gtmsecshr_exit(0, 0); /* Doesn't return */ } - recd = 0; - mesg_len = 0; recv_ptr = (char *)&mesg; - recv_len = SIZEOF(mesg); - recv_complete = 0; client_addr_len = SIZEOF(struct sockaddr_un); msec_timeout = timeout2msec(GTMSECSHR_MESG_TIMEOUT); + DBGGSSHR((LOGFLAGS, "gtmsecshr: Select rc = %d message timeout = %d\n", selstat, msec_timeout)); start_timer(timer_id, msec_timeout, gtmsecshr_timer_handler, 0, NULL); - while (!recv_complete) - { - num_chars_recd = (int)(RECVFROM(gtmsecshr_sockfd, (void *)recv_ptr, recv_len, 0, + recv_complete = FALSE; + do + { /* Note RECVFROM does not loop on EINTR return codes so must be handled */ + num_chars_recd = (int)(RECVFROM(gtmsecshr_sockfd, (void *)recv_ptr, SIZEOF(mesg), 0, (struct sockaddr *)&client_addr, &client_addr_len)); - if ((-1 == num_chars_recd) && (gtmsecshr_timer_popped || EINTR != errno)) - { - rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRRECVF, 0, errno); - assert(FALSE); /* the above rts_error should never return */ - } else if (0 == num_chars_recd) - recv_complete = 1; - else - { - recd += num_chars_recd; - if ((0 == mesg_len) && (SIZEOF(int) <= recd)) - mesg_len = mesg.len; - if (recd == mesg_len) - recv_complete = 1; - else - { - recv_ptr += num_chars_recd; - recv_len -= num_chars_recd; - } - } - } + save_errno = errno; + DBGGSSHR((LOGFLAGS, "gtmsecshr: timer-popped: %d RECVFROM rc = %d errno = %d (only relevant if rc = " + "-1)\n", gtmsecshr_timer_popped, num_chars_recd, save_errno)); + if ((0 >= num_chars_recd) && (gtmsecshr_timer_popped || EINTR != save_errno)) + /* Note error includes 0 return from UDP read - should never be possible with UDP */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1, + process_id, ERR_GTMSECSHRRECVF, 0, save_errno); + if (0 < num_chars_recd) + recv_complete = TRUE; /* Only complete messages received via UDP datagram */ + } while (!recv_complete); cancel_timer(timer_id); - - sent = send_complete = 0; - serv_fail = service_request(&mesg); - send_len = mesg_len = mesg.len; /* We may not need to send same message size. Only return code is enough ??? */ - send_ptr = (char *)&mesg; - msec_timeout = timeout2msec(GTMSECSHR_MESG_TIMEOUT); - start_timer(timer_id, msec_timeout, gtmsecshr_timer_handler, 0, NULL); - while (!send_complete) - { - num_chars_sent = (int)(SENDTO(gtmsecshr_sockfd, send_ptr, send_len, 0, - (struct sockaddr *)&client_addr, (GTM_SOCKLEN_TYPE)client_addr_len)); - if ((-1 == num_chars_sent) && (gtmsecshr_timer_popped || errno != EINTR)) + assert(0 < num_chars_recd); + service_request(&mesg, num_chars_recd, rundir, rundir_len); + DBGGSSHR((LOGFLAGS, "gtmsecshr: service request complete - return code: %d\n", mesg.code)); + if (INVALID_COMMAND != mesg.code) + { /* Reply if code not overridden to mean no acknowledgement required */ + send_ptr = (char *)&mesg; + msec_timeout = timeout2msec(GTMSECSHR_MESG_TIMEOUT); + start_timer(timer_id, msec_timeout, gtmsecshr_timer_handler, 0, NULL); + send_complete = FALSE; + do { - rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSENDF, 0, errno); - send_complete = 1; - } else - { - sent += num_chars_sent; - if (sent == mesg_len) - send_complete = 1; - else - { - send_ptr += num_chars_sent; - send_len -= num_chars_sent; - } - } - } - cancel_timer(timer_id); - - /* Note: The condition serv_fail should happen only when gtmsecshr does - * not have permission to service a request and should happen only when - * the gtmsecshr is not installed set-uid to root. - */ - if (serv_fail) - gtmsecshr_exit(serv_fail, FALSE); - + num_chars_sent = (int)(SENDTO(gtmsecshr_sockfd, send_ptr, GTM_MESG_HDR_SIZE, 0, + (struct sockaddr *)&client_addr, (GTM_SOCKLEN_TYPE)client_addr_len)); + save_errno = errno; + DBGGSSHR((LOGFLAGS, "gtmsecshr: timer-popped: %d SENDTO rc = %d errno = %d (only relevant if " + "rc = -1)\n", gtmsecshr_timer_popped, num_chars_recd, save_errno)); + if ((0 >= num_chars_sent) && (gtmsecshr_timer_popped || save_errno != EINTR)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1, + process_id, ERR_GTMSECSHRSENDF, 0, save_errno); + if (0 < num_chars_sent) + send_complete = TRUE; + } while (!send_complete); + cancel_timer(timer_id); + } else + DBGGSSHR((LOGFLAGS, "gtmsecshr: SENDTO reply skipped due to mesg.code = INVALID_COMMAND\n")); assert('a' > 'F' && 'a' > '9'); if ('a' <= client_addr.sun_path[strlen(client_addr.sun_path) - 1]) clean_client_sockets(client_addr.sun_path); } } -void gtmsecshr_init(void) +void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len) { int file_des, save_errno, len = 0; int create_attempts = 0; int secshr_sem; - int semop_res; - char *name_ptr; - now_t now; /* for GET_CUR_TIME macro */ - char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ + int semop_res, rndirln, modlen; + char *name_ptr, *rndir, *cp, realpathbef[GTM_PATH_MAX], *realpathaft, gtmdist[GTM_PATH_MAX]; + char *path, *chrrv, *envvarnm; pid_t pid; struct sembuf sop[4]; gtmsecshr_mesg mesg; @@ -315,39 +313,207 @@ void gtmsecshr_init(void) int rc; int lib_gid; struct stat dist_stat_buff; +# ifdef _AIX + FILE *envfile; + int recnum, reclen; + char *fgets_rc, *newtz; + boolean_t tzfnd; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; process_id = getpid(); set_blocksig(); + /* Before priv escalation need to understand how/where we were invoked in terms of module path and name. + * + * Steps: + * + * 1. Verify we are "gtmsecshr" and not a module renamed for some other purpose. + * 2. Verify current working dir is $gtm_dist/gtmsecshrdir. + * 3. Verify we are loaded from $gtm_dist (a pretense setup by the wrapper). + * + * Note when/if this module merges with its wrapper, step 2 should be modified to that extent. Note our dependence + * on argv[0] for correct startup directory may preclude getting rid of the wrapper. The execl*() functions allow + * an invocation dir to be specified that has little to nothing to do with the actual invocation. + */ + + /* Step 1 */ + rndir = argv[0]; + rndirln = STRLEN(rndir); + if (0 == rndirln) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRNOARG0); + gtmsecshr_exit(UNABLETODETERMINEPATH, FALSE); + } + for (cp = rndir + rndirln - 1; cp >= rndir; cp--) + { + if ('/' == *cp) + break; + } + cp++; /* Bump back past the '/' */ + modlen = (rndir + rndirln) - cp; + if ((STRLEN(execname) != modlen) || (0 != memcmp(execname, cp, modlen))) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRISNOT, 2, modlen, cp); + gtmsecshr_exit(NOTGTMSECSHR, FALSE); + } + rndirln = rndirln - modlen - 1; + /* Step 2 */ + realpathaft = malloc(GTM_PATH_MAX); /* Malloc space as this dir is used later during message validations */ + memcpy(realpathbef, rndir, rndirln); /* Need to copy before we modify it */ + realpathbef[rndirln] = '\0'; /* Terminate directory string (executable/dir name already checked) */ + chrrv = realpath(realpathbef, realpathaft); /* Normalize dir name - eliminate all symlinks */ + if (NULL == chrrv) + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRISNOT, 0, save_errno); + gtmsecshr_exit(NOTGTMSECSHR, FALSE); + } + rndirln = STRLEN(realpathaft); /* Record (new) length now that realpath has normalized the path */ + /* Temporaryily add gtmsecshrdir to exec path for verification purposes */ + memcpy(realpathaft + rndirln, GTMSECSHR_DIR_SUFFIX, SIZEOF(GTMSECSHR_DIR_SUFFIX)); /* includes null terminator */ + chrrv = getcwd(gtmdist, GTM_PATH_MAX); /* Use gtmdist 'cause it's convenient */ + if ((NULL == chrrv) || (0 != strncmp(gtmdist, realpathaft, GTM_PATH_MAX))) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR); + gtmsecshr_exit(BADGTMDISTDIR, FALSE); + } + realpathaft[rndirln] = '\0'; /* Remove gtmsecshrdir part - Put it back to supplied path ($gtm_dist) */ + *rundir = realpathaft; /* This value for $gtm_dist is used in later validations */ + *rundir_len = rndirln; /* .. and can be used either with this len or NULL char terminator */ + /* Step 3 */ + envvarnm = GTM_DIST_LOG; + path = GETENV(++envvarnm); /* Retrieve value for $gtm_dist (bumping ptr past the '$' for getenv)*/ + chrrv = realpath(path, gtmdist); + if ((NULL == chrrv) || (0 != strncmp(realpathaft, gtmdist, GTM_PATH_MAX))) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR); + gtmsecshr_exit(BADGTMDISTDIR, FALSE); + } +# ifdef _AIX + /* Note time is handled very oddly on AIX. If one undefines the TZ environment variable (such as our wrapper does to + * prevent reporting time in the timezone of the process that started gtmsecshr, process time reverts to GMT. So to + * prevent that, lookup the default timezone in /etc/environment and use it to prevent whacky time reporting by + * gtmsecshr in the operator log. Secure file read method is to switch dir first, then do relative open. + */ + if (-1 == CHDIR("/etc")) /* Note chdir is changed again below so this is only temporary */ + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, + 2, RTS_ERROR_LITERAL("Error during chdir to /etc - TZ cannot be determined"), save_errno); + } else + { + envfile = fopen("environment", "r"); + if (NULL == envfile) + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Failed to read /etc/environment - TZ cannot be determined"), save_errno); + } else + { /* /etc/environments is open, locate TZ= record */ + tzfnd = FALSE; + for (recnum = 0; ; recnum++) + { /* Reuse realpathbef as it is not otherwise needed any longer */ + FGETS(realpathbef, GTM_PATH_MAX, envfile, fgets_rc); + if (NULL == fgets_rc) + break; + if (STRLEN(TZLOCATOR) >= (reclen = STRLEN(realpathbef))) + continue; + if (0 == memcmp(TZLOCATOR, realpathbef, STRLEN(TZLOCATOR))) + { + tzfnd = TRUE; + break; + } + } + if (!tzfnd) + { /* We didn't find the TZ record - report it depending if we just hit EOF or something more + * severe. + */ + if (!feof(envfile)) + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error reading /etc/environment - TZ cannot be determined"), + save_errno); + } else + /* Have EOF - didn't find TZ */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("TZ cannot be determined")); + } else + { /* TZ record acquired - isolate TZ - malloc space to put it once determine exact length */ + if (NEWLINE == realpathbef[reclen - 1]) + 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) + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("TZ reset with putenv() failed"), save_errno); + } + } + fclose(envfile); + } + } +# endif /* _AIX */ + /* + **** With invocation validated, begin our priviledge escalation **** + */ if (-1 == setuid(ROOTUID)) { - send_msg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRSUIDF, 0, ERR_GTMSECSHROPCMP, 0, errno); + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRSUIDF, 0, ERR_GTMSECSHROPCMP, 0, save_errno); gtmsecshr_exit(SETUIDROOT, FALSE); } + /* Before we fork, close the system log because when the facility name disappears in this middle-process, + * the logging capability disappears on some systems too - On others, it takes the executable name instead. + * Either one causes our tests to fail. + */ + DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); + CLOSELOG(); + ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); + first_syslog = TRUE; + FORK(pid); /* Timers have not been initialized, no need to do FORK_CLEAN; BYPASSOK */ + if (0 > pid) + { /* Fork failed */ + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRFORKF, 0, save_errno); + exit(GNDCHLDFORKFLD); + } else if (0 < pid) + /* This is the original process - it dies quietly (no exit handler of any sort) to isolate us */ + _exit(EXIT_SUCCESS); + /****** We are now in the (isolated) child process ******/ + process_id = getpid(); pid = getsid(process_id); if ((pid != process_id) && ((pid_t)-1 == setsid())) { save_errno = errno; - send_msg(VARLSTCNT(8) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRSSIDF, 0, save_errno); + DEBUG_ONLY(util_out_print("expected sid !UL but have !UL", OPER, process_id, pid)); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRSSIDF, 0, save_errno); } - gtmsecshr_open_log_file(); - pid = fork(); /* timers have not been initialized, no need to do FORK_CLEAN; BYPASSOK */ - if (0 > pid) - { - save_errno = errno; - send_msg(VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRFORKF, 0, save_errno); - gtm_putmsg(VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRFORKF, 0, save_errno); - exit (GNDCHLDFORKFLD); - } else if (0 < pid) - exit(0); - process_id = getpid(); - GET_CUR_TIME; - util_out_print("gtmsecshr started at !AD", TRUE, RTS_ERROR_STRING(time_ptr)); - gtmsecshr_sig_init(); - CLOSEFILE(0, rc); + /* 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 */ + /* 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. + */ + sig_init(gtmsecshr_signal_handler, NULL, NULL, NULL); file_des = sysconf(_SC_OPEN_MAX); for (file_des = file_des - 1; file_des >= 3; file_des--) { /* Close the file only if we have it open. This is to avoid a CLOSEFAIL error in case of @@ -355,29 +521,24 @@ void gtmsecshr_init(void) */ CLOSEFILE_IF_OPEN(file_des, rc); } - if (-1 == CHDIR(P_tmpdir)) + if (-1 == CHDIR(P_tmpdir)) /* Switch to temporary directory as CWD */ { save_errno = errno; - send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRCHDIRF, 2, LEN_AND_STR(P_tmpdir), save_errno); - gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_GTMSECSHRCHDIRF, 2, LEN_AND_STR(P_tmpdir), save_errno); - exit (UNABLETOCHDIR); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRCHDIRF, 2, LEN_AND_STR(P_tmpdir), save_errno); + exit(UNABLETOCHDIR); } umask(0); - if (gtmsecshr_pathname_init(SERVER) != 0) - { - send_msg(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server path"), process_id); - rts_error(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server path"), process_id); - } + if (0 != gtmsecshr_pathname_init(SERVER, *rundir, *rundir_len)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server path"), process_id); if (-1 == (secshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_NOWAIT))) { secshr_sem = INVALID_SEMID; - if (ENOENT != errno || /* below will fail otherwise */ - -1 == (secshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT | IPC_NOWAIT | IPC_EXCL))) + if ((ENOENT != errno) || /* Below will fail otherwise */ + (-1 == (secshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT | IPC_NOWAIT | IPC_EXCL)))) { secshr_sem = INVALID_SEMID; - util_out_print("semget error errno = !UL", TRUE, errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRSEMGET, 1, errno); gtmsecshr_exit(SEMGETERROR, FALSE); } } @@ -390,61 +551,62 @@ void gtmsecshr_init(void) SEMOP(secshr_sem, sop, 2, semop_res, NO_WAIT); if (0 > semop_res) { - send_msg(VARLSTCNT(10) MAKE_MSG_SEVERE(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("server already running"), errno); - /* if gtm_tmp is not defined, show default path */ - if (gtm_tmp_ptr = GETENV("gtm_tmp")) - send_msg(VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT(gtm_tmp_ptr), - ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)")); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_SEVERE(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("server already running"), errno); + /* If gtm_tmp is not defined, show default path */ + if (gtm_tmp_ptr = GETENV("gtm_tmp")) /* Warning - assignment */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, + RTS_ERROR_TEXT(gtm_tmp_ptr), ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)")); else - send_msg(VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp")); - util_out_print("A gtmsecshr server is already running - exiting", TRUE); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp")); gtmsecshr_exit(SEMAPHORETAKEN, FALSE); } - if (gtmsecshr_sock_init(SERVER) != 0) - { - send_msg(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server"), process_id); - rts_error(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server"), process_id); - } + if (0 != gtmsecshr_sock_init(SERVER)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server"), process_id); if (-1 == Stat(gtmsecshr_sock_name.sun_path, &stat_buf)) - gtm_putmsg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get status of socket file"), errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to get status of socket file"), errno); /* Get the distribution group */ lib_gid = gtm_get_group_id(&dist_stat_buff); - /* if it is world accessible then make mode 666 */ + /* If it is world accessible then make mode 666 */ if ((-1 != lib_gid) && (dist_stat_buff.st_mode & 04)) lib_gid = -1; if (-1 == lib_gid) stat_buf.st_mode = 0666; else { - /* change group if different from current user group */ + /* Change group if different from current user group */ if (lib_gid != GETGID() && (-1 == CHOWN(gtmsecshr_sock_name.sun_path, -1, lib_gid))) - { - gtm_putmsg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, - RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Unable to change socket file group"), errno); - } - /* change mode to 660 */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to change socket file group"), errno); stat_buf.st_mode = 0660; } if (-1 == CHMOD(gtmsecshr_sock_name.sun_path, stat_buf.st_mode)) - gtm_putmsg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to change socket file permisions"), errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, + RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to change socket file permisions"), errno); name_ptr = strrchr(gtmsecshr_sock_name.sun_path, '/'); while (*name_ptr == '/') /* back off in case of double-slash */ name_ptr--; gtmsecshr_socket_dir_len = (int)(name_ptr - gtmsecshr_sock_name.sun_path + 1); /* Preallocate some timer blocks. */ - prealloc_gt_timers(); + prealloc_gt_timers(); /* Note we do NOT call gt_timers_add_safe_hndlrs here - don't need them or their baggage */ + /* Create communication key used in all gtmsecshr messages. Key's purpose is to eliminate cross-version + * communication issues. + */ + STR_HASH((char *)gtm_release_name, gtm_release_name_len, TREF(gtmsecshr_comkey), 0); + /* Initialization complete */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRDMNSTARTED, 5, + gtmsecshr_key, gtm_release_name_len, gtm_release_name, *rundir_len, *rundir); return; } -void gtmsecshr_exit (int exit_code, boolean_t dump) +void gtmsecshr_exit(int exit_code, boolean_t dump) { int gtmsecshr_sem; - now_t now; /* for GET_CUR_TIME macro */ - char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ if (dump) DUMP_CORE; @@ -455,172 +617,15 @@ void gtmsecshr_exit (int exit_code, boolean_t dump) if (-1 == (gtmsecshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_NOWAIT))) { gtmsecshr_sem = INVALID_SEMID; - util_out_print("error getting semaphore errno = !UL", TRUE, errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRGETSEMFAIL, 1, errno); } if (-1 == semctl(gtmsecshr_sem, 0, IPC_RMID, 0)) - util_out_print("error removing semaphore errno = !UL", TRUE, errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRREMSEMFAIL, 1, errno); } - util_out_print("", TRUE); - GET_CUR_TIME; - util_out_print("gtmsecshr exited on !AD", TRUE, RTS_ERROR_STRING(time_ptr)); - util_out_close(); + /* Note shutdown message taken care of by generic_signal_handler */ exit(exit_code); } -int gtmsecshr_open_log_file (void) -{ - struct stat buf; - int save_errno = 0, status; - char gtmsecshr_path[MAX_TRANS_NAME_LEN], *error_mesg; - mstr gtmsecshr_lognam, gtmsecshr_transnam; -# ifdef __MVS__ - int create_logfile = 0, realfiletag; -# endif - - gtmsecshr_lognam.addr = GTMSECSHR_LOG_DIR; - gtmsecshr_lognam.len = SIZEOF(GTMSECSHR_LOG_DIR) - 1; - status = TRANS_LOG_NAME(>msecshr_lognam, >msecshr_transnam, gtmsecshr_logpath, SIZEOF(gtmsecshr_logpath), - dont_sendmsg_on_log2long); - if ((SS_NORMAL != status) || !ABSOLUTE_PATH(gtmsecshr_logpath)) - { /* gtm_log not defined or not defined to absolute path, use default gtm_log - * This is not considered error, just informational - */ - if (SS_LOG2LONG == status) - send_msg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtmsecshr_lognam.len, gtmsecshr_lognam.addr, - SIZEOF(gtmsecshr_logpath) - 1); - send_msg(VARLSTCNT(4) ERR_GTMSECSHRDEFLOG, 2, RTS_ERROR_TEXT(DEFAULT_GTMSECSHR_LOG_DIR)); - strcpy(gtmsecshr_logpath, DEFAULT_GTMSECSHR_LOG_DIR); - gtmsecshr_logpath_len = SIZEOF(DEFAULT_GTMSECSHR_LOG_DIR) - 1; - } else - gtmsecshr_logpath_len = gtmsecshr_transnam.len; - if (-1 == Stat(gtmsecshr_logpath, &buf)) - { - save_errno = errno; - send_msg(VARLSTCNT(14) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_TEXT("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_TEXT("Unable to locate default log directory"), ERR_TEXT, 2, - RTS_ERROR_STRING(gtmsecshr_logpath), save_errno); - exit(UNABLETOOPNLOGFILEFTL); - } else if (!S_ISDIR(buf.st_mode)) - { - send_msg(VARLSTCNT(13) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("$gtm_log not a directory"), ERR_TEXT, 2, - RTS_ERROR_STRING(gtmsecshr_logpath)); - exit(UNABLETOOPNLOGFILEFTL); - } - if (gtmsecshr_logpath[gtmsecshr_logpath_len - 1] != '/') - gtmsecshr_logpath[gtmsecshr_logpath_len++] = '/'; - strcpy(gtmsecshr_logpath + gtmsecshr_logpath_len , GTMSECSHR_LOG_PREFIX); -# if defined(__MVS__) - if (-1 == Stat(gtmsecshr_logpath, &buf)) - create_logfile = 1; -# endif - if (0 > (gtmsecshr_log_file = OPEN3(gtmsecshr_logpath, O_RDWR|O_CREAT|O_APPEND, GTMSECSHR_PERMS))) - { - send_msg(VARLSTCNT(14) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("gtmsecshr unable to open log file"), - ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_logpath), errno); - exit(UNABLETOOPNLOGFILEFTL); - } -# if defined(__MVS__) - if ((1 == create_logfile) && (-1 == gtm_zos_set_tag(gtmsecshr_log_file, TAG_EBCDIC, TAG_TEXT, TAG_FORCE, &realfiletag))) - gtm_tag_error(gtmsecshr_logpath, realfiletag, TAG_EBCDIC); - else if (!gtm_zos_autocvt_enabled()) - { - send_msg(VARLSTCNT(14) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("_BPXK_AUTOCVT='ON' not set, policy tagging the log file"), - ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_logpath), errno); - if (-1 == gtm_zos_tag_to_policy(gtmsecshr_log_file, TAG_UNTAGGED, &realfiletag)) - gtm_tag_error(gtmsecshr_logpath, realfiletag, TAG_UNTAGGED); - } -# endif - assert(0 <= gtmsecshr_log_file); - if (-1 == dup2(gtmsecshr_log_file, 1)) - { - send_msg(VARLSTCNT(10) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Unable to dup standard out"), errno); - exit(UNABLETODUPLOG); - } - if (-1 == dup2(gtmsecshr_log_file, 2)) - { - send_msg(VARLSTCNT(10) ERR_GTMSECSHRLOGF, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Unable to dup standard error"), errno); - exit(UNABLETODUPLOG); - } - return 0; -} - -void gtmsecshr_switch_log_file(int sig) -{ - now_t now; /* for GET_CUR_TIME macro */ - char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ - char newname[MAX_TRANS_NAME_LEN], *err_msg; - struct tm *tm_struct; - size_t dummy; - struct stat fs; - int newname_len, suffix, save_errno, temp_fd, rc; - ZOS_ONLY(int realfiletag;) - - assert((SIGHUP == sig) || (0 == sig)); /* sig could be either SIGHUP or 0 */ - assert((SIGHUP == sig) || (!ready_to_switch_log_file)); - - if ((SIGHUP == sig) && (!ready_to_switch_log_file)) - { - times_to_switch_log_file++; - return; - } - /* --- log this switching action in the old log file --- */ - GET_CUR_TIME; - util_out_print("!/gtmsecshr log was switched from this file at !AD -- process id !UL", - TRUE, RTS_ERROR_STRING(time_ptr), process_id); - /* --- construct a name for the old gtmsecshr log file --- */ - strcpy(newname, gtmsecshr_logpath); - if (((time_t)-1 == (now = time(NULL))) || (!(tm_struct = localtime(&now)))) - { - SPRINTF(&newname[gtmsecshr_logpath_len + SIZEOF(GTMSECSHR_LOG_PREFIX) - 1], - ".timerrno%d", errno); - } else - { - STRFTIME(&newname[gtmsecshr_logpath_len + SIZEOF(GTMSECSHR_LOG_PREFIX) - 1], - MAX_TRANS_NAME_LEN - gtmsecshr_logpath_len - SIZEOF(GTMSECSHR_LOG_PREFIX), - TIME_FORMAT, tm_struct, dummy); - } - newname_len = STRLEN(newname); - suffix = 1; - while ((0 == Stat(newname, &fs)) || (ENOENT != errno)) /* This file exists */ - { - SPRINTF(&newname[newname_len], ".%d", suffix); - suffix++; - } - /* --- switch to use the new log file --- */ - if ((-1 == RENAME(gtmsecshr_logpath, &newname[0])) - || (FD_INVALID == (temp_fd = OPEN3(gtmsecshr_logpath, O_RDWR | O_CREAT | O_APPEND, GTMSECSHR_PERMS))) - || (-1 == dup2(temp_fd, gtmsecshr_log_file)) -# if defined(__MVS__) - || (-1 == gtm_zos_set_tag(temp_fd, TAG_EBCDIC, TAG_TEXT, TAG_FORCE, &realfiletag) - && gtm_tag_error(gtmsecshr_logpath, realfiletag, TAG_EBCDIC)) - || ((!gtm_zos_autocvt_enabled()) && ((-1 == gtm_zos_tag_to_policy(gtmsecshr_log_file, TAG_UNTAGGED, &realfiletag)) - && gtm_tag_error(gtmsecshr_logpath, realfiletag, TAG_UNTAGGED))) -# endif - || (-1 == dup2(temp_fd, 1)) - || (-1 == dup2(temp_fd, 2))) - { - save_errno = errno; - send_msg(VARLSTCNT(14) ERR_GTMSECSHRLOGSWH, 7, RTS_ERROR_STRING(gtmsecshr_logpath), - RTS_ERROR_STRING(&newname[0]), RTS_ERROR_LITERAL("rename"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Recycling gtmsecshr is suggested."), save_errno); - gtm_putmsg(VARLSTCNT(14) ERR_GTMSECSHRLOGSWH, 7, RTS_ERROR_STRING(gtmsecshr_logpath), - RTS_ERROR_STRING(&newname[0]), RTS_ERROR_LITERAL("rename"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Recycling gtmsecshr is suggested."), save_errno); - return; - } - CLOSEFILE_RESET(gtmsecshr_log_file, rc); /* resets "gtmsecshr_log_file" to FD_INVALID */ - gtmsecshr_log_file = temp_fd; - /* --- log this switching action in the new log file --- */ - GET_CUR_TIME; - util_out_print("!/gtmsecshr log was switched to this file at !AD -- process id !UL", - TRUE, RTS_ERROR_STRING(time_ptr), process_id); -} - void gtmsecshr_timer_handler(void) { gtmsecshr_timer_popped = TRUE; @@ -628,8 +633,6 @@ void gtmsecshr_timer_handler(void) void gtmsecshr_signal_handler(int sig, siginfo_t *info, void *context) { - boolean_t process_signal(enum gtmImageTypes, int, siginfo_t *, void *); - /* Do standard signal handling */ (void)generic_signal_handler(sig, info, context); /* Note that we are not letting process_signal run gtm_fork_n_core. In testing, @@ -640,238 +643,486 @@ void gtmsecshr_signal_handler(int sig, siginfo_t *info, void *context) gtmsecshr_exit(sig, need_core); } -void gtmsecshr_sig_init(void) +void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_len) { - struct sigaction act; - - sig_init(gtmsecshr_signal_handler, gtmsecshr_signal_handler, suspsigs_handler); - /* Redefine handler for SIGHUP to switch log file */ - memset(&act, 0, SIZEOF(act)); - act.sa_handler = gtmsecshr_switch_log_file; - sigaction(SIGHUP, &act, 0); -} - -int service_request(gtmsecshr_mesg *buf) -{ - int ret_status = 0; int fn_len, index, basind, save_errno, save_code; - int stat_res; - now_t now; /* for GET_CUR_TIME macro */ - char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ + int stat_res, fd; char *basnam, *fn; struct shmid_ds temp_shmctl_buf; struct stat statbuf; sgmnt_data header; + endian32_struct check_endian; + char *intent; + ZOS_ONLY(int realfiletag;) + DCL_THREADGBL_ACCESS; - GET_CUR_TIME; + SETUP_THREADGBL_ACCESS; save_code = buf->code; + /* First up, validate the communication key for this gtmsecshr version */ + if (TREF(gtmsecshr_comkey) != buf->comkey) + { + buf->code = INVALID_COMKEY; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Comkey not correct for this gtmsecshr version")); + return; + } + /* Process code (with code specific valications) */ switch(buf->code) { - case WAKE_MESSAGE: - if (buf->code = (-1 == kill((pid_t )buf->mesg.id, SIGALRM)) ? errno : 0) - { - save_errno = errno; - send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to wake up process"), save_errno); - util_out_print("!AD [client pid !UL]", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid); - gtm_putmsg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to wake up process"), save_errno); - } - DEBUG_ONLY( - else - util_out_print("!AD [client pid !UL] Process !UL was awakened", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid, - buf->mesg.id); - ) - break ; - case REMOVE_SEM: - buf->code = ( -1 == semctl((int )buf->mesg.id, 0, IPC_RMID, 0)) ? errno : 0; - if (!buf->code) - util_out_print("!AD [client pid !UL] Semaphore (!UL) removed", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid, - buf->mesg.id); - else - { - send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove semaphore"), buf->code); - gtm_putmsg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove semaphore"), buf->code); - } - break; - case REMOVE_SHMMEM: - buf->code = (-1 == shmctl((int )buf->mesg.id, IPC_STAT, &temp_shmctl_buf)) ? errno : 0; - if (buf->code) - { - send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get shared memory statistics"), buf->code); - gtm_putmsg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get shared memory statistics"), buf->code); - break; - } - else if (1 < temp_shmctl_buf.shm_nattch) - { - util_out_print("More than one process attached to Shared memory segment (!UL) not removed (!UL)", TRUE, - buf->mesg.id, temp_shmctl_buf.shm_nattch); - buf->code = EBUSY; - break; - } - buf->code = (-1 == shmctl((int )buf->mesg.id, IPC_RMID, 0)) ? errno : 0; - if (!buf->code) - util_out_print("!AD [client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", TRUE, - CTIME_BEFORE_NL, time_ptr, buf->pid, buf->mesg.id, temp_shmctl_buf.shm_nattch); - else - { - send_msg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove shared memory segment"), buf->code); - gtm_putmsg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove shared memory segment"), buf->code); - } - break; - case REMOVE_FILE : -# ifndef MUTEX_MSEM_WAKE - for (index = 0; index < SIZEOF(buf->mesg.path); index++) - { - if ('\0' == buf->mesg.path[index]) - break; - } - if ((0 == index) || (index >= SIZEOF(buf->mesg.path))) - { - gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, - buf->code, index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, - buf->mesg.path, ERR_TEXT, 2, RTS_ERROR_LITERAL("no file or length too long")); - buf->code = EINVAL; - } else - { - if ('/' == buf->mesg.path[index - 1] && 1 < index) - { /* remove trailing slash unless only slash */ - buf->mesg.path[index - 1] = '\0'; - index--; - } - for (basind = index - 1; 0 <= basind; basind--) +# ifdef NOT_CURRENTLY_USED + /* Currently, M LOCK wakeup logic is disabled in the client and here. This code was not being used due to a + * requirement (and check) that crit was not being held. Since mlk_unlock()->mlk_wake_pending->crit_wake() + * runs in crit, this prevented gtmsecshr from EVER being called with this message. This code is disabled until + * the next gtmsecshr improvement phase which will modify M unLOCK logic to drive the wakeups only after the + * process has released crit. This will restore fast M LOCK wakeups for processes with a different userid than + * the current process which currently waits until a 100ms poll timer expires to retry the lock. + */ + case WAKE_MESSAGE: + /* if (0 != validate_receiver(buf, rundir, rundir_len, save_code)) + return; / * buf->code already set - to be re-enabled when routine is completed */ + if (buf->code = (-1 == kill((pid_t)buf->mesg.id, SIGALRM)) ? errno : 0) { - if ('/' == buf->mesg.path[basind]) + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to wake up process"), save_errno); + } +# ifdef DEBUG + else + /* Output msg only in DEBUG mode as these could otherwise be frequent */ + util_out_print("[client pid !UL] Process !UL was awakened", OPER, buf->pid, buf->mesg.id); +# endif + break; +# endif + case CONTINUE_PROCESS: + /* if (0 != validate_receiver(buf, rundir, rundir_len, save_code)) + return; / * buf->code already set - to be re-enabled when routine is completed */ + if (buf->code = (-1 == kill((pid_t)buf->mesg.id, SIGCONT)) ? errno : 0) + { + save_errno = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to request process to resume processing"), save_errno); + } +# ifdef DEBUG + else + /* Output msg only in DEBUG mode as these could otherwise be frequent */ + util_out_print("[client pid !UL] Process !UL was requested to resume processing", OPER, + buf->pid, buf->mesg.id); +# endif + break ; + case REMOVE_SEM: + buf->code = (-1 == semctl((int)buf->mesg.id, 0, IPC_RMID, 0)) ? errno : 0; + if (!buf->code) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRREMSEM, 2, buf->pid, buf->mesg.id); + else + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to remove semaphore"), buf->code); + } + break; + case REMOVE_SHM: + buf->code = (-1 == shmctl((int)buf->mesg.id, IPC_STAT, &temp_shmctl_buf)) ? errno : 0; + if (buf->code) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to get shared memory statistics"), buf->code); + break; + } else if (1 < temp_shmctl_buf.shm_nattch) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRSHMCONCPROC, 2, + buf->mesg.id, temp_shmctl_buf.shm_nattch); + buf->code = EBUSY; + break; + } + buf->code = (-1 == shmctl((int)buf->mesg.id, IPC_RMID, 0)) ? errno : 0; + if (!buf->code) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRREMSHM, 3, + buf->pid, buf->mesg.id, temp_shmctl_buf.shm_nattch); + else + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to remove shared memory segment"), buf->code); + } + break; +# ifndef MUTEX_MSEM_WAKE + case REMOVE_FILE : + /* This case only exists for plastforms using socket based long sleep when waiting for the + * critical section. The memory semaphore based sleeps do not use so cannot orphan this socket. + */ + for (index = 0; index < SIZEOF(buf->mesg.path); index++) + { /* Verify has null terminator within the message */ + if ('\0' == buf->mesg.path[index]) break; } - if (0 < basind || (0 == basind && '/' == buf->mesg.path[basind])) - basnam = &buf->mesg.path[basind + 1]; - else - basnam = &buf->mesg.path[0]; - STAT_FILE(buf->mesg.path, &statbuf, stat_res); - if (-1 == stat_res) + if ((0 == index) || (index >= SIZEOF(buf->mesg.path)) || (index != (msglen - GTM_MESG_HDR_SIZE - 1))) { - buf->code = errno; - gtm_putmsg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, - index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, buf->mesg.path, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get file status"), errno); -# ifndef __MVS__ - } else if (!S_ISSOCK(statbuf.st_mode)) -# else - } else if (!(S_ISSOCK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))) -# endif - { - gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, - RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, - index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, buf->mesg.path, - ERR_TEXT, 2, RTS_ERROR_LITERAL("File is not a GTM mutex socket file")); + index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, + buf->mesg.path, ERR_TEXT, 2, + RTS_ERROR_LITERAL("no file name or length too long or invalid")); buf->code = EINVAL; - } else if (0 != MEMCMP_LIT(basnam, MUTEX_SOCK_FILE_PREFIX)) - { - gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, - RTS_ERROR_LITERAL("Server"), process_id, buf->pid, - buf->code, index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, - buf->mesg.path, ERR_TEXT, 2, - RTS_ERROR_LITERAL("File name does not match the naming convention for a GT.M mutex socket file")); - buf->code = EINVAL; - } else if (0 != memcmp(gtmsecshr_sock_name.sun_path, buf->mesg.path, gtmsecshr_socket_dir_len)) - { - gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, - RTS_ERROR_LITERAL("Server"), process_id, buf->pid, - buf->code, index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index, - buf->mesg.path, ERR_TEXT, 2, - RTS_ERROR_LITERAL("File does not reside in the normal directory for a GT.M mutex socket file")); - buf->code = EINVAL; - } else if (buf->code = (-1 == UNLINK(buf->mesg.path)) ? errno : 0) - { - gtm_putmsg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_LITERAL("Server"), process_id, - buf->pid, save_code, RTS_ERROR_STRING(buf->mesg.path), - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove file"), buf->code); } else { - util_out_print("!AD [client pid !UL] File (!AD) removed", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid, - RTS_ERROR_STRING(buf->mesg.path)); + if (('/' == buf->mesg.path[index - 1]) && (1 < index)) + { /* remove trailing slash unless only slash */ + buf->mesg.path[index - 1] = '\0'; + index--; + } + for (basind = index - 1; 0 <= basind; basind--) + { + if ('/' == buf->mesg.path[basind]) + break; + } + if ((0 < basind) || ((0 == basind) && ('/' == buf->mesg.path[basind]))) + basnam = &buf->mesg.path[basind + 1]; + else + basnam = &buf->mesg.path[0]; + /* Verify: + * + * 1. File exists. + * 2. File is a socket. + * 3. Has a name prefix GT.M would use + * 4. File is resident in expected directory ($gtm_tmp or /tmp). + * + */ + STAT_FILE(buf->mesg.path, &statbuf, stat_res); + if (-1 == stat_res) + { +# ifdef DEBUG + if (buf->usesecshr && (ENOENT == errno)) + /* ALL unlinks for the mutex socket come thru here in this mode so if socket does + * not exist, just let it go. + */ + buf->code = 0; + else +# endif + { + save_errno = errno; + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, + index, buf->mesg.path, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to get file status"), save_errno); + } + } else if ((!S_ISSOCK(statbuf.st_mode)) ZOS_ONLY(|| (S_ISCHR(statbuf.st_mode)))) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, + index, buf->mesg.path, ERR_TEXT, 2, + RTS_ERROR_LITERAL("File is not a GTM mutex socket file")); + } else if (0 != MEMCMP_LIT(basnam, MUTEX_SOCK_FILE_PREFIX)) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, + index, buf->mesg.path, ERR_TEXT, 2, + RTS_ERROR_LITERAL("File name does not match the naming convention for a GT.M " + "mutex socket file")); + } else if (0 != memcmp(gtmsecshr_sock_name.sun_path, buf->mesg.path, gtmsecshr_socket_dir_len)) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, + index, buf->mesg.path, ERR_TEXT, 2, + RTS_ERROR_LITERAL("File does not reside in the normal directory for a GT.M " + "mutex socket file")); + } else if (buf->code = (-1 == UNLINK(buf->mesg.path)) ? errno : 0) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, + RTS_ERROR_STRING(buf->mesg.path), ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to remove file"), buf->code); + } else + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRREMFILE, 3, + buf->pid, RTS_ERROR_STRING(buf->mesg.path)); } - } -# else - /* For platforms that use MSEMs for mutex inter process communication, mutex socket files are not used - * by GT.M so the need to remove those (i.e. using the REMOVE_FILE command should not be necessary). - */ - assert(FALSE); -# endif - break; - case CONTINUE_PROCESS: - if (buf->code = (-1 == kill((pid_t)buf->mesg.id, SIGCONT)) ? errno : 0) - { - save_errno = errno; - send_msg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to request process to resume processing"), save_errno); - util_out_print("!AD [client pid !UL]", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid); - gtm_putmsg(VARLSTCNT(13) - ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to request process to resume processing"), save_errno); - } - DEBUG_ONLY( - else - util_out_print("!AD [client pid !UL] Process !UL was requested to resume processing", TRUE, CTIME_BEFORE_NL, - time_ptr, buf->pid, buf->mesg.id); - ) - break ; - case FLUSH_DB_IPCS_INFO: - fn = buf->mesg.db_ipcs.fn; - fn_len = buf->mesg.db_ipcs.fn_len; - *(fn + fn_len) = 0; /* We assumed we have one extra byte. fn must be null terminated */ - if (!file_head_read(fn, &header, SIZEOF(header))) - { - buf->code = errno; - send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to read database file header")); break; - } - header.semid = buf->mesg.db_ipcs.semid; - header.shmid = buf->mesg.db_ipcs.shmid; - header.gt_sem_ctime.ctime = buf->mesg.db_ipcs.gt_sem_ctime; - header.gt_shm_ctime.ctime = buf->mesg.db_ipcs.gt_shm_ctime; - if (!file_head_write(fn, &header, SIZEOF(header))) - { - buf->code = errno; - send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to write database file header")); - } - util_out_print("!AD [client pid !UL] database fileheader (!AD) updated", TRUE, CTIME_BEFORE_NL, time_ptr, buf->pid, - fn_len, fn); - buf->code = 0; - break; - default: - buf->ack = ACK_NOT_REQUIRED; - send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Invalid Service Request")); - send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code, - buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Invalid Service Request")); - buf->code = 0; +# endif + case FLUSH_DB_IPCS_INFO: + /* Most of this code came from file_head_read/write.c but those routines don't follow our rules + * (no stdout/stderr IO) so we streamline it here. + */ + fn = buf->mesg.db_ipcs.fn; + fn_len = buf->mesg.db_ipcs.fn_len; + if ((GTM_PATH_MAX < fn_len) || ('\0' != *(fn + fn_len)) + || (fn_len != (msglen - GTM_MESG_HDR_SIZE - offsetof(ipcs_mesg, fn[0]) - 1))) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("invalid file name argument")); + break; + } + /* First open and read-in the fileheader */ + OPENFILE(fn, O_RDWR, fd); + if (FD_INVALID == fd) + { + save_errno = buf->code = errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, + buf->mesg.id, ERR_DBFILOPERR, 2, fn_len, fn, save_errno); + break; + } +# ifdef __MVS__ + if (-1 == gtm_zos_tag_to_policy(fd, TAG_BINARY, &realfiletag)) + TAG_POLICY_SEND_MSG(fn, errno, realfiletag, TAG_BINARY); +# endif + /* Verify is a GT.M database - validations: + * + * 1. Is a regular file (not a special type). + * 2. Is of a size at least as large as the file header (doesn't get fancy with this) + * 3. Able to read the file. + * 4. Verify tag at top of file denotes a GT.M database of the correct version. + * 5. Validate fields being set into database file (see details below). + * 6. Set the fields into the database. + * 7. Write updated database header and close the database. + */ + FSTAT_FILE(fd, &statbuf, save_errno); + if (-1 == save_errno) + { + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno); + CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */ + break; + } + if (!S_ISREG(statbuf.st_mode) || (SIZEOF(header) > statbuf.st_size)) + { + buf->code = ERR_DBNOTGDS; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn)); + CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */ + break; + } + LSEEKREAD(fd, 0, &header, SIZEOF(header), save_errno); + if (0 != save_errno) + { + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno); + CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */ + break; + } + if (0 != memcmp(header.label, GDS_LABEL, GDS_LABEL_SZ - 1)) /* Verify is GT.M database file */ + { + buf->code = ERR_DBNOTGDS; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn)); + CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */ + break; + } + /* It would be easier to use the CHECK_DB_ENDIAN macro here but we'd prefer it didn't raise rts_error */ + check_endian.word32 = header.minor_dbver; + if (!check_endian.shorts.ENDIANCHECKTHIS) + { + buf->code = ERR_DBENDIAN; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + save_code, buf->mesg.id, ERR_DBENDIAN, 4, fn_len, fn, ENDIANOTHER, ENDIANTHIS); + CLOSEFILE_RESET(fd, save_errno); + break; + } + /* Verify the fields to update make sense. + * + * 1. If new semid is INVALID_SEMID, then (file close): + * a. New shmid should be INVALID_SHMID. + * b. Both ctime fields should be zero. + * c. If current value of semid in header is INVALID_SEMID, verify the other settings are also correct + * for a closed database, close file. + * d. If current value of semid is not INVALID_SEMID, check its value - should be <= 1 else error. + * e. The current shmid should exist and have 1 attachment. + * 2. If new semid is *not* INVALID_SEMID then (file open): + * a. Initial impulse is to check that new shmid is NOT INVALID_SHMID, but in one case which we can't + * detect (standalone access of R/O DB by MUPIP INTEG and perhaps others), only the semaphore id + * and ctime are modified. The shm fields are left as is. + * b. If previous semid is not INVALID_SEMID, verify is same as we've been requested to update and close + * with an already open message. + * c. If previous semid is INVALID_SEMID, check the new semid and query its value. Should be <= 1 or + * raise error. + * d. Ditto for shmid and its attach value should also be <= 1. + * + * Note - Items 1c - 1e and items 2b - 2d not yet implemented (phase 3). + */ + if (INVALID_SEMID == buf->mesg.db_ipcs.semid) + { /* Intent is to close the given database */ + intent = intent_close; + if ((INVALID_SHMID != buf->mesg.db_ipcs.shmid) || (0 != buf->mesg.db_ipcs.gt_sem_ctime) + || (0 != buf->mesg.db_ipcs.gt_shm_ctime)) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, + buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Invalid header value combination")); + CLOSEFILE_RESET(fd, save_errno); + break; + } + } else + { /* Intent is to open the given database - Note if this is a standalone access of a read-only + * DB by such as MUPIP INTEG, only the semaphore is set, not shared memory so we must relax our + * checks a bit and allow the shm id and ctime to remain in "closed" state. But if shmid is + * specified, do validate that ctime was specified and vice-versa. + */ + intent = intent_open; + if ((0 == buf->mesg.db_ipcs.gt_sem_ctime) + || ((INVALID_SEMID == buf->mesg.db_ipcs.shmid) && (0 != buf->mesg.db_ipcs.gt_shm_ctime)) + || ((INVALID_SEMID != buf->mesg.db_ipcs.shmid) && (0 == buf->mesg.db_ipcs.gt_shm_ctime))) + { + buf->code = EINVAL; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, + buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Invalid header value combination")); + CLOSEFILE_RESET(fd, save_errno); + break; + } + } + /* Update file header fields */ + header.semid = buf->mesg.db_ipcs.semid; + header.shmid = buf->mesg.db_ipcs.shmid; + header.gt_sem_ctime.ctime = buf->mesg.db_ipcs.gt_sem_ctime; + header.gt_shm_ctime.ctime = buf->mesg.db_ipcs.gt_shm_ctime; + /* And flush the changes back out. Note this service code is only used by read-only processes so + * we don't need any anticipatory freeze insertion which anyway pulls in the world so LSEEKWRITE does + * what we need. + */ + LSEEKWRITE(fd, 0, &header, SIZEOF(header), save_errno); + if (0 != save_errno) + { + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, + buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Unable to write database file header"), save_errno); + CLOSEFILE_RESET(fd, save_errno); + break; + } + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRUPDDBHDR, 5, + buf->pid, fn_len, fn, RTS_ERROR_STRING(intent)); + buf->code = 0; + CLOSEFILE_RESET(fd, save_errno); + break; + default: + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, + buf->code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Invalid Service Request")); + buf->code = 0x8000; /* Flag for no-ack required - invalid commands get no response */ } - return ret_status; + return; +} + +/* Service request asks gtmsecshr to send a signal to a given process. Verify (as best we can) this process is running something + * related to GT.M. Two potential methods are used: + * + * 1. Target process has an execution directory the same as ours ($gtm_dist). Note it is possible a target process is doing + * a call-in so this test is not always TRUE but is the faster of the two tests. + * 2. Target process has libgtmshr.{suffix} (aka GTMSHR_IMAGE_NAME from mdefsa.h) loaded which we can tell by examining the + * open files of the target process. + * + * Note - this routine is currently NOT USED as it is incomplete and not yet implemented for all platforms. We leave it in here + * for now and plan to complete it in an upcoming version. + */ +int validate_receiver(gtmsecshr_mesg *buf, char *rundir, int rundir_len, int save_code) +{ + int save_errno; +# ifdef __linux__ +# define PROCPATH_PREFIX "/proc/" +# define PROCPATH_CMDLSUFFIX "/cmdline" +# define PROCPATH_MAPSSUFFIX "/maps" + int lnln, clrv, cmdbufln; + FILE *procstrm; + char procpath[GTM_PATH_MAX], cmdbuf[GTM_PATH_MAX], rpcmdbuf[GTM_PATH_MAX]; + char *ppptr, *ppptr_save, *csrv, *cptr; + + /* Check #1 - open /proc//cmdline, read to first NULL - this is the command name */ + ppptr = procpath; + MEMCPY_LIT(procpath, PROCPATH_PREFIX); + ppptr += STRLEN(PROCPATH_PREFIX); + ppptr = i2asc(ppptr, buf->mesg.id); + ppptr_save = ppptr; /* Save where adding cmdline so can replace if need to move to check #2 */ + memcpy(ppptr, PROCPATH_CMDLSUFFIX, SIZEOF(PROCPATH_CMDLSUFFIX)); /* Copy includes terminating null of literal */ + procstrm = Fopen(procpath, "r"); + if (NULL == procstrm) + { + save_errno = errno; + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Could not open /proc//cmdline"), save_errno); + return save_errno; + } + FGETS(cmdbuf, GTM_PATH_MAX, procstrm, csrv); + if (NULL == csrv) + { + save_errno = errno; + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Could not read /proc//cmdline"), save_errno); + return save_errno; + } + FCLOSE(procstrm, clrv); + if (-1 == clrv) + /* Not a functional issue so just warn about it in op-log */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno); + lnln = STRLEN(cmdbuf); + /* Look from the end backwards to find the last '/' to isolate the directory */ + for (cptr = cmdbuf + lnln - 1; (cptr >= cmdbuf) && ('/' != *cptr); cptr--) + ; + cmdbufln = INTCAST(cptr - cmdbuf); + if (0 < cmdbufln) + { /* Normalize the directory via realpath so comparison possible */ + cmdbuf[cmdbufln] = rpcmdbuf[0] = '\0'; + csrv = realpath(cmdbuf, rpcmdbuf); + cmdbufln = STRLEN(rpcmdbuf); + if ((cmdbufln == rundir_len) && (0 == memcmp(rundir, rpcmdbuf, cmdbufln))) + { + buf->code = 0; /* Successful validation */ + DEBUG_ONLY(util_out_print("Successful validation of target processid !UL", OPER, buf->pid)); + return 0; + } + } + /* Check #1 failed - attempt check #2 - read /proc//maps to see if libgtmshr is there */ + memcpy(ppptr_save, PROCPATH_MAPSSUFFIX, SIZEOF(PROCPATH_MAPSSUFFIX)); /* Copy includes terminating null of literal */ + procstrm = Fopen(procpath, "r"); + if (NULL == procstrm) + { + save_errno = errno; + buf->code = save_errno; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Could not open /proc//cmdline"), save_errno); + return save_errno; + } + /* Insert map reading code TODO */ + FCLOSE(procstrm, clrv); + if (-1 == clrv) + /* Not a functional issue so just warn about it in op-log */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno); +# endif + return 0; } #ifdef __MVS__ boolean_t gtm_tag_error(char *filename, int realtag, int desiredtag) { - char *errmsg = STRERROR(errno); - send_msg(VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(filename), realtag, - desiredtag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); - return 0; + char *errmsg; + + errmsg = STRERROR(errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(filename), + realtag, desiredtag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); + return FALSE; } #endif diff --git a/sr_unix/gtmsecshr.h b/sr_unix/gtmsecshr.h index 6dc3f9e..0552175 100644 --- a/sr_unix/gtmsecshr.h +++ b/sr_unix/gtmsecshr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,23 +12,32 @@ #ifndef _GTMSECSHR #define _GTMSECSHR +/* To enable debugging of gtmsecshr, uncomment #define immediately below */ +/* #define DEBUG_GTMSECSHR */ +#ifdef DEBUG_GTMSECSHR +# define LOGFLAGS (LOG_USER | LOG_INFO) +# define DBGGSSHR(x) syslog x +#else +# define DBGGSSHR(x) +#endif +#define ABSOLUTE_PATH(X) ('/' == X[0]) #define GTMSECSHR_MESG_TIMEOUT 30 #define GTMSECSHR_PERMS 0666 -/* Exit codes from gtmsecshr */ +/* Exit codes from gtmsecshr - note matching text entries are in message table in secshr_client.c */ #define NORMALEXIT 0 #define SETUIDROOT 1 -#define SETGIDROOT 2 -#define UNABLETOOPNLOGFILE 3 -#define UNABLETODUPLOG 4 -#define INVTRANSGTMSECSHR 5 -#define UNABLETOEXECGTMSECSHR 6 -#define GNDCHLDFORKFLD 7 -#define UNABLETOOPNLOGFILEFTL 8 -#define SEMGETERROR 9 -#define SEMAPHORETAKEN 10 -#define SYSLOGHASERRORDETAIL 11 -#define UNABLETOCHDIR 12 +#define INVTRANSGTMSECSHR 2 +#define UNABLETOEXECGTMSECSHR 3 +#define GNDCHLDFORKFLD 4 +#define SEMGETERROR 5 +#define SEMAPHORETAKEN 6 +#define SYSLOGHASERRORDETAIL 7 +#define UNABLETOCHDIR 8 +#define UNABLETODETERMINEPATH 9 +#define NOTGTMSECSHR 10 +#define BADGTMDISTDIR 11 +#define LASTEXITCODE 11 /* Should have same value as last error code */ /* return codes with gtmsecshr*/ #define INVLOGNAME 20 @@ -44,86 +53,88 @@ #define SERVER 0 #define CLIENT 1 -#define GTMSECSHR_LOG_DIR GTM_LOG_ENV -#define DEFAULT_GTMSECSHR_LOG_DIR DEFAULT_GTM_TMP -#define GTMSECSHR_LOG_PREFIX "gtm_secshr_log" #define GTMSECSHR_SOCK_DIR GTM_TMP_ENV #define DEFAULT_GTMSECSHR_SOCK_DIR DEFAULT_GTM_TMP #define GTMSECSHR_SOCK_PREFIX "gtm_secshr" -#define GTMSECSHR_PATH GTM_DIST_LOG "/gtmsecshr" +#define GTMSECSHR_DIR_SUFFIX "/gtmsecshrdir" +#define GTMSECSHR_EXECUTABLE "gtmsecshr" +#define GTMSECSHR_PATH GTM_DIST_LOG "/" GTMSECSHR_EXECUTABLE #define ROOTUID 0 -#define ROOTGID 0 - -#define ABSOLUTE_PATH(X) (X[0] == '/') #ifdef SHORT_GTMSECSHR_TIMEOUT -#define MAX_TIMEOUT_VALUE 30 +# define MAX_TIMEOUT_VALUE 30 #else -#define MAX_TIMEOUT_VALUE 6000 +# ifdef DEBUG +# define MAX_TIMEOUT_VALUE 60 /* Give secshr timeout/startup some excercise in DEBUG mode */ +# else +# define MAX_TIMEOUT_VALUE 6000 +# endif #endif #define MAX_ID_LEN 8 #define MAX_MESG 2048 -#define MAX_GTMSECSHR_FAIL_MESG_LEN 70 -#define MAX_SOCKFILE_NAME_LEN 25 +#define MAX_SECSHR_SOCKFILE_NAME_LEN (SIZEOF(GTMSECSHR_SOCK_PREFIX) + MAX_DIGITS_IN_INT) -typedef struct ipcs_mesg_struct { +typedef struct ipcs_mesg_struct +{ int semid; int shmid; time_t gt_sem_ctime; time_t gt_shm_ctime; unsigned int fn_len; - char fn[MAX_TRANS_NAME_LEN]; + char fn[GTM_PATH_MAX]; } ipcs_mesg; -typedef struct gtmsecshr_mesg_struct { - int len; /* this is the whole hdr (4 ints) plus the mesg data */ - int code; - int ack; - int pid; - unsigned long seqno; +typedef struct gtmsecshr_mesg_struct +{ + int code; /* To gtmsecshr: requested gtmsecshr_mesg_type function code. + * From gtmsecshr: return code (0 or errno). + */ + unsigned int comkey; /* Unique key per version keeps from having cross-version issues */ + boolean_t usesecshr; /* Copy of client's gtm_usesecshr flag. Only used in debug build but always kept + * for alignment. + */ + pid_t pid; /* Process id of sender */ + unsigned long seqno; /* Used only by client to validate response is for message sent */ union { - long id; - char path[MAX_TRANS_NAME_LEN]; + int4 id; /* Can be pid, semid or shmid */ + char path[GTM_PATH_MAX]; ipcs_mesg db_ipcs; - }mesg; -}gtmsecshr_mesg; + } mesg; +} gtmsecshr_mesg; /* include for offsetof() */ #define GTM_MESG_HDR_SIZE offsetof(gtmsecshr_mesg, mesg.id) -/* There should be NO deletions of messages types. Only replacements with the UNUSED_ prefix to signal disuse. - * This is because we want to maintain a static mapping between a given command and its corresponding message - * type number across all versions of GT.M (old and new). This way there is no chance of misinterpreting a command - * in case there is a version mismatch between the GT.M client and GTMSECSHR server processes. +/* Version V6.0-000 largely re-built the interface between gtmsecshr client and server. Later versions should strive to + * not change the order or placement of the message codes below. If a message becomes obsolete, rename the code to be + * prefixed with "UNUSED_". This is so for future versions, if a security bug is found, we can take the source, compile + * it for the relevant version and refresh just this module (assuming the client doesn't have issues). */ -enum gtmsecshr_mesg_type{ +enum gtmsecshr_mesg_type +{ + /* Starting here, these are request codes put in mesg.code. They are returned unchanged except in case of error */ WAKE_MESSAGE = 1, - UNUSED_CHECK_PROCESS_ALIVE, REMOVE_SEM, - REMOVE_SHMMEM, - UNUSED_PING_MESSAGE, + REMOVE_SHM, REMOVE_FILE, CONTINUE_PROCESS, - UNUSED_PING_MESG_RECVD, FLUSH_DB_IPCS_INFO, - GTMSECSHR_MESG_COUNT + /* From here down are response codes. These codes are never processed but all except INVALID_COMMAND (for which there is + * no response) can be returned to client. + */ + INVALID_COMMAND = 0x8000, /* No response given */ + INVALID_COMKEY + }; -enum gtmsecshr_ack_type{ - ACK_NOT_REQUIRED, - ACK_REQUIRED -}; - -void gtmsecshr_log(char *, int), gtmsecshr_exit(int, boolean_t), gtmsecshr_init(void), gtmsecshr_sig_init(void); -void gtmsecshr_switch_log_file(int); -int gtmsecshr_open_log_file(void), gtmsecshr_getenv(char *, char **); -int service_request(gtmsecshr_mesg *); -int4 gtmsecshr_sock_init(int caller); -void gtmsecshr_sock_cleanup(int); -int4 gtmsecshr_pathname_init(int caller); -int continue_proc(pid_t pid); +int validate_receiver(gtmsecshr_mesg *buf, char *rundir, int rundir_len, int save_code); +void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_len); +int4 gtmsecshr_sock_init(int caller); +void gtmsecshr_sock_cleanup(int); +int4 gtmsecshr_pathname_init(int caller, char *execpath, int execpathln); +int continue_proc(pid_t pid); #endif diff --git a/sr_unix/gtmsecshr_sock_cleanup.c b/sr_unix/gtmsecshr_sock_cleanup.c index 9e8abef..c16edb5 100644 --- a/sr_unix/gtmsecshr_sock_cleanup.c +++ b/sr_unix/gtmsecshr_sock_cleanup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,11 +12,13 @@ #include "mdef.h" #include -#include "gtm_socket.h" #include +#include "gtm_socket.h" #include "gtm_stdio.h" #include "gtm_unistd.h" #include "gtm_string.h" +#include "gtm_limits.h" + #include "io.h" #include "gtmsecshr.h" #include "error.h" diff --git a/sr_unix/gtmsecshr_sock_init.c b/sr_unix/gtmsecshr_sock_init.c index 9beb45d..d4da588 100644 --- a/sr_unix/gtmsecshr_sock_init.c +++ b/sr_unix/gtmsecshr_sock_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,6 +21,7 @@ #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gtm_socket.h" +#include "gtm_limits.h" #include "gtm_logicals.h" #include "io.h" @@ -44,9 +45,8 @@ GBLREF boolean_t gtmsecshr_sock_init_done; GBLREF uint4 process_id; GBLREF int gtmsecshr_sockfd; -static char gtmsecshr_sockpath[MAX_TRANS_NAME_LEN]; -static char gtmsecshr_path[MAX_TRANS_NAME_LEN]; - +static char gtmsecshr_sockpath[GTM_PATH_MAX]; +static char gtmsecshr_path[GTM_PATH_MAX]; static char hex_table[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; unsigned char *mypid2ascx(unsigned char *, pid_t); @@ -57,7 +57,11 @@ unsigned char *mypid2ascx(unsigned char *, pid_t); # define EXACT_SIZE_SOCKNAME #endif -int4 gtmsecshr_pathname_init(int caller) +error_def(ERR_GTMSECSHRSOCKET); +error_def(ERR_LOGTOOLONG); +error_def(ERR_TEXT); + +int4 gtmsecshr_pathname_init(int caller, char *execpath, int execpathln) { int ret_status = 0, status; char *error_mesg; @@ -66,93 +70,106 @@ int4 gtmsecshr_pathname_init(int caller) struct stat buf; int4 max_sock_path_len; - error_def(ERR_GTMSECSHRSOCKET); - error_def(ERR_LOGTOOLONG); - error_def(ERR_TEXT); - if (!process_id) getjobnum(); - secshrsock_lognam.addr = GTMSECSHR_SOCK_DIR; secshrsock_lognam.len = SIZEOF(GTMSECSHR_SOCK_DIR) - 1; - /* Get the maximum size of the path excluding the socket filename */ - max_sock_path_len = SIZEOF(gtmsecshr_sock_name.sun_path) - MAX_SOCKFILE_NAME_LEN; + max_sock_path_len = SIZEOF(gtmsecshr_sock_name.sun_path) - MAX_SECSHR_SOCKFILE_NAME_LEN; /* Make sure this length is atmost equal to the size of the buffer that will hold the socket path */ - if (MAX_TRANS_NAME_LEN < max_sock_path_len) - max_sock_path_len = MAX_TRANS_NAME_LEN - MAX_SOCKFILE_NAME_LEN; - + if (GTM_PATH_MAX < max_sock_path_len) + max_sock_path_len = GTM_PATH_MAX - MAX_SECSHR_SOCKFILE_NAME_LEN; /* Get the value of the GTMSECSHR_SOCK_DIR logical from the environment. status will be SS_LOG2LONG if * the value is greater than max_sock_path_len */ status = TRANS_LOG_NAME(&secshrsock_lognam, &secshrsock_transnam, gtmsecshr_sockpath, max_sock_path_len, - do_sendmsg_on_log2long); + do_sendmsg_on_log2long); if ((SS_NORMAL != status) || !ABSOLUTE_PATH(gtmsecshr_sockpath)) { if (SS_LOG2LONG == status) - gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, secshrsock_lognam.len, secshrsock_lognam.addr, - max_sock_path_len); + { + if (SERVER == caller) + send_msg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, secshrsock_lognam.len, secshrsock_lognam.addr, + max_sock_path_len); + else + gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, secshrsock_lognam.len, secshrsock_lognam.addr, + max_sock_path_len); + } ret_status = INVLOGNAME; strcpy(gtmsecshr_sockpath, DEFAULT_GTMSECSHR_SOCK_DIR); gtmsecshr_sockpath_len = SIZEOF(DEFAULT_GTMSECSHR_SOCK_DIR) - 1; } else gtmsecshr_sockpath_len = secshrsock_transnam.len; - if ((-1 == Stat(gtmsecshr_sockpath, &buf)) || !S_ISDIR(buf.st_mode) ) { if (ret_status) error_mesg = "Unable to locate default tmp directory"; else error_mesg = "$gtm_tmp not a directory"; - - send_msg(VARLSTCNT(9) MAKE_MSG_SEVERE(ERR_GTMSECSHRSOCKET), 3, - RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, - ERR_TEXT, 2, RTS_ERROR_STRING(error_mesg)); - gtm_putmsg(VARLSTCNT(9) ERR_GTMSECSHRSOCKET, 3, - RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, ERR_TEXT, 2, - RTS_ERROR_STRING(error_mesg)); + if (SERVER == caller) + send_msg(VARLSTCNT(9) MAKE_MSG_SEVERE(ERR_GTMSECSHRSOCKET), 3, + RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, + ERR_TEXT, 2, RTS_ERROR_STRING(error_mesg)); + else + gtm_putmsg(VARLSTCNT(9) MAKE_MSG_SEVERE(ERR_GTMSECSHRSOCKET), 3, + RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, + ERR_TEXT, 2, RTS_ERROR_STRING(error_mesg)); return INVLOGNAME; } - ret_status = 0; if ('/' != gtmsecshr_sockpath[gtmsecshr_sockpath_len - 1]) gtmsecshr_sockpath[gtmsecshr_sockpath_len++] = '/'; - gtmsecshr_sockpath[gtmsecshr_sockpath_len] = '\0'; - strcpy(gtmsecshr_sockpath + gtmsecshr_sockpath_len , GTMSECSHR_SOCK_PREFIX); gtmsecshr_sockpath_len += (SIZEOF(GTMSECSHR_SOCK_PREFIX) - 1); - - gtmsecshr_logname.addr = GTMSECSHR_PATH; - gtmsecshr_logname.len = SIZEOF(GTMSECSHR_PATH) - 1; - - if (SS_NORMAL != - (status = TRANS_LOG_NAME(>msecshr_logname, >msecshr_pathname, gtmsecshr_path, SIZEOF(gtmsecshr_path), - dont_sendmsg_on_log2long))) - { - if (SS_LOG2LONG == status) - gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtmsecshr_logname.len, gtmsecshr_logname.addr, - SIZEOF(gtmsecshr_path) - 1); - gtmsecshr_pathname.len = 0; - gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSOCKET, 3, - RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Environment variable gtm_dist pointing to an invalid path"), - ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_logname.addr)); - ret_status = INVLOGNAME; + /* Servers have already determined the executable name. Use that instead of below. */ + if (SERVER == caller) + { /* Use path name discovered by gtmsecshr_init() */ + strcpy(gtmsecshr_path, execpath); + gtmsecshr_path[execpathln++] = '/'; + gtmsecshr_path[execpathln] = '\0'; + strcat(gtmsecshr_path, GTMSECSHR_EXECUTABLE); + gtmsecshr_pathname.addr = gtmsecshr_path; + gtmsecshr_pathname.len = execpathln + STRLEN(GTMSECSHR_EXECUTABLE); + } else + { /* Discover path name */ + gtmsecshr_logname.addr = GTMSECSHR_PATH; + gtmsecshr_logname.len = SIZEOF(GTMSECSHR_PATH) - 1; + if (SS_NORMAL != + (status = TRANS_LOG_NAME(>msecshr_logname, >msecshr_pathname, gtmsecshr_path, SIZEOF(gtmsecshr_path), + dont_sendmsg_on_log2long))) + { + if (SS_LOG2LONG == status) + gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtmsecshr_logname.len, gtmsecshr_logname.addr, + SIZEOF(gtmsecshr_path) - 1); + gtmsecshr_pathname.len = 0; + gtm_putmsg(VARLSTCNT(13) ERR_GTMSECSHRSOCKET, 3, + RTS_ERROR_STRING("Caller"), process_id, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Environment variable gtm_dist pointing to an invalid path"), + ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_logname.addr)); + ret_status = INVLOGNAME; + } + gtmsecshr_path[gtmsecshr_pathname.len] = '\0'; } - gtmsecshr_path[gtmsecshr_pathname.len] = 0; /* We have different project id here. This guarantees to avoid deadlock, if only one gtm installation is there */ if (-1 == (gtmsecshr_key = FTOK(gtmsecshr_path, GTMSECSHR_ID))) { ret_status = FTOKERR; - gtm_putmsg(VARLSTCNT(14) ERR_GTMSECSHRSOCKET, 3, - RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with gtmsecshr ftok :"), - ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_path), errno); + if (SERVER == caller) + gtm_putmsg(VARLSTCNT(14) ERR_GTMSECSHRSOCKET, 3, + RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, + ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with gtmsecshr ftok :"), + ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_path), errno); + else + send_msg(VARLSTCNT(14) ERR_GTMSECSHRSOCKET, 3, + RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, + ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with gtmsecshr ftok :"), + ERR_TEXT, 2, RTS_ERROR_STRING(gtmsecshr_path), errno); } - return(ret_status); + return ret_status; } +/* Note - only the server passes in the executable name/len - ignore for client */ int4 gtmsecshr_sock_init(int caller) { int ret_status = 0; @@ -167,25 +184,18 @@ int4 gtmsecshr_sock_init(int caller) struct stat dist_stat_buff; int lib_gid; - error_def(ERR_GTMSECSHRSOCKET); - error_def(ERR_TEXT); - - - assert (FALSE == gtmsecshr_sock_init_done); - + assert(FALSE == gtmsecshr_sock_init_done); if (!process_id) getjobnum(); - if (CLIENT == caller) { - if ((init_pathname_status = gtmsecshr_pathname_init(CLIENT)) != 0) - return(init_pathname_status); + if (0 != (init_pathname_status = gtmsecshr_pathname_init(CLIENT, NULL, 0))) + return init_pathname_status; gtmsecshr_cli_sock_name.sun_family = AF_UNIX; memcpy(gtmsecshr_cli_sock_name.sun_path, gtmsecshr_sockpath, gtmsecshr_sockpath_len); strcpy(gtmsecshr_cli_sock_name.sun_path + gtmsecshr_sockpath_len, (char *)mypid2ascx(pid_str, process_id)); gtmsecshr_cli_sockpath_len = (int)(SUN_LEN(>msecshr_cli_sock_name)); } - id_str[i2hex_nofill((unsigned int)gtmsecshr_key, (uchar_ptr_t )id_str, MAX_ID_LEN)] = 0; id_str_len = STRLEN((char *)id_str); memcpy(gtmsecshr_sockpath + gtmsecshr_sockpath_len, (char *)id_str, id_str_len); @@ -193,14 +203,12 @@ int4 gtmsecshr_sock_init(int caller) gtmsecshr_sock_name.sun_family = AF_UNIX; memcpy(gtmsecshr_sock_name.sun_path, gtmsecshr_sockpath, gtmsecshr_sockpath_len); gtmsecshr_sockpath_len = (int)(SUN_LEN(>msecshr_sock_name)); - if (FD_INVALID == (gtmsecshr_sockfd = socket(AF_UNIX, SOCK_DGRAM, 0))) { rts_error(VARLSTCNT(10) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_STRING((SERVER == caller) ? "Server" : "Caller"), process_id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with gtmsecshr socket create"), errno); ret_status = SOCKETERR; } - if (SERVER == caller) { if (!ret_status) @@ -218,7 +226,6 @@ int4 gtmsecshr_sock_init(int caller) } } } - if (!ret_status) { if (0 > BIND(gtmsecshr_sockfd, (struct sockaddr *)>msecshr_sock_name, gtmsecshr_sockpath_len)) @@ -230,8 +237,7 @@ int4 gtmsecshr_sock_init(int caller) ret_status = BINDERR; } } - } - else /* CLIENT */ + } else /* CLIENT */ { for (suffix = '\0'; !ret_status && 'z' >= suffix; ) { @@ -244,9 +250,9 @@ int4 gtmsecshr_sock_init(int caller) suffix = 'a'; gtmsecshr_cli_sockpath_end = STRLEN(gtmsecshr_cli_sock_name.sun_path); gtmsecshr_cli_sock_name.sun_path[gtmsecshr_cli_sockpath_end + 1] = '\0'; -#ifdef EXACT_SIZE_SOCKNAME +# ifdef EXACT_SIZE_SOCKNAME gtmsecshr_cli_sockpath_len++; /* Account for socket name growth (suffix) */ -#endif +# endif } else suffix++; gtmsecshr_cli_sock_name.sun_path[gtmsecshr_cli_sockpath_end] = suffix; @@ -264,14 +270,12 @@ int4 gtmsecshr_sock_init(int caller) } else break; } - if ( 'z' < suffix) { send_msg(VARLSTCNT(9) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Client"), process_id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Too many left over gtmsecshr_cli sockets")); ret_status = UNLINKERR; } - if (!ret_status) { if (0 > BIND(gtmsecshr_sockfd, (struct sockaddr *)>msecshr_cli_sock_name, gtmsecshr_cli_sockpath_len)) @@ -282,19 +286,19 @@ int4 gtmsecshr_sock_init(int caller) ret_status = BINDERR; } else if ('\0' != suffix) ret_status = ONETIMESOCKET; - /* if ret_status is zero do the following checks - * if $gtm_dist/libgtmshr.so is not world accessible then set mode to 0660 - * and change the gid to the gid of $gtm_dist/libgtmshr.so - * if different from current user */ + /* If ret_status is zero do the following checks if $gtm_dist/libgtmshr.so is not world accessible + * then set mode to 0660 and change the gid to the gid of $gtm_dist/libgtmshr.so if different from + * current user. + */ if (!ret_status) { lib_gid = gtm_get_group_id(&dist_stat_buff); if ((-1 != lib_gid) && (dist_stat_buff.st_mode & 04)) lib_gid = -1; /* don't change it */ - - if ((-1 != lib_gid) && - (-1 == CHMOD(gtmsecshr_cli_sock_name.sun_path, 0660) || ((lib_gid != GETGID()) && - (-1 == CHOWN(gtmsecshr_cli_sock_name.sun_path, -1, lib_gid))))) + if ((-1 != lib_gid) + && (-1 == CHMOD(gtmsecshr_cli_sock_name.sun_path, 0660) + || ((lib_gid != GETGID()) + && (-1 == CHOWN(gtmsecshr_cli_sock_name.sun_path, -1, lib_gid))))) { rts_error(VARLSTCNT(10) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_STRING("Caller"), process_id, ERR_TEXT, 2, @@ -308,17 +312,15 @@ int4 gtmsecshr_sock_init(int caller) } unsigned char *mypid2ascx(unsigned char *pid_str, pid_t pid) -{ - /* pid_str should accommodate atleast 2*SIZEOF(pid_t) + 1 characters */ - +{ /* pid_str should accommodate at least 2 * SIZEOF(pid_t) + 1 characters */ register unsigned char *cp; - cp = &pid_str[2*SIZEOF(pid_t)]; - *cp = '\0'; /* Null terminate the string */ - while(cp > pid_str) + cp = &pid_str[2 * SIZEOF(pid_t)]; + *cp = '\0'; /* Null terminate the string */ + while (cp > pid_str) { *--cp = hex_table[pid & 0xF]; pid >>= 4; } - return(pid_str); + return pid_str; } diff --git a/sr_unix/gtmsecshr_wrapper.c b/sr_unix/gtmsecshr_wrapper.c index 7e1cfc0..79bda13 100644 --- a/sr_unix/gtmsecshr_wrapper.c +++ b/sr_unix/gtmsecshr_wrapper.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2008, 2012 Fidelity Information Services, Inc * + * Copyright 2008, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,11 +13,12 @@ #define BYPASS_MEMCPY_OVERRIDE /* Signals gtm_string.h to not override memcpy(). This causes linking problems when libmumps.a * is not available. */ -#/* We want system malloc, not gtm_malloc (which comes from mdef.h --> mdefsp.h). Since gtmsecshr_wrapper runs as root, +/* We want system malloc, not gtm_malloc (which comes from mdef.h --> mdefsp.h). Since gtmsecshr_wrapper runs as root, * using the system malloc will increase security over using gtm_malloc. Additionally, by not using gtm_malloc, we * are reducing code bloat. */ #undef malloc +#undef free #include "gtm_unistd.h" #include "gtm_stat.h" #include "gtm_stdlib.h" @@ -26,30 +27,25 @@ #include "gtm_syslog.h" #include "main_pragma.h" #ifndef __MVS__ -#include +# include #endif +#include #include #define ROOTUID 0 #define ROOTGID 0 - #define MAX_ENV_VAR_VAL_LEN 1024 #define MAX_ALLOWABLE_LEN 256 - +#define ASCIICTLMAX 32 /* space character */ +#define ASCIICTLMIN 0 /* NULL character */ #define OVERWRITE 1 - -#define GTM_LOG "gtm_log" #define GTM_TMP "gtm_tmp" #define GTM_DIST "gtm_dist" #define GTM_DBGLVL "gtmdbglvl" -#ifdef __MVS__ -#define GTM_ZOS_AUTOCVT "_BPXK_AUTOCVT" -#define GTM_ZOS_AUTOCVT_ON "ON" -#endif - #define SUB_PATH_TO_GTMSECSHRDIR "/gtmsecshrdir" #define REL_PATH_TO_CURDIR "." #define REL_PATH_TO_GTMSECSHR "./gtmsecshr" #define GTMSECSHR_BASENAME "/gtmsecshr" +#define MAX_ENV_NAME_LEN 2048 #ifdef __osf__ /* On OSF/1 (Digital Unix), pointers are 64 bits wide; the only exception to this is C programs for which one may @@ -69,43 +65,66 @@ extern char **environ; #pragma pointer_size (restore) #endif -int gtm_setenv(char * env_var_name, char * env_var_val, int overwrite); +/* Since gtmsecshr_wrapper.c is a stand-alone module, we cannot use error_def-style definitions, so use simple macro defines to + * initialize all error types used along with their respective mnemonics. Note that we need two '%' to ensure the '%' prefix + * in the syslog. + */ +#define ERR_SECSHRCHDIRFAILED \ + "%%GTM-E-SECSHRCHDIRFAILED, chdir failed on %s, errno %d. gtmsecshr will not be started\n" +#define ERR_SECSHRCLEARENVFAILED \ + "%%GTM-E-SECSHRCLEARENVFAILED, clearenv failed. gtmsecshr will not be started\n" +#define ERR_SECSHREXECLFAILED \ + "%%GTM-E-SECSHREXECLFAILED, execl of %s failed\n" +#define ERR_SECSHRGTMDBGLVL2LONG \ + "%%GTM-E-SECSHRGTMDBGLVL2LONG, gtmdbglvl env var too long. gtmsecshr will not be started\n" +#define ERR_SECSHRGTMDIST2LONG \ + "%%GTM-E-SECSHRGTMDIST2LONG, gtm_dist env var too long. gtmsecshr will not be started\n" +#define ERR_SECSHRGTMTMP2LONG \ + "%%GTM-E-SECSHRGTMTMP2LONG, gtm_tmp env var too long. gtmsecshr will not be started\n" +#define ERR_SECSHRNOGTMDIST \ + "%%GTM-E-SECSHRNOGTMDIST, gtm_dist env var does not exist. gtmsecshr will not be started\n" +#define ERR_SECSHRNOTOWNEDBYROOT \ + "%%GTM-E-SECSHRNOTOWNEDBYROOT, %s not owned by root. gtmsecshr will not be started\n" +#define ERR_SECSHRNOTSETUID \ + "%%GTM-E-SECSHRNOTSETUID, %s not set-uid. gtmsecshr will not be started\n" +#define ERR_SECSHRPERMINCRCT \ + "%%GTM-E-SECSHRPERMINCRCT, %s permissions incorrect (%04o). gtmsecshr will not be started\n" +#define ERR_SECSHRSETGTMDISTFAILED \ + "%%GTM-E-SECSHRSETGTMDISTFAILED, setenv for gtm_dist failed. gtmsecshr will not be started\n" +#define ERR_SECSHRSETGTMTMPFAILED \ + "%%GTM-E-SECSHRSETGTMTMPFAILED, setenv for gtm_tmp failed. gtmsecshr will not be started\n" +#define ERR_SECSHRSETUIDFAILED \ + "%%GTM-E-SECSHRSETUIDFAILED, setuid failed. gtmsecshr will not be started\n" +#define ERR_SECSHRSTATFAILED \ + "%%GTM-E-SECSHRSTATFAILED, stat failed on %s, errno %d. gtmsecshr will not be started\n" +#define ERR_SECSHRWRITABLE \ + "%%GTM-E-SECSHRWRITABLE, %s writable. gtmsecshr will not be started\n" +int gtm_setenv(char * env_var_name, char * env_var_val, int overwrite); int gtm_setenv(char * env_var_name, char * env_var_val, int overwrite) -{ -/* - The overwrite parameter is not used. In our case we always want to set the value. -*/ - char *env_var_ptr; - int len; +{ /* The overwrite parameter is not used. In our case we always want to set the value */ + char *env_var_ptr; + int len; len = STRLEN(env_var_name) + STRLEN("=") + STRLEN(env_var_val) + 1; - env_var_ptr = (char *)malloc(len); if (NULL == env_var_ptr) return -1; - strcpy(env_var_ptr, env_var_name); strcat(env_var_ptr, "="); strcat(env_var_ptr, env_var_val); - if (putenv(env_var_ptr)) return -1; - return 0; } int gtm_unsetenv(char * env_var_name); - int gtm_unsetenv(char * env_var_name) { - return gtm_setenv(env_var_name,"",OVERWRITE); + return gtm_setenv(env_var_name, "", OVERWRITE); } -#define MAX_ENV_NAME_LEN 2048 - int gtm_clearenv(void); - int gtm_clearenv() { char env_var_name[MAX_ENV_NAME_LEN]; @@ -135,73 +154,79 @@ int gtm_clearenv() return 0; } +void strsanitize(char *src, char *dst); +void strsanitize(char *src, char *dst) +{ + int i, srclen; + + /* The calling function already validate the string length. */ + srclen = strlen(src); + for (i = 0; i <= srclen && i < MAX_ENV_VAR_VAL_LEN; i++) + { + /* Convert all control characters to '*'. */ + if (ASCIICTLMAX > (int)src[i] && ASCIICTLMIN < (int)src[i]) + dst[i] = '*'; + else + dst[i] = src[i]; + } +} + int main() { - int ret, status; - char * env_var_ptr; - struct stat gtm_secshrdir_stat; - struct stat gtm_secshr_stat; - - char gtm_dist_val[MAX_ENV_VAR_VAL_LEN]; - char gtm_log_val[MAX_ENV_VAR_VAL_LEN]; - char gtm_tmp_val[MAX_ENV_VAR_VAL_LEN]; - char gtm_dbglvl_val[MAX_ENV_VAR_VAL_LEN]; - char gtm_secshrdir_path[MAX_ENV_VAR_VAL_LEN]; - char gtm_secshr_path[MAX_ENV_VAR_VAL_LEN]; - char gtm_secshr_orig_path[MAX_ENV_VAR_VAL_LEN]; - - int gtm_log_exists = 0; - int gtm_tmp_exists = 0; - int gtm_dbglvl_exists = 0; - - openlog("GTMSECSHRINIT", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER); + int ret, status; + char *env_var_ptr; + struct stat gtm_secshrdir_stat; + struct stat gtm_secshr_stat; + char gtm_dist_val[MAX_ENV_VAR_VAL_LEN]; + char gtm_tmp_val[MAX_ENV_VAR_VAL_LEN]; + char gtm_dbglvl_val[MAX_ENV_VAR_VAL_LEN]; + char gtm_secshrdir_path[MAX_ENV_VAR_VAL_LEN]; + char gtm_secshrdir_path_display[MAX_ENV_VAR_VAL_LEN]; + char gtm_secshr_path[MAX_ENV_VAR_VAL_LEN]; + char gtm_secshr_path_display[MAX_ENV_VAR_VAL_LEN]; + char gtm_secshr_orig_path[MAX_ENV_VAR_VAL_LEN]; + int gtm_tmp_exists = 0; + int gtm_dbglvl_exists = 0; + sigset_t mask; + /* Reset the signal mask (since the one inherited from the invoking process might have signals such as SIGALRM or SIGTERM + * blocked) to let gtmsecshr manage its own signals using sig_init. + */ + sigemptyset(&mask); + sigprocmask(SIG_SETMASK, &mask, NULL); + OPENLOG("GTMSECSHRINIT", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER); ret = 0; /* start positive */ - /* get the ones we need */ - if (env_var_ptr = getenv(GTM_DIST)) + if (env_var_ptr = getenv(GTM_DIST)) /* Warning - assignment */ { - if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr) + STR_LIT_LEN(SUB_PATH_TO_GTMSECSHRDIR) + - STR_LIT_LEN(GTMSECSHR_BASENAME)) + if (MAX_ALLOWABLE_LEN < (strlen(env_var_ptr) + STR_LIT_LEN(SUB_PATH_TO_GTMSECSHRDIR) + + STR_LIT_LEN(GTMSECSHR_BASENAME))) { - syslog(LOG_USER | LOG_INFO, "gtm_dist env var too long. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMDIST2LONG); ret = -1; } else { - strcpy(gtm_dist_val,env_var_ptr); + strcpy(gtm_dist_val, env_var_ptr); /* point the path to the real gtmsecshr - for display purposes only */ strcpy(gtm_secshr_path, env_var_ptr); strcat(gtm_secshr_path, SUB_PATH_TO_GTMSECSHRDIR); strcat(gtm_secshr_path, GTMSECSHR_BASENAME); + strsanitize(gtm_secshr_path, gtm_secshr_path_display); /* point the path to the real gtmsecshrdir */ strcpy(gtm_secshrdir_path, env_var_ptr); strcat(gtm_secshrdir_path, SUB_PATH_TO_GTMSECSHRDIR); + strsanitize(gtm_secshrdir_path, gtm_secshrdir_path_display); } } else { - syslog(LOG_USER | LOG_INFO, "gtm_dist env var does not exist. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOGTMDIST); ret = -1; } - - if (env_var_ptr = getenv(GTM_LOG)) + if (env_var_ptr = getenv(GTM_TMP)) /* Warning - assignment */ { if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr)) { - syslog(LOG_USER | LOG_INFO, "gtm_log env var too long. gtmsecshr will not be started.\n"); - ret = -1; - } else - { - gtm_log_exists = 1; - strcpy(gtm_log_val, env_var_ptr); - } - - } - - if (env_var_ptr = getenv(GTM_TMP)) - { - if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr)) - { - syslog(LOG_USER | LOG_INFO, "gtm_tmp env var too long. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMTMP2LONG); ret = -1; } else { @@ -209,12 +234,11 @@ int main() strcpy(gtm_tmp_val, env_var_ptr); } } - - if (env_var_ptr = getenv(GTM_DBGLVL)) + if (env_var_ptr = getenv(GTM_DBGLVL)) /* Warning - assignment */ { if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr)) { - syslog(LOG_USER | LOG_INFO, "gtmdbglvl env var too long. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMDBGLVL2LONG); ret = -1; } else { @@ -222,102 +246,61 @@ int main() strcpy(gtm_dbglvl_val, env_var_ptr); } } - -#ifdef __MVS__ - if (!(env_var_ptr = getenv(GTM_ZOS_AUTOCVT))) - { - syslog(LOG_USER | LOG_INFO, "_BPXK_AUTOCVT is not set, forcing autoconversion\n"); - } -#endif - if (!ret) { /* clear all */ status = gtm_clearenv(); if (status) { - syslog(LOG_USER | LOG_INFO, "clearenv failed. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRCLEARENVFAILED); ret = -1; } - /* add the ones we need */ status = gtm_setenv(GTM_DIST, gtm_dist_val, OVERWRITE); if (status) { - syslog(LOG_USER | LOG_INFO, "setenv for gtm_dist failed. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETGTMDISTFAILED); ret = -1; } - if (gtm_log_exists) - { - status = gtm_setenv(GTM_LOG, gtm_log_val, OVERWRITE); - if (status) - { - syslog(LOG_USER | LOG_INFO, "setenv for gtm_log failed. gtmsecshr will not be started.\n"); - ret = -1; - } - } if (gtm_tmp_exists) { status = gtm_setenv(GTM_TMP, gtm_tmp_val, OVERWRITE); if (status) { - syslog(LOG_USER | LOG_INFO, "setenv for gtm_tmp failed. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETGTMTMPFAILED); ret = -1; } } - if (gtm_dbglvl_exists) - { - status = gtm_setenv(GTM_DBGLVL, gtm_dbglvl_val, OVERWRITE); - if (status) - { - syslog(LOG_USER | LOG_INFO, "setenv for gtmdbglvl failed. gtmsecshr will not be started.\n"); - ret = -1; - } - } -#ifdef __MVS__ - status = gtm_setenv(GTM_ZOS_AUTOCVT, GTM_ZOS_AUTOCVT_ON, OVERWRITE); - if (status) - { - syslog(LOG_USER | LOG_INFO, - "setenv for _BPXK_AUTOCVT failed. gtmsecshr logs may contain mixed ASCII and EBCDIC.\n"); - } -#endif } - if (!ret) { /* go to root */ if (-1 == CHDIR(gtm_secshrdir_path)) - syslog(LOG_USER | LOG_INFO, "chdir failed on %s, errno %d. gtmsecshr will not be started.\n", - gtm_secshrdir_path, errno); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRCHDIRFAILED, gtm_secshrdir_path_display, errno); else if (-1 == Stat(REL_PATH_TO_CURDIR, >m_secshrdir_stat)) - syslog(LOG_USER | LOG_INFO, "stat failed on %s, errno %d. gtmsecshr will not be started.\n", - gtm_secshrdir_path, errno); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSTATFAILED, gtm_secshrdir_path_display, errno); else if (ROOTUID != gtm_secshrdir_stat.st_uid) - syslog(LOG_USER | LOG_INFO, "%s not owned by root. gtmsecshr will not be started.\n", gtm_secshrdir_path); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTOWNEDBYROOT, gtm_secshrdir_path_display); else if (gtm_secshrdir_stat.st_mode & 0277) - syslog(LOG_USER | LOG_INFO, "%s permissions incorrect (%04o). gtmsecshr will not be started.\n", - gtm_secshrdir_path, gtm_secshrdir_stat.st_mode & 0777); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRPERMINCRCT, gtm_secshrdir_path_display, + gtm_secshrdir_stat.st_mode & 0777); else if (-1 == Stat(REL_PATH_TO_GTMSECSHR, >m_secshr_stat)) - syslog(LOG_USER | LOG_INFO, "stat failed on %s, errno %d. gtmsecshr will not be started.\n", - gtm_secshr_path, errno); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSTATFAILED, gtm_secshr_path_display, errno); else if (ROOTUID != gtm_secshr_stat.st_uid) - syslog(LOG_USER | LOG_INFO, "%s not owned by root. gtmsecshr will not be started.\n", gtm_secshr_path); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTOWNEDBYROOT, gtm_secshr_path_display); else if (gtm_secshr_stat.st_mode & 022) - syslog(LOG_USER | LOG_INFO, "%s writable. gtmsecshr will not be started.\n", gtm_secshr_path); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRWRITABLE, gtm_secshr_path_display); else if (!(gtm_secshr_stat.st_mode & 04000)) - syslog(LOG_USER | LOG_INFO, "%s not set-uid. gtmsecshr will not be started.\n", gtm_secshr_path); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTSETUID, gtm_secshr_path_display); else if (-1 == setuid(ROOTUID)) - syslog(LOG_USER | LOG_INFO, "setuid failed. gtmsecshr will not be started.\n"); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETUIDFAILED); else { /* call the real gtmsecshr, but have ps display the original gtmsecshr location */ strcpy(gtm_secshr_orig_path, gtm_dist_val); strcat(gtm_secshr_orig_path, GTMSECSHR_BASENAME); ret = execl(REL_PATH_TO_GTMSECSHR, gtm_secshr_orig_path, NULL); if (-1 == ret) - syslog(LOG_USER | LOG_INFO, "execl of %s failed\n", gtm_secshr_path); + SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHREXECLFAILED, gtm_secshr_path_display); } } - - closelog(); - + CLOSELOG(); return ret; } diff --git a/sr_unix/gtmshr_symbols.exp b/sr_unix/gtmshr_symbols.exp index 4dfc1de..db6aed3 100644 --- a/sr_unix/gtmshr_symbols.exp +++ b/sr_unix/gtmshr_symbols.exp @@ -1,6 +1,8 @@ gtm_main gtm_init +gtm_jinit gtm_ci +gtm_cij gtm_cip gtm_exit gtm_zstatus @@ -8,9 +10,9 @@ gtm_hiber_start gtm_hiber_start_wait_any gtm_start_timer gtm_cancel_timer -gtm_jnlpool_detach gtm_malloc gtm_free gtm_filename_to_id gtm_is_file_identical gtm_xcfileid_free +gtm_is_main_thread diff --git a/sr_unix/gtmsource.c b/sr_unix/gtmsource.c index f8a0e54..93f3d2a 100644 --- a/sr_unix/gtmsource.c +++ b/sr_unix/gtmsource.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -60,10 +60,12 @@ #include "gtm_zlib.h" #include "fork_init.h" #include "heartbeat_timer.h" +#include "gtmio.h" GBLDEF boolean_t gtmsource_logstats = FALSE, gtmsource_pool2file_transition = FALSE; GBLDEF int gtmsource_filter = NO_FILTER; GBLDEF boolean_t update_disable = FALSE; +GBLDEF boolean_t last_seen_freeze_flag = FALSE; GBLREF gtmsource_options_t gtmsource_options; GBLREF gtmsource_state_t gtmsource_state; @@ -73,8 +75,6 @@ GBLREF uint4 process_id; GBLREF int gtmsource_sock_fd; GBLREF int gtmsource_log_fd; GBLREF FILE *gtmsource_log_fp; -GBLREF int gtmsource_statslog_fd; -GBLREF FILE *gtmsource_statslog_fp; GBLREF gd_addr *gd_header; GBLREF void (*call_on_signal)(); GBLREF seq_num gtmsource_save_read_jnl_seqno, seq_num_zero; @@ -84,6 +84,7 @@ GBLREF sgmnt_data_ptr_t cs_data; GBLREF repl_msg_ptr_t gtmsource_msgp; GBLREF int gtmsource_msgbufsiz; GBLREF unsigned char *gtmsource_tcombuff_start; +GBLREF boolean_t is_jnlpool_creator; GBLREF uchar_ptr_t repl_filter_buff; GBLREF int repl_filter_bufsiz; GBLREF int gtmsource_srv_count; @@ -97,7 +98,10 @@ error_def(ERR_MUPCLIERR); error_def(ERR_NOTALLDBOPN); error_def(ERR_NULLCOLLDIFF); error_def(ERR_REPLCOMM); +error_def(ERR_REPLERR); error_def(ERR_REPLINFO); +error_def(ERR_REPLINSTFREEZECOMMENT); +error_def(ERR_REPLINSTFROZEN); error_def(ERR_REPLOFFJNLON); error_def(ERR_TEXT); @@ -107,18 +111,19 @@ int gtmsource() char print_msg[1024], tmpmsg[1024]; gd_region *reg, *region_top; sgmnt_addrs *csa, *repl_csa; - boolean_t jnlpool_creator, all_files_open, isalive; + boolean_t all_files_open, isalive; pid_t pid, ppid, procgp; seq_num read_jnl_seqno, jnl_seqno; unix_db_info *udi; gtmsource_local_ptr_t gtmsource_local; boolean_t this_side_std_null_coll; + int null_fd, rc; memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool_addrs)); call_on_signal = gtmsource_sigstop; ESTABLISH_RET(gtmsource_ch, SS_NORMAL); if (-1 == gtmsource_get_opt()) - rts_error(VARLSTCNT(1) ERR_MUPCLIERR); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR); if (gtmsource_options.shut_down) { /* Wait till shutdown time nears even before going to "jnlpool_init". This is because the latter will return * with the ftok semaphore and access semaphore held and we do not want to be holding those locks (while @@ -137,16 +142,16 @@ int gtmsource() repl_log(stdout, TRUE, TRUE, "Initiating START of source server for secondary instance [%s]\n", gtmsource_options.secondary_instname); } - jnlpool_init(GTMSOURCE, gtmsource_options.start, &jnlpool_creator); - /* jnlpool_creator == TRUE ==> this process created the journal pool - * jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it. + jnlpool_init(GTMSOURCE, gtmsource_options.start, &is_jnlpool_creator); + /* is_jnlpool_creator == TRUE ==> this process created the journal pool + * is_jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it. */ if (gtmsource_options.shut_down) gtmsource_exit(gtmsource_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN); else if (gtmsource_options.activate) - gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE) - NORMAL_SHUTDOWN); + gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE_REQUESTED) - NORMAL_SHUTDOWN); else if (gtmsource_options.deactivate) - gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE) - NORMAL_SHUTDOWN); + gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE_REQUESTED) - NORMAL_SHUTDOWN); else if (gtmsource_options.checkhealth) gtmsource_exit(gtmsource_checkhealth() - NORMAL_SHUTDOWN); else if (gtmsource_options.changelog) @@ -161,6 +166,10 @@ int gtmsource() gtmsource_exit(gtmsource_losttncomplete() - NORMAL_SHUTDOWN); else if (gtmsource_options.needrestart) gtmsource_exit(gtmsource_needrestart() - NORMAL_SHUTDOWN); + else if (gtmsource_options.showfreeze) + gtmsource_exit(gtmsource_showfreeze() - NORMAL_SHUTDOWN); + else if (gtmsource_options.setfreeze) + gtmsource_exit(gtmsource_setfreeze() - NORMAL_SHUTDOWN); else if (!gtmsource_options.start) { assert(CLI_PRESENT == cli_present("STATSLOG")); @@ -174,8 +183,8 @@ int gtmsource() FORK_CLEAN(pid); if (0 > pid) { - save_errno = REPL_SEM_ERRNO; - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, + save_errno = errno; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork source server"), save_errno); } else if (0 < pid) { /* Parent. Wait until child sets "child_server_running" to FALSE. That is an indication that the child @@ -194,7 +203,7 @@ int gtmsource() if (isalive) { /* Child process is alive and started with no issues */ if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM))) - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in rel_sem"), save_errno); ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); } else @@ -202,7 +211,7 @@ int gtmsource() * If we were the one who created the journal pool, let us clean it up. */ repl_log(stdout, TRUE, TRUE, "Source server startup failed. See source server log file\n"); - if (jnlpool_creator) + if (is_jnlpool_creator) status = gtmsource_shutdown(TRUE, NORMAL_SHUTDOWN); } /* If the parent is killed (or crashes) between the fork and exit, checkhealth may not detect that startup @@ -211,6 +220,16 @@ int gtmsource() */ gtmsource_exit(isalive ? SRV_ALIVE : SRV_ERR); } + /* Point stdin to /dev/null */ + OPENFILE("/dev/null", O_RDONLY, null_fd); + if (0 > null_fd) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0); + FCNTL3(null_fd, F_DUPFD, 0, rc); + if (0 > rc) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0); + CLOSEFILE(null_fd, rc); + if (0 > rc) + rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0); /* The parent process (source server startup command) will be holding the ftok semaphore and jnlpool access semaphore * at this point. The variables that indicate this would have been copied over to the child during the fork. This will * make the child think it is actually holding them as well when actually it is not. Reset those variables in the child @@ -225,6 +244,7 @@ int gtmsource() assert(!holds_sem[SOURCE][SRC_SERV_COUNT_SEM]); /* Start child source server initialization */ is_src_server = TRUE; + OPERATOR_LOG_MSG; process_id = getpid(); /* Reinvoke secshr related initialization with the child's pid */ INVOKE_INIT_SECSHR_ADDRS; @@ -236,11 +256,12 @@ int gtmsource() mutex_per_process_init(); START_HEARTBEAT_IF_NEEDED; ppid = getppid(); - log_init_status = repl_log_init(REPL_GENERAL_LOG, >msource_log_fd, NULL, gtmsource_options.log_file, NULL); + log_init_status = repl_log_init(REPL_GENERAL_LOG, >msource_log_fd, gtmsource_options.log_file); assert(SS_NORMAL == log_init_status); repl_log_fd2fp(>msource_log_fp, gtmsource_log_fd); if (-1 == (procgp = setsid())) - send_msg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Source server error in setsid"), errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Source server error in setsid"), errno); #endif /* REPL_DEBUG_NOBACKGROUND */ if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level) gtm_zlib_init(); /* Open zlib shared library for compression/decompression */ @@ -251,7 +272,7 @@ int gtmsource() all_files_open = region_init(FALSE); if (!all_files_open) { - gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN); gtmsource_exit(ABNORMAL_SHUTDOWN); } /* Determine primary side null subscripts collation order */ @@ -266,18 +287,18 @@ int gtmsource() this_side_std_null_coll = csa->hdr->std_null_coll; else { - gtm_putmsg(VARLSTCNT(1) ERR_NULLCOLLDIFF); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF); gtmsource_exit(ABNORMAL_SHUTDOWN); } } if (!REPL_ALLOWED(csa) && JNL_ALLOWED(csa)) { - gtm_putmsg(VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg)); gtmsource_exit(ABNORMAL_SHUTDOWN); } - if (reg->read_only && REPL_ALLOWED(csa->hdr)) + if (reg->read_only && REPL_ALLOWED(csa)) { - gtm_putmsg(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Source Server does not have write permissions to one or " "more database files that are replicated")); gtmsource_exit(ABNORMAL_SHUTDOWN); @@ -286,8 +307,9 @@ int gtmsource() /* Initialize source server alive/dead state related fields in "gtmsource_local" before the ftok semaphore is released */ gtmsource_local->gtmsource_pid = process_id; gtmsource_local->gtmsource_state = GTMSOURCE_START; - if (jnlpool_creator) + if (is_jnlpool_creator) { + DEBUG_ONLY(jnlpool.jnlpool_ctl->jnlpool_creator_pid = process_id); gtmsource_seqno_init(this_side_std_null_coll); if (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary) { /* Created the journal pool as a root primary. Append a history record to the replication instance file. @@ -305,18 +327,18 @@ int gtmsource() * that. Do that while the parent is still holding on to the ftok semaphore waiting for our okay. */ if (!ftok_sem_incrcnt(jnlpool.jnlpool_dummy_reg)) - rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); /* Increment the source server count semaphore */ status = incr_sem(SOURCE, SRC_SERV_COUNT_SEM); - save_errno = REPL_SEM_ERRNO; if (0 != status) { - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + save_errno = errno; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Counter semaphore increment failure in child source server"), save_errno); } #else if (0 != (save_errno = rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM))) - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in rel_sem_immediate"), save_errno); #endif /* REPL_DEBUG_NOBACKGROUND */ @@ -331,7 +353,7 @@ int gtmsource() process_id, gtmsource_local->secondary_instname); sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg)); repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); - if (jnlpool_creator) + if (is_jnlpool_creator) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Created jnlpool with shmid = [%d] and semid = [%d]\n", jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid); @@ -339,13 +361,23 @@ int gtmsource() repl_log(gtmsource_log_fp, TRUE, TRUE, "Attached to existing jnlpool with shmid = [%d] and semid = [%d]\n", jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid); gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg); + if (jnlpool.jnlpool_ctl->freeze) + { + last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze; + sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname); + repl_log(gtmsource_log_fp, TRUE, FALSE, print_msg); + sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); + repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); + } do - { /* If mode is passive, go to sleep. Wakeup every now and - * then and check to see if I have to become active */ + { /* 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; - while (gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE - && gtmsource_local->shutdown == NO_SHUTDOWN) + if ((gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE) && (gtmsource_local->shutdown == NO_SHUTDOWN)) + { + gtmsource_poll_actions(FALSE); SHORT_SLEEP(GTMSOURCE_WAIT_FOR_MODE_CHANGE); + continue; + } if (GTMSOURCE_MODE_PASSIVE == gtmsource_local->mode) { /* Shutdown initiated */ assert(gtmsource_local->shutdown == SHUTDOWN); @@ -358,13 +390,15 @@ int gtmsource() gtmsource_poll_actions(FALSE); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) continue; + if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsource_local->mode) + gtmsource_local->mode = GTMSOURCE_MODE_ACTIVE; SPRINTF(tmpmsg, "GTM Replication Source Server now in ACTIVE mode using port %d", gtmsource_local->secondary_port); sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg)); repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg); DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n"); @@ -385,7 +419,7 @@ int gtmsource() } rel_lock(jnlpool.jnlpool_dummy_reg); if (SS_NORMAL != (status = gtmsource_alloc_tcombuff())) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error allocating initial tcom buffer space. Malloc error"), status); gtmsource_filter = NO_FILTER; if ('\0' != gtmsource_local->filter_cmd[0]) diff --git a/sr_unix/gtmsource.h b/sr_unix/gtmsource.h index 0ee048c..3936144 100644 --- a/sr_unix/gtmsource.h +++ b/sr_unix/gtmsource.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,20 +13,23 @@ #define GTMSOURCE_H /* for in_addr_t typedef on Linux */ -#ifdef __linux__ #include "gtm_inet.h" -#else -#include GBLREF gd_addr *gd_header; -#endif #include "min_max.h" #include "mdef.h" #include "gt_timer.h" +#include "gtm_ipv6.h" /* for union gtm_sockaddr_in46 */ /* Needs mdef.h, gdsfhead.h and its dependencies */ #define JNLPOOL_DUMMY_REG_NAME "JNLPOOL_REG" #define MAX_FILTER_CMD_LEN 512 #define MIN_JNLPOOL_SIZE (1 * 1024 * 1024) +#define MAX_FREEZE_COMMENT_LEN 1024 +/* We need space in the journal pool to let other processes know which error messages should trigger anticipatory freeze. + * Instead of storing them as a list, allocate one byte for each error message. Currently, the only piece of information + * associated with each error message is whether it can trigger anticipatory freeze or not. + */ +#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 */ @@ -41,7 +44,9 @@ enum enum { GTMSOURCE_MODE_PASSIVE, - GTMSOURCE_MODE_ACTIVE + GTMSOURCE_MODE_ACTIVE, + GTMSOURCE_MODE_PASSIVE_REQUESTED, + GTMSOURCE_MODE_ACTIVE_REQUESTED }; enum @@ -75,9 +80,6 @@ typedef enum GTMSOURCE_NUM_STATES } gtmsource_state_t; -#define MAX_GTMSOURCE_POLL_WAIT 1000000 /* 1s in micro secs */ -#define GTMSOURCE_POLL_WAIT (MAX_GTMSOURCE_POLL_WAIT - 1) /* micro sec, almost 1s */ - #define GTMSOURCE_WAIT_FOR_RECEIVER_TO_QUIT 5 /* seconds */ #define GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN (1000 - 1) /* ms */ #define GTMSOURCE_WAIT_FOR_JNLOPEN 10 /* ms */ @@ -87,6 +89,7 @@ typedef enum #define GTMSOURCE_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1 sec */ #define GTMSOURCE_WAIT_FOR_SOURCESTART (1000 - 1) /* ms, almost 1 sec */ #define GTMSOURCE_WAIT_FOR_FIRSTHISTINFO (1000 - 1) /* ms, almost 1 sec */ +#define LOG_WAIT_FOR_JNLOPEN_TIMES 5 /* Number of times the source logs wait_for_jnlopen */ /* Wait for a max of 2 minutes on a single region database as all the source server shutdown * timeouts seen so far have been on a single region database. For multi-region databases, wait @@ -111,8 +114,9 @@ typedef enum #define GTMSOURCE_FH_FLUSH_INTERVAL 60 /* seconds, if required, flush file header(s) every these many seconds */ typedef struct -{ /* IMPORTANT : all fields that are used by the source server reading from pool logic must be defined VOLATILE to avoid compiler - * optimization, forcing fresh load on every access */ +{ /* IMPORTANT : all fields that are used by the source server reading from pool logic must be defined VOLATILE to avoid + * compiler optimization, forcing fresh load on every access. + */ replpool_identifier jnlpool_id; sm_off_t critical_off; /* Offset from the start of this structure to "csa->critical" in jnlpool */ sm_off_t filehdr_off; /* Offset to "repl_inst_filehdr" section in jnlpool */ @@ -170,12 +174,18 @@ typedef struct boolean_t pool_initialized; /* Set to TRUE only after completely finished with initialization. * Anyone who does a "jnlpool_init" before this will issue a error. */ - uint4 filler_8byte_align; + uint4 jnlpool_creator_pid; /* DEBUG-ONLY field used for fake ENOSPC testing */ repl_conn_info_t this_side; /* Replication connection details of this side/instance */ seq_num strm_seqno[MAX_SUPPL_STRMS]; /* the current jnl seqno of each stream */ volatile uint4 onln_rlbk_pid; /* process ID of currently running ONLINE ROLLBACK. 0 if none. */ volatile uint4 onln_rlbk_cycle; /* incremented everytime an ONLINE ROLLBACK ends */ - unsigned char filler_align_16[8]; /* for 16-byte alignment */ + boolean_t freeze; /* Freeze all regions in this instance. */ + char freeze_comment[MAX_FREEZE_COMMENT_LEN]; /* Text explaining reason for freeze */ + boolean_t instfreeze_environ_inited; + unsigned char merrors_array[MERRORS_ARRAY_SZ]; + /* Note: while adding fields to this structure, keep in mind that it needs to be 16-byte aligned so add filler bytes + * as necessary + */ } jnlpool_ctl_struct; #if defined(__osf__) && defined(__alpha) @@ -197,9 +207,9 @@ typedef struct gtmsrc_lcl_struct *gtmsrc_lcl_ptr_t; * * struct jnlpool_trans_struct * { - * jnldata_hdr_struct jnldata_hdr; - jnldata_hdr.jnldata_len - * is the length of journal - * data of a transaction + * jnldata_hdr_struct jnldata_hdr; - jnldata_hdr.jnldata_len + * is the length of journal + * data of a transaction * uchar jnldata[jnldata_len]; - transaction journal * data * }; @@ -213,11 +223,9 @@ typedef struct gtmsrc_lcl_struct *gtmsrc_lcl_ptr_t; **********************************************************************/ typedef struct { - uint4 jnldata_len; /* length of the journal data of a - * a transaction in bytes */ - uint4 prev_jnldata_len; /* length of the journal data of - * the previous transaction in the - * journal pool (in bytes) */ + uint4 jnldata_len; /* length of the journal data of a transaction in bytes */ + uint4 prev_jnldata_len; /* length of the journal data of the previous transaction in the + * journal pool (in bytes) */ } jnldata_hdr_struct; #if defined(__osf__) && defined(__alpha) @@ -237,8 +245,8 @@ typedef jnldata_hdr_struct *jnldata_hdr_ptr_t; #define REPL_CONN_ALERT_ALERT_PERIOD 30 /* sec Default alert period*/ #define REPL_CONN_HEARTBEAT_PERIOD 15 /* sec Default heartbeat period */ #define REPL_CONN_HEARTBEAT_MAX_WAIT 60 /* sec Default heartbeat maximum waiting period */ - -#define REPL_MAX_CONN_HARD_TRIES_PERIOD 1000 /* ms */ +#define REPL_MAX_CONN_HARD_TRIES_PERIOD 1000 /* ms */ +#define REPL_MAX_LOG_PERIOD 150 /* sec Maximum logging period */ enum { @@ -255,7 +263,8 @@ enum #define JNLPOOL_SEGMENT 'J' /*************** Macro to send a REPL_HISTREC message, given an histinfo type of record ***************/ -#define GTMSOURCE_SEND_REPL_HISTREC(HSTINFO, GTMSRCLCL, RCVR_SAME_ENDIANNESS) \ +/* Note that HSTINFO.start_seqno is modified by this macro */ +#define GTMSOURCE_SEND_REPL_HISTREC(HSTINFO, GTMSRCLCL, RCVR_CROSS_ENDIAN) \ { \ repl_histrec_msg_t histrec_msg; \ \ @@ -263,9 +272,10 @@ enum histrec_msg.type = REPL_HISTREC; \ histrec_msg.len = SIZEOF(repl_histrec_msg_t); \ histrec_msg.histjrec.jrec_type = JRT_HISTREC; \ + /* Update history record's start_seqno to reflect the starting point of transmission */ \ + HSTINFO.start_seqno = GTMSRCLCL->read_jnl_seqno; \ histrec_msg.histjrec.histcontent = HSTINFO; \ - histrec_msg.histjrec.histcontent.start_seqno = GTMSRCLCL->read_jnl_seqno; \ - if (!RCVR_SAME_ENDIANNESS && (this_side->jnl_ver < remote_side->jnl_ver)) \ + if (RCVR_CROSS_ENDIAN && (this_side->jnl_ver < remote_side->jnl_ver)) \ { \ histrec_msg.histjrec.forwptr = GTM_BYTESWAP_24(SIZEOF(repl_histrec_jnl_t)); \ ENDIAN_CONVERT_REPL_HISTINFO(&histrec_msg.histjrec.histcontent); \ @@ -321,7 +331,9 @@ typedef struct * FALSE after the message gets sent. */ char secondary_host[MAX_HOST_NAME_LEN]; /* hostname of the secondary */ - uint4 secondary_inet_addr; /* IP address of the secondary */ + union gtm_sockaddr_in46 secondary_inet_addr; /* IP address of the secondary */ + int secondary_af; /* address family of the seconary */ + int secondary_addrlen; /* length of the secondary address */ uint4 secondary_port; /* Port at which Receiver is listening */ boolean_t child_server_running; /* Set to FALSE before starting a source server; * Set to TRUE by the source server process after its initialization. @@ -338,6 +350,9 @@ 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; +#if 0 + int4 padding; /* Pad structure out to multiple of 8 bytes - un-"#if 0" if needed */ +#endif } gtmsource_local_struct; #if defined(__osf__) && defined(__alpha) @@ -368,7 +383,7 @@ typedef gtmsource_local_struct *gtmsource_local_ptr_t; /* Push the jnldata_base_off to be aligned to (~JNL_WRT_END_MASK + 1)-byte boundary */ #define JNLPOOL_CTL_SIZE ROUND_UP(SIZEOF(jnlpool_ctl_struct), CACHELINE_SIZE) /* align crit semaphore at cache line */ -#define JNLPOOL_CRIT_SIZE (CRIT_SPACE + SIZEOF(mutex_spin_parms_struct) + SIZEOF(node_local)) +#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 @@ -410,11 +425,14 @@ typedef jnlpool_addrs *jnlpool_addrs_ptr_t; /* Types of processes that can do jnlpool_init */ typedef enum { - GTMPROC, /* For GT.M */ - GTMSOURCE, /* For source server */ - GTMRECEIVE /* For receiver server. Note this name should be different from GTMRECV which is defined to server + GTMPROC, /* For GT.M and Update Process */ + GTMSOURCE, /* For Source Server */ + GTMRECEIVE, /* For Receiver Server. Note this name should be different from GTMRECV which is defined to serve * a similar purpose in gtmrecv.h for processes that do recvpool_init. */ + GTMRELAXED, /* For processes which want to a attach to an existing journal pool without the usual validations (currently + * NOJNLPOOL is the only validation that is skipped) + */ } jnlpool_user; typedef struct @@ -436,11 +454,14 @@ typedef struct boolean_t instsecondary; /* TRUE if -INSTSECONDARY is explicitly or implicitly specified, FALSE otherwise */ boolean_t needrestart; /* TRUE if -NEEDRESTART was specified, FALSE otherwise */ boolean_t losttncomplete; /* TRUE if -LOSTTNCOMPLETE was specified, FALSE otherwise */ + boolean_t showfreeze; /* TRUE if -FREEZE was specified with no value, FALSE otherwise */ + 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 */ int4 cmplvl; int4 shutdown_time; int4 buffsize; int4 mode; - in_addr_t sec_inet_addr; /* 32 bits */ int4 secondary_port; uint4 src_log_interval; int4 connect_parms[GTMSOURCE_CONN_PARMS_COUNT]; @@ -448,34 +469,14 @@ typedef struct char secondary_host[MAX_HOST_NAME_LEN]; char log_file[MAX_FN_LEN + 1]; char secondary_instname[MAX_INSTNAME_LEN]; /* instance name specified in -INSTSECONDARY qualifier */ + char freeze_comment[MAX_FREEZE_COMMENT_LEN]; } gtmsource_options_t; -#define ASSERT_VALID_JNLPOOL(CSA) \ -{ \ - GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ - GBLREF jnlpool_addrs jnlpool; \ - \ - assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \ - assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \ - assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \ - assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + CRIT_SPACE \ - + SIZEOF(mutex_spin_parms_struct))); \ - assert(jnlpool_ctl->filehdr_off); \ - assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \ - assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \ - assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->filehdr_off)); \ - assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->srclcl_array_off)); \ - assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ - + jnlpool_ctl->sourcelocal_array_off)); \ -} - /********** Source server function prototypes **********/ int gtmsource(void); boolean_t gtmsource_is_heartbeat_overdue(time_t *now, repl_heartbeat_msg_ptr_t overdue_heartbeat); int gtmsource_alloc_filter_buff(int bufsiz); -int gtmsource_alloc_msgbuff(int maxbuffsize); +int gtmsource_alloc_msgbuff(int maxbuffsize, boolean_t discard_oldbuff); int gtmsource_alloc_tcombuff(void); void gtmsource_free_filter_buff(void); void gtmsource_free_msgbuff(void); @@ -487,7 +488,7 @@ int gtmsource_ctl_close(void); int gtmsource_ctl_init(void); int gtmsource_jnlpool(void); int gtmsource_end1(boolean_t auto_shutdown); -int gtmsource_est_conn(struct sockaddr_in *secondary_addr); +int gtmsource_est_conn(void); int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple); int gtmsource_get_opt(void); int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_src_servers_running); @@ -506,7 +507,6 @@ int gtmsource_stopfilter(void); int gtmsource_update_zqgblmod_seqno_and_tn(seq_num resync_seqno); void gtmsource_end(void); void gtmsource_exit(int exit_status); -void gtmsource_init_sec_addr(struct sockaddr_in *secondary_addr); void gtmsource_seqno_init(boolean_t this_side_std_null_coll); void gtmsource_stop(boolean_t exit); void gtmsource_sigstop(void); @@ -526,5 +526,7 @@ void gtmsource_jnl_release_timer(TID tid, int4 interval_len, int *interval_ptr) int gtmsource_start_jnl_release_timer(void); int gtmsource_stop_jnl_release_timer(void); void gtmsource_onln_rlbk_clnup(void); +int gtmsource_showfreeze(void); +int gtmsource_setfreeze(void); #endif /* GTMSOURCE_H */ diff --git a/sr_unix/gtmsource_changelog.c b/sr_unix/gtmsource_changelog.c index 049df11..e213730 100644 --- a/sr_unix/gtmsource_changelog.c +++ b/sr_unix/gtmsource_changelog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006 Fidelity Information Services, Inc.* + * Copyright 2006, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,7 +10,9 @@ ****************************************************************/ #include "mdef.h" - +#include "gtm_fcntl.h" +#include "gtmio.h" +#include "repl_sp.h" #include "gtm_time.h" #include "gtm_string.h" #include "gtm_inet.h" /* Required for gtmsource.h */ @@ -37,10 +39,14 @@ GBLREF jnlpool_addrs jnlpool; GBLREF gtmsource_options_t gtmsource_options; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; - +error_def(ERR_REPLLOGOPN); int gtmsource_changelog(void) { uint4 changelog_desired = 0, changelog_accepted = 0; + int log_fd = 0; /*used to indicate whether the new specified log file is writable*/ + int close_status = 0; /*used to indicate if log file is successfully closed*/ + char* err_code; + int save_errno; assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); repl_log(stderr, TRUE, TRUE, "Initiating CHANGELOG operation on source server pid [%d] for secondary instance [%s]\n", @@ -54,10 +60,23 @@ int gtmsource_changelog(void) { changelog_desired |= REPLIC_CHANGE_LOGFILE; if (0 != STRCMP(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file)) - { - changelog_accepted |= REPLIC_CHANGE_LOGFILE; - STRCPY(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file); - util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmsource_options.log_file)); + { /*check if the new log file is writable*/ + OPENFILE3(gtmsource_options.log_file, + O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, log_fd); + if (log_fd < 0) { + save_errno = ERRNO; + err_code = STRERROR(save_errno); + gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, + LEN_AND_STR(gtmsource_options.log_file), + LEN_AND_STR(err_code), + LEN_AND_STR(NULL_DEVICE)); + } else { + CLOSEFILE_IF_OPEN(log_fd, close_status); + assert(close_status==0); + changelog_accepted |= REPLIC_CHANGE_LOGFILE; + STRCPY(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file); + util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmsource_options.log_file)); + } } else util_out_print("Log file is already !AD. Not initiating change in log file", TRUE, LEN_AND_STR(gtmsource_options.log_file)); diff --git a/sr_unix/gtmsource_checkhealth.c b/sr_unix/gtmsource_checkhealth.c index bc9af4a..d9618c0 100644 --- a/sr_unix/gtmsource_checkhealth.c +++ b/sr_unix/gtmsource_checkhealth.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -49,10 +49,14 @@ GBLREF gtmsource_options_t gtmsource_options; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; GBLREF gd_addr *gd_header; +error_def(ERR_NOTALLDBOPN); +error_def(ERR_REPLJNLCLOSED); +error_def(ERR_SRCSRVNOTEXIST); + int gtmsource_checkhealth(void) { uint4 gtmsource_pid; - int status, semval; + int status, semval, save_errno; boolean_t srv_alive, all_files_open; gtmsource_local_ptr_t gtmsourcelocal_ptr; int4 index, num_servers; @@ -61,10 +65,7 @@ int gtmsource_checkhealth(void) sgmnt_addrs *csa; sgmnt_data_ptr_t csd; char errtxt[OUT_BUFF_SIZE]; - - error_def(ERR_NOTALLDBOPN); - error_def(ERR_REPLJNLCLOSED); - error_def(ERR_SRCSRVNOTEXIST); + char *modestr; assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); if (NULL != jnlpool.gtmsource_local) /* Check health of a specific source server */ @@ -92,14 +93,27 @@ int gtmsource_checkhealth(void) srv_alive = (0 == gtmsource_pid) ? FALSE : is_proc_alive(gtmsource_pid, 0); if (srv_alive) { - repl_log(stderr, FALSE, TRUE, FORMAT_STR1, gtmsource_pid, "Source server", "", - ((GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) ? "ACTIVE" : "PASSIVE")); + if (GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) + modestr = "ACTIVE"; + else if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsourcelocal_ptr->mode) + modestr = "ACTIVE REQUESTED"; + else if (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode) + modestr = "PASSIVE"; + else if (GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsourcelocal_ptr->mode) + modestr = "PASSIVE REQUESTED"; + else + { + assert(gtmsourcelocal_ptr->mode != gtmsourcelocal_ptr->mode); + modestr = "UNKNOWN"; + } + repl_log(stderr, FALSE, TRUE, FORMAT_STR1, gtmsource_pid, "Source server", "", modestr); status |= SRV_ALIVE; num_servers++; } else { repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmsource_pid, "Source server", " NOT"); - gtm_putmsg(VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2, LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2, + LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname)); status |= SRV_DEAD; } if (NULL != jnlpool.gtmsource_local) @@ -112,8 +126,9 @@ int gtmsource_checkhealth(void) semval = get_sem_info(SOURCE, SRC_SERV_COUNT_SEM, SEM_INFO_VAL); if (-1 == semval) { + save_errno = errno; repl_log(stderr, FALSE, TRUE, - "Error fetching source server count semaphore value : %s\n", REPL_SEM_ERROR); + "Error fetching source server count semaphore value : %s\n", STRERROR(save_errno)); status |= SRV_ERR; } else if (semval != num_servers) { @@ -132,7 +147,7 @@ int gtmsource_checkhealth(void) all_files_open = region_init(FALSE); if (!all_files_open) { - gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN); status |= SRV_ERR; } else { @@ -152,5 +167,11 @@ int gtmsource_checkhealth(void) } } } + if (jnlpool.jnlpool_ctl->freeze) + { + repl_log(stderr, FALSE, FALSE, "Warning: Instance Freeze is ON\n"); + repl_log(stderr, FALSE, TRUE, " Freeze Comment: %s\n", jnlpool.jnlpool_ctl->freeze_comment); + status |= SRV_ERR; + } return (status + NORMAL_SHUTDOWN); } diff --git a/sr_unix/gtmsource_end.c b/sr_unix/gtmsource_end.c index f131143..c7b714e 100644 --- a/sr_unix/gtmsource_end.c +++ b/sr_unix/gtmsource_end.c @@ -40,6 +40,8 @@ #include "mutex.h" #include "repl_log.h" #include "repl_comm.h" +#include "have_crit.h" +#include "anticipatory_freeze.h" GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; @@ -62,11 +64,13 @@ GBLREF boolean_t pool_init; int gtmsource_end1(boolean_t auto_shutdown) { - int exit_status, idx; + int exit_status, idx, status, save_errno; seq_num read_jnl_seqno, jnlpool_seqno, diff_seqno, jnlpool_strm_seqno[MAX_SUPPL_STRMS]; int fclose_res; sgmnt_addrs *repl_csa; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; gtmsource_ctl_close(); DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke and "rel_lock" unconditionally */ @@ -81,11 +85,11 @@ int gtmsource_end1(boolean_t auto_shutdown) jnlpool_strm_seqno[idx] = jnlpool.jnlpool_ctl->strm_seqno[idx]; jnlpool.gtmsource_local->gtmsource_pid = 0; jnlpool.gtmsource_local->gtmsource_state = GTMSOURCE_DUMMY_STATE; - if (!auto_shutdown) + if (!auto_shutdown && !ANTICIPATORY_FREEZE_AVAILABLE) { /* Detach from journal pool */ - if (jnlpool.jnlpool_ctl && 0 > SHMDT(jnlpool.jnlpool_ctl)) - repl_log(gtmsource_log_fp, FALSE, TRUE, "Error detaching from journal pool : %s\n", REPL_STR_ERROR); - jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; + JNLPOOL_SHMDT(status, save_errno); + if (0 > status) + repl_log(gtmsource_log_fp, FALSE, TRUE, "Error detaching from journal pool : %s\n", STRERROR(save_errno)); jnlpool.repl_inst_filehdr = NULL; jnlpool.gtmsrc_lcl_array = NULL; jnlpool.gtmsource_local_array = NULL; diff --git a/sr_unix/gtmsource_flush_fh.c b/sr_unix/gtmsource_flush_fh.c index 0be873a..c00c6fe 100644 --- a/sr_unix/gtmsource_flush_fh.c +++ b/sr_unix/gtmsource_flush_fh.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -42,7 +42,7 @@ void gtmsource_flush_fh(seq_num resync_seqno) if (jnlpool.gtmsource_local->last_flush_resync_seqno == resync_seqno) return; /* need to flush resync_seqno to instance file. Grab the journal pool lock before flushing */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); /* sets gtmsource_state */ + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); /* sets gtmsource_state */ if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return; repl_inst_flush_gtmsrc_lcl(); /* this requires the ftok semaphore to be held */ diff --git a/sr_unix/gtmsource_get_opt.c b/sr_unix/gtmsource_get_opt.c index 025c606..0510bc9 100644 --- a/sr_unix/gtmsource_get_opt.c +++ b/sr_unix/gtmsource_get_opt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ #include "gtm_inet.h" #include "gtm_string.h" #include "gtm_ctype.h" -#if !defined(__MVS__) && !defined(VMS) && !defined(__CYGWIN__) +#if !defined(__MVS__) && !defined(VMS) && !defined(__CYGWIN__) && (!defined(__GNUC__) && defined(__hpux)) #include #endif #ifdef VMS @@ -56,9 +56,11 @@ GBLREF gtmsource_options_t gtmsource_options; +error_def(ERR_GETADDRINFO); error_def(ERR_LOGTOOLONG); error_def(ERR_REPLINSTSECLEN); error_def(ERR_REPLINSTSECUNDF); +error_def(ERR_TEXT); int gtmsource_get_opt(void) { @@ -66,13 +68,19 @@ int gtmsource_get_opt(void) char *connect_parm_token_str, *connect_parm; char *connect_parms_str, tmp_connect_parms_str[GTMSOURCE_CONN_PARMS_LEN + 1]; char secondary_sys[MAX_SECONDARY_LEN], *c, inst_name[MAX_FN_LEN + 1]; - char statslog_val[4]; /* "ON" or "OFF" */ + char statslog_val[SIZEOF("OFF")]; /* "ON" or "OFF" */ char update_val[SIZEOF("DISABLE")]; /* "ENABLE" or "DISABLE" */ + char freeze_val[SIZEOF("OFF")]; /* "ON" or "OFF" */ + char freeze_comment[SIZEOF(gtmsource_options.freeze_comment)]; int tries, index = 0, timeout_status, connect_parms_index, status; mstr log_nam, trans_name; struct hostent *sec_hostentry; unsigned short log_file_len, filter_cmd_len; unsigned short secondary_len, inst_name_len, statslog_val_len, update_val_len, connect_parms_str_len; + unsigned short freeze_val_len, freeze_comment_len; + int errcode; + int port_len; + char *ip_end; memset((char *)>msource_options, 0, SIZEOF(gtmsource_options)); gtmsource_options.start = (CLI_PRESENT == cli_present("START")); @@ -134,9 +142,9 @@ int gtmsource_get_opt(void) } else if (!gtmsource_options.checkhealth && !gtmsource_options.showbacklog && !gtmsource_options.shut_down) { if (SS_LOG2LONG == status) - gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, log_nam.len, log_nam.addr, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, log_nam.len, log_nam.addr, SIZEOF(inst_name) - 1); - gtm_putmsg(VARLSTCNT(1) ERR_REPLINSTSECUNDF); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLINSTSECUNDF); return (-1); } } @@ -146,7 +154,7 @@ int gtmsource_get_opt(void) inst_name[inst_name_len] = '\0'; if ((MAX_INSTNAME_LEN <= inst_name_len) || (0 == inst_name_len)) { - gtm_putmsg(VARLSTCNT(4) ERR_REPLINSTSECLEN, 2, inst_name_len, inst_name); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINSTSECLEN, 2, inst_name_len, inst_name); return (-1); } assert((inst_name_len + 1) <= MAX_INSTNAME_LEN); @@ -166,50 +174,37 @@ int gtmsource_get_opt(void) * and secondary_port */ c = secondary_sys; dotted_notation = TRUE; - while(*c && *c != ':') + if ('[' == *c) { - if ('.' != *c && !ISDIGIT_ASCII(*c)) - dotted_notation = FALSE; - gtmsource_options.secondary_host[index++] = *c++; + ip_end = strchr(++c, ']'); + if (NULL == ip_end || 0 == (index = ip_end - c)) + { + util_out_print("Invalid IP address !AD", TRUE, + LEN_AND_STR(secondary_sys)); + return(-1); + } + memcpy(gtmsource_options.secondary_host, c, index); + gtmsource_options.secondary_host[index] = '\0'; + c = ip_end + 1; + } else + { + while(*c && (':' != *c)) + gtmsource_options.secondary_host[index++] = *c++; + gtmsource_options.secondary_host[index] = '\0'; } - gtmsource_options.secondary_host[index] = '\0'; if (':' != *c) { util_out_print("Secondary port number should be specified", TRUE); return(-1); } + port_len = strlen(++c); errno = 0; - if (((0 == (gtmsource_options.secondary_port = ATOI(++c))) && (0 != errno)) + if (((0 == (gtmsource_options.secondary_port = ATOI(c))) && (0 != errno)) || (0 >= gtmsource_options.secondary_port)) { util_out_print("Error parsing secondary port number !AD", TRUE, LEN_AND_STR(c)); return(-1); } - /* Validate the specified secondary host name */ - if (dotted_notation) - { - if ((in_addr_t)-1 == - (gtmsource_options.sec_inet_addr = INET_ADDR(gtmsource_options.secondary_host))) - { - util_out_print("Invalid IP address !AD", TRUE, - LEN_AND_STR(gtmsource_options.secondary_host)); - return(-1); - } - } else - { - for (tries = 0; - tries < MAX_GETHOST_TRIES && - !(sec_hostentry = GETHOSTBYNAME(gtmsource_options.secondary_host)) && - h_errno == TRY_AGAIN; - tries++); - if (NULL == sec_hostentry) - { - util_out_print("Could not find IP address for !AD", TRUE, - LEN_AND_STR(gtmsource_options.secondary_host)); - return(-1); - } - gtmsource_options.sec_inet_addr = ((struct in_addr *)sec_hostentry->h_addr_list[0])->s_addr; - } } if (CLI_PRESENT == cli_present("CONNECTPARAMS")) { @@ -382,9 +377,58 @@ int gtmsource_get_opt(void) gtmsource_options.statslog = FALSE; else { - util_out_print("Invalid value for STATSLOG qualifier, should be either ON or OFF", TRUE); + util_out_print("Invalid value for STATSLOG qualifier, must be either ON or OFF", TRUE); return(-1); } } + if (cli_present("FREEZE") == CLI_PRESENT) + { + freeze_val_len = SIZEOF(freeze_val); + if (cli_get_str("FREEZE", freeze_val, &freeze_val_len)) + { + gtmsource_options.setfreeze = TRUE; + cli_strupper(freeze_val); + if (0 == STRCMP(freeze_val, "ON")) + gtmsource_options.freezeval = TRUE; + else if (0 == STRCMP(freeze_val, "OFF")) + gtmsource_options.freezeval = FALSE; + else + { + util_out_print("Invalid value for FREEZE qualifier, must be either ON or OFF", TRUE); + return -1; + } + if (cli_present("COMMENT") == CLI_PRESENT) + { + if (!gtmsource_options.freezeval) + { + util_out_print("Invalid qualifier combination, cannot specify FREEZE=OFF with COMMENT", + TRUE); + return -1; + } + freeze_comment_len = SIZEOF(freeze_comment); + if (!cli_get_str("COMMENT", freeze_comment, &freeze_comment_len)) + { + util_out_print("Error parsing COMMENT qualifier", TRUE); + return -1; + } + gtmsource_options.setcomment = TRUE; + STRNCPY_STR(gtmsource_options.freeze_comment, freeze_comment, + SIZEOF(gtmsource_options.freeze_comment) - 1); + gtmsource_options.freeze_comment[SIZEOF(gtmsource_options.freeze_comment) - 1] = '\0'; + } + else if (cli_present("COMMENT") == CLI_NEGATED) + { + gtmsource_options.setcomment = TRUE; + gtmsource_options.freeze_comment[0] = '\0'; + } + else if (gtmsource_options.freezeval) + { + util_out_print("Missing qualifier, must specify either COMMENT or NOCOMMENT with FREEZE=ON", TRUE); + return -1; + } + } + else + gtmsource_options.showfreeze = TRUE; + } return(0); } diff --git a/sr_unix/gtmsource_heartbeat.c b/sr_unix/gtmsource_heartbeat.c index e59893a..bf50cc4 100644 --- a/sr_unix/gtmsource_heartbeat.c +++ b/sr_unix/gtmsource_heartbeat.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,9 +46,6 @@ GBLREF int gtmsource_sock_fd; GBLREF boolean_t gtmsource_logstats; GBLREF int gtmsource_log_fd; GBLREF FILE *gtmsource_log_fp; -GBLREF int gtmsource_statslog_fd; -GBLREF FILE *gtmsource_statslog_fp; -GBLREF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate; GBLREF gtmsource_state_t gtmsource_state; GBLREF gd_addr *gd_header; @@ -58,6 +55,9 @@ GBLDEF repl_heartbeat_que_entry_t *repl_heartbeat_free_head = NULL; GBLDEF volatile time_t gtmsource_now; GBLDEF time_t last_sent_time, earliest_sent_time; +error_def(ERR_REPLCOMM); +error_def(ERR_TEXT); + static int heartbeat_period, heartbeat_max_wait; void gtmsource_heartbeat_timer(TID tid, int4 interval_len, int *interval_ptr) @@ -75,9 +75,6 @@ int gtmsource_init_heartbeat(void) int num_q_entries; repl_heartbeat_que_entry_t *heartbeat_element; - error_def(ERR_REPLCOMM); - error_def(ERR_TEXT); - assert(NULL == repl_heartbeat_que_head); heartbeat_period = jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD]; @@ -86,8 +83,8 @@ int gtmsource_init_heartbeat(void) REPL_DPRINT4("Initialized heartbeat, heartbeat_period = %d s, heartbeat_max_wait = %d s, num_q_entries = %d\n", heartbeat_period, heartbeat_max_wait, num_q_entries); if (!(repl_heartbeat_que_head = (repl_heartbeat_que_entry_t *)malloc(num_q_entries * SIZEOF(repl_heartbeat_que_entry_t)))) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in allocating heartbeat queue"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error in allocating heartbeat queue"), errno); memset(repl_heartbeat_que_head, 0, num_q_entries * SIZEOF(repl_heartbeat_que_entry_t)); repl_heartbeat_free_head = repl_heartbeat_que_head + 1; @@ -170,26 +167,20 @@ int gtmsource_send_heartbeat(time_t *now) unsigned char seq_num_str[32], *seq_num_ptr; gtmsource_local_ptr_t gtmsource_local; - error_def(ERR_REPLCOMM); - error_def(ERR_TEXT); - heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_free_head); if (NULL == heartbeat_element) /* Too many pending heartbeats, send later */ return (SS_NORMAL); - QWASSIGN(*(seq_num *)&heartbeat_element->heartbeat.ack_seqno[0], jnlpool.jnlpool_ctl->jnl_seqno); *(gtm_time4_t *)&heartbeat_element->heartbeat.ack_time[0] = (gtm_time4_t)(*now); heartbeat_element->heartbeat.type = REPL_HEARTBEAT; heartbeat_element->heartbeat.len = MIN_REPL_MSGLEN; - REPL_SEND_LOOP(gtmsource_sock_fd, &heartbeat_element->heartbeat, MIN_REPL_MSGLEN, FALSE, >msource_poll_immediate) + REPL_SEND_LOOP(gtmsource_sock_fd, &heartbeat_element->heartbeat, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT) { gtmsource_poll_actions(FALSE); /* Recursive call */ - if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state || - GTMSOURCE_CHANGING_MODE == gtmsource_state) + if ((GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) || (GTMSOURCE_CHANGING_MODE == gtmsource_state)) return (SS_NORMAL); } - if (SS_NORMAL == status) { insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_que_head); @@ -213,12 +204,12 @@ int gtmsource_send_heartbeat(time_t *now) return (SS_NORMAL); } if (EREPL_SEND == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending HEARTBEAT message. Error in send"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending HEARTBEAT message. Error in send"), status); if (EREPL_SELECT == repl_errno) - rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error sending HEARTBEAT message. Error in select"), status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error sending HEARTBEAT message. Error in select"), status); GTMASSERT; return -1; /* This will never get executed, added to make compiler happy */ diff --git a/sr_unix/gtmsource_losttncomplete.c b/sr_unix/gtmsource_losttncomplete.c index 8595c37..481f864 100644 --- a/sr_unix/gtmsource_losttncomplete.c +++ b/sr_unix/gtmsource_losttncomplete.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,14 +35,12 @@ GBLREF jnlpool_addrs jnlpool; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; -error_def(ERR_MUPCLIERR); -error_def(ERR_TEXT); - int gtmsource_losttncomplete(void) { int idx; gtmsource_local_ptr_t gtmsourcelocal_ptr; sgmnt_addrs *repl_csa; + uint4 exit_status; assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); assert(NULL == jnlpool.gtmsource_local); @@ -56,7 +54,7 @@ int gtmsource_losttncomplete(void) { DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); jnlpool.jnlpool_ctl->send_losttn_complete = TRUE; gtmsourcelocal_ptr = jnlpool.gtmsource_local_array; for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsourcelocal_ptr++) @@ -70,11 +68,13 @@ int gtmsource_losttncomplete(void) rel_lock(jnlpool.jnlpool_dummy_reg); } /* Reset zqgblmod_seqno and zqgblmod_tn to 0 in this instance as well */ - if (SS_NORMAL != repl_inst_reset_zqgblmod_seqno_and_tn()) - { /* Only reason we know of the above function returning error is in case of an online rollback. But, that's not + exit_status = repl_inst_reset_zqgblmod_seqno_and_tn(); + if (SS_NORMAL != exit_status) + { /* Only reason we know of the above function returning -1 is in case of an online rollback. But, that's not * possible because we hold the access control semaphore at this point which online rollback needs at startup. + * Also in case of gds_rundown failure the function returns EXIT_ERR which results in an assert failure here. */ assert(FALSE); } - return (NORMAL_SHUTDOWN); + return (exit_status + NORMAL_SHUTDOWN); } diff --git a/sr_unix/gtmsource_mode_change.c b/sr_unix/gtmsource_mode_change.c index 2f0dbf6..bc1470f 100644 --- a/sr_unix/gtmsource_mode_change.c +++ b/sr_unix/gtmsource_mode_change.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,12 +16,9 @@ #include "gtm_unistd.h" #include "gtm_inet.h" #include "gtm_string.h" - +#include "gtmio.h" +#include "repl_sp.h" #include -#ifdef VMS -#include /* Required for gtmsource.h */ -#endif - #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" @@ -41,26 +38,55 @@ GBLREF jnlpool_addrs jnlpool; GBLREF gtmsource_options_t gtmsource_options; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +error_def(ERR_REPLLOGOPN); int gtmsource_mode_change(int to_mode) { uint4 savepid; int exit_status; int status, detach_status, remove_status; + int log_fd = 0, close_status = 0; + char* err_code; + int save_errno; sgmnt_addrs *repl_csa; assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); repl_log(stdout, TRUE, TRUE, "Initiating %s operation on source server pid [%d] for secondary instance [%s]\n", - (GTMSOURCE_MODE_ACTIVE == to_mode) ? "ACTIVATE" : "DEACTIVATE", + (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) ? "ACTIVATE" : "DEACTIVATE", jnlpool.gtmsource_local->gtmsource_pid, jnlpool.gtmsource_local->secondary_instname); - if (jnlpool.gtmsource_local->mode == to_mode) + if ((jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) + || (jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE_REQUESTED)) + { + repl_log(stderr, FALSE, TRUE, "Source Server %s already requested, not changing mode\n", + (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVATE" : "DEACTIVATE"); + return (ABNORMAL_SHUTDOWN); + } + if (((GTMSOURCE_MODE_ACTIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode)) + || ((GTMSOURCE_MODE_PASSIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_PASSIVE_REQUESTED == to_mode))) { repl_log(stderr, FALSE, TRUE, "Source Server already %s, not changing mode\n", - (to_mode == GTMSOURCE_MODE_ACTIVE) ? "ACTIVE" : "PASSIVE"); + (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVE" : "PASSIVE"); return (ABNORMAL_SHUTDOWN); } assert(ROOTPRIMARY_UNSPECIFIED != gtmsource_options.rootprimary); - if ((GTMSOURCE_MODE_ACTIVE == to_mode) + /*check if the new log file is writable*/ + if ('\0' != gtmsource_options.log_file[0] && 0 != STRCMP(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file)) + { + OPENFILE3(gtmsource_options.log_file, + O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, log_fd); + if (log_fd < 0) { + save_errno = ERRNO; + err_code = STRERROR(save_errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLLOGOPN, 6, + LEN_AND_STR(gtmsource_options.log_file), + LEN_AND_STR(err_code), + LEN_AND_STR(NULL_DEVICE)); + return (ABNORMAL_SHUTDOWN); + } + CLOSEFILE_IF_OPEN(log_fd, close_status); + assert(close_status==0); + } + if ((GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) && (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary) && jnlpool.jnlpool_ctl->upd_disabled) { /* ACTIVATE is specified with ROOTPRIMARY on a journal pool that was created with PROPAGATEPRIMARY. This is a * case of transition from propagating primary to root primary. Enable updates in this journal pool and append @@ -70,16 +96,16 @@ int gtmsource_mode_change(int to_mode) } DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); /* Any ACTIVATE/DEACTIVATE versus ROOTPRIMARY/PROPAGATE incompatibilities have already been checked in the * function "jnlpool_init" so go ahead and document the impending activation/deactivation and return. * This flag will be eventually detected by the concurrently running source server which will then change mode. */ - if (GTMSOURCE_MODE_ACTIVE == to_mode) + if (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) { jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port; - jnlpool.gtmsource_local->secondary_inet_addr = gtmsource_options.sec_inet_addr; STRCPY(jnlpool.gtmsource_local->secondary_host, gtmsource_options.secondary_host); + jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port; memcpy(&jnlpool.gtmsource_local->connect_parms[0], >msource_options.connect_parms[0], SIZEOF(gtmsource_options.connect_parms)); } diff --git a/sr_unix/gtmsource_needrestart.c b/sr_unix/gtmsource_needrestart.c index b3f65a5..7f1090e 100644 --- a/sr_unix/gtmsource_needrestart.c +++ b/sr_unix/gtmsource_needrestart.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -55,7 +55,7 @@ int gtmsource_needrestart(void) gtmsource_options.secondary_instname); DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); if ((NULL != gtmsource_local) && (gtmsource_local->connect_jnl_seqno >= jnlpool.jnlpool_ctl->start_jnl_seqno)) util_out_print("Secondary Instance [!AZ] DOES NOT NEED to be restarted", TRUE, gtmsource_local->secondary_instname); else diff --git a/sr_unix/gtmsource_onln_rlbk_clnup.c b/sr_unix/gtmsource_onln_rlbk_clnup.c index bea30a2..35c32ac 100644 --- a/sr_unix/gtmsource_onln_rlbk_clnup.c +++ b/sr_unix/gtmsource_onln_rlbk_clnup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2012 Fidelity Information Services, Inc * + * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -77,7 +77,7 @@ void gtmsource_onln_rlbk_clnup() */ gtmsource_local->gtmsource_state = gtmsource_state = GTMSOURCE_HANDLE_ONLN_RLBK; if (!was_crit) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK) + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); /* We have to let the read files logic know that until we have sent data "upto" the current journal sequence number * at this point, we cannot rely on the journal pool. Indicate this through the gtmsource_save_read_jnl_seqno global * variable diff --git a/sr_unix/gtmsource_process.c b/sr_unix/gtmsource_process.c index 5ca266f..aca7f0a 100644 --- a/sr_unix/gtmsource_process.c +++ b/sr_unix/gtmsource_process.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc.* + * Copyright 2006, 2013 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 "gtm_string.h" #include "gtm_stdio.h" #include "gtm_socket.h" +#include "gtm_netdb.h" #include "gtm_inet.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" @@ -27,10 +28,6 @@ #include #include -#ifdef VMS -#include /* Required for gtmsource.h */ -#endif - #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" @@ -70,7 +67,7 @@ #include "gtmsource_srv_latch.h" #include "gv_trigger_common.h" -#define MAX_HEXDUMP_CHARS_PER_LINE 26 /* 2 characters per byte + space, 80 column assumed */ +#define MAX_HEXDUMP_CHARS_PER_LINE 26 /* 2 characters per byte + space, 80 column assumed */ #define BREAK_IF_CMP_ERROR(CMPRET, SEND_TR_LEN) \ { \ @@ -143,7 +140,6 @@ #endif -GBLDEF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate; GBLDEF repl_msg_ptr_t gtmsource_msgp = NULL; GBLDEF int gtmsource_msgbufsiz = 0; GBLDEF repl_msg_ptr_t gtmsource_cmpmsgp = NULL; @@ -157,6 +153,7 @@ GBLDEF qw_num repl_source_lastlog_msg_sent = 0; GBLDEF time_t repl_source_prev_log_time; GBLDEF time_t repl_source_this_log_time; GBLDEF time_t gtmsource_last_flush_time; + GBLREF gtmsource_state_t gtmsource_state; GBLREF uchar_ptr_t repl_filter_buff; GBLREF int repl_filter_bufsiz; @@ -170,9 +167,7 @@ GBLREF gd_region *gv_cur_region; GBLREF repl_ctl_element *repl_ctl_list; GBLREF gtmsource_options_t gtmsource_options; GBLREF int gtmsource_log_fd; -GBLREF int gtmsource_statslog_fd; GBLREF FILE *gtmsource_log_fp; -GBLREF FILE *gtmsource_statslog_fp; GBLREF boolean_t gtmsource_logstats; GBLREF int gtmsource_filter; GBLREF gd_addr *gd_header; @@ -295,7 +290,8 @@ static void repl_tr_endian_convert(repl_msg_ptr_t send_msgp, int send_tr_len, se if ((-1 == status) || (0 != jlen)) { assert(FALSE); - rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, + LEN_AND_LIT("Originating"), &pre_read_seqno); } /* move on to the next transaction */ remaining_len -= (buflen + REPL_MSG_HDRLEN); @@ -306,7 +302,7 @@ static void repl_tr_endian_convert(repl_msg_ptr_t send_msgp, int send_tr_len, se } if (0 != remaining_len) { - rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno); assert(FALSE); } } @@ -317,7 +313,6 @@ int gtmsource_process(void) gtmsource_local_ptr_t gtmsource_local; jnlpool_ctl_ptr_t jctl; seq_num recvd_seqno, sav_read_jnl_seqno; - struct sockaddr_in secondary_addr; seq_num recvd_jnl_seqno, tmp_read_jnl_seqno; int data_len, srch_status; unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */ @@ -325,22 +320,19 @@ int gtmsource_process(void) int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */ int status; /* needed for REPL_{SEND,RECV}_LOOP */ int tot_tr_len, send_tr_len, remaining_len, pre_cmpmsglen; - struct timeval poll_time; int recvd_msg_type, recvd_start_flags; uchar_ptr_t in_buff, out_buff, out_buffmsg; uint4 in_buflen, out_buflen, out_bufsiz; seq_num log_seqno, diff_seqno, pre_read_seqno, post_read_seqno, jnl_seqno; char err_string[1024]; - boolean_t xon_wait_logged, prev_catchup, catchup, force_recv_check, already_communicated; + boolean_t xon_wait_logged, already_communicated; double time_elapsed; seq_num resync_seqno, zqgblmod_seqno, filter_seqno; gd_region *reg, *region_top; - sgmnt_addrs *csa; - qw_num backlog_bytes, backlog_count, delta_sent_cnt, delta_data_sent, delta_msg_sent; - long prev_msg_sent = 0; - time_t prev_now = 0, save_now; - int index; - struct timeval poll_wait, poll_immediate; + sgmnt_addrs *csa, *repl_csa; + qw_num delta_sent_cnt, delta_data_sent, delta_msg_sent; + time_t prev_now; + int index, poll_time; uint4 temp_ulong; unix_db_info *udi; repl_histinfo remote_histinfo, local_histinfo; @@ -359,6 +351,7 @@ int gtmsource_process(void) char histdetail[256]; gtm_time4_t tmp_time4; repl_heartbeat_msg_ptr_t heartbeat_msg; + sm_global_latch_ptr_t gtmsource_srv_latch; DEBUG_ONLY(uchar_ptr_t save_inbuff;) DEBUG_ONLY(uchar_ptr_t save_outbuff;) DCL_THREADGBL_ACCESS; @@ -366,9 +359,9 @@ int gtmsource_process(void) SETUP_THREADGBL_ACCESS; assert((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open); DEBUG_ONLY( - csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; - assert(!csa->hold_onto_crit); /* so we can do unconditional grab_lock/rel_lock */ - ASSERT_VALID_JNLPOOL(csa); + repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; + assert(!repl_csa->hold_onto_crit); /* so we can do unconditional grab_lock/rel_lock */ + ASSERT_VALID_JNLPOOL(repl_csa); ) assert(REPL_MSG_HDRLEN == SIZEOF(jnldata_hdr_struct)); /* necessary for reading multiple transactions from jnlpool in * a single attempt */ @@ -378,18 +371,12 @@ int gtmsource_process(void) gtmsource_msgbufsiz = MAX_REPL_MSGLEN; if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level) gtmsource_cmpmsgp = NULL; - assert(GTMSOURCE_POLL_WAIT < MAX_GTMSOURCE_POLL_WAIT); - gtmsource_poll_wait.tv_sec = 0; - gtmsource_poll_wait.tv_usec = GTMSOURCE_POLL_WAIT; - poll_wait = gtmsource_poll_wait; - gtmsource_poll_immediate.tv_sec = 0; - gtmsource_poll_immediate.tv_usec = 0; - poll_immediate = gtmsource_poll_immediate; + assert(REPL_POLL_WAIT < MILLISECS_IN_SEC); + assert(GTMSOURCE_IDLE_POLL_WAIT < REPL_POLL_WAIT); - gtmsource_init_sec_addr(&secondary_addr); gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION; - + gtmsource_srv_latch = >msource_local->gtmsource_srv_latch; /* Below is a simplistic representation of the state diagram of a source server. * * ------------------------------ @@ -457,9 +444,9 @@ int gtmsource_process(void) SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN); } jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno; - repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : %llu\n", + repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Current Jnlpool Seqno : "INT8_FMT"\n", jnl_seqno); - repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Last Seqno sent : %llu\n", + repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Last Seqno sent : "INT8_FMT"\n", gtmsource_local->read_jnl_seqno - 1); /* gtmsource_save_read_jnl_seqno is kept uptodate with gtmsource_local->read_addr and gtmsource_local->read * fields in gtmsource_onln_rlbk_clnup. But, gtmsource_local->read_jnl_seqno is still pointing to the last @@ -471,7 +458,7 @@ int gtmsource_process(void) * it is bundled up as part of libgtmshr.so whereas repl_log is bundled in libmupip.a. */ gtmsource_local->read_jnl_seqno = gtmsource_save_read_jnl_seqno; - repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Source Server Read Seqno is now set to : %llu\n", + repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Source Server Read Seqno is now set to : "INT8_FMT"\n", gtmsource_local->read_jnl_seqno); gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION; assert(READ_FILE == gtmsource_local->read_state); @@ -480,7 +467,7 @@ int gtmsource_process(void) if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) { gtmsource_start_jnl_release_timer(); - gtmsource_est_conn(&secondary_addr); + gtmsource_est_conn(); gtmsource_stop_jnl_release_timer(); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) return (SS_NORMAL); @@ -488,7 +475,7 @@ int gtmsource_process(void) repl_source_lastlog_data_sent = 0; repl_source_lastlog_msg_sent = 0; - gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN); + gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN, TRUE); gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_RESTART; recvd_start_flags = START_FLAG_NONE; repl_source_prev_log_time = time(NULL); @@ -511,7 +498,8 @@ int gtmsource_process(void) { SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESTART SEQNO. Error in recv : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } else if (EREPL_SEND == repl_errno) { @@ -527,12 +515,14 @@ int gtmsource_process(void) } SNPRINTF(err_string, SIZEOF(err_string), "Error sending XOFF_ACK_ME message. Error in send : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } else if (EREPL_SELECT == repl_errno) { SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESTART SEQNO/sending XOFF_ACK_ME. " "Error in select : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } if (GTMSOURCE_CHANGING_MODE == gtmsource_state) @@ -569,7 +559,7 @@ int gtmsource_process(void) } rollback_first = FALSE; secondary_ahead = FALSE; - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; local_jnl_seqno = jctl->jnl_seqno; @@ -579,14 +569,14 @@ int gtmsource_process(void) * a response. */ assert(0 == GET_STRM_INDEX(recvd_seqno)); assert(0 == GET_STRM_INDEX(local_jnl_seqno)); - repl_log(gtmsource_log_fp, TRUE, FALSE, "Current Journal Seqno of the instance is %llu [0x%llx]\n", + repl_log(gtmsource_log_fp, TRUE, FALSE, "Current Journal Seqno of the instance is "INT8_FMT" "INT8_FMTX"\n", local_jnl_seqno, local_jnl_seqno); if (recvd_seqno > local_jnl_seqno) { /* Secondary journal seqno is greater than that of the Primary. We know it is ahead of the primary. */ secondary_ahead = TRUE; repl_log(gtmsource_log_fp, TRUE, FALSE, - "Secondary instance journal seqno %llu [0x%llx] is greater than Primary " - "instance journal seqno %llu [0x%llx]\n", + "Secondary instance journal seqno "INT8_FMT" "INT8_FMTX" is greater than Primary " + "instance journal seqno "INT8_FMT" "INT8_FMTX"\n", recvd_seqno, recvd_seqno, local_jnl_seqno, local_jnl_seqno); /* Since the secondary is at least multi-site, the determination of the rollback seqno involves comparing * the histinfo records between the primary and secondary starting down from "local_jnl_seqno-1" @@ -669,7 +659,7 @@ int gtmsource_process(void) * the 0th history record in the instance file corresponds to the 0th stream. So it is * safe to look at the start_seqno of just the 0th history record in all cases. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; status = repl_inst_histinfo_get(0, &local_histinfo); @@ -685,7 +675,7 @@ int gtmsource_process(void) } if (!skip_last_histinfo_check) { /* Find histinfo record in the local instance file corresponding to seqno "recvd_seqno-1" */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; assert(recvd_seqno <= local_jnl_seqno); @@ -713,7 +703,7 @@ int gtmsource_process(void) */ SPRINTF(histdetail, "seqno "INT8_FMT" "INT8_FMTX, recvd_seqno - 1, recvd_seqno - 1); - gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn)); instnohist_msg.type = REPL_INST_NOHIST; instnohist_msg.len = MIN_REPL_MSGLEN; @@ -822,7 +812,10 @@ int gtmsource_process(void) QWASSIGN(*(seq_num *)&reply_msgp->start_seqno[0], resync_seqno); if (!rollback_first) { - GRAB_GTMSOURCE_SRV_LATCH(gtmsource_local, max_epoch_interval); + assert(NULL != gd_header); + assert(0 < gd_header->n_regions); + grab_gtmsource_srv_latch(gtmsource_srv_latch, 2 * gd_header->n_regions * max_epoch_interval, + HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; srch_status = gtmsource_srch_restart(resync_seqno, recvd_start_flags); @@ -890,7 +883,7 @@ int gtmsource_process(void) /* After having established connection, initialize a few fields in the gtmsource_local * structure and flush those changes to the instance file on disk. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; gtmsource_local->connect_jnl_seqno = jctl->jnl_seqno; @@ -903,11 +896,12 @@ int gtmsource_process(void) assert(reply_msgp->type == REPL_RESYNC_SEQNO || reply_msgp->type == REPL_ROLLBACK_FIRST); if ((REPL_RESYNC_SEQNO == reply_msgp->type) && secondary_was_rootprimary) { - repl_log(gtmsource_log_fp, TRUE, TRUE, "Sent REPL_RESYNC_SEQNO message with SEQNO %llu [0x%llx]\n", + repl_log(gtmsource_log_fp, TRUE, TRUE, "Sent REPL_RESYNC_SEQNO message with SEQNO " + INT8_FMT" "INT8_FMTX"\n", (*(seq_num *)&reply_msgp->start_seqno[0]), (*(seq_num *)&reply_msgp->start_seqno[0])); region_top = gd_header->regions + gd_header->n_regions; assert(NULL != jnlpool.jnlpool_dummy_reg); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) continue; zqgblmod_seqno = jctl->max_zqgblmod_seqno; @@ -924,8 +918,8 @@ int gtmsource_process(void) gtmsource_local->send_losttn_complete = jctl->send_losttn_complete; } rel_lock(jnlpool.jnlpool_dummy_reg); - REPL_DPRINT2("BEFORE FINDING RESYNC - zqgblmod_seqno is %llu", zqgblmod_seqno); - REPL_DPRINT2(", curr_seqno is %llu\n", jctl->jnl_seqno); + REPL_DPRINT2("BEFORE FINDING RESYNC - zqgblmod_seqno is "INT8_FMT, zqgblmod_seqno); + REPL_DPRINT2(", curr_seqno is "INT8_FMT"\n", jctl->jnl_seqno); if (zqgblmod_seqno > resync_seqno) { /* reset "zqgblmod_seqno" and "zqgblmod_tn" in all fileheaders to "resync_seqno" */ if (SS_NORMAL != gtmsource_update_zqgblmod_seqno_and_tn(resync_seqno)) @@ -984,7 +978,11 @@ int gtmsource_process(void) assert(READ_FILE == gtmsource_local->read_state); gtmsource_set_lookback(); } - poll_time = poll_immediate; + /* The variable poll_time indicates if we should wait for the receive pipe to be I/O ready and should be set to + * a non-zero value ONLY if the source server has nothing to send. At this point we have data to send and so + * set poll_time to no-wait. + */ + poll_time = REPL_POLL_NOWAIT; gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_SENDING_JNLRECS; assert(1 <= gtmsource_local->read_jnl_seqno); /* Now that "gtmsource_local->read_jnl_seqno" is initialized, ensure the first send gets logged. */ @@ -1018,11 +1016,9 @@ int gtmsource_process(void) if (NO_FILTER == gtmsource_filter) gtmsource_free_filter_buff(); } - catchup = FALSE; - force_recv_check = TRUE; xon_wait_logged = FALSE; - /* Flush "gtmsource_local->read_jnl_seqno" to disk right now. - * This will serve as a reference point for next timed flush to occur. + /* Flush "gtmsource_local->read_jnl_seqno" to disk right now. This will serve as a reference point for next timed + * flush to occur. */ gtmsource_flush_fh(gtmsource_local->read_jnl_seqno); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) @@ -1030,6 +1026,7 @@ int gtmsource_process(void) gtmsource_local->send_new_histrec = TRUE; /* Send new histinfo unconditionally at start of connection */ gtmsource_local->next_histinfo_seqno = MAX_SEQNO; /* Initial value. Reset by "gtmsource_send_new_histrec" below */ assert(-1 == gtmsource_local->next_histinfo_num); + prev_now = gtmsource_now; while (TRUE) { gtmsource_poll_actions(TRUE); @@ -1043,7 +1040,7 @@ int gtmsource_process(void) losttncomplete_msg.len = MIN_REPL_MSGLEN; gtmsource_repl_send((repl_msg_ptr_t)&losttncomplete_msg, "REPL_LOSTTNCOMPLETE", MAX_SEQNO, INVALID_SUPPL_STRM); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) break; /* the outerloop will continue */ gtmsource_local->send_losttn_complete = FALSE; @@ -1063,108 +1060,45 @@ int gtmsource_process(void) break; assert(FALSE == gtmsource_local->send_new_histrec); } - /* If the backlog is high, we want to avoid communication overhead as much as possible. We switch - * our communication mode to *catchup* mode, wherein we don't wait for the pipe to become ready to - * send. Rather, we assume the pipe is ready for sending. The risk is that the send may block if - * the pipe is not ready for sending. In the user's perspective, the risk is that the source server - * may not respond to administrative actions such as "change log", "shutdown" (although mupip stop - * would work). - */ - pre_read_seqno = gtmsource_local->read_jnl_seqno; - prev_catchup = catchup; - assert(jctl->write_addr >= gtmsource_local->read_addr); - backlog_bytes = jctl->write_addr - gtmsource_local->read_addr; - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); - if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) - break; /* the outerloop will continue */ - jnl_seqno = jctl->jnl_seqno; - rel_lock(jnlpool.jnlpool_dummy_reg); - assert(jnl_seqno >= pre_read_seqno - 1); /* jnl_seqno >= pre_read_seqno is the most common case; - * see gtmsource_readpool() for when the rare case can occur */ - backlog_count = (jnl_seqno >= pre_read_seqno) ? (jnl_seqno - pre_read_seqno) : 0; - catchup = (BACKLOG_BYTES_THRESHOLD <= backlog_bytes || BACKLOG_COUNT_THRESHOLD <= backlog_count); - if (!prev_catchup && catchup) /* transition from non catchup to catchup */ + if (prev_now != gtmsource_now) { - repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server entering catchup mode at Seqno %llu " - "[0x%llx] : Current backlog %llu [0x%llx] : Backlog size in journal pool %llu [0x%llx] " - "bytes\n", pre_read_seqno, pre_read_seqno, backlog_count, backlog_count, - backlog_bytes, backlog_bytes); prev_now = gtmsource_now; - prev_msg_sent = repl_source_msg_sent; - force_recv_check = TRUE; - } else if (prev_catchup && !catchup) /* transition from catchup to non catchup */ - { - repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server returning to regular mode from catchup mode " - "at Seqno %llu [0x%llx] : Current backlog %llu [0x%llx] : Backlog size in journal pool " - " %llu [0x%llx] bytes\n", pre_read_seqno, pre_read_seqno, backlog_count, backlog_count, - backlog_bytes, backlog_bytes); if (gtmsource_msgbufsiz - MAX_REPL_MSGLEN > 2 * OS_PAGE_SIZE) - {/* We have expanded the buffer by too much (could have been avoided had we sent one transaction - * at a time while reading from journal files); let's revert back to our initial buffer size. - * If we don't reduce our buffer, it is possible that the buffer keeps growing (while reading - * from journal file) thus making the size of sends while reading from journal pool very - * large (> 1 MB). Better to do some house keeping. We will force an expansion if the transaction - * size dictates it. Ideally, this must be done while switching reading back from files to - * pool, but we can't afford to free the buffer until we sent the transaction out. That apart, - * let's wait for some breathing time to do house keeping. In catchup mode, we intend to keep - * the send size large. */ + { /* We have expanded the buffer by too much (could have been avoided had we sent one + * transaction at a time while reading from journal files); let's revert back to our + * initial buffer size. If we don't reduce our buffer, it is possible that the buffer keeps + * growing (while reading * from journal file) thus making the size of sends while reading + * from journal pool very large (> 1 MB). + */ gtmsource_free_filter_buff(); gtmsource_free_msgbuff(); - gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN); /* will also allocate filter buffer */ + gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN, TRUE); /* will also allocate filter buffer */ } } - /* Check if receiver sent us any control message. - * Typically, the traffic from receiver to source is very low compared to traffic in the other direction. - * More often than not, there will be nothing on the pipe to receive. Ideally, we should let TCP - * notify us when there is data on the pipe (async I/O on Unix and VMS). We are not there yet. Until then, - * we use heuristics - attempt receive every GTMSOURCE_SENT_THRESHOLD_FOR_RECV bytes of sent data, and - * every heartbeat period, OR whenever we want to force a check + /* Check if receiver sent us any control message. Typically, the traffic from receiver to source is very + * low compared to traffic in the other direction. More often than not, there will be nothing on the pipe + * to receive. Ideally, we should let TCP notify us when there is data on the pipe (async I/O on Unix and + * VMS). But, we are not there yet. Since we do a select() before a recv(), we won't block if there is + * nothing in the pipe. So, it shouldn't be an expensive operation even if done before every send. Also, + * in doing so, we react to an XOFF sooner than later. */ - if ((GTMSOURCE_SENDING_JNLRECS != gtmsource_state) || !catchup || prev_now != (save_now = gtmsource_now) - || (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= (repl_source_msg_sent - prev_msg_sent)) - || force_recv_check) + /* Make sure we don't sleep for an extended period of time if there is something to be sent across */ + assert((GTMSOURCE_SENDING_JNLRECS != gtmsource_state) + || ((0 == poll_time) || (GTMSOURCE_IDLE_POLL_WAIT == poll_time))); + REPL_RECV_LOOP(gtmsource_sock_fd, gtmsource_msgp, MIN_REPL_MSGLEN, poll_time) { - REPL_EXTRA_DPRINT2("gtmsource_process: receiving because : %s\n", - (GTMSOURCE_SENDING_JNLRECS != gtmsource_state) ? "state is not SENDING_JNLRECS" : - !catchup ? "not in catchup mode" : - (prev_now != save_now) ? "heartbeat interval passed" : - (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= repl_source_msg_sent - prev_msg_sent) ? - "sent bytes threshold for recv crossed" : - "force recv check"); - REPL_EXTRA_DPRINT6("gtmsource_state : %d prev_now : %ld gtmsource_now : %ld repl_source_msg_sent " - ": %ld prev_msg_sent : %ld\n", gtmsource_state, prev_now, save_now, - repl_source_msg_sent, prev_msg_sent); - REPL_RECV_LOOP(gtmsource_sock_fd, gtmsource_msgp, MIN_REPL_MSGLEN, FALSE, &poll_time) - { - if (0 == recvd_len) /* nothing received in the first attempt, let's try again later */ - break; - gtmsource_poll_actions(TRUE); - if (GTMSOURCE_CHANGING_MODE == gtmsource_state) - return (SS_NORMAL); - if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) - break; - } - REPL_EXTRA_DPRINT3("gtmsource_process: %d received, type is %d\n", recvd_len, - (0 != recvd_len) ? gtmsource_msgp->type : -1); - if (GTMSOURCE_SENDING_JNLRECS == gtmsource_state && catchup) - { - if (prev_now != save_now) - prev_now = save_now; - else if (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= repl_source_msg_sent - prev_msg_sent) - { /* do not set to repl_source_msg_sent; increment by GTMSOURCE_SENT_THRESHOLD_FOR_RECV - * instead so that we force recv every GTMSOURCE_SENT_THRESHOLD_FOR_RECV bytes */ - prev_msg_sent += GTMSOURCE_SENT_THRESHOLD_FOR_RECV; - } - } - } else - { /* behave as if there was nothing to be read */ - status = SS_NORMAL; - recvd_len = 0; + if (0 == recvd_len) /* nothing received in the first attempt, let's try again later */ + break; + gtmsource_poll_actions(TRUE); + if (GTMSOURCE_CHANGING_MODE == gtmsource_state) + return (SS_NORMAL); + if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) + break; } - force_recv_check = FALSE; - if (SS_NORMAL == status && 0 != recvd_len) + if ((SS_NORMAL == status) && (0 != recvd_len)) { /* Process the received control message */ assert(MIN_REPL_MSGLEN == recvd_len); + REPL_DPRINT3("gtmsource_process: %d bytes received, type is %d\n", recvd_len, gtmsource_msgp->type); /* One is not always guaranteed the received message is in source native endian format. * See endianness related comments in gtmsource_recv_restart for why. So be safe and handle * it just like how gtmsource_recv_restart does. The below check works as all messages we @@ -1179,19 +1113,12 @@ int gtmsource_process(void) } assert(MIN_REPL_MSGLEN == gtmsource_msgp->len); assert(remote_side->endianness_known); - /* Even though we know the endianness of the remote side at this point, we use - * msg_is_cross_endian as it should be a safer alternative in case of messages - * like REPL_XOFF_ACK_ME where the receiver (particularly pre-V55000 versions) - * is not careful to send in a consistent endian format across versions. So we - * use the endianness of this particular message rather than the endianness of - * the connection. - */ switch(gtmsource_msgp->type) { case REPL_XOFF: case REPL_XOFF_ACK_ME: gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_XON; - poll_time = poll_wait; + poll_time = REPL_POLL_WAIT; /* because we are waiting for a REPL_XON */ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XOFF/REPL_XOFF_ACK_ME received. Send stalled...\n"); xon_wait_logged = FALSE; @@ -1213,25 +1140,10 @@ int gtmsource_process(void) break; case REPL_XON: gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_SENDING_JNLRECS; - poll_time = poll_immediate; + poll_time = REPL_POLL_NOWAIT; /* because we received XON and data ready for send */ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XON received\n"); - gtmsource_restart_heartbeat; /*Macro*/ + heartbeat_stalled = FALSE; REPL_DPRINT1("Restarting HEARTBEAT\n"); - xon_wait_logged = FALSE; - /* In catchup mode, we do not receive as often as we would have in non catchup mode. - * The consequence of this may be that we do not react to XOFF quickly enough, - * making it worse for the replication pipe. We may end up with multiple XOFFs (with - * intervening XONs) sitting on the replication pipe that are yet to be received - * and processed by the source server. To avoid such a situation, on receipt of - * an XON, we immediately force a check on the incoming pipe thereby draining - * all pending XOFF/XONs, keeping the pipe smooth. Also, there is less likelihood - * of missing a HEARTBEAT response (that is perhaps on the pipe) which may lead to - * connection breakage although the pipe is alive and well. - * - * We will force a check regardless of mode (catchup or non catchup) as we may - * be pounding the secondary even in non catchup mode - */ - force_recv_check = TRUE; break; case REPL_BADTRANS: case REPL_CMP2UNCMP: @@ -1248,12 +1160,12 @@ int gtmsource_process(void) recvd_start_flags = START_FLAG_NONE; if (REPL_BADTRANS == gtmsource_msgp->type) repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_BADTRANS " - "message with SEQNO %llu [0x%llx]\n", + "message with SEQNO "INT8_FMT" "INT8_FMTX"\n", recvd_seqno, recvd_seqno); else { repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_CMP2UNCMP " - "message with SEQNO %llu [0x%llx]\n", + "message with SEQNO "INT8_FMT" "INT8_FMTX"\n", recvd_seqno, recvd_seqno); repl_log(gtmsource_log_fp, TRUE, FALSE, "Defaulting to NO compression for this connection\n"); @@ -1266,8 +1178,8 @@ int gtmsource_process(void) recvd_start_flags = GTM_BYTESWAP_32(recvd_start_flags); already_communicated = FALSE; repl_log(gtmsource_log_fp, TRUE, TRUE, - "Received REPL_START_JNL_SEQNO message with SEQNO %llu [0x%llx]. " - "Possible crash of recvr/update process\n", + "Received REPL_START_JNL_SEQNO message with SEQNO "INT8_FMT" " + INT8_FMTX". Possible crash of recvr/update process\n", recvd_seqno, recvd_seqno); } break; @@ -1318,14 +1230,16 @@ int gtmsource_process(void) SNPRINTF(err_string, SIZEOF(err_string), "Error receiving Control message from Receiver. Error in recv : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } else if (EREPL_SELECT == repl_errno) { SNPRINTF(err_string, SIZEOF(err_string), "Error receiving Control message from Receiver. Error in select : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } if (GTMSOURCE_WAITING_FOR_XON == gtmsource_state) @@ -1333,7 +1247,7 @@ int gtmsource_process(void) if (!xon_wait_logged) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting to receive XON\n"); - gtmsource_stall_heartbeat; /* Macro */ + heartbeat_stalled = TRUE; REPL_DPRINT1("Stalling HEARTBEAT\n"); xon_wait_logged = TRUE; } @@ -1345,17 +1259,13 @@ int gtmsource_process(void) } continue; } - if (GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state || - GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) - { - xon_wait_logged = FALSE; + if ((GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state) + || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)) break; - } assert(gtmsource_state == GTMSOURCE_SENDING_JNLRECS); - if (force_recv_check) /* we want to poll the incoming pipe for possible XOFF */ - continue; - assert(pre_read_seqno == gtmsource_local->read_jnl_seqno); - GRAB_GTMSOURCE_SRV_LATCH(gtmsource_local, max_epoch_interval); + pre_read_seqno = gtmsource_local->read_jnl_seqno; + grab_gtmsource_srv_latch(gtmsource_srv_latch, 2 * gd_header->n_regions * max_epoch_interval, + HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) break; /* the outerloop will continue */ tot_tr_len = gtmsource_get_jnlrecs(>msource_msgp->msg[0], &data_len, @@ -1524,7 +1434,7 @@ int gtmsource_process(void) * server will communicate the appropriate sequence number as part of the histinfo * exchange. */ - REPL_SEND_LOOP(gtmsource_sock_fd, send_msgp, send_tr_len, catchup, &poll_immediate) + REPL_SEND_LOOP(gtmsource_sock_fd, send_msgp, send_tr_len, REPL_POLL_WAIT) { gtmsource_poll_actions(FALSE); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) @@ -1546,9 +1456,9 @@ int gtmsource_process(void) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Connection reset while sending seqno data from " - "%llu [0x%llx] to %llu [0x%llx]. Status = %d ; %s\n", - pre_read_seqno, pre_read_seqno, post_read_seqno, post_read_seqno, - status, STRERROR(status)); + INT8_FMT" "INT8_FMTX" to "INT8_FMT" "INT8_FMTX + ". Status = %d ; %s\n", pre_read_seqno, pre_read_seqno, + post_read_seqno, post_read_seqno, status, STRERROR(status)); repl_close(>msource_sock_fd); SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN); gtmsource_state = gtmsource_local->gtmsource_state @@ -1559,15 +1469,15 @@ int gtmsource_process(void) { SNPRINTF(err_string, SIZEOF(err_string), "Error sending DATA. Error in send : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } if (EREPL_SELECT == repl_errno) { SNPRINTF(err_string, SIZEOF(err_string), "Error sending DATA. Error in select : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, - RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } if (intfilter_error) @@ -1605,73 +1515,83 @@ int gtmsource_process(void) /* jctl->jnl_seqno >= post_read_seqno is the most common case; * see gtmsource_readpool() for when the rare case can occur */ jnl_seqno = jctl->jnl_seqno; - assert(jnl_seqno >= post_read_seqno - 1); - diff_seqno = (jnl_seqno >= post_read_seqno) ? - (jnl_seqno - post_read_seqno) : 0; - repl_log(gtmsource_log_fp, FALSE, FALSE, "REPL INFO - Seqno : %llu [0x%llx]", - log_seqno, log_seqno); - repl_log(gtmsource_log_fp, FALSE, FALSE, " Jnl Total : %llu [0x%llx] Msg Total :" - " %llu [0x%llx] CmpMsg Total : %llu [0x%llx] ", - repl_source_data_sent, repl_source_data_sent, - repl_source_msg_sent, repl_source_msg_sent, - repl_source_cmp_sent, repl_source_cmp_sent); - repl_log(gtmsource_log_fp, FALSE, TRUE, "Current backlog : %llu [0x%llx]\n", - diff_seqno, diff_seqno); - /* gtmsource_now is updated by the heartbeat protocol every heartbeat - * interval. To cut down on calls to time(), we use gtmsource_now as the - * time to figure out if we have to log statistics. This works well as the - * logging interval generally is larger than the heartbeat interval, and that - * the heartbeat protocol is running when we are sending data. The consequence - * although is that we may defer logging when we would have logged. We can live - * with that given the benefit of not calling time related system calls. - * Currently, the logging interval is not changeable by users. When/if we provide - * means of choosing log interval, this code may have to be re-examined. - * Vinaya 2003, Sep 08 - */ - assert(0 != gtmsource_now); /* must hold if we are sending data */ - repl_source_this_log_time = gtmsource_now; /* approximate time, in the worst case, - * behind by heartbeat interval */ - assert(repl_source_this_log_time >= repl_source_prev_log_time); - time_elapsed = difftime(repl_source_this_log_time, - repl_source_prev_log_time); - if ((double)GTMSOURCE_LOGSTATS_INTERVAL <= time_elapsed) + if (jnl_seqno >= post_read_seqno - 1) { - delta_sent_cnt = trans_sent_cnt - last_log_tr_sent_cnt; - delta_data_sent = repl_source_data_sent - - repl_source_lastlog_data_sent; - delta_msg_sent = repl_source_msg_sent - - repl_source_lastlog_msg_sent; - repl_log(gtmsource_log_fp, TRUE, FALSE, "REPL INFO since last log : " - "Time elapsed : %00.f Tr sent : %llu [0x%llx] Tr bytes : %llu " - "[0x%llx] Msg bytes : %llu [0x%llx]\n", time_elapsed, - delta_sent_cnt, delta_sent_cnt, delta_data_sent, delta_data_sent, - delta_msg_sent, delta_msg_sent); - repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO since last log : " - "Time elapsed : %00.f Tr sent/s : %f Tr bytes/s : %f " - "Msg bytes/s : %f\n", time_elapsed, - (float)delta_sent_cnt / time_elapsed, - (float)delta_data_sent / time_elapsed, - (float)delta_msg_sent / time_elapsed); - repl_source_lastlog_data_sent = repl_source_data_sent; - repl_source_lastlog_msg_sent = repl_source_msg_sent; - last_log_tr_sent_cnt = trans_sent_cnt; - repl_source_prev_log_time = repl_source_this_log_time; - } - lastlog_seqno = log_seqno; + diff_seqno = (jnl_seqno >= post_read_seqno) ? + (jnl_seqno - post_read_seqno) : 0; + repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Seqno : "INT8_FMT" " + INT8_FMTX" Jnl Total : "INT8_FMT" "INT8_FMTX + " Msg Total : "INT8_FMT" "INT8_FMTX" CmpMsg Total : " + INT8_FMT" "INT8_FMTX" Current backlog : "INT8_FMT" "INT8_FMTX"\n", + log_seqno, log_seqno, repl_source_data_sent, repl_source_data_sent, + repl_source_msg_sent, repl_source_msg_sent, + repl_source_cmp_sent, repl_source_cmp_sent, diff_seqno, diff_seqno); + /* gtmsource_now is updated by the heartbeat protocol every heartbeat + * interval. To cut down on calls to time(), we use gtmsource_now as the + * time to figure out if we have to log statistics. This works well as the + * logging interval generally is larger than the heartbeat interval, and + * that the heartbeat protocol is running when we are sending data. The + * consequence although is that we may defer logging when we would have + * logged. We can live with that given the benefit of not calling time + * related system calls. Currently, the logging interval is not changeable + * by users. When/if we provide means of choosing log interval, this code + * may have to be re-examined. Vinaya 2003, Sep 08 + */ + assert(0 != gtmsource_now); /* must hold if we are sending data */ + repl_source_this_log_time = gtmsource_now; /* approximate time, in the + * worst case, behind by + * heartbeat interval */ + assert(repl_source_this_log_time >= repl_source_prev_log_time); + time_elapsed = difftime(repl_source_this_log_time, + repl_source_prev_log_time); + if ((double)GTMSOURCE_LOGSTATS_INTERVAL <= time_elapsed) + { + delta_sent_cnt = trans_sent_cnt - last_log_tr_sent_cnt; + delta_data_sent = repl_source_data_sent + - repl_source_lastlog_data_sent; + delta_msg_sent = repl_source_msg_sent + - repl_source_lastlog_msg_sent; + repl_log(gtmsource_log_fp, TRUE, FALSE, + "REPL INFO since last log : " + "Time elapsed : %00.f Tr sent : "INT8_FMT" "INT8_FMTX" " + "Tr bytes : "INT8_FMT" "INT8_FMTX + " Msg bytes : "INT8_FMT" "INT8_FMTX"\n", time_elapsed, + delta_sent_cnt, delta_sent_cnt, delta_data_sent, + delta_data_sent, delta_msg_sent, delta_msg_sent); + repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO since last log : " + "Time elapsed : %00.f Tr sent/s : %f Tr bytes/s : %f " + "Msg bytes/s : %f\n", time_elapsed, + (float)delta_sent_cnt / time_elapsed, + (float)delta_data_sent / time_elapsed, + (float)delta_msg_sent / time_elapsed); + repl_source_lastlog_data_sent = repl_source_data_sent; + repl_source_lastlog_msg_sent = repl_source_msg_sent; + last_log_tr_sent_cnt = trans_sent_cnt; + repl_source_prev_log_time = repl_source_this_log_time; + } + lastlog_seqno = log_seqno; + } /* else an online rollback occurred. Fall-through and the subsequent iteration + * will take care of re-establishing the connection + */ } - poll_time = poll_immediate; + /* Because we sent data to the other side and there might be more to be sent across, don't + * wait for the receive pipe to be ready. + */ + poll_time = REPL_POLL_NOWAIT; } else /* data_len == 0 */ { /* nothing to send */ gtmsource_flush_fh(post_read_seqno); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) break; /* the outerloop will continue */ - poll_time = poll_wait; - rel_quant(); /* give up processor and let other processes run */ + /* Sleep for a while (as part of the next REPL_RECV_LOOP) to avoid spinning when there is no + * data to be sent + */ + poll_time = GTMSOURCE_IDLE_POLL_WAIT; } } else /* else tot_tr_len < 0, error */ { if (0 < data_len) /* Insufficient buffer space, increase the buffer space */ - gtmsource_alloc_msgbuff(data_len + REPL_MSG_HDRLEN); + gtmsource_alloc_msgbuff(data_len + REPL_MSG_HDRLEN, TRUE); else GTMASSERT; /* Major problems */ } diff --git a/sr_unix/gtmsource_process_ops.c b/sr_unix/gtmsource_process_ops.c index bb045ea..a679efa 100644 --- a/sr_unix/gtmsource_process_ops.c +++ b/sr_unix/gtmsource_process_ops.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,6 +17,7 @@ #include "gtm_stdio.h" /* for FILE * in repl_comm.h */ #include "gtm_socket.h" +#include "gtm_netdb.h" #include "gtm_inet.h" #include #include @@ -24,9 +25,6 @@ #include "gtm_unistd.h" #include "gtm_stat.h" #include "gtm_string.h" -#ifdef VMS -#include /* Required for gtmsource.h */ -#endif #include "gdsroot.h" #include "gdsblk.h" @@ -47,6 +45,7 @@ #include "muprec.h" #include "repl_ctl.h" #include "repl_errno.h" +#include "gtmio.h" /* for REPL_DPRINT* macros */ #include "repl_dbg.h" #include "iosp.h" #include "gtm_event_log.h" @@ -67,13 +66,26 @@ #include "gtm_zlib.h" #include "replgbl.h" #include "repl_inst_dump.h" /* for "repl_dump_histinfo" prototype */ +#include "gtmdbgflags.h" + +#define SEND_REPL_LOGFILE_INFO(LOGFILE, LOGFILE_MSG) \ +{ \ + int len; \ + \ + len = repl_logfileinfo_get(LOGFILE, &LOGFILE_MSG, FALSE, gtmsource_log_fp); \ + REPL_SEND_LOOP(gtmsource_sock_fd, &LOGFILE_MSG, len, REPL_POLL_NOWAIT) \ + { \ + gtmsource_poll_actions(FALSE); \ + if (GTMSOURCE_CHANGING_MODE == gtmsource_state) \ + return SS_NORMAL; \ + } \ +} GBLREF boolean_t gtmsource_logstats; GBLREF boolean_t gtmsource_pool2file_transition; GBLREF boolean_t gtmsource_received_cmp2uncmp_msg; GBLREF boolean_t secondary_side_std_null_coll; GBLREF FILE *gtmsource_log_fp; -GBLREF FILE *gtmsource_statslog_fp; GBLREF gd_addr *gd_header; GBLREF gtmsource_state_t gtmsource_state; GBLREF int4 strm_index; @@ -82,7 +94,6 @@ GBLREF int gtmsource_filter; GBLREF int gtmsource_log_fd; GBLREF int gtmsource_msgbufsiz; GBLREF int gtmsource_sock_fd; -GBLREF int gtmsource_statslog_fd; GBLREF int repl_filter_bufsiz; GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize; GBLREF jnlpool_addrs jnlpool; @@ -92,11 +103,11 @@ GBLREF repl_msg_ptr_t gtmsource_cmpmsgp; GBLREF repl_msg_ptr_t gtmsource_msgp; GBLREF seq_num gtmsource_save_read_jnl_seqno; GBLREF seq_num seq_num_zero; -GBLREF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate; GBLREF uchar_ptr_t repl_filter_buff; GBLREF uint4 process_id; GBLREF unsigned char *gtmsource_tcombuffp; GBLREF unsigned char *gtmsource_tcombuff_start; +GBLREF gtmsource_options_t gtmsource_options; error_def(ERR_REPL2OLD); error_def(ERR_REPLCOMM); @@ -112,23 +123,16 @@ error_def(ERR_TEXT); static unsigned char *tcombuff, *msgbuff, *cmpmsgbuff, *filterbuff; -void gtmsource_init_sec_addr(struct sockaddr_in *secondary_addr) -{ - gtmsource_local_ptr_t gtmsource_local; - - gtmsource_local = jnlpool.gtmsource_local; - memset((char *)secondary_addr, 0, SIZEOF(*secondary_addr)); - (*secondary_addr).sin_family = AF_INET; - (*secondary_addr).sin_addr.s_addr = gtmsource_local->secondary_inet_addr; - (*secondary_addr).sin_port = htons(gtmsource_local->secondary_port); -} - -int gtmsource_est_conn(struct sockaddr_in *secondary_addr) +int gtmsource_est_conn() { int connection_attempts, alert_attempts, save_errno, status; char print_msg[1024], msg_str[1024], *errmsg; gtmsource_local_ptr_t gtmsource_local; int send_buffsize, recv_buffsize, tcp_s_bufsize; + int logging_period, logging_interval; /* logging period = soft_tries_period*logging_interval */ + int logging_attempts; + sockaddr_ptr secondary_sa; + int secondary_addrlen; gtmsource_local = jnlpool.gtmsource_local; assert(remote_side == >msource_local->remote_side); @@ -136,17 +140,19 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) remote_side->endianness_known = FALSE; /* Connect to the secondary - use hard tries, soft tries ... */ connection_attempts = 0; - gtmsource_comm_init(); + gtmsource_comm_init(); /* set up gtmsource_local.secondary_ai */ repl_log(gtmsource_log_fp, TRUE, TRUE, "Connect hard tries count = %d, Connect hard tries period = %d\n", gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT], gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD]); do { - status = gtm_connect(gtmsource_sock_fd, (struct sockaddr *)secondary_addr, SIZEOF(*secondary_addr)); + secondary_sa = (sockaddr_ptr)(>msource_local->secondary_inet_addr); + secondary_addrlen = gtmsource_local->secondary_addrlen; + status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen); if (0 == status) break; repl_log(gtmsource_log_fp, FALSE, FALSE, "%d hard connection attempt failed : %s\n", connection_attempts + 1, - STRERROR(ERRNO)); + STRERROR(errno)); repl_close(>msource_sock_fd); if (REPL_MAX_CONN_HARD_TRIES_PERIOD > jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD]) SHORT_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD]) @@ -157,13 +163,16 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) return (SS_NORMAL); gtmsource_comm_init(); } while (++connection_attempts < gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT]); - gtmsource_poll_actions(FALSE); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) return (SS_NORMAL); if (gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT] <= connection_attempts) - { + { /*Initialize logging period related variables*/ + logging_period = gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]; + logging_interval = 1; + logging_attempts = 0; + alert_attempts = DIVIDE_ROUND_DOWN(gtmsource_local->connect_parms[GTMSOURCE_CONN_ALERT_PERIOD], gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]); repl_log(gtmsource_log_fp, TRUE, TRUE, "Soft tries period = %d, Alert period = %d\n", @@ -172,20 +181,26 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) connection_attempts = 0; do { - status = gtm_connect(gtmsource_sock_fd, (struct sockaddr *)secondary_addr, SIZEOF(*secondary_addr)); + secondary_sa = (sockaddr_ptr)(>msource_local->secondary_inet_addr); + secondary_addrlen = gtmsource_local->secondary_addrlen; + status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen); if (0 == status) break; repl_close(>msource_sock_fd); - repl_log(gtmsource_log_fp, TRUE, TRUE, "%d soft connection attempt failed : %s\n", - connection_attempts + 1, STRERROR(ERRNO)); + if (0 == (connection_attempts + 1) % logging_interval) + { + repl_log(gtmsource_log_fp, TRUE, TRUE, "%d soft connection attempt failed : %s\n", + connection_attempts + 1, STRERROR(errno)); + logging_attempts++; + } LONG_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]); gtmsource_poll_actions(FALSE); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) return (SS_NORMAL); gtmsource_comm_init(); connection_attempts++; - if (0 == connection_attempts % alert_attempts) - { /* Log ALERT message */ + if (0 == (connection_attempts % logging_interval) && 0 == (logging_attempts % alert_attempts)) + { /* Log ALERT message */ SNPRINTF(msg_str, SIZEOF(msg_str), "GTM Replication Source Server : Could not connect to secondary in %d seconds\n", connection_attempts * @@ -194,12 +209,20 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLWARN", print_msg); } + if (logging_period <= REPL_MAX_LOG_PERIOD) + { /*the maximum real_period can reach 2*REPL_MAX_LOG_PERIOD)*/ + if (0 == connection_attempts % logging_interval) + { /* Double the logging period after every logging attempt*/ + logging_interval = logging_interval << 1; + logging_period = logging_period << 1; + } + } } while (TRUE); } if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &send_buffsize))) { SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); } if (send_buffsize < GTMSOURCE_TCP_SEND_BUFSIZE) { @@ -213,19 +236,20 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP send buffer size in range [%d, %d], last " "known error : %s", GTMSOURCE_MIN_TCP_SEND_BUFSIZE, GTMSOURCE_TCP_SEND_BUFSIZE, STRERROR(status)); - rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); } } if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &repl_max_send_buffsize))) /* may have changed */ { SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); } if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &recv_buffsize))) { errmsg = STRERROR(status); - rts_error(VARLSTCNT(10) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT("Error getting socket recv buffsize"), - ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error getting socket recv buffsize"), + ERR_TEXT, 2, LEN_AND_STR(errmsg)); } if (recv_buffsize < GTMSOURCE_TCP_RECV_BUFSIZE) { @@ -235,14 +259,15 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr) { SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP recv buffer size to %d : %s", GTMSOURCE_MIN_TCP_RECV_BUFSIZE, STRERROR(status)); - rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, + LEN_AND_STR(msg_str)); } } } if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &repl_max_recv_buffsize))) /* may have changed */ { SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket recv buffsize : %s", STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str)); } repl_log(gtmsource_log_fp, TRUE, TRUE, "Connected to secondary, using TCP send buffer size %d receive buffer size %d\n", repl_max_send_buffsize, repl_max_recv_buffsize); @@ -312,9 +337,8 @@ void gtmsource_free_filter_buff(void) } } -int gtmsource_alloc_msgbuff(int maxbuffsize) -{ /* Allocate message buffer */ - +int gtmsource_alloc_msgbuff(int maxbuffsize, boolean_t discard_oldbuff) +{ /* Allocate message buffer */ repl_msg_ptr_t oldmsgp; unsigned char *free_msgp; @@ -330,7 +354,8 @@ int gtmsource_alloc_msgbuff(int maxbuffsize) if (NULL != free_msgp) { /* Copy existing data */ assert(NULL != oldmsgp); - memcpy((unsigned char *)gtmsource_msgp, (unsigned char *)oldmsgp, gtmsource_msgbufsiz); + if (!discard_oldbuff) + memcpy((unsigned char *)gtmsource_msgp, (unsigned char *)oldmsgp, gtmsource_msgbufsiz); free(free_msgp); } gtmsource_msgbufsiz = maxbuffsize; @@ -373,196 +398,250 @@ void gtmsource_free_msgbuff(void) /* Receive starting jnl_seqno for (re)starting transmission */ int gtmsource_recv_restart(seq_num *recvd_jnl_seqno, int *msg_type, int *start_flags) { - boolean_t msg_is_cross_endian; - fd_set input_fds; - repl_msg_t msg; - unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */ - int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */ - int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */ - int status; /* needed for REPL_{SEND,RECV}_LOOP */ - unsigned char seq_num_str[32], *seq_num_ptr; - repl_msg_t xoff_ack; + boolean_t msg_is_cross_endian, log_waitmsg; + fd_set input_fds; + repl_msg_t msg; + repl_logfile_info_msg_t logfile_msg; + unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */ + int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */ + int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */ + int status; /* needed for REPL_{SEND,RECV}_LOOP */ + uint4 remaining_len, len; + unsigned char seq_num_str[32], *seq_num_ptr, *buffp; + repl_msg_t xoff_ack; # ifdef DEBUG - boolean_t remote_side_endianness_known; + boolean_t remote_side_endianness_known; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; status = SS_NORMAL; assert(remote_side == &jnlpool.gtmsource_local->remote_side); - for ( ; SS_NORMAL == status; ) + DEBUG_ONLY(*msg_type = -1); + for (log_waitmsg = TRUE; SS_NORMAL == status; ) { - repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC message\n"); - REPL_RECV_LOOP(gtmsource_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >msource_poll_wait) + if (log_waitmsg) + repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC message\n"); + REPL_RECV_LOOP(gtmsource_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT) { gtmsource_poll_actions(FALSE); if (GTMSOURCE_CHANGING_MODE == gtmsource_state) return (SS_NORMAL); } DEBUG_ONLY(remote_side_endianness_known = remote_side->endianness_known); - if (SS_NORMAL == status) - { /* If endianness of other side is not yet known, determine that now by seeing if the msg.len is - * greater than expected. If it is, convert it and see if it is now what we expect. If it is, - * then the other system is of opposite endianness. Note: We would normally use msg.type since - * it is effectively an enum and we control by adding new messages. But, REPL_START_JNL_SEQNO - * is lucky number zero which means it is identical on systems of either endianness. - * - * If endianness of other side is not yet known, determine that from the message length as we - * expect it to be MIN_REPL_MSGLEN. There is one exception though. If a pre-V55000 receiver sends - * a REPL_XOFF_ACK_ME message, it could send it in the receiver's native-endian or cross-endian - * format (depending on how its global variable "src_node_same_endianness" is initialized). This - * bug in the receiver server logic is fixed V55000 onwards (proto_ver is REPL_PROTO_VER_SUPPLEMENTARY). - * Therefore, in this case, we cannot use the endianness of the REPL_XOFF_ACK_ME message to determine - * the endianness of the connection. In this case, wait for the next non-REPL_XOFF_ACK_ME message - * to determine the connection endianness. Handle this exception case correctly. - * - * If on the other hand, we know the endianness of the other side, we still cannot guarantee which - * endianness a REPL_XOFF_ACK_ME message is sent in (in pre-V55000 versions for example in V53004A where - * it is sent in receiver native endian format whereas in V54002B it is sent in source native - * endian format). So better be safe on the source side and handle those cases like we did when - * we did not know the endianness of the remote side. - * - * The below check works as all messages we expect at this point have a fixed length of MIN_REPL_MSGLEN. + if (SS_NORMAL != status) + break; + if (REPL_LOGFILE_INFO == msg.type) /* No need to endian convert as the receiver converts this to our native fmt */ + { /* We received a REPL_START_JNL_SEQNO/REPL_FETCH_RESYNC and coming through the loop again + * to receive REPL_LOGFILE_INFO. At this point, we should have already established the endianness + * of the remote side and even if the remote side is of different endianness, we are going to interpret the + * message without endian conversion because the Receiver Server, from REPL_PROTO_VER_SUPPLEMENTARY + * onwards, always endian converts the message intended for the Source Server */ - msg_is_cross_endian = (((unsigned)MIN_REPL_MSGLEN < (unsigned)msg.len) - && ((unsigned)MIN_REPL_MSGLEN == GTM_BYTESWAP_32((unsigned)msg.len))); + assert(remote_side->endianness_known); + assert(REPL_PROTO_VER_REMOTE_LOGPATH <= remote_side->proto_ver); + assert(-1 != *msg_type); + buffp = (unsigned char *)&logfile_msg; + /* First copy what we already received */ + memcpy(buffp, &msg, MIN_REPL_MSGLEN); + assert((logfile_msg.fullpath_len > MIN_REPL_MSGLEN) + && logfile_msg.fullpath_len < REPL_LOGFILE_PATH_MAX); + /* Now receive the rest of the message */ + buffp += MIN_REPL_MSGLEN; + remaining_len = msg.len - MIN_REPL_MSGLEN; + REPL_RECV_LOOP(gtmsource_sock_fd, buffp, remaining_len, REPL_POLL_WAIT) + { + gtmsource_poll_actions(FALSE); + if (GTMSOURCE_CHANGING_MODE == gtmsource_state) + return SS_NORMAL; + } + if (SS_NORMAL != status) + return status; + assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msg.proto_ver); + assert(logfile_msg.proto_ver == remote_side->proto_ver); + assert('\0' == logfile_msg.fullpath[logfile_msg.fullpath_len - 1]); + if (REPL_FETCH_RESYNC == *msg_type) + { + repl_log(gtmsource_log_fp, TRUE, TRUE, "Remote side rollback path is %s; Rollback PID = %d\n", + logfile_msg.fullpath, logfile_msg.pid); + } + else + { + assert(REPL_START_JNL_SEQNO == *msg_type); + repl_log(gtmsource_log_fp, TRUE, TRUE, "Remote side receiver log file path is %s; " + "Receiver Server PID = %d\n", logfile_msg.fullpath, logfile_msg.pid); + } + /* Now that we've received REPL_LOGFILE_INFO message from the other side, handshake is complete. */ + return SS_NORMAL; + } + /* If endianness of other side is not yet known, determine that now by seeing if the msg.len is + * greater than expected. If it is, convert it and see if it is now what we expect. If it is, + * then the other system is of opposite endianness. Note: We would normally use msg.type since + * it is effectively an enum and we control by adding new messages. But, REPL_START_JNL_SEQNO + * is lucky number zero which means it is identical on systems of either endianness. + * + * If endianness of other side is not yet known, determine that from the message length as we + * expect it to be MIN_REPL_MSGLEN. There is one exception though. If a pre-V55000 receiver sends + * a REPL_XOFF_ACK_ME message, it could send it in the receiver's native-endian or cross-endian + * format (depending on how its global variable "src_node_same_endianness" is initialized). This + * bug in the receiver server logic is fixed V55000 onwards (proto_ver is REPL_PROTO_VER_SUPPLEMENTARY). + * Therefore, in this case, we cannot use the endianness of the REPL_XOFF_ACK_ME message to determine + * the endianness of the connection. In this case, wait for the next non-REPL_XOFF_ACK_ME message + * to determine the connection endianness. Handle this exception case correctly. + * + * If on the other hand, we know the endianness of the other side, we still cannot guarantee which + * endianness a REPL_XOFF_ACK_ME message is sent in (in pre-V55000 versions for example in V53004A where + * it is sent in receiver native endian format whereas in V54002B it is sent in source native + * endian format). So better be safe on the source side and handle those cases like we did when + * we did not know the endianness of the remote side. + * + * The below check works as all messages we expect at this point have a fixed length of MIN_REPL_MSGLEN. + */ + msg_is_cross_endian = (((unsigned)MIN_REPL_MSGLEN < (unsigned)msg.len) + && ((unsigned)MIN_REPL_MSGLEN == GTM_BYTESWAP_32((unsigned)msg.len))); + if (msg_is_cross_endian) + { + msg.type = GTM_BYTESWAP_32(msg.type); + msg.len = GTM_BYTESWAP_32(msg.len); + } + assert(msg.type == REPL_START_JNL_SEQNO || msg.type == REPL_FETCH_RESYNC || msg.type == REPL_XOFF_ACK_ME); + assert(MIN_REPL_MSGLEN == msg.len); + /* If we dont yet know the endianness of the other side and the input message is not a REPL_XOFF_ACK_ME + * we can decide the endianness of the receiver side by the endianness of the input message. + * REPL_XOFF_ACK_ME is an exception due to its handling by pre-V5500 versions (described in comments above). + */ + if (!remote_side->endianness_known && (REPL_XOFF_ACK_ME != msg.type)) + { + remote_side->endianness_known = TRUE; + remote_side->cross_endian = msg_is_cross_endian; + if (remote_side->cross_endian) + repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have opposite " + "endianness\n"); + else + repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have same endianness\n"); + } + /* We only expect REPL_START_JNL_SEQNO, REPL_LOGFILE_INFO and REPL_XOFF_ACK_ME messages to be sent once the + * endianness of the remote side has been determined. We dont expect the REPL_FETCH_RESYNC message to be + * ever sent in the middle of a handshake (i.e. after the remote side endianness has been determined). + * Assert that. The logic that sets "msg_is_cross_endian" relies on this. If this assert fails, the logic + * has to change. + */ + assert((REPL_FETCH_RESYNC != msg.type) || !remote_side_endianness_known); + *msg_type = msg.type; + *start_flags = START_FLAG_NONE; + memcpy((uchar_ptr_t)recvd_jnl_seqno, (uchar_ptr_t)&msg.msg[0], SIZEOF(seq_num)); + if (REPL_START_JNL_SEQNO == msg.type) + { if (msg_is_cross_endian) + *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); + repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_START_JNL_SEQNO message with SEQNO " + "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno)); + if (msg_is_cross_endian) + ((repl_start_msg_ptr_t)&msg)->start_flags = + GTM_BYTESWAP_32(((repl_start_msg_ptr_t)&msg)->start_flags); + *start_flags = ((repl_start_msg_ptr_t)&msg)->start_flags; + assert(!msg_is_cross_endian || (NODE_ENDIANNESS != ((repl_start_msg_ptr_t)&msg)->node_endianness)); + if (*start_flags & START_FLAG_STOPSRCFILTER) { - msg.type = GTM_BYTESWAP_32(msg.type); - msg.len = GTM_BYTESWAP_32(msg.len); - } - assert(msg.type == REPL_START_JNL_SEQNO || msg.type == REPL_FETCH_RESYNC || msg.type == REPL_XOFF_ACK_ME); - assert(MIN_REPL_MSGLEN == msg.len); - /* If we dont yet know the endianness of the other side and the input message is not a REPL_XOFF_ACK_ME - * we can decide the endianness of the receiver side by the endianness of the input message. - * REPL_XOFF_ACK_ME is an exception due to its handling by pre-V5500 versions (described in comments above). - */ - if (!remote_side->endianness_known && (REPL_XOFF_ACK_ME != msg.type)) - { - remote_side->endianness_known = TRUE; - remote_side->cross_endian = msg_is_cross_endian; - if (remote_side->cross_endian) - repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have opposite " - "endianness\n"); - else - repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have same endianness\n"); - } - /* We only expect REPL_START_JNL_SEQNO and REPL_XOFF_ACK_ME messages to be sent once the endianness of - * the remote side has been determined. We dont expect the REPL_FETCH_RESYNC message to be ever sent in - * the middle of a handshake (i.e. after the remote side endianness has been determined). Assert that. - * The logic that sets "msg_is_cross_endian" relies on this. If this assert fails, the logic has to change. - */ - assert((REPL_FETCH_RESYNC != msg.type) || !remote_side_endianness_known); - *msg_type = msg.type; - *start_flags = START_FLAG_NONE; - memcpy((uchar_ptr_t)recvd_jnl_seqno, (uchar_ptr_t)&msg.msg[0], SIZEOF(seq_num)); - if (REPL_START_JNL_SEQNO == msg.type) - { - if (msg_is_cross_endian) - *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); - repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_START_JNL_SEQNO message with SEQNO " - "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno)); - if (msg_is_cross_endian) - ((repl_start_msg_ptr_t)&msg)->start_flags = - GTM_BYTESWAP_32(((repl_start_msg_ptr_t)&msg)->start_flags); - *start_flags = ((repl_start_msg_ptr_t)&msg)->start_flags; - assert(!msg_is_cross_endian || (NODE_ENDIANNESS != ((repl_start_msg_ptr_t)&msg)->node_endianness)); - if (*start_flags & START_FLAG_STOPSRCFILTER) + repl_log(gtmsource_log_fp, TRUE, TRUE, + "Start JNL_SEQNO msg tagged with STOP SOURCE FILTER\n"); + if (gtmsource_filter & EXTERNAL_FILTER) { - repl_log(gtmsource_log_fp, TRUE, TRUE, - "Start JNL_SEQNO msg tagged with STOP SOURCE FILTER\n"); - if (gtmsource_filter & EXTERNAL_FILTER) - { - repl_stop_filter(); - gtmsource_filter &= ~EXTERNAL_FILTER; - } else - repl_log(gtmsource_log_fp, TRUE, TRUE, - "Filter is not active, ignoring STOP SOURCE FILTER msg\n"); - *msg_type = REPL_START_JNL_SEQNO; - } - /* Determine the protocol version of the receiver side. That information is encoded in the - * "proto_ver" field of the message from V51 onwards but to differentiate V50 vs V51 we need - * to check if the START_FLAG_VERSION_INFO bit is set in start_flags. If not the protocol is V50. - * V51 implies support for multi-site while V50 implies dual-site configuration only. - */ - if (*start_flags & START_FLAG_VERSION_INFO) - { - assert(REPL_PROTO_VER_DUALSITE != ((repl_start_msg_ptr_t)&msg)->proto_ver); - remote_side->is_supplementary = ((repl_start_msg_ptr_t)&msg)->is_supplementary; - remote_side->proto_ver = ((repl_start_msg_ptr_t)&msg)->proto_ver; + repl_stop_filter(); + gtmsource_filter &= ~EXTERNAL_FILTER; } else - { /* Issue REPL2OLD error because receiver is dual-site */ - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME), - LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); - } - assert(*start_flags & START_FLAG_HASINFO); /* V4.2+ versions have jnl ver in the start msg */ - remote_side->jnl_ver = ((repl_start_msg_ptr_t)&msg)->jnl_ver; - REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n", - this_side->jnl_ver, remote_side->jnl_ver); - repl_check_jnlver_compat(!remote_side->cross_endian); - assert(remote_side->jnl_ver > V15_JNL_VER || 0 == (*start_flags & START_FLAG_COLL_M)); - if (remote_side->jnl_ver <= V15_JNL_VER) - *start_flags &= ~START_FLAG_COLL_M; /* zap it for pro, just in case */ - remote_side->is_std_null_coll = (*start_flags & START_FLAG_COLL_M) ? TRUE : FALSE; - assert((remote_side->jnl_ver >= V19_JNL_VER) || (0 == (*start_flags & START_FLAG_TRIGGER_SUPPORT))); - if (remote_side->jnl_ver < V19_JNL_VER) - *start_flags &= ~START_FLAG_TRIGGER_SUPPORT; /* zap it for pro, just in case */ - remote_side->trigger_supported = (*start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE; -# ifdef GTM_TRIGGER - if (!remote_side->trigger_supported) - repl_log(gtmsource_log_fp, TRUE, TRUE, "Warning : Secondary does not support GT.M " - "database triggers. #t updates on primary will not be replicated\n"); -# endif - /* remote_side->null_subs_xform is initialized later in function "gtmsource_process" */ - (TREF(replgbl)).trig_replic_warning_issued = FALSE; - return (SS_NORMAL); - } else if (REPL_FETCH_RESYNC == msg.type) - { /* Determine the protocol version of the receiver side. - * Take care to set the flush parameter in repl_log calls below to FALSE until at least the - * first message gets sent back. This is so the fetchresync rollback on the other side does - * not timeout before receiving a response. */ - remote_side->proto_ver = (RECAST(repl_resync_msg_ptr_t)&msg)->proto_ver; - remote_side->is_supplementary = (RECAST(repl_resync_msg_ptr_t)&msg)->is_supplementary; - /* The following fields dont need to be initialized since they are needed (for internal filter - * transformations) only if we send journal records across. REPL_FETCH_RESYNC causes only - * protocol messages to be exchanged (no journal records). - * remote_side->jnl_ver = ... - * remote_side->is_std_null_coll = ... - * remote_side->trigger_supported = ... - * remote_side->null_subs_xform = ... - */ - if (msg_is_cross_endian) - *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); - repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_FETCH_RESYNC message with SEQNO " - "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno)); - return (SS_NORMAL); - } else if (REPL_XOFF_ACK_ME == msg.type) - { - repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_XOFF_ACK_ME message. " - "Possible crash/shutdown of update process\n"); - /* Send XOFF_ACK */ - xoff_ack.type = REPL_XOFF_ACK; - if (msg_is_cross_endian) - *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); - memcpy((uchar_ptr_t)&xoff_ack.msg[0], (uchar_ptr_t)recvd_jnl_seqno, SIZEOF(seq_num)); - xoff_ack.len = MIN_REPL_MSGLEN; - repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_XOFF_ACK message\n"); - REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, FALSE, >msource_poll_immediate) - { - gtmsource_poll_actions(FALSE); - if (GTMSOURCE_CHANGING_MODE == gtmsource_state) - return (SS_NORMAL); - } - } else - { /* If unknown message is received, close connection. Caller will reopen the same. */ - repl_log(gtmsource_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). " - "Closing connection.\n", msg.type); - assert(FALSE); - repl_close(>msource_sock_fd); - SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN); - gtmsource_state = jnlpool.gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION; - return (SS_NORMAL); + repl_log(gtmsource_log_fp, TRUE, TRUE, + "Filter is not active, ignoring STOP SOURCE FILTER msg\n"); } + /* Determine the protocol version of the receiver side. That information is encoded in the + * "proto_ver" field of the message from V51 onwards but to differentiate V50 vs V51 we need + * to check if the START_FLAG_VERSION_INFO bit is set in start_flags. If not the protocol is V50. + * V51 implies support for multi-site while V50 implies dual-site configuration only. + */ + if (*start_flags & START_FLAG_VERSION_INFO) + { + assert(REPL_PROTO_VER_DUALSITE != ((repl_start_msg_ptr_t)&msg)->proto_ver); + remote_side->is_supplementary = ((repl_start_msg_ptr_t)&msg)->is_supplementary; + remote_side->proto_ver = ((repl_start_msg_ptr_t)&msg)->proto_ver; + } else + { /* Issue REPL2OLD error because receiver is dual-site */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME), + LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); + } + assert(*start_flags & START_FLAG_HASINFO); /* V4.2+ versions have jnl ver in the start msg */ + remote_side->jnl_ver = ((repl_start_msg_ptr_t)&msg)->jnl_ver; + REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n", + this_side->jnl_ver, remote_side->jnl_ver); + repl_check_jnlver_compat(!remote_side->cross_endian); + assert(remote_side->jnl_ver > V15_JNL_VER || 0 == (*start_flags & START_FLAG_COLL_M)); + if (remote_side->jnl_ver <= V15_JNL_VER) + *start_flags &= ~START_FLAG_COLL_M; /* zap it for pro, just in case */ + remote_side->is_std_null_coll = (*start_flags & START_FLAG_COLL_M) ? TRUE : FALSE; + assert((remote_side->jnl_ver >= V19_JNL_VER) || (0 == (*start_flags & START_FLAG_TRIGGER_SUPPORT))); + if (remote_side->jnl_ver < V19_JNL_VER) + *start_flags &= ~START_FLAG_TRIGGER_SUPPORT; /* zap it for pro, just in case */ + remote_side->trigger_supported = (*start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE; +# ifdef GTM_TRIGGER + if (!remote_side->trigger_supported) + repl_log(gtmsource_log_fp, TRUE, TRUE, "Warning : Secondary does not support GT.M " + "database triggers. #t updates on primary will not be replicated\n"); +# endif + /* remote_side->null_subs_xform is initialized later in function "gtmsource_process" */ + (TREF(replgbl)).trig_replic_warning_issued = FALSE; + if (REPL_PROTO_VER_REMOTE_LOGPATH > remote_side->proto_ver) + return SS_NORMAL; /* Remote side doesn't support REPL_LOGFILE_INFO message */ + SEND_REPL_LOGFILE_INFO(jnlpool.gtmsource_local->log_file, logfile_msg); + log_waitmsg = FALSE; + } else if (REPL_FETCH_RESYNC == msg.type) + { /* Determine the protocol version of the receiver side. + * Take care to set the flush parameter in repl_log calls below to FALSE until at least the + * first message gets sent back. This is so the fetchresync rollback on the other side does + * not timeout before receiving a response. */ + remote_side->proto_ver = (RECAST(repl_resync_msg_ptr_t)&msg)->proto_ver; + remote_side->is_supplementary = (RECAST(repl_resync_msg_ptr_t)&msg)->is_supplementary; + /* The following fields dont need to be initialized since they are needed (for internal filter + * transformations) only if we send journal records across. REPL_FETCH_RESYNC causes only + * protocol messages to be exchanged (no journal records). + * remote_side->jnl_ver = ... + * remote_side->is_std_null_coll = ... + * remote_side->trigger_supported = ... + * remote_side->null_subs_xform = ... + */ + if (msg_is_cross_endian) + *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); + repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_FETCH_RESYNC message with SEQNO " + "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno)); + if (REPL_PROTO_VER_REMOTE_LOGPATH > remote_side->proto_ver) + return SS_NORMAL; /* Remote side doesn't support REPL_LOGFILE_INFO message */ + SEND_REPL_LOGFILE_INFO(jnlpool.gtmsource_local->log_file, logfile_msg); + log_waitmsg = FALSE; + } else if (REPL_XOFF_ACK_ME == msg.type) + { + repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_XOFF_ACK_ME message. " + "Possible crash/shutdown of update process\n"); + /* Send XOFF_ACK */ + xoff_ack.type = REPL_XOFF_ACK; + if (msg_is_cross_endian) + *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno); + memcpy((uchar_ptr_t)&xoff_ack.msg[0], (uchar_ptr_t)recvd_jnl_seqno, SIZEOF(seq_num)); + xoff_ack.len = MIN_REPL_MSGLEN; + repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_XOFF_ACK message\n"); + REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, REPL_POLL_NOWAIT) + { + gtmsource_poll_actions(FALSE); + if (GTMSOURCE_CHANGING_MODE == gtmsource_state) + return (SS_NORMAL); + } + log_waitmsg = TRUE; /* Wait for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC */ + } else + { /* If unknown message is received, close connection. Caller will reopen the same. */ + repl_log(gtmsource_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). " + "Closing connection.\n", msg.type); + assert(FALSE); + repl_close(>msource_sock_fd); + SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN); + gtmsource_state = jnlpool.gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION; + return (SS_NORMAL); } } return (status); @@ -588,9 +667,9 @@ int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags) if (recvd_jnl_seqno > cur_read_jnl_seqno) { /* The secondary is requesting a seqno higher than what we last remember having sent but yet it is in sync with us * upto seqno "recvd_jnl_seqno" as otherwise the caller would have determined it is out of sync and not even call - * us. To illustrate an example of how this could happen, consider an INSTA->INSTB replication and INSTA->INSTB - * replication going on. Lets say INSTA's journal sequence number is at 100. INSTB is at 60 and INSTB is at 30. - * This means, last sequence number sent by INSTA to INSTB is 60 and to INSTB is 30. Now, lets say INSTA is shutdown + * us. To illustrate an example of how this could happen, consider an INSTA->INSTB replication and INSTA->INSTC + * replication going on. Lets say INSTA's journal sequence number is at 100. INSTB is at 60 and INSTC is at 30. + * This means, last sequence number sent by INSTA to INSTB is 60 and to INSTC is 30. Now, lets say INSTA is shutdown * and INSTB comes up as the primary to INSTC and starts replicating the 30 updates thereby bringing both INSTB and * INSTC sequence number to 60. Now, if INSTA comes backup again as primary against INSTC, we will have a case where * gtmsource_local->read_jnl_seqno as 30, but recvd_jnl_seqno as 60. This means that we are going to bump @@ -602,7 +681,7 @@ int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags) */ if ((READ_FILE != gtmsource_local->read_state) || (recvd_jnl_seqno > gtmsource_save_read_jnl_seqno)) { - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); gtmsource_local->read_state = READ_FILE; gtmsource_save_read_jnl_seqno = jctl->jnl_seqno; gtmsource_local->read_addr = jnlpool.jnlpool_ctl->write_addr; @@ -675,7 +754,8 @@ int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags) { assert(cur_read + SIZEOF(jnldata_hdr_struct) <= jnlpool_size); prev_tr_size = ((jnldata_hdr_ptr_t)(jnlpool.jnldata_base + cur_read))->prev_jnldata_len; - if (jnlpool_hasnt_overflowed(jctl, jnlpool_size, cur_read_addr)) + if ((prev_tr_size <= cur_read_addr) && + jnlpool_hasnt_overflowed(jctl, jnlpool_size, cur_read_addr - prev_tr_size)) { QWDECRBYDW(cur_read_addr, prev_tr_size); prev_read = cur_read; @@ -773,14 +853,10 @@ int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boole read_addr = gtmsource_local->read_addr; assert(read_addr <= write_addr); assert((0 != write_addr) || (read_jnl_seqno <= jctl->start_jnl_seqno)); - -#ifdef GTMSOURCE_ALWAYS_READ_FILES - gtmsource_local->read_state = READ_FILE; -#endif + GTMDBGFLAGS_NOFREQ_ONLY(GTMSOURCE_FORCE_READ_FILE_MODE, gtmsource_local->read_state = READ_FILE); switch(gtmsource_local->read_state) { case READ_POOL: -#ifndef GTMSOURCE_ALWAYS_READ_FILES_STRESS if (read_addr == write_addr) { /* Nothing to read. While reading pool, the comparison of read_addr against write_addr is * the only reliable indicator if there are any transactions to be read. This is due to @@ -801,7 +877,6 @@ int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boole return (total_tr_len); if (0 < *data_len) return (-1); -#endif /* for GTMSOURCE_ALWAYS_READ_FILES_STRESS, we let the source server switch back and forth between pool read and file read */ /* Overflow, switch to READ_FILE */ gtmsource_local->read_state = READ_FILE; QWASSIGN(gtmsource_save_read_jnl_seqno, read_jnl_seqno); @@ -886,7 +961,7 @@ void gtmsource_repl_send(repl_msg_ptr_t msg, char *msgtypestr, seq_num optional_ msgtypestr, optional_seqno, optional_seqno, optional_strm_num); } else repl_log(gtmsource_log_fp, TRUE, FALSE, "Sending %s message\n", msgtypestr); - REPL_SEND_LOOP(gtmsource_sock_fd, msg, msg->len, FALSE, >msource_poll_immediate) + REPL_SEND_LOOP(gtmsource_sock_fd, msg, msg->len, REPL_POLL_NOWAIT) { gtmsource_poll_actions(FALSE); if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)) @@ -908,13 +983,13 @@ void gtmsource_repl_send(repl_msg_ptr_t msg, char *msgtypestr, seq_num optional_ { SNPRINTF(err_string, SIZEOF(err_string), "Error sending %s message. " "Error in send : %s", msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string)); } if (EREPL_SELECT == repl_errno) { SNPRINTF(err_string, SIZEOF(err_string), "Error sending %s message. " "Error in select : %s", msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string)); } } } @@ -954,7 +1029,7 @@ static boolean_t gtmsource_repl_recv(repl_msg_ptr_t msg, int4 msglen, int4 msgty * code that passes a 3rd parameter > MIN_REPL_MSGLEN. All such usages need a check inside the body of the * loop to account for a REPL_XOFF_ACK_ME and if so break. */ - REPL_RECV_LOOP(gtmsource_sock_fd, buff, bufflen, FALSE, >msource_poll_wait) + REPL_RECV_LOOP(gtmsource_sock_fd, buff, bufflen, REPL_POLL_WAIT) { gtmsource_poll_actions(TRUE); if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)) @@ -986,14 +1061,16 @@ static boolean_t gtmsource_repl_recv(repl_msg_ptr_t msg, int4 msglen, int4 msgty SNPRINTF(err_string, SIZEOF(err_string), "Error receiving %s message from Receiver. Error in recv : %s", msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } else if (EREPL_SELECT == repl_errno) { SNPRINTF(err_string, SIZEOF(err_string), "Error receiving %s message from Receiver. Error in select : %s", msgtypestr, STRERROR(status)); - rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, + LEN_AND_STR(err_string)); } } assert(SS_NORMAL == status); @@ -1209,7 +1286,7 @@ boolean_t gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_ if (jnlpool.repl_inst_filehdr->is_supplementary) { /* Issue REPL2OLD error because this is a supplementary instance and remote side runs * on a GT.M version that does not understand the supplementary protocol */ - rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_instinfo_msg.instname), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_instinfo_msg.instname), LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname)); } /* Check if instance name in the REPL_OLD_INSTANCE_INFO message matches that in the source server command line */ @@ -1255,7 +1332,7 @@ boolean_t gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_ { /* Issue SECNOTSUPPLEMENTARY error because this is a supplementary primary and secondary * is not a supplementary instance. */ - rts_error(VARLSTCNT(6) ERR_SECNOTSUPPLEMENTARY, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SECNOTSUPPLEMENTARY, 4, LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname), LEN_AND_STR(instinfo_msg.instname)); } @@ -1394,7 +1471,7 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac return FALSE; /* recv did not succeed */ assert(REPL_STRMINFO == strminfo_msg.type); /* Verify that the list of known streams is identical on both sides */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return FALSE; /* concurrent online rollback happened */ status = repl_inst_histinfo_find_seqno(seqno, INVALID_SUPPL_STRM, &local_histinfo); @@ -1412,9 +1489,15 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac lcl_strm_valid = (INVALID_HISTINFO_NUM != local_histinfo.last_histinfo_num[idx]); remote_strm_valid = (INVALID_HISTINFO_NUM != strminfo_msg.last_histinfo_num[idx]); if (!lcl_strm_valid && remote_strm_valid) - rts_error(VARLSTCNT(3) ERR_STRMNUMMISMTCH1, 1, idx); + { + assert(FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STRMNUMMISMTCH1, 1, idx); + } else if (lcl_strm_valid && !remote_strm_valid) - rts_error(VARLSTCNT(3) ERR_STRMNUMMISMTCH2, 1, idx); + { + assert(FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STRMNUMMISMTCH2, 1, idx); + } } /* Now that we know both sides have the exact set of known streams, verify history record for each stream matches */ /* Send REPL_NEED_HISTINFO message for each stream. Do common initialization outside loop */ @@ -1444,7 +1527,7 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac return FALSE; /* recv did not succeed */ assert(REPL_HISTINFO == histinfo_msg.type); /* Find corresponding history record on LOCAL side */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return FALSE; /* concurrent online rollback happened */ status = repl_inst_histinfo_get(lcl_histinfo_num, &local_histinfo); @@ -1478,7 +1561,7 @@ void gtmsource_histinfo_get(int4 index, repl_histinfo *histinfo) { assert(ERR_REPLINSTNOHIST == status); /* currently the only error returned by "repl_inst_histinfo_get" */ SPRINTF(histdetail, "record number %d [0x%x]", index, index); - gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn)); /* Send this error status to the receiver server before closing the connection. This way the receiver * will know to shut down rather than loop back trying to reconnect. This avoids an infinite loop of * connection open and closes between the source server and receiver server. @@ -1586,7 +1669,7 @@ seq_num gtmsource_find_resync_seqno(repl_histinfo *local_histinfo, repl_histinfo { /* Need to get the previous histinfo record on the primary */ local_histinfo_num = local_histinfo->prev_histinfo_num; assert(0 <= local_histinfo->histinfo_num); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return MAX_SEQNO; gtmsource_histinfo_get(local_histinfo_num, local_histinfo); @@ -1643,7 +1726,7 @@ void gtmsource_send_new_histrec() if ((GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) || (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)) return; /* "gtmsource_set_next_histinfo_seqno" encountered REPLINSTNOHIST or concurrent online rollback occurred */ /*************** Read histinfo (to send) from instance file first ***************/ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return; assert(1 <= gtmsource_local->next_histinfo_num); @@ -1765,7 +1848,7 @@ void gtmsource_set_next_histinfo_seqno(boolean_t detect_new_histinfo) csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; ASSERT_VALID_JNLPOOL(csa); ) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return; assert(NULL != jnlpool.repl_inst_filehdr); /* journal pool should be set up */ @@ -1798,7 +1881,7 @@ void gtmsource_set_next_histinfo_seqno(boolean_t detect_new_histinfo) NON_GTM64_ONLY(SPRINTF(histdetail, "seqno [0x%llx]", read_seqno - 1)); GTM64_ONLY(SPRINTF(histdetail, "seqno [0x%lx]", read_seqno - 1)); udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); - gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn)); /* Send error status to the receiver server before closing the connection. This way the * receiver will know to shut down rather than loop back trying to reconnect. This avoids diff --git a/sr_unix/gtmsource_readfiles.c b/sr_unix/gtmsource_readfiles.c index 93f2344..313d75f 100644 --- a/sr_unix/gtmsource_readfiles.c +++ b/sr_unix/gtmsource_readfiles.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,6 +58,7 @@ #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif +#include "gtmdbgflags.h" #define LOG_WAIT_FOR_JNL_RECS_PERIOD (10 * 1000) /* ms */ #define LOG_WAIT_FOR_JNLOPEN_PERIOD (10 * 1000) /* ms */ @@ -78,17 +79,20 @@ GBLREF int gtmsource_msgbufsiz; GBLREF seq_num seq_num_zero, seq_num_one; GBLREF gd_region *gv_cur_region; GBLREF FILE *gtmsource_log_fp; -GBLREF FILE *gtmsource_statslog_fp; GBLREF gtmsource_state_t gtmsource_state; GBLREF uint4 process_id; +LITREF char *jnl_file_state_lit[]; + error_def(ERR_JNLBADRECFMT); error_def(ERR_JNLEMPTY); +error_def(ERR_JNLFILRDOPN); error_def(ERR_JNLRECINCMPL); error_def(ERR_NOPREVLINK); error_def(ERR_REPLBRKNTRANS); error_def(ERR_REPLCOMM); error_def(ERR_REPLFILIOERR); +error_def(ERR_SEQNUMSEARCHTIMEOUT); error_def(ERR_TEXT); static int4 num_tcom = -1; @@ -139,6 +143,11 @@ static int repl_read_file(repl_buff_t *rb) assert(!fc->jfh->crash); dskaddr = REAL_END_OF_DATA(fc); } +# ifdef DEBUG + b->save_readaddr = b->readaddr; + b->save_dskaddr = dskaddr; + b->save_buffremaining = b->buffremaining; +# endif /* Make sure we do not read beyond end of data in the journal file */ /* Note : This logic is always needed when journal file is pre-allocated. * With no pre-allocation, this logic is needed only when repl_read_file is called from @@ -163,11 +172,11 @@ static int repl_read_file(repl_buff_t *rb) if ((off_t)-1 == lseek(fc->fd, (off_t)start_addr, SEEK_SET)) { repl_errno = EREPL_JNLFILESEEK; - return (ERRNO); + return (errno); } READ_FILE(fc->fd, b->base + REPL_BLKSIZE(rb) - b->buffremaining - (b->readaddr - start_addr), end_addr - start_addr, nb); - status = ERRNO; + status = errno; if (nb < (b->readaddr - start_addr)) { /* This case means that we didn't read enough bytes to get from the alignment point in the disk file * to the start of the actual desired read (the offset we did the lseek to above). This can't happen @@ -199,16 +208,18 @@ static int repl_next(repl_buff_t *rb) uint4 maxreclen; int status, sav_buffremaining; char err_string[BUFSIZ]; - GTMCRYPT_ONLY( - int crypt_status; - enum jnl_record_type rectype; - jnl_record *rec; - jnl_string *keystr; - ) + repl_ctl_element *backctl; +# ifdef GTM_CRYPT + int gtmcrypt_errno; + enum jnl_record_type rectype; + jnl_record *rec; + jnl_string *keystr; +# endif b = &rb->buff[rb->buffindex]; b->recbuff += b->reclen; /* The next record */ b->recaddr += b->reclen; + backctl = rb->backctl; if (b->recaddr == b->readaddr && b->buffremaining == 0) { /* Everything in this buffer processed */ @@ -217,7 +228,7 @@ static int repl_next(repl_buff_t *rb) b->buffremaining = REPL_BLKSIZE(rb); } if (b->recaddr == b->readaddr || b->reclen == 0 || - (rb->backctl->eof_addr_final && (b->readaddr != REAL_END_OF_DATA(rb->fc)) && b->buffremaining)) + (backctl->eof_addr_final && (b->readaddr != REAL_END_OF_DATA(rb->fc)) && b->buffremaining)) { sav_buffremaining = b->buffremaining; if ((status = repl_read_file(rb)) == SS_NORMAL) @@ -240,7 +251,7 @@ static int repl_next(repl_buff_t *rb) MEMCPY_LIT(err_string, READ_ERR_STR); else MEMCPY_LIT(err_string, UNKNOWN_ERR_STR); - rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, rb->backctl->jnl_fn_len, rb->backctl->jnl_fn, + rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, backctl->jnl_fn_len, backctl->jnl_fn, ERR_TEXT, 2, LEN_AND_STR(err_string), status); } } @@ -261,10 +272,9 @@ static int repl_next(repl_buff_t *rb) keystr = (jnl_string *)&rec->jrec_set_kill.mumps_node; /* Assert that ZTWORMHOLE type record too has same layout as KILL/SET */ assert((sm_uc_ptr_t)keystr == (sm_uc_ptr_t)&rec->jrec_ztworm.ztworm_str); - DECODE_SET_KILL_ZKILL_ZTRIG(keystr, rec->prefix.forwptr, rb->backctl->encr_key_handle, - crypt_status); - if (0 != crypt_status) - GC_RTS_ERROR(crypt_status, rb->backctl->jnl_fn); + MUR_DECRYPT_LOGICAL_RECS(keystr, rec->prefix.forwptr, backctl->encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, backctl->jnl_fn_len, backctl->jnl_fn); } } # endif @@ -383,7 +393,7 @@ static int open_newer_gener_jnlfiles(gd_region *reg, repl_ctl_element *reg_ctl_e } /* Except the latest generation, mark the newly opened future generations CLOSED, or EMPTY. * We assume that when a new file is opened, the previous generation has been flushed to disk fully. - */ + C9M06-999999 */ for (ctl = reg_ctl_end, n = nopen; n; n--, ctl = ctl->next) { if (ctl->file_state == JNL_FILE_UNREAD) @@ -440,7 +450,7 @@ static int update_eof_addr(repl_ctl_element *ctl, int *eof_change) F_READ_BLK_ALIGNED(fc->fd, 0, fc->jfh, REAL_JNL_HDR_LEN, status); if (SS_NORMAL != status) rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, ctl->jnl_fn_len, ctl->jnl_fn, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in reading jfh in update_eof_addr"), status); + ERR_TEXT, 2, LEN_AND_LIT("Error in reading jfh in update_eof_addr"), status); REPL_DPRINT2("Update EOF : Jnl file hdr refreshed from file for %s\n", ctl->jnl_fn); ctl->eof_addr_final = TRUE; /* No more updates to fc->eof_addr for this journal file */ } @@ -758,13 +768,17 @@ static void increase_buffer(unsigned char **buff, int *buflen, int buffer_needed REPL_DPRINT3("Buff space shortage. Attempting to increase buff space. Curr buff space %d. Attempt increase to atleast %d\n", gtmsource_msgbufsiz, newbuffsize); old_msgp = (unsigned char *)gtmsource_msgp; - if ((alloc_status = gtmsource_alloc_msgbuff(newbuffsize)) != SS_NORMAL) + if ((alloc_status = gtmsource_alloc_msgbuff(newbuffsize, FALSE)) != SS_NORMAL) { rts_error(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_DPRINT2("Old *buff = 0x%llx\n", *buff); *buff = (unsigned char *)gtmsource_msgp + (*buff - old_msgp); + REPL_DPRINT2("New *buff = 0x%llx\n", *buff); *buflen =(int)(gtmsource_msgbufsiz - (*buff - (unsigned char *)gtmsource_msgp)); + REPL_DPRINT2("New remaining len = %ld\n", *buflen); return; } @@ -864,7 +878,7 @@ static int read_transaction(repl_ctl_element *ctl, unsigned char **buff, int *bu { assert(FALSE); rts_error(VARLSTCNT(7) ERR_REPLBRKNTRANS, 1, &read_jnl_seqno, - ERR_TEXT, 2, RTS_ERROR_LITERAL("Early EOF found")); + ERR_TEXT, 2, LEN_AND_LIT("Early EOF found")); } } else if (status == EREPL_JNLRECINCMPL) { /* Log warning message for every certain number of attempts. There might have been a crash and the file @@ -1237,16 +1251,19 @@ static tr_search_state_t position_read(repl_ctl_element *ctl, seq_num read_seqno lo_addr = ctl->min_seqno_dskaddr; hi_addr = b->recaddr + b->reclen; } else - { /* trying to locate min, better to do linear search */ + { /* trying to locate min, better to do linear search */ srch_func = do_linear_search; lo_addr = ctl->min_seqno_dskaddr; hi_addr = MAXUINT4; - if (read_seqno == ctl->seqno) /* we are positioned where we want to be, no need for read */ - { - assert(lo_addr == b->recaddr); + /* read_seqno == ctl->seqno == ctl->min_seqno is a special case. But, don't know how that can happen without + * lookback set and hence the assert below. + */ + assert((read_seqno != ctl->seqno) || ctl->lookback); + if ((read_seqno == ctl->seqno) && (lo_addr == b->recaddr)) + { /* we are positioned where we want to be, no need for a read */ assert(MIN_JNLREC_SIZE <= b->reclen); - DEBUG_ONLY(jrec = (jnl_record *)b->recbuff;) - DEBUG_ONLY(rectype = (enum jnl_record_type)jrec->prefix.jrec_type;) + DEBUG_ONLY(jrec = (jnl_record *)b->recbuff); + DEBUG_ONLY(rectype = (enum jnl_record_type)jrec->prefix.jrec_type); assert(b->reclen == jrec->prefix.forwptr); assert(IS_VALID_JNLREC(jrec, rb->fc->jfh)); assert(IS_REPLICATED(rectype)); @@ -1257,13 +1274,13 @@ static tr_search_state_t position_read(repl_ctl_element *ctl, seq_num read_seqno } } } -#if defined(GTMSOURCE_READFILES_LINEAR_SEARCH_TEST) +# if defined(GTMSOURCE_READFILES_LINEAR_SEARCH_TEST) srch_func = do_linear_search; hi_addr = MAXUINT4; -#elif defined(GTMSOURCE_READFILES_BINARY_SEARCH_TEST) +# elif defined(GTMSOURCE_READFILES_BINARY_SEARCH_TEST) srch_func = do_binary_search; hi_addr = rb->fc->eof_addr; -#endif +# endif REPL_DPRINT6("position_read: Using %s search to locate %llu in %s between %u and %u\n", (srch_func == do_linear_search) ? "linear" : "binary", read_seqno, ctl->jnl_fn, lo_addr, hi_addr); found = srch_func(ctl, lo_addr, hi_addr, read_seqno, &srch_status); @@ -1289,7 +1306,11 @@ static int read_and_merge(unsigned char *buff, int maxbufflen, seq_num read_jnl_ boolean_t brkn_trans; unsigned char *seq_num_ptr, seq_num_str[32]; /* INT8_PRINT */ repl_ctl_element *ctl; + int wait_for_jnlopen_log_num = -1; + sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; trans_read = FALSE; num_tcom = -1; tot_tcom_len = 0; @@ -1298,18 +1319,47 @@ static int read_and_merge(unsigned char *buff, int maxbufflen, seq_num read_jnl_ total_wait_for_jnlopen = 0; tcombuffp = gtmsource_tcombuff_start; buff_avail = maxbufflen; + /* ensure that buff is always within gtmsource_msgp bounds (especially in case the buffer got expanded in the last call) */ + assert((buff >= (uchar_ptr_t)gtmsource_msgp + REPL_MSG_HDRLEN) + && (buff <= (uchar_ptr_t)gtmsource_msgp + gtmsource_msgbufsiz)); for (ctl = repl_ctl_list->next; ctl != NULL; ctl = ctl->next) ctl->read_complete = FALSE; for (pass = 1; !trans_read; pass++) { - if (pass > 1) + if (1 < pass) { gtmsource_poll_actions(TRUE); SHORT_SLEEP(GTMSOURCE_WAIT_FOR_JNLOPEN); - if ((total_wait_for_jnlopen += GTMSOURCE_WAIT_FOR_JNLOPEN) % LOG_WAIT_FOR_JNLOPEN_PERIOD == 0) + if (0 == ((total_wait_for_jnlopen += GTMSOURCE_WAIT_FOR_JNLOPEN) % LOG_WAIT_FOR_JNLOPEN_PERIOD)) + { + if (LOG_WAIT_FOR_JNLOPEN_TIMES > ++wait_for_jnlopen_log_num) repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_WARN : Source server waited %dms for journal file(s) " "to be opened, or updated while attempting to read seqno %llu [0x%llx]. Check for " "problems with journaling\n", total_wait_for_jnlopen, read_jnl_seqno, read_jnl_seqno); + else + { + for (ctl = repl_ctl_list->next; NULL != ctl; ctl = ctl->next) + { + repl_log(gtmsource_log_fp, FALSE, FALSE, "DGB_INFO: Journal File: %s for Database File: %s;" + " State: %s.", ctl->jnl_fn, ctl->reg->dyn.addr->fname, + jnl_file_state_lit[ctl->file_state]); + if (JNL_FILE_OPEN == ctl->file_state) + { + csa = &FILE_INFO(ctl->reg)->s_addrs; + repl_log(gtmsource_log_fp, FALSE, FALSE, " " + "ctl->seqno = %llu [0x%llx]. [dskaddr = 0x%x,freeaddr = 0x%x]. " + "ctl->read_complete = %d\n", + ctl->seqno, ctl->seqno, csa->jnl->jnl_buff->dskaddr, + csa->jnl->jnl_buff->freeaddr, ctl->read_complete); + } 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(VARLSTCNT(4) ERR_SEQNUMSEARCHTIMEOUT, 2, &read_jnl_seqno, &read_jnl_seqno); + } + } } read_len = read_regions(&buff, &buff_avail, pass > 1, &brkn_trans, read_jnl_seqno); if (brkn_trans) @@ -1340,14 +1390,21 @@ static int read_regions(unsigned char **buff, int *buff_avail, sgmnt_addrs *csa; jnlpool_ctl_ptr_t jctl; uint4 freeaddr; + DEBUG_ONLY(boolean_t file_close;) cumul_read = 0; *brkn_trans = TRUE; + DEBUG_ONLY(file_close = FALSE;) assert(repl_ctl_list->next != NULL); jctl = jnlpool.jnlpool_ctl; + DEBUG_ONLY(GTM_WHITE_BOX_TEST(WBTEST_CLOSE_JNLFILE, file_close, TRUE);) /* For each region */ for (ctl = repl_ctl_list->next, prev_ctl = repl_ctl_list; ctl != NULL && !trans_read; prev_ctl = ctl, ctl = ctl->next) { +#ifdef DEBUG + if (file_close) + ctl->file_state = JNL_FILE_CLOSED; +#endif found = TR_NOT_FOUND; region = ctl->reg; DEBUG_ONLY(loopcnt = 0;) @@ -1361,7 +1418,7 @@ static int read_regions(unsigned char **buff, int *buff_avail, ; if (ctl == NULL || ctl->reg != region) { /* Hit the end of generation list for journal file */ - if (!attempt_open_oldnew) + if (!attempt_open_oldnew DEBUG_ONLY( || file_close)) { /* Reposition to skip prev_ctl */ REPL_DPRINT2("First pass...not opening newer gener file...skipping %s\n", prev_ctl->jnl_fn); ctl = prev_ctl; @@ -1621,12 +1678,12 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool * post-update value differ in their most significant 4-bytes. Since that is considered a virtually impossible * rare occurrence and since we want to avoid the overhead of doing a "grab_lock", we dont do that here. */ - assert(buff == (unsigned char *)gtmsource_msgp + REPL_MSG_HDRLEN); /* else increasing buffer space will not work */ - assert(maxbufflen == gtmsource_msgbufsiz - REPL_MSG_HDRLEN); assert(REPL_MSG_HDRLEN == SIZEOF(jnldata_hdr_struct)); DEBUG_ONLY(loopcnt = 0;) do { + assert(buff == (unsigned char *)gtmsource_msgp + REPL_MSG_HDRLEN); /* else increasing buffer space will not work */ + assert(maxbufflen == gtmsource_msgbufsiz - REPL_MSG_HDRLEN); DEBUG_ONLY(loopcnt++); file2pool = FALSE; if (max_read_seqno > gtmsource_local->next_histinfo_seqno) @@ -1637,6 +1694,7 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool if (read_jnl_seqno == gtmsource_local->next_histinfo_seqno) { /* Request a REPL_HISTREC message be sent first before sending any more seqnos across */ gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_SEND_NEW_HISTINFO; + REPL_DPRINT1("REPL_HISTREC message first needs to be sent before any more seqnos can be sent across\n"); return 0; } read_addr = gtmsource_local->read_addr; @@ -1711,6 +1769,11 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool gtmsource_set_next_histinfo_seqno(TRUE); if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) return 0; /* Connection got reset in "gtmsource_set_next_histinfo_seqno" */ + /* Since the buffer may have expanded, reposition buff to the beginning and set maxbufflen to the maximum + * available size (as if this is the first time we came into the while loop) + */ + buff = (unsigned char *)gtmsource_msgp + REPL_MSG_HDRLEN; + maxbufflen = gtmsource_msgbufsiz - REPL_MSG_HDRLEN; } } while (TRUE); if (file2pool) @@ -1722,9 +1785,7 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool gtmsource_local->read_addr = read_addr; assert(read_jnl_seqno <= gtmsource_local->next_histinfo_seqno); gtmsource_local->read_jnl_seqno = read_jnl_seqno; -#ifdef GTMSOURCE_ALWAYS_READ_FILES - gtmsource_local->read_state = read_state = READ_FILE; -#endif + GTMDBGFLAGS_NOFREQ_ONLY(GTMSOURCE_FORCE_READ_FILE_MODE, gtmsource_local->read_state = read_state = READ_FILE); if (read_state == READ_POOL) { gtmsource_ctl_close(); /* no need to keep files open now that we are going to read from pool */ @@ -1883,7 +1944,7 @@ int gtmsource_update_zqgblmod_seqno_and_tn(seq_num resync_seqno) assert(0 < max_zqgblmod_seqno); assert(resync_seqno >= max_zqgblmod_seqno); assert(!(FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs.now_crit)); - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) { assert(process_id != jnlpool.gtmsource_local->gtmsource_srv_latch.u.parts.latch_pid); diff --git a/sr_unix/gtmsource_readpool.c b/sr_unix/gtmsource_readpool.c index 7c58126..85b97a7 100644 --- a/sr_unix/gtmsource_readpool.c +++ b/sr_unix/gtmsource_readpool.c @@ -98,7 +98,8 @@ int gtmsource_readpool(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_ avail_data_qw = stop_read_at - read_addr; assert(maxbufflen <= MAXPOSINT4); /* to catch the case of change in type of maxbufflen */ avail_data = (uint4)MIN(avail_data_qw, (qw_num)maxbufflen); - read_multiple = (first_tr_len < avail_data); + assert(next_read_seqno < next_histinfo_seqno); + read_multiple = (first_tr_len < avail_data) && ((next_read_seqno + 1) < next_histinfo_seqno); if (read_multiple) jnldata_len = avail_data; } @@ -126,7 +127,7 @@ int gtmsource_readpool(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_ ) next_read_seqno++; assert(next_read_seqno <= next_histinfo_seqno); - if ((read_multiple) && (next_read_seqno < next_histinfo_seqno)) + if (read_multiple) { /* Although stop_read_at - read_addr contains no partial transaction, it * is possible that stop_read_at - read_addr is more than maxbufflen, and * hence we read fewer bytes than stop_read_at - read_addr; scan what we diff --git a/sr_unix/gtmsource_rootprimary_init.c b/sr_unix/gtmsource_rootprimary_init.c index ec59de1..2d748dc 100644 --- a/sr_unix/gtmsource_rootprimary_init.c +++ b/sr_unix/gtmsource_rootprimary_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,6 +12,7 @@ #include "mdef.h" #include "gtm_string.h" +#include "gtm_time.h" #include "gtm_unistd.h" #include "gdsroot.h" @@ -48,7 +49,7 @@ void gtmsource_rootprimary_init(seq_num start_seqno) assert(!udi->s_addrs.hold_onto_crit || jgbl.onlnrlbk); was_crit = udi->s_addrs.now_crit; if (!was_crit) - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); jnlpool.repl_inst_filehdr->root_primary_cycle++; jnlpool.repl_inst_filehdr->was_rootprimary = TRUE; assert(start_seqno >= jnlpool.jnlpool_ctl->start_jnl_seqno); diff --git a/sr_unix/gtmsource_seqno_init.c b/sr_unix/gtmsource_seqno_init.c index 233d1f4..3374b20 100644 --- a/sr_unix/gtmsource_seqno_init.c +++ b/sr_unix/gtmsource_seqno_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,10 +14,6 @@ #include "gtm_string.h" #include "gtm_inet.h" #include "gtm_fcntl.h" -#ifdef VMS -#include /* Required for gtmsource.h */ -#endif - #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" @@ -154,7 +150,7 @@ void gtmsource_seqno_init(boolean_t this_side_std_null_coll) */ DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); jnlpool_ctl->start_jnl_seqno = db_seqno; jnlpool_ctl->jnl_seqno = db_seqno; jnlpool_ctl->max_zqgblmod_seqno = zqgblmod_seqno; diff --git a/sr_unix/gtmsource_showbacklog.c b/sr_unix/gtmsource_showbacklog.c index 820eea6..01ff00b 100644 --- a/sr_unix/gtmsource_showbacklog.c +++ b/sr_unix/gtmsource_showbacklog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -47,6 +47,8 @@ GBLREF jnlpool_addrs jnlpool; GBLREF gtmsource_options_t gtmsource_options; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +error_def(ERR_SRCSRVNOTEXIST); + int gtmsource_showbacklog(void) { seq_num seq_num, jnl_seqno, read_jnl_seqno; @@ -55,8 +57,6 @@ int gtmsource_showbacklog(void) boolean_t srv_alive; uint4 gtmsource_pid; - error_def(ERR_SRCSRVNOTEXIST); - assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno; if (NULL != jnlpool.gtmsource_local) /* Show backlog for a specific source server */ @@ -95,9 +95,10 @@ int gtmsource_showbacklog(void) util_out_print("!@UQ : sequence number of last transaction sent by source server", TRUE, &seq_num); srv_alive = (0 == gtmsource_pid) ? FALSE : is_proc_alive(gtmsource_pid, 0); if (!srv_alive) - gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_SRCSRVNOTEXIST), 2, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) MAKE_MSG_WARNING(ERR_SRCSRVNOTEXIST), 2, LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname)); - else if (gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_PASSIVE) + else if ((gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_PASSIVE) + || (gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED)) util_out_print("WARNING - Source Server is in passive mode, transactions are not being replicated", TRUE); if (NULL != jnlpool.gtmsource_local) break; diff --git a/sr_unix/gtmsource_shutdown.c b/sr_unix/gtmsource_shutdown.c index e8eacd0..822eb96 100644 --- a/sr_unix/gtmsource_shutdown.c +++ b/sr_unix/gtmsource_shutdown.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,21 +16,12 @@ #include "gtm_inet.h" #include "gtm_fcntl.h" #include "gtm_socket.h" - #include -#if !(defined(__MVS__)) && !(defined(VMS)) #include -#endif #include #include -#ifdef UNIX #include #include "repl_instance.h" -#endif -#ifdef VMS -#include /* Required for gtmsource.h */ -#endif - #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" @@ -47,12 +38,14 @@ #include "is_proc_alive.h" #include "repl_comm.h" #include "repl_log.h" -#ifdef UNIX #include "ftok_sems.h" -#endif #include "gtm_c_stack_trace.h" - -#define GTMSOURCE_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1 s */ +#ifdef DEBUG +#include "wbox_test_init.h" +#include "gtmio.h" +#include "anticipatory_freeze.h" +#include "gtm_threadgbl.h" +#endif GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; @@ -72,13 +65,17 @@ error_def(ERR_TEXT); int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) { - boolean_t all_dead, first_time, regrab_lock; + boolean_t all_dead, first_time, sem_incremented, regrab_lock; uint4 savepid[NUM_GTMSRC_LCL]; - int status, shutdown_status; + int status, shutdown_status, save_errno; int4 index, maxindex, lcnt, num_src_servers_running; unix_db_info *udi; gtmsource_local_ptr_t gtmsourcelocal_ptr; +#ifdef DEBUG + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; +#endif /* Significance of shutdown field in gtmsource_local: * This field is initially set to NO_SHUTDOWN. When a command to shut down the source server is issued, * the process initiating the shutdown sets this field to SHUTDOWN. The Source Server on sensing @@ -120,14 +117,38 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) } } } - /* Wait for source server(s) to die. But release ftok semaphore and jnlpool access control semaphore before - * waiting as the concurrently running source server(s) might need these (e.g. if it is about to call the - * function "gtmsource_set_next_histinfo_seqno"). + /* Wait for source server(s) to die. But before that release ftok semaphore and jnlpool access control semaphore. + * This way, other processes (either in this environment or a different one) don't encounter startup issues. + * However, to ensure that a concurrent argument-less rundown doesn't remove these semaphores (in case they + * are orphaned), increment the counter semaphore. */ + if (0 != incr_sem(SOURCE, SRC_SERV_COUNT_SEM)) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not increment Journal Pool counter semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + /* Even though we hold the FTOK and JNL_POOL_ACCESS_SEM before entering this function (as ensured by + * asserts above), it is safe to release them in case of a premature error (like this one). The caller + * doesn't rely on the semaphores being held and this function is designed to release these semaphores + * eventually anyways (after gtmsource_ipc_cleanup()) + */ + repl_inst_ftok_sem_release(); + status = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } if (0 != rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)) - rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in source server shutdown rel_sem"), - REPL_SEM_ERRNO); + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not release Journal Pool access control semaphore : %s. " + "Shutdown did not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); /* see comment above for why this is okay */ + status = decr_sem(SOURCE, SRC_SERV_COUNT_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } repl_inst_ftok_sem_release(); + regrab_lock = sem_incremented = TRUE; gvinit(); /* Get the gd header*/ /* Wait for ONE particular or ALL source servers to die */ repl_log(stdout, TRUE, TRUE, "Waiting for upto [%d] seconds for the source server to shutdown\n", @@ -147,9 +168,8 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) } } if (!all_dead) - { - SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN); - } else + SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN) + else break; } if (GTMSOURCE_MAX_SHUTDOWN_WAITLOOP < lcnt) @@ -177,25 +197,23 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) } repl_log(stderr, FALSE, TRUE, "Shutdown cannot proceed. Stop the above processes and reissue " "the shutdown command.\n"); - assert (FALSE); - return (ABNORMAL_SHUTDOWN); + status = decr_sem(SOURCE, SRC_SERV_COUNT_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; } - /* At this point, the source server process is dead. The call to "gtmsource_ipc_cleanup" below relies on this. */ - regrab_lock = TRUE; } else { + sem_incremented = FALSE; if (gtmsource_srv_count) { repl_log(stdout, TRUE, TRUE, "Initiating shut down\n"); - if (udi->grabbed_ftok_sem) - { /* Possible if we were holding the ftok semaphore and the journal pool lock "grab_lock" and - * got a SIG-15 before we did the "rel_lock" (while still holding the ftok semaphore). The - * "rel_lock" would have invoked "deferred_signal_handler" which would have in turn recognized - * the signal and triggered shutdown processing all the while holding the ftok semaphore. - * Release the ftok semaphore and grab it again. - */ - repl_inst_ftok_sem_release(); - } + /* A non-zero gtmsource_srv_count indicates we are the spawned off child source server. That means we + * are not holding any semaphores. More importantly, none of the source server's mainline code holds + * the ftok or the access control semaphore anymore. So, even if we reach here due to an external signal + * we are guaranteed that we don't hold any semaphores. Assert that. + */ + assert(!udi->grabbed_ftok_sem); + assert(!holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); regrab_lock = TRUE; } else { @@ -211,14 +229,40 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) } } if (regrab_lock) - { /* (Re)Grab the ftok semaphore and jnlpool access control semaphore IN THAT ORDER (to avoid deadlocks) */ + { /* Now that the source servers are shutdown, regrab the FTOK and access control semaphore (IN THAT ORDER to avoid + * deadlocks) + */ repl_inst_ftok_sem_lock(); - status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM); - if (0 > status) +# ifdef DEBUG + /* Sleep for a few seconds to test for concurrent argument-less RUNDOWN to ensure that the latter doesn't remove + * the JNL_POOL_ACCESS_SEM under the assumption that it is orphaned. + */ + if (gtm_white_box_test_case_enabled && (WBTEST_LONGSLEEP_IN_REPL_SHUTDOWN == gtm_white_box_test_case_number)) { - repl_log(stderr, TRUE, TRUE, - "Error grabbing jnlpool access control semaphore : %s. Shutdown not complete\n", REPL_SEM_ERROR); - return (ABNORMAL_SHUTDOWN); + DBGFPF((stderr, "GTMSOURCE_SHUTDOWN is about to start long sleep\n")); + LONG_SLEEP(10); + } +# endif + if (0 > (status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not acquire Journal Pool access control semaphore : %s. " + "Shutdown not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); + status = decr_sem(SOURCE, SRC_SERV_COUNT_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; + } + /* Now that the locks are re-acquired, decrease the counter sempahore */ + if (sem_incremented && (0 > (status = decr_sem(SOURCE, SRC_SERV_COUNT_SEM)))) + { + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Could not decrement Journal Pool counter semaphore : %s." + "Shutdown not complete\n", STRERROR(save_errno)); + repl_inst_ftok_sem_release(); + status = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM); + assert(0 == status); + return ABNORMAL_SHUTDOWN; } } if (!auto_shutdown) @@ -259,8 +303,11 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status) */ if (FALSE == gtmsource_ipc_cleanup(auto_shutdown, &exit_status, &num_src_servers_running)) rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); - else if (NORMAL_SHUTDOWN == exit_status) + else + { /* Journal Pool and Access Control Semaphores removed. Invalidate corresponding fields in file header */ + assert(NORMAL_SHUTDOWN == exit_status); repl_inst_jnlpool_reset(); + } if (!ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, FALSE)) rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP); assert(!num_src_servers_running || (ABNORMAL_SHUTDOWN == exit_status)); @@ -271,7 +318,7 @@ void gtmsource_stop(boolean_t exit) { int status; - assert(gtmsource_srv_count); /* This is a source server process */ + assert(gtmsource_srv_count || is_src_server); status = gtmsource_end1(TRUE); status = gtmsource_shutdown(TRUE, status) - NORMAL_SHUTDOWN; if (exit) diff --git a/sr_unix/gtmsource_srv_latch.c b/sr_unix/gtmsource_srv_latch.c index 248379f..05cde74 100644 --- a/sr_unix/gtmsource_srv_latch.c +++ b/sr_unix/gtmsource_srv_latch.c @@ -17,6 +17,7 @@ #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" +#include "jnl.h" #include "copy.h" #include "interlock.h" #include "performcaslatchcheck.h" @@ -30,26 +31,32 @@ #include "gtmsource.h" #include "repl_instance.h" #include "have_crit.h" +#include "util.h" /* For OUT_BUFF_SIZE */ GBLREF int4 process_id; GBLREF int num_additional_processors; GBLREF jnlpool_addrs jnlpool; +GBLREF jnl_gbls_t jgbl; #ifdef DEBUG GBLREF node_local_ptr_t locknl; GBLREF gd_region *gv_cur_region; +GBLREF boolean_t is_src_server; #endif - +error_def(ERR_REPLREQROLLBACK); +error_def(ERR_TEXT); /* Note we don't increment fast_lock_count as part of getting the latch and decrement it when releasing it because ROLLBACK * can hold onto this latch for a long while and can do updates in this duration and we should NOT have a non-zero fast_lock_count * as many places like t_begin/dsk_read have asserts to this effect. It is okay to NOT increment fast_lock_count as ROLLBACK * anyways have logic to disable interrupts the moment it starts doing database updates. */ -boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeout_in_secs) +boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeout_in_secs, uint4 onln_rlbk_action) { int spins, maxspins, retries, max_retries; unix_db_info *udi; sgmnt_addrs *repl_csa; + boolean_t cycle_mismatch; + char scndry_msg[OUT_BUFF_SIZE]; assert(!have_crit(CRIT_HAVE_ANY_REG)); udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); @@ -66,6 +73,27 @@ boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeou DEBUG_ONLY(locknl = repl_csa->nl); /* Use the journal pool to maintain lock history */ LOCK_HIST("OBTN", latch, process_id, retries); DEBUG_ONLY(locknl = NULL); + if (jnlpool.repl_inst_filehdr->file_corrupt && !jgbl.onlnrlbk) + { + /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until + * the rollback command is re-run to bring the journal pool/file and instance file to a + * consistent state. + */ + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to " + "TRUE"); + /* No need to release the latch before rts_error (mupip_exit_handler will do it for us) */ + rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), + ERR_TEXT, 2, LEN_AND_STR(scndry_msg)); + } + cycle_mismatch = (repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle); + assert((ASSERT_NO_ONLINE_ROLLBACK != onln_rlbk_action) || !cycle_mismatch); + if ((HANDLE_CONCUR_ONLINE_ROLLBACK == onln_rlbk_action) && cycle_mismatch) + { + assert(is_src_server); + SYNC_ONLN_RLBK_CYCLES; + gtmsource_onln_rlbk_clnup(); /* side-effect : sets gtmsource_state */ + rel_gtmsource_srv_latch(latch); + } return TRUE; } } @@ -82,7 +110,9 @@ boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeou } DUMP_LOCKHIST(); assert(FALSE); - return FALSE; + assert(jnlpool.gtmsource_local && jnlpool.gtmsource_local->gtmsource_pid); + rts_error(VARLSTCNT(5) ERR_SRVLCKWT2LNG, 2, max_timeout_in_secs, jnlpool.gtmsource_local->gtmsource_pid); + return FALSE; /* to keep the compiler happy */ } boolean_t rel_gtmsource_srv_latch(sm_global_latch_ptr_t latch) diff --git a/sr_unix/gtmsource_srv_latch.h b/sr_unix/gtmsource_srv_latch.h index 7b31ef7..550d2a6 100644 --- a/sr_unix/gtmsource_srv_latch.h +++ b/sr_unix/gtmsource_srv_latch.h @@ -12,7 +12,7 @@ #ifndef _GTMSOURCE_SRV_LATCH #define _GTMSOURCE_SRV_LATCH -boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeout_in_secs); +boolean_t grab_gtmsource_srv_latch(sm_global_latch_ptr_t latch, uint4 max_timeout_in_secs, uint4 onln_rlbk_action); boolean_t rel_gtmsource_srv_latch(sm_global_latch_ptr_t latch); diff --git a/sr_unix/gtmsource_statslog.c b/sr_unix/gtmsource_statslog.c index 1cdcc43..a2ab02f 100644 --- a/sr_unix/gtmsource_statslog.c +++ b/sr_unix/gtmsource_statslog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,6 +14,8 @@ #include "gtm_string.h" #include "gtm_inet.h" #include "gtm_stdio.h" +#include "gtm_fcntl.h" +#include "gtmio.h" #if !defined(__MVS__) && !defined(VMS) #include @@ -35,6 +37,7 @@ #include "gdsfhead.h" #include "filestruct.h" #include "repl_msg.h" +#include "repl_sp.h" #include "gtmsource.h" #include "repl_dbg.h" #include "repl_shutdcode.h" @@ -45,7 +48,7 @@ GBLREF jnlpool_addrs jnlpool; GBLREF gtmsource_options_t gtmsource_options; GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; - +error_def(ERR_REPLLOGOPN); int gtmsource_statslog(void) { assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); @@ -64,20 +67,7 @@ int gtmsource_statslog(void) util_out_print("STATSLOG turned OFF", TRUE); return (NORMAL_SHUTDOWN); } - if ('\0' == gtmsource_options.log_file[0]) /* Stats log file not specified, use general log file */ - { - util_out_print("No file specified for stats log. Using general log file !AD", TRUE, - LEN_AND_STR(jnlpool.gtmsource_local->log_file)); - STRCPY(gtmsource_options.log_file, jnlpool.gtmsource_local->log_file); - } else if (0 == STRCMP(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file)) - { - util_out_print("Stats log file is already !AD. Not initiating change in log file", TRUE, - LEN_AND_STR(gtmsource_options.log_file)); - return (ABNORMAL_SHUTDOWN); - } - STRCPY(jnlpool.gtmsource_local->statslog_file, gtmsource_options.log_file); jnlpool.gtmsource_local->statslog = TRUE; - util_out_print("Stats log turned on with file !AD", TRUE, strlen(jnlpool.gtmsource_local->statslog_file), - jnlpool.gtmsource_local->statslog_file); + util_out_print("Stats log turned on", TRUE); return (NORMAL_SHUTDOWN); } diff --git a/sr_unix/gtmstart.gtc b/sr_unix/gtmstart.gtc index c188096..98a6a0f 100644 --- a/sr_unix/gtmstart.gtc +++ b/sr_unix/gtmstart.gtc @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2001, 2005 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -93,7 +93,8 @@ if [ "$resp" = "Y" -o "$resp" = "y" ] ; then $echo "logging directory (${logdir}/${service}) does not exist, creating it..." mkdir $logdir/$service fi - nohup $gtm_dist/gtcm_run -service $service -id ${id} -log - $options >> $logdir/${service}/session.log 2>&1 < /dev/null & + nohup $gtm_dist/gtcm_run -service $service -id ${id} -log - $options \ + >> $logdir/${service}/session.log 2>&1 < /dev/null & if [ $? != 0 ]; then $echo "The GT.CM server (${service}) failed to start." @@ -114,7 +115,8 @@ if [ "$resp" = "Y" -o "$resp" = "y" ] ; then $echo "logging directory (${logdir}/${service}) does not exist, creating it..." mkdir $logdir/$service fi - nohup $gtm_dist/gtcm_run -service $service -id ${id} -log - $options >> $logdir/${service}/session.log 2>&1 < /dev/null & + nohup $gtm_dist/gtcm_run -service $service -id ${id} -log - $options \ + >> $logdir/${service}/session.log 2>&1 < /dev/null & if [ $? != 0 ]; then $echo "The GT.CM server (${service}) failed to start." diff --git a/sr_unix/gtmstop.gtc b/sr_unix/gtmstop.gtc index 75e522b..8cc56ef 100644 --- a/sr_unix/gtmstop.gtc +++ b/sr_unix/gtmstop.gtc @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2001, 2005 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -9,7 +9,6 @@ # the license, please stop and do not read further. # # # ################################################################# -: gtm_dist=GTMDIST echo=ECHO arch=ARCH diff --git a/sr_unix/gtmxc_types.h b/sr_unix/gtmxc_types.h index 81f83b2..985738d 100644 --- a/sr_unix/gtmxc_types.h +++ b/sr_unix/gtmxc_types.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,74 +13,95 @@ #ifndef GTMXC_TYPES_H #define GTMXC_TYPES_H +#include /* For intptr_t */ +#include "inttypes.h" /* .. ditto (defined different places in different platforms) .. */ + #ifdef __osf__ /* Ensure 32-bit pointers for compatibility with GT.M internal representations. */ #pragma pointer_size (save) #pragma pointer_size (short) #endif - -typedef int xc_status_t; -typedef int xc_int_t; -typedef unsigned int xc_uint_t; - +typedef int gtm_status_t; +typedef int gtm_int_t; +typedef unsigned int gtm_uint_t; #if defined(__osf__) -typedef int xc_long_t; -typedef unsigned int xc_ulong_t; +typedef int gtm_long_t; +typedef unsigned int gtm_ulong_t; #else -typedef long xc_long_t; -typedef unsigned long xc_ulong_t; +typedef long gtm_long_t; +typedef unsigned long gtm_ulong_t; #endif - -typedef float xc_float_t; - -typedef double xc_double_t; - -typedef char xc_char_t; - -typedef int (*xc_pointertofunc_t)(); - +typedef float gtm_float_t; +typedef double gtm_double_t; +typedef char gtm_char_t; +typedef int (*gtm_pointertofunc_t)(); typedef struct { - xc_long_t length; - xc_char_t *address; -} xc_string_t; - + gtm_long_t length; + gtm_char_t *address; +} gtm_string_t; +typedef int gtmcrypt_key_t; #ifdef __osf__ #pragma pointer_size (restore) #endif -/* new types for external/call-in user - xc_* types still valid for backward compatibility */ -typedef xc_status_t gtm_status_t; -typedef xc_int_t gtm_int_t; -typedef xc_uint_t gtm_uint_t; -typedef xc_long_t gtm_long_t; -typedef xc_ulong_t gtm_ulong_t; -typedef xc_float_t gtm_float_t; -typedef xc_double_t gtm_double_t; -typedef xc_char_t gtm_char_t; -typedef xc_string_t gtm_string_t; -typedef xc_pointertofunc_t gtm_pointertofunc_t; +#if !defined(__alpha) +typedef intptr_t gtm_tid_t; +#else +typedef int gtm_tid_t; +#endif +typedef void *gtm_fileid_ptr_t; typedef struct { - gtm_string_t rtn_name; - void* handle; + gtm_string_t rtn_name; + void* handle; } ci_name_descriptor; -/* call-in interface */ -xc_status_t gtm_ci(const char *c_rtn_name, ...); -xc_status_t gtm_cip(ci_name_descriptor *ci_info, ...); -xc_status_t gtm_init(void); -xc_status_t gtm_exit(void); +/* Define deprecated types for backward compatibility. */ +typedef gtm_status_t xc_status_t; +typedef gtm_int_t xc_int_t; +typedef gtm_uint_t xc_uint_t; +typedef gtm_long_t xc_long_t; +typedef gtm_ulong_t xc_ulong_t; +typedef gtm_float_t xc_float_t; +typedef gtm_double_t xc_double_t; +typedef gtm_char_t xc_char_t; +typedef gtm_string_t xc_string_t; +typedef gtm_pointertofunc_t xc_pointertofunc_t; +typedef gtm_fileid_ptr_t xc_fileid_ptr_t; + +/* Java types with special names for clarity. */ +typedef gtm_int_t gtm_jboolean_t; +typedef gtm_int_t gtm_jint_t; +typedef gtm_long_t gtm_jlong_t; +typedef gtm_float_t gtm_jfloat_t; +typedef gtm_double_t gtm_jdouble_t; +typedef gtm_char_t gtm_jstring_t; +typedef gtm_char_t gtm_jbyte_array_t; +typedef gtm_char_t gtm_jbig_decimal_t; + +/* Call-in interface. */ +gtm_status_t gtm_ci(const char *c_rtn_name, ...); +gtm_status_t gtm_cip(ci_name_descriptor *ci_info, ...); +gtm_status_t gtm_init(void); +#ifdef GTM_PTHREAD +gtm_status_t gtm_jinit(void); +#endif +gtm_status_t gtm_exit(void); +gtm_status_t 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); void gtm_zstatus(char* msg, int len); -typedef int gtmcrypt_key_t; - -typedef void *xc_fileid_ptr_t; -xc_status_t gtm_filename_to_id(xc_string_t *filename, xc_fileid_ptr_t *fileid); -xc_status_t gtm_is_file_identical(xc_fileid_ptr_t fileid1, xc_fileid_ptr_t fileid2); -void gtm_xcfileid_free(xc_fileid_ptr_t fileid); - +/* Other entry points accessable in libgtmshr. */ +gtm_status_t gtm_filename_to_id(gtm_string_t *filename, gtm_fileid_ptr_t *fileid); +void gtm_hiber_start(gtm_uint_t mssleep); +void gtm_hiber_start_wait_any(gtm_uint_t mssleep); +void gtm_start_timer(gtm_tid_t tid, gtm_int_t time_to_expir, void (*handler)(), gtm_int_t hdata_len, void *hdata); +void gtm_cancel_timer(gtm_tid_t tid); +gtm_status_t gtm_is_file_identical(gtm_fileid_ptr_t fileid1, gtm_fileid_ptr_t fileid2); +void gtm_xcfileid_free(gtm_fileid_ptr_t fileid); +int gtm_is_main_thread(void); void *gtm_malloc(size_t); void gtm_free(void *); diff --git a/sr_unix/gv_trigger.c b/sr_unix/gv_trigger.c index 355013d..3a4ef22 100644 --- a/sr_unix/gv_trigger.c +++ b/sr_unix/gv_trigger.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -78,6 +78,7 @@ GBLREF int tprestart_state; GBLREF unsigned int t_tries; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF pid_t process_id; +GBLREF trans_num local_tn; #ifdef DEBUG GBLREF uint4 dollar_trestart; GBLREF boolean_t donot_INVOKE_MUMTSTART; @@ -178,12 +179,13 @@ LITREF mval literal_zero; SAVE_RTN_NAME(rt_name, rt_name_len, lcl_trigdsc); \ GVTR_HASHTGBL_READ_CLEANUP(TRUE); \ if (ERR_PATMAXLEN == status) \ - rts_error(VARLSTCNT(6) status, 0, ERR_TRIGIS, 2, rt_name_len, rt_name); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) status, 0, ERR_TRIGIS, 2, rt_name_len, \ + rt_name); \ else if (ERR_TRIGSUBSCRANGE == status) \ - rts_error(VARLSTCNT(10) status, 4, save_var_name_len, save_var_name, SUBSCSTRLEN, \ - SUBSCSTR, ERR_TRIGIS, 2, rt_name_len, rt_name); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) status, 4, save_var_name_len, save_var_name, \ + SUBSCSTRLEN, SUBSCSTR, ERR_TRIGIS, 2, rt_name_len, rt_name); \ else /* error return from patstr */ \ - rts_error(VARLSTCNT(1) status); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); \ } \ /* End of a range (in a set of ranges) or a subscript itself. \ * Either case, colon_imbalance can be safely reset. \ @@ -243,7 +245,7 @@ LITREF mval literal_zero; } /* This error macro is used for all definition errors where the target is ^#t(GVN,,) */ -#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT) \ +#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \ { \ if (CDB_STAGNATE > t_tries) \ { \ @@ -256,13 +258,14 @@ LITREF mval literal_zero; GVTR_HASHTGBL_READ_CLEANUP(TRUE); \ /* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */ \ SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT); \ - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, save_var_name_len, save_var_name, \ - save_var_name_len, save_var_name, util_len, util_buff); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, save_var_name_len, \ + save_var_name, save_var_name_len, save_var_name, util_len, \ + util_buff); \ } \ } /* This error macro is used for all definition errors where the target is ^#t(GVN,<#COUNT|#CYCLE>) */ -#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO) \ +#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO,CSA) \ { \ if (CDB_STAGNATE > t_tries) \ { \ @@ -270,18 +273,18 @@ LITREF mval literal_zero; t_retry(cdb_sc_triggermod); \ } else \ { \ - HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO); \ + HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA); \ } \ } -#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO) \ +#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA) \ { \ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \ SAVE_VAR_NAME(save_var_name, save_var_name_len, gvt); \ GVTR_HASHTGBL_READ_CLEANUP(TRUE); \ - rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6, save_var_name_len, save_var_name, \ - save_var_name_len, save_var_name, LEN_AND_LIT(SUBSCRIPT), \ - ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(12) ERR_TRIGDEFBAD, 6, save_var_name_len, \ + save_var_name, save_var_name_len, save_var_name, \ + LEN_AND_LIT(SUBSCRIPT), ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \ } /* This code is modeled around "updproc_ch" in updproc.c */ @@ -437,26 +440,34 @@ STATICFNDEF uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int end--; } len = UINTCAST(end - start); - if (len) + if (len || (GVTR_PARSE_POINT == type)) { gvt_trigger = gvt->gvt_trigger; - nelems = DIVIDE_ROUND_UP(len, GVTR_LIST_ELE_SIZE); - dststart = (char *)get_new_element(gvt_trigger->gv_trig_list, nelems); - dstptr = dststart; - for (srcptr = start; srcptr < end; srcptr++) + if (len == 0) { - ch = *srcptr; - if ('"' == ch) - { /* A double-quote in the middle of the string better be TWO consecutive double-quotes */ - assert(((srcptr + 1) < end) && ('"' == srcptr[1])); - srcptr++; + tmpmval.mvtype = MV_STR; + tmpmval.str.addr = ""; + tmpmval.str.len = 0; + } else + { + nelems = DIVIDE_ROUND_UP(len, GVTR_LIST_ELE_SIZE); + dststart = (char *)get_new_element(gvt_trigger->gv_trig_list, nelems); + dstptr = dststart; + for (srcptr = start; srcptr < end; srcptr++) + { + ch = *srcptr; + if ('"' == ch) + { /* A double-quote in the middle of the string better be TWO consecutive double-quotes */ + assert(((srcptr + 1) < end) && ('"' == srcptr[1])); + srcptr++; + } + *dstptr++ = ch; } - *dstptr++ = ch; + assert((dstptr - dststart) <= len); + tmpmval.mvtype = MV_STR; + tmpmval.str.addr = dststart; + tmpmval.str.len = INTCAST(dstptr - dststart); } - assert((dstptr - dststart) <= len); - tmpmval.mvtype = MV_STR; - tmpmval.str.addr = dststart; - tmpmval.str.len = INTCAST(dstptr - dststart); /* switch gv_target for mval2subsc */ save_gvt = gv_target; gv_target = gvt; @@ -465,15 +476,20 @@ STATICFNDEF uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int out_key->top = DBKEYSIZE(MAX_KEY_SZ); mval2subsc(&tmpmval, out_key); gv_target = save_gvt; + if(len > 0) + { /* Now that mval2subsc is done, free up the allocated dststart buffer */ - ret = free_last_n_elements(gvt_trigger->gv_trig_list, nelems); - assert(ret); + ret = free_last_n_elements(gvt_trigger->gv_trig_list, nelems); + assert(ret); + } } - /* else len == 0 means an open range (where left or right side of range is unspecified) */ + /* else it means an open range (where left or right side of range is unspecified) + * null subscript on the right side of a range is treated as negative infinity and + * on the left side of a range is treated as positive infinity. + */ switch(type) { case GVTR_PARSE_POINT: - assert(len); assert(&subsdsc->gvtr_subs_type == &subsdsc->gvtr_subs_point.gvtr_subs_type); len = out_key->end; /* keep trailing 0 */ subsdsc->gvtr_subs_point.len = len; @@ -635,6 +651,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + assert(dollar_tlevel); /* the code below is not designed to work in non-TP */ save_gvtarget = gv_target; SETUP_TRIGGER_GLOBAL; /* Save gv_currkey and gv_altkey */ @@ -708,7 +725,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) return; } if ((STR_LIT_LEN(HASHT_GBL_CURLABEL) != ret_mval->str.len) || MEMCMP_LIT(ret_mval->str.addr, HASHT_GBL_CURLABEL)) - HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL field is not " HASHT_GBL_CURLABEL); + HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL field is not " HASHT_GBL_CURLABEL, csa); /* So we can go ahead and read other ^#t("GBL") records */ /* ----------------------------------------------------------------------------- * Now read ^#t("GBL","#CYCLE") @@ -716,10 +733,10 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) */ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcycle, ret_mval); if (!is_defined) - HASHT_DEFINITION_RETRY_OR_ERROR("\"#CYCLE\"","#CYCLE field is missing"); + HASHT_DEFINITION_RETRY_OR_ERROR("\"#CYCLE\"","#CYCLE field is missing", csa); tmpint4 = mval2i(ret_mval); /* decimal values are truncated by mval2i so we will accept a #CYCLE of 1.5 as 1 */ if (0 >= tmpint4) /* ^#t("GBL","#CYCLE") is not a positive integer. Error out */ - HASHT_DEFINITION_ERROR("\"#CYCLE\"","#CYCLE field is negative"); + HASHT_DEFINITION_ERROR("\"#CYCLE\"","#CYCLE field is negative", csa); cycle = (uint4)tmpint4; /* Check if ^#t("GBL") has previously been read from the db. If so, check if cycle is same as ^#t("GBL","#CYCLE"). */ gvt_trigger = gvt->gvt_trigger; @@ -740,6 +757,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) assert(NULL == gvt->gvt_trigger); } gvt_trigger = (gvt_trigger_t *)malloc(SIZEOF(gvt_trigger_t)); + gvt_trigger->gv_trigger_cycle = 0; gvt_trigger->gv_trig_array = NULL; gvt_trigger->gv_trig_list = NULL; /* Set gvt->gvt_trigger to this malloced memory (after gv_trig_array has been initialized to NULL to avoid garbage @@ -752,10 +770,10 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) */ is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcount, ret_mval); if (!is_defined) - HASHT_DEFINITION_RETRY_OR_ERROR("\"#COUNT\"","#COUNT field is missing"); + HASHT_DEFINITION_RETRY_OR_ERROR("\"#COUNT\"","#COUNT field is missing", csa); tmpint4 = mval2i(ret_mval); /* decimal values are truncated by mval2i so we will accept a #COUNT of 1.5 as 1 */ if (0 >= tmpint4) /* ^#t("GBL","#COUNT") is not a positive integer. Error out */ - HASHT_DEFINITION_ERROR("\"#COUNT\"","#COUNT field is negative"); + HASHT_DEFINITION_ERROR("\"#COUNT\"","#COUNT field is negative", csa); num_gv_triggers = (uint4)tmpint4; gvt_trigger->num_gv_triggers = num_gv_triggers; /* We want a memory store for all the values that are going to be read in from the database. We dont know upfront @@ -790,7 +808,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\""); + 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 @@ -808,7 +826,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\""); + HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa); /* Initialize trigdsc->cmdmask */ ptr = ret_mval->str.addr; ptr_top = ptr + ret_mval->str.len; @@ -1071,7 +1089,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\""); + 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) @@ -1080,7 +1098,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) SAVE_VAR_NAME(save_var_name, save_var_name_len, gvt); SAVE_RTN_NAME(save_rtn_name, save_rtn_name_len, trigdsc); GVTR_HASHTGBL_READ_CLEANUP(TRUE); - rts_error(VARLSTCNT(8) ERR_TRIGINVCHSET, 6, save_rtn_name_len, save_rtn_name, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TRIGINVCHSET, 6, save_rtn_name_len, save_rtn_name, save_var_name_len, save_var_name, ret_mval->str.len, ret_mval->str.addr); } /* Defer loading xecute string until time to compile it */ @@ -1151,7 +1169,31 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa) # endif GVTR_HASHTGBL_READ_CLEANUP(FALSE); /* do NOT free gvt->gvt_trigger so pass FALSE */ DBGTRIGR((stderr, "gvtr_db_read_hasht: gvt_trigger->gv_trigger_cycle = cycle\n")); - gvt_trigger->gv_trigger_cycle = cycle; /* Now that ^#t has been read, we can safely update "cycle" to the higher value */ + /* Now that ^#t has been read, we update "cycle" to the higher value. In case this transaction restarts, + * we cannot be sure of the correctness of whatever we read so we need to undo the "cycle" update. + * We take care of this by setting "gvt_triggers_read_this_tn" to TRUE and use this in "tp_clean_up". + * Set gvt->trig_read_tn as well so this gvt is part of the list of gvts whose cycle gets restored in tp_clean_up. + * In addition, make sure this gvt is added to the gvt_tp_list. In case callers are gvcst_put or gvcst_kill, they + * do database operations on gvt and an accompanying tp_hist which automatically ensures this. But in case the caller + * is ZTRIGGER, it is possible only the ^#t global gvtarget gets added as part of the above "gvtr_get_hasht_gblsubs" + * calls and the triggering global does not get referenced anywhere else in the TP transaction. Since ZTRIGGER command + * does no db operations on the triggering global, it is possible "gvt" does not get added to the gvt_tp_list which + * means if a trollback/tprestart occurs we would not undo this gvt's trigger related cycles. To avoid + * this issue, we add this gvt to the gvt_tp_list always. The macro anyways does nothing if this gvt has already been + * added so we should be fine correctness and performance wise. + */ + gvt_trigger->gv_trigger_cycle = cycle; + TREF(gvt_triggers_read_this_tn) = TRUE; + gvt->trig_read_tn = local_tn; + /* This ADD_TO_GVT_TP_LIST could potentially happen BEFORE a gvcst_search of this gvt occurred in this transaction. + * This means if gvt->clue.end is non-zero, gvcst_search would not get a chance to clear the first_tp_srch_status + * fields (which it does using the GVT_CLEAR_FIRST_TP_SRCH_STATUS macro) because gvt->read_local_tn would be set to + * local_tn as part of the ADD_TO_GVT_TP_LIST macro invocation. We therefore pass the second parameter indicating + * that first_tp_srch_status needs to be cleared too if gvt->read_local_tn gets synced to local_tn. All other callers + * of ADD_TO_GVT_TP_LIST (as of this writing) happen AFTER a gvcst_search of this gvt occurred in this TP transaction. + * Therefore this is currently the only place which uses TRUE for the second parameter. + */ + ADD_TO_GVT_TP_LIST(gvt, RESET_FIRST_TP_SRCH_STATUS_TRUE); return; } @@ -1323,9 +1365,7 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_ * control back to wherever that global reference occurred instead of this ^#t global read. Assert that below. */ cycle_start = csa->db_trigger_cycle; - assert(NULL != first_sgm_info); /* The region corresponding to ^#t should be the only one in this TP so far */ - assert(NULL == first_sgm_info->next_sgm_info); - assert(!first_sgm_info->num_of_blks); /* This region should not have had ANY other reads until now */ + ASSERT_BEGIN_OF_FRESH_TP_TRANS; lcl_t_tries = t_tries; t_fail_hist[lcl_t_tries] = cdb_sc_normal; assert(donot_INVOKE_MUMTSTART); @@ -1359,7 +1399,7 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_ break; } /* else we encountered a TP restart (which would have triggered a call to t_retry - * which in turn would have done a rts_error(TPRETRY) which would have been caught + * which in turn would have done a rts_error(TPRETRY) which would have been caught {BYPASSOK} * by gvtr_tpwrap_ch which would in turn have unwound the C-stack upto the point * where the ESTABLISH is done in gvtr_tpwrap_helper and then returned from there). * In this case we have to keep retrying the read until there are no tp restarts or @@ -1372,15 +1412,15 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_ * an error OR redo the root search of the original global as online rollback related restart * resets root block of all gv_targets to zero. */ - assert(((cdb_sc_onln_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure)) - || (TREF(dollar_zonlnrlbk) && !gv_target->root)); + assert(((cdb_sc_onln_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure)) || !gv_target->root); + assert((cdb_sc_onln_rlbk2 != failure) || TREF(dollar_zonlnrlbk)); if (cdb_sc_onln_rlbk1 == failure) { root_srch_needed = (ERR_GVPUTFAIL != err_code); } else if (cdb_sc_onln_rlbk2 == failure) { assert(tstart_trigger_depth == gtm_trigger_depth); - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_DBROLLEDBACK); } /* update lcl_t_tries to reflect the fact that a restart happened */ lcl_t_tries = t_tries; @@ -1644,7 +1684,7 @@ int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_ if (MAX_XECUTE_LEN <= trigdsc->xecute_str.str.len) { assert(FALSE); - rts_error(VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_XECUTE_LEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_XECUTE_LEN); } } gtm_trig_status = gtm_trigger(trigdsc, trigparms); @@ -1694,8 +1734,7 @@ int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_ assert(si == sgm_info_ptr); assert(gv_target == save_targ); assert(0 == memcmp(save_gv_currkey, gv_currkey, OFFSETOF(gv_key, base[0]) + gv_currkey->end)); - DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); gvtr_parms->num_triggers_invoked = num_triggers_invoked; return 0; } diff --git a/sr_unix/gv_trigger.h b/sr_unix/gv_trigger.h index 955dd05..c2cf291 100644 --- a/sr_unix/gv_trigger.h +++ b/sr_unix/gv_trigger.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,8 +36,8 @@ typedef enum #define GVTR_SUBS_RANGE 3 /* Allow a RANGE of values for this subscript */ #define GVTR_SUBS_PATTERN 4 /* Allow all values for subscript that match a specified pattern */ -#define GVTR_RANGE_OPEN_LEN (uint4)-1 /* length assigned to open side of a range (e.g. "a": has an open right side); - * is considered an impossible value for the length of any valid subscript */ +#define GVTR_RANGE_OPEN_LEN (uint4)-1 /* length assigned to open side of a range (e.g. "a": has an open right side); + * is considered an impossible value for the length of any valid subscript */ #define GVTR_LIST_ELE_SIZE 8 /* size of each element in gv_trig_list buddy list (see comment in gv_trigger.c) */ #define GV_TRIG_LIST_INIT_ALLOC 256 /* we anticipate 256 bytes to be used by each trigger so start the buddy list there */ @@ -92,11 +92,11 @@ typedef union gvtr_subs_struct typedef gtm_num_range_t gvtr_piece_t; -/* gv_trigger_t is the structure describing the static components of ONE trigger for a given global variable name. - * At the time of trigger invocation, there is some process-context-specific information that needs to be - * passed in which is done in a separate gtm_trigger_parms structure (defined in gtm_trigger.h). - * The below fields are arranged in order to ensure minimal structure padding added by the compiler. This might not - * seem logical at first (for e.g. the related fields is_zdelim & delimiter are in different sections). +/* gv_trigger_t is the structure describing the static components of ONE trigger for a given global variable name. At the time of + * trigger invocation, there is some process-context-specific information that needs to be passed in which is done in a separate + * gtm_trigger_parms structure (defined in gtm_trigger.h). The below fields are arranged in order to ensure minimal structure + * padding added by the compiler. This might not seem logical at first (for e.g. the related fields is_zdelim & delimiter are in + * different sections). */ typedef struct gv_trigger_struct { @@ -105,32 +105,26 @@ typedef struct gv_trigger_struct *next_kill, /* Next KILL type trigger for this global */ *next_ztrig; /* Next ZTRIGGER type trigger for this global */ uint4 cmdmask; /* bitwise OR of all commands defining this trigger in ^#t(,,"CMD"). - * e.g. if ^#t(..,"CMD") is "S,K", cmdmask will be "GVTR_OPER_SET | GVTR_OPER_KILL" - */ + * e.g. if ^#t(..,"CMD") is "S,K", cmdmask will be "GVTR_OPER_SET | GVTR_OPER_KILL" */ uint4 numsubs; /* # of comma-separated subscripts specified for this particular trigger */ uint4 numlvsubs; /* # of subscripts for which the trigger requested a local variable name to be bound. - * i.e. numlvsubs <= numsubs is always true. - */ + * i.e. numlvsubs <= numsubs is always true. */ uint4 numpieces; /* # of contiguous piece ranges specified in the trigger */ gvtr_subs_t *subsarray; /* pointer to an array of "numsubs" number of gvtr_subs_t structures. - * NULL if no subscript specified in the trigger (i.e. numsubs = 0) and is very unusual. - */ + * NULL if no subscript specified in the trigger (i.e. numsubs = 0) and is very unusual. */ uint4 *lvindexarray; /* pointer to an array of "numlvsubs" number of uint4 type fields which contain the index - * in "subsarray" of the subscript whose local variable name binding this corresponds to. - */ + * in "subsarray" of the subscript whose local variable name binding this corresponds to. */ mname_entry *lvnamearray; /* pointer to an array of "numlvsubs" number of mname_entry structures that contain the * local variable names which need to be bound to each subscript at trigger invocation. * If no subscripts have lvns specified, this is NULL. * e.g. if the trigger specified "^GBL(lvn1=:,1,lvn3=:) ..." in this case, * numsubs = 3, numlvsubs = 2, lvindexarray[0] = 0, lvindexarray[1] = 2, - * lvnamearray[0].var_name = "lvn1", lvnamearray[1].var_name = "lvn3", - */ + * lvnamearray[0].var_name = "lvn1", lvnamearray[1].var_name = "lvn3", */ gtm_num_range_t *piecearray; /* pointer to an array of "numpieces" ranges (range is the closed interval [min,max]). * e.g, if the piece string specified in ^#t(,,"PIECES") is "4:6;8" then * numpieces = 2 * piecearray[0].min=4, piecearray[0].max=6 - * piecearray[1].min=8, piecearray[1].max=8 - */ + * 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(,,"DELIM") or ^#t(..."ZDELIM") whichever is defined */ @@ -138,8 +132,7 @@ typedef struct gv_trigger_struct 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 */ *gvt_trigger; /* .. gv_trigger_t but not owning region or trigger#. Allows us to get both with no - * additional lookup - */ + * additional lookup */ } gv_trigger_t; /* Structure describing ALL triggers for a given global variable name */ @@ -159,8 +152,8 @@ typedef struct gvt_trigger_struct /* Structure describing parameters passed (from gvcst_put/gvcst_kill) to trigger invocation routine */ typedef struct gvtr_invoke_parms_struct { - gvt_trigger_t *gvt_trigger; /* Input parameter */ - gvtr_cmd_type_t gvtr_cmd; /* Input parameter */ + gvt_trigger_t *gvt_trigger; /* Input parameter */ + gvtr_cmd_type_t gvtr_cmd; /* Input parameter */ int num_triggers_invoked; /* Output parameter : # of triggers invoked by an update */ } gvtr_invoke_parms_t; @@ -191,12 +184,12 @@ typedef struct gvtr_invoke_parms_struct \ assert(TPRESTART_STATE_NORMAL == tprestart_state); \ assert(!skip_dbtriggers); \ - /* If start of transaction, read in GVT's triggers from ^#t global if not already done. \ - * If restart and if it was due to GVT's triggers being out-of-date re-read them. \ - * Note theoretically either CSD or CSA can be used to get the cycle # for comparison with GVT but while \ - * using CSD can relatively reduce the # of times "gvtr_init" is invoked, it can also cause an issue where \ - * a nested trigger for the same global can cause a restart which unloads a running trigger causing problems \ - * (see trigthrash subtest in triggers test suite specifically trigthrash3.m). For that reason, we stick wish CSA. \ + /* If start of transaction, read in GVT's triggers from ^#t global if not already done. If restart and if it was due to \ + * GVT's triggers being out-of-date re-read them. Note theoretically either CSD or CSA can be used to get the cycle for \ + * comparison with GVT but while using CSD can relatively reduce the # of times "gvtr_init" is invoked, it can also \ + * cause an issue where a nested trigger for the same global can cause a restart which unloads a running trigger \ + * causing problems (see trigthrash subtest in triggers test suite specifically trigthrash3.m). For that reason, we \ + * stick wish CSA. \ */ \ cycle = CSA->db_trigger_cycle; \ assert(CSD == cs_data); \ @@ -214,41 +207,48 @@ typedef struct gvtr_invoke_parms_struct { /* need to create implicit TP wrap */ \ 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 tp-wrapped non-tp update, we dont expect "t_retry" to be called \ - * while this gvcst_put is in the C-call-stack. This is because we have not set up the \ - * TP transaction using opp_tstart (like what M code does) and so there is no point \ - * to go back to generated code (mdb_condition_handler invoked from t_retry does this \ - * transfer of control using the MUM_TSTART macro). We instead expect to handle retries \ - * internally in gvcst_put. We also expect any restarts occurring in nested trigger \ - * code to eventually end up as a RESTART return code from "gtm_trigger" so we get to \ - * choose how to handle the restart for this implicit TSTART. \ + /* Set a debug-only global variable to indicate that from now onwards, until the completion of this \ + * tp-wrapped non-tp update, we dont expect "t_retry" to be called while this gvcst_put is in the \ + * C-call-stack. This is because we have not set up the TP transaction using opp_tstart (like what M \ + * code does) and so there is no point to go back to generated code (mdb_condition_handler invoked from \ + * t_retry does this transfer of control using the MUM_TSTART macro). We instead expect to handle \ + * retries internally in gvcst_put. We also expect any restarts occurring in nested trigger code to \ + * eventually end up as a RESTART return code from "gtm_trigger" so we get to choose how to handle the \ + * restart for this implicit TSTART. \ */ \ assert(!donot_INVOKE_MUMTSTART); \ DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE;) \ - /* With journal recovery, we expect it to play non-TP journal records as non-TP transactions \ - * and ZTP journal records as ZTP transactions so we dont expect an implicit TP wrap to be \ - * done inside recovery due to a trigger (as this means GT.M and recovery have different \ - * values for GVT->gvt_trigger which is not possible). Assert that. \ + /* With journal recovery, we expect it to play non-TP journal records as non-TP transactions and ZTP \ + * journal records as ZTP transactions so we dont expect an implicit TP wrap to be done inside recovery \ + * due to a trigger (as this means GT.M and recovery have different values for GVT->gvt_trigger which \ + * is not possible). Assert that. \ */ \ assert(!jgbl.forw_phase_recovery); \ LCL_TSTART = TRUE; \ /* 0 ==> save no locals but RESTART OK */ \ op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &literal_batch, 0); \ /* Ensure that the op_tstart done above has set up the TP frame and that the first entry is \ - * of MVST_TPHOLD type. */ \ + * of MVST_TPHOLD type. \ + */ \ assert((tp_pointer->fp == frame_pointer) && (MVST_TPHOLD == mv_chain->mv_st_type) \ && (msp == (unsigned char *)mv_chain)); \ IS_TPWRAP = TRUE; \ assert(!CSA->sgm_info_ptr->tp_set_sgm_done && !CSA->sgm_info_ptr->update_trans); \ tp_set_sgm(); \ - /* tp_set_sgm above will update CSA->db_trigger_cycle (from CSD->db_trigger_cycle). Set local variable \ - * cycle to match CSA->db_trigger_cycle so as to pass the updated value to gvtr_init. \ + /* tp_set_sgm above could modify CSA->db_trigger_cycle (from CSD->db_trigger_cycle). Set local variable \ + * cycle to match CSA->db_trigger_cycle so as to pass the updated value to gvtr_init. Also in that \ + * case recompute cycle_mismatch (and related variables) now that CSA->db_trigger_cycle changed. \ */ \ - cycle = CSA->db_trigger_cycle; \ - /* Assert that if db_trigger_cycle mismatch was TRUE above, it better be TRUE after 'cycle' update \ - * as well */ \ - assert(!db_trigger_cycle_mismatch || (GVT->db_trigger_cycle != cycle)); \ + if (cycle != CSA->db_trigger_cycle) \ + { \ + cycle = CSA->db_trigger_cycle; \ + /* Assert that if db_trigger_cycle mismatch was TRUE above, \ + * it better be TRUE after 'cycle' update as well. \ + */ \ + assert(!db_trigger_cycle_mismatch || (GVT->db_trigger_cycle != cycle)); \ + db_trigger_cycle_mismatch = (GVT->db_trigger_cycle != cycle); \ + cycle_mismatch = (db_trigger_cycle_mismatch || ztrig_cycle_mismatch); \ + } \ /* An implicit TP wrap is created for an explicit TP update. tp_set_sgm call done above will initalize \ * sgm_info_ptr for this TP transaction and will have sgm_info_ptr->update_trans set to zero. If the \ * op_tstart done above is for ^#t read, then set_upd_trans_t_err set to TRUE just after gvtr_init will \ @@ -282,15 +282,14 @@ typedef struct gvtr_invoke_parms_struct gvtr_init(GVT, cycle, LCL_TSTART, T_ERR); \ /* ^#t reads done via gvtr_init will cause t_err to be set to GVGETFAIL which needs to be reset to \ * T_ERR (incoming parameter to this macro) before leaving the macro. Also, in case of an implicit \ - * tstart (LCL_TSTART = TRUE), if a restart happens while reading ^#t global, gvtr_tpwrap_ch will \ - * be invoked which inturn will invoke tp_restart that would reset sgm_info_ptr->update_trans to \ - * zero. The caller of the macro (gvcst_put and gvcst_kill) relies on sgm_info_ptr->update_trans \ - * being non-zero. \ + * tstart (LCL_TSTART = TRUE), if a restart happens while reading ^#t global, gvtr_tpwrap_ch will be \ + * invoked which inturn will invoke tp_restart that would reset sgm_info_ptr->update_trans to zero. The \ + * caller of the macro (gvcst_put and gvcst_kill) relies on sgm_info_ptr->update_trans being non-zero. \ */ \ assert(((0 < dollar_tlevel) || (ERR_GVZTRIGFAIL != T_ERR)) && (2)) ; /* &&(2) idents assert */ \ set_upd_trans_t_err = TRUE; \ - /* Check that gvtr_init does not play with "reset_gv_target" a global variable that callers \ - * of this function (e.g. gvcst_put) might have set to a non-default value. \ + /* Check that gvtr_init does not play with "reset_gv_target" a global variable that callers of this \ + * function (e.g. gvcst_put) might have set to a non-default value. \ */ \ assert(reset_gv_target == save_reset_gv_target); \ CSD = cs_data; /* if MM and db extension occurred, reset CSD to cs_data to avoid stale value */ \ @@ -345,22 +344,24 @@ typedef struct gvtr_invoke_parms_struct GBLREF mv_stent *mv_chain; \ GBLREF unsigned char *msp; \ \ - /* Create mval on the M-stack (thereby it is known to stp_gcol) to save pre-gvcst_put/gvcst_kill value. \ - * The memory needed to save the actual value will be obtained from the stringpool later. \ + /* Create mval on the M-stack (thereby it is known to stp_gcol (BYPASSOK)) to save \ + * pre-gvcst_put/gvcst_kill value. The memory needed to save the actual value will be obtained from the \ + * stringpool later. \ */ \ assert(NULL == ZTOLD_MVAL); \ - SAVE_MSP = msp; /* Save current msp & mv_chain to restore finally */ \ + SAVE_MSP = msp; /* Save current msp & mv_chain to restore finally */ \ SAVE_MV_CHAIN = mv_chain; \ - PUSH_MV_STENT(MVST_MVAL); /* protect $ztoldval from stp_gcol */ \ + PUSH_MV_STENT(MVST_MVAL); /* protect $ztoldval from stp_gcol (BYPASSOK) */ \ ZTOLD_MVAL = &mv_chain->mv_st_cont.mvs_mval; \ - ZTOLD_MVAL->mvtype = 0; /* make sure mval is setup enough to protect stp_gcol, if invoked below, from \ - * incorrectly reading its contents until it is fully initialized later. */ \ + ZTOLD_MVAL->mvtype = 0; /* make sure mval is setup enough to protect stp_gcol (BYPASSOK)(if invoked \ + * below) from incorrectly reading its contents until it is fully initialized \ + * later. */ \ } -/* The POP_MVALS_FROM_M_STACK_IF_NEEDED macro below pops some mvals pushed on the stack but pops them in an unusual way - * for performance reasons (not really popping them but just restoring previous pointers). The debug version - * of that macro will use the slightly longer but verifying form of unwind defined below to make sure we aren't - * popping something we need in an invisible and tough to track fashion. +/* The POP_MVALS_FROM_M_STACK_IF_NEEDED macro below pops some mvals pushed on the stack but pops them in an unusual way for + * performance reasons (not really popping them but just restoring previous pointers). The debug version of that macro will use the + * slightly longer but verifying form of unwind defined below to make sure we aren't popping something we need in an invisible and + * tough to track fashion. */ #ifdef DEBUG #define UNW_MV_STENT_TO(prev_msp, prev_mv_chain) \ @@ -392,8 +393,8 @@ typedef struct gvtr_invoke_parms_struct GBLREF unsigned char *msp; \ \ if (NULL != ZTOLD_MVAL) \ - { /* ZTOLD_MVAL & potentially a few other mvals have been pushed \ - * on to the M-stack. Pop them all in one restore of the M-stack. \ + { /* ZTOLD_MVAL & potentially a few other mvals have been pushed onto the \ + * M-stack. Pop them all in one restore of the M-stack. \ */ \ assert(!skip_dbtriggers); \ assert(SAVE_MSP > msp); \ @@ -428,9 +429,9 @@ typedef struct gvtr_invoke_parms_struct key += HASHT_GBLNAME_FULL_LEN; \ *key++ = '\0'; /* double '\0' for terminating key */ \ gv_currkey->end = HASHT_GBLNAME_FULL_LEN; \ - /* Determine root block of ^#t global in this database file. Need to use gvcst_root_search for this. \ - * It expects gv_currkey, gv_target, gv_cur_region, cs_addrs & cs_data to be set up appropriately. \ - * gv_currkey & gv_target are already set up. The remaining should be set up which is asserted below. \ + /* Determine root block of ^#t global in this database file. Need to use gvcst_root_search for this. It expects \ + * gv_currkey, gv_target, gv_cur_region, cs_addrs & cs_data to be set up appropriately. gv_currkey & gv_target \ + * are already set up. The remaining should be set up which is asserted below. \ */ \ assert(&FILE_INFO(gv_cur_region)->s_addrs == csa); \ assert(cs_addrs == csa); \ @@ -463,23 +464,21 @@ GBLREF uint4 dollar_tlevel; GBLREF int4 gtm_trigger_depth; GBLREF int4 tstart_trigger_depth; -/* This macro returns if the current update is an EXPLICIT update or not. Any update done as part of a - * trigger invocation is not considered an explicit update. Note that it is possible to do a TROLLBACK - * while inside trigger code. In this case, any updates done after the trollback while still inside the - * trigger code are considered explicit updates. Hence the seemingly complicated check below. - * There is a version without the asserts for use ONLY WITH the IS_OK_TO_INVOKE_GVCST_KILL macro where nested - * asserts dont work well with the C preprocessor. +/* This macro returns if the current update is an EXPLICIT update or not. Any update done as part of a trigger invocation is not + * considered an explicit update. Note that it is possible to do a TROLLBACK while inside trigger code. In this case, any updates + * done after the trollback while still inside the trigger code are considered explicit updates. Hence the seemingly complicated + * check below. There is a version without the asserts for use ONLY WITH the IS_OK_TO_INVOKE_GVCST_KILL macro where nested asserts + * dont work well with the C preprocessor. */ #define IS_EXPLICIT_UPDATE (DBG_ASSERT(!dollar_tlevel || (tstart_trigger_depth <= gtm_trigger_depth)) \ IS_EXPLICIT_UPDATE_NOASSERT) #define IS_EXPLICIT_UPDATE_NOASSERT (!dollar_tlevel || (tstart_trigger_depth == gtm_trigger_depth)) -/* Check if update is inside trigger (implicit update) and to a replicated database. If so check that - * corresponding triggering update (explicit update) also occurred in a replicated database. If not this - * is an out-of-design situation as the replicating secondary will see no journal records for this TP - * transaction (since the triggering update did not get replicated) and so cannot keep the secondary - * in sync with the primary. In this case, issue an error. +/* Check if update is inside trigger (implicit update) and to a replicated database. If so check that corresponding triggering + * update (explicit update) also occurred in a replicated database. If not this is an out-of-design situation as the replicating + * secondary will see no journal records for this TP transaction (since the triggering update did not get replicated) and so cannot + * keep the secondary in sync with the primary. In this case, issue an error. */ #define TRIG_CHECK_REPLSTATE_MATCHES_EXPLICIT_UPDATE(REG, CSA) \ { \ @@ -492,7 +491,8 @@ GBLREF int4 tstart_trigger_depth; \ if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ end = &buff[MAX_ZWR_KEY_SZ - 1]; \ - rts_error(VARLSTCNT(8) ERR_TRIGREPLSTATE, 2, DB_LEN_STR(REG), ERR_GVIS, 2, end - buff, buff); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGREPLSTATE, 2, DB_LEN_STR(REG), ERR_GVIS, 2, \ + end - buff, buff); \ } \ } @@ -519,8 +519,8 @@ GBLREF int4 tstart_trigger_depth; \ uint4 nodeflags; \ \ - /* No need to write ZTWORMHOLE journal records for updates inside trigger since \ - * those records are not replicated anyways. \ + /* No need to write ZTWORMHOLE journal records for updates inside trigger since those records are not \ + * replicated anyway. \ */ \ assert(dollar_tlevel); /* tstart_trigger_depth is not usable otherwise */ \ assert(tstart_trigger_depth <= gtm_trigger_depth); \ @@ -533,14 +533,14 @@ GBLREF int4 tstart_trigger_depth; explicit_update_repl_state = REPL_ALLOWED(CSA); \ /* Write ZTWORMHOLE records only if replicating since secondary is the only one that cares about it. */ \ if (explicit_update_repl_state && dollar_ztwormhole.str.len) \ - { /* $ZTWORMHOLE is non-NULL. Journal that BEFORE the corresponding SET record. \ - * If it is found that the trigger invocation did not REFERENCE it, we will \ - * remove this from the list of formatted journal records. \ + { /* $ZTWORMHOLE is non-NULL. Journal that BEFORE the corresponding SET record. If it is found \ + * that the trigger invocation did not REFERENCE it, we will remove this from the list of \ + * formatted journal records. \ */ \ ZTWORM_JFB = jnl_format(JNL_ZTWORM, NULL, &dollar_ztwormhole, 0); \ - /* Note : ztworm_jfb could be NULL if it was determined that this ZTWORMHOLE \ - * record is not needed i.e. if the exact same value of ZTWORMHOLE was \ - * already written as part of the previous update in this TP transaction. \ + /* Note : ztworm_jfb could be NULL if it was determined that this ZTWORMHOLE record is not \ + * needed i.e. if the exact same value of ZTWORMHOLE was already written as part of the \ + * previous update in this TP transaction. \ */ \ } \ } else \ @@ -578,11 +578,11 @@ GBLREF int4 tstart_trigger_depth; { /* $ZTWORMHOLE was non-zero before the trigger invocation and was never used inside the trigger. We \ * need to remove the corresponding formatted journal record. We dont free up the memory occupied by \ * ZTWORM_JFB as it is not easy to free up memory in the middle of a buddy list. This memory will \ - * anyways be freed up eventually at tp_clean_up time. \ + * anyway be freed up eventually at tp_clean_up time. \ * NOTE: Trigger code that does NOT use the $ZTWORMHOLE is equivalent to a trigger code that has \ - * $ZTWORMHOLE set to NULL and hence should have the JS_NULL_ZTWORM_MASK set in the nodeflags. But \ - * for that to happen, checksum of the SET/KILL/ZTRIG records need to be recomputed. Since this is \ - * a costly operation, we don't touch the nodeflags as there is no known correctness issue. \ + * $ZTWORMHOLE set to NULL and hence should have the JS_NULL_ZTWORM_MASK set in the nodeflags. But for \ + * that to happen, checksum of the SET/KILL/ZTRIG records need to be recomputed. Since this is a costly \ + * operation, we don't touch the nodeflags as there is no known correctness issue. \ */ \ assert(NULL != JFB); \ tmpjfb = ZTWORM_JFB->prev; \ @@ -614,7 +614,7 @@ GBLREF int4 tstart_trigger_depth; \ util_ptr = i2asc(&UTIL_BUFF[0], TRIGIDX); /* UTIL_BUFF = 1 */ \ assert(MAX_TRIG_UTIL_LEN >= STR_LIT_LEN(PARAM)); \ - MEMCPY_LIT(util_ptr, PARAM); /* UTIL_BUFF = 1,"CMD" */ \ + MEMCPY_LIT(util_ptr, PARAM); /* UTIL_BUFF = 1,"CMD" */ \ util_ptr += STR_LIT_LEN(PARAM); \ UTIL_LEN = UINTCAST(util_ptr - &UTIL_BUFF[0]); \ assert(MAX_TRIG_UTIL_LEN >= UTIL_LEN); \ diff --git a/sr_unix/gvcst_init_sysops.c b/sr_unix/gvcst_init_sysops.c index 7b732fb..74acb82 100644 --- a/sr_unix/gvcst_init_sysops.c +++ b/sr_unix/gvcst_init_sysops.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,6 +28,9 @@ #include "gtm_string.h" #include "gtm_sem.h" #include "gtm_statvfs.h" +#ifdef __linux__ +#include "hugetlbfs_overrides.h" +#endif #include "gt_timer.h" #include "gdsroot.h" @@ -56,6 +59,7 @@ #include "ftok_sems.h" #include "repl_msg.h" #include "gtmsource.h" +#include "anticipatory_freeze.h" /* Include prototypes */ #include "mlk_shr_init.h" @@ -101,6 +105,9 @@ #define REQRUNDOWN_TEXT "semid is invalid but shmid is valid or at least one of sem_ctime or shm_ctime are non-zero" #define MAX_ACCESS_SEM_RETRIES 2 +#define RTS_ERROR(...) rts_error_csa(CSA_ARG(csa) __VA_ARGS__) +#define SEND_MSG(...) send_msg_csa(CSA_ARG(csa) __VA_ARGS__) + #define SS_INFO_INIT(CSA) \ { \ shm_snapshot_ptr_t ss_shm_ptr; \ @@ -109,7 +116,7 @@ lcl_cnl = CSA->nl; \ lcl_cnl->ss_shmid = INVALID_SHMID; \ lcl_cnl->ss_shmcycle = 0; \ - lcl_cnl->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(lcl_cnl); \ lcl_cnl->num_snapshots_in_effect = 0; \ SET_LATCH_GLOBAL(&lcl_cnl->snapshot_crit_latch, LOCK_AVAILABLE); \ assert(1 == MAX_SNAPSHOTS); /* To ensure that we revisit this whenever multiple snapshots is implemented */ \ @@ -121,7 +128,7 @@ { \ if (-1 == status_l) \ { \ - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), \ + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), \ ERR_TEXT, 2, LEN_AND_LIT("Error attaching to database shared memory"), errno); \ } \ } @@ -145,16 +152,16 @@ if (!MEMCMP_LIT(csa->nl->label, GDS_LABEL_GENERIC)) \ { \ if (memcmp(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1)) \ - { /* Copy csa->nl->now_running into a local variable before passing to rts_error() due to the following \ + { /* Copy csa->nl->now_running into a local variable before passing to rts_error due to the following \ * issue: \ - * In VMS, a call to rts_error() copies only the error message and its arguments (as pointers) and \ + * In VMS, a call to rts_error copies only the error message and its arguments (as pointers) and \ * transfers control to the topmost condition handler which is dbinit_ch() in this case. dbinit_ch() \ * does a PRN_ERROR only for SUCCESS/INFO (VERMISMATCH is neither of them) and in addition \ * nullifies csa->nl as part of its condition handling. It then transfers control to the next level \ * condition handler which does a PRN_ERROR but at that point in time, the parameter \ * csa->nl->now_running is no longer accessible and hence no \parameter substitution occurs (i.e. the \ * error message gets displayed with plain !ADs). \ - * In UNIX, this is not an issue since the first call to rts_error() does the error message \ + * In UNIX, this is not an issue since the first call to rts_error does the error message \ * construction before handing control to the topmost condition handler. But it does not hurt to do \ * the copy. \ */ \ @@ -167,44 +174,47 @@ } \ } -#define GTM_VERMISMATCH_ERROR \ -{ \ - if (!vermismatch_already_printed) \ - { \ - vermismatch_already_printed = TRUE; \ - /* for DSE, change VERMISMATCH to be INFO (instead of the more appropriate WARNING) \ - * as we want the condition handler (dbinit_ch) to do a CONTINUE (which it does \ - * only for severity levels SUCCESS or INFO) and resume processing in gvcst_init.c \ - * instead of detaching from shared memory. \ - */ \ - rts_error(VARLSTCNT(8) MAKE_MSG_TYPE(ERR_VERMISMATCH, (!IS_DSE_IMAGE ? ERROR : INFO)), 6, \ - DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name, LEN_AND_STR(now_running)); \ - } \ +#define GTM_VERMISMATCH_ERROR \ +{ \ + if (!vermismatch_already_printed) \ + { \ + vermismatch_already_printed = TRUE; \ + RTS_ERROR(VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name, \ + LEN_AND_STR(now_running)); \ + } \ } #ifdef GTM_CRYPT #define INIT_DB_ENCRYPTION_IF_NEEDED(DO_CRYPT_INIT, INIT_STATUS, REG, CSA, TSD) \ { \ + int fn_len = 0; \ + char *fn; \ + \ if (DO_CRYPT_INIT) \ - { /* Do database specific encryption initialization. For all utilities other than GT.M, defer the error until \ - * encryption invocation is actually necessary. This way, MUPIP/DSE can continue as long as the operation does \ - * not involve encryption (for instance MUPIP JOURNAL -EXTRACT -SHOW=HEADER). For GT.M, issue error right away \ - */ \ + { \ if (0 == INIT_STATUS) \ - INIT_DB_ENCRYPTION(REG->dyn.addr->fname, CSA, TSD, INIT_STATUS); \ - if ((0 != INIT_STATUS) && IS_GTM_IMAGE) \ - GC_RTS_ERROR(INIT_STATUS, REG->dyn.addr->fname); \ - CSA->encrypt_init_status = INIT_STATUS; /* defer error reporting */ \ + INIT_DB_ENCRYPTION(CSA, TSD, INIT_STATUS); \ + if (0 != INIT_STATUS) \ + { \ + fn = (char *)(REG->dyn.addr->fname); \ + fn_len = REG->dyn.addr->fname_len; \ + if (IS_GTM_IMAGE) \ + { \ + GTMCRYPT_REPORT_ERROR(INIT_STATUS, rts_error, fn_len, fn); \ + } else \ + GTMCRYPT_REPORT_ERROR(MAKE_MSG_WARNING(INIT_STATUS), gtm_putmsg, fn_len, fn); \ + CSA->encr_key_handle = GTMCRYPT_INVALID_KEY_HANDLE; \ + } \ } \ } -#define INIT_PROC_ENCRYPTION_IF_NEEDED(DO_CRYPT_INIT, INIT_STATUS) \ +#define INIT_PROC_ENCRYPTION_IF_NEEDED(CSA, DO_CRYPT_INIT, INIT_STATUS) \ { \ if (DO_CRYPT_INIT) \ - INIT_PROC_ENCRYPTION(INIT_STATUS); \ + INIT_PROC_ENCRYPTION(CSA, INIT_STATUS); \ } #else #define INIT_DB_ENCRYPTION_IF_NEEDED(IS_ENCRYPTED, INIT_STATUS, REG, CSA, TSD) -#define INIT_PROC_ENCRYPTION_IF_NEEDED(IS_ENCRYPTED, INIT_STATUS) +#define INIT_PROC_ENCRYPTION_IF_NEEDED(CSA, IS_ENCRYPTED, INIT_STATUS) #endif #define READ_DB_FILE_HEADER(REG, TSD) \ @@ -224,7 +234,6 @@ { \ file_control *fc; \ \ - assert(dba_bg == CSD->acc_meth); \ fc = REG->dyn.addr->file_cntl; \ fc->file_type = dba_bg; \ fc->op = FC_READ; \ @@ -234,6 +243,24 @@ dbfilop(fc); \ } +/* Depending on whether journaling and/or replication was enabled at the time of the crash, + * print REQRUNDOWN, REQRECOV, or REQROLLBACK error message. + */ +#define PRINT_CRASH_MESSAGE(CNT, ARG, ...) \ +{ \ + if (JNL_ENABLED(tsd)) \ + { \ + if (REPL_ENABLED(tsd) && tsd->jnl_before_image) \ + RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQROLLBACK, 4, DB_LEN_STR(reg), \ + LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \ + else \ + RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQRECOV, 4, DB_LEN_STR(reg), \ + LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \ + } else \ + RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), \ + LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \ +} + GBLREF boolean_t gtm_fullblockwrites; /* Do full (not partial) database block writes T/F */ GBLREF boolean_t is_src_server; GBLREF boolean_t mupip_jnl_recover; @@ -260,7 +287,7 @@ OS_PAGE_SIZE_DECLARE error_def(ERR_BADDBVER); ZOS_ONLY(error_def(ERR_BADTAG);) -error_def(ERR_CLSTCONFLICT); +error_def(ERR_HOSTCONFLICT); error_def(ERR_CRITSEMFAIL); error_def(ERR_DBCREINCOMP); error_def(ERR_DBFILERR); @@ -269,10 +296,14 @@ error_def(ERR_DBIDMISMATCH); error_def(ERR_DBNAMEMISMATCH); error_def(ERR_DBNOTGDS); error_def(ERR_DBSHMNAMEDIFF); +error_def(ERR_JNLBUFFREGUPD); error_def(ERR_NLMISMATCHCALC); error_def(ERR_MMNODYNUPGRD); error_def(ERR_PERMGENFAIL); +error_def(ERR_REQROLLBACK); +error_def(ERR_REQRECOV); error_def(ERR_REQRUNDOWN); +error_def(ERR_REGOPENRETRY); error_def(ERR_SYSCALL); error_def(ERR_TEXT); error_def(ERR_VERMISMATCH); @@ -289,11 +320,14 @@ gd_region *dbfilopn (gd_region *reg) int status; bool raw; int stat_res, rc, save_errno; + sgmnt_addrs *csa; ZOS_ONLY(int realfiletag;) seg = reg->dyn.addr; assert(seg->acc_meth == dba_bg || seg->acc_meth == dba_mm); FILE_CNTL_INIT_IF_NULL(seg); + udi = FILE_INFO(reg); + csa = &udi->s_addrs; file.addr = (char *)seg->fname; file.len = seg->fname_len; memset(&pblk, 0, SIZEOF(pblk)); @@ -322,7 +356,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(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); @@ -336,7 +370,6 @@ gd_region *dbfilopn (gd_region *reg) return (gd_region *)-1L; } fnptr = (char *)seg->fname + pblk.b_node; - udi = FILE_INFO(reg); udi->raw = raw; udi->fn = (char *)fnptr; OPENFILE(fnptr, O_RDWR, udi->fd); @@ -349,7 +382,7 @@ gd_region *dbfilopn (gd_region *reg) udi->gt_shm_ctime = 0; } reg->read_only = FALSE; /* maintain csa->read_write simultaneously */ - udi->s_addrs.read_write = TRUE; /* maintain reg->read_only simultaneously */ + csa->read_write = TRUE; /* maintain reg->read_only simultaneously */ if (FD_INVALID == udi->fd) { OPENFILE(fnptr, O_RDONLY, udi->fd); @@ -362,10 +395,10 @@ 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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno); } reg->read_only = TRUE; /* maintain csa->read_write simultaneously */ - udi->s_addrs.read_write = FALSE; /* maintain reg->read_only simultaneously */ + csa->read_write = FALSE; /* maintain reg->read_only simultaneously */ } # ifdef __MVS__ if (-1 == gtm_zos_tag_to_policy(udi->fd, TAG_BINARY, &realfiletag)) @@ -375,7 +408,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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno); } set_gdid_from_stat(&udi->fileid, &buf); if (prev_reg = gv_match(reg)) @@ -391,38 +424,43 @@ gd_region *dbfilopn (gd_region *reg) void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size) { + gtm_uint64_t tmp_sec_size; + /* Ensure that all the various sections that the shared memory contains are actually * aligned at the OS_PAGE_SIZE boundary */ - assert(0 == NODE_LOCAL_SPACE % OS_PAGE_SIZE); + INIT_NUM_CRIT_ENTRY_IF_NEEDED(csd); + assert(MIN_NODE_LOCAL_SPACE <= NODE_LOCAL_SPACE(csd)); + assert(0 == NODE_LOCAL_SPACE(csd) % OS_PAGE_SIZE); assert(0 == LOCK_SPACE_SIZE(csd) % OS_PAGE_SIZE); assert(0 == JNL_SHARE_SIZE(csd) % OS_PAGE_SIZE); assert(0 == SHMPOOL_SECTION_SIZE % OS_PAGE_SIZE); - switch(reg->dyn.addr->acc_meth) + assert(0 == CACHE_CONTROL_SIZE(csd) % OS_PAGE_SIZE); + /* First compute the size based on sections common to both MM and BG */ + tmp_sec_size = NODE_LOCAL_SPACE(csd) + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE + LOCK_SPACE_SIZE(csd); + /* Now, add sections specific to MM and BG */ + if (dba_mm == reg->dyn.addr->acc_meth) + tmp_sec_size += SIZEOF_FILE_HDR(csd); + else { - case dba_mm: - assert(0 == MMBLK_CONTROL_SIZE(csd) % OS_PAGE_SIZE); - *sec_size = ROUND_UP(NODE_LOCAL_SPACE + LOCK_SPACE_SIZE(csd) + MMBLK_CONTROL_SIZE(csd) \ - + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE, OS_PAGE_SIZE); - break; - case dba_bg: - assert(0 == CACHE_CONTROL_SIZE(csd) % OS_PAGE_SIZE); - *sec_size = ROUND_UP(NODE_LOCAL_SPACE + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csd) \ - + CACHE_CONTROL_SIZE(csd) + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE, OS_PAGE_SIZE); - break; - default: - GTMASSERT; + 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 return; } -void db_init(gd_region *reg) +int db_init(gd_region *reg) { boolean_t is_bg, read_only, sem_created = FALSE, need_stacktrace, have_standalone_access; boolean_t shm_setup_ok = FALSE, vermismatch = FALSE, vermismatch_already_printed = FALSE; boolean_t new_shm_ipc, do_crypt_init = FALSE, replinst_mismatch; char machine_name[MAX_MCNAMELEN]; - int gethostname_res, stat_res, mm_prot, group_id, perm, save_udi_semid; + int gethostname_res, stat_res, group_id, perm, save_udi_semid; int4 status, semval, dblksize, fbwsize, save_errno, wait_time, loopcnt, sem_pid; sm_long_t status_l; sgmnt_addrs *csa; @@ -438,53 +476,65 @@ void db_init(gd_region *reg) unix_db_info *udi; char now_running[MAX_REL_NAME]; int init_status; - gtm_uint64_t sec_size; + gtm_uint64_t sec_size, mmap_sz; semwait_status_t retstat; struct perm_diag_data pdd; + boolean_t bypassed_ftok = FALSE, bypassed_access = FALSE; + int jnl_buffer_size; + char s[JNLBUFFUPDAPNDX_SIZE]; /* JNLBUFFUPDAPNDX_SIZE is defined in jnl.h */ DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; - ESTABLISH(dbinit_ch); + ESTABLISH_NOUNWIND(dbinit_ch); assert(INTRPT_IN_GVCST_INIT == intrpt_ok_state); /* we better be called from gvcst_init */ wcs_clean_dbsync_fptr = &wcs_clean_dbsync; tsd = &tsdbuff; read_only = reg->read_only; - TREF(new_dbinit_ipc) = 0; /* we did not create a new ipc resource */ udi = FILE_INFO(reg); memset(machine_name, 0, SIZEOF(machine_name)); - if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, gethostname_res)) - rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Unable to get the hostname"), errno); - assert(strlen(machine_name) < MAX_MCNAMELEN); csa = &udi->s_addrs; - csa->db_addrs[0] = csa->db_addrs[1] = csa->lock_addrs[0] = NULL; /* to help in dbinit_ch and gds_rundown */ + assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id); + if (!mutex_per_process_init_pid) + mutex_per_process_init(); + if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, gethostname_res)) + RTS_ERROR(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Unable to get the hostname"), errno); + if (WBTEST_ENABLED(WBTEST_TAMPER_HOSTNAME)) + STRCPY(machine_name, "s_i_l_l_y"); + assert(strlen(machine_name) < MAX_MCNAMELEN); + assert(NULL == csa->hdr); /* dbinit_ch relies on this to unmap the db (if mm) */ + assert((NULL == csa->db_addrs[0]) && (NULL == csa->db_addrs[1])); + assert((NULL == csa->lock_addrs[0]) && (NULL == csa->lock_addrs[1])); reg->opening = TRUE; assert(0 <= udi->fd); /* database file must have been already opened by dbfilopn() done from gvcst_init() */ FSTAT_FILE(udi->fd, &stat_buf, stat_res); /* get the stats for the database file */ if (-1 == stat_res) - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); + RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); /* Setup new group and permissions if indicated by the security rules. */ if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_IPC, &pdd) < 0) { - send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + SEND_MSG(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("ipc resources"), RTS_ERROR_STRING(udi->fn), PERMGENDIAG_ARGS(pdd)); - rts_error(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + RTS_ERROR(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("ipc resources"), RTS_ERROR_STRING(udi->fn), PERMGENDIAG_ARGS(pdd)); } - /* if the process has standalone access, it will have udi->grabbed_access_sem set to TRUE at this point. Note that down - * in a local variable as the udi->grabbed_access_sem will be set to TRUE even for non-standalone access below and hence - * we can't rely on that later to determine if the process had standalone access or not when it entered this function. + /* if the process has standalone access, it will have udi->grabbed_access_sem set to TRUE at + * this point. Note that down in a local variable as the udi->grabbed_access_sem will be set + * to TRUE even for non-standalone access below and hence we can't rely on that later to determine if the process had + * standalone access or not when it entered this function. */ have_standalone_access = udi->grabbed_access_sem; if (!have_standalone_access) { do_crypt_init = (reg->dyn.addr->is_encrypted && !IS_LKE_IMAGE); - INIT_PROC_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status); /* heavy-weight so needs to be done before ftok */ + INIT_PROC_ENCRYPTION_IF_NEEDED(csa, do_crypt_init, init_status); /* heavy-weight so needs to be done before ftok */ start_hrtbt_cntr = heartbeat_counter; - if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat)) + if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat, &bypassed_ftok)) ISSUE_SEMWAIT_ERROR((&retstat), reg, udi, "ftok"); - /* At this point we have ftok_semid sempahore based on ftok key. Any ftok conflicted region will block at this + if (bypassed_ftok) + SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("FTOK bypassed at database initialization")); + /* At this point we have ftok_semid semaphore based on ftok key. Any ftok conflicted region will block at this * point. For example, if a.dat and b.dat both have same ftok and process A tries to open or close a.dat and * process B tries to open or close b.dat, even though the database accesses don't conflict, the first one to * control the ftok semaphore blocks (makes wait) the other(s). @@ -501,61 +551,62 @@ void db_init(gd_region *reg) * as initialization is heavy-weight. */ if (!ftok_sem_release(reg, TRUE, FALSE)) /* decrement counter so later increment is correct */ - rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); - INIT_PROC_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status); /* redo initialization */ + RTS_ERROR(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); + INIT_PROC_ENCRYPTION_IF_NEEDED(csa, do_crypt_init, init_status); /* redo initialization */ start_hrtbt_cntr = heartbeat_counter; /* update to reflect time lost in encryption initialization */ - if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat)) + if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat, &bypassed_ftok)) ISSUE_SEMWAIT_ERROR((&retstat), reg, udi, "ftok"); + if (bypassed_ftok) + SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("bypassed at database encryption initialization")); } /* else encryption is turned off in the file header. Continue as-is. Any encryption initialization done * before is discarded */ } INIT_DB_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status, reg, csa, tsd); -# ifdef DEBUG - if (gtm_white_box_test_case_enabled && (WBTEST_HOLD_ONTO_FTOKSEM_IN_DBINIT == gtm_white_box_test_case_number)) + if (WBTEST_ENABLED(WBTEST_HOLD_ONTO_FTOKSEM_IN_DBINIT)) { DBGFPF((stderr, "Holding the ftok semaphore.. Sleeping for 30 seconds\n")); LONG_SLEEP(30); DBGFPF((stderr, "30 second sleep exhausted.. continuing with rest of db_init..\n")); } -# endif for (loopcnt = 0; MAX_ACCESS_SEM_RETRIES > loopcnt; loopcnt++) { CSD2UDI(tsd, udi); /* sets udi->semid/shmid/sem_ctime/shm_ctime from file header */ - TREF(new_dbinit_ipc) = 0; + /* we did not create a new ipc resource */ + udi->new_sem = udi->new_shm = FALSE; sem_created = FALSE; if (INVALID_SEMID == udi->semid) { /* access control semaphore does not exist. Create one */ if (0 != udi->gt_sem_ctime || INVALID_SHMID != udi->shmid || 0 != udi->gt_shm_ctime) { /* We must have somthing wrong in protocol or, code, if this happens. */ assert(FALSE); - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name), - ERR_TEXT, 2, LEN_AND_LIT(REQRUNDOWN_TEXT)); + PRINT_CRASH_MESSAGE(0, tsd, ERR_TEXT, 2, LEN_AND_STR(REQRUNDOWN_TEXT)); } /* Create new semaphore using IPC_PRIVATE. System guarantees a unique id. */ if (-1 == (udi->semid = semget(IPC_PRIVATE, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT))) { udi->semid = INVALID_SEMID; - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semget"), errno); } udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */ - TREF(new_dbinit_ipc) |= (NEW_DBINIT_SEM_IPC_MASK | NEW_DBINIT_SHM_IPC_MASK); + udi->new_sem = udi->new_shm = TRUE; sem_created = TRUE; /* change group and permissions */ semarg.buf = &semstat; if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_STAT1"), errno); if ((-1 != group_id) && (group_id != semstat.sem_perm.gid)) semstat.sem_perm.gid = group_id; semstat.sem_perm.mode = perm; if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_SET, semarg)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_SET"), errno); SET_GTM_ID_SEM(udi->semid, status); if (-1 == status) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl SETVAL"), errno); /* WARNING: Because SETVAL changes sem_ctime, we must NOT do any SETVAL after this one; code here * and elsewhere uses IPC_STAT to get sem_ctime and relies on sem_ctime as the creation time of the @@ -563,58 +614,74 @@ void db_init(gd_region *reg) */ semarg.buf = &semstat; if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_STAT2"), errno); tsd->gt_sem_ctime.ctime = udi->gt_sem_ctime = semarg.buf->sem_ctime; } else { /* "semid" already exists. Need to lock it. Before that do sanity check on "semid" and "shmid" */ if (INVALID_SHMID != udi->shmid) { + if (WBTEST_ENABLED(WBTEST_HOLD_FTOK_UNTIL_BYPASS)) + { + if (4 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)) + { /* We are bypasser */ + DBGFPF((stderr, "Waiting for all processes to quit.\n")); + while (1 < semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)) + LONG_SLEEP(1); + } + } if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) - rts_error(VARLSTCNT(11) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), - LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, - LEN_AND_LIT("Error with database control shmctl"), errno); - else if (shmstat.shm_ctime != tsd->gt_shm_ctime.ctime) + { + if (bypassed_ftok) + { + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_REGOPENRETRY, 4, + REG_LEN_STR(reg), DB_LEN_STR(reg)); + REVERT; + return -1; /* Retry calling db_init. Cleanup in gvcst_init() */ + } + PRINT_CRASH_MESSAGE(1, tsd, ERR_TEXT, 2, + LEN_AND_LIT("Error with database control shmctl"), errno); + } else if (shmstat.shm_ctime != tsd->gt_shm_ctime.ctime) { GTM_ATTACH_SHM_AND_CHECK_VERS(vermismatch, shm_setup_ok); if (vermismatch) { GTM_VERMISMATCH_ERROR; } else - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), - LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, - LEN_AND_LIT("shm_ctime does not match")); + { + PRINT_CRASH_MESSAGE(0, tsd, ERR_TEXT, 2, + LEN_AND_LIT("IPC creation time indicates a probable prior crash")); + } } semarg.buf = &semstat; - if (-1 == semctl(udi->semid, 0, IPC_STAT, semarg)) - /* file header has valid semid but semaphore does not exist */ - rts_error(VARLSTCNT(11) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), - LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, - LEN_AND_LIT("Error with database control semaphore (IPC_STAT)"), - errno); - else if (semarg.buf->sem_ctime != tsd->gt_sem_ctime.ctime) + if (-1 == semctl(udi->semid, DB_CONTROL_SEM, IPC_STAT, semarg)) + { /* file header has valid semid but semaphore does not exist */ + PRINT_CRASH_MESSAGE(1, tsd, ERR_TEXT, 2, + LEN_AND_LIT("Error with database control semaphore (IPC_STAT)"), errno); + } else if (semarg.buf->sem_ctime != tsd->gt_sem_ctime.ctime) { GTM_ATTACH_SHM_AND_CHECK_VERS(vermismatch, shm_setup_ok); if (vermismatch) { GTM_VERMISMATCH_ERROR; } else - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), - LEN_AND_STR(tsd->machine_name), ERR_TEXT, 2, - LEN_AND_LIT("sem_ctime does not match")); + { + PRINT_CRASH_MESSAGE(0, tsd, ERR_TEXT, 2, + LEN_AND_LIT("IPC creation time indicates a probable prior crash")); + } } } else - { /* else "shmid" is NOT valid. This is possible if - - * (a) Another process is holding the access control semaphore for a longer duration of time but - * does NOT have the shared memory setup (MUPIP INTEG -FILE or MUPIP RESTORE). - * - * (b) If a process (like in (a)) were kill -15ed or -9ed and hence did not get a chance to do - * db_ipcs_reset which resets "semid"/"shmid" field in the file header to INVALID. - * - * In either case, try grabbing the semaphore. If not, wait (depending on the user specified wait - * time). Eventually, we will either get hold of the semaphore OR will error out. - */ - TREF(new_dbinit_ipc) |= NEW_DBINIT_SHM_IPC_MASK; /* Need to create shared memory */ + { /* else "shmid" is NOT valid. This is possible if - + * (a) Another process is holding the access control semaphore for a longer duration of time + * but does NOT have the shared memory setup (MUPIP INTEG -FILE or MUPIP RESTORE). + * + * (b) If a process (like in (a)) were kill -15ed or -9ed and hence did not get a chance to + * do db_ipcs_reset which resets "semid"/"shmid" field in the file header to INVALID. + * + * In either case, try grabbing the semaphore. If not, wait (depending on the user specified + * wait time). Eventually, we will either get hold of the semaphore OR will error out. + */ + udi->new_shm = TRUE; /* Need to create shared memory */ } } /* We already have ftok semaphore of this region, so all we need is the access control semaphore */ @@ -630,10 +697,10 @@ void db_init(gd_region *reg) { if (NO_SEMWAIT_ON_EAGAIN == TREF(dbinit_max_hrtbt_delta)) { - sem_pid = semctl(udi->semid, 0, GETPID); + sem_pid = semctl(udi->semid, DB_CONTROL_SEM, GETPID); if (-1 != sem_pid) { - rts_error(VARLSTCNT(13) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(13) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_SEMWT2LONG, 7, process_id, 0, LEN_AND_LIT("access control"), DB_LEN_STR(reg), sem_pid); } else @@ -641,26 +708,28 @@ void db_init(gd_region *reg) save_errno = errno; if (!SEM_REMOVED(save_errno)) { - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); } /* else semaphore was removed. Fall-through */ } - } else if (!do_blocking_semop(udi->semid, sop, sopcnt, gtm_access_sem, start_hrtbt_cntr, - &retstat)) + } else if (!do_blocking_semop(udi->semid, gtm_access_sem, start_hrtbt_cntr, + &retstat, reg, &bypassed_access)) { if (!SEM_REMOVED(retstat.save_errno)) ISSUE_SEMWAIT_ERROR((&retstat), reg, udi, "access control"); save_errno = retstat.save_errno; } else { - assert(SS_NORMAL == retstat.save_errno); + if (bypassed_access) + SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("Access control bypassed at init")); save_errno = status = SS_NORMAL; break; } } else if (!SEM_REMOVED(save_errno)) { - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ + RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); } /* this is possible if a concurrent gds_rundown removed the access control semaphore (if @@ -673,21 +742,23 @@ void db_init(gd_region *reg) assert(SEM_REMOVED(save_errno)); if (1 == loopcnt) { - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ + RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); } READ_DB_FILE_HEADER(reg, tsd); } } - assert(-1 != status); - udi->grabbed_access_sem = TRUE; + assert(-1 != status || bypassed_access); + if (!bypassed_access) + udi->grabbed_access_sem = TRUE; + if(!read_only) + udi->counter_acc_incremented = TRUE; /* Now that we have the access control semaphore, re-read the file header so we have the uptodate information * in case some of the fields (like access method) were modified concurrently by MUPIP SET -FILE */ READ_DB_FILE_HEADER(reg, tsd); UDI2CSD(udi, tsd); /* Since we read the file header again, tsd->semid/shmid and corresponding ctime fields - * will not be uptodate. Refresh it with the udi copies as they are the ones used above - */ + * will not be uptodate. Refresh it with the udi copies as they are the ones used above */ } else { /* for have_standalone_access we were already in "mu_rndwn_file" and got "semid" semaphore. Since mu_rndwn_file * would have gotten "ftok" semaphore before acquiring the access control semaphore, no need to get the "ftok" @@ -695,7 +766,7 @@ void db_init(gd_region *reg) */ READ_DB_FILE_HEADER(reg, tsd); /* file already opened by dbfilopn() done from gvcst_init() */ do_crypt_init = (tsd->is_encrypted && !IS_LKE_IMAGE); - INIT_PROC_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status); + INIT_PROC_ENCRYPTION_IF_NEEDED(csa, do_crypt_init, init_status); INIT_DB_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status, reg, csa, tsd); CSD2UDI(tsd, udi); /* Make sure "mu_rndwn_file" has created semaphore for standalone access */ @@ -705,27 +776,54 @@ void db_init(gd_region *reg) assert((INVALID_SHMID == udi->shmid) && (0 == udi->gt_shm_ctime)); /* In pro, just clear it and proceed */ udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */ - TREF(new_dbinit_ipc) |= (NEW_DBINIT_SEM_IPC_MASK | NEW_DBINIT_SHM_IPC_MASK); + udi->new_shm = udi->new_sem = TRUE; } - assert(udi->grabbed_access_sem); + assert(udi->grabbed_access_sem || bypassed_access); DO_DB_HDR_CHECK(reg, tsd); /* Basic sanity check on the file header fields */ -# ifdef DEBUG - if (gtm_white_box_test_case_enabled && (WBTEST_HOLD_ONTO_ACCSEM_IN_DBINIT == gtm_white_box_test_case_number)) + if (WBTEST_ENABLED(WBTEST_HOLD_ONTO_ACCSEM_IN_DBINIT)) { DBGFPF((stderr, "Holding the access control semaphore.. Sleeping for 30 seconds\n")); LONG_SLEEP(30); DBGFPF((stderr, "30 second sleep exhausted.. continuing with rest of db_init..\n")); } -# endif + if (WBTEST_ENABLED(WBTEST_HOLD_FTOK_UNTIL_BYPASS)) + { + if (3 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)) + { /* We are ftok semaphore holder */ + DBGFPF((stderr, "Holding the ftok semaphore until a new process comes along.\n")); + while (3 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)) + LONG_SLEEP(1); + } + } /* Now that the access control lock is obtained and file header passed all sanity checks, update the acc_meth of the * region from the one in the file header (in case they are different). This way, any later code that relies on the * acc_meth dereferenced from the region will work correctly. Instead of checking if they are different, do the assignment * unconditionally */ reg->dyn.addr->acc_meth = tsd->acc_meth; - new_shm_ipc = (TREF(new_dbinit_ipc) & NEW_DBINIT_SHM_IPC_MASK); + new_shm_ipc = udi->new_shm; if (new_shm_ipc) - { + { /* Bypassers are not allowed to create shared memory so we don't end up with conflicting shared memories */ + if (bypassed_ftok || bypassed_access) + { + gtm_putmsg_csa(CSA_ARG(csa) ERR_REGOPENRETRY, 2, REG_LEN_STR(reg), DB_LEN_STR(reg)); + REVERT; + return -1; /* Retry calling db_init. Cleanup in gvcst_init() */ + } + /* Since we are about to allocate new shared memory, if necessary, adjust the journal buffer size right now. + * Note that if the process setting up shared memory is a read-only process, then we might not flush updated + * jnl_buffer_size to the file header, which is fine because the value in shared memory is what all processes + * are looking at. If necessary, the next process to initialize shared memory will repeat the process of + * adjusting the jnl_buffer_size value. + */ + jnl_buffer_size = tsd->jnl_buffer_size; + if ((0 != jnl_buffer_size) && (jnl_buffer_size < JNL_BUFFER_MIN)) + { + ROUND_UP_MIN_JNL_BUFF_SIZE(tsd->jnl_buffer_size, tsd); + SNPRINTF(s, JNLBUFFUPDAPNDX_SIZE, JNLBUFFUPDAPNDX, JNL_BUFF_PORT_MIN(tsd), JNL_BUFFER_MAX); + SEND_MSG(VARLSTCNT(10) ERR_JNLBUFFREGUPD, 4, REG_LEN_STR(reg), + jnl_buffer_size, tsd->jnl_buffer_size, ERR_TEXT, 2, LEN_AND_STR(s)); + } dbsecspc(reg, tsd, &sec_size); /* Find db segment size */ /* Create new shared memory using IPC_PRIVATE. System guarantees a unique id */ GTM_WHITE_BOX_TEST(WBTEST_FAIL_ON_SHMGET, sec_size, GTM_UINT64_MAX); @@ -733,26 +831,26 @@ void db_init(gd_region *reg) { udi->shmid = (int)INVALID_SHMID; status_l = INVALID_SHMID; - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database shmget"), errno); } tsd->shmid = udi->shmid; if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_STAT1"), errno); /* change group and permissions */ if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid)) shmstat.shm_perm.gid = group_id; shmstat.shm_perm.mode = perm; if (-1 == shmctl(udi->shmid, IPC_SET, &shmstat)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_SET"), errno); /* Warning: We must read the shm_ctime using IPC_STAT after IPC_SET, which changes it. * We must NOT do any more IPC_SET or SETVAL after this. Our design is to use * shm_ctime as creation time of shared memory and store it in file header. */ if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_STAT2"), errno); tsd->gt_shm_ctime.ctime = udi->gt_shm_ctime = shmstat.shm_ctime; GTM_ATTACH_SHM; @@ -764,18 +862,20 @@ void db_init(gd_region *reg) { GTM_VERMISMATCH_ERROR; } else if (!shm_setup_ok) - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(tsd->machine_name), - ERR_TEXT, 2, LEN_AND_LIT("shared memory is invalid")); + { + PRINT_CRASH_MESSAGE(0, tsd, ERR_TEXT, 2, LEN_AND_LIT("shared memory is invalid")); + } } csa->critical = (mutex_struct_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SIZE); assert(((INTPTR_T)csa->critical & 0xf) == 0); /* critical should be 16-byte aligned */ # ifdef CACHELINE_SIZE assert(0 == ((INTPTR_T)csa->critical & (CACHELINE_SIZE - 1))); # endif - /* Note: Here we check jnl_sate from database file and its value cannot change without standalone access. - * The jnl_buff buffer should be initialized irrespective of read/write process */ + /* Note: Here we check jnl_state from database file; its value cannot change without stand-alone access. + * The jnl_buff should be initialized irrespective of read/write process + */ JNL_INIT(csa, reg, tsd); - csa->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SPACE + JNL_SHARE_SIZE(tsd)); + csa->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SPACE(tsd) + JNL_SHARE_SIZE(tsd)); /* Initialize memory for snapshot context */ \ csa->ss_ctx = malloc(SIZEOF(snapshot_context_t)); DEFAULT_INIT_SS_CTX((SS_CTX_CAST(csa->ss_ctx))); @@ -799,48 +899,49 @@ void db_init(gd_region *reg) csd = csa->hdr = (sgmnt_data_ptr_t)(csa->lock_addrs[1] + 1 + CACHE_CONTROL_SIZE(tsd)); else { - csa->acc_meth.mm.mmblk_state = (mmblk_que_heads_ptr_t)(csa->lock_addrs[1] + 1); FSTAT_FILE(udi->fd, &stat_buf, stat_res); if (-1 == stat_res) - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); - mm_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE); - if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, - (size_t)stat_buf.st_size, - mm_prot, - GTM_MM_FLAGS, udi->fd, (off_t)0))) - rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); - csa->db_addrs[1] = csa->db_addrs[0] + stat_buf.st_size - 1; - csd = csa->hdr = (sgmnt_data_ptr_t)csa->db_addrs[0]; + RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno); + mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(tsd); + assert(0 < mmap_sz); + CHECK_LARGEFILE_MMAP(reg, mmap_sz); /* can issue rts_error MMFILETOOLARGE */ + if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(tsd), read_only))) + { + RTS_ERROR(VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(reg), + ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, errno); + } + csa->db_addrs[1] = csa->db_addrs[0] + mmap_sz - 1; /* '- 1' due to 0-based indexing */ + assert(csa->db_addrs[1] > csa->db_addrs[0]); + csd = csa->hdr = (sgmnt_data_ptr_t)((sm_uc_ptr_t)csa->lock_addrs[1] + 1); } /* At this point, shm_setup_ok is TRUE so we are guaranteed that vermismatch is FALSE. Therefore, we can safely * dereference csa->nl->glob_sec_init without worrying about whether or not it could be at a different offset than * the current version. The only exception is DSE which can continue even after the VERMISMATCH error and hence * can have shm_setup_ok set to FALSE at this point. */ - if (shm_setup_ok && !csa->nl->glob_sec_init) + if (shm_setup_ok && !csa->nl->glob_sec_init && !(bypassed_ftok || bypassed_access)) { assert(new_shm_ipc); assert(!vermismatch); csa->dbinit_shm_created = TRUE; - if (is_bg) - { - memcpy(csd, tsd, SIZEOF(sgmnt_data)); - READ_DB_FILE_MASTERMAP(reg, csd); - } - if (csd->machine_name[0]) /* crash occured */ + memcpy(csd, tsd, SIZEOF(sgmnt_data)); + READ_DB_FILE_MASTERMAP(reg, csd); + if (csd->machine_name[0]) /* crash occurred */ { if (0 != STRNCMP_STR(csd->machine_name, machine_name, MAX_MCNAMELEN)) /* crashed on some other node */ - rts_error(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name)); + RTS_ERROR(VARLSTCNT(8) ERR_HOSTCONFLICT, 6, LEN_AND_STR(machine_name), DB_LEN_STR(reg), + LEN_AND_STR(csd->machine_name)); else - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name), - ERR_TEXT, 2, - LEN_AND_LIT("machine name in file header is non-null implying possible crash")); + { + PRINT_CRASH_MESSAGE(0, csd, ERR_TEXT, 2, + LEN_AND_LIT("machine name in file header is non-null implying possible crash")); + } } if (is_bg) { - bt_malloc(csa); - csa->nl->cache_off = -CACHE_CONTROL_SIZE(tsd); + csa->nl->cache_off = -CACHE_CONTROL_SIZE(csd); db_csh_ini(csa); + bt_malloc(csa); } db_csh_ref(csa, TRUE); shmpool_buff_init(reg); @@ -877,18 +978,20 @@ void db_init(gd_region *reg) # include "tab_db_csh_acct_rec.h" # undef TAB_DB_CSH_ACCT_REC } - csd->wc_blocked = FALSE; /* Since we are creating shared memory, reset wc_blocked to FALSE */ + csa->nl->wc_blocked = FALSE; /* Since we are creating shared memory, reset wc_blocked to FALSE */ gvstats_rec_csd2cnl(csa); /* should be called before "db_auto_upgrade" */ reg->dyn.addr->ext_blk_count = csd->extension_size; mlk_shr_init(csa->lock_addrs[0], csd->lock_space_size, csa, (FALSE == read_only)); + db_auto_upgrade(reg); /* should be called before "gtm_mutex_init" to ensure NUM_CRIT_ENTRY is nonzero */ DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */ - gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE); + gtm_mutex_init(reg, NUM_CRIT_ENTRY(csd), FALSE); DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */ if (read_only) csa->nl->remove_shm = TRUE; /* gds_rundown can remove shmem if first process has read-only access */ - db_auto_upgrade(reg); if (FALSE == csd->multi_site_open) - { /* first time database is opened after upgrading to a GTM version that supports multi-site replication */ + { /* first time database is opened after upgrading to a GTM version that supports multi-site + * replication + */ csd->zqgblmod_seqno = 0; csd->zqgblmod_tn = 0; if (csd->pre_multisite_resync_seqno > csd->reg_seqno) @@ -900,7 +1003,7 @@ void db_init(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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno); } set_gdid_from_stat(&csa->nl->unique_id.uid, &stat_buf); # ifdef RELEASE_LATCH_GLOBAL @@ -921,11 +1024,13 @@ void db_init(gd_region *reg) if (STRNCMP_STR(csa->nl->machine_name, machine_name, MAX_MCNAMELEN)) /* machine names do not match */ { if (csa->nl->machine_name[0]) - rts_error(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name)); + RTS_ERROR(VARLSTCNT(8) ERR_HOSTCONFLICT, 6, LEN_AND_STR(machine_name), DB_LEN_STR(reg), + LEN_AND_STR(csa->nl->machine_name)); else - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name), - ERR_TEXT, 2, - LEN_AND_LIT("machine name in shared memory is non-null implying possible crash")); + { + PRINT_CRASH_MESSAGE(0, csd, ERR_TEXT, 2, + LEN_AND_LIT("machine name in shared memory is non-null implying possible crash")); + } } /* Since nl is memset to 0 initially and then fname is copied over from gv_cur_region and since "fname" is * guaranteed to not exceed MAX_FN_LEN, we should have a terminating '\0' atleast at csa->nl->fname[MAX_FN_LEN] @@ -936,18 +1041,17 @@ void db_init(gd_region *reg) if (-1 == stat_res) { save_errno = errno; - send_msg(VARLSTCNT(13) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_DBNAMEMISMATCH, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname, save_errno); - rts_error(VARLSTCNT(13) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), + SEND_MSG(VARLSTCNT(13) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), ERR_DBNAMEMISMATCH, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname, save_errno); + PRINT_CRASH_MESSAGE(3, csa->nl, ERR_DBNAMEMISMATCH, 4, + DB_LEN_STR(reg), udi->shmid, csa->nl->fname, save_errno); } /* Check whether csa->nl->fname and csa->nl->unique_id.uid are in sync. If not error out. */ if (FALSE == is_gdid_stat_identical(&csa->nl->unique_id.uid, &stat_buf)) { - send_msg(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_DBIDMISMATCH, 4, csa->nl->fname, DB_LEN_STR(reg), udi->shmid); - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), + SEND_MSG(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), ERR_DBIDMISMATCH, 4, csa->nl->fname, DB_LEN_STR(reg), udi->shmid); + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_DBIDMISMATCH, 4, csa->nl->fname, DB_LEN_STR(reg), udi->shmid); } /* Previously, we used to check for csa->nl->creation_date_time4 vs csd->creation_time4 and treat it as * an id mismatch situation as well. But later it was determined that as long as the filename and the fileid @@ -958,10 +1062,9 @@ void db_init(gd_region *reg) */ if (FALSE == is_gdid_gdid_identical(&FILE_INFO(reg)->fileid, &csa->nl->unique_id.uid)) { - send_msg(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_DBSHMNAMEDIFF, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname); - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), + SEND_MSG(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), ERR_DBSHMNAMEDIFF, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname); + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_DBSHMNAMEDIFF, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname); } /* If a regular Recover/Rollback created the shared memory and died (because of a user error or runtime error), * any process that comes up after that should NOT touch the shared memory or database. The user should reissue @@ -973,32 +1076,39 @@ void db_init(gd_region *reg) if (csa->nl->donotflush_dbjnl && !jgbl.onlnrlbk) { assert(FALSE); - rts_error(VARLSTCNT(10) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_TEXT, 2, LEN_AND_LIT("mupip recover/rollback created shared memory. Needs MUPIP RUNDOWN")); + PRINT_CRASH_MESSAGE(0, csa->nl, ERR_TEXT, 2, + LEN_AND_LIT("mupip recover/rollback created shared memory. Needs MUPIP RUNDOWN")); } /* verify pointers from our calculation vs. the copy in shared memory */ if (csa->nl->critical != (sm_off_t)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl)) - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("critical"), + { + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("critical"), (uint4)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->critical); + } if ((JNL_ALLOWED(csa)) && (csa->nl->jnl_buff != (sm_off_t)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl))) - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("journal buffer"), + { + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("journal buffer"), (uint4)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->jnl_buff); + } if (csa->nl->shmpool_buffer != (sm_off_t)((sm_uc_ptr_t)csa->shmpool_buffer - (sm_uc_ptr_t)csa->nl)) - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("backup buffer"), + { + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("backup buffer"), (uint4)((sm_uc_ptr_t)csa->shmpool_buffer - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->shmpool_buffer); + } if ((is_bg) && (csa->nl->hdr != (sm_off_t)((sm_uc_ptr_t)csd - (sm_uc_ptr_t)csa->nl))) - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("file header"), + { + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("file header"), (uint4)((sm_uc_ptr_t)csd - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->hdr); + } if (csa->nl->lock_addrs != (sm_off_t)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl)) - rts_error(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name), - ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("lock address"), + { + PRINT_CRASH_MESSAGE(2, csa->nl, ERR_NLMISMATCHCALC, 4, LEN_AND_LIT("lock address"), (uint4)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->lock_addrs); + } csa->dbinit_shm_created = FALSE; + if (is_bg) + db_csh_ini(csa); } if (REPL_ALLOWED(csd) && is_src_server) { /* Bind this database to the journal pool shmid & instance file name that the source server started with. @@ -1035,22 +1145,23 @@ void db_init(gd_region *reg) } /* Replication instance file or jnlpool id mismatch. Issue error. */ if (replinst_mismatch) - rts_error(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, + RTS_ERROR(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, LEN_AND_STR(jnlpool.jnlpool_ctl->jnlpool_id.instfilename), jnlpool.repl_inst_filehdr->jnlpool_shmid, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->replinstfilename), csa->nl->jnlpool_shmid); } + csa->root_search_cycle = csa->nl->root_search_cycle; csa->onln_rlbk_cycle = csa->nl->onln_rlbk_cycle; /* take local copy of the current Online Rollback cycle */ csa->db_onln_rlbkd_cycle = csa->nl->db_onln_rlbkd_cycle; /* take local copy of the current Online Rollback mod cycle */ /* Record ftok information as soon as shared memory set up is done */ - if (!have_standalone_access) + if (!have_standalone_access && !bypassed_ftok) FTOK_TRACE(csa, csd->trans_hist.curr_tn, ftok_ops_lock, process_id); - if (-1 == (semval = semctl(udi->semid, 1, GETVAL))) /* semval = number of process attached */ + if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL))) /* semval = number of process attached */ { save_errno = errno; - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ + RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ RTS_ERROR_LITERAL("semctl()"), CALLFROM, save_errno); } - if (!read_only && 1 == semval) + if (!read_only && (1 == semval) && !bypassed_ftok && !bypassed_access) { /* For read-write process flush file header to write machine_name, * semaphore, shared memory id and semaphore creation time to disk. */ @@ -1063,10 +1174,10 @@ void db_init(gd_region *reg) csd->gt_sem_ctime = tsd->gt_sem_ctime; csd->gt_shm_ctime = tsd->gt_shm_ctime; } - LSEEKWRITE(udi->fd, (off_t)0, (sm_uc_ptr_t)csd, SIZEOF(sgmnt_data), save_errno); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, (sm_uc_ptr_t)csd, SIZEOF(sgmnt_data), save_errno); if (0 != save_errno) { - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error with database header flush"), save_errno); } } else if (read_only && new_shm_ipc) @@ -1080,26 +1191,27 @@ void db_init(gd_region *reg) db_ipcs.fn_len = reg->dyn.addr->fname_len; memcpy(db_ipcs.fn, reg->dyn.addr->fname, reg->dyn.addr->fname_len); db_ipcs.fn[reg->dyn.addr->fname_len] = 0; + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa); if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0)) - rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), + RTS_ERROR(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("gtmsecshr failed to update database file header")); } if (gtm_fullblockwrites) { /* We have been asked to do FULL BLOCK WRITES for this database. On *NIX, attempt to get the filesystem - blocksize from statvfs. This allows a full write of a blockwithout the OS having to fetch the old - block for a read/update operation. We will round the IOs to the next filesystem blocksize if the - following criteria are met: - - 1) Database blocksize must be a whole multiple of the filesystem blocksize for the above - mentioned reason. - - 2) Filesystem blocksize must be a factor of the location of the first data block - given by the start_vbn. - - The saved length (if the feature is enabled) will be the filesystem blocksize and will be the - length that a database IO is rounded up to prior to initiation of the IO. - */ + * blocksize from statvfs. This allows a full write of a blockwithout the OS having to fetch the old + * block for a read/update operation. We will round the IOs to the next filesystem blocksize if the + * following criteria are met: + * + * 1) Database blocksize must be a whole multiple of the filesystem blocksize for the above + * mentioned reason. + * + * 2) Filesystem blocksize must be a factor of the location of the first data block + * given by the start_vbn. + * + * The saved length (if the feature is enabled) will be the filesystem blocksize and will be the + * length that a database IO is rounded up to prior to initiation of the IO. + */ FSTATVFS_FILE(udi->fd, &dbvfs, status); if (-1 != status) { @@ -1109,47 +1221,50 @@ void db_init(gd_region *reg) csa->do_fullblockwrites = TRUE; /* This region is fullblockwrite enabled */ /* Report this length in DSE even if not enabled */ csa->fullblockwrite_len = fbwsize; /* Length for rounding fullblockwrite */ - } - else + } else { save_errno = errno; - send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fstatvfs"), CALLFROM, save_errno); + SEND_MSG(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fstatvfs"), CALLFROM, save_errno); } } ++csa->nl->ref_cnt; /* This value is changed under control of the init/rundown semaphore only */ assert(!csa->ref_cnt); /* Increment shared ref_cnt before private ref_cnt increment. */ csa->ref_cnt++; /* Currently journaling logic in gds_rundown() in VMS relies on this order to detect last writer */ - if (!have_standalone_access && !jgbl.onlnrlbk) + if (WBTEST_ENABLED(WBTEST_HOLD_SEM_BYPASS) && !IS_GTM_IMAGE) + { + if (0 == csa->nl->wbox_test_seq_num) + { + csa->nl->wbox_test_seq_num = 1; + DBGFPF((stderr, "Holding semaphores...\n")); + while (1 == csa->nl->wbox_test_seq_num) + LONG_SLEEP(1); + } + } + if (!have_standalone_access && !jgbl.onlnrlbk && !bypassed_access) { /* Release control lockout now that it is init'd */ - if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO))) + if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO))) { save_errno = errno; - rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ + RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \ RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); } udi->grabbed_access_sem = FALSE; } -# ifdef DEBUG - if (gtm_white_box_test_case_enabled && (WBTEST_SEMTOOLONG_STACK_TRACE == gtm_white_box_test_case_number) \ - && (1 == csa->nl->wbox_test_seq_num)) + if (WBTEST_ENABLED(WBTEST_SEMTOOLONG_STACK_TRACE) && (1 == csa->nl->wbox_test_seq_num)) { csa->nl->wbox_test_seq_num = 2; /* Wait till the other process has got some stack traces */ while (csa->nl->wbox_test_seq_num != 3) LONG_SLEEP(10); } -# endif - if (!have_standalone_access) + if (!have_standalone_access && !bypassed_ftok) { /* Release ftok semaphore lock so that any other ftok conflicted database can continue now */ if (!ftok_sem_release(reg, FALSE, FALSE)) - rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); + RTS_ERROR(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg)); FTOK_TRACE(csa, csd->trans_hist.curr_tn, ftok_ops_release, process_id); + udi->grabbed_ftok_sem = FALSE; } - /* Do the per process initialization of mutex stuff */ - assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id); - if (!mutex_per_process_init_pid) - mutex_per_process_init(); REVERT; - return; + return 0; } diff --git a/sr_unix/heartbeat_timer.c b/sr_unix/heartbeat_timer.c index 7aad698..ab14edb 100644 --- a/sr_unix/heartbeat_timer.c +++ b/sr_unix/heartbeat_timer.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,22 +30,168 @@ #include "gtmimagename.h" #include "dpgbldir.h" #include "have_crit.h" +#include "anticipatory_freeze.h" + +#ifdef DEBUG +STATICDEF uint4 next_heartbeat_counter = 1; /* the heartbeat_counter at which enospc manipulations need to happen */ +GBLREF boolean_t is_jnlpool_creator; /* The purpose of this check is to assign only one process responsible of + * setting fake ENOSPC flags. If we had multiple processes messing with FREEZE, + * the test would freeze more often and eventually do nothing but freeze. + */ +STATICDEF uint4 syslog_deferred = 0; +#endif GBLREF volatile uint4 heartbeat_counter; GBLREF boolean_t is_src_server; GBLREF enum gtmImageTypes image_type; GBLREF uint4 process_id; +GBLREF jnlpool_addrs jnlpool; +GBLREF volatile int4 gtmMallocDepth; + +#ifdef DEBUG + +#define ENOSPC_FROZEN_DURATION 2 /* 16 seconds */ +#define ENOSPC_UNFROZEN_DURATION (2 * (rand() % 120 + 1)) /* 16 seconds to 32 minutes */ +#define MAX_REGIONS 50 + +#define NONE 0 /* 1/2 probablility */ +#define DB_ON 1 /* 1/6 probablility */ +#define JNL_ON 2 /* 1/6 probablility */ +#define DB_AND_JNL_ON 3 /* 1/6 probablility */ +#define MAX_ENOSPC_TARGET 4 + +error_def(ERR_TEXT); +error_def(ERR_FAKENOSPCLEARED); + +void choose_random_reg_list(char *enospc_enable_list, int n_reg) +{ + int i; + + assert(MAX_REGIONS >= n_reg); + for (i = 0; i < n_reg; i++) + { + if(rand() % 2) /* Should we trigger fake ENOSPC on this region */ + enospc_enable_list[i] = rand() % (MAX_ENOSPC_TARGET - 1) + 1; /* What kind? */ + else + enospc_enable_list[i] = NONE; + } +} + +void set_enospc_if_needed() +{ + gd_addr *addr_ptr; + char enospc_enable_list[MAX_REGIONS]; + boolean_t ok_to_interrupt, is_time_to_act; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + + if (TREF(gtm_test_fake_enospc) && is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE) + { + ok_to_interrupt = (INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (0 == gtmMallocDepth); + is_time_to_act = (next_heartbeat_counter == heartbeat_counter); + if (syslog_deferred && ok_to_interrupt) + { + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_FAKENOSPCLEARED, 1, (heartbeat_counter - syslog_deferred)); + syslog_deferred = 0; + } + if (!is_time_to_act || syslog_deferred || (!ok_to_interrupt && !IS_REPL_INST_FROZEN)) + { + /* We have to skip this because we have just fallen into deferred zone or we are currently in it */ + if (is_time_to_act) + next_heartbeat_counter++; /* Try again in the next heartbeat */ + return; + } + assert(0 == syslog_deferred); + srand(time(NULL)); + addr_ptr = get_next_gdr(NULL); + if (NULL == addr_ptr) /* Ensure that there is a global directory to operate on. */ + return; + assert(NULL == get_next_gdr(addr_ptr)); + /* Randomly simulate ENOSPC or free space. NO more than 50 regions are allowed to avoid unnecessary + * malloc/frees in debug-only code + */ + assert(MAX_REGIONS >= addr_ptr->n_regions); + if (!IS_REPL_INST_FROZEN) + { /* We are in an UNFROZEN state, and about to be FROZEN due to ENOSPC */ + choose_random_reg_list(enospc_enable_list, addr_ptr->n_regions); + next_heartbeat_counter = heartbeat_counter + ENOSPC_FROZEN_DURATION; + } else + { /* We are in a FROZEN state, and about to be UNFROZEN due to free space */ + memset(enospc_enable_list, 0, MAX_REGIONS); + next_heartbeat_counter = heartbeat_counter + ENOSPC_UNFROZEN_DURATION; + if (!ok_to_interrupt) + syslog_deferred = heartbeat_counter; + } + set_enospc_flags(addr_ptr, enospc_enable_list, ok_to_interrupt); + } +} + +void set_enospc_flags(gd_addr *addr_ptr, char enospc_enable_list[], boolean_t ok_to_interrupt) +{ + gd_region *r_local, *r_top; + int i; + sgmnt_addrs *csa; + const char *syslog_msg; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + + for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions, i = 0; + r_local < r_top; r_local++, i++) + { + if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth)) + continue; + csa = REG2CSA(r_local); + if ((NULL != csa) && (NULL != csa->nl) && ANTICIPATORY_FREEZE_ENABLED(csa)) + { + switch(enospc_enable_list[i]) + { + case NONE: + syslog_msg = "Turning off fake ENOSPC for both database and journal file."; + csa->nl->fake_db_enospc = FALSE; + csa->nl->fake_jnl_enospc = FALSE; + break; + case DB_ON: + syslog_msg = "Turning on fake ENOSPC only for database file."; + csa->nl->fake_db_enospc = TRUE; + csa->nl->fake_jnl_enospc = FALSE; + break; + case JNL_ON: + syslog_msg = "Turning on fake ENOSPC only for journal file."; + csa->nl->fake_db_enospc = FALSE; + csa->nl->fake_jnl_enospc = TRUE; + break; + case DB_AND_JNL_ON: + syslog_msg = "Turning on fake ENOSPC for both database and journal file."; + csa->nl->fake_db_enospc = TRUE; + csa->nl->fake_jnl_enospc = TRUE; + break; + default: + assert(FALSE); + } + if (ok_to_interrupt) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2, + LEN_AND_STR(syslog_msg)); + } + } +} +#endif void heartbeat_timer(void) { gd_addr *addr_ptr; - gd_region *r_top, *r_save, *r_local; sgmnt_addrs *csa; jnl_private_control *jpc; + gd_region *r_local, *r_top; int rc; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; /* It will take heartbeat_counter about 1014 years to overflow. */ heartbeat_counter++; + DEBUG_ONLY(set_enospc_if_needed()); /* Check every 1 minute if we have an older generation journal file open. If so, close it. * The only exceptions are * a) The source server can have older generations open and they should not be closed. @@ -66,7 +212,7 @@ void heartbeat_timer(void) continue; if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth)) continue; - csa = &FILE_INFO(r_local)->s_addrs; + csa = REG2CSA(r_local); if (csa->now_crit) continue; jpc = csa->jnl; diff --git a/sr_unix/heartbeat_timer.h b/sr_unix/heartbeat_timer.h index 101b687..0b0be3c 100644 --- a/sr_unix/heartbeat_timer.h +++ b/sr_unix/heartbeat_timer.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,3 +38,12 @@ GBLREF boolean_t heartbeat_started; void heartbeat_timer(void); #endif + +#ifdef DEBUG +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" +void set_enospc_if_needed(void); +void choose_random_reg_list(char *enospc_enable_list, int); +void set_enospc_flags(gd_addr *addr_ptr, char enospc_enable_list[], boolean_t ok_to_interrupt); +#endif diff --git a/sr_unix/hpuxia64_badd.txt b/sr_unix/hpuxia64_badd.txt index 0646f48..29fecc1 100644 --- a/sr_unix/hpuxia64_badd.txt +++ b/sr_unix/hpuxia64_badd.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2012 Fidelity Information Services, Inc # +# Copyright 2012, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -11,8 +11,9 @@ # Do not add any blank lines after this comment pro: TTTGEN.m%-r--r----- README.txt +dse%-r--r----- custom_errors_sample.txt gdehelp.dat%-r--r----- gdedefaults -gtm_descript.h%-r-xr-x--- gtm +gtm_common_defs.h%-r-xr-x--- gtm gtmcshrc.gtc%-r-xr-x--- gtmbase gtmhelp.dat%-r-xr-x--- gtmcshrc gtmsecshr%-r-xr-x--- gtmprofile @@ -28,4 +29,10 @@ zzz_insert%-r--r----- source.tar pro/utf8: TTTGEN.m -> ../TTTGEN.m%lrwxr-xr-x README.txt -> ../README.txt +dse -> ../dse%lrwxr-xr-x custom_errors_sample.txt -> ../custom_errors_sample.txt +gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr +gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir lke -> ../lke%-r-xr-x--- libgtmutil.so + +pro/utf8/gtmsecshrdir: +zzz_insert%-r-s------ gtmsecshr diff --git a/sr_unix/hpuxparisc_badd.txt b/sr_unix/hpuxparisc_badd.txt index f28eac2..b9c9f69 100644 --- a/sr_unix/hpuxparisc_badd.txt +++ b/sr_unix/hpuxparisc_badd.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2011, 2012 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -11,8 +11,9 @@ # Do not add any blank lines after this comment pro: TTTGEN.m%-r--r----- README.txt +dse%-r--r----- custom_errors_sample.txt gdehelp.dat%-r--r----- gdedefaults -gtm_descript.h%-r-xr-x--- gtm +gtm_common_defs.h%-r-xr-x--- gtm gtmcshrc.gtc%-r-xr-x--- gtmbase gtmhelp.dat%-r-xr-x--- gtmcshrc gtmsecshr%-r-xr-x--- gtmprofile @@ -20,13 +21,12 @@ gtmsecshr%-r-xr-x--- gtmprofile_preV54000 lke%-r-xr-x--- libgtmutil.sl semstat2%dr-xr-x--- plugin -pro/plugin: -zzz_insert%dr-xr-x--- o -zzz_insert%dr-xr-x--- r - -pro/plugin/gtmcrypt: -zzz_insert%-r--r----- source.tar - pro/utf8: TTTGEN.m -> ../TTTGEN.m%lrwxr-xr-x README.txt -> ../README.txt +dse -> ../dse%lrwxr-xr-x custom_errors_sample.txt -> ../custom_errors_sample.txt +gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr +gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir lke -> ../lke%-r-xr-x--- libgtmutil.sl + +pro/utf8/gtmsecshrdir: +zzz_insert%-r-s------ gtmsecshr diff --git a/sr_unix/incr_link.c b/sr_unix/incr_link.c index 74613d3..8e4a75a 100644 --- a/sr_unix/incr_link.c +++ b/sr_unix/incr_link.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -113,14 +113,16 @@ bool incr_link (int file_desc, zro_ent *zro_entry) pre_v5_mident *pre_v5_routine_name; urx_rtnref urx_lcl_anchor; int order; + boolean_t dynlits; size_t offset_correction; unsigned char *shdr, *rel_base; mval *curlit, *littop; lab_tabent *curlbe, *lbetop; var_tabent *curvar, *vartop; char name_buf[PATH_MAX+1]; - int name_buf_len; + int name_buf_len, alloc_len; char marker[SIZEOF(JSB_MARKER) - 1]; + char *rw_rel_start; AIX_ONLY( FILHDR hddr; @@ -296,11 +298,13 @@ bool incr_link (int file_desc, zro_ent *zro_entry) * * Read-only releasable section */ + dynlits = DYNAMIC_LITERALS_ENABLED(hdr); + rw_rel_start = RW_REL_START_ADR(hdr); /* Marks end of R/O-release section and start of R/W-release section */ if (shlib) rel_base = shdr; else { - sect_ro_rel_size = (unsigned int)((INTPTR_T)hdr->literal_adr - (INTPTR_T)hdr->ptext_adr); + sect_ro_rel_size = (unsigned int)((INTPTR_T)rw_rel_start - (INTPTR_T)hdr->ptext_adr); sect_ro_rel = GTM_TEXT_ALLOC(sect_ro_rel_size); /* It should be aligned well at this point but make a debug level check to verify */ assert((INTPTR_T)sect_ro_rel == ((INTPTR_T)sect_ro_rel & ~(LINKAGE_PSECT_BOUNDARY - 1))); @@ -336,27 +340,32 @@ bool incr_link (int file_desc, zro_ent *zro_entry) RELOCATE(hdr->ptext_end_adr, unsigned char *, rel_base); RELOCATE(hdr->lnrtab_adr, lnr_tabent *, rel_base); RELOCATE(hdr->literal_text_adr, unsigned char *, rel_base); + if (dynlits) + RELOCATE(hdr->literal_adr, mval *, rel_base); /* Read-write releasable section */ - sect_rw_rel_size = (int)((INTPTR_T)hdr->labtab_adr - (INTPTR_T)hdr->literal_adr); + sect_rw_rel_size = (int)((INTPTR_T)hdr->labtab_adr - (INTPTR_T)rw_rel_start); sect_rw_rel = malloc(sect_rw_rel_size); if (shlib) - memcpy(sect_rw_rel, shdr + (INTPTR_T)hdr->literal_adr, sect_rw_rel_size); + memcpy(sect_rw_rel, shdr + (INTPTR_T)rw_rel_start, sect_rw_rel_size); else { DOREADRC_OBJFILE(file_desc, sect_rw_rel, sect_rw_rel_size, status); if (0 != status) zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } - offset_correction = (size_t)hdr->literal_adr; + offset_correction = (size_t)rw_rel_start; rel_base = sect_rw_rel - offset_correction; - RELOCATE(hdr->literal_adr, mval *, rel_base); + if (!dynlits) + RELOCATE(hdr->literal_adr, mval *, rel_base); RELOCATE(hdr->vartab_adr, var_tabent *, rel_base); /* Also read-write releasable is the linkage section which had no initial value and was thus * not resident in the object. The values in this section will be setup later by addr_fix() - * and/or auto-zlink. + * and/or auto-zlink. Note we always allocate at least one element here just so we don't get + * the potentially unaligned "null string" address provided by gtm_malloc() when a zero + * length is requested. */ - /* Allocate 1 extra, to align linkage_adr */ - hdr->linkage_adr = (lnk_tabent *)malloc((hdr->linkage_len * SIZEOF(lnk_tabent)) + SIZEOF(lnk_tabent)); + alloc_len = hdr->linkage_len * SIZEOF(lnk_tabent); + hdr->linkage_adr = (lnk_tabent *)malloc((0 != alloc_len) ? alloc_len : SIZEOF(lnk_tabent)); assert(PADLEN(hdr->linkage_adr, SIZEOF(lnk_tabent) == 0)); assert(((UINTPTR_T)hdr->linkage_adr % SIZEOF(lnk_tabent)) == 0); memset((char *)hdr->linkage_adr, 0, (hdr->linkage_len * SIZEOF(lnk_tabent))); @@ -364,9 +373,12 @@ bool incr_link (int file_desc, zro_ent *zro_entry) * variable table entries since they both point to the offsets from the beginning of the * literal text pool. The relocations for the linkage section is done in addr_fix() */ - for (curlit = hdr->literal_adr, littop = curlit + hdr->literal_len; curlit < littop; ++curlit) - if (curlit->str.len) - RELOCATE(curlit->str.addr, char *, hdr->literal_text_adr); + if (!dynlits) + { + for (curlit = hdr->literal_adr, littop = curlit + hdr->literal_len; curlit < littop; ++curlit) + if (curlit->str.len) + RELOCATE(curlit->str.addr, char *, hdr->literal_text_adr); + } for (curvar = hdr->vartab_adr, vartop = curvar + hdr->vartab_len; curvar < vartop; ++curvar) { assert(0 < curvar->var_name.len); @@ -464,6 +476,8 @@ bool incr_link (int file_desc, zro_ent *zro_entry) old_rhead->temp_size = hdr->temp_size; old_rhead->linkage_adr = hdr->linkage_adr; 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 = (rhdtyp *)old_rhead->old_rhead_adr; } /* Add local unresolves to global chain freeing elements that already existed in the global chain */ diff --git a/sr_unix/incr_link.h b/sr_unix/incr_link.h index a4aa0b4..1ad00b2 100644 --- a/sr_unix/incr_link.h +++ b/sr_unix/incr_link.h @@ -13,7 +13,7 @@ #define INCR_LINK_INCLUDED #ifdef USHBIN_SUPPORTED -#include "incr_link_sp.h" +#include bool incr_link(int file_desc, zro_ent *zro_entry); #else bool incr_link(int file_desc); diff --git a/sr_unix/init_gtm.c b/sr_unix/init_gtm.c index 8c0cf3c..7b1a824 100644 --- a/sr_unix/init_gtm.c +++ b/sr_unix/init_gtm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,8 +11,12 @@ #include "mdef.h" +#ifdef GTM_PTHREAD +# include +#endif #include "gtm_stdlib.h" #include "gtm_string.h" + #include "startup.h" #include #include "stack_frame.h" @@ -37,6 +41,7 @@ #include "gtm_malloc.h" #include "stp_parms.h" #include "create_fatal_error_zshow_dmp.h" +#include "mtables.h" GBLREF void (*ctrlc_handler_ptr)(); GBLREF void (*tp_timeout_action_ptr)(void); @@ -48,6 +53,11 @@ GBLREF void (*op_wteol_ptr)(int4 n); GBLREF void (*unw_prof_frame_ptr)(void); GBLREF mstr default_sysid; +#ifdef GTM_PTHREAD +GBLREF pthread_t gtm_main_thread_id; +GBLREF boolean_t gtm_main_thread_id_set; +GBLREF boolean_t gtm_jvm_process; +#endif GBLDEF boolean_t gtm_startup_active = FALSE; void init_gtm(void) @@ -80,8 +90,17 @@ void init_gtm(void) assert(SIZEOF(mval) == SIZEOF(mval_b)); assert(SIZEOF(chkmval.fnpc_indx) == SIZEOF(chkmval_b.fnpc_indx)); assert(OFFSETOF(mval, fnpc_indx) == OFFSETOF(mval_b, fnpc_indx)); + DEBUG_ONLY(mtables_chk()); /* Validate mtables.c assumptions */ SFPTR(create_fatal_error_zshow_dmp_fptr, create_fatal_error_zshow_dmp); +# ifdef GTM_PTHREAD + assert(!gtm_main_thread_id_set); + if (!gtm_main_thread_id_set && gtm_jvm_process) + { + gtm_main_thread_id = pthread_self(); + gtm_main_thread_id_set = TRUE; + } +# endif tp_timeout_start_timer_ptr = tp_start_timer; tp_timeout_clear_ptr = tp_clear_timeout; tp_timeout_action_ptr = tp_timeout_action; @@ -101,7 +120,6 @@ void init_gtm(void) svec.rtn_start = svec.rtn_end = malloc(SIZEOF(rtn_tabent)); memset(svec.rtn_start, 0, SIZEOF(rtn_tabent)); svec.user_stack_size = (272 ZOS_ONLY(+ 64))* 1024; /* ZOS stack frame 2x other platforms so give more stack */ - svec.user_indrcache_size = 32; svec.user_strpl_size = STP_INITSIZE_REQUESTED; svec.ctrlc_enable = 1; svec.break_message_mask = 31; diff --git a/sr_unix/install.sh b/sr_unix/install.sh index dc3b345..c9a12e2 100644 --- a/sr_unix/install.sh +++ b/sr_unix/install.sh @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2009, 2010 Fidelity Information Services, Inc # +# Copyright 2009, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -10,12 +10,20 @@ # # ################################################################# -# Install encryption plugin artifacts (libgtmcrypt.so and maskpass) from the build directory to GT.M distribution -# directory +if [ $# -lt 1 ]; then + echo "Usage: $0 ENCRYPTION_LIB [ALGORITHM]" + echo "ENCRYPTION_LIB is either gcrypt or openssl" + echo " gcrypt : Install encryption plugin built with libgcrypt (if one exists)" + echo " openssl: Install encryption plugin built with OpenSSL (if one exists)" + echo "ALGORITHM is either AES256CFB (default) or BLOWFISHCFB" + echo " AES256CFB : Install encryption plugin built with AES (CFB mode) with 256-bit encryption" + echo " BLOWFISHCFB : Install encryption plugin built with BLOWFISH (CFB mode) with 256-bit encryption" + exit 1 +fi # Since we are installing in the GT.M distribution directory, we better have $gtm_dist set and the plugin and plugin/gtmcrypt # subdirectories present for us to do a successful copy. -if [ ! $?gtm_dist ]; then +if [ "" = $gtm_dist ]; then echo "Environment variable - gtm_dist not defined." exit 1 fi @@ -30,44 +38,52 @@ if [ ! -d $gtm_dist/plugin/gtmcrypt ]; then exit 1 fi +encryption_lib=$1 +algorithm="AES256CFB" +if [ $# -eq 2 ]; then algorithm="$2" ; fi + platform_name=`uname -s` -from_path=`pwd` +cwd=`pwd` gtm_dist_plugin="$gtm_dist/plugin" -if [ "OS/390" = $platform_name ]; then - lib_name="libgtmcrypt.dll" -else - lib_name="libgtmcrypt.so" -fi +ext=".so" +if [ "OS/390" = $platform_name ]; then ext=".dll" ; fi + +base_libname="libgtmcrypt" +generic_libname=$base_libname$ext +specific_libname=${base_libname}_${encryption_lib}_${algorithm}${ext} echo "Installing M programs and shared libraries..." -if [ ! -f $from_path/$lib_name ]; then - echo "Shared library $lib_name not built. Please check errors from build.sh" +if [ ! -f $cwd/$specific_libname ]; then + echo "Shared library $specific_libname not built. Please check errors from build.sh" exit 1 fi -if [ ! -f $from_path/maskpass ]; then +if [ ! -f $cwd/maskpass ]; then echo "Helper executable maskpass not built. Please check errors from build.sh" exit 1 fi -# Create external call table needed by pinenty-gtm -cat > $gtm_dist_plugin/gpgagent.tab << tabfile -$gtm_dist_plugin/$lib_name -unmaskpwd: xc_status_t gc_pk_mask_unmask_passwd_interlude(I:xc_string_t*,O:xc_string_t*[512],I:xc_int_t) -tabfile - -# Move the shared libraries to $gtm_dist/plugin -\cp $from_path/$lib_name $gtm_dist_plugin/$lib_name - -if [ "$from_path" = "$gtm_dist_plugin"/gtmcrypt ] ; then - # The build is done from the distribution directory. No need to install" - echo "Installation Complete" - exit 0 +\rm -f $gtm_dist_plugin/$generic_libname # Remove existing artifacts +if [ $cwd != $gtm_dist_plugin/gtmcrypt ]; then + # Current directory is NOT a part of $gtm_dist/plugin. Just copy the shared libraries to $gtm_dist/plugin + \cp $base_libname*$ext $gtm_dist_plugin + \cp maskpass $gtm_dist_plugin/gtmcrypt/maskpass +else + # Current directory is $gtm_dist/plugin/gtmcrypt. Move the shared libraries to $gtm_dist/plugin to avoid duplicate copies + \mv $base_libname*$ext $gtm_dist_plugin fi -# Move maskpass to $gtm_dist/plugin/gtmcrypt -\cp $from_path/maskpass $gtm_dist_plugin/gtmcrypt/maskpass +\ln -s ./$specific_libname $gtm_dist_plugin/$generic_libname + +cat << EOF > $gtm_dist_plugin/gpgagent.tab +$gtm_dist_plugin/$generic_libname +unmaskpwd: xc_status_t gc_pk_mask_unmask_passwd_interlude(I:xc_string_t*,O:xc_string_t*[512],I:xc_int_t) +EOF + +cat << EOF > $gtm_dist_plugin/gtmcrypt/gtmcrypt.tab +getpass:char* getpass^GETPASS(I:gtm_int_t) +EOF echo "Installation Complete" exit 0 diff --git a/sr_unix/interlock.h b/sr_unix/interlock.h index 12ea2b7..3125629 100644 --- a/sr_unix/interlock.h +++ b/sr_unix/interlock.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -44,9 +44,6 @@ } /* On HPPA, SET_LATCH_GLOBAL forces its available value, for others it is the same as SET_LATCH */ -#define INTERLOCK_INIT_MM(X) (SET_LATCH((sm_int_ptr_t)&((X)->interlock.latch), LATCH_CLEAR)) - /* similar to INTERLOCK_INIT except this is for a mmblk_rec */ - /* New buffer doesn't need interlocked operation. */ #define LOCK_NEW_BUFF_FOR_UPDATE(X) (SET_LATCH((sm_int_ptr_t)&((X)->interlock.latch), LATCH_SET)) @@ -96,13 +93,13 @@ #define INCR_CNT(X,Y) INTERLOCK_ADD(X,Y,1) #define DECR_CNT(X,Y) INTERLOCK_ADD(X,Y,-1) -#ifndef __ia64 +#if !defined(__ia64) && !defined(__x86_64__) && !defined(__sparc) #define GET_SWAPLOCK(X) (COMPSWAP_LOCK((X), LOCK_AVAILABLE, 0, process_id, 0)) #else /* Doing the simple test before COMPSWAP_LOCK can help performance when a lock is highly contended */ #define GET_SWAPLOCK(X) (((X)->u.parts.latch_pid == LOCK_AVAILABLE) && COMPSWAP_LOCK((X), LOCK_AVAILABLE, 0, process_id, 0)) -#endif /* __ia64 */ +#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 diff --git a/sr_unix/io_open_try.c b/sr_unix/io_open_try.c index 20080e9..bbb3d40 100644 --- a/sr_unix/io_open_try.c +++ b/sr_unix/io_open_try.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,8 +16,10 @@ #include "gtm_unistd.h" #include "gtm_stat.h" #include "gtm_iconv.h" +#include "gtm_netdb.h" #include "gtm_socket.h" #include "gtm_inet.h" +#include "gtm_stdlib.h" #include #include @@ -59,6 +61,10 @@ GBLREF int4 outofband; GBLREF int4 write_filter; LITREF mstr chset_names[]; +error_def(ERR_GETNAMEINFO); +error_def(ERR_GTMEISDIR); +error_def(ERR_TEXT); + bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mval *mspace) /* timeout in seconds */ { uint4 status; @@ -88,15 +94,18 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva int fstat_res; int p_offset, len; - boolean_t mknod_err , stat_err; + boolean_t mknod_err , stat_err, dir_err; int save_mknod_err, save_stat_err; int sockstat, sockoptval; in_port_t sockport; GTM_SOCKLEN_TYPE socknamelen; - struct sockaddr_in sockname; + struct sockaddr_storage sockname; GTM_SOCKLEN_TYPE sockoptlen; boolean_t ichset_specified, ochset_specified; + int errcode; + unsigned int port_len; + char port_buffer[NI_MAXSERV], *port_ptr; mt_ptr = NULL; char_or_block_special = FALSE; @@ -105,6 +114,7 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva oflag = 0; mknod_err = FALSE; stat_err = FALSE; + dir_err = FALSE; tn.len = tl->len; if (tn.len > LOGNAME_LEN) tn.len = LOGNAME_LEN; @@ -239,8 +249,10 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva case S_IFIFO: tl->iod->type = ff; break; - case S_IFREG: case S_IFDIR: + dir_err = TRUE; /* directories should not be opened */ + /* no break in order to set iod->type value */ + case S_IFREG: tl->iod->type = rm; break; case S_IFSOCK: @@ -264,9 +276,19 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva sockstat = getsockname(file_des, (struct sockaddr *)&sockname, (GTM_SOCKLEN_TYPE *)&socknamelen); - if (!sockstat && AF_INET == sockname.sin_family) + if (!sockstat && ((AF_INET == ((sockaddr_ptr)&sockname)->sa_family) + || (AF_INET6 == ((sockaddr_ptr)&sockname)->sa_family))) { - sockport = ntohs(sockname.sin_port); + port_len = NI_MAXSERV; + if (0 != (errcode = getnameinfo((struct sockaddr *)&sockname, + socknamelen, NULL, 0, + port_buffer, port_len, + NI_NUMERICHOST))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } + sockport=atoi(port_buffer); if (RSHELL_PORT != sockport && KSHELL_PORT != sockport) { tl->iod->type = gtmsocket; @@ -369,10 +391,14 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva /* Check the saved error from mknod() for fifo, also saved error from fstat() or stat() so error handler (if set) can handle it */ if (ff == tl->iod->type && mknod_err) - rts_error(VARLSTCNT(1) save_mknod_err); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_mknod_err); /* Error from either stat() or fstat() function */ if (stat_err) - rts_error(VARLSTCNT(1) save_stat_err); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_stat_err); + /* Error from trying to open a dir */ + if (dir_err) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMEISDIR, 2, LEN_AND_STR(buf)); + if (timed) start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); @@ -483,15 +509,24 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva } #endif if (-1 == file_des) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (n_io_dev_types == naml->iod->type) { - if (isatty(file_des)) + /* On AIX, /dev/{,*}random are of 'terminal type'.Hence define its type before + * calling isatty() + */ + if ((0 == memvcmp(tn.addr, tn.len, LIT_AND_LEN("/dev/random"))) + || (0 == memvcmp(tn.addr, tn.len, LIT_AND_LEN("/dev/urandom")))) + tl->iod->type = rm; + else if (isatty(file_des)) naml->iod->type = tt; - else if (char_or_block_special && file_des > 2) - /* assume mag tape */ - naml->iod->type = mt; + else if (char_or_block_special && file_des > 2) + if (0 == memvcmp(tn.addr, tn.len, LIT_AND_LEN("/dev/zero"))) + tl->iod->type = rm; + else + /* assume mag tape */ + naml->iod->type = mt; else naml->iod->type = rm; } @@ -510,6 +545,8 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva naml->iod->dollar.y = 0; naml->iod->dollar.za = 0; naml->iod->dollar.zb[0] = 0; + naml->iod->dollar.key[0] = 0; + naml->iod->dollar.device[0] = 0; } #ifdef __MVS__ /* copy over the content of tl->iod(naml->iod) to (tl->iod->pair.out) */ @@ -545,8 +582,18 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva status = (naml->iod->disp_ptr->open)(naml, pp, file_des, mspace, timeout); if (TRUE == status) naml->iod->state = dev_open; - else if ((dev_open == naml->iod->state) && (gtmsocket != naml->iod->type)) - naml->iod->state = dev_closed; + else + { + if ((dev_open == naml->iod->state) && (gtmsocket != naml->iod->type)) + naml->iod->state = dev_closed; + if ((gtmsocket == naml->iod->type) && naml->iod->newly_created) + { + assert (naml->iod->state != dev_open); + iosocket_destroy(naml->iod); + active_device = 0; + return status; + } + } #ifdef __MVS__ d_rm_out = tl->iod->pair.out->dev_sp; d_rm_in = tl->iod->pair.in->dev_sp; diff --git a/sr_unix/iomt_ch.c b/sr_unix/iomt_ch.c index ab200d4..0d2e552 100644 --- a/sr_unix/iomt_ch.c +++ b/sr_unix/iomt_ch.c @@ -18,7 +18,7 @@ #include "iomtdef.h" #include "iosp.h" #include "io_params.h" -#include "gtm_mtio.h" +#include GBLREF io_pair io_curr_device; diff --git a/sr_unix/iomt_info.c b/sr_unix/iomt_info.c index 747af32..11b1217 100644 --- a/sr_unix/iomt_info.c +++ b/sr_unix/iomt_info.c @@ -21,7 +21,7 @@ #include "iosp.h" #include "error.h" /* ***************** -#include "gtm_mtio.h" +#include #include "gtm_stat.h" #include #include diff --git a/sr_unix/iomt_open.c b/sr_unix/iomt_open.c index f99bf3a..ee15b21 100644 --- a/sr_unix/iomt_open.c +++ b/sr_unix/iomt_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,17 +30,6 @@ #include "stringpool.h" #include "namelook.h" -static readonly nametabent mtlab_names[] = -{ - {3, "ANS"}, {4, "ANSI"}, {3, "DOS"}, {5, "DOS11"} -}; -static readonly unsigned char mtlab_index[27] = -{ - 0, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ,4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 - ,4, 4, 4 -}; - LITDEF unsigned char LIB_AB_ASC_EBC[256] = { 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, @@ -60,7 +49,6 @@ LITDEF unsigned char LIB_AB_ASC_EBC[256] = 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 255 }; - LITDEF unsigned char LIB_AB_EBC_ASC[256] = { 0, 1, 2, 3, 92, 9, 92, 127, 92, 92, 92, 11, 12, 13, 14, @@ -80,11 +68,34 @@ LITDEF unsigned char LIB_AB_EBC_ASC[256] = 92, 92, 92, 83, 84, 85, 86, 87, 88, 89, 90, 92, 92, 92, 92, 92, 92, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 92, 92, 92, 92, 92, 255 }; - LITREF unsigned char io_params_size[]; +static readonly nametabent mtlab_names[] = +{ + {3, "ANS"}, {4, "ANSI"}, {3, "DOS"}, {5, "DOS11"} +}; +static readonly unsigned char mtlab_index[27] = +{ + 0, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ,4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + ,4, 4, 4 +}; static readonly char mtlab_type[] = {MTLAB_ANSI, MTLAB_ANSI, MTLAB_DOS11, MTLAB_DOS11}; +error_def(ERR_DEVPARMNEG); +error_def(ERR_MTBLKTOOBIG); +error_def(ERR_MTBLKTOOSM); +error_def(ERR_MTFIXRECSZ); +error_def(ERR_MTRECGTRBLK); +error_def(ERR_MTRECTOOBIG); +error_def(ERR_MTRECTOOSM); +error_def(ERR_MTINVLAB); +error_def(ERR_MTDOSFOR); +error_def(ERR_MTANSIFOR); +error_def(ERR_MTIS); +error_def(ERR_MTIOERR); +error_def(ERR_VARRECBLKSZ); + #define VREC_HDR_LEN 4 short iomt_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) @@ -101,20 +112,6 @@ short iomt_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time char *tab; int p_offset; - error_def(ERR_MTRECTOOBIG); - error_def(ERR_MTRECGTRBLK); - error_def(ERR_MTBLKTOOBIG); - error_def(ERR_MTBLKTOOSM); - error_def(ERR_MTFIXRECSZ); - error_def(ERR_MTRECTOOSM); - error_def(ERR_VARRECBLKSZ); - error_def(ERR_MTINVLAB); - error_def(ERR_MTDOSFOR); - error_def(ERR_MTANSIFOR); - error_def(ERR_MTIS); - error_def(ERR_DEVPARMNEG); - error_def(ERR_MTIOERR); - #ifdef DP FPRINTF(stderr, ">> iomt_open(%d)\n", fd); #endif @@ -304,7 +301,7 @@ short iomt_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (newmt.block_sz / newmt.record_sz * newmt.record_sz != newmt.block_sz) { iomt_closesp(fd); - rts_error(VARLSTCNT(3) ERR_MTFIXRECSZ, newmt.block_sz, newmt.record_sz); + rts_error(VARLSTCNT(4) ERR_MTFIXRECSZ, 2, newmt.block_sz, newmt.record_sz); } } else { diff --git a/sr_unix/iomt_qio.c b/sr_unix/iomt_qio.c index 753f105..470cbc0 100644 --- a/sr_unix/iomt_qio.c +++ b/sr_unix/iomt_qio.c @@ -25,7 +25,7 @@ #include "iosp.h" #include "error.h" /********** -#include "gtm_mtio.h" +#include #include #include *********/ diff --git a/sr_unix/iomt_sense.c b/sr_unix/iomt_sense.c index 296bf2c..57d1269 100644 --- a/sr_unix/iomt_sense.c +++ b/sr_unix/iomt_sense.c @@ -19,7 +19,7 @@ #include "iottdef.h" #include "iomtdef.h" /* **************** -#include "gtm_mtio.h" +#include **************** */ uint4 diff --git a/sr_unix/iopi_iocontrol.c b/sr_unix/iopi_iocontrol.c index 1524169..a587e50 100644 --- a/sr_unix/iopi_iocontrol.c +++ b/sr_unix/iopi_iocontrol.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2008, 2009 Fidelity Information Services, Inc * + * Copyright 2008, 2013 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" GBLREF io_pair io_curr_device; +error_def(ERR_INVCTLMNE); void iopi_iocontrol(mstr *d) { @@ -35,24 +36,35 @@ void iopi_iocontrol(mstr *d) d_rm_struct *d_rm; int rc; - error_def(ERR_INVCTLMNE); - d_rm = (d_rm_struct *) io_curr_device.out->dev_sp; - if (!d_rm->pipe && !d_rm->fifo) + /* WRITE /EOF only applies to PIPE devices. Sequential file and FIFO devices should be closed with CLOSE.*/ + if (!d_rm->pipe) return; + /* we should not get here unless there is some string length after write / */ + assert((int)d->len); if (0 == d->len) return; lower_to_upper((uchar_ptr_t)&action[0], (uchar_ptr_t)d->addr, MIN(d->len, SIZEOF(action))); if (0 == memcmp(&action[0], "EOF", MIN(d->len, SIZEOF(action)))) { /* Implement the write /EOF action. Close the output stream to force any blocked output to complete. - * Doing a write /EOF closes the output file descriptor for the current device but does not close the - * device (for a pipe this forces any blocked io to be complete). Since the M program could attempt - * this command more than once, check if the file is not already closed before the actual close. + * Doing a write /EOF closes the output file descriptor for the pipe device but does not close the + * device. Since the M program could attempt this command more than once, check if the file descriptor + * is already closed before the actual close. + * Ignore the /EOF action if the device is read-only as this is a nop */ + if (d_rm->noread) + return; if (FD_INVALID != d_rm->fildes) + { + /* The output will be flushed via iorm_flush() like in iorm_close.c. After this call returns, + * $X will be zero which will keep iorm_readfl() from attempting an iorm_wteol() in the fix mode + * after the file descriptor has been closed. + */ + iorm_flush(io_curr_device.in); CLOSEFILE_RESET(d_rm->fildes, rc); /* resets "d_rm->fildes" to FD_INVALID */ + } } else - rts_error(VARLSTCNT(1) ERR_INVCTLMNE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE); return; } @@ -60,15 +72,13 @@ void iopi_dlr_device(mstr *d) { io_desc *iod; int len; - d_rm_struct *d_rm; /* We will default to the output device for setting $device, since pipe uses both */ iod = io_curr_device.out; - d_rm = (d_rm_struct *)iod->dev_sp; - len = STRLEN(d_rm->dollar_device); + len = STRLEN(iod->dollar.device); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); - memcpy(d->addr, d_rm->dollar_device, MIN(len,d->len)); + memcpy(d->addr, iod->dollar.device, MIN(len,d->len)); d->len = len; return; } @@ -77,16 +87,14 @@ void iopi_dlr_key(mstr *d) { io_desc *iod; int len; - d_rm_struct *d_rm; iod = io_curr_device.out; - d_rm = (d_rm_struct *)iod->dev_sp; - len = STRLEN(d_rm->dollar_key); + len = STRLEN(iod->dollar.key); /* verify internal buffer has enough space for $KEY string value */ assert((int)d->len > len); if (len > 0) - memcpy(d->addr, d_rm->dollar_key, MIN(len,d->len)); + memcpy(d->addr, iod->dollar.key, MIN(len,d->len)); d->len = len; return; } diff --git a/sr_unix/iopi_open.c b/sr_unix/iopi_open.c index 0f4b1f8..8f47bfc 100644 --- a/sr_unix/iopi_open.c +++ b/sr_unix/iopi_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2008, 2012 Fidelity Information Services, Inc * + * Copyright 2008, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -8,7 +8,9 @@ * the license, please stop and do not read further. * * * ****************************************************************/ -#define _REENTRANT +#ifndef _REENTRANT +# define _REENTRANT +#endif #include "mdef.h" @@ -30,6 +32,8 @@ #include "gtmio.h" #include "iosp.h" #include "jobsp.h" +#include "have_crit.h" +#include "fork_init.h" #ifdef __MVS__ #include "gtm_zos_io.h" #include "gtm_zos_chset.h" @@ -97,7 +101,7 @@ int parse_pipe(char *cmd_string, char *ret_token); */ int parse_pipe(char *cmd_string, char *ret_token) { - char *str1, *str2, *str3, *token; + char *str1, *str2, *str3; char *saveptr1, *saveptr2, *saveptr3; char *env_var; int env_inc; @@ -348,10 +352,10 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { PIPE_ERROR_INIT(); if (0 == sparams[PCOMMAND]) - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Missing command string")); else - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Command string has no value")); } else { @@ -364,7 +368,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { PIPE_ERROR_INIT(); SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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)); } } @@ -375,7 +379,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (sparams[PSHELL] && (0 == slen[PSHELL])) { PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("SHELL parameter has no value")); } else if (0 != slen[PSHELL]) { @@ -390,7 +394,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time assert(GTM_MAX_DIR_LEN - 1 >= STRLEN(pshell)); SPRINTF(error_str, "Invalid shell: %s", pshell); PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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)); } pshell_name = basename(pshell); @@ -401,7 +405,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (sparams[PSTDERR] && (0 == slen[PSTDERR])) { PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("STDERR parameter has no value")); } else if (0 != slen[PSTDERR]) { @@ -416,7 +420,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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 - pipe(pfd_write) failed"), save_errno); } else { @@ -431,11 +435,12 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time /* child to write stdout (and possibly stderr) to pfd_read[1] and parent to read from pfd_read[0] */ if (return_stdout) + { if (-1 == pipe(pfd_read)) { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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 - pipe(pfd_read) failed"), save_errno); } else { @@ -446,14 +451,16 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time #endif file_des_read = pfd_read[0]; } + } /* child to write to pfd_read_stderr[1] and parent to read from pfd_read_stderr[0] */ if (return_stderr) + { if (-1 == pipe(pfd_read_stderr)) { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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 - pipe(pfd_read_stderr) failed"), save_errno); } else { @@ -465,15 +472,15 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time #endif file_des_read_stderr = pfd_read_stderr[0]; } - + } file_des_write = pfd_write[1]; /*do the fork and exec */ - cpid = fork(); /* BYPASSOK: we exec() immediately, no FORK_CLEAN needed */ + FORK(cpid); /* BYPASSOK: we exec() immediately, no FORK_CLEAN needed */ if (-1 == cpid) { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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 - fork() failed"), save_errno); /* BYPASSOK */ } if (0 == cpid) @@ -508,7 +515,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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); } if (return_stdout) @@ -519,7 +526,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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); } /* stderr also becomes pfd_read[1] if return_stderr is false*/ @@ -530,8 +537,9 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(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); + 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],2) failed in child"), save_errno); } } } @@ -542,8 +550,10 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(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); + 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_stderr[1],2) failed in child"), + save_errno); } } if (0 == slen[PSHELL]) @@ -562,7 +572,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + 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); } } else @@ -593,17 +603,18 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time /* save read file descriptor for stdout return if set */ if (file_des_read) { - if (NULL == (d_rm->read_filstr = FDOPEN(file_des_read, "r"))) + FDOPEN(d_rm->read_filstr, file_des_read, "r"); + if (NULL == d_rm->read_filstr) { save_errno = errno; PIPE_ERROR_INIT(); - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Error in stream open"), save_errno); } d_rm->read_fildes = file_des_read; } - SPRINTF(&d_rm->dollar_key[0], "%d", cpid); /* save in pipe specific structure for $KEY access */ - memcpy(d_rm->dollar_device, "0", SIZEOF("0")); + SPRINTF(&iod->dollar.key[0], "%d", cpid); /* save in pipe specific structure for $KEY access */ + memcpy(iod->dollar.device, "0", SIZEOF("0")); iod->state = dev_closed; d_rm->stream = FALSE; iod->width = DEF_RM_WIDTH; @@ -672,7 +683,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time io_ptr->dev_sp = (void*)malloc(SIZEOF(d_rm_struct)); memset(io_ptr->dev_sp, 0, SIZEOF(d_rm_struct)); in_d_rm = (d_rm_struct *) io_ptr->dev_sp; - memcpy(in_d_rm->dollar_device, "0", SIZEOF("0")); + memcpy(io_ptr->dollar.device, "0", SIZEOF("0")); io_ptr->state = dev_closed; in_d_rm->stream = d_rm->stream; io_ptr->width = iod->width; @@ -682,6 +693,8 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time io_ptr->dollar.y = 0; io_ptr->dollar.za = 0; io_ptr->dollar.zb[0] = 0; + io_ptr->dollar.key[0] = 0; + io_ptr->dollar.device[0] = 0; io_ptr->disp_ptr = iod->disp_ptr; in_d_rm->fixed = d_rm->fixed; in_d_rm->noread = TRUE; @@ -689,6 +702,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time in_d_rm->inbuf = d_rm->inbuf; in_d_rm->outbuf = d_rm->outbuf; in_d_rm->stderr_parent = iod; + in_d_rm->read_fildes = FD_INVALID; /* checked in iorm_get_bom to get correct file descriptor */ } in_d_rm->pipe = TRUE; io_ptr->type = rm; @@ -703,9 +717,9 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time flags = 0; FCNTL2(file_des_write, F_GETFL, flags); if (0 > flags) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); FCNTL3(file_des_write, F_SETFL, (flags | O_NONBLOCK), fcntl_res); if (0 > fcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); return iorm_open(dev_name, pp, file_des_write, mspace, timeout); } diff --git a/sr_unix/iorm_close.c b/sr_unix/iorm_close.c index bb5950b..94dcfcd 100644 --- a/sr_unix/iorm_close.c +++ b/sr_unix/iorm_close.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ GBLREF io_pair io_curr_device; GBLREF io_pair io_std_device; GBLREF boolean_t gtm_pipe_child; + error_def(ERR_CLOSEFAIL); LITREF unsigned char io_params_size[]; @@ -52,10 +53,15 @@ void iorm_close(io_desc *iod, mval *pp) unsigned int *dollary_ptr; char *savepath2 = 0; int path2len; + boolean_t rm_destroy = TRUE; + boolean_t rm_rundown = FALSE; assert (iod->type == rm); if (iod->state != dev_open) - return; + { + remove_rms(iod); + return; + } rm_ptr = (d_rm_struct *)iod->dev_sp; @@ -85,23 +91,23 @@ void iorm_close(io_desc *iod, mval *pp) path = iod->trans_name->dollar_io; FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res); if (-1 == fstat_res) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); STAT_FILE(path, &statbuf, stat_res); if (-1 == stat_res) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino) if (UNLINK(path) == -1) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); break; case iop_rename: path = iod->trans_name->dollar_io; path2 = (char*)(pp->str.addr + p_offset + 1); FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res); if (-1 == fstat_res) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); STAT_FILE(path, &statbuf, stat_res); if (-1 == stat_res) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino) { /* make a copy of path2 so we can null terminate it */ @@ -115,11 +121,20 @@ void iorm_close(io_desc *iod, mval *pp) assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); if (LINK(path, savepath2) == -1) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if (UNLINK(path) == -1) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); } break; + case iop_destroy: + rm_destroy = TRUE; + break; + case iop_nodestroy: + rm_destroy = FALSE; + break; + case iop_rundown: + rm_rundown = TRUE; + break; default: break; } @@ -148,12 +163,12 @@ void iorm_close(io_desc *iod, mval *pp) rm_ptr->outbuf = NULL; } - /* Do the close first. If the fclose() is done first and we are being called from io_rundown just prior to the execv - in a newly JOBbed off process, the fclose() does an implied fflush() which is known to do an lseek() which resets - the file pointers of any open (flat) files in the parent due to an archane interaction between child and parent - processes prior to an execv() call. The fclose (for stream files) will fail but it will clean up structures orphaned - by the CLOSEFILE_RESET. - */ + /* Do the close first. If the fclose is done first and we are being called from io_rundown just prior to the execv + * in a newly JOBbed off process, the fclose does an implied FFLUSH which is known to do an lseek which resets + * the file pointers of any open (flat) files in the parent due to an archane interaction between child and parent + * processes prior to an execv call. The fclose (for stream files) will fail but it will clean up structures orphaned + * by the CLOSEFILE_RESET. + */ /* Close the fildes unless this is a direct close of the stderr device */ if (!rm_ptr->stderr_parent) { @@ -166,7 +181,7 @@ void iorm_close(io_desc *iod, mval *pp) save_fd = rm_ptr->fildes; CLOSEFILE_RESET(rm_ptr->fildes, rc); /* resets "rm_ptr->fildes" to FD_INVALID */ if (0 != rc) - rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc); } if (rm_ptr->filstr != NULL) { @@ -179,7 +194,7 @@ void iorm_close(io_desc *iod, mval *pp) save_fd = rm_ptr->read_fildes; CLOSEFILE_RESET(rm_ptr->read_fildes, rc); /* resets "rm_ptr->read_fildes" to FD_INVALID */ if (0 != rc) - rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc); } if (rm_ptr->read_filstr != NULL) { @@ -216,8 +231,9 @@ void iorm_close(io_desc *iod, mval *pp) stderr_rm_ptr = (d_rm_struct *)rm_ptr->stderr_child->dev_sp; stderr_rm_ptr->stderr_parent = 0; iorm_close(rm_ptr->stderr_child,pp); - remove_rms(rm_ptr->stderr_child); } } + if ((rm_destroy || rm_ptr->pipe) && !rm_rundown) + remove_rms (iod); return; } diff --git a/sr_unix/iorm_get.c b/sr_unix/iorm_get.c index 75338d7..e874061 100644 --- a/sr_unix/iorm_get.c +++ b/sr_unix/iorm_get.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -71,7 +71,7 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in if (CHSET_UTF16LE == *chset) { iod->dollar.za = 9; - rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr, chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr); } @@ -82,7 +82,7 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in if (CHSET_UTF16BE == *chset) { iod->dollar.za = 9; - rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr, chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr); } @@ -103,6 +103,314 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in /* When we get to this routine it is guaranteed that rm_ptr->done_1st_read is FALSE. */ +int iorm_get_bom_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t *bom_timeout) +{ + int4 bytes2read, bytes_read, reclen, bom_bytes2read, bom_bytes_read; + int status = 0; + gtm_chset_t chset; + d_rm_struct *rm_ptr; + int fildes; + int4 sleep_left; + int4 sleep_time; + + rm_ptr = (d_rm_struct *)(io_ptr->dev_sp); + fildes = rm_ptr->fildes; + + chset = io_ptr->ichset; + assert(UTF16BE_BOM_LEN == UTF16LE_BOM_LEN); + bom_bytes2read = (int4)((CHSET_UTF8 == chset) ? UTF8_BOM_LEN : UTF16BE_BOM_LEN); + PIPE_DEBUG(PRINTF("enter iorm_get_bom_fl: bom_buf_cnt: %d bom_bytes2read: %d bom_read_one_done: %d chset: %d\n", + rm_ptr->bom_buf_cnt,bom_bytes2read,rm_ptr->bom_read_one_done,chset); DEBUGPIPEFLUSH;); + /* rms-file device in follow mode */ + if (timed) + { + /* check iorm_get_bom_fol.... for msc_timeout */ + if (0 < *msec_timeout) + { + sleep_left = *msec_timeout; + } else + sleep_left = 0; + } + /* if zeof is set in follow mode then ignore any previous zeof */ + if (TRUE == io_ptr->dollar.zeof) + io_ptr->dollar.zeof = FALSE; + do + { + status = read(fildes, &rm_ptr->bom_buf[rm_ptr->bom_buf_cnt], bom_bytes2read - rm_ptr->bom_buf_cnt); + if (0 < status) /* we read some chars */ + { + rm_ptr->bom_buf_cnt += status; + } else if (0 == status) /* end of file */ + { + if ((TRUE == timed) && (0 >= sleep_left)) + { + *bom_timeout = TRUE; + *tot_bytes_read = rm_ptr->bom_buf_cnt; + break; + } + /* if a timed read, sleep the minimum of 100 ms and sleep_left. + If not a timed read then just sleep 100 ms */ + if (TRUE == timed) + sleep_time = MIN(100,sleep_left); + else + sleep_time = 100; + SHORT_SLEEP(sleep_time); + if (TRUE == timed) + sleep_left -= sleep_time; + if (outofband) + { + return 0; + } + continue; /* for now try and read again if eof or no input ready */ + } else /* error returned */ + { + if (errno != EINTR) + break; + } + } while (rm_ptr->bom_buf_cnt < bom_bytes2read); + PIPE_DEBUG(PRINTF("iorm_get_bom_fl: status: %d, bom_buf_cnt: %d\n", status,rm_ptr->bom_buf_cnt); DEBUGPIPEFLUSH;); + if (rm_ptr->bom_buf_cnt >= bom_bytes2read) + { + PIPE_DEBUG(PRINTF("iorm_get_bom_fl do bomcheck: bom_buf_cnt: %d bom_buf: %o\n", + rm_ptr->bom_buf_cnt,rm_ptr->bom_buf[0]); DEBUGPIPEFLUSH;); + rm_ptr->bom_buf_off = gtm_utf_bomcheck(io_ptr, &io_ptr->ichset, rm_ptr->bom_buf, rm_ptr->bom_buf_cnt); + rm_ptr->file_pos += rm_ptr->bom_buf_off; /* If there is BOM bytes increment file position by bom_buf_off */ + } + else if (CHSET_UTF16 == chset) /* if UTF16 default to UTF16BE */ + io_ptr->ichset = CHSET_UTF16BE; + if (chset != io_ptr->ichset) + { /* UTF16 changed to UTF16BE or UTF16LE */ + chset = io_ptr->ichset; + get_chset_desc(&chset_names[chset]); + } + /* if outofband is not set then we are done getting the bom */ + if (!outofband) + rm_ptr->done_1st_read = TRUE; + return 0; +} + +/* If we are in this routine then it is a fixed utf disk read with rm_ptr->follow = TRUE */ + +int iorm_get_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, + boolean_t zint_restart, boolean_t *follow_timeout) +{ + boolean_t ret; + char inchar, *temp; + unsigned char *pad_ptr, *nextmb, padchar, padcharray[2]; + int fcntl_res, save_errno; + int4 bytes2read, bytes_read, char_bytes_read, add_bytes, reclen, bytes_already_read, tmp_bytes_read; + wint_t utf_code; + d_rm_struct *rm_ptr; + int4 status, from_bom; + gtm_chset_t chset; + int fildes; + int bytes_count = 0; + int4 sleep_left; + int4 sleep_time; + boolean_t bom_timeout = FALSE; + + assert (io_ptr->state == dev_open); + rm_ptr = (d_rm_struct *)(io_ptr->dev_sp); + fildes = rm_ptr->fildes; + assert(gtm_utf8_mode ? (IS_UTF_CHSET(io_ptr->ichset)) : FALSE); + assert(rm_ptr->fixed); + if (!zint_restart) + { + bytes2read = rm_ptr->recordsize; + bytes_already_read = 0; + rm_ptr->inbuf_pos = rm_ptr->inbuf_top = rm_ptr->inbuf_off = rm_ptr->inbuf; + } + else + { + bytes_already_read = rm_ptr->inbuf_top - rm_ptr->inbuf; + bytes2read = rm_ptr->recordsize - bytes_already_read; + /* skip past if bom already read */ + if (rm_ptr->done_1st_read) + rm_ptr->inbuf_pos = rm_ptr->inbuf_top; + else + rm_ptr->inbuf_pos = rm_ptr->inbuf_off = rm_ptr->inbuf; + } + PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read: %d, zint_restart: %d\n", bytes2read,zint_restart); DEBUGPIPEFLUSH;); + bytes_read = 0; + assert(rm_ptr->bufsize >= rm_ptr->recordsize); + errno = status = 0; + /* don't reset this if continuing from an interrupt unless we haven't read the bom yet */ +/* if (!rm_ptr->done_1st_read || FALSE == zint_restart) + rm_ptr->inbuf_pos = rm_ptr->inbuf_off = rm_ptr->inbuf;*/ + chset = io_ptr->ichset; + if (!rm_ptr->done_1st_read) + { + PIPE_DEBUG(PRINTF("do iorm_get_bom_fol: bytes2read: %d\n", bytes2read); DEBUGPIPEFLUSH;) + status = iorm_get_bom_fol(io_ptr, tot_bytes_read, msec_timeout, timed, &bom_timeout); + if (!rm_ptr->done_1st_read && outofband) + { + PIPE_DEBUG(PRINTF("return since iorm_get_bom_fol went outofband\n"); DEBUGPIPEFLUSH;); + return 0; + } + if (TRUE == bom_timeout) + *follow_timeout = TRUE; + chset = io_ptr->ichset; /* UTF16 will have changed to UTF16BE or UTF16LE */ + } + assert(CHSET_UTF16 != chset); + PIPE_DEBUG(PRINTF("iorm_get_fol: bom_buf_cnt: %d bom_buf_off: %d\n",rm_ptr->bom_buf_cnt,rm_ptr->bom_buf_off ); + DEBUGPIPEFLUSH;); + if (0 <= status && rm_ptr->bom_buf_cnt > rm_ptr->bom_buf_off) + { + PIPE_DEBUG(PRINTF("move bom: status: %d\n", status); DEBUGPIPEFLUSH;); + from_bom = MIN((rm_ptr->bom_buf_cnt - rm_ptr->bom_buf_off), bytes2read); + memcpy(rm_ptr->inbuf, &rm_ptr->bom_buf[rm_ptr->bom_buf_off], from_bom); + rm_ptr->bom_buf_off += from_bom; + bytes2read -= from_bom; /* now in buffer */ + rm_ptr->inbuf_pos += from_bom; + bytes_read = from_bom; + rm_ptr->file_pos += from_bom; + status = 0; + } + /* if outofband then we didn't finish so return 0 */ + if (outofband) + { + PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read: %d bytes_already_read: %d, zint_restart: %d\n", + bytes2read,bytes_already_read,zint_restart); DEBUGPIPEFLUSH;); + return 0; + } + if (0 <= status && 0 < bytes2read) + { + PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read after bom: %d\n", bytes2read); DEBUGPIPEFLUSH;); + if (timed) + { + if (0 < *msec_timeout) + { + sleep_left = *msec_timeout; + } else + sleep_left = 0; + } + /* if zeof is set in follow mode then ignore any previous zeof */ + if (TRUE == io_ptr->dollar.zeof) + io_ptr->dollar.zeof = FALSE; + temp = (char *)rm_ptr->inbuf_pos; + do + { + status = read(fildes, temp, (int)bytes2read - bytes_count); + if (0 < status) /* we read some chars */ + { + tot_bytes_read += status; + bytes_count += status; + temp = temp + status; + } else if (0 == status) /* end of file */ + { + if ((TRUE == timed) && (0 >= sleep_left)) + { + /* need to set tot_bytes_read and status for timeout */ + *follow_timeout = TRUE; + break; + } + /* if a timed read, sleep the minimum of 100 ms and sleep_left. + If not a timed read then just sleep 100 ms */ + if (TRUE == timed) + sleep_time = MIN(100,sleep_left); + else + sleep_time = 100; + SHORT_SLEEP(sleep_time); + if (TRUE == timed) + sleep_left -= sleep_time; + if (outofband) + break; + continue; /* for now try and read again if eof or no input ready */ + } else /* error returned */ + { + break; + } + } while (bytes_count < bytes2read); + status = bytes_count; + } + /* if outofband then we didn't finish so just adjust inbuf_top and inbuf_pos and return 0 */ + if (outofband) + { + PIPE_DEBUG(PRINTF("iorm_get_fol: outofband: bytes2read: %d status: %d tot_bytes_read: %d\n", + bytes2read, status, *tot_bytes_read); DEBUGPIPEFLUSH;); + if (0 > status) + { + rm_ptr->inbuf_top = rm_ptr->inbuf_pos += *tot_bytes_read; + return(0); + } + else + { + rm_ptr->inbuf_top = rm_ptr->inbuf_pos += status; + if ((rm_ptr->inbuf_pos - rm_ptr->inbuf_off) < rm_ptr->recordsize) + return(0); + } + } + /* if some bytes were read prior to timeout then process them as if no timeout occurred */ + if (0 > status && *tot_bytes_read && ((FALSE == timed) || (TRUE == *follow_timeout))) + status = *tot_bytes_read; + if (0 > status) + { + bytes_read = 0; + if (TRUE == *follow_timeout) + status = -2; + } else if (bytes_read || status) + { + bytes_read += status; + rm_ptr->file_pos += status; + padchar = rm_ptr->padchar; + if ((CHSET_UTF16LE == chset) || (CHSET_UTF16BE == chset)) + { /* strip 2-byte PADCHAR in UTF-16LE or UTF-16BE from tail of line */ + /* It's possible that only one byte is read if this is an interrupt restart one byte from the width + * In that case it's not an error if already_read is non-zero, but we have to adjust bytes_read differently. + */ + PIPE_DEBUG(PRINTF("pipeget: bytes_read: %d bytes_already_read: %d, zint_restart: %d\n", + bytes_read,bytes_already_read,zint_restart); DEBUGPIPEFLUSH;); + if (zint_restart && bytes_already_read) + { + tmp_bytes_read = bytes_read + bytes_already_read; + } else + { + tmp_bytes_read = bytes_read; + } + assert(tmp_bytes_read >= 2); + if (CHSET_UTF16LE == chset) + { + padcharray[0] = padchar; + padcharray[1] = '\0'; + } else + { + padcharray[0] = '\0'; + padcharray[1] = padchar; + } + for (pad_ptr = rm_ptr->inbuf + tmp_bytes_read - 2; + 0 < tmp_bytes_read && rm_ptr->inbuf <= pad_ptr; pad_ptr-=2) + { + PIPE_DEBUG(PRINTF("pad 16 loop: bytes_read: %d pad_ptr: %sx\n", + bytes_read,pad_ptr); DEBUGPIPEFLUSH;); + if ((padcharray[0] == pad_ptr[0]) && (padcharray[1] == pad_ptr[1])) + tmp_bytes_read -= 2; + else + break; + } + bytes_read = tmp_bytes_read; + } else + { /* strip 1-byte PADCHAR in UTF-8 from tail of line */ + if (zint_restart && bytes_already_read) + bytes_read = bytes_read + bytes_already_read; + assert(CHSET_UTF8 == chset); + for (pad_ptr = rm_ptr->inbuf + bytes_read - 1; 0 < bytes_read && rm_ptr->inbuf <= pad_ptr; pad_ptr--) + { + PIPE_DEBUG(PRINTF("pad 8 loop: bytes_read: %d pad_ptr: %sx\n", + bytes_read,pad_ptr); DEBUGPIPEFLUSH;); + if (*pad_ptr == padchar) + bytes_read--; + else + break; + } + } + } + rm_ptr->inbuf_top = rm_ptr->inbuf_pos = rm_ptr->inbuf + bytes_read; + rm_ptr->inbuf_off = rm_ptr->inbuf; + return (0 <= status ? bytes_read : status); +} + +/* When we get to this routine it is guaranteed that rm_ptr->done_1st_read is FALSE. */ + int iorm_get_bom(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read, TID timer_id, int4 *msec_timeout, boolean_t pipe_zero_timeout) { @@ -329,7 +637,7 @@ int iorm_get(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 bytes_read = 0; if (errno == EINTR && out_of_time) status = -2; - } else + } else if (bytes_read || status) { bytes_read += status; rm_ptr->file_pos += status; diff --git a/sr_unix/iorm_open.c b/sr_unix/iorm_open.c index 810c8bc..d6821c0 100644 --- a/sr_unix/iorm_open.c +++ b/sr_unix/iorm_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,7 @@ #include "iormdef.h" #include "io_params.h" #include "eintr_wrappers.h" +#include "have_crit.h" #ifdef __MVS__ #include "gtm_zos_io.h" #include "gtm_zos_chset.h" @@ -85,6 +86,7 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time d_rm->padchar = DEF_RM_PADCHAR; d_rm->inbuf = NULL; d_rm->outbuf = NULL; + d_rm->follow = FALSE; } else d_rm = (d_rm_struct *)iod->dev_sp; if (dev_closed == iod->state) @@ -94,19 +96,21 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time d_rm->crlast = FALSE; d_rm->done_1st_read = FALSE; d_rm->done_1st_write = FALSE; + d_rm->follow = FALSE; assert(0 <= fd); d_rm->fildes = fd; FSTAT_FILE(fd, &statbuf, fstat_res); if (-1 == fstat_res) - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, - LEN_AND_LIT("Error in fstat"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, + dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Error in fstat"), errno); for (p_offset = 0; iop_eol != *(pp->str.addr + p_offset); ) { if (iop_append == (ch = *(pp->str.addr + p_offset++))) { if (!d_rm->fifo && !d_rm->pipe && (off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_END))) - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, - ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to end of file"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, + dev_name->dollar_io, + ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to end of file"), errno); if (0 < statbuf.st_size) { /* Only disable BOM writing if there is something in the file already (not empty) */ d_rm->done_1st_read = FALSE; @@ -121,7 +125,7 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (!d_rm->fifo && !d_rm->pipe && fd != 0) { if ((off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_CUR))) - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to the current position"), errno); if (size == statbuf.st_size) iod->dollar.zeof = TRUE; @@ -132,9 +136,18 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time } if (1 == fd) d_rm->filstr = NULL; - else if (NULL == (d_rm->filstr = FDOPEN(fd, "r")) && NULL == (d_rm->filstr = FDOPEN(fd, "w"))) - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, - ERR_TEXT, 2, LEN_AND_LIT("Error in stream open"), errno); + else + { + FDOPEN(d_rm->filstr, fd, "r"); + if (NULL == d_rm->filstr) + { + FDOPEN(d_rm->filstr, fd, "w"); + if (NULL == d_rm->filstr) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, + dev_name->dollar_io, ERR_TEXT, 2, + LEN_AND_LIT("Error in stream open"), errno); + } + } } recsize_before = d_rm->recordsize; def_recsize_before = d_rm->def_recsize; @@ -152,8 +165,8 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time #ifdef __MVS__ /* need to get file tag info before set policy which can change what is returned */ if (-1 == gtm_zos_check_tag(fd, &file_tag, &text_tag)) - rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2, - LEN_AND_LIT("Error in check_tag fstat"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, + 2, LEN_AND_LIT("Error in check_tag fstat"), errno); SET_CHSET_FROM_TAG(file_tag, iod->file_chset); iod->text_flag = text_tag; if (!d_rm->pipe && 2 < fd) @@ -172,8 +185,9 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (-1 == gtm_zos_set_tag(fd, file_tag, text_tag, TAG_FORCE, &realfiletag)) { errmsg = STRERROR(errno); - rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag, - file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, + dev_name->dollar_io, realfiletag, file_tag, ERR_TEXT, 2, + RTS_ERROR_STRING(errmsg)); } if (gtm_utf8_mode && gtm_tag_utf8_as_ascii && (CHSET_UTF8 == iod->ochset)) iod->process_chset = iod->ochset; @@ -192,8 +206,8 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time if (-1 == (obtained_tag = gtm_zos_tag_to_policy(fd, file_tag, &realfiletag))) { errmsg = STRERROR(errno); - rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag, - file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, + realfiletag, file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } SET_CHSET_FROM_TAG(obtained_tag, iod->process_chset); } diff --git a/sr_unix/iorm_readfl.c b/sr_unix/iorm_readfl.c index 365f1f2..a5506a2 100644 --- a/sr_unix/iorm_readfl.c +++ b/sr_unix/iorm_readfl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -92,14 +92,14 @@ void iorm_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned cha { /* Set $KEY and $ZB with the failing badchar */ memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1)); iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0'; - memcpy(rm_ptr->dollar_key, delimptr, MIN(delimlen, RM_BUFLEN - 1)); - rm_ptr->dollar_key[MIN(delimlen, RM_BUFLEN - 1)] = '\0'; + memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1)); + iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0'; } } - /* set dollar_device in the output device */ + /* set dollar.device in the output device */ len = SIZEOF(ONE_COMMA) - 1; - memcpy(rm_ptr->dollar_device, ONE_COMMA, len); - memcpy(&rm_ptr->dollar_device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG)); + memcpy(iod->dollar.device, ONE_COMMA, len); + memcpy(&iod->dollar.device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG)); } #endif @@ -126,6 +126,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ FILE *filstr; boolean_t pipe_zero_timeout = FALSE; boolean_t pipe_or_fifo = FALSE; + boolean_t follow_timeout = FALSE; + boolean_t bom_timeout = FALSE; int blocked_in = TRUE; int do_clearerr = FALSE; int saved_lastop; @@ -135,6 +137,11 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ mv_stent *mv_zintdev; unsigned int *dollarx_ptr; unsigned int *dollary_ptr; + struct timeval poll_interval; + int poll_status; + fd_set input_fds; + int4 sleep_left; + int4 sleep_time; DCL_THREADGBL_ACCESS; @@ -149,7 +156,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ io_ptr = io_curr_device.in; /* don't allow a read from a writeonly fifo */ if (((d_rm_struct *)io_ptr->dev_sp)->write_only) - rts_error(VARLSTCNT(1) ERR_DEVICEWRITEONLY); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEWRITEONLY); #ifdef __MVS__ /* on zos if it is a fifo device then point to the pair.out for $X and $Y */ if (((d_rm_struct *)io_ptr->dev_sp)->fifo) @@ -201,12 +208,12 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ flags = 0; FCNTL2(rm_ptr->fildes, F_GETFL, flags); if (0 > flags) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); if (flags & O_NONBLOCK) { FCNTL3(rm_ptr->fildes, F_SETFL, (flags & ~O_NONBLOCK), fcntl_res); if (0 > fcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); } } @@ -218,7 +225,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ GTMASSERT; /* Interrupt should never have an invalid save state */ /* check we aren't recursing on this device */ if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); if (pipewhich_readfl != pipeintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ PIPE_DEBUG(PRINTF("piperfl: *#*#*#*#*#*#*# Restarted interrupted read\n"); DEBUGPIPEFLUSH); @@ -341,7 +348,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ temp = (char *)(stringpool.free + bytes_read); tot_bytes_read = bytes_count = bytes_read; - width -= bytes_read; + if (!(rm_ptr->fixed && rm_ptr->follow)) + width -= bytes_read; } } @@ -391,7 +399,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ "computed msec_timeout: %d\n", msec_timeout); DEBUGPIPEFLUSH); } PIPE_DEBUG(PRINTF("msec_timeout: %d\n", msec_timeout); DEBUGPIPEFLUSH); - if (0 < msec_timeout) + /* if it is a disk read with follow don't start timer, as we use a sleep loop instead */ + if ((0 < msec_timeout) && !rm_ptr->follow) start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else @@ -402,10 +411,10 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ out_of_time = TRUE; FCNTL2(fildes, F_GETFL, flags); if (0 > flags) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); FCNTL3(fildes, F_SETFL, (flags | O_NONBLOCK), fcntl_res); if (0 > fcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); blocked_in = FALSE; if (rm_ptr->pipe) pipe_zero_timeout = TRUE; @@ -421,62 +430,152 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ * Note the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, since action is taken on EINTR, not a retry. */ - /* If it is a pipe and at least one character is read, a timer with timer_id - will be started. It is canceled later in this routine if not expired - prior to return */ - DOREADRLTO2(fildes, temp, width, out_of_time, &blocked_in, rm_ptr->pipe, flags, status, - &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout, FALSE, pipe_or_fifo); - - PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH); - - if (0 > status) + if (rm_ptr->follow) { - if (pipe_or_fifo) - bytes_count = tot_bytes_read; - else - bytes_count = 0; - if (errno == EINTR && out_of_time) - status = -2; + PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH); + if (timed) + { + if (0 < msec_timeout) + { + sleep_left = msec_timeout; + } else + sleep_left = 0; + } + /* if zeof is set in follow mode then ignore any previous zeof */ + if (TRUE == io_ptr->dollar.zeof) + io_ptr->dollar.zeof = FALSE; + do + { + status = read(fildes, temp, width - bytes_count); + if (0 < status) /* we read some chars */ + { + tot_bytes_read += status; + rm_ptr->file_pos += status; + bytes_count += status; + temp = temp + status; + } else if (0 == status) /* end of file */ + { + if ((TRUE == timed) && (0 >= sleep_left)) + { + follow_timeout = TRUE; + break; + } + /* if a timed read, sleep the minimum of 100 ms and sleep_left. + If not a timed read then just sleep 100 ms */ + if (TRUE == timed) + sleep_time = MIN(100,sleep_left); + else + sleep_time = 100; + SHORT_SLEEP(sleep_time); + if (TRUE == timed) + sleep_left -= sleep_time; + if (outofband) + { + PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH); + PUSH_MV_STENT(MVST_ZINTDEV); + mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = + (char *)stringpool.free; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read; + mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; + pipeintr->who_saved = pipewhich_readfl; + if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout) + { + pipeintr->end_time = end_time; + pipeintr->end_time_valid = TRUE; + } + pipeintr->max_bufflen = exp_width; + pipeintr->bytes_read = tot_bytes_read; + rm_ptr->mupintr = TRUE; + stringpool.free += tot_bytes_read; /* Don't step on our parade in + the interrupt */ + (TREF(pipefifo_interrupt))++; + outofband_action(FALSE); + GTMASSERT; /* Should *never* return from outofband_action */ + return FALSE; /* For the compiler.. */ + } + continue; /* for now try and read again if eof or no input ready */ + } else /* error returned */ + { + PIPE_DEBUG(PRINTF("errno= %d fixed\n", errno); DEBUGPIPEFLUSH); + if (errno != EINTR) + { + bytes_count = 0; + break; + } + } + } while (bytes_count < width); } else { - tot_bytes_read = bytes_count = status; - rm_ptr->file_pos += status; - } + /* If it is a pipe and at least one character is read, a timer with timer_id + will be started. It is canceled later in this routine if not expired + prior to return */ + DOREADRLTO2(fildes, temp, width, out_of_time, &blocked_in, rm_ptr->pipe, flags, status, + &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout, FALSE, pipe_or_fifo); - if (zint_restart) - { - tot_bytes_read += bytes_read; - bytes_count = tot_bytes_read; - PIPE_DEBUG(PRINTF(" %d temp= %s tot_bytes_read = %d\n", pid, temp, tot_bytes_read); DEBUGPIPEFLUSH); - } + PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH); - if (pipe_or_fifo && outofband) - { - PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH); - PUSH_MV_STENT(MVST_ZINTDEV); - mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr; - mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; - mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read; - mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; - pipeintr->who_saved = pipewhich_readfl; - if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout) + if (0 > status) { - pipeintr->end_time = end_time; - pipeintr->end_time_valid = TRUE; - cancel_timer(timer_id); /* Worry about timer if/when we come back */ + if (pipe_or_fifo) + bytes_count = tot_bytes_read; + else + bytes_count = 0; + if (errno == EINTR && out_of_time) + status = -2; + } else + { + tot_bytes_read = bytes_count = status; + rm_ptr->file_pos += status; + } + if (zint_restart) + { + tot_bytes_read += bytes_read; + bytes_count = tot_bytes_read; + PIPE_DEBUG(PRINTF(" %d temp= %s tot_bytes_read = %d\n", pid, temp, tot_bytes_read); + DEBUGPIPEFLUSH); + } + + if (pipe_or_fifo && outofband) + { + PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH); + PUSH_MV_STENT(MVST_ZINTDEV); + mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read; + mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; + pipeintr->who_saved = pipewhich_readfl; + if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout) + { + pipeintr->end_time = end_time; + pipeintr->end_time_valid = TRUE; + cancel_timer(timer_id); /* Worry about timer if/when we come back */ + } + pipeintr->max_bufflen = exp_width; + pipeintr->bytes_read = tot_bytes_read; + rm_ptr->mupintr = TRUE; + stringpool.free += tot_bytes_read; /* Don't step on our parade in the interrupt */ + (TREF(pipefifo_interrupt))++; + outofband_action(FALSE); + GTMASSERT; /* Should *never* return from outofband_action */ + return FALSE; /* For the compiler.. */ } - pipeintr->max_bufflen = exp_width; - pipeintr->bytes_read = tot_bytes_read; - rm_ptr->mupintr = TRUE; - stringpool.free += tot_bytes_read; /* Don't step on our parade in the interrupt */ - (TREF(pipefifo_interrupt))++; - outofband_action(FALSE); - GTMASSERT; /* Should *never* return from outofband_action */ - return FALSE; /* For the compiler.. */ } } else if (!rm_ptr->pipe && !rm_ptr->fifo) { /* rms-file device */ + if ((rm_ptr->follow) && timed) + { + if (0 < msec_timeout) + { + sleep_left = msec_timeout; + } else + sleep_left = 0; + } + + /* if zeof is set and follow is TRUE then ignore any previous zeof */ + if (rm_ptr->follow && (TRUE == io_ptr->dollar.zeof)) + io_ptr->dollar.zeof = FALSE; do { if (EOF != (status = getc(filstr))) @@ -499,6 +598,51 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ { status = 0; clearerr(filstr); + + if (rm_ptr->follow) + { + if ((TRUE == timed) && (0 >= sleep_left)) + { + follow_timeout = TRUE; + break; + } + /* if a timed read, sleep the minimum of 100 ms and sleep_left. + If not a timed read then just sleep 100 ms */ + if (TRUE == timed) + sleep_time = MIN(100,sleep_left); + else + sleep_time = 100; + SHORT_SLEEP(sleep_time); + if (TRUE == timed) + sleep_left -= sleep_time; + if (outofband) + { + PIPE_DEBUG(PRINTF(" %d outofband\n", pid); DEBUGPIPEFLUSH); + PUSH_MV_STENT(MVST_ZINTDEV); + mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = + (char *)stringpool.free; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = + tot_bytes_read; + mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; + pipeintr->who_saved = pipewhich_readfl; + if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout) + { + pipeintr->end_time = end_time; + pipeintr->end_time_valid = TRUE; + } + pipeintr->max_bufflen = exp_width; + pipeintr->bytes_read = tot_bytes_read; + rm_ptr->mupintr = TRUE; + stringpool.free += tot_bytes_read; /* Don't step on our parade + in the interrupt */ + (TREF(pipefifo_interrupt))++; + outofband_action(FALSE); + GTMASSERT; /* Should *never* return from outofband_action */ + return FALSE; /* For the compiler.. */ + } + continue; /* for now try and read again if eof or no input ready */ + } } else do_clearerr = TRUE; @@ -553,7 +697,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ { FCNTL3(fildes, F_SETFL, flags, tfcntl_res); if (0 > tfcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); blocked_in = TRUE; out_of_time = FALSE; @@ -614,14 +758,18 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ what to do. */ if ((0 == buff_len) || zint_restart) { /* need to refill the buffer */ - buff_len = iorm_get(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read, + if (rm_ptr->follow) + buff_len = iorm_get_fol(io_ptr, &tot_bytes_read, &msec_timeout, timed, zint_restart, + &follow_timeout); + else + buff_len = iorm_get(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout, zint_restart); if (0 > buff_len) { bytes_count = 0; if (errno == EINTR && out_of_time) buff_len = -2; - } else if (pipe_or_fifo && outofband && (buff_len < rm_ptr->recordsize)) + } else if (outofband && (buff_len < rm_ptr->recordsize)) { PIPE_DEBUG(PRINTF(" %d utf fixed outofband, buff_len: %d done_1st_read: %d\n", pid, buff_len, rm_ptr->done_1st_read); DEBUGPIPEFLUSH); @@ -707,6 +855,9 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ GTMASSERT; } } + if (rm_ptr->follow && (char_count == width) && (TRUE == follow_timeout)) + follow_timeout = FALSE; + v->str.len = INTCAST(char_ptr - rm_ptr->inbuf_off); UNICODE_ONLY(v->str.char_len = char_count;) if (0 < v->str.len) @@ -732,8 +883,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ } } else { /* VARIABLE or STREAM */ - PIPE_DEBUG(PRINTF("enter utf stream: %d inbuf_pos: %d inbuf_off: %d\n", rm_ptr->done_1st_read, - rm_ptr->inbuf_pos, rm_ptr->inbuf_off); DEBUGPIPEFLUSH); + PIPE_DEBUG(PRINTF("enter utf stream: %d inbuf_pos: %d inbuf_off: %d follow: %d\n", rm_ptr->done_1st_read, + rm_ptr->inbuf_pos, rm_ptr->inbuf_off, rm_ptr->follow); DEBUGPIPEFLUSH); assert(IS_UTF_CHSET(chset)); if (rm_ptr->inbuf_pos <= rm_ptr->inbuf_off) { /* reset buffer pointers */ @@ -758,18 +909,43 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ status, bytes2read,rm_ptr->utf_start_pos,rm_ptr->utf_tot_bytes_in_buffer, char_bytes_read, add_bytes); DEBUGPIPEFLUSH); char_start = rm_ptr->inbuf_off; + + if (rm_ptr->follow) + { + PIPE_DEBUG(PRINTF(" %d utf streaming with follow\n", pid); DEBUGPIPEFLUSH); + + /* rms-file device in follow mode */ + if (timed) + { + if (0 < msec_timeout) + { + sleep_left = msec_timeout; + } else + sleep_left = 0; + } + + /* if zeof is set in follow mode then ignore any previous zeof */ + if (TRUE == io_ptr->dollar.zeof) + io_ptr->dollar.zeof = FALSE; + } + do { if (!rm_ptr->done_1st_read) { /* need to check BOM */ - status = iorm_get_bom(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read, + if (rm_ptr->follow) + { + status = iorm_get_bom_fol(io_ptr, &tot_bytes_read, &msec_timeout, timed, + &bom_timeout); + } else + status = iorm_get_bom(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout); - /* if we got an interrupt then the iorm_get_bom did not complete so not as much state needs - to be saved*/ + /* if we got an interrupt then the iorm_get_bom did not complete so not as much state + needs to be saved*/ - if (pipe_or_fifo && outofband) + if (outofband && (pipe_or_fifo || rm_ptr->follow)) { PIPE_DEBUG(PRINTF(" %d utf1 stream outofband\n", pid); DEBUGPIPEFLUSH); PUSH_MV_STENT(MVST_ZINTDEV); @@ -782,7 +958,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ { pipeintr->end_time = end_time; pipeintr->end_time_valid = TRUE; - cancel_timer(timer_id); /* Worry about timer if/when we come back */ + cancel_timer(timer_id); /* Worry about timer if/when we come back */ } pipeintr->max_bufflen = exp_width; /* nothing copied to stringpool.free yet */ @@ -832,10 +1008,91 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ rm_ptr->utf_start_pos = rm_ptr->utf_tot_bytes_in_buffer = 0; /* Read CHUNK_SIZE bytes from device into the temporary buffer. By doing this * one-byte reads can be avoided when in UTF mode. + * */ - DOREADRLTO2(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE, out_of_time, &blocked_in, - rm_ptr->pipe, flags, status, &utf_tot_bytes_read, - timer_id, &msec_timeout, pipe_zero_timeout, pipe_or_fifo, pipe_or_fifo); + + if (rm_ptr->follow) + { + if (FALSE == bom_timeout) + { + status = read(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE); + + if (0 == status) /* end of file */ + { + if ((TRUE == timed) && (0 >= sleep_left)) + { + follow_timeout = TRUE; + break; + } + + /* if a timed read, sleep the minimum of 100 ms and + sleep_left. If not a timed read then just sleep 100 ms */ + if (TRUE == timed) + sleep_time = MIN(100,sleep_left); + else + sleep_time = 100; + SHORT_SLEEP(sleep_time); + if (TRUE == timed) + sleep_left -= sleep_time; + + if (outofband) + { + PIPE_DEBUG(PRINTF(" %d utf2 stream outofband\n", + pid); DEBUGPIPEFLUSH); + PUSH_MV_STENT(MVST_ZINTDEV); + mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr + = (char *)stringpool.free; + mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len + = bytes_count; + mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = + TRUE; + pipeintr->who_saved = pipewhich_readfl; + if (0 < msec_timeout && NO_M_TIMEOUT != + msec_timeout) + { + pipeintr->end_time = end_time; + pipeintr->end_time_valid = TRUE; + } + pipeintr->max_bufflen = exp_width; + /* streaming mode uses bytes_count to show how many + bytes are in *temp, but the interrupt re-entrant + code uses bytes_read */ + pipeintr->bytes_read = bytes_count; + pipeintr->bytes2read = bytes2read; + pipeintr->char_count = char_count; + pipeintr->add_bytes = add_bytes; + pipeintr->bytes_count = bytes_count; + PIPE_DEBUG(PRINTF("utf2 stream outofband " + "char_bytes_read %d add_bytes " + "%d bytes_count %d\n", + char_bytes_read, + add_bytes, bytes_count); + DEBUGPIPEFLUSH); + rm_ptr->mupintr = TRUE; + /* Don't step on our parade in the interrupt */ + stringpool.free += bytes_count; + (TREF(pipefifo_interrupt))++; + outofband_action(FALSE); + GTMASSERT; /* Should *never* return from + outofband_action */ + return FALSE; /* For the compiler.. */ + } + continue; /* for now try and read again if eof or no input + ready */ + } else if (-1 == status && errno != EINTR) /* error returned */ + { + bytes_count = 0; + break; + } + } + } else + { + DOREADRLTO2(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE, + out_of_time, &blocked_in, rm_ptr->pipe, flags, + status, &utf_tot_bytes_read, timer_id, + &msec_timeout, pipe_zero_timeout, pipe_or_fifo, pipe_or_fifo); + } PIPE_DEBUG(PRINTF("4: read chunk status: %d utf_tot_bytes_read: %d\n", status, utf_tot_bytes_read); DEBUGPIPEFLUSH); @@ -1151,7 +1408,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ real_errno = errno; if (TRUE == do_clearerr) clearerr(filstr); - memcpy(rm_ptr->dollar_device, "0", SIZEOF("0")); + memcpy(io_ptr->dollar.device, "0", SIZEOF("0")); io_ptr->dollar.za = 0; /* On error, getc() returns EOF while read() returns -1. Both code paths converge here. Thankfully EOF is -1 on all * platforms that we know of so it is enough to check for -1 status here. Assert that below. @@ -1169,8 +1426,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ cancel_timer(timer_id); io_ptr->dollar.za = 9; /* save error in $device */ - DOLLAR_DEVICE_SET(rm_ptr, real_errno); - rts_error(VARLSTCNT(1) real_errno); + DOLLAR_DEVICE_SET(io_ptr, real_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno); } ret = FALSE; } @@ -1185,7 +1442,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ { FCNTL3(fildes, F_SETFL, flags, fcntl_res); if (0 > fcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), + CALLFROM, errno); } if ((rm_ptr->pipe && (0 == status)) || (rm_ptr->fifo && (0 == status || real_errno == EAGAIN))) ret = FALSE; @@ -1193,7 +1451,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ { if (out_of_time) ret = FALSE; - else + else if (!rm_ptr->follow) /* if follow then no timer started */ cancel_timer(timer_id); } } @@ -1204,19 +1462,25 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ v->str.addr = (char *)stringpool.free; /* ensure valid address */ UNICODE_ONLY(v->str.char_len = 0;) + if (rm_ptr->follow) + { + if (TRUE == io_ptr->dollar.zeof) + io_ptr->dollar.zeof = FALSE; /* no EOF in follow mode */ + return(FALSE); + } /* on end of file set $za to 9 */ len = SIZEOF(ONE_COMMA_DEV_DET_EOF); - memcpy(rm_ptr->dollar_device, ONE_COMMA_DEV_DET_EOF, len); + memcpy(io_ptr->dollar.device, ONE_COMMA_DEV_DET_EOF, len); io_ptr->dollar.za = 9; if ((TRUE == io_ptr->dollar.zeof) && (RM_READ == saved_lastop)) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); io_ptr->dollar.zeof = TRUE; *dollarx_ptr = 0; (*dollary_ptr)++; if (io_ptr->error_handler.len > 0) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); if ((pipe_zero_timeout || rm_ptr->fifo) && out_of_time) { ret = TRUE; @@ -1231,6 +1495,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ else ret = FALSE; } + if (rm_ptr->follow && !rm_ptr->fixed && !line_term_seen) + ret = FALSE; if (!utf_active || !rm_ptr->fixed) { /* if Unicode and fixed, already setup the mstr */ v->str.len = bytes_count; @@ -1255,6 +1521,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */ } } } + if (follow_timeout) + ret = FALSE; assert(FALSE == rm_ptr->mupintr); return (rm_ptr->pipe && out_of_time) ? FALSE : ret; } diff --git a/sr_unix/iorm_use.c b/sr_unix/iorm_use.c index 616cbe8..dd6a2e8 100644 --- a/sr_unix/iorm_use.c +++ b/sr_unix/iorm_use.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,7 +40,8 @@ if (-1 == fstat_res) \ { \ save_errno = errno; \ - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fstat"), CALLFROM, save_errno); \ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fstat"), \ + CALLFROM, save_errno); \ } \ mode = mode1 = statbuf.st_mode; \ fstat_done = TRUE; \ @@ -123,7 +124,7 @@ void iorm_use(io_desc *iod, mval *pp) case iop_length: GET_LONG(length, (pp->str.addr + p_offset)); if (length < 0) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); iod->length = length; break; case iop_w_protection: @@ -147,7 +148,7 @@ void iorm_use(io_desc *iod, mval *pp) { GET_LONG(padchar, (pp->str.addr + p_offset)); if (!IS_PADCHAR_VALID(iod->ochset, padchar)) - rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0); rm_ptr->padchar = padchar; } break; @@ -169,9 +170,9 @@ void iorm_use(io_desc *iod, mval *pp) { /* only if not open, not UTF, or no reads or writes yet */ GET_LONG(recordsize, (pp->str.addr + p_offset)); if (recordsize <= 0) - rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHPOS); else if (MAX_STRLEN < recordsize) - rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHTOOBIG); rm_ptr->recordsize = recordsize; rm_ptr->def_recsize = FALSE; } @@ -182,12 +183,12 @@ void iorm_use(io_desc *iod, mval *pp) iorm_flush(iod); if (lseek(rm_ptr->fildes, (off_t)0, SEEK_SET) == -1) { - rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"), RTS_ERROR_LITERAL("REWIND"), CALLFROM, errno); } if (fseek(rm_ptr->filstr, (long)0, SEEK_SET) == -1) /* Rewind the input stream */ { - rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"), RTS_ERROR_LITERAL("REWIND"), CALLFROM, errno); } iod->dollar.zeof = FALSE; @@ -229,18 +230,18 @@ void iorm_use(io_desc *iod, mval *pp) int ftruncate_res; if (fseek(rm_ptr->filstr, (long)rm_ptr->file_pos, SEEK_SET) == -1) { - rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"), RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno); } if (lseek(rm_ptr->fildes, (off_t)rm_ptr->file_pos, SEEK_SET) == -1) { - rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"), RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno); } FTRUNCATE(rm_ptr->fildes, (off_t)rm_ptr->file_pos, ftruncate_res); if (0 != ftruncate_res) { - rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("ftruncate"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("ftruncate"), RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno); } iod->dollar.zeof = TRUE; @@ -281,19 +282,19 @@ void iorm_use(io_desc *iod, mval *pp) } CHG_OWNER(iod->trans_name->dollar_io, uic.mem, uic.grp, chown_res); if (-1 == chown_res) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); break; } case iop_width: assert(iod->state == dev_open); GET_LONG(width, (pp->str.addr + p_offset)); if (0 > width || (0 == width && !IS_UTF_CHSET(iod->ochset))) - rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHPOS); else if (MAX_STRLEN < width) - rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHTOOBIG); /* Do not allow a WIDTH of 1 if either ICHSET or OCHSET is UTF-* */ if ((1 == width) && gtm_utf8_mode && ((IS_UTF_CHSET(iod->ochset)) || (IS_UTF_CHSET(iod->ichset)))) - rts_error(VARLSTCNT(1) ERR_WIDTHTOOSMALL); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WIDTHTOOSMALL); if (IS_UTF_CHSET(iod->ochset) && rm_ptr->fixed) iorm_flush(iod); /* need to flush current record first */ rm_ptr->def_width = FALSE; @@ -372,7 +373,7 @@ void iorm_use(io_desc *iod, mval *pp) iod->ochset = temp_chset; ochset_specified = TRUE; if (gtm_utf8_mode && !IS_PADCHAR_VALID(iod->ochset, rm_ptr->padchar)) - rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0); } } break; @@ -387,7 +388,7 @@ void iorm_use(io_desc *iod, mval *pp) break; /* ignore UTF chsets if not utf8_mode */ iod->ochset = temp_chset; if (gtm_utf8_mode && !IS_PADCHAR_VALID(iod->ochset, rm_ptr->padchar)) - rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0); iod->ichset = iod->ochset; ochset_specified = ichset_specified = TRUE; } @@ -413,6 +414,14 @@ void iorm_use(io_desc *iod, mval *pp) ichset_specified = ochset_specified = TRUE; } break; + case iop_follow: + if (!rm_ptr->fifo && !rm_ptr->pipe) + rm_ptr->follow = TRUE; + break; + case iop_nofollow: + if (!rm_ptr->fifo && !rm_ptr->pipe) + rm_ptr->follow = FALSE; + break; default: break; } @@ -448,13 +457,13 @@ void iorm_use(io_desc *iod, mval *pp) assert(DEF_RM_RECORDSIZE == 32767); rm_ptr->recordsize = ROUND_DOWN2(rm_ptr->recordsize, 4); } else if (0 != rm_ptr->recordsize % 2) - rts_error(VARLSTCNT(3) ERR_RECSIZENOTEVEN, 1, rm_ptr->recordsize); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECSIZENOTEVEN, 1, rm_ptr->recordsize); } } if (fstat_done && mode != mode1) { /* if the mode has been changed by the qualifiers, reset it */ if (-1 == CHMOD(iod->trans_name->dollar_io, mode)) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); } return; } diff --git a/sr_unix/iorm_write.c b/sr_unix/iorm_write.c index 616599b..3db26d8 100644 --- a/sr_unix/iorm_write.c +++ b/sr_unix/iorm_write.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,9 @@ GBLREF io_pair io_curr_device; #ifdef UNICODE_SUPPORTED LITREF mstr chset_names[]; #endif + +#define MAX_WIDTH 65535 + error_def(ERR_NOTTOEOFONPUT); error_def(ERR_DEVICEREADONLY); error_def(ERR_SYSCALL); @@ -84,9 +87,9 @@ int iorm_write_utf_ascii(io_desc *iod, char *string, int len) DOWRITERC(rm_ptr->fildes, outstart, outlen, status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } rm_ptr->out_bytes += outlen; } @@ -143,9 +146,9 @@ void iorm_write_utf(mstr *v) DOWRITERC(rm_ptr->fildes, outstart, outbytes, status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } outptr = outstart; rm_ptr->out_bytes = outbytes = 0; @@ -203,9 +206,9 @@ void iorm_write_utf(mstr *v) } if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } iod->dollar.x += usedwidth; @@ -243,9 +246,9 @@ void iorm_write_utf(mstr *v) DOWRITERC(rm_ptr->fildes, temppadarray, padsize, status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } assert(rm_ptr->out_bytes == rm_ptr->recordsize); @@ -317,14 +320,14 @@ void iorm_write(mstr *v) #else rm_ptr = (d_rm_struct *)iod->dev_sp; #endif - memcpy(rm_ptr->dollar_device, "0", SIZEOF("0")); + memcpy(iod->dollar.device, "0", SIZEOF("0")); if (rm_ptr->noread) - rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEREADONLY); if (!iod->dollar.zeof && !rm_ptr->fifo && !rm_ptr->pipe) { iod->dollar.za = 9; - rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTTOEOFONPUT); } /* if it's a fifo and not system output/error, last operation was not a write and O_NONBLOCK is not set @@ -334,12 +337,12 @@ void iorm_write(mstr *v) flags = 0; FCNTL2(rm_ptr->fildes, F_GETFL, flags); if (0 > flags) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); if (!(flags & O_NONBLOCK)) { FCNTL3(rm_ptr->fildes, F_SETFL, (flags | O_NONBLOCK), fcntl_res); if (0 > fcntl_res) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); } } @@ -355,7 +358,7 @@ void iorm_write(mstr *v) else outlen = iod->width - iod->dollar.x; - if (!iod->wrap && inlen > outlen) + if (!iod->wrap && inlen > outlen && outlen != MAX_WIDTH) inlen = outlen; if (!inlen) return; @@ -373,9 +376,9 @@ void iorm_write(mstr *v) } if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } iod->dollar.x += len; if ((inlen -= len) <= 0) @@ -391,9 +394,9 @@ void iorm_write(mstr *v) DOWRITERC(rm_ptr->fildes, RMEOL, STRLEN(RMEOL), status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } diff --git a/sr_unix/iorm_wteol.c b/sr_unix/iorm_wteol.c index 37e90ab..3ad75e6 100644 --- a/sr_unix/iorm_wteol.c +++ b/sr_unix/iorm_wteol.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -59,11 +59,11 @@ void iorm_wteol(int4 x,io_desc *iod) rm_ptr = (d_rm_struct *)iod->dev_sp; } if (rm_ptr->noread) - rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEREADONLY); if (!iod->dollar.zeof && !rm_ptr->fifo && !rm_ptr->pipe) { iod->dollar.za = 9; - rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTTOEOFONPUT); } rm_ptr->lastop = RM_WRITE; #ifdef __MVS__ @@ -83,9 +83,9 @@ void iorm_wteol(int4 x,io_desc *iod) if (-1 == res_size) { int real_errno = errno; - DOLLAR_DEVICE_WRITE(rm_ptr,real_errno); + DOLLAR_DEVICE_WRITE(iod, real_errno); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) real_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno); } iod->ochset = CHSET_UTF16BE; get_chset_desc(&chset_names[iod->ochset]); @@ -130,9 +130,9 @@ void iorm_wteol(int4 x,io_desc *iod) DOWRITERC(rm_ptr->fildes, temppadarray, bytes_per_char, status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } assert(rm_ptr->out_bytes == rm_ptr->recordsize); @@ -153,9 +153,9 @@ void iorm_wteol(int4 x,io_desc *iod) if (-1 == res_size) { int real_errno = errno; - DOLLAR_DEVICE_WRITE(rm_ptr,real_errno); + DOLLAR_DEVICE_WRITE(iod, real_errno); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) real_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno); } assert(res_size == pad_size); } @@ -164,9 +164,9 @@ void iorm_wteol(int4 x,io_desc *iod) DOWRITERC(rm_ptr->fildes, RMEOL, STRLEN(RMEOL), status); if (0 != status) { - DOLLAR_DEVICE_WRITE(rm_ptr,status); + DOLLAR_DEVICE_WRITE(iod, status); iod->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } *dollarx_ptr = 0; diff --git a/sr_unix/iormdef.h b/sr_unix/iormdef.h index e22b45d..ee1b9bc 100644 --- a/sr_unix/iormdef.h +++ b/sr_unix/iormdef.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -15,7 +15,6 @@ #define DEF_RM_WIDTH 32767 #define DEF_RM_RECORDSIZE 32767 #define DEF_RM_LENGTH 66 -#define RM_BUFLEN 80 #define CHUNK_SIZE 512 #define ONE_COMMA "1," @@ -121,6 +120,7 @@ typedef struct boolean_t def_width; /* WIDTH has not been changed */ boolean_t def_recsize; /* RECORDSIZE has not been changed */ boolean_t bom_read_one_done; /* If pipe/fifo and UTF8, read one byte to check for bom if not set */ + boolean_t follow; /* True if disk read with follow - similar to tail -f on a file */ pipe_interrupt pipe_save_state; /* Saved state of interrupted IO */ boolean_t mupintr; /* We were mupip interrupted */ unsigned int lastop; /* Last operation done on file */ @@ -130,8 +130,6 @@ typedef struct struct io_desc_struct *stderr_child; /* pointer to io descriptor for pipe stderr device */ struct io_desc_struct *stderr_parent; /* pointer to io descriptor for pipe which opened stderr device */ pid_t pipe_pid; /* child process id for reaping on close */ - char dollar_key[RM_BUFLEN]; /* String representation of process id of child - $KEY */ - char dollar_device[RM_BUFLEN];/* String representation $DEVICE */ Dev_param_pairs dev_param_pairs; int bufsize; /* Size of inbuf */ int outbufsize; /* Size of outbuf */ @@ -163,6 +161,9 @@ typedef struct int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, int len); int iorm_get_bom(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read, TID timer_id, int4 *msec_timeout, boolean_t colon_zero); +int iorm_get_bom_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t *bom_timeout); +int iorm_get_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t zint_restart, + boolean_t *follow_timeout); int iorm_get(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read, TID timer_id, int4 *msec_timeout, boolean_t colon_zero, boolean_t zint_restart); int iorm_write_utf_ascii(io_desc *iod, char *string, int len); diff --git a/sr_unix/iott_open.c b/sr_unix/iott_open.c index 89410bb..495baee 100644 --- a/sr_unix/iott_open.c +++ b/sr_unix/iott_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,8 +32,15 @@ GBLREF int COLUMNS, GTM_LINES, AUTO_RIGHT_MARGIN; GBLREF uint4 gtm_principal_editing_defaults; GBLREF io_pair io_std_device; -LITREF unsigned char io_params_size[]; GBLREF boolean_t gtm_utf8_mode; +LITREF unsigned char io_params_size[]; + +error_def(ERR_BADCHSET); +error_def(ERR_NOTERMENTRY); +error_def(ERR_NOTERMENV); +error_def(ERR_NOTERMINFODB); +error_def(ERR_TCGETATTR); +error_def(ERR_ZINTRECURSEIO); short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { @@ -44,13 +51,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time int save_errno; int p_offset; mstr chset; - - error_def(ERR_NOTERMENV); - error_def(ERR_NOTERMENTRY); - error_def(ERR_NOTERMINFODB); - error_def(ERR_TCGETATTR); - error_def(ERR_BADCHSET); - error_def(ERR_ZINTRECURSEIO); + boolean_t empt = FALSE; ioptr = dev_name->iod; if (ioptr->state == dev_never_opened) @@ -68,7 +69,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time } tt_ptr = (d_tt_struct *)dev_name->iod->dev_sp; if (tt_ptr->mupintr) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); p_offset = 0; while (*(pp->str.addr + p_offset) != iop_eol) { @@ -80,8 +81,12 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time break; } else if (ch == iop_canonical) tt_ptr->canonical = TRUE; - else if (ch == iop_nocanonical) + else if (ch == iop_nocanonical) tt_ptr->canonical = FALSE; + else if (ch == iop_empterm) + empt = TRUE; + else if (ch == iop_noempterm) + empt = FALSE; else if (iop_m == ch) ioptr->ichset = ioptr->ochset = CHSET_M; else if (gtm_utf8_mode && iop_utf8 == ch) @@ -102,7 +107,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time else ioptr->ochset = CHSET_UTF8; else - rts_error(VARLSTCNT(4) ERR_BADCHSET, 2, chset.len, chset.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, chset.len, chset.addr); } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); @@ -119,7 +124,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time { save_errno = errno; if (gtm_isanlp(tt_ptr->fildes) == 0) - rts_error(VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno); } if (IS_GTM_IMAGE) /* Only the true runtime runs with the modified terminal settings */ @@ -132,12 +137,12 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time env_term = GETENV("TERM"); if (!env_term) { - rts_error(VARLSTCNT(1) ERR_NOTERMENV); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTERMENV); env_term = "unknown"; } - rts_error(VARLSTCNT(4) ERR_NOTERMENTRY, 2, LEN_AND_STR(env_term)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTERMENTRY, 2, LEN_AND_STR(env_term)); } else - rts_error(VARLSTCNT(1) ERR_NOTERMINFODB); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTERMINFODB); } ioptr->width = COLUMNS; ioptr->length = GTM_LINES; @@ -151,6 +156,8 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time ioptr->ichset = ioptr->ochset = gtm_utf8_mode ? CHSET_UTF8 : CHSET_M; /* default */ } else tt_ptr->ext_cap = 0; + if (empt) + tt_ptr->ext_cap |= TT_EMPTERM; if (tt_ptr->default_mask_term) { memset(&tt_ptr->mask_term.mask[0], 0, SIZEOF(io_termmask)); diff --git a/sr_unix/iott_rdone.c b/sr_unix/iott_rdone.c index eaf7807..c01f503 100644 --- a/sr_unix/iott_rdone.c +++ b/sr_unix/iott_rdone.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -51,6 +51,13 @@ GBLREF boolean_t gtm_utf8_mode; LITREF unsigned char lower_to_upper_table[]; +error_def(ERR_CTRAP); +error_def(ERR_IOEOF); +error_def(ERR_NOPRINCIO); +error_def(ERR_ZINTRECURSEIO); +error_def(ERR_STACKOFLOW); +error_def(ERR_STACKCRIT); + int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ { boolean_t ret = FALSE, timed, utf8_active, zint_restart, first_time; @@ -76,13 +83,6 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ ABS_TIME cur_time, end_time; mv_stent *mv_zintdev; - error_def(ERR_CTRAP); - error_def(ERR_IOEOF); - error_def(ERR_NOPRINCIO); - error_def(ERR_ZINTRECURSEIO); - error_def(ERR_STACKOFLOW); - error_def(ERR_STACKCRIT); - io_ptr = io_curr_device.in; assert (io_ptr->state == dev_open); iott_flush(io_curr_device.out); @@ -103,7 +103,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ { tt_ptr->mupintr = FALSE; tt_state->who_saved = ttwhichinvalid; - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); } if (ttrdone != tt_state->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ @@ -151,7 +151,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ if (0 != status) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } } @@ -249,7 +249,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ io_ptr->dollar.za = 9; if (timed && (0 == msec_timeout)) iott_rterm(io_ptr); - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); break; } } else if (0 == selstat) @@ -350,7 +350,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ if (0 == msec_timeout) iott_rterm(io_ptr); } - rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is); ret = FALSE; break; } @@ -430,7 +430,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ if (0 == msec_timeout) iott_rterm(io_ptr); } - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } break; @@ -442,7 +442,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ io_ptr->dollar.za = 9; if (timed && (0 == msec_timeout)) iott_rterm(io_ptr); - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); break; } } else @@ -461,20 +461,20 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ prin_in_dev_failure = TRUE; else { - send_msg(VARLSTCNT(1) ERR_NOPRINCIO); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); stop_image_no_core(); } } if (io_ptr->dollar.zeof) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); } else { io_ptr->dollar.zeof = TRUE; io_ptr->dollar.za = 0; if (io_ptr->error_handler.len > 0) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); } break; } @@ -492,7 +492,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ if (0 != status) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } @@ -536,9 +536,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ *zb_ptr++ = 0; } else - { io_ptr->dollar.zb[0] = '\0'; - } if ((!(msk_in & tt_ptr->mask_term.mask[msk_num])) && (!(mask & TRM_NOECHO))) { if ((io_ptr->dollar.x += inchar_width) >= io_ptr->width && io_ptr->wrap) @@ -548,10 +546,11 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */ io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; if (io_ptr->dollar.x == 0) - DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL)); + DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL)); } } } + memcpy(io_ptr->dollar.key, io_ptr->dollar.zb, (zb_ptr - io_ptr->dollar.zb)); return ret; } diff --git a/sr_unix/iott_readfl.c b/sr_unix/iott_readfl.c index d60fe2a..e93ab9a 100644 --- a/sr_unix/iott_readfl.c +++ b/sr_unix/iott_readfl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -80,6 +80,13 @@ static readonly char dc1 = 17; static readonly char dc3 = 19; static readonly unsigned char eraser[3] = { NATIVE_BS, NATIVE_SP, NATIVE_BS }; +error_def(ERR_CTRAP); +error_def(ERR_IOEOF); +error_def(ERR_NOPRINCIO); +error_def(ERR_ZINTRECURSEIO); +error_def(ERR_STACKOFLOW); +error_def(ERR_STACKCRIT); + #ifdef UNICODE_SUPPORTED /* Maintenance of $ZB on a badchar error and returning partial data (if any) */ @@ -122,6 +129,8 @@ void iott_readfl_badchar(mval *vmvalptr, wint_t *dataptr32, int datalen, iod = io_curr_device.in; memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1)); iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0'; + memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1)); + iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0'; } } } @@ -151,7 +160,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ int outlen; /* total characters in line so far */ int keypad_len, backspace, delete; int up, down, right, left, insert_key; - boolean_t escape_edit; + boolean_t escape_edit, empterm; int4 msec_timeout; /* timeout in milliseconds */ io_desc *io_ptr; d_tt_struct *tt_ptr; @@ -165,13 +174,6 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ struct timeval input_timeval; struct timeval save_input_timeval; - error_def(ERR_CTRAP); - error_def(ERR_IOEOF); - error_def(ERR_NOPRINCIO); - error_def(ERR_ZINTRECURSEIO); - error_def(ERR_STACKOFLOW); - error_def(ERR_STACKCRIT); - assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); io_ptr = io_curr_device.in; @@ -179,6 +181,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ assert(dev_open == io_ptr->state); iott_flush(io_curr_device.out); insert_mode = !(TT_NOINSERT & tt_ptr->ext_cap); /* get initial mode */ + empterm = (TT_EMPTERM & tt_ptr->ext_cap); ioptr_width = io_ptr->width; utf8_active = gtm_utf8_mode ? (CHSET_M != io_ptr->ichset) : FALSE; /* if utf8_active, need room for multi byte characters plus wint_t buffer */ @@ -193,7 +196,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ { tt_ptr->mupintr = FALSE; tt_state->who_saved = ttwhichinvalid; - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); } assert(length == tt_state->length); if (ttread != tt_state->who_saved) @@ -280,7 +283,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ if (0 != status) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } } @@ -304,7 +307,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ if (0 != status) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } #endif @@ -430,7 +433,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ io_ptr->dollar.y++; tt_ptr->discard_lf = FALSE; if (io_ptr->error_handler.len > 0) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); break; } else io_ptr->dollar.zeof = FALSE; @@ -518,7 +521,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ GETASCII(asc_inchar,inchar); if (!edit_mode && (dx >= ioptr_width) && io_ptr->wrap && !(mask & TRM_NOECHO)) { - DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL)); + DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL)); dx = 0; } if ((' ' > INPUT_CHAR) && (tt_ptr->enbld_outofbands.mask & (1 << INPUT_CHAR))) @@ -529,7 +532,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ SEND_KEYPAD_LOCAL if (!msec_timeout) iott_rterm(io_ptr); - rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is); break; } if (((0 != (mask & TRM_ESCAPE)) || edit_mode) @@ -576,7 +579,10 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ assert(0 <= instr); assert(!edit_mode || 0 <= dx); assert(outlen >= instr); - if ((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE] + /* For most of the terminal the 'kbs' string capability is a byte in length. It means that it is + Not treated as escape sequence. So explicitly check if the input corresponds to the 'kbs' */ + if ((((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]) || + (empterm && ('\0' == KEY_BACKSPACE[1]) && (inchar == KEY_BACKSPACE[0]))) && !(mask & TRM_PASTHRU)) { if (0 < instr && (edit_mode || 0 < dx)) @@ -628,6 +634,11 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ } } dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start); + } else if (empterm && (0 == outlen)) + { + assert(zb_ptr == io_ptr->dollar.zb); + *zb_ptr++ = (unsigned char)INPUT_CHAR; + break; } } else { @@ -913,7 +924,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ prin_in_dev_failure = TRUE; else { - send_msg(VARLSTCNT(1) ERR_NOPRINCIO); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); stop_image_no_core(); } } @@ -921,14 +932,14 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ { io_ptr->dollar.za = 9; SEND_KEYPAD_LOCAL - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); } else { io_ptr->dollar.zeof = TRUE; io_ptr->dollar.za = 0; SEND_KEYPAD_LOCAL if (0 < io_ptr->error_handler.len) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); } break; } @@ -940,7 +951,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ io_ptr->dollar.y++; SEND_KEYPAD_LOCAL if (0 < io_ptr->error_handler.len) - rts_error(VARLSTCNT(1) ERR_IOEOF); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF); break; } } else if (EINTR != errno) /* rdlen < 0 */ @@ -948,7 +959,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ term_error_line = __LINE__; goto term_error; } - if (FINI == io_ptr->esc_state) + if (FINI == io_ptr->esc_state) { int zb_len = (int)(zb_ptr - io_ptr->dollar.zb); @@ -1006,6 +1017,10 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ goto term_error; } dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start); + } else if (empterm && 0 == outlen) + { + assert(instr == 0); + break; } escape_edit = TRUE; } @@ -1100,6 +1115,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ } } while (outlen < length); *zb_ptr++ = 0; + memcpy(io_ptr->dollar.key, io_ptr->dollar.zb, (zb_ptr - io_ptr->dollar.zb)); if (!msec_timeout) { iott_rterm(io_ptr); @@ -1112,7 +1128,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ if (0 != status) { io_ptr->dollar.za = 9; - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); } } SEND_KEYPAD_LOCAL /* to turn keypad off if possible */ @@ -1157,7 +1173,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */ io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= ioptr_width; if (0 == io_ptr->dollar.x) - DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL)); + DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL)); } } return ((short)ret); @@ -1169,6 +1185,6 @@ term_error: SEND_KEYPAD_LOCAL /* to turn keypad off if possible */ if (!msec_timeout) iott_rterm(io_ptr); - rts_error(VARLSTCNT(1) save_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_errno); return FALSE; } diff --git a/sr_unix/iott_use.c b/sr_unix/iott_use.c index b14eba6..a8ce829 100644 --- a/sr_unix/iott_use.c +++ b/sr_unix/iott_use.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -60,6 +60,15 @@ GBLREF boolean_t dollar_zininterrupt; LITREF unsigned char io_params_size[]; +error_def(ERR_DEVPARMNEG); +error_def(ERR_NOPRINCIO); +error_def(ERR_SYSCALL); +error_def(ERR_TCGETATTR); +error_def(ERR_TCSETATTR); +error_def(ERR_TTINVFILTER); +error_def(ERR_WIDTHTOOSMALL); +error_def(ERR_ZINTRECURSEIO); + void iott_use(io_desc *iod, mval *pp) { boolean_t flush_input; @@ -77,15 +86,6 @@ void iott_use(io_desc *iod, mval *pp) int save_errno; int p_offset; - error_def(ERR_DEVPARMNEG); - error_def(ERR_NOPRINCIO); - error_def(ERR_SYSCALL); - error_def(ERR_TCGETATTR); - error_def(ERR_TCSETATTR); - error_def(ERR_TTINVFILTER); - error_def(ERR_WIDTHTOOSMALL); - error_def(ERR_ZINTRECURSEIO); - p_offset = 0; assert(iod->state == dev_open); iott_flush(iod); @@ -94,7 +94,7 @@ void iott_use(io_desc *iod, mval *pp) { if (tt_ptr->mupintr) if (dollar_zininterrupt) - rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); else { /* The interrupted read was not properly resumed so clear it now */ tt_ptr->mupintr = FALSE; @@ -111,11 +111,11 @@ void iott_use(io_desc *iod, mval *pp) prin_out_dev_failure = TRUE; else { - send_msg(VARLSTCNT(1) ERR_NOPRINCIO); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); stop_image_no_core(); } } - rts_error(VARLSTCNT(3) ERR_TCGETATTR, tt_ptr->fildes, save_errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno); } flush_input = FALSE; d_in = iod->pair.in; @@ -135,6 +135,12 @@ void iott_use(io_desc *iod, mval *pp) tt_ptr->canonical = FALSE; t.c_lflag &= ~(ICANON); break; + case iop_empterm: + tt_ptr->ext_cap |= TT_EMPTERM; + break; + case iop_noempterm: + tt_ptr->ext_cap &= ~TT_EMPTERM; + break; case iop_cenable: temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp; if (tt_ptr->fildes == temp_ptr->fildes && !ctrlc_on) @@ -223,7 +229,7 @@ void iott_use(io_desc *iod, mval *pp) ttab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, ttab, len)) < 0) { - rts_error(VARLSTCNT(1) ERR_TTINVFILTER); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) @@ -265,7 +271,7 @@ void iott_use(io_desc *iod, mval *pp) case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (0 > length) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); d_out->length = length; break; case iop_pasthru: @@ -282,7 +288,7 @@ void iott_use(io_desc *iod, mval *pp) temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp; DOWRITERC(temp_ptr->fildes, &dc1, 1, status); if (0 != status) - rts_error(VARLSTCNT(1) status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); mask_in &= (~TRM_READSYNC); break; case iop_terminator: @@ -333,10 +339,10 @@ void iott_use(io_desc *iod, mval *pp) case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (0 > width) - rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); /* Do not allow a WIDTH of 1 if UTF mode (ICHSET or OCHSET is not M) */ if ((1 == width) && ((CHSET_M != d_in->ochset) || (CHSET_M != d_in->ichset))) - rts_error(VARLSTCNT(1) ERR_WIDTHTOOSMALL); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WIDTHTOOSMALL); if (0 == width) { d_out->wrap = FALSE; @@ -407,16 +413,16 @@ void iott_use(io_desc *iod, mval *pp) (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } temp_ptr = (d_tt_struct *)d_in->dev_sp; - Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status); + Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno); if (0 != status) - rts_error(VARLSTCNT(3) ERR_TCSETATTR, tt_ptr->fildes, errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno); temp_ptr->term_ctrl = mask_in; memcpy(&temp_ptr->mask_term, &mask_term, SIZEOF(io_termmask)); if (flush_input) { TCFLUSH(tt_ptr->fildes, TCIFLUSH, status); if (0 != status) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LIT_AND_LEN("tcflush input"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LIT_AND_LEN("tcflush input"), CALLFROM, errno); } } else if (tt_ptr->mupintr && !dollar_zininterrupt) diff --git a/sr_unix/iottdef.h b/sr_unix/iottdef.h index 95d83b0..f76bcfc 100644 --- a/sr_unix/iottdef.h +++ b/sr_unix/iottdef.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,6 +33,7 @@ #define TT_EDITING 0x1000 #define TT_NOINSERT 0x2000 +#define TT_EMPTERM 0x4000 enum tt_which { diff --git a/sr_unix/ipcrmid.c b/sr_unix/ipcrmid.c index 1e07a9f..794e754 100644 --- a/sr_unix/ipcrmid.c +++ b/sr_unix/ipcrmid.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,62 +12,107 @@ /* Perform forks to priv'd gtmsecshr routine to remove ipc ids */ #include "mdef.h" + #include #include #include #include +#include "gtm_string.h" +#include "gtm_limits.h" + #include "io.h" #include "gtmsecshr.h" #include "secshr_client.h" #include "gtmmsg.h" #include "ipcrmid.h" +#include "send_msg.h" #define REMIPC(op, ipcid) (send_mesg2gtmsecshr((unsigned int)(op), (unsigned int)(ipcid), (char *)NULL, 0)) +error_def(ERR_SYSCALL); + +/* General note - in the routines below (and indeed in general), if the "error" is not relevant to the current process + * being able to continue, process should (at most) send the message to the operator log and continue. No gtm_putmsg() + * to the console and continue. This just screws up the output console for the client. + */ + /* Remove a semaphore id : if the current process has no permissions to remove it by itself, - * force it through gtmsecshr. + * force it through gtmsecshr. If we are a debug build and $gtm_useproc is set, send it through + * gtmsecshr anyway. */ int sem_rmid(int ipcid) { - int status; + int status, save_errno; + char buff[128]; + DCL_THREADGBL_ACCESS; - if (-1 == semctl(ipcid, 0, IPC_RMID)) + SETUP_THREADGBL_ACCESS; + DEBUG_ONLY(if (!TREF(gtm_usesecshr))) { - if (EPERM != errno) + if (-1 == semctl(ipcid, 0, IPC_RMID)) { - gtm_putmsg(VARLSTCNT(1) errno); - return -1; - } else - { - if (0 != (status = REMIPC(REMOVE_SEM, ipcid))) + if (EPERM != errno) { - gtm_putmsg(VARLSTCNT(1) status); + save_errno = errno; + SNPRINTF(buff, 128, "semctl(IPC_RMID, %d)", ipcid); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_STR(buff), CALLFROM, save_errno); + errno = save_errno; return -1; + } else + { + if (0 != (status = REMIPC(REMOVE_SEM, ipcid))) + { + errno = status; + return -1; + } } } } +# ifdef DEBUG + else if (0 != (status = REMIPC(REMOVE_SEM, ipcid))) + { + errno = status; + return -1; + } +# endif return 0; } /* Remove a shared memory id */ int shm_rmid(int ipcid) { - int status; + int status, save_errno; + char buff[128]; + DCL_THREADGBL_ACCESS; - if (-1 == shmctl(ipcid, IPC_RMID, NULL)) + SETUP_THREADGBL_ACCESS; + DEBUG_ONLY(if (!TREF(gtm_usesecshr))) { - if (EPERM != errno) + if (-1 == shmctl(ipcid, IPC_RMID, NULL)) { - gtm_putmsg(VARLSTCNT(1) errno); - return -1; - } else - { - if (0 != (status = REMIPC(REMOVE_SHMMEM, ipcid))) + if (EPERM != errno) { - gtm_putmsg(VARLSTCNT(1) status); + save_errno = errno; + SNPRINTF(buff, 128, "semctl(IPC_RMID, %d)", ipcid); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_STR(buff), CALLFROM, save_errno); + errno = save_errno; return -1; + } else + { + if (0 != (status = REMIPC(REMOVE_SHM, ipcid))) + { + errno = status; + return -1; + } } } } +# ifdef DEBUG + else if (0 != (status = REMIPC(REMOVE_SHM, ipcid))) + { + errno = status; + return -1; + } +# endif return 0; } diff --git a/sr_unix/jnl_file_extend.c b/sr_unix/jnl_file_extend.c index b1bc0c1..90c4834 100644 --- a/sr_unix/jnl_file_extend.c +++ b/sr_unix/jnl_file_extend.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,11 +33,15 @@ #include "dbfilop.h" #include "disk_block_available.h" #include "wcs_flu.h" +#include "anticipatory_freeze.h" +#include "error.h" GBLREF gd_region *gv_cur_region; +GBLREF jnl_gbls_t jgbl; +GBLREF jnlpool_addrs jnlpool; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; -GBLREF jnl_gbls_t jgbl; +GBLREF boolean_t in_jnl_file_autoswitch; error_def(ERR_JNLEXTEND); error_def(ERR_JNLREADEOF); @@ -66,9 +70,10 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) char prev_jnl_fn[JNL_NAME_SIZE]; uint4 jnl_status = 0, status; int new_blocks, warn_blocks, result; - GTM_BAVAIL_TYPE avail_blocks; + gtm_uint64_t avail_blocks; uint4 aligned_tot_jrec_size, count; uint4 jnl_fs_block_size, read_write_size; + DCL_THREADGBL_ACCESS; switch(jpc->region->dyn.addr->acc_meth) { @@ -117,23 +122,35 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) if ((warn_blocks * EXTEND_WARNING_FACTOR) > avail_blocks) { if (new_blocks > avail_blocks) - { /* if we cannot satisfy the request, it is an error */ - send_msg(VARLSTCNT(6) ERR_NOSPACEEXT, 4, JNL_LEN_STR(csd), - new_blocks, avail_blocks); - new_blocks = 0; - jpc->status = SS_NORMAL; - break; + { /* If we cannot satisfy the request, it is an error, unless the anticipatory freeze + * scheme is in effect in which case, we will assume space is available even if + * it is not and go ahead with writes to the disk. If the writes fail with ENOSPC + * we will freeze the instance and wait for space to become available and keep + * retrying the writes. Therefore, we make the NOSPACEEXT a warning in this case. + */ + SETUP_THREADGBL_ACCESS; + if (!ANTICIPATORY_FREEZE_ENABLED(csa)) + { + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_NOSPACEEXT, 4, + JNL_LEN_STR(csd), new_blocks, avail_blocks); + new_blocks = 0; + jpc->status = SS_NORMAL; + break; + } else + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4, + JNL_LEN_STR(csd), new_blocks, avail_blocks); } else - send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd), - (avail_blocks - warn_blocks)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd), + (avail_blocks - warn_blocks)); } } else - send_msg(VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status); new_alq = jb->filesize + new_blocks; /* ensure current journal file size is well within autoswitchlimit --> design constraint */ assert(csd->autoswitchlimit >= jb->filesize); if (csd->autoswitchlimit < (jb->filesize + (EXTEND_WARNING_FACTOR * new_blocks))) /* close to max */ - send_msg(VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd), csd->autoswitchlimit - jb->filesize); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd), + csd->autoswitchlimit - jb->filesize); if (csd->autoswitchlimit < new_alq) { /* Reached max, need to autoswitch */ /* Ensure new journal file can hold the entire current transaction's journal record requirements */ @@ -145,18 +162,49 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) jnl_status = jnl_ensure_open(); if (0 == jnl_status) { /* flush the cache and jnl-buffer-contents to current journal file before - * switching to a new journal. */ - wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH); + * switching to a new journal. Set a global variable in_jnl_file_autoswitch + * so jnl_write can know not to do the padding check. But because this is a global + * variable, we also need to make sure it is reset in case of errors during the + * autoswitch (or else calls to jnl_write after we are out of the autoswitch logic + * will continue to incorrectly not do the padding check. Hence a condition handler. + */ + assert(!in_jnl_file_autoswitch); + in_jnl_file_autoswitch = TRUE; + /* Also make sure time is not changed. This way if "jnl_write" as part of writing a + * journal record invokes jnl_file_extend, when the autoswitch is done and writing + * of the parent jnl_write resumes, we want it to continue with the same timestamp + * and not have to reset its time (non-trivial task) to reflect any changes since then. + */ + assert(!jgbl.save_dont_reset_gbl_jrec_time); + jgbl.save_dont_reset_gbl_jrec_time = jgbl.dont_reset_gbl_jrec_time; + jgbl.dont_reset_gbl_jrec_time = TRUE; + /* Establish a condition handler so we reset a few global variables that have + * temporarily been modified in case of errors inside wcs_flu/jnl_file_close. + */ + ESTABLISH_RET(jnl_file_autoswitch_ch, EXIT_ERR); + /* It is possible we still have not written a PINI record in this journal file + * (e.g. mupip extend saw the need to do jnl_file_extend inside jnl_write while + * trying to write a PINI record). Write a PINI record in that case before closing + * the journal file that way the EOF record will have a non-zero pini_addr. + */ + if (0 == jpc->pini_addr) + jnl_put_jrt_pini(csa); + wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SPEEDUP_NOBEFORE); jnl_file_close(gv_cur_region, TRUE, TRUE); + REVERT; + in_jnl_file_autoswitch = FALSE; + jgbl.dont_reset_gbl_jrec_time = jgbl.save_dont_reset_gbl_jrec_time; + DEBUG_ONLY(jgbl.save_dont_reset_gbl_jrec_time = FALSE); assert((dba_mm == cs_data->acc_meth) || (csd == cs_data)); csd = cs_data; /* In MM, wcs_flu() can remap an extended DB, so reset csd to be sure */ } else { if (SS_NORMAL != jpc->status) - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), - jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region), jpc->status); else - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region)); } assert(!jgbl.forw_phase_recovery || (NULL != jgbl.mur_pini_addr_reset_fnptr)); assert(jgbl.forw_phase_recovery || (NULL == jgbl.mur_pini_addr_reset_fnptr)); @@ -175,7 +223,7 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) assert(csd->jnl_before_image == jnl_info.before_images); csd->jnl_checksum = jnl_info.checksum; csd->jnl_eovtn = csd->trans_hist.curr_tn; - send_msg(VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd)); fc = gv_cur_region->dyn.addr->file_cntl; fc->op = FC_WRITE; fc->op_buff = (sm_uc_ptr_t)csd; @@ -183,17 +231,18 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) fc->op_pos = 1; status = dbfilop(fc); if (SS_NORMAL != status) - send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status); assert(JNL_ENABLED(csa)); /* call jnl_ensure_open instead of jnl_file_open to make sure jpc->pini_addr is set to 0 */ jnl_status = jnl_ensure_open(); /* sets jpc->status */ if (0 != jnl_status) { if (jpc->status) - rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), - jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region), jpc->status); else - rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), + DB_LEN_STR(gv_cur_region)); } assert(jb->filesize == csd->jnl_alq); if (csd->jnl_alq + csd->jnl_deq <= csd->autoswitchlimit) @@ -212,7 +261,7 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) } } else { - send_msg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd)); jpc->status = ERR_JNLNOCREATE; new_blocks = -1; } @@ -228,24 +277,38 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size) if (SS_NORMAL != jpc->status) { assert(FALSE); - rts_error(VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status); } assert((header->virtual_size + new_blocks) == new_alq); jb->filesize = new_alq; /* Actually this is virtual file size blocks */ header->virtual_size = new_alq; - DO_FILE_WRITE(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); + JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, + header, read_write_size, jpc->status, jpc->status2); if (SS_NORMAL != jpc->status) { - assert(FALSE); - rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status); + assert(WBTEST_RECOVER_ENOSPC == gtm_white_box_test_case_number); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status); } } if (0 >= new_blocks) break; } if (0 < new_blocks) + { + INCR_GVSTATS_COUNTER(csa, csa->nl, n_jnl_extends, 1); return EXIT_NRM; + } jpc->status = ERR_JNLREADEOF; jnl_file_lost(jpc, ERR_JNLEXTEND); return EXIT_ERR; } + +CONDITION_HANDLER(jnl_file_autoswitch_ch) +{ + START_CH; + assert(in_jnl_file_autoswitch); + in_jnl_file_autoswitch = FALSE; + jgbl.dont_reset_gbl_jrec_time = jgbl.save_dont_reset_gbl_jrec_time; + DEBUG_ONLY(jgbl.save_dont_reset_gbl_jrec_time = FALSE); + NEXTCH; +} diff --git a/sr_unix/jnl_fsync.c b/sr_unix/jnl_fsync.c index 6207b43..69e36bd 100644 --- a/sr_unix/jnl_fsync.c +++ b/sr_unix/jnl_fsync.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,10 +33,11 @@ #include "gtm_string.h" #include "gtm_c_stack_trace.h" #include "gtmsecshr.h" /* for continue_proc */ +#include "anticipatory_freeze.h" +#include "wbox_test_init.h" #ifdef DEBUG #include "gt_timer.h" #include "gtm_stdio.h" -#include "wbox_test_init.h" #include "is_proc_alive.h" #endif @@ -49,8 +50,6 @@ error_def(ERR_JNLFSYNCERR); error_def(ERR_JNLFSYNCLSTCK); error_def(ERR_TEXT); -#define CURRENT_WRITER jb->fsync_in_prog_latch.u.parts.latch_pid - void jnl_fsync(gd_region *reg, uint4 fsync_addr) { jnl_private_control *jpc; @@ -65,60 +64,55 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr) csa = &FILE_INFO(reg)->s_addrs; jpc = csa->jnl; jb = jpc->jnl_buff; - /* If a concurrent online rollback is running, we should never be here since online rollback at the start flushes all the - * dirty buffers and ensures that the journal buffers are all synced to disk. So, there is no need for GT.M processes to - * reach here with a concurrent online rollback. Assert to that effect. - */ - DEBUG_ONLY(onln_rlbk_pid = csa->nl->onln_rlbk_pid); - assert(jgbl.onlnrlbk || !onln_rlbk_pid || !is_proc_alive(onln_rlbk_pid, 0)); + assert(process_id != CURRENT_JNL_FSYNC_WRITER(jb)); if ((NOJNL != jpc->channel) && !JNL_FILE_SWITCHED(jpc)) { csd = csa->hdr; for (lcnt = 1; fsync_addr > jb->fsync_dskaddr && !JNL_FILE_SWITCHED(jpc); lcnt++) { - if (MAX_FSYNC_WAIT_CNT / 2 == lcnt) /* half way into the wait timeout */ + if (0 == (lcnt % FSYNC_WAIT_HALF_TIME)) { saved_status = jpc->status; jpc->status = SS_NORMAL; - DEBUG_ONLY( - if (CURRENT_WRITER) - GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK_HALF_TIME", - process_id, CURRENT_WRITER, ONCE); - ) +# ifdef DEBUG + if (CURRENT_JNL_FSYNC_WRITER(jb)) + GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK_HALF_TIME", + process_id, CURRENT_JNL_FSYNC_WRITER(jb), lcnt / FSYNC_WAIT_HALF_TIME); +# endif jnl_send_oper(jpc, ERR_JNLFSYNCLSTCK); jpc->status = saved_status; - } else if (MAX_FSYNC_WAIT_CNT < lcnt) /* timed-out waiting for the fsync lock */ + } + else if (0 == (lcnt % FSYNC_WAIT_TIME)) { saved_status = jpc->status; jpc->status = SS_NORMAL; - if (CURRENT_WRITER) - GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK", process_id, CURRENT_WRITER, TWICE); + if (CURRENT_JNL_FSYNC_WRITER(jb)) + GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK", + process_id, CURRENT_JNL_FSYNC_WRITER(jb), lcnt / FSYNC_WAIT_HALF_TIME); jnl_send_oper(jpc, ERR_JNLFSYNCLSTCK); jpc->status = saved_status; - send_msg(VARLSTCNT(4) ERR_FSYNCTIMOUT, 2, JNL_LEN_STR(csd)); - GTMASSERT; } BG_TRACE_PRO_ANY(csa, n_jnl_fsync_tries); if (GET_SWAPLOCK(&jb->fsync_in_prog_latch)) break; wcs_sleep(lcnt); /* trying to wake up the lock holder one iteration before calling c_script */ - if ((MAX_FSYNC_WAIT_CNT / 2 - 1 == lcnt) || (MAX_FSYNC_WAIT_CNT == lcnt)) + if ((lcnt % FSYNC_WAIT_HALF_TIME) == (FSYNC_WAIT_HALF_TIME - 1)) performCASLatchCheck(&jb->fsync_in_prog_latch, TRUE); } - DEBUG_ONLY( - if (gtm_white_box_test_case_enabled - && (WBTEST_EXTEND_JNL_FSYNC == gtm_white_box_test_case_number)) - { - FPRINTF(stderr, "JNL_FSYNC: will sleep for 40 seconds\n", process_id); - LONG_SLEEP(40); - FPRINTF(stderr, "JNL_FSYNC: done sleeping\n", process_id); - gtm_white_box_test_case_enabled = FALSE; - } - ) +# ifdef DEBUG + if (gtm_white_box_test_case_enabled + && (WBTEST_EXTEND_JNL_FSYNC == gtm_white_box_test_case_number)) + { + FPRINTF(stderr, "JNL_FSYNC: will sleep for 40 seconds\n", process_id); + LONG_SLEEP(40); + FPRINTF(stderr, "JNL_FSYNC: done sleeping\n", process_id); + gtm_white_box_test_case_enabled = FALSE; + } +# endif if (fsync_addr > jb->fsync_dskaddr && !JNL_FILE_SWITCHED(jpc)) { - assert(process_id == jb->fsync_in_prog_latch.u.parts.latch_pid); /* assert we have the lock */ + assert(process_id == CURRENT_JNL_FSYNC_WRITER(jb)); /* assert we have the lock */ saved_dsk_addr = jb->dskaddr; if (jpc->sync_io) { /* We need to maintain the fsync control fields irrespective of the type of IO, because we might @@ -127,14 +121,25 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr) jb->fsync_dskaddr = saved_dsk_addr; } else { - GTM_FSYNC(jpc->channel, fsync_ret); + /* If a concurrent online rollback is running, we should never be here since online rollback at the + * start flushes all the dirty buffers and ensures that the journal buffers are all synced to disk. + * So, there is no need for GT.M processes to reach here with a concurrent online rollback. Assert + * to that effect. + */ + DEBUG_ONLY(onln_rlbk_pid = csa->nl->onln_rlbk_pid); + assert(jgbl.onlnrlbk || !onln_rlbk_pid || !is_proc_alive(onln_rlbk_pid, 0) + || (onln_rlbk_pid != csa->nl->in_crit)); + GTM_JNL_FSYNC(csa, jpc->channel, fsync_ret); + GTM_WHITE_BOX_TEST(WBTEST_FSYNC_SYSCALL_FAIL, fsync_ret, -1); + WBTEST_ASSIGN_ONLY(WBTEST_FSYNC_SYSCALL_FAIL, errno, EIO); if (-1 == fsync_ret) { save_errno = errno; - assert(FALSE); - send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), + assert(WBTEST_ENABLED(WBTEST_FSYNC_SYSCALL_FAIL)); + RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), save_errno); - rts_error(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), + rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), save_errno); } else { @@ -143,8 +148,9 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr) } } } - if (process_id == jb->fsync_in_prog_latch.u.parts.latch_pid) + if (process_id == CURRENT_JNL_FSYNC_WRITER(jb)) RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch); } + assert(process_id != CURRENT_JNL_FSYNC_WRITER(jb)); return; } diff --git a/sr_unix/jnl_output_sp.c b/sr_unix/jnl_output_sp.c index 33b0f8c..80cb1f9 100644 --- a/sr_unix/jnl_output_sp.c +++ b/sr_unix/jnl_output_sp.c @@ -1,6 +1,6 @@ /*************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,7 +12,7 @@ #include "mdef.h" #include -#include "gtm_unistd.h" /* fsync() needs this */ +#include "gtm_unistd.h" /* DB_FSYNC macro needs this */ #include "gtm_string.h" #include "gtmio.h" /* this has to come in before gdsfhead.h, for all "open" to be defined @@ -37,12 +37,14 @@ #include "repl_sp.h" /* for F_CLOSE used by the JNL_FD_CLOSE macro */ #include "memcoherency.h" #include "gtm_dbjnl_dupfd_check.h" +#include "anticipatory_freeze.h" GBLREF volatile int4 db_fsync_in_prog; GBLREF volatile int4 jnl_qio_in_prog; GBLREF uint4 process_id; error_def(ERR_DBFSYNCERR); +error_def(ERR_ENOSPCQIODEFER); error_def(ERR_JNLACCESS); error_def(ERR_JNLCNTRL); error_def(ERR_JNLRDERR); @@ -63,6 +65,7 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) jnl_buffer_ptr_t jb; int4 free_ptr; sgmnt_addrs *csa; + node_local_ptr_t cnl; sm_uc_ptr_t base; unix_db_info *udi; unsigned int status; @@ -72,9 +75,11 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) int aligned_tsz; sm_uc_ptr_t aligned_base; uint4 jnl_fs_block_size; + gd_region *reg; assert(NULL != jpc); - udi = FILE_INFO(jpc->region); + reg = jpc->region; + udi = FILE_INFO(reg); csa = &udi->s_addrs; jb = jpc->jnl_buff; if (jb->io_in_prog_latch.u.parts.latch_pid == process_id) /* We already have the lock? */ @@ -86,6 +91,16 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) assert(0 <= jnl_qio_in_prog); return ERR_JNLWRTDEFER; } +# ifdef DEBUG + /* When jnl_sub_qio_start() is called as part of WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP white-box test case, + * aligned_write should always be FALSE. But depending upon the filesystem block size, it is possible that + * the function could also be called with aligned_write being TRUE. This could lead to sending SIGTSTP + * twice. Hence ensure that SIGTSTP is sent only for the unaligned write. + */ + if (gtm_white_box_test_case_enabled && (WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP == gtm_white_box_test_case_number) + && !aligned_write) + kill(process_id, SIGTSTP); +# endif if (jb->dsk != (jb->dskaddr % jb->size)) { RELEASE_SWAPLOCK(&jb->io_in_prog_latch); @@ -111,13 +126,16 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) */ if (jb->need_db_fsync) { - DB_FSYNC(jpc->region, udi, csa, db_fsync_in_prog, save_errno); + DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno); + GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_DBFSYNCERR, save_errno, EIO); if (0 != save_errno) { RELEASE_SWAPLOCK(&jb->io_in_prog_latch); jnl_qio_in_prog--; assert(0 <= jnl_qio_in_prog); - rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(jpc->region), save_errno); + /* DBFSYNCERR can potentially cause syslog flooding. Remove the following line if we it becomes an issue. */ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); assert(FALSE); /* should not come here as the rts_error above should not return */ return ERR_DBFSYNCERR; /* ensure we do not fall through to the code below as we no longer have the lock */ } @@ -182,7 +200,8 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) /* Assert that both ends of the source buffer for the write falls within journal buffer limits */ assert(aligned_base >= &jb->buff[jb->buff_off]); assert(aligned_base + aligned_tsz <= &jb->buff[jb->buff_off + jb->size]); - LSEEKWRITE(jpc->channel, (off_t)aligned_dskaddr, aligned_base, aligned_tsz, jpc->status); + JNL_LSEEKWRITE(csa, csa->hdr->jnl_file_name, jpc->channel, + (off_t)aligned_dskaddr, aligned_base, (size_t)aligned_tsz, jpc->status); status = jpc->status; if (SS_NORMAL == status) { /* update jnl_buff pointers to reflect the successful write to the journal file */ @@ -201,15 +220,25 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) jb->dsk = jpc->new_dsk; jb->dskaddr = jpc->new_dskaddr; jpc->dsk_update_inprog = FALSE; + cnl = csa->nl; + INCR_GVSTATS_COUNTER(csa, cnl, n_jfile_bytes, aligned_tsz); + INCR_GVSTATS_COUNTER(csa, cnl, n_jfile_writes, 1); } else { - assert(ENOSPC == status); + assert((ENOSPC == status) || (ERR_ENOSPCQIODEFER == status)); jb->errcnt++; if (ENOSPC == status) jb->enospc_errcnt++; else jb->enospc_errcnt = 0; - jnl_send_oper(jpc, ERR_JNLACCESS); + + if (ERR_ENOSPCQIODEFER != status) + { + jnl_send_oper(jpc, ERR_JNLACCESS); + jpc->status = status; /* set jpc->status back to original error as jnl_send_oper resets + * jpc->status to SS_NORMAL. We need it in callers of this function + * (e.g. jnl_write_attempt). */ + } # ifdef GTM_FD_TRACE if ((EBADF == status) || (ESPIPE == status)) { /* likely case of D9I11-002714. check if fd is valid */ @@ -219,13 +248,16 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write) * if the fd in itself is valid and points back to the journal file. If not reset it to NOJNL. */ if (NOJNL != jpc->channel) - gtm_check_fd_is_valid(jpc->region, FALSE, jpc->channel); + gtm_check_fd_is_valid(reg, FALSE, jpc->channel); /* If jpc->channel still did not get reset to NOJNL, it means the file descriptor is valid but * not sure why we are getting EBADF/ESPIPE errors. No further recovery attempted at this point. */ } # endif - status = ERR_JNLACCESS; + if (ERR_ENOSPCQIODEFER == status) + status = ERR_JNLWRTDEFER; + else + status = ERR_JNLACCESS; } } RELEASE_SWAPLOCK(&jb->io_in_prog_latch); diff --git a/sr_unix/jnlpool_init.c b/sr_unix/jnlpool_init.c index 6d2bc6a..5437293 100644 --- a/sr_unix/jnlpool_init.c +++ b/sr_unix/jnlpool_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -51,25 +51,36 @@ #include "send_msg.h" #include "heartbeat_timer.h" #include "lockconst.h" +#include "anticipatory_freeze.h" +#include "have_crit.h" +#include "gtmsource_srv_latch.h" +#include "util.h" /* For OUT_BUFF_SIZE */ -GBLREF jnlpool_addrs jnlpool; -GBLREF recvpool_addrs recvpool; -GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; -GBLREF sm_uc_ptr_t jnldata_base; -GBLREF uint4 process_id; -GBLREF gd_region *gv_cur_region; -GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; -GBLREF gtmsource_options_t gtmsource_options; -GBLREF boolean_t pool_init; -GBLREF uint4 process_id; -GBLREF seq_num seq_num_zero; -GBLREF enum gtmImageTypes image_type; -GBLREF node_local_ptr_t locknl; -GBLREF uint4 log_interval; -GBLREF boolean_t is_updproc; -GBLREF uint4 mutex_per_process_init_pid; -GBLREF repl_conn_info_t *this_side, *remote_side; -GBLREF int4 strm_index; +GBLREF jnlpool_addrs jnlpool; +GBLREF recvpool_addrs recvpool; +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +GBLREF sm_uc_ptr_t jnldata_base; +GBLREF uint4 process_id; +GBLREF gd_region *gv_cur_region; +GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; +GBLREF gtmsource_options_t gtmsource_options; +GBLREF boolean_t pool_init; +GBLREF seq_num seq_num_zero; +GBLREF enum gtmImageTypes image_type; +GBLREF node_local_ptr_t locknl; +GBLREF uint4 log_interval; +GBLREF boolean_t is_updproc; +GBLREF uint4 mutex_per_process_init_pid; +GBLREF repl_conn_info_t *this_side, *remote_side; +GBLREF int4 strm_index; +GBLREF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr; +GBLREF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr; +GBLREF err_ctl merrors_ctl; +GBLREF jnl_gbls_t jgbl; + +#ifdef DEBUG +GBLREF boolean_t is_updhelper; +#endif LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; @@ -92,7 +103,7 @@ error_def(ERR_SRCSRVNOTEXIST); error_def(ERR_SRCSRVTOOMANY); error_def(ERR_TEXT); -#define REMOVE_OR_RELEASE_SEM(NEW_IPC, UDI) \ +#define REMOVE_OR_RELEASE_SEM(NEW_IPC) \ { \ if (NEW_IPC) \ remove_sem_set(SOURCE); \ @@ -108,7 +119,7 @@ error_def(ERR_TEXT); if (NULL != jnlpool.jnlpool_ctl) \ { \ if (-1 == shmdt((caddr_t)jnlpool.jnlpool_ctl)) \ - gtm_putmsg(VARLSTCNT(5) ERR_REPLWARN, 2, \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2, \ RTS_ERROR_LITERAL("Could not detach from journal pool"), errno); \ jnlpool_ctl = NULL; \ jnlpool.jnlpool_ctl = NULL; \ @@ -120,7 +131,7 @@ error_def(ERR_TEXT); } \ assert(INVALID_SHMID != udi->shmid); \ if (0 != shm_rmid(udi->shmid)) \ - gtm_putmsg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, \ RTS_ERROR_LITERAL("Error removing jnlpool "), errno); \ remove_sem_set(SOURCE); \ } \ @@ -130,7 +141,8 @@ error_def(ERR_TEXT); { \ if ((GTMSOURCE_DUMMY_STATE != gtmsourcelocal_ptr->gtmsource_state) || (0 != gtmsourcelocal_ptr->gtmsource_pid)) \ { /* Slot is in an out-of-design situation. Send an operator log message with enough debugging detail */ \ - send_msg(VARLSTCNT(7) ERR_JNLPOOLBADSLOT, 5, LEN_AND_STR((char *)gtmsourcelocal_ptr->secondary_instname), \ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLBADSLOT, 5, \ + LEN_AND_STR((char *)gtmsourcelocal_ptr->secondary_instname), \ gtmsourcelocal_ptr->gtmsource_pid, gtmsourcelocal_ptr->gtmsource_state, \ gtmsourcelocal_ptr->gtmsrc_lcl_array_index); \ } \ @@ -139,7 +151,8 @@ error_def(ERR_TEXT); void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t *jnlpool_creator) { boolean_t new_ipc, is_src_srvr, slot_needs_init, reset_gtmsrclcl_info, hold_onto_ftok_sem, srv_alive; - char machine_name[MAX_MCNAMELEN], instfilename[MAX_FN_LEN + 1]; + boolean_t skip_locks; + char machine_name[MAX_MCNAMELEN], instfilename[MAX_FN_LEN + 1], scndry_msg[OUT_BUFF_SIZE]; gd_region *r_save, *reg; int status, save_errno; int4 index; @@ -161,11 +174,16 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t repl_histinfo last_histinfo; jnlpool_ctl_ptr_t tmp_jnlpool_ctl; DEBUG_ONLY(int4 semval;) + DEBUG_ONLY(boolean_t sem_created = FALSE;) + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(gtmsource_startup == gtmsource_options.start); + skip_locks = (gtmsource_options.setfreeze && (gtmsource_options.freezeval == FALSE)) || + gtmsource_options.showfreeze; memset(machine_name, 0, SIZEOF(machine_name)); if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, status)) - rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno); if (NULL == recvpool.recvpool_dummy_reg) { r_save = gv_cur_region; @@ -182,7 +200,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * "ftok_sem_get" done with either "jnlpool.jnlpool_dummy_reg" region or "recvpool.recvpool_dummy_reg" region * locks the same entity. */ - assert(is_updproc); /* Should have already attached to receive pool only in case of update process */ + assert(is_updproc || ((GTMRELAXED == pool_user) && is_updhelper)); reg = jnlpool.jnlpool_dummy_reg = recvpool.recvpool_dummy_reg; } udi = FILE_INFO(reg); @@ -204,7 +222,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * or shut down replication for this instance. We will release ftok semaphore when initialization is done. */ if (!ftok_sem_get(jnlpool.jnlpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE)) - rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); is_src_srvr = (GTMSOURCE == pool_user); /* If caller is source server and secondary instance name has been specified check if it is different from THIS instance */ @@ -213,7 +231,8 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t if (0 == STRCMP(repl_instance.inst_info.this_instname, gtmsource_options.secondary_instname)) { ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_REPLINSTNMSAME, 2, LEN_AND_STR((char *)repl_instance.inst_info.this_instname)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINSTNMSAME, 2, + LEN_AND_STR((char *)repl_instance.inst_info.this_instname)); } } new_ipc = FALSE; @@ -224,20 +243,25 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t if (!is_src_srvr || !gtmsource_options.start) { ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn); + if (GTMRELAXED == pool_user) + return; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn); } if (repl_instance.crash) { ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_REPLREQROLLBACK, 2, full_len, udi->fn); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has crash field set to TRUE"); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, + LEN_AND_STR(scndry_msg)); } + DEBUG_ONLY(sem_created = TRUE); new_ipc = TRUE; assert(NUM_SRC_SEMS == NUM_RECV_SEMS); if (INVALID_SEMID == (udi->semid = init_sem_set_source(IPC_PRIVATE, NUM_SRC_SEMS, RWDALL | IPC_CREAT))) { ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error creating journal pool semaphore"), REPL_SEM_ERRNO); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error creating journal pool semaphore"), errno); } /* Following will set semaphore SOURCE_ID_SEM value as GTM_ID. In case we have orphaned semaphore * for some reason, mupip rundown will be able to identify GTM semaphores checking the value and can remove. @@ -248,7 +272,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t save_errno = errno; remove_sem_set(SOURCE); /* Remove what we created */ ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with jnlpool semctl SETVAL"), save_errno); } /* Warning: We must read the sem_ctime using IPC_STAT after SETVAL, which changes it. We must NOT do any @@ -260,24 +284,29 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t save_errno = errno; remove_sem_set(SOURCE); /* Remove what we created */ ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with jnlpool semctl IPC_STAT"), save_errno); } udi->gt_sem_ctime = semarg.buf->sem_ctime; } else { /* find create time of semaphore from the file header and check if the id is reused by others */ - assert(repl_instance.crash); + assert(repl_instance.crash || jgbl.mur_rollback); semarg.buf = &semstat; - if (-1 == semctl(repl_instance.jnlpool_semid, 0, IPC_STAT, semarg)) + if (-1 == semctl(repl_instance.jnlpool_semid, DB_CONTROL_SEM, IPC_STAT, semarg)) { save_errno = errno; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(5) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, save_errno); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SEMID (%d)", + repl_instance.jnlpool_semid); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, + ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno); } else if (semarg.buf->sem_ctime != repl_instance.jnlpool_semid_ctime) { ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, - ERR_TEXT, 2, RTS_ERROR_TEXT("jnlpool sem_ctime does not match")); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Creation time for Journal Pool SEMID (%d) is %d; Expected %d", + repl_instance.jnlpool_semid, semarg.buf->sem_ctime, repl_instance.jnlpool_semid_ctime); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, + LEN_AND_STR(scndry_msg)); } udi->semid = repl_instance.jnlpool_semid; udi->gt_sem_ctime = repl_instance.jnlpool_semid_ctime; @@ -285,14 +314,18 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t } assert((INVALID_SEMID != udi->semid) && (0 != udi->gt_sem_ctime)); assert(!udi->grabbed_access_sem); - status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM); - if (SS_NORMAL != status) + if (!skip_locks) { - ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with journal pool access semaphore"), REPL_SEM_ERRNO); + status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM); + if (SS_NORMAL != status) + { + ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error with journal pool access semaphore"), errno); + } + udi->grabbed_access_sem = TRUE; + udi->counter_acc_incremented = TRUE; } - udi->grabbed_access_sem = TRUE; if (INVALID_SHMID == repl_instance.jnlpool_shmid) { /* We have an INVALID shmid in the file header. There are three ways this can happen * @@ -316,9 +349,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t } else if (-1 == shmctl(repl_instance.jnlpool_shmid, IPC_STAT, &shmstat)) { /* shared memory ID was removed form the system by an IPCRM command or we have a permission issue (or such) */ save_errno = errno; - REMOVE_OR_RELEASE_SEM(new_ipc, udi); + REMOVE_OR_RELEASE_SEM(new_ipc); ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(5) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, save_errno); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SHMID (%d)", repl_instance.jnlpool_shmid); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, + LEN_AND_STR(scndry_msg), save_errno); } else if (shmstat.shm_ctime != repl_instance.jnlpool_shmid_ctime) { /* shared memory was possibly reused (causing shm_ctime and jnlpool_shmid_ctime to be different. We can't rely * on the shmid as it could be connected to a valid instance file in a different environment. Create new IPCs @@ -332,16 +367,29 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t /* Source server startup is the only command that can create the journal pool. Check that. */ if (new_ipc && (!is_src_srvr || !gtmsource_options.start)) { - REMOVE_OR_RELEASE_SEM(new_ipc, udi); + REMOVE_OR_RELEASE_SEM(new_ipc); ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn); + if (GTMRELAXED == pool_user) + return; + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn); } if (repl_instance.file_corrupt) - { /* A prior rollback on this instance have been killed in the middle. Can't proceed until rollback is-rerun */ - REMOVE_OR_RELEASE_SEM(new_ipc, udi); - ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, - ERR_TEXT, 2, LEN_AND_LIT("file_corrupt field in instance file header is set to TRUE")); + { /* Indicates that a prior rollback was killed and so requires a re-run. It is also possible this process started + * waiting on the semaphores during a concurrent rollback and so has a stale file header values. Read the instance + * file header again to see if the file_corrupt field is still TRUE. + */ + repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); + assert((udi->shmid == repl_instance.jnlpool_shmid) && (udi->gt_shm_ctime == repl_instance.jnlpool_shmid_ctime)); + assert(sem_created || ((udi->semid == repl_instance.jnlpool_semid) && (udi->gt_sem_ctime == + repl_instance.jnlpool_semid_ctime))); + if (repl_instance.file_corrupt) + { + REMOVE_OR_RELEASE_SEM(new_ipc); + ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE"); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, + LEN_AND_STR(scndry_msg)); + } } if (new_ipc) { /* create new shared memory */ @@ -351,7 +399,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t save_errno = errno; remove_sem_set(SOURCE); ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with journal pool creation"), save_errno); } if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat)) @@ -359,7 +407,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t save_errno = errno; DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */ ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with jnlpool shmctl IPC_STAT"), save_errno); } udi->gt_shm_ctime = shmstat.shm_ctime; @@ -373,7 +421,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert below ensures we dont try to clean up the journal pool even though we errored out while attaching to it */ assert(NULL == jnlpool.jnlpool_ctl); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with journal pool shmat"), save_errno); } jnlpool.jnlpool_ctl = tmp_jnlpool_ctl; @@ -388,6 +436,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * aligned at a boundary that is suitable for journal records (defined by JNL_WRT_END_MASK). */ assert(JNLPOOL_CTL_SIZE % 8 == 0); + /* The assert below trips, if node_local struct is unaligned in gdsbt.h. If you have added a new field, verify that filler + * arrays are adjusted accordingly. + */ assert(JNLPOOL_CRIT_SIZE % 8 == 0); assert(SIZEOF(repl_inst_hdr) % 8 == 0); assert(SIZEOF(gtmsrc_lcl) % 8 == 0); @@ -396,9 +447,19 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t assert(GTMSRC_LCL_SIZE % 8 == 0); assert(GTMSOURCE_LOCAL_SIZE % 8 == 0); assert(JNLDATA_BASE_OFF % JNL_WRT_END_MODULUS == 0); + /* Ensure that the overhead in the journal pool is never greater than gtmsource_options.buffsize as that would indicate a + * out-of-design situation + */ + assert(!gtmsource_options.start || + ((JNLPOOL_CTL_SIZE + JNLPOOL_CRIT_SIZE + REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE) < gtmsource_options.buffsize)); + /* jnlpool_ctl has an array of size MERRORS_ARRAY_SZ which holds one byte of information for each error in the merrors.msg. + * Whenever the below assert fails, the MERRORS_ARRAY_SZ has to be increased while maintaining the 16 byte alignment of the + * journal pool. + */ + assert(MERRORS_ARRAY_SZ > merrors_ctl.msg_cnt); csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); /* secshr_db_clnup uses this * relationship */ - jnlpool_mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE); + jnlpool_mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE); csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)jnlpool_mutex_spin_parms + SIZEOF(mutex_spin_parms_struct)); if (new_ipc) memset(csa->nl, 0, SIZEOF(node_local)); /* Make csa->nl->glob_sec_init FALSE */ @@ -409,16 +470,27 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t jnlpool.gtmsource_local_array = (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool.gtmsrc_lcl_array + GTMSRC_LCL_SIZE); jnldata_base = jnlpool.jnldata_base = (sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLDATA_BASE_OFF; jnlpool_ctl = jnlpool.jnlpool_ctl; - jnlpool_ctl->critical_off = (sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)jnlpool_ctl; - jnlpool_ctl->filehdr_off = (sm_uc_ptr_t)jnlpool.repl_inst_filehdr - (sm_uc_ptr_t)jnlpool_ctl; - jnlpool_ctl->srclcl_array_off = (sm_uc_ptr_t)jnlpool.gtmsrc_lcl_array - (sm_uc_ptr_t)jnlpool_ctl; - jnlpool_ctl->sourcelocal_array_off = (sm_uc_ptr_t)jnlpool.gtmsource_local_array - (sm_uc_ptr_t)jnlpool_ctl; assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id); if (!mutex_per_process_init_pid) mutex_per_process_init(); START_HEARTBEAT_IF_NEEDED; if (new_ipc) - { /* Need to initialize the different sections of journal pool. Start with the FILE HEADER section */ + { + jnlpool_ctl->instfreeze_environ_inited = FALSE; + if (ANTICIPATORY_FREEZE_AVAILABLE && !init_anticipatory_freeze_errors()) + { + DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */ + udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; + ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error initializing custom errors")); + } + jnlpool_ctl->critical_off = (sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)jnlpool_ctl; + jnlpool_ctl->filehdr_off = (sm_uc_ptr_t)jnlpool.repl_inst_filehdr - (sm_uc_ptr_t)jnlpool_ctl; + jnlpool_ctl->srclcl_array_off = (sm_uc_ptr_t)jnlpool.gtmsrc_lcl_array - (sm_uc_ptr_t)jnlpool_ctl; + jnlpool_ctl->sourcelocal_array_off = (sm_uc_ptr_t)jnlpool.gtmsource_local_array - (sm_uc_ptr_t)jnlpool_ctl; + /* Need to initialize the different sections of journal pool. Start with the FILE HEADER section */ repl_instance.jnlpool_semid = udi->semid; repl_instance.jnlpool_shmid = udi->shmid; repl_instance.jnlpool_semid_ctime = udi->gt_sem_ctime; @@ -429,12 +501,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * grab_locks to work correctly */ DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */ - gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE); + gtm_mutex_init(reg, DEFAULT_NUM_CRIT_ENTRY, FALSE); DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */ jnlpool_mutex_spin_parms->mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT; jnlpool_mutex_spin_parms->mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT; jnlpool_mutex_spin_parms->mutex_spin_sleep_mask = MUTEX_SPIN_SLEEP_MASK; - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + jnlpool_mutex_spin_parms->mutex_que_entry_space_size = DEFAULT_NUM_CRIT_ENTRY; + assert(!skip_locks); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); /* Flush the file header to disk so future callers of "jnlpool_init" see the jnlpool_semid and jnlpool_shmid */ repl_inst_flush_filehdr(); /* Initialize GTMSRC_LCL section in journal pool */ @@ -456,10 +530,12 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t } } else if (!jnlpool.jnlpool_ctl->pool_initialized) { /* Source server that created the journal pool died before completing initialization. */ - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(10) ERR_REPLREQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(machine_name), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_REPLREQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(machine_name), ERR_TEXT, 2, RTS_ERROR_TEXT("Journal pool is incompletely initialized. Run MUPIP RUNDOWN first.")); } slot_needs_init = FALSE; @@ -528,12 +604,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t { /* Source server is already up and running for this secondary instance */ if (gtmsource_options.start) { + assert(!skip_locks); rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert we did not create shm or sem so no need to remove any */ assert(!new_ipc); - rts_error(VARLSTCNT(5) ERR_SRCSRVEXISTS, 3, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SRCSRVEXISTS, 3, LEN_AND_STR(gtmsource_options.secondary_instname), gtmsource_pid); } } else @@ -554,12 +632,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * even though the source server is not alive. We can generate backlog/checkhealth * information using values from the matched slot. */ - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert we did not create shm or sem so no need to remove any */ assert(!new_ipc); - rts_error(VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2, LEN_AND_STR(gtmsource_options.secondary_instname)); } } @@ -577,12 +657,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t { /* No used or unused slot found. Issue REPLINSTSECNONE error except for -start */ if (!gtmsource_options.start) { - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert we did not create shm or sem so no need to remove any */ assert(!new_ipc); - rts_error(VARLSTCNT(6) ERR_REPLINSTSECNONE, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTSECNONE, 4, LEN_AND_STR(gtmsource_options.secondary_instname), full_len, udi->fn); } else { /* Find a used slot that can be reused. Find one with least value of "connect_jnl_seqno". */ @@ -603,12 +685,15 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t } if (NULL == reuse_slot_ptr) { - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert we did not create shm or sem so no need to remove any */ assert(!new_ipc); - rts_error(VARLSTCNT(5) ERR_SRCSRVTOOMANY, 3, NUM_GTMSRC_LCL, full_len, udi->fn); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SRCSRVTOOMANY, 3, NUM_GTMSRC_LCL, + full_len, udi->fn); } else { /* We want to reinitialize the source server related fields in "gtmsource_local" * as well as reinitialize any fields that intersect with "gtmsrc_lcl" as this @@ -636,12 +721,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * ACTIVATE, CHANGELOG, CHECKHEALTH, DEACTIVATE, SHOWBACKLOG, * STATSLOG, SHUTDOWN or STOPSOURCEFILTER */ - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); /* Assert we did not create shm or sem so no need to remove any */ assert(!new_ipc); - rts_error(VARLSTCNT(6) ERR_REPLINSTSECNONE, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTSECNONE, 4, LEN_AND_STR(gtmsource_options.secondary_instname), full_len, udi->fn); } } @@ -662,10 +749,12 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * specified -PROPAGATEPRIMARY (or -UPDNOTOK) or a receiver server command is being attempted * on a non-supplementary instance. Issue error. */ - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_PRIMARYISROOT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYISROOT, 2, LEN_AND_STR((char *)repl_instance.inst_info.this_instname)); } } else if (is_src_srvr) @@ -674,12 +763,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t { /* Journal pool was created with a -PROPAGATEPRIMARY command and current source server command * has specified -ROOTPRIMARY (or -UPDOK). */ + assert(!skip_locks); if (!gtmsource_options.activate) { /* START or DEACTIVATE was specified. Issue incompatibility error right away */ rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *)repl_instance.inst_info.this_instname)); } else { /* ACTIVATE was specified. Check if there is only one process attached to the journal @@ -694,8 +785,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t { rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(4) ERR_ACTIVATEFAIL, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ACTIVATEFAIL, 2, LEN_AND_STR(gtmsource_options.secondary_instname)); } else hold_onto_ftok_sem = TRUE; @@ -707,13 +799,17 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t { assert(new_ipc); assert(slot_needs_init); + assert(!skip_locks); + assert(GTMRELAXED != pool_user); if (!is_src_srvr || !gtmsource_options.start) { assert(FALSE); - rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); + if (udi->grabbed_access_sem) + rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Journal pool has not been initialized")); } /* Initialize the shared memory fields. */ @@ -730,20 +826,21 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t QWASSIGNDW(jnlpool_ctl->write_addr, 0); if (0 < jnlpool.repl_inst_filehdr->num_histinfo) { - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); status = repl_inst_histinfo_get(jnlpool.repl_inst_filehdr->num_histinfo - 1, &last_histinfo); rel_lock(jnlpool.jnlpool_dummy_reg); assert(0 == status); if (0 != status) { assert(ERR_REPLINSTNOHIST == status); /* the only error returned by repl_inst_histinfo_get() */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); repl_inst_flush_jnlpool(TRUE, TRUE); /* to reset "crash" field in instance file header to FALSE */ rel_lock(jnlpool.jnlpool_dummy_reg); DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */ udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Error reading last history record in replication instance file")); } instfilehdr_seqno = jnlpool.repl_inst_filehdr->jnl_seqno; @@ -751,13 +848,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t assert(instfilehdr_seqno); if (instfilehdr_seqno < last_histinfo.start_seqno) { /* The jnl seqno in the instance file header is not greater than the last histinfo's start seqno */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); repl_inst_flush_jnlpool(TRUE, TRUE); /* to reset "crash" field in instance file header to FALSE */ rel_lock(jnlpool.jnlpool_dummy_reg); DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */ udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(8) ERR_REPLINSTSEQORD, 6, LEN_AND_LIT("Instance file header"), + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLINSTSEQORD, 6, LEN_AND_LIT("Instance file header"), &instfilehdr_seqno, &last_histinfo.start_seqno, LEN_AND_STR(udi->fn)); } jnlpool_ctl->last_histinfo_seqno = last_histinfo.start_seqno; @@ -776,12 +874,6 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id)); /* ensure that the pool identifier is at the top of the pool */ jnlpool_ctl->jnlpool_id.pool_type = JNLPOOL_SEGMENT; - DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */ - gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE); - DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */ - jnlpool_mutex_spin_parms->mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT; - jnlpool_mutex_spin_parms->mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT; - jnlpool_mutex_spin_parms->mutex_spin_sleep_mask = MUTEX_SPIN_SLEEP_MASK; csa->nl->glob_sec_init = TRUE; assert(NULL != jnlpool_creator); *jnlpool_creator = TRUE; @@ -801,6 +893,8 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t } assert(!(is_src_srvr && gtmsource_options.start) || slot_needs_init); jnlpool.gtmsource_local = gtmsourcelocal_ptr; + assert((NULL == gtmsourcelocal_ptr) + || (gtmsourcelocal_ptr->gtmsrc_lcl_array_index == (gtmsourcelocal_ptr - jnlpool.gtmsource_local_array))); reg->open = TRUE; /* this is used by t_commit_cleanup/tp_restart/mutex_deadlock_check */ reg->read_only = FALSE; /* maintain csa->read_write simultaneously */ csa->read_write = TRUE; /* maintain reg->read_only simultaneously */ @@ -809,6 +903,8 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t assert(is_src_srvr); assert(NULL != gtmsourcelocal_ptr); assert(gtmsource_options.start || gtmsource_options.showbacklog); + assert(!skip_locks); + assert(GTMRELAXED != pool_user); gtmsourcelocal_ptr->gtmsource_pid = 0; gtmsourcelocal_ptr->gtmsource_state = GTMSOURCE_DUMMY_STATE; if (gtmsource_options.start) @@ -818,11 +914,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t gtmsourcelocal_ptr->read = 0; gtmsourcelocal_ptr->read_state = READ_POOL; gtmsourcelocal_ptr->mode = gtmsource_options.mode; - assert(gtmsourcelocal_ptr->gtmsrc_lcl_array_index == (gtmsourcelocal_ptr - jnlpool.gtmsource_local_array)); gtmsourcelocal_ptr->statslog = FALSE; gtmsourcelocal_ptr->shutdown = NO_SHUTDOWN; gtmsourcelocal_ptr->shutdown_time = -1; - gtmsourcelocal_ptr->secondary_inet_addr = gtmsource_options.sec_inet_addr; gtmsourcelocal_ptr->secondary_port = gtmsource_options.secondary_port; STRCPY(gtmsourcelocal_ptr->secondary_host, gtmsource_options.secondary_host); STRCPY(gtmsourcelocal_ptr->filter_cmd, gtmsource_options.filter_cmd); @@ -862,7 +956,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t /* Now make the corresponding changes from gtmsource_local to the gtmsrc_lcl structure and flush to disk. * This assumes "jnlpool.gtmsource_local" is set appropriately. */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); repl_inst_flush_gtmsrc_lcl(); rel_lock(jnlpool.jnlpool_dummy_reg); } @@ -881,15 +975,19 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t */ if (!is_src_srvr) { - if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM))) + if (udi->grabbed_access_sem) { - ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - /* Assert we did not create shm or sem so no need to remove any */ - assert(!new_ipc); - rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error in rel_sem"), save_errno); + if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM))) + { + ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); + /* Assert we did not create shm or sem so no need to remove any */ + assert(!new_ipc); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, + RTS_ERROR_LITERAL("Error in rel_sem"), save_errno); + } + udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; } - udi->grabbed_access_sem = FALSE; } else { this_side = &jnlpool_ctl->this_side; @@ -897,19 +995,26 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t * later when source server connects to receiver */ } if (!hold_onto_ftok_sem && !ftok_sem_release(jnlpool.jnlpool_dummy_reg, FALSE, FALSE)) - rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP); pool_init = TRUE; + ENABLE_FREEZE_ON_ERROR; return; } void jnlpool_detach(void) { + int status, save_errno; + if (TRUE == pool_init) { - if (-1 == shmdt((caddr_t)jnlpool_ctl)) - rts_error(VARLSTCNT(5) ERR_REPLWARN, 2, RTS_ERROR_LITERAL("Could not detach from journal pool"), errno); - jnlpool_ctl = NULL; - jnlpool.jnlpool_ctl = NULL; + rel_lock(jnlpool.jnlpool_dummy_reg); + mutex_cleanup(jnlpool.jnlpool_dummy_reg); + if (jnlpool.gtmsource_local && (process_id == jnlpool.gtmsource_local->gtmsource_srv_latch.u.parts.latch_pid)) + rel_gtmsource_srv_latch(&jnlpool.gtmsource_local->gtmsource_srv_latch); + JNLPOOL_SHMDT(status, save_errno); + if (0 > status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2, + RTS_ERROR_LITERAL("Could not detach from journal pool"), save_errno); jnlpool.repl_inst_filehdr = NULL; jnlpool.gtmsrc_lcl_array = NULL; jnlpool.gtmsource_local_array = NULL; diff --git a/sr_unix/jnlsp.h b/sr_unix/jnlsp.h index 7a84e1b..7f243d6 100644 --- a/sr_unix/jnlsp.h +++ b/sr_unix/jnlsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,7 +25,12 @@ typedef unix_file_info fi_type; #else #define JNL_ALLOC_MAX 8388607 /* 4GB - 512 Bytes */ #endif -#define JNL_BUFFER_DEF ROUND_UP2(128, MAX_IO_BLOCK_SIZE / DISK_BLOCK_SIZE) +/* Since the journal buffer size always gets rounded up to the next multiple of + * MIN(MAX_IO_BLOCK_SIZE, csd->blk_size) / DISK_BLOCK_SIZE), make the default journal + * buffer size a multiple of default-block-size-to-512 ratio, which equals 2. That + * value might need readjustment for certain block sizes, but should currently suit + * well block sizes of 1K and 2K. */ +#define JNL_BUFFER_DEF ROUND_UP(JNL_BUFFER_MIN, 2) #define NOJNL FD_INVALID_NONPOSIX #define MID_TIME(W) W #define EXTTIMEVMS(T) diff --git a/sr_unix/jobchild_init.c b/sr_unix/jobchild_init.c index c35e5e0..d3df53e 100644 --- a/sr_unix/jobchild_init.c +++ b/sr_unix/jobchild_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,6 +35,7 @@ #include "invocation_mode.h" #include "gtmci.h" #include "send_msg.h" +#include "have_crit.h" #define FILE_NAME_SIZE 255 @@ -47,6 +48,7 @@ GBLREF uint4 process_id; error_def(ERR_RUNPARAMERR); error_def(ERR_TEXT); error_def(ERR_SYSCALL); +error_def(ERR_JOBLABOFF); CONDITION_HANDLER(job_init_ch) { @@ -68,6 +70,7 @@ void jobchild_init(void) mval job_args[MAX_ACTUALS]; mstr routine, label; int offset; + int rc; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -82,24 +85,26 @@ void jobchild_init(void) if (PUTENV(CLEAR_CHILD_FLAG_ENV)) { util_out_print("Unable to clear gtmj0 process !UL exiting.", TRUE, process_id); - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); } /* read parameters into parameter structure */ ojchildparms(&jparms, &job_arglist, job_args); /* Execute the command to be run before executing the actual M routine */ - if (jparms.startup.len && (0 != SYSTEM(jparms.startup.addr))) - rts_error(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("STARTUP command failed")); - /* Set up job's input, output and error files. Redirect them, if necessary. - * It is needed since the middle process would not have always done this(under jobpid == TRUE cases) - */ - if (!(status = ojchildioset(&jparms))) - rts_error(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Failed to set STDIN/OUT/ERR for the job")); - job_addr(&jparms.routine, &jparms.label, jparms.offset, (char **)&base_addr, (char **)&transfer_addr); + if (jparms.startup.len) + { + rc = SYSTEM(jparms.startup.addr); + if ((0 != rc)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, + LEN_AND_LIT("STARTUP command failed")); + } + if(!job_addr(&jparms.routine, &jparms.label, jparms.offset, + (char **)&base_addr, (char **)&transfer_addr)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF); /* Set process priority */ if (jparms.baspri) { /* send message to system log if nice fails */ if (-1 == nice((int)jparms.baspri)) - send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("nice"), CALLFROM, errno); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("nice"), CALLFROM, errno); } /* Set up $ZMODE to "OTHER" */ (TREF(dollar_zmode)).mvtype = MV_STR; @@ -130,9 +135,10 @@ void jobchild_init(void) { arg_len = FILE_NAME_SIZE; if (!cli_get_str("INFILE", run_file_name, &arg_len)) - rts_error(VARLSTCNT(1) ERR_RUNPARAMERR); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RUNPARAMERR); lref_parse((uchar_ptr_t)run_file_name, &routine, &label, &offset); - job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr); + if(!job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF); } else if (MUMPS_CALLIN & invocation_mode) /* call-in mode */ { base_addr = make_cimode(); diff --git a/sr_unix/joberr.h b/sr_unix/joberr.h index 1b3f962..b0839cb 100644 --- a/sr_unix/joberr.h +++ b/sr_unix/joberr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,16 +14,31 @@ char *msg; int len; }joberr_msg; +/* + * The follwoing array is index by values from the enum joberr_t from jobsp.h. + */ LITDEF joberr_msg joberrs[] = { "", 0, - "Job error in child process", SIZEOF("Job error in child process")-1, - "Job error in I/O specification", SIZEOF("Job error in I/O specification")-1, - "Job error in directory specification", SIZEOF("Job error in directory specification")-1, - "Job error in routine specification", SIZEOF("Job error in routine specification")-1, - "Job error in fork", SIZEOF("Job error in fork")-1, - "Job error in syscall", SIZEOF("Job error in syscall")-1, - "Job child was stopped by signal", SIZEOF("Job child was stopped by signal")-1, - "Job child terminated due to signal", SIZEOF("Job child terminated due to signal")-1, - "", SIZEOF("")-1 /* this is used internally to determine try-again situations */ + LIT_AND_LEN("Job error in child process"), + LIT_AND_LEN("Job error in opening STDIN"), + LIT_AND_LEN("Job error in directing input to STDIN"), + LIT_AND_LEN("Job error in creating STDOUT"), + LIT_AND_LEN("Job error in opening STDOUT"), + LIT_AND_LEN("Job error in directing output to STDOUT"), + LIT_AND_LEN("Job error in creating STDERR"), + LIT_AND_LEN("Job error in opening STDERR"), + LIT_AND_LEN("Job error in directing output to STDERR"), + LIT_AND_LEN("Job error in directory specification"), + LIT_AND_LEN("Job error - CHDIR error"), + LIT_AND_LEN("Job error in routine specification. Label and offset not found in created process"), + LIT_AND_LEN("Job error in setting independent session"), + LIT_AND_LEN("Job error in fork"), + LIT_AND_LEN("Job error in renaming standard output file"), + LIT_AND_LEN("Job error in renaming standard error file"), + LIT_AND_LEN("Job error in middle process to parent process pipe communication"), + LIT_AND_LEN("Job error in middle process to grandchild process pipe communication"), + LIT_AND_LEN("Job child was stopped by signal"), + LIT_AND_LEN("Job child terminated due to signal"), + LIT_AND_LEN("") /* this is used internally to determine try-again situations */ }; diff --git a/sr_unix/jobsp.h b/sr_unix/jobsp.h index f36b86d..4851ebc 100644 --- a/sr_unix/jobsp.h +++ b/sr_unix/jobsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,24 +17,25 @@ #define MAX_PIDSTR_LEN 10 #define MAX_MBXNAM_LEN 16 #define MAX_PRCNAM_LEN 15 +#define MAX_STDIOE_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" +#define CLEAR_CHILD_FLAG_ENV "gtmj0=""" +#define GBLDIR_ENV "gtmgbldir" +#define CWD_ENV "gtmj2" +#define IN_FILE_ENV "gtmj3" +#define OUT_FILE_ENV "gtmj4" +#define ERR_FILE_ENV "gtmj5" +#define LOG_FILE_ENV "gtmj6" +#define ROUTINE_ENV "gtmj7" +#define LABEL_ENV "gtmj8" +#define OFFSET_ENV "gtmj9" +#define PRIORITY_ENV "gtmja" +#define STARTUP_ENV "gtmjb" +#define GTMJCNT_ENV "gtmjcnt" -#define CHILD_FLAG_ENV "gtmj0" -#define CLEAR_CHILD_FLAG_ENV "gtmj0=""" -#define GBLDIR_ENV "gtmgbldir" -#define CWD_ENV "gtmj2" -#define IN_FILE_ENV "gtmj3" -#define OUT_FILE_ENV "gtmj4" -#define ERR_FILE_ENV "gtmj5" -#define LOG_FILE_ENV "gtmj6" -#define ROUTINE_ENV "gtmj7" -#define LABEL_ENV "gtmj8" -#define OFFSET_ENV "gtmj9" -#define PRIORITY_ENV "gtmja" -#define STARTUP_ENV "gtmjb" -#define GTMJCNT_ENV "gtmjcnt" - -#define TIMEOUT_ERROR (MAX_SYSERR + 1) /* a special value to differentiate it from the rest of errno's */ +GBLDEF int job_errno; /******************************************************************************************************************** * Following enum is used to identify the cause of error in the middle process (M) to the main thread (P) @@ -46,18 +47,30 @@ * it adds joberr_tryagain to the main status (one of the status' upto joberr_tryagain) and exits with the new status. *********************************************************************************************************************/ -enum joberr_nm -{ joberr_gen = 1, - joberr_io, +typedef enum +{ joberr_ok, + joberr_gen, + joberr_io_stdin_open, + joberr_io_stdin_dup, + joberr_io_stdout_creat, + joberr_io_stdout_open, + joberr_io_stdout_dup, + joberr_io_stderr_creat, + joberr_io_stderr_open, + joberr_io_stderr_dup, + joberr_cd_toolong, joberr_cd, joberr_rtn, + joberr_sid, joberr_frk, - joberr_syscall, + joberr_stdout_rename, + joberr_stderr_rename, + joberr_pipe_mp, + joberr_pipe_mgc, joberr_stp, joberr_sig, - joberr_tryagain, joberr_end -}; +} joberr_t; typedef struct job_parm_struct { mval *parm; @@ -71,6 +84,7 @@ typedef struct mstr logfile; mstr routine; mstr label; + mstr cmdline; int4 baspri; int4 offset; job_parm *parms; @@ -89,7 +103,7 @@ typedef enum #include "jobparams.h" } jp_type; -bool ojchildioset(job_params_type *jparms); +int ojchildioset(job_params_type *jparms); int ojstartchild(job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[]); void ojparams(char *p, job_params_type *job_params); void ojgetch_env(job_params_type *jparms); diff --git a/sr_unix/kitstart.csh b/sr_unix/kitstart.csh index a8637df..65fd13e 100644 --- a/sr_unix/kitstart.csh +++ b/sr_unix/kitstart.csh @@ -1,7 +1,7 @@ #!/usr/local/bin/tcsh ################################################################# # # -# Copyright 2011, 2012 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -9,13 +9,16 @@ # the license, please stop and do not read further. # # # ################################################################# -# kitstart.csh creates distribution kits for pro and dbg. +# kitstart.csh creates distribution kits for pro and dbg and bta. # In order to test any configure.csh changes, copy a modified version into /usr/library/Vxxx/pro/configure # and /usr/library/Vxxx/dbg/configure. Then execute $gtm_tools/kitstart.csh -ti Vxxx and check output log. # If changes are made to the configure script, such as removing files or changing permissions in the install # directory there may need to be changes made to files used by kitstart.csh to execute # $gtm_tools/gtm_compare_dist.csh. # +# set echo +# set verbose +# # Make sure don't start in utf-8 mode if ($?gtm_chset) then if (M != $gtm_chset) then @@ -25,6 +28,15 @@ if ($?gtm_chset) then endif endif +# This script needs root privileges to +# - test install GT.M +# - set file ownership to 40535 +set euser = `$gtm_dist/geteuid` +if ("$euser" != "root") then + echo "You must have root privileges to run kitstart" + exit -1 +endif + if (-e /etc/csh.cshrc) then # on lester (HPUX), /etc/csh.cshrc does not seem to be invoked at tcsh startup so invoke it explicitly # this is what defines the "version" alias used down below. @@ -35,61 +47,44 @@ endif source $cms_tools/cms_cshrc.csh source $cms_tools/server_list -if ("$distrib_servers_unix" !~ *${HOST:r:r:r}*) then - echo "This is not a distribution server. Exiting." - exit -endif setenv PATH "/usr/local/bin:/usr/sbin:/usr/ccs/bin:/usr/bin:/bin" # get the osname and arch type from the tables in server_list -set servers = `echo $distrib_servers_unix` -set platformarch = `echo $distrib_unix_platformarch` +set servers = ( $distrib_servers_unix ) +set platformarch = ( $distrib_unix_platformarch ) -@ index = 0 -while ($index < $#servers) - @ index = $index + 1 - if ("$servers[$index]" =~ *${HOST:r:r:r}*) then +foreach server ( $servers ) + @ index++ + if ("$server" =~ *${HOST:r:r:r}*) then + set os_arch=$platformarch[$index] # contortion alert! get the OS_ARCH value from the list + set os_arch="${os_arch:s/_/ /}" # and spilt OS_ARCH into "OS ARCH" and + set os_arch=( ${os_arch:s/_/ /} ) # enclose it inside parenthesis to force conversion to an array break endif end -set osname = `echo $platformarch[$index] | awk -F_ '{print $1}'` -set arch = `echo $platformarch[$index] | awk -F_ '{print $2}'` -# create a README.txt which has the current year in it -setenv readme_txt ${gtm_com}/README.txt -set year = `date | tail -c5` -cat $cms_tools/license_README_txt | sed "s/#YEAR#/$year/" > $readme_txt +# if not found in distribution servers then try from uname in case -allow entered +if (! $?os_arch) then + # make a directory in /tmp to use to run unamearch.m + setenv randstr `$gtm_dist/mumps -r %XCMD 'do ^%RANDSTR'` + set tempdir = /tmp/kit_unamearch_${randstr} + mkdir $tempdir + cp $cms_tools/unamearch.m $tempdir + set os_arch=`(cd $tempdir; $gtm_dist/mumps -r unamearch $distrib_unix_platformarch%$uname_platformarch)` + if ("" == "$os_arch") then + echo "Problem getting platform and arch from uname -a" + rm -rf $tempdir + exit 1 + endif + set os_arch="${os_arch:s/_/ /}" # and spilt OS_ARCH into "OS ARCH" and + set os_arch=( ${os_arch:s/_/ /} ) # enclose it inside parenthesis to force conversion to an array + rm -rf $tempdir +endif -# Set the open source flag and set lib_specific to the platform specific directories that needs to -# be copied as a part of open source distribution (down the script) -set open_source = 0 -set GNU_COPYING_license = "" -set OPENSOURCE_build_README = "" -if ("$osname" == "linux" && "$arch" == "i686") then - set open_source = 1 - # set lib_specific to be the union of s_linux and s_linux64 so we get the linux sources for - # x86 and x86_64 - set lib_specific = `echo $s_linux $s_linux64 | awk '{for(x=1;x<=NF;x++) array[$x]++ ; for (i in array) print i}'` - /bin/cp -pf $cms_tools/opensource_COPYING ${gtm_com}/COPYING - # create README with current year in it - cat $cms_tools/opensource_README | sed "s/#YEAR#/$year/" > ${gtm_com}/README - set GNU_COPYING_license = "${gtm_com}/COPYING" - set OPENSOURCE_build_README = "${gtm_com}/README" -endif -if ("linux" == "$osname" && "x8664" == "$arch") then - # sources already included in i686 above - /bin/cp -pf $cms_tools/opensource_COPYING ${gtm_com}/COPYING - set GNU_COPYING_license = "${gtm_com}/COPYING" -endif -if ("$osname" == "osf1" && "$arch" == "alpha") then - set open_source = 1 - set lib_specific = "$s_dux" - /bin/cp -pf $cms_tools/opensource_COPYING ${gtm_com}/COPYING - set GNU_COPYING_license = "${gtm_com}/COPYING" - set OPENSOURCE_build_README = "" -endif +set osname = $os_arch[1] +set arch = $os_arch[2] set package = "tar cf" set repackage = "tar rf" @@ -106,31 +101,54 @@ if ($#argv < 1) then set syntaxerr = 1 else set testinstall = 0 + set leavedir = 0 + # when present, do not fire off a background kitstart if ("$1" == "logfile") then set logfile = 1 shift endif + # perform a test installation if ("$1" == "-ti") then set testinstall = 1 shift endif - if ("$1" == "" || "$2" != "" && "$2" != "pro" && "$2" != "dbg") then + # build a kit on a non-dist server + set allow = 0 + if ("$1" == "-allow") then + set allow = 1 + shift + endif + # Test the test install + if ("$1" == "-tti") then + set testinstall = 1 + set leavedir = 1 + set allow = 1 + shift + endif + if ("$1" == "" || "$2" != "" && "$2" != "pro" && "$2" != "dbg" && "$2" != "bta") then set syntaxerr = 1 endif endif if ($syntaxerr) then echo "" - echo "Usage : `basename $0` [-ti] [pro | dbg]" + echo "Usage : $0 [-ti] [-allow] [-tti] [pro | dbg | bta]" echo "" echo " : Version with no punctuations; create distribution of this GT.M version (must be in $gtm_root)" echo "-ti : Test installation" - echo "[pro | dbg] : Create distribution of this image; both if not specified" + echo "-allow : allow kit to be built on a non-distribution server" + echo "-tti : Test the test installation, implies -allow and always leaves dist, tmp_dist, install directories" + echo "[pro | dbg | bta] : Create distribution of this image; or pro and dbg if not specified" echo "" exit 1 endif -set version = `echo $1 | tr "[a-z]" "[A-Z]"` +if (! $allow && ("$distrib_servers_unix" !~ *${HOST:r:r:r}*)) then + echo "This is not a distribution server. Exiting." + exit +endif + +set version = "${1:au}" # ':au' - 'a' means apply to the whole string and 'u' means uppercase everything set imagetype = "pro dbg" if ($2 != "") then @@ -162,7 +180,25 @@ if (! $?logfile) then endif ######################################################################################## -version $version p +version $version p # Set the current version so that relative paths work +cmsver $version # Set appropriate path to locate $version sources in CMS, the default is V990 +set releasever = `$gtm_dist/mumps -run %XCMD 'write $piece($zversion," ",2),!'` + +# create a README.txt which has the current year in it +setenv readme_txt ${gtm_com}/README.txt +set year = `date +%Y` +sed "s/#YEAR#/$year/" $cms_tools/license_README_txt > $readme_txt +chmod 444 $readme_txt + +# Set the open source flag and set lib_specific to the platform specific directories that needs to +# 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 + set open_source = 1 + /bin/cp -pf $cms_tools/opensource_COPYING $GNU_COPYING_license + chmod 444 $GNU_COPYING_license +endif set product = "gtm" set dist = "$gtm_ver/dist" @@ -179,18 +215,8 @@ if (-d $dist || -d $tmp_dist || -d $install) then endif echo "" -if ("$GNU_COPYING_license" != "") then - if (! -r "$GNU_COPYING_license") then - echo "Could not locate GNU Copying license at $GNU_COPYING_license. Exiting..." - exit 4 - endif - if ("$OPENSOURCE_build_README" != "") then - if (! -r $OPENSOURCE_build_README) then - echo "Could not locate Open Source Build README at $OPENSOURCE_build_README. Exiting..." - exit 4 - endif - endif - set opensource_dist = "${dist}/opensource" +set opensource_dist = "${dist}/opensource" +if (1 == $open_source) then echo "Creating $dist (for non open source customers) and $opensource_dist (for open source)" mkdir -p $opensource_dist || exit 4 else @@ -198,22 +224,6 @@ else mkdir $dist || exit 4 endif -if ("$GNU_COPYING_license" != "") then - if (! -e ${dist}/README) then - cat > ${dist}/README << OPENSOURCE_EOF -For paying customers, distribute files in ${dist} -For non paying customers (Sourceforge) who use the Open Source version, -distribute files in ${opensource_dist} -The Open Source binary distribution includes the GNU License (file $GNU_COPYING_license:t) -The Open Source source distribution includes the GNU License (file $GNU_COPYING_license:t) -OPENSOURCE_EOF - if ("$OPENSOURCE_build_README" != "") then - cat >> ${dist}/README << OPENSOURCE_EOF -and the build procedure documentation (file $OPENSOURCE_build_README:t) -OPENSOURCE_EOF - endif - endif -endif foreach image ($imagetype) echo "" echo "Creating ${tmp_dist}/${image}" @@ -238,6 +248,8 @@ foreach image ($imagetype) endif # add the README.txt file cp $readme_txt README.txt || exit 9 + # add the custom_errors_sample.txt file + cp $gtm_tools/custom_errors_sample.txt . || exit 9 if (-e gtmsecshrdir) then $gtm_com/IGS gtmsecshr "UNHIDE" # make root-owned gtmsecshrdir world-readable chmod u+w gtmsecshrdir @@ -249,7 +261,7 @@ foreach image ($imagetype) $package $dist_file README.txt dbcertify V5CBSU.m || exit 10 echo "Gzipping $dist_file" gzip $dist_file || exit 11 - if ("$GNU_COPYING_license" != "") then + if (1 == $open_source) then echo "" echo "Creating dbcertify distribution for open source (includes GNU License)" echo "" @@ -282,7 +294,7 @@ foreach image ($imagetype) $package $dist_file README.txt GTMDefinedTypesInit.m || exit 10 echo "Gzipping $dist_file" gzip $dist_file || exit 11 - if ("$GNU_COPYING_license" != "") then + if (1 == $open_source) then echo "" echo "Creating GTMDefinedTypesInit distribution for open source (includes GNU License)" echo "" @@ -331,12 +343,13 @@ foreach image ($imagetype) echo "" echo "Gzipping $dist_file" gzip $dist_file || exit 11 - if ("$GNU_COPYING_license" != "") then + if (1 == $open_source) then echo "" echo "Creating distribution for open source (includes GNU License)" echo "" echo "Copying $GNU_COPYING_license to $cwd" /bin/cp $GNU_COPYING_license . || exit 8 + chown 40535:40535 COPYING set dist_file="${opensource_dist}/${dist_prefix}_${image}.${package_ext}" echo "" echo "Creating $dist_file" @@ -349,55 +362,6 @@ foreach image ($imagetype) end echo "" -# sources for 32 and 64 bit linux done for linux i686 so don't do it for 64 bit linux -if ("linux" == "$osname" && "x8664" == "$arch") then - set GNU_COPYING_license = "" -endif - -# create src tar only for linux and tru64 -if ("$GNU_COPYING_license" != "") then - cmsver $version # Set appropriate path to locate $version sources in CMS mirror - if ("$OPENSOURCE_build_README" != "") then - echo "Creating source distribution for Opensource including $GNU_COPYING_license:t and $OPENSOURCE_build_README:t" - else - echo "Creating source distribution for Opensource including $GNU_COPYING_license:t" - endif - echo "" - set liblist = "" - foreach libdir ($lib_specific) - set liblist = "$liblist $libdir:t" - end - echo "" - set src_tar="${opensource_dist}/${dist_prefix}_src.${package_ext}" - echo "Creating $src_tar" - cd $cms_root/$version || exit 10 - $package $src_tar $liblist || exit 10 - cd $gtm_com || exit 10 - if ("$OPENSOURCE_build_README" != "") then - $repackage $src_tar $GNU_COPYING_license:t $OPENSOURCE_build_README:t || exit 10 - else - $repackage $src_tar $GNU_COPYING_license:t $readme_txt:t || exit 10 - endif - echo "" - echo "Gzipping $src_tar" - gzip $src_tar || exit 11 - echo "" - if ("$OPENSOURCE_build_README" != "") then - cat << EOF_MK -############################################################################ -!!!!! TEST THE MAKEFILE !!!!! -First untar the opensource files in a directory: -mkdir ${opensource_dist}/build -cd ${opensource_dist}/build -tar zxvf $src_tar -Then follow the instructions from $gtm_com/README: ----------------------------------------------------------------------------- -`cat $gtm_com/README` -############################################################################ -EOF_MK - endif -endif - find $dist -type f -exec chmod 444 {} \; find $dist -type d -exec chmod 755 {} \; chown -R library:gtc $dist @@ -405,8 +369,7 @@ echo "Files in $dist" /bin/ls -lR $dist echo "" -set leavedir = 0 -set kitver = `echo $gtm_ver:t | cut -c 2-6` +set kitver = ${gtm_ver:t:s/V//} if ($testinstall) then echo "" @@ -470,15 +433,10 @@ n CONFIGURE_EOF endif - # We need for root to be a member of the restricted group. It is a member of the "root" group - # for all linux OS and it is a member of "lp" for all others except osf1 where it is "vboxusers" - if("$osname" == "linux") then - setenv rootgroup "root" - else if ("$osname" != "osf1") then - setenv rootgroup "lp" - else - setenv rootgroup "vboxusers" - endif + # We need for root to be a member of the restricted group so that it can run tests. root is a + # member of the gtmsec NIS group. + setenv rootgroup gtmsec + # V54002 now asks for an installation group before the restricted group question so response is # reversed from V54000 # V54003 now asks whether or not to retain .o files if libgtmutil.so is created @@ -541,12 +499,13 @@ CONFIGURE_EOF if ("pro" == ${image}) then # create the build.dir. Only have to do it once cd $gtm_ver || exit 14 + # insert "pro:" for non Linux/Solaris if ((${osname} != linux) && (${osname} != solaris)) echo pro: > ${tmp_dist}/build.dir ls -lR pro >> ${tmp_dist}/build.dir if (aix == ${osname}) then - cat ${tmp_dist}/build.dir | \ -awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" {printf "%s\n", $0}' > ${tmp_dist}/tbuild.dir - mv ${tmp_dist}/tbuild.dir ${tmp_dist}/build.dir + # insert a newline before "pro/gtmsecshrdir:" on AIX + mv ${tmp_dist}/build.dir ${tmp_dist}/tbuild.dir + awk '/^pro.gtmsecshrdir:$/{print ""}{print $0}' ${tmp_dist}/tbuild.dir > ${tmp_dist}/build.dir endif # make a defgroup directory under ${tmp_dist} and copy in the build.dir for use in @@ -559,36 +518,38 @@ awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" { while (2 > $both) # create the install.dir from both installations cd ${install}/$defgroup + # insert "pro:" for non Linux/Solaris if ((${osname} != linux) && (${osname} != solaris)) echo pro: > ${tmp_dist}/$defgroup/install.dir ls -lR pro >> ${tmp_dist}/$defgroup/install.dir if (aix == ${osname}) then - cat ${tmp_dist}/$defgroup/install.dir | \ -awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" {printf "%s\n", $0}' > \ -${tmp_dist}/$defgroup/tinstall.dir - mv ${tmp_dist}/$defgroup/tinstall.dir ${tmp_dist}/$defgroup/install.dir + # insert a newline before "pro/gtmsecshrdir:" on AIX + mv ${tmp_dist}/$defgroup/install.dir ${tmp_dist}/$defgroup/tinstall.dir + awk '/^pro.gtmsecshrdir:$/{print ""}{print $0}' ${tmp_dist}/$defgroup/tinstall.dir \ + > ${tmp_dist}/$defgroup/install.dir endif cd ${tmp_dist}/${image} 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 - $comp $gtm_tools/linuxi686_badd.txt $gtm_tools/bdeldir.txt ${osname} - set teststat = $status + set adddir=$gtm_tools/linuxi686_badd.txt else if (("hpux" == ${osname}) && ("parisc" == ${arch})) then - $comp $gtm_tools/hpuxparisc_badd.txt $gtm_tools/hpuxparisc_bdeldir.txt ${osname} - set teststat = $status + set adddir=$gtm_tools/hpuxparisc_badd.txt + set deldir=$gtm_tools/hpuxparisc_bdeldir.txt else if (("hpux" == ${osname}) && ("ia64" == ${arch})) then - $comp $gtm_tools/hpuxia64_badd.txt $gtm_tools/bdeldir.txt ${osname} - set teststat = $status + set adddir=$gtm_tools/hpuxia64_badd.txt else if (("osf1" == ${osname}) && ("alpha" == ${arch})) then - $comp $gtm_tools/osf1alpha_badd.txt $gtm_tools/hpuxparisc_bdeldir.txt ${osname} - set teststat = $status - else - $comp $gtm_tools/badd.txt $gtm_tools/bdeldir.txt ${osname} - set teststat = $status + set adddir=$gtm_tools/osf1alpha_badd.txt + set deldir=$gtm_tools/hpuxparisc_bdeldir.txt endif + $comp $adddir $deldir ${osname} + set teststat = $status if ($teststat) then echo "" echo "Comparison of build and install directories failed." echo "Look in ${tmp_dist}/$defgroup/dircompare/diff.out" + echo "$comp $adddir $deldir ${osname}" + chmod -R ugo+rwx ${tmp_dist}/$defgroup/dircompare exit 16 endif # to simplify the code to do the gtm_compare_dir.csh for both restricted and unrestricted group diff --git a/sr_unix/libmupip.list b/sr_unix/libmupip.list index aebbd28..b78fd63 100644 --- a/sr_unix/libmupip.list +++ b/sr_unix/libmupip.list @@ -85,14 +85,18 @@ mu_reduce_level mu_reorg mu_reorg_upgrd_dwngrd mu_replpool_grab_sem -mu_replpool_remove_sem +mu_replpool_release_sem mu_rndwn_all mu_rndwn_file mu_rndwn_repl_instance mu_rndwn_replpool mu_signal_process +mu_size_arsample +mu_size_impsample +mu_size_scan mu_split mu_swap_blk +mu_swap_root mu_term_setup mu_trig_trgfile mu_truncate @@ -138,6 +142,7 @@ mupip_set_journal mupip_set_journal_fname mupip_set_journal_newstate mupip_set_journal_parse +mupip_size mupip_stop mupip_trigger mupip_upgrade @@ -185,7 +190,6 @@ mur_validate_checksum mur_ztp_lookback murgetlst read_db_files_from_gld -recvpool_init repl_comm repl_filter repl_inst_create @@ -194,6 +198,7 @@ repl_inst_edit repl_ipc_cleanup repl_log repl_log_init +repl_logfileinfo_get repl_tr_good replic_gbldefs ss_anal_shdw_file diff --git a/sr_unix/linuxi686_badd.txt b/sr_unix/linuxi686_badd.txt index 3529e42..f7ba825 100644 --- a/sr_unix/linuxi686_badd.txt +++ b/sr_unix/linuxi686_badd.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2011, 2012 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -11,8 +11,9 @@ # Do not add any blank lines after this comment pro: TTTGEN.m%-r--r----- README.txt +dse%-r--r----- custom_errors_sample.txt gdehelp.dat%-r--r----- gdedefaults -gtm_descript.h%-r-xr-x--- gtm +gtm_common_defs.h%-r-xr-x--- gtm gtmcshrc.gtc%-r-xr-x--- gtmbase gtmhelp.dat%-r-xr-x--- gtmcshrc gtmsecshr%-r-xr-x--- gtmprofile @@ -27,3 +28,9 @@ zzz_insert%-r--r----- source.tar pro/utf8: TTTGEN.m -> ../TTTGEN.m%lrwxrwxrwx README.txt -> ../README.txt +dse -> ../dse%lrwxrwxrwx custom_errors_sample.txt -> ../custom_errors_sample.txt +gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr +gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir + +pro/utf8/gtmsecshrdir: +zzz_insert%-r-s------ gtmsecshr diff --git a/sr_unix/list_file.c b/sr_unix/list_file.c index cb9f76c..962b64d 100644 --- a/sr_unix/list_file.c +++ b/sr_unix/list_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,7 @@ #include "parse_file.h" #include "list_file.h" #include "op.h" +#include "have_crit.h" #define LISTEXT ".lis" @@ -97,7 +98,7 @@ void open_list_file(void) dev_in_use = io_curr_device; op_use(&file,&parms); clock = time(0); - p = GTM_CTIME(&clock); + GTM_CTIME(p, &clock); memcpy (print_time_buf, p + 4, SIZEOF(print_time_buf)); list_head(0); return; diff --git a/sr_unix/lke.c b/sr_unix/lke.c index 49deae8..cde233b 100644 --- a/sr_unix/lke.c +++ b/sr_unix/lke.c @@ -63,10 +63,14 @@ #include "gtm_threadgbl_init.h" #include "gtmio.h" #include "have_crit.h" +#include "gt_timers_add_safe_hndlrs.h" +#include "continue_handler.h" #ifdef UNICODE_SUPPORTED -#include "gtm_icu_api.h" -#include "gtm_utf8.h" +# include "gtm_icu_api.h" +# include "gtm_utf8.h" +# include "gtm_conv.h" +GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ #endif GBLREF VSIG_ATOMIC_T util_interrupt; @@ -95,8 +99,9 @@ int main (int argc, char *argv[]) gtm_env_init(); /* read in all environment variables */ licensed = TRUE; err_init(util_base_ch); + UNICODE_ONLY(gtm_strToTitle_ptr = >m_strToTitle); GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ - sig_init(generic_signal_handler, lke_ctrlc_handler, suspsigs_handler); + sig_init(generic_signal_handler, lke_ctrlc_handler, suspsigs_handler, continue_handler); atexit(util_exit_handler); SET_LATCH_GLOBAL(&defer_latch, LOCK_AVAILABLE); get_page_size(); @@ -105,7 +110,9 @@ int main (int argc, char *argv[]) getjobname(); INVOKE_INIT_SECSHR_ADDRS; getzdir(); + gtm_chk_dist(argv[0]); prealloc_gt_timers(); + gt_timers_add_safe_hndlrs(); initialize_pattern_table(); gvinit(); region_init(TRUE); @@ -113,8 +120,7 @@ int main (int argc, char *argv[]) cli_lex_setup(argc, argv); /* this should be after cli_lex_setup() due to S390 A/E conversion */ - gtm_chk_dist(argv[0]); - + OPERATOR_LOG_MSG; while (1) { if (!lke_process(argc) || 2 <= argc) diff --git a/sr_unix/lke_cmd.c b/sr_unix/lke_cmd.c index 541ab6b..93d349e 100644 --- a/sr_unix/lke_cmd.c +++ b/sr_unix/lke_cmd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,7 @@ #include "cli.h" #include "lke.h" #include "util_spawn.h" +#include "util_help.h" #include "lke_cmd_disallow.h" static readonly CLI_ENTRY clear_qual[] = { @@ -58,7 +59,7 @@ static readonly CLI_ENTRY show_qual[] = { GBLDEF CLI_ENTRY lke_cmd_ary[] = { { "CLEAR", lke_clear, clear_qual, 0, 0, cli_disallow_lke_clear, 0, VAL_NOT_REQ, 2, 0, VAL_STR, 0}, { "EXIT", lke_exit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0}, - { "HELP", lke_help, 0, 0, 0, 0, 0, VAL_NOT_REQ, 5, 0, 0, 0}, + { "HELP", util_help, 0, 0, 0, 0, 0, VAL_NOT_REQ, 1, 0, 0, 0}, { "SETGDR", lke_setgdr, 0, 0, 0, 0, 0, VAL_REQ, 1, 0, 0, 0}, { "SHOW", lke_show, show_qual, 0, 0, 0, 0, VAL_NOT_REQ, 1, 0, VAL_STR, 0}, { "SPAWN", util_spawn, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0}, diff --git a/sr_unix/lke_help.c b/sr_unix/lke_help.c index 844d6b4..85d2498 100644 --- a/sr_unix/lke_help.c +++ b/sr_unix/lke_help.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -23,5 +23,5 @@ void lke_help(void) { - PRINTF("Help command not implemented in this revision\n"); + /* This function is a STUB to avoid editting sr_port/lke.h */ } diff --git a/sr_unix/lke_setgdr.c b/sr_unix/lke_setgdr.c index dc3d0e1..70a4cd7 100644 --- a/sr_unix/lke_setgdr.c +++ b/sr_unix/lke_setgdr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -36,6 +36,8 @@ GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_addr *gd_header; GBLREF mval dollar_zgbldir; +error_def(ERR_NOTALLDBRNDWN); + void lke_setgdr(void) { gd_region *r_top; @@ -43,6 +45,7 @@ void lke_setgdr(void) bool def; short len; char buf[256]; + int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ static readonly char init_gdr[] = "gtmgbldir"; gvcmy_rundown(); @@ -54,9 +57,12 @@ void lke_setgdr(void) gv_cur_region++) { tp_change_reg(); - gds_rundown(); + UNIX_ONLY(rundown_status |=) gds_rundown(); } + if (EXIT_NRM != rundown_status) + rts_error(VARLSTCNT(1) ERR_NOTALLDBRNDWN); + if (cli_present("gld")) { cli_get_value("gld", buf) ; @@ -68,7 +74,7 @@ void lke_setgdr(void) else { reset.mvtype = MV_STR; - reset.str.len = sizeof (init_gdr) - 1; + reset.str.len = SIZEOF(init_gdr) - 1; reset.str.addr = init_gdr; } diff --git a/sr_unix/lockdefs.h b/sr_unix/lockdefs.h index aca0f4f..a649dca 100644 --- a/sr_unix/lockdefs.h +++ b/sr_unix/lockdefs.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * diff --git a/sr_unix/make_mode.h b/sr_unix/make_mode.h index 8bb1214..435bc19 100644 --- a/sr_unix/make_mode.h +++ b/sr_unix/make_mode.h @@ -23,6 +23,6 @@ rhdtyp *make_mode (int mode_index); #else #define CODE_SIZE (CODE_LINES * CALL_SIZE + SIZEOF(uint4) * EXTRA_INST) #endif /* __ia64 */ -#include "make_mode_sp.h" +#include #endif diff --git a/sr_unix/maskpass.c b/sr_unix/maskpass.c index bc8d47f..d2e7f09 100644 --- a/sr_unix/maskpass.c +++ b/sr_unix/maskpass.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2011 Fidelity Information Services, Inc * + * Copyright 2009, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #ifdef USE_OPENSSL # include @@ -33,8 +35,6 @@ #define GTM_DIST "gtm_dist" #define HASH_LENGTH 64 /* 512 bits = 64 bytes */ -struct termios old_tty, no_echo_tty; - #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define HEX(a, b, len) \ @@ -44,6 +44,33 @@ struct termios old_tty, no_echo_tty; sprintf(b + i, "%02X", (unsigned char)a[i/2]); \ } +#define SIGPROCMASK(FUNC, NEWSET, OLDSET, RC) \ +{ \ + do \ + { \ + RC = sigprocmask(FUNC, NEWSET, OLDSET); \ + } while (-1 == RC && EINTR == errno); \ +} + +#define Tcsetattr(FDESC, WHEN, TERMPTR, RC, ERRNO) \ +{ \ + sigset_t block_ttinout; \ + sigset_t oldset; \ + int rc; \ + sigemptyset(&block_ttinout); \ + sigaddset(&block_ttinout, SIGTTIN); \ + sigaddset(&block_ttinout, SIGTTOU); \ + SIGPROCMASK(SIG_BLOCK, &block_ttinout, &oldset, rc); \ + do \ + { \ + RC = tcsetattr(FDESC, WHEN, TERMPTR); \ + } while(-1 == RC && EINTR == errno); \ + ERRNO = errno; \ + SIGPROCMASK(SIG_SETMASK, &oldset, NULL, rc); \ +} + +struct termios old_tty, no_echo_tty; + static void maskpass(char passwd[], size_t password_len, char hash[], size_t hash_length) { size_t i; @@ -53,7 +80,7 @@ static void maskpass(char passwd[], size_t password_len, char hash[], size_t has static int echo_off() { - int fd, status; + int fd, status, save_errno; fd = fileno(stdin); /* Save current TTY settings */ @@ -62,16 +89,16 @@ static int echo_off() return 1; no_echo_tty = old_tty; no_echo_tty.c_lflag &= ~ECHO; /* Turn off echo */ - status = tcsetattr(fd, TCSAFLUSH, &no_echo_tty); + Tcsetattr(fd, TCSAFLUSH, &no_echo_tty, status, save_errno); return status; } static int echo_on() { - int fd, status; + int fd, status, save_errno; fd = fileno(stdin); - status = tcsetattr(fd, TCSAFLUSH, &old_tty); + Tcsetattr(fd, TCSAFLUSH, &old_tty, status, save_errno); return status; } @@ -193,7 +220,7 @@ int main() { printf("libgcrypt version mismatch. %s or higher is required.\n", GCRYPT_VERSION); - exit(1); + exit(EXIT_FAILURE); } /* Since we will just be hashing, secure memory is not needed. */ if (!(err = gcry_control(GCRYCTL_DISABLE_SECMEM,0))) @@ -201,18 +228,18 @@ int main() if (GPG_ERR_NO_ERROR != err) { printf("Libgcrypt error: %s\n", gcry_strerror(err)); - exit(1); + exit(EXIT_FAILURE); } # endif - passwd_len = -1; + passwd_len = (size_t)-1; memset(passwd, 0, MAX_LEN); memset(out, 0, MAX_LEN * 2); if (get_hash_via_env_var(hash)) if (get_hash_via_username_and_inode(hash, passwd, &passwd_len)) - exit(1); - if (-1 == passwd_len) + exit(EXIT_FAILURE); + if ((size_t)-1 == passwd_len) { prompt_passwd(passwd); passwd_len = strlen(passwd); diff --git a/sr_unix/mdefsa.h b/sr_unix/mdefsa.h index 97be247..729fb9d 100644 --- a/sr_unix/mdefsa.h +++ b/sr_unix/mdefsa.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,7 +38,6 @@ #define GTM_DIST "gtm_dist" #define GTM_IMAGE_NAME "mumps" #define GTM_IMAGE_NAMELEN (SIZEOF(GTM_IMAGE_NAME) - 1) -#define DIR_SEPARATOR '/' #define GTMSECSHR_NAME "gtmsecshr" #define GTMSECSHR_NAMELEN (SIZEOF(GTMSECSHR_NAME) - 1) @@ -75,7 +74,5 @@ #define cancel_timer GTM_PREFIX(cancel_timer) #define hiber_start GTM_PREFIX(hiber_start) #define hiber_start_wait_any GTM_PREFIX(hiber_start_wait_any) -#define start_timer GTM_PREFIX(start_timer) -#define jnlpool_detach GTM_PREFIX(jnlpool_detach) #endif /* MDEFSA_included */ diff --git a/sr_unix/mdefsp.h b/sr_unix/mdefsp.h index 487bc49..4311150 100644 --- a/sr_unix/mdefsp.h +++ b/sr_unix/mdefsp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,10 +14,6 @@ #include -#if defined(__ia64) || defined(__x86_64__) || defined(__sparc) || defined(__s390__) -#define GTM64 -#endif /* __ia64 */ - #ifdef GTM64 typedef long int8; /* 8-byte signed integer */ typedef unsigned long uint8; /* 8-byte unsigned integer */ @@ -38,18 +34,6 @@ typedef uint2 mach_inst; #define INT8_FMTX "[0x%llx]" #define UNICODE_SUPPORTED -/* Starting off life as debugging parms and now we need them for the - short term so define them here */ -#define DEBUG_LEAVE_SM -#define DEBUG_NOMSYNC - -#define readonly -#define GBLDEF -#define GBLREF extern -#define LITDEF const -#define LITREF extern const -#define error_def(x) LITREF int x - #define UNIX 1 #undef VMS #define BIGENDIAN 1 @@ -57,7 +41,6 @@ typedef uint2 mach_inst; #ifdef __sparc #define CACHELINE_SIZE 256 -#define MSYNC_ADDR_INCS OS_PAGE_SIZE #define USHBIN_SUPPORTED #define LINKAGE_PSECT_BOUNDARY 8 #define OFF_T_LONG @@ -85,7 +68,6 @@ typedef uint4 mach_inst; #endif /* __ia64 */ #ifdef __hpux -#define MSYNC_ADDR_INCS OS_PAGE_SIZE #define MUTEX_MSEM_WAKE #define POSIX_MSEM #define USHBIN_SUPPORTED @@ -93,9 +75,12 @@ typedef uint4 mach_inst; /* Make sure linkage Psect is aligned on appropriate boundary. */ #ifdef __ia64 #define LINKAGE_PSECT_BOUNDARY 8 -#else +#else /* parisc */ #define LINKAGE_PSECT_BOUNDARY 4 -#endif //__ia64 +#ifdef __GNUC__ +typedef unsigned short in_port_t; /* GCC needs this on PARISC */ +#endif +#endif typedef uint4 mach_inst; /* machine instruction */ #endif /* __hpux */ @@ -117,15 +102,8 @@ typedef unsigned short in_port_t; #ifdef __linux__ #define SYS_ERRLIST_INCLUDE "gtm_stdio.h" -/* For 32-bit linux in i386, we noticed during the RHEL 5.5 upgrade that using msems affects process wakeup times - * dramatically enough to cause test hangs/failures. Not sure if it is a linux kernel or package issue. - * Therefore disabling msems on that platform for now until we know better. The alternative is socket waits (using - * select/poll system call). Performance differences, if any, is expected to be only a marginally slowdown. - */ -# ifndef __i386 -# define MUTEX_MSEM_WAKE -# define POSIX_MSEM -# endif +#define MUTEX_MSEM_WAKE +#define POSIX_MSEM #endif #ifdef __CYGWIN__ @@ -141,16 +119,14 @@ typedef unsigned short in_port_t; #define GTM_CONTEXT(func) (unsigned char *)func #define SSM_SIZE 256*1024*1024 /* Segments on 256M boundary */ #define SHMAT_ADDR_INCS SSM_SIZE -#define MSYNC_ADDR_INCS OS_PAGE_SIZE #define USHBIN_SUPPORTED #endif /* __s390__ */ #ifdef __ia64 # ifdef __linux__ -# define MSYNC_ADDR_INCS OS_PAGE_SIZE -# undef BIGENDIAN +# undef BIGENDIAN # define USHBIN_SUPPORTED - /* Make sure linkage Psect is aligned on appropriate boundary. */ + /* Make sure linkage Psect is aligned on appropriate boundary. */ # define LINKAGE_PSECT_BOUNDARY 8 typedef uint4 mach_inst; /* machine instruction */ # elif defined(__hpux) @@ -163,14 +139,12 @@ void dyncall(); #ifdef __i386 /* Through Pentium Pro/II/III, should use CPUID to get real value perhaps */ #define CACHELINE_SIZE 32 -#define MSYNC_ADDR_INCS OS_PAGE_SIZE #undef BIGENDIAN typedef char mach_inst; /* machine instruction */ #endif /* __i386 */ #ifdef __x86_64__ #define CACHELINE_SIZE 64 -#define MSYNC_ADDR_INCS OS_PAGE_SIZE #define USHBIN_SUPPORTED #define INO_T_LONG /* @@ -229,6 +203,13 @@ typedef struct #define malloc gtm_malloc #define free gtm_free +/* gtm_shmget calls either the native shmget or libhugetlbfs's shmget which uses Huge Pages + * to back the shared segment if possible. This is a Linux only library. + */ +#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__)) +# define shmget gtm_shmget + extern int gtm_shmget(key_t , size_t , int); +#endif #ifndef __ia64 #define CODE_ADDRESS(func) (unsigned char *)func diff --git a/sr_unix/mu_all_version_standalone.c b/sr_unix/mu_all_version_standalone.c index ed04ea1..6af0afa 100644 --- a/sr_unix/mu_all_version_standalone.c +++ b/sr_unix/mu_all_version_standalone.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2011 Fidelity Information Services, Inc * + * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,6 +46,8 @@ static int ftok_ver[FTOK_ID_CNT] = {0, 0, 1}; error_def(ERR_MUSTANDALONE); error_def(ERR_DBOPNERR); +error_def(ERR_FTOKKEY); +error_def(ERR_SEMID); error_def(ERR_SYSCALL); error_def(ERR_TEXT); ZOS_ONLY(error_def(ERR_BADTAG);) @@ -105,9 +107,11 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn)); + 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); else - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno); + rts_error(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) @@ -115,9 +119,12 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn)); + rts_error(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); else - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); + 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); } } @@ -159,7 +166,8 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn)); + 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); } } diff --git a/sr_unix/mu_cre_file.c b/sr_unix/mu_cre_file.c index f5c69a5..2b4f64c 100644 --- a/sr_unix/mu_cre_file.c +++ b/sr_unix/mu_cre_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,10 +40,12 @@ #include "gtmmsg.h" #include "util.h" #include "gtmdbglvl.h" +#include "anticipatory_freeze.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #include "shmpool.h" /* Needed for the shmpool structures */ +#include "jnl.h" #define BLK_SIZE (((gd_segment*)gv_cur_region->dyn.addr)->blk_size) @@ -78,6 +80,7 @@ } GBLREF gd_region *gv_cur_region; +GBLREF jnlpool_addrs jnlpool; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF uint4 gtmDebugLevel; @@ -93,19 +96,18 @@ unsigned char mu_cre_file(void) int fd = FD_INVALID, i, lower, upper, norm_vbn; ssize_t status; uint4 raw_dev_size; /* size of a raw device, in bytes */ - int4 blocks_for_create, blocks_for_extension, save_errno; - GTM_BAVAIL_TYPE avail_blocks; + int4 save_errno; + gtm_uint64_t avail_blocks, blocks_for_create, blocks_for_extension, delta_blocks; file_control fc; mstr file; parse_blk pblk; unix_db_info udi_struct, *udi; char *fgets_res; gd_segment *seg; - GTMCRYPT_ONLY( +# ifdef GTM_CRYPT char datfile_hash[GTMCRYPT_HASH_LEN]; - int init_status; - int crypt_status; - ) + int gtmcrypt_errno; +# endif ZOS_ONLY(int realfiletag;) assert((-(SIZEOF(uint4) * 2) & SIZEOF_FILE_HDR_DFLT) == SIZEOF_FILE_HDR_DFLT); @@ -117,7 +119,7 @@ unsigned char mu_cre_file(void) pblk.buff_size = MAX_FBUFF; file.addr = (char*)gv_cur_region->dyn.addr->fname; file.len = gv_cur_region->dyn.addr->fname_len; - strncpy(path,file.addr,file.len); + strncpy(path, file.addr, file.len); *(path+file.len) = '\0'; if (is_raw_dev(path)) { /* do not use a default extension for raw device files */ @@ -130,7 +132,7 @@ unsigned char mu_cre_file(void) } if (1 != (parse_file(&file, &pblk) & 1)) { - PRINTF("Error translating filename %s.\n", gv_cur_region->dyn.addr->fname); + PRINTF("Error translating filename %s.\n", file.addr); return EXIT_ERR; } path[pblk.b_esl] = 0; @@ -147,10 +149,10 @@ unsigned char mu_cre_file(void) /* Check if this file is an encrypted database. If yes, do init */ if (gv_cur_region->dyn.addr->is_encrypted) { - INIT_PROC_ENCRYPTION(init_status); - if (0 != init_status) + INIT_PROC_ENCRYPTION(cs_addrs, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(init_status, NULL); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, file.len, file.addr); return EXIT_ERR; } } @@ -226,32 +228,40 @@ unsigned char mu_cre_file(void) seg = gv_cur_region->dyn.addr; /* blocks_for_create is in the unit of DISK_BLOCK_SIZE */ - blocks_for_create = (int4)(DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE) + 1 + + blocks_for_create = (gtm_uint64_t)(DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE) + 1 + (seg->blk_size / DISK_BLOCK_SIZE * - ((DIVIDE_ROUND_UP(seg->allocation, BLKS_PER_LMAP - 1)) + seg->allocation))); + (gtm_uint64_t)((DIVIDE_ROUND_UP(seg->allocation, BLKS_PER_LMAP - 1)) + seg->allocation))); + blocks_for_extension = (seg->blk_size / DISK_BLOCK_SIZE * + ((DIVIDE_ROUND_UP(EXTEND_WARNING_FACTOR * (gtm_uint64_t)seg->ext_blk_count, + BLKS_PER_LMAP - 1)) + + EXTEND_WARNING_FACTOR * (gtm_uint64_t)seg->ext_blk_count)); if (!(gtmDebugLevel & GDL_IgnoreAvailSpace)) { /* Bypass this space check if debug flag above is on. Allows us to create a large sparce DB * in space it could never fit it if wasn't sparse. Needed for some tests. + * Also, if the anticipatory freeze scheme is in effect at this point, we would have issued + * a NOSPACECRE warning (see NOSPACEEXT message which goes through a similar transformation). + * But at this point, we are guaranteed to not have access to the journal pool or csa both + * of which are necessary for the ANTICIPATORY_FREEZE_ENABLED(csa) macro so we dont bother + * to do the warning transformation in this case. */ - if ((uint4)avail_blocks < blocks_for_create) + assert(NULL == jnlpool.jnlpool_ctl); + if (avail_blocks < blocks_for_create) { - gtm_putmsg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), blocks_for_create, - (uint4)avail_blocks); - send_msg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), blocks_for_create, - (uint4)avail_blocks); + gtm_putmsg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), &blocks_for_create, + &avail_blocks); + send_msg(VARLSTCNT(6) ERR_NOSPACECRE, 4, LEN_AND_STR(path), &blocks_for_create, + &avail_blocks); CLEANUP(EXIT_ERR); return EXIT_ERR; } - } - blocks_for_extension = (seg->blk_size / DISK_BLOCK_SIZE * - ((DIVIDE_ROUND_UP(EXTEND_WARNING_FACTOR * seg->ext_blk_count, BLKS_PER_LMAP - 1)) - + EXTEND_WARNING_FACTOR * seg->ext_blk_count)); - if ((uint4)(avail_blocks - blocks_for_create) < blocks_for_extension) - { - gtm_putmsg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, blocks_for_extension, - DISK_BLOCK_SIZE, (uint4)(avail_blocks - blocks_for_create)); - send_msg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, blocks_for_extension, - DISK_BLOCK_SIZE, (uint4)(avail_blocks - blocks_for_create)); + delta_blocks = avail_blocks - blocks_for_create; + if (delta_blocks < blocks_for_extension) + { + gtm_putmsg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, + &blocks_for_extension, DISK_BLOCK_SIZE, &delta_blocks); + send_msg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, LEN_AND_STR(path), EXTEND_WARNING_FACTOR, + &blocks_for_extension, DISK_BLOCK_SIZE, &delta_blocks); + } } } gv_cur_region->dyn.addr->file_cntl = &fc; @@ -307,28 +317,30 @@ unsigned char mu_cre_file(void) /* Check if this file is an encrypted database. If yes, do init */ if (gv_cur_region->dyn.addr->is_encrypted) { - GTMCRYPT_HASH_GEN(path, STRLEN(path), datfile_hash, crypt_status); - if (0 != crypt_status) + GTMCRYPT_HASH_GEN(cs_addrs, path, STRLEN(path), datfile_hash, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, gv_cur_region->dyn.addr->fname); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, file.len, file.addr); CLEANUP(EXIT_ERR); return EXIT_ERR; } memcpy(cs_data->encryption_hash, datfile_hash, GTMCRYPT_HASH_LEN); cs_data->is_encrypted = TRUE; /* Mark this file as encrypted */ - ALLOC_BUFF_GET_ENCR_KEY(cs_addrs, cs_data->encryption_hash, BLK_SIZE, crypt_status); - if (0 != crypt_status) + ALLOC_BUFF_GET_ENCR_KEY(cs_addrs, cs_data->encryption_hash, BLK_SIZE, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, (gv_cur_region->dyn.addr->fname)); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, file.len, file.addr); CLEANUP(EXIT_ERR); return EXIT_ERR; } } else cs_data->is_encrypted = FALSE; # endif + cs_data->span_node_absent = TRUE; + cs_data->maxkeysz_assured = TRUE; mucregini(cs_data->trans_hist.total_blks); cs_data->createinprogress = FALSE; - LSEEKWRITE(udi->fd, 0, cs_data, SIZEOF_FILE_HDR_DFLT, status); + DB_LSEEKWRITE(cs_addrs, udi->fn, udi->fd, 0, cs_data, SIZEOF_FILE_HDR_DFLT, status); if (0 != status) { SPRINTF_AND_PERROR("Error writing out header for file %s\n"); @@ -337,7 +349,7 @@ unsigned char mu_cre_file(void) } cc = (char*)malloc(DISK_BLOCK_SIZE); memset(cc, 0, DISK_BLOCK_SIZE); - LSEEKWRITE(udi->fd, + DB_LSEEKWRITE(cs_addrs, udi->fn, udi->fd, (cs_data->start_vbn - 1) * DISK_BLOCK_SIZE + ((off_t)(cs_data->trans_hist.total_blks) * cs_data->blk_size), cc, DISK_BLOCK_SIZE, diff --git a/sr_unix/mu_decrypt.c b/sr_unix/mu_decrypt.c index ccb74f7..21660aa 100644 --- a/sr_unix/mu_decrypt.c +++ b/sr_unix/mu_decrypt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,7 +30,7 @@ int mu_decrypt(char *fname, uint4 off, uint4 len) { # ifdef GTM_CRYPT - int fd, n_len, save_errno, status, i; + int fd, n_len, save_errno, gtmcrypt_errno, i; char hash[GTMCRYPT_HASH_LEN], *buff; boolean_t is_encrypted; gtmcrypt_key_t key_handle; @@ -48,15 +48,15 @@ int mu_decrypt(char *fname, uint4 off, uint4 len) } if (is_encrypted) { - INIT_PROC_ENCRYPTION(status); - GTMCRYPT_GETKEY(hash, key_handle, status); - if (0 == status) - GTMCRYPT_DECODE_FAST(key_handle, buff, len, NULL, status); - if (0 != status) + INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno); + GTMCRYPT_GETKEY(NULL, hash, key_handle, gtmcrypt_errno); + if (0 == gtmcrypt_errno) + GTMCRYPT_DECRYPT(NULL, key_handle, buff, len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { close(fd); free(buff); - GC_RTS_ERROR(status, fname); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, n_len, fname); } } for (i = 0; i < len; i++) @@ -68,7 +68,7 @@ int mu_decrypt(char *fname, uint4 off, uint4 len) } free(buff); close(fd); -#endif +# endif return SS_NORMAL; } diff --git a/sr_unix/mu_extract.c b/sr_unix/mu_extract.c index ba33202..07b0255 100644 --- a/sr_unix/mu_extract.c +++ b/sr_unix/mu_extract.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,7 +24,6 @@ #include "gtm_zos_io.h" #endif #include "stp_parms.h" -#include "stringpool.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" @@ -53,15 +52,16 @@ #include "filestruct.h" #include "gvcst_protos.h" /* for gvcst_root_search in GV_BIND_NAME_AND_ROOT_SEARCH macro */ -GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace); -GBLREF bool mu_ctrlc_occurred; -GBLREF bool mu_ctrly_occurred; -GBLREF spdesc rts_stringpool, stringpool; -GBLREF gd_region *gv_cur_region; -GBLREF gd_addr *gd_header; -GBLREF io_pair io_curr_device; -GBLREF io_desc *active_device; -GBLREF gv_namehead *gv_target; +GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace); +GBLREF bool mu_ctrlc_occurred; +GBLREF bool mu_ctrly_occurred; +GBLREF gd_region *gv_cur_region; +GBLREF gd_addr *gd_header; +GBLREF io_pair io_curr_device; +GBLREF io_desc *active_device; +GBLREF gv_namehead *gv_target; +GBLREF boolean_t jnlpool_init_needed; +GBLREF mstr sys_output; error_def(ERR_EXTRACTCTRLY); error_def(ERR_EXTRACTFILERR); @@ -72,6 +72,7 @@ error_def(ERR_MUPCLIERR); error_def(ERR_NOSELECT); error_def(ERR_NULLCOLLDIFF); error_def(ERR_RECORDSTAT); +error_def(ERR_EXTRFILEXISTS); LITDEF mval mu_bin_datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(BIN_HEADER_DATEFMT) - 1, BIN_HEADER_DATEFMT, 0, 0); @@ -79,7 +80,6 @@ LITDEF mval mu_bin_datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(BIN_HEADER LITREF mstr chset_names[]; static readonly unsigned char datefmt_txt[] = "DD-MON-YEAR 24:60:SS"; -static readonly unsigned char gt_lit[] = "TOTAL"; static readonly unsigned char select_text[] = "SELECT"; static readonly mval datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(datefmt_txt) - 1, (char *)datefmt_txt, 0, 0); static readonly mval null_str = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, 0, 0, 0, 0); @@ -109,7 +109,6 @@ static readonly unsigned char no_param = (unsigned char)iop_eol; #define WRITE_NUMERIC(nmfield) \ { \ MV_FORCE_MVAL(&val, nmfield); \ - stringpool.free = stringpool.base; \ n2s(&val); \ if (val.mvtype & MV_NUM_APPROX) \ GTMASSERT; \ @@ -167,16 +166,16 @@ void mu_extract(void) mval val, curr_gbl_name, op_val, op_pars; mstr chset_mstr; gtm_chset_t saved_out_set; - coll_hdr extr_collhdr; + coll_hdr extr_collhdr; int bin_header_size; int reg_no; boolean_t is_any_file_encrypted = FALSE; - GTMCRYPT_ONLY( - unsigned short hash_buff_len; - sgmnt_data_ptr_t csd; - sgmnt_addrs *csa; - muext_hash_hdr_ptr_t hash_array; - ) +# ifdef GTM_CRYPT + unsigned short hash_buff_len; + sgmnt_data_ptr_t csd; + sgmnt_addrs *csa; + muext_hash_hdr_ptr_t hash_array; +# endif /* Initialize all local character arrays to zero before using */ memset(cli_buff, 0, SIZEOF(cli_buff)); @@ -242,20 +241,21 @@ void mu_extract(void) cli_buff[0] = '*'; } /* gv_select will select globals */ + jnlpool_init_needed = TRUE; gv_select(cli_buff, n_len, freeze, (char *)select_text, &gl_head, ®_max_rec, ®_max_key, ®_max_blk, FALSE); if (!gl_head.next) { - rts_error(VARLSTCNT(1) ERR_NOSELECT); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSELECT); mupip_exit(ERR_NOSELECT); } /* For binary format, check whether all regions have same null collation order */ if (MU_FMT_BINARY == format) { - GTMCRYPT_ONLY( - hash_buff_len = (SIZEOF(muext_hash_hdr) * gd_header->n_regions); - hash_array = (muext_hash_hdr *)malloc(hash_buff_len); - memset(hash_array, 0, hash_buff_len); - ) +# ifdef GTM_CRYPT + hash_buff_len = (SIZEOF(muext_hash_hdr) * gd_header->n_regions); + hash_array = (muext_hash_hdr *)malloc(hash_buff_len); + memset(hash_array, 0, hash_buff_len); +# endif for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions, reg_std_null_coll = -1, reg_no = 0; reg < region_top ; reg++, reg_no++) @@ -268,7 +268,7 @@ void mu_extract(void) reg_std_null_coll = reg->std_null_coll; else { - rts_error(VARLSTCNT(1) ERR_NULLCOLLDIFF); + rts_error_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(1) ERR_NULLCOLLDIFF); mupip_exit(ERR_NULLCOLLDIFF); } } @@ -285,32 +285,33 @@ void mu_extract(void) } grand_total.recknt = grand_total.reclen = grand_total.keylen = grand_total.datalen = 0; global_total.recknt = global_total.reclen = global_total.keylen = global_total.datalen = 0; - n_len = SIZEOF(outfilename); - if (FALSE == cli_get_str("FILE", outfilename, &n_len)) + if (CLI_PRESENT == cli_present("STDOUT")) + /* Redirect to standard output */ + op_val.str = sys_output; + else if (FALSE == cli_get_str("FILE", outfilename, &n_len)) { - rts_error(VARLSTCNT(1) ERR_MUPCLIERR); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR); mupip_exit(ERR_MUPCLIERR); - } - if (-1 == Stat((char *)outfilename, &statbuf)) - { + } else if (-1 == Stat((char *)outfilename, &statbuf)) + { /* Redirect to file */ if (ENOENT != errno) { local_errno = errno; - perror("Error opening output file"); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_EXTRACTFILERR, 2, LEN_AND_STR(outfilename), local_errno); mupip_exit(local_errno); } + op_val.str.len = filename_len = n_len; + op_val.str.addr = (char *)outfilename; } else { - util_out_print("Error opening output file: !AD -- File exists", TRUE, n_len, outfilename); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_EXTRFILEXISTS, 2, LEN_AND_STR(outfilename)); mupip_exit(ERR_MUNOACTION); } op_pars.mvtype = MV_STR; op_pars.str.len = SIZEOF(open_params_list); op_pars.str.addr = (char *)open_params_list; op_val.mvtype = MV_STR; - op_val.str.len = filename_len = n_len; - op_val.str.addr = (char *)outfilename; (*op_open_ptr)(&op_val, &op_pars, 0, 0); ESTABLISH(mu_extract_handler); op_pars.str.len = SIZEOF(no_param); @@ -327,16 +328,14 @@ void mu_extract(void) outptr = outbuf; if (is_any_file_encrypted) { - MEMCPY_LIT(outptr, BIN_HEADER_LABEL); - outptr += STR_LIT_LEN(BIN_HEADER_LABEL); + MEMCPY_LIT(outptr, BIN_HEADER_LABEL_ENCR); + outptr += STR_LIT_LEN(BIN_HEADER_LABEL_ENCR); } else { - MEMCPY_LIT(outptr, V4_BIN_HEADER_LABEL); - outptr += STR_LIT_LEN(V4_BIN_HEADER_LABEL); + MEMCPY_LIT(outptr, BIN_HEADER_LABEL); + outptr += STR_LIT_LEN(BIN_HEADER_LABEL); } - stringpool.free = stringpool.base; op_horolog(&val); - stringpool.free = stringpool.base; op_fnzdate(&val, (mval *)&mu_bin_datefmt, &null_str, &null_str, &val); memcpy(outptr, val.str.addr, val.str.len); outptr += val.str.len; @@ -423,9 +422,7 @@ void mu_extract(void) op_val.str.len = label_len; op_val.str.addr = label_buff; op_write(&op_val); - stringpool.free = stringpool.base; op_horolog(&val); - stringpool.free = stringpool.base; op_fnzdate(&val, &datefmt, &null_str, &null_str, &val); op_val = val; op_val.mvtype = MV_STR; @@ -449,7 +446,7 @@ void mu_extract(void) { gbl_name_buff[0]='^'; memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len); - gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff, global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen); mu_ctrlc_occurred = FALSE; } @@ -484,7 +481,7 @@ void mu_extract(void) { gbl_name_buff[0]='^'; memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len); - gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff, global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen); mu_ctrlc_occurred = FALSE; } @@ -505,10 +502,10 @@ void mu_extract(void) REVERT; if (mu_ctrly_occurred) { - gtm_putmsg(VARLSTCNT(1) ERR_EXTRACTCTRLY); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXTRACTCTRLY); mupip_exit(ERR_MUNOFINISH); } - gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT(gt_lit), + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT("TOTAL"), grand_total.recknt, grand_total.keylen, grand_total.datalen, grand_total.reclen); if (MU_FMT_BINARY == format) { /* truncate the last newline charactor flushed by op_close */ diff --git a/sr_unix/mu_replpool_grab_sem.c b/sr_unix/mu_replpool_grab_sem.c index 8a26e03..297e1d7 100644 --- a/sr_unix/mu_replpool_grab_sem.c +++ b/sr_unix/mu_replpool_grab_sem.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -45,6 +45,7 @@ #include "mu_rndwn_replpool.h" #include "ftok_sems.h" #include "util.h" +#include "anticipatory_freeze.h" #define REMOVE_SEM_SET(SEM_CREATED, POOL_TYPE) /* Assumes 'sem_created_ptr' is is already declared */ \ { \ @@ -91,9 +92,8 @@ GBLREF jnlpool_addrs jnlpool; GBLREF recvpool_addrs recvpool; GBLREF gd_region *gv_cur_region; GBLREF jnl_gbls_t jgbl; -#ifdef UNIX -GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; -#endif +GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +GBLREF boolean_t argumentless_rundown; error_def(ERR_JNLPOOLSETUP); error_def(ERR_RECVPOOLSETUP); @@ -108,21 +108,24 @@ error_def(ERR_TEXT); * Grab all replication semaphores for the instance (both jnlpool and recvpool) * Release ftok semaphore * Parameters: - * Return Value: TRUE, if succsessful - * FALSE, if fails. + * Return Value: SS_NORMAL, if succsessful + * -1, if fails. */ -int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t *sem_created_ptr) +int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t *sem_created_ptr, boolean_t immediate) { int status, save_errno, sem_id, semval, semnum, instfilelen; time_t sem_ctime; - boolean_t sem_created; + boolean_t sem_created, force_increment; char *instfilename; union semun semarg; struct semid_ds semstat; gd_region *replreg; DEBUG_ONLY(unix_db_info *udi;) + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; *sem_created_ptr = sem_created = FALSE; /* assume semaphore not created by default */ + force_increment = (jgbl.onlnrlbk || (!jgbl.mur_rollback && !argumentless_rundown && ANTICIPATORY_FREEZE_AVAILABLE)); /* First ensure that the caller has grabbed the ftok semaphore on the replication instance file */ assert((NULL != jnlpool.jnlpool_dummy_reg) && (jnlpool.jnlpool_dummy_reg == recvpool.recvpool_dummy_reg)); replreg = jnlpool.jnlpool_dummy_reg; @@ -169,7 +172,7 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semctl()"); } semarg.buf = &semstat; - if (-1 == semctl(sem_id, 0, IPC_STAT, semarg)) + if (-1 == semctl(sem_id, DB_CONTROL_SEM, IPC_STAT, semarg)) { save_errno = errno; DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semctl()"); @@ -182,7 +185,8 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, /* Semaphores are setup. Grab them */ if (JNLPOOL_SEGMENT == pool_type) { - if (jgbl.onlnrlbk) + assert(!jgbl.onlnrlbk || !immediate); + if (!immediate) status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM); /* want to wait in case of online rollback */ else status = grab_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM); @@ -198,7 +202,7 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, RELEASE_ALREADY_HELD_SEMAPHORE(SOURCE, JNL_POOL_ACCESS_SEM); DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semctl()"); } - if (0 < semval && !jgbl.onlnrlbk) + if (0 < semval && !force_increment) { RELEASE_ALREADY_HELD_SEMAPHORE(SOURCE, JNL_POOL_ACCESS_SEM); util_out_print("Replpool semaphore (id = !UL) for replication instance !AD is in use by another process.", @@ -220,7 +224,7 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, } else { - if (jgbl.onlnrlbk) + if (!immediate) status = grab_sem(RECV, RECV_POOL_ACCESS_SEM); else status = grab_sem_immediate(RECV, RECV_POOL_ACCESS_SEM); @@ -229,7 +233,7 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, save_errno = errno; DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semop()"); } - if (jgbl.onlnrlbk) + if (!immediate) status = grab_sem(RECV, RECV_SERV_OPTIONS_SEM); else status = grab_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); diff --git a/sr_unix/mu_rndwn_all.c b/sr_unix/mu_rndwn_all.c index 44680f4..b97a907 100644 --- a/sr_unix/mu_rndwn_all.c +++ b/sr_unix/mu_rndwn_all.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,14 +61,39 @@ #include "db_snapshot.h" #endif +#define PRINT_AND_SEND_SHMREMOVED_MSG(MSGBUFF, FNAME_LEN, FNAME, SHMID) \ +{ \ + gtm_putmsg(VARLSTCNT(9) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), ERR_SHMREMOVED, 3, SHMID, FNAME_LEN, FNAME); \ + send_msg(VARLSTCNT(9) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), ERR_SHMREMOVED, 3, SHMID, FNAME_LEN, FNAME); \ +} + +#define PRINT_AND_SEND_REPLPOOL_FAILURE_MSG(MSGBUFF, REPLPOOL_ID, SHMID) \ +{ \ + int msgid; \ + unsigned char ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr; \ + \ + ipcs_ptr = i2asc(ipcs_buff, SHMID); \ + *ipcs_ptr = '\0'; \ + msgid = (JNLPOOL_SEGMENT == REPLPOOL_ID->pool_type) ? ERR_MUJPOOLRNDWNFL : ERR_MURPOOLRNDWNFL; \ + gtm_putmsg(VARLSTCNT(10) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), msgid, 4, LEN_AND_STR(ipcs_buff), \ + LEN_AND_STR(REPLPOOL_ID->instfilename)); \ + send_msg(VARLSTCNT(10) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), msgid, 4, LEN_AND_STR(ipcs_buff), \ + LEN_AND_STR(REPLPOOL_ID->instfilename)); \ +} + +#define PRINT_AND_SEND_DBRNDWN_FAILURE_MSG(MSGBUFF, FNAME, SHMID) \ +{ \ + gtm_putmsg(VARLSTCNT(9) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), ERR_MUFILRNDWNFL2, 3, SHMID, LEN_AND_STR(FNAME)); \ + send_msg(VARLSTCNT(9) ERR_TEXT, 2, LEN_AND_STR(MSGBUFF), ERR_MUFILRNDWNFL2, 3, SHMID, LEN_AND_STR(FNAME)); \ +} + GBLREF gd_region *gv_cur_region; LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; -#define TMP_BUF_LEN 50 - error_def(ERR_DBFILERR); +error_def(ERR_MUFILRNDWNFL2); error_def(ERR_MUFILRNDWNSUC); error_def(ERR_MUJPOOLRNDWNFL); error_def(ERR_MUJPOOLRNDWNSUC); @@ -107,9 +132,8 @@ CONDITION_HANDLER(mu_rndwn_all_helper_ch) STATICFNDEF void mu_rndwn_all_helper(shm_parms *parm_buff, char *fname, int *exit_status, int *tmp_exit_status) { replpool_identifier replpool_id; - boolean_t ret_status; - uchar_ptr_t ret_ptr; - char shmid_buff[TMP_BUF_LEN]; + boolean_t ret_status, jnlpool_sem_created; + unsigned char ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr; ESTABLISH(mu_rndwn_all_helper_ch); if (validate_db_shm_entry(parm_buff, fname, tmp_exit_status)) @@ -135,13 +159,13 @@ STATICFNDEF void mu_rndwn_all_helper(shm_parms *parm_buff, char *fname, int *exi if (SS_NORMAL == *tmp_exit_status) { assert(JNLPOOL_SEGMENT == replpool_id.pool_type || RECVPOOL_SEGMENT == replpool_id.pool_type); - ret_status = mu_rndwn_repl_instance(&replpool_id, TRUE, FALSE); - ret_ptr = i2asc((uchar_ptr_t)shmid_buff, parm_buff->shmid); - *ret_ptr = '\0'; + ret_status = mu_rndwn_repl_instance(&replpool_id, TRUE, FALSE, &jnlpool_sem_created); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, parm_buff->shmid); + *ipcs_ptr = '\0'; gtm_putmsg(VARLSTCNT(6) (JNLPOOL_SEGMENT == replpool_id.pool_type) ? (ret_status ? ERR_MUJPOOLRNDWNSUC : ERR_MUJPOOLRNDWNFL) : (ret_status ? ERR_MURPOOLRNDWNSUC : ERR_MURPOOLRNDWNFL), - 4, LEN_AND_STR(shmid_buff), LEN_AND_STR(replpool_id.instfilename)); + 4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(replpool_id.instfilename)); if (!ret_status) *exit_status = ERR_MUNOTALLSEC; } else @@ -206,38 +230,41 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta { boolean_t remove_shmid; file_control *fc; - int fname_len, save_errno, status; + int fname_len, save_errno, status, shmid; node_local_ptr_t nl_addr; sm_uc_ptr_t start_addr; struct stat st_buff; struct shmid_ds shmstat; sgmnt_data tsd; unix_db_info *udi; + char msgbuff[OUT_BUFF_SIZE]; if (NULL == parm_buff) return FALSE; /* check for the bare minimum size of the shared memory segment that we expect * (with no fileheader related information at hand) */ - if (NODE_LOCAL_SPACE + SHMPOOL_SECTION_SIZE > parm_buff->sgmnt_siz) + if (MIN_NODE_LOCAL_SPACE + SHMPOOL_SECTION_SIZE > parm_buff->sgmnt_siz) return FALSE; if (IPC_PRIVATE != parm_buff->key) return FALSE; + shmid = parm_buff->shmid; /* we do not need to lock the shm for reading the rundown information as * the other rundowns (if any) can also be allowed to share reading the * same info concurrently. */ - if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(parm_buff->shmid, 0, SHM_RND))) + if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shmid, 0, SHM_RND))) return FALSE; nl_addr = (node_local_ptr_t)start_addr; memcpy(fname, nl_addr->fname, MAX_FN_LEN + 1); fname[MAX_FN_LEN] = '\0'; /* make sure the fname is null terminated */ fname_len = STRLEN(fname); + msgbuff[0] = '\0'; if (memcmp(nl_addr->label, GDS_LABEL, GDS_LABEL_SZ - 1)) { if (!memcmp(nl_addr->label, GDS_LABEL, GDS_LABEL_SZ - 3)) { util_out_print("Cannot rundown shmid = !UL for database !AD as it has format !AD " - "but this mupip uses format !AD", TRUE, parm_buff->shmid, + "but this mupip uses format !AD", TRUE, shmid, fname_len, fname, GDS_LABEL_SZ - 1, nl_addr->label, GDS_LABEL_SZ - 1, GDS_LABEL); *exit_stat = ERR_MUNOTALLSEC; } @@ -246,13 +273,25 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta } if (memcmp(nl_addr->now_running, gtm_release_name, gtm_release_name_len + 1)) { - util_out_print("Cannot rundown shmid !UL for database !AD -> Attempt to access with version !AD, " - "while already using !AD.", TRUE, parm_buff->shmid, fname_len, fname, - gtm_release_name_len, gtm_release_name, LEN_AND_STR(nl_addr->now_running)); + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "Cannot rundown database %s. Attempt to access with version %s, " + "while already using %s", fname, gtm_release_name, nl_addr->now_running); + PRINT_AND_SEND_DBRNDWN_FAILURE_MSG(msgbuff, fname, shmid); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); return FALSE; } + if (-1 == shmctl(shmid, IPC_STAT, &shmstat)) + { + save_errno = errno; + assert(FALSE);/* we were able to attach to this shmid before so should be able to get stats on it */ + util_out_print("!AD -> Error with shmctl for shmid = !UL", + TRUE, fname_len, fname, shmid); + gtm_putmsg(VARLSTCNT(1) save_errno); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } + remove_shmid = FALSE; /* Check if db filename reported in shared memory still exists. If not, clean this shared memory section * without even invoking "mu_rndwn_file" as that expects the db file to exist. Same case if shared memory * points back to a database whose file header does not have this shmid. @@ -260,12 +299,21 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta if (-1 == Stat(fname, &st_buff)) { if (ENOENT == errno) + { + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "File %s does not exist", fname); + if (1 < shmstat.shm_nattch) + { + PRINT_AND_SEND_DBRNDWN_FAILURE_MSG(msgbuff, fname, shmid); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } remove_shmid = TRUE; - else + } else { /* Stat errored out e.g. due to file permissions. Log that */ save_errno = errno; util_out_print("Cannot rundown shmid !UL for database file !AD as stat() on the file" - " returned the following error", TRUE, parm_buff->shmid, fname_len, fname); + " returned the following error", TRUE, shmid, fname_len, fname); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); @@ -281,8 +329,7 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta status = dbfilop(fc); if (SS_NORMAL != status) { - util_out_print("!AD -> Error with dbfilop for shmid = !UL", TRUE, fname_len, fname, - parm_buff->shmid); + util_out_print("!AD -> Error with dbfilop for shmid = !UL", TRUE, fname_len, fname, shmid); gtm_putmsg(VARLSTCNT(5) status, 2, DB_LEN_STR(gv_cur_region), errno); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); @@ -293,48 +340,54 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta if (0 != status) { save_errno = errno; - util_out_print("!AD -> Error with LSEEKREAD for shmid = !UL", TRUE, fname_len, fname, - parm_buff->shmid); + util_out_print("!AD -> Error with LSEEKREAD for shmid = !UL", TRUE, fname_len, fname, shmid); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); return FALSE; } mu_gv_cur_reg_free(); - if (tsd.shmid != parm_buff->shmid) - remove_shmid = TRUE; - else + if (tsd.shmid != shmid) { - if (-1 == shmctl(parm_buff->shmid, IPC_STAT, &shmstat)) + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "Shared memory ID (%d) in the DB file header does not match with the one" + " reported by \"ipcs\" command (%d)", tsd.shmid, shmid); + if (1 < shmstat.shm_nattch) { - save_errno = errno; - assert(FALSE);/* we were able to attach to this shmid before so should be able to get stats on it */ - util_out_print("!AD -> Error with shmctl for shmid = !UL", - TRUE, fname_len, fname, parm_buff->shmid); - gtm_putmsg(VARLSTCNT(1) save_errno); + PRINT_AND_SEND_DBRNDWN_FAILURE_MSG(msgbuff, fname, shmid); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); return FALSE; } - remove_shmid = (tsd.gt_shm_ctime.ctime != shmstat.shm_ctime); + remove_shmid = TRUE; + } else if (tsd.gt_shm_ctime.ctime != shmstat.shm_ctime) + { + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "Shared memory creation time in the DB file header does not match with" + " the one reported by shmctl"); + if (1 < shmstat.shm_nattch) + { + PRINT_AND_SEND_DBRNDWN_FAILURE_MSG(msgbuff, fname, shmid); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } + remove_shmid = TRUE; } } shmdt((void *)start_addr); if (remove_shmid) { - if (0 != shm_rmid(parm_buff->shmid)) + assert('\0' != msgbuff[0]); + if (0 != shm_rmid(shmid)) { save_errno = errno; gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fname_len, fname, ERR_TEXT, 2, RTS_ERROR_TEXT("Error removing shared memory")); - util_out_print("!AD -> Error removing shared memory for shmid = !UL", TRUE, fname_len, fname, - parm_buff->shmid); + util_out_print("!AD -> Error removing shared memory for shmid = !UL", TRUE, fname_len, fname, shmid); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; return FALSE; } - gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, parm_buff->shmid, fname_len, fname); - send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, parm_buff->shmid, fname_len, fname); + PRINT_AND_SEND_SHMREMOVED_MSG(msgbuff, fname_len, fname, shmid); *exit_stat = ERR_SHMREMOVED; } else *exit_stat = SS_NORMAL; @@ -350,11 +403,13 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta */ boolean_t validate_replpool_shm_entry(shm_parms *parm_buff, replpool_id_ptr_t replpool_id, int *exit_stat) { - boolean_t remove_shmid; + boolean_t remove_shmid, jnlpool_segment; int fd; repl_inst_hdr repl_instance; sm_uc_ptr_t start_addr; - int save_errno, status; + int save_errno, status, shmid; + struct shmid_ds shmstat; + char msgbuff[OUT_BUFF_SIZE], *instfilename; if (NULL == parm_buff) return FALSE; @@ -364,13 +419,15 @@ boolean_t validate_replpool_shm_entry(shm_parms *parm_buff, replpool_id_ptr_t re return FALSE; if (IPC_PRIVATE != parm_buff->key) return FALSE; + shmid = parm_buff->shmid; /* we do not need to lock the shm for reading the rundown information as * the other rundowns (if any) can also be allowed to share reading the * same info concurrently. */ - if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(parm_buff->shmid, 0, SHM_RND))) + if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shmid, 0, SHM_RND))) return FALSE; memcpy((void *)replpool_id, (void *)start_addr, SIZEOF(replpool_identifier)); + instfilename = replpool_id->instfilename; /* Even though we could be looking at a replication pool structure that has been created by an older version * or newer version of GT.M, the format of the "replpool_identifier" structure is expected to be the same * across all versions so we can safely dereference the "label" and "instfilename" fields in order to generate @@ -383,7 +440,7 @@ boolean_t validate_replpool_shm_entry(shm_parms *parm_buff, replpool_id_ptr_t re { util_out_print("Cannot rundown replpool shmid = !UL as it has format !AD " "created by !AD but this mupip is version and uses format !AD", - TRUE, parm_buff->shmid, GDS_LABEL_SZ - 1, replpool_id->label, + TRUE, shmid, GDS_LABEL_SZ - 1, replpool_id->label, LEN_AND_STR(replpool_id->now_running), gtm_release_name_len, gtm_release_name, GDS_LABEL_SZ - 1, GDS_RPL_LABEL); *exit_stat = ERR_MUNOTALLSEC; @@ -397,22 +454,45 @@ boolean_t validate_replpool_shm_entry(shm_parms *parm_buff, replpool_id_ptr_t re shmdt((void *)start_addr); return FALSE; } + jnlpool_segment = (JNLPOOL_SEGMENT == replpool_id->pool_type); + if (-1 == shmctl(shmid, IPC_STAT, &shmstat)) + { + save_errno = errno; + assert(FALSE);/* we were able to attach to this shmid before so should be able to get stats on it */ + util_out_print("!AD -> Error with shmctl for shmid = !UL", + TRUE, LEN_AND_STR(instfilename), shmid); + gtm_putmsg(VARLSTCNT(1) save_errno); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } /* Check if instance filename reported in shared memory still exists. If not, clean this * shared memory section without even invoking "mu_rndwn_repl_instance" as that expects * the instance file to exist. Same case if shared memory points back to an instance file * whose file header does not have this shmid. */ - OPENFILE(replpool_id->instfilename, O_RDONLY, fd); /* check if we can open it */ + OPENFILE(instfilename, O_RDONLY, fd); /* check if we can open it */ + msgbuff[0] = '\0'; + remove_shmid = FALSE; if (FD_INVALID == fd) { if (ENOENT == errno) + { + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "File %s does not exist", instfilename); + if (1 < shmstat.shm_nattch) + { + PRINT_AND_SEND_REPLPOOL_FAILURE_MSG(msgbuff, replpool_id, shmid); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } remove_shmid = TRUE; - else + } else { /* open() errored out e.g. due to file permissions. Log that */ save_errno = errno; util_out_print("Cannot rundown replpool shmid !UL for instance file" " !AD as open() on the file returned the following error", - TRUE, parm_buff->shmid, LEN_AND_STR(replpool_id->instfilename)); + TRUE, shmid, LEN_AND_STR(instfilename)); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); @@ -425,32 +505,43 @@ boolean_t validate_replpool_shm_entry(shm_parms *parm_buff, replpool_id_ptr_t re { save_errno = errno; util_out_print("!AD -> Error with LSEEKREAD for shmid = !UL", TRUE, - LEN_AND_STR(replpool_id->instfilename), parm_buff->shmid); + LEN_AND_STR(instfilename), shmid); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; shmdt((void *)start_addr); return FALSE; } - if (repl_instance.jnlpool_shmid != parm_buff->shmid) + if ((jnlpool_segment && (repl_instance.jnlpool_shmid != shmid)) + || (!jnlpool_segment && (repl_instance.recvpool_shmid != shmid))) + { + SNPRINTF(msgbuff, OUT_BUFF_SIZE, "%s SHMID (%d) in the instance file header does not match with the" + " one reported by \"ipcs\" command (%d)", jnlpool_segment ? "Journal Pool" : "Receive Pool", + jnlpool_segment ? repl_instance.jnlpool_shmid : repl_instance.recvpool_shmid, shmid); + if (1 < shmstat.shm_nattch) + { + PRINT_AND_SEND_REPLPOOL_FAILURE_MSG(msgbuff, replpool_id, shmid); + *exit_stat = ERR_MUNOTALLSEC; + shmdt((void *)start_addr); + return FALSE; + } remove_shmid = TRUE; - else - remove_shmid = FALSE; + } CLOSEFILE_RESET(fd, status); /* resets "fd" to FD_INVALID */ } shmdt((void *)start_addr); if (remove_shmid) { - if (0 != shm_rmid(parm_buff->shmid)) + assert('\0' != msgbuff[0]); + if (0 != shm_rmid(shmid)) { save_errno = errno; util_out_print("!AD -> Error removing shared memory for shmid = !UL", - TRUE, LEN_AND_STR(replpool_id->instfilename), parm_buff->shmid); + TRUE, LEN_AND_STR(instfilename), shmid); gtm_putmsg(VARLSTCNT(1) save_errno); *exit_stat = ERR_MUNOTALLSEC; return FALSE; } - gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, parm_buff->shmid, LEN_AND_STR(replpool_id->instfilename)); - send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, parm_buff->shmid, LEN_AND_STR(replpool_id->instfilename)); + PRINT_AND_SEND_SHMREMOVED_MSG(msgbuff, STRLEN(instfilename), instfilename, shmid); *exit_stat = ERR_SHMREMOVED; } else *exit_stat = SS_NORMAL; @@ -505,11 +596,14 @@ char *parse_shm_entry(char *entry, int which_field) for(iter = 1; iter < which_field; iter++) { + /* Strip leading spaces */ while(entry[indx1] == ' ') indx1++; + /* Accept until spaces or NULL */ while(entry[indx1] && entry[indx1] != ' ') indx1++; } + /* Strip leading spaces */ while(entry[indx1] == ' ') indx1++; if ('\0' == entry[indx1]) @@ -518,8 +612,8 @@ char *parse_shm_entry(char *entry, int which_field) return NULL; } parm = (char *)malloc(MAX_PARM_LEN); - memset(parm, 0, MAX_PARM_LEN); - while(entry[indx1] && entry[indx1] != ' ') + /* Copy value from entry until NULL or a space character */ + while(entry[indx1] && (entry[indx1] != ' ') && (indx2 < (MAX_PARM_LEN - 1))) parm[indx2++] = entry[indx1++]; parm[indx2] = '\0'; diff --git a/sr_unix/mu_rndwn_file.c b/sr_unix/mu_rndwn_file.c index dfb0701..424250d 100644 --- a/sr_unix/mu_rndwn_file.c +++ b/sr_unix/mu_rndwn_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,6 +61,7 @@ #include "ftok_sems.h" #include "mu_rndwn_all.h" #include "error.h" +#include "anticipatory_freeze.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif @@ -68,6 +69,8 @@ #include "shmpool.h" /* Needed for the shmpool structures */ #include "is_proc_alive.h" #include "ss_lock_facility.h" +#include "cli.h" +#include "gtm_file_stat.h" #ifndef GTM_SNAPSHOT # error "Snapshot facility not available in this platform" @@ -90,103 +93,114 @@ static gd_region *temp_region; static sgmnt_data_ptr_t temp_cs_data; static sgmnt_addrs *temp_cs_addrs; static boolean_t restore_rndwn_gbl; +static boolean_t mu_rndwn_file_standalone; LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; error_def(ERR_BADDBVER); error_def(ERR_DBFILERR); +error_def(ERR_DBIDMISMATCH); +error_def(ERR_DBNAMEMISMATCH); error_def(ERR_DBNOTGDS); error_def(ERR_DBRDONLY); -error_def(ERR_DBNAMEMISMATCH); -error_def(ERR_DBIDMISMATCH); error_def(ERR_DBSHMNAMEDIFF); +error_def(ERR_JNLORDBFLU); +error_def(ERR_MURNDWNOVRD); +error_def(ERR_MUUSERECOV); +error_def(ERR_MUUSERLBK); +error_def(ERR_SEMREMOVED); +error_def(ERR_SHMREMOVED); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); error_def(ERR_VERMISMATCH); -error_def(ERR_SYSCALL); -error_def(ERR_SHMREMOVED); -error_def(ERR_SEMREMOVED); -#define RESET_GV_CUR_REGION \ -{ \ - gv_cur_region = temp_region; \ - cs_addrs = temp_cs_addrs; \ - cs_data = temp_cs_data; \ +#define RESET_GV_CUR_REGION \ +{ \ + gv_cur_region = temp_region; \ + cs_addrs = temp_cs_addrs; \ + cs_data = temp_cs_data; \ } -#define CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \ -{ \ - int rc; \ - \ - if (FD_INVALID != UDI->fd) \ - { \ - CLOSEFILE_RESET(UDI->fd, rc); \ - assert(FD_INVALID == UDI->fd); \ - } \ - if (NULL != TSD) \ - { \ - free(TSD); \ - TSD = NULL; \ - } \ - if (SEM_INCREMENTED) \ - { \ - do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO); \ - SEM_INCREMENTED = FALSE; \ - } \ - if (SEM_CREATED) \ - { \ - if (-1 == sem_rmid(UDI->semid)) \ - { \ - RNDWN_ERR("!AD -> Error removing semaphore.", REG); \ - } else \ - SEM_CREATED = FALSE; \ - } \ - REVERT; \ - assert((NULL == ftok_sem_reg) || (REG == ftok_sem_reg)); \ - if (REG == ftok_sem_reg) \ - ftok_sem_release(REG, TRUE, TRUE); \ - if (restore_rndwn_gbl) \ - { \ - RESET_GV_CUR_REGION; \ - restore_rndwn_gbl = FALSE; \ - } \ - return FALSE; \ +#define CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \ +{ \ + int rc; \ + \ + if (FD_INVALID != UDI->fd) \ + { \ + CLOSEFILE_RESET(UDI->fd, rc); \ + assert(FD_INVALID == UDI->fd); \ + } \ + if (NULL != TSD) \ + { \ + free(TSD); \ + TSD = NULL; \ + } \ + if (SEM_INCREMENTED) \ + { \ + do_semop(udi->semid, DB_CONTROL_SEM, -1, IPC_NOWAIT | SEM_UNDO); \ + SEM_INCREMENTED = FALSE; \ + } \ + if (SEM_CREATED) \ + { \ + if (-1 == sem_rmid(UDI->semid)) \ + { \ + RNDWN_ERR("!AD -> Error removing semaphore.", REG); \ + } else \ + SEM_CREATED = FALSE; \ + } \ + REVERT; \ + assert((NULL == ftok_sem_reg) || (REG == ftok_sem_reg)); \ + if (REG == ftok_sem_reg) \ + ftok_sem_release(REG, TRUE, TRUE); \ + if (restore_rndwn_gbl) \ + { \ + RESET_GV_CUR_REGION; \ + restore_rndwn_gbl = FALSE; \ + } \ + return FALSE; \ } -#define SEG_SHMATTACH(addr, reg, udi, tsd, sem_created, sem_incremented) \ -{ \ - if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t) \ - do_shmat(udi->shmid, addr, SHM_RND))) \ - { \ - if (EINVAL != errno) \ - RNDWN_ERR("!AD -> Error attaching to shared memory", (reg)); \ - /* shared memory segment no longer exists */ \ - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \ - } \ +#define SEG_SHMATTACH(addr, reg, udi, tsd, sem_created, sem_incremented) \ +{ \ + if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t) \ + do_shmat(udi->shmid, addr, SHM_RND))) \ + { \ + if (EINVAL != errno) \ + RNDWN_ERR("!AD -> Error attaching to shared memory", (reg)); \ + /* shared memory segment no longer exists */ \ + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \ + } \ } -#define SEG_MEMMAP(addr, reg, udi, tsd, sem_created, sem_incremented) \ +#define REMOVE_SEMID_IF_ORPHANED(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \ +{ \ + if (is_orphaned_gtm_semaphore(UDI->semid)) \ + { \ + if (0 != sem_rmid(UDI->semid)) \ + { \ + RNDWN_ERR("!AD -> Error removing semaphore.", reg); \ + CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED); \ + } \ + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \ + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \ + UDI->semid = INVALID_SEMID; \ + } \ +} + +/* Print an error message that, based on whether replication was enabled at the time of the crash, would instruct + * the user to a more appropriate operation than RUNDOWN, such as RECOVER or REQROLLBACK. + */ +#define PRINT_PREVENT_RUNDOWN_MESSAGE(REG) \ { \ - if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)addr, \ - (size_t)stat_buf.st_size, PROT_READ | PROT_WRITE, GTM_MM_FLAGS, udi->fd, (off_t)0))) \ + if (REPL_ENABLED(tsd) && tsd->jnl_before_image) \ { \ - RNDWN_ERR("!AD -> Error mapping memory", (reg)); \ - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \ - } \ -} - -#define REMOVE_SEMID_IF_ORPHANED(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \ -{ \ - if (is_orphaned_gtm_semaphore(UDI->semid)) \ + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MUUSERLBK, 2, DB_LEN_STR(REG), \ + ERR_TEXT, 2, LEN_AND_LIT("Run MUPIP JOURNAL ROLLBACK")); \ + } else \ { \ - if (0 != sem_rmid(UDI->semid)) \ - { \ - RNDWN_ERR("!AD -> Error removing semaphore.", reg); \ - CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED); \ - } \ - send_msg(VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \ - gtm_putmsg(VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \ - UDI->semid = INVALID_SEMID; \ + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MUUSERECOV, 2, DB_LEN_STR(REG), \ + ERR_TEXT, 2, LEN_AND_LIT("Run MUPIP JOURNAL RECOVER")); \ } \ } @@ -201,6 +215,8 @@ error_def(ERR_SEMREMOVED); * Parameters: * standalone = TRUE => create semaphore to get standalone access * standalone = FALSE => rundown shared memory + * Note: Currently there are no callers with standalone == FALSE other + * than MUPIP RUNDOWN. * Return Value: * TRUE for success * FALSE for failure @@ -208,9 +224,9 @@ error_def(ERR_SEMREMOVED); boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { int status, save_errno, sopcnt, tsd_size, save_udi_semid = INVALID_SEMID, semop_res, stat_res, rc; - int csd_size, init_status; + int csd_size; char now_running[MAX_REL_NAME]; - boolean_t rc_cpt_removed = FALSE, sem_created = FALSE, sem_incremented = FALSE, is_gtm_shm; + boolean_t rc_cpt_removed = FALSE, sem_created = FALSE, is_gtm_shm; boolean_t glob_sec_init, db_shm_in_sync, remove_shmid, no_shm_exists; sgmnt_data_ptr_t csd, tsd = NULL; sgmnt_addrs *csa; @@ -225,10 +241,22 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) union semun semarg; uint4 status_msg, ss_pid; shm_snapshot_t *ss_shm_ptr; - gtm_uint64_t sec_size; + gtm_uint64_t sec_size, mmap_sz = 0; +# ifdef GTM_CRYPT + gd_segment *seg; + int gtmcrypt_errno; +# endif + boolean_t override_present, wcs_flu_success, prevent_mu_rndwn; + unsigned char *fn; + mstr jnlfile; + int jnl_fd; + jnl_file_header header; + int4 status1; + uint4 status2; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + mu_rndwn_file_standalone = standalone; restore_rndwn_gbl = FALSE; assert(!jgbl.onlnrlbk); assert(!mupip_jnl_recover || standalone); @@ -240,11 +268,12 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) fc = reg->dyn.addr->file_cntl; fc->op = FC_OPEN; status = dbfilop(fc); - gv_cur_region = temp_region; udi = FILE_INFO(reg); + csa = &(udi->s_addrs); /* Need valid cs_addrs in is_anticipatory_freeze_needed, which can be called */ + cs_addrs = csa; /* by gtm_putmsg(), so set it up here. */ if (SS_NORMAL != status) { - gtm_putmsg(VARLSTCNT(5) status, 2, DB_LEN_STR(reg), errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) status, 2, DB_LEN_STR(reg), errno); if (FD_INVALID != udi->fd) /* Since dbfilop failed, close udi->fd only if it was opened */ CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ return FALSE; @@ -256,13 +285,13 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) */ if (reg->read_only && !standalone) { - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg)); CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ return FALSE; } ESTABLISH_RET(mu_rndwn_file_ch, FALSE); if (!ftok_sem_get(reg, TRUE, GTM_ID, !standalone)) - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); /* Now we have standalone access of the database using ftok semaphore. Any other ftok conflicted database suspends * their operation at this point. At the end of this routine, we release ftok semaphore lock. */ @@ -272,34 +301,29 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (0 != status) { RNDWN_ERR("!AD -> Error reading from file.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } + csa->hdr = tsd; + csa->region = gv_cur_region; # ifdef GTM_CRYPT - /* During rundown gvcst_init is not called and hence we need to do the encryption setup here. */ - /* We do some basic encryption initializations here. - * 1. Call hash check to figure out if the database file's hash matches with that of the db_key_file. - * 2. if the database file is encrypted, then make a call to the encryption plugin with GTMCRYPT_GETKEY to obtain the - * symmetric key which can be used at later stages for encryption and decryption. - * 3. malloc csa->encrypted_blk_contents to be used in jnl_write_aimg_rec and dsk_write_nocache - */ if (tsd->is_encrypted) { csa = &(udi->s_addrs); - INIT_PROC_ENCRYPTION(init_status); - if (0 == init_status) - INIT_DB_ENCRYPTION(reg->dyn.addr->fname, csa, tsd, init_status); - if (0 != init_status) + INIT_PROC_ENCRYPTION(csa, gtmcrypt_errno); + if (0 == gtmcrypt_errno) + INIT_DB_ENCRYPTION(csa, tsd, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(init_status, (reg->dyn.addr->fname)); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + seg = reg->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } } # endif - CSD2UDI(tsd, udi); semarg.buf = &semstat; - REMOVE_SEMID_IF_ORPHANED(reg, udi, tsd, sem_created, sem_incremented); - if (INVALID_SEMID == udi->semid || (-1 == semctl(udi->semid, 0, IPC_STAT, semarg)) || + REMOVE_SEMID_IF_ORPHANED(reg, udi, tsd, sem_created, udi->counter_acc_incremented); + if (INVALID_SEMID == udi->semid || (-1 == semctl(udi->semid, DB_CONTROL_SEM, IPC_STAT, semarg)) || # ifdef GTM64 (((tsd->gt_sem_ctime.ctime & 0xffffffff) == 0) && ((tsd->gt_sem_ctime.ctime >> 32) != semarg.buf->sem_ctime)) || # endif @@ -311,7 +335,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { udi->semid = INVALID_SEMID; RNDWN_ERR("!AD -> Error with semget with IPC_CREAT.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } sem_created = TRUE; tsd->semid = udi->semid; @@ -324,7 +348,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, SETVAL, semarg)) { RNDWN_ERR("!AD -> Error with semctl with SETVAL.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } /* * Warning: We must read the sem_ctime after SETVAL, which changes it. @@ -335,7 +359,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg)) { RNDWN_ERR("!AD -> Error with semctl with IPC_STAT.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } udi->gt_sem_ctime = tsd->gt_sem_ctime.ctime = semarg.buf->sem_ctime; } @@ -351,10 +375,10 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) * specified in a single line. However, each of the 4 lines below represent "one" semaphore operation and hence an * acceptible exception to the coding guidelines. */ - sop[0].sem_num = 0; sop[0].sem_op = 0; /* wait for access control semaphore to be available */ - sop[1].sem_num = 0; sop[1].sem_op = 1; /* lock it */ - sop[2].sem_num = 1; sop[2].sem_op = 0; /* wait for counter semaphore to become 0 */ - sop[3].sem_num = 1; sop[3].sem_op = 1; /* increment the counter semaphore */ + sop[0].sem_num = DB_CONTROL_SEM; sop[0].sem_op = 0; /* wait for access control semaphore to be available */ + sop[1].sem_num = DB_CONTROL_SEM; sop[1].sem_op = 1; /* lock it */ + sop[2].sem_num = DB_COUNTER_SEM; sop[2].sem_op = 0; /* wait for counter semaphore to become 0 */ + sop[3].sem_num = DB_COUNTER_SEM; sop[3].sem_op = 1; /* increment the counter semaphore */ # if defined(GTM64) && defined(BIGENDIAN) /* If the shared memory was created by a 32-bit big-endian version of GT.M the correct ctime will be in the * upper 32 bits and the lower 32 bits will be zero. Detect this case and adjust the time. We expect it to @@ -388,20 +412,65 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (-1 == semop_res) { RNDWN_ERR("!AD -> File already open by another process.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } udi->grabbed_access_sem = TRUE; - sem_incremented = no_shm_exists; - /* Now rundown database if shared memory segment exists. We try this for both values of "standalone" */ + udi->counter_acc_incremented = no_shm_exists; + override_present = (cli_present("OVERRIDE") == CLI_PRESENT); + /* Proceed with rundown if either journaling is off or we got here as a result of MUPIP JOURNAL -RECOVER or + * MUPIP JOURNAL -ROLLBACK, unless the OVERRIDE qualifier is present (see the following code). + */ + prevent_mu_rndwn = JNL_ENABLED(tsd) && !standalone; + /* Now rundown database if shared memory segment exists. We try this for both values of 'standalone'. */ if (no_shm_exists) - { /* No shared memory exists */ - assert(sem_incremented); + { + if (prevent_mu_rndwn) + { + if (override_present) + { /* If the rundown should normally be prevented, but the operator specified an OVERRIDE qualifier, + * record the fact of the usage in the syslog and continue. + */ + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2, DB_LEN_STR(reg), ERR_TEXT, 2, + LEN_AND_LIT("Overriding enabled journaling state")); + } else + { /* Issue error if the crash bit in the journal file is set thereby preventing the user from doing a + * less appropriate operation than RECOVER or ROLLBACK. + */ + jnlfile.addr = (char *)tsd->jnl_file_name; + jnlfile.len = tsd->jnl_file_len; + if (FILE_PRESENT & gtm_file_stat(&jnlfile, NULL, NULL, TRUE, &status2)) + { /* The journal file exists. */ + assert('\0' == jnlfile.addr[jnlfile.len]); + jnlfile.addr[jnlfile.len] = '\0'; /* In case the above assert fails. */ + OPENFILE(jnlfile.addr, O_RDONLY, jnl_fd); + if (0 <= jnl_fd) + { + DO_FILE_READ(jnl_fd, 0, &header, SIZEOF(header), status1, status2); + if (SS_NORMAL == status1) + { /* FALSE in the call below is to skip gtm_putmsgs even on errors. */ + CHECK_JNL_FILE_IS_USABLE(&header, status1, FALSE, 0, NULL); + if ((SS_NORMAL == status1) + && (ARRAYSIZE(header.data_file_name) > header.data_file_name_length)) + { + assert('\0' == header.data_file_name[header.data_file_name_length]); + header.data_file_name[header.data_file_name_length] = '\0'; + if (is_file_identical((char *)header.data_file_name, + (char *)gv_cur_region->dyn.addr->fname) && header.crash) + { + PRINT_PREVENT_RUNDOWN_MESSAGE(reg); + } + } + } + } + } + } + } if (rc_cpt_removed) { /* reset RC values if we've rundown the RC CPT */ /* attempt to force-write header */ tsd->rc_srv_cnt = tsd->dsid = tsd->rc_node = 0; assert(FALSE); /* not sure what to do here. handle it if/when it happens */ - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } else { /* Note that if creation time does not match, we ignore that shared memory segment. It might result in * orphaned shared memory segment which can be later removed with argument-less MUPIP RUNDOWN. @@ -414,11 +483,11 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { if (mupip_jnl_recover) memset(tsd->machine_name, 0, MAX_MCNAMELEN); - LSEEKWRITE(udi->fd, (off_t)0, tsd, tsd_size, status); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, tsd, tsd_size, status); if (0 != status) { RNDWN_ERR("!AD -> Unable to write header to disk.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } } else { @@ -429,21 +498,22 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (!get_full_path((char *)DB_STR_LEN(reg), db_ipcs.fn, &db_ipcs.fn_len, MAX_TRANS_NAME_LEN, &status_msg)) { - gtm_putmsg(VARLSTCNT(1) status_msg); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(1) status_msg); RNDWN_ERR("!AD -> get_full_path failed.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } db_ipcs.fn[db_ipcs.fn_len] = 0; + WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa); if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0)) { RNDWN_ERR("!AD -> gtmsecshr was unable to write header to disk.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } } if (!ftok_sem_release(reg, FALSE, FALSE)) { RNDWN_ERR("!AD -> Error from ftok_sem_release.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ REVERT; @@ -452,18 +522,18 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) return TRUE; /* For "standalone" and "no shared memory existing", we exit here */ } else { /* We are here for not standalone (basically the "mupip rundown" command). */ - if (0 != do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO)) + if (0 != do_semop(udi->semid, DB_CONTROL_SEM, -1, IPC_NOWAIT | SEM_UNDO)) { assert(FALSE); /* We incremented the semaphore, so we should be able to decrement it */ RNDWN_ERR("!AD -> Error decrementing semaphore.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - sem_incremented = FALSE; + udi->counter_acc_incremented = FALSE; if (sem_created && (0 != sem_rmid(udi->semid))) { assert(FALSE); /* We've created the semaphore, so we should be able to remove it */ RNDWN_ERR("!AD -> Error removing semaphore.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } sem_created = FALSE; udi->grabbed_access_sem = FALSE; @@ -475,11 +545,11 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) } } assert(!standalone); - LSEEKWRITE(udi->fd, (off_t)0, tsd, tsd_size, status); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, tsd, tsd_size, status); if (0 != status) { RNDWN_ERR("!AD -> Unable to write header to disk.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ free(tsd); @@ -494,17 +564,17 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) } if (reg->read_only) /* read only process can't succeed beyond this point */ { - gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg)); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg)); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } /* Now we have a pre-existing shared memory section. Do some setup */ if (memcmp(tsd->label, GDS_LABEL, GDS_LABEL_SZ - 1)) { if (memcmp(tsd->label, GDS_LABEL, GDS_LABEL_SZ - 3)) - gtm_putmsg(VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(reg)); else - gtm_putmsg(VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(reg)); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(reg)); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } reg->dyn.addr->acc_meth = acc_meth = tsd->acc_meth; dbsecspc(reg, tsd, &sec_size); @@ -527,8 +597,21 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) restore_rndwn_gbl = TRUE; gv_cur_region = reg; tp_change_reg(); - SEG_SHMATTACH(0, reg, udi, tsd, sem_created, sem_incremented); + SEG_SHMATTACH(0, reg, udi, tsd, sem_created, udi->counter_acc_incremented); cs_addrs->nl = (node_local_ptr_t)cs_addrs->db_addrs[0]; + if (prevent_mu_rndwn && cs_addrs->nl->jnl_file.u.inode) + { + if (override_present) + { /* If the rundown should normally be prevented, but the operator specified an OVERRIDE qualifier, record + * the fact of the usage in the syslog and continue. + */ + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2, DB_LEN_STR(reg), ERR_TEXT, 2, + LEN_AND_LIT("Overriding OPEN journal file state in shared memory")); + } else + { /* Journal file state being still open in shared memory implies a crashed state, so error out. */ + PRINT_PREVENT_RUNDOWN_MESSAGE(reg); + } + } /* The following checks for GDS_LABEL_GENERIC, gtm_release_name, and cs_addrs->nl->glob_sec_init ensure that the * shared memory under consideration is valid. First, since cs_addrs->nl->label is in the same place for every * version, a failing check means it is most likely NOT a GT.M created shared memory, so no attempt will be @@ -544,9 +627,9 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) memcpy(now_running, cs_addrs->nl->now_running, MAX_REL_NAME); if (memcmp(now_running, gtm_release_name, gtm_release_name_len + 1)) { - gtm_putmsg(VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name, LEN_AND_STR(now_running)); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } if (cs_addrs->nl->glob_sec_init) { @@ -554,12 +637,12 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1)) { if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 3)) - gtm_putmsg(VARLSTCNT(8) ERR_DBNOTGDS, 2, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBNOTGDS, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_LITERAL("(from shared segment - nl)")); else - gtm_putmsg(VARLSTCNT(8) ERR_BADDBVER, 2, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BADDBVER, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_LITERAL("(from shared segment - nl)")); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } /* Since nl is memset to 0 initially and then fname is copied over from gv_cur_region and since "fname" is * guaranteed to not exceed MAX_FN_LEN, we should have a terminating '\0' at least at @@ -573,22 +656,24 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { save_errno = errno; db_shm_in_sync = FALSE; - if( ENOENT == save_errno) + if (ENOENT == save_errno) { - send_msg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg), - udi->shmid, cs_addrs->nl->fname, save_errno); - gtm_putmsg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, + DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname, save_errno); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, + DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname); /* In this case, the shared memory no longer points to a valid db file in the filesystem. * So it is best that we remove this shmid. But remove_shmid is already TRUE. Assert that. */ assert(remove_shmid); - } - else /* Could be permission issue */ + } else /* Could be permission issue */ { - send_msg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, + DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname, save_errno); - gtm_putmsg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, + DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname, save_errno); remove_shmid = FALSE; /* Shared memory might be pointing to valid database */ } @@ -597,11 +682,11 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { /* Check if csa->nl->fname and csa->nl->dbfid are in sync. If not, then db & shm are not in sync */ if (FALSE == is_gdid_stat_identical(&cs_addrs->nl->unique_id.uid, &stat_buf)) { - send_msg(VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, cs_addrs->nl->fname, - DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, + cs_addrs->nl->fname, DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2, LEN_AND_LIT("[MUPIP] Database filename and fileid in shared memory are not in sync")); - gtm_putmsg(VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, cs_addrs->nl->fname, - DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, + cs_addrs->nl->fname, DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2, LEN_AND_LIT("[MUPIP] Database filename and fileid in shared memory are not in sync")); db_shm_in_sync = FALSE; /* In this case, the shared memory points to a file that exists in the filesystem but @@ -620,13 +705,14 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) */ if (db_shm_in_sync && !is_file_identical((char *)cs_addrs->nl->fname, (char *)reg->dyn.addr->fname)) { - send_msg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname); - gtm_putmsg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname); db_shm_in_sync = FALSE; remove_shmid = FALSE; } + wcs_flu_success = TRUE; /* If db & shm are not in sync at this point, skip the part of flushing shm to db file on disk. * We still need to reset the fields (shmid, semid etc.) in db file header. * About deleting the shmid, it depends on the type of out-of-sync between db & shm. This is handled @@ -634,7 +720,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) */ if (db_shm_in_sync) { - if (!sem_incremented) + if (!udi->counter_acc_incremented) { /* Now that we have ensured db & shm are in sync and will be doing the "actual" * rundown, we need to ensure that no one is attached to the database (counter * sempahore is 0) @@ -648,16 +734,16 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) if (-1 == semop_res) { RNDWN_ERR("!AD -> File already open by another process.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - sem_incremented = TRUE; + udi->counter_acc_incremented = TRUE; } /* If db & shm are in sync AND we aren't alone in using it, we can do nothing */ if (0 != shm_buf.shm_nattch) { util_out_print("!AD [!UL]-> File is in use by another process.", TRUE, DB_LEN_STR(reg), udi->shmid); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } /* The shared section is valid and up-to-date with respect to the database file header; * ignore the temporary storage and use the shared section from here on @@ -668,26 +754,34 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) assert(0 == ((INTPTR_T)cs_addrs->critical & (CACHELINE_SIZE - 1))); # endif JNL_INIT(cs_addrs, reg, tsd); - cs_addrs->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(cs_addrs->db_addrs[0] + NODE_LOCAL_SPACE + + cs_addrs->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(cs_addrs->db_addrs[0] + NODE_LOCAL_SPACE(tsd) + JNL_SHARE_SIZE(tsd)); cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)cs_addrs->shmpool_buffer + SHMPOOL_SECTION_SIZE; cs_addrs->lock_addrs[1] = cs_addrs->lock_addrs[0] + LOCK_SPACE_SIZE(tsd) - 1; - if (dba_bg == acc_meth) - cs_data = csd = cs_addrs->hdr = (sgmnt_data_ptr_t)(cs_addrs->lock_addrs[1] + 1 + - CACHE_CONTROL_SIZE(tsd)); - else { - cs_addrs->acc_meth.mm.mmblk_state = (mmblk_que_heads_ptr_t)(cs_addrs->lock_addrs[1] + 1); + cs_data = csd = csa->hdr = (sgmnt_data_ptr_t)(cs_addrs->lock_addrs[1] + 1 + + CACHE_CONTROL_SIZE(tsd)); + assert(csa->nl->cache_off == -CACHE_CONTROL_SIZE(csd)); + db_csh_ini(csa); + } else + { + cs_data = csd = csa->hdr = (sgmnt_data_ptr_t)((sm_uc_ptr_t)csa->lock_addrs[1] + 1); FSTAT_FILE(udi->fd, &stat_buf, stat_res); if (-1 == stat_res) { RNDWN_ERR("!AD -> Error with fstat.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - SEG_MEMMAP(NULL, reg, udi, tsd, sem_created, sem_incremented); - cs_data = csd = cs_addrs->hdr = (sgmnt_data_ptr_t)cs_addrs->db_addrs[0]; - cs_addrs->db_addrs[1] = cs_addrs->db_addrs[0] + stat_buf.st_size - 1; + mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(csd); + CHECK_LARGEFILE_MMAP(reg, mmap_sz); /* can issue rts_error MMFILETOOLARGE */ + cs_addrs->db_addrs[0] = (sm_uc_ptr_t) MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(csd), FALSE); + if (-1 == (sm_long_t)(cs_addrs->db_addrs[0])) + { + RNDWN_ERR("!AD -> Error mapping memory", reg); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); + } + cs_addrs->db_addrs[1] = cs_addrs->db_addrs[0] + mmap_sz - 1; } assert(sem_created || ((csd->semid == tsd->semid) && (csd->gt_sem_ctime.ctime == tsd->gt_sem_ctime.ctime))); @@ -709,28 +803,25 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { status_msg = ERR_DBNOTGDS; if (0 != shm_rmid(udi->shmid)) - gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_TEXT("Error removing shared memory")); else { - gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); - send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, + DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, + DB_LEN_STR(reg)); } } else status_msg = ERR_BADDBVER; - gtm_putmsg(VARLSTCNT(8) status_msg, 2, DB_LEN_STR(reg), + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) status_msg, 2, DB_LEN_STR(reg), ERR_TEXT, 2, RTS_ERROR_LITERAL("(File header in the shared segment seems corrupt)")); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - if (dba_bg == acc_meth) - db_csh_ini(cs_addrs); - else - cs_addrs->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_ulong_t)csd + (int)(csd->start_vbn - 1) - * DISK_BLOCK_SIZE); db_common_init(reg, cs_addrs, csd); /* do initialization common to "db_init" and "mu_rndwn_file" */ /* cleanup mutex stuff */ cs_addrs->hdr->image_count = 0; - gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE); /* it is ensured, this is the only process running */ + gtm_mutex_init(reg, NUM_CRIT_ENTRY(cs_addrs->hdr), FALSE); /* this is the only process running */ assert(!cs_addrs->hold_onto_crit); /* so it is safe to do unconditional grab_crit/rel_crit below */ cs_addrs->nl->in_crit = 0; cs_addrs->now_crit = FALSE; @@ -775,8 +866,32 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) * So, a new process will switch the journal file and cut the journal file link, * though it might be a good journal without an EOF */ - wcs_flu(WCSFLU_NONE); - csd = cs_addrs->hdr; + wcs_flu_success = wcs_flu(WCSFLU_NONE); + if (!wcs_flu_success) + { + if (override_present && !standalone) + { /* Case of MUPIP RUNDOWN with OVERRIDE flag; continue. */ + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2, + DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT( + "Overriding error during database block flush")); + csd = cs_addrs->hdr; + } else + { /* In case of MUPIP RUNDOWN append a suggestion to use OVERRIDE flag + * to bypass the error. + */ + if (standalone) + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) + ERR_JNLORDBFLU, 2, DB_LEN_STR(reg)); + else + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) + ERR_JNLORDBFLU, 2, DB_LEN_STR(reg), + ERR_TEXT, 2, LEN_AND_LIT( + "To force the operation to proceed, use the " + "OVERRIDE qualifier")); + assert(FALSE); /* The above rts_error should not return. */ + return FALSE; + } + } } jpc = cs_addrs->jnl; if (NULL != jpc) @@ -806,45 +921,52 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) csd_size = tsd_size; /* SIZEOF(sgmnt_data) */ } reg->open = FALSE; - /* Note: At this point we have write permission */ - memset(csd->machine_name, 0, MAX_MCNAMELEN); - if (!mupip_jnl_recover) - csd->freeze = 0; - RESET_SHMID_CTIME(csd); - if (!standalone) - { /* Invalidate semid in the file header as part of rundown. The actual semaphore still - * exists and we'll remove that just before releasing the ftok semaphore. However, if the - * MUPIP RUNDOWN command gets killed AFTER we write the file header but BEFORE we remove - * the semaphore from the system, we can have an orphaned semaphore. But, this is okay - * since an arugment-less MUPIP RUNDOWN, if invoked, will remove those orphaned semaphores - */ - RESET_SEMID_CTIME(csd); - } - if (!db_shm_in_sync || (dba_bg == acc_meth)) - { - LSEEKWRITE(udi->fd, (off_t)0, csd, csd_size, status); + /* If wcs_flu returned FALSE, it better be because of MUPIP RUNDOWN run with OVERRIDE qualifier. */ + assert(wcs_flu_success || (override_present && !standalone)); + /* In case MUPIP RUNDOWN is invoked with OVERRIDE qualifier and we ignored a FALSE return from wcs_flu, do + * not update the database header, thus forcing the operator to either use a ROLLBACK/RECOVER or supply the + * OVERRIDE qualifier with RUNDOWN before GT.M could again be used to access the database. + */ + if (wcs_flu_success) + { /* Note: At this point we have write permission */ + memset(csd->machine_name, 0, MAX_MCNAMELEN); + if (!mupip_jnl_recover) + csd->freeze = 0; + RESET_SHMID_CTIME(csd); + if (!standalone) + { /* Invalidate semid in the file header as part of rundown. The actual semaphore still + * exists and we'll remove that just before releasing the ftok semaphore. However, if the + * MUPIP RUNDOWN command gets killed AFTER we write the file header but BEFORE we remove + * the semaphore from the system, we can have an orphaned semaphore. But, this is okay + * since an arugment-less MUPIP RUNDOWN, if invoked, will remove those orphaned semaphores + */ + RESET_SEMID_CTIME(csd); + } + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, csd, csd_size, status); if (0 != status) { RNDWN_ERR("!AD -> Error writing header to disk.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - if (NULL != tsd) - { - assert(!db_shm_in_sync); - free(tsd); - tsd = NULL; - } - } else + } + if (NULL != tsd) { - if (-1 == msync((caddr_t)cs_addrs->db_addrs[0], (size_t)stat_buf.st_size, MS_SYNC)) + assert(!db_shm_in_sync); + free(tsd); + tsd = NULL; + } + if (dba_mm == acc_meth) + { + assert(0 != mmap_sz); + if (-1 == msync((caddr_t)cs_addrs->db_addrs[0], mmap_sz, MS_SYNC)) { RNDWN_ERR("!AD -> Error synchronizing mapped memory.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } - if (-1 == munmap((caddr_t)cs_addrs->db_addrs[0], (size_t)stat_buf.st_size)) + if (-1 == munmap((caddr_t)cs_addrs->db_addrs[0], mmap_sz)) { RNDWN_ERR("!AD -> Error unmapping mapped memory.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } } } else @@ -859,7 +981,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { assert(FALSE); RNDWN_ERR("!AD -> Error detaching from shared memory.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } cs_addrs->nl = NULL; /* Remove the shared memory only if it is a GT.M created one. */ @@ -869,13 +991,17 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) { if (0 != shm_rmid(udi->shmid)) { - assert(FALSE); - RNDWN_ERR("!AD -> Error removing shared memory.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + save_errno = errno; + if ((EINVAL != save_errno) && (EIDRM != save_errno)) + { + assert(FALSE); + RNDWN_ERR("!AD -> Error removing shared memory.", reg); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); + } } else { - gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); - send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg)); } } udi->shmid = INVALID_SHMID; @@ -891,11 +1017,11 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) RESET_SHMID_CTIME(tsd); if (mupip_jnl_recover) memset(tsd->machine_name, 0, MAX_MCNAMELEN); - LSEEKWRITE(udi->fd, (off_t)0, tsd, tsd_size, status); + DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, tsd, tsd_size, status); if (0 != status) { RNDWN_ERR("!AD -> Unable to write header to disk.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } free(tsd); tsd = NULL; @@ -903,25 +1029,19 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) assert(INVALID_SHMID == udi->shmid); assert(0 == udi->gt_shm_ctime); assert(udi->grabbed_access_sem); - assert(!db_shm_in_sync || sem_incremented); + assert(!db_shm_in_sync || udi->counter_acc_incremented); assert(INVALID_SEMID != udi->semid); if (!standalone && (db_shm_in_sync || sem_created)) - { /* need to release the access control semaphore */ - if (0 != do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO)) - { - assert(FALSE); /* We incremented the semaphore, so we should be able to decrement it */ - RNDWN_ERR("!AD -> Error decrementing semaphore.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); - } - sem_incremented = FALSE; + { if (0 != sem_rmid(udi->semid)) { assert(FALSE); /* We've created the semaphore, so we should be able to remove it */ RNDWN_ERR("!AD -> Error removing semaphore.", reg); - CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); + CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented); } sem_created = FALSE; udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; udi->semid = INVALID_SEMID; } REVERT; @@ -933,7 +1053,8 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone) */ if (!ftok_sem_release(reg, !standalone, !standalone)) return FALSE; - assert(!standalone || udi->grabbed_access_sem); /* if "standalone" we better leave this function with standalone access */ + /* if "standalone" we better leave this function with standalone access */ + assert(!standalone || udi->grabbed_access_sem); CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */ DEBUG_ONLY(in_mu_rndwn_file = FALSE); return TRUE; @@ -945,11 +1066,7 @@ CONDITION_HANDLER(mu_rndwn_file_ch) sgmnt_addrs *csa; START_CH; - /* The mu_rndwn_file_ch was introduced in revision 1.54 to account for the ERR_DBIDMISMATCH rts_error that no longer - * exists. So, it is not expected that mu_rndwn_file_ch will ever be called. Add an assert(FALSE). If the assert does - * not trip after an year or two, we can remove this condition handler altogether. 2010/07 - */ - assert(FALSE); + PRN_ERROR; assert(NULL != rundown_reg); if (NULL != rundown_reg) { @@ -964,5 +1081,15 @@ CONDITION_HANDLER(mu_rndwn_file_ch) { RESET_GV_CUR_REGION; } - NEXTCH; + rundown_reg->open = FALSE; + /* We want to proceed to the next condition handler in case we have stand-alone access, because if an error happens on one + * region, we should signal an issue and not proceed to the next region. Otherwise, we try to rundown the next region. + */ + if (mu_rndwn_file_standalone) + { + NEXTCH; + } else + { + UNWIND(NULL, NULL); + } } diff --git a/sr_unix/mu_rndwn_repl_instance.c b/sr_unix/mu_rndwn_repl_instance.c index 6504f6b..b16b1de 100644 --- a/sr_unix/mu_rndwn_repl_instance.c +++ b/sr_unix/mu_rndwn_repl_instance.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -55,6 +55,9 @@ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" #include "error.h" +#include "anticipatory_freeze.h" +#include "heartbeat_timer.h" +#include "mutex.h" GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; @@ -74,8 +77,6 @@ error_def(ERR_REPLACCSEM); error_def(ERR_SEMREMOVED); error_def(ERR_SYSCALL); -#define TMP_BUF_LEN 50 - /* * This will rundown a replication instance journal (and receiver) pool. * Input Parameter: @@ -84,19 +85,24 @@ error_def(ERR_SYSCALL); * TRUE, if successful. * FALSE, otherwise. */ -boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t immediate, boolean_t rndwn_both_pools) +boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t immediate, boolean_t rndwn_both_pools, + boolean_t *jnlpool_sem_created) { boolean_t jnlpool_stat = SS_NORMAL, recvpool_stat = SS_NORMAL, decr_cnt, sem_created = FALSE, ipc_rmvd; - char *instfilename, shmid_buff[TMP_BUF_LEN]; + char *instfilename; + unsigned char ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr; gd_region *r_save; repl_inst_hdr repl_instance; static gd_region *reg = NULL; struct semid_ds semstat; struct shmid_ds shmstat; - uchar_ptr_t ret_ptr; unix_db_info *udi; - int save_errno, sem_id, shm_id; + int save_errno, sem_id, shm_id, status; + sgmnt_addrs *repl_csa; + boolean_t was_crit; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (NULL == reg) { r_save = gv_cur_region; @@ -104,6 +110,7 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm reg = gv_cur_region; gv_cur_region = r_save; } + *jnlpool_sem_created = FALSE; /* Assert that the layout of replpool_identifier is identical for all versions going forward as the function * "validate_replpool_shm_entry" (used by the argumentless mupip rundown aka "mupip rundown") relies on this. * This assert is placed here (instead of there) because the automated tests exercise this logic much more @@ -143,15 +150,17 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm ESTABLISH_RET(mu_rndwn_repl_instance_ch, FALSE); repl_inst_read(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); assert(rndwn_both_pools || JNLPOOL_SEGMENT == replpool_id->pool_type || RECVPOOL_SEGMENT == replpool_id->pool_type); - memset(shmid_buff, 0, TMP_BUF_LEN); if (rndwn_both_pools || (JNLPOOL_SEGMENT == replpool_id->pool_type)) { /* -------------------------- * First rundown Journal pool * -------------------------- */ shm_id = repl_instance.jnlpool_shmid; - if (SS_NORMAL == (jnlpool_stat = mu_replpool_grab_sem(&repl_instance, JNLPOOL_SEGMENT, &sem_created))) + if (SS_NORMAL == (jnlpool_stat = mu_replpool_grab_sem(&repl_instance, JNLPOOL_SEGMENT, &sem_created, immediate))) { + /* Got JNL_POOL_ACCESS_SEM and incremented SRC_SRV_COUNT_SEM */ + assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); + assert(holds_sem[SOURCE][SRC_SERV_COUNT_SEM]); sem_id = repl_instance.jnlpool_semid; if ((INVALID_SHMID == shm_id) || (-1 == shmctl(shm_id, IPC_STAT, &shmstat)) || (shmstat.shm_ctime != repl_instance.jnlpool_shmid_ctime)) @@ -165,10 +174,11 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm { replpool_id->pool_type = JNLPOOL_SEGMENT; jnlpool_stat = mu_rndwn_replpool(replpool_id, &repl_instance, shm_id, &ipc_rmvd); - i2asc((uchar_ptr_t)shmid_buff, shm_id); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id); + *ipcs_ptr = '\0'; if (rndwn_both_pools && ((SS_NORMAL != jnlpool_stat) || ipc_rmvd)) gtm_putmsg(VARLSTCNT(6) (jnlpool_stat ? ERR_MUJPOOLRNDWNFL : ERR_MUJPOOLRNDWNSUC), - 4, LEN_AND_STR(shmid_buff), LEN_AND_STR(replpool_id->instfilename)); + 4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(instfilename)); } assert(ipc_rmvd || (NULL != jnlpool_ctl)); assert((NULL == jnlpool.jnlpool_ctl) || (SS_NORMAL == jnlpool_stat) || jgbl.onlnrlbk); @@ -179,22 +189,38 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm { /* Invoked by MUPIP RUNDOWN in which case the semaphores needs to be removed. But, remove the * semaphore ONLY if we created it here OR the journal pool was successfully removed. */ - if ((sem_created || (SS_NORMAL == jnlpool_stat)) - && (SS_NORMAL == mu_replpool_remove_sem(&repl_instance, JNLPOOL_SEGMENT, TRUE))) - { /* Now that semaphores are removed, reset fields in file header */ - if (!sem_created) - { /* if sem_id was "created" by mu_replpool_grab_sem then do NOT report the - * MURPOOLRNDWNSUC message as it indicates that the semaphore was orphaned and we - * removed it when in fact there was no orphaned semaphore and we "created" it as - * part of mu_replpool_grab_sem to get standalone access to rundown the receiver - * pool (which may or may not exist) - */ - /* note that shmid_buff used here is actually a buffer to hold semid (not shmid) */ - i2asc((uchar_ptr_t)shmid_buff, sem_id); - gtm_putmsg(VARLSTCNT(9) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(shmid_buff), - LEN_AND_STR(replpool_id->instfilename), ERR_SEMREMOVED, 1, sem_id); + if (NULL == jnlpool_ctl) + { + if (((sem_created || (SS_NORMAL == jnlpool_stat)) + && (SS_NORMAL == mu_replpool_release_sem(&repl_instance, JNLPOOL_SEGMENT, TRUE)))) + { /* Now that semaphores are removed, reset fields in file header */ + if (!sem_created) + { /* If sem_id was created by mu_replpool_grab_sem then do NOT report the + * MURPOOLRNDWNSUC message as it indicates that the semaphore was orphaned + * and we removed it when in fact there was no orphaned semaphore and we + * created it as part of mu_replpool_grab_sem to get standalone access to + * rundown the receiver pool (which may or may not exist) + */ + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, sem_id); + *ipcs_ptr = '\0'; + gtm_putmsg(VARLSTCNT(9) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename), ERR_SEMREMOVED, 1, sem_id); + } + repl_inst_jnlpool_reset(); } - repl_inst_jnlpool_reset(); + } else + { /* Anticipatory Freeze scheme is turned ON. So, release just the JNL_POOL_ACCESS_SEM. The + * semaphore will be released/removed in the caller (mupip_rundown) + */ + assert(ANTICIPATORY_FREEZE_AVAILABLE); + assertpro(SS_NORMAL == (status = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM))); + assert(!holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); + /* Since we are not resetting the semaphore IDs in the file header, we need to write out + * the semaphore IDs in the instance file (if we created them). + */ + if (sem_created) + repl_inst_write(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, + SIZEOF(repl_inst_hdr)); } /* If semaphore is not created and the journal pool rundown failed (due to attached processes), * rundown process continues to holds the journal pool access control semaphore. This way, we hold @@ -207,16 +233,17 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm * until we record such semaphores in an ignore-list (or some such) and change mu_rndwn_sem_all to * skip the ones that are present in the ignore list. */ - assert((sem_created || (SS_NORMAL == jnlpool_stat)) || holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]); holds_sem[SOURCE][JNL_POOL_ACCESS_SEM] = FALSE; } } else if (rndwn_both_pools && (INVALID_SHMID != shm_id)) { - i2asc((uchar_ptr_t)shmid_buff, shm_id); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id); + *ipcs_ptr = '\0'; if (rndwn_both_pools) - gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, LEN_AND_STR(shmid_buff), - LEN_AND_STR(replpool_id->instfilename)); + gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename)); } + *jnlpool_sem_created = sem_created; } if (((SS_NORMAL == jnlpool_stat) || !jgbl.mur_rollback) && (rndwn_both_pools || (RECVPOOL_SEGMENT == replpool_id->pool_type))) @@ -229,7 +256,7 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm * RECVPOOL even if the JNLPOOL rundown failed. */ shm_id = repl_instance.recvpool_shmid; - if (SS_NORMAL == (recvpool_stat = mu_replpool_grab_sem(&repl_instance, RECVPOOL_SEGMENT, &sem_created))) + if (SS_NORMAL == (recvpool_stat = mu_replpool_grab_sem(&repl_instance, RECVPOOL_SEGMENT, &sem_created, immediate))) { sem_id = repl_instance.recvpool_semid; if ((INVALID_SHMID == shm_id) || (-1 == shmctl(shm_id, IPC_STAT, &shmstat)) @@ -243,10 +270,11 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm { replpool_id->pool_type = RECVPOOL_SEGMENT; recvpool_stat = mu_rndwn_replpool(replpool_id, &repl_instance, shm_id, &ipc_rmvd); - i2asc((uchar_ptr_t)shmid_buff, shm_id); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id); + *ipcs_ptr = '\0'; if (rndwn_both_pools && ((SS_NORMAL != recvpool_stat) || ipc_rmvd)) gtm_putmsg(VARLSTCNT(6) (recvpool_stat ? ERR_MURPOOLRNDWNFL : ERR_MURPOOLRNDWNSUC), - 4, LEN_AND_STR(shmid_buff), LEN_AND_STR(replpool_id->instfilename)); + 4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(instfilename)); } assert((TRUE == ipc_rmvd) || (SS_NORMAL != recvpool_stat) || jgbl.onlnrlbk); assert((INVALID_SHMID != repl_instance.recvpool_shmid) || (0 == repl_instance.recvpool_shmid_ctime)); @@ -254,10 +282,10 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm assert(INVALID_SEMID != sem_id); if (!mur_options.rollback) { /* Invoked by MUPIP RUNDOWN in which case the semaphores needs to be removed. But, remove the - * semaphore ONLY if we created it here OR the journal pool was successfully removed. + * semaphore ONLY if we created it here OR the receive pool was successfully removed. */ if ((sem_created || (SS_NORMAL == recvpool_stat)) - && (SS_NORMAL == mu_replpool_remove_sem(&repl_instance, RECVPOOL_SEGMENT, TRUE))) + && (SS_NORMAL == mu_replpool_release_sem(&repl_instance, RECVPOOL_SEGMENT, TRUE))) { /* Now that semaphores are removed, reset fields in file header */ if (!sem_created) { /* if sem_id was "created" by mu_replpool_grab_sem then do NOT report the @@ -266,12 +294,32 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm * part of mu_replpool_grab_sem to get standalone access to rundown the receiver * pool (which may or may not exist) */ - /* note that shmid_buff used here is actually a buffer to hold semid (not shmid) */ - i2asc((uchar_ptr_t)shmid_buff, sem_id); - gtm_putmsg(VARLSTCNT(9) ERR_MURPOOLRNDWNSUC, 4, LEN_AND_STR(shmid_buff), - LEN_AND_STR(replpool_id->instfilename), ERR_SEMREMOVED, 1, sem_id); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, sem_id); + *ipcs_ptr = '\0'; + gtm_putmsg(VARLSTCNT(9) ERR_MURPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename), ERR_SEMREMOVED, 1, sem_id); + } + if (NULL != jnlpool_ctl) + { /* Journal pool is not yet removed. So, grab lock before resetting semid/shmid + * fields in the file header as the function expects the caller to hold crit + * if the journal pool is available + */ + repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; + assert(!repl_csa->now_crit); + assert(!repl_csa->hold_onto_crit); + was_crit = repl_csa->now_crit; + /* Since we do grab_lock, below, we need to do a per-process initialization. Also, + * start heartbeat so that grab_lock can issue MUTEXLCKALERT and get C-stacks if + * waiting for crit + */ + START_HEARTBEAT_IF_NEEDED; + mutex_per_process_init(); + if (!was_crit) + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); } repl_inst_recvpool_reset(); + if ((NULL != jnlpool_ctl) && !was_crit) + rel_lock(jnlpool.jnlpool_dummy_reg); } /* If semaphore is not created and the receive pool rundown failed (due to attached processes), * rundown process continues to holds the receive pool access control semaphore. This way, we hold @@ -285,20 +333,21 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm * skip the ones that are present in the ignore list. */ assert((sem_created || (SS_NORMAL == recvpool_stat)) || holds_sem[RECV][RECV_POOL_ACCESS_SEM]); - holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE; + DEBUG_ONLY(set_sem_set_recvr(sem_id)); } } else if (rndwn_both_pools && (INVALID_SHMID != shm_id)) { - i2asc((uchar_ptr_t)shmid_buff, shm_id); + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shm_id); + *ipcs_ptr = '\0'; if (rndwn_both_pools) - gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNFL, 4, LEN_AND_STR(shmid_buff), - LEN_AND_STR(replpool_id->instfilename)); + gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNFL, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename)); } } - assert(jgbl.onlnrlbk || (NULL == jnlpool.repl_inst_filehdr)); + assert(jgbl.onlnrlbk || ANTICIPATORY_FREEZE_AVAILABLE || (NULL == jnlpool.repl_inst_filehdr)); if (mur_options.rollback && (SS_NORMAL == jnlpool_stat) && (SS_NORMAL == recvpool_stat)) { - assert(jgbl.onlnrlbk || ((INVALID_SHMID == repl_instance.jnlpool_shmid) + assert(jgbl.onlnrlbk || ANTICIPATORY_FREEZE_AVAILABLE || ((INVALID_SHMID == repl_instance.jnlpool_shmid) && (INVALID_SHMID == repl_instance.recvpool_shmid))); /* Initialize jnlpool.repl_inst_filehdr as it is used later by gtmrecv_fetchresync() */ decr_cnt = FALSE; @@ -325,8 +374,8 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm } /* Flush changes to the replication instance file header to disk */ repl_inst_write(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); - } else /* for MUPIP RUNDOWN, semid fields in the file header are reset and is written in mu_replpool_remove_sem() above */ - decr_cnt = TRUE; + } else /* for MUPIP RUNDOWN, semid fields in the file header are reset and is written in mu_replpool_release_sem() above */ + decr_cnt = (NULL == jnlpool_ctl); /* for anticipatory freeze, mupip_rundown releases the semaphore */ REVERT; /* Release replication instance ftok semaphore lock */ if (!ftok_sem_release(reg, decr_cnt, immediate)) /* Do not decrement the counter if ROLLBACK */ diff --git a/sr_unix/mu_rndwn_repl_instance.h b/sr_unix/mu_rndwn_repl_instance.h index 7e9d768..a5c565a 100644 --- a/sr_unix/mu_rndwn_repl_instance.h +++ b/sr_unix/mu_rndwn_repl_instance.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 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 MU_RNDWN_REPL_INSTANCE_INCLUDED #define MU_RNDWN_REPL_INSTANCE_INCLUDED -boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t immediate, boolean_t rndwn_both_pools); +boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t immediate, boolean_t rndwn_both_pools, + boolean_t *jnlpool_sem_created); #endif /* MU_RNDWN_REPL_INSTANCE_INCLUDED */ diff --git a/sr_unix/mu_rndwn_replpool.c b/sr_unix/mu_rndwn_replpool.c index 48ab3f4..ae3cad7 100644 --- a/sr_unix/mu_rndwn_replpool.c +++ b/sr_unix/mu_rndwn_replpool.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -56,6 +56,7 @@ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" #include "error.h" +#include "anticipatory_freeze.h" GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; @@ -63,6 +64,7 @@ GBLREF jnl_gbls_t jgbl; GBLREF uint4 mutex_per_process_init_pid; GBLREF uint4 process_id; GBLREF mur_gbls_t murgbl; +GBLREF boolean_t argumentless_rundown; LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; @@ -73,13 +75,6 @@ error_def(ERR_REPLPOOLINST); error_def(ERR_SYSCALL); error_def(ERR_TEXT); - -#define ISSUE_REPLPOOLINST(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ -{ \ - gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, SHM_ID, LEN_AND_STR(INSTFILENAME)); \ - gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT(FAILED_OP), CALLFROM, SAVE_ERRNO); \ -} - #define ISSUE_REPLPOOLINST_AND_RETURN(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ { \ ISSUE_REPLPOOLINST(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ @@ -102,26 +97,27 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep { int semval, status, save_errno, nattch; char *instfilename, pool_type; - boolean_t sem_created = FALSE, sem_grabbed = FALSE; sm_uc_ptr_t start_addr; - struct semid_ds semstat; struct shmid_ds shm_buf; - union semun semarg; unix_db_info *udi; sgmnt_addrs *csa; + boolean_t anticipatory_freeze_available, force_attach; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; assert(INVALID_SHMID != shm_id); - semarg.buf = &semstat; instfilename = replpool_id->instfilename; pool_type = replpool_id->pool_type; assert((JNLPOOL_SEGMENT == pool_type) || (RECVPOOL_SEGMENT == pool_type)); + anticipatory_freeze_available = ANTICIPATORY_FREEZE_AVAILABLE; + force_attach = (jgbl.onlnrlbk || (!jgbl.mur_rollback && !argumentless_rundown && anticipatory_freeze_available)); if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf)) { save_errno = errno; ISSUE_REPLPOOLINST_AND_RETURN(save_errno, shm_id, instfilename, "shmctl()"); } nattch = shm_buf.shm_nattch; - if ((0 != nattch) && !jgbl.onlnrlbk) /* It must be zero before I attach to it (except online rollback) */ + if ((0 != nattch) && !force_attach) { util_out_print("Replpool segment (id = !UL) for replication instance !AD is in use by another process.", TRUE, shm_id, LEN_AND_STR(instfilename)); @@ -155,8 +151,8 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep LEN_AND_STR(replpool_id->now_running), shm_id, LEN_AND_STR(instfilename)); DETACH_AND_RETURN(start_addr, shm_id, instfilename); } - /* Assert that if we haven't yet attached to the journal pool yet, we have the corresponding global vars set to NULL */ - assert((JNLPOOL_SEGMENT != pool_type) || ((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl))); + /* Assert that if we haven't yet attached to the journal pool yet, jnlpool_ctl better be NULL */ + assert((JNLPOOL_SEGMENT != pool_type) || (NULL == jnlpool.jnlpool_ctl)); if (JNLPOOL_SEGMENT == pool_type) { /* Initialize variables to simulate a "jnlpool_init". This is required by "repl_inst_flush_jnlpool" called below */ jnlpool_ctl = jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr; @@ -164,7 +160,7 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); csa = &udi->s_addrs; csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); - csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE + SIZEOF(mutex_spin_parms_struct)); + csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE + SIZEOF(mutex_spin_parms_struct)); /* secshr_db_clnup uses this relationship */ assert(jnlpool.jnlpool_ctl->filehdr_off); assert(jnlpool.jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); @@ -179,9 +175,11 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep if (0 == nattch) { /* No one attached. So, we can safely flush the journal pool so that the gtmsrc_lcl structures in the * jnlpool and disk are in sync with each other. More importantly we are about to remove the jnlpool - * so we better get things in sync before that. - */ - /* If mu_rndwn_repl_instance created new semaphores (in mu_replpool_remove_sem), we need to flush those + * so we better get things in sync before that. If anticipatory freeze scheme is in effect, then we + * need to keep the journal pool up and running. So, don't reset the crash field in the instance file + * header (dictated by the second parameter to repl_inst_flush_jnlpool below). + * Note: + * If mu_rndwn_repl_instance created new semaphores (in mu_replpool_remove_sem), we need to flush those * to the instance file as well. So, override the jnlpool_semid and jnlpool_semid_ctime with the new * values. */ @@ -189,23 +187,25 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep && (0 != repl_inst_filehdr->jnlpool_semid_ctime)); jnlpool.repl_inst_filehdr->jnlpool_semid = repl_inst_filehdr->jnlpool_semid; jnlpool.repl_inst_filehdr->jnlpool_semid_ctime = repl_inst_filehdr->jnlpool_semid_ctime; - repl_inst_flush_jnlpool(FALSE, TRUE); - assert(!jnlpool.repl_inst_filehdr->crash); + repl_inst_flush_jnlpool(FALSE, !anticipatory_freeze_available); + assert(!jnlpool.repl_inst_filehdr->crash || anticipatory_freeze_available); /* Refresh local copy (repl_inst_filehdr) with the copy that was just flushed (jnlpool.repl_inst_filehdr) */ memcpy(repl_inst_filehdr, jnlpool.repl_inst_filehdr, SIZEOF(repl_inst_hdr)); - /* Now that jnlpool has been flushed and there is going to be no journal pool, reset - * "jnlpool.repl_inst_filehdr" as otherwise other routines (e.g. "repl_inst_recvpool_reset") are - * affected by whether this is NULL or not. - */ - jnlpool.jnlpool_ctl = NULL; - jnlpool_ctl = NULL; - jnlpool.gtmsrc_lcl_array = NULL; - jnlpool.gtmsource_local_array = NULL; - jnlpool.jnldata_base = NULL; - jnlpool.repl_inst_filehdr = NULL; + if (!anticipatory_freeze_available || argumentless_rundown) + { /* Now that jnlpool has been flushed and there is going to be no journal pool, reset + * "jnlpool.repl_inst_filehdr" as otherwise other routines (e.g. "repl_inst_recvpool_reset") are + * affected by whether this is NULL or not. + */ + jnlpool.jnlpool_ctl = NULL; + jnlpool_ctl = NULL; + jnlpool.gtmsrc_lcl_array = NULL; + jnlpool.gtmsource_local_array = NULL; + jnlpool.jnldata_base = NULL; + jnlpool.repl_inst_filehdr = NULL; + } } /* else we are ONLINE ROLLBACK. repl_inst_flush_jnlpool will be done later after gvcst_init in mur_open_files */ } - if (0 == nattch) + if ((0 == nattch) && (!anticipatory_freeze_available || argumentless_rundown || (RECVPOOL_SEGMENT == pool_type))) { if (-1 == shmdt((caddr_t)start_addr)) { @@ -227,11 +227,16 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep { repl_inst_filehdr->recvpool_shmid = INVALID_SHMID; repl_inst_filehdr->recvpool_shmid_ctime = 0; + if (NULL != jnlpool.repl_inst_filehdr) + { + jnlpool.repl_inst_filehdr->recvpool_shmid = INVALID_SHMID; + jnlpool.repl_inst_filehdr->recvpool_shmid_ctime = 0; + } *ipc_rmvd = TRUE; } } else - { /* else we are ONLINE ROLLBACK. Processes actively attached to the journal pool. Do not remove and/or reset the - * fields in the file heade + { /* Else we are ONLINE ROLLBACK or anticipatory freeze is in effect and so we want to keep the journal pool available + * for the duration of the rollback. Do not remove and/or reset the fields in the file header */ assert((JNLPOOL_SEGMENT != pool_type) || ((NULL != jnlpool.jnlpool_ctl) && (NULL != jnlpool_ctl))); if (JNLPOOL_SEGMENT == pool_type) @@ -246,7 +251,7 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep CONDITION_HANDLER(mu_rndwn_replpool_ch) { unix_db_info *udi; - int save_errno; + int status, save_errno; repl_inst_hdr_ptr_t inst_hdr; START_CH; @@ -255,9 +260,9 @@ CONDITION_HANDLER(mu_rndwn_replpool_ch) NEXTCH; if (NULL != jnlpool.jnlpool_ctl) { - if (-1 == shmdt((caddr_t)jnlpool.jnlpool_ctl)) + JNLPOOL_SHMDT(status, save_errno); + if (0 > status) { - save_errno = errno; inst_hdr = jnlpool.repl_inst_filehdr; assert(NULL != inst_hdr); assert(NULL != jnlpool.jnlpool_dummy_reg); @@ -267,7 +272,6 @@ CONDITION_HANDLER(mu_rndwn_replpool_ch) assert(INVALID_SHMID != inst_hdr->jnlpool_shmid); ISSUE_REPLPOOLINST(save_errno, inst_hdr->jnlpool_shmid, udi->fn, "shmdt()"); } - jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; jnlpool.gtmsrc_lcl_array = NULL; jnlpool.gtmsource_local_array = NULL; jnlpool.jnldata_base = NULL; diff --git a/sr_unix/mu_rndwn_replpool.h b/sr_unix/mu_rndwn_replpool.h index e1f9185..dbda8a6 100644 --- a/sr_unix/mu_rndwn_replpool.h +++ b/sr_unix/mu_rndwn_replpool.h @@ -13,7 +13,15 @@ #define MU_RNDWN_REPLPOOL_INCLUDED int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t repl_inst_filehdr, int shmid, boolean_t *ipc_rmvd); -int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t *sem_created); -int mu_replpool_remove_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t remove_sem); +int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t *sem_created, boolean_t immediate); +int mu_replpool_release_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type, boolean_t remove_sem); + +#define MAX_IPCS_ID_BUF 64 /* Shared memory or semaphore ID is an int and so won't be more than 12 digits long */ + +#define ISSUE_REPLPOOLINST(SAVE_ERRNO, SHM_ID, INSTFILENAME, FAILED_OP) \ +{ \ + gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, SHM_ID, LEN_AND_STR(INSTFILENAME)); \ + gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT(FAILED_OP), CALLFROM, SAVE_ERRNO); \ +} #endif /* MU_RNDWN_REPLPOOL_INCLUDED */ diff --git a/sr_unix/mu_term_setup.c b/sr_unix/mu_term_setup.c index d93a092..87974b7 100644 --- a/sr_unix/mu_term_setup.c +++ b/sr_unix/mu_term_setup.c @@ -59,26 +59,27 @@ void mu_get_term_characterstics(void) void mu_reset_term_characterstics(void) { int tcsetattr_res; + int save_errno; /* Do not use TCSAFLUSH as it drains all buffered (but yet unprocessed) input in the terminal * even if that was for the next command at the shell prompt. TCSANOW seems to do what we want * (which is to reset terminal characteristics right away). */ - Tcsetattr(STDIN_FILENO, TCSANOW, &term_in, tcsetattr_res); + Tcsetattr(STDIN_FILENO, TCSANOW, &term_in, tcsetattr_res, save_errno); if (get_stdin_charc_pass && (-1 == tcsetattr_res)) { PERROR("tcsetattr :"); FPRINTF(stderr, "Unable to set terminal characterstics for standard in\n"); } - Tcsetattr(STDOUT_FILENO, TCSANOW, &term_out, tcsetattr_res); + Tcsetattr(STDOUT_FILENO, TCSANOW, &term_out, tcsetattr_res, save_errno); if (get_stdout_charc_pass && (-1 == tcsetattr_res)) { PERROR("tcsetattr :"); FPRINTF(stderr, "Unable to set terminal characterstics for standard out\n"); } - Tcsetattr(STDERR_FILENO, TCSANOW, &term_err, tcsetattr_res); + Tcsetattr(STDERR_FILENO, TCSANOW, &term_err, tcsetattr_res, save_errno); if (get_stderr_charc_pass && (-1 == tcsetattr_res)) { PERROR("tcsetattr :"); diff --git a/sr_unix/mu_truncate.c b/sr_unix/mu_truncate.c index a620681..771a13c 100644 --- a/sr_unix/mu_truncate.c +++ b/sr_unix/mu_truncate.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2012 Fidelity Information Services, Inc * + * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,6 +33,7 @@ #include #include "gtm_string.h" +#include "gtm_time.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" @@ -60,6 +61,7 @@ #include "mu_truncate.h" #include "gtmio.h" #include "util.h" +#include "anticipatory_freeze.h" #include "sleep_cnt.h" #include "wcs_sleep.h" @@ -69,6 +71,8 @@ #include "shmpool.h" #include "clear_cache_array.h" #include "wcs_flu.h" +#include "repl_msg.h" +#include "gtmsource.h" error_def(ERR_BUFFLUFAILED); error_def(ERR_DBFILERR); @@ -105,6 +109,7 @@ GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF volatile int4 db_fsync_in_prog; /* for DB_FSYNC macro usage */ GBLREF jnl_gbls_t jgbl; GBLREF int num_additional_processors; +GBLREF jnlpool_addrs jnlpool; boolean_t mu_truncate(int4 truncate_percent) { @@ -120,6 +125,7 @@ boolean_t mu_truncate(int4 truncate_percent) uint4 old_free, new_free; uint4 end_blocks; int4 blks_in_lmap, blk; + gtm_uint64_t before_trunc_file_size; off_t trunc_file_size; uchar_ptr_t lmap_addr; boolean_t was_crit; @@ -141,20 +147,21 @@ boolean_t mu_truncate(int4 truncate_percent) csd = cs_data; if (dba_mm == csd->acc_meth) { - gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOTBG, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOTBG, 2, REG_LEN_STR(gv_cur_region)); return TRUE; } if ((GDSVCURR != csd->desired_db_format) || (csd->blks_to_upgrd != 0)) { - gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); return TRUE; } if (csa->ti->free_blocks < (truncate_percent * csa->ti->total_blks / 100)) { - gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); return TRUE; } /* already checked for parallel truncates on this region --- see mupip_reorg.c */ + gv_target = NULL; assert(csa->nl->trunc_pid == process_id); assert(dba_mm != csd->acc_meth); old_total = csa->ti->total_blks; @@ -175,7 +182,8 @@ boolean_t mu_truncate(int4 truncate_percent) assert(csa->ti->total_blks >= old_total); /* otherwise, a concurrent truncate happened... */ if (csa->ti->total_blks != old_total) /* Extend (likely called by mupip extend) -- don't truncate */ { - gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), + truncate_percent); return TRUE; } lmap_blk_num = lmap_num * BLKS_PER_LMAP; @@ -253,8 +261,12 @@ boolean_t mu_truncate(int4 truncate_percent) /* block processed, scan from the next one */ blk++; break; + } else + { + assert(t_tries < CDB_STAGNATE); + t_retry(cdb_sc_badbitmap); + continue; } - assertpro(FALSE); } /* END recycled2free retry loop */ } /* END scanning blocks of this particular lmap */ /* Write PBLK for the bitmap block, in case it hasn't been written i.e. t_end() was never called above */ @@ -264,7 +276,6 @@ boolean_t mu_truncate(int4 truncate_percent) for (;;) { RESET_UPDATE_ARRAY; - gv_target->clue.end = 0; BLK_ADDR(blkid_ptr, SIZEOF(block_id), block_id); *blkid_ptr = 0; update_trans = UPDTRNS_DB_UPDATED_MASK; @@ -294,10 +305,10 @@ boolean_t mu_truncate(int4 truncate_percent) for (;;) { /* wait for FREEZE, we don't want to truncate a frozen database */ grab_crit(gv_cur_region); - if (!cs_data->freeze) + if (!cs_data->freeze && !IS_REPL_INST_FROZEN) break; rel_crit(gv_cur_region); - while (cs_data->freeze) + while (cs_data->freeze || IS_REPL_INST_FROZEN) hiber_start(1000); } assert(csa->nl->trunc_pid == process_id); @@ -305,13 +316,14 @@ boolean_t mu_truncate(int4 truncate_percent) if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_MSYNC_DB)) { assert(FALSE); - gtm_putmsg(VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT("MUPIP REORG TRUNCATE"), DB_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT("MUPIP REORG TRUNCATE"), + DB_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return FALSE; } csa->nl->highest_lbm_with_busy_blk = MAX(found_busy_blk, csa->nl->highest_lbm_with_busy_blk); - assert(csa->nl->highest_lbm_with_busy_blk % BLKS_PER_LMAP == 0); /* should be a bitmap block */ - new_total = MIN(old_total, csa->nl->highest_lbm_with_busy_blk + BLKS_PER_LMAP); + assert(IS_BITMAP_BLK(csa->nl->highest_lbm_with_busy_blk)); + new_total = MIN(old_total, csa->nl->highest_lbm_with_busy_blk + BLKS_PER_LMAP); if (mu_ctrly_occurred || mu_ctrlc_occurred) { rel_crit(gv_cur_region); @@ -319,22 +331,22 @@ boolean_t mu_truncate(int4 truncate_percent) } else if (csa->ti->total_blks != old_total || new_total == old_total) { assert(csa->ti->total_blks >= old_total); /* Better have been an extend, not a truncate... */ - gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent); rel_crit(gv_cur_region); return TRUE; } else if (GDSVCURR != csd->desired_db_format || csd->blks_to_upgrd != 0 || !csd->fully_upgraded) { - gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } else if (SNAPSHOTS_IN_PROG(csa->nl)) { - gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCSSINPROG, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCSSINPROG, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } else if (BACKUP_NOT_IN_PROGRESS != cs_addrs->nl->nbb) { - gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCBACKINPROG, 2, REG_LEN_STR(gv_cur_region)); + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCBACKINPROG, 2, REG_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); return TRUE; } @@ -352,7 +364,7 @@ boolean_t mu_truncate(int4 truncate_percent) ADJUST_GBL_JREC_TIME(jgbl, jbp); jnl_status = jnl_ensure_open(); if (SS_NORMAL != jnl_status) - send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); else { if (0 == jpc->pini_addr) @@ -363,7 +375,7 @@ boolean_t mu_truncate(int4 truncate_percent) jnl_status = jnl_flush(gv_cur_region); if (SS_NORMAL != jnl_status) { - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during mu_truncate"), jnl_status); assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */ @@ -375,12 +387,10 @@ boolean_t mu_truncate(int4 truncate_percent) CHECK_TN(csa, csd, curr_tn); udi = FILE_INFO(gv_cur_region); /* Information used by recover_truncate to check if the file size and csa->ti->total_blks are INCONSISTENT */ - csd->before_trunc_file_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); /* in DISK_BLOCKs */ - assert((off_t)csd->before_trunc_file_size * DISK_BLOCK_SIZE > (off_t)(old_total - new_total) * csd->blk_size); - trunc_file_size = (off_t)csd->before_trunc_file_size * DISK_BLOCK_SIZE + before_trunc_file_size = gds_file_size(gv_cur_region->dyn.addr->file_cntl); /* in DISK_BLOCKs */ + assert((off_t)before_trunc_file_size * DISK_BLOCK_SIZE > (off_t)(old_total - new_total) * csd->blk_size); + trunc_file_size = (off_t)before_trunc_file_size * DISK_BLOCK_SIZE - (off_t)(old_total - new_total) * csd->blk_size; /* in bytes */ - DBGEHND((stdout, "DBG:: csd->before_trunc_file_size * DISK_BLOCK_SIZE = [%lld], trunc_file_size = [%lld]\n", - (off_t)csd->before_trunc_file_size * DISK_BLOCK_SIZE, trunc_file_size)); csd->after_trunc_total_blks = new_total; csd->before_trunc_free_blocks = csa->ti->free_blocks; csd->before_trunc_total_blks = old_total; /* Flags interrupted truncate for recover_truncate */ @@ -401,7 +411,7 @@ boolean_t mu_truncate(int4 truncate_percent) if (0 != save_errno) { err_msg = (char *)STRERROR(errno); - rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); return FALSE; } KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_3); /* 57 : Issue a kill -9 after reducing csa->ti->total_blks, before FTRUNCATE */ @@ -414,12 +424,17 @@ boolean_t mu_truncate(int4 truncate_percent) if (0 != ftrunc_status) { err_msg = (char *)STRERROR(errno); - rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg)); /* should go through recover_truncate now, which will again try to FTRUNCATE */ return FALSE; } /* file size and total blocks: CONSISTENT (shrunk) */ KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_4); /* 58 : Issue a kill -9 after FTRUNCATE, before 2nd fsync */ + csa->nl->root_search_cycle++; /* Force concurrent processes to restart in t_end/tp_tend to make sure no one + * tries to commit updates past the end of the file. Bitmap validations together + * with highest_lbm_with_busy_blk should actually be sufficient, so this is + * just to be safe. + */ csd->before_trunc_total_blks = 0; /* indicate CONSISTENT */ /* Increment TN */ assert(csa->ti->early_tn == csa->ti->curr_tn); @@ -432,7 +447,7 @@ boolean_t mu_truncate(int4 truncate_percent) ENABLE_INTERRUPTS(INTRPT_IN_TRUNC); curr_tn = csa->ti->curr_tn; rel_crit(gv_cur_region); - send_msg(VARLSTCNT(7) ERR_MUTRUNCSUCCESS, 5, DB_LEN_STR(gv_cur_region), old_total, new_total, &curr_tn); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_MUTRUNCSUCCESS, 5, DB_LEN_STR(gv_cur_region), old_total, new_total, &curr_tn); util_out_print("Truncated region: !AD. Reduced total blocks from [!UL] to [!UL]. Reduced free blocks from [!UL] to [!UL].", FLUSH, REG_LEN_STR(gv_cur_region), old_total, new_total, old_free, new_free); return TRUE; @@ -459,7 +474,7 @@ STATICFNDEF int4 bml_find_busy_recycled(int4 hint, uchar_ptr_t base_addr, int4 b GET_STATUS(*ptr, i, status); if (status != BLK_FREE) { - assert(status == BLK_BUSY || status == BLK_RECYCLED); + assert((t_tries < CDB_STAGNATE) || (status == BLK_BUSY) || (status == BLK_RECYCLED)); *bml_status_ptr = status; return blknum; } diff --git a/sr_unix/mu_truncate.h b/sr_unix/mu_truncate.h index c6c02ff..b79a869 100644 --- a/sr_unix/mu_truncate.h +++ b/sr_unix/mu_truncate.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2012 Fidelity Information Services, Inc * + * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,8 +21,8 @@ { \ if (0 != save_errno) \ { \ - send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \ - rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \ + send_msg_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \ + rts_error_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \ assert(FALSE); /* should not come here as the rts_error above should not return */ \ rel_crit(reg); \ return FALSE; \ diff --git a/sr_unix/mubfilcpy.c b/sr_unix/mubfilcpy.c index 34705a4..9e388d6 100644 --- a/sr_unix/mubfilcpy.c +++ b/sr_unix/mubfilcpy.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -93,16 +93,15 @@ bool mubfilcpy (backup_reg_list *list) mstr *file, tempfile; unsigned char cmdarray[COMMAND_ARRAY_SIZE], *command = &cmdarray[0]; sgmnt_data_ptr_t header_cpy; - int4 backup_fd = FD_INVALID, size, vbn, counter, hdrsize, rsize, ntries; + int4 backup_fd = FD_INVALID, counter, hdrsize, rsize, ntries; ssize_t status; - int4 adjust, blk_num, cmdlen, rv, save_errno, temp, tempfilelen, tmplen; + int4 blk_num, cmdlen, rv, save_errno, tempfilelen, tmplen; struct stat stat_buf; - off_t filesize, handled, offset; + off_t filesize, offset; char *inbuf, *zero_blk, *ptr, *errptr; - boolean_t done; char tempfilename[MAX_FN_LEN + 1], tempdir[MAX_FN_LEN], prefix[MAX_FN_LEN]; int fstat_res; - uint4 ustatus; + uint4 ustatus, size; muinc_blk_hdr_ptr_t sblkh_p; ZOS_ONLY(int realfiletag;) int group_id; @@ -158,11 +157,12 @@ bool mubfilcpy (backup_reg_list *list) (ntries > MAX_TEMP_OPEN_TRY)) { if (FILE_STAT_ERROR != fstat_res) - gtm_putmsg(VARLSTCNT(8) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr, ERR_TEXT, 2, LEN_AND_LIT("Tried a maximum number of times, clean-up temporary files " \ "in backup directory and retry.")); else - gtm_putmsg(VARLSTCNT(5) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr, ustatus); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr, + ustatus); return FALSE; } ntries++; @@ -183,7 +183,8 @@ bool mubfilcpy (backup_reg_list *list) command[cmdlen] = 0; if (debug_mupip) util_out_print("!/MUPIP INFO: !AD", TRUE, cmdlen, command); - if (0 != (rv = SYSTEM((char *)command))) + rv = SYSTEM(((char *)command)); + if (0 != rv) { if (-1 == rv) { @@ -217,11 +218,11 @@ bool mubfilcpy (backup_reg_list *list) if (-1 != fstat_res) if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0) { - send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"), RTS_ERROR_STRING(((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn), PERMGENDIAG_ARGS(pdd)); - gtm_putmsg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"), RTS_ERROR_STRING(((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn), PERMGENDIAG_ARGS(pdd)); @@ -252,7 +253,7 @@ bool mubfilcpy (backup_reg_list *list) { /* A concurrent online rollback happened since we did the gvcst_init. The backup is not reliable. * Cleanup and exit */ - gtm_putmsg(VARLSTCNT(1) ERR_DBROLLEDBACK); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); CLEANUP_AND_RETURN_FALSE; } /* if there has been an extend, truncate it */ @@ -309,7 +310,7 @@ bool mubfilcpy (backup_reg_list *list) if (cs_addrs->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(cs_addrs, NULL)) { assert(FALSE); - gtm_putmsg(VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1, + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1, cs_addrs->nl->wcs_phase2_commit_pidcnt, DB_LEN_STR(gv_cur_region)); rel_crit(gv_cur_region); CLEANUP_AND_RETURN_FALSE; @@ -327,7 +328,7 @@ bool mubfilcpy (backup_reg_list *list) backup_buffer_flush(gv_cur_region); if (++counter > MAX_BACKUP_FLUSH_TRY) { - gtm_putmsg(VARLSTCNT(1) ERR_BCKUPBUFLUSH); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_BCKUPBUFLUSH); CLEANUP_AND_RETURN_FALSE; } if (counter & 0xF) @@ -337,7 +338,7 @@ bool mubfilcpy (backup_reg_list *list) if (FALSE == shmpool_lock_hdr(gv_cur_region)) { assert(FALSE); - gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region), + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region), ERR_ERRCALL, 3, CALLFROM); CLEANUP_AND_RETURN_FALSE; } @@ -351,7 +352,7 @@ bool mubfilcpy (backup_reg_list *list) assert(EACCES == cs_addrs->shmpool_buffer->backup_errno); util_out_print("Process !UL encountered the following error.", TRUE, cs_addrs->shmpool_buffer->failed); if (0 != cs_addrs->shmpool_buffer->backup_errno) - gtm_putmsg(VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno); + gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno); util_out_print("WARNING: backup file !AD is not valid.", TRUE, file->len, file->addr); CLEANUP_AND_RETURN_FALSE; } @@ -418,8 +419,8 @@ bool mubfilcpy (backup_reg_list *list) size = (((blk_hdr_ptr_t)inbuf)->bsiz + 1) & ~1; if (cs_addrs->do_fullblockwrites) - size = (int4)ROUND_UP(size, cs_addrs->fullblockwrite_len); - assert(cs_addrs->hdr->blk_size >= size); + size = ROUND_UP(size, cs_addrs->fullblockwrite_len); + assert((uint4)cs_addrs->hdr->blk_size >= size); offset = (header_cpy->start_vbn - 1) * DISK_BLOCK_SIZE + ((off_t)header_cpy->blk_size * blk_num); LSEEKWRITE(backup_fd, @@ -487,7 +488,8 @@ bool mubfilcpy (backup_reg_list *list) command[cmdlen] = 0; if (debug_mupip) util_out_print("MUPIP INFO: !AD", TRUE, cmdlen, command); - if (0 != (rv = SYSTEM((char *)command))) + rv = SYSTEM(((char *)command)); + if (0 != rv) { if (-1 == rv) { diff --git a/sr_unix/mucblkini.c b/sr_unix/mucblkini.c index 7cb90ee..c6885cc 100644 --- a/sr_unix/mucblkini.c +++ b/sr_unix/mucblkini.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,6 +28,8 @@ #include "gdsbml.h" #include "gtmio.h" #include "mucblkini.h" +#include "anticipatory_freeze.h" +#include "jnl.h" #define DIR_ROOT 1 #define DIR_DATA 2 @@ -58,7 +60,7 @@ void mucblkini (void) } bml_busy(DIR_ROOT, bmp + SIZEOF(blk_hdr)); bml_busy(DIR_DATA, bmp + SIZEOF(blk_hdr)); - LSEEKWRITE(udi->fd, (off_t)(cs_addrs->hdr->start_vbn - 1) * DISK_BLOCK_SIZE, bmp, bmpsize, status); + DB_LSEEKWRITE(cs_addrs, udi->fn, udi->fd, (off_t)(cs_addrs->hdr->start_vbn - 1) * DISK_BLOCK_SIZE, bmp, bmpsize, status); if (0 != status) { PERROR("Error writing out first bitmap"); diff --git a/sr_unix/mumps_clitab.c b/sr_unix/mumps_clitab.c index a4b1bef..28533de 100644 --- a/sr_unix/mumps_clitab.c +++ b/sr_unix/mumps_clitab.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,6 +30,7 @@ static readonly CLI_ENTRY mumps_qual[] = { { "CROSS_REFERENCE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0}, { "DEBUG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0}, { "DIRECT_MODE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0}, +{ "DYNAMIC_LITERALS", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0}, { "IGNORE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0}, { "INLINE_LITERALS", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0}, { "LABELS", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0}, diff --git a/sr_unix/mupip.c b/sr_unix/mupip.c index 8638595..7fef06e 100644 --- a/sr_unix/mupip.c +++ b/sr_unix/mupip.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -65,10 +65,13 @@ #include "invocation_mode.h" #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" +#include "continue_handler.h" #ifdef UNICODE_SUPPORTED -#include "gtm_icu_api.h" -#include "gtm_utf8.h" +# include "gtm_icu_api.h" +# include "gtm_utf8.h" +# include "gtm_conv.h" +GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ #endif GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace); @@ -97,18 +100,19 @@ int main (int argc, char **argv) gtm_wcswidth_fnptr = gtm_wcswidth; gtm_env_init(); /* read in all environment variables */ err_init(util_base_ch); + UNICODE_ONLY(gtm_strToTitle_ptr = >m_strToTitle); GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ - sig_init(generic_signal_handler, NULL, suspsigs_handler); /* Note: no ^C handler is defined (yet) */ + sig_init(generic_signal_handler, NULL, suspsigs_handler, continue_handler); /* Note: no ^C handler is defined (yet) */ atexit(mupip_exit_handler); licensed = TRUE; in_backup = FALSE; op_open_ptr = mu_op_open; mu_get_term_characterstics(); + gtm_chk_dist(argv[0]); cli_lex_setup(argc,argv); if (argc < 2) /* Interactive mode */ display_prompt(); /* this call should be after cli_lex_setup() due to S390 A/E conversion */ - gtm_chk_dist(argv[0]); INIT_GBL_ROOT(); /* Needed for GVT initialization */ init_gtm(); while (TRUE) diff --git a/sr_unix/mupip_cmd.c b/sr_unix/mupip_cmd.c index 34a7662..18310c8 100644 --- a/sr_unix/mupip_cmd.c +++ b/sr_unix/mupip_cmd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,7 +37,7 @@ #include "mupip_extend.h" #include "muextr.h" #include "mupip_freeze.h" -#include "mupip_help.h" +#include "util_help.h" #include "mupip_integ.h" #include "mupip_intrpt.h" #include "mupip_quit.h" @@ -46,6 +46,7 @@ #include "mupip_restore.h" #include "mupip_rundown.h" #include "mupip_set.h" +#include "mupip_size.h" #include "mupip_stop.h" #include "mupip_trigger.h" #include "mupip_upgrade.h" @@ -95,6 +96,12 @@ static CLI_ENTRY mup_set_acc_qual[] = { }; static CLI_ENTRY mup_set_dbver_qual[] = { + { "V4", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { "V6", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { 0 } +}; + +static CLI_ENTRY mup_downgrade_dbver_qual[] = { { "V4", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, { "V5", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, { 0 } @@ -235,6 +242,7 @@ static CLI_ENTRY mup_extract_qual[] = { { "LABEL", mu_extract, 0, mup_extr_label_parm, 0, 0, 0, VAL_NOT_REQ, 1, NON_NEG, VAL_STR, 0 }, { "LOG", mu_extract, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NEG, VAL_N_A, 0 }, { "SELECT", mu_extract, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, + { "STDOUT", mu_extract, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 }, { "OCHSET", mu_extract, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, { 0 } }; @@ -416,6 +424,26 @@ static CLI_ENTRY mup_reorg_qual[] = { { 0 } }; +/* + * MUPIP SIZE + */ +static CLI_ENTRY mup_size_heuristic_qual[] = { + { "ARSAMPLE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { "IMPSAMPLE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { "LEVEL", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, /* VAL_STR to be able to get negative values */ + { "SAMPLES", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, VAL_DCM}, + { "SCAN", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + { "SEED", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, VAL_DCM}, + { 0 } +}; +static CLI_ENTRY mup_size_qual[] = { + { "HEURISTIC", 0, 0, 0, mup_size_heuristic_qual, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, + { "REGION", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, + { "SELECT", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, + { 0 } +}; + + static readonly CLI_PARM gtmsource_timeout_parm[] = { {"TIMEOUT", "30", PARM_REQ}, {"", "", PARM_REQ} @@ -437,34 +465,40 @@ static CLI_ENTRY inst_edit_qual[] = { { 0 } }; +static CLI_ENTRY inst_freeze_qual[] = { + {"COMMENT", 0, 0, 0, 0, 0, 0, VAL_NOT_REQ, 0, NEG, VAL_STR, 0 }, + { 0 } +}; + static CLI_ENTRY gtmsource_qual[] = { - {"ACTIVATE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"BUFFSIZE", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 }, - {"CHANGELOG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"CHECKHEALTH", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"CMPLVL", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 }, - {"CONNECTPARAMS", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, - {"DEACTIVATE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"DETAIL", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"FILTER", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, - {"INSTSECONDARY", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 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 }, - {"LOSTTNCOMPLETE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"NEEDRESTART", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"PASSIVE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"PROPAGATEPRIMARY", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"ROOTPRIMARY", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"SECONDARY", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, - {"SHOWBACKLOG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"SHUTDOWN", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"START", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"STATSLOG", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, - {"STOPSOURCEFILTER", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"TIMEOUT", 0, 0, gtmsource_timeout_parm, 0, 0, 0, VAL_NOT_REQ, 1, NEG, VAL_NUM, 0 }, - {"UPDNOTOK", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, - {"UPDOK", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"ACTIVATE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"BUFFSIZE", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 }, + {"CHANGELOG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"CHECKHEALTH", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"CMPLVL", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 }, + {"CONNECTPARAMS", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, + {"DEACTIVATE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"DETAIL", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"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 }, + {"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 }, + {"LOSTTNCOMPLETE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"NEEDRESTART", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"PASSIVE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"PROPAGATEPRIMARY", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"ROOTPRIMARY", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"SECONDARY", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, + {"SHOWBACKLOG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"SHUTDOWN", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"START", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"STATSLOG", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, + {"STOPSOURCEFILTER", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"TIMEOUT", 0, 0, gtmsource_timeout_parm, 0, 0, 0, VAL_NOT_REQ, 1, NEG, VAL_NUM, 0 }, + {"UPDNOTOK", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, + {"UPDOK", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, { 0 } }; @@ -486,6 +520,7 @@ static CLI_ENTRY gtmrecv_qual[] = { {"CMPLVL", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 0 }, {"FILTER", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_STR, 0 }, {"HELPERS", 0, 0, gtmrecv_helpers_parm, 0, 0, 0, VAL_NOT_REQ, 0, NON_NEG, VAL_STR, 0 }, + {"INITIALIZE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0 }, {"LISTENPORT", 0, 0, 0, 0, 0, 0, VAL_REQ, 0, NON_NEG, VAL_NUM, 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_STR, 0 }, @@ -559,8 +594,9 @@ static CLI_PARM mup_rundown_parm[] = { }; static CLI_ENTRY mup_rundown_qual[] = { - { "FILE", 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 }, + { "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 }, { 0 } }; @@ -582,11 +618,16 @@ static CLI_ENTRY mup_set_qual[] = { { "FILE", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 }, { "FLUSH_TIME", mupip_set, 0, mup_set_ftime_parm, 0, 0, 0, VAL_NOT_REQ, 1, NON_NEG, VAL_TIME, 0 }, { "GLOBAL_BUFFERS", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 }, +{ "INST_FREEZE_ON_ERROR", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NEG, VAL_N_A, 0 }, { "JNLFILE", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 }, { "JOURNAL", mupip_set, 0, 0, mup_set_journal_qual, 0, 0, VAL_NOT_REQ, 1, NEG, VAL_STR, 0 }, +{ "KEY_SIZE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 }, { "LOCK_SPACE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 }, +{ "MUTEX_SLOTS", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 }, { "PARTIAL_RECOV_BYPASS", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 }, { "PREVJNLFILE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NEG, VAL_STR, 0 }, +{ "QDBRUNDOWN", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NEG, VAL_N_A, 0 }, +{ "RECORD_SIZE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 }, { "REGION", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 }, { "REPLICATION", mupip_set, 0, 0, mup_repl_qual, 0, 0, VAL_REQ, 1, NEG, VAL_STR, 0 }, { "REPL_STATE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NEG, VAL_STR, 0 }, @@ -638,34 +679,40 @@ static CLI_PARM mup_downgrade_parm[] = { { "", "", 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 }, -{ "CREATE", mupip_create, mup_create_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, -{ "CRYPT", mupip_crypt, mup_crypt_qual, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "DOWNGRADE", mupip_downgrade, 0, mup_downgrade_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "ENDIANCVT", mupip_endiancvt, mup_endian_qual, mup_endian_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "EXIT", mupip_quit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, -{ "EXTEND", mupip_extend, mup_extend_qual, mup_extend_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "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 }, -{ "HELP", mupip_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 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 }, -{ "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 }, -{ "RUNDOWN", mupip_rundown, mup_rundown_qual, mup_rundown_parm, 0, cli_disallow_mupip_rundown, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "SET", mupip_set, mup_set_qual, mup_set_parm, 0, cli_disallow_mupip_set, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -{ "STOP", mupip_stop, 0, mup_stop_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -#ifdef GTM_TRIGGER -{ "TRIGGER", mupip_trigger, mup_trigger_qual, mup_trig_parm, 0, cli_disallow_mupip_trigger, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, -#endif -{ "UPGRADE", mupip_upgrade, 0, mup_upgrade_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +static CLI_ENTRY mup_downgrade_qual[] = { +{ "VERSION", mupip_downgrade, 0, 0, mup_downgrade_dbver_qual, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0 }, +{ 0 } +}; + +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 }, +{ "CREATE", mupip_create, mup_create_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, +{ "CRYPT", mupip_crypt, mup_crypt_qual, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "DOWNGRADE", mupip_downgrade,mup_downgrade_qual, mup_downgrade_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "ENDIANCVT", mupip_endiancvt,mup_endian_qual, mup_endian_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "EXIT", mupip_quit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 }, +{ "EXTEND", mupip_extend, mup_extend_qual, mup_extend_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "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 }, +{ "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 }, +{ "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 }, +{ "RUNDOWN", mupip_rundown, mup_rundown_qual, mup_rundown_parm, 0, cli_disallow_mupip_rundown, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "SET", mupip_set, mup_set_qual, mup_set_parm, 0, cli_disallow_mupip_set, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "SIZE", mupip_size, mup_size_qual, 0, 0, cli_disallow_mupip_size, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +{ "STOP", mupip_stop, 0, mup_stop_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +#ifdef GTM_TRIGGER +{ "TRIGGER", mupip_trigger, mup_trigger_qual, mup_trig_parm, 0, cli_disallow_mupip_trigger, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, +#endif +{ "UPGRADE", mupip_upgrade, 0, mup_upgrade_parm, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 }, { 0 } }; diff --git a/sr_unix/mupip_cmd_disallow.c b/sr_unix/mupip_cmd_disallow.c index ac3dbe2..2b177de 100644 --- a/sr_unix/mupip_cmd_disallow.c +++ b/sr_unix/mupip_cmd_disallow.c @@ -287,9 +287,11 @@ boolean_t cli_disallow_mupip_replic_receive(void) CLI_DIS_CHECK_N_RESET; disallow_return_value = (d_c_cli_present("UPDATERESYNC") && d_c_cli_present("NORESYNC")); CLI_DIS_CHECK_N_RESET; - disallow_return_value = (!d_c_cli_present("UPDATERESYNC") && d_c_cli_present("REUSE")); + disallow_return_value = (!d_c_cli_present("UPDATERESYNC") && (d_c_cli_present("REUSE") + || d_c_cli_present("RESUME") + || d_c_cli_present("INITIALIZE"))); CLI_DIS_CHECK_N_RESET; - disallow_return_value = (!d_c_cli_present("UPDATERESYNC") && d_c_cli_present("RESUME")); + disallow_return_value = (d_c_cli_present("INITIALIZE") && d_c_cli_present("RESUME")); CLI_DIS_CHECK_N_RESET; disallow_return_value = (d_c_cli_present("REUSE") && d_c_cli_present("RESUME")); CLI_DIS_CHECK_N_RESET; @@ -310,13 +312,16 @@ boolean_t cli_disallow_mupip_replic_receive(void) CLI_DIS_CHECK_N_RESET; disallow_return_value = (d_c_cli_present("AUTOROLLBACK") && !d_c_cli_present("LISTENPORT") && !d_c_cli_present("START")); CLI_DIS_CHECK_N_RESET; + /* LOG are not allowed with STATS qualifier */ + disallow_return_value = (d_c_cli_present("STATSLOG") && d_c_cli_present("LOG")); + CLI_DIS_CHECK_N_RESET; return FALSE; } boolean_t cli_disallow_mupip_replic_source(void) { int disallow_return_value = 0; - boolean_t p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12; + boolean_t p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13; *cli_err_str_ptr = 0; @@ -332,15 +337,16 @@ boolean_t cli_disallow_mupip_replic_source(void) p10 = d_c_cli_present("LOSTTNCOMPLETE"); p11 = d_c_cli_present("NEEDRESTART"); p12 = d_c_cli_present("JNLPOOL"); + p13 = d_c_cli_present("FREEZE"); /* every source server command must have at least one of the above control qualifiers */ - disallow_return_value = !(p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10 || p11 || p12); + disallow_return_value = !(p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10 || p11 || p12 || p13); CLI_DIS_CHECK; /* Note CLI_DIS_CHECK_N_RESET is not used as we want to reuse the computed error string (cli_err_str_ptr) * for the next check as well in case it fails. Note that this can be done only if both checks use * exactly the same set of qualifiers (which is TRUE in this case). */ /* every source server command cannot have any more than one of the above control qualifiers */ - disallow_return_value = cli_check_any2(VARLSTCNT(11) p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + disallow_return_value = cli_check_any2(VARLSTCNT(11) p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); CLI_DIS_CHECK_N_RESET; /* BUFFSIZE, CMPLVL, FILTER, PASSIVE are supported only with START qualifier */ @@ -354,12 +360,21 @@ boolean_t cli_disallow_mupip_replic_source(void) disallow_return_value = (!d_c_cli_present("START") && !d_c_cli_present("ACTIVATE") && (d_c_cli_present("CONNECTPARAMS") || d_c_cli_present("SECONDARY"))); CLI_DIS_CHECK_N_RESET; - /* LOG, LOG_INTERVAL are supported only with START, CHANGELOG, ACTIVATE, STATSLOG qualifiers */ + /* LOG are not allowed with STATS qualifier */ + disallow_return_value = (d_c_cli_present("STATSLOG") && d_c_cli_present("LOG")); + CLI_DIS_CHECK_N_RESET; + /* LOG are supported only with START, CHANGELOG, ACTIVATE qualifiers */ + disallow_return_value = (!d_c_cli_present("START") + && !d_c_cli_present("CHANGELOG") + && !d_c_cli_present("ACTIVATE") + && d_c_cli_present("LOG")); + CLI_DIS_CHECK_N_RESET; + /* LOG_INTERVAL are supported only with START, CHANGELOG, ACTIVATE, STATSLOG qualifiers */ disallow_return_value = (!d_c_cli_present("START") && !d_c_cli_present("CHANGELOG") && !d_c_cli_present("ACTIVATE") && !d_c_cli_present("STATSLOG") - && (d_c_cli_present("LOG") || d_c_cli_present("LOG_INTERVAL"))); + && d_c_cli_present("LOG_INTERVAL")); CLI_DIS_CHECK_N_RESET; /* TIMEOUT is supported only with SHUTDOWN qualifier */ disallow_return_value = (!d_c_cli_present("SHUTDOWN") && d_c_cli_present("TIMEOUT")); @@ -379,7 +394,7 @@ boolean_t cli_disallow_mupip_replic_source(void) disallow_return_value = (d_c_cli_present("CHANGELOG") && !d_c_cli_present("LOG") && !d_c_cli_present("LOG_INTERVAL")); CLI_DIS_CHECK_N_RESET; /* ROOTPRIMARY (or UPDOK) and PROPAGATEPRIMARY (or UPDNOTOK) are mutually exclusive */ - disallow_return_value = ((d_c_cli_present("ROOTPRIMARY") || d_c_cli_present("UPDNOTOK")) + disallow_return_value = ((d_c_cli_present("ROOTPRIMARY") || d_c_cli_present("UPDOK")) && (d_c_cli_present("PROPAGATEPRIMARY") || d_c_cli_present("UPDNOTOK"))); CLI_DIS_CHECK_N_RESET; /* ROOTPRIMARY and PROPAGATEPRIMARY are allowed only along with START, ACTIVATE or DEACTIVATE qualifiers */ @@ -469,6 +484,13 @@ boolean_t cli_disallow_mupip_set(void) || d_c_cli_present("WAIT_DISK") || d_c_cli_present("PARTIAL_RECOV_BYPASS"))); CLI_DIS_CHECK_N_RESET; + disallow_return_value = (d_c_cli_present("INST_FREEZE_ON_ERROR") && p3); + CLI_DIS_CHECK_N_RESET; + p1 = d_c_cli_present("KEY_SIZE"); + p2 = d_c_cli_present("RECORD_SIZE"); + p3 = d_c_cli_present("RESERVED_BYTES"); + disallow_return_value = cli_check_any2(VARLSTCNT(3) p1, p2, p3); + CLI_DIS_CHECK_N_RESET; return FALSE; } @@ -483,3 +505,37 @@ boolean_t cli_disallow_mupip_trigger(void) CLI_DIS_CHECK_N_RESET; return FALSE; } + +/* + * Disallows multiple heuristics, both region and filename, and invalid matching of heuristic parameter with the heuristic. + */ +boolean_t cli_disallow_mupip_size(void) +{ + boolean_t disallow_return_value = FALSE; + int4 heur_cnt = 0; + + heur_cnt += (d_c_cli_present("HEURISTIC.ARSAMPLE") ? 1 : 0); + heur_cnt += (d_c_cli_present("HEURISTIC.IMPSAMPLE") ? 1 : 0); + heur_cnt += (d_c_cli_present("HEURISTIC.SCAN") ? 1 : 0); + disallow_return_value = heur_cnt > 1; + CLI_DIS_CHECK_N_RESET; + + disallow_return_value = ! ( + /* SAMPLES is param for AR and IMP. So: SAMPLES => (AR || IMP) */ + (d_c_cli_present("HEURISTIC.ARSAMPLE") || d_c_cli_present("HEURISTIC.IMPSAMPLE") || + !d_c_cli_present("HEURISTIC.SAMPLES")) + && + /* LEVEL is param for SCAN So: LEVEL => SCAN */ + (d_c_cli_present("HEURISTIC.SCAN") || !d_c_cli_present("HEURISTIC.LEVEL")) + ); + CLI_DIS_CHECK_N_RESET; + + disallow_return_value = ! ( + /* SEED is param for AR and IMP. So: SAMPLES => (AR || IMP) */ + (d_c_cli_present("HEURISTIC.ARSAMPLE") || d_c_cli_present("HEURISTIC.IMPSAMPLE") || + !d_c_cli_present("HEURISTIC.SEED")) + ); + CLI_DIS_CHECK_N_RESET; + + return disallow_return_value; +} diff --git a/sr_unix/mupip_cmd_disallow.h b/sr_unix/mupip_cmd_disallow.h index 63e147d..e6b804a 100644 --- a/sr_unix/mupip_cmd_disallow.h +++ b/sr_unix/mupip_cmd_disallow.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2002, 2010 Fidelity Information Services, Inc * + * Copyright 2002, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,4 +25,6 @@ boolean_t cli_disallow_mupip_replic_updhelper(void); boolean_t cli_disallow_mupip_rundown(void); boolean_t cli_disallow_mupip_set(void); boolean_t cli_disallow_mupip_trigger(void); +boolean_t cli_disallow_mupip_size(void); +boolean_t cli_disallow_mupip_size_heuristic(void); #endif diff --git a/sr_unix/mupip_cvtgbl.c b/sr_unix/mupip_cvtgbl.c index 62706b3..53cff74 100644 --- a/sr_unix/mupip_cvtgbl.c +++ b/sr_unix/mupip_cvtgbl.c @@ -38,6 +38,7 @@ GBLREF boolean_t is_replicator; GBLREF boolean_t skip_dbtriggers; GBLREF mstr sys_input; +error_def(ERR_MUNOFINISH); error_def(ERR_MUPCLIERR); error_def(ERR_LOADEDBG); error_def(ERR_LOADBGSZ); @@ -146,12 +147,5 @@ void mupip_cvtgbl(void) } } else go_load(begin, end); - - if (mupip_error_occurred) - { - util_out_print("Error occurred during loading",TRUE); - exit(-1); - } - else - mupip_exit(SS_NORMAL); + mupip_exit(mupip_error_occurred ? ERR_MUNOFINISH : SS_NORMAL); } diff --git a/sr_unix/mupip_endiancvt.c b/sr_unix/mupip_endiancvt.c index 04f7909..2cb4623 100644 --- a/sr_unix/mupip_endiancvt.c +++ b/sr_unix/mupip_endiancvt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -64,6 +64,7 @@ #include "shmpool.h" #include "min_max.h" #include "spec_type.h" /* collation info */ +#include "anticipatory_freeze.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif @@ -95,11 +96,11 @@ error_def(ERR_TEXT); #define DBCORRUPT "the database is corrupted" #define MAX_CONF_RESPONSE 30 -GTMCRYPT_ONLY( - boolean_t is_encrypted = FALSE; - gtmcrypt_key_t encr_key_handle; - char source_file_name[MAX_FN_LEN + 1]; -) + +#ifdef GTM_CRYPT +boolean_t is_encrypted = FALSE; +gtmcrypt_key_t encr_key_handle; +#endif typedef struct { /* adapted from dbcertify.h */ @@ -111,14 +112,16 @@ typedef struct typedef struct { - int db_fd; - int outdb_fd; /* FD_INVALID if inplace */ - boolean_t inplace; /* update in place */ - boolean_t endian_native; /* original database */ - uint4 tot_blks; - int bsize; /* GDS block size */ - int4 startvbn; /* in DISK_BLOCK_SIZE units */ - block_id last_blk_cvt; /* highest block converted so far not lbm */ + int db_fd; + int outdb_fd; /* FD_INVALID if inplace */ + boolean_t inplace; /* update in place */ + boolean_t endian_native; /* original database */ + uint4 tot_blks; + int bsize; /* GDS block size */ + int4 startvbn; /* in DISK_BLOCK_SIZE units */ + block_id last_blk_cvt; /* highest block converted so far not lbm */ + char *database_fn; + int database_fn_len; struct /* used by find_dtblk related routines */ { char *buff; @@ -175,9 +178,9 @@ void mupip_endiancvt(void) char *from_endian, *to_endian; endian32_struct endian_check; endian_info info; - GTMCRYPT_ONLY( - int crypt_status; - ) +# ifdef GTM_CRYPT + int gtmcrypt_errno; +# endif ZOS_ONLY(int realfiletag;) if (CLI_PRESENT == (cli_status = cli_present("OUTDB"))) @@ -394,23 +397,20 @@ void mupip_endiancvt(void) CLOSEFILE_RESET(db_fd, rc); /* resets "db_fd" to FD_INVALID */ mupip_exit(ERR_MUNOACTION); } - /* Once the header is read, make a note whether the db is encrypted or not. If encrypted, get the - * needed key information also. We need to get the key information here as the code path of endiancvt - * doesn't go through db_init (which gets the key information in the usual cases). */ # ifdef GTM_CRYPT is_encrypted = endian_native ? old_data->is_encrypted : GTM_BYTESWAP_32(old_data->is_encrypted); if (is_encrypted) - { - INIT_PROC_ENCRYPTION(crypt_status); - /* If the encryption init failed in db_init, the below MACRO should return an error. - * Depending on the error returned, report the error.*/ - GTMCRYPT_GETKEY(old_data->encryption_hash, encr_key_handle, crypt_status); - if (0 != crypt_status) + { /* Database is encrypted. Initialize encryption and setup the keys to be used in later encryption/decryption */ + INIT_PROC_ENCRYPTION(NULL, gtmcrypt_errno); + if (0 == gtmcrypt_errno) + GTMCRYPT_GETKEY(NULL, old_data->encryption_hash, encr_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, db_name); - mupip_exit(crypt_status); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, n_len, db_name); + mupip_exit(gtmcrypt_errno); } - strcpy(source_file_name, db_name); + info.database_fn = &db_name[0]; + info.database_fn_len = n_len; } # endif from_endian = endian_check.shorts.big_endian ? "BIG" : "LITTLE"; @@ -545,7 +545,11 @@ void mupip_endiancvt(void) mupip_exit(ERR_MUNOFINISH); /* endian_process issued specific message */ } new_data->file_corrupt = endian_native ? GTM_BYTESWAP_32(FALSE) : FALSE; - LSEEKWRITE(outdb_specified ? outdb_fd : db_fd, 0, new_data, SIZEOF(sgmnt_data), save_errno); + if (outdb_specified) + { + LSEEKWRITE(outdb_fd, 0, new_data, SIZEOF(sgmnt_data), save_errno); + } else + DB_LSEEKWRITE((sgmnt_addrs *)NULL, (char *)NULL, db_fd, 0, new_data, SIZEOF(sgmnt_data), save_errno); if (0 != save_errno) { free(new_data); @@ -570,7 +574,11 @@ void mupip_endiancvt(void) DO_STANDALONE_CLNUP_IF_NEEDED(endian_native); free(new_data); free(old_data); - GTM_FSYNC((outdb_specified ? outdb_fd : db_fd), rc); + if (outdb_specified) + { + GTM_FSYNC(outdb_fd, rc); + } else + GTM_DB_FSYNC((sgmnt_addrs *)NULL, db_fd, rc); if (-1 == rc) { save_errno = errno; @@ -683,7 +691,6 @@ void endian_header(sgmnt_data *new, sgmnt_data *old, boolean_t new_is_native) SWAP_SD4(n_wrt_per_flu); SWAP_SD4(wait_disk_space); SWAP_SD4(defer_time); - new->wc_blocked = FALSE; /* is relevant only when database shared memory is up so reset it unconditionally */ SWAP_SD4(reserved_for_upd); SWAP_SD4(avg_blks_per_100gbl); SWAP_SD4(pre_read_trigger_factor); @@ -782,19 +789,19 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat { /* returns 0 for success This routine based on mubinccpy and dbcertify_scan_phase */ - int4 startvbn; - int save_errno, bsize, lbmap_cnt, lbm_status; - int buff_native, buff_old, buff_new; - int mm_offset, lm_offset; - int4 bplmap; - uint4 totblks, lbm_done, busy_done, recycled_done, free_done, last_blk_written; - off_t dbptr; - block_id blk_num; - boolean_t new_is_native; - char *blk_buff[2], *lbmap_buff[2], *errptr; + int4 startvbn; + int save_errno, bsize, lbmap_cnt, lbm_status; + int buff_native, buff_old, buff_new; + int mm_offset, lm_offset; + int4 bplmap; + uint4 totblks, lbm_done, busy_done, recycled_done, free_done, last_blk_written; + off_t dbptr; + block_id blk_num; + boolean_t new_is_native; + char *blk_buff[2], *lbmap_buff[2], *errptr; # ifdef GTM_CRYPT - int crypt_blk_size, crypt_status; - blk_hdr_ptr_t bp_new, bp_native; + int crypt_blk_size, gtmcrypt_errno; + blk_hdr_ptr_t bp_new, bp_native; boolean_t blk_needs_encryption; # endif if (info->endian_native) @@ -818,7 +825,8 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat new_is_native = TRUE; buff_old = 0; } - dbptr = (startvbn - 1) * DISK_BLOCK_SIZE; + GTMCRYPT_ONLY(assert((0 != info->database_fn_len) || !is_encrypted)); + dbptr = (off_t)(startvbn - 1) * DISK_BLOCK_SIZE; info->tot_blks = totblks; info->bsize = bsize; info->startvbn = startvbn; @@ -844,7 +852,7 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat memcpy(lbmap_buff[buff_new], lbmap_buff[buff_old], bsize); endian_cvt_blk_hdr((blk_hdr_ptr_t)lbmap_buff[buff_new], new_is_native, FALSE); assert(LCL_MAP_LEVL == ((blk_hdr_ptr_t)lbmap_buff[buff_native])->levl); - /* set all recycled bits to free to avoid trouble if pre GDSV5 */ + /* set all recycled bits to free to avoid trouble if pre GDSV6 */ /* lm_offset 0 is the local bit map itself */ for (lm_offset = 1; lm_offset < bplmap && (blk_num + lm_offset) < totblks; lm_offset++) { @@ -858,7 +866,11 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat else if (BLK_MAPINVALID == lbm_status) GTMASSERT; } - LSEEKWRITE(info->inplace ? info->db_fd : info->outdb_fd, dbptr, lbmap_buff[buff_new], bsize, save_errno); + if (info->inplace) + { + DB_LSEEKWRITE(NULL, NULL, info->db_fd, dbptr, lbmap_buff[buff_new], bsize, save_errno); + } else + LSEEKWRITE(info->outdb_fd, dbptr, lbmap_buff[buff_new], bsize, save_errno); if (0 != save_errno) { free(blk_buff[0]); @@ -905,15 +917,13 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat blk_needs_encryption = BLK_NEEDS_ENCRYPTION(bp_new->levl, crypt_blk_size); if (blk_needs_encryption) { - GTMCRYPT_DECODE_FAST(encr_key_handle, - (char *)(bp_new + 1), - crypt_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) + GTMCRYPT_DECRYPT(NULL, encr_key_handle, (char *)(bp_new + 1), crypt_blk_size, NULL, + gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, source_file_name); - return crypt_status; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, info->database_fn_len, + info->database_fn); + return gtmcrypt_errno; } } if (!new_is_native) @@ -923,15 +933,13 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat endian_cvt_blk_recs(info, (char *)bp_new, bp_native, blk_num); if (blk_needs_encryption) { - GTMCRYPT_ENCODE_FAST(encr_key_handle, - (char *)(bp_new + 1), - crypt_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) + GTMCRYPT_ENCRYPT(NULL, encr_key_handle, (char *)(bp_new + 1), crypt_blk_size, NULL, + gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, source_file_name); - return crypt_status; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, info->database_fn_len, + info->database_fn); + return gtmcrypt_errno; } } } else @@ -944,8 +952,11 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat # ifdef GTM_CRYPT } # endif - LSEEKWRITE(info->inplace ? info->db_fd : info->outdb_fd, dbptr, blk_buff[buff_new], bsize, - save_errno); + if (info->inplace) + { + DB_LSEEKWRITE(NULL, NULL, info->db_fd, dbptr, blk_buff[buff_new], bsize, save_errno); + } else + LSEEKWRITE(info->outdb_fd, dbptr, blk_buff[buff_new], bsize, save_errno); if (0 != save_errno) { free(blk_buff[0]); @@ -966,7 +977,11 @@ int4 endian_process(endian_info *info, sgmnt_data *new_data, sgmnt_data *old_dat { /* need to create last disk block */ memset(blk_buff[0], 0, DISK_BLOCK_SIZE); dbptr = ((off_t)(startvbn - 1) * DISK_BLOCK_SIZE) + ((off_t)totblks * bsize); - LSEEKWRITE(info->inplace ? info->db_fd : info->outdb_fd, dbptr, blk_buff[0], DISK_BLOCK_SIZE, save_errno); + if (info->inplace) + { + DB_LSEEKWRITE(NULL, NULL, info->db_fd, dbptr, blk_buff[0], DISK_BLOCK_SIZE, save_errno); + } else + LSEEKWRITE(info->outdb_fd, dbptr, blk_buff[0], DISK_BLOCK_SIZE, save_errno); if (0 != save_errno) { free(blk_buff[0]); @@ -1015,7 +1030,7 @@ void endian_cvt_blk_hdr(blk_hdr_ptr_t blkhdr, boolean_t new_is_native, boolean_t v15tn = ((v15_blk_hdr *)blkhdr)->tn; assert(SIZEOF(char) == SIZEOF(blkhdr->levl)); /* no need to swap */ blkhdr->levl = v15levl; - bver = GDSV5; + bver = GDSV6; bsiz = SIZEOF(v15_blk_hdr); if (!new_is_native) { @@ -1047,12 +1062,12 @@ char *endian_read_dbblk(endian_info *info, block_id blk_to_get) int save_errno; boolean_t blk_is_native; char *buff; - GTMCRYPT_ONLY( - int req_dec_blk_size; - char *inbuf; - blk_hdr_ptr_t bp; - int crypt_status; - ) +# ifdef GTM_CRYPT + int gtmcrypt_errno; + int req_dec_blk_size; + char *inbuf; + blk_hdr_ptr_t bp; +# endif if (DIR_ROOT == blk_to_get) { @@ -1072,7 +1087,7 @@ char *endian_read_dbblk(endian_info *info, block_id blk_to_get) return info->dtblk.buff; /* already have it */ buff = info->dtblk.buff; } - blkoff = ((info->startvbn - 1) * DISK_BLOCK_SIZE) + (blk_to_get * info->bsize); + blkoff = ((off_t)(info->startvbn - 1) * DISK_BLOCK_SIZE) + ((off_t)blk_to_get * info->bsize); LSEEKREAD(info->db_fd, blkoff, buff, info->bsize, save_errno); if (0 != save_errno) { @@ -1094,10 +1109,10 @@ char *endian_read_dbblk(endian_info *info, block_id blk_to_get) { ASSERT_ENCRYPTION_INITIALIZED; inbuf = (char *)(bp + 1); - GTMCRYPT_DECODE_FAST(encr_key_handle, inbuf, req_dec_blk_size, NULL, crypt_status); - if (0 != crypt_status) + GTMCRYPT_DECRYPT(NULL, encr_key_handle, inbuf, req_dec_blk_size, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, NULL); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, info->database_fn, info->database_fn_len); return NULL; } } @@ -1116,6 +1131,7 @@ char *endian_read_dbblk(endian_info *info, block_id blk_to_get) void endian_find_key(endian_info *info, end_gv_key *targ_gv_key, char *rec_p, int rec_len, int blk_levl) { /* find the key for the record and set targ_gv_key */ int cmpc; + int tmp_cmpc; unsigned char *targ_key; char *rec_key; @@ -1124,7 +1140,7 @@ void endian_find_key(endian_info *info, end_gv_key *targ_gv_key, char *rec_p, in targ_gv_key->end = 0; return; } - cmpc = ((rec_hdr_ptr_t)rec_p)->cmpc; + cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_p); targ_key = targ_gv_key->key + cmpc; rec_key = rec_p + SIZEOF(rec_hdr); while (TRUE) @@ -1179,6 +1195,7 @@ block_id endian_find_dtblk(endian_info *info, end_gv_key *gv_key) { block_id blk_to_get, blk_ptr; int save_errno, rec_len, blk_levl, ptroffset; + int tmp_cmpc; boolean_t blk_is_native; char *buff, *blk_top, *rec_p; unsigned short us_rec_len; @@ -1221,7 +1238,7 @@ block_id endian_find_dtblk(endian_info *info, end_gv_key *gv_key) { if (0 == blk_levl) return blk_to_get; /* found dtleaf block we are looking for */ - ptroffset = found_gv_key.end - ((rec_hdr *)rec_p)->cmpc + 1; + ptroffset = found_gv_key.end - EVAL_CMPC((rec_hdr *)rec_p) + 1; GET_ULONG(blk_ptr, (rec_p + SIZEOF(rec_hdr) + ptroffset)); if (!blk_is_native) blk_ptr = GTM_BYTESWAP_32(blk_ptr); @@ -1245,12 +1262,12 @@ void endian_cvt_blk_recs(endian_info *info, char *new_block, blk_hdr_ptr_t blkhd { /* convert records in new_block, could be data, index, or directory use converted header fields from blkhdr which is in native format */ int rec1_len, rec1_gvn_len, rec2_cmpc, rec2_len; + int tmp_cmpc; int blk_levl; - rec_hdr *recp; block_id ptr2blk, ptr2blk_swap, dtblk; boolean_t new_is_native, have_dt_blk; unsigned short us_rec_len, us_rec_len_swap; - unsigned char *rec1_ptr, *rec2_ptr, *blk_top, *key_top, *tmp_ptr; + unsigned char *rec1_ptr, *rec2_ptr, *blk_top, *key_top; boolean_t have_gvtleaf; end_gv_key gv_key; @@ -1267,7 +1284,7 @@ void endian_cvt_blk_recs(endian_info *info, char *new_block, blk_hdr_ptr_t blkhd /* need to check there really is a 2nd record */ rec2_ptr = rec1_ptr + rec1_len; if (rec2_ptr < blk_top) - rec2_cmpc = ((rec_hdr *)rec2_ptr)->cmpc; + rec2_cmpc = EVAL_CMPC((rec_hdr *)rec2_ptr); else rec2_cmpc = -1; /* no second record */ @@ -1340,11 +1357,7 @@ void endian_cvt_blk_recs(endian_info *info, char *new_block, blk_hdr_ptr_t blkhd us_rec_len_swap = GTM_BYTESWAP_16(us_rec_len); PUT_USHORT(&((rec_hdr *)rec1_ptr)->rsiz, us_rec_len_swap); rec1_len = new_is_native ? us_rec_len_swap : us_rec_len; - /* clear left over char after cmpc */ - recp = (rec_hdr *)rec1_ptr; - tmp_ptr = &recp->cmpc + 1; - assert(SIZEOF(rec_hdr) > (tmp_ptr - rec1_ptr)); - *tmp_ptr = 0; + /* leave cmpc and cmpc2 bytes alone */ if (!have_gvtleaf) { /* fix up pointers as well */ key_top = rec1_ptr + SIZEOF(rec_hdr); diff --git a/sr_unix/mupip_exit.c b/sr_unix/mupip_exit.c index ce1ecfc..e4662f3 100644 --- a/sr_unix/mupip_exit.c +++ b/sr_unix/mupip_exit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,7 +27,7 @@ void mupip_exit(int4 stat) { if (error_condition != stat) /* If message not already put out.. */ { - gtm_putmsg(VARLSTCNT(1) stat); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) stat); tmp_severity = SEVMASK(stat); } else tmp_severity = severity; diff --git a/sr_unix/mupip_exit_handler.c b/sr_unix/mupip_exit_handler.c index 2402b92..c1fc50f 100644 --- a/sr_unix/mupip_exit_handler.c +++ b/sr_unix/mupip_exit_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -69,9 +69,7 @@ GBLREF boolean_t created_core; GBLREF unsigned int core_in_progress; GBLREF boolean_t exit_handler_active; GBLREF recvpool_addrs recvpool; -GBLREF jnlpool_addrs jnlpool; GBLREF boolean_t pool_init; -GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF boolean_t is_src_server; GBLREF boolean_t is_rcvr_server; GBLREF boolean_t is_updproc; @@ -81,15 +79,10 @@ GBLREF FILE *gtmrecv_log_fp; GBLREF FILE *updproc_log_fp; GBLREF FILE *updhelper_log_fp; GBLREF int gtmsource_log_fd; -GBLREF int gtmsource_statslog_fd; -GBLREF FILE *gtmsource_statslog_fp; GBLREF int gtmrecv_log_fd; -GBLREF int gtmrecv_statslog_fd; -GBLREF FILE *gtmrecv_statslog_fp; GBLREF int updproc_log_fd; GBLREF int updhelper_log_fd; GBLREF gd_region *gv_cur_region; -GBLREF gd_region *ftok_sem_reg; GBLREF jnl_gbls_t jgbl; GBLREF upd_helper_entry_ptr_t helper_entry; GBLREF uint4 dollar_tlevel; @@ -100,8 +93,8 @@ void close_repl_logfiles(void); void mupip_exit_handler(void) { char err_log[1024]; - unix_db_info *udi; FILE *fp; + boolean_t files_closed = TRUE; if (exit_handler_active) /* Don't recurse if exit handler exited */ return; @@ -109,25 +102,14 @@ void mupip_exit_handler(void) SET_PROCESS_EXITING_TRUE; if (jgbl.mupip_journal) { - mur_close_files(); + files_closed = mur_close_files(); mupip_jnl_recover = FALSE; } jgbl.dont_reset_gbl_jrec_time = jgbl.forw_phase_recovery = FALSE; cancel_timer(0); /* Cancel all timers - No unpleasant surprises */ secshr_db_clnup(NORMAL_TERMINATION); - if (jnlpool.jnlpool_ctl) - { - rel_lock(jnlpool.jnlpool_dummy_reg); - mutex_cleanup(jnlpool.jnlpool_dummy_reg); - if (jnlpool.gtmsource_local && (process_id == jnlpool.gtmsource_local->gtmsource_srv_latch.u.parts.latch_pid)) - rel_gtmsource_srv_latch(&jnlpool.gtmsource_local->gtmsource_srv_latch); - SHMDT(jnlpool.jnlpool_ctl); - jnlpool.jnlpool_ctl = jnlpool_ctl = NULL; - pool_init = FALSE; - } if (dollar_tlevel) OP_TROLLBACK(0); - gv_rundown(); if (is_updhelper && NULL != helper_entry) /* haven't had a chance to cleanup, must be an abnormal exit */ { helper_entry->helper_shutdown = ABNORMAL_SHUTDOWN; @@ -139,44 +121,7 @@ void mupip_exit_handler(void) SHMDT(recvpool.recvpool_ctl); recvpool.recvpool_ctl = NULL; } - /* - * Note: - * In older versions we used to release replication semaphores here. - * But it does not really help. We do not want to release them until this process exits. - * We use SEM_UNDO flag for semaphore creation. So when this process will exit, - * OS will automatically release the semaphore value by 1. That is do nothing about them. - */ - if (ftok_sem_reg) - { - /* This segment of code will be executed by utilities - * like mupip integ file/mupip restore etc., which operates on one single region. - * In case of an error or, for any other code path, if the ftok semaphore is - * grabbed but not released, ftok_sem_reg will have non-null value - * and grabbed_ftok_sem will be TRUE. - * (We cannot rely on gv_cur_region which is used in so many places in so many ways.) - * In case a processed released ftok semaphore lock but did not decrement - * the counter, ftok_sem_reg will be NULL. In that case we rely on OS to decrement - * the counter when the process exits completely. - */ - DEBUG_ONLY(udi = FILE_INFO(ftok_sem_reg);) - assert(udi->grabbed_ftok_sem); - ftok_sem_release(ftok_sem_reg, TRUE, TRUE); - } else - { - /* This segment is for replication ftok semaphore cleanup in case of error. */ - if (NULL != jnlpool.jnlpool_dummy_reg) - { - udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); - if (udi->grabbed_ftok_sem) - ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); - } - if (NULL != recvpool.recvpool_dummy_reg) - { - udi = FILE_INFO(recvpool.recvpool_dummy_reg); - if (udi->grabbed_ftok_sem) - ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); - } - } + gv_rundown(); /* also takes care of detaching from the journal pool */ /* 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. */ @@ -208,32 +153,18 @@ void mupip_exit_handler(void) ++core_in_progress; DUMP_CORE; /* This will not return */ } + if (!files_closed) + _exit(EXIT_FAILURE); } void close_repl_logfiles() { int rc; - if (FD_INVALID != gtmsource_statslog_fd) - { - if (gtmsource_log_fd == gtmsource_statslog_fd) - gtmsource_log_fd = FD_INVALID; - CLOSEFILE_RESET(gtmsource_statslog_fd, rc); /* resets "gtmsource_statslog_fd" to FD_INVALID */ - } - if (NULL != gtmsource_statslog_fp) - FCLOSE(gtmsource_statslog_fp, rc); if (FD_INVALID != gtmsource_log_fd) CLOSEFILE_RESET(gtmsource_log_fd, rc); /* resets "gtmsource_log_fd" to FD_INVALID */ if (NULL != gtmsource_log_fp) FCLOSE(gtmsource_log_fp, rc); - if (FD_INVALID != gtmrecv_statslog_fd) - { - if (gtmrecv_log_fd == gtmrecv_statslog_fd) - gtmrecv_log_fd = FD_INVALID; - CLOSEFILE_RESET(gtmrecv_statslog_fd, rc); /* resets "gtmrecv_statslog_fd" to FD_INVALID */ - } - if (NULL != gtmrecv_statslog_fp) - FCLOSE(gtmrecv_statslog_fp, rc); if (FD_INVALID != gtmrecv_log_fd) CLOSEFILE_RESET(gtmrecv_log_fd, rc); /* resets "gtmrecv_log_fd" to FD_INVALID */ if (NULL != gtmrecv_log_fp) diff --git a/sr_unix/mupip_help.c b/sr_unix/mupip_help.c index 508328f..0e8cb2d 100644 --- a/sr_unix/mupip_help.c +++ b/sr_unix/mupip_help.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -9,11 +9,10 @@ * * ****************************************************************/ -/* STUB FILE */ - #include "mdef.h" #include "mupip_help.h" void mupip_help(void) -{ return; +{ + /* This function is a STUB to avoid editting sr_port/mupip.h */ } diff --git a/sr_unix/mupip_restore.c b/sr_unix/mupip_restore.c index 52326ad..d32e2a8 100644 --- a/sr_unix/mupip_restore.c +++ b/sr_unix/mupip_restore.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -67,6 +67,8 @@ #include "min_max.h" #include "gtmxc_types.h" #include "gtmcrypt.h" +#include "jnl.h" +#include "anticipatory_freeze.h" GBLDEF inc_list_struct in_files; GBLREF uint4 pipe_child; @@ -102,7 +104,6 @@ error_def(ERR_TEXT); CONDITION_HANDLER(iob_io_error) { - int dummy1, dummy2; char s[80]; char *fgets_res; @@ -115,7 +116,7 @@ CONDITION_HANDLER(iob_io_error) CONTINUE; } PRN_ERROR; - UNWIND(dummy1, dummy2); + UNWIND(NULL, NULL); } @@ -126,9 +127,8 @@ void mupip_restore(void) inc_list_struct *ptr; inc_header inhead; sgmnt_data old_data; - short iosb[4]; unsigned short n_len; - int4 status, rsize, size, temp, save_errno, old_start_vbn; + int4 status, rsize, temp, save_errno, old_start_vbn; uint4 rest_blks, totblks; trans_num curr_tn; uint4 ii; @@ -137,7 +137,7 @@ void mupip_restore(void) uint4 cli_status; BFILE *in; int i, db_fd; - uint4 old_blk_size, old_tot_blks, bplmap, old_bit_maps, new_bit_maps; + uint4 old_blk_size, size, old_tot_blks, bplmap, old_bit_maps, new_bit_maps; off_t new_eof, offset; # ifdef GTM_TRUNCATE off_t new_size; @@ -150,15 +150,14 @@ void mupip_restore(void) backup_type type; unsigned short port; int4 timeout, cut, match; - char debug_info[256]; void (*common_read)(); char *errptr; pid_t waitpid_res; muinc_blk_hdr_ptr_t sblkh_p; int rc; # ifdef GTM_CRYPT - char bkup_hash[GTMCRYPT_HASH_LEN]; - int req_dec_blk_size, crypt_status; + char bkup_hash[GTMCRYPT_HASH_LEN], *inptr; + int in_len, gtmcrypt_errno; gtmcrypt_key_t bkup_key_handle, target_key_handle; boolean_t is_bkup_file_encrypted, is_same_hash = FALSE; # endif @@ -360,7 +359,7 @@ void mupip_restore(void) + ((off_t)inhead.db_total_blks * old_blk_size); new_size = new_eof + DISK_BLOCK_SIZE; memset(buff, 0, DISK_BLOCK_SIZE); - LSEEKWRITE(db_fd, new_eof, buff, DISK_BLOCK_SIZE, status); + DB_LSEEKWRITE(NULL, NULL, db_fd, new_eof, buff, DISK_BLOCK_SIZE, status); if (0 != status) { util_out_print("Aborting restore!/", TRUE); @@ -411,7 +410,7 @@ void mupip_restore(void) new_eof = ((off_t)(old_start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)inhead.db_total_blks * old_blk_size); memset(buff, 0, DISK_BLOCK_SIZE); - LSEEKWRITE(db_fd, new_eof, buff, DISK_BLOCK_SIZE, status); + DB_LSEEKWRITE(NULL, NULL, db_fd, new_eof, buff, DISK_BLOCK_SIZE, status); if (0 != status) { util_out_print("Aborting restore!/", TRUE); @@ -422,7 +421,7 @@ void mupip_restore(void) util_out_print(" Current input file is !AD with !UL (!XL hex) total blocks!/", TRUE, ptr->input_file.len, ptr->input_file.addr, inhead.db_total_blks, inhead.db_total_blks); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) status); CLNUP_AND_EXIT(ERR_MUPRESTERR, inbuf); } /* --- initialize all new bitmaps, just in case they are not touched later --- */ @@ -439,12 +438,12 @@ void mupip_restore(void) for (ii = ROUND_UP(old_tot_blks, bplmap); ii < inhead.db_total_blks; ii += bplmap) { new_eof = (off_t)(old_start_vbn - 1) * DISK_BLOCK_SIZE + (off_t)ii * old_blk_size; - LSEEKWRITE(db_fd, new_eof, newmap, old_blk_size, status); + DB_LSEEKWRITE(NULL, NULL, db_fd, new_eof, newmap, old_blk_size, status); if (0 != status) { util_out_print("Aborting restore!/", TRUE); util_out_print("Bitmap 0x!XL initialization error!", TRUE, ii); - gtm_putmsg(VARLSTCNT(1) status); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) status); free(newmap); CLNUP_AND_EXIT(ERR_MUPRESTERR, inbuf); } @@ -459,31 +458,29 @@ void mupip_restore(void) # ifdef GTM_CRYPT if (is_bkup_file_encrypted || old_data.is_encrypted) { - /* See if the backup file and the target file are going to have - * the same hash thereby speeding up the most common case. */ + /* See if the backup file and the target file have the same hash thereby speeding up the most common case */ if (!memcmp(bkup_hash, old_data.encryption_hash, GTMCRYPT_HASH_LEN)) is_same_hash = TRUE; + ASSERT_ENCRYPTION_INITIALIZED; /* should have been done in mu_rndwn_file (called from STANDALONE) */ if (!is_same_hash) { - INIT_PROC_ENCRYPTION(crypt_status); - if (0 != crypt_status) - CLNUP_AND_EXIT(crypt_status, inbuf); if (is_bkup_file_encrypted) { - GTMCRYPT_GETKEY(bkup_hash, bkup_key_handle, crypt_status); - if (0 != crypt_status) + GTMCRYPT_GETKEY(NULL, bkup_hash, bkup_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, ptr->input_file.addr); - CLNUP_AND_EXIT(crypt_status, inbuf); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, ptr->input_file.len, + ptr->input_file.addr); + CLNUP_AND_EXIT(gtmcrypt_errno, inbuf); } } if (old_data.is_encrypted) { - GTMCRYPT_GETKEY(old_data.encryption_hash, target_key_handle, crypt_status); - if (0 != crypt_status) + GTMCRYPT_GETKEY(NULL, old_data.encryption_hash, target_key_handle, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, db_name); - CLNUP_AND_EXIT(crypt_status, inbuf); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, n_len, db_name); + CLNUP_AND_EXIT(gtmcrypt_errno, inbuf); } } } @@ -540,40 +537,35 @@ void mupip_restore(void) } # ifdef GTM_CRYPT assert((size <= old_blk_size) && (size >= SIZEOF(blk_hdr))); - req_dec_blk_size = MIN(old_blk_size, size) - SIZEOF(blk_hdr); - if (!is_same_hash && (BLOCK_REQUIRE_ENCRYPTION(is_bkup_file_encrypted, (((blk_hdr_ptr_t)blk_ptr)->levl), - req_dec_blk_size))) + in_len = MIN(old_blk_size, size) - SIZEOF(blk_hdr); + if (!is_same_hash + && (BLOCK_REQUIRE_ENCRYPTION(is_bkup_file_encrypted, (((blk_hdr_ptr_t)blk_ptr)->levl), in_len))) { - GTMCRYPT_DECODE_FAST(bkup_key_handle, - blk_ptr + SIZEOF(blk_hdr), - req_dec_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) + inptr = blk_ptr + SIZEOF(blk_hdr); + GTMCRYPT_DECRYPT(NULL, bkup_key_handle, inptr, in_len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, ptr->input_file.addr); - CLNUP_AND_EXIT(crypt_status, inbuf); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, ptr->input_file.len, + ptr->input_file.addr); + CLNUP_AND_EXIT(gtmcrypt_errno, inbuf); } } # endif offset = (old_start_vbn - 1) * DISK_BLOCK_SIZE + ((off_t)old_blk_size * blk_num); # ifdef GTM_CRYPT - if (!is_same_hash && (BLOCK_REQUIRE_ENCRYPTION(old_data.is_encrypted, - (((blk_hdr_ptr_t)blk_ptr)->levl), req_dec_blk_size))) + if (!is_same_hash + && (BLOCK_REQUIRE_ENCRYPTION(old_data.is_encrypted, (((blk_hdr_ptr_t)blk_ptr)->levl), in_len))) { - GTMCRYPT_ENCODE_FAST(target_key_handle, - blk_ptr + SIZEOF(blk_hdr), - req_dec_blk_size, - NULL, - crypt_status); - if (0 != crypt_status) + inptr = blk_ptr + SIZEOF(blk_hdr); + GTMCRYPT_ENCRYPT(NULL, target_key_handle, inptr, in_len, NULL, gtmcrypt_errno); + if (0 != gtmcrypt_errno) { - GC_GTM_PUTMSG(crypt_status, db_name); - CLNUP_AND_EXIT(crypt_status, inbuf); + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, n_len, db_name); + CLNUP_AND_EXIT(gtmcrypt_errno, inbuf); } } # endif - LSEEKWRITE(db_fd, offset, blk_ptr, size, save_errno); + DB_LSEEKWRITE(NULL, NULL, db_fd, offset, blk_ptr, size, save_errno); if (0 != save_errno) { util_out_print("Error accessing output file !AD. Aborting restore.", @@ -605,7 +597,7 @@ void mupip_restore(void) ((sgmnt_data_ptr_t)inbuf)->gt_sem_ctime.ctime = old_data.gt_sem_ctime.ctime; ((sgmnt_data_ptr_t)inbuf)->shmid = old_data.shmid; ((sgmnt_data_ptr_t)inbuf)->gt_shm_ctime.ctime = old_data.gt_shm_ctime.ctime; - LSEEKWRITE(db_fd, 0, inbuf, rsize - SIZEOF(int4), save_errno); + DB_LSEEKWRITE(NULL, NULL, db_fd, 0, inbuf, rsize - SIZEOF(int4), save_errno); if (0 != save_errno) { util_out_print("Error accessing output file !AD. Aborting restore.", @@ -635,7 +627,7 @@ void mupip_restore(void) COMMON_READ(in, inbuf, rsize, inbuf); if (!MEMCMP_LIT(inbuf, MAP_MSG)) break; - LSEEKWRITE(db_fd, + DB_LSEEKWRITE(NULL, NULL, db_fd, offset, inbuf, rsize - SIZEOF(int4), @@ -702,7 +694,7 @@ STATICFNDEF void exec_read(BFILE *bf, char *buf, int nbytes) */ else if ((EINTR != errno) && (EAGAIN != errno)) { - gtm_putmsg(VARLSTCNT(1) errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); if ((pipe_child > 0) && (FALSE != is_proc_alive(pipe_child, 0))) WAITPID(pipe_child, (int *)&status, 0, waitpid_res); CLOSEFILE_RESET(bf->fd, rc); /* resets "bf->fd" to FD_INVALID */ @@ -752,7 +744,7 @@ STATICFNDEF void tcp_read(BFILE *bf, char *buf, int nbytes) } if ((status < 0) && (errno != EINTR)) { - gtm_putmsg(VARLSTCNT(1) errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); CLOSEFILE_RESET(bf->fd, rc); /* resets "bf->fd" to FD_INVALID */ restore_read_errno = errno; break; diff --git a/sr_unix/mupip_rundown.c b/sr_unix/mupip_rundown.c index a9f78f0..499bd3b 100644 --- a/sr_unix/mupip_rundown.c +++ b/sr_unix/mupip_rundown.c @@ -11,6 +11,7 @@ #include "mdef.h" +#include #include "gtm_string.h" #include "gtm_inet.h" @@ -49,29 +50,48 @@ #include "repl_instance.h" #include "mu_rndwn_repl_instance.h" #include "util.h" +#include "anticipatory_freeze.h" +#include "gtm_ipc.h" +#include "repl_sem.h" +#include "ftok_sems.h" +#include "ipcrmid.h" -GBLREF bool in_backup; -GBLREF bool error_mupip; -GBLREF tp_region *grlist; -GBLREF gd_region *gv_cur_region; -GBLREF boolean_t mu_star_specified; -GBLREF boolean_t donot_fflush_NULL; +GBLREF bool in_backup; +GBLREF bool error_mupip; +GBLREF tp_region *grlist; +GBLREF gd_region *gv_cur_region; +GBLREF boolean_t mu_star_specified; +GBLREF boolean_t donot_fflush_NULL; +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +GBLREF jnlpool_addrs jnlpool; +GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; +GBLREF boolean_t argumentless_rundown; error_def(ERR_MUFILRNDWNSUC); +error_def(ERR_MUJPOOLRNDWNFL); +error_def(ERR_MUJPOOLRNDWNSUC); error_def(ERR_MUNOACTION); error_def(ERR_MUNODBNAME); error_def(ERR_MUNOTALLSEC); error_def(ERR_MUPCLIERR); error_def(ERR_MUQUALINCOMP); +error_def(ERR_REPLPOOLINST); +error_def(ERR_SEMREMOVED); +error_def(ERR_SYSCALL); error_def(ERR_TEXT); void mupip_rundown(void) { - int exit_status; - boolean_t region, file, arg_present; + int exit_status, semid, shmid, save_errno, status; + boolean_t region, file, arg_present, do_jnlpool_detach, jnlpool_sem_created, jnlpool_rndwn_required; + boolean_t repl_inst_available, shm_removed = FALSE, anticipatory_freeze_available; tp_region *rptr, single; replpool_identifier replpool_id; + repl_inst_hdr repl_instance; + struct shmid_ds shm_buf; unsigned int full_len; + char *instfilename; + unsigned char ipcs_buff[MAX_IPCS_ID_BUF], *ipcs_ptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -106,6 +126,24 @@ void mupip_rundown(void) in_backup = FALSE; /* Only want yes/no from mupfndfil, not an address */ if (region || file) { + do_jnlpool_detach = FALSE; + anticipatory_freeze_available = ANTICIPATORY_FREEZE_AVAILABLE; + if ((jnlpool_rndwn_required = (region && mu_star_specified)) || anticipatory_freeze_available) /* note:assigmnent */ + { + if (DEBUG_ONLY(repl_inst_available = )REPL_INST_AVAILABLE) /* sets replpool_id/full_len; note: assignment */ + { + instfilename = &replpool_id.instfilename[0]; + if (!mu_rndwn_repl_instance(&replpool_id, !anticipatory_freeze_available, TRUE, + &jnlpool_sem_created)) + { + assert(NULL == jnlpool_ctl); + exit_status = ERR_MUNOTALLSEC; + } + else + do_jnlpool_detach = (NULL != jnlpool_ctl); + ENABLE_FREEZE_ON_ERROR; + } + } for ( ; NULL != rptr; rptr = rptr->fPtr) { if (region) @@ -127,31 +165,137 @@ void mupip_rundown(void) memset(gv_cur_region->dyn.addr->file_cntl->file_info, 0, SIZEOF(GDS_INFO)); } } - if (TRUE == mu_rndwn_file(gv_cur_region, FALSE)) - { - gtm_putmsg(VARLSTCNT(4) ERR_MUFILRNDWNSUC, 2, gv_cur_region->dyn.addr->fname_len, - gv_cur_region->dyn.addr->fname); - } + gtm_putmsg(VARLSTCNT(4) ERR_MUFILRNDWNSUC, 2, DB_LEN_STR(gv_cur_region)); else exit_status = ERR_MUNOTALLSEC; } - if (region && mu_star_specified) /* rundown repl pools belonging to this global directory */ + if (do_jnlpool_detach) { - if (repl_inst_get_name((char *)replpool_id.instfilename, &full_len, SIZEOF(replpool_id.instfilename), - return_on_error)) + assert(anticipatory_freeze_available && repl_inst_available); + assert(NULL != jnlpool_ctl); + /* Read the instance file to invalidate the journal pool semaphore ID and shared memory ID */ + assert(NULL != jnlpool.jnlpool_dummy_reg); + assert(INVALID_SEMID != jnlpool.repl_inst_filehdr->jnlpool_semid); + assert(INVALID_SHMID != jnlpool.repl_inst_filehdr->jnlpool_shmid); + assert(0 != jnlpool.repl_inst_filehdr->jnlpool_semid_ctime); + assert(0 != jnlpool.repl_inst_filehdr->jnlpool_shmid_ctime); + semid = jnlpool.repl_inst_filehdr->jnlpool_semid; + shmid = jnlpool.repl_inst_filehdr->jnlpool_shmid; + /* Detach from the journal pool */ + JNLPOOL_SHMDT(status, save_errno); + jnlpool.gtmsrc_lcl_array = NULL; + jnlpool.repl_inst_filehdr = NULL; + jnlpool.gtmsource_local_array = NULL; + jnlpool.jnldata_base = NULL; + if (0 > status) { - if (!mu_rndwn_repl_instance(&replpool_id, TRUE, TRUE)) - exit_status = ERR_MUNOTALLSEC; + ISSUE_REPLPOOLINST(save_errno, shmid, instfilename, "shmdt()"); + mupip_exit(ERR_MUNOTALLSEC); + } + /* Grab the ftok again */ + if (!ftok_sem_lock(jnlpool.jnlpool_dummy_reg, FALSE, FALSE)) + { /* CRITSEMFAIL is issued in case of an error */ + assert(FALSE); + mupip_exit(ERR_MUNOTALLSEC); + } + if (jnlpool_rndwn_required) + { /* User requested for running down the journal pool as well. So, regrab the access control semaphore + * before proceeding to remove the shared memory. We should already have incremented the counter + * semaphore. But, before that read the instance file since we need to invalidate the semid/shmid + * below. + */ + repl_inst_read(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); + assert(semid == repl_instance.jnlpool_semid); /* Should still be valid */ + assert(shmid == repl_instance.jnlpool_shmid); /* Should still be valid */ + assert(holds_sem[SOURCE][SRC_SERV_COUNT_SEM]); + if (SS_NORMAL != grab_sem(SOURCE, JNL_POOL_ACCESS_SEM)) + { + save_errno = errno; + ISSUE_REPLPOOLINST(save_errno, shmid, instfilename, "semop()"); + mupip_exit(ERR_MUNOTALLSEC); + } + if (-1 == shmctl(shmid, IPC_STAT, &shm_buf)) + { + save_errno = errno; + ISSUE_REPLPOOLINST(save_errno, shmid, instfilename, "shmctl(IPC_STAT)"); + mupip_exit(ERR_MUNOTALLSEC); + } + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, shmid); + *ipcs_ptr = '\0'; + if (0 == shm_buf.shm_nattch) + { /* No one else attached and no new process can attach (as we hold the ftok and access + * control semaphore on the journal pool) + */ + if (SS_NORMAL != shm_rmid(shmid)) + { + save_errno = errno; + ISSUE_REPLPOOLINST(save_errno, shmid, instfilename, "shmctl(IPC_RMID)"); + mupip_exit(ERR_MUNOTALLSEC); + } else + { + gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename)); + repl_instance.jnlpool_shmid = INVALID_SHMID; + repl_instance.jnlpool_shmid_ctime = 0; + shm_removed = TRUE; + } + } else + { + util_out_print("Replpool segment (id = !UL) for replication instance !AD is in" + " use by another process.", TRUE, shmid, LEN_AND_STR(instfilename)); + gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename)); + } + /* Now, go ahead and release/remove the access control semaphores */ + ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, semid); + *ipcs_ptr = '\0'; + assert(INVALID_SEMID != repl_instance.jnlpool_semid); + if (SS_NORMAL == mu_replpool_release_sem(&repl_instance, JNLPOOL_SEGMENT, shm_removed)) + { + if (INVALID_SEMID == repl_instance.jnlpool_semid) + { /* Successfully removed the semaphore */ + assert(0 == repl_instance.jnlpool_semid_ctime); + if (!jnlpool_sem_created) + { + gtm_putmsg(VARLSTCNT(9) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), + LEN_AND_STR(instfilename), ERR_SEMREMOVED, 1, semid); + } + repl_instance.crash = FALSE; /* No more semaphore IDs. Reset crash bit */ + } + } else + { /* REPLACCESSSEM is issued from within mu_replpool_release_sem */ + assert(FALSE); + mupip_exit(ERR_MUNOTALLSEC); + } + assert(shm_removed || (INVALID_SEMID != repl_instance.jnlpool_semid)); + assert(!shm_removed || (INVALID_SEMID == repl_instance.jnlpool_semid)); + repl_inst_write(instfilename, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr)); + } else + { /* User did not request to rundown the journal pool as well. So, just decrement the counter + * semaphore. We've already released the access control semaphore. + */ + if (SS_NORMAL != decr_sem(SOURCE, SRC_SERV_COUNT_SEM)) + { + save_errno = errno; + ISSUE_REPLPOOLINST(save_errno, shmid, instfilename, "semop()"); + mupip_exit(ERR_MUNOTALLSEC); + } + } + if (!ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, FALSE)) + { /* CRITSEMFAIL is issued in case of an error */ + assert(FALSE); + mupip_exit(ERR_MUNOTALLSEC); } } } else { + argumentless_rundown = TRUE; /* Both "mu_rndwn_all" and "mu_rndwn_sem_all" do POPEN which opens an input stream (of type "FILE *"). - * We have noticed that on HPUX, a call to "fflush(NULL)" (done inside gtm_putmsg which is called from + * We have noticed that on HPUX, a call to "fflush NULL" (done inside gtm_putmsg which is called from * the above two functions at various places) causes unread (but buffered) data from the input stream * to be cleared/consumed resulting in incomplete processing of the input list of ipcs. To avoid this - * we set this global variable. That causes gtm_putmsg to skip the fflush(NULL). We dont have an issue + * we set this global variable. That causes gtm_putmsg to skip the fflush NULL. We dont have an issue * with out-of-order mixing of stdout and stderr streams (like is there with replication server logfiles) * and so it is okay for this global variable to be set to TRUE for the entire lifetime of the argumentless * rundown command. See . diff --git a/sr_unix/mupip_set_file.c b/sr_unix/mupip_set_file.c index 45c64c7..0373696 100644 --- a/sr_unix/mupip_set_file.c +++ b/sr_unix/mupip_set_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,6 +58,7 @@ #include "desired_db_format_set.h" #include "gtmmsg.h" /* for gtm_putmsg prototype */ #include "gtmcrypt.h" +#include "anticipatory_freeze.h" GBLREF tp_region *grlist; GBLREF gd_region *gv_cur_region; @@ -83,6 +84,7 @@ error_def(ERR_WCWRNNOTCHG); #define MAX_ACC_METH_LEN 2 #define MAX_DB_VER_LEN 2 +#define MIN_MAX_KEY_SZ 3 #define DO_CLNUP_AND_SET_EXIT_STAT(EXIT_STAT, EXIT_WRN_ERR_MASK) \ { \ @@ -91,6 +93,13 @@ error_def(ERR_WCWRNNOTCHG); mu_gv_cur_reg_free(); \ } +#define CLOSE_AND_RETURN \ +{ \ + CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */ \ + db_ipcs_reset(gv_cur_region); \ + return (int4)ERR_WCWRNNOTCHG; \ +} + int4 mupip_set_file(int db_fn_len, char *db_fn) { bool got_standalone; @@ -101,8 +110,12 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) int4 status; int4 status1; int glbl_buff_status, defer_status, rsrvd_bytes_status, - extn_count_status, lock_space_status, disk_wait_status; - int4 new_disk_wait, new_cache_size, new_extn_count, new_lock_space, reserved_bytes, defer_time; + extn_count_status, lock_space_status, disk_wait_status, + inst_freeze_on_error_status, qdbrundown_status, mutex_space_status; + int4 new_disk_wait, new_cache_size, new_extn_count, new_lock_space, reserved_bytes, defer_time, + new_mutex_space; + int key_size_status, rec_size_status; + int4 new_key_size, new_rec_size; sgmnt_data_ptr_t csd; tp_region *rptr, single; enum db_acc_method access, access_new; @@ -111,13 +124,19 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) char *errptr, *command = "MUPIP SET VERSION"; int save_errno; int rc; - ZOS_ONLY(int realfiletag;) + ZOS_ONLY(int realfiletag;) + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; exit_stat = EXIT_NRM; defer_status = cli_present("DEFER_TIME"); if (defer_status) need_standalone = TRUE; - bypass_partial_recov = cli_present("PARTIAL_RECOV_BYPASS") == CLI_PRESENT; + /* If the user requested MUPIP SET -PARTIAL_RECOV_BYPASS, then skip the check in grab_crit, which triggers an rts_error, as + * this is one of the ways of turning off the file_corrupt flag in the file header + */ + TREF(skip_file_corrupt_check) = bypass_partial_recov = cli_present("PARTIAL_RECOV_BYPASS") == CLI_PRESENT; if (bypass_partial_recov) need_standalone = TRUE; if (disk_wait_status = cli_present("WAIT_DISK")) @@ -205,6 +224,28 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) } need_standalone = TRUE; } + if (mutex_space_status = cli_present("MUTEX_SLOTS")) + { + if (cli_get_int("MUTEX_SLOTS", &new_mutex_space)) + { + if (new_mutex_space > MAX_CRIT_ENTRY) + { + util_out_print("!UL too large, maximum number of mutex slots allowed is !UL", TRUE, + new_mutex_space, MAX_CRIT_ENTRY); + return (int4)ERR_WCWRNNOTCHG; + } else if (new_mutex_space < MIN_CRIT_ENTRY) + { + util_out_print("!UL too small, minimum number of mutex slots allowed is !UL", TRUE, + new_mutex_space, MIN_CRIT_ENTRY); + return (int4)ERR_WCWRNNOTCHG; + } + } else + { + util_out_print("Error getting MUTEX_SPACE qualifier value", TRUE); + return (int4)ERR_WCWRNNOTCHG; + } + need_standalone = TRUE; + } if (rsrvd_bytes_status = cli_present("RESERVED_BYTES")) { if (!cli_get_int("RESERVED_BYTES", &reserved_bytes)) @@ -228,6 +269,24 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) } else access = n_dba; /* really want to keep current method, which has not yet been read */ + if (key_size_status = cli_present("KEY_SIZE")) + { + if (!cli_get_int("KEY_SIZE", &new_key_size)) + { + util_out_print("Error getting KEY_SIZE qualifier value", TRUE); + return (int4)ERR_WCWRNNOTCHG; + } + need_standalone = TRUE; + } + if (rec_size_status = cli_present("RECORD_SIZE")) + { + if (!cli_get_int("RECORD_SIZE", &new_rec_size)) + { + util_out_print("Error getting RECORD_SIZE qualifier value", TRUE); + return (int4)ERR_WCWRNNOTCHG; + } + need_standalone = TRUE; + } if (cli_present("VERSION")) { assert(!need_standalone); @@ -235,12 +294,14 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) cli_strupper(ver_spec); if (0 == memcmp(ver_spec, "V4", ver_spec_len)) desired_dbver = GDSV4; - else if (0 == memcmp(ver_spec, "V5", ver_spec_len)) - desired_dbver = GDSV5; + else if (0 == memcmp(ver_spec, "V6", ver_spec_len)) + desired_dbver = GDSV6; else GTMASSERT; /* CLI should prevent us ever getting here */ } else desired_dbver = GDSVLAST; /* really want to keep version, which has not yet been read */ + inst_freeze_on_error_status = cli_present("INST_FREEZE_ON_ERROR"); + qdbrundown_status = cli_present("QDBRUNDOWN"); if (region) rptr = grlist; else @@ -321,10 +382,28 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) if (GDSVLAST != desired_dbver) util_out_print("Database file !AD now has desired DB format !AD", TRUE, fn_len, fn, LEN_AND_STR(gtm_dbversion_table[cs_data->desired_db_format])); + if (CLI_NEGATED == inst_freeze_on_error_status) + { + cs_data->freeze_on_fail = FALSE; + util_out_print("Database file !AD now has inst freeze on fail flag set to FALSE", + TRUE, fn_len, fn); + } + else if (CLI_PRESENT == inst_freeze_on_error_status) + { + cs_data->freeze_on_fail = TRUE; + util_out_print("Database file !AD now has inst freeze on fail flag set to TRUE", + TRUE, fn_len, fn); + } + if (qdbrundown_status) + { + cs_data->mumps_can_bypass = CLI_PRESENT == qdbrundown_status; + util_out_print("Database file !AD now has quick database rundown flag set to !AD", TRUE, + fn_len, fn, 5, (cs_data->mumps_can_bypass ? " TRUE" : "FALSE")); + } } else exit_stat |= status; rel_crit(gv_cur_region); - gds_rundown(); + UNIX_ONLY(exit_stat |=)gds_rundown(); } else { /* Following part needs standalone access */ assert(GDSVLAST == desired_dbver); @@ -370,6 +449,53 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) } csd->reserved_bytes = reserved_bytes; } + if (key_size_status) + { + if (MAX_KEY_SZ < new_key_size) + { /* bigger than 1023 not supported */ + util_out_print("!UL too large, highest maximum key size allowed is !UL", TRUE, + new_key_size, MAX_KEY_SZ); + CLOSE_AND_RETURN; + } else if (MIN_MAX_KEY_SZ > new_key_size) + { /* less than 3 not supported */ + util_out_print("!UL too small, lowest maximum key size allowed is !UL", TRUE, + new_key_size, MIN_MAX_KEY_SZ); + CLOSE_AND_RETURN; + } else if (csd->blk_size < (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + new_key_size + SIZEOF(block_id) + + BSTAR_REC_SIZE + csd->reserved_bytes)) + { /* too big for block */ + util_out_print("!UL too large, lowest maximum key size allowed (given block size) is !UL", + TRUE, new_key_size, csd->blk_size - SIZEOF(blk_hdr) - SIZEOF(rec_hdr) + - SIZEOF(block_id) - csd->reserved_bytes + BSTAR_REC_SIZE); + CLOSE_AND_RETURN; + } else if (csd->max_key_size > new_key_size) + { /* lowering the maximum key size can cause problems if large keys already exist in db */ + util_out_print("!UL smaller than current maximum key size !UL", TRUE, + new_key_size, csd->max_key_size); + CLOSE_AND_RETURN; + } + csd->max_key_size = new_key_size; + } + if (rec_size_status) + { + if (MAX_STRLEN < new_rec_size) + { + util_out_print("!UL too large, highest maximum record size allowed is !UL", TRUE, + new_rec_size, MAX_STRLEN); + CLOSE_AND_RETURN; + } else if (0 > new_key_size) + { + util_out_print("!UL too small, lowest maximum record size allowed is !UL", TRUE, + new_rec_size, 0); + CLOSE_AND_RETURN; + } else if (csd->max_rec_size > new_rec_size) + { + util_out_print("!UL smaller than current maximum record size !UL", TRUE, + new_rec_size, csd->max_rec_size); + CLOSE_AND_RETURN; + } + csd->max_rec_size = new_rec_size; + } access_new = (n_dba == access ? csd->acc_meth : access); /* recalculate; n_dba is a proxy for no change */ change_fhead_timer("FLUSH_TIME", csd->flush_time, @@ -406,6 +532,10 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) csd->extension_size = (uint4)new_extn_count; if (lock_space_status) csd->lock_space_size = (uint4)new_lock_space * OS_PAGELET_SIZE; + if (mutex_space_status) + NUM_CRIT_ENTRY(csd) = new_mutex_space; + if (qdbrundown_status) + csd->mumps_can_bypass = CLI_PRESENT == qdbrundown_status; if (bypass_partial_recov) { csd->file_corrupt = FALSE; @@ -466,7 +596,11 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) continue; } } - LSEEKWRITE(fd, 0, csd, SIZEOF(sgmnt_data), status); + if (CLI_NEGATED == inst_freeze_on_error_status) + csd->freeze_on_fail = FALSE; + else if (CLI_PRESENT == inst_freeze_on_error_status) + csd->freeze_on_fail = TRUE; + DB_LSEEKWRITE(NULL, NULL, fd, 0, csd, SIZEOF(sgmnt_data), status); if (0 != status) { save_errno = errno; @@ -487,15 +621,33 @@ int4 mupip_set_file(int db_fn_len, char *db_fn) if (rsrvd_bytes_status) util_out_print("Database file !AD now has !UL reserved bytes", TRUE, fn_len, fn, csd->reserved_bytes); + if (key_size_status) + util_out_print("Database file !AD now has maximum key size !UL", + TRUE, fn_len, fn, csd->max_key_size); + if (rec_size_status) + util_out_print("Database file !AD now has maximum record size !UL", + TRUE, fn_len, fn, csd->max_rec_size); if (extn_count_status) util_out_print("Database file !AD now has extension count !UL", TRUE, fn_len, fn, csd->extension_size); if (lock_space_status) util_out_print("Database file !AD now has lock space !UL pages", TRUE, fn_len, fn, csd->lock_space_size/OS_PAGELET_SIZE); + if (mutex_space_status) + util_out_print("Database file !AD now has !UL mutex queue slots", + TRUE, fn_len, fn, NUM_CRIT_ENTRY(csd)); + if (qdbrundown_status) + util_out_print("Database file !AD now has quick database rundown flag set to !AD", TRUE, + fn_len, fn, 5, (csd->mumps_can_bypass ? " TRUE" : "FALSE")); if (disk_wait_status) util_out_print("Database file !AD now has wait disk set to !UL seconds", TRUE, fn_len, fn, csd->wait_disk_space); + if (CLI_NEGATED == inst_freeze_on_error_status) + util_out_print("Database file !AD now has inst freeze on fail flag set to FALSE", + TRUE, fn_len, fn); + else if (CLI_PRESENT == inst_freeze_on_error_status) + util_out_print("Database file !AD now has inst freeze on fail flag set to TRUE", + TRUE, fn_len, fn); db_ipcs_reset(gv_cur_region); } /* end of else part if (!need_standalone) */ mu_gv_cur_reg_free(); diff --git a/sr_unix/mupip_set_jnlfile.c b/sr_unix/mupip_set_jnlfile.c index 79bd863..910743b 100644 --- a/sr_unix/mupip_set_jnlfile.c +++ b/sr_unix/mupip_set_jnlfile.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,6 +38,7 @@ #include "util.h" #include "mu_rndwn_file.h" #include "db_ipcs_reset.h" +#include "anticipatory_freeze.h" GBLREF gd_region *gv_cur_region; GBLREF boolean_t need_no_standalone; @@ -87,7 +88,7 @@ int4 mupip_set_jnlfile(char *jnl_fname, int jnl_fn_len) header = (jnl_file_header *)hdr_buffer; if (SS_NORMAL != (status = mupip_set_jnlfile_aux(header, jnl_fname))) return status; - LSEEKWRITE(jnl_fd, 0, (sm_uc_ptr_t)hdr_buffer, SIZEOF(hdr_buffer), status); + JNL_LSEEKWRITE(NULL, NULL, jnl_fd, 0, (sm_uc_ptr_t)hdr_buffer, SIZEOF(hdr_buffer), status); if (0 != status) { save_no = errno; diff --git a/sr_unix/mur_cre_file_extfmt.c b/sr_unix/mur_cre_file_extfmt.c index 210a0f7..518f5fc 100644 --- a/sr_unix/mur_cre_file_extfmt.c +++ b/sr_unix/mur_cre_file_extfmt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2003, 2011 Fidelity Information Services, Inc * + * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -95,7 +95,7 @@ int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat) while (DOT != *ptr) /* we know journal file name alway has a DOT */ ptr--; base_len = (int)(ptr - (char *)&jctl->jnl_fn[0]); - file_info = murgbl.file_info[recstat] = (void *)malloc(SIZEOF(fi_type)); + file_info = (void *)malloc(SIZEOF(fi_type)); if (0 == mur_options.extr_fn_len[recstat]) { mur_options.extr_fn[recstat] = malloc(MAX_FN_LEN); @@ -107,6 +107,7 @@ int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat) } file_info->fn_len = mur_options.extr_fn_len[recstat]; file_info->fn = mur_options.extr_fn[recstat]; + murgbl.file_info[recstat] = file_info; if (RENAME_FAILED == rename_file_if_exists(file_info->fn, file_info->fn_len, rename_fn, &rename_fn_len, &status)) return status; op_pars.mvtype = MV_STR; diff --git a/sr_unix/mutex.c b/sr_unix/mutex.c index 916a391..53421d0 100644 --- a/sr_unix/mutex.c +++ b/sr_unix/mutex.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -53,6 +53,7 @@ #include "mutex_deadlock_check.h" #include "gt_timer.h" #include "gtmio.h" +#include "gtm_c_stack_trace.h" #ifdef DEBUG #include "wbox_test_init.h" #include "repl_msg.h" /* needed by gtmsource.h */ @@ -64,7 +65,7 @@ #ifdef MUTEX_MSEM_WAKE #define MUTEX_MAX_HEARTBEAT_WAIT 2 /* so that total wait for both select and msem wait will be the same */ -#define MUTEX_LCKALERT_PERIOD 8 +#define MUTEX_LCKALERT_PERIOD 4 #endif /* The following CAREFUL_* macros invoke the corresponding * macros except in the case csa->hdr is NULL. @@ -79,7 +80,7 @@ assert((NULL != lcl_csd) \ || (CSA == &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs)); \ if (NULL != lcl_csd) \ - SET_TRACEABLE_VAR(lcl_csd->wc_blocked, TRUE); \ + SET_TRACEABLE_VAR(CSA->nl->wc_blocked, TRUE); \ } #define CAREFUL_BG_TRACE_PRO_ANY(CSA, EVENT) \ @@ -94,6 +95,7 @@ } GBLREF pid_t process_id; +GBLREF int process_exiting; GBLREF uint4 image_count; GBLREF int num_additional_processors; #ifdef MUTEX_MSEM_WAKE @@ -131,6 +133,7 @@ void mutex_salvage(gd_region *reg); error_def(ERR_MUTEXERR); error_def(ERR_MUTEXFRCDTERM); error_def(ERR_MUTEXLCKALERT); +error_def(ERR_ORLBKINPROG); error_def(ERR_TEXT); error_def(ERR_WCBLOCKED); @@ -169,6 +172,8 @@ error_def(ERR_WCBLOCKED); * --------------------------------- * | crash count | * --------------------------------- + * | stuckexec | <-UNIX only + * -------------------------------- * | # of que slots | * -------------------------------- * |_ fl waiting process que head _| @@ -200,7 +205,7 @@ error_def(ERR_WCBLOCKED); * ^Note: only one entry at a time (at the head of the * waiting process queue) will ever use "super_crit". * CCP is used in VMS only - 03/11/98 - * 07-31-2002 se: super-crit is not used at all anymore. Comments are left for historical purposes. + * 07-31-2002 se: super-crit is not used at all anymore. Comments are left for historical purposes. * * Fields may be interspersed with fillers for alignment purposes. */ @@ -245,6 +250,7 @@ static void clean_initialize(mutex_struct_ptr_t addr, int n, bool crash) RTS_ERROR_TEXT("Interlock instruction failure in mutex initialize")); } SET_LATCH_GLOBAL(&addr->semaphore, LOCK_AVAILABLE); + SET_LATCH_GLOBAL((global_latch_t *)&addr->stuckexec, LOCK_AVAILABLE); if (!crash) { SET_LATCH(&addr->crashcnt, 0); @@ -298,7 +304,7 @@ static void crash_initialize(mutex_struct_ptr_t addr, int n, bool crash) } while (TRUE); } -static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_lock_type) +static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_lock_type, sgmnt_addrs *csa) { enum cdb_sc status; boolean_t wakeup_status; @@ -315,6 +321,7 @@ static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_ int timeout_intr_slpcnt; long timeout_val; # endif + # ifdef DEBUG if (gtm_white_box_test_case_enabled && (WBTEST_SENDTO_EPERM == gtm_white_box_test_case_number)) @@ -369,7 +376,6 @@ static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_ } else rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex wake msem"), errno); - } /* wakeup_status is set to true, if I was able to lock...somebody woke me up; * wakeup_status is set to false, if I timed out and should go to recovery. @@ -459,7 +465,7 @@ static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_ if (MUTEX_LOCK_WRITE == mutex_lock_type) return (cdb_sc_normal); } else - mutex_deadlock_check(addr); /* Timed out: See if any deadlocks and fix if detected */ + mutex_deadlock_check(addr, csa); /* Timed out: See if any deadlocks and fix if detected */ status = mutex_wakeup(addr); /* Timed out or reader. In case * of reader this causes * accelerated wakeup of readers @@ -524,10 +530,9 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type) { free_slot = (mutex_que_entry_ptr_t)REMQHI((que_head_ptr_t)&addr->freehead); # ifdef MUTEX_MSEM_WAKE - msem_slot = free_slot; + msem_slot = free_slot; # endif - if ((mutex_que_entry_ptr_t)NULL != free_slot && - (mutex_que_entry_ptr_t)INTERLOCK_FAIL != free_slot) + if (!process_exiting && (NULL != free_slot) && (mutex_que_entry_ptr_t)INTERLOCK_FAIL != free_slot) { free_slot->pid = process_id; free_slot->mutex_wake_instance = mutex_expected_wake_instance; @@ -571,14 +576,23 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type) { MUTEX_DPRINT3("%d: Inserted %d into wait queue\n", process_id, free_slot->pid); - return (mutex_long_sleep(addr, mutex_lock_type)); + return (mutex_long_sleep(addr, mutex_lock_type, csa)); } } while (--queue_retry_counter_insq); if (!(--quant_retry_counter_insq)) return (cdb_sc_dbccerr); /* Too many failures */ rel_quant(); } while (quant_retry_counter_insq); - } else if ((mutex_que_entry_ptr_t)NULL == free_slot) + continue; + } + if ((mutex_que_entry_ptr_t)INTERLOCK_FAIL == free_slot) + { + /* secondary interlock failed on an attempt to + * remove an entry from the free queue */ + redo_cntr = 0; + continue; + } + if ((mutex_que_entry_ptr_t)NULL == free_slot) { /* Record queue full event in db file header if applicable. * Take care not to do it for jnlpool which has no concept of a db cache. @@ -586,36 +600,31 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type) */ CAREFUL_BG_TRACE_PRO_ANY(csa, mutex_queue_full); MUTEX_DPRINT2("%d: Free Queue full\n", process_id); - /* Wait a second, then try again */ - MICROSEC_SLEEP(ONE_MILLION - 1); - if (++redo_cntr < MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR) - break; /* - * 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 return cdb_sc_normal which in - * turn causes another spin-loop initiation (or - * recovery when implemented). - * The objective of mutex_sleep is achieved - * (partially) in that sleep is done, though - * queueing isn't. - */ - return (cdb_sc_normal); + * 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 return cdb_sc_normal which in + * turn causes another spin-loop initiation (or + * recovery when implemented). + * The objective of mutex_sleep is achieved + * (partially) in that sleep is done, though + * queueing isn't. + */ } else - { - /* secondary interlock failed on an attempt to - * remove an entry from the free queue */ - redo_cntr = 0; - } + assert(process_exiting); /* timers might be off, but this adds CPU load at an awkward time */ + MICROSEC_SLEEP(ONE_MILLION - 1); /* Wait a second, then try again */ + mutex_deadlock_check(addr, csa); + if (++redo_cntr < MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR) + break; + return (cdb_sc_normal); } while (--queue_retry_counter_remq); if (redo_cntr) quant_retry_counter_remq = QUANT_RETRY + 1; else rel_quant(); } while (--quant_retry_counter_remq); - return (cdb_sc_dbccerr); } @@ -712,11 +721,9 @@ static enum cdb_sc mutex_wakeup(mutex_struct_ptr_t addr) else rel_quant(); } while (quant_retry_counter_remq); - return (cdb_sc_dbccerr); /* This will never get executed, added to make compiler happy */ } - void gtm_mutex_init(gd_region *reg, int n, bool crash) { if (!crash) @@ -726,7 +733,6 @@ void gtm_mutex_init(gd_region *reg, int n, bool crash) return; } - static enum cdb_sc write_lock_spin(gd_region *reg, mutex_spin_parms_ptr_t mutex_spin_parms, int crash_count, @@ -753,6 +759,7 @@ static enum cdb_sc write_lock_spin(gd_region *reg, return (cdb_sc_critreset); if (GET_SWAPLOCK(&addr->semaphore)) { + csa->critical->crit_cycle++; MUTEX_DPRINT3("%d: Write %sACQUIRED\n", process_id, (MUTEX_LOCK_WRITE == mutex_lock_type) ? "" : "IMMEDIATE "); MUTEX_TEST_SIGNAL_HERE("WRTLCK NOW CRIT\n", FALSE); @@ -793,17 +800,16 @@ static enum cdb_sc write_lock_spin(gd_region *reg, static enum cdb_sc mutex_lock(gd_region *reg, mutex_spin_parms_ptr_t mutex_spin_parms, int crash_count, - int max_lock_attempts, mutex_lock_t mutex_lock_type) { - int lock_attempts; - sgmnt_addrs *csa; + boolean_t try_recovery; enum cdb_sc status; - boolean_t alert; -# ifdef MUTEX_MSEM_WAKE - uint4 alert_heartbeat_counter = 0; -# endif - uint4 in_crit_pid; + int lock_attempts; + latch_t local_crit_cycle; + pid_t in_crit_pid; + sgmnt_addrs *csa; + time_t curr_time; + uint4 curr_time_uint4, next_alert_uint4; csa = &FILE_INFO(reg)->s_addrs; /* Check that "mutex_per_process_init" has happened before we try to grab crit and that it was done with our current @@ -811,62 +817,86 @@ static enum cdb_sc mutex_lock(gd_region *reg, * 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); + MUTEX_TRACE_CNTR((MUTEX_LOCK_WRITE == mutex_lock_type) ? mutex_trc_lockw : mutex_trc_lockwim); optimistic_attempts = 0; lock_attempts = 0; - alert = FALSE; + 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 */ do { in_crit_pid = csa->nl->in_crit; - if (MUTEX_LOCK_WRITE == mutex_lock_type) - { - MUTEX_TRACE_CNTR(mutex_trc_w_atmpts); - /* If we are ONLINE ROLLBACK and a prior ONLINE ROLLBACK was killed, salvage the lock immediately */ - alert = alert | (jgbl.onlnrlbk && in_crit_pid && (in_crit_pid == csa->nl->onln_rlbk_pid)); - status = write_lock_spin(reg, mutex_spin_parms, crash_count, alert, mutex_lock_type); - } else - { - assert(MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type); - return (write_lock_spin(reg, mutex_spin_parms, crash_count, FALSE, mutex_lock_type)); - } - if (cdb_sc_normal == status || cdb_sc_critreset == status) + lock_attempts++; + MUTEX_TRACE_CNTR(mutex_trc_w_atmpts); + status = write_lock_spin(reg, mutex_spin_parms, crash_count, try_recovery, mutex_lock_type); + if ((cdb_sc_normal == status) || (MUTEX_LOCK_WRITE_IMMEDIATE == mutex_lock_type) || (cdb_sc_critreset == status)) return (status); + try_recovery = FALSE; /* only try recovery once per MUTEXLCKALERT */ assert(cdb_sc_nolock == status); -# ifdef MUTEX_MSEM_WAKE - if (0 == alert_heartbeat_counter) - alert_heartbeat_counter = heartbeat_counter + MUTEX_LCKALERT_PERIOD; - alert = (heartbeat_counter >= alert_heartbeat_counter); -# else - alert = (lock_attempts >= max_lock_attempts); -# endif - ++lock_attempts; - if (alert && in_crit_pid && (in_crit_pid != csa->nl->onln_rlbk_pid)) - { /* We've waited long enough. So, issue a message in the syslog. But, we do this only if the holding PID - * is NOT online rollback because the latter (which hold crit on database and journal pool for the entire - * duration) can take arbitrary time to complete and issuing MUTEXLCKALERT frequently in such cases seems - * to add no value. - */ - send_msg(VARLSTCNT(5) ERR_MUTEXLCKALERT, 3, DB_LEN_STR(reg), in_crit_pid); /* Alert the admin */ - lock_attempts = 0; -# ifdef MUTEX_MSEM_WAKE - alert_heartbeat_counter = 0; -# endif + 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 (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 */ + 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)) + { /* 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) + { /* 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); + send_msg(VARLSTCNT(6) ERR_MUTEXLCKALERT, 4, DB_LEN_STR(reg), in_crit_pid, + csa->critical->crit_cycle); + try_recovery = TRUE; /* set off a salvage */ + continue; /* make sure to act on it soon, likely this process */ + } + /* If the holding PID belongs to online rollback which holds crit on database and + * journal pool for its entire duration, use a different message + */ + send_msg(VARLSTCNT(5) ERR_ORLBKINPROG, 3, csa->nl->onln_rlbk_pid, DB_LEN_STR(reg)); + assert(csa->nl->in_crit == csa->nl->onln_rlbk_pid); + } + } else + { /* nobody home */ + local_crit_cycle = csa->critical->crit_cycle; + try_recovery = TRUE; /* set off a salvage */ + continue; /* make sure to act on it soon, likely this process */ + } + } else + { /* didn't get resource to do the MUTEXLCKALERT and procestuckexec */ + MUTEX_DPRINT2("%d: Could not acquire STUCKEXEC time lock", process_id); + } } + if (0 == local_crit_cycle) + local_crit_cycle = csa->critical->crit_cycle; /* sync first time waiter */ if (cdb_sc_dbccerr == mutex_sleep(csa, mutex_lock_type)) return (cdb_sc_dbccerr); } while (TRUE); } +/* in UNIX calls to the following two entry points should be replaced by appropriate (perhaps macro) calls to mutex_lock */ enum cdb_sc mutex_lockw(gd_region *reg, mutex_spin_parms_ptr_t mutex_spin_parms, int crash_count) { - MUTEX_TRACE_CNTR(mutex_trc_lockw); - return (mutex_lock(reg, mutex_spin_parms, crash_count, MUTEX_MAX_WRITE_LOCK_ATTEMPTS, MUTEX_LOCK_WRITE)); + return (mutex_lock(reg, mutex_spin_parms, crash_count, MUTEX_LOCK_WRITE)); } enum cdb_sc mutex_lockwim(gd_region *reg, mutex_spin_parms_ptr_t mutex_spin_parms, int crash_count) { - MUTEX_TRACE_CNTR(mutex_trc_lockwim); - return (mutex_lock(reg, mutex_spin_parms, crash_count, 0, MUTEX_LOCK_WRITE_IMMEDIATE)); + return (mutex_lock(reg, mutex_spin_parms, crash_count, MUTEX_LOCK_WRITE_IMMEDIATE)); } enum cdb_sc mutex_unlockw(gd_region *reg, int crash_count) @@ -922,10 +952,9 @@ void mutex_salvage(gd_region *reg) pid_t holder_pid, onln_rlbk_pid; boolean_t mutex_salvaged; VMS_ONLY(uint4 holder_imgcnt;) - DCL_THREADGBL_ACCESS; - - SETUP_THREADGBL_ACCESS; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; csa = &FILE_INFO(reg)->s_addrs; if (0 != (holder_pid = csa->critical->semaphore.u.parts.latch_pid)) { @@ -961,7 +990,7 @@ void mutex_salvage(gd_region *reg) if ((NULL != csa->jnl) && (NULL != csa->jnl->jnl_buff) && (csa->jnl->jnl_buff->blocked == holder_pid)) csa->jnl->jnl_buff->blocked = 0; MUTEX_DPRINT3("%d : mutex salvaged, culprit was %d\n", process_id, holder_pid); - } else if (FALSE == TREF(disable_sigcont)) + } else if (!TREF(disable_sigcont)) { /* The process might have been STOPPED (kill -SIGSTOP). Send SIGCONT and nudge the stopped process forward. * However, skip this call in case of SENDTO_EPERM white-box test, because we do not want the intentionally diff --git a/sr_unix/mutex_sock_init.c b/sr_unix/mutex_sock_init.c index 506dd3b..109993e 100644 --- a/sr_unix/mutex_sock_init.c +++ b/sr_unix/mutex_sock_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,7 +40,6 @@ #include "trans_log_name.h" GBLREF uint4 process_id; - GBLREF int mutex_sock_fd; GBLREF struct sockaddr_un mutex_sock_address; GBLREF struct sockaddr_un mutex_wake_this_proc; @@ -48,7 +47,7 @@ GBLREF int mutex_wake_this_proc_len; GBLREF int mutex_wake_this_proc_prefix_len; GBLREF fd_set mutex_wait_on_descs; -static char hex_table[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; +static readonly char hex_table[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; error_def(ERR_MUTEXERR); error_def(ERR_MUTEXRSRCCLNUP); @@ -64,16 +63,17 @@ void mutex_sock_init(void) struct stat mutex_sock_stat_buf; int status; unsigned char pid_str[2 * SIZEOF(pid_t) + 1]; + DEBUG_ONLY(boolean_t existed;) + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (FD_INVALID != mutex_sock_fd) /* Initialization done already */ return; - /* Create the socket used for sending and receiving mutex wake mesgs */ if (FD_INVALID == (mutex_sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0))) - rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex socket create"), errno); - + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, + RTS_ERROR_TEXT("Error with mutex socket create"), errno); memset((char *)&mutex_sock_address, 0, SIZEOF(mutex_sock_address)); - /* Get the socket path */ mutex_sock_dir_lognam.len = SIZEOF(MUTEX_SOCK_DIR) - 1; mutex_sock_dir_lognam.addr = MUTEX_SOCK_DIR; @@ -85,70 +85,79 @@ void mutex_sock_init(void) mutex_sock_path_len = SIZEOF(DEFAULT_MUTEX_SOCK_DIR) - 1; } else mutex_sock_path_len = mutex_sock_dir_transnam.len; - /* If the path doesn't already end with a '/' pad a '/' */ if (mutex_sock_path[mutex_sock_path_len - 1] != '/') { mutex_sock_path[mutex_sock_path_len++] = '/'; mutex_sock_path[mutex_sock_path_len] = '\0'; } - - if ((mutex_sock_path_len + MAX_SOCKFILE_NAME_LEN) > SIZEOF(mutex_sock_address.sun_path)) - rts_error(VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Mutex socket path too long")); - + if ((mutex_sock_path_len + MAX_MUTEX_SOCKFILE_NAME_LEN) > SIZEOF(mutex_sock_address.sun_path)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, + RTS_ERROR_TEXT("Mutex socket path too long")); strcpy(mutex_sock_path + mutex_sock_path_len, MUTEX_SOCK_FILE_PREFIX); mutex_sock_path_len += (SIZEOF(MUTEX_SOCK_FILE_PREFIX) - 1); mutex_wake_this_proc_prefix_len = mutex_sock_path_len; /* Extend mutex_sock_path with pid */ strcpy(mutex_sock_path + mutex_sock_path_len, (char *)pid2ascx(pid_str, process_id)); mutex_sock_path_len += STRLEN((char *)pid_str); - if (mutex_sock_path_len > SIZEOF(mutex_sock_address.sun_path)) - rts_error(VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Mutex socket path too long")); - + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, + RTS_ERROR_TEXT("Mutex socket path too long")); mutex_sock_address.sun_family = AF_UNIX; strcpy(mutex_sock_address.sun_path, mutex_sock_path); mutex_sock_len = SIZEOF(mutex_sock_address.sun_family) + mutex_sock_path_len + 1; /* Include NULL byte in length */ - - if (UNLINK(mutex_sock_address.sun_path) == -1) /* in case it was left from last time */ + DEBUG_ONLY(if (!TREF(gtm_usesecshr))) { - if (errno != ENOENT) + status = UNLINK(mutex_sock_address.sun_path); /* in case it was left from last time */ + save_errno = (-1 == status) ? errno : 0; + } DEBUG_ONLY(else save_errno = -1); /* Non-zero and non-ENOENT value so uses gtmsecshr */ + if (0 != save_errno) + { /* Separate checks for unlink success vs no file removal needed */ + if (ENOENT != save_errno) { - if ((status = send_mesg2gtmsecshr(REMOVE_FILE, (unsigned int)-1, mutex_sock_address.sun_path, - mutex_sock_path_len + 1)) == 0) - send_msg(VARLSTCNT(8) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path, - ERR_TEXT, 2, LEN_AND_LIT("Resource removed by gtmsecshr")); - else if (status != ENOENT) /* don't bother if somebody removed the file before gtmsecshr got to it */ - rts_error(VARLSTCNT(10) ERR_MUTEXERR, 0, ERR_TEXT, 2, - LEN_AND_LIT("gtmsecshr failed to remove leftover mutex resource"), +# ifdef DEBUG + /* If using gtm_usesecshr, can get a log of bogus MUTEXRSRCCLNUP messages so see if the socket + * actually exists or not so can supress the message if not (but still push it through secshr). + */ + if (TREF(gtm_usesecshr)) + { + STAT_FILE(mutex_sock_address.sun_path, &mutex_sock_stat_buf, status); + existed = (0 == status) ? TRUE : FALSE; + } else + existed = TRUE; /* If no gtm_usesecshr, wouldn't be here unless existed */ +# endif + if (0 == (status = send_mesg2gtmsecshr(REMOVE_FILE, (unsigned int)-1, mutex_sock_address.sun_path, + mutex_sock_path_len + 1))) + { + DEBUG_ONLY(if (existed)) /* Avoid mesg unless socket existed */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, + mutex_sock_path, ERR_TEXT, 2, LEN_AND_LIT("Resource removed by gtmsecshr")); + } else if (ENOENT != status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_MUTEXERR, 0, ERR_TEXT, 2, + LEN_AND_LIT("gtmsecshr failed to remove leftover mutex resource"), ERR_TEXT, 2, mutex_sock_path_len, mutex_sock_path); + /* else don't bother if somebody removed the file before gtmsecshr got to it */ } - } else /* unlink succeeded */ - send_msg(VARLSTCNT(4) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path); - - if (BIND(mutex_sock_fd, (struct sockaddr *)&mutex_sock_address, mutex_sock_len) < 0) - rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, - RTS_ERROR_TEXT("Error with mutex socket bind"), - errno); - + } else /* unlink succeeded - socket must have existed - now cleaned up */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path); + if (0 > BIND(mutex_sock_fd, (struct sockaddr *)&mutex_sock_address, mutex_sock_len)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, + RTS_ERROR_TEXT("Error with mutex socket bind"), errno); /* Set the socket permissions to override any umask settings. * Allow owner and group read and write access. */ STAT_FILE(mutex_sock_address.sun_path, &mutex_sock_stat_buf, status); if (-1 == status) - rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex socket stat"), errno); - mutex_sock_stat_buf.st_mode |= (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (-1 == CHMOD(mutex_sock_address.sun_path, mutex_sock_stat_buf.st_mode)) - rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex socket chmod"), errno); - /* Clear the descriptor set used to sense wake up message */ FD_ZERO(&mutex_wait_on_descs); - /* To make mutex_wake_proc faster, pre-initialize portions of * mutex_wake_this_proc which are invariant of the pid to be woken up. */ @@ -159,9 +168,7 @@ void mutex_sock_init(void) } unsigned char *pid2ascx(unsigned char *pid_str, pid_t pid) -{ - /* pid_str should accommodate atleast 2*SIZEOF(pid_t) + 1 characters */ - +{ /* pid_str should accommodate atleast 2*SIZEOF(pid_t) + 1 characters */ register unsigned char *cp; cp = &pid_str[2*SIZEOF(pid_t)]; diff --git a/sr_unix/mutexsp.h b/sr_unix/mutexsp.h index 12f1eba..7e3dbe8 100644 --- a/sr_unix/mutexsp.h +++ b/sr_unix/mutexsp.h @@ -37,6 +37,7 @@ #define MUTEX_SOCK_DIR GTM_TMP_ENV #define DEFAULT_MUTEX_SOCK_DIR DEFAULT_GTM_TMP #define MUTEX_SOCK_FILE_PREFIX "gtm_mutex" +#define MAX_MUTEX_SOCKFILE_NAME_LEN (SIZEOF(MUTEX_SOCK_FILE_PREFIX) + MAX_DIGITS_IN_INT) #define BIN_TOGGLE(x) ((x) ? 0 : 1) diff --git a/sr_unix/obj_code.c b/sr_unix/obj_code.c index 2de6411..78b8e02 100644 --- a/sr_unix/obj_code.c +++ b/sr_unix/obj_code.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -72,17 +72,17 @@ GBLREF spdesc stringpool; * * +---------------+ * | rhead | > - R/O - retain - * +---------------+ - * | generated | \ - * | code | \ - * + - - - - - - - + | - * | line num tbl | |- R/O releasable - * + - - - - - - - + / - * | lit text pool | / - * +---------------+ - * | lit mval tbl | \ + * +---------------+ Alternative layout if compiled with GTM_DYNAMIC_LITERALS: + * | generated | \ \ + * | code | \ \ + * + - - - - - - - + | | + * | line num tbl | |- R/O releasable | + * + - - - - - - - + / |- R/O releasable + * | lit text pool | / | + * +---------------+ / + * | lit mval tbl | \ / * +---------------+ |- R/W releasable - * | variable tbl | / + * | variable tbl | / > - R/W releasable * + - - - - - - - + * | label tbl | > - R/W retain * +---------------+ @@ -93,6 +93,10 @@ GBLREF spdesc stringpool; * * Note in addition to the above layout, a "linkage section" is allocated at run time and is * also releasable. + * + * 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_TEXT); diff --git a/sr_unix/ojchildioset.c b/sr_unix/ojchildioset.c index 3098f36..1c24595 100644 --- a/sr_unix/ojchildioset.c +++ b/sr_unix/ojchildioset.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -27,54 +27,45 @@ #include "gtm_zos_io.h" #endif -GBLREF boolean_t job_try_again; - -#define NULL_DEV_FNAME "/dev/null" /* Null device file name */ -#define OPEN_RSRC_CRUNCH_FAILURE \ - (EDQUOT == errno || ENFILE == errno || ENOMEM == errno || ENOSPC == errno || ETIMEDOUT == errno) +GBLREF int job_errno; +ZOS_ONLY(error_def(ERR_BADTAG);) +error_def(ERR_JOBFAIL); +error_def(ERR_TEXT); /* * --------------------------------------------------------- - * Set up input, output and error file descriptors in + * Set up output and error file descriptors in * a child. * --------------------------------------------------------- */ -bool ojchildioset(job_params_type *jparms) +int ojchildioset(job_params_type *jparms) { - int dup_ret, in_fd, out_fd, err_fd, save_errno; - char fname_buf[1024], buf[1024]; - int rc; + int dup_ret, in_fd, out_fd, err_fd; + char fname_buf[MAX_STDIOE_LEN], buf[MAX_STDIOE_LEN]; + int rc; + joberr_t joberr = joberr_gen; ZOS_ONLY(int realfiletag;) - error_def(ERR_TEXT); - error_def(ERR_JOBFAIL); - ZOS_ONLY(error_def(ERR_BADTAG);) - - /* Redirect input */ +/* + * Redirect input + */ strncpy(fname_buf, jparms->input.addr, jparms->input.len); *(fname_buf + jparms->input.len) = '\0'; OPENFILE(fname_buf, O_RDONLY, in_fd); if (FD_INVALID == in_fd) { - if (OPEN_RSRC_CRUNCH_FAILURE) - job_try_again = TRUE; - else - { - save_errno = errno; - SPRINTF(buf, "Error redirecting stdin (open) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - } - return FALSE; + joberr = joberr_io_stdin_open; + job_errno = errno; + return joberr; } CLOSEFILE(0, rc); FCNTL3(in_fd, F_DUPFD, 0, dup_ret); if (-1 == dup_ret) { - save_errno = errno; - SPRINTF(buf, "Error redirecting stdin (fcntl) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - return FALSE; + joberr = joberr_io_stdin_dup; + job_errno = errno; + return joberr; } #ifdef __MVS__ /* policy tagging because by default input is /dev/null */ @@ -82,6 +73,7 @@ bool ojchildioset(job_params_type *jparms) TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_UNTAGGED); #endif CLOSEFILE_RESET(in_fd, rc); /* resets "in_fd" to FD_INVALID */ + /* * Redirect Output */ @@ -91,17 +83,10 @@ bool ojchildioset(job_params_type *jparms) CREATE_FILE(fname_buf, 0666, out_fd); if (FD_INVALID == out_fd) { - if (OPEN_RSRC_CRUNCH_FAILURE) - job_try_again = TRUE; - else - { - save_errno = errno; - SPRINTF(buf, "Error redirecting stdout (creat) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - } - return FALSE; + joberr = joberr_io_stdout_creat; + job_errno = errno; + return joberr; } - #ifdef __MVS__ /* tagging as ASCII is fine now, that might change in the future for gtm_utf8_mode */ if (-1 == gtm_zos_set_tag(out_fd, TAG_ASCII, TAG_TEXT, TAG_FORCE, &realfiletag)) @@ -112,25 +97,18 @@ bool ojchildioset(job_params_type *jparms) OPENFILE(fname_buf, O_WRONLY, out_fd); if (FD_INVALID == out_fd) { - if (OPEN_RSRC_CRUNCH_FAILURE) - job_try_again = TRUE; - else - { - save_errno = errno; - SPRINTF(buf, "Error redirecting stdout (open) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - } - return FALSE; + joberr = joberr_io_stdout_open; + job_errno = errno; + return joberr; } CLOSEFILE(1, rc); FCNTL3(out_fd, F_DUPFD, 0, dup_ret); if (-1 == dup_ret) { - save_errno = errno; - SPRINTF(buf, "Error redirecting stdout (fcntl) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - return FALSE; + joberr = joberr_io_stdout_dup; + job_errno = errno; + return joberr; } CLOSEFILE_RESET(out_fd, rc); /* resets "out_fd" to FD_INVALID */ /* @@ -142,47 +120,31 @@ bool ojchildioset(job_params_type *jparms) CREATE_FILE(fname_buf, 0666, err_fd); if (FD_INVALID == err_fd) { - if (OPEN_RSRC_CRUNCH_FAILURE) - job_try_again = TRUE; - else - { - save_errno = errno; - SPRINTF(buf, "Error redirecting stderr (creat) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - } - return FALSE; + joberr = joberr_io_stderr_creat; + job_errno = errno; + return joberr; } - #ifdef __MVS__ if (-1 == gtm_zos_set_tag(err_fd, TAG_EBCDIC, TAG_TEXT, TAG_FORCE, &realfiletag)) TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_EBCDIC); #endif CLOSEFILE_RESET(err_fd, rc); /* resets "err_fd" to FD_INVALID */ - OPENFILE(fname_buf, O_WRONLY, err_fd); if (FD_INVALID == err_fd) { - if (OPEN_RSRC_CRUNCH_FAILURE) - job_try_again = TRUE; - else - { - save_errno = errno; - SPRINTF(buf, "Error redirecting stderr (open) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - } - return FALSE; + joberr = joberr_io_stderr_open; + job_errno = errno; + return joberr; } - CLOSEFILE(2, rc); FCNTL3(err_fd, F_DUPFD, 0, dup_ret); if (-1 == dup_ret) { - save_errno = errno; - SPRINTF(buf, "Error redirecting stderr (fcntl) to %s", fname_buf); - gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno); - return FALSE; + joberr = joberr_io_stderr_dup; + job_errno = errno; + return joberr; } CLOSEFILE_RESET(err_fd, rc); /* resets "err_fd" to FD_INVALID */ - return(TRUE); + return 0; } diff --git a/sr_unix/ojparams.c b/sr_unix/ojparams.c index 983624b..4adbd2d 100644 --- a/sr_unix/ojparams.c +++ b/sr_unix/ojparams.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -33,6 +33,7 @@ MSTR_CONST(deferrext, ".mje"); LITREF jp_datatype job_param_datatypes[]; +error_def (ERR_PARFILSPC); /* * ------------------------------------------------ @@ -47,7 +48,6 @@ void ojparams (char *p, job_params_type *job_params) unsigned char ch; int4 status; - error_def (ERR_PARFILSPC); /* Initializations */ job_params->baspri = 0; @@ -60,6 +60,8 @@ void ojparams (char *p, job_params_type *job_params) job_params->logfile.len = 0; job_params->directory.len = 0; job_params->directory.addr = 0; + job_params->cmdline.len = 0; + job_params->cmdline.addr = 0; /* Process parameter list */ while (*p != jp_eol) @@ -69,7 +71,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_default: if (*p != 0) { - job_params->directory.len = *p; + job_params->directory.len = (int)((unsigned char) *p); job_params->directory.addr = (p + 1); } break; @@ -77,7 +79,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_error: if (*p != 0) { - job_params->error.len = *p; + job_params->error.len = (int)((unsigned char) *p); job_params->error.addr = (p + 1); } break; @@ -85,7 +87,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_gbldir: if (*p != 0) { - job_params->gbldir.len = *p; + job_params->gbldir.len = (int)((unsigned char) *p); job_params->gbldir.addr = (p + 1); } break; @@ -93,7 +95,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_input: if (*p != 0) { - job_params->input.len = *p; + job_params->input.len = (int)((unsigned char) *p); job_params->input.addr = p + 1; } break; @@ -101,7 +103,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_logfile: if (*p != 0) { - job_params->logfile.len = *p; + job_params->logfile.len = (int)((unsigned char) *p); job_params->logfile.addr = p + 1; } break; @@ -109,7 +111,7 @@ void ojparams (char *p, job_params_type *job_params) case jp_output: if (*p != 0) { - job_params->output.len = *p; + job_params->output.len = (int)((unsigned char) *p); job_params->output.addr = p + 1; } break; @@ -121,11 +123,19 @@ void ojparams (char *p, job_params_type *job_params) case jp_startup: if (*p != 0) { - job_params->startup.len = *p; + job_params->startup.len = (int)((unsigned char) *p); job_params->startup.addr = p + 1; } break; + case jp_cmdline: + if(*p != 0) + { + job_params->cmdline.len = (int)((unsigned char) *p); + job_params->cmdline.addr = p + 1; + } + break; + case jp_account: case jp_detached: case jp_image: @@ -146,11 +156,11 @@ void ojparams (char *p, job_params_type *job_params) break; case jpdt_num: - p += sizeof (int4); + p += SIZEOF(int4); break; case jpdt_str: - p += (unsigned)*p + 1; + p += ((int)((unsigned char)*p)) + 1; break; default: GTMASSERT; @@ -170,7 +180,7 @@ void ojparams (char *p, job_params_type *job_params) else if (!(status = ojchkfs (job_params->input.addr, job_params->input.len, TRUE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "INPUT", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "INPUT", job_params->input.len, job_params->input.addr); /* @@ -193,7 +203,7 @@ void ojparams (char *p, job_params_type *job_params) else if (!(status = ojchkfs (job_params->output.addr, job_params->output.len, FALSE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 6, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 6, "OUTPUT", job_params->output.len, job_params->output.addr); /* @@ -216,7 +226,7 @@ void ojparams (char *p, job_params_type *job_params) else if (!(status = ojchkfs (job_params->error.addr, job_params->error.len, FALSE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "ERROR", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "ERROR", job_params->error.len, job_params->error.addr); /* @@ -225,7 +235,7 @@ void ojparams (char *p, job_params_type *job_params) if (job_params->gbldir.len) if (!(status = ojchkfs (job_params->gbldir.addr, job_params->gbldir.len, FALSE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 6, "GBLDIR", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 6, "GBLDIR", job_params->gbldir.len, job_params->gbldir.addr); /* * Startup @@ -233,7 +243,7 @@ void ojparams (char *p, job_params_type *job_params) if (job_params->startup.len) if (!(status = ojchkfs (job_params->startup.addr, job_params->startup.len, TRUE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "STARTUP", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "STARTUP", job_params->startup.len, job_params->startup.addr); /* * Default Directory @@ -241,7 +251,7 @@ void ojparams (char *p, job_params_type *job_params) if (job_params->directory.len) if (!(status = ojchkfs (job_params->directory.addr, job_params->directory.len, FALSE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "DEFAULT", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "DEFAULT", job_params->directory.len, job_params->directory.addr); /* * Logfile @@ -254,7 +264,7 @@ void ojparams (char *p, job_params_type *job_params) else if (!(status = ojchkfs (job_params->logfile.addr, job_params->logfile.len, FALSE))) - rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "LOGFILE", + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "LOGFILE", job_params->logfile.len, job_params->logfile.addr); } diff --git a/sr_unix/ojstartchild.c b/sr_unix/ojstartchild.c index 4154e46..c1b7db1 100644 --- a/sr_unix/ojstartchild.c +++ b/sr_unix/ojstartchild.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -26,6 +26,8 @@ #include "gtm_stdio.h" #include "gtm_stat.h" #include "gtm_string.h" +#include "gtm_limits.h" + #if defined(SYS_ERRLIST_INCLUDE) && !defined(__CYGWIN__) #include SYS_ERRLIST_INCLUDE #endif @@ -34,6 +36,8 @@ #include "error.h" #include #include "io.h" +#include "iormdef.h" +#include "io_params.h" #include "iosp.h" #include "eintr_wrappers.h" #include "compiler.h" @@ -42,31 +46,18 @@ #include "gtm_facility.h" #include "fileinfo.h" #include "gtmio.h" +#include "fork_init.h" -#define MAX_JOB_LEN 8192 /* Arbitrary length maximum used for checking job arguments and parameters */ -#define MAX_PATH 128 /* Maximum file path length */ -#define MAX_LAB_LEN 32 /* Maximum Label string length */ -#define MAX_RTN_LEN 32 /* Maximum Routine string length */ -#define TEMP_BUFF_SIZE 1024 -#define PARM_STRING_SIZE 9 -#define MAX_NUM_LEN 10 /* Maximum length number will be when converted to string */ -#define MAX_JOB_QUALS 12 /* Maximum environ variables set for job qualifiers */ -#define MUMPS_EXE_STR "/mumps" -#define MUMPS_DIRECT_STR "-direct" -#define GTMJ_FMT "gtmj%03d=" -#define PARM_STR "gtmj000=" +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; -static int joberr = joberr_gen; -static boolean_t job_launched = FALSE; +static joberr_t joberr = joberr_gen; +static int pipe_fd; -GBLREF bool jobpid; /* job's output files should have the pid appended to them. */ -GBLREF volatile boolean_t ojtimeout; -GBLREF boolean_t job_try_again; -GBLREF uint4 process_id; -GBLREF boolean_t gtm_pipe_child; #ifndef SYS_ERRLIST_INCLUDE -/* currently either stdio.h or errno.h both of which are included above */ -/* needed by TIMEOUT_ERROR in jobsp.h */ +/* currently either stdio.h or errno.h both of which are included above needed by TIMEOUT_ERROR in jobsp.h */ #if !defined(__sun) && !defined(___MVS__) GBLREF int sys_nerr; #endif @@ -79,15 +70,26 @@ GBLREF int sys_nerr; #endif GBLREF char **environ; +GBLREF char gtm_dist[GTM_PATH_MAX]; #ifdef __osf__ #pragma pointer_size (restore) #endif -error_def(ERR_JOBFAIL); -error_def(ERR_JOBPARTOOLONG); -error_def(ERR_LOGTOOLONG); -error_def(ERR_TEXT); +#define MAX_JOB_LEN 8192 /* Arbitrary length maximum used for checking job arguments and parameters */ +#define MAX_PATH 128 /* Maximum file path length */ +#define MAX_LAB_LEN 32 /* Maximum Label string length */ +#define MAX_RTN_LEN 32 /* Maximum Routine string length */ +#define TEMP_BUFF_SIZE 1024 +#define PARM_STRING_SIZE 9 +#define MAX_NUM_LEN 10 /* Maximum length number will be when converted to string */ +#define MAX_JOB_QUALS 12 /* Maximum environ variables set for job qualifiers */ +#define MUMPS_EXE_STR "/mumps" +#define MUMPS_DIRECT_STR "-direct" +#define GTMJ_FMT "gtmj%03d=" +#define PARM_STR "gtmj000=" +#define JOB_CONTINUE 1 +#define JOB_EXIT 0 #define KILL_N_REAP(PROCESS_ID, SIGNAL, RET_VAL) \ { \ @@ -99,69 +101,137 @@ error_def(ERR_TEXT); } \ } -/* Note that this module uses _exit instead of exit to avoid running the inherited - exit handlers which this mid-level process does not want to run */ +#define FORK_RETRY(PID) \ +{ \ + FORK(PID); /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */ \ + while (-1 == PID) \ + { \ + assertpro(EAGAIN == errno || ENOMEM == errno); \ + usleep(50000); \ + FORK(PID); /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */ \ + } \ +} -/* if we get an error assembling the child environment, - we don't want a rogue child running loose */ +error_def(ERR_JOBFAIL); +error_def(ERR_JOBPARTOOLONG); +error_def(ERR_LOGTOOLONG); +error_def(ERR_TEXT); + +/* Note that this module uses _exit instead of exit to avoid running the inherited exit handlers which this mid-level process does + * not want to run. + */ void job_term_handler(int sig); +static int io_rename(job_params_type *jparms, const int jobid); -static CONDITION_HANDLER(bad_child) +/* 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 + * executed. That condition handler might not be adequate to handle the rts_error happened in the context of middle process. + * Hence middle process is provided with its own condition handler. + */ +static CONDITION_HANDLER(middle_child) { - PRN_ERROR; + int pipe_status; + /* As of now, middle process could encounter rts_error only while setting entryref. Hence the following assert. */ + assert(joberr == joberr_rtn); + DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status); _exit(joberr); } -#define FAILED_TO_LAUNCH 1 +/* Following condition handles the rts_error occurred in the grandchild before doing execv(). Sinec we have not started executing + * M-cmd specified as a part of JOB command, it is enough to print the error and exit. + */ +static CONDITION_HANDLER(grand_child) +{ + PRN_ERROR; + _exit(EXIT_SUCCESS); +} -/* This is to close the window of racing condition where the timeout occurs and actually - * by that time, the middle process had already successfully forked the job +/* This is to close the window of race condition where the timeout occurs and actually by that time, the middle process had already + * successfully forked-off the job. */ -void job_term_handler(int sig){ - if (job_launched) - _exit(0); - else - _exit(FAILED_TO_LAUNCH); +void job_term_handler(int sig) +{ + int ret; + int status; + joberr_t exit_status = joberr_gen; + /* + * ret = 0 - Child is present but not changed the state + * < 0 - Error. No child present. + * > 0 - Child PID. + */ + ret = waitpid(-1, &status, WNOHANG); /* BYPASSOK */ + job_errno = errno; + if (0 == ret) + return; + else if ( 0 > ret) + _exit(exit_status); + else + return; +} + +static int io_rename(job_params_type *jparms, const int jobid) +{ + char path[MAX_STDIOE_LEN]; + + strncpy(path, jparms->output.addr, jparms->output.len); + *(jparms->output.addr + jparms->output.len) = '\0'; + SPRINTF(&path[jparms->output.len], ".%d", jobid); + if (rename(jparms->output.addr, path)) + { + job_errno = errno; + return(joberr_stdout_rename); + } + strncpy(path, jparms->error.addr, jparms->error.len); + *(jparms->error.addr + jparms->error.len) = '\0'; + SPRINTF(&path[jparms->error.len], ".%d", jobid); + if (rename(jparms->error.addr, path)) + { + job_errno = errno; + return(joberr_stderr_rename); + } + return 0; } /* - * --------------------------------------------------------------------------------------------------------------------- - * The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the - * actual Job (J) and exits, culminating the parent's (P) wait. The Job process (J) sets up its env and exexs mumps. + * -------------------------------------------------------------------------------------------------------------------------------- + * The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the actual Job (J) + * and exits, culminating the parent's (P) wait. The Job process (J) sets up its env and execs mumps. * * Arguments * First argument is a pointer to the structure holding Job parameter values. * Second argument is the number of parameters being passed. - * The third boolean argument indicates to the caller if the return from this function was due to an exit from the - * middle process or due to reasons other than that. It is set to true for the latter case of return. - * Fourth argument is the pair of file descriptors [opened by pipe] for the child process (M) to write PID - * of the jobbed off process (J). + * The third boolean argument indicates to the caller if the return from this function was due to an exit from the middle + * process or due to reasons other than that. It is set to true for the latter case of return. + * Fourth argument is the pair of file descriptors [opened by pipe] for the child process (M) to write PID of the jobbed off + * process (J). * * Return: * Exit status of child (that the parent gets by WAITing) in case the return was after an exit from the middle process. - * errno in other cases with the third argument set to TRUE and returned by pointer. + * Errno in other cases with the third argument set to TRUE and returned by pointer. * TIMEOUT_ERROR in case a timeout occured. * Return zero indicates success. - * --------------------------------------------------------------------------------------------------------------------- + * -------------------------------------------------------------------------------------------------------------------------------- */ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[]) { - char cbuff[TEMP_BUFF_SIZE], pbuff[TEMP_BUFF_SIZE]; - char tbuff[MAX_JOB_LEN], tbuff2[MAX_JOB_LEN]; + 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; char *transfer_addr; int4 index, environ_count, string_len, temp; int wait_status, save_errno, kill_ret; - int rc; - bool status; + int rc, dup_ret, in_fd; + int status; pid_t par_pid, child_pid, done_pid; job_parm *jp; rhdtyp *base_addr; struct sigaction act, old_act; int pipe_status, env_len; + int mproc_fds[2]; /* pipe between middle process and grandchild process */ + int decision; #ifdef __osf__ /* These must be O/S-compatible 64-bit pointers for OSF/1. */ @@ -170,115 +240,181 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur #endif char *c1, *c2, **c3; - char *argv[3]; + 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 - job_launched = FALSE; - par_pid = process_id; - if (-1 == (child_pid = fork())) /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */ - { - if (EAGAIN == errno || ENOMEM == errno) - job_try_again = TRUE; - *non_exit_return = TRUE; - return (errno); - } + par_pid = getppid(); + FORK_RETRY(child_pid); if (child_pid == 0) { - /* This is a child process (middle process, M) */ - /* Test out various parameters and setup everything possible for the actual Job (J), so it(J) can - * start off without much hitch. If any error occurs during this, exit with appropriate status so - * the waiting parent can diagnose. + /* This is a child process (middle process, M) + * Test out various parameters and setup everything possible for the actual Job (J), so it(J) can start off without + * much hitch. If any error occurs during this, exit with appropriate status so the waiting parent can diagnose. */ /* 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; - ESTABLISH_RET(bad_child, 0); + job_errno = -1; + pipe_fd = pipe_fds[1]; + ESTABLISH_RET(middle_child, 0); sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = job_term_handler; sigaction(SIGTERM, &act, &old_act); - if (!jobpid) /* if the Job pid need not be appended to the std-in/out/err file names */ + OPEN_PIPE(mproc_fds, pipe_status); + if (-1 == pipe_status) { - joberr = joberr_io; - /* attempt to open output files */ - /* this also redirects stdin/out/err, so any error messages by this process during - * the creation of the Job will get redirected */ - if (!(status = ojchildioset(jparms))) - { - if (job_try_again) - joberr += joberr_tryagain; - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, - LEN_AND_LIT("Failed to set STDIN/OUT/ERR for the job")); - } - } /* else, all the errors during the creation of Job go to the STDOUT/ERR of the parent process */ + joberr = joberr_pipe_mgc; + job_errno = errno; + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(joberr); + } + /* Redirect input before potentially changing the default directory below.*/ + strncpy(fname_buf, jparms->input.addr, jparms->input.len); + *(fname_buf + jparms->input.len) = '\0'; - joberr = joberr_cd; /* pass current directory to child */ - if (jparms->directory.len != 0) + OPENFILE(fname_buf, O_RDONLY, in_fd); + if (FD_INVALID == in_fd) + { + joberr = joberr_io_stdin_open; + job_errno = errno; + return joberr; + } + CLOSEFILE(0, rc); + FCNTL3(in_fd, F_DUPFD, 0, dup_ret); + if (-1 == dup_ret) + { + joberr = joberr_io_stdin_dup; + job_errno = errno; + return joberr; + } +#ifdef __MVS__ + /* policy tagging because by default input is /dev/null */ + if (-1 == gtm_zos_tag_to_policy(in_fd, TAG_UNTAGGED, &realfiletag)) + TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_UNTAGGED); +#endif + CLOSEFILE_RESET(in_fd, rc); /* resets "in_fd" to FD_INVALID */ + if (0 != jparms->directory.len) { /* If directory is specified, change it */ if (jparms->directory.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); - + { + joberr = joberr_cd_toolong; + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(joberr); + } strncpy(pbuff, jparms->directory.addr, jparms->directory.len); *(pbuff + jparms->directory.len) = '\0'; + if (CHDIR(pbuff) != 0) { - if (ETIMEDOUT == errno) /* atleast on AIX */ - joberr += joberr_tryagain; - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, - LEN_AND_LIT("Error changing directory for the Job."),errno); + joberr = joberr_cd; + job_errno = errno; + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(errno), pipe_status); + _exit(joberr); } } + /* attempt to open output files. This also redirects stdin/out/err, so any error messages by this process during the + * creation of the Job will get redirected. + */ + if ((status = ojchildioset(jparms))) + { + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(status); + } + joberr = joberr_rtn; - job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr); - - joberr = joberr_syscall; - if (-1 == setsid()) - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, - LEN_AND_LIT("Error setting session id for the Job."), errno); - - joberr = joberr_frk; - /* clone self and exit */ - if (0 != (child_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr)) { - /* This is still the middle process. */ - if (0 > child_pid) - { - if (EAGAIN == errno || ENOMEM == errno) - joberr += joberr_tryagain; - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, - LEN_AND_LIT("Error forking the Job."), errno); - } else - { - job_launched = TRUE; - - assert(SIZEOF(pid_t) == SIZEOF(child_pid)); - /* write child_pid into pipe to be read by parent process(P) for $ZJOB */ - DOWRITERC(pipe_fds[1], &child_pid, SIZEOF(child_pid), pipe_status); - if (0 != pipe_status) - { - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, - LEN_AND_LIT("Error writing to pipe"), errno); - } - _exit(0); - } + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(joberr); } - /* This is now the grandchild process (actual Job process) -- an orphan as soon as the exit(0) above occurs. */ - /* set up the environment and exec */ + joberr = joberr_sid; + if (-1 == setsid()) + { + job_errno = errno; + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(joberr); + } + /* clone self and exit */ + FORK_RETRY(child_pid); + if (child_pid) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + { + /* This is still the middle process. */ + /* Close the read end of the pipe between middle process and grandchild process. */ + CLOSEFILE_RESET(mproc_fds[0], pipe_status); /* resets "pipe_fds[0]" to FD_INVALID */ + assert(SIZEOF(pid_t) == SIZEOF(child_pid)); + /* if the Job pid need to be appended to the std out/err file names */ + if (jobpid) + { + joberr = io_rename(jparms, child_pid); + if (joberr) + { + /* Inform grandchild that it will have to exit. If pipe operation failed terminate + * the grandchild. + */ + decision = JOB_EXIT; + DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status); + if (pipe_status) + kill(child_pid, SIGTERM); + DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status); + _exit(joberr); + } + } + /* write child_pid into pipe to be read by parent process(P) for $ZJOB */ + DOWRITERC(pipe_fds[1], &child_pid, SIZEOF(child_pid), pipe_status); + /* Failed to send parent new JOBID. Terminate the child and exit middle process. */ + if (pipe_status) + { + /* Inform grandchild that it will have to exit. If pipe operation failed terminate the + * grandchild. + */ + joberr = joberr_pipe_mp; + decision = JOB_EXIT; + DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status); + if (pipe_status) + kill(child_pid, SIGTERM); + _exit(joberr); + } else + { + /* 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); + /* If pipe_status is non-zero i.e. error occurred in pipe operation or total + * SIZEOF(decision) bytes are not written in the pipe. In this case, we let the grandchild + * handle its own fate as we have already conveyed back the grandchild's pid to parent + * process and all the setup for the grandchild is successfully done. + */ + } + _exit(EXIT_SUCCESS); + } + /* 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; + ESTABLISH_RET(grand_child, 0); sigaction(SIGTERM, &old_act, 0); /* restore the SIGTERM handler */ - - joberr = joberr_io; + CLOSEFILE_RESET(mproc_fds[1], pipe_status); /* resets "mproc_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 */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error reading from pipe"), errno); + 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); @@ -309,7 +445,6 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur * then the environment array passed is as follows * gtmj0= // parent pid * gtmgbldir=mumps.gld // current global directory - * gtmjb= // startup parameter to job command * gtmj3=/dev/null // input file parameter to job command * gtmj4=x.mjo // output file parameter to job command * gtmj5=x.mje // error file parameter to job command @@ -317,6 +452,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur * gtmj8= // label name to job off * gtmj9=0 // offset to job off * gtmja= // base priority; + * gtmjb= // startup parameter to job command * gtmj000=1 // parameter 1 to routine ^x * gtmj001=2 // parameter 2 to routine ^x * gtmjcnt=2 // number of parameters to routine ^x @@ -335,7 +471,7 @@ 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) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -352,12 +488,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->gbldir.len != 0) { if (jparms->gbldir.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->gbldir.addr, jparms->gbldir.len); *(pbuff + jparms->gbldir.len) = '\0'; string_len = STRLEN("%s=%s") + STRLEN(GBLDIR_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -371,12 +507,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->startup.len != 0) { if (jparms->startup.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->startup.addr, jparms->startup.len); *(pbuff + jparms->startup.len) = '\0'; string_len = STRLEN("%s=%s") + STRLEN(STARTUP_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -390,12 +526,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->input.len != 0) { if (jparms->input.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->input.addr, jparms->input.len); *(pbuff + jparms->input.len) = '\0'; string_len = STRLEN("%s=%s") + STRLEN(IN_FILE_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -410,14 +546,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->output.addr != 0) { if (jparms->output.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->output.addr, jparms->output.len); *(pbuff + jparms->output.len) = '\0'; if (jobpid) SPRINTF(&pbuff[jparms->output.len], ".%d", getpid()); string_len = STRLEN("%s=%s") + STRLEN(OUT_FILE_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -432,14 +568,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->error.len != 0) { if (jparms->error.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->error.addr, jparms->error.len); *(pbuff + jparms->error.len) = '\0'; if (jobpid) SPRINTF(&pbuff[jparms->error.len], ".%d", getpid()); string_len = STRLEN("%s=%s") + STRLEN(ERR_FILE_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -454,12 +590,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur if (jparms->routine.len != 0) { if (jparms->routine.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->routine.addr, jparms->routine.len); *(pbuff + jparms->routine.len) = '\0'; string_len = STRLEN("%s=%s") + STRLEN(ROUTINE_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -472,12 +608,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur /* pass label name to child */ if (jparms->label.len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); strncpy(pbuff, jparms->label.addr, jparms->label.len); *(pbuff + jparms->label.len) = '\0'; string_len = STRLEN("%s=%s") + STRLEN(LABEL_ENV) + STRLEN(pbuff) - 4; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -490,7 +626,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur /* pass the offset */ string_len = STRLEN("%s=%ld") + STRLEN(OFFSET_ENV) + MAX_NUM_LEN - 5; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -505,7 +641,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur { string_len = STRLEN("%s=%ld") + STRLEN(PRIORITY_ENV) + MAX_NUM_LEN - 5; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -519,13 +655,13 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur for (index = 0, jp = jparms->parms; jp ; index++, jp = jp->next) { if (jp->parm->str.len > MAX_JOB_LEN - 2) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); if (0 != jp->parm->mvtype) { MV_FORCE_STR(jp->parm); string_len = STRLEN(PARM_STR) + jp->parm->str.len + 1; if (string_len > MAX_JOB_LEN) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len); # ifdef KEEP_zOS_EBCDIC __getEstring1_a_copy(c1, STR_AND_LEN(PARM_STRING)); @@ -540,7 +676,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur } string_len = STRLEN("%s=%ld") + STRLEN(GTMJCNT_ENV) + MAX_NUM_LEN - 5; if (string_len > TEMP_BUFF_SIZE) - rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); c1 = (char *)malloc(string_len + 1); #ifdef KEEP_zOS_EBCDIC #pragma convlit(suspend) @@ -592,7 +728,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur #pragma pointer_size (restore) #endif - c1 = GETENV("gtm_dist"); + c1 = gtm_dist; string_len = STRLEN(c1); if ((string_len + SIZEOF(MUMPS_EXE_STR)) < SIZEOF(tbuff)) { @@ -600,7 +736,8 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur c2 = &tbuff[string_len]; strcpy(c2, MUMPS_EXE_STR); } else - rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, string_len, c1, SIZEOF(tbuff) - SIZEOF(MUMPS_EXE_STR)); + 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) @@ -610,6 +747,16 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur # pragma convlit(resume) # endif + /* pass cmdline to child */ + if (jparms->cmdline.len != 0) + { + if (jparms->cmdline.len > TEMP_BUFF_SIZE) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG); + memcpy(cmdbuff, jparms->cmdline.addr, jparms->cmdline.len); + *(cmdbuff + jparms->cmdline.len) = 0; + } else + memset(cmdbuff, 0, TEMP_BUFF_SIZE); + #ifdef KEEP_zOS_EBCDIC __getEstring1_a_copy(tbuff2, STR_AND_LEN(tbuff)); argv[0] = tbuff2; @@ -617,11 +764,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur argv[0] = tbuff; #endif argv[1] = cbuff; - argv[2] = (char *)0; + argv[2] = cmdbuff; + argv[3] = (char *)0; EXECVE(tbuff, argv, env_ary); /* if we got here, error starting the Job */ - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Exec error in Job"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Exec error in Job"), errno); REVERT; } else { @@ -652,13 +800,13 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur WAITPID(child_pid, &wait_status, 0, done_pid); if (done_pid == child_pid) return (wait_status); - } else if (-1 != kill_ret && done_pid == child_pid && 0 == wait_status) - return 0; /* timer popped in the window of child fork and middle process exit */ + } else if (-1 != kill_ret && done_pid == child_pid) + return (wait_status); /* timer popped in the window of child fork and middle process exit */ *non_exit_return = TRUE; return TIMEOUT_ERROR; /* return special value so as to eliminate the window where the timer * might pop after this routine returns to the callee and before the callee * analyses the return status (ojtimeout may not be a reliable indicator) */ - } else if (0 > done_pid) + } else if (0 > done_pid) /* Some other signal received OR there is no child to be waited on */ { *non_exit_return = TRUE; save_errno = errno; diff --git a/sr_unix/op_fnfgncal.c b/sr_unix/op_fnfgncal.c index fde2f9b..e932216 100644 --- a/sr_unix/op_fnfgncal.c +++ b/sr_unix/op_fnfgncal.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,6 +14,9 @@ #include "gtm_string.h" #include #include +#ifdef GTM_PTHREAD +# include +#endif #include "gtm_stdlib.h" #include "stringpool.h" @@ -58,7 +61,7 @@ * * would result in the following call: * - * op_fnfgncal(8, 0, mval*("package"), mval*("bessel"), 4, 3, mval*(p1), mval*(p2), mval*(p3)) + * op_fnfgncal(8, 0, mval*("mathpak"), mval*("bessel"), 4, 3, mval*(p1), mval*(p2), mval*(p3)) * * where, mval*(val) indicates the address of an mval that has the string value val. * @@ -102,7 +105,13 @@ GBLREF spdesc stringpool; GBLREF int (*callintogtm_vectortable[])(); GBLREF int mumps_status; GBLREF volatile int4 gtmMallocDepth; +#ifdef GTM_PTHREAD +GBLREF boolean_t gtm_jvm_process; +GBLREF pthread_t gtm_main_thread_id; +GBLREF boolean_t gtm_main_thread_id_set; +#endif +error_def(ERR_JNI); error_def(ERR_MAXSTRLEN); error_def(ERR_TEXT); error_def(ERR_UNIMPLOP); @@ -116,73 +125,148 @@ error_def(ERR_ZCSTATUSRET); error_def(ERR_ZCUSRRTN); error_def(ERR_ZCVECTORINDX); -STATICDEF int call_table_initialized = 0; +STATICDEF int call_table_initialized = 0; +/* The following are one-letter mnemonics for Java argument types (capital letters to denote output direction): + * boolean int long float double String byte[] */ +STATICDEF char gtm_jtype_chars[] = { 'b', 'i', 'l', 'f', 'd', 'j', 'a', + 'B', 'I', 'L', 'F', 'D', 'J', 'A' }; +STATICDEF int gtm_jtype_start_idx = gtm_jboolean, /* Value of first gtm_j... type for calculation of table indices. */ + gtm_jtype_count = gtm_jbyte_array - gtm_jboolean + 1; /* Number of types supported with Java call-outs. */ -STATICFNDCL void extarg2mval(void *src, enum xc_types typ, mval *dst); -STATICFNDCL int extarg_getsize(void *src, enum xc_types typ, mval *dst); +STATICFNDCL void extarg2mval(void *src, enum gtm_types typ, mval *dst, boolean_t java, boolean_t starred); +STATICFNDCL int extarg_getsize(void *src, enum gtm_types typ, mval *dst); +STATICFNDCL void op_fgnjavacal(mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, int4 entry_argcnt, + struct extcall_package_list *package_ptr, struct extcall_entry_list *entry_ptr, va_list var); -/* routine to convert external return values to mval's */ -STATICFNDEF void extarg2mval(void *src, enum xc_types typ, mval *dst) +/* Routine to convert external return values to mval's */ +STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst, boolean_t java, boolean_t starred) { - xc_long_t str_len; - xc_int_t s_int_num; - xc_uint_t uns_int_num; - xc_long_t s_long_num; - xc_ulong_t uns_long_num; + gtm_int_t s_int_num; + gtm_long_t str_len, s_long_num; + gtm_uint_t uns_int_num; + gtm_ulong_t uns_long_num; char *cp; struct extcall_string *sp; + if (java) + { + switch(typ) + { + case gtm_notfound: + break; + case gtm_void: + break; + case gtm_status: + /* Note: reason for double cast is to first turn ptr to same sized int, then big int to little int + * (on 64 bit platforms). This avoids a warning msg with newer 64 bit gcc compilers. + */ + s_int_num = (gtm_int_t)(intszofptr_t)src; + if (0 != s_int_num) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET); + MV_FORCE_MVAL(dst, s_int_num); + break; + case gtm_jboolean: + case gtm_jint: + if (starred) + s_int_num = *((gtm_int_t *)src); + else + s_int_num = (gtm_int_t)(intszofptr_t)src; + MV_FORCE_MVAL(dst, s_int_num); + break; + case gtm_jlong: +# ifdef GTM64 + if (starred) + s_long_num = *((gtm_long_t *)src); + else + s_long_num = (gtm_long_t)src; + MV_FORCE_LMVAL(dst, s_long_num); +# else + i82mval(dst, *(gtm_int64_t *)src); +# endif + break; + case gtm_jfloat: + float2mval(dst, *((float *)src)); + break; + case gtm_jdouble: + double2mval(dst, *((double *)src)); + break; + case gtm_jstring: + case gtm_jbyte_array: + sp = (struct extcall_string *)src; + dst->mvtype = MV_STR; + if (sp->len > MAX_STRLEN) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); + dst->str.len = (mstr_len_t)sp->len; + if ((0 < sp->len) && (NULL != sp->addr)) + { + dst->str.addr = sp->addr; + s2pool(&dst->str); + /* In case of GTMByteArray or GTMString, the buffer is allocated in xc_gateway.c (since the + * user might need to return a bigger buffer than the original array size will allow (in + * case of a string the content is immutable). So, if we have determined that the provided + * value buffer is legitimate (non-null and non-empty), we free it on the GT.M side. */ + free(sp->addr); + } + break; + default: + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); + break; + } + return; + } + /* The following switch is for non-Java call-outs. */ switch(typ) { - case xc_notfound: + case gtm_notfound: break; - case xc_void: + case gtm_void: break; - case xc_status: + case gtm_status: /* Note: reason for double cast is to first turn ptr to same sized int, then big int to little int - (on 64 bit platforms). This avoids a warning msg with newer 64 bit gcc compilers */ - s_int_num = (xc_int_t)(intszofptr_t)src; + * (on 64 bit platforms). This avoids a warning msg with newer 64 bit gcc compilers. + */ + s_int_num = (gtm_int_t)(intszofptr_t)src; if (0 != s_int_num) - dec_err(VARLSTCNT(1) ERR_ZCSTATUSRET, 0, s_int_num); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET); MV_FORCE_MVAL(dst, s_int_num); break; - case xc_int: - s_int_num = (xc_int_t)(intszofptr_t)src; + case gtm_int: + s_int_num = (gtm_int_t)(intszofptr_t)src; MV_FORCE_MVAL(dst, s_int_num); break; - case xc_uint: - uns_int_num = (xc_uint_t)(intszofptr_t)src; + case gtm_uint: + uns_int_num = (gtm_uint_t)(intszofptr_t)src; MV_FORCE_UMVAL(dst, uns_int_num); break; - case xc_int_star: - s_int_num = *((xc_int_t *)src); + case gtm_int_star: + s_int_num = *((gtm_int_t *)src); MV_FORCE_MVAL(dst, s_int_num); break; - case xc_uint_star: - uns_int_num = *((xc_uint_t *)src); + case gtm_uint_star: + uns_int_num = *((gtm_uint_t *)src); MV_FORCE_UMVAL(dst, uns_int_num); break; - case xc_long: - s_long_num = (xc_long_t)src; + case gtm_long: + s_long_num = (gtm_long_t)src; MV_FORCE_LMVAL(dst, s_long_num); break; - case xc_ulong: - uns_long_num = (xc_ulong_t)src; + case gtm_ulong: + uns_long_num = (gtm_ulong_t)src; MV_FORCE_ULMVAL(dst, uns_long_num); break; - case xc_long_star: - s_long_num = *((xc_long_t *)src); + case gtm_long_star: + s_long_num = *((gtm_long_t *)src); MV_FORCE_LMVAL(dst, s_long_num); break; - case xc_ulong_star: - uns_long_num = *((xc_ulong_t *)src); + case gtm_ulong_star: + uns_long_num = *((gtm_ulong_t *)src); MV_FORCE_ULMVAL(dst, uns_long_num); break; - case xc_string_star: + case gtm_string_star: sp = (struct extcall_string *)src; dst->mvtype = MV_STR; if (sp->len > MAX_STRLEN) - rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); dst->str.len = (mstr_len_t)sp->len; if ((0 < sp->len) && (NULL != sp->addr)) { @@ -190,121 +274,421 @@ STATICFNDEF void extarg2mval(void *src, enum xc_types typ, mval *dst) s2pool(&dst->str); } break; - case xc_float_star: - double2mval(dst, (double)*((float *)src)); + case gtm_float_star: + float2mval(dst, *((float *)src)); break; - case xc_char_star: + case gtm_char_star: cp = (char *)src; assert(((INTPTR_T)cp < (INTPTR_T)stringpool.base) || ((INTPTR_T)cp > (INTPTR_T)stringpool.top)); dst->mvtype = MV_STR; str_len = STRLEN(cp); if (str_len > MAX_STRLEN) - rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); dst->str.len = (mstr_len_t)str_len; dst->str.addr = cp; s2pool(&dst->str); break; - case xc_char_starstar: + case gtm_char_starstar: if (!src) dst->mvtype = 0; else - extarg2mval(*((char **)src), xc_char_star, dst); + extarg2mval(*((char **)src), gtm_char_star, dst, java, starred); break; - case xc_double_star: + case gtm_double_star: double2mval(dst, *((double *)src)); break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } return; } -/* subroutine to calculate stringpool requirements for an external argument */ -STATICFNDEF int extarg_getsize(void *src, enum xc_types typ, mval *dst) +/* Subroutine to calculate stringpool requirements for an external argument */ +STATICFNDEF int extarg_getsize(void *src, enum gtm_types typ, mval *dst) { - int4 n; char *cp, **cpp; struct extcall_string *sp; if (!src) return 0; switch(typ) - { - /* the following group of cases either return nothing or use the numeric part of the mval */ - case xc_notfound: - case xc_void: - case xc_double_star: - case xc_status: - case xc_int: - case xc_uint: - case xc_long: - case xc_ulong: - case xc_float_star: - case xc_int_star: - case xc_uint_star: - case xc_long_star: - case xc_ulong_star: + { /* The following group of cases either return nothing or use the numeric part of the mval */ + case gtm_notfound: + case gtm_void: + case gtm_double_star: + case gtm_status: + case gtm_int: + case gtm_uint: + case gtm_long: + case gtm_ulong: + case gtm_float_star: + case gtm_int_star: + case gtm_uint_star: + case gtm_long_star: + case gtm_ulong_star: + case gtm_jboolean: + case gtm_jint: + case gtm_jlong: + case gtm_jfloat: + case gtm_jdouble: return 0; - case xc_char_starstar: + case gtm_char_starstar: cpp = (char **)src; if (*cpp) return STRLEN(*cpp); else return 0; - case xc_char_star: + case gtm_char_star: cp = (char *)src; return STRLEN(cp); - case xc_string_star: + case gtm_jstring: + case gtm_jbyte_array: + case gtm_string_star: sp = (struct extcall_string *)src; if ((0 < sp->len) && ((INTPTR_T)sp->addr < (INTPTR_T)stringpool.free) && ((INTPTR_T)sp->addr >= (INTPTR_T)stringpool.base)) - { /* the stuff is already in the stringpool */ + { /* The stuff is already in the stringpool */ assert(dst->str.addr == sp->addr); dst->str.addr = sp->addr; - sp->addr = NULL; /* prevent subsequent s2pool */ + sp->addr = NULL; /* Prevent subsequent s2pool */ return 0; } else if (NULL == sp->addr) sp->len = 0; return (int)(sp->len); break; default: - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } return 0; /* This should never get executed, added to make compiler happy */ } +STATICFNDEF void op_fgnjavacal(mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, int4 entry_argcnt, + struct extcall_package_list *package_ptr, struct extcall_entry_list *entry_ptr, va_list var) +{ + boolean_t error_in_xc = FALSE; + char *free_string_pointer, *free_string_pointer_start, jtype_char; + char str_buffer[MAX_NAME_LENGTH], *tmp_buff_ptr, *jni_err_buf; + char *types_descr_ptr, *types_descr_dptr, *xtrnl_table_name; + gparam_list *param_list; + gtm_long_t *free_space_pointer; + int i, j, save_mumps_status; + int4 m1, m2, n; + INTPTR_T status; + mval *v; + va_list var_copy; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; +# ifdef GTM_PTHREAD + assert(gtm_jvm_process == gtm_main_thread_id_set); + gtm_jvm_process = TRUE; + if (!gtm_main_thread_id_set) + { + gtm_main_thread_id = pthread_self(); + gtm_main_thread_id_set = TRUE; + } +# endif + /* This is how many parameters we will use for callg, including the implicit ones described below. So, better make + * sure we are not trying to pass more than callg can handle. + */ + if (MAX_ACTUALS < argcnt + 3) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCMAXPARAM); + VAR_COPY(var_copy, var); + /* Compute size of parameter block */ + n = entry_ptr->parmblk_size + (3 * SIZEOF(void *)); /* This is enough for the parameters and the fixed length entries */ + mask >>= 2; /* Bypass the class and method arguments. */ + /* The first byte of the first argument (types_descr_ptr) stores the number of expected arguments, according to the external + * calls table; the second byte describes the expected return type, and subsequent bytes---the expected argument types using + * a one-character mnemonic which gets deciphered in the JNI layer. Note that in case of an error the xc_gateway.c module + * would set the first byte to 0xFF, followed by an address at which the error message is stored. For that reason, we + * allocate more space than we might strictly need for the arguments, return type, and type descriptor. + */ + types_descr_ptr = (char *)malloc(MAX(SIZEOF(char) * (argcnt + 2), SIZEOF(char *) * 2)); + types_descr_dptr = types_descr_ptr; + *types_descr_dptr = (char)entry_argcnt; + types_descr_dptr++; + if (dst) + { /* Record the expected return type. */ + switch (entry_ptr->return_type) + { + case gtm_status: + *types_descr_dptr = 'i'; + break; + case gtm_jlong: + *types_descr_dptr = 'l'; + break; + default: + *types_descr_dptr = 'v'; + } + } else + *types_descr_dptr = 'v'; + types_descr_dptr++; + assert(2 * gtm_jtype_count == SIZEOF(gtm_jtype_chars)); + for (i = argcnt + 2, j = -2, m1 = entry_ptr->input_mask, m2 = mask & entry_ptr->output_mask; 0 < i; i--, j++) + { /* Enforce mval values and record expected argument types. */ + v = va_arg(var, mval *); + if (0 > j) + { + MV_FORCE_STR(v); + n += v->str.len + SIZEOF(gtm_long_t) + 1; + continue; + } + if (m1 & 1) + { + if ((gtm_jstring == entry_ptr->parms[j]) || (gtm_jbyte_array == entry_ptr->parms[j])) + { + MV_FORCE_STR(v); + n += v->str.len + SIZEOF(gtm_long_t) + 1; + } else + { + MV_FORCE_DEFINED(v); + } + } + jtype_char = entry_ptr->parms[j] - gtm_jtype_start_idx; + if ((0 > jtype_char) || (gtm_jtype_count <= jtype_char)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); + else + *types_descr_dptr = gtm_jtype_chars[(m2 & 1) ? (gtm_jtype_count + jtype_char) : jtype_char]; + types_descr_dptr++; + m1 >>= 1; + m2 >>= 1; + } + va_end(var); + /* Double the size, to take care of any alignments in the middle. */ + param_list = (gparam_list *)malloc(n * 2); + param_list->arg[0] = (void *)types_descr_ptr; + /* Adding 3 to account for type descriptions, class name, and method name arguments. */ + free_space_pointer = (gtm_long_t *)((char *)param_list + SIZEOF(intszofptr_t) + (SIZEOF(void *) * (argcnt + 3))); + /* Adding 3 for the same reason as above and another 3 to account for the fact that each of type description, class name, + * and method name arguments require room in the free_space buffer, which comes ahead of free_string buffer in memory. + */ + free_string_pointer_start = free_string_pointer = (char *)param_list + entry_ptr->parmblk_size + (SIZEOF(void *) * (3 + 3)); + /* Load-up the parameter list */ + VAR_COPY(var, var_copy); + /* We need to enter this loop even if argcnt == 0, so that the class and method arguments get set. */ + for (i = (0 == argcnt ? -1 : 0), j = 1, m1 = entry_ptr->input_mask, m2 = mask & entry_ptr->output_mask; i < argcnt; j++) + { + v = va_arg(var_copy, mval *); + if (j < 3) + { + param_list->arg[j] = free_string_pointer; + if (v->str.len) + memcpy(free_string_pointer, v->str.addr, v->str.len); + free_string_pointer += v->str.len; + *free_string_pointer++ = 0; + /* In case there are 0 arguments. */ + if (2 == j && 0 > i) + i = 0; + continue; + } + /* Verify that all input values are defined. */ + switch (entry_ptr->parms[i]) + { + case gtm_jboolean: + if (m2 & 1) + { /* Output expected. */ + param_list->arg[j] = free_space_pointer; + *((gtm_int_t *)free_space_pointer) = (m1 & 1) ? ((gtm_int_t)(mval2i(v) ? 1 : 0)) : 0; + free_space_pointer++; + } else if (m1 & 1) + param_list->arg[j] = (void *)((gtm_long_t)(mval2i(v) ? 1 : 0)); + break; + case gtm_jint: + if (m2 & 1) + { /* Output expected. */ + param_list->arg[j] = free_space_pointer; + *((gtm_int_t *)free_space_pointer) = (m1 & 1) ? (gtm_int_t)mval2i(v) : 0; + free_space_pointer++; + } else if (m1 & 1) + param_list->arg[j] = (void *)(gtm_long_t)mval2i(v); + break; + case gtm_jlong: + if (m2 & 1) + { /* Output expected. */ +# ifndef GTM64 + free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), + SIZEOF(gtm_int64_t))); +# endif + param_list->arg[j] = free_space_pointer; + *((gtm_int64_t *)free_space_pointer) = (m1 & 1) ? (gtm_int64_t)mval2i8(v) : 0; + free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(gtm_int64_t)); + } else if (m1 & 1) + { +# ifdef GTM64 + param_list->arg[j] = (void *)(gtm_int64_t)mval2i8(v); +# else + /* Only need to do this rounding on non-64 it platforms because this one type has a 64 bit + * alignment requirement on those platforms. + */ + free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), + SIZEOF(gtm_int64_t))); + param_list->arg[j] = free_space_pointer; + *((gtm_int64_t *)free_space_pointer) = (gtm_int64_t)mval2i8(v); + free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(gtm_int64_t)); +# endif + } + break; + case gtm_jfloat: + param_list->arg[j] = free_space_pointer; + *((float *)free_space_pointer) = (m1 & 1) ? (float)mval2double(v) : (float)0.0; + free_space_pointer++; + break; + case gtm_jdouble: +# ifndef GTM64 + /* Only need to do this rounding on non-64 it platforms because this one type has a 64 bit + * alignment requirement on those platforms. + */ + free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), SIZEOF(double))); +# endif + param_list->arg[j] = free_space_pointer; + *((double *)free_space_pointer) = (m1 & 1) ? (double)mval2double(v) : (double)0.0; + free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(double)); + break; + case gtm_jstring: + case gtm_jbyte_array: + param_list->arg[j] = free_space_pointer; + *free_space_pointer++ = (gtm_long_t)v->str.len; + *(char **)free_space_pointer = (char *)free_string_pointer; + free_space_pointer++; + if (m1 & 1) + { + if (v->str.len) + memcpy(free_string_pointer, v->str.addr, v->str.len); + free_string_pointer += v->str.len; + *free_string_pointer++ = 0; + } + break; + default: + va_end(var_copy); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); + break; + } + assert(((char *)free_string_pointer <= ((char *)param_list + n * 2)) + && ((char *)free_space_pointer <= ((char *)param_list + n * 2))); + i++; + m1 = m1 >> 1; + m2 = m2 >> 1; + } + assert((char *)free_space_pointer <= free_string_pointer_start); + va_end(var_copy); + param_list->n = argcnt + 3; /* Take care of the three implicit parameters. */ + save_mumps_status = mumps_status; /* Save mumps_status as a callin from external call may change it. */ + status = callg((callgfnptr)entry_ptr->fcn, param_list); + mumps_status = save_mumps_status; + /* The first byte of the type description argument gets set to 0xFF in case error happened in JNI glue code, + * so check for that and act accordingly. + */ + if ((char)0xFF == *(char *)param_list->arg[0]) + { + error_in_xc = TRUE; + jni_err_buf = *(char **)((char *)param_list->arg[0] + SIZEOF(char *)); + if (NULL != jni_err_buf) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNI, 2, LEN_AND_STR(jni_err_buf)); + else + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET); + } + free(types_descr_ptr); + /* Exit from the residual call-in environment(SFF_CI and base frames) which might still exist on M stack when the externally + * called function in turn called into an M routine. + */ + if (frame_pointer->flags & SFF_CI) + ci_ret_code_quit(); + /* Only process the input-output and output-only arguments if the external call succeeded; otherwise, return -1 + * if non-void return is expected. */ + if (!error_in_xc) + { /* Compute space requirement for return values. */ + n = 0; + VAR_COPY(var_copy, var); + for (i = 0, j = 1, m1 = mask & entry_ptr->output_mask; i < argcnt; j++) + { + v = va_arg(var, mval *); + if (j < 3) + continue; + if (m1 & 1) + n += extarg_getsize(param_list->arg[j], entry_ptr->parms[i], v); + i++; + m1 = m1 >> 1; + } + va_end(var); + if (dst) + n += extarg_getsize((void *)&status, gtm_status, dst); + ENSURE_STP_FREE_SPACE(n); + /* Convert return values. */ + VAR_COPY(var, var_copy); + for (i = 0, j = 1, m1 = mask & entry_ptr->output_mask; i < argcnt; j++) + { + v = va_arg(var_copy, mval *); + if (j < 3) + continue; + if (m1 & 1) + extarg2mval((void *)param_list->arg[j], entry_ptr->parms[i], v, TRUE, TRUE); + i++; + m1 = m1 >> 1; + } + va_end(var); + if (dst) + { + if (entry_ptr->return_type != gtm_void) + extarg2mval((void *)status, entry_ptr->return_type, dst, TRUE, FALSE); + else + { + memcpy(str_buffer, PACKAGE_ENV_PREFIX, SIZEOF(PACKAGE_ENV_PREFIX)); + tmp_buff_ptr = &str_buffer[SIZEOF(PACKAGE_ENV_PREFIX) - 1]; + if (package->str.len) + { + assert(package->str.len < MAX_NAME_LENGTH - SIZEOF(PACKAGE_ENV_PREFIX) - 1); + *tmp_buff_ptr++ = '_'; + memcpy(tmp_buff_ptr, package->str.addr, package->str.len); + tmp_buff_ptr += package->str.len; + } + *tmp_buff_ptr = 0; + xtrnl_table_name = GETENV(str_buffer); + if (NULL == xtrnl_table_name) + { /* Environment variable for the package not found. This part of code is for more safety. + * We should not come into this path at all. + */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer)); + } + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_XCVOIDRET, 4, + LEN_AND_STR(entry_ptr->call_name.addr), LEN_AND_STR(xtrnl_table_name)); + } + } + } else if (dst && (gtm_void != entry_ptr->return_type)) + i2mval(dst, -1); + free(param_list); + check_for_timer_pops(); + return; +} + void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, ...) { - va_list var; - int i, rslt; - int4 callintogtm_vectorindex; - mval *arg, *v; - int4 n; - xc_long_t *free_space_pointer; - uint4 m1; + boolean_t java = FALSE; + char *free_string_pointer, *free_string_pointer_start; + char str_buffer[MAX_NAME_LENGTH], *tmp_buff_ptr, *xtrnl_table_name; + int i, pre_alloc_size, rslt, save_mumps_status; + int4 callintogtm_vectorindex, n; + gparam_list *param_list; + gtm_long_t *free_space_pointer; INTPTR_T status; - char *cp, *free_string_pointer, *free_string_pointer_start; - int pre_alloc_size; - int save_mumps_status; - char *gtmvectortable_temp, *tmp_buff_ptr, str_buffer[MAX_NAME_LENGTH]; - char *xtrnl_table_name; + mval *v; struct extcall_package_list *package_ptr; struct extcall_entry_list *entry_ptr; - gparam_list *param_list; + uint4 m1; + va_list var; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(n_mvals == argcnt + 5); - assert(MV_IS_STRING(package)); /* package and routine are literal strings */ + assert(MV_IS_STRING(package)); /* Package and routine are literal strings */ assert(MV_IS_STRING(extref)); if (MAX_ACTUALS < argcnt) - rts_error(VARLSTCNT(1) ERR_ZCMAXPARAM); - assert(INTRPT_OK_TO_INTERRUPT == intrpt_ok_state); /* interrupts should be enabled for external calls */ - /* find package */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCMAXPARAM); + assert(INTRPT_OK_TO_INTERRUPT == intrpt_ok_state); /* Interrupts should be enabled for external calls */ + /* Find package */ for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package) { MSTR_CMP(package_ptr->package_name, package->str, rslt); @@ -321,7 +705,7 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m /* At this point, we have a valid package, pointed to by package_ptr */ assert(NULL != package_ptr); if (NULL == package_ptr->package_handle) - rts_error(VARLSTCNT(1) errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno); /* Find entry */ for (entry_ptr = package_ptr->first_entry; entry_ptr; entry_ptr = entry_ptr->next_entry) { @@ -334,34 +718,44 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m call_table_initialized = TRUE; init_callin_functable(); } - /* entry not found */ + /* Entry not found */ if ((NULL == entry_ptr) || (NULL == entry_ptr->fcn)) - rts_error(VARLSTCNT(4) ERR_ZCRTENOTF, 2, extref->str.len, extref->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCRTENOTF, 2, extref->str.len, extref->str.addr); + /* Detect a call-out to Java. */ + if ((NULL != entry_ptr->call_name.addr) && !strncmp(entry_ptr->call_name.addr, "gtm_xcj", 7)) + { + java = TRUE; + argcnt -= 2; + } /* It is an error to have more actual parameters than formal parameters */ if (argcnt > entry_ptr->argcnt) - rts_error(VARLSTCNT(4) ERR_ZCARGMSMTCH, 2, argcnt, entry_ptr->argcnt); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCARGMSMTCH, 2, argcnt, entry_ptr->argcnt); VAR_START(var, argcnt); - /* compute size of parameter block */ + if (java) + { + op_fgnjavacal(dst, package, extref, mask, argcnt, entry_ptr->argcnt, package_ptr, entry_ptr, var); + return; + } + /* Compute size of parameter block */ n = entry_ptr->parmblk_size; /* This is enough for the parameters and the fixed length entries */ /* Now, add enough for the char *'s and the char **'s and string *'s */ for (i = 0, m1 = entry_ptr->input_mask; i < argcnt; i++, m1 = m1 >> 1) { v = va_arg(var, mval *); - /* if it is an input value of char* or char **, add the length */ - /* also a good time to force it into string form */ + /* If it is an input value of char* or char **, add the length. Also a good time to force it into string form */ switch(entry_ptr->parms[i]) { - case xc_char_star: + case gtm_char_star: n += (-1 != entry_ptr->param_pre_alloc_size[i]) ? entry_ptr->param_pre_alloc_size[i] : 0; /* Caution fall through */ - case xc_char_starstar: + case gtm_char_starstar: if (m1 & 1) { MV_FORCE_STR(v); n += v->str.len + 1; } break; - case xc_string_star: + case gtm_string_star: if (m1 & 1) { MV_FORCE_STR(v); @@ -369,7 +763,7 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m } else n += (-1 != entry_ptr->param_pre_alloc_size[i]) ? entry_ptr->param_pre_alloc_size[i] : 0; break; - case xc_double_star: + case gtm_double_star: n += SIZEOF(double); if (m1 & 1) MV_FORCE_DEFINED(v); @@ -383,45 +777,51 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m va_end(var); /* Double the size, to take care of any alignments in the middle */ param_list = (gparam_list *)malloc(n * 2); - free_space_pointer = (xc_long_t *)((char *)param_list + SIZEOF(intszofptr_t) + (SIZEOF(void *) * argcnt)); + free_space_pointer = (gtm_long_t *)((char *)param_list + SIZEOF(intszofptr_t) + (SIZEOF(void *) * argcnt)); free_string_pointer_start = free_string_pointer = (char *)param_list + entry_ptr->parmblk_size; - /* load-up the parameter list */ + /* Load-up the parameter list */ VAR_START(var, argcnt); for (i = 0, m1 = entry_ptr->input_mask; i < argcnt; i++, m1 = m1 >> 1) { v = va_arg(var, mval *); /* Note that even in this second pass at these mvals, we need to do the MV_FORCE processing because - in a NOUNDEF environment, undefiend mvals were NOT modified in the first pass and thus reamin undefined - in this pass. - */ - if (xc_char_star != entry_ptr->parms[i] && (m1 & 1)) + * in a NOUNDEF environment, undefiend mvals were NOT modified in the first pass and thus reamin undefined + * in this pass. + */ + if (gtm_char_star != entry_ptr->parms[i] && (m1 & 1)) MV_FORCE_DEFINED(v); /* Redefine undef'd mvals */ /* Verify that all input values are defined */ pre_alloc_size = entry_ptr->param_pre_alloc_size[i]; switch(entry_ptr->parms[i]) { /* Note the int/long types are handled separately here in anticipation of correct handling - of "long" types on 64 bit hardware in the future. For the time being however, they are - using the same mval2i interface routine so are both restricted to 32 bits. - */ - case xc_uint: + * of "long" types on 64 bit hardware in the future. For the time being however, they are + * using the same mval2i interface routine so are both restricted to 32 bits. + */ + case gtm_uint: if (m1 & 1) - param_list->arg[i] = (void *)(xc_long_t)mval2ui(v); - /* Note: output xc_int and xc_uint is an error (only "star" flavor can be modified) */ + param_list->arg[i] = (void *)(gtm_long_t)mval2ui(v); + /* Note: output gtm_int and gtm_uint is an error (only "star" flavor can be modified) */ break; - case xc_int: + case gtm_int: if (m1 & 1) - param_list->arg[i] = (void *)(xc_long_t)mval2i(v); + param_list->arg[i] = (void *)(gtm_long_t)mval2i(v); break; - case xc_ulong: + case gtm_ulong: if (m1 & 1) - param_list->arg[i] = (void *)(xc_long_t)mval2ui(v); + { + GTM64_ONLY(param_list->arg[i] = (void *)(gtm_uint64_t)mval2ui8(v)); + NON_GTM64_ONLY(param_list->arg[i] = (void *)(gtm_ulong_t)mval2ui(v)); + } /* Note: output xc_long and xc_ulong is an error as described above */ break; - case xc_long: + case gtm_long: if (m1 & 1) - param_list->arg[i] = (void *)(xc_ulong_t)mval2i(v); + { + GTM64_ONLY(param_list->arg[i] = (void *)(gtm_int64_t)mval2i8(v)); + NON_GTM64_ONLY(param_list->arg[i] = (void *)(gtm_long_t)mval2i(v)); + } break; - case xc_char_star: + case gtm_char_star: param_list->arg[i] = free_string_pointer; if (m1 & 1) { @@ -434,15 +834,15 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m else /* Output and no pre-allocation specified */ { if (0 == package->str.len) - /* default package - do not display package name */ - rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i+1, RTS_ERROR_LITERAL(""), - extref->str.len, extref->str.addr); + /* Default package - do not display package name */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, + RTS_ERROR_LITERAL(""), extref->str.len, extref->str.addr); else - rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i+1, package->str.len, - package->str.addr, extref->str.len, extref->str.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, + package->str.len, package->str.addr, extref->str.len, extref->str.addr); } break; - case xc_char_starstar: + case gtm_char_starstar: param_list->arg[i] = free_space_pointer; if (m1 & 1) { @@ -455,29 +855,31 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m *(char **)free_space_pointer = free_string_pointer++; free_space_pointer++; break; - case xc_int_star: + case gtm_int_star: param_list->arg[i] = free_space_pointer; - *((xc_int_t *)free_space_pointer) = (m1 & 1) ? (xc_int_t)mval2i(v) : 0; + *((gtm_int_t *)free_space_pointer) = (m1 & 1) ? (gtm_int_t)mval2i(v) : 0; free_space_pointer++; break; - case xc_uint_star: + case gtm_uint_star: param_list->arg[i] = free_space_pointer; - *((xc_uint_t *)free_space_pointer) = (m1 & 1) ? (xc_uint_t)mval2ui(v) : 0; + *((gtm_uint_t *)free_space_pointer) = (m1 & 1) ? (gtm_uint_t)mval2ui(v) : 0; free_space_pointer++; break; - case xc_long_star: + case gtm_long_star: param_list->arg[i] = free_space_pointer; - *((xc_long_t *)free_space_pointer) = (m1 & 1) ? (xc_long_t)mval2i(v) : 0; + GTM64_ONLY(*((gtm_int64_t *)free_space_pointer) = (m1 & 1) ? (gtm_int64_t)mval2i8(v) : 0); + NON_GTM64_ONLY(*((gtm_long_t *)free_space_pointer) = (m1 & 1) ? (gtm_long_t)mval2i(v) : 0); free_space_pointer++; break; - case xc_ulong_star: + case gtm_ulong_star: param_list->arg[i] = free_space_pointer; - *((xc_ulong_t *)free_space_pointer) = (m1 & 1) ? (xc_ulong_t)mval2ui(v) : 0; + GTM64_ONLY(*((gtm_uint64_t *)free_space_pointer) = (m1 & 1) ? (gtm_uint64_t)mval2ui8(v) : 0); + NON_GTM64_ONLY(*((gtm_ulong_t *)free_space_pointer) = (m1 & 1) ? (gtm_ulong_t)mval2ui(v) : 0); free_space_pointer++; break; - case xc_string_star: + case gtm_string_star: param_list->arg[i] = free_space_pointer; - *free_space_pointer++ = (xc_long_t)v->str.len; + *free_space_pointer++ = (gtm_long_t)v->str.len; *(char **)free_space_pointer = (char *)free_string_pointer; free_space_pointer++; if (m1 & 1) @@ -490,69 +892,69 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m else /* Output and no pre-allocation specified */ { if (0 == package->str.len) - /* default package - do not display package name */ - rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, + /* Default package - do not display package name */ + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, RTS_ERROR_LITERAL(""), extref->str.len, extref->str.addr); else - rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1, package->str.len, package->str.addr, extref->str.len, extref->str.addr); } break; - case xc_float_star: + case gtm_float_star: param_list->arg[i] = free_space_pointer; *((float *)free_space_pointer) = (m1 & 1) ? (float)mval2double(v) : (float)0.0; free_space_pointer++; break; - case xc_double_star: + case gtm_double_star: /* Only need to do this rounding on non-64 it platforms because this one type has a 64 bit - alignment requirement on those platforms. - */ - NON_GTM64_ONLY(free_space_pointer = (xc_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), + * alignment requirement on those platforms. + */ + NON_GTM64_ONLY(free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), SIZEOF(double)))); param_list->arg[i] = free_space_pointer; *((double *)free_space_pointer) = (m1 & 1) ? (double)mval2double(v) : (double)0.0; - free_space_pointer = (xc_long_t *)((char *)free_space_pointer + SIZEOF(double)); + free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(double)); break; - case xc_pointertofunc: - if (((callintogtm_vectorindex = (int4)mval2i(v)) >= xc_unknown_function) + case gtm_pointertofunc: + if (((callintogtm_vectorindex = (int4)mval2i(v)) >= gtmfunc_unknown_function) || (callintogtm_vectorindex < 0)) { - rts_error(VARLSTCNT(7) ERR_ZCVECTORINDX, 1, callintogtm_vectorindex, ERR_TEXT, 2, - RTS_ERROR_TEXT("Passing Null vector")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCVECTORINDX, 1, callintogtm_vectorindex, + ERR_TEXT, 2, RTS_ERROR_TEXT("Passing Null vector")); param_list->arg[i] = 0; } else param_list->arg[i] = (void *)callintogtm_vectortable[callintogtm_vectorindex]; break; - case xc_pointertofunc_star: - /* cannot pass in a function address to be modified by the user program */ - free_space_pointer = (xc_long_t *)ROUND_UP2(((INTPTR_T)free_space_pointer), SIZEOF(INTPTR_T)); + case gtm_pointertofunc_star: + /* Cannot pass in a function address to be modified by the user program */ + free_space_pointer = (gtm_long_t *)ROUND_UP2(((INTPTR_T)free_space_pointer), SIZEOF(INTPTR_T)); param_list->arg[i] = free_space_pointer; *((INTPTR_T *)free_space_pointer) = 0; free_space_pointer++; break; default: va_end(var); - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } } assert((char *)free_space_pointer <= free_string_pointer_start); va_end(var); param_list->n = argcnt; - save_mumps_status = mumps_status; /* save mumps_status as a callin from external call may change it */ + save_mumps_status = mumps_status; /* Save mumps_status as a callin from external call may change it */ status = callg((callgfnptr)entry_ptr->fcn, param_list); mumps_status = save_mumps_status; /* Exit from the residual call-in environment(SFF_CI and base frames) which might * still exist on M stack when the externally called function in turn called - * into an M routine */ + * into an M routine. + */ if (frame_pointer->flags & SFF_CI) ci_ret_code_quit(); - /* NOTE: ADD RETURN STATUS CALCUATIONS HERE */ - /* compute space requirement for return values */ + /* Compute space requirement for return values */ n = 0; VAR_START(var, argcnt); for (i = 0, m1 = mask & entry_ptr->output_mask; i < argcnt; i++, m1 = m1 >> 1) @@ -563,21 +965,21 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m } va_end(var); if (dst) - n += extarg_getsize((void *)&status, xc_status, dst); + n += extarg_getsize((void *)&status, gtm_status, dst); ENSURE_STP_FREE_SPACE(n); - /* convert return values */ + /* Convert return values */ VAR_START(var, argcnt); for (i = 0, m1 = mask & entry_ptr->output_mask; i < argcnt; i++, m1 = m1 >> 1) { v = va_arg(var, mval *); if (m1 & 1) - extarg2mval((void *)param_list->arg[i], entry_ptr->parms[i], v); + extarg2mval((void *)param_list->arg[i], entry_ptr->parms[i], v, FALSE, TRUE); } va_end(var); if (dst) { - if (entry_ptr->return_type != xc_void) - extarg2mval((void *)status, entry_ptr->return_type, dst); + if (entry_ptr->return_type != gtm_void) + extarg2mval((void *)status, entry_ptr->return_type, dst, FALSE, FALSE); else { memcpy(str_buffer, PACKAGE_ENV_PREFIX, SIZEOF(PACKAGE_ENV_PREFIX)); @@ -597,9 +999,9 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m * This part of code is for more safety. We should * not come into this path at all. */ - rts_error(VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer)); } - rts_error(VARLSTCNT(6) ERR_XCVOIDRET, 4, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_XCVOIDRET, 4, LEN_AND_STR(entry_ptr->call_name.addr), LEN_AND_STR(xtrnl_table_name)); } } diff --git a/sr_unix/op_horolog.c b/sr_unix/op_horolog.c index 7dfa4a2..2206497 100644 --- a/sr_unix/op_horolog.c +++ b/sr_unix/op_horolog.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,6 +10,7 @@ ****************************************************************/ #include "mdef.h" +#include #include "gtm_time.h" #include "stringpool.h" #include "op.h" @@ -19,13 +20,15 @@ GBLREF spdesc stringpool; void op_horolog(mval *s) { - uint4 days; - time_t seconds; + uint4 days; + time_t seconds; + struct timeval tv; assert (stringpool.free <= stringpool.top); assert (stringpool.free >= stringpool.base); ENSURE_STP_FREE_SPACE(MAXNUMLEN + 1); - seconds = time(0); + gettimeofday(&tv, NULL); + seconds = tv.tv_sec; dollarh(seconds, &days, &seconds); s->str.addr = (char *) stringpool.free; stringpool.free = i2asc(stringpool.free, days); diff --git a/sr_unix/op_job.c b/sr_unix/op_job.c index aadb523..5fd3a61 100644 --- a/sr_unix/op_job.c +++ b/sr_unix/op_job.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,18 +31,43 @@ #include "io.h" #include "mvalconv.h" +#include "gdsroot.h" +#include "gdskill.h" +#include "gdsbt.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsfhead.h" +#include "gdscc.h" +#include "filestruct.h" +#include "buddy_list.h" /* needed for tp.h */ +#include "jnl.h" +#include "hashtab_int4.h" /* needed for tp.h */ +#include "tp.h" +#include "send_msg.h" +#include "gtmmsg.h" /* for gtm_putmsg() prototype */ +#include "change_reg.h" +#include "setterm.h" +#include "getzposition.h" +#ifdef DEBUG +#include "have_crit.h" /* for the TPNOTACID_CHECK macro */ +#endif + +void job_timer_handler(void); + GBLDEF short jobcnt = 0; GBLDEF volatile boolean_t ojtimeout = TRUE; -GBLREF uint4 dollar_zjob; -GBLREF int4 outofband; +GBLREF uint4 dollar_trestart; GBLREF int dollar_truth; -GBLREF boolean_t job_try_again; - +GBLREF uint4 dollar_zjob; +GBLREF int4 outofband; static int4 tid; /* Job Timer ID */ -void job_timer_handler(void); -#define MAX_CHAR_CAPACITY 0xFF +error_def(ERR_TEXT); +error_def(ERR_JOBFAIL); +error_def(ERR_NULLENTRYREF); + +#define JOBTIMESTR "JOB time too long" /* * --------------------------------------------------- @@ -55,7 +80,6 @@ void job_timer_handler(void) ojtimeout = TRUE; } - /* * --------------------------------------------------- * Job command main entry point @@ -68,27 +92,25 @@ int op_job(int4 argcnt, ...) mval *label, *inp; int4 offset; mval *routine, *param_buf; - int4 timeout; /* timeout in seconds */ - int4 msec_timeout; /* timeout in milliseconds */ + int4 timeout; /* timeout in seconds */ + int4 msec_timeout; /* timeout in milliseconds */ boolean_t timed, single_attempt, non_exit_return; unsigned char buff[128], *c; int4 status, exit_stat, term_sig, stop_sig; - pid_t zjob_pid = 0; /* zjob_pid should exactly match in type with child_pid(ojstartchild.c) */ + pid_t zjob_pid = 0; /* zjob_pid should exactly match in type with child_pid(ojstartchild.c) */ int pipe_fds[2], pipe_status; -#ifdef _BSD +# ifdef _BSD union wait wait_stat; -#else +# else int4 wait_stat; -#endif - +# endif job_params_type job_params; char combuf[128]; mstr command; job_parm *jp; + DCL_THREADGBL_ACCESS; - error_def(ERR_TEXT); - error_def(ERR_JOBFAIL); - + SETUP_THREADGBL_ACCESS; VAR_START(var, argcnt); assert(argcnt >= 5); label = va_arg(var, mval *); @@ -97,37 +119,43 @@ int op_job(int4 argcnt, ...) param_buf = va_arg(var, mval *); timeout = va_arg(var, int4); /* in seconds */ argcnt -= 5; - /* initialize $zjob = 0, in case JOB fails */ dollar_zjob = 0; - MV_FORCE_DEFINED(label); MV_FORCE_DEFINED(routine); MV_FORCE_DEFINED(param_buf); - /* create a pipe to channel the PID of the jobbed off process(J) from middle level - * process(M) to the current process (P) */ + * process(M) to the current process (P) + */ OPEN_PIPE(pipe_fds, pipe_status); if (-1 == pipe_status) { va_end(var); - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error creating pipe"), errno); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error creating pipe"), errno); } jobcnt++; command.addr = &combuf[0]; - /* Setup job parameters by parsing param_buf and using label, offset, routine, & timeout). */ job_params.routine = routine->str; job_params.label = label->str; job_params.offset = offset; ojparams(param_buf->str.addr, &job_params); - + /* + * Verify that entryref to JOB command is not NULL. + */ + if (!job_params.routine.len) + { + va_end(var); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JOBFAIL, 0, ERR_NULLENTRYREF, 0); + } /* Clear the buffers */ flush_pio(); - /* Start the timer */ ojtimeout = FALSE; - single_attempt = FALSE; + if (timeout < 0) + timeout = 0; + else if (TREF(tpnotacidtime) < timeout) + TPNOTACID_CHECK(JOBTIMESTR); if (NO_M_TIMEOUT == timeout) { timed = FALSE; @@ -138,10 +166,7 @@ int op_job(int4 argcnt, ...) msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) start_timer((TID)&tid, msec_timeout, job_timer_handler, 0, NULL); - else - single_attempt = TRUE; } - if (argcnt) { jp = job_params.parms = (job_parm *)malloc(SIZEOF(job_parm) * argcnt); @@ -159,49 +184,54 @@ int op_job(int4 argcnt, ...) } else job_params.parms = 0; va_end(var); - - assert(joberr_tryagain + 1 == joberr_end); /* they must be adjacent and the last two */ - assert((joberr_tryagain * 2 - 1) < MAX_CHAR_CAPACITY); /* Setup parameters and start the job */ - do + job_errno = -1; + non_exit_return = FALSE; + status = ojstartchild(&job_params, argcnt, &non_exit_return, pipe_fds); + if (!non_exit_return) { - job_try_again = FALSE; - non_exit_return = FALSE; - status = ojstartchild(&job_params, argcnt, &non_exit_return, pipe_fds); - if (status && !non_exit_return) - { - /* check if it was a try_again kind of failure */ #ifdef _BSD - assert(SIZEOF(wait_stat) == SIZEOF(int4)); - wait_stat.w_status = status; - /* waitpid() in ojstartchild() expects an int wait_status whereas the WIF* macros expect a - * union wait_stat as an arg */ + assert(SIZEOF(wait_stat) == SIZEOF(int4)); + wait_stat.w_status = status; + /* waitpid in ojstartchild() expects an int wait_status whereas the WIF* macros expect a union wait_stat as an + * argument. + */ #else - wait_stat = status; + wait_stat = status; #endif - if (WIFEXITED(wait_stat) && (joberr_tryagain < (exit_stat = WEXITSTATUS(wait_stat)))) - { - /* one of try-again situations */ - job_try_again = TRUE; - exit_stat -= joberr_tryagain; - assert(exit_stat < joberr_stp); - } + exit_stat = WIFEXITED(wait_stat) ? WEXITSTATUS(wait_stat) : 0; + /* Middle process uses pipe(pipe_fds) + * a) to communicate a PID of grandchild to its parent process(i.e. current process) + * b) to communicate an errno to current process if any required setup for the grandchild is failed. + * exit status joberr_pipe_mp of middle process means it failed WRITE operation on pipe used to communicate + * grandchild's PID to current process. In this scenario, grandchild is terminated and middle process do not + * communicate errno to current process. Hence this process do not read the errno for joberr_pipe_mp exit status. + */ + if (status && joberr_pipe_mp != exit_stat) + { + DOREADRC(pipe_fds[0], &job_errno, SIZEOF(job_errno), pipe_status); + if (0 < pipe_status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, joberrs[exit_stat].len, + joberrs[exit_stat].msg, 2, errno); } - } while (!single_attempt && status && !ojtimeout && job_try_again); + } if (argcnt) free(job_params.parms); if (timed && !ojtimeout) cancel_timer((TID)&tid); - - /* the child process (M), that wrote to pipe, would have been exited by now */ - CLOSEFILE_RESET(pipe_fds[1], pipe_status); /* close the write-end to make the following read non-blocking; - * also resets "pipe_fds[1]" to FD_INVALID */ + /* the child process (M), that wrote to pipe, would have been exited by now. Close the write-end to make the following read + * non-blocking. also resets "pipe_fds[1]" to FD_INVALID + */ + CLOSEFILE_RESET(pipe_fds[1], pipe_status); assert(SIZEOF(pid_t) == SIZEOF(zjob_pid)); - DOREADRC(pipe_fds[0], &zjob_pid, SIZEOF(zjob_pid), pipe_status); /* read jobbed off PID from pipe */ - if (0 < pipe_status) /* empty pipe (pipe_status == -1) is ignored and not reported as error */ - rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error reading from pipe"), errno); - CLOSEFILE_RESET(pipe_fds[0], pipe_status); /* release the pipe; also resets "pipe_fds[0]" to FD_INVALID */ + DOREADRC(pipe_fds[0], &zjob_pid, SIZEOF(zjob_pid), pipe_status); + /* empty pipe (pipe_status == -1) is ignored and not reported as error */ + if (0 < pipe_status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, + LEN_AND_LIT("Error reading zjobid from pipe"), errno); + /* release the pipe; also resets "pipe_fds[0]" to FD_INVALID */ + CLOSEFILE_RESET(pipe_fds[0], pipe_status); if (status) { if (timed) /* $test should be modified only for timed job commands */ @@ -209,7 +239,7 @@ int op_job(int4 argcnt, ...) if (non_exit_return) { if (TIMEOUT_ERROR != status) /* one of errno returns, not the wait_status/timeout situation */ - rts_error(VARLSTCNT(3) ERR_JOBFAIL, 0, status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBFAIL, 0, status); else return FALSE; } else /* wait_status from the child */ @@ -219,44 +249,54 @@ int op_job(int4 argcnt, ...) term_sig = WTERMSIG(wait_stat); /* signal that caused the termination */ memcpy(buff, joberrs[joberr_sig].msg, joberrs[joberr_sig].len); c = i2asc(&buff[joberrs[joberr_sig].len], term_sig); - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff); + assert(FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff); } else if (WIFSTOPPED(wait_stat)) /* child was STOPped */ { stop_sig = WSTOPSIG(wait_stat); /* signal that caused the stop */ memcpy(buff, joberrs[joberr_stp].msg, joberrs[joberr_stp].len); c = i2asc(&buff[joberrs[joberr_stp].len], stop_sig); - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff); + assert(FALSE); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff); } else if (WIFEXITED(wait_stat)) /* child EXITed normally */ { if (exit_stat < joberr_stp) /* one of our EXITs */ { - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, - joberrs[exit_stat].len, joberrs[exit_stat].msg); + if (-1 == job_errno) + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, + joberrs[exit_stat].len, + joberrs[exit_stat].msg); + } else + { + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, + joberrs[exit_stat].len, + joberrs[exit_stat].msg, + job_errno); + + } } else /* unknown exit status */ { assert(FALSE); util_out_print("Unknown exit status !UL (status = !UL)", TRUE, exit_stat, status); - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, joberrs[joberr_gen].len, joberrs[joberr_gen].msg); } } else { assert(FALSE); util_out_print("Unknown wait status !UL", TRUE, status); - rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, joberrs[joberr_gen].len, joberrs[joberr_gen].msg); } - } } else { if (timed) dollar_truth = 1; - assert(0 < zjob_pid); dollar_zjob = zjob_pid; return TRUE; } - return FALSE; /* This will never get executed, added to make compiler happy */ } diff --git a/sr_unix/op_setextract.c b/sr_unix/op_setextract.c index 49dfa23..820c87a 100644 --- a/sr_unix/op_setextract.c +++ b/sr_unix/op_setextract.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2009 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,8 @@ GBLREF spdesc stringpool; GBLREF boolean_t badchar_inhibit; +error_def(ERR_MAXSTRLEN); + /* * ---------------------------------------------------------- * Set version of $extract @@ -37,11 +39,10 @@ GBLREF boolean_t badchar_inhibit; */ void op_setextract(mval *src, mval *expr, int schar, int echar, mval *dst) { - int srclen, padlen, pfxlen, sfxoff, sfxlen, dstlen, bytelen, skip, char_len; + size_t dstlen, padlen; + int pfxlen, sfxoff, sfxlen, skip, bytelen, srclen, char_len; unsigned char *srcptr, *srcbase, *srctop, *straddr; - error_def(ERR_MAXSTRLEN); - padlen = pfxlen = sfxlen = 0; MV_FORCE_STR(expr); /* Expression to put into piece place */ if (MV_DEFINED(src)) @@ -51,41 +52,40 @@ void op_setextract(mval *src, mval *expr, int schar, int echar, mval *dst) } else /* Source is not defined -- treat as a null string */ srclen = 0; schar = MAX(schar, 1); /* schar starts at 1 at a minimum */ - /* There are four cases in the spec: - 1) schar > echar or echar < 1 -- glvn and naked indicator are not changed. This is - handled by generated code in m_set - 2) echar >= schar-1 > $L(src) -- dst = src_$J("",schar-1-$L(src))_expr - 3) schar-1 <= $L(src) < echar -- dst = $E(src,1,schar-1)_expr - 4) All others -- dst = $E(src,1,schar-1)_expr_$E(src,echar+1,$L(src)) - */ + * 1) schar > echar or echar < 1 -- glvn and naked indicator are not changed. This is + * handled by generated code in m_set + * 2) echar >= schar-1 > $L(src) -- dst = src_$J("",schar-1-$L(src))_expr + * 3) schar-1 <= $L(src) < echar -- dst = $E(src,1,schar-1)_expr + * 4) All others -- dst = $E(src,1,schar-1)_expr_$E(src,echar+1,$L(src)) + */ srcbase = (unsigned char *)src->str.addr; srctop = srcbase + srclen; - for (srcptr = srcbase, skip = schar - 1; (skip > 0 && srcptr < srctop); --skip) - { /* skip the first schar - 1 characters */ + for (srcptr = srcbase, skip = schar - 1; ((0 < skip) && (srcptr < srctop)); --skip) + { /* skip the first schar - 1 characters */ if (!UTF8_VALID(srcptr, srctop, bytelen) && !badchar_inhibit) utf8_badchar(0, srcptr, srctop, 0, NULL); srcptr += bytelen; } - pfxlen = (int)(srcptr - srcbase); - if (skip > 0) - { /* Case #2: schar is past the string length. echar test handled in generated code. - Should be padded with as many spaces as characters remained to be skipped */ - padlen = skip; - } - for (skip = echar - schar + 1; (skip > 0 && srcptr < srctop); --skip) - { /* skip up to the character position echar */ + pfxlen = INTCAST(srcptr - srcbase); + if (0 < skip) + /* Case #2: schar is past the string length. echar test handled in generated code. + * Should be padded with as many spaces as characters remained to be skipped + */ + padlen = (size_t)skip; + for (skip = echar - schar + 1; (0 < skip) && (srcptr < srctop); --skip) + { /* skip up to the character position echar */ if (!UTF8_VALID(srcptr, srctop, bytelen) && !badchar_inhibit) utf8_badchar(0, srcptr, srctop, 0, NULL); srcptr += bytelen; } char_len = 0; - if (skip <= 0) - { /* Case #4: echar is within the string length, suffix to be added */ - sfxoff = (int)(srcptr - srcbase); - sfxlen = (int)(srctop - srcptr); - if (!badchar_inhibit && sfxlen > 0) - { /* validate the suffix, and we can compute char_len as well */ + if (0 >= skip) + { /* Case #4: echar is within the string length, suffix to be added */ + sfxoff = INTCAST(srcptr - srcbase); + sfxlen = INTCAST(srctop - srcptr); + if (!badchar_inhibit && (0 str.char_len; } } - /* Calculate total string len */ - dstlen = pfxlen + padlen + expr->str.len + sfxlen; - if (dstlen > MAX_STRLEN) + dstlen = (size_t)pfxlen + padlen + (size_t)expr->str.len + (size_t)sfxlen; + if (MAX_STRLEN < dstlen) rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); - ENSURE_STP_FREE_SPACE(dstlen); - + ENSURE_STP_FREE_SPACE((int)dstlen); srcbase = (unsigned char *)src->str.addr; straddr = stringpool.free; - if (0 < pfxlen) - { /* copy prefix */ + { /* copy prefix */ memcpy(straddr, srcbase, pfxlen); straddr += pfxlen; } if (0 < padlen) - { /* insert padding */ + { /* insert padding */ memset(straddr, ' ', padlen); straddr += padlen; } if (0 < expr->str.len) - { /* copy expression */ + { /* copy expression */ memcpy(straddr, expr->str.addr, expr->str.len); straddr += expr->str.len; } if (0 < sfxlen) - { /* copy suffix */ + { /* copy suffix */ memcpy(straddr, srcbase + sfxoff, sfxlen); straddr += sfxlen; } - assert(straddr - stringpool.free == dstlen); + assert((straddr - stringpool.free) == dstlen); MV_INIT_STRING(dst, straddr - stringpool.free, (char *)stringpool.free); if (0 < char_len) { diff --git a/sr_unix/op_setp1.c b/sr_unix/op_setp1.c index a5b78bd..31ba31e 100644 --- a/sr_unix/op_setp1.c +++ b/sr_unix/op_setp1.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2010 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -37,6 +37,8 @@ GBLREF int cs_small_pcs; /* chars scanned by small scan */ # define INCR_COUNT(x,y) #endif +error_def(ERR_MAXSTRLEN); + /* * ---------------------------------------------------------- * Fast path setpiece when delimiter is one (lit) char replacing @@ -55,7 +57,8 @@ GBLREF int cs_small_pcs; /* chars scanned by small scan */ */ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) { - int len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, str_len, delim_cnt, pfx_scan_offset; + size_t str_len, delim_cnt; + int len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, pfx_scan_offset; int dlmlen, cpy_cache_lines, mblen; unsigned char *start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx; boolean_t do_scan, delim_last_scan, valid_char; @@ -64,41 +67,38 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) delimfmt ldelim; DCL_THREADGBL_ACCESS; - error_def(ERR_MAXSTRLEN); - SETUP_THREADGBL_ACCESS; assert(gtm_utf8_mode); do_scan = FALSE; cpy_cache_lines = -1; ldelim.unichar_val = delim; - if (!UTF8_VALID(ldelim.unibytes_val, (ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val)), dlmlen) && - !badchar_inhibit) - { /* The delimiter is a bad character so error out if badchar not inhibited */ + if (!UTF8_VALID(ldelim.unibytes_val, (ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val)), dlmlen) + && !badchar_inhibit) + { /* The delimiter is a bad character so error out if badchar not inhibited */ UTF8_BADCHAR(0, ldelim.unibytes_val, ldelim.unibytes_val + SIZEOF(ldelim.unibytes_val), 0, NULL); } - MV_FORCE_STR(expr); /* Expression to put into piece place */ if (MV_DEFINED(src)) { /* We have 3 possible scenarios: - 1) The source string is null. Nothing to do but proceed to building output. - 2) If the requested piece is larger than can be cached by op_fnp1, call fnp1 - for the maximum piece possible, use the cache info to "prime the pump" and - then process the rest of the string ourselves. - 3) If the requested piece can be obtained from the cache, call op_fnp1 to validate - and rebuild the cache if necessary and then retrieve the necessary info from - the fnpc cache. - */ + * 1) The source string is null. Nothing to do but proceed to building output. + * 2) If the requested piece is larger than can be cached by op_fnp1, call fnp1 + * for the maximum piece possible, use the cache info to "prime the pump" and + * then process the rest of the string ourselves. + * 3) If the requested piece can be obtained from the cache, call op_fnp1 to validate + * and rebuild the cache if necessary and then retrieve the necessary info from + * the fnpc cache. + */ MV_FORCE_STR(src); /* Make sure is string prior to length check */ if (0 == src->str.len) { /* We have a null source string */ pfx_str_len = sfx_str_len = sfx_start_offset = 0; - delim_cnt = ind - 1; + delim_cnt = (0 < ind) ? (size_t)ind - 1 : 0; } else if (FNPC_ELEM_MAX >= ind) { /* 3) Best of all possible cases. The op_fnp1 can do most of our work for us - and we can preload the cache on the new string to help its subsequent - uses along as well. - */ + * and we can preload the cache on the new string to help its subsequent + * uses along as well. + */ SETWON; op_fnp1(src, delim, ind, &dummymval); SETWOFF; @@ -108,8 +108,8 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) assert(cfnpc->delim == delim); assert(0 < cfnpc->npcs); /* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran - out of text or #3 piece is beyond what can be cached - */ + * out of text or #3 piece is beyond what can be cached + */ if (cfnpc->npcs >= ind) { /* #1 The piece we want is totally within the cache which is good news */ pfx_str_len = cfnpc->pstart[ind - 1]; @@ -120,21 +120,21 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) cpy_cache_lines = ind - 1; } else { /* #2 The string was too short so the cache does not contain our string. This means - that the prefix becomes any text that IS in the cache and we set the delim_cnt - to be the number of missing pieces so the delimiters can be put in as part of the - prefix when we build the new string. - */ + * that the prefix becomes any text that IS in the cache and we set the delim_cnt + * to be the number of missing pieces so the delimiters can be put in as part of the + * prefix when we build the new string. + */ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen; - delim_cnt = ind - cfnpc->npcs; + delim_cnt = (size_t)(ind - cfnpc->npcs); sfx_start_offset = 0; sfx_str_len = 0; cpy_cache_lines = cfnpc->npcs; } } else { /* 2) We have a element that would not be able to be in the fnpc cache. Go ahead - and call op_fnp1 to get cache info up to the maximum and then we will continue - the scan on our own. - */ + * and call op_fnp1 to get cache info up to the maximum and then we will continue + * the scan on our own. + */ SETWON; op_fnp1(src, delim, FNPC_ELEM_MAX, &dummymval); SETWOFF; @@ -145,55 +145,52 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) assert(0 < cfnpc->npcs); if (FNPC_ELEM_MAX > cfnpc->npcs) { /* We ran out of text so the scan is complete. This is basically the same - as case #2 above. - */ + * as case #2 above. + */ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - dlmlen; - delim_cnt = ind - cfnpc->npcs; + delim_cnt = (size_t)(ind - cfnpc->npcs); sfx_start_offset = 0; sfx_str_len = 0; cpy_cache_lines = cfnpc->npcs; } else { /* We have a case where the piece we want cannot be kept in cache. In the special - case where there is no more text to handle, we don't need to scan further. Otherwise - we prime the pump and continue the scan where the cache left off. - */ - if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len) - { /* Normal case where we prime the pump */ + * case where there is no more text to handle, we don't need to scan further. Otherwise + * we prime the pump and continue the scan where the cache left off. + */ + if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len) /* Note assignment */ + /* Normal case where we prime the pump */ do_scan = TRUE; - } else + else { /* Special case -- no more text to scan */ pfx_str_len = cfnpc->pstart[FNPC_ELEM_MAX] - dlmlen; sfx_start_offset = 0; sfx_str_len = 0; } - delim_cnt = ind - FNPC_ELEM_MAX; + delim_cnt = (size_t)ind - FNPC_ELEM_MAX; cpy_cache_lines = FNPC_ELEM_MAX; } - } } else { /* Source is not defined -- treat as a null string */ pfx_str_len = sfx_str_len = sfx_start_offset = 0; - delim_cnt = ind - 1; + delim_cnt = (size_t)ind - 1; } - /* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been - set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters - still need to be processed. - */ + * set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters + * still need to be processed. + */ if (do_scan) { /* Scan the line isolating prefix piece, and end of the - piece being replaced - */ + * piece being replaced + */ COUNT_EVENT(cs_small); end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset; end_src = (unsigned char *)src->str.addr + src->str.len; - /* The compiler would unroll this loop this way anyway but we want to - adjust the start_sfx pointer after the loop but only if we have gone - into it at least once. - */ - if (0 < delim_cnt && start_sfx < end_src) + * adjust the start_sfx pointer after the loop but only if we have gone + * into it at least once. + */ + if ((0 < delim_cnt) && (start_sfx < end_src)) { do { @@ -204,16 +201,16 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) valid_char = UTF8_VALID(start_sfx, end_src, mblen); /* Length of next char */ if (!valid_char) { /* Next character is not valid unicode. If badchar error is not inhibited, - signal it now. If it is inhibited, just treat the character as a single - character and continue. - */ + * signal it now. If it is inhibited, just treat the character as a single + * character and continue. + */ if (!badchar_inhibit) utf8_badchar(0, start_sfx, end_src, 0, NULL); assert(1 == mblen); } /* Getting mblen first allows us to do quick length compare before the - heavier weight memcmp call. - */ + * heavier weight memcmp call. + */ assert(0 < mblen); if (mblen == dlmlen && 0 == memcmp(start_sfx, ldelim.unibytes_val, dlmlen)) { @@ -225,38 +222,35 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) } start_sfx += dlmlen; delim_cnt--; - } while (0 < delim_cnt && start_sfx < end_src); - + } while ((0 < delim_cnt) && (start_sfx < end_src)); /* We have to backup up the suffix start pointer except under the condition - that the last character in the buffer is the last delimiter we were looking - for. - */ - if (0 == delim_cnt || start_sfx < end_src || !delim_last_scan) + * that the last character in the buffer is the last delimiter we were looking + * for. + */ + if ((0 == delim_cnt) || (start_sfx < end_src) || !delim_last_scan) start_sfx -= dlmlen; /* Back up suffix to include delimiter char */ - /* If we scanned to the end (no text left) and still have delimiters to - find, the entire src text should be part of the prefix */ - if (start_sfx >= end_src && 0 < delim_cnt) + * find, the entire src text should be part of the prefix + */ + if ((start_sfx >= end_src) && (0 < delim_cnt)) { end_pfx = start_sfx; if (delim_last_scan) /* if last char was delim, reduce delim cnt */ --delim_cnt; } - } else { /* If not doing any token finding, then this count becomes the number - of tokens to output. Adjust accordingly. - */ - if (0 > --delim_cnt) - delim_cnt = 0; + * of tokens to output. Adjust accordingly. + */ + if (0 < delim_cnt) + --delim_cnt; } - INCR_COUNT(cs_small_pcs, ind - delim_cnt); - + INCR_COUNT(cs_small_pcs, (int)((size_t)ind - delim_cnt)); /* Now having the following situation: - end_pfx -> end of the prefix piece including delimiter - start_sfx -> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none - */ + * end_pfx -> end of the prefix piece including delimiter + * start_sfx -> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none + */ pfx_str_len = (int)(end_pfx - (unsigned char *)src->str.addr); if (0 > pfx_str_len) pfx_str_len = 0; @@ -265,54 +259,47 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) if (0 > sfx_str_len) sfx_str_len = 0; } - /* Calculate total string len. delim_cnt has needed padding delimiters for null fields */ - str_len = expr->str.len + pfx_str_len + (delim_cnt * dlmlen) + sfx_str_len; - if (str_len > MAX_STRLEN) + str_len = (size_t)expr->str.len + (size_t)pfx_str_len + (delim_cnt * (size_t)dlmlen) + (size_t)sfx_str_len; + if (MAX_STRLEN < str_len) rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); - ENSURE_STP_FREE_SPACE(str_len); + ENSURE_STP_FREE_SPACE((int)str_len); str_addr = stringpool.free; start_pfx = (unsigned char *)src->str.addr; - /* copy prefix */ if (0 < pfx_str_len) { memcpy(str_addr, src->str.addr, pfx_str_len); str_addr += pfx_str_len; } - /* copy delimiters */ - while (delim_cnt-- > 0) + while (0 < delim_cnt--) { memcpy(str_addr, ldelim.unibytes_val, dlmlen); str_addr += dlmlen; } - /* copy expression */ if (0 < expr->str.len) { memcpy(str_addr, expr->str.addr, expr->str.len); str_addr += expr->str.len; } - /* copy suffix */ if (0 < sfx_str_len) { memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len); str_addr += sfx_str_len; } - - assert(str_addr - stringpool.free == str_len); + assert((str_addr - stringpool.free) == str_len); dst->mvtype = MV_STR; dst->str.len = INTCAST(str_addr - stringpool.free); dst->str.addr = (char *)stringpool.free; stringpool.free = str_addr; - /* If available, update the cache information for this newly created mval to hopefully - give it a head start on its next usage. Note that we can only copy over the cache info - for the prefix. We cannot include information for the 'expression' except where it starts - because the expression could itself contain delimiters that would be found on a rescan. - */ + * give it a head start on its next usage. Note that we can only copy over the cache info + * for the prefix. We cannot include information for the 'expression' except where it starts + * because the expression could itself contain delimiters that would be found on a rescan. + */ if (0 < cpy_cache_lines) { pfnpc = cfnpc; /* pointer for src mval's cache */ @@ -323,15 +310,14 @@ void op_setp1(mval *src, int delim, mval *expr, int ind, mval *dst) cfnpc = &(TREF(fnpca)).fnpcs[0]; (TREF(fnpca)).fnpcsteal = cfnpc + 1; /* -> next element to steal */ } while (cfnpc == pfnpc); /* Make sure we don't step on ourselves */ - cfnpc->last_str = dst->str; /* Save validation info */ cfnpc->delim = delim; cfnpc->npcs = cpy_cache_lines; dst->fnpc_indx = cfnpc->indx + 1; /* Save where we are putting this element - (1 based index in mval so 0 isn't so common) */ + * (1 based index in mval so 0 isn't so common) + */ memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * SIZEOF(unsigned int)); } else - { /* No cache available -- just reset index pointer to get fastest cache validation failure */ + /* No cache available -- just reset index pointer to get fastest cache validation failure */ dst->fnpc_indx = (unsigned char)-1; - } } diff --git a/sr_unix/op_setpiece.c b/sr_unix/op_setpiece.c index 8f20ba7..39d2883 100644 --- a/sr_unix/op_setpiece.c +++ b/sr_unix/op_setpiece.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2009 Fidelity Information Services, Inc * + * Copyright 2006, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,6 +21,8 @@ GBLREF boolean_t gtm_utf8_mode; GBLREF spdesc stringpool; +error_def(ERR_MAXSTRLEN); + /* -------------------------------------------------------------------- * NOTE: This module is a near copy of sr_port/op_setzpiece.c differing * only in that it calls "matchc" instead of "matchb" to do matching. @@ -46,13 +48,11 @@ GBLREF spdesc stringpool; */ void op_setpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval *dst) { - int match_res, len, src_len, str_len, delim_cnt; - int first_src_ind, second_src_ind, numpcs; + size_t str_len, delim_cnt; + int match_res, len, src_len, first_src_ind, second_src_ind, numpcs; unsigned char *match_ptr, *src_str, *str_addr, *tmp_str; delimfmt unichar; - error_def(ERR_MAXSTRLEN); - /* --- code start --- */ assert(gtm_utf8_mode); if (--first < 0) @@ -117,18 +117,18 @@ void op_setpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval * second_src_ind = (0 == match_res) ? -1 : INTCAST(match_ptr - (unsigned char *)src->str.addr - del->str.len); } } - delim_cnt = first; + delim_cnt = (size_t)first; /* Calculate total string len. */ - str_len = expr->str.len + (first_src_ind + del->str.len * delim_cnt); + str_len = (size_t)expr->str.len + ((size_t)first_src_ind + ((size_t)del->str.len * delim_cnt)); /* add len. of trailing chars past insertion point */ - if (second_src_ind >= 0) - str_len += (src->str.len - second_src_ind); - if (str_len > MAX_STRLEN) + if (0 <= second_src_ind) + str_len += (size_t)(src->str.len - second_src_ind); + if (MAX_STRLEN < str_len) { rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); return; } - ENSURE_STP_FREE_SPACE(str_len); + ENSURE_STP_FREE_SPACE((int)str_len); str_addr = stringpool.free; /* copy prefix */ if (first_src_ind) @@ -137,7 +137,7 @@ void op_setpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval * str_addr += first_src_ind; } /* copy delimiters */ - while (delim_cnt-- > 0) + while (0 < delim_cnt--) { memcpy(str_addr, del->str.addr, del->str.len); str_addr += del->str.len; @@ -146,14 +146,14 @@ void op_setpiece(mval *src, mval *del, mval *expr, int4 first, int4 last, mval * memcpy(str_addr, expr->str.addr, expr->str.len); str_addr += expr->str.len; /* copy trailing pieces */ - if (second_src_ind >= 0) + if (0 <= second_src_ind) { len = src->str.len - second_src_ind; tmp_str = (unsigned char *)src->str.addr + second_src_ind; memcpy(str_addr, tmp_str, len); str_addr += len; } - assert(str_addr - stringpool.free == str_len); + assert((str_addr - stringpool.free) == str_len); dst->mvtype = MV_STR; dst->str.len = INTCAST(str_addr - stringpool.free); dst->str.addr = (char *)stringpool.free; diff --git a/sr_unix/op_zedit.c b/sr_unix/op_zedit.c index 29ec3e5..9ef7204 100644 --- a/sr_unix/op_zedit.c +++ b/sr_unix/op_zedit.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,6 +25,7 @@ #include "stringpool.h" #include "setterm.h" #include "op.h" +#include "fork_init.h" GBLREF io_pair io_std_device; GBLREF mval dollar_zsource; @@ -58,26 +59,26 @@ void op_zedit(mval *v, mval *p) edt = GETENV("EDITOR"); if (!edt) edt = "editor"; - rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt)); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt)); } MV_FORCE_STR(v); MV_FORCE_STR(p); src.len = v->str.len; src.addr = v->str.addr; if (0 == src.len) - rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr); memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = es; pblk.buff_size = MAX_FBUFF; status = parse_file(&src, &pblk); if (!(status & 1)) - rts_error(VARLSTCNT(5) ERR_ZEDFILSPEC, 2, src.len, src.addr, status); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZEDFILSPEC, 2, src.len, src.addr, status); has_ext = 0 != (pblk.fnb & F_HAS_EXT); exp_dir = 0 != (pblk.fnb & F_HAS_DIR); if (!(pblk.fnb & F_HAS_NAME)) { assert(!has_ext); - rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, pblk.b_esl, pblk.buffer); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, pblk.b_esl, pblk.buffer); } if (!exp_dir) { @@ -96,14 +97,14 @@ void op_zedit(mval *v, mval *p) { typ = STR_LIT_LEN(DOTM); if (path_len + typ > MAX_FBUFF) - rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es); memcpy(&es[path_len], DOTM, STR_LIT_LEN(DOTM)); path_len += typ; } } else { if ((STR_LIT_LEN(DOTOBJ) == pblk.b_ext) && !MEMCMP_LIT(ptr + pblk.b_name, DOTOBJ)) - rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es); else if ((STR_LIT_LEN(DOTM) == pblk.b_ext) && !MEMCMP_LIT(ptr + pblk.b_name, DOTM)) typ = STR_LIT_LEN(DOTM); } @@ -139,7 +140,7 @@ void op_zedit(mval *v, mval *p) assert(ZRO_TYPE_SOURCE == srcdir->type); tslash = ('/' == srcdir->str.addr[srcdir->str.len - 1]) ? 0 : 1; if (path_len + srcdir->str.len + tslash >= SIZEOF(es)) - rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr); memmove(&es[ srcdir->str.len + tslash], &es[0], path_len); if (tslash) es[ srcdir->str.len ] = '/'; @@ -157,7 +158,7 @@ void op_zedit(mval *v, mval *p) act.sa_flags = 0; act.sa_handler = SIG_IGN; sigaction(SIGINT, &act, &intr); - childid = fork(); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + FORK(childid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ if (childid) { waitid = (int)childid; diff --git a/sr_unix/op_zmess.c b/sr_unix/op_zmess.c index e4829ad..1bd4233 100644 --- a/sr_unix/op_zmess.c +++ b/sr_unix/op_zmess.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,9 +17,64 @@ #include "error.h" #include "op.h" #include "mval2fao.h" -#include "tp_restart.h" +#include "gtmmsg.h" + +#define ZMESS_DISALLWD_LIST_SIZE 10 +#define FAO_BUFFER_SPACE 2048 +#define MAX_ERR_MSG_LEN 256 + +STATICFNDCL boolean_t is_disallowed(unsigned int errnum); + +STATICDEF unsigned int zmess_disallowed_list[ZMESS_DISALLWD_LIST_SIZE] = {0}; + +error_def(ERR_REPEATERROR); +error_def(ERR_TPRETRY); +error_def(ERR_JOBINTRRQST); +error_def(ERR_JOBINTRRETHROW); +error_def(ERR_UNSOLCNTERR); +error_def(ERR_CTRLY); +error_def(ERR_CTRLC); +error_def(ERR_CTRAP); +error_def(ERR_STACKCRIT); +error_def(ERR_SPCLZMSG); + +/* + * Returns whether an errnum is not allowed to be raised by ZMESSAGE. The errors on this list generally + * trigger additional processing by the error handler which either assumes certain context to be setup + * before the processing or does something which should not be triggered manually. + */ +STATICFNDEF boolean_t is_disallowed(unsigned int errnum) +{ + int i; /* search iterator */ + + if (0 == zmess_disallowed_list[0]) + { + /* + * Lazy initialization of the disallowed array + * The ERR_XXXX take value at runtime, hence individual assignments. + */ + i = 0; + zmess_disallowed_list[i++] = ERR_REPEATERROR; + zmess_disallowed_list[i++] = ERR_TPRETRY; + zmess_disallowed_list[i++] = ERR_JOBINTRRQST; + zmess_disallowed_list[i++] = ERR_JOBINTRRETHROW; + zmess_disallowed_list[i++] = ERR_UNSOLCNTERR; + zmess_disallowed_list[i++] = ERR_CTRLY; + zmess_disallowed_list[i++] = ERR_CTRLC; + zmess_disallowed_list[i++] = ERR_CTRAP; + zmess_disallowed_list[i++] = ERR_STACKCRIT; + zmess_disallowed_list[i++] = ERR_SPCLZMSG; + assert(ZMESS_DISALLWD_LIST_SIZE == i); + } + + /* linear search as the list is short */ + for (i = 0; i < ZMESS_DISALLWD_LIST_SIZE; ++i) + /* message severity doesn't matter */ + if ((zmess_disallowed_list[i] >> MSGSEVERITY) == (errnum >> MSGSEVERITY)) + return TRUE; + return FALSE; +} -#define FAO_BUFFER_SPACE 2048 void op_zmess(unsigned int cnt, ...) { @@ -31,30 +86,23 @@ void op_zmess(unsigned int cnt, ...) unsigned int errnum, j; int faocnt; - error_def(ERR_TPRETRY); - VAR_START(var, cnt); errnum = va_arg(var, int); cnt--; - if (ectl = err_check(errnum)) + if (NULL != (ectl = err_check(errnum))) /* note assignment */ { - assert((errnum & FACMASK(ectl->facnum)) && (MSGMASK(errnum, ectl->facnum) <= ectl->msg_cnt)); - j = MSGMASK(errnum, ectl->facnum); - eptr = ectl->fst_msg + j - 1; - + GET_MSG_INFO(errnum, ectl, eptr); faocnt = eptr->parm_count; faocnt = (faocnt > MAX_FAO_PARMS ? MAX_FAO_PARMS : faocnt); faocnt = mval2fao(eptr->msg, var, &fao[0], cnt, faocnt, buff, buff + SIZEOF(buff)); va_end(var); - if (faocnt != -1) - { - if (ERR_TPRETRY == errnum) - { /* A TP restart is being signalled. Set t_fail_hist just like a TRESTART command would */ - op_trestart_set_cdb_code(); - } - rts_error(VARLSTCNT(faocnt+2) errnum, faocnt, fao[0], fao[1], fao[2], fao[3], fao[4], fao[5], fao[6], - fao[7], fao[8], fao[9], fao[10], fao[11]); - } + if (0 <= faocnt) + if (is_disallowed(errnum)) + rts_error(VARLSTCNT(4 + faocnt) ERR_SPCLZMSG, 0, errnum, faocnt, fao[0], fao[1], fao[2], fao[3], + fao[4], fao[5], fao[6], fao[7], fao[8], fao[9], fao[10], fao[11]); + else + rts_error(VARLSTCNT(2 + faocnt) errnum, faocnt, fao[0], fao[1], fao[2], fao[3], fao[4], fao[5], + fao[6], fao[7], fao[8], fao[9], fao[10], fao[11]); } else { va_end(var); diff --git a/sr_unix/op_ztrigger.c b/sr_unix/op_ztrigger.c index 273e9c4..0724b1f 100644 --- a/sr_unix/op_ztrigger.c +++ b/sr_unix/op_ztrigger.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -61,6 +61,7 @@ #include "op_tcommit.h" /* for op_tcommit prototype */ #include "have_crit.h" #include "gvcst_protos.h" +#include "gtmimagename.h" LITREF mval literal_null; @@ -105,7 +106,7 @@ error_def(ERR_UNIMPLOP); void op_ztrigger(void) { - rts_error(VARLSTCNT(1) ERR_UNIMPLOP); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); } #else void op_ztrigger(void) @@ -119,6 +120,8 @@ void op_ztrigger(void) boolean_t write_logical_jnlrecs, jnl_format_done; boolean_t is_tpwrap; boolean_t lcl_implicit_tstart; /* local copy of the global variable "implicit_tstart" */ + boolean_t want_root_search = FALSE; + uint4 lcl_onln_rlbkd_cycle; gtm_trigger_parms trigparms; gvt_trigger_t *gvt_trigger; gvtr_invoke_parms_t gvtr_parms; @@ -133,7 +136,7 @@ void op_ztrigger(void) DCL_THREADGBL_ACCESS; if (gv_cur_region->read_only) - rts_error(VARLSTCNT(4) ERR_ZTRIGNOTRW, 2, REG_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_ZTRIGNOTRW, 2, REG_LEN_STR(gv_cur_region)); SETUP_THREADGBL_ACCESS; csa = cs_addrs; csd = csa->hdr; @@ -151,7 +154,7 @@ void op_ztrigger(void) } JNLPOOL_INIT_IF_NEEDED(csa, csd, cnl); assert(('\0' != gv_currkey->base[0]) && gv_currkey->end); - DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC; + DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVZTRIGFAIL); lcl_implicit_tstart = FALSE; assert(NULL != update_array); @@ -221,6 +224,14 @@ void op_ztrigger(void) UNW_MV_STENT_TO(save_msp, save_mv_chain); } } + /* finish off any pending root search from previous retry */ + REDO_ROOT_SEARCH_IF_NEEDED(want_root_search, cdb_status); + if (cdb_sc_normal != cdb_status) + { /* gvcst_root_search invoked from REDO_ROOT_SEARCH_IF_NEEDED ended up with a restart situation but did not + * actually invoke t_retry. Instead, it returned control back to us asking us to restart. + */ + goto retry; + } if (write_logical_jnlrecs) { /* Only write jnl recs if we are in fact journaling.. * skip_dbtriggers is set to TRUE for trigger unsupporting platforms. So, nodeflags will be set to skip @@ -272,6 +283,7 @@ void op_ztrigger(void) if ((NULL != save_msp) && (save_msp > msp)) UNW_MV_STENT_TO(save_msp, save_mv_chain); t_retry(cdb_status); + skip_INVOKE_RESTART = FALSE; } else { /* else: t_retry has already been done so no need to do that again but need to still invoke tp_restart * to complete pending "tprestart_state" related work. @@ -284,43 +296,19 @@ void op_ztrigger(void) rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); assert(0 == rc && TPRESTART_STATE_NORMAL == tprestart_state); } -# ifdef GTM_TRIGGER assert(0 < t_tries); if (lcl_implicit_tstart) { - assert((cdb_sc_normal != cdb_status) || (ERR_TPRETRY == gtm_trig_status)); - if (cdb_sc_normal == cdb_status) - { - DEBUG_ONLY(save_cdb_status = cdb_status); - cdb_status = t_fail_hist[t_tries - 1]; /* get the last restart code */ - } - assert(((cdb_sc_onln_rlbk1 != cdb_status) && (cdb_sc_onln_rlbk2 != cdb_status)) - || (TREF(dollar_zonlnrlbk) && !gv_target->root)); - if (cdb_sc_onln_rlbk1 == cdb_status) - { /* We are implicit transaction and online rollback update the database but did NOT take us to a - * different logical state. We've already done the restart, but the root is now reset to zero. Do - * root search to establish the new root - */ - ASSERT_BEGIN_OF_FRESH_TP_TRANS; /* ensures gvcst_root_search is the first thing done in the - * restarted transaction */ - GVCST_ROOT_SEARCH; - } else if (cdb_sc_onln_rlbk2 == cdb_status) - { /* Database was taken back to a different logical state and we are an implicit TP transaction. - * Issue DBROLLEDBACK error that the application programmer can catch and do the necessary stuff. - */ - assert(gtm_trigger_depth == tstart_trigger_depth); - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); - } + SET_WANT_ROOT_SEARCH(cdb_status, want_root_search); + assert(!skip_INVOKE_RESTART); /* if set to TRUE above, should have been reset by t_retry */ } -# endif - assert(!skip_INVOKE_RESTART); /* if set to TRUE above, should have been reset by t_retry */ /* At this point, we can be in TP only if we implicitly did a tstart in op_ztrigger trying to drive a trigger. * Assert that. So reinvoke the T_BEGIN call only in case of TP. For non-TP, update_trans is unaffected by * t_retry. */ assert(!dollar_tlevel || lcl_implicit_tstart); if (dollar_tlevel) - { + { /* gvcst_kill has similar code and should be maintained in parallel */ tp_set_sgm(); /* set sgm_info_ptr & first_sgm_info for TP start */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVZTRIGFAIL); } diff --git a/sr_unix/osf1alpha_badd.txt b/sr_unix/osf1alpha_badd.txt index f694bda..0b4bd1a 100644 --- a/sr_unix/osf1alpha_badd.txt +++ b/sr_unix/osf1alpha_badd.txt @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2011, 2012 Fidelity Information Services, Inc # +# Copyright 2011, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -11,8 +11,9 @@ # Do not add any blank lines after this comment pro: TTTGEN.m%-r--r----- README.txt +dse%-r--r----- custom_errors_sample.txt gdehelp.dat%-r--r----- gdedefaults -gtm_descript.h%-r-xr-x--- gtm +gtm_common_defs.h%-r-xr-x--- gtm gtmcshrc.gtc%-r-xr-x--- gtmbase gtmhelp.dat%-r-xr-x--- gtmcshrc gtmsecshr%-r-xr-x--- gtmprofile @@ -20,13 +21,3 @@ gtmsecshr%-r-xr-x--- gtmprofile_preV54000 lke%-r--r----- libgtmutil.so semstat2%dr-xr-x--- plugin zzz_insert%-r--r----- so_locations - -pro/plugin: -zzz_insert%dr-xr-x--- o -zzz_insert%dr-xr-x--- r - -pro/plugin/gtmcrypt: -zzz_insert%-r--r----- source.tar - -pro/utf8: -lke -> ../lke%-r-xr-x--- libgtmutil.sl diff --git a/sr_unix/parse_file.c b/sr_unix/parse_file.c index 47523f1..1030085 100644 --- a/sr_unix/parse_file.c +++ b/sr_unix/parse_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,8 +14,11 @@ #include "gtm_inet.h" /* for struct in_addr */ #include "gtm_stat.h" #include "gtm_string.h" +#include "gtm_stdio.h" #include "gtm_unistd.h" +#include "gtm_socket.h" /* for using sockaddr and sockaddr_storage */ #include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "parse_file.h" #include "io.h" @@ -23,8 +26,18 @@ #include "eintr_wrappers.h" #include "trans_log_name.h" #include "setzdir.h" +#include "gtmmsg.h" /* for gtm_putmsg */ #define LOCALHOSTNAME "localhost" +#define LOCALHOSTNAME6 "::1" + +error_def(ERR_FILENOTFND); +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_PARBUFSM); +error_def(ERR_PARNORMAL); +error_def(ERR_SYSCALL); +error_def(ERR_TEXT); enum parse_state { @@ -40,7 +53,8 @@ GBLREF mval dollar_zdir; int4 parse_file(mstr *file, parse_blk *pblk) { struct stat statbuf; - struct hostent *hostinfo; + struct addrinfo *ai_ptr = NULL, *localhost_ai_ptr = NULL, *temp_ai_ptr = NULL; + struct addrinfo hints; mstr trans, tmp; int status, diff, local_node_len, query_node_len, node_name_len; parse_blk def; @@ -50,13 +64,10 @@ int4 parse_file(mstr *file, parse_blk *pblk) char def_string[MAX_FBUFF + 1]; boolean_t hasnode, hasdir, hasname, hasext, wilddir, wildname; enum parse_state state; - struct in_addr query_ip, localhost_ip, *local_ip; + struct sockaddr_storage query_sas; + struct sockaddr localhost_sa, *localhost_sa_ptr; mval def_trans; - - error_def(ERR_PARNORMAL); - error_def(ERR_PARBUFSM); - error_def(ERR_FILENOTFND); - error_def(ERR_SYSCALL); + int errcode; pblk->fnb = 0; assert(((unsigned int)pblk->buff_size + 1) <= (MAX_FBUFF + 1)); @@ -126,39 +137,61 @@ int4 parse_file(mstr *file, parse_blk *pblk) assert(':' == *(trans.addr + query_node_len)); memcpy(query_node_name, trans.addr, query_node_len); query_node_name[query_node_len] = 0; - local_ip = NULL; /* null value needed in case can't find query node (remote default) */ - if (NULL != (hostinfo = GETHOSTBYNAME(query_node_name))) - { /* We know about this node -- check further */ - query_ip = *(struct in_addr *)hostinfo->h_addr; - /* See if is a "localhost" (127.0.0.1 usually) node */ - if (NULL != (hostinfo = GETHOSTBYNAME(LOCALHOSTNAME))) + localhost_sa_ptr = NULL; /* null value needed if not find query node (remote default) */ + CLIENT_HINTS(hints); + if (0 != (errcode = getaddrinfo(query_node_name, NULL, &hints, &ai_ptr))) + ai_ptr = NULL; /* skip additional lookups */ + else + memcpy((sockaddr_ptr)&query_sas, ai_ptr->ai_addr, ai_ptr->ai_addrlen); + CLIENT_HINTS(hints); + if (0 == (errcode = getaddrinfo(LOCALHOSTNAME, NULL, &hints, &localhost_ai_ptr))) + { + if (0 == memcmp(localhost_ai_ptr->ai_addr, (sockaddr_ptr)&query_sas, + localhost_ai_ptr->ai_addrlen)) + localhost_sa_ptr = localhost_ai_ptr->ai_addr; + } + FREEADDRINFO(localhost_ai_ptr); + if (ai_ptr && !localhost_sa_ptr) + { /* Have not yet established this is not a local node -- check further */ + GETHOSTNAME(local_node_name, MAX_HOST_NAME_LEN, status); + if (-1 == status) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, + LEN_AND_LIT("gethostname"), CALLFROM, errno); + CLIENT_HINTS(hints); + if (0 != (errcode = getaddrinfo(local_node_name, NULL, &hints, &localhost_ai_ptr))) + localhost_ai_ptr = NULL; /* empty address list */ + for (temp_ai_ptr = localhost_ai_ptr; temp_ai_ptr!= NULL; + temp_ai_ptr = temp_ai_ptr->ai_next) { - localhost_ip = *(struct in_addr *)hostinfo->h_addr; - if (0 == memcmp(&localhost_ip, &query_ip, SIZEOF(struct in_addr))) - local_ip = &localhost_ip; - } - if (!local_ip) - { /* Have not yet established this as a local node -- check further */ - GETHOSTNAME(local_node_name, MAX_HOST_NAME_LEN, status); - if (-1 == status) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("gethostname"), - CALLFROM, errno); - if (NULL == (hostinfo = GETHOSTBYNAME(local_node_name))) - rts_error(VARLSTCNT(7) ERR_SYSCALL, 5, LEN_AND_LIT("gethostbyname"), - CALLFROM); - for (hostaddrlist = (char **) hostinfo->h_addr_list; ; hostaddrlist++) + if (0 == memcmp((sockaddr_ptr)&query_sas, temp_ai_ptr->ai_addr, + temp_ai_ptr->ai_addrlen)) { - local_ip = (struct in_addr *)*hostaddrlist; - if (!local_ip) /* End of list -- must be remote */ - break; - if (0 == memcmp(&query_ip, local_ip, SIZEOF(struct in_addr))) - break; /* Tiz truly a local node */ + localhost_sa_ptr = temp_ai_ptr->ai_addr; + break; /* Tiz truly a local node */ } } - } /* Else, unknown nodename -- treat as remote (probably fail later) */ - - if (!local_ip) /* Not local (or an unknown) host given */ + FREEADDRINFO(localhost_ai_ptr); + } + if (ai_ptr && !localhost_sa_ptr) + { + CLIENT_HINTS(hints); + if (0 != (errcode = getaddrinfo(LOCALHOSTNAME6, NULL, &hints, &localhost_ai_ptr))) + localhost_ai_ptr = NULL; /* empty address list */ + for (temp_ai_ptr = localhost_ai_ptr; temp_ai_ptr!= NULL; + temp_ai_ptr = temp_ai_ptr->ai_next) + { + if (0 == memcmp((sockaddr_ptr)&query_sas, temp_ai_ptr->ai_addr, + temp_ai_ptr->ai_addrlen)) + { + localhost_sa_ptr = temp_ai_ptr->ai_addr; + break; /* Tiz truly a local node */ + } + } + FREEADDRINFO(localhost_ai_ptr); + } + if (!localhost_sa_ptr) /* Not local (or an unknown) host given */ { /* Remote node specified -- don't apply any defaults */ + FREEADDRINFO(ai_ptr); pblk->l_node = trans.addr; pblk->b_node = node_name_len; pblk->l_dir = base; @@ -169,7 +202,7 @@ int4 parse_file(mstr *file, parse_blk *pblk) pblk->fnb |= (hasnode << V_HAS_NODE); return ERR_PARNORMAL; } - + FREEADDRINFO(ai_ptr); /* Remove local node name from filename buffer */ assert(0 < trans.len - node_name_len); memmove(trans.addr, node, trans.len - node_name_len); diff --git a/sr_unix/rc.h b/sr_unix/rc.h index a436091..e0708b3 100644 --- a/sr_unix/rc.h +++ b/sr_unix/rc.h @@ -14,7 +14,7 @@ * * Include file for the GTCM server (RC code). * - * $Header:$ + * $Header: /cvsroot/fis-gtm/gtm/sr_unix/rc.h,v 1.6 2013/10/23 03:49:30 tuskentower Exp $ * */ diff --git a/sr_unix/rc_cpt_ops.c b/sr_unix/rc_cpt_ops.c index 8b0ed49..e095387 100644 --- a/sr_unix/rc_cpt_ops.c +++ b/sr_unix/rc_cpt_ops.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -562,7 +562,7 @@ void rc_send_cpt(rc_xblk_hdr *head, rc_rsp_page *last_aq) /* Zero if no read op rc_cpt_lock(); GET_LONG(blknum, last_aq->pageaddr); if ((b = bt_get(blknum)) ? rc_read_stamp <= b->tn : - (rc_read_stamp <= ((th_rec *)((uchar_ptr_t)cs_addrs->th_base + cs_addrs->th_base->tnque.fl))->tn)) + (rc_read_stamp <= OLDEST_HIST_TN(cs_addrs))) { last_aq->hdr.a.erc.value = RC_NETERRRETRY; } diff --git a/sr_unix/recover_truncate.c b/sr_unix/recover_truncate.c index b0a8ad4..a2d13c2 100644 --- a/sr_unix/recover_truncate.c +++ b/sr_unix/recover_truncate.c @@ -35,6 +35,7 @@ #include "clear_cache_array.h" #include "is_proc_alive.h" #include "do_semop.h" +#include "anticipatory_freeze.h" /* needed for WRITE_EOF_BLOCK */ error_def(ERR_DBFILERR); error_def(ERR_MUTRUNCERROR); @@ -60,8 +61,11 @@ void recover_truncate(sgmnt_addrs *csa, sgmnt_data_ptr_t csd, gd_region* reg) udi = FILE_INFO(reg); assert((udi->grabbed_access_sem && (1 == (semval = semctl(udi->semid, 1, GETVAL)))) || csa->now_crit); /* Interrupted truncate scenario */ + if (NULL != csa->nl) + csa->nl->root_search_cycle++; old_total = csd->before_trunc_total_blks; /* Pre-truncate total_blks */ - old_size = (off_t)csd->before_trunc_file_size * DISK_BLOCK_SIZE; /* Pre-truncate file size (in bytes) */ + old_size = (off_t)SIZEOF_FILE_HDR(csd) /* Pre-truncate file size (in bytes) */ + + (off_t)old_total * csd->blk_size + DISK_BLOCK_SIZE; cur_total = csa->ti->total_blks; /* Actual total_blks right now */ cur_size = (off_t)gds_file_size(reg->dyn.addr->file_cntl) * DISK_BLOCK_SIZE; /* Actual file size right now (in bytes) */ new_total = csd->after_trunc_total_blks; /* Post-truncate total_blks */ diff --git a/sr_unix/recvpool_init.c b/sr_unix/recvpool_init.c index d085756..72da7cc 100644 --- a/sr_unix/recvpool_init.c +++ b/sr_unix/recvpool_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,6 +46,7 @@ #include "repl_msg.h" #include "gtmsource.h" #include "repl_instance.h" +#include "util.h" /* For OUT_BUFF_SIZE */ GBLREF jnlpool_addrs jnlpool; GBLREF recvpool_addrs recvpool; @@ -65,7 +66,7 @@ error_def(ERR_TEXT); #define MAX_RES_TRIES 620 /* Also defined in gvcst_init_sysops.c */ -#define REMOVE_OR_RELEASE_SEM(NEW_IPC, UDI) \ +#define REMOVE_OR_RELEASE_SEM(NEW_IPC) \ { \ if (NEW_IPC) \ remove_sem_set(RECV); \ @@ -78,6 +79,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) boolean_t shm_created, new_ipc = FALSE; char instfilename[MAX_FN_LEN + 1]; char machine_name[MAX_MCNAMELEN]; + char scndry_msg[OUT_BUFF_SIZE]; gd_region *r_save, *reg; int status, save_errno; union semun semarg; @@ -107,7 +109,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) * locks the same entity. * Should have already attached to journal pool only for receiver server startup or shutdown. Assert that. */ - assert(gtmrecv_options.start || gtmrecv_options.shut_down); + assert(gtmrecv_options.start || gtmrecv_options.shut_down || (GTMZPEEK == pool_user)); reg = recvpool.recvpool_dummy_reg = jnlpool.jnlpool_dummy_reg; } udi = FILE_INFO(reg); @@ -143,7 +145,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error creating recv pool"), REPL_SEM_ERRNO); + RTS_ERROR_LITERAL("Error creating recv pool"), errno); } /* Following will set semaphore RECV_ID_SEM value as GTM_ID. In case we have orphaned semaphore for some reason, * mupip rundown will be able to identify GTM semaphores checking the value and can remove. @@ -173,17 +175,21 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) } else { /* find create time of semaphore from the file header and check if the id is reused by others */ semarg.buf = &semstat; - if (-1 == semctl(repl_instance.recvpool_semid, 0, IPC_STAT, semarg)) + if (-1 == semctl(repl_instance.recvpool_semid, DB_CONTROL_SEM, IPC_STAT, semarg)) { save_errno = errno; ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(5) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, save_errno); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Receive Pool SEMID (%d)", + repl_instance.recvpool_semid); + rts_error(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, + ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno); } else if (semarg.buf->sem_ctime != repl_instance.recvpool_semid_ctime) { ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, - ERR_TEXT, 2, RTS_ERROR_TEXT("recvpool sem_ctime does not match")); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Creation time for Receive Pool SEMID (%d) is %d; Expected %d", + repl_instance.recvpool_semid, semarg.buf->sem_ctime, repl_instance.recvpool_semid_ctime); + rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg)); } udi->semid = repl_instance.recvpool_semid; udi->gt_sem_ctime = repl_instance.recvpool_semid_ctime; @@ -196,9 +202,10 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) { ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, - RTS_ERROR_LITERAL("Error with receive pool semaphores"), REPL_SEM_ERRNO); + RTS_ERROR_LITERAL("Error with receive pool semaphores"), errno); } udi->grabbed_access_sem = TRUE; + udi->counter_acc_incremented = TRUE; if (INVALID_SHMID == repl_instance.recvpool_shmid) { /* We have an INVALID shmid in the file header. There are three ways this can happen * @@ -228,9 +235,10 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) } else if (-1 == shmctl(repl_instance.recvpool_shmid, IPC_STAT, &shmstat)) { /* shared memory ID was removed form the system by an IPCRM command or we have a permission issue (or such) */ save_errno = errno; - REMOVE_OR_RELEASE_SEM(new_ipc, udi); + REMOVE_OR_RELEASE_SEM(new_ipc); ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); - rts_error(VARLSTCNT(5) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, save_errno); + SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with shmctl on Receive Pool SHMID (%d)", repl_instance.recvpool_shmid); + rts_error(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno); } else if (shmstat.shm_ctime != repl_instance.recvpool_shmid_ctime) { /* shared memory was possibly reused (causing shm_ctime and jnlpool_shmid_ctime to be different. We can't rely * on the shmid as it could be connected to a valid instance file in a different environment. Create new IPCs @@ -243,7 +251,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) } if (new_ipc && (GTMRECV != pool_user || !gtmrecv_startup)) { - REMOVE_OR_RELEASE_SEM(new_ipc, udi); + REMOVE_OR_RELEASE_SEM(new_ipc); ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(4) ERR_NORECVPOOL, 2, full_len, udi->fn); } @@ -273,7 +281,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) udi->gt_shm_ctime = shmstat.shm_ctime; shm_created = TRUE; } - assert((INVALID_SHMID != udi->shmid) && (0 != udi->gt_shm_ctime) && (0 != recvpool_shmid)); + assert((INVALID_SHMID != udi->shmid) && (0 != udi->gt_shm_ctime) && (INVALID_SHMID != recvpool_shmid)); status_l = (sm_long_t)(recvpool.recvpool_ctl = (recvpool_ctl_ptr_t)do_shmat(recvpool_shmid, 0, 0)); if (-1 == status_l) { @@ -283,6 +291,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) else rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receive pool shmat"), save_errno); @@ -307,6 +316,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) else rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool has not been initialized")); @@ -379,7 +389,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) assert(NULL != jnlpool.repl_inst_filehdr); DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;) assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); jnlpool.repl_inst_filehdr->recvpool_shmid = udi->shmid; jnlpool.repl_inst_filehdr->recvpool_semid = udi->semid; jnlpool.repl_inst_filehdr->recvpool_shmid_ctime = udi->gt_shm_ctime; @@ -397,6 +407,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) { rel_sem(RECV, RECV_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; if (!ftok_sem_release(recvpool.recvpool_dummy_reg, FALSE, FALSE)) rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP); } @@ -409,12 +420,13 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup) */ if ((GTMRECV == pool_user) && gtmrecv_options.start && (0 != grab_sem(RECV, RECV_SERV_OPTIONS_SEM))) { - save_errno = REPL_SEM_ERRNO; + save_errno = errno; if (new_ipc) remove_sem_set(RECV); else rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM); udi->grabbed_access_sem = FALSE; + udi->counter_acc_incremented = FALSE; ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receive pool options semaphore"), save_errno); diff --git a/sr_unix/rel_crit.c b/sr_unix/rel_crit.c index 9fd4a3c..d649e16 100644 --- a/sr_unix/rel_crit.c +++ b/sr_unix/rel_crit.c @@ -83,5 +83,5 @@ void rel_crit(gd_region *reg) /* Now that crit for THIS region is released, check if deferred signal/exit handling can be done and if so do it */ DEFERRED_EXIT_HANDLING_CHECK; if ((DEFER_SUSPEND == suspend_status) && OK_TO_INTERRUPT) - suspend(); + suspend(SIGSTOP); } diff --git a/sr_unix/rel_lock.c b/sr_unix/rel_lock.c index 4018485..db62d54 100644 --- a/sr_unix/rel_lock.c +++ b/sr_unix/rel_lock.c @@ -87,5 +87,5 @@ void rel_lock(gd_region *reg) /* Now that crit for THIS region is released, check if deferred signal/exit handling can be done and if so do it */ DEFERRED_EXIT_HANDLING_CHECK; if ((DEFER_SUSPEND == suspend_status) && OK_TO_INTERRUPT) - suspend(); + suspend(SIGSTOP); } diff --git a/sr_unix/remove_rms.c b/sr_unix/remove_rms.c index a0f6d9b..be6757a 100644 --- a/sr_unix/remove_rms.c +++ b/sr_unix/remove_rms.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,7 +25,6 @@ void remove_rms (io_desc *ciod) io_log_name **lpp, *lp; /* logical name pointers */ d_rm_struct *rm_ptr; int rc, fclose_res; - assert (ciod->type == rm); assert (ciod->state == dev_closed || ciod->state == dev_never_opened); rm_ptr = (d_rm_struct *) ciod->dev_sp; diff --git a/sr_unix/repl_inst_create.c b/sr_unix/repl_inst_create.c index 1727498..1c85f1b 100644 --- a/sr_unix/repl_inst_create.c +++ b/sr_unix/repl_inst_create.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2011 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -81,6 +81,7 @@ void repl_inst_create(void) gtmsrc_lcl_ptr_t gtmsrc_lcl_array; mstr log_nam, trans_name; uint4 status2; + jnl_tm_t now; if (!repl_inst_get_name(inst_fn, &inst_fn_len, MAX_FN_LEN + 1, issue_rts_error)) GTMASSERT; /* rts_error should have been issued by repl_inst_get_name */ @@ -132,8 +133,9 @@ void repl_inst_create(void) rts_error(VARLSTCNT(4) ERR_REPLINSTSTNDALN, 2, inst_fn_len, inst_fn); assert(FALSE); } + JNL_SHORT_TIME(now); if (SS_NORMAL != (status = prepare_unique_name((char *)inst_fn, inst_fn_len, "", "", - rename_fn, &rename_fn_len, &status2))) + rename_fn, &rename_fn_len, now, &status2))) { gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Error preparing unique name for renaming instance file")); if (SS_NORMAL != status2) diff --git a/sr_unix/repl_inst_dump.c b/sr_unix/repl_inst_dump.c index eb7f14c..06c3cd6 100644 --- a/sr_unix/repl_inst_dump.c +++ b/sr_unix/repl_inst_dump.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 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 "gtmrecv.h" #include "repl_inst_dump.h" #include "repl_log.h" /* for "repl_log" prototype */ +#include "iotcpdef.h" /* for SA_MAXLEN */ LITDEF char state_array[][23] = { "DUMMY_STATE", @@ -684,14 +685,27 @@ void repl_inst_dump_jnlpoolctl(jnlpool_ctl_ptr_t jnlpool_ctl) PRINT_OFFSET_PREFIX(offsetof(jnlpool_ctl_struct, onln_rlbk_cycle), SIZEOF(jnlpool_ctl->onln_rlbk_cycle)); util_out_print( PREFIX_JNLPOOLCTL "Online Rollback Cycle !20UL [0x!XL]", TRUE, jnlpool_ctl->onln_rlbk_cycle, jnlpool_ctl->onln_rlbk_cycle); + PRINT_OFFSET_PREFIX(offsetof(jnlpool_ctl_struct, freeze), SIZEOF(jnlpool_ctl->freeze)); + PRINT_BOOLEAN( PREFIX_JNLPOOLCTL "Freeze !R10AZ", jnlpool_ctl->freeze, -1); + if (jnlpool_ctl->freeze) + { + PRINT_OFFSET_PREFIX(offsetof(jnlpool_ctl_struct, freeze_comment[0]), SIZEOF(jnlpool_ctl->freeze_comment)); + if (STRLEN(jnlpool_ctl->freeze_comment) <= 38) + util_out_print( PREFIX_JNLPOOLCTL "Freeze Comment !R38AZ", TRUE, jnlpool_ctl->freeze_comment); + else + util_out_print( PREFIX_JNLPOOLCTL "Freeze Comment: !AZ", TRUE, jnlpool_ctl->freeze_comment); + } + } void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr) { - int idx; + int idx, idx2; char *string; boolean_t first_time = TRUE; repl_conn_info_t *remote_side; + int errcode; + char secondary_addr[SA_MAXLEN + 1]; for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsourcelocal_ptr++) { @@ -720,8 +734,16 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr) gtmsourcelocal_ptr->gtmsource_pid); PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, mode), SIZEOF(gtmsourcelocal_ptr->mode)); - string = (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode) ? "PASSIVE" : - ((GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) ? "ACTIVE" : "UNKNOWN"); + if (GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) + string = "ACTIVE"; + else if (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode) + string = "PASSIVE"; + else if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsourcelocal_ptr->mode) + string = "ACTIVE REQUESTED"; + else if (GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsourcelocal_ptr->mode) + string = "PASSIVE REQUESTED"; + else + string = "UNKNOWN"; if (MEMCMP_LIT(string, "UNKNOWN")) util_out_print( PREFIX_SOURCELOCAL "Source Server Mode !R22AZ", TRUE, idx, string); else @@ -857,11 +879,24 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr) util_out_print( PREFIX_SOURCELOCAL "Secondary HOSTNAME !AZ", TRUE, idx, gtmsourcelocal_ptr->secondary_host); } + PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_af), + SIZEOF(gtmsourcelocal_ptr->secondary_af)); + string = (AF_INET == gtmsourcelocal_ptr->secondary_af)? "IPv4" : + ((AF_INET6 == gtmsourcelocal_ptr->secondary_af) ? "IPv6" : "UNKNOWN"); + util_out_print( PREFIX_SOURCELOCAL "Secondary Address Family !R10AZ",TRUE, idx, string); PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_inet_addr), SIZEOF(gtmsourcelocal_ptr->secondary_inet_addr)); - util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !10UL [0x!XL]", TRUE, idx, - gtmsourcelocal_ptr->secondary_inet_addr, gtmsourcelocal_ptr->secondary_inet_addr); + errcode = getnameinfo((struct sockaddr *)>msourcelocal_ptr->secondary_inet_addr, + gtmsourcelocal_ptr->secondary_addrlen, secondary_addr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST); + if (0 == errcode) + { + util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !R24AZ", TRUE, idx, secondary_addr); + } else + { + string = "UNKNOWN"; + util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !R10AZ", TRUE, idx, string); + } PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_port), SIZEOF(gtmsourcelocal_ptr->secondary_port)); util_out_print( PREFIX_SOURCELOCAL "Secondary Port !10UL [0x!XL]", TRUE, idx, @@ -888,12 +923,12 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr) gtmsourcelocal_ptr->statslog, gtmsourcelocal_ptr->statslog); PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, statslog_file[0]), SIZEOF(gtmsourcelocal_ptr->statslog_file)); - if (20 >= strlen(gtmsourcelocal_ptr->log_file)) + if (20 >= strlen(gtmsourcelocal_ptr->statslog_file)) { util_out_print( PREFIX_SOURCELOCAL "Statslog File !R20AZ", TRUE, idx, gtmsourcelocal_ptr->statslog_file); } else - { + { /*After gtm-7296, the statslog_file length should always be 0, so the following in fact won't be executed*/ util_out_print( PREFIX_SOURCELOCAL "Statslog File !AZ", TRUE, idx, gtmsourcelocal_ptr->statslog_file); } diff --git a/sr_unix/repl_instance.c b/sr_unix/repl_instance.c index edde7d1..4311201 100644 --- a/sr_unix/repl_instance.c +++ b/sr_unix/repl_instance.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -52,6 +52,7 @@ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" #include "have_crit.h" +#include "anticipatory_freeze.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif @@ -101,7 +102,7 @@ error_def(ERR_TEXT); */ boolean_t repl_inst_get_name(char *fn, unsigned int *fn_len, unsigned int bufsize, instname_act error_action) { - char temp_inst_fn[MAX_FN_LEN+1]; + char temp_inst_fn[MAX_FN_LEN + 1]; mstr log_nam, trans_name; uint4 ustatus; int4 status; @@ -111,18 +112,7 @@ boolean_t repl_inst_get_name(char *fn, unsigned int *fn_len, unsigned int bufsiz log_nam.len = SIZEOF(GTM_REPL_INSTANCE) - 1; trans_name.addr = temp_inst_fn; ret = FALSE; - if ((SS_NORMAL == (status = TRANS_LOG_NAME(&log_nam, &trans_name, temp_inst_fn, SIZEOF(temp_inst_fn), - do_sendmsg_on_log2long))) - && (0 != trans_name.len)) - { - temp_inst_fn[trans_name.len] = '\0'; - if (!get_full_path(trans_name.addr, trans_name.len, fn, fn_len, bufsize, &ustatus)) - { - gtm_putmsg(VARLSTCNT(9) ERR_REPLINSTACC, 2, trans_name.len, trans_name.addr, - ERR_TEXT, 2, RTS_ERROR_LITERAL("full path could not be found"), ustatus); - } else - ret = TRUE; - } + GET_INSTFILE_NAME(do_sendmsg_on_log2long, issue_gtm_putmsg); if (FALSE == ret) { if (issue_rts_error == error_action) @@ -310,7 +300,7 @@ void repl_inst_write(char *fn, off_t offset, sm_uc_ptr_t buff, size_t buflen) TAG_POLICY_GTM_PUTMSG(fn, errno, realfiletag, TAG_BINARY); #endif assert(0 < buflen); - LSEEKWRITE(fd, offset, buff, buflen, status); + REPL_INST_LSEEKWRITE(fd, offset, buff, buflen, status); assert(0 == status); if (0 != status) rts_error(VARLSTCNT(7) ERR_REPLINSTWRITE, 4, buflen, (qw_off_t *)&offset, LEN_AND_STR(fn), status); @@ -355,7 +345,7 @@ void repl_inst_sync(char *fn) OPENFILE3(fn, oflag, 0666, fd); if (FD_INVALID == fd) rts_error(VARLSTCNT(5) ERR_REPLINSTOPEN, 2, LEN_AND_STR(fn), errno); - GTM_FSYNC(fd, status); + GTM_REPL_INST_FSYNC(fd, status); assert(0 == status); if (0 != status) rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fsync()"), CALLFROM, errno); @@ -708,7 +698,8 @@ void repl_inst_histinfo_add(repl_histinfo *histinfo) } assert((histinfo->start_seqno != last_strm_histinfo->start_seqno) || (histinfo->strm_seqno == last_strm_histinfo->strm_seqno) - || (HISTINFO_TYPE_NORESYNC == histinfo->history_type)); + || (HISTINFO_TYPE_NORESYNC == histinfo->history_type) + || (HISTINFO_TYPE_UPDRESYNC == histinfo->history_type)); /* If stream seqnos match between input history and last stream specific history in the instance file, * make sure the to-be-written history record skips past the last stream specific history record (as we * expect a decreasing sequence of strm_seqnos in the "prev_histinfo_num" linked list of history records). @@ -794,8 +785,9 @@ void repl_inst_histinfo_add(repl_histinfo *histinfo) /* Assert that the prev_histinfo_num list of history records have decreasing "start_seqno" and "strm_seqno" values. * The only exception is stream # 0 for a supplementary instance as described in a previous comment in this function. */ - if (INVALID_HISTINFO_NUM != prev_histinfo_num) + if (INVALID_HISTINFO_NUM != histinfo->prev_histinfo_num) { + assert(histinfo->prev_histinfo_num == prev_histinfo_num); status = repl_inst_histinfo_get(prev_histinfo_num, &last2_histinfo); assert(0 == status); /* Since the strm_histinfo_num we are passing is >=0 and < num_histinfo */ assert(strm_idx == last2_histinfo.strm_index); /* they both better have the same stream # */ @@ -877,9 +869,13 @@ seq_num repl_inst_histinfo_truncate(seq_num rollback_seqno) } index = -1; /* Since we are rolling back all history records in the instance file, - * clear all of "strm_seqno", "strm_group_info[]" and "last_histinfo_num[]" arrays. - * The following logic is similar to that in "repl_inst_create" to initialize the above 4 fields. - * Leave out "jnl_seqno" initialization as that is done anyways after this "if" block. + * clear all of "strm_group_info[]" and "last_histinfo_num[]" arrays. + * The following logic is similar to that in "repl_inst_create" to initialize the above 2 fields. + * Note that we keep "jnl_seqno" and "strm_seqno" set to whatever value it came in with (as opposed + * to setting it to 0). This is different from what is done in "repl_inst_create" because we want + * to keep these set to a non-zero value if possible (see detailed comment below where "jnl_seqno" + * gets set). Keeping "jnl_seqno" at a non-zero value necessitates keeping "strm_seqno" at a non-zero + * value as well in order to avoid REPLINSTDBSTRM errors at source server startup. */ assert(MAX_SUPPL_STRMS == ARRAYSIZE(inst_hdr->last_histinfo_num)); for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) @@ -888,11 +884,31 @@ seq_num repl_inst_histinfo_truncate(seq_num rollback_seqno) { assert(MAX_SUPPL_STRMS == ARRAYSIZE(inst_hdr->strm_seqno)); assert(SIZEOF(seq_num) == SIZEOF(inst_hdr->strm_seqno[0])); - memset(inst_hdr->strm_seqno, 0, MAX_SUPPL_STRMS * SIZEOF(seq_num)); - inst_hdr->strm_seqno[0] = 1; /* like is done in repl_inst_create */ assert((MAX_SUPPL_STRMS - 1) == ARRAYSIZE(inst_hdr->strm_group_info)); assert(SIZEOF(repl_inst_uuid) == SIZEOF(inst_hdr->strm_group_info[0])); - memset(inst_hdr->strm_group_info, 0, (MAX_SUPPL_STRMS - 1) * SIZEOF(repl_inst_uuid)); + /* Keep the strm_seqno 0 for those streams which this instance has never used/communicated. For all + * other stream#, set the strm_seqno to 1 if the current value of strm_seqno is 0. If the current + * value of strm_seqno is non-zero, let it stay as it is (see comment above about strm_seqno). + * This way, if this instance reconnects after the ROLLBACK to the same instance it was + * communicating before, we avoid issuing REPLINSTNOHIST thereby making it user-friendly. + * Note: The LMS group info for stream# "i" is found in strm_group_info[i - 1] (used below) + */ + for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) + { + if ((idx == 0) || (IS_REPL_INST_UUID_NON_NULL(inst_hdr->strm_group_info[idx - 1]))) + { + if (0 == inst_hdr->strm_seqno[idx]) + inst_hdr->strm_seqno[idx] = 1; + } +# ifdef DEBUG + else + assert(0 == inst_hdr->strm_seqno[idx]); +# endif + } + /* Leave the LMS group information as-is in the instance file header. By doing so, we avoid cases + * where receiver server continuing after the rollback issues an INSUNKNOWN error. While this is + * a valid error, we try to make it as user-friendly as possible. + */ } } else { @@ -930,8 +946,22 @@ seq_num repl_inst_histinfo_truncate(seq_num rollback_seqno) assert(MAX_SUPPL_STRMS > strmhistinfo.strm_index); assert(IS_REPL_INST_UUID_NON_NULL(strmhistinfo.lms_group)); inst_hdr->strm_group_info[idx] = strmhistinfo.lms_group; - } else - NULL_INITIALIZE_REPL_INST_UUID(inst_hdr->strm_group_info[idx]); + } else if (IS_REPL_INST_UUID_NON_NULL(inst_hdr->strm_group_info[idx])) + { /* stream# (idx + 1) has a non-zero UUID information in the file header + * but all the history records corresponding to this stream are now + * truncated. This also implies that strm_seqno of this stream is reset + * to zero by ROLLBACK. To avoid REPLINSTNOHIST next time a communication + * happens with the instance corresponding to stream# idx + 1, set the + * strm_seqno to 1. + * Note: The LMS group info for stream-i is found in strm_group_info[i - 1] + */ + inst_hdr->strm_seqno[idx + 1] = 1; + /* Also, leave the LMS group information for stream# idx + 1 as-is in the + * instance file header By doing so, we avoid cases where receiver server + * continuing after the rollback issues an INSUNKNOWN error. While this is + * a valid error, we try to mae it as user-friendly as possible. + */ + } } } } @@ -973,9 +1003,8 @@ seq_num repl_inst_histinfo_truncate(seq_num rollback_seqno) inst_hdr->recvpool_shmid = INVALID_SHMID; /* Just in case it is not already reset */ inst_hdr->recvpool_semid_ctime = 0; inst_hdr->recvpool_shmid_ctime = 0; - } /* else for rollback, we reset the IPC fields in mu_replpool_remove_sem() and crash in mur_close_files */ + } /* else for rollback, we reset the IPC fields in mu_replpool_release_sem() and crash in mur_close_files */ /* Flush all file header changes in jnlpool.repl_inst_filehdr to disk */ - assert(!jnlpool.jnlpool_dummy_reg->open); /* Ensure the call below will not do a "grab_lock" as there is no jnlpool */ repl_inst_flush_filehdr(); assert((0 == inst_hdr->num_histinfo) || (0 < last_histinfo_seqno)); return last_histinfo_seqno; @@ -1133,14 +1162,16 @@ boolean_t repl_inst_was_rootprimary(void) repl_histinfo temphistinfo, *last_histinfo = &temphistinfo; boolean_t was_rootprimary, was_crit = FALSE; sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (NULL != jnlpool.jnlpool_ctl) { /* If the journal pool is available (indicated by NULL != jnlpool_ctl), we expect jnlpool_dummy_reg to be open. * The only exception is online rollback which doesn't do a jnlpool_init thereby leaving jnlpool_dummy_reg->open * to be FALSE. Assert accordingly. */ assert(((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) - || jgbl.onlnrlbk); + || jgbl.onlnrlbk || (jgbl.mur_rollback && ANTICIPATORY_FREEZE_AVAILABLE)); csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; ASSERT_VALID_JNLPOOL(csa); assert(csa->now_crit); @@ -1232,7 +1263,7 @@ int4 repl_inst_reset_zqgblmod_seqno_and_tn(void) * an online rollback is detected, return without resetting max_zqgblmod_seqno. The caller knows to take appropriate * action (on seeing -1 as the return code). */ - GRAB_LOCK(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY); + grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY); if (repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle) { assert(is_rcvr_server); @@ -1254,7 +1285,7 @@ int4 repl_inst_reset_zqgblmod_seqno_and_tn(void) assert(reg->open); TP_CHANGE_REG(reg); assert(!cs_addrs->now_crit); - gds_rundown(); + UNIX_ONLY(ret |=) gds_rundown(); } assert(!repl_csa->now_crit); return ret; diff --git a/sr_unix/repl_instance.h b/sr_unix/repl_instance.h index d59aec9..db69aa2 100644 --- a/sr_unix/repl_instance.h +++ b/sr_unix/repl_instance.h @@ -177,6 +177,22 @@ typedef struct gtmsrc_lcl_struct #define OK_TO_LOG_FALSE FALSE #define OK_TO_LOG_TRUE TRUE +#define GET_INSTFILE_NAME(sendmsg, err_act) \ +{ \ + if ((SS_NORMAL == (status = TRANS_LOG_NAME(&log_nam, &trans_name, temp_inst_fn, SIZEOF(temp_inst_fn), \ + sendmsg))) \ + && (0 != trans_name.len)) \ + { \ + temp_inst_fn[trans_name.len] = '\0'; \ + if (!get_full_path(trans_name.addr, trans_name.len, fn, fn_len, bufsize, &ustatus) && err_act) \ + { \ + gtm_putmsg(VARLSTCNT(9) ERR_REPLINSTACC, 2, trans_name.len, trans_name.addr, \ + ERR_TEXT, 2, RTS_ERROR_LITERAL("full path could not be found"), ustatus); \ + } else \ + ret = TRUE; \ + } \ +} + typedef enum { return_on_error, issue_rts_error, diff --git a/sr_unix/repl_ipc_cleanup.c b/sr_unix/repl_ipc_cleanup.c index c20470d..7ec0112 100644 --- a/sr_unix/repl_ipc_cleanup.c +++ b/sr_unix/repl_ipc_cleanup.c @@ -37,6 +37,8 @@ #include "ipcrmid.h" #include "repl_instance.h" #include "wbox_test_init.h" +#include "have_crit.h" +#include "gtm_ipc.h" GBLREF jnlpool_addrs jnlpool; GBLREF boolean_t pool_init; @@ -50,7 +52,7 @@ GBLREF int recvpool_shmid; int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_src_servers_running) { boolean_t i_am_the_last_user, attempt_ipc_cleanup; - int status, detach_status, remove_status, semval; + int status, detach_status, remove_status, semval, save_errno; unix_db_info *udi; struct shmid_ds shm_buf; @@ -62,8 +64,9 @@ int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_s semval = get_sem_info(SOURCE, SRC_SERV_COUNT_SEM, SEM_INFO_VAL); if (-1 == semval) { - repl_log(stderr, TRUE, TRUE, - "Error fetching source server count semaphore value : %s. Shutdown not complete\n", REPL_SEM_ERROR); + save_errno = errno; + repl_log(stderr, TRUE, TRUE, "Error fetching source server count semaphore value : %s. " + "Shutdown not complete\n", STRERROR(save_errno)); attempt_ipc_cleanup = FALSE; *exit_status = ABNORMAL_SHUTDOWN; } @@ -104,7 +107,7 @@ int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_s } } /* detach from shared memory irrespective of whether we need to cleanup ipcs or not */ - detach_status = SHMDT(jnlpool.jnlpool_ctl); + JNLPOOL_SHMDT(detach_status, save_errno); if (0 == detach_status) { jnlpool.jnlpool_ctl = NULL; /* Detached successfully */ @@ -116,8 +119,7 @@ int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_s pool_init = FALSE; } else { - repl_log(stderr, TRUE, TRUE, - "Error detaching from jnlpool shared memory : %s. Shared memory not removed\n", STRERROR(ERRNO)); + repl_log(stderr, TRUE, TRUE, "Error detaching from Journal Pool : %s\n", STRERROR(save_errno)); attempt_ipc_cleanup = FALSE; *num_src_servers_running = 0; *exit_status = ABNORMAL_SHUTDOWN; @@ -147,7 +149,7 @@ int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_s int gtmrecv_ipc_cleanup(boolean_t auto_shutdown, int *exit_status) { boolean_t i_am_the_last_user, attempt_ipc_cleanup; - int status, detach_status, remove_status, expected_nattach; + int status, detach_status, remove_status, expected_nattach, save_errno; struct shmid_ds shm_buf; /* Attempt cleaning up the IPCs */ @@ -161,12 +163,12 @@ int gtmrecv_ipc_cleanup(boolean_t auto_shutdown, int *exit_status) else status = 0; if (0 == status && 0 > (status = grab_sem(RECV, UPD_PROC_COUNT_SEM))) - rel_sem(RECV, RECV_SERV_COUNT_SEM); - if (status < 0) { - repl_log(stderr, TRUE, TRUE, - "Error taking control of Receiver Server/Update Process count semaphore : %s. Shutdown not complete\n", - REPL_SEM_ERROR); + save_errno = errno; + status = rel_sem(RECV, RECV_SERV_COUNT_SEM); + assert(0 == status); + repl_log(stderr, TRUE, TRUE, "Error taking control of Receiver Server/Update Process count semaphore : %s. " + "Shutdown not complete\n", STRERROR(save_errno)); *exit_status = ABNORMAL_SHUTDOWN; attempt_ipc_cleanup = FALSE; } @@ -180,7 +182,7 @@ int gtmrecv_ipc_cleanup(boolean_t auto_shutdown, int *exit_status) if (!i_am_the_last_user) { if (status < 0) - repl_log(stderr, TRUE, TRUE, "Error in jnlpool shmctl : %s\n", STRERROR(ERRNO)); + repl_log(stderr, TRUE, TRUE, "Error in jnlpool shmctl : %s\n", STRERROR(errno)); else repl_log(stderr, TRUE, TRUE, "Not deleting receive pool ipcs. %d processes still attached to receive pool\n", diff --git a/sr_unix/repl_log.c b/sr_unix/repl_log.c index 3b952df..cef0acd 100644 --- a/sr_unix/repl_log.c +++ b/sr_unix/repl_log.c @@ -23,15 +23,11 @@ #include "iosp.h" GBLREF int gtmsource_log_fd; -GBLREF int gtmsource_statslog_fd; GBLREF int gtmrecv_log_fd; -GBLREF int gtmrecv_statslog_fd; GBLREF int updproc_log_fd; GBLREF FILE *gtmsource_log_fp; -GBLREF FILE *gtmsource_statslog_fp; GBLREF FILE *gtmrecv_log_fp; -GBLREF FILE *gtmrecv_statslog_fp; GBLREF FILE *updproc_log_fp; int repl_log(FILE *fp, boolean_t stamptime, boolean_t flush, char *fmt, ...) diff --git a/sr_unix/repl_log_init.c b/sr_unix/repl_log_init.c index 78248d6..893791e 100644 --- a/sr_unix/repl_log_init.c +++ b/sr_unix/repl_log_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,33 +32,31 @@ #include "repl_sp.h" #include "send_msg.h" #include "gtmmsg.h" +#include "have_crit.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif GBLDEF int gtmsource_log_fd = FD_INVALID; -GBLDEF int gtmsource_statslog_fd = FD_INVALID; GBLDEF int gtmrecv_log_fd = FD_INVALID; -GBLDEF int gtmrecv_statslog_fd = FD_INVALID; GBLDEF int updproc_log_fd = FD_INVALID; GBLDEF int updhelper_log_fd = FD_INVALID; GBLDEF FILE *gtmsource_log_fp = NULL; -GBLDEF FILE *gtmsource_statslog_fp = NULL; GBLDEF FILE *gtmrecv_log_fp = NULL; -GBLDEF FILE *gtmrecv_statslog_fp = NULL; GBLDEF FILE *updproc_log_fp = NULL; GBLDEF FILE *updhelper_log_fp = NULL; +error_def(ERR_REPLLOGOPN); +error_def(ERR_TEXT); +error_def(ERR_REPLEXITERR); +ZOS_ONLY(error_def(ERR_BADTAG);) int repl_log_init(repl_log_file_t log_type, int *log_fd, - int *stats_fd, - char *log, - char *stats_log) + char *log) { /* Open the log file */ - - char log_file_name[MAX_FN_LEN + 1], *err_code; + char log_file_name[MAX_FN_LEN + 1], *err_code; int tmp_fd; int save_errno; int stdout_status, stderr_status; @@ -68,55 +66,31 @@ int repl_log_init(repl_log_file_t log_type, int realfiletag; struct stat info; #endif - error_def(ERR_REPLLOGOPN); - error_def(ERR_TEXT); - ZOS_ONLY(error_def(ERR_BADTAG);) - if (*log == '\0') return(EREPL_LOGFILEOPEN); strcpy(log_file_name, log); - if (log_type == REPL_STATISTICS_LOG) - { - if (strcmp(log_file_name, stats_log) != 0) - strcpy(log_file_name, stats_log); - else - { - *stats_fd = *log_fd; - return(SS_NORMAL); - } - } - ZOS_ONLY(STAT_FILE(log_file_name, &info, status);) OPENFILE3(log_file_name, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, tmp_fd); if (tmp_fd < 0) { - if ((REPL_GENERAL_LOG == log_type) && (FD_INVALID == *log_fd) || (FD_INVALID == *stats_fd)) + if ((REPL_GENERAL_LOG == log_type) && (FD_INVALID == *log_fd)) { save_errno = ERRNO; err_code = STRERROR(save_errno); - send_msg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, - LEN_AND_STR(log_file_name), - LEN_AND_STR(err_code), - LEN_AND_STR(NULL_DEVICE)); + gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), + LEN_AND_STR(err_code),LEN_AND_STR(NULL_DEVICE)); strcpy(log_file_name, NULL_DEVICE); if (log_type == REPL_GENERAL_LOG) - strcpy(log, log_file_name); - else - strcpy(stats_log, log_file_name); + strcpy(log, NULL_DEVICE); OPENFILE(log_file_name, O_RDWR, tmp_fd); /* Should not fail */ + exit(EREPL_LOGFILEOPEN); } else { save_errno = ERRNO; err_code = STRERROR(save_errno); - gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, - LEN_AND_STR(log_file_name), - LEN_AND_STR(err_code), - (log_type == REPL_GENERAL_LOG) ? - strlen(log) : strlen(stats_log), - (log_type == REPL_GENERAL_LOG) ? - log : stats_log); - + gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), + LEN_AND_STR(err_code), LEN_AND_STR(log)); return(EREPL_LOGFILEOPEN); } } @@ -166,19 +140,11 @@ int repl_log_init(repl_log_file_t log_type, gtm_putmsg(VARLSTCNT(10) ERR_REPLLOGOPN, 6, LEN_AND_STR(log_file_name), LEN_AND_STR(err_code), - (log_type == REPL_GENERAL_LOG) ? - strlen(log) : strlen(stats_log), - (log_type == REPL_GENERAL_LOG) ? - log : stats_log, + strlen(log), + log, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in dup2")); } - } else - { - if (FD_INVALID != *stats_fd) - CLOSEFILE_RESET(*stats_fd, rc); /* resets "*stats_fd" to FD_INVALID */ - *stats_fd = tmp_fd; } - return(SS_NORMAL); } @@ -191,7 +157,7 @@ int repl_log_fd2fp(FILE **fp, int fd) * FDOPEN will fail returning NULL for the file pointer. */ if (NULL != *fp) FCLOSE(*fp, fclose_res); - *fp = FDOPEN(fd, "a"); + FDOPEN(*fp, fd, "a"); assert(NULL != *fp); /* we don't expect FDOPEN to fail */ return(SS_NORMAL); } diff --git a/sr_unix/repl_msg.h b/sr_unix/repl_msg.h index 705b9d2..ee47e53 100644 --- a/sr_unix/repl_msg.h +++ b/sr_unix/repl_msg.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2006, 2012 Fidelity Information Services, Inc * + * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -50,6 +50,7 @@ enum REPL_HISTREC, /* 31 */ /* sent in the middle of a journal record stream to signal start of new history */ REPL_NEED_STRMINFO, /* 32 */ /* sent by a supplementary source server to a supplementary receiver server */ REPL_STRMINFO, /* 33 */ /* sent in response to a REPL_NEED_STRMINFO message */ + REPL_LOGFILE_INFO, /* 34 */ /* sent (at time of handshake) to communicate to one another the $CWD/logfile */ REPL_MSGTYPE_LAST=256 /* 256 */ /* any new message need to be added before REPL_MSGTYPE_LAST */ }; @@ -57,14 +58,22 @@ enum #define REPL_PROTO_VER_UNINITIALIZED (char)0xFF /* -1, the least of the versions to denote an uninitialized version field */ #define REPL_PROTO_VER_DUALSITE (char)0x0 /* Versions GT.M V5.0 and prior that dont support multi site replication */ #define REPL_PROTO_VER_MULTISITE (char)0x1 /* Versions V5.1-000 and above that support multi site replication */ -#define REPL_PROTO_VER_MULTISITE_CMP (char)0x2 /* Versions V5.3-003 and above that suport multisite replication with +#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 suport supplementary instances */ -#define REPL_PROTO_VER_THIS REPL_PROTO_VER_SUPPLEMENTARY +#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_THIS REPL_PROTO_VER_REMOTE_LOGPATH /* The current/latest version of the communication protocol between the * primary (source server) and secondary (receiver server or rollback) */ +/* Below macro defines the maximum size of the replication logfile path information that will be sent across to the other side. + * While the actual path max is defined by GTM_PATH_MAX, the value of GTM_PATH_MAX differ across different platforms and so we + * cannot always be sure if this side can store the remote side's logfile path. Since REPL_LOGFILE_INFO message is sent across + * only during handshake, malloc too is an overkill. So, have a fixed size buffer (see repl_logfile_info_msg_t beow) bounded by + * the below size. + */ +#define REPL_LOGFILE_PATH_MAX 1023 /* A few of these flag bits (e.g. START_FLAG_SRCSRV_IS_VMS) are no longer used but they should not be removed just in case prior * versions that used those bitslots communicate with a newer version that assigns a different meaning to those slots. Any new @@ -139,7 +148,12 @@ typedef struct /* Used also to send a message of type REPL_TR_CMP_JNL_RECS2 */ * small message buffer */ } repl_cmpmsg_t; -#define MAX_REPL_MSGLEN (1 * 1024 * 1024) /* should ideally match the TCP send (recv) bufsiz of source (receiver) server */ +/* This should ideally match the TCP send/recv buffer size of source/receiver server. However, since the maximum TCP buffer + * varies by system, and on many systems it is less than 2 MB or even 1 MB, we keep GTMRECV_TCP_RECV_BUFSIZE and + * GTMSOURCE_TCP_SEND_BUFSIZE at 1 MB to avoid extra attempts to send/receive TCP packets before the limit is lowered enough + * for the OS to support it. + */ +#define MAX_REPL_MSGLEN (2 * 1024 * 1024) #define MAX_TR_BUFFSIZE (MAX_REPL_MSGLEN - REPL_MSG_HDRLEN2) /* allow for biggest replication message header */ typedef struct /* used to send a message of type REPL_START_JNL_SEQNO */ @@ -366,6 +380,19 @@ typedef struct /* Used to send a message of type REPL_BADTRANS or REPL_CMP2UNCM char filler_32[16]; } repl_badtrans_msg_t; +typedef struct +{ + int4 type; + int4 len; + int4 fullpath_len; + uint4 pid; + char proto_ver; + char filler_32[15]; /* to ensure that at least 32 bytes are sent across (gtmrecv_fetchresync relies on this) */ + char fullpath[REPL_LOGFILE_PATH_MAX + 1]; /* + 1 for null-terminator */ +} repl_logfile_info_msg_t; + +#define REPL_LOGFILE_INFO_MSGHDR_SZ OFFSETOF(repl_logfile_info_msg_t, fullpath[0]) + #if defined(__osf__) && defined(__alpha) # pragma pointer_size(save) # pragma pointer_size(long) @@ -401,5 +428,6 @@ void gtmsource_send_new_histrec(void); void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypestr, seq_num optional_seqno); void gtmrecv_send_histinfo(repl_histinfo *histinfo); void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, boolean_t is_rcvr_srvr); +uint4 repl_logfileinfo_get(char *logfile, repl_logfile_info_msg_t *msgp, boolean_t cross_endian, FILE *logfp); #endif diff --git a/sr_unix/repl_sem.c b/sr_unix/repl_sem.c index 8c0603f..2277135 100644 --- a/sr_unix/repl_sem.c +++ b/sr_unix/repl_sem.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -81,12 +81,12 @@ void set_sem_set_src(int semid) } int init_sem_set_recvr(sem_key_t key, int nsems, permissions_t sem_flags) { + int semid; + assert(IPC_PRIVATE == (key_t)key); assert(SIZEOF(key_t) >= SIZEOF(sem_key_t)); - sem_set_id[RECV] = semget(key, nsems, sem_flags); - holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE; - holds_sem[RECV][RECV_SERV_COUNT_SEM] = FALSE; - holds_sem[RECV][UPD_PROC_COUNT_SEM] = FALSE; + semid = semget(key, nsems, sem_flags); + set_sem_set_recvr(semid); return sem_set_id[RECV]; } void set_sem_set_recvr(int semid) @@ -95,6 +95,7 @@ void set_sem_set_recvr(int semid) holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE; holds_sem[RECV][RECV_SERV_COUNT_SEM] = FALSE; holds_sem[RECV][UPD_PROC_COUNT_SEM] = FALSE; + holds_sem[RECV][RECV_SERV_OPTIONS_SEM] = FALSE; } int grab_sem(int set_index, int sem_num) @@ -124,6 +125,14 @@ int incr_sem(int set_index, int sem_num) sop[0].sem_num = sem_num; sop[0].sem_flg = SEM_UNDO; SEMOP(sem_set_id[set_index], sop, 1, rc, NO_WAIT); + if (0 == rc) + { + /* decr_sem internally calls rel_sem directly which expects that the entry for hold_sem[SOURCE][SRC_SERV_COUNT_SEM] + * is set to TRUE. But, incr_sem doesn't set this entry. This causes decr_sem (done below) to assert fail. to avoid + * the assert, set the hold_sem array to TRUE even if this is an increment operation + */ + holds_sem[set_index][sem_num] = TRUE; + } return rc; } diff --git a/sr_unix/repl_sem_sp.h b/sr_unix/repl_sem_sp.h index 3d3464a..42c3edc 100644 --- a/sr_unix/repl_sem_sp.h +++ b/sr_unix/repl_sem_sp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,11 +12,7 @@ #ifndef _REPL_SEM_SP_H #define _REPL_SEM_SP_H -#define REPL_SEM_ERRNO errno -#define REPL_SEM_ERROR STRERROR(errno) #define REPL_SEM_NOT_GRABBED (EAGAIN == errno) -#define REPL_SEM_NOT_GRABBED1 (EAGAIN == save_errno) -#define REPL_STR_ERROR STRERROR(errno) typedef int sem_key_t; typedef int permissions_t; diff --git a/sr_unix/repl_sp.h b/sr_unix/repl_sp.h index c39c1c1..2af3bc3 100644 --- a/sr_unix/repl_sp.h +++ b/sr_unix/repl_sp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc.* + * Copyright 2001, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,5 +21,4 @@ #define F_COPY_GDID(to, from) memcpy(&(to), &(from), SIZEOF(to)) #define F_COPY_GDID_FROM_STAT(to, stat_buf) set_gdid_from_stat(&(to), &stat_buf); #define F_READ_BLK_ALIGNED LSEEKREAD -#define F_WRITE_BLK_ALIGNED LSEEKWRITE #endif diff --git a/sr_unix/resetterm.c b/sr_unix/resetterm.c index 0e423af..0acd5aa 100644 --- a/sr_unix/resetterm.c +++ b/sr_unix/resetterm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,22 +21,22 @@ #include "setterm.h" #include "gtm_isanlp.h" +error_def(ERR_TCSETATTR); + void resetterm(io_desc *iod) { int status; int save_errno; struct termios t; d_tt_struct *ttptr; - error_def(ERR_TCSETATTR); ttptr =(d_tt_struct *) iod->dev_sp; if (ttptr->ttio_struct) { t = *ttptr->ttio_struct; - Tcsetattr(ttptr->fildes, TCSANOW, &t, status); + Tcsetattr(ttptr->fildes, TCSANOW, &t, status, save_errno); if (status != 0) { - save_errno = errno; if (gtm_isanlp(ttptr->fildes) == 0) rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, ttptr->fildes, save_errno); } diff --git a/sr_unix/rtnhdr.h b/sr_unix/rtnhdr.h index bc85792..d72f8c9 100644 --- a/sr_unix/rtnhdr.h +++ b/sr_unix/rtnhdr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -147,6 +147,9 @@ typedef struct #define CODE_BASE_ADDR(rtnhdr) ((rtnhdr)->ptext_adr) #define CODE_OFFSET(rtnhdr, addr) ((char *)(addr) - (char *)(rtnhdr->ptext_adr)) +#define DYNAMIC_LITERALS_ENABLED(rtnhdr) ((rtnhdr)->compiler_qlf & CQ_DYNAMIC_LITERALS) +#define RW_REL_START_ADR(rtnhdr) (((DYNAMIC_LITERALS_ENABLED(rtnhdr)) ? (char *)VARTAB_ADR(rtnhdr) : (char *)LITERAL_ADR(rtnhdr))) + /* Macro to determine if given address is inside code segment. Note that even though * the PTEXT_END_ADR macro is the address of end_of_code + 1, we still want a <= check * here because in many cases, the address being tested is the RETURN address from a diff --git a/sr_unix/rts_error.c b/sr_unix/rts_error.c index f451e91..cb2dfd7 100644 --- a/sr_unix/rts_error.c +++ b/sr_unix/rts_error.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,20 +17,30 @@ #include "gtm_putmsg_list.h" #include +#include "gtmimagename.h" #include "error.h" #include "util.h" +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "filestruct.h" +#include "gtmmsg.h" +#include "repl_msg.h" +#include "gtmsource.h" +#include "anticipatory_freeze.h" -GBLREF int gtm_errno; -GBLREF boolean_t created_core; -GBLREF boolean_t dont_want_core; - -#define FLUSH 1 -#define RESET 2 +GBLREF int gtm_errno; +GBLREF boolean_t created_core; +GBLREF boolean_t dont_want_core; +GBLREF gd_region *gv_cur_region; +GBLREF jnlpool_addrs jnlpool; error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); +error_def(ERR_JOBINTRRETHROW); +error_def(ERR_JOBINTRRQST); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_REPEATERROR); @@ -38,21 +48,58 @@ error_def(ERR_REPLONLNRLBK); error_def(ERR_STACKOFLOW); error_def(ERR_TPRETRY); +int rts_error_va(void *csa, int argcnt, va_list var); + /* ---------------------------------------------------------------------------------------- * WARNING: For chained error messages, all messages MUST be followed by an fao count; * ======= zero MUST be specified if there are no parameters. * ---------------------------------------------------------------------------------------- */ + int rts_error(int argcnt, ...) { - int msgid; + va_list var; + sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL; + VAR_START(var, argcnt); + return rts_error_va(csa, argcnt, var); +} + +int rts_error_csa(void *csa, int argcnt, ...) +{ va_list var; + VAR_START(var, argcnt); + return rts_error_va(csa, argcnt, var); +} + +int rts_error_va(void *csa, int argcnt, va_list var) +{ + int msgid; + va_list var_dup; + const err_msg *msg; + const err_ctl *ctl; +# ifdef DEBUG + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + if (TREF(rts_error_unusable) && !TREF(rts_error_unusable_seen)) + { + TREF(rts_error_unusable_seen) = TRUE; + /* The below assert ensures that this rts_error invocation is appropriate in the current context of the code that + * triggered this rts_error. If ever this assert fails, investigate the window of DBG_MARK_RTS_ERROR_UNUSABLE + * and DBG_MARK_RTS_ERROR_USABLE in the call-stack. + */ + assert(FALSE); + } +# endif + VAR_COPY(var_dup, var); if (-1 == gtm_errno) gtm_errno = errno; - VAR_START(var, argcnt); - msgid = va_arg(var, int); - va_end(var); + msgid = va_arg(var_dup, int); /* If there was a previous fatal error that did not yet get printed, do it before overwriting the * util_output buffer with the about-to-be-handled nested error. This way one will see ALL the * fatal error messages (e.g. assert failures) in the order in which they occurred instead of @@ -61,23 +108,30 @@ int rts_error(int argcnt, ...) if (DUMPABLE) PRN_ERROR; /* This is simply a place holder msg to signal tp restart or otherwise rethrow an error */ - if (ERR_TPRETRY == msgid || ERR_REPEATERROR == msgid || ERR_REPLONLNRLBK == msgid) - { + if ((ERR_TPRETRY == msgid) || (ERR_REPEATERROR == msgid) || (ERR_REPLONLNRLBK == msgid) || (ERR_JOBINTRRQST == msgid) + || (ERR_JOBINTRRETHROW == msgid)) error_condition = msgid; - /* util_out_print(NULL, RESET); Believe this is superfluous housecleaning. SE 9/2000 */ - } else - { - /* Note this message is not flushed out. This is so user console is not - polluted with messages that are going to be handled by a ZTRAP. If - ZTRAP is not active, the message will be flushed out in mdb_condition_handler - (which is usually the top level handler or is rolled over into by higher handlers. */ - VAR_START(var, argcnt); /* restart arg list */ - gtm_putmsg_list(argcnt, var); - va_end(var); + else + { /* Note this message is not flushed out. This is so user console is not polluted with messages that are going to be + * handled by a ZTRAP. If ZTRAP is not active, the message will be flushed out in mdb_condition_handler - which is + * usually the top level handler or is rolled over into by higher handlers. + */ + if (IS_GTMSECSHR_IMAGE) + util_out_print(NULL, RESET); + if (NULL == (ctl = err_check(msgid))) + msg = NULL; + else + GET_MSG_INFO(msgid, ctl, msg); + error_condition = msgid; + severity = NULL == msg ? ERROR : SEVMASK(msgid); + gtm_putmsg_list(csa, argcnt, var); if (DUMPABLE) created_core = dont_want_core = FALSE; /* We can create a(nother) core now */ - + if (IS_GTMSECSHR_IMAGE) + util_out_print(NULL, OPER); /* gtmsecshr errors always immediately pushed out */ } + va_end(var_dup); + va_end(var); DRIVECH(msgid); /* Drive the topmost (inactive) condition handler */ /* Note -- at one time there was code here to catch if we returned from the condition handlers * when the severity was error or above. That code had to be removed because of several errors @@ -85,4 +139,3 @@ int rts_error(int argcnt, ...) */ return 0; } - diff --git a/sr_unix/runall.csh b/sr_unix/runall.csh index 759bf7c..be64b40 100644 --- a/sr_unix/runall.csh +++ b/sr_unix/runall.csh @@ -1,7 +1,7 @@ #!/usr/local/bin/tcsh -f ################################################################# # # -# Copyright 2001, 2011 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -47,39 +47,6 @@ while (0 < $#) endsw shift end -#set temp=(`getopt nchl $argv:q`) -#if ($? == 0) then -# eval set argv=\($temp:q\) -# while (1) -# switch ($1:q) -# case -n : -# set listonly = 1 -# shift -# breaksw -# -# case -c : -# set compileonly = 1 -# shift -# breaksw -# -# case -l : -# set linkonly = 1 -# shift -# breaksw -# -# case -h : -# set helponly = 1 -# shift -# breaksw -# -# case -- : -# shift -# break -# endsw -# end -#else -# set helponly = 1 -#endif if ($helponly) then echo "Usage : `basename $0` [-n|-c|-h] [file...]" @@ -130,6 +97,20 @@ endif cd $gtm_root/$RUNALL_VERSION/${RUNALL_IMAGE}/obj +version $RUNALL_VERSION $RUNALL_IMAGE + +if ($?RUNALL_BYPASS_VERSION_CHECK == 0) then + if ($gtm_verno =~ V[4-8]* || $gtm_verno == "V990" ) then + echo "" + echo "-----------------------------------------------------------------------------------" + echo "RUNALL-E-WRONGVERSION : Cannot Runall a Non-Developemental Version ----> $gtm_verno" + echo "-----------------------------------------------------------------------------------" + echo "" + @ runall_status = 1 # to signal that the runall failed to do its job + goto cleanup + endif +endif + echo "" echo "Start of $gtm_tools/runall.csh" echo "" @@ -147,6 +128,7 @@ echo " RUNALL_VERSION ----> [ $RUNALL_VERSION ]" echo " RUNALL_IMAGE ----> [ $RUNALL_IMAGE ]" echo " RUNALL_EXTRA_CC_FLAGS ----> [ $RUNALL_EXTRA_CC_FLAGS ]" echo " RUNALL_EXTRA_AS_FLAGS ----> [ $RUNALL_EXTRA_AS_FLAGS ]" +echo " gtmroutines ----> [ $gtmroutines ]" echo "" if (`uname` == "SunOS") then @@ -155,7 +137,6 @@ endif set user=`id -u -n` -version $RUNALL_VERSION $RUNALL_IMAGE rm -f $gtm_log/error.$RUNALL_IMAGE.log >& /dev/null @@ -168,19 +149,6 @@ onintr cleanup set platform_name = `uname | sed 's/-//g' | sed 's,/,,' | tr '[A-Z]' '[a-z]'` set mach_type = `uname -m` -if ($?RUNALL_BYPASS_VERSION_CHECK == 0) then - set temp_ver=`echo $gtm_verno | sed 's/./& /g'` - if ($temp_ver[2] != "9" || $temp_ver[3] == "9" && $temp_ver[4] == "0") then - echo "" - echo "-----------------------------------------------------------------------------------" - echo "RUNALL-E-WRONGVERSION : Cannot Runall a Non-Developemental Version ----> $gtm_verno" - echo "-----------------------------------------------------------------------------------" - echo "" - @ runall_status = 1 # to signal that the runall failed to do its job - goto cleanup - endif -endif - # ---- currently, dtgbldir isn't built into an executable. So a "dummy" executable is assigned to it. cat - << LABEL >>! ${TMP_DIR}_exclude @@ -498,15 +466,17 @@ if (! -z ${TMP_DIR}_src_files) then # gtm_startup_chk requires gtm_dist setup rm -f ${file}_ctl.c ${file}_ansi.h # in case an old version is lying around set real_gtm_dist = "$gtm_dist" + if ($?gtmroutines) set save_gtmroutines = "$gtmroutines" setenv gtm_dist "$gtm_root/$gtm_curpro/pro" setenv gtmroutines "$gtm_obj($gtm_pct)" $gtm_root/$gtm_curpro/pro/mumps -run msg $gtm_src/$file.msg Unix if (0 != $status) @ runall_status = $status setenv gtm_dist "$real_gtm_dist" unset real_gtm_dist - mv ${file}_ctl.c $gtm_src/${file}_ctl.c + if ($?save_gtmroutines) setenv gtmroutines "$save_gtmroutines" + \mv -f ${file}_ctl.c $gtm_src/${file}_ctl.c if ( -f ${file}_ansi.h ) then - mv -f ${file}_ansi.h $gtm_inc + \mv -f ${file}_ansi.h $gtm_inc endif runall_cc $RUNALL_EXTRA_CC_FLAGS $gtm_src/${file}_ctl.c if (0 != $status) @ runall_status = $status @@ -610,7 +580,7 @@ else cat ${TMP_DIR}_main_.final >>! ${TMP_DIR}_build_routine.final endif # If we have a non-zero pct file list then include gde as one of the final build routines - if (! -z ${TMP_DIR}_pct_files) then + if (-e ${TMP_DIR}_pct_files && ! -z ${TMP_DIR}_pct_files) then echo "gde" >>! ${TMP_DIR}_build_routine.final endif set build_routine = `cat ${TMP_DIR}_build_routine.final` diff --git a/sr_unix/secshr_client.c b/sr_unix/secshr_client.c index bbea7f7..f4831ad 100644 --- a/sr_unix/secshr_client.c +++ b/sr_unix/secshr_client.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,17 +11,17 @@ #include "mdef.h" -#include "gtm_stdlib.h" /* for exit() */ - +#include +#include +#include #include #include #include #include +#include +#include #include "gtm_ctype.h" -#include -#include -#include - +#include "gtm_stdlib.h" /* for exit() */ #include "gtm_string.h" #include "gtm_socket.h" #include "gtm_fcntl.h" @@ -29,7 +29,10 @@ #include "gtm_stdio.h" #include "gtm_stat.h" #include "gt_timer.h" +#include "gtm_limits.h" +#include "gtm_syslog.h" +#include "gtmio.h" #include "io.h" #include "gtmsecshr.h" #include "iosp.h" @@ -48,6 +51,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" GBLREF struct sockaddr_un gtmsecshr_sock_name; GBLREF key_t gtmsecshr_key; @@ -59,53 +65,42 @@ GBLREF boolean_t gtmsecshr_sock_init_done; GBLREF uint4 process_id; GBLREF ipcs_mesg db_ipcs; +LITREF char gtm_release_name[]; +LITREF int4 gtm_release_name_len; + static int secshr_sem; -static int gtmsecshr_file_check_done = 0; +static boolean_t gtmsecshr_file_check_done; static mstr gtmsecshr_logname; -static char gtmsecshr_path[MAX_TRANS_NAME_LEN]; -static volatile int client_timer_popped; -static unsigned long cur_seqno = 0; +static char gtmsecshr_path[GTM_PATH_MAX]; +static volatile boolean_t client_timer_popped; +static unsigned long cur_seqno; - -const static char readonly secshr_fail_mesg_code[][MAX_GTMSECSHR_FAIL_MESG_LEN] = { +/* The below messages match up with the gtmsecshr_mesg_type codes */ +const static char readonly *secshr_fail_mesg_code[] = { "", "Wake Message Failed", - "Check process alive failed", "Remove Semaphore failed", "Remove Shared Memory segment failed", - "Ping Message failed", "Remove File failed", "Continue Process failed", }; - -const static char readonly secshrstart_error_code[][MAX_GTMSECSHR_FAIL_MESG_LEN] = { +/* The below messages match up with gtmsecshr exit codes from gtmsecshr.h. */ +const static char readonly *secshrstart_error_code[] = { "", "gtmsecshr unable to set-uid to root", - "gtmsecshr unable to set-gid to root", - "gtmsecshr unable to open log file", - "gtmsecshr unable to dup stdout and stderr", "The environmental variable gtm_dist is pointing to an invalid path", "Unable to exec gtmsecshr", "gtmsecshr unable to create a child process", - "The environmental variable gtm_log is pointing to an invalid path", "Error with gtmsecshr semaphore", - "Invalid gtm exit message", + "gtmsecshr already running - invalid invocation", "See syslog for cause of failure", + "gtmsecshr startup failed - gtmsecshr unable to chdir to tmp directory", + "gtmsecshr startup failed - gtmsecshr unable to determine invocation path", + "gtmsecshr startup failed - gtmsecshr not named gtmsecshr", + "gtmsecshr startup failed - $gtm_dist not same as startup path" }; -error_def(ERR_GTMSECSHR); -error_def(ERR_GTMSECSHRPERM); -error_def(ERR_GTMSECSHRSOCKET); -error_def(ERR_GTMSECSHRSRVF); -error_def(ERR_GTMSECSHRSRVFID); -error_def(ERR_GTMSECSHRSRVFIL); -error_def(ERR_GTMSECSHRSTART); -error_def(ERR_GTMSECSHRTMPPATH); -error_def(ERR_LOGTOOLONG); -error_def(ERR_SYSCALL); -error_def(ERR_TEXT); - -#define MAX_RETRIES 7 +#define MAX_COMM_ATTEMPTS 4 /* 1 to start secshr, 2 maybe slow, 3 maybe really slow, 4 outside max */ #define CLIENT_ACK_TIMER 5 #define START_SERVER \ @@ -114,13 +109,13 @@ error_def(ERR_TEXT); \ if (0 != (create_server_status = create_server())) \ { \ - assert(ARRAYSIZE(secshrstart_error_code) == (SYSLOGHASERRORDETAIL + 1)); \ + assert(ARRAYSIZE(secshrstart_error_code) == (LASTEXITCODE + 1)); \ errorindex = create_server_status; \ - if ((0 > errorindex) || (SYSLOGHASERRORDETAIL < errorindex)) \ - errorindex = SYSLOGHASERRORDETAIL; \ + if ((0 > errorindex) || (LASTEXITCODE < errorindex)) \ + errorindex = LASTEXITCODE; \ assert(0 <= errorindex); \ assert(ARRAYSIZE(secshrstart_error_code) > errorindex); \ - gtm_putmsg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), \ + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), \ process_id, ERR_TEXT, 2, \ RTS_ERROR_STRING(secshrstart_error_code[errorindex])); \ if (FATALFAILURE(create_server_status)) \ @@ -135,30 +130,42 @@ error_def(ERR_TEXT); #define SETUP_FOR_RECV \ { \ - recd = 0; \ - mesg_len = 0; \ recv_ptr = (char *)&mesg; \ recv_len = SIZEOF(mesg); \ - client_timer_popped = 0; \ + client_timer_popped = FALSE; \ + recv_complete = FALSE; \ + save_errno = 0; \ msec_timeout = timeout2msec(CLIENT_ACK_TIMER); \ start_timer(timer_id, msec_timeout, client_timer_handler, 0, NULL); \ } +error_def(ERR_GTMSECSHR); +error_def(ERR_GTMSECSHRPERM); +error_def(ERR_GTMSECSHRSOCKET); +error_def(ERR_GTMSECSHRSRVF); +error_def(ERR_GTMSECSHRSRVFID); +error_def(ERR_GTMSECSHRSRVFIL); +error_def(ERR_GTMSECSHRSTART); +error_def(ERR_GTMSECSHRTMPPATH); +error_def(ERR_LOGTOOLONG); +error_def(ERR_SYSCALL); +error_def(ERR_TEXT); + void client_timer_handler(void) { - client_timer_popped = 1; + client_timer_popped = TRUE; } int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path_len) { int client_sockfd, create_server_status, fcntl_res; int req_code, wait_count = 0; - int mesg_len; int recv_len, send_len; - ssize_t recd = 0, sent, num_chars_recvd, num_chars_sent; + ssize_t num_chars_recvd, num_chars_sent; int save_errno, ret_code = 0, init_ret_code = 0; int loop_count = 0; - boolean_t retry = FALSE, recv_complete, send_complete; + int recv_complete, send_complete; + boolean_t retry = FALSE; size_t server_proc_len; int semop_res; int selstat, status; @@ -170,209 +177,250 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path TID timer_id; int4 msec_timeout; char *gtm_tmp_ptr; + struct stat stat_buf; + struct shmid_ds shm_info; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; + DBGGSSHR((LOGFLAGS, "secshr_client: New send request\n")); + /* Create communication key (hash of release name) if it has not already been done */ + if (0 == TREF(gtmsecshr_comkey)) + { + STR_HASH((char *)gtm_release_name, gtm_release_name_len, TREF(gtmsecshr_comkey), 0); + } timer_id = (TID)send_mesg2gtmsecshr; - if (!gtmsecshr_file_check_done) { - struct stat stat_buf; - gtmsecshr_logname.addr = GTMSECSHR_PATH; - gtmsecshr_logname.len = SIZEOF(GTMSECSHR_PATH) - 1; + gtmsecshr_logname.len = SIZEOF(GTMSECSHR_PATH); status = TRANS_LOG_NAME(>msecshr_logname, >msecshr_pathname, gtmsecshr_path, SIZEOF(gtmsecshr_path), - dont_sendmsg_on_log2long); + dont_sendmsg_on_log2long); if (SS_NORMAL != status) { if (SS_LOG2LONG == status) - send_msg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtmsecshr_logname.len, gtmsecshr_logname.addr, - SIZEOF(gtmsecshr_path) - 1); - send_msg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR])); - rts_error(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR])); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, + gtmsecshr_logname.len, gtmsecshr_logname.addr, SIZEOF(gtmsecshr_path) - 1); + 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])); + rts_error_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])); } gtmsecshr_pathname.addr[gtmsecshr_pathname.len] = '\0'; if (-1 == Stat(gtmsecshr_pathname.addr, &stat_buf)) - rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, errno); + 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)) - rts_error(VARLSTCNT(1) ERR_GTMSECSHRPERM); - gtmsecshr_file_check_done = 1; + !(stat_buf.st_mode & S_ISUID)) + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRPERM); + gtmsecshr_file_check_done = TRUE; } - if (!gtmsecshr_sock_init_done && ((init_ret_code = gtmsecshr_sock_init(CLIENT)) > 0)) + if (!gtmsecshr_sock_init_done && (0 < (init_ret_code = gtmsecshr_sock_init(CLIENT)))) /* Note assignment */ return init_ret_code; - while (MAX_RETRIES > loop_count) + DEBUG_ONLY(mesg.usesecshr = TREF(gtm_usesecshr)); /* Flag ignored in PRO build */ + while (MAX_COMM_ATTEMPTS >= loop_count) { /* first, try the sendto */ req_code = mesg.code = code; - mesg.len = (int4)(GTM_MESG_HDR_SIZE); + send_len = (int4)(GTM_MESG_HDR_SIZE); if (REMOVE_FILE == code) { + assert(GTM_PATH_MAX > path_len); /* Name is not user supplied so simple check */ memcpy(mesg.mesg.path, path, path_len); - mesg.len += path_len; + send_len += path_len; } else if (FLUSH_DB_IPCS_INFO == code) { - memcpy(&mesg.mesg.db_ipcs, &db_ipcs, SIZEOF(struct ipcs_mesg_struct)); - /* most of the time file length is much smaller than MAX_TRANS_NAME_LEN */ - mesg.len += (SIZEOF(struct ipcs_mesg_struct) - MAX_TRANS_NAME_LEN); - mesg.len += mesg.mesg.db_ipcs.fn_len; + assert(GTM_PATH_MAX > db_ipcs.fn_len); + memcpy(&mesg.mesg.db_ipcs, &db_ipcs, (offsetof(ipcs_mesg, fn[0]) + db_ipcs.fn_len + 1)); + /* Most of the time file length is much smaller than GTM_PATH_MAX */ + send_len += offsetof(ipcs_mesg, fn[0]); + send_len += mesg.mesg.db_ipcs.fn_len + 1; } else { mesg.mesg.id = id; - mesg.len += SIZEOF(mesg.mesg.id); + send_len += SIZEOF(mesg.mesg.id); } - mesg.pid = process_id; + DBGGSSHR((LOGFLAGS, "secshr_client: loop %d frm-pid: %d to-pid: %d send_len: %d code: %d\n", loop_count, + process_id, id, send_len, code)); + mesg.comkey = TREF(gtmsecshr_comkey); /* Version communication key */ + mesg.pid = process_id; /* Process id of client */ mesg.seqno = ++cur_seqno; - sent = 0; send_ptr = (char *)&mesg; - send_len = mesg_len = mesg.len; - for (send_complete = FALSE; !send_complete;) - { - SENDTO_SOCK(gtmsecshr_sockfd, send_ptr, send_len, 0, (struct sockaddr *)>msecshr_sock_name, - (GTM_SOCKLEN_TYPE)gtmsecshr_sockpath_len, num_chars_sent); - if (0 <= num_chars_sent) + send_complete = FALSE; + SENDTO_SOCK(gtmsecshr_sockfd, send_ptr, send_len, 0, (struct sockaddr *)>msecshr_sock_name, + (GTM_SOCKLEN_TYPE)gtmsecshr_sockpath_len, num_chars_sent); /* This form handles EINTR internally */ + save_errno = errno; + DBGGSSHR((LOGFLAGS, "secshr_client: sendto rc: %d errno: %d (only important if rc=-1)\n", (int)num_chars_sent, + save_errno)); + if (0 >= num_chars_sent) + { /* SENDTO_SOCK failed - start server and attempt to resend */ + if ((EISCONN == save_errno) || (EBADF == save_errno)) { - sent += num_chars_sent; - if (sent == mesg_len) - { - send_complete = TRUE; - break; - } - send_ptr += num_chars_sent; - send_len -= (int)num_chars_sent; + gtmsecshr_sock_cleanup(CLIENT); + gtmsecshr_sock_init(CLIENT); + wcs_backoff(loop_count + 1); + DBGGSSHR((LOGFLAGS, "secshr_client: Connection error, reset socket\n")); } else { - /* sendto failed - start server and attempt to resend */ - save_errno = errno; - if ((EISCONN == save_errno) || (EBADF == save_errno)) - { - gtmsecshr_sock_cleanup(CLIENT); - gtmsecshr_sock_init(CLIENT); - wcs_backoff(loop_count + 1); - } else - { -# ifdef SECSHR_DEBUG - util_out_print("secshr_client starting server due to sendto failure errno = !UL", - TRUE, save_errno); -# endif - send_msg(VARLSTCNT(10) ERR_GTMSECSHRSRVF, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_TEXT("sendto to gtmsecshr failed"), save_errno); - /* if gtm_tmp is not defined, show default path */ - if (gtm_tmp_ptr = GETENV("gtm_tmp")) - send_msg(VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT(gtm_tmp_ptr), - ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)")); - else - send_msg(VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp")); - START_SERVER; - } - loop_count++; - break; + if (0 < loop_count) + /* No message unless attempted server start at least once */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4, + RTS_ERROR_TEXT("Client"), process_id, + loop_count - 1, ERR_TEXT, 2, + RTS_ERROR_TEXT("sendto to gtmsecshr failed"), save_errno); + START_SERVER; + DBGGSSHR((LOGFLAGS, "secshr_client: sendto() failed - restarting server\n")); } - } - if (!send_complete) + loop_count++; continue; - SETUP_FOR_RECV; - for (save_errno = 0, recv_complete = FALSE; !recv_complete;) - { - num_chars_recvd = recvfrom(gtmsecshr_sockfd, recv_ptr, MAX_MESG, 0, (struct sockaddr *)0, - (GTM_SOCKLEN_TYPE *)0); - if (0 <= num_chars_recvd) - { - recd += num_chars_recvd; - if ((0 == mesg_len) && (SIZEOF(int) <= recd)) - mesg_len = mesg.len; - if (recd == mesg_len) - { - if (mesg.seqno == cur_seqno) - { - recv_complete = TRUE; - break; - } - else - { - cancel_timer(timer_id); - recv_complete = FALSE; - save_errno = 0; - SETUP_FOR_RECV; - continue; - } - - } - recv_ptr += num_chars_recvd; - recv_len -= (int)num_chars_recvd; - continue; - } - if (client_timer_popped) - break; - if (EINTR == errno) - continue; - save_errno = errno; - if (EBADF == errno) - break; - send_msg(VARLSTCNT(10) ERR_GTMSECSHRSRVF, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_TEXT("recvfrom from gtmsecshr failed"), save_errno); - if ((ECONNRESET == save_errno) || (ENOTCONN == save_errno)) - { - num_chars_recvd = 0; - break; - } - gtmsecshr_sock_cleanup(CLIENT); - cancel_timer(timer_id); - return save_errno; } - if ((client_timer_popped || (EBADF == save_errno))) - { + SETUP_FOR_RECV; /* Sets timer, recvcomplete = FALSE */ + do + { /* Note RECVFROM does not loop on EINTR return codes so must be handled. Note also we only expect + * to receive the message header back as an acknowledgement. + */ + num_chars_recvd = RECVFROM(gtmsecshr_sockfd, recv_ptr, GTM_MESG_HDR_SIZE, 0, (struct sockaddr *)0, + (GTM_SOCKLEN_TYPE *)0); + save_errno = errno; + DBGGSSHR((LOGFLAGS, "secshr_client: recvfrom rc: %d errno: %d (only important if rc=-1)\n", + (int)num_chars_recvd, save_errno)); + if (0 <= num_chars_recvd) + { /* Message received - make sure it is large enough to have set seqno before we do anything + * to rely on it. + */ + if ((GTM_MESG_HDR_SIZE <= num_chars_recvd) && (mesg.seqno == cur_seqno) + && (TREF(gtmsecshr_comkey) == mesg.comkey)) + recv_complete = TRUE; + else + { /* Message too short or not correct sequence */ + cancel_timer(timer_id); + /* Print True/False for the possibilities we failed */ + DBGGSSHR((LOGFLAGS, "secshr_client: Message incorrect - chars: %d, seq: %d\n", + (GTM_MESG_HDR_SIZE <= num_chars_recvd), (mesg.seqno == cur_seqno))); + SETUP_FOR_RECV; + continue; + } + } else + { /* Something untoward happened */ + if (client_timer_popped) + break; + if (EINTR == save_errno) /* Had an irrelevant interrupt - ignore */ + continue; + if (EBADF == save_errno) + break; + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4, + RTS_ERROR_TEXT("Client"), process_id, loop_count - 1, ERR_TEXT, 2, + RTS_ERROR_TEXT("recvfrom from gtmsecshr failed"), save_errno); + if ((ECONNRESET == save_errno) || (ENOTCONN == save_errno)) + { + num_chars_recvd = 0; + break; + } + gtmsecshr_sock_cleanup(CLIENT); + return save_errno; + } + } while (!recv_complete); + cancel_timer(timer_id); + if (client_timer_popped || (EBADF == save_errno) || (0 == num_chars_recvd)) + { /* Timeout, connection issues, bad descriptor block - retry */ gtmsecshr_sock_cleanup(CLIENT); gtmsecshr_sock_init(CLIENT); retry = TRUE; if (client_timer_popped) { -# ifdef SECSHR_DEBUG - util_out_print("secshr_client starting server due to recvfrom timeout", TRUE); -# endif START_SERVER; - } + DBGGSSHR((LOGFLAGS, "secshr_client: Read timer popped - restarting server\n")); + } else + DBGGSSHR((LOGFLAGS, "secshr_client: Read error - socket reset, retrying\n")); loop_count++; continue; } - cancel_timer(timer_id); - if (ret_code = mesg.code) /* assign to ret_code, then test value */ + /* Response to *our* latest message available */ + assert(recv_complete); + if (ret_code = mesg.code) /* Warning - assignment */ { + DBGGSSHR((LOGFLAGS, "secshr_client: non-zero response from gtmsecshr - request: %d retcode: %d\n", + req_code, ret_code)); + if (INVALID_COMKEY == ret_code) + { /* Comkey mismatch means for a different version of GT.M - we will not handle it */ + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path), + ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version")); + rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path), + ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version")); + break; /* rts_error should not return */ + } switch(req_code) { - case REMOVE_FILE : - if (retry && ENOENT == ret_code) - ret_code = 0; /* assume first time worked */ + case REMOVE_FILE: + /* Called from mutex_sock_init(). Path (and length) contain null terminator byte. + * See if file still exists (may have been deleted by earlier attempt). Caller + * handles actual error. + */ + if ((-1 != Stat(path, &stat_buf)) || (ENOENT != ret_code)) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, + RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path), + ERR_TEXT, 2, RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), + mesg.code); else - send_msg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"), - process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path), - ERR_TEXT, 2, RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), - mesg.code); + ret_code = 0; /* File is gone so this or a previous try actually worked */ break; case REMOVE_SEM: - case REMOVE_SHMMEM: - if (retry && (mesg.mesg.id == id)) - ret_code = 0; + /* See if semaphore still eixsts (may have been removed by earlier attempt that + * got a reply confused or lost). If not there, no error. Else error to op-log. + */ + if ((-1 != semctl(id, 0, GETVAL)) && !SEM_REMOVED(errno)) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2, + RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), + mesg.code); + else + ret_code = 0; /* File is gone so this or a previous try actually worked */ + case REMOVE_SHM: + /* See if shmem still eixsts (may have been removed by earlier attempt that + * got a reply confused or lost). If not there, no error. Else error to op-log. + * Note - + */ + if ((-1 != shmctl(id, IPC_STAT, &shm_info)) && !SEM_REMOVED(errno)) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2, + RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), + mesg.code); + else + ret_code = 0; /* File is gone so this or a previous try actually worked */ break; - case FLUSH_DB_IPCS_INFO: + case FLUSH_DB_IPCS_INFO: /* Errors handled by caller */ break; - default : + default: if (EPERM != mesg.code && EACCES != mesg.code) - send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_TEXT("Client"), - process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2, - RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), - mesg.code); + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, + RTS_ERROR_TEXT("Client"), + process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2, + RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]), + mesg.code); break; - } } - if (recv_complete) - break; + break; } - if (MAX_RETRIES == loop_count) + if (MAX_COMM_ATTEMPTS < loop_count) { ret_code = -1; - gtm_putmsg(VARLSTCNT(9) ERR_GTMSECSHRSRVF, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to communicate with gtmsecshr")); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSRVF, 4, + RTS_ERROR_TEXT("Client"), process_id, loop_count - 1, + ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to communicate with gtmsecshr")); + /* If gtm_tmp is not defined, show default path */ + if (gtm_tmp_ptr = GETENV("gtm_tmp")) + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, + RTS_ERROR_TEXT(gtm_tmp_ptr), + ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)")); + else + send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) + ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp")); } if (ONETIMESOCKET == init_ret_code) gtmsecshr_sock_cleanup(CLIENT); @@ -390,16 +438,16 @@ int create_server(void) # endif int save_errno; - if (0 == (child_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + FORK(child_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ + if (0 == child_pid) { process_id = getpid(); - - /* do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */ + /* Do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */ status = EXECL(gtmsecshr_path, gtmsecshr_path, 0); if (-1 == status) { - send_msg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR])); + 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); } } else @@ -407,12 +455,12 @@ int create_server(void) if (-1 == child_pid) { status = GNDCHLDFORKFLD; - gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, - ERR_TEXT, 2, RTS_ERROR_TEXT("Failed to fork off gtmsecshr"), errno); + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, + ERR_TEXT, 2, RTS_ERROR_TEXT("Failed to fork off gtmsecshr"), errno); /* Sleep for a while and hope a subsequent fork will succeed */ hiber_start(1000); } - for ( ; !status ; ) + for (; !status ;) { /* To prevent a warning message that the compiler issues */ done_pid = wait(&CSTAT); @@ -427,7 +475,8 @@ int create_server(void) else if (EINTR != errno) { status = GNDCHLDFORKFLD; - gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id, + gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, + RTS_ERROR_TEXT("Client"), process_id, ERR_TEXT, 2, RTS_ERROR_TEXT("Error spawning gtmsecshr"), errno); } } diff --git a/sr_unix/semstat2.c b/sr_unix/semstat2.c index ce779f8..1b53e0d 100644 --- a/sr_unix/semstat2.c +++ b/sr_unix/semstat2.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,7 +58,7 @@ int main (int argc, char *argv[]) if (argc == 1) { usage(argv[0]); - exit(1); + exit(EXIT_FAILURE); } semarg.buf = &semstat; for(i=1; i< argc; i++) @@ -110,5 +110,5 @@ int main (int argc, char *argv[]) PRINTF("sempid=%d)\n", sempid); } } - exit(0); + exit(EXIT_SUCCESS); } diff --git a/sr_unix/send_msg.c b/sr_unix/send_msg.c index fd10b73..c8c67ea 100644 --- a/sr_unix/send_msg.c +++ b/sr_unix/send_msg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,21 +22,28 @@ #include "send_msg.h" #include "caller_id.h" #include "gtmsiginfo.h" +/* database/replication related includes due to anticipatory freeze */ +#include "gdsroot.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "filestruct.h" +#include "repl_msg.h" /* for gtmsource.h */ +#include "gtmsource.h" /* for anticipatory_freeze.h */ +#include "anticipatory_freeze.h" /* for SET_ANTICIPATORY_FREEZE_IF_NEEDED */ -GBLREF bool caller_id_flag; -GBLREF va_list last_va_list_ptr; -GBLREF volatile int4 exit_state; +GBLREF bool caller_id_flag; +GBLREF volatile int4 exit_state; +GBLREF volatile boolean_t timer_in_handler; +GBLREF jnlpool_addrs jnlpool; +GBLREF gd_region *gv_cur_region; +GBLREF jnlpool_addrs jnlpool; +GBLREF VSIG_ATOMIC_T forced_exit; #ifdef DEBUG static uint4 nesting_level = 0; #endif -#define NOFLUSH 0 -#define FLUSH 1 -#define RESET 2 -#define OPER 4 - - +void send_msg_va(void *csa, int arg_count, va_list var); /* ** WARNING: For chained error messages, all messages MUST be followed by an fao count; @@ -47,38 +54,66 @@ static uint4 nesting_level = 0; void send_msg(int arg_count, ...) { - va_list var; - int dummy, fao_actual, fao_count, i, msg_id; - char msg_buffer[1024]; - mstr msg_string; + va_list var; + sgmnt_addrs *csa; + DCL_THREADGBL_ACCESS; - /* Since send_msg uses a global variable buffer, reentrant calls to send_msg will use the same buffer. - * Ensure we never overwrite an under-construction send_msg buffer with a nested send_msg call. The - * only exception to this is if the nested call to send_msg is done by exit handling code in which case - * the latest send_msg call prevails and it is ok since we will never return to the original send_msg() - * call again. Detect if ever this assmption gets violated with an assert. - */ - assert((0 == nesting_level) || (EXIT_IMMED == exit_state)); - DEBUG_ONLY(nesting_level++;) + SETUP_THREADGBL_ACCESS; + csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL; VAR_START(var, arg_count); - assert(arg_count > 0); - util_out_save(); - util_out_print(NULL, RESET); + send_msg_va(csa, arg_count, var); + va_end(var); +} +void send_msg_csa(void *csa, int arg_count, ...) +{ + va_list var; + + VAR_START(var, arg_count); + send_msg_va(csa, arg_count, var); + va_end(var); +} + +void send_msg_va(void *csa, int arg_count, va_list var) +{ + int dummy, fao_actual, fao_count, i, msg_id, freeze_msg_id; + char msg_buffer[1024]; + mstr msg_string; + char *save_util_outptr; + va_list save_last_va_list_ptr; + boolean_t util_copy_saved = FALSE; + boolean_t freeze_needed = FALSE; + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + /* Since send_msg uses a global variable buffer, reentrant calls to send_msg will use the same buffer. + * Ensure we never overwrite an under-construction send_msg buffer with a nested send_msg call. One + * exception to this is if the nested call to send_msg is done by exit handling code in which case the + * latest send_msg call prevails and it is ok since we will never return to the original send_msg call + * again. The other exception is if enable interrupts in util_out_send_oper results in a new send_msg + * in deferred_signal_handler. + */ + assert((0 == nesting_level) || ((2 > nesting_level) && timer_in_handler) + || (EXIT_IMMED == exit_state) || (2 == forced_exit)); + DEBUG_ONLY(nesting_level++;) + assert(arg_count > 0); + if ((NULL != TREF(util_outptr)) && (TREF(util_outptr) != TREF(util_outbuff_ptr))) + { + SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); + } + util_out_print(NULL, RESET); for (;;) { msg_id = (int) va_arg(var, VA_ARG_TYPE); + CHECK_IF_FREEZE_ON_ERROR_NEEDED(csa, msg_id, freeze_needed, freeze_msg_id); --arg_count; - msg_string.addr = msg_buffer; msg_string.len = SIZEOF(msg_buffer); gtm_getmsg(msg_id, &msg_string); - - if (arg_count > 0) + if (0 < arg_count) { fao_actual = (int) va_arg(var, VA_ARG_TYPE); --arg_count; - fao_count = fao_actual; if (fao_count > MAX_FAO_PARMS) { @@ -87,11 +122,10 @@ void send_msg(int arg_count, ...) } } else fao_actual = fao_count = 0; - util_out_print_vaparm(msg_string.addr, NOFLUSH, var, fao_count); va_end(var); /* need this before used as dest in copy */ - VAR_COPY(var, last_va_list_ptr); - va_end(last_va_list_ptr); + VAR_COPY(var, TREF(last_va_list_ptr)); + va_end(TREF(last_va_list_ptr)); arg_count -= fao_count; if (0 >= arg_count) @@ -102,12 +136,11 @@ void send_msg(int arg_count, ...) } util_out_print("!/", NOFLUSH); } - va_end(var); - util_out_print(NULL, OPER); - util_out_restore(); + RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); /* it has been suggested that this would be a place to check a view_debugN * and conditionally enter a "forever" loop on wcs_sleep for unix debugging */ DEBUG_ONLY(nesting_level--;) + FREEZE_INSTANCE_IF_NEEDED(csa, freeze_needed, freeze_msg_id); } diff --git a/sr_unix/set_library_path.csh b/sr_unix/set_library_path.csh index 95a1d51..b40f889 100644 --- a/sr_unix/set_library_path.csh +++ b/sr_unix/set_library_path.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2010 Fidelity Information Services, Inc # +# Copyright 2010, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -21,9 +21,12 @@ if ($HOSTOS == "AIX" || $HOSTOS == "SunOS" || $HOSTOS == "OS/390") then setenv LIBPATH /usr/local/lib64:/usr/local/lib setenv LD_LIBRARY_PATH /usr/local/lib64:/usr/local/lib else -# Its worth noting that SuSE+RedHat,Debian & Ubuntu handle the lib32 vs lib64 differently +# Its worth noting that SuSE+RedHat, Debian & Ubuntu handle the lib32 vs lib64 differently # Debian way: /lib 32bit points to /emul/ia32-linux/lib # /lib64 64bit +# Debian 7 layout is uniform across archs, but is more annoying than before +# /usr/lib/i386-linux-gnu 32bit +# /usr/lib/x86_64-linux-gnu 64bit # Ubuntu way: /lib ARCH default points to either lib32 or lib64 # /lib32 32bit # /lib64 64bit @@ -34,9 +37,10 @@ else exit endif +# please keep in sync with sr_unix/gtm_test_install.csh if (( -e $gtm_inc/s390.h ) || ( -e $gtm_inc/x86_64.h )) then - setenv LD_LIBRARY_PATH "/usr/local/lib64:/usr/local/lib:/usr/lib64:/usr/lib" + setenv LD_LIBRARY_PATH "/usr/local/lib64:/usr/local/lib:/usr/lib64:/usr/lib/x86_64-linux-gnu:/usr/lib" else - setenv LD_LIBRARY_PATH "/usr/local/lib:/usr/lib:/usr/lib32" + setenv LD_LIBRARY_PATH "/usr/local/lib:/usr/lib:/usr/lib/i386-linux-gnu:/usr/lib32" endif endif diff --git a/sr_unix/set_zstatus.c b/sr_unix/set_zstatus.c index fdb4125..64c5ebf 100644 --- a/sr_unix/set_zstatus.c +++ b/sr_unix/set_zstatus.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,7 +30,6 @@ GBLREF mval dollar_zstatus, dollar_zerror; GBLREF mval dollar_ztrap, dollar_etrap; GBLREF stack_frame *zyerr_frame, *frame_pointer; -GBLREF char *util_outptr, util_outbuff[OUT_BUFF_SIZE]; GBLREF mstr *err_act; error_def(ERR_MEMORY); @@ -45,7 +44,9 @@ unsigned char *set_zstatus(mstr *src, int arg, unsigned char **ctxtp, boolean_t size_t util_len ; mval *status_loc; boolean_t trans_frame; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; b_line = 0; if (!need_rtsloc) trans_frame = FALSE; @@ -68,35 +69,35 @@ unsigned char *set_zstatus(mstr *src, int arg, unsigned char **ctxtp, boolean_t memcpy(zstatus_buff, val.str.addr, val.str.len); zstatus_bptr = zstatus_buff + val.str.len; *zstatus_bptr++ = ','; - if (0 != b_line) + if (NULL != b_line) { memcpy(zstatus_bptr, src->addr, src->len); zstatus_bptr += src->len; *zstatus_bptr++ = ','; } zstatus_iter = zstatus_bptr; - util_len = util_outptr - util_outbuff; + util_len = TREF(util_outptr) - TREF(util_outbuff_ptr); if (trans_frame) { /* currently no inserted message (arg) needs arguments. The following code needs * to be changed if any new parametered message is added. */ - util_outbuff[0] = '-'; - memcpy(&zstatus_buff[OUT_BUFF_SIZE], util_outbuff, util_len); /* save original message */ + *(TREF(util_outbuff_ptr)) = '-'; + memcpy(&zstatus_buff[OUT_BUFF_SIZE], TREF(util_outbuff_ptr), util_len); /* save original message */ util_out_print(NULL, RESET); /* clear any pending msgs and reset util_out_buff */ gtm_putmsg_noflush(VARLSTCNT(1) arg); - memcpy(zstatus_bptr, util_outbuff, util_outptr - util_outbuff); - zstatus_bptr += (util_outptr - util_outbuff); + memcpy(zstatus_bptr, TREF(util_outbuff_ptr), TREF(util_outptr) - TREF(util_outbuff_ptr)); + zstatus_bptr += (TREF(util_outptr) - TREF(util_outbuff_ptr)); *zstatus_bptr++ = ','; memcpy(zstatus_bptr, &zstatus_buff[OUT_BUFF_SIZE], util_len); /* restore original message into util_outbuf */ - memcpy(util_outbuff, &zstatus_buff[OUT_BUFF_SIZE], util_len); - util_outbuff[0] = '%'; - util_outptr = util_outbuff + util_len; + memcpy(TREF(util_outbuff_ptr), &zstatus_buff[OUT_BUFF_SIZE], util_len); + *(TREF(util_outbuff_ptr)) = '%'; + TREF(util_outptr) = TREF(util_outbuff_ptr) + util_len; arg = save_arg; } else - memcpy(zstatus_bptr, util_outbuff, util_len); + memcpy(zstatus_bptr, TREF(util_outbuff_ptr), util_len); zstatus_bptr += util_len; for (; zstatus_iter < zstatus_bptr; zstatus_iter++) { diff --git a/sr_unix/setterm.c b/sr_unix/setterm.c index e48be94..0e506b3 100644 --- a/sr_unix/setterm.c +++ b/sr_unix/setterm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -22,13 +22,14 @@ #include "setterm.h" #include "gtm_isanlp.h" +error_def(ERR_TCSETATTR); + void setterm(io_desc *ioptr) { int status; int save_errno; struct termios t; d_tt_struct *tt_ptr; - error_def(ERR_TCSETATTR); tt_ptr = (d_tt_struct *) ioptr->dev_sp; t = *tt_ptr->ttio_struct; @@ -41,10 +42,9 @@ void setterm(io_desc *ioptr) t.c_cc[VMIN] = 1; } t.c_iflag &= ~(ICRNL); - Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status); + Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno); if (0 != status) { - save_errno = errno; if (gtm_isanlp(tt_ptr->fildes) == 0) rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno); } @@ -64,9 +64,9 @@ void setterm(io_desc *ioptr) void iott_mterm(io_desc *ioptr) { int status; + int save_errno; struct termios t; d_tt_struct *tt_ptr; - error_def(ERR_TCSETATTR); tt_ptr = (d_tt_struct *) ioptr->dev_sp; t = *tt_ptr->ttio_struct; @@ -83,9 +83,9 @@ void iott_mterm(io_desc *ioptr) t.c_cc[VMIN] = 0; } t.c_iflag &= ~(ICRNL); - Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status); + Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno); if (0 != status) - rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, errno); + rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno); return; } @@ -96,6 +96,7 @@ void iott_mterm(io_desc *ioptr) void iott_rterm(io_desc *ioptr) { int status; + int save_errno; struct termios t; d_tt_struct *tt_ptr; @@ -110,8 +111,8 @@ void iott_rterm(io_desc *ioptr) t.c_cc[VMIN] = 1; } t.c_iflag &= ~(ICRNL); - Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status); + Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno); if (0 != status) - rts_error(VARLSTCNT(1) status); + rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno); return; } diff --git a/sr_unix/sgtm_putmsg.c b/sr_unix/sgtm_putmsg.c index f8eb0c8..9750258 100644 --- a/sr_unix/sgtm_putmsg.c +++ b/sr_unix/sgtm_putmsg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,9 +32,6 @@ #include "util_out_print_vaparm.h" #include "sgtm_putmsg.h" -GBLREF char util_outbuff[]; -GBLREF va_list last_va_list_ptr; - /* ** WARNING: For chained error messages, all messages MUST be followed by an fao count; ** ======= zero MUST be specified if there are no parameters. @@ -48,7 +45,9 @@ void sgtm_putmsg(char *out_str, ...) char msg_buffer[OUT_BUFF_SIZE]; mstr msg_string; size_t util_outbufflen; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; VAR_START(var, out_str); arg_count = va_arg(var, int); @@ -80,8 +79,8 @@ void sgtm_putmsg(char *out_str, ...) util_out_print_vaparm(msg_string.addr, NOFLUSH, var, fao_count); va_end(var); /* need before using as dest in va_copy */ - VAR_COPY(var, last_va_list_ptr); - va_end(last_va_list_ptr); + VAR_COPY(var, TREF(last_va_list_ptr)); + va_end(TREF(last_va_list_ptr)); arg_count -= fao_count; if (0 >= arg_count) @@ -92,8 +91,8 @@ void sgtm_putmsg(char *out_str, ...) va_end(var); util_out_print(NULL, SPRINT); - util_outbufflen = strlen(util_outbuff); - memcpy(out_str, util_outbuff, util_outbufflen); + util_outbufflen = STRLEN(TREF(util_outbuff_ptr)); + memcpy(out_str, TREF(util_outbuff_ptr), util_outbufflen); out_str[util_outbufflen] = '\n'; out_str[util_outbufflen + 1] = '\0'; } diff --git a/sr_unix/sig_init.c b/sr_unix/sig_init.c index b53ac6f..363b9f4 100644 --- a/sr_unix/sig_init.c +++ b/sr_unix/sig_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,116 +21,125 @@ #include "sig_init.h" #include "gtmci_signals.h" +#ifdef GTM_PTHREAD +GBLREF boolean_t gtm_jvm_process; +#endif + void null_handler(int sig); -void sig_init(void (*signal_handler)(), void (*ctrlc_handler)(), void (*suspsig_handler)()) +void sig_init(void (*signal_handler)(), void (*ctrlc_handler)(), void (*suspsig_handler)(), void (*continue_handler)()) { - struct sigaction ignore, act; + struct sigaction ignore, null_action, def_action, susp_action, + gen_action, ctrlc_action, cont_action; int sig; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; + memset(&ignore, 0, SIZEOF(ignore)); + sigemptyset(&ignore.sa_mask); - memset(&act, 0, SIZEOF(act)); - sigemptyset(&act.sa_mask); - ignore = act; + /* Copying only up to susp_action here to later specify SA_SIGINFO flag and continue copying with it. */ + null_action = def_action = susp_action = ignore; ignore.sa_handler = SIG_IGN; + null_action.sa_handler = null_handler; + def_action.sa_handler = SIG_DFL; + + /* Give us extra info on the following signals and a full core if necessary. */ + susp_action.sa_flags = SA_SIGINFO; + gen_action = ctrlc_action = cont_action = susp_action; + susp_action.sa_sigaction = suspsig_handler; + gen_action.sa_sigaction = signal_handler; + ctrlc_action.sa_sigaction = ctrlc_handler; + cont_action.sa_sigaction = continue_handler; for (sig = 1; sig <= NSIG; sig++) - sigaction(sig, &ignore, NULL); - - /* -------------------------------------------------------------- - * Tandem hack: rather than ignore SIGHUP, we must catch it - * and do nothing with the signal. This prevents ioctls on - * modem/tty devices from hanging when carrier drops during - * the system call. - * -------------------------------------------------------------- - */ - act.sa_handler = null_handler; - sigaction(SIGHUP, &act, 0); - - /* -------------------------------------------------------------- - * Default handling necessary for SIGCLD signal. - * CAUTION :consider the affect on JOB (timeout) implementation before - * changing this behaviour (like defuncts, ECHILD errors etc..) - * -------------------------------------------------------------- - */ - act.sa_handler = SIG_DFL; - sigaction(SIGCLD, &act, 0); - - /* -------------------------------------------------------------- - * Give us extra info on the following signals and a full core - * if necessary. - * -------------------------------------------------------------- - */ - act.sa_flags = SA_SIGINFO; - - /* -------------------------------------------------------------- - * Signals that suspend a process - * -------------------------------------------------------------- - */ - if (NULL != suspsig_handler) { - act.sa_sigaction = suspsig_handler; - sigaction(SIGTSTP, &act, 0); - sigaction(SIGTTIN, &act, 0); - sigaction(SIGTTOU, &act, 0); + switch (sig) + { + case SIGHUP: + /* Tandem hack: rather than ignore SIGHUP, we must catch it and do nothing with the signal. This + * prevents ioctls on modem/tty devices from hanging when carrier drops during the system call. + */ + sigaction(sig, &null_action, NULL); + break; + case SIGCLD: + /* Default handling necessary for SIGCLD signal. CAUTION: consider the affect on JOB (timeout) + * implementation before changing this behavior (like defuncts, ECHILD errors, etc.). + */ + sigaction(sig, &def_action, NULL); + break; + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + /* These are all signals that suspend a process. */ + if (NULL != suspsig_handler) + sigaction(sig, &susp_action, NULL); + else + sigaction(sig, &ignore, NULL); + break; + case SIGINT: + /* If supplied with a control-C handler, install it now. */ + if (NULL != ctrlc_handler) + sigaction(sig, &ctrlc_action, NULL); + else + sigaction(sig, &ignore, NULL); + break; + case SIGCONT: + /* Special handling for SIGCONT. */ + if (NULL != continue_handler) + { +# ifndef DISABLE_SIGCONT_PROCESSING + if (FALSE == TREF(disable_sigcont)) + sigaction(SIGCONT, &cont_action, NULL); +# else + TREF(disable_sigcont) = TRUE; +# endif + } else + { + sigaction(sig, &ignore, NULL); + TREF(disable_sigcont) = TRUE; + } + break; + case SIGSEGV: +# ifdef GTM_PTHREAD + if (gtm_jvm_process) + break; +# endif + case SIGABRT: +# ifdef GTM_PTHREAD + if (gtm_jvm_process) + break; +# endif + case SIGBUS: +# ifdef _AIX + case SIGDANGER: +# endif + case SIGFPE: +# ifdef __MVS__ + case SIGABND: +# else + /* On Linux SIGIOT is commonly same as SIGABRT, so to avoid duplicate cases, check for that. */ +# if !defined(__CYGWIN__) && defined (SIGIOT) && (SIGIOT != SIGABRT) + case SIGIOT: +# endif +# ifndef __linux__ + case SIGEMT: +# endif +# endif + case SIGILL: + case SIGQUIT: +# ifndef __linux__ + case SIGSYS: +# endif + case SIGTERM: + case SIGTRAP: + /* These are all being handled by the generic_signal_handler. */ + sigaction(sig, &gen_action, NULL); + break; + default: + sigaction(sig, &ignore, NULL); + } } - - /* -------------------------------------------------------------- - * Set special rundown handler for the following terminal signals - * -------------------------------------------------------------- - */ - act.sa_sigaction = signal_handler; - - sigaction(SIGABRT, &act, 0); - sigaction(SIGBUS, &act, 0); -#ifdef _AIX - sigaction(SIGDANGER, &act, 0); -#endif - sigaction(SIGFPE, &act, 0); -#ifdef __MVS__ - sigaction(SIGABND, &act, 0); -#else -# ifndef __linux__ - sigaction(SIGEMT, &act, 0); -# endif -#ifndef __CYGWIN__ - sigaction(SIGIOT, &act, 0); -#endif -#endif - sigaction(SIGILL, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGSEGV, &act, 0); -#ifndef __linux__ - sigaction(SIGSYS, &act, 0); -#endif - sigaction(SIGTERM, &act, 0); - sigaction(SIGTRAP, &act, 0); - - /* -------------------------------------------------------------- - * If supplied with a control-C handler, install it now. - * -------------------------------------------------------------- - */ - if (NULL != ctrlc_handler) - { - act.sa_sigaction = ctrlc_handler; - sigaction(SIGINT, &act, 0); - } - - /* -------------------------------------------------------------- - * Special handling for SIGCONT - * -------------------------------------------------------------- - */ -#ifndef DISABLE_SIGCONT_PROCESSING - if (FALSE == TREF(disable_sigcont)) - { - act.sa_sigaction = continue_handler; - sigaction(SIGCONT, &act, 0); - } -#else - TREF(disable_sigcont) = TRUE; -#endif } /* Provide null signal handler */ diff --git a/sr_unix/sig_init.h b/sr_unix/sig_init.h index 2499a57..f8e2181 100644 --- a/sr_unix/sig_init.h +++ b/sr_unix/sig_init.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,7 +11,7 @@ #ifndef __SIG_INIT_H__ #define __SIG_INIT_H__ -void sig_init(void (*signal_handler)(), void (*ctrlc_handler)(), void (*suspsig_handler)()); +void sig_init(void (*signal_handler)(), void (*ctrlc_handler)(), void (*suspsig_handler)(), void (*continue_handler)()); void null_handler(int sig); #endif diff --git a/sr_unix/sleep.h b/sr_unix/sleep.h index 70b9741..3a1bc6a 100644 --- a/sr_unix/sleep.h +++ b/sr_unix/sleep.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -12,11 +12,10 @@ #ifndef SLEEP_H #define SLEEP_H -/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function - causes problems with GT.M's timers on some platforms. Specifically, the sleep() function - causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least). - This leads to lost timer pops and has the potential for system hangs. The proper long sleep mechanism - is hiber_start which can be accessed through the LONG_SLEEP macro defined in mdef.h. +/* Note: GT.M code *MUST NOT* use the sleep function because it causes problems with GT.M's timers on some platforms. Specifically, + * the sleep function results in SIGARLM handler being silently deleted on Solaris systems (through Solaris 9 at least). This leads + * to lost timer pops and has the potential for system hangs. The proper long sleep mechanism is hiber_start which can be accessed + * through the LONG_SLEEP macro defined in mdef.h. */ int m_sleep(int seconds); @@ -31,6 +30,135 @@ int m_nsleep(int nseconds); # endif # endif +#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 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); \ + } \ +} +#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. + */ +# 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 diff --git a/sr_unix/source_file.c b/sr_unix/source_file.c index 5117109..ed67b46 100644 --- a/sr_unix/source_file.c +++ b/sr_unix/source_file.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,6 +32,7 @@ #include "cmd_qlf.h" #include "min_max.h" #include "cli.h" +#include "have_crit.h" GBLREF unsigned short source_name_len; GBLREF unsigned char source_file_name[]; @@ -219,7 +220,7 @@ bool open_source_file (void) int_module_name.len = routine_name.len; if ('_' == *routine_name.addr) routine_name.addr[0] = '%'; - p = (char *)GTM_CTIME(&clock); + GTM_CTIME(p, &clock); memcpy(rev_time_buf, p + 4, REV_TIME_BUFF_LEN); io_curr_device = dev_in_use; /* set it back to make open_list_file save the device */ return TRUE; diff --git a/sr_unix/ss_initiate.c b/sr_unix/ss_initiate.c index 9a20556..58bbedb 100644 --- a/sr_unix/ss_initiate.c +++ b/sr_unix/ss_initiate.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2012 Fidelity Information Services, Inc * + * Copyright 2009, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -69,6 +69,7 @@ GBLREF boolean_t online_specified; GBLREF gd_region *gv_cur_region; GBLREF void (*call_on_signal)(); GBLREF int process_exiting; +GBLREF boolean_t muint_fast; error_def(ERR_BUFFLUFAILED); error_def(ERR_DBROLLEDBACK); @@ -186,10 +187,7 @@ void ss_initiate_call_on_signal(void) csa = &FILE_INFO(gv_cur_region)->s_addrs; call_on_signal = NULL; /* Do not recurse via call_on_signal if there is an error */ - process_exiting = TRUE; /* Signal function "free" (in gtm_malloc_src.h) not to bother with frees as we are anyways exiting. - * This avoids assert failures that would otherwise occur due to nested storage mgmt calls - * just in case we came here because of an interrupt (e.g. SIGTERM) while a malloc was in progress. - */ + assert(process_exiting); /* Set by generic_signal_handler() */ assert(NULL != csa->ss_ctx); ss_release(&csa->ss_ctx); return; @@ -217,9 +215,9 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s struct stat stat_buf; enum db_acc_method acc_meth; void *ss_shmaddr; - gtm_int64_t db_file_size; - uint4 tempnamprefix_len, crit_counter, tot_blks, prev_ss_shmsize, native_size, fstat_status; - uint4 *kip_pids_arr_ptr; + gtm_uint64_t db_file_size, native_size; + uint4 tempnamprefix_len, crit_counter, tot_blks, prev_ss_shmsize, fstat_status; + pid_t *kip_pids_arr_ptr; mstr tempdir_log, tempdir_full, tempdir_trans; boolean_t debug_mupip = FALSE, wait_for_zero_kip, final_retry; now_t now; @@ -386,7 +384,12 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s FSTAT_FILE(((unix_db_info *)(reg->dyn.addr->file_cntl->file_info))->fd, &stat_buf, fstat_res); assert(-1 != fstat_res); if (-1 != fstat_res) - if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0) + { + /* Even though the temporary snapshot file is a physical file, we give it a relaxed IPC permissions to allow + * INTEG started by read-only processes to create snapshot files that are writable by processes having write + * permissions on the database file. + */ + if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_IPC, &pdd) < 0) { send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("snapshot file"), @@ -399,7 +402,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s UNFREEZE_REGION_IF_NEEDED(csd, reg); return FALSE; } - + } if ((-1 == fstat_res) || (-1 == FCHMOD(shdw_fd, perm)) || ((-1 != group_id) && (-1 == fchown(shdw_fd, -1, group_id)))) { @@ -506,7 +509,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s } /* Write EOF block in the snapshot file */ native_size = gds_file_size(reg->dyn.addr->file_cntl); - db_file_size = (gtm_int64_t)(native_size) * DISK_BLOCK_SIZE; /* Size of database file in bytes */ + db_file_size = native_size * DISK_BLOCK_SIZE; /* Size of database file in bytes */ LSEEKWRITE(shdw_fd, ((off_t)db_file_size + ss_shmsize), eof_marker, EOF_MARKER_SIZE, status); if (0 != status) { /* error while writing EOF record to snapshot file */ @@ -576,7 +579,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s { /* We have a consistent copy of the total blocks and csd->kill_in_prog is FALSE inside crit. No need for * retry. */ - assert(native_size == ((tot_blks * (csd->blk_size / DISK_BLOCK_SIZE)) + (csd->start_vbn))); + assert(native_size == (((gtm_uint64_t)tot_blks * (csd->blk_size / DISK_BLOCK_SIZE)) + (csd->start_vbn))); break; } } @@ -586,7 +589,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s * proceed gracefully */ assert(csa->now_crit); - assert(native_size == ((tot_blks * (csd->blk_size / DISK_BLOCK_SIZE)) + (csd->start_vbn))); + assert(native_size == (((gtm_uint64_t)tot_blks * (csd->blk_size / DISK_BLOCK_SIZE)) + (csd->start_vbn))); assert(NULL != ss_shmaddr); assert(0 == ((long)ss_shmaddr % OS_PAGE_SIZE)); assert(0 == ss_shmsize % OS_PAGE_SIZE); @@ -611,7 +614,6 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s { gtm_putmsg(VARLSTCNT(4) ERR_SSV4NOALLOW, 2, DB_LEN_STR(reg)); util_out_print(NO_ONLINE_ERR_MSG, TRUE); - mu_int_errknt++; GET_CRIT_AND_DECR_INHIBIT_KILLS(reg, cnl); UNFREEZE_REGION_IF_NEEDED(csd, reg); return FALSE; @@ -649,7 +651,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s /* ========== STEP 6: Copy the file header, master map and the native file size into a private structure =========== */ memcpy(util_ss_ptr->header, csd, SGMNT_HDR_LEN); - memcpy(util_ss_ptr->master_map, MM_ADDR(csd), MASTER_MAP_SIZE_MAX); + memcpy(util_ss_ptr->master_map, MM_ADDR(csd), MASTER_MAP_SIZE(csd)); util_ss_ptr->native_size = native_size; /* We are about to copy the process private variables to shared memory. Although we have done grab_crit above, we take @@ -685,8 +687,9 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s DECR_INHIBIT_KILLS(cnl); /* announce GT.M that it's now ok to write the before images */ if (!SNAPSHOTS_IN_PROG(cnl)) - cnl->snapshot_in_prog = TRUE; - csa->snapshot_in_prog = TRUE; + SET_SNAPSHOTS_IN_PROG(cnl); + SET_SNAPSHOTS_IN_PROG(csa); + cnl->fastinteg_in_prog = muint_fast; /* Having a write memory barrier here ensures that whenever GT.M reads a newer value of cnl->ss_shmcycle, it is guaranteed * that the remaining fields that it reads from the shared memory will be the latest ones. */ @@ -711,11 +714,16 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s ISSUE_WRITE_ERROR_AND_EXIT(reg, pwrite_res, csa, tempfilename); dsk_addr += ((int)ss_shmsize + (int)SGMNT_HDR_LEN); /* write the database master map to the shadow file */ - LSEEKWRITE(shdw_fd, dsk_addr, (sm_uc_ptr_t)util_ss_ptr->master_map, MASTER_MAP_SIZE_MAX, pwrite_res); + assert(0 == ((dsk_addr + MASTER_MAP_SIZE_MAX) % OS_PAGE_SIZE)); + LSEEKWRITE(shdw_fd, dsk_addr, (sm_uc_ptr_t)util_ss_ptr->master_map, MASTER_MAP_SIZE(csd), pwrite_res); if (0 != pwrite_res) ISSUE_WRITE_ERROR_AND_EXIT(reg, pwrite_res, csa, tempfilename); + /* The size of the master map written to snap-shot file is read from database header i.e. MASTER_MAP_SIZE(csd). + * That is the actual size which may differ depending on the version that created the database file. + * But this sets the dsk_addr for the Starting VBN using the current MASTER_MAP_SIZE_MAX to keep it aligned + * to the OS PAGE SIZE + */ dsk_addr += MASTER_MAP_SIZE_MAX; - assert(0 == (dsk_addr % OS_PAGE_SIZE)); lcl_ss_ctx->cur_state = SNAPSHOT_INIT_DONE; /* Same as AFTER_SHM_CREAT but set for clarity of the snapshot state */ call_on_signal = NULL; /* Any further cleanup on signals will be taken care by gds_rundown */ ENABLE_INTERRUPTS(INTRPT_IN_SS_INITIATE); diff --git a/sr_unix/ss_release.c b/sr_unix/ss_release.c index 0f92d2b..45029e7 100644 --- a/sr_unix/ss_release.c +++ b/sr_unix/ss_release.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -52,6 +52,11 @@ GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; GBLREF enum gtmImageTypes image_type; +error_def(ERR_COMMITWAITSTUCK); +error_def(ERR_SYSCALL); +error_def(ERR_SSFILCLNUPFAIL); +error_def(ERR_SSSHMCLNUPFAIL); + #define CLEANUP_SHADOW_FILE(preserve_snapshot, shadow_file) \ { \ int status; \ @@ -96,7 +101,7 @@ GBLREF enum gtmImageTypes image_type; cnl->num_snapshots_in_effect--; \ if (0 == cnl->num_snapshots_in_effect) \ { \ - cnl->snapshot_in_prog = FALSE; \ + CLEAR_SNAPSHOTS_IN_PROG(cnl); \ cnl->ss_shmid = INVALID_SHMID; \ } \ SS_DEFAULT_INIT_POOL(ss_shm_ptr); \ @@ -119,11 +124,6 @@ void ss_release(snapshot_context_ptr_t *ss_ctx) char shadow_file[GTM_PATH_MAX]; ss_proc_status cur_state; - error_def(ERR_COMMITWAITSTUCK); - error_def(ERR_SYSCALL); - error_def(ERR_SSFILCLNUPFAIL); - error_def(ERR_SSSHMCLNUPFAIL); - assert(NULL != cs_addrs && (NULL != gv_cur_region)); csa = cs_addrs; cnl = csa->nl; diff --git a/sr_unix/ss_write_block.c b/sr_unix/ss_write_block.c index c765cf9..75860e8 100644 --- a/sr_unix/ss_write_block.c +++ b/sr_unix/ss_write_block.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2009, 2010 Fidelity Information Services, Inc * + * Copyright 2009, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -39,6 +39,8 @@ GBLREF uint4 process_id; +error_def(ERR_SSFILOPERR); + boolean_t ss_write_block(sgmnt_addrs *csa, block_id blk, cache_rec_ptr_t cr, @@ -49,14 +51,14 @@ boolean_t ss_write_block(sgmnt_addrs *csa, node_local_ptr_t cnl; sm_uc_ptr_t blk_ptr; shm_snapshot_ptr_t ss_shm_ptr; - int blk_size, pwrite_res, status, size; + int save_errno; + uint4 size, blk_size; off_t blk_offset; boolean_t is_bg; DEBUG_ONLY( blk_hdr_ptr_t save_blk_ptr; ) - error_def(ERR_SSFILOPERR); assert(NULL != lcl_ss_ctx); csd = csa->hdr; cnl = csa->nl; @@ -74,23 +76,14 @@ boolean_t ss_write_block(sgmnt_addrs *csa, } assert(cnl->ss_shmid == lcl_ss_ctx->attach_shmid); assert(ss_shm_ptr->ss_info.ss_shmid == lcl_ss_ctx->attach_shmid); - /* If this block falls outside the total number of blocks that were present during the time of snapshot initiation, then - * we should not be writing the before image as the shadow bitmap might not have that much space. Hence do an early return - * to let GT.M continue as if the block was already written to the shadow file. - */ - if (blk >= lcl_ss_ctx->total_blks) - return TRUE; /* ss_release (function that invalidates a snapshot and announces GT.M not to write any more * before images) waits for the active phase 2 commits to complete and hence the below * assert is safe to be used. */ assert(ss_shm_ptr->in_use && SNAPSHOTS_IN_PROG(csa)); assert(!is_bg || ((NULL != cr) && cr->in_cw_set)); /* ensure the buffer has been pinned (from preemption in db_csh_getn) */ - blk_size = csd->blk_size; - if (is_bg) - blk_ptr = GDS_ANY_REL2ABS(csa, cr->buffaddr); - else - blk_ptr = mm_blk_ptr; + blk_size = (uint4)csd->blk_size; + blk_ptr = is_bg ? GDS_ANY_REL2ABS(csa, cr->buffaddr) : mm_blk_ptr; # ifdef GTM_CRYPT /* If the database is encrypted, the old_block will be in the encrypted twin buffer. Logic similar to the one * done in backup_block.c @@ -113,27 +106,27 @@ boolean_t ss_write_block(sgmnt_addrs *csa, assert(NULL != blk_ptr); size = ((blk_hdr_ptr_t)blk_ptr)->bsiz; if (csa->do_fullblockwrites) - size = (int)(ROUND_UP(size, csa->fullblockwrite_len)); + size = ROUND_UP(size, csa->fullblockwrite_len); /* If the block is FREE and block size is zero, we don't want to issue an empty write below. Instead write block of size * equal to the database block size. */ - if (!size || (size > csd->blk_size)) - size = csd->blk_size; + if (!size || (size > blk_size)) + size = blk_size; assert(size <= ss_shm_ptr->ss_info.db_blk_size); - assert(((blk_hdr_ptr_t)blk_ptr)->tn < ss_shm_ptr->ss_info.snapshot_tn); blk_offset = ((off_t)(lcl_ss_ctx->shadow_vbn - 1) * DISK_BLOCK_SIZE + (off_t)blk * blk_size); /* Note: If a FREE block is being written here, then we could avoid the write below: if the underlying file system * is guaranteed to give us all zeros for a block and if the block header is empty */ assert(-1 != lcl_ss_ctx->shdw_fd); - LSEEKWRITE(lcl_ss_ctx->shdw_fd, blk_offset, blk_ptr, size, pwrite_res); - if ((0 != pwrite_res) && SNAPSHOTS_IN_PROG(cnl)) + LSEEKWRITE(lcl_ss_ctx->shdw_fd, blk_offset, blk_ptr, size, save_errno); + if ((0 != save_errno) && SNAPSHOTS_IN_PROG(cnl)) { - send_msg(VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("write"), + assert(FALSE); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("write"), LEN_AND_STR(lcl_ss_ctx->shadow_file), - pwrite_res); + save_errno); ss_shm_ptr->failed_pid = process_id; - ss_shm_ptr->failure_errno = pwrite_res; + ss_shm_ptr->failure_errno = save_errno; return FALSE; } /* Mark the block as before imaged in the bitmap */ diff --git a/sr_unix/suspend.c b/sr_unix/suspend.c index 4c9189f..84957ff 100644 --- a/sr_unix/suspend.c +++ b/sr_unix/suspend.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,6 +13,7 @@ #include #include +#include "gtm_unistd.h" #include "gtmsiginfo.h" #include "io.h" @@ -22,18 +23,26 @@ GBLREF volatile int suspend_status; GBLREF io_pair io_std_device; GBLREF uint4 process_id; +GBLREF uint4 sig_count; -void suspend(void) +error_def(ERR_SUSPENDING); +error_def(ERR_TEXT); + +void suspend(int sig) { int status; - error_def(ERR_SUSPENDING); - - send_msg(VARLSTCNT(1) ERR_SUSPENDING); + send_msg(VARLSTCNT(3) ERR_SUSPENDING, 1, sig); suspend_status = NOW_SUSPEND; - flush_pio(); + /* Dont call flush_pio() if the received signal is SIGTTOU OR if the received signal is SIGTTIN + * and the $P.out is terminal. Arrival of SIGTTIN and SIGTTOU indicates that current process is + * in the background. Hence it does not make sense to do flush_pio() $P.out is terminal. + */ + if (!(sig == SIGTTOU || ((tt == io_std_device.out->type) && (sig == SIGTTIN)))) + flush_pio(); if (NULL != io_std_device.in && tt == io_std_device.in->type) resetterm(io_std_device.in); + sig_count = 0; status = kill(process_id, SIGSTOP); assert(0 == status); return; diff --git a/sr_unix/suspsigs_handler.c b/sr_unix/suspsigs_handler.c index d5049e1..8e425b9 100644 --- a/sr_unix/suspsigs_handler.c +++ b/sr_unix/suspsigs_handler.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,10 +20,13 @@ #include "have_crit.h" #include "suspsigs_handler.h" +#define MAXINOUT 16 + GBLREF volatile int suspend_status; GBLREF uint4 process_id; GBLREF volatile int4 exit_state; GBLREF volatile int4 gtmMallocDepth; /* Recursion indicator */ +GBLDEF uint4 sig_count=0; void suspsigs_handler(int sig, siginfo_t* info, void *context) { @@ -50,9 +53,20 @@ void suspsigs_handler(int sig, siginfo_t* info, void *context) * the I/O operation since we are running in the foreground already due to the * first SIGCONT. */ + sig_count++; + /* When process receives SIGTTIN or SIGTTOUT signal, it goes into suspend mode. + * If it is NOT OK_TO_INTERRUPT i.e. if process is holding some critical + * resources, the suspension of the process is deferred until the critical + * resources are released. It is not expected to arrive extra TTIN/TTOU signals + * between arrival of first TTIN/TTOU and actual suspension of the process. + * If such out of design situation arises, we limit the number of unexpected + * TTIN/TTOU to MAXINOUT and then GTMASSERT. + */ + if (MAXINOUT == sig_count) + GTMASSERT; break; } - suspend(); + suspend(sig); } break; @@ -66,7 +80,7 @@ void suspsigs_handler(int sig, siginfo_t* info, void *context) suspend_status = DEFER_SUSPEND; break; } - suspend(); + suspend(sig); } } break; diff --git a/sr_unix/t_recycled2free.c b/sr_unix/t_recycled2free.c index 8d7cc16..6e78113 100644 --- a/sr_unix/t_recycled2free.c +++ b/sr_unix/t_recycled2free.c @@ -43,13 +43,16 @@ boolean_t t_recycled2free(srch_blk_status *blkhist) SETUP_THREADGBL_ACCESS; csa = cs_addrs; assert(cw_set_depth < CDB_CW_SET_SIZE); + assert(dba_bg == csa->hdr->acc_meth); cse = &cw_set[cw_set_depth]; cse->mode = gds_t_recycled2free; cse->blk = blkhist->blk_num; cse->old_block = blkhist->buffaddr; old_block = (blk_hdr_ptr_t)cse->old_block; - /* t_recycled2free operates on RECYCLED blocks and hence cse->was_free is set to FALSE unconditionally */ - cse->was_free = FALSE; + /* t_recycled2free operates on RECYCLED blocks and hence cse->blk_prior_state's free_status is set to FALSE */ + BIT_CLEAR_FREE(cse->blk_prior_state); + BIT_SET_RECYCLED(cse->blk_prior_state); /* set recycled bit as this is relied upon to write to snapshot file */ + cse->level = old_block->levl; /* maintain level information so only level>0 will be written to snapshot file */ cse->cr = blkhist->cr; cse->cycle = blkhist->cycle; cse->blk_checksum = 0; @@ -68,6 +71,7 @@ boolean_t t_recycled2free(srch_blk_status *blkhist) cse->upd_addr = NULL; cse->jnl_freeaddr = 0; /* reset jnl_freeaddr that previous transaction might have filled in */ cse->done = FALSE; + cse->new_buff = NULL; blkhist->cse = cse; cw_set_depth++; return TRUE; diff --git a/sr_unix/term_setup.c b/sr_unix/term_setup.c index b0e3a1c..426aa13 100644 --- a/sr_unix/term_setup.c +++ b/sr_unix/term_setup.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,14 +20,6 @@ GBLDEF bool ctrlc_on; /* whether ctrlc trap enabled*/ void term_setup(bool ctrlc_enable) { - if (io_std_device.in->type == tt) - { - outofband = 0; - ctrlc_on = ctrlc_enable ; - } - else - { - outofband = 0; - ctrlc_on = FALSE; - } + outofband = 0; + ctrlc_on = (io_std_device.in->type == tt) ? ctrlc_enable : FALSE; } diff --git a/sr_unix/timersp.h b/sr_unix/timersp.h index 3ad01b8..d4d5124 100644 --- a/sr_unix/timersp.h +++ b/sr_unix/timersp.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,15 +16,6 @@ /* These values are used during file creation but may be changed on the fly */ #define TIM_FLU_MOD_BG (1000 * TIMER_SCALE) /* 1 sec */ - -#if defined(UNTARGETED_MSYNC) -#define TIM_FLU_MOD_MM (30000 * TIMER_SCALE) /* 30 sec - longer since is a full sync */ -#elif defined(TARGETED_MSYNC) -#define TIM_FLU_MOD_MM (10000 * TIMER_SCALE) /* 10 sec */ -#else #define TIM_FLU_MOD_MM (1000 * TIMER_SCALE) /* 1 sec */ -#endif -#define TIM_AST_WAIT (5 * TIMER_SCALE) /* 5 msec */ - -#endif /*TIMERSP_included */ +#endif /* TIMERSP_included */ diff --git a/sr_unix/trigger_compare.c b/sr_unix/trigger_compare.c index 3e9f1c6..c07e2b2 100644 --- a/sr_unix/trigger_compare.c +++ b/sr_unix/trigger_compare.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -151,8 +151,8 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h if (!gvcst_get(&key_val)) { /* There has to be a #TRHASH entry */ assert(FALSE); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, LEN_AND_LIT("\"#TRHASH\""), - mv_hash.str.len, mv_hash.str.addr); + 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); @@ -226,8 +226,8 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va if (!gvcst_get(&key_val)) { /* There has to be a #TRHASH entry */ assert(FALSE); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, LEN_AND_LIT("\"#TRHASH\""), - mv_hash.str.len, mv_hash.str.addr); + 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); diff --git a/sr_unix/trigger_delete.c b/sr_unix/trigger_delete.c index 9ba8161..df0d02e 100644 --- a/sr_unix/trigger_delete.c +++ b/sr_unix/trigger_delete.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -68,19 +68,20 @@ error_def(ERR_TRIGMODREGNOTRW); #define MAX_CMD_LEN 20 /* Plenty of room for S,K,ZK,ZTK */ /* This error macro is used for all definition errors where the target is ^#t("TRHASH",) */ -#define TRHASH_DEFINITION_RETRY_OR_ERROR(HASH) \ +#define TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA) \ { \ if (CDB_STAGNATE > t_tries) \ t_retry(cdb_sc_triggermod); \ else \ { \ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \ - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \ - LEN_AND_LIT("\"#TRHASH\""),HASH->str.len, HASH->str.addr); \ + 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) \ +#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA) \ { \ mval mv_hash_indx; \ mval mv_hash_val; \ @@ -94,7 +95,7 @@ error_def(ERR_TRIGMODREGNOTRW); gvcst_kill(FALSE); \ } else \ { /* There has to be a #TRHASH entry */ \ - TRHASH_DEFINITION_RETRY_OR_ERROR(HASH); \ + TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA); \ } \ } @@ -116,14 +117,14 @@ STATICFNDEF void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **value SWITCH_TO_DEFAULT_REGION; assert(0 != gv_target->root); if (gv_cur_region->read_only) - rts_error(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)); if (NULL != strchr(values[CMD_SUB], 'S')) { - SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, set_hash, match_index) + 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); + SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, kill_hash, match_index, csa); } RESTORE_TRIGGER_REGION_INFO; } @@ -165,7 +166,7 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge if (0 != gv_target->root) { if (gv_cur_region->read_only) - rts_error(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)); if (is_auto_name) { /* $get(^#t("#TNAME",,"#TNCOUNT")) */ @@ -226,7 +227,7 @@ STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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(0 != gv_target->root); /* $get(^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) */ BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1); @@ -237,7 +238,8 @@ STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int else { assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); - rts_error(VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1, trig_name); + 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; @@ -278,20 +280,20 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char ** SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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(0 != gv_target->root); if (NULL != strchr(values[CMD_SUB], 'S')) { 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); + 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); if (!gvcst_get(&key_val)) { /* There has to be a #TRHASH entry */ - TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash); + 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); @@ -311,14 +313,14 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char ** } 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); + 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); if (!gvcst_get(&key_val)) { /* There has to be a #TRHASH entry */ - TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash); + 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); @@ -385,7 +387,7 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 /* $data(^#t) */ SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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)); INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; if (0 == gv_target->root) { @@ -416,7 +418,7 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4 gbl_name.len = trigvn_len; GV_BIND_NAME_ONLY(gd_header, &gbl_name); if (gv_cur_region->read_only) - rts_error(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)); csa = gv_target->gd_csa; SETUP_TRIGGER_GLOBAL; INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; @@ -638,8 +640,8 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index else { assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, - trigvn_len, trigvn, trigvn_len, trigvn, + 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]); } } @@ -729,11 +731,11 @@ void trigger_delete_all(void) for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh) { if (gvt->trig_local_tn == local_tn) - rts_error(VARLSTCNT(1) ERR_TRIGMODINTP); + rts_error_csa(CSA_ARG(gvt->gd_csa) VARLSTCNT(1) ERR_TRIGMODINTP); } SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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)); INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; if (0 != gv_target->root) { @@ -759,7 +761,7 @@ void trigger_delete_all(void) * of triggers. */ if (reg->read_only) - rts_error(VARLSTCNT(4) ERR_TRIGMODREGNOTRW, REG_LEN_STR(reg)); + 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 */ @@ -788,7 +790,7 @@ void trigger_delete_all(void) else { assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); - rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6, + 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\""), diff --git a/sr_unix/trigger_fill_xecute_buffer.c b/sr_unix/trigger_fill_xecute_buffer.c index be82cc2..2981c28 100644 --- a/sr_unix/trigger_fill_xecute_buffer.c +++ b/sr_unix/trigger_fill_xecute_buffer.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -60,7 +60,6 @@ LITREF mval literal_hasht; error_def(ERR_TRIGNAMBAD); error_def(ERR_TPRETRY); -error_def(ERR_GVGETFAIL); STATICFNDCL CONDITION_HANDLER(trigger_fill_xecute_buffer_ch); STATICFNDCL void trigger_fill_xecute_buffer_read_trigger_source(gv_trigger_t *trigdsc); diff --git a/sr_unix/trigger_gbl_fill_xecute_buffer.c b/sr_unix/trigger_gbl_fill_xecute_buffer.c index 024903b..e24a335 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, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 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 "memcoherency.h" #include "t_retry.h" #include "gtmimagename.h" +#include "filestruct.h" /* for FILE_INFO, needed by REG2CSA */ LITREF mval literal_ten; @@ -135,7 +136,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in assert(FALSE); trgindx = mval2i(&index); SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\""); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len, util_buff); + rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, + trigvn_len, trigvn, util_len, util_buff); } val_ptr = &key_val; xecute_buff_len = mval2i(val_ptr); @@ -154,8 +156,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in free(xecute_buff); assert(FALSE); SET_PARAM_STRING(util_buff, util_len, num, ",\"XECUTE\""); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len, - util_buff); + rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, + trigvn_len, trigvn, util_len, util_buff); } memcpy(xecute_buff_ptr, key_val.str.addr, key_val.str.len); xecute_buff_ptr += key_val.str.len; diff --git a/sr_unix/trigger_parse.c b/sr_unix/trigger_parse.c index 83b6a38..18ac7c7 100644 --- a/sr_unix/trigger_parse.c +++ b/sr_unix/trigger_parse.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -237,6 +237,8 @@ GBLREF boolean_t gtm_cli_interpret_string; LITREF unsigned char lower_to_upper_table[]; LITREF mval gvtr_cmd_mval[GVTR_CMDTYPES]; +error_def(ERR_INVSTRLEN); + STATICFNDEF char *scan_to_end_quote(char *ptr, int len, int max_len) { int str_len = 0; @@ -597,7 +599,7 @@ STATICFNDEF boolean_t process_options(char *option_str, uint4 option_len, boolea return !((*isolation && *noisolation) || (*consistency && *noconsistency)); } -STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str) +STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str, char *out_str, int4 *out_max) { boolean_t alternation; char dst[MAX_GVSUBS_LEN]; @@ -627,8 +629,6 @@ STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, ch uint4 tmp_len; boolean_t valid_sub; - error_def(ERR_INVSTRLEN); - have_pattern = have_range = valid_sub = have_star = FALSE; ptr = subscr_str; start_len = len = *subscr_len; @@ -963,7 +963,7 @@ STATICFNDEF boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, ch util_out_print_gtmio("Too many subscripts", FLUSH); return FALSE; } - memcpy(subscr_str, dst, (int)(dst_ptr - dst)); + CHECK_FOR_ROOM_IN_OUTPUT_AND_COPY(dst, out_str, (int)(dst_ptr - dst), *out_max); *subscr_len = (uint4)(dst_ptr - dst); *next_str = ptr + 1; return TRUE; @@ -1291,11 +1291,10 @@ boolean_t trigger_parse(char *input, uint4 input_len, char *trigvn, char **value { ptr1++; len--; - if (!process_subscripts(ptr1, &len, &ptr2)) + if (!process_subscripts(ptr1, &len, &ptr2, values[GVSUBS_SUB], &max_output_len)) { ERROR_MSG_RETURN("", input_len, input); } - CHECK_FOR_ROOM_IN_OUTPUT_AND_COPY(ptr1, values[GVSUBS_SUB], len, max_output_len); } else len = 0; if (0 > --max_output_len) diff --git a/sr_unix/trigger_parse_protos.h b/sr_unix/trigger_parse_protos.h index 8ff6222..b092c23 100644 --- a/sr_unix/trigger_parse_protos.h +++ b/sr_unix/trigger_parse_protos.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010 Fidelity Information Services, Inc * + * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ STATICFNDCL boolean_t process_dollar_char(char **src_ptr, int *src_len, boolean_ STATICFNDCL boolean_t process_delim(char *delim_str, uint4 *delim_len); STATICFNDCL boolean_t process_options(char *option_str, uint4 option_len, boolean_t *isolation, boolean_t *noisolation, boolean_t *consistency, boolean_t *noconsistency); -STATICFNDCL boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str); +STATICFNDCL boolean_t process_subscripts(char *subscr_str, uint4 *subscr_len, char **next_str, char *out_str, int4 *out_max); STATICFNDCL boolean_t process_pieces(char *piece_str, uint4 *piece_len); STATICFNDCL boolean_t process_xecute(char *xecute_str, uint4 *xecute_len, boolean_t multi_line); diff --git a/sr_unix/trigger_read_name_entry.c b/sr_unix/trigger_read_name_entry.c index 23c88df..780a34a 100644 --- a/sr_unix/trigger_read_name_entry.c +++ b/sr_unix/trigger_read_name_entry.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2011 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -58,7 +58,11 @@ boolean_t trigger_read_name_entry(mident *trig_name, mval *val) SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; - assert(0 != gv_target->root); + if (0 == gv_target->root) + { + RESTORE_TRIGGER_REGION_INFO; + 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; diff --git a/sr_unix/trigger_select.c b/sr_unix/trigger_select.c index 42cde4e..b7cc1fa 100644 --- a/sr_unix/trigger_select.c +++ b/sr_unix/trigger_select.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -231,8 +231,8 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil else { assert(FALSE); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len, gbl_name, gbl_name_len, gbl_name, - LEN_AND_LIT("\"#LABEL\"")); + 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; @@ -253,8 +253,8 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil else { assert(FALSE); - rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len, gbl_name, gbl_name_len, gbl_name, - LEN_AND_LIT("\"#CYCLE\"")); + 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); @@ -544,7 +544,7 @@ 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) { - char *sel_ptr, *prev_ptr, *ptr1, *ptr2; + char *sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2; int gbl_len, prev_len; mstr gbl_name; sgmnt_addrs *csa; @@ -642,7 +642,7 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na else { len = select_list_len; - sel_ptr = strtok(save_select_list, ","); + sel_ptr = strtok_r(save_select_list, ",", &strtok_ptr); do { trig_name = ('^' != *sel_ptr); @@ -696,7 +696,7 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na if (0 != gv_target->root) write_gbls_or_names(gbl_name.addr, gbl_name.len, file_name_len, &op_val, trig_name); RESTORE_TRIGGER_REGION_INFO; - } while (NULL != (sel_ptr = strtok(NULL, ","))); /* Embedded assignment is intended */ + } while (NULL != (sel_ptr = strtok_r(NULL, ",", &strtok_ptr))); /* Embedded assignment is intended */ } if (0 != file_name_len) { diff --git a/sr_unix/trigger_source_read_andor_verify.c b/sr_unix/trigger_source_read_andor_verify.c index be8d0f8..102532e 100644 --- a/sr_unix/trigger_source_read_andor_verify.c +++ b/sr_unix/trigger_source_read_andor_verify.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2011, 2012 Fidelity Information Services, Inc * + * Copyright 2011, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,10 +70,12 @@ GBLREF boolean_t donot_INVOKE_MUMTSTART; LITREF mval literal_batch; LITREF mval literal_hasht; +#define TRIG_FAILURE_RC -1 + 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 void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc); +STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc); error_def(ERR_DBROLLEDBACK); error_def(ERR_TPRETRY); @@ -185,7 +187,7 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op) { /* 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); - if (0 == src_fetch_status) + if ((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status)) { assert(0 == dollar_tlevel); /* op_tcommit should have made sure of this */ break; @@ -197,11 +199,10 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op) assert(CDB_STAGNATE >= t_tries); assert(0 < t_tries); assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); - failure = t_fail_hist[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_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure)) - || !IS_MCODE_RUNNING || TREF(dollar_zonlnrlbk)); + assert((cdb_sc_onln_rlbk2 != failure) || TREF(dollar_zonlnrlbk)); if (cdb_sc_onln_rlbk2 == failure) rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); /* else if (cdb_sc_onln_rlbk1 == status) we don't need to do anything other than proceeding with the next @@ -214,9 +215,9 @@ 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); - assert(0 == src_fetch_status); + assert((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status)); RESTORE_TRIGGER_REGION_INFO; - return 0; + return src_fetch_status; } /* Now TP wrap and fetch the trigger source lines from the ^#t global */ @@ -229,7 +230,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action ESTABLISH_RET(trigger_source_raov_ch, SIGNAL); assert(donot_INVOKE_MUMTSTART); rc = trigger_source_raov(trigname, trigger_op); - assert(0 == rc); + assert((0 == rc) || (TRIG_FAILURE_RC == rc)); /* Finish it now verifying it completed successfully */ GVTR_OP_TCOMMIT(cdb_status); if (cdb_sc_normal != cdb_status) @@ -238,7 +239,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action t_retry(cdb_status); } REVERT; - return 0; + return rc; } /* Routine to do the dirty work of resolving a trigger name into a trigger and perform the missing parts of @@ -260,10 +261,12 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op) uint4 cycle_start; boolean_t triggers_reloaded, db_trigger_cycle_mismatch, ztrig_cycle_mismatch; + 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 */ - trigger_source_raov_trigload(trigname, &trigdsc); + if(TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc)) + return TRIG_FAILURE_RC; } 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 @@ -329,7 +332,8 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op) 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)); - trigger_source_raov_trigload(trigname, &trigdsc); + if (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc)) + return TRIG_FAILURE_RC; triggers_reloaded = TRUE; } else DBGTRIGR((stderr, "trigger_source_raov: trigger validated\n")); @@ -390,7 +394,7 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op) } /* Routine called when need triggers loaded for a given global */ -STATICFNDEF void 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) { mname_entry gvent; mval val; @@ -405,12 +409,18 @@ STATICFNDEF void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret mval trig_index; gv_trigger_t *trigdsc; uint4 cycle_start; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; /* Find region trigger name is in */ if (!trigger_read_name_entry(trigname, &val)) { /* Trigger name not found - nothing we can do */ - CLEAR_IMPLICIT_TP_BEFORE_ERROR; - rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr); + if (!TREF(in_op_fntext)) + { + CLEAR_IMPLICIT_TP_BEFORE_ERROR; + rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr); + } + return TRIG_FAILURE; } /* Extract region name and trigger index number from result */ ptr = val.str.addr; @@ -449,7 +459,7 @@ STATICFNDEF void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret 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; *ret_trigdsc = trigdsc; - return; + return TRIG_SUCCESS; } #endif /* GTM_TRIGGER */ diff --git a/sr_unix/trigger_trgfile.c b/sr_unix/trigger_trgfile.c index b74a3f5..2ef752d 100644 --- a/sr_unix/trigger_trgfile.c +++ b/sr_unix/trigger_trgfile.c @@ -213,11 +213,10 @@ boolean_t trigger_trgfile_tpwrap(char *trigger_filename, uint4 trigger_filename_ break; assert(0 < t_tries); assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); - failure = t_fail_hist[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_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure)) - || !IS_MCODE_RUNNING || TREF(dollar_zonlnrlbk)); + assert((cdb_sc_onln_rlbk2 != failure) || !IS_GTM_IMAGE || TREF(dollar_zonlnrlbk)); if (cdb_sc_onln_rlbk2 == failure) rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); /* else if (cdb_sc_onln_rlbk1 == status) we don't need to do anything other than trying again. Since this diff --git a/sr_unix/trigger_update.c b/sr_unix/trigger_update.c index b9384be..3fe6b58 100644 --- a/sr_unix/trigger_update.c +++ b/sr_unix/trigger_update.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2010, 2012 Fidelity Information Services, Inc * + * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -110,11 +110,11 @@ LITREF char *trigger_subs[]; #define BUILD_COMMAND_BITMAP(BITMAP, COMMANDS) \ { \ char lcl_cmds[MAX_COMMANDS_LEN + 1]; \ - char *lcl_ptr; \ + char *lcl_ptr, *strtok_ptr; \ \ memcpy(lcl_cmds, COMMANDS, STRLEN(COMMANDS) + 1); \ BITMAP = 0; \ - lcl_ptr = strtok(lcl_cmds, ","); \ + lcl_ptr = strtok_r(lcl_cmds, ",", &strtok_ptr); \ do \ { \ switch (*lcl_ptr) \ @@ -154,7 +154,7 @@ LITREF char *trigger_subs[]; GTMASSERT; /* Parsing should have found invalid command */ \ break; \ } \ - } while (lcl_ptr = strtok(NULL, ",")); \ + } while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr)); \ } #define COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN) \ @@ -180,11 +180,11 @@ LITREF char *trigger_subs[]; #define BUILD_OPTION_BITMAP(BITMAP, OPTIONS) \ { \ char lcl_options[MAX_OPTIONS_LEN + 1]; \ - char *lcl_ptr; \ + char *lcl_ptr, *strtok_ptr; \ \ memcpy(lcl_options, OPTIONS, STRLEN(OPTIONS) + 1); \ BITMAP = 0; \ - lcl_ptr = strtok(lcl_options, ","); \ + lcl_ptr = strtok_r(lcl_options, ",", &strtok_ptr); \ if (NULL != lcl_ptr) \ do \ { \ @@ -215,7 +215,7 @@ LITREF char *trigger_subs[]; GTMASSERT; /* Parsing should have found invalid command */ \ break; \ } \ - } while (lcl_ptr = strtok(NULL, ",")); \ + } while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr)); \ } #define OPTION_BITMAP_TO_STR(OPTIONS, BITMAP, LEN) \ @@ -276,7 +276,7 @@ LITREF char *trigger_subs[]; } /* This error macro is used for all definition errors where the target is ^#t(GVN,,) */ -#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT) \ +#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \ { \ if (CDB_STAGNATE > t_tries) \ t_retry(cdb_sc_triggermod); \ @@ -285,28 +285,28 @@ LITREF char *trigger_subs[]; 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(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \ trigvn_len, trigvn, util_len, util_buff); \ } \ } /* This error macro is used for all definition errors where the target is ^#t(GVN,<#LABEL|#COUNT|#CYCLE>) */ -#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO) \ +#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO,CSA) \ { \ if (CDB_STAGNATE > t_tries) \ t_retry(cdb_sc_triggermod); \ else \ { \ - HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO); \ + HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA); \ } \ } -#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO) \ -{ \ - assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \ - rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \ - trigvn_len, trigvn, LEN_AND_LIT(SUBSCRIPT), \ - ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \ +#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA) \ +{ \ + assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \ + rts_error_csa(CSA_ARG(CSA) VARLSTCNT(12) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \ + trigvn_len, trigvn, LEN_AND_LIT(SUBSCRIPT), \ + ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \ } STATICFNDEF boolean_t validate_label(char *trigvn, int trigvn_len) @@ -317,7 +317,7 @@ STATICFNDEF boolean_t validate_label(char *trigvn, int trigvn_len) SETUP_THREADGBL_ACCESS; BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL)); if (!gvcst_get(&trigger_label)) /* There has to be a #LABEL */ - HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL was not found") + HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL was not found", REG2CSA(gv_cur_region)) return ((trigger_label.str.len == STRLEN(HASHT_GBL_CURLABEL)) && (0 == memcmp(trigger_label.str.addr, HASHT_GBL_CURLABEL, trigger_label.str.len))); } @@ -455,7 +455,7 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_ SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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)); INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; set_cmp = (NULL != strchr(cmd_value, 'S')); mv_indx_ptr = &mv_indx; @@ -556,7 +556,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char 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\""); + 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]))); } @@ -573,7 +573,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char 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\""); + 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))); @@ -590,7 +590,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char 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\""); + 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]))); } @@ -855,7 +855,7 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in i2mval(&trigindx, trigger_index); 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\""); + 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'; /* get(^#t(GVN,trigindx,"OPTIONS") */ @@ -985,13 +985,13 @@ STATICFNDEF int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigg SAVE_TRIGGER_REGION_INFO; SWITCH_TO_DEFAULT_REGION; if (gv_cur_region->read_only) - rts_error(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)); INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED; if (0 == user_trigname_len) { /* autogenerated name */ + val_ptr = &val; if (0 != gv_target->root) { - val_ptr = &val; /* $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)); @@ -1219,14 +1219,14 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u gbl_name.len = trigvn_len; GV_BIND_NAME_ONLY(gd_header, &gbl_name); if (gv_cur_region->read_only) - rts_error(VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region)); + rts_error_csa(CSA_ARG(gv_target->gd_csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region)); csa = gv_target->gd_csa; /* 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(VARLSTCNT(1) ERR_TRIGMODINTP); + 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 @@ -1644,13 +1644,12 @@ boolean_t trigger_update(char *trigger_rec, uint4 len) break; assert(0 < t_tries); assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); - failure = t_fail_hist[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_rlbk1 != failure) && (cdb_sc_onln_rlbk2 != failure)) - || !IS_MCODE_RUNNING || TREF(dollar_zonlnrlbk)); + assert((cdb_sc_onln_rlbk2 != failure) || !IS_GTM_IMAGE || TREF(dollar_zonlnrlbk)); if (cdb_sc_onln_rlbk2 == failure) - rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); + rts_error_csa(CSA_ARG(gv_target->gd_csa) 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 diff --git a/sr_unix/ttt.txt b/sr_unix/ttt.txt index 9843afc..41ec42a 100644 --- a/sr_unix/ttt.txt +++ b/sr_unix/ttt.txt @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2012 Fidelity Information Services, Inc ; +; Copyright 2001, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -161,25 +161,25 @@ OC_FNFIND: pushab val.0 pushab val.1 calls #4,xfer.xf_fnfind OC_FNFNUMBER: pushab val.0 + pushl val.4 + pushl val.3 pushab val.2 pushab val.1 - calls #3,xfer.xf_fnfnumber + calls #5,xfer.xf_fnfnumber OC_FNGET: movab val.1,r1 movab val.0,r0 jsb xfer.xf_fnget -OC_FNGET2: pushab val.2 +OC_FNGET2: pushab val.0 + pushab val.2 pushab val.1 - pushab val.0 calls #3,xfer.xf_fnget2 -OC_FNGVGET: pushab val.1 - pushab val.0 - calls #2,xfer.xf_fngvget +OC_FNGVGET: pushab val.0 + calls #1,xfer.xf_fngvget OC_FNGVGET1: pushab val.0 calls #1,xfer.xf_fngvget1 -OC_FNGVGET2: pushab val.2 - pushab val.1 - pushab val.0 - calls #3,xfer.xf_fngvget2 +OC_FNGET1: pushab val.0 + pushab val.1 + calls #2,xfer.xf_fnget1 OC_FNINCR: pushab val.0 ; result of $INCR pushab val.2 ; r->operand[1] = increment pushab val.1 ; r->operand[0] = local-variable to increment @@ -558,18 +558,14 @@ OC_INDDEVPARMS: pushab val.0 pushl val.2 pushab val.1 jsb xfer.xf_inddevparms -OC_INDFNNAME: pushab val.2 ; r->operand[1] - pushab val.1 ; r->operand[0] - pushab val.0 ; result of $NAME +OC_INDFNNAME: pushab val.2 ; r->operand[1] = depth + pushab val.1 ; r->operand[0] = name + pushab val.0 ; r->dst jsb xfer.xf_indfnname OC_INDFUN: pushab val.0 pushl val.2 pushab val.1 jsb xfer.xf_indfun -OC_INDGET: pushab val.2 - pushab val.1 - pushab val.0 - jsb xfer.xf_indget OC_INDGLVN: pushab val.0 pushab val.1 jsb xfer.xf_indglvn @@ -586,16 +582,17 @@ OC_INDLVARG: pushab val.0 OC_INDMERGE: pushab val.1 pushab val.2 jsb xfer.xf_indmerge -OC_INDNAME: irepab val.2 +OC_INDNAME: pushab val.2 + pushab val.1 pushab val.0 - calls val.1,xfer.xf_indname + calls #3,xfer.xf_indname OC_INDLVNAMADR: pushab val.1 jsb xfer.xf_indlvnamadr movl r0,addr.0 OC_INDO2: pushab val.2 pushab val.1 pushab val.0 - jsb xfer.xf_indo2 + calls #3,xfer.xf_indo2 OC_INDPAT: pushab val.0 pushab val.1 jsb xfer.xf_indpat @@ -615,7 +612,8 @@ OC_IOCONTROL: jsb xfer.xf_restartpc calls val.1,xfer.xf_iocontrol OC_IRETMVAD: movab val.1,r1 jsb xfer.xf_iretmvad -OC_IRETMVAL: pushab val.1 +OC_IRETMVAL: pushab val.2 + pushab val.1 jsb xfer.xf_iretmval OC_JMP-BYTE: brb jmp.1 OC_JMP-LONG: jmp jmp.1 @@ -975,13 +973,61 @@ OC_ZTRIGGER: calls #0,xfer.xf_ztrigger OC_ZTSTART: calls #0,xfer.xf_ztstart OC_ZWRITESVN: pushl val.1 calls #1,xfer.xf_zwritesvn -OC_RFRSHINDX: pushl val.2 - pushl val.1 - calls #2,xfer.xf_rfrshindx +OC_FNZWRITE: pushab val.0 ; destination mval + pushab val.1 ; string + calls #2,xfer.xf_fnzwrite +OC_IGETDST: calls #0,xfer.xf_igetdst + movl r0,addr.0 +OC_INDGET1: pushab val.0 + pushab val.1 + calls #2,xfer.xf_indget1 +OC_GLVNPOP: pushab val.1 + calls #1,xfer.xf_glvnpop +OC_GLVNSLOT: pushl val.1 + calls #1,xfer.xf_glvnslot movl r0,addr.0 -OC_SAVPUTINDX: irepab val.2 - calls val.1,xfer.xf_savputindx +OC_INDSAVGLVN: pushl val.3 + pushab val.2 + pushab val.1 + jsb xfer.xf_indsavglvn +OC_INDSAVLVN: pushab val.2 + pushab val.1 + jsb xfer.xf_indsavlvn +OC_RFRSHLVN: pushl val.2 + pushab val.1 + calls #2,xfer.xf_rfrshlvn movl r0,addr.0 -OC_FORFREEINDX: calls #0,xfer.xf_forfreeindx -OC_FORNESTLVL: pushl val.1 - calls #1,xfer.xf_fornestlvl +OC_SAVGVN: irepab val.2 + calls val.1,xfer.xf_savgvn +OC_SAVLVN: irepab val.2 + calls val.1,xfer.xf_savlvn +OC_SHARESLOT: pushl val.2 + pushab val.1 + calls #2,xfer.xf_shareslot +OC_STOGLVN: pushab val.2 + pushab val.1 + calls #2,xfer.xf_stoglvn +OC_RFRSHGVN: pushl val.2 + pushab val.1 + calls #2,xfer.xf_rfrshgvn +OC_INDFNNAME2: pushab val.2 + pushab val.1 + pushab val.0 + calls #3,xfer.xf_indfnname2 +OC_INDGET2: pushab val.1 + pushab val.0 + calls #2,xfer.xf_indget2 +OC_INDMERGE2: pushab val.1 + calls #1,xfer.xf_indmerge2 +OC_LITC: pushab val.1 ; opcode not in sr_unix_nsb/ttt or sr_vvms/ttt + pushab val.0 + calls #2,xfer.xf_litc +OC_STOLITC: movc3 #16,val.2,val.1 ; opcode not in sr_unix_nsb/ttt or sr_vvms/ttt + pushab val.1 + calls #1,xfer.xf_stolitc +OC_FNZPEEK: pushab val.0 + pushab val.4 + pushl val.3 + pushl val.2 + pushab val.1 + calls #5,xfer.xf_fnzpeek diff --git a/sr_unix/upd_log_init.c b/sr_unix/upd_log_init.c index 6d54aa7..d651404 100644 --- a/sr_unix/upd_log_init.c +++ b/sr_unix/upd_log_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2005, 2009 Fidelity Information Services, Inc * + * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -40,7 +40,7 @@ GBLREF uint4 process_id; int upd_log_init(recvpool_user who) { - char log_file[MAX_FN_LEN + 1], file_suffix_str[MAX_FN_LEN + 1], pid_str[11], *pid_end_ptr, *file_suffix; + char log_file[MAX_FN_LEN + 1], file_suffix_str[MAX_FN_LEN + 1], pid_str[11], *pid_end_ptr, *file_suffix; int status = SS_NORMAL; int *fd_addrs; FILE **fp_addrs; @@ -67,7 +67,7 @@ int upd_log_init(recvpool_user who) } if (FD_INVALID == *fd_addrs || (UPDPROC == who && 0 != strcmp(log_file, recvpool.upd_proc_local->log_file))) { - status = repl_log_init(REPL_GENERAL_LOG, fd_addrs, NULL, log_file, NULL); + status = repl_log_init(REPL_GENERAL_LOG, fd_addrs, log_file); repl_log_fd2fp(fp_addrs, *fd_addrs); if (UPDPROC == who) { diff --git a/sr_unix/util_output.c b/sr_unix/util_output.c index 9efa686..c44d38d 100644 --- a/sr_unix/util_output.c +++ b/sr_unix/util_output.c @@ -1,6 +1,6 @@ -/**************************************************************** + /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -28,39 +28,76 @@ #include "util_out_print_vaparm.h" #include "gtmimagename.h" +#include "gdsroot.h" +#include "gtm_facility.h" +#include "fileinfo.h" +#include "gdsbt.h" +#include "gdsfhead.h" +#include "filestruct.h" +#include "repl_msg.h" +#include "repl_shutdcode.h" +#include "gtmsource.h" +#include "gtmrecv.h" +#include "repl_instance.h" +#include "trans_log_name.h" +#include "gtmio.h" +#include "gtm_logicals.h" +#include "have_crit.h" + #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" #endif +GBLDEF boolean_t first_syslog = TRUE; /* Global for a process - not thread specific */ +GBLDEF char facility[MAX_INSTNAME_LEN + 100]; + +GBLREF io_pair io_std_device; +GBLREF boolean_t blocksig_initialized; +GBLREF sigset_t block_sigsent; +GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; +GBLREF jnlpool_addrs jnlpool; +GBLREF boolean_t is_src_server; +GBLREF boolean_t is_rcvr_server; +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 GETFAOVALDEF(faocnt, var, type, result, defval) \ if (faocnt > 0) {result = (type)va_arg(var, type); faocnt--;} else result = defval; -GBLREF io_pair io_std_device; -GBLDEF char *util_outptr, util_outbuff[OUT_BUFF_SIZE]; -GBLDEF va_list last_va_list_ptr; -GBLREF boolean_t blocksig_initialized; -GBLREF sigset_t block_sigsent; -GBLREF void (*op_write_ptr)(mval *v); -GBLREF void (*op_wteol_ptr)(int4 n); +#define INSERT_MARKER \ +{ \ + STRNCPY_STR(offset, "-", STRLEN("-")); \ + offset += STRLEN("-"); \ +} -static boolean_t first_syslog = TRUE; -static char save_util_outbuff[OUT_BUFF_SIZE]; -static int4 save_buff_used; +#define BUILD_FACILITY(strptr) \ +{ \ + STRNCPY_STR(offset, strptr, STRLEN(strptr)); \ + offset += STRLEN(strptr); \ + INSERT_MARKER; \ +} /* * This routine implements a SUBSET of FAO directives, namely: * * !/ !_ !^ !! * + * !mAC !mAD !mAF !mAS !mAZ * * !mSB !mSW !mSL * * !mUB !mUW !mUL !m@UJ !m@UQ * - * !mXB !mXW !mXL !m@XJ !m@XQ + * !mXB !mXW !mXL !mXJ !m@XJ !m@XQ * * !mZB !mZW !mZL * @@ -74,16 +111,25 @@ static int4 save_buff_used; * FAO stands for "formatted ASCII output". The FAO directives may be considered equivalent to format * specifications and are documented with the VMS Lexical Fuction F$FAO in the OpenVMS DCL Dictionary. * - * The @XH and @XJ types need special mention. XH and XJ are ascii formatting of addresses and integers respectively. - * BOTH are ASCII formatted hexdecimal output of a 64 bit sign-extended value. - * The present implementation of util_output does not support 'H'. - * This support was new in VMS 7.2 (and is one reason why GTM 4.2 requires VMS 7.2). - * The "@" designates an "indirect" request meaning that the address of - * the 8 byte item is passed rather than the item itself. This is what allows us to print 8 byte values in the - * non-Alpha 32 bit parameter worlds. These types are documented in the VMS System services manual under SYS$FAO. - * There are several other types that are supported on VMS but only these two were added on Unix. + * The @XH and @XJ types need special mention. XH and XJ are ascii formatting of addresses and integers respectively. BOTH are + * ASCII formatted hexdecimal output of a 64 bit sign-extended value. The present implementation of util_output does not + * support 'H'. This support was new in VMS 7.2 (and is one reason why GTM 4.2 requires VMS 7.2). The "@" designates an + * "indirect" request meaning that the address of the 8 byte item is passed rather than the item itself. This is what allows + * us to print 8 byte values in the non-Alpha 32 bit parameter worlds. These types are documented in the VMS System services + * manual under SYS$FAO. There are several other types that are supported on VMS but only these two were added on Unix. * - * In addition this implements another directive + * Another variant of the 'J' type is !mXJ which the routine implements. This variant is used to print 'addresses' in platform + * independent way. For examples of this type, see the definition and usages of the following messages: + * + * CALLERID + * KILLBYSIGSINFO1 + * KILLBYSIGSINFO2 + * + * One important caveat in using !mXJ variant is that the input value is expected to be 4-byte on 32-bit platforms and 8-byte + * on 64-bit platforms. Passing an 8-byte quantity on a 32-bit platform can cause SIGSEGV. If a field is always 8-bytes on both + * the 32 and 64 bit platforms (like transaction numbers), use 0x!16@XQ variant instead. + * + * In addition, this routine also implements another set of directives * * !RmAC !RmAD !RmAF !RmAS !RmAZ * @@ -128,12 +174,12 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in unsigned char numa[22]; unsigned char *numptr; boolean_t right_justify, isprintable; + DCL_THREADGBL_ACCESS; - VAR_COPY(last_va_list_ptr, fao); + SETUP_THREADGBL_ACCESS; + VAR_COPY(TREF(last_va_list_ptr), fao); outptr = buff; - outtop = outptr + size - 5; /* 5 bytes to prevent writing across border */ - /* 5 comes from line 268 -- 278 */ - + outtop = outptr + size - 5; /* 5 bytes to prevent writing across border */ while (outptr < outtop) { /* Look for the '!' that starts an FAO directive */ @@ -141,19 +187,18 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in { if (schar == '\0') { - va_end(last_va_list_ptr); /* reset before using as dest in copy */ - VAR_COPY(last_va_list_ptr, fao); + va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */ + VAR_COPY(TREF(last_va_list_ptr), fao); return outptr; } *outptr++ = schar; if (outptr >= outtop) { - va_end(last_va_list_ptr); /* reset before using as dest in copy */ - VAR_COPY(last_va_list_ptr, fao); + va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */ + VAR_COPY(TREF(last_va_list_ptr), fao); return outptr; } } - field_width = 0; /* Default values */ repeat_count = 1; right_justify = FALSE; @@ -172,7 +217,6 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in { for (c = message; *c >= '0' && *c <= '9'; ++c) ; - if ((length = (int)(c - message)) > 0) { field_width = repeat_count @@ -180,36 +224,30 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in message = c; } } - if ('@' == *message) /* Indirectly addressed operand */ { indirect = TRUE; message++; } else indirect = FALSE; - switch (type = *message++) { case '/': assert(!indirect); *outptr++ = '\n'; continue; - case '_': assert(!indirect); *outptr++ = '\t'; continue; - case '^': assert(!indirect); *outptr++ = '\f'; continue; - case '!': assert(!indirect); *outptr++ = '!'; continue; - case '*': assert(!indirect); if (repeat_count > 0) @@ -227,7 +265,6 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in } message += chlen; continue; - case 'A': assert(!indirect); switch(type2 = *message++) @@ -236,13 +273,11 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL); length = c ? *c++ : 0; break; - case 'D': case 'F': /* string with length and addr parameters */ GETFAOVALDEF(faocnt, fao, int4, length, 0); GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL); break; - case 'S': if (faocnt) { @@ -256,7 +291,6 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in length = 0; } break; - case 'Z': /* null teminated string */ GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL); length = c ? STRLEN(c) : 0; @@ -323,10 +357,10 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in break; if (!isprintable && (('F' == type2) UNICODE_ONLY(|| (('D' == type2) && gtm_utf8_mode)))) { /* Since HPUX stops printing lines (via FPRINTF) when it - encounters a bad character, all platforms in utf8 mode - will behave as if !AF were specified and put a "." in place - of non-printable characters. SE 01/2007 - */ + * encounters a bad character, all platforms in utf8 mode + * will behave as if !AF were specified and put a "." in place + * of non-printable characters. SE 01/2007 + */ *outptr++ = '.'; i = nexti; } else if ('\0' != ch) /* skip NULL bytes in the middle of the string */ @@ -351,7 +385,6 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in *outptr++ = ' '; } continue; - default: /* Rest of numeric types come here */ assert('S' == type || 'U' == type || 'X' == type || 'Z' == type); numptr = numa; @@ -412,7 +445,7 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in } switch (type) { - case 'S': /* Signed value. Give sign if need to */ + case 'S': /* Signed value. Give sign if need to */ if ('J' == type2) { GTM64_ONLY( @@ -433,7 +466,7 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in { *numptr++ = '-'; int_val = -(int_val); - } /* note fall into unsigned */ + } /* note fall into unsigned */ case 'U': case 'Z': /* zero filled */ NON_GTM64_ONLY(numptr = i2asc(numptr, int_val);) @@ -446,7 +479,7 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in break; case 'X': /* Hex */ switch (type2) - { /* length is number of ascii hex chars */ + { /* length is number of ascii hex chars */ case 'B': length = SIZEOF(short); break; @@ -490,8 +523,7 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in } } else /* support ZJ, ZQ, UQ and UJ */ { - if ('Z' != type && 'U' != type ) - GTMASSERT; + assertpro(('Z' == type) || ('U' == type)); assert('J' == type2 || 'Q' == type2); GETFAOVALDEF(faocnt, fao, qw_num_ptr_t, val_ptr, NULL); /* Addr of long type */ if (val_ptr) @@ -530,15 +562,17 @@ caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, in } } } - va_end(last_va_list_ptr); /* reset before using as dest in copy */ - VAR_COPY(last_va_list_ptr, fao); + va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */ + VAR_COPY(TREF(last_va_list_ptr), fao); return outptr; } void util_out_close(void) { + DCL_THREADGBL_ACCESS; - if ((NULL != util_outptr) && (util_outptr != util_outbuff)) + SETUP_THREADGBL_ACCESS; + if ((NULL != TREF(util_outptr)) && (TREF(util_outptr) != TREF(util_outbuff_ptr))) util_out_print("", FLUSH); } @@ -547,48 +581,170 @@ void util_out_send_oper(char *addr, unsigned int len) /* 2nd arg: length of system long message (not used in Unix implementation) */ { sigset_t savemask; + char *img_type, *offset, *proc_type=NULL, *helper_type=NULL; + char temp_inst_fn[MAX_FN_LEN + 1], fn[MAX_FN_LEN + 1]; + mstr log_nam, trans_name; + uint4 ustatus; + int4 status; + unsigned int bufsize, file_name_len, *fn_len; + boolean_t ret; + repl_inst_hdr replhdr; + int fd; + upd_helper_ctl_ptr_t upd_helper_ctl; + upd_helper_entry_ptr_t helper, helper_top; if (first_syslog) { first_syslog = FALSE; - (void)OPENLOG("GTM", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER); + + offset = facility; + BUILD_FACILITY("GTM"); + switch (image_type) + { + case GTM_IMAGE: + img_type = "MUMPS"; + break; + case MUPIP_IMAGE: + img_type = "MUPIP"; + break; + case DSE_IMAGE: + img_type = "DSE"; + break; + case LKE_IMAGE: + img_type = "LKE"; + break; + case DBCERTIFY_IMAGE: + img_type = "DBCERTIFY"; + break; + case GTM_SVC_DAL_IMAGE: + img_type = "GTM_SVC_DAL"; + break; + case GTCM_SERVER_IMAGE: + img_type = "GTCM"; + break; + case GTCM_GNP_SERVER_IMAGE: + img_type = "GTCM_GNP"; + break; + case GTMSECSHR_IMAGE: + img_type = "SECSHR"; + break; + default: + assertpro(FALSE); + } + STRNCPY_STR(offset, img_type, STRLEN(img_type)); + offset += STRLEN(img_type); + if (jnlpool_ctl) + { /* Read instace file name from jnlpool */ + if (image_type == MUPIP_IMAGE) + { + if (is_src_server) + proc_type = "SRCSRVR"; + else if (is_rcvr_server) + proc_type = "RCVSRVR"; + else if (is_updproc) + proc_type = "UPDPROC"; + } + if (proc_type) + { + offset -= STRLEN(img_type); + BUILD_FACILITY(proc_type); + } + else + INSERT_MARKER; + STRNCPY_STR(offset, (char *)jnlpool.repl_inst_filehdr->inst_info.this_instname, + STRLEN((char *)jnlpool.repl_inst_filehdr->inst_info.this_instname)); + } else + { /* Read instance name from instance file */ + if (is_updhelper) + { /* Determine helper type from recvpool */ + upd_helper_ctl = recvpool.upd_helper_ctl; + for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; + helper < helper_top; helper++) + { + if (helper->helper_pid_prev == process_id) /* found my entry */ + { + if ( UPD_HELPER_READER == helper->helper_type ) + helper_type = "UPDREAD"; + else if (UPD_HELPER_WRITER == helper->helper_type) + helper_type = "UPDWRITE"; + break; + } + } + offset -= STRLEN(img_type); + if (helper_type) /*Otherwise entry for helper is not present in the receiver pool*/ + { + BUILD_FACILITY(helper_type); + } + else { + proc_type = "UPDHELP"; + BUILD_FACILITY(proc_type); + } + } + fn_len = &file_name_len; + bufsize = MAX_FN_LEN + 1; + log_nam.addr = GTM_REPL_INSTANCE; + log_nam.len = SIZEOF(GTM_REPL_INSTANCE) - 1; + trans_name.addr = temp_inst_fn; + ret = FALSE; + GET_INSTFILE_NAME(dont_sendmsg_on_log2long, return_on_error); + /* We want the instance name as part of operator log messages, but if we can’t get it, + * we will get by without it, so ignore any errors we might encounter trying to find the name + */ + if (ret) + { + OPENFILE(fn, O_RDONLY, fd); + if (FD_INVALID != fd) + { + LSEEKREAD(fd, 0, &replhdr, SIZEOF(repl_inst_hdr), status); + if (0 == status) + { + if (!is_updhelper) + { + INSERT_MARKER; + } + STRNCPY_STR(offset, (char *)replhdr.inst_info.this_instname, + STRLEN((char *)replhdr.inst_info.this_instname)); + } + CLOSEFILE_RESET(fd, status); + } + } + } + DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); + (void)OPENLOG(facility, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER); + ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); } /* * When syslog is processing and a signal occurs, the signal processing might eventually lead to another syslog * call. But in libc the first syslog has grabbed a lock (syslog_lock), and now the other syslog call will * block waiting for that lock which can't be released since the first syslog was interrupted by the signal. - * A work around is to temporarily block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) and then - * restore them after the syslog call returns. + * We address this issue by deferring signals for the duration of the call; generic_signal_handler.c will also + * skip send_msg invocations if the interrupt comes while INTRPT_IN_LOG_FUNCTION is set. */ - /* It is possible for early process startup code to invoke this function so blocksig_initialized might not yet be set. - * An example C-stack is main/get_page_size/system-function interrupted by MUPIP STOP/generic_signal_handler/send_msg. - * Therefore this does not have an assert(blocksig_initialized) that similar code in other places (e.g. dollarh.c) has. - */ - if (blocksig_initialized) /* In pro, dont take chances and handle case where it is not initialized */ - sigprocmask(SIG_BLOCK, &block_sigsent, &savemask); - (void)SYSLOG(LOG_USER | LOG_INFO, "%s", addr); - if (blocksig_initialized) - sigprocmask(SIG_SETMASK, &savemask, NULL); + DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); + SYSLOG(LOG_USER | LOG_INFO, "%s", addr); + ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION); } - void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt) { - char fmt_buff[OUT_BUFF_SIZE]; /* needs to be same size as that of util_outbuff */ + char fmt_buff[OUT_BUFF_SIZE]; /* needs to be same size as that of the util out buffer */ caddr_t fmtc; int rc, count; char *fmt_top1, *fmt_top2; /* the top of the buffer after leaving 1 (and 2 bytes respectively) at the end */ int util_avail_len; + DCL_THREADGBL_ACCESS; - assert(SIZEOF(fmt_buff) == SIZEOF(util_outbuff)); - if (util_outptr == NULL) - util_outptr = util_outbuff; - if (message != NULL) + 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); + if (NULL != message) { - util_avail_len = INTCAST(util_outbuff + SIZEOF(util_outbuff) - util_outptr - 2); + util_avail_len = INTCAST(TREF(util_outbuff_ptr) + OUT_BUFF_SIZE - TREF(util_outptr) - 2); assert(0 <= util_avail_len); if (0 < util_avail_len) - util_outptr = util_format(message, var, util_outptr, util_avail_len, faocnt); + TREF(util_outptr) = util_format(message, var, TREF(util_outptr), util_avail_len, faocnt); } switch (flush) { @@ -597,7 +753,7 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt) case RESET: break; case FLUSH: - *util_outptr++ = '\n'; + *(TREF(util_outptr))++ = '\n'; case OPER: case SPRINT: /* For all three of these actions we need to do some output buffer translation. In all cases a '%' @@ -607,40 +763,42 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt) * requirements, we could potentially overflow the buffer after the translation. In that case we will * stop copying just before the point of overflow is reached even though it means loss of the tail data. */ - *util_outptr = '\0'; + *(TREF(util_outptr)) = '\0'; fmt_top1 = fmt_buff + SIZEOF(fmt_buff) - 1; fmt_top2 = fmt_top1 - 1; - for (util_outptr = util_outbuff, fmtc = fmt_buff; (0 != *util_outptr) && (fmtc < fmt_top1); ) + for (TREF(util_outptr) = TREF(util_outbuff_ptr), fmtc = fmt_buff; + (0 != *(TREF(util_outptr))) && (fmtc < fmt_top1); ) { - if ('%' == *util_outptr) + if ('%' == *(TREF(util_outptr))) { if (fmtc >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */ break; - *fmtc++ = '%'; /* escape for '%' */ + if (flush == SPRINT) + *fmtc++ = '%'; /* give buffered users what they expect %% */ *fmtc++ = '%'; - util_outptr++; - } else if ('\n' == *util_outptr && (OPER == flush || SPRINT == flush)) + (TREF(util_outptr))++; + } else if ('\n' == *(TREF(util_outptr)) && (OPER == flush || SPRINT == flush)) { if (fmtc >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */ break; *fmtc++ = ','; *fmtc++ = ' '; - util_outptr++; + (TREF(util_outptr))++; } else - *fmtc++ = *util_outptr++; + *fmtc++ = *(TREF(util_outptr))++; } assert(fmtc <= fmt_top1); *fmtc++ = '\0'; switch (flush) { case FLUSH: - FPRINTF(stderr, fmt_buff); + FPRINTF(stderr, "%s", fmt_buff); break; case OPER: util_out_send_oper(fmt_buff, UINTCAST(fmtc - fmt_buff)); break; case SPRINT: - memcpy(util_outbuff, fmt_buff, fmtc - fmt_buff); + memcpy(TREF(util_outbuff_ptr), fmt_buff, fmtc - fmt_buff); break; } break; @@ -656,7 +814,7 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt) case OPER: case SPRINT: /* Reset buffer information. */ - util_outptr = util_outbuff; + TREF(util_outptr) = TREF(util_outbuff_ptr); break; } } @@ -664,11 +822,12 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt) void util_out_print(caddr_t message, int flush, ...) { va_list var; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; va_start(var, flush); - util_out_print_vaparm(message, flush, var, MAXPOSINT4); - va_end(last_va_list_ptr); + va_end(TREF(last_va_list_ptr)); va_end(var); } @@ -682,9 +841,10 @@ void util_out_print_gtmio(caddr_t message, int flush, ...) boolean_t usestdio; va_list var; mval flushtxt; + 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; @@ -693,45 +853,41 @@ void util_out_print_gtmio(caddr_t message, int 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 = util_outbuff; - flushtxt.str.len = INTCAST(util_outptr - util_outbuff); + 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); - util_outptr = util_outbuff; /* Signal text is flushed */ + TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal text is flushed */ } - va_end(last_va_list_ptr); + va_end(TREF(last_va_list_ptr)); va_end(var); } /* If $x of the standard output device is non-zero, and we are going to flush a buffer, - put out a new line and then do the buffer flush. Called and used only by PRN_ERROR - macro. -*/ + * put out a new line and then do the buffer flush. Called and used only by PRN_ERROR + * macro. + */ void util_cond_flush(void) { - if (NULL != io_std_device.out && 0 < io_std_device.out->dollar.x && util_outptr != util_outbuff) + DCL_THREADGBL_ACCESS; + + SETUP_THREADGBL_ACCESS; + if (NULL != io_std_device.out && 0 < io_std_device.out->dollar.x && TREF(util_outptr) != TREF(util_outbuff_ptr)) FPRINTF(stderr, "\n"); - if (util_outptr != util_outbuff) + if (TREF(util_outptr) != TREF(util_outbuff_ptr)) util_out_print(NULL, FLUSH); } -void util_out_save(void) +#ifdef DEBUG +/* White-box test only! Start a timer that prints something to the operator log with a period of + * UTIL_OUT_SYSLOG_INTERVAL in attempt to interrupt util_outbuff construction and overwrite the + * buffer's contents. + */ +void util_out_syslog_dump(void) { - if (NULL != util_outptr) - { - save_buff_used = MIN(OUT_BUFF_SIZE, ((NULL != util_outptr) ? (int4)(util_outptr - util_outbuff) : 0)); - if (0 != save_buff_used) - memcpy(save_util_outbuff, util_outbuff, save_buff_used); - } -} - -void util_out_restore(void) -{ - if (0 != save_buff_used) - { - assert(OUT_BUFF_SIZE >= save_buff_used); - memcpy(util_outbuff, save_util_outbuff, save_buff_used); - util_outptr = util_outbuff + save_buff_used; - save_buff_used = 0; - } + util_out_print("Just some white-box test message long enough to ensure that " + "whatever under-construction util_out buffer is not damaged.\n", OPER); + /* Resubmit itself for the purposes of the white-box test which expects periodic writes to the syslog. */ + start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL); } +#endif diff --git a/sr_unix/util_output_cm.c b/sr_unix/util_output_cm.c index 39f691b..f9b9591 100644 --- a/sr_unix/util_output_cm.c +++ b/sr_unix/util_output_cm.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -30,30 +30,28 @@ static unsigned char outbuff[OUT_BUFF_SIZE]; static unsigned char *outptr; -GBLREF unsigned char *util_outptr; -GBLREF va_list last_va_list_ptr; void util_cm_print(clb_struct *lnk, int code, char *message, int flush, ...) { va_list var; int4 status, i; size_t msglen ; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; VAR_START(var, flush); if (outptr == outbuff) - { *outptr++ = code; - } if (message) { util_out_print(NULL, RESET); /* Clear any pending messages */ util_out_print_vaparm(message, NOFLUSH, var, MAXPOSINT4); - msglen = (size_t)((char *)util_outptr - (char *)util_outbuff); - memcpy(outptr, util_outbuff, msglen); + msglen = (size_t)(TREF(util_outptr) - TREF(util_outbuff_ptr)); + memcpy(outptr, TREF(util_outbuff_ptr), msglen); outptr += msglen; } - va_end(last_va_list_ptr); + va_end(TREF(last_va_list_ptr)); va_end(var); switch (flush) { diff --git a/sr_unix/util_spawn.c b/sr_unix/util_spawn.c index 0235664..a9f2b08 100644 --- a/sr_unix/util_spawn.c +++ b/sr_unix/util_spawn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,6 +17,7 @@ void util_spawn(void) { char *cmd; + int rc; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; @@ -26,13 +27,15 @@ void util_spawn(void) cmd = GETENV("SHELL"); if (!cmd) cmd = "/bin/sh"; - if (-1 == SYSTEM(cmd)) + rc = SYSTEM(cmd); + if (-1 == rc) PERROR("system : "); } else { assert(TAREF1(parm_ary, TREF(parms_cnt) - 1)); assert((char *)-1L != (TAREF1(parm_ary, TREF(parms_cnt) - 1))); - if (-1 == SYSTEM(TAREF1(parm_ary, TREF(parms_cnt) - 1))) + rc = SYSTEM((TAREF1(parm_ary, TREF(parms_cnt) - 1))); + if (-1 == rc) PERROR("system : "); } } diff --git a/sr_unix/versions.csh b/sr_unix/versions.csh index 382132e..6f53ac2 100644 --- a/sr_unix/versions.csh +++ b/sr_unix/versions.csh @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2001, 2011 Fidelity Information Services, Inc # +# Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -20,7 +20,7 @@ # gtm_curpro is the current production version if (`uname -s` != "OS/390") then - setenv gtm_curpro "V54001" + setenv gtm_curpro "V60001" else setenv gtm_curpro "V53004A" # until newer version built on z/OS endif diff --git a/sr_unix/wcs_clean_dbsync.c b/sr_unix/wcs_clean_dbsync.c index 9e597bf..0dba4ca 100644 --- a/sr_unix/wcs_clean_dbsync.c +++ b/sr_unix/wcs_clean_dbsync.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,6 @@ #include "gdsbgtr.h" /* for the BG_TRACE_PRO macros */ #include "gtmio.h" /* for the GET_LSEEK_FLAG macro */ #include "wcs_clean_dbsync.h" -#include "tp_grab_crit.h" #include "wcs_flu.h" #include "lockconst.h" @@ -54,6 +53,7 @@ GBLREF volatile int4 gtmMallocDepth; /* Recursion indicator */ GBLREF boolean_t mupip_jnl_recover; #ifdef DEBUG GBLREF unsigned int t_tries; +GBLREF volatile boolean_t timer_in_handler; #endif /* Sync the filehdr (and epoch in the journal file if before imaging). The goal is to sync the database, @@ -74,6 +74,7 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr) SETUP_THREADGBL_ACCESS; csa = *csaptr; + assert(timer_in_handler); assert(csa->dbsync_timer); /* to ensure no duplicate dbsync timers */ CANCEL_DBSYNC_TIMER(csa); /* reset csa->dbsync_timer now that the dbsync timer has popped */ assert(!csa->dbsync_timer); @@ -133,16 +134,16 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr) dbsync_defer_timer = TRUE; GET_LSEEK_FLAG(FILE_INFO(reg)->fd, lseekIoInProgress_flag); DEBUG_ONLY( - /* We invoke tp_grab_crit below which can potentially do cache-recoveries if csd->wc_blocked is set. + /* We invoke grab_crit_immediate below which can potentially do cache-recoveries if cnl->wc_blocked is set. * But wcs_recover has an assert that we never invoke it in the final retry. This is to avoid - * restarts in the final retry. But wcs_clean_dbsync invokes tp_grab_crit only if we dont already + * restarts in the final retry. But wcs_clean_dbsync invokes grab_crit_immediate only if we dont already * hold crit and that means we have already finished commit on this particular region (e.g. if * commit is complete on all regions and crit is released on all of them but before we reset t_tries * to 0 in t_end/tp_tend) so it is okay to invoke wcs_recover in that case. Signal that to wcs_recover * by setting ok_to_call_wcs_recover to TRUE. Need to save and restore the global as it could be * TRUE or FALSE depending on where wcs_clean_dbsync interrupted mainline code. */ - assert(CDB_STAGNATE >= t_tries); + assert(CDB_STAGNATE >= t_tries || WBTEST_ENABLED(WBTEST_ANTIFREEZE_GVDATAFAIL)); if (CDB_STAGNATE <= t_tries) { save_ok_to_call_wcs_recover = TREF(ok_to_call_wcs_recover); @@ -157,12 +158,12 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr) && (!jpc || !jpc->jnl_buff || (LOCK_AVAILABLE == jpc->jnl_buff->fsync_in_prog_latch.u.parts.latch_pid)) && ((NULL == check_csaddrs) || !T_IN_CRIT_OR_COMMIT_OR_WRITE(check_csaddrs)) && !T_IN_CRIT_OR_COMMIT_OR_WRITE(csa) - && (FALSE != tp_grab_crit(reg))) - { /* Note that tp_grab_crit invokes wcs_recover in case csd->wc_blocked is non-zero. - * This means we could be doing cache recovery even though we are in interrupt code. - * If this is found undesirable, the logic in tp_grab_crit that invokes wcs_recover has to be re-examined. + && (FALSE != grab_crit_immediate(reg))) + { /* Note that grab_crit_immediate invokes wcs_recover in case cnl->wc_blocked is non-zero. This means we + * could be doing cache recovery even though we are in interrupt code. If this is found undesirable, the + * logic in grab_crit_immediate that invokes wcs_recover has to be re-examined. */ - /* Note that if we are here, we have obtained crit using tp_grab_crit. */ + /* Note that if we are here, we have obtained crit using grab_crit_immediate. */ assert(csa->ti->early_tn == csa->ti->curr_tn); /* Do not invoke wcs_flu if the database has a newer journal file than what this process had open * when the dbsync timer was started in wcs_wtstart. This is because mainline (non-interrupt) code @@ -181,20 +182,41 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr) * This way wcs_flu is not redundantly invoked and it ensures that the least number of epochs * (only the necessary ones) are written OR the least number of db file header flushes are done. * - * If MM and not writing EPOCHs, we dont need to even flush the file header since MM by default - * does NO msyncs of the database file during normal operation but instead only at database rundown. - * So no need to do wcs_flu in this case. + * If MM and not writing EPOCHs, we need to flush the fileheader out as that is not mmap'ed. */ - if ((NULL != jpc) && JNL_HAS_EPOCH(jpc->jnl_buff) + /* Write idle/free epoch only if db curr_tn did not change since when the last dirty cache record was + * written in wcs_wtstart to when the dbsync timer (5 seconds) popped. If the curr_tn changed it means + * some other update happened in between and things are no longer idle so the previous idle dbsync + * timer can be stopped. A new timer will be written when the later updates finish and leave the db + * idle again. Note that there are some race conditions where we might not be accurate in writing idle + * EPOCH only when necessary (since we dont hold crit at the time we record csa->dbsync_timer_tn). But + * any error will always be on the side of caution so we might end up writing more idle EPOCHs than + * necessary. Also, even if we dont write an idle EPOCH (for example because we found an update + * happened later but that update turned out to be a duplicate SET which will not start an idle + * EPOCH timer), journal recovery already knows to handle the case where an idle EPOCH did not get + * written. So things will still work but it might just take a little longer than usual. + */ + if (csa->dbsync_timer_tn == csa->ti->curr_tn) + { /* Note that it is possible in rare cases that an online rollback took csa->ti->curr_tn back + * and the exact # of updates happened concurrently to take csa->ti->curr_tn back to where it + * was to match csa->dbsync_timer_tn. In this case, we will be writing an epoch unnecessarily + * but this is a very rare situation that is considered okay to write the epoch in that case + * as it keeps the if check simple for the most frequent path. + */ + if ((NULL != jpc) && JNL_HAS_EPOCH(jpc->jnl_buff) ? (((NOJNL == jpc->channel) || !JNL_FILE_SWITCHED(jpc)) && (jpc->jnl_buff->epoch_tn < csa->ti->curr_tn)) - : !is_mm && (cnl->last_wcsflu_tn < csa->ti->curr_tn)) - { - wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH); - BG_TRACE_PRO_ANY(csa, n_dbsync_writes); - /* If MM, file could have been remapped by wcs_flu above. If so, cs_data needs to be reset */ - if (is_mm && (save_csaddrs == cs_addrs) && (save_csdata != cs_data)) - save_csdata = cs_addrs->hdr; + : (cnl->last_wcsflu_tn < csa->ti->curr_tn)) + { + wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_CLEAN_DBSYNC + | WCSFLU_SPEEDUP_NOBEFORE); + BG_TRACE_PRO_ANY(csa, n_dbsync_writes); + /* If MM, file could have been remapped by wcs_flu above. + * If so, cs_data needs to be reset. + */ + if (is_mm && (save_csaddrs == cs_addrs) && (save_csdata != cs_data)) + save_csdata = cs_addrs->hdr; + } } dbsync_defer_timer = FALSE; assert(!csa->hold_onto_crit); /* this ensures we can safely do unconditional rel_crit */ @@ -208,6 +230,11 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr) if (dbsync_defer_timer) { assert(SIZEOF(INTPTR_T) == SIZEOF(csa)); + /* Adding a new dbsync timer should typically be done in a deferred zone to avoid duplicate timer additions for the + * same TID. But, in this case, we are guaranteed that timers won't pop as we are already in a timer handler. As + * for the external interrupts, they should be okay to interrupt at this point since, unlike timer interrupts, + * control won't return to mainline code. So, in either case, we can safely add the new timer. + */ if (!csa->dbsync_timer) START_DBSYNC_TIMER(csa, TIM_DEFER_DBSYNC); } diff --git a/sr_unix/wcs_clean_dbsync.h b/sr_unix/wcs_clean_dbsync.h index b8298f5..ebf5d94 100644 --- a/sr_unix/wcs_clean_dbsync.h +++ b/sr_unix/wcs_clean_dbsync.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,7 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr); #define START_DBSYNC_TIMER(CSA, TIM_DEFER_DBSYNC) \ { \ CSA->dbsync_timer = TRUE; \ + CSA->dbsync_timer_tn = CSA->ti->curr_tn; \ start_timer((TID)CSA, TIM_DEFER_DBSYNC, &wcs_clean_dbsync, SIZEOF(CSA), (char *)&CSA); \ } diff --git a/sr_unix/wcs_flu.c b/sr_unix/wcs_flu.c index d4486b1..c106053 100644 --- a/sr_unix/wcs_flu.c +++ b/sr_unix/wcs_flu.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,7 +16,7 @@ #include "gtm_string.h" #include "gtm_time.h" -#include "gtm_unistd.h" /* fsync() needs this */ +#include "gtm_unistd.h" /* DB_FSYNC needs this */ #include "aswp.h" /* for ASWP */ #include "gdsroot.h" @@ -44,6 +44,8 @@ #include "wcs_mm_recover.h" #include "memcoherency.h" #include "gtm_c_stack_trace.h" +#include "anticipatory_freeze.h" +#include "eintr_wrappers.h" GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; @@ -58,6 +60,7 @@ GBLREF boolean_t mupip_jnl_recover; error_def(ERR_DBFILERR); error_def(ERR_DBFSYNCERR); +error_def(ERR_DBIOERR); error_def(ERR_GBLOFLOW); error_def(ERR_JNLFILOPN); error_def(ERR_JNLFLUSH); @@ -68,6 +71,19 @@ error_def(ERR_WAITDSKSPACE); error_def(ERR_WCBLOCKED); error_def(ERR_WRITERSTUCK); +#define JNL_WRITE_EPOCH_REC(CSA, CNL, CLEAN_DBSYNC) \ +{ \ + jnl_write_epoch_rec(CSA); \ + /* Note: Cannot easily use ? : syntax below as INCR_GVSTATS_COUNTER macro \ + * is not an arithmetic expression but a sequence of statements. \ + */ \ + if (!CLEAN_DBSYNC) \ + { \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_jrec_epoch_regular, 1); \ + } else \ + INCR_GVSTATS_COUNTER(CSA, CNL, n_jrec_epoch_idle, 1); \ +} + #define WAIT_FOR_CONCURRENT_WRITERS_TO_FINISH(FIX_IN_WTSTART, WAS_CRIT) \ { \ GTM_WHITE_BOX_TEST(WBTEST_BUFOWNERSTUCK_STACK, (cnl->in_wtstart), 1); \ @@ -77,7 +93,7 @@ error_def(ERR_WRITERSTUCK); DEBUG_ONLY(int4 intent_wtstart;) /* temporary for debugging purposes */ \ \ assert(csa->now_crit); \ - SIGNAL_WRITERS_TO_STOP(csd); /* to stop all active writers */ \ + SIGNAL_WRITERS_TO_STOP(cnl); /* to stop all active writers */ \ lcnt = 0; \ do \ { \ @@ -96,7 +112,7 @@ error_def(ERR_WRITERSTUCK); assert((gtm_white_box_test_case_enabled) && \ (WBTEST_BUFOWNERSTUCK_STACK == gtm_white_box_test_case_number)); \ cnl->wcsflu_pid = 0; \ - SIGNAL_WRITERS_TO_RESUME(csd); \ + SIGNAL_WRITERS_TO_RESUME(cnl); \ if (!WAS_CRIT) \ rel_crit(gv_cur_region); \ /* Disable white box testing after the first time the \ @@ -105,7 +121,8 @@ error_def(ERR_WRITERSTUCK); and at that time we do not want the WBTEST_BUFOWNERSTUCK_STACK white box \ mechanism to kick in.*/ \ GTM_WHITE_BOX_TEST(WBTEST_BUFOWNERSTUCK_STACK, gtm_white_box_test_case_enabled, FALSE); \ - send_msg(VARLSTCNT(5) ERR_WRITERSTUCK, 3, cnl->in_wtstart, DB_LEN_STR(gv_cur_region)); \ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_WRITERSTUCK, 3, cnl->in_wtstart, \ + DB_LEN_STR(gv_cur_region)); \ return FALSE; \ } \ if (-1 == shmctl(udi->shmid, IPC_STAT, &shm_buf)) \ @@ -113,9 +130,10 @@ error_def(ERR_WRITERSTUCK); save_errno = errno; \ if (1 == lcnt) \ { \ - send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region)); \ - send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmctl()"), \ - CALLFROM, save_errno); \ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2, \ + DB_LEN_STR(gv_cur_region)); \ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_SYSCALL, 5, \ + RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno); \ } \ } else if (1 == shm_buf.shm_nattch) \ { \ @@ -126,15 +144,22 @@ error_def(ERR_WRITERSTUCK); } else \ wcs_sleep(lcnt); /* wait for any in wcs_wtstart to finish */ \ } while (WRITERS_ACTIVE(cnl)); \ - SIGNAL_WRITERS_TO_RESUME(csd); \ + SIGNAL_WRITERS_TO_RESUME(cnl); \ } \ } +#define REL_CRIT_BEFORE_RETURN \ +{ \ + cnl->wcsflu_pid = 0; \ + if (!was_crit) \ + rel_crit(gv_cur_region); \ +} + boolean_t wcs_flu(uint4 options) { bool success, was_crit; boolean_t fix_in_wtstart, flush_hdr, jnl_enabled, sync_epoch, write_epoch, need_db_fsync, in_commit; - boolean_t flush_msync; + boolean_t flush_msync, speedup_nobefore, clean_dbsync, return_early; unsigned int lcnt, pass; int save_errno, wtstart_errno; jnl_buffer_ptr_t jb; @@ -155,6 +180,8 @@ boolean_t wcs_flu(uint4 options) sync_epoch = options & WCSFLU_SYNC_EPOCH; need_db_fsync = options & WCSFLU_FSYNC_DB; flush_msync = options & WCSFLU_MSYNC_DB; + speedup_nobefore = options & WCSFLU_SPEEDUP_NOBEFORE; + clean_dbsync = options & WCSFLU_CLEAN_DBSYNC; /* WCSFLU_IN_COMMIT bit is set if caller is t_end or tp_tend. In that case, we should NOT invoke wcs_recover if we * encounter an error. Instead we should return the error as such so they can trigger appropriate error handling. * This is necessary because t_end and tp_tend could have pinned one or more cache-records (cr->in_cw_set non-zero) @@ -168,72 +195,25 @@ boolean_t wcs_flu(uint4 options) csd = csa->hdr; cnl = csa->nl; assert(cnl->glob_sec_init); - BG_TRACE_ANY(csa, total_buffer_flush); /* If called from online rollback, we will have hold_onto_crit set to TRUE with the only exception when called from * gds_rundown in which case process_exiting will be TRUE anyways */ assert(!jgbl.onlnrlbk || csa->hold_onto_crit || process_exiting); assert(mupip_jnl_recover || !csa->nl->donotflush_dbjnl); assert(!csa->hold_onto_crit || csa->now_crit); + assert(0 == memcmp(csd->label, GDS_LABEL, GDS_LABEL_SZ - 1)); if (!(was_crit = csa->now_crit)) /* Caution: assignment */ grab_crit(gv_cur_region); - cnl->wcsflu_pid = process_id; - if (dba_mm == csd->acc_meth) - { -#if !defined(NO_MSYNC) && !defined(UNTARGETED_MSYNC) - SIGNAL_WRITERS_TO_STOP(csd); /* to stop all active writers */ - WAIT_FOR_WRITERS_TO_STOP(cnl, lcnt, MAXGETSPACEWAIT); - if (MAXGETSPACEWAIT == lcnt) - { - GET_C_STACK_MULTIPLE_PIDS("WRITERSTUCK", cnl->wtstart_pid, MAX_WTSTART_PID_SLOTS, 1); - assert(FALSE); - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); - return FALSE; - } - SIGNAL_WRITERS_TO_RESUME(csd); - /* wcs_flu() is currently also called from wcs_clean_dbsync() which is interrupt driven code. We are about to - * remap the database in interrupt code. Depending on where the interrupt occurred, all sorts of strange failures - * can occur in the mainline code after the remap in interrupt code. Thankfully, this code is currently not - * enabled by default (NO_MSYNC is the default) so we are fine. If ever this gets re-enabled, we need to - * solve this problem by changing wcs_clean_dbsync not to call wcs_flu. The assert below is a note for this. - */ - assert(FALSE); - MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region); - /* MM MM_DBFILEXT_REMAP_IF_NEEDED can remap the file so reset csd which might no long point to the file */ - csd = csa->hdr; - while (0 != csa->acc_meth.mm.mmblk_state->mmblkq_active.fl) - { - wtstart_errno = wcs_wtstart(gv_cur_region, csd->n_bts); - assert(ERR_GBLOFLOW != wtstart_errno); - } -#else - if (NO_MSYNC_ONLY((csd->freeze || flush_msync) && ) (csa->ti->last_mm_sync != csa->ti->curr_tn)) - { - if (0 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC)) - csa->ti->last_mm_sync = csa->ti->curr_tn; /* Save when did last full sync */ - else - { - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); - return FALSE; - } - } -#endif - } /* jnl_enabled is an overloaded variable. It is TRUE only if JNL_ENABLED(csd) is TRUE * and if the journal file has been opened in shared memory. If the journal file hasn't * been opened in shared memory, we needn't (and shouldn't) do any journal file activity. */ jnl_enabled = (JNL_ENABLED(csd) && (0 != cnl->jnl_file.u.inode)); + jpc = csa->jnl; if (jnl_enabled) { - jpc = csa->jnl; jb = jpc->jnl_buff; /* 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) SET_GBL_JREC_TIME; /* needed before jnl_ensure_open */ @@ -244,54 +224,102 @@ boolean_t wcs_flu(uint4 options) ADJUST_GBL_JREC_TIME(jgbl, jb); assert(csa == cs_addrs); /* for jnl_ensure_open */ jnl_status = jnl_ensure_open(); - if (SS_NORMAL == jnl_status) - { - fsync_dskaddr = jb->fsync_dskaddr; /* take a local copy as it could change concurrently */ - if (fsync_dskaddr != jb->freeaddr) - { - assert(fsync_dskaddr <= jb->dskaddr); - if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region))) - { - assert(NOJNL == jpc->channel); /* jnl file lost */ - if (!was_crit) - rel_crit(gv_cur_region); - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during wcs_flu1"), - jnl_status); - return FALSE; - } - assert(jb->freeaddr == jb->dskaddr); - jnl_fsync(gv_cur_region, jb->dskaddr); - assert(jb->fsync_dskaddr == jb->dskaddr); - } - } else + WBTEST_ASSIGN_ONLY(WBTEST_WCS_FLU_FAIL, jnl_status, ERR_JNLFILOPN); + if (SS_NORMAL != jnl_status) { assert(ERR_JNLFILOPN == jnl_status); - send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); if (JNL_ENABLED(csd)) - { /* If journaling is still enabled, but we failed to open the journal file, we don't want to continue - * processing. - */ - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); + { /* If journaling is still enabled, but we failed to open the journal file, + * we don't want to continue processing. + */ + REL_CRIT_BEFORE_RETURN; return FALSE; } jnl_enabled = FALSE; } } - if (dba_mm != csd->acc_meth) + if (jnl_enabled) { - /* If not mupip rundown, wait for ALL active phase2 commits to complete first. + assert(SS_NORMAL == jnl_status); + if (return_early = (speedup_nobefore && !csd->jnl_before_image)) + { /* Finish easiest option first. This database has NOBEFORE image journaling and caller has asked for + * processing to be speeded up in that case. Write only an epoch record, dont do heavyweight flush or fsync + * of db.This will avoid bunching of IO at the epoch time like is the case with before-image journaling + * where this is currently necessary for correctness. But for nobefore, there is no need to do this since + * no backward recovery will be performed. Note that if db has journaling disabled OR enabled with before- + * image journaling, we skip this portion of code and follow through to the rest of wcs_flu as if + * WCSFLU_SPEEDUP_NOBEFORE was not specified. + */ + assert(!jgbl.mur_extract); /* Dont know of a case where journal extract calls us with skip_db_flush set */ + assert(write_epoch); + assert(flush_hdr); + /* For Recovery/Rollback logic (even in case of NOBEFORE image journaling) to work correctly, the TN values + * in the file header - jnl_eovtn and curr_tn - should be greater than eov_tn in the journal file header. + * Note: eov_tn in the journal file header is the TN of the penultimate EPOCH and so should always be <= + * current database transaction number. If this relation is not maintained by GT.M, Rollback/Recovery logic + * can issue JNLDBTNNOMATCH error. To avoid this situation, flush and sync the DB file header. + */ + fileheader_sync(gv_cur_region); + assert(NULL != jpc); + if (0 == jpc->pini_addr) + jnl_put_jrt_pini(csa); + JNL_WRITE_EPOCH_REC(csa, cnl, clean_dbsync); + } + fsync_dskaddr = jb->fsync_dskaddr; /* take a local copy as it could change concurrently */ + if (fsync_dskaddr != jb->freeaddr) + { + assert(fsync_dskaddr <= jb->dskaddr); + if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region))) + { + assert(NOJNL == jpc->channel); /* jnl file lost */ + REL_CRIT_BEFORE_RETURN; + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, + RTS_ERROR_TEXT("Error with journal flush during wcs_flu1"), jnl_status); + return FALSE; + } + assert(jb->freeaddr == jb->dskaddr); + jnl_fsync(gv_cur_region, jb->dskaddr); + assert(jb->fsync_dskaddr == jb->dskaddr); + } + if (return_early) + { + REL_CRIT_BEFORE_RETURN; + return TRUE; + } + } + BG_TRACE_ANY(csa, total_buffer_flush); + INCR_GVSTATS_COUNTER(csa, cnl, n_db_flush, 1); + cnl->wcsflu_pid = process_id; + if (dba_mm == csd->acc_meth) + { + if (WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL) + || ((csd->freeze || flush_msync) && (csa->ti->last_mm_sync != csa->ti->curr_tn))) + { + if (!(WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL)) + && (0 == MSYNC((caddr_t)(MM_BASE_ADDR(csa)), (caddr_t)csa->db_addrs[1]))) + { /* Save when did last full sync */ + csa->ti->last_mm_sync = csa->ti->curr_tn; + } else + { + REL_CRIT_BEFORE_RETURN; + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), ERR_TEXT, 2, + RTS_ERROR_TEXT("Error during file msync during flush")); + return FALSE; + } + } + } + if (dba_mm != csd->acc_meth) + { /* If not mupip rundown, wait for ALL active phase2 commits to complete first. * In case of mupip rundown, we know no one else is accessing shared memory so no point waiting. */ assert(!in_mu_rndwn_file || (0 == cnl->wcs_phase2_commit_pidcnt)); - if (cnl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL)) + if (WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL) || (cnl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL))) { - assert(WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number); /* see wcs_phase2_commit_wait.c */ - if (!was_crit) - rel_crit(gv_cur_region); - return FALSE; /* we expect the caller to trigger cache-recovery which will fix this counter */ + assert((WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number) /* see wcs_phase2_commit_wait.c */ + || (WBTEST_WCS_FLU_FAIL == gtm_white_box_test_case_number)); + REL_CRIT_BEFORE_RETURN; + return FALSE; /* We expect the caller to trigger cache-recovery which will fix this counter */ } /* Now that all concurrent commits are complete, wait for these dirty buffers to be flushed to disk. * Note that calling wcs_wtstart just once assumes that if we ask it to flush all the buffers, it will. @@ -314,10 +342,27 @@ boolean_t wcs_flu(uint4 options) */ crq = &csa->acc_meth.bg.cache_state->cacheq_active; assert(((0 <= cnl->wcs_active_lvl) && (cnl->wcs_active_lvl || 0 == crq->fl)) || (ENOSPC == wtstart_errno)); +# ifdef DEBUG + if (in_commit) + GTM_WHITE_BOX_TEST(WBTEST_WCS_FLU_IOERR, cnl->wcs_active_lvl, 1); + GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_OUTOFSPACE, cnl->wcs_active_lvl, 1); +# endif if (cnl->wcs_active_lvl || crq->fl) { wtstart_errno = wcs_wtstart(gv_cur_region, csd->n_bts); /* Flush it all */ WAIT_FOR_CONCURRENT_WRITERS_TO_FINISH(fix_in_wtstart, was_crit); +# ifdef DEBUG + if (in_commit) + { + GTM_WHITE_BOX_TEST(WBTEST_WCS_FLU_IOERR, cnl->wcs_active_lvl, 1); + GTM_WHITE_BOX_TEST(WBTEST_WCS_FLU_IOERR, wtstart_errno, ENOENT); + } + if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_OUTOFSPACE == gtm_white_box_test_case_number)) + { + cnl->wcs_active_lvl = 1; + wtstart_errno = ENOSPC; + } +# endif if (cnl->wcs_active_lvl || crq->fl) /* give allowance in PRO */ { if (ENOSPC == wtstart_errno) @@ -329,9 +374,9 @@ boolean_t wcs_flu(uint4 options) if ((to_wait == csd->wait_disk_space) || (0 == to_wait % to_msg)) { - send_msg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(gv_cur_region), wtstart_errno); - gtm_putmsg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(gv_cur_region), wtstart_errno); } hiber_start(1000); @@ -342,11 +387,13 @@ boolean_t wcs_flu(uint4 options) } if ((to_wait <= 0) && (cnl->wcs_active_lvl || crq->fl)) { /* not enough space became available after the wait */ - send_msg(VARLSTCNT(5) ERR_OUTOFSPACE, 3, DB_LEN_STR(gv_cur_region), process_id); - rts_error(VARLSTCNT(5) ERR_OUTOFSPACE, 3, DB_LEN_STR(gv_cur_region), process_id); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_OUTOFSPACE, 3, + DB_LEN_STR(gv_cur_region), process_id); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_OUTOFSPACE, 3, + DB_LEN_STR(gv_cur_region), process_id); } } else - { /* There are three cases we know of currently when this is possible: + { /* There are four different cases we know of currently when this is possible: * (a) If a process encountered an error in the midst of committing in phase2 and * secshr_db_clnup completed the commit for it and set wc_blocked to TRUE (even though * it was OUT of crit) causing the wcs_wtstart calls done above to do nothing. @@ -358,23 +405,39 @@ boolean_t wcs_flu(uint4 options) * But phase1 and phase2 commit errors are currently enabled only through white-box testing. * (c) If a test does crash shutdown (kill -9) that hit the process in the middle of * wcs_wtstart which means the writes did not complete successfully. + * (d) If WBTEST_WCS_FLU_IOERR/WBTEST_WCS_WTSTART_IOERR white box test case is set that + * forces wcs_wtstart invocations to end up with I/O errors. */ assert((WBTEST_BG_UPDATE_PHASE2FAIL == gtm_white_box_test_case_number) || (WBTEST_BG_UPDATE_BTPUTNULL == gtm_white_box_test_case_number) - || (WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number)); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); - BG_TRACE_PRO_ANY(csa, wcb_wcs_flu1); - send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_wcs_flu1"), - process_id, &csa->ti->curr_tn, DB_LEN_STR(gv_cur_region)); + || (WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number) + || (WBTEST_WCS_FLU_IOERR == gtm_white_box_test_case_number) + || (WBTEST_WCS_WTSTART_IOERR == gtm_white_box_test_case_number) + || (WBTEST_ANTIFREEZE_DBDANGER == gtm_white_box_test_case_number) + || (WBTEST_ANTIFREEZE_JNLCLOSE == gtm_white_box_test_case_number)); + if (0 == wtstart_errno) + { + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); + BG_TRACE_PRO_ANY(csa, wcb_wcs_flu1); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, + LEN_AND_LIT("wcb_wcs_flu1"), process_id, &csa->ti->curr_tn, + DB_LEN_STR(gv_cur_region)); + } else + { /* Encountered I/O error. Transfer control to error trap */ + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(gv_cur_region), + DB_LEN_STR(gv_cur_region), wtstart_errno); + } if (in_commit) { /* We should NOT be invoking wcs_recover as otherwise the callers (t_end or tp_tend) * will get confused (see explanation above where variable "in_commit" gets set). */ assert(was_crit); /* so dont need to rel_crit */ + cnl->wcsflu_pid = 0; return FALSE; } assert(!jnl_enabled || jb->fsync_dskaddr == jb->freeaddr); - wcs_recover(gv_cur_region); + if (0 == wtstart_errno) + wcs_recover(gv_cur_region); if (jnl_enabled) { fsync_dskaddr = jb->fsync_dskaddr; @@ -388,10 +451,9 @@ boolean_t wcs_flu(uint4 options) if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region))) { assert(NOJNL == jpc->channel); /* jnl file lost */ - if (!was_crit) - rel_crit(gv_cur_region); - send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), - ERR_TEXT, 2, + REL_CRIT_BEFORE_RETURN; + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, + JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during wcs_flu2"), jnl_status); return FALSE; @@ -409,9 +471,7 @@ boolean_t wcs_flu(uint4 options) WAIT_FOR_CONCURRENT_WRITERS_TO_FINISH(fix_in_wtstart, was_crit); if (cnl->wcs_active_lvl || crq->fl) { - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); + REL_CRIT_BEFORE_RETURN; GTMASSERT; } } @@ -419,17 +479,14 @@ boolean_t wcs_flu(uint4 options) } } if (flush_hdr) - { - assert(memcmp(csd->label, GDS_LABEL, GDS_LABEL_SZ - 1) == 0); fileheader_sync(gv_cur_region); - } if (jnl_enabled && write_epoch) { /* If need to write an epoch, * (1) get hold of the jnl io_in_prog lock. * (2) set need_db_fsync to TRUE in the journal buffer. * (3) release the jnl io_in_prog lock. * (4) write an epoch record in the journal buffer. - * The next call to jnl_qio_start() will do the fsync() of the db before doing any jnl qio. + * The next call to jnl_qio_start will do the fsync of the db before doing any jnl qio. * The basic requirement is that we shouldn't write the epoch out until we have synced the database. */ assert(jb->fsync_dskaddr == jb->freeaddr); @@ -446,9 +503,7 @@ boolean_t wcs_flu(uint4 options) { GET_C_STACK_MULTIPLE_PIDS("MAXJNLQIOLOCKWAIT", cnl->wtstart_pid, MAX_WTSTART_PID_SLOTS, 1); assert(FALSE); - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); + REL_CRIT_BEFORE_RETURN; GTMASSERT; } wcs_sleep(SLEEP_JNLQIOLOCKWAIT); /* since it is a short lock, sleep the minimum */ @@ -464,14 +519,15 @@ boolean_t wcs_flu(uint4 options) RELEASE_SWAPLOCK(&jb->io_in_prog_latch); assert(!(JNL_FILE_SWITCHED(jpc))); assert(jgbl.gbl_jrec_time); - if (0 == jpc->pini_addr) - jnl_put_jrt_pini(csa); - jnl_write_epoch_rec(csa); + if (!jgbl.mur_extract) + { + if (0 == jpc->pini_addr) + jnl_put_jrt_pini(csa); + JNL_WRITE_EPOCH_REC(csa, cnl, clean_dbsync); + } } cnl->last_wcsflu_tn = csa->ti->curr_tn; /* record when last successful wcs_flu occurred */ - cnl->wcsflu_pid = 0; - if (!was_crit) - rel_crit(gv_cur_region); + REL_CRIT_BEFORE_RETURN; /* sync the epoch record in the journal if needed. */ if (jnl_enabled && write_epoch && sync_epoch && (csa->ti->curr_tn == csa->ti->early_tn)) { /* Note that if we are in the midst of committing and came here through a bizarre @@ -488,34 +544,11 @@ boolean_t wcs_flu(uint4 options) DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno); if (0 != save_errno) { - send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); assert(FALSE); /* should not come here as the rts_error above should not return */ return FALSE; } - } else - { -#ifndef NO_MSYNC -#ifndef TARGETED_MSYNC - DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno); - if (0 != save_errno) - { - send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno); - assert(FALSE); /* should not come here as the rts_error above should not return */ - return FALSE; - } -#else - if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC)) - { - save_errno = errno; - rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync during flush"), save_errno); - assert(FALSE); /* should not come here as the rts_error above should not return */ - return FALSE; - } -#endif -#endif } } return TRUE; diff --git a/sr_unix/wcs_get_space.c b/sr_unix/wcs_get_space.c index b996bb7..034d81e 100644 --- a/sr_unix/wcs_get_space.c +++ b/sr_unix/wcs_get_space.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2007, 2011 Fidelity Information Services, Inc * + * Copyright 2007, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -87,7 +87,6 @@ error_def(ERR_GBLOFLOW); } \ /* go after a specific number of buffers or a particular buffer */ -/* not called if UNTARGETED_MSYNC and MM mode */ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) { sgmnt_addrs *csa; @@ -98,7 +97,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) int maxspins, retries, spins; uint4 lcnt, size, to_wait, to_msg, this_idx; wcs_conflict_trace_t wcs_conflict_trace[WCS_CONFLICT_TRACE_ARRAYSIZE]; - boolean_t is_mm; cache_rec cr_contents; DCL_THREADGBL_ACCESS; @@ -108,8 +106,8 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; cnl = csa->nl; - is_mm = (dba_mm == csd->acc_meth); - assert(is_mm || (dba_bg == csd->acc_meth)); + assert(dba_bg == csd->acc_meth); + assert((0 == needed) || ((DB_CSH_RDPOOL_SZ <= needed) && (needed <= csd->n_bts))); if (FALSE == csa->now_crit) { assert(0 != needed); /* if needed == 0, then we should be in crit */ @@ -118,7 +116,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) /* a macro that ensure jnl is open, invokes wcs_wtstart() and checks for errors etc. */ return TRUE; } - UNTARGETED_MSYNC_ONLY(assert(!is_mm);) csd->flush_trigger = MAX(csd->flush_trigger - MAX(csd->flush_trigger / STEP_FACTOR, 1), MIN_FLUSH_TRIGGER(csd->n_bts)); /* Routine actually serves two purposes: * 1 - Free up required number of buffers or @@ -131,8 +128,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) for (lcnt = 1; (cnl->wc_in_free < needed) && (BUF_OWNER_STUCK > lcnt); ++lcnt) { JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, needed, save_errno); - if (is_mm && (ERR_GBLOFLOW == save_errno)) - wcs_recover(reg); if (cnl->wc_in_free < needed) { if ((ENOSPC == save_errno) && (csa->hdr->wait_disk_space > 0)) @@ -153,16 +148,14 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) if ((to_wait == cs_data->wait_disk_space) || (0 == to_wait % to_msg)) { - send_msg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno); - gtm_putmsg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno); } hiber_start(1000); to_wait--; JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, needed, save_errno); - if (is_mm && (ERR_GBLOFLOW == save_errno)) - wcs_recover(reg); if (cnl->wc_in_free >= needed) break; } @@ -198,14 +191,10 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) assert(csa->now_crit); /* must be crit to play with queues when not the writer */ BG_TRACE_PRO_ANY(csa, spcfc_buffer_flush); ++fast_lock_count; /* Disable wcs_stale for duration */ - if (!is_mm) /* Determine queue base to use */ - { - base = &csa->acc_meth.bg.cache_state->cacheq_active; - /* If another process is concurrently finishing up phase2 of commit, wait for that to complete first. */ - if (cr->in_tend && !wcs_phase2_commit_wait(csa, cr)) - return FALSE; /* assumption is that caller will set wc_blocked and trigger cache recovery */ - } else - base = &csa->acc_meth.mm.mmblk_state->mmblkq_active; + base = &csa->acc_meth.bg.cache_state->cacheq_active; + /* If another process is concurrently finishing up phase2 of commit, wait for that to complete first. */ + if (cr->in_tend && !wcs_phase2_commit_wait(csa, cr)) + return FALSE; /* assumption is that caller will set wc_blocked and trigger cache recovery */ maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1; for (retries = LOCK_TRIES - 1; retries > 0 ; retries--) { @@ -231,8 +220,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) * If this didn't work, flush normal amount next time in the loop. */ JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 1, save_errno); - if (is_mm && (ERR_GBLOFLOW == save_errno)) - wcs_recover(reg); for (lcnt = 1; (0 != cr->dirty) && (UNIX_GETSPACEWAIT > lcnt); ++lcnt) { if (0 == (lcnt % LCNT_INTERVAL)) @@ -250,7 +237,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) * wcs_wtstart as it will return right away. Instead return FALSE so * cache-recovery can be triggered by the caller. */ - if (csd->wc_blocked) + if (cnl->wc_blocked) { assert(gtm_white_box_test_case_enabled); return FALSE; @@ -261,8 +248,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) { BG_TRACE_PRO_ANY(csa, spcfc_buffer_flush_retries); JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, save_errno); - if (is_mm && (ERR_GBLOFLOW == save_errno)) - wcs_recover(reg); } /* Usually we want to sleep only if we need to wait on someone else * i.e. (i) if we are waiting for another process' fsync to complete @@ -273,7 +258,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) * Right now we know of only one case where there is no point in waiting * which is if the cache-record is out of the active queue and is dirty. * But since that is quite rare and we don't lose much in that case by - * sleeping we do an unconditional sleep (only if cr is dirty). + * sleeping we do an unconditional sleep (only if cr is dirty). {BYPASSOK} */ if (!cr->dirty) return TRUE; @@ -328,7 +313,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr) return TRUE; } if (ENOSPC == save_errno) - rts_error(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno); + rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno); else assert(FALSE); INVOKE_C_STACK_APPROPRIATE(cr, csa, 2); diff --git a/sr_unix/wcs_wtstart.c b/sr_unix/wcs_wtstart.c index 1240da9..4074c15 100644 --- a/sr_unix/wcs_wtstart.c +++ b/sr_unix/wcs_wtstart.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -43,7 +43,6 @@ #include "gt_timer.h" #include "send_msg.h" #include "gtmmsg.h" -#include "tp_grab_crit.h" #include "wcs_flu.h" #include "add_inter.h" #include "wcs_recover.h" @@ -54,6 +53,7 @@ #include "memcoherency.h" #include "wbox_test_init.h" #include "wcs_clean_dbsync.h" +#include "anticipatory_freeze.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif @@ -66,18 +66,25 @@ if (INTERLOCK_FAIL == n) \ { \ assert(FALSE); \ - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); \ + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); \ BG_TRACE_PRO_ANY(csa, trace_cntr); \ break; \ } \ } +#define DBIOERR_LOGGING_PERIOD 100 + GBLREF boolean_t *lseekIoInProgress_flags; /* needed for the LSEEK* macros in gtmio.h */ GBLREF uint4 process_id; GBLREF sm_uc_ptr_t reformat_buffer; GBLREF int reformat_buffer_len; -GBLREF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */ -GBLREF volatile int4 fast_lock_count; +GBLREF gd_region *gv_cur_region; +GBLREF sgmnt_addrs *cs_addrs; +GBLREF sgmnt_data *cs_data; +#ifdef DEBUG +GBLREF volatile int reformat_buffer_in_use; +GBLREF volatile int4 gtmMallocDepth; +#endif /* In case of a disk-full situation, we want to print a message every 1 minute. We maintain two global variables to that effect. * dskspace_msg_counter and save_dskspace_msg_counter. If we encounter a disk-full situation and both those variables are different * we start a timer dskspace_msg_timer() that pops after a minute and increments one of the variables dskspace_msg_counter. @@ -87,10 +94,12 @@ static volatile uint4 save_dskspace_msg_counter = 0; GBLDEF volatile uint4 dskspace_msg_counter = 1; /* not static since used in dskspace_msg_timer.c */ error_def(ERR_DBFILERR); +error_def(ERR_DBIOERR); +error_def(ERR_ENOSPCQIODEFER); +error_def(ERR_GBLOFLOW); error_def(ERR_JNLFSYNCERR); error_def(ERR_JNLWRTDEFER); error_def(ERR_JNLWRTNOWWRTR); -error_def(ERR_GBLOFLOW); error_def(ERR_SYSCALL); error_def(ERR_TEXT); @@ -98,9 +107,8 @@ int4 wcs_wtstart(gd_region *region, int4 writes) { blk_hdr_ptr_t bp, save_bp; boolean_t need_jnl_sync, queue_empty, got_lock, bmp_status; - cache_que_head_ptr_t ahead; /* serves dual purpose since cache_que_head = mmblk_que_head */ - cache_state_rec_ptr_t csr, csrfirst; /* serves dual purpose for MM and BG */ - /* since mmblk_state_rec is equal to the top of cache_state_rec */ + cache_que_head_ptr_t ahead; + cache_state_rec_ptr_t csr, csrfirst; int4 err_status = 0, n, n1, n2, max_ent, max_writes, save_errno; size_t size ; jnl_buffer_ptr_t jb; @@ -115,43 +123,47 @@ int4 wcs_wtstart(gd_region *region, int4 writes) cache_rec_ptr_t cr, cr_lo, cr_hi; static int4 error_message_loop_count = 0; uint4 index; - boolean_t is_mm; + boolean_t is_mm, was_crit; uint4 curr_wbox_seq_num; - int try_sleep; - GTMCRYPT_ONLY( - int req_enc_blk_size; - int4 crypt_status = 0; - char *inbuf; - boolean_t is_encrypted; - blk_hdr_ptr_t enc_bp; - ) + int try_sleep, rc; + gd_region *sav_cur_region; + sgmnt_addrs *sav_cs_addrs; + sgmnt_data *sav_cs_data; +# ifdef GTM_CRYPT + char *in, *out; + int in_len; + int4 gtmcrypt_errno = 0; + gd_segment *seg; +# endif + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; + if (ANTICIPATORY_FREEZE_AVAILABLE) + PUSH_GV_CUR_REGION(region, sav_cur_region, sav_cs_addrs, sav_cs_data) udi = FILE_INFO(region); csa = &udi->s_addrs; csd = csa->hdr; is_mm = (dba_mm == csd->acc_meth); assert(is_mm || (dba_bg == csd->acc_meth)); - - /* you don't enter this routine if this has been compiled with #define UNTARGETED_MSYNC and it is MM mode */ -# if defined(UNTARGETED_MSYNC) - assert(!is_mm); -# endif - BG_TRACE_ANY(csa, wrt_calls); /* Calls to wcs_wtstart */ /* If *this* process is already in wtstart, we won't interrupt it do it again */ if (csa->in_wtstart) { BG_TRACE_ANY(csa, wrt_busy); + if (ANTICIPATORY_FREEZE_AVAILABLE) + POP_GV_CUR_REGION(sav_cur_region, sav_cs_addrs, sav_cs_data) return err_status; /* Already here, get out */ } cnl = csa->nl; INCR_INTENT_WTSTART(cnl); /* signal intent to enter wcs_wtstart */ /* the above interlocked instruction does the appropriate write memory barrier to publish this change to the world */ - SHM_READ_MEMORY_BARRIER; /* need to do this to ensure uptodate value of csd->wc_blocked is read */ - if (csd->wc_blocked) + SHM_READ_MEMORY_BARRIER; /* need to do this to ensure uptodate value of cnl->wc_blocked is read */ + if (cnl->wc_blocked) { DECR_INTENT_WTSTART(cnl); BG_TRACE_ANY(csa, wrt_blocked); + if (ANTICIPATORY_FREEZE_AVAILABLE) + POP_GV_CUR_REGION(sav_cur_region, sav_cs_addrs, sav_cs_data) return err_status; } csa->in_wtstart = TRUE; /* Tell ourselves we're here and make the csa->in_wtstart (private copy) */ @@ -179,34 +191,34 @@ int4 wcs_wtstart(gd_region *region, int4 writes) cr_hi = cr_lo + csd->n_bts; } else { - ahead = &csa->acc_meth.mm.mmblk_state->mmblkq_active; - if (cnl->mm_extender_pid == process_id) - max_writes = max_ent; /* allow file extender or rundown to write everything out */ - DEBUG_ONLY(cr_lo = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets)); - DEBUG_ONLY(cr_hi = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets + csd->n_bts)); + queue_empty = TRUE; + n1 = 1; /* set to a non-zero value so dbsync timer canceling (if needed) can happen */ + goto writes_completed; /* to avoid unnecessary IF checks in the more common case (BG) */ } assert(((sm_long_t)ahead & 7) == 0); queue_empty = FALSE; csa->wbuf_dqd++; /* Tell rundown we have an orphaned block in case of interrupt */ - for (n1 = n2 = 0, csrfirst = NULL; n1 < max_ent && n2 < max_writes && !csd->wc_blocked ; ++n1) - { - csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)ahead); - if (INTERLOCK_FAIL == (INTPTR_T)csr) + was_crit = csa->now_crit; + for (n1 = n2 = 0, csrfirst = NULL; (n1 < max_ent) && (n2 < max_writes) && !cnl->wc_blocked; ++n1) + { /* If not-crit, avoid REMQHI by peeking at the active queue and if it is found to have a 0 fl link, assume + * there is nothing to flush and break out of the loop. This avoids unnecessary interlock usage (GTM-7635). + * If holding crit, we cannot safely avoid the REMQHI so interlock usage is avoided only in the no-crit case. + */ + if (!was_crit && (0 == ahead->fl)) + csr = NULL; + else { - assert(FALSE); - SET_TRACEABLE_VAR(csd->wc_blocked, TRUE); - BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail1); - break; + csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)ahead); + if (INTERLOCK_FAIL == (INTPTR_T)csr) + { + assert(FALSE); + SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE); + BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail1); + break; + } } if (NULL == csr) - { - NO_MSYNC_ONLY( - /* NO_MSYNC doesn't sync db, make sure it syncs the journal file */ - if (is_mm) - queue_empty = TRUE; - ) break; /* the queue is empty */ - } if (csr == csrfirst) { /* completed a tour of the queue */ queue_empty = FALSE; @@ -258,10 +270,11 @@ int4 wcs_wtstart(gd_region *region, int4 writes) jb->fsync_dskaddr = saved_dsk_addr; } else { - if (-1 == fsync(jpc->channel)) + GTM_JNL_FSYNC(csa, jpc->channel, rc); + if (-1 == rc) { assert(FALSE); - send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), errno); RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch); REINSERT_CR_AT_TAIL(csr, ahead, n, csa, csd, wcb_wtstart_lckfail3); @@ -298,14 +311,10 @@ int4 wcs_wtstart(gd_region *region, int4 writes) assert(((blk_hdr_ptr_t)bp)->bver); /* GDSV4 (0) version uses this field as a block length so should always be > 0 */ if (IS_GDS_BLK_DOWNGRADE_NEEDED(csr->ondsk_blkver)) - { /* Need to downgrade/reformat this block back to a previous format. */ - assert(0 <= fast_lock_count); - ++fast_lock_count; /* do not allow interrupts to use reformat buffer until we are done */ - /* reformat_buffer_in_use should always be incremented only AFTER incrementing - * fast_lock_count as it is the latter that prevents interrupts from using the - * reformat buffer. Similarly the decrement of fast_lock_count should be done - * AFTER decrementing reformat_buffer_in_use. + { /* Need to downgrade/reformat this block back to a previous format. But, first defer timer + * or external interrupts from using the reformat buffer while we are modifying it. */ + DEFER_INTERRUPTS(INTRPT_IN_REFORMAT_BUFFER_USE); assert(0 == reformat_buffer_in_use); DEBUG_ONLY(reformat_buffer_in_use++;) DEBUG_DYNGRD_ONLY(PRINTF("WCS_WTSTART: Block %d being dynamically downgraded on write\n", \ @@ -314,7 +323,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes) { /* Buffer not big enough (or does not exist) .. get a new one releasing * old if it exists */ - assert(1 == fast_lock_count); /* should not be in a nested free/malloc */ + assert(0 == gtmMallocDepth); /* should not be in a nested free/malloc */ if (reformat_buffer) free(reformat_buffer); /* Different blksized databases in use .. keep only largest one */ @@ -324,7 +333,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes) gds_blk_downgrade((v15_blk_hdr_ptr_t)reformat_buffer, (blk_hdr_ptr_t)bp); bp = (blk_hdr_ptr_t)reformat_buffer; size = (((v15_blk_hdr_ptr_t)bp)->bsiz + 1) & ~1; - } else DEBUG_ONLY(if (GDSV5 == csr->ondsk_blkver)) + } else DEBUG_ONLY(if (GDSV6 == csr->ondsk_blkver)) size = (bp->bsiz + 1) & ~1; DEBUG_ONLY(else GTMASSERT); if (csa->do_fullblockwrites) @@ -341,66 +350,39 @@ int4 wcs_wtstart(gd_region *region, int4 writes) save_bp = (blk_hdr_ptr_t) GDS_ANY_ENCRYPTGLOBUF(bp, csa); DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csd, (sm_uc_ptr_t)save_bp); assert((bp->bsiz <= csd->blk_size) && (bp->bsiz >= SIZEOF(*bp))); - req_enc_blk_size = MIN(csd->blk_size, bp->bsiz) - SIZEOF(*bp); - if (BLK_NEEDS_ENCRYPTION(bp->levl, req_enc_blk_size)) + in_len = MIN(csd->blk_size, bp->bsiz) - SIZEOF(*bp); + if (BLK_NEEDS_ENCRYPTION(bp->levl, in_len)) { ASSERT_ENCRYPTION_INITIALIZED; memcpy(save_bp, bp, SIZEOF(blk_hdr)); - GTMCRYPT_ENCODE_FAST(csa->encr_key_handle, - (char *)(bp + 1), - req_enc_blk_size, - (char *)(save_bp + 1), - crypt_status); - if (0 != crypt_status) - save_errno = crypt_status; + in = (char *)(bp + 1); + out = (char *)(save_bp + 1); + GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, in, in_len, out, gtmcrypt_errno); + save_errno = gtmcrypt_errno; } else memcpy(save_bp, bp, bp->bsiz); } # endif if (0 == save_errno) - { /* Do db write without timer protect (no need since wtstart not reenterable in one task) */ - LSEEKWRITE(udi->fd, offset, save_bp, size, save_errno); - if ((blk_hdr_ptr_t)reformat_buffer == bp) - { - DEBUG_ONLY(reformat_buffer_in_use--;) - assert(0 == reformat_buffer_in_use); - /* allow interrupts now that we are done using the reformat buffer */ - --fast_lock_count; - assert(0 <= fast_lock_count); - } + { /* Due to csa->in_wtstart protection (at the beginning of this module), we are guaranteed + * that the write below won't be interrupted by another nested wcs_wtstart + */ + DB_LSEEKWRITE(csa, udi->fn, udi->fd, offset, save_bp, size, save_errno); } - } else - { -# if defined(TARGETED_MSYNC) - bp = (blk_hdr_ptr_t)(csa->db_addrs[0] + (sm_off_t)csr->blk * MSYNC_ADDR_INCS); - if ((sm_uc_ptr_t)bp > csa->db_addrs[1]) - save_errno = ERR_GBLOFLOW; - else + if ((blk_hdr_ptr_t)reformat_buffer == bp) { - size = MSYNC_ADDR_INCS; - save_errno = 0; /* Assume all will work well */ - if (-1 == msync((caddr_t)bp, MSYNC_ADDR_INCS, MS_ASYNC)) - save_errno = errno; + assert(INTRPT_OK_TO_INTERRUPT != intrpt_ok_state); + DEBUG_ONLY(reformat_buffer_in_use--;) + assert(0 == reformat_buffer_in_use); + /* allow interrupts now that we are done using the reformat buffer */ + ENABLE_INTERRUPTS(INTRPT_IN_REFORMAT_BUFFER_USE); } -# elif !defined(NO_MSYNC) - bp = (blk_hdr_ptr_t)(csa->acc_meth.mm.base_addr + (sm_off_t)csr->blk * csd->blk_size); - if ((sm_uc_ptr_t)bp > csa->db_addrs[1]) - save_errno = ERR_GBLOFLOW; - else - { - size = bp->bsiz; - if (csa->do_fullblockwrites) - size = ROUND_UP(size, csa->fullblockwrite_len); - assert(size <= csd->blk_size); - offset = (off_t)((sm_uc_ptr_t)bp - (sm_uc_ptr_t)csd); - INCR_DB_CSH_COUNTER(csa, n_dsk_writes, 1); - /* Do db write without timer protect (not needed -- wtstart not reenterable in one task) */ - LSEEKWRITE(udi->fd, offset, bp, size, save_errno); - } -# endif } + /* Trigger I/O error if white box test case is turned on */ + GTM_WHITE_BOX_TEST(WBTEST_WCS_WTSTART_IOERR, save_errno, ENOENT); if (0 != save_errno) { + assert(ERR_ENOSPCQIODEFER != save_errno || !csa->now_crit); if (!is_mm) /* before releasing update lock, clear epid as well in case of bg */ csr->epid = 0; CLEAR_BUFF_UPDATE_LOCK(csr, &cnl->db_latch); @@ -408,19 +390,52 @@ int4 wcs_wtstart(gd_region *region, int4 writes) /* note: this will be automatically retried after csd->flush_time[0] msec, if this was called * through a timer-pop, otherwise, error should be handled (including ignored) by the caller. */ - if ((ENOSPC == save_errno) && (dskspace_msg_counter != save_dskspace_msg_counter)) - { /* first time and every minute */ - send_msg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during flush write"), save_errno); - if (!IS_GTM_IMAGE) - gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region), - ERR_TEXT, 2, RTS_ERROR_TEXT("Error during flush write"), save_errno); - save_dskspace_msg_counter = dskspace_msg_counter; - start_timer((TID)&dskspace_msg_timer, DSKSPACE_MSG_INTERVAL, dskspace_msg_timer, 0, NULL); + if (ENOSPC == save_errno) + { + if (dskspace_msg_counter != save_dskspace_msg_counter) + { /* Report ENOSPC errors for first time and every minute after that. While this + * approach reduces the number of times ENOSPC is issued by every process, it still + * allows for flooding the syslog with ENOSPC messages if there are a lot of + * concurrent processes encountering ENOSPC errors. We should consider using a + * scheme like what is used limiting non-ENOSPC errors (see below) or MUTEXLCKALERT + * (see mutex.c) + * Also, may be DBFILERR should be replaced with DBIOERR for specificity. + */ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region), + ERR_TEXT, 2, RTS_ERROR_TEXT("Error during flush write"), save_errno); + if (!IS_GTM_IMAGE) + { + gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, + DB_LEN_STR(region), ERR_TEXT, 2, + RTS_ERROR_TEXT("Error during flush write"), save_errno); + } + save_dskspace_msg_counter = dskspace_msg_counter; + start_timer((TID)&dskspace_msg_timer, DSKSPACE_MSG_INTERVAL, dskspace_msg_timer, 0, + NULL); + } + } else if(ERR_ENOSPCQIODEFER != save_errno) + { + cnl->wtstart_errcnt++; + if (1 == (cnl->wtstart_errcnt % DBIOERR_LOGGING_PERIOD)) + { /* Every 100th failed attempt, issue an operator log indicating an I/O error. + * wcs_wtstart is typically invoked during periodic flush timeout and since there + * cannot be more than 2 pending flush timers per region, number of concurrent + * processes issuing the below send_msg should be relatively small even if there + * are 1000s of processes. + */ + send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(region), + DB_LEN_STR(region), save_errno); + } } + /* if (ERR_ENOSPCQIODEFER == save_errno): DB_LSEEKWRITE above encountered ENOSPC but couldn't + * trigger a freeze as it did not hold crit. It is okay to return as this is not a critical + * write. Eventually, some crit holding process will trigger a freeze and wait for space to be freed + * up. + */ err_status = save_errno; break; } + cnl->wtstart_errcnt = 0; /* Discard any previously noted I/O errors */ ++n2; BG_TRACE_ANY(csa, wrt_count); /* Detect whether queue has become empty. Defer action (calling wcs_clean_dbsync) @@ -444,6 +459,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes) } } csa->wbuf_dqd--; +writes_completed: DEBUG_ONLY( if (0 == n2) BG_TRACE_ANY(csa, wrt_noblks_wrtn); @@ -459,23 +475,23 @@ int4 wcs_wtstart(gd_region *region, int4 writes) } DECR_CNT(&cnl->in_wtstart, &cnl->wc_var_lock); CLEAR_WTSTART_PID(cnl, index); - /* do not allow interrupts (particularly dbsync timer) in this two-line window (C9J06-003139) */ - assert(0 <= fast_lock_count); - ++fast_lock_count; + /* Defer interrupts to protect the decrement of cnl->intent_wtstart and potential addition of a new dbsync timer */ + DEFER_INTERRUPTS(INTRPT_IN_WCS_WTSTART); csa->in_wtstart = FALSE; /* This process can write again */ DECR_INTENT_WTSTART(cnl); - --fast_lock_count; - assert(0 <= fast_lock_count); - GTMCRYPT_ONLY( - if (0 != crypt_status) - { /* Now that we have done all cleanup (reinserted the cache-record that failed the write and cleared - * cnl->in_wtstart and cnl->intent_wtstart, go ahead and issue the error. - */ - GC_RTS_ERROR(crypt_status, region->dyn.addr->fname); - } - ) - DEFERRED_EXIT_HANDLING_CHECK; /* now that in_wtstart is FALSE, check if deferred signal/exit handling needs to be done */ if (queue_empty) /* Active queue has become empty. */ wcs_clean_dbsync_timer(csa); /* Start a timer to flush-filehdr (and write epoch if before-imaging) */ + ENABLE_INTERRUPTS(INTRPT_IN_WCS_WTSTART); +# ifdef GTM_CRYPT + if (0 != gtmcrypt_errno) + { /* Now that we have done all cleanup (reinserted the cache-record that failed the write and cleared cnl->in_wtstart + * and cnl->intent_wtstart, go ahead and issue the error. + */ + seg = region->dyn.addr; + GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); + } +# endif + if (ANTICIPATORY_FREEZE_AVAILABLE) + POP_GV_CUR_REGION(sav_cur_region, sav_cs_addrs, sav_cs_data) return err_status; } diff --git a/sr_unix/zlmov_lnames.c b/sr_unix/zlmov_lnames.c index 4f9ff45..12e4ce0 100644 --- a/sr_unix/zlmov_lnames.c +++ b/sr_unix/zlmov_lnames.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2007 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -10,7 +10,7 @@ ****************************************************************/ #include "mdef.h" -#include +#include "gtm_string.h" #include #ifdef USHBIN_SUPPORTED @@ -31,11 +31,10 @@ void zlmov_lnames(rhdtyp *hdr) size += lab_ent->lab_name.len; } lab_ptr = (char *)malloc(size); - /* Store the pointer to malloc'd area in literal_text_adr so it can be accessable from the routine header. - * Although we do not need this pointer, it is kept in literal_text_adr which otherwise anyway becomes - * dangling after ptext_adr is released */ - hdr->literal_text_adr = (unsigned char *)lab_ptr; - hdr->literal_text_len = size; + /* Previously, we would store the pointer to this malloc'd area in literal_text_adr so it could be accessable from the + * routine header. However, we never use the field (e.g., to free it), so there's no point in saving it. With dynamic + * literals, we still need literal_text_adr, so let's not do that. + */ for (lab_ent = lab_bot + 1; lab_ent < lab_top; lab_ent++) { memcpy(lab_ptr, lab_ent->lab_name.addr, lab_ent->lab_name.len); diff --git a/sr_unix/zshow_devices.c b/sr_unix/zshow_devices.c index dcf94bf..987a9c1 100644 --- a/sr_unix/zshow_devices.c +++ b/sr_unix/zshow_devices.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -35,13 +35,6 @@ #include <_Ccsid.h> #endif -LITREF mstr chset_names[]; -LITREF nametabent dev_param_names[]; -LITREF unsigned char dev_param_index[]; -LITREF zshow_index zshow_param_index[]; - -static readonly char space_text[] = {' '}; - #define ZS_ONE_OUT(V,TEXT) ((V)->str.len = 1, (V)->str.addr = (TEXT), zshow_output(output,&(V)->str)) #define ZS_STR_OUT(V,TEXT) ((V)->str.len = SIZEOF((TEXT)) - 1, (V)->str.addr = (TEXT), zshow_output(output,&(V)->str)) #define ZS_VAR_STR_OUT(V,TEXT) ((V)->str.len = STRLEN((TEXT)), (V)->str.addr = (TEXT), zshow_output(output,&(V)->str)) @@ -54,6 +47,12 @@ static readonly char space_text[] = {' '}; (V)->str.addr = (char *)dev_param_names[dev_param_index[zshow_param_index[(TEXT)].letter] + \ zshow_param_index[(TEXT)].offset ].name, zshow_output(output,&(V)->str), ZS_ONE_OUT((V),equal_text)) +static readonly char space_text[] = {' '}; + +LITREF mstr chset_names[]; +LITREF nametabent dev_param_names[]; +LITREF unsigned char dev_param_index[]; +LITREF zshow_index zshow_param_index[]; GBLREF bool ctrlc_on; GBLREF io_log_name *io_root_log_name; GBLREF io_pair *io_std_device; @@ -270,6 +269,8 @@ void zshow_devices(zshow_out *output) 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) @@ -313,7 +314,13 @@ void zshow_devices(zshow_out *output) 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_PARM_SP(&v, zshow_follow); + } + } else { ZS_STR_OUT(&v,pipe_text); @@ -590,15 +597,22 @@ void zshow_devices(zshow_out *output) } else { ZS_STR_OUT(&v, remote_text); - v.str.addr = socketptr->remote.saddr_ip; - v.str.len = STRLEN(socketptr->remote.saddr_ip); + 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); 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 (socketptr->local.saddr_ip[0]) + if (NULL != socketptr->local.saddr_ip) { ZS_STR_OUT(&v, local_text); v.str.addr = socketptr->local.saddr_ip; diff --git a/sr_unix_cm/gtcm.h b/sr_unix_cm/gtcm.h index a0f689d..9555675 100644 --- a/sr_unix_cm/gtcm.h +++ b/sr_unix_cm/gtcm.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2005 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 file for the GTCM server. * - * $Header:$ + * $Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm.h,v 1.7 2013/10/23 03:49:31 tuskentower Exp $ * */ @@ -52,7 +52,7 @@ int gtcm_dmpstat P((int)); void gtcm_rep_err P((char *, int)); int omi_srvc_xact P((omi_conn *)); int rc_srvc_xact P((omi_conn *, char *)); -char *gtcm_hname P((struct sockaddr_in *)); +char *gtcm_hname P((struct addrinfo *)); void gtcm_cpktdmp P((char *, int, char *)); void gtcm_pktdmp P((char *, int, char *)); void init_hist P((void)); diff --git a/sr_unix_cm/gtcm_bgn_net.c b/sr_unix_cm/gtcm_bgn_net.c index bbb6f30..d51a675 100644 --- a/sr_unix_cm/gtcm_bgn_net.c +++ b/sr_unix_cm/gtcm_bgn_net.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,10 +17,11 @@ #include "gtm_stdlib.h" #include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */ -#include "gtm_time.h" /* for ctime() and time() */ +#include "gtm_time.h" /* for GTM_CTIME() and GTM_TIME() */ +#include "gtm_string.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_bgn_net.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include @@ -30,6 +31,9 @@ static char rcsid[] = "$Header:$"; #include "gtcm.h" #include "gtmio.h" +#include "gtm_socket.h" +#include "gtm_netdb.h" +#include "gtm_ipv6.h" GBLREF char *omi_service; GBLREF int rc_server_id; @@ -39,6 +43,10 @@ GBLREF int psock; GBLREF int ping_keepalive; GBLREF int omi_pid; +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_TEXT); + int gtcm_bgn_net(omi_conn_ll *cll) { extern int4 omi_nxact, omi_nerrs, omi_brecv, omi_bsent; @@ -49,10 +57,12 @@ int gtcm_bgn_net(omi_conn_ll *cll) #ifdef NET_TCP struct servent *se; unsigned short port; + char port_buffer[NI_MAXSERV]; #endif /* defined(NET_TCP) */ #ifdef BSD_TCP - struct sockaddr_in sin; - int on = 1; + struct addrinfo *ai_ptr, hints; + const boolean_t reuseaddr = TRUE; + int errcode; #else /* defined(BSD_TCP) */ #ifdef SYSV_TCP struct t_bind *bind; @@ -75,54 +85,52 @@ int gtcm_bgn_net(omi_conn_ll *cll) if (!omi_service) omi_service = SRVC_NAME; #ifdef NET_TCP -/* If not specified, we ask the system for any port */ - if (!omi_service) - port = htons(0); -/* Ask for a specific port */ - else - { - if (ISDIGIT_ASCII(*omi_service)) - port = atoi(omi_service); - else - { - se = getservbyname(omi_service, "tcp"); - endservent(); - if (!se) - { - OMI_DBG((omi_debug, "%s: Service \"%s\" not found in /etc/services.\n", SRVR_NAME, omi_service)); - return -1; - } - port = htons(se->s_port); - } - } + /* NET_TCP is defined only when BSD_TCP is defined or SYSV_TCP is defined, but SYSV_TCP is never defined (a bug?) + * so we move the code of obtaining port information from service down to #ifdef BSD_TCP + */ +#ifdef SYSV_TCP + GTMASSERT; +#endif #endif /* defined(NET_TCP) */ #ifdef BSD_TCP - /* Create a socket */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + /* Create a socket always tries IPv6 first */ + SERVER_HINTS(hints, ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET)); + if ((fd = socket(hints.ai_family, SOCK_STREAM, 0)) < 0) { - save_errno = errno; - return save_errno; - } - /* Reuse a specified address */ - if (port && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, SIZEOF(on)) < 0) - { - save_errno = errno; - CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */ - return save_errno; - } - /* the system should periodically check to see if the connections are live */ - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, SIZEOF(on)) < 0) - { - save_errno = errno; - perror("setsockopt:"); - CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */ - return save_errno; + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + save_errno = errno; + return save_errno; + } + hints.ai_family = AF_INET; } /* Bind an address to the socket */ - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons(port); - if (bind(fd, (struct sockaddr *)&sin, SIZEOF(sin)) < 0) + if (0 != (errcode = getaddrinfo(NULL, omi_service, &hints, &ai_ptr))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); + return errcode; + } + if (ISDIGIT_ASCII(*omi_service)) + port = atoi(omi_service); + else + { + if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, NULL, 0, port_buffer, + NI_MAXSERV, NI_NUMERICSERV))) + { + assert(FALSE); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return errcode; + } + port = atoi(port_buffer); + } + /* Reuse a specified address */ + if (port && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuseaddr, SIZEOF(reuseaddr)) < 0) + { + save_errno = errno; + CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */ + return save_errno; + } + if (bind(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen) < 0) { save_errno = errno; CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */ @@ -154,6 +162,7 @@ int gtcm_bgn_net(omi_conn_ll *cll) return 0; #else /* defined(BSD_TCP) */ #ifdef SYSV_TCP + GTMASSERT; if ((fd = t_open(SYSV_TCP, O_RDWR, NULL)) < 0) { save_errno = errno; diff --git a/sr_unix_cm/gtcm_cn_acpt.c b/sr_unix_cm/gtcm_cn_acpt.c index 2e71e7d..7a6ae66 100644 --- a/sr_unix_cm/gtcm_cn_acpt.c +++ b/sr_unix_cm/gtcm_cn_acpt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,20 +21,21 @@ #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */ -#include "gtm_time.h" /* for ctime() and time() */ +#include "gtm_time.h" /* for ctime and time */ #include "gtcm.h" #include "rc_oflow.h" #include "eintr_wrappers.h" #include "gtm_socket.h" #include "gtmio.h" +#include "have_crit.h" #ifdef BSD_TCP #include "gtm_inet.h" #endif /* defined(BSD_TCP) */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_cn_acpt.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLREF char *omi_pklog; @@ -47,15 +48,17 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds omi_conn *cptr; omi_fd fd; int rc; + char *tmp_time; #ifdef BSD_TCP - GTM_SOCKLEN_TYPE sln; - struct sockaddr_in sin; - int option, optsize; + GTM_SOCKLEN_TYPE sln; + struct sockaddr_storage sas; + int optsize; + const boolean_t keepalive = TRUE; /* Accept the connection from the network layer */ - sln = SIZEOF(sin); - if ((fd = accept(cll->nve, (struct sockaddr *)&sin, (GTM_SOCKLEN_TYPE *)&sln)) < 0) + sln = SIZEOF(sas); + if ((fd = accept(cll->nve, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sln)) < 0) return -1; #endif /* defined(BSD_TCP) */ @@ -83,7 +86,9 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds memset(cptr->of, 0, SIZEOF(struct rc_oflow)); cptr->pklog = FD_INVALID; /* Initialize the statistics */ - memcpy(&cptr->stats.sin,&sin,SIZEOF(sin)); + memcpy(&cptr->stats.sas, &sas, sln); + cptr->stats.ai.ai_addr = (struct sockaddr *)&cptr->stats.sas; + cptr->stats.ai.ai_addrlen = sln; cptr->stats.bytes_recv = 0; cptr->stats.bytes_send = 0; cptr->stats.start = time((time_t *)0); @@ -99,7 +104,7 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds for (prev = NULL, this = cll->head; this; prev = this, this = this->next) { - if (this->stats.sin.sin_addr.s_addr == sin.sin_addr.s_addr) + if (0 == memcmp((sockaddr_ptr)(&this->stats.sas), (sockaddr_ptr)&sas, sln)) { if (cll->tail == this) cll->tail = cptr; @@ -110,7 +115,7 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds cptr->next = this->next; OMI_DBG_STMP; OMI_DBG((omi_debug, "%s: dropping old connection to %s\n", - SRVR_NAME, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, gtcm_hname(&cptr->stats.ai))); gtcm_cn_disc(this, cll); break; } @@ -153,10 +158,10 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds } } ) + GTM_CTIME(tmp_time, &cptr->stats.start); OMI_DBG((omi_debug, "%s: connection %d from %s by user <%s> at %s", SRVR_NAME, - cptr->stats.id, gtcm_hname(&cptr->stats.sin), cptr->ag_name, GTM_CTIME(&cptr->stats.start))); - option = -1; - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&option, SIZEOF(option)) < 0) + cptr->stats.id, gtcm_hname(&cptr->stats.ai), cptr->ag_name, tmp_time)); + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, SIZEOF(keepalive)) < 0) { PERROR("setsockopt:"); return -1; diff --git a/sr_unix_cm/gtcm_cn_disc.c b/sr_unix_cm/gtcm_cn_disc.c index 4b10b09..88f6f30 100644 --- a/sr_unix_cm/gtcm_cn_disc.c +++ b/sr_unix_cm/gtcm_cn_disc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,14 +17,14 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_cn_disc.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" #include "gtm_stdio.h" #include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */ -#include "gtm_time.h" /* for ctime() and time() */ +#include "gtm_time.h" /* for GTM_CTIME() and GTM_TIME() */ #include "gtcm.h" #include "gtmio.h" @@ -59,7 +59,7 @@ void gtcm_cn_disc(omi_conn *cptr, omi_conn_ll *cll) cll->stats.clos++; OMI_DBG_STMP; OMI_DBG((omi_debug, "%s: connection %d to %s closed\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); OMI_DBG((omi_debug, "%s:\t%ld seconds connect time\n", SRVR_NAME, end - cptr->stats.start)); OMI_DBG((omi_debug, "%s:\t%d transactions\n", SRVR_NAME, nxact)); OMI_DBG((omi_debug, "%s:\t%d errors\n", SRVR_NAME, nerrs)); diff --git a/sr_unix_cm/gtcm_dmpstat.c b/sr_unix_cm/gtcm_dmpstat.c index 26cd963..93e1a74 100644 --- a/sr_unix_cm/gtcm_dmpstat.c +++ b/sr_unix_cm/gtcm_dmpstat.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_dmpstat.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" @@ -51,6 +51,7 @@ int gtcm_dmpstat(int sig) time_t uptime, uphours, upmins, upsecs; time_t itime, ihours, imins, isecs; int status; + char *tmp_time; #ifdef __MVS__ int tag_status; @@ -70,8 +71,9 @@ int gtcm_dmpstat(int sig) imins = (itime % 3600) / 60; isecs = itime % 60; - FPRINTF(fp, "%s", GTM_CTIME(&t)); - OMI_DBG((omi_debug, "%s", GTM_CTIME(&t))); + GTM_CTIME(tmp_time, &t); + FPRINTF(fp, "%s", tmp_time); + OMI_DBG((omi_debug, "%s", tmp_time)); FPRINTF(fp, "%d\n", omi_pid); OMI_DBG((omi_debug, "%d\n", omi_pid)); FPRINTF(fp, "Up time: %ld:%.2ld:%.2ld\n",uphours,upmins,upsecs); diff --git a/sr_unix_cm/gtcm_end_net.c b/sr_unix_cm/gtcm_end_net.c index 95c2248..86d7aa2 100644 --- a/sr_unix_cm/gtcm_end_net.c +++ b/sr_unix_cm/gtcm_end_net.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_end_net.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/gtcm_exit.c b/sr_unix_cm/gtcm_exit.c index 134c35a..913a84b 100644 --- a/sr_unix_cm/gtcm_exit.c +++ b/sr_unix_cm/gtcm_exit.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_exit.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/gtcm_exit_ch.c b/sr_unix_cm/gtcm_exit_ch.c index e826c48..8486e6e 100644 --- a/sr_unix_cm/gtcm_exit_ch.c +++ b/sr_unix_cm/gtcm_exit_ch.c @@ -23,7 +23,7 @@ #include "util.h" /* for util_out_print() prototype */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_exit_ch.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLREF int4 gtcm_exi_condition; diff --git a/sr_unix_cm/gtcm_hist.c b/sr_unix_cm/gtcm_hist.c index 0632ac3..c26e423 100644 --- a/sr_unix_cm/gtcm_hist.c +++ b/sr_unix_cm/gtcm_hist.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,6 +20,7 @@ #include "gtm_string.h" #include "gtm_stdio.h" /* for SPRINTF() atleast */ #include "gtm_time.h" +#include "have_crit.h" #include #include "gtcm.h" @@ -115,9 +116,10 @@ void save_rc_rsp(char *buff, int len) void dump_omi_rq(void) { char msg[256]; - char *then = GTM_CTIME(&omi_hist[omi_hist_num].timestamp); + char *then; omi_conn *temp; + GTM_CTIME(then, &omi_hist[omi_hist_num].timestamp); then[24] = '\0'; if (omi_hist_num < 0) /* no history? */ return; @@ -131,18 +133,19 @@ void dump_omi_rq(void) void dump_rc_hist(void) { - int i; + int i; + char msg[256]; + char *then; if (rc_hist_num < 0) /* no history? */ return; i = rc_hist_num; do { - i = (i+1) % HISTORY; + i = (i + 1) % HISTORY; if (rc_hist[i].timestamp) { - char msg[256]; - char *then = GTM_CTIME(&rc_hist[i].timestamp); + GTM_CTIME(then, &rc_hist[i].timestamp); then[24] = '\0'; /* eliminate newline */ if (rc_hist[i].toobigflag) { diff --git a/sr_unix_cm/gtcm_init.c b/sr_unix_cm/gtcm_init.c index 3b58aed..84c2964 100644 --- a/sr_unix_cm/gtcm_init.c +++ b/sr_unix_cm/gtcm_init.c @@ -31,7 +31,6 @@ #include "stp_parms.h" #include "patcode.h" #include "error.h" -#include "gtmimagename.h" #include "stringpool.h" #include "gdsroot.h" #include "gtm_facility.h" @@ -53,18 +52,17 @@ #include "hashtab_int4.h" #include "tp.h" #include "init_secshr_addrs.h" -#include "gtm_imagetype_init.h" #include "fork_init.h" #include "gtmio.h" #include "have_crit.h" - +#include "gt_timers_add_safe_hndlrs.h" #ifdef UNICODE_SUPPORTED -#include "gtm_icu_api.h" -#include "gtm_utf8.h" +# include "gtm_icu_api.h" +# include "gtm_utf8.h" #endif #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_init.c,v 1.10 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLDEF CLI_ENTRY *cmd_ary = NULL; /* The GTCM server does not have any command tables so initialize command array to NULL */ @@ -100,10 +98,8 @@ void gtcm_init(int argc, char_ptr_t argv[]) /* Disassociate from the rest of the universe */ get_page_size(); - gtm_imagetype_init(GTCM_SERVER_IMAGE); gtm_wcswidth_fnptr = gtm_wcswidth; - -#ifndef GTCM_DEBUG_NOBACKGROUND +# ifndef GTCM_DEBUG_NOBACKGROUND FORK_CLEAN(pid); if (0 > pid) { @@ -115,17 +111,14 @@ void gtcm_init(int argc, char_ptr_t argv[]) else if (0 < pid) exit(0); (void) setpgrp(); -#endif +# endif /* Initialize logging */ - omi_pid = getpid(); - /* Initialize signals */ sigemptyset(&act.sa_mask); act.sa_flags = 0; ignore = act; ignore.sa_handler = SIG_IGN; - act.sa_handler = (void (*)()) gtcm_term; (void) sigaction(SIGTERM, &act, 0); act.sa_handler = (void (*)()) gtcm_dmpstat; @@ -135,7 +128,7 @@ void gtcm_init(int argc, char_ptr_t argv[]) (void) sigaction(SIGALRM, &ignore, 0); (void) sigaction(SIGPIPE, &ignore, 0); (void) sigaction(SIGINT, &ignore, 0); -#ifdef GTCM_RC +# ifdef GTCM_RC act.sa_handler = gtcm_fail; act.sa_flags = SA_RESETHAND; /* restore signal handler to default action upon receipt @@ -145,19 +138,16 @@ void gtcm_init(int argc, char_ptr_t argv[]) (void) sigaction(SIGILL, &act, 0); (void) sigaction(SIGTRAP, &act, 0); (void) sigaction(SIGABRT, &act, 0); -#ifndef __linux__ +# ifndef __linux__ (void) sigaction(SIGEMT, &act, 0); (void) sigaction(SIGSYS, &act, 0); -#endif -#endif - +# endif +# endif /* Initialize the process flags */ if (0 != gtcm_prsopt(argc, argv)) exit(-1); - /* Write down pid into log file */ OMI_DBG((omi_debug, "GTCM_SERVER pid : %d\n", omi_pid)); - /* Initialize history mechanism */ if (history) { @@ -166,7 +156,6 @@ void gtcm_init(int argc, char_ptr_t argv[]) act.sa_flags = 0; (void) sigaction(SIGUSR2, &act, 0); } - /* Initialize the DBMS */ licensed = TRUE; getjobnum(); @@ -184,10 +173,9 @@ void gtcm_init(int argc, char_ptr_t argv[]) pattern_typemask = mumps_pattern.typemask; INVOKE_INIT_SECSHR_ADDRS; initialize_pattern_table(); - - /* Preallocate some timer blocks. */ - prealloc_gt_timers(); - + /* Preallocate some timer blocks. */ + prealloc_gt_timers(); + gt_timers_add_safe_hndlrs(); /* Moved to omi_gvextnam, omi_lkextnam */ /* gvinit(); */ return; diff --git a/sr_unix_cm/gtcm_loop.c b/sr_unix_cm/gtcm_loop.c index 8666796..f1f1a79 100644 --- a/sr_unix_cm/gtcm_loop.c +++ b/sr_unix_cm/gtcm_loop.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -46,9 +46,11 @@ #include "error.h" #include "gtmio.h" #include "have_crit.h" +#include "gtm_time.h" +#include "fork_init.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_loop.c,v 1.8 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLREF int psock; @@ -240,7 +242,7 @@ void gcore_server(void) dump_rc_hist(); } - pid=fork(); /* BYPASSOK: we are dumping a core, so no FORK_CLEAN needed */ + FORK(pid); /* BYPASSOK: we are dumping a core, so no FORK_CLEAN needed */ if (pid < 0) /* fork error */ { OMI_DBG((omi_debug, diff --git a/sr_unix_cm/gtcm_main.c b/sr_unix_cm/gtcm_main.c index 03d296b..c7659ac 100644 --- a/sr_unix_cm/gtcm_main.c +++ b/sr_unix_cm/gtcm_main.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,9 +32,13 @@ #include "error.h" #include "gtm_env_init.h" /* for gtm_env_init() prototype */ #include "gtm_threadgbl_init.h" +#include "gtmimagename.h" +#include "gtm_imagetype_init.h" +#include "send_msg.h" +#include "wbox_test_init.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_main.c,v 1.8 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLDEF short gtcm_ast_avail; @@ -53,18 +57,17 @@ GBLDEF omi_conn_ll *omi_conns = (omi_conn_ll *)0; GBLDEF int omi_exitp = 0; GBLDEF int omi_pid = 0; GBLDEF int4 omi_errno = 0; -GBLDEF int4 omi_nxact = 0; /* # of transactions */ -GBLDEF int4 omi_nxact2 = 0; /* transactions since last stat - dump */ +GBLDEF int4 omi_nxact = 0; /* # of transactions */ +GBLDEF int4 omi_nxact2 = 0; /* transactions since last stat dump */ GBLDEF int4 omi_nerrs = 0; GBLDEF int4 omi_brecv = 0; GBLDEF int4 omi_bsent = 0; -GBLDEF int4 gtcm_stime = 0; /* start time for GT.CM */ -GBLDEF int4 gtcm_ltime = 0; /* last time stats were dumped */ +GBLDEF int4 gtcm_stime = 0; /* start time for GT.CM */ +GBLDEF int4 gtcm_ltime = 0; /* last time stats were dumped */ GBLDEF int one_conn_per_inaddr = -1; -GBLDEF int authenticate = 0; /* authenticate OMI connections */ -GBLDEF int psock = -1; /* pinging socket */ -GBLDEF int ping_keepalive = 0; /* check connections using ping */ +GBLDEF int authenticate = 0; /* authenticate OMI connections */ +GBLDEF int psock = -1; /* pinging socket */ +GBLDEF int ping_keepalive = 0; /* check connections using ping */ GBLDEF int conn_timeout = TIMEOUT_INTERVAL; GBLDEF int history = 0; GBLREF int rc_server_id; @@ -77,63 +80,56 @@ GBLREF int rc_server_id; */ int main(int argc, char_ptr_t argv[]) { - omi_conn_ll conns; - bool set_pset(); - int ret_val; - DCL_THREADGBL_ACCESS; + omi_conn_ll conns; + bool set_pset(); + int ret_val; + DCL_THREADGBL_ACCESS; - GTM_THREADGBL_INIT; - ctxt = NULL; - set_blocksig(); - gtm_env_init(); /* read in all environment variables before calling any function particularly malloc (from err_init below)*/ - - SPRINTF(image_id,"%s=gtcm_server", image_id); - -#ifdef SEQUOIA + GTM_THREADGBL_INIT; + ctxt = NULL; + set_blocksig(); + gtm_imagetype_init(GTCM_SERVER_IMAGE); + gtm_env_init(); /* read in all environment variables before calling any function particularly malloc (from err_init below)*/ + SPRINTF(image_id,"%s=gtcm_server", image_id); +# ifdef SEQUOIA if (!set_pset()) exit(-1); -#endif -/* Initialize everything but the network */ - err_init(gtcm_exit_ch); - omi_errno = OMI_ER_NO_ERROR; - ctxt = ctxt; - ESTABLISH_RET(omi_dbms_ch, -1); /* any return value to signify error return */ - gtcm_init(argc, argv); - gtcm_ltime = gtcm_stime = (int4)time(0); -#ifdef GTCM_RC - rc_create_cpt(); -#endif - REVERT; - - if (omi_errno != OMI_ER_NO_ERROR) - exit(omi_errno); - -/* Initialize the network interface */ - if ((ret_val = gtcm_bgn_net(&conns)) != 0) - { - gtcm_rep_err("Error initializing TCP", ret_val); - gtcm_exi_condition = ret_val; +# endif + /* Initialize everything but the network */ + err_init(gtcm_exit_ch); + omi_errno = OMI_ER_NO_ERROR; + ctxt = ctxt; + ESTABLISH_RET(omi_dbms_ch, -1); /* any return value to signify error return */ + gtcm_init(argc, argv); + gtcm_ltime = gtcm_stime = (int4)time(0); +# ifdef GTCM_RC + rc_create_cpt(); +# endif + REVERT; + if (OMI_ER_NO_ERROR != omi_errno) + exit(omi_errno); + /* Initialize the network interface */ + if (0 != (ret_val = gtcm_bgn_net(&conns))) /* Warning - assignment */ + { + gtcm_rep_err("Error initializing TCP", ret_val); + gtcm_exi_condition = ret_val; + gtcm_exit(); + } + SPRINTF(image_id,"%s(pid=%d) %s %s %s -id %d -service %s", + image_id, + omi_pid, + ( history ? "-hist" : "" ), + ( authenticate ? "-auth" : "" ), + ( ping_keepalive ? "-ping" : "" ), + rc_server_id, + omi_service + ); + OPERATOR_LOG_MSG; + omi_conns = &conns; + /* Should be forever, unless an error occurs */ + gtcm_loop(&conns); + /* Clean up */ + gtcm_end_net(&conns); gtcm_exit(); - } - - SPRINTF(image_id,"%s(pid=%d) %s %s %s -id %d -service %s", - image_id, - omi_pid, - ( history ? "-hist" : "" ), - ( authenticate ? "-auth" : "" ), - ( ping_keepalive ? "-ping" : "" ), - rc_server_id, - omi_service - ); - omi_conns = &conns; - -/* Should be forever, unless an error occurs */ - gtcm_loop(&conns); - -/* Clean up */ - gtcm_end_net(&conns); - gtcm_exit(); - - return 0; - + return 0; } diff --git a/sr_unix_cm/gtcm_ping.c b/sr_unix_cm/gtcm_ping.c index 6a365fa..e92560a 100644 --- a/sr_unix_cm/gtcm_ping.c +++ b/sr_unix_cm/gtcm_ping.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -25,11 +25,9 @@ #include "gtm_time.h" #endif #include -#include "gtm_netdb.h" #include "gtm_socket.h" -#ifndef __MVS__ -#include -#endif +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "gtm_inet.h" #ifndef __MVS__ @@ -72,6 +70,9 @@ struct icmp #endif /* __CYGWIN__ || __MVS */ #ifdef __MVS__ + +error_def(ERR_GETNAMEINFO); + struct ip { unsigned int ip_v:4; /* version */ @@ -124,8 +125,8 @@ int init_ping(void) int icmp_ping(int conn) { fd_set fdmask; - struct sockaddr_in paddr; - GTM_SOCKLEN_TYPE paddr_len = SIZEOF(struct sockaddr_in); + struct sockaddr_storage paddr; + GTM_SOCKLEN_TYPE paddr_len = SIZEOF(struct sockaddr_storage); struct icmp *icp; struct ip *ip; struct timeval timeout; @@ -163,21 +164,14 @@ int icmp_ping(int conn) } #ifdef DEBUG_PING { - char *host; + char host[SA_MAXLEN]; struct hostent *he; - char msg[64]; -#ifndef SUNOS - host = inet_ntoa(paddr.sin_addr.s_addr); - if ((he = gethostbyaddr(paddr.sin_addr.s_addr, SIZEOF(paddr.sin_addr.s_addr), 0))) - host = he->h_name; -#else - SPRINTF(msg, "%d.%d.%d.%d", - paddr.sin_addr.s_addr >> 24, - paddr.sin_addr.s_addr >> 16 & 0xFF, - paddr.sin_addr.s_addr >> 8 & 0xFF, - paddr.sin_addr.s_addr & 0xFF); - host = msg; -#endif + if (0 != (errcode = getnameinfo((struct sockaddr *)&paddr, paddr_len, host, SA_MAXLEN, NULL, 0 0))) + { + assert(FALSE); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } OMI_DBG((omi_debug, "ping: send to %s\n",host)); } #endif @@ -192,7 +186,7 @@ int icmp_ping(int conn) */ int get_ping_rsp(void) { - struct sockaddr_in from; + struct sockaddr_storage from; register int cc; GTM_SOCKLEN_TYPE fromlen; struct icmp *icp; @@ -203,6 +197,9 @@ int get_ping_rsp(void) FPRINTF(stderr,"icmp_ping: no ping socket.\n"); exit(1); } + /* SIZEOF() does not provide correct fromlen. + * fromlen in fact decided by recvfrom() below, so no need getaddrinfo() is needed to obtain the correct fromlen + */ fromlen = SIZEOF(from); while ((cc = (int)(recvfrom(pingsock, (char *)pingrcv, IP_MAXPACKET, 0, (struct sockaddr *)&from, (GTM_SOCKLEN_TYPE *)&fromlen))) < 0) @@ -217,22 +214,14 @@ int get_ping_rsp(void) /* xxxxxxx icp = (struct icmp *)(pingrcv + (ip->ip_hl << 2)); */ #ifdef DEBUG_PING { - char *host; + char host[SA_MAXLEN]; struct hostent *he; - char msg[64]; -#ifndef SUNOS - host = inet_ntoa(from.sin_addr.s_addr); - if ((he = gethostbyaddr(from.sin_addr.s_addr, - SIZEOF(from.sin_addr.s_addr), 0))) - host = he->h_name; -#else - SPRINTF(msg, "%d.%d.%d.%d", - from.sin_addr.s_addr >> 24, - from.sin_addr.s_addr >> 16 & 0xFF, - from.sin_addr.s_addr >> 8 & 0xFF, - from.sin_addr.s_addr & 0xFF); - host = msg; -#endif + if (0 != (errcode = getnameinfo((struct sockaddr *)&from, fromlen, host, SA_MAXLEN, NULL, 0 0))) + { + assert(FALSE); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return FALSE; + } OMI_DBG((omi_debug, "ping: response from %s\n",host)); } #endif diff --git a/sr_unix_cm/gtcm_pkdisp.c b/sr_unix_cm/gtcm_pkdisp.c index 84d3828..8e135cc 100644 --- a/sr_unix_cm/gtcm_pkdisp.c +++ b/sr_unix_cm/gtcm_pkdisp.c @@ -31,7 +31,7 @@ #include "omi.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_pkdisp.c,v 1.8 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLREF char *omi_oprlist[]; diff --git a/sr_unix_cm/gtcm_pktdmp.c b/sr_unix_cm/gtcm_pktdmp.c index a7b74c9..1bb8954 100644 --- a/sr_unix_cm/gtcm_pktdmp.c +++ b/sr_unix_cm/gtcm_pktdmp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -31,38 +31,34 @@ GBLREF omi_conn *curr_conn; GBLREF char *omi_service; +error_def(ERR_GETADDRINFO); +error_def(ERR_GETNAMEINFO); +error_def(ERR_TEXT); + /* return in a static buffer the ASCII representation of a network address. Returned as: "hostid (nn.nn.nn.nn)" or "nn.nn.nn.nn" depending on whether or not the host is listed in /etc/hosts. */ -char *gtcm_hname(struct sockaddr_in *sin) +char *gtcm_hname(struct addrinfo *ai_ptr) { - struct hostent *he; - static char name[256]; + static char name[NI_MAXHOST + NI_MAXSERV + 4]; + char ipname[NI_MAXSERV]; + char host[NI_MAXHOST]; + int errcode; -#ifndef SUNOS - if ((he = gethostbyaddr((void *)&sin->sin_addr.s_addr, - SIZEOF(struct in_addr), AF_INET))) - SPRINTF(name,"%s (%d.%d.%d.%d)",he->h_name, - sin->sin_addr.s_addr >> 24, - sin->sin_addr.s_addr >> 16 & 0xFF, - sin->sin_addr.s_addr >> 8 & 0xFF, - sin->sin_addr.s_addr & 0xFF); - else - SPRINTF(name,"%d.%d.%d.%d", - sin->sin_addr.s_addr >> 24, - sin->sin_addr.s_addr >> 16 & 0xFF, - sin->sin_addr.s_addr >> 8 & 0xFF, - sin->sin_addr.s_addr & 0xFF); -#else - SPRINTF(name,"%d.%d.%d.%d", - sin->sin_addr.s_addr >> 24, - sin->sin_addr.s_addr >> 16 & 0xFF, - sin->sin_addr.s_addr >> 8 & 0xFF, - sin->sin_addr.s_addr & 0xFF); -#endif - return name; + if(0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, ipname, + SIZEOF(ipname), NULL, 0, NI_NUMERICHOST))) + { + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return NULL; + } + if(0 == (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, host, SIZEOF(host), + NULL, 0, NI_NAMEREQD))) + SPRINTF(name, "%s (%s)", host, ipname); + else + SPRINTF(name, "%s", ipname); + return name; } @@ -77,7 +73,7 @@ void gtcm_cpktdmp(char *ptr, int length, char *msg) if (curr_conn && (512-strlen(msg)) > 25) { SPRINTF(newmsg,"Conn: %s - %s", - gtcm_hname(&curr_conn->stats.sin), msg); + gtcm_hname(&curr_conn->stats.ai), msg); gtcm_pktdmp(ptr, length, newmsg); } @@ -103,7 +99,7 @@ void gtcm_pktdmp(char *ptr, int length, char *msg) char *gtm_dist; ctim = time(0); - ltime = localtime(&ctim); + GTM_LOCALTIME(ltime, &ctim); SPRINTF(tbuf, "%02d%02d%02d%02d",ltime->tm_mon + 1,ltime->tm_mday, ltime->tm_hour,ltime->tm_min); diff --git a/sr_unix_cm/gtcm_play.c b/sr_unix_cm/gtcm_play.c index c663cbb..a0393cf 100644 --- a/sr_unix_cm/gtcm_play.c +++ b/sr_unix_cm/gtcm_play.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -24,7 +24,6 @@ #include "gt_timer.h" /* for set_blocksig() */ #include "gtm_fcntl.h" #include "gtm_string.h" /* for strerror() */ - #include #include #include @@ -33,14 +32,15 @@ #include "error.h" #include "gtm_env_init.h" /* for gtm_env_init() prototype */ #include "gtm_threadgbl_init.h" +#include "gtmimagename.h" +#include "gtm_imagetype_init.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_play.c,v 1.9 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLDEF short gtcm_ast_avail; GBLDEF int4 gtcm_exi_condition; - GBLDEF char *omi_service = (char *)0; GBLDEF FILE *omi_debug = (FILE *)0; GBLDEF char *omi_pklog = (char *)0; @@ -63,7 +63,6 @@ GBLDEF int psock = -1; /* pinging socket */ GBLDEF int ping_keepalive = 0; /* check connections using ping */ GBLDEF int conn_timeout = TIMEOUT_INTERVAL; GBLDEF int history = 0; - #ifdef GTCM_RC GBLREF int rc_nxact; GBLREF int rc_nerrs; @@ -77,78 +76,75 @@ GBLREF int rc_nerrs; */ int main(int argc, char_ptr_t argv[]) { - omi_conn *cptr, conn; - int i; - char buff[OMI_BUFSIZ]; - DCL_THREADGBL_ACCESS; + omi_conn *cptr, conn; + int i; + char buff[OMI_BUFSIZ]; + DCL_THREADGBL_ACCESS; - GTM_THREADGBL_INIT; - set_blocksig(); - gtm_env_init(); /* read in all environment variables before calling any function particularly malloc (from err_init below)*/ -/* Open the packet log file for playback */ - if (argc == 1) - conn.fd = fileno(stdin); - else if (argc == 2) { - if (INV_FD_P((conn.fd = open(argv[argc - 1], O_RDONLY)))) + GTM_THREADGBL_INIT; + set_blocksig(); + gtm_imagetype_init(GTCM_SERVER_IMAGE); + gtm_env_init(); /* read in all environment variables before calling any function particularly malloc (from err_init below)*/ + /* Open the packet log file for playback */ + if (1 == argc) + conn.fd = fileno(stdin); + else if (2 == argc) { - PRINTF("%s: open(\"%s\"): %s\n", argv[0], argv[argc - 1], - STRERROR(errno)); - exit(-1); + if (INV_FD_P((conn.fd = open(argv[argc - 1], O_RDONLY)))) + { + PRINTF("%s: open(\"%s\"): %s\n", argv[0], argv[argc - 1], + STRERROR(errno)); + exit(-1); + } + } else + { + PRINTF("%s: bad command line arguments\n\t%s [ filename ]\n", + argv[0], argv[0]); + exit(-1); } - } - else { - PRINTF("%s: bad command line arguments\n\t%s [ filename ]\n", - argv[0], argv[0]); - exit(-1); - } - -/* Initialize everything but the network */ - err_init(gtcm_exit_ch); - omi_errno = OMI_ER_NO_ERROR; - ESTABLISH_RET(omi_dbms_ch, -1); /* any return value to signify error return */ - gtcm_init(argc, argv); -#ifdef GTCM_RC - rc_create_cpt(); -#endif - REVERT; - if (omi_errno != OMI_ER_NO_ERROR) - exit(omi_errno); -/* Initialize the connection structure */ - conn.next = (omi_conn *)0; - conn.bsiz = OMI_BUFSIZ; - conn.bptr = conn.buff = buff; - conn.xptr = (char *)0; - conn.blen = 0; - conn.exts = 0; - conn.state = OMI_ST_DISC; - conn.ga = (ga_struct *)0; /* struct gd_addr_struct */ - conn.of = (oof_struct *)0; /* struct rc_oflow */ - conn.pklog = FD_INVALID; -/* Initialize the statistics */ - conn.stats.bytes_recv = 0; - conn.stats.bytes_send = 0; - conn.stats.start = time((time_t *)0); - for (i = 0; i < OMI_OP_MAX; i++) - conn.stats.xact[i] = 0; - for (i = 0; i < OMI_ER_MAX; i++) - conn.stats.errs[i] = 0; - - for (;;) - if (omi_srvc_xact(&conn) < 0) - break; - - PRINTF("%ld seconds connect time\n", time((time_t)0) - conn.stats.start); - PRINTF("%d OMI transactions\n", omi_nxact); - PRINTF("%d OMI errors\n", omi_nerrs); -#ifdef GTCM_RC - PRINTF("%d RC transactions\n", rc_nxact); - PRINTF("%d RC errors\n", rc_nerrs); -#endif /* defined(GTCM_RC) */ - PRINTF("%d bytes recv'd\n", conn.stats.bytes_recv); - PRINTF("%d bytes sent\n", conn.stats.bytes_send); - - gtcm_exit(); - - return 0; + /* Initialize everything but the network */ + err_init(gtcm_exit_ch); + omi_errno = OMI_ER_NO_ERROR; + ESTABLISH_RET(omi_dbms_ch, -1); /* any return value to signify error return */ + gtcm_init(argc, argv); +# ifdef GTCM_RC + rc_create_cpt(); +# endif + REVERT; + if (omi_errno != OMI_ER_NO_ERROR) + exit(omi_errno); + /* Initialize the connection structure */ + conn.next = (omi_conn *)0; + conn.bsiz = OMI_BUFSIZ; + conn.bptr = conn.buff = buff; + conn.xptr = (char *)0; + conn.blen = 0; + conn.exts = 0; + conn.state = OMI_ST_DISC; + conn.ga = (ga_struct *)0; /* struct gd_addr_struct */ + conn.of = (oof_struct *)0; /* struct rc_oflow */ + conn.pklog = FD_INVALID; + /* Initialize the statistics */ + conn.stats.bytes_recv = 0; + conn.stats.bytes_send = 0; + conn.stats.start = time((time_t *)0); + for (i = 0; i < OMI_OP_MAX; i++) + conn.stats.xact[i] = 0; + for (i = 0; i < OMI_ER_MAX; i++) + conn.stats.errs[i] = 0; + for (;;) + if (omi_srvc_xact(&conn) < 0) + break; + PRINTF("%ld seconds connect time\n", time((time_t)0) - conn.stats.start); + PRINTF("%d OMI transactions\n", omi_nxact); + PRINTF("%d OMI errors\n", omi_nerrs); +# ifdef GTCM_RC + PRINTF("%d RC transactions\n", rc_nxact); + PRINTF("%d RC errors\n", rc_nerrs); +# endif /* defined(GTCM_RC) */ + PRINTF("%d bytes recv'd\n", conn.stats.bytes_recv); + PRINTF("%d bytes sent\n", conn.stats.bytes_send); + gtcm_exit(); + return 0; } diff --git a/sr_unix_cm/gtcm_prsopt.c b/sr_unix_cm/gtcm_prsopt.c index 104c980..c37a80a 100644 --- a/sr_unix_cm/gtcm_prsopt.c +++ b/sr_unix_cm/gtcm_prsopt.c @@ -32,7 +32,7 @@ #include "gtcm.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_prsopt.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif GBLREF FILE *omi_debug; diff --git a/sr_unix_cm/gtcm_rep_err.c b/sr_unix_cm/gtcm_rep_err.c index b767e24..7224518 100644 --- a/sr_unix_cm/gtcm_rep_err.c +++ b/sr_unix_cm/gtcm_rep_err.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_rep_err.c,v 1.7 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" @@ -46,42 +46,37 @@ static char rcsid[] = "$Header:$"; #define GTM_DIST_PATH "$gtm_dist" GBLREF char *omi_service; -STATICDEF boolean_t first_syslog = TRUE; +STATICDEF boolean_t first_error = TRUE; STATICDEF char fileName[GTM_PATH_MAX]; +error_def(ERR_TEXT); +error_def(ERR_DISTPATHMAX); +ZOS_ONLY(error_def(ERR_BADTAG);) + void gtcm_rep_err(char *msg, int errcode) { FILE *fp; char outbuf[OUT_BUFF_SIZE]; time_t now; int status, retval; - char *gtm_dist, *filebuf; + char *gtm_dist, *filebuf, *tag_emsg, *tmp_time; mstr tn; - MSTR_DEF(val, strlen(GTM_DIST_PATH), GTM_DIST_PATH); - - error_def(ERR_TEXT); - error_def(ERR_DISTPATHMAX); - ZOS_ONLY(error_def(ERR_BADTAG);) - /*error_def(ERR_OMISERVHANG);*/ + MSTR_DEF(val, strlen(GTM_DIST_PATH), GTM_DIST_PATH); /* BYPASSOK */ if ('\0' == msg[0]) - sgtm_putmsg(outbuf, VARLSTCNT(2) errcode, 0); + sgtm_putmsg(outbuf, VARLSTCNT(2) errcode, 0); else - sgtm_putmsg(outbuf, VARLSTCNT(6) errcode, 0, ERR_TEXT, 2, LEN_AND_STR(msg)); - if (first_syslog) + sgtm_putmsg(outbuf, VARLSTCNT(6) errcode, 0, ERR_TEXT, 2, LEN_AND_STR(msg)); + if (first_error) { -# ifdef BSD_LOG - (void)OPENLOG("GTCM", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER); -# endif - first_syslog = FALSE; + first_error = FALSE; filebuf = fileName; status = TRANS_LOG_NAME(&val, &tn, fileName, GTM_PATH_MAX, dont_sendmsg_on_log2long); if ((SS_LOG2LONG == status) || (tn.len + strlen(GTCM_SERV_LOG) >= GTM_PATH_MAX)) { send_msg(VARLSTCNT(3) ERR_DISTPATHMAX, 1, GTM_PATH_MAX - strlen(GTCM_SERV_LOG)); exit(ERR_DISTPATHMAX); - } - else if (SS_NORMAL == status) + } else if (SS_NORMAL == status) filebuf = strcat(fileName, GTCM_SERV_LOG); else { @@ -92,20 +87,19 @@ void gtcm_rep_err(char *msg, int errcode) # ifdef __MVS__ if (-1 != gtm_zos_create_tagged_file(fileName, TAG_EBCDIC)) { - char *tag_emsg = STRERROR(errno); + tag_emsg = STRERROR(errno); sgtm_putmsg(outbuf, VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(fileName), - -1, TAG_EBCDIC, ERR_TEXT, 2, RTS_ERROR_STRING(tag_emsg)); + -1, TAG_EBCDIC, ERR_TEXT, 2, RTS_ERROR_STRING(tag_emsg)); } # endif if ((fp = Fopen(fileName, "a"))) { now = time(0); - FPRINTF(fp, "%s", GTM_CTIME(&now)); - FPRINTF(fp,"server(%s) %s", omi_service, outbuf); + GTM_CTIME(tmp_time, &now); + FPRINTF(fp, "%s", tmp_time); + FPRINTF(fp, "server(%s) %s", omi_service, outbuf); FCLOSE(fp, status); } -# ifdef BSD_LOG - SYSLOG(LOG_USER | LOG_INFO, "%s", outbuf); -# endif /* defined(BSD_LOG) */ + util_out_print(outbuf, OPER); /* Same message goes out to operator log */ return; } diff --git a/sr_unix_cm/gtcm_run.gtc b/sr_unix_cm/gtcm_run.gtc index 0a6f553..ad7c840 100644 --- a/sr_unix_cm/gtcm_run.gtc +++ b/sr_unix_cm/gtcm_run.gtc @@ -1,7 +1,7 @@ #!/bin/sh ################################################################# # # -# Copyright 2001, 2005 Fidelity Information Services, Inc # +# Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -9,7 +9,6 @@ # the license, please stop and do not read further. # # # ################################################################# -: # gtcm_run - This script is used to start an invidiaul GTCM server # Usually this is called from gtmstart script # diff --git a/sr_unix_cm/gtcm_term.c b/sr_unix_cm/gtcm_term.c index f49aa4e..c1a250c 100644 --- a/sr_unix_cm/gtcm_term.c +++ b/sr_unix_cm/gtcm_term.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/gtcm_term.c,v 1.6 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include diff --git a/sr_unix_cm/omi.h b/sr_unix_cm/omi.h index 7be7a3f..ac7e9fd 100644 --- a/sr_unix_cm/omi.h +++ b/sr_unix_cm/omi.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 file for the GTCM server (OMI code). * - * $Header:$ + * $Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi.h,v 1.7 2013/10/23 03:49:31 tuskentower Exp $ * */ @@ -57,23 +57,26 @@ { \ extern FILE *omi_debug; \ time_t clock; \ + char *time_ptr; \ + \ if (omi_debug) \ { \ clock = time((time_t *)0); \ - FPRINTF(omi_debug, "%s", ctime(&clock)); \ + GTM_CTIME(time_ptr, &clock); \ + FPRINTF(omi_debug, "%s", time_ptr); \ FFLUSH(omi_debug); \ } \ } while (0) -#define OMI_DBG(X) \ - do \ - { \ - extern FILE *omi_debug; \ - if (omi_debug) \ - { \ - FPRINTF X ; \ - FFLUSH(omi_debug); \ - } \ +#define OMI_DBG(X) \ + do \ + { \ + extern FILE *omi_debug; \ + if (omi_debug) \ + { \ + FPRINTF X ; \ + FFLUSH(omi_debug); \ + } \ } while (0) @@ -301,7 +304,8 @@ typedef struct omi_cn_stat { int id; time_t start; - struct sockaddr_in sin; + struct addrinfo ai; + struct sockaddr_storage sas; int bytes_recv; int bytes_send; int xact[OMI_OP_MAX]; diff --git a/sr_unix_cm/omi_buff_rsp.c b/sr_unix_cm/omi_buff_rsp.c index 4513067..b9c26a9 100644 --- a/sr_unix_cm/omi_buff_rsp.c +++ b/sr_unix_cm/omi_buff_rsp.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_buff_rsp.c,v 1.6 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_dbms_ch.c b/sr_unix_cm/omi_dbms_ch.c index d869217..d028b9c 100644 --- a/sr_unix_cm/omi_dbms_ch.c +++ b/sr_unix_cm/omi_dbms_ch.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_dbms_ch.c,v 1.6 2013/10/23 03:49:31 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_dmp_pkt.c b/sr_unix_cm/omi_dmp_pkt.c index 1f0fa1f..8ac63b9 100644 --- a/sr_unix_cm/omi_dmp_pkt.c +++ b/sr_unix_cm/omi_dmp_pkt.c @@ -32,7 +32,7 @@ GBLREF int omi_pkdbg; GBLREF char *omi_oprlist[]; #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_dmp_pkt.c,v 1.8 2013/10/23 03:49:32 tuskentower Exp $"; #endif diff --git a/sr_unix_cm/omi_extstr.c b/sr_unix_cm/omi_extstr.c index eda7ba0..368eeb2 100644 --- a/sr_unix_cm/omi_extstr.c +++ b/sr_unix_cm/omi_extstr.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_extstr.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_gvextnam.c b/sr_unix_cm/omi_gvextnam.c index e1f6c42..959815a 100644 --- a/sr_unix_cm/omi_gvextnam.c +++ b/sr_unix_cm/omi_gvextnam.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_gvextnam.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_lkextnam.c b/sr_unix_cm/omi_lkextnam.c index 34ce5b6..ab566d4 100644 --- a/sr_unix_cm/omi_lkextnam.c +++ b/sr_unix_cm/omi_lkextnam.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_lkextnam.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_conn.c b/sr_unix_cm/omi_prc_conn.c index ffb8e99..1e19d5a 100644 --- a/sr_unix_cm/omi_prc_conn.c +++ b/sr_unix_cm/omi_prc_conn.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_conn.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" @@ -150,7 +150,7 @@ int omi_prc_conn(omi_conn *cptr, char *xend, char *buff, char *bend) { OMI_DBG((omi_debug, "%s: memory allocation error (insufficient resources) while\n", SRVR_NAME)); OMI_DBG((omi_debug, "processing connect request from connection %d, %s.\n", - cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + cptr->stats.id, gtcm_hname(&cptr->stats.ai))); return -OMI_ER_DB_UNRECOVER; } assert(ss_len.value < MAX_USER_NAME && ss_len.value > 0); @@ -165,7 +165,7 @@ int omi_prc_conn(omi_conn *cptr, char *xend, char *buff, char *bend) { OMI_DBG((omi_debug, "%s: memory allocation error (insufficient resources) while\n", SRVR_NAME)); OMI_DBG((omi_debug, "processing connect request from connection %d, %s.\n", - cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + cptr->stats.id, gtcm_hname(&cptr->stats.ai))); return -OMI_ER_DB_UNRECOVER; } diff --git a/sr_unix_cm/omi_prc_def.c b/sr_unix_cm/omi_prc_def.c index 8bcbed2..1d6f42b 100644 --- a/sr_unix_cm/omi_prc_def.c +++ b/sr_unix_cm/omi_prc_def.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_def.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_disc.c b/sr_unix_cm/omi_prc_disc.c index 8bfc494..5fb395e 100644 --- a/sr_unix_cm/omi_prc_disc.c +++ b/sr_unix_cm/omi_prc_disc.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_disc.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_get.c b/sr_unix_cm/omi_prc_get.c index a5893d2..0d3fda0 100644 --- a/sr_unix_cm/omi_prc_get.c +++ b/sr_unix_cm/omi_prc_get.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_get.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_incr.c b/sr_unix_cm/omi_prc_incr.c index e1c00e2..b45c32d 100644 --- a/sr_unix_cm/omi_prc_incr.c +++ b/sr_unix_cm/omi_prc_incr.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_incr.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_kill.c b/sr_unix_cm/omi_prc_kill.c index bca6a28..a097ab0 100644 --- a/sr_unix_cm/omi_prc_kill.c +++ b/sr_unix_cm/omi_prc_kill.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_kill.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_lock.c b/sr_unix_cm/omi_prc_lock.c index 98b713b..61a9fd3 100644 --- a/sr_unix_cm/omi_prc_lock.c +++ b/sr_unix_cm/omi_prc_lock.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_lock.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_next.c b/sr_unix_cm/omi_prc_next.c index 816eb89..0719613 100644 --- a/sr_unix_cm/omi_prc_next.c +++ b/sr_unix_cm/omi_prc_next.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_next.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_ordr.c b/sr_unix_cm/omi_prc_ordr.c index 0589c09..9fa5ff7 100644 --- a/sr_unix_cm/omi_prc_ordr.c +++ b/sr_unix_cm/omi_prc_ordr.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_ordr.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_qry.c b/sr_unix_cm/omi_prc_qry.c index c70fd29..e9ca56b 100644 --- a/sr_unix_cm/omi_prc_qry.c +++ b/sr_unix_cm/omi_prc_qry.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_qry.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_rord.c b/sr_unix_cm/omi_prc_rord.c index 33d141c..c5f1081 100644 --- a/sr_unix_cm/omi_prc_rord.c +++ b/sr_unix_cm/omi_prc_rord.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_rord.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_set.c b/sr_unix_cm/omi_prc_set.c index 66aa22c..5a596a0 100644 --- a/sr_unix_cm/omi_prc_set.c +++ b/sr_unix_cm/omi_prc_set.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_set.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_sete.c b/sr_unix_cm/omi_prc_sete.c index 9f0c1c5..544e4af 100644 --- a/sr_unix_cm/omi_prc_sete.c +++ b/sr_unix_cm/omi_prc_sete.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_sete.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_setp.c b/sr_unix_cm/omi_prc_setp.c index df7a1ee..211f568 100644 --- a/sr_unix_cm/omi_prc_setp.c +++ b/sr_unix_cm/omi_prc_setp.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_setp.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_stat.c b/sr_unix_cm/omi_prc_stat.c index 1fdd4f7..bf71c41 100644 --- a/sr_unix_cm/omi_prc_stat.c +++ b/sr_unix_cm/omi_prc_stat.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_stat.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_unla.c b/sr_unix_cm/omi_prc_unla.c index a14f9d3..29b88e0 100644 --- a/sr_unix_cm/omi_prc_unla.c +++ b/sr_unix_cm/omi_prc_unla.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_unla.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_unlc.c b/sr_unix_cm/omi_prc_unlc.c index 5e914ad..39d7019 100644 --- a/sr_unix_cm/omi_prc_unlc.c +++ b/sr_unix_cm/omi_prc_unlc.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_unlc.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_prc_unlk.c b/sr_unix_cm/omi_prc_unlk.c index 89339d3..dd376a4 100644 --- a/sr_unix_cm/omi_prc_unlk.c +++ b/sr_unix_cm/omi_prc_unlk.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_prc_unlk.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/omi_srvc_xct.c b/sr_unix_cm/omi_srvc_xct.c index 1bbc615..184bfc8 100644 --- a/sr_unix_cm/omi_srvc_xct.c +++ b/sr_unix_cm/omi_srvc_xct.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -32,7 +32,7 @@ #include "error.h" #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/omi_srvc_xct.c,v 1.8 2013/10/23 03:49:32 tuskentower Exp $"; #endif GBLREF int4 omi_errno; @@ -99,18 +99,18 @@ int omi_srvc_xact (omi_conn *cptr) if (errno == ETIMEDOUT) { OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); } else if (errno == ECONNRESET) { OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); } else { char msg[256]; SPRINTF(msg, "Attempted read from connection %d to %s failed", - cptr->stats.id, gtcm_hname(&cptr->stats.sin)); + cptr->stats.id, gtcm_hname(&cptr->stats.ai)); gtcm_rep_err(msg, save_errno); } return -1; @@ -426,17 +426,17 @@ int omi_srvc_xact (omi_conn *cptr) if (errno == ETIMEDOUT) { OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); } else if (errno == ECONNRESET) { OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); } else if (errno == EPIPE) { OMI_DBG((omi_debug, "%s: remote client no longer attached to connection %d, %s.\n", - SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin))); + SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai))); } else if (errno == EINTR) continue; diff --git a/sr_unix_cm/rc_dbms_ch.c b/sr_unix_cm/rc_dbms_ch.c index 6498bcf..536b655 100644 --- a/sr_unix_cm/rc_dbms_ch.c +++ b/sr_unix_cm/rc_dbms_ch.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/rc_dbms_ch.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/rc_mval2subsc.c b/sr_unix_cm/rc_mval2subsc.c index af62644..d0f528d 100644 --- a/sr_unix_cm/rc_mval2subsc.c +++ b/sr_unix_cm/rc_mval2subsc.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -112,7 +112,7 @@ unsigned char *mval2subsc(mval *v, gv_key *g) in_ptr = (unsigned char *)mstr_buf1.addr; /* mstr_buf1.addr is used just in case it is reallocated by the XFORM routine */ } - if ((g->end + n + 3) > (g->top - MAX_NUM_SUBSC_LEN)) + if ((g->end + n + 3) > (g->top - MAX_GVKEY_PADDING_LEN)) { if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, g, TRUE))) end = &buff[MAX_ZWR_KEY_SZ - 1]; @@ -127,7 +127,7 @@ unsigned char *mval2subsc(mval *v, gv_key *g) if (ch <= 1) { *out_ptr++ = STR_SUB_ESCAPE; - if ( out_ptr - g->base + n + 3 > g->top - MAX_NUM_SUBSC_LEN) + if ( out_ptr - g->base + n + 3 > g->top - MAX_GVKEY_PADDING_LEN) { if ((end = format_targ_key(buff, MAX_ZWR_KEY_SZ, g, TRUE)) == 0) { @@ -144,7 +144,7 @@ unsigned char *mval2subsc(mval *v, gv_key *g) *out_ptr++ = (!TREF(transform) || 0 == gv_cur_region->std_null_coll) ? STR_SUB_PREFIX : SUBSCRIPT_STDCOL_NULL; } - goto FINI; + goto ALLDONE; } /* Its a number, is it an integer? */ if ( mvt & MV_INT ) @@ -159,7 +159,7 @@ unsigned char *mval2subsc(mval *v, gv_key *g) } else if (0 == m) { *out_ptr++ = 0x80; - goto FINI; + goto ALLDONE; } if (10 > m) { @@ -285,11 +285,11 @@ LAST_LONGWORD: FINISH_NUMBER: if (is_negative) *out_ptr++ = 0xff; -FINI: +ALLDONE: *out_ptr++ = 0 ; *out_ptr = 0 ; g->prev = g->end ; g->end = out_ptr - g->base ; - if (g->end > g->top - MAX_NUM_SUBSC_LEN - 1) + if (g->end > g->top - MAX_GVKEY_PADDING_LEN - 1) { /* take of extra space and one for last zero */ if ((end = format_targ_key(buff, MAX_ZWR_KEY_SZ, g, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; diff --git a/sr_unix_cm/rc_oflow.c b/sr_unix_cm/rc_oflow.c index 17b27bd..8519b24 100644 --- a/sr_unix_cm/rc_oflow.c +++ b/sr_unix_cm/rc_oflow.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/rc_oflow.c,v 1.6 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_cm/rc_srvc_xct.c b/sr_unix_cm/rc_srvc_xct.c index cb4b2de..b66f91a 100644 --- a/sr_unix_cm/rc_srvc_xct.c +++ b/sr_unix_cm/rc_srvc_xct.c @@ -17,7 +17,7 @@ */ #ifndef lint -static char rcsid[] = "$Header:$"; +static char rcsid[] = "$Header: /cvsroot/fis-gtm/gtm/sr_unix_cm/rc_srvc_xct.c,v 1.7 2013/10/23 03:49:32 tuskentower Exp $"; #endif #include "mdef.h" diff --git a/sr_unix_gnp/cmi_init.c b/sr_unix_gnp/cmi_init.c index 6e74fb8..e41cadf 100644 --- a/sr_unix_gnp/cmi_init.c +++ b/sr_unix_gnp/cmi_init.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -16,6 +16,7 @@ #include "gtm_netdb.h" #include "gtm_socket.h" #include "gtm_inet.h" +#include "gtm_ipv6.h" #include "cmidef.h" #include "eintr_wrappers.h" @@ -39,16 +40,17 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr, char *envvar; struct protoent *p; unsigned short myport; - struct sockaddr_in in; sigset_t oset; int on = 1; int rval, rc, save_errno; + struct addrinfo *ai_ptr, *local_ai_ptr; + boolean_t af; status = cmj_netinit(); if (CMI_ERROR(status)) return status; - status = cmj_getsockaddr(tnd, &in); + status = cmj_getsockaddr(NULL, tnd, &local_ai_ptr); if (CMI_ERROR(status)) return status; ntd_root->pool_size = pool_size; @@ -61,9 +63,13 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr, return CMI_NETFAIL; /* create the listening socket */ - ntd_root->listen_fd = socket(AF_INET, SOCK_STREAM, p->p_proto); - if (FD_INVALID == ntd_root->listen_fd) + if ((GTM_IPV6_SUPPORTED && !ipv4_only) + && (FD_INVALID != (ntd_root->listen_fd = socket(AF_INET6, SOCK_STREAM, p->p_proto)))) + af = AF_INET6; + else if (FD_INVALID == (ntd_root->listen_fd = socket(AF_INET, SOCK_STREAM, p->p_proto))) return errno; + else + af = AF_INET; /* make sure we can re-run quickly w/o reuse problems */ status = setsockopt(ntd_root->listen_fd, SOL_SOCKET, SO_REUSEADDR, @@ -75,7 +81,19 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr, return save_errno; } - status = bind(ntd_root->listen_fd, (struct sockaddr*)&in, SIZEOF(in)); + for(ai_ptr = local_ai_ptr; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next) + if (af == ai_ptr->ai_family) + break; + + if (NULL == ai_ptr) + { + CLOSEFILE_RESET(ntd_root->listen_fd, rc); + return CMI_NETFAIL; + } + + status = bind(ntd_root->listen_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); + freeaddrinfo(ai_ptr); + if (-1 == status) { save_errno = errno; diff --git a/sr_unix_gnp/cmi_open.c b/sr_unix_gnp/cmi_open.c index 46ca6be..355ebf4 100644 --- a/sr_unix_gnp/cmi_open.c +++ b/sr_unix_gnp/cmi_open.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -38,14 +38,13 @@ cmi_status_t cmi_open(struct CLB *lnk) int rval; unsigned char *cp; char hn[MAX_HOST_NAME_LEN]; - struct sockaddr_in in; - struct hostent *hp; - struct protoent *p; + struct addrinfo *ai_ptr, *ai_head; sigset_t oset; int new_fd, rc, save_errno; int sockerror; GTM_SOCKLEN_TYPE sockerrorlen; fd_set writefds; + int save_error; if (!ntd_root) { @@ -55,14 +54,10 @@ cmi_status_t cmi_open(struct CLB *lnk) } lnk->ntd = ntd_root; - status = cmj_resolve_nod_tnd(&lnk->nod, &lnk->tnd, &in); + status = cmj_getsockaddr(&lnk->nod, &lnk->tnd, &ai_head); if (CMI_ERROR(status)) return status; - p = getprotobyname(GTCM_SERVER_PROTOCOL); - endprotoent(); - if (!p) - return CMI_NETFAIL; lnk->mun = -1; memset((void *)&lnk->cqe, 0, SIZEOF(lnk->cqe)); @@ -74,11 +69,18 @@ cmi_status_t cmi_open(struct CLB *lnk) lnk->sta = CM_CLB_DISCONNECT; lnk->err = NULL; lnk->ast = NULL; - new_fd = socket(AF_INET, SOCK_STREAM, p->p_proto); - if (FD_INVALID == new_fd) + for(ai_ptr = ai_head; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next) + { + if (FD_INVALID != (new_fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol))) + break; + save_errno = errno; + } + if (NULL == ai_ptr) + { + freeaddrinfo(ai_head); return errno; - - rval = connect(new_fd, (struct sockaddr *)&in, SIZEOF(in)); + } + rval = connect(new_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if ((-1 == rval) && ((EINTR == errno) || (EINPROGRESS == errno) #if (defined(__osf__) && defined(__alpha)) || defined(__sun) || defined(__vms) || (EWOULDBLOCK == errno) @@ -126,12 +128,15 @@ cmi_status_t cmi_open(struct CLB *lnk) if (new_fd > ntd_root->max_fd) ntd_root->max_fd = new_fd; lnk->mun = new_fd; - lnk->peer = in; + memcpy((struct sockaddr *)(&lnk->peer_sas), ai_ptr->ai_addr, ai_ptr->ai_addrlen); + memcpy(&lnk->peer_ai, ai_ptr, SIZEOF(struct addrinfo)); + lnk->peer_ai.ai_addr = (struct sockaddr *)(&lnk->peer_sas); FD_SET(new_fd, &ntd_root->es); lnk->sta = CM_CLB_IDLE; } else CLOSEFILE_RESET(new_fd, rc); /* resets "new_fd" to FD_INVALID */ } SIGPROCMASK(SIG_SETMASK, &oset, NULL, rc); + freeaddrinfo(ai_head); /* prevent mem-leak */ return status; } diff --git a/sr_unix_gnp/cmi_peer_info.c b/sr_unix_gnp/cmi_peer_info.c index 1943adb..f48eaae 100644 --- a/sr_unix_gnp/cmi_peer_info.c +++ b/sr_unix_gnp/cmi_peer_info.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2002, 2009 Fidelity Information Services, Inc * + * Copyright 2002, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,35 +13,48 @@ #define _ISOC99_SOURCE #endif +#include /* for errno, used by RTS_ERROR_ADDRINFO */ + #include "mdef.h" #include "cmidef.h" #include "gtm_netdb.h" #include "gtm_socket.h" #include "gtm_stdio.h" +#include "iotcpdef.h" +#include "gtm_string.h" /* for rts_error */ /* return in a the char * the ASCII representation of a network address. Returned as: "hostid (nn.nn.nn.nn)" or "nn.nn.nn.nn" depending on whether or not the host is listed in /etc/hosts. */ +error_def(ERR_GETNAMEINFO); +error_def(ERR_TEXT); + void cmi_peer_info(struct CLB *lnk, char *buf, size_t sz) { - struct sockaddr_in *sin = &lnk->peer; -#ifndef SUNOSwhysmw - struct hostent *he; + struct addrinfo *ai_ptr; + char hostname[SA_MAXLITLEN]; + char ipname[SA_MAXLEN]; + char port_str[NI_MAXSERV]; + int errcode; - if ((he = gethostbyaddr((char *)&sin->sin_addr.s_addr, - SIZEOF(struct in_addr), AF_INET))) - snprintf(buf, sz, "%s (%d.%d.%d.%d:%d)",he->h_name, - sin->sin_addr.s_addr >> 24, - sin->sin_addr.s_addr >> 16 & 0xFF, - sin->sin_addr.s_addr >> 8 & 0xFF, - sin->sin_addr.s_addr & 0xFF, (int)sin->sin_port); - else -#endif - snprintf(buf, sz, "%d.%d.%d.%d:%d", - sin->sin_addr.s_addr >> 24, - sin->sin_addr.s_addr >> 16 & 0xFF, - sin->sin_addr.s_addr >> 8 & 0xFF, - sin->sin_addr.s_addr & 0xFF, (int)sin->sin_port); + ai_ptr = &lnk->peer_ai; + if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, + ipname, SA_MAXLEN, + port_str, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV))) + { + assert(0); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return; + } + if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, + hostname, SA_MAXLITLEN, + NULL, 0, 0))) + { + assert(0); + RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); + return; + } + SNPRINTF(buf, sz, "%s (%s:%s)", hostname, ipname, port_str); } diff --git a/sr_unix_gnp/cmj_get_port.c b/sr_unix_gnp/cmj_get_port.c index 4ab1026..47d4a36 100644 --- a/sr_unix_gnp/cmj_get_port.c +++ b/sr_unix_gnp/cmj_get_port.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001 Sanchez Computer Associates, Inc. * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -14,7 +14,6 @@ #include "gtm_netdb.h" #include "gtm_stdlib.h" #include "gtm_string.h" -#include #include "gtm_inet.h" diff --git a/sr_unix_gnp/cmj_getsockaddr.c b/sr_unix_gnp/cmj_getsockaddr.c index af31667..811c1ae 100644 --- a/sr_unix_gnp/cmj_getsockaddr.c +++ b/sr_unix_gnp/cmj_getsockaddr.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2010 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -11,8 +11,9 @@ #include "mdef.h" -#include "gtm_netdb.h" #include "gtm_socket.h" +#include "gtm_netdb.h" +#include "gtm_ipv6.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_inet.h" @@ -23,75 +24,137 @@ #include "cmidef.h" #include "eintr_wrappers.h" +#define IPV6_SEPARATOR ']' +#define IPV6_START '[' + +error_def(CMI_BADIPADDRPORT); +error_def(CMI_NOSERVENT); +error_def(ERR_TEXT); +error_def(CMI_NETFAIL); + /* writes into outport the TCP port cooresponding to tnd in NBO */ -cmi_status_t cmj_getsockaddr(cmi_descriptor *tnd, struct sockaddr_in *inp) +cmi_status_t cmj_getsockaddr(cmi_descriptor *nod, cmi_descriptor *tnd, struct addrinfo **ai_ptr_ptr) { struct servent *s; - char *tnd_str, *cp; - char port_str[MAX_HOST_NAME_LEN]; - int tnd_len, ip_len; - - error_def(CMI_BADIPADDRPORT); - error_def(CMI_NOSERVENT); + char *tnd_str, *cp, *addr_str_ptr; + char addr_end; + char port_str[MAX_HOST_NAME_LEN], *port_str_ptr; + char hn[MAX_HOST_NAME_LEN]; + int loop_limit = MAX_GETHOST_TRIES; + int tnd_len, iplen, port_len; + struct addrinfo hints, *ai_ptr = NULL; + struct protoent *pe_ptr; + int errcode; + int port; /* * address/port number determination: * - * tnd := [IP address:]port + * tnd := IP address:port for IPv4 + * tnd := [IP address]:port for IPv6 * * If tnd is an empty string, get port number from services database * */ tnd_str = CMI_DESC_POINTER(tnd); tnd_len = CMI_DESC_LENGTH(tnd); - if (tnd && 0 < tnd->len) + if (tnd && (0 < tnd->len)) { - /* look for : */ - for (ip_len = 0, cp = tnd_str; cp < tnd_str + tnd_len; cp++) + /* look for symbol separted ip address and port in ipv6 */ + if (IPV6_START == tnd_str[0]) { - if (*cp != ':' && *cp != '.' && !ISDIGIT_ASCII(*cp)) - return CMI_BADIPADDRPORT; - if (*cp == ':') + if (NULL != (port_str_ptr = memchr(tnd_str, IPV6_SEPARATOR, tnd_len))) { - if (0 == ip_len) - { - if (0 == (ip_len = (int)(cp - tnd_str))) - return CMI_BADIPADDRPORT; - } else + if (0 == (iplen = (int)(port_str_ptr - &tnd_str[1]))) return CMI_BADIPADDRPORT; - } - } - if (0 != ip_len) - { - *(tnd_str + ip_len) = '\0'; - inp->sin_addr.s_addr = INET_ADDR(tnd_str); - *(tnd_str + ip_len) = ':'; - if ((in_addr_t)-1 == inp->sin_addr.s_addr) + if (iplen == tnd_len) + return CMI_BADIPADDRPORT; + } else return CMI_BADIPADDRPORT; + addr_str_ptr = &tnd_str[1]; /* skip the '[' */ + iplen = port_str_ptr - addr_str_ptr; + port_str_ptr += 1; /* skip the ']' */ + if (*port_str_ptr != ':') + return CMI_BADIPADDRPORT; + port_str_ptr += 1; } else { - inp->sin_addr.s_addr = INADDR_ANY; - ip_len = -1; + /* look for : */ + addr_str_ptr = port_str_ptr = tnd_str; + for (iplen = 0, cp = tnd_str; cp < tnd_str + tnd_len; cp++) + { + if (*cp != ':' && *cp != '.' && !ISDIGIT_ASCII(*cp)) + return CMI_BADIPADDRPORT; + if (*cp == ':') + { + if (0 == iplen) + { + if (0 == (iplen = (int)(cp - tnd_str))) + return CMI_BADIPADDRPORT; + port_str_ptr = (cp + 1); + } else + return CMI_BADIPADDRPORT; + } + } + } - if (tnd_len - ip_len > SIZEOF(port_str)) + port_len = (tnd_str + tnd_len) - port_str_ptr; + if (0 >= port_len) return CMI_BADIPADDRPORT; - memcpy(port_str, tnd_str + ip_len + 1, tnd_len - ip_len - 1); - port_str[tnd_len - ip_len - 1] = '\0'; + memcpy(port_str, port_str_ptr, port_len); + port_str[port_len] = '\0'; + + if (0 != iplen) + { /* specified host name and port */ + addr_end = *(addr_str_ptr + iplen); /* the end can be ] or : */ + *(addr_str_ptr + iplen) = '\0'; + /* obtain ipv4/6 address for host tnd_str */ + CLIENT_HINTS(hints); + if (0 != (errcode = getaddrinfo(addr_str_ptr, port_str, &hints, &ai_ptr))) + { + *(addr_str_ptr + iplen) = addr_end; + return CMI_BADIPADDRPORT; + } + *(addr_str_ptr + iplen) = addr_end; + } else + { /* only port is specified */ + if (NULL != nod) + { + assert(CMI_DESC_LENGTH(nod) < (SIZEOF(hn)-1)); + memcpy(hn, CMI_DESC_POINTER(nod), CMI_DESC_LENGTH(nod)); + hn[CMI_DESC_LENGTH(nod)] = '\0'; + CLIENT_HINTS(hints); + + while ((EAI_AGAIN == (errcode = getaddrinfo(hn, port_str, &hints, &ai_ptr))) && (0 < loop_limit)) + { + loop_limit--; + } + if (0 != errcode) + return CMI_NETFAIL; + *ai_ptr_ptr = ai_ptr; + return SS_NORMAL; + } + + SERVER_HINTS(hints, (ipv4_only ? AF_INET : AF_UNSPEC)); + if (0 != (errcode = getaddrinfo(NULL, port_str, &hints, &ai_ptr))) + { + return CMI_BADIPADDRPORT; + } + iplen = -1; + } errno = 0; - if (((0 == (inp->sin_port = ATOI(port_str))) && (0 != errno)) || (0 >= inp->sin_port)) + port = ATOI(port_str); + if ((0 == port) && (0 != errno) || (0 >= port)) return CMI_BADIPADDRPORT; - inp->sin_port = htons(inp->sin_port); } else - { - inp->sin_addr.s_addr = INADDR_ANY; + { /* neither host nor port is specified */ /* use the services db */ - s = getservbyname(GTCM_SERVER_NAME, GTCM_SERVER_PROTOCOL); - endservent(); - if (!s) + SERVER_HINTS(hints, (ipv4_only ? AF_INET : AF_UNSPEC)); + if (0 != (errcode = getaddrinfo(NULL, GTCM_SERVER_NAME, &hints, &ai_ptr))) + { return CMI_NOSERVENT; - /* get port - netdb routine returns in NBO */ - inp->sin_port = s->s_port; + } } - inp->sin_family = AF_INET; + *ai_ptr_ptr = ai_ptr; return SS_NORMAL; } diff --git a/sr_unix_gnp/cmj_incoming_call.c b/sr_unix_gnp/cmj_incoming_call.c index 81f197a..3213880 100644 --- a/sr_unix_gnp/cmj_incoming_call.c +++ b/sr_unix_gnp/cmj_incoming_call.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -20,16 +20,17 @@ #include #include "gtmio.h" #include "relqop.h" +#include "gtm_string.h" /* for memcpy */ void cmj_incoming_call(struct NTD *tsk) { int rval, rc; struct CLB *lnk; - struct sockaddr_in in; - GTM_SOCKLEN_TYPE sz = SIZEOF(in); + struct sockaddr_storage sas; + GTM_SOCKLEN_TYPE sz = SIZEOF(struct sockaddr); cmi_status_t status; - while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&in, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno) + while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno) ; while (rval >= 0) { @@ -59,14 +60,16 @@ void cmj_incoming_call(struct NTD *tsk) tsk->max_fd = rval; lnk->mun = rval; lnk->sta = CM_CLB_IDLE; - lnk->peer = in; + memcpy(&lnk->peer_sas, &sas, sz); + lnk->peer_ai.ai_addr = (struct sockaddr *)&lnk->peer_sas; + lnk->peer_ai.ai_addrlen = sz; insqh(&lnk->cqe, &tsk->cqh); lnk->ntd = tsk; FD_SET(rval, &tsk->es); /* setup for callback processing */ lnk->deferred_event = TRUE; lnk->deferred_reason = CMI_REASON_CONNECT; - while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&in, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno) - ; + while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sz))) + && EINTR == errno); } } diff --git a/sr_unix_gnp/cmj_setupfd.c b/sr_unix_gnp/cmj_setupfd.c index d1c1c93..d5c3282 100644 --- a/sr_unix_gnp/cmj_setupfd.c +++ b/sr_unix_gnp/cmj_setupfd.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -17,9 +17,6 @@ #endif #include #include "gtm_inet.h" -#ifndef __MVS__ -#include -#endif #include #include "eintr_wrappers.h" diff --git a/sr_unix_gnp/cmu_getclb.c b/sr_unix_gnp/cmu_getclb.c index b4931ed..df020c3 100644 --- a/sr_unix_gnp/cmu_getclb.c +++ b/sr_unix_gnp/cmu_getclb.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2009 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,19 +13,25 @@ #include "cmidef.h" #include "gtm_string.h" #include "eintr_wrappers.h" +#include "gtm_netdb.h" +#include "gtm_socket.h" +#include "iotcpdef.h" GBLREF struct NTD *ntd_root; +error_def(ERR_GETNAMEINFO); +error_def(ERR_TEXT); + struct CLB *cmu_getclb(cmi_descriptor *node, cmi_descriptor *task) { cmi_status_t status; struct CLB *p; que_ent_ptr_t qp; sigset_t oset; - struct sockaddr_in in; + struct addrinfo *ai_ptr; int rc; - status = cmj_resolve_nod_tnd(node, task, &in); + status = cmj_getsockaddr(node, task, &ai_ptr); if (CMI_ERROR(status)) return NULL; @@ -36,9 +42,8 @@ struct CLB *cmu_getclb(cmi_descriptor *node, cmi_descriptor *task) qp = RELQUE2PTR(p->cqe.fl)) { p = QUEENT2CLB(qp, cqe); - if (p->peer.sin_port == in.sin_port && 0 == memcmp(&p->peer.sin_addr, &in.sin_addr, SIZEOF(in.sin_addr))) - { /* (port, address) pair is necessary and sufficient for uniqueness. There might be other fields in - sockaddr_in that might be implementation dependent. So, compare only (port, address) pair. */ + if (0 == memcpy(ai_ptr->ai_addr, (sockaddr_ptr)(&p->peer_sas), ai_ptr->ai_addrlen)) + { sigprocmask(SIG_SETMASK, &oset, NULL); return p; } diff --git a/sr_unix_gnp/gtcm_ch.c b/sr_unix_gnp/gtcm_ch.c index 52ecd7c..db1a6e4 100644 --- a/sr_unix_gnp/gtcm_ch.c +++ b/sr_unix_gnp/gtcm_ch.c @@ -25,7 +25,7 @@ #include "fao_parm.h" #include "gtm_fcntl.h" #include "cmi.h" -#include "preemptive_ch.h" +#include "preemptive_db_clnup.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "copy.h" @@ -45,7 +45,6 @@ GBLDEF bool gtcm_firsterr = TRUE; GBLDEF FILE *gtcm_errfs = NULL; GBLREF connection_struct *curr_entry; -GBLREF unsigned char *util_outptr; GBLREF bool undef_inhibit; static short szero = 0; @@ -71,34 +70,34 @@ CONDITION_HANDLER(gtcm_ch) if (gtcm_firsterr) gtcm_open_cmerrlog(); msgnum = 1; - msglen = (int)((char *)util_outptr - (char *)util_outbuff); + msglen = (int)(TREF(util_outptr) - TREF(util_outbuff_ptr)); if (0 == msglen) { /* gtm_putmsg_list has already flushed message. Get length another way. Also reduce msg length by <\n> on it's end which we don't want to send. */ - msglen = STRLEN(util_outbuff) - 1; + msglen = STRLEN(TREF(util_outbuff_ptr)) - 1; } else { /* msg yet to be flushed. Properly terminate it in the buffer */ - *util_outptr = '\n'; - *(util_outptr + 1) = 0; + *(TREF(util_outptr)) = '\n'; + *(TREF(util_outptr) + 1) = 0; } - msgptr = (unsigned char *)util_outbuff; + msgptr = (unsigned char *)TREF(util_outbuff_ptr); assert(msglen); if (gtcm_errfile) { GET_CUR_TIME; time_str[CTIME_BEFORE_NL] = 0; - FPRINTF(gtcm_errfs, "%s: %s", time_str, util_outbuff); + FPRINTF(gtcm_errfs, "%s: %s", time_str, TREF(util_outbuff_ptr)); FFLUSH(gtcm_errfs); } orig_severity = SEVERITY; /* Don't let severe error message cause client to necessarily die. Reflect error using ERR_SERVERERR */ if (4 <= SEVERITY) { - memcpy(sevmsgbuf, util_outbuff, msglen); + memcpy(sevmsgbuf, TREF(util_outbuff_ptr), msglen); util_out_print(NULL, OPER); /* write msg to operator log */ gtm_putmsg_noflush(VARLSTCNT(4) ERR_SERVERERR, 2, msglen, sevmsgbuf); - msglen = (int)((char *)util_outptr - (char *)util_outbuff); + msglen = (int)(TREF(util_outptr) - TREF(util_outbuff_ptr)); } if (curr_entry) { @@ -158,7 +157,7 @@ CONDITION_HANDLER(gtcm_ch) } if (WARNING == orig_severity || ERROR == orig_severity) { - preemptive_ch(orig_severity); + preemptive_db_clnup(orig_severity); UNWIND(x,y); } NEXTCH; diff --git a/sr_unix_gnp/gtcm_exi_ch.c b/sr_unix_gnp/gtcm_exi_ch.c index e9ad7a2..f3d87ca 100644 --- a/sr_unix_gnp/gtcm_exi_ch.c +++ b/sr_unix_gnp/gtcm_exi_ch.c @@ -36,7 +36,6 @@ GBLREF bool gtcm_errfile; GBLREF bool gtcm_firsterr; GBLREF FILE *gtcm_errfs; -GBLREF unsigned char *util_outptr; GBLREF int4 exi_condition; error_def(ERR_TEXT); @@ -46,20 +45,22 @@ CONDITION_HANDLER(gtcm_exi_ch) int rc; now_t now; /* for GET_CUR_TIME macro */ char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; if (gtcm_firsterr) gtcm_open_cmerrlog(); if (gtcm_errfile) { - if ((char *)util_outptr != util_outbuff) + if (TREF(util_outptr) != TREF(util_outbuff_ptr)) { /* msg yet to be flushed. Properly terminate it in the buffer. If msg has already been flushed (to stderr) then this has already been done. */ - *util_outptr = '\n'; - *(util_outptr + 1) = 0; + *(TREF(util_outptr)) = '\n'; + *(TREF(util_outptr) + 1) = 0; } GET_CUR_TIME; time_str[CTIME_BEFORE_NL] = 0; - FPRINTF(gtcm_errfs, "%s: %s", time_str, util_outbuff); + FPRINTF(gtcm_errfs, "%s: %s", time_str, TREF(util_outbuff_ptr)); FFLUSH(gtcm_errfs); } send_msg(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_TEXT("GT.CM TERMINATION RUNDOWN ERROR")); diff --git a/sr_unix_gnp/gtcm_gnp_pktdmp.c b/sr_unix_gnp/gtcm_gnp_pktdmp.c index aa59741..b8d78e3 100644 --- a/sr_unix_gnp/gtcm_gnp_pktdmp.c +++ b/sr_unix_gnp/gtcm_gnp_pktdmp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -78,7 +78,7 @@ void gtcm_gnp_pktdmp(FILE *fp, struct CLB *lnk, int sta, unsigned char *buf, siz } chr = buf; ctim = time(NULL); - ltime = localtime(&ctim); + GTM_LOCALTIME(ltime, &ctim); FPRINTF(fp, "%04d%02d%02d%02d%02d%02d (%s) %s length %d\n", ltime->tm_year+1900, ltime->tm_mon + 1, ltime->tm_mday, ltime->tm_hour,ltime->tm_min, ltime->tm_sec, op, msg, count); diff --git a/sr_unix_gnp/gtcm_gnp_server.c b/sr_unix_gnp/gtcm_gnp_server.c index f37cc01..45f4c0f 100644 --- a/sr_unix_gnp/gtcm_gnp_server.c +++ b/sr_unix_gnp/gtcm_gnp_server.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 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 "gtm_stdlib.h" #include "gtm_time.h" #include "gtm_stat.h" - #include #include @@ -82,22 +81,23 @@ #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" #include "fork_init.h" - +#include "gt_timers_add_safe_hndlrs.h" +#include "wbox_test_init.h" #ifdef UNICODE_SUPPORTED -#include "gtm_icu_api.h" -#include "gtm_utf8.h" +# include "gtm_icu_api.h" +# include "gtm_utf8.h" #endif +#include "continue_handler.h" +#include "have_crit.h" #ifdef __osf__ -#pragma pointer_size (save) -#pragma pointer_size (long) +# pragma pointer_size (save) +# pragma pointer_size (long) #endif - GBLDEF char **gtmenvp; GBLREF char cli_err_str[]; - #ifdef __osf__ -#pragma pointer_size (restore) +# pragma pointer_size (restore) #endif GBLREF FILE *gtcm_errfs; @@ -429,7 +429,7 @@ int main(int argc, char **argv, char **envp) stp_init(STP_INITSIZE); rts_stringpool = stringpool; getzdir(); - sig_init(generic_signal_handler, null_handler, suspsigs_handler); /* should do be done before cmi_init */ + sig_init(generic_signal_handler, null_handler, suspsigs_handler, continue_handler); /* should do be done before cmi_init */ /* Redefine handler for SIGHUP to switch log file */ memset(&act, 0, SIZEOF(act)); @@ -479,10 +479,9 @@ int main(int argc, char **argv, char **envp) atexit(gtcm_exi_handler); INVOKE_INIT_SECSHR_ADDRS; initialize_pattern_table(); - /* Pre-allocate some timer blocks. */ prealloc_gt_timers(); - + gt_timers_add_safe_hndlrs(); SET_LATCH_GLOBAL(&action_que.latch, LOCK_AVAILABLE); mu_gv_cur_reg_init(); cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; @@ -490,6 +489,7 @@ int main(int argc, char **argv, char **envp) cs_addrs->nl = (node_local_ptr_t)malloc(SIZEOF(node_local)); memset((char *)cs_addrs->nl, 0, SIZEOF(node_local)); action_que_dummy_reg = gv_cur_region; + OPERATOR_LOG_MSG; /* ... now we are ready! */ ntd_root->crq = gtcm_init_ast; while (!cm_shutdown) diff --git a/sr_unix_gnp/gvcmz_errmsg.c b/sr_unix_gnp/gvcmz_errmsg.c index 9eb8fbc..ec8d940 100644 --- a/sr_unix_gnp/gvcmz_errmsg.c +++ b/sr_unix_gnp/gvcmz_errmsg.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -21,7 +21,6 @@ #include "gvcmz.h" #include "copy.h" -GBLREF unsigned char *util_outptr; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; @@ -42,7 +41,9 @@ void gvcmz_errmsg(struct CLB *c, bool close) uint4 status; cmi_descriptor *desc; link_info *li; + DCL_THREADGBL_ACCESS; + SETUP_THREADGBL_ACCESS; li = (link_info *)c->usr; util_out_print(NULL, RESET); flush_pio(); @@ -63,8 +64,8 @@ void gvcmz_errmsg(struct CLB *c, bool close) CM_GET_LONG(SEVERITY, bufptr, li->convert_byteorder); bufptr += SIZEOF(SEVERITY); - memcpy(util_outptr, bufptr, msglen); - util_outptr += msglen; + memcpy(TREF(util_outptr), bufptr, msglen); + TREF(util_outptr) += msglen; while(cont) { status = cmi_read(c); @@ -81,8 +82,8 @@ void gvcmz_errmsg(struct CLB *c, bool close) } CM_GET_SHORT(msglen, bufptr, li->convert_byteorder); bufptr += SIZEOF(short); - memcpy(util_outptr, bufptr, msglen); - util_outptr += msglen; + memcpy(TREF(util_outptr), bufptr, msglen); + TREF(util_outptr) += msglen; } if (close) diff --git a/sr_unix_gnp/libcmisockettcp.list b/sr_unix_gnp/libcmisockettcp.list index 23eab73..338a50b 100644 --- a/sr_unix_gnp/libcmisockettcp.list +++ b/sr_unix_gnp/libcmisockettcp.list @@ -24,7 +24,6 @@ cmj_init_clb cmj_netinit cmj_postevent cmj_read -cmj_resolve_nod_tnd cmj_select cmj_setupfd cmj_unit2clb diff --git a/sr_unix_nsb/comp_lits.c b/sr_unix_nsb/comp_lits.c index 06df2e2..5db7087 100644 --- a/sr_unix_nsb/comp_lits.c +++ b/sr_unix_nsb/comp_lits.c @@ -11,7 +11,7 @@ #include "mdef.h" #include "compiler.h" -#include "rtnhdr.h" +#include #include "mdq.h" #include "stringpool.h" diff --git a/sr_unix_nsb/m_do.c b/sr_unix_nsb/m_do.c index 67820a4..2e39830 100644 --- a/sr_unix_nsb/m_do.c +++ b/sr_unix_nsb/m_do.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2011 Fidelity Information Services, Inc * + * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -126,7 +126,7 @@ int m_do(void) cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); @@ -139,7 +139,7 @@ int m_do(void) triptr->operand[0] = put_mfun(&calltrip->operand[0].oprval.lab->mvname); calltrip->operand[0].oprclass = ILIT_REF; /* dummy placeholder */ } - if (TREF(expr_start) != TREF(expr_start_orig)) + if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); diff --git a/sr_unix_nsb/obj_code.c b/sr_unix_nsb/obj_code.c index e46189f..30d1c1c 100644 --- a/sr_unix_nsb/obj_code.c +++ b/sr_unix_nsb/obj_code.c @@ -20,7 +20,7 @@ #include "compiler.h" #include "obj_gen.h" -#include "rtnhdr.h" +#include #include "cmd_qlf.h" #include "cgp.h" #ifdef UNIX diff --git a/sr_unix_nsb/opcode_def.h b/sr_unix_nsb/opcode_def.h index 2807165..2265270 100644 --- a/sr_unix_nsb/opcode_def.h +++ b/sr_unix_nsb/opcode_def.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -256,7 +256,6 @@ OPCODE_DEF(OC_TRESTART, (OCT_NULL)) OPCODE_DEF(OC_TCOMMIT, (OCT_NULL)) OPCODE_DEF(OC_EXP, (OCT_MVAL)) OPCODE_DEF(OC_FNGET2, (OCT_MVAL | OCT_EXPRLEAF)) -OPCODE_DEF(OC_INDGET, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_INDINCR, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNNAME, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_INDFNNAME, (OCT_MVAL | OCT_EXPRLEAF)) @@ -279,7 +278,7 @@ OPCODE_DEF(OC_FGNLOOKUP, (OCT_CDADDR)) OPCODE_DEF(OC_SORTS_AFTER, (OCT_BOOL)) OPCODE_DEF(OC_NSORTS_AFTER, (OCT_BOOL)) OPCODE_DEF(OC_FNGVGET1, (OCT_MVAL | OCT_EXPRLEAF)) -OPCODE_DEF(OC_FNGVGET2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_FNGET1, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETP1, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETZP1, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZQGBLMOD, (OCT_MVAL | OCT_EXPRLEAF)) @@ -302,6 +301,7 @@ OPCODE_DEF(OC_FNZSIGPROC, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZCONVERT2, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZCONVERT3, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZWIDTH, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_FNZWRITE, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FNZSUBSTR, (OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_SETALS2ALS, (OCT_NULL)) OPCODE_DEF(OC_SETALSIN2ALSCT, (OCT_NULL)) @@ -323,3 +323,21 @@ OPCODE_DEF(OC_SAVPUTINDX, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) OPCODE_DEF(OC_FORFREEINDX, (OCT_NULL)) OPCODE_DEF(OC_FORNESTLVL, (OCT_NULL)) OPCODE_DEF(OC_ZHALT, (OCT_NULL)) +OPCODE_DEF(OC_IGETDST, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDGET1, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_GLVNPOP, (OCT_NULL)) +OPCODE_DEF(OC_GLVNSLOT, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDSAVGLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDSAVLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_RFRSHLVN, (OCT_MVADDR | OCT_MVAL)) +OPCODE_DEF(OC_SAVGVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_SAVLVN, (OCT_MVADDR | OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_SHARESLOT, (OCT_NULL)) +OPCODE_DEF(OC_STOGLVN, (OCT_NULL)) +OPCODE_DEF(OC_RFRSHGVN, (OCT_NULL)) +OPCODE_DEF(OC_INDFNNAME2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDGET2, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_INDMERGE2, (OCT_NULL)) +OPCODE_DEF(OC_LITC, (OCT_MVAL | OCT_EXPRLEAF)) +OPCODE_DEF(OC_STOLITC, (OCT_NULL)) +OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF)) diff --git a/sr_unix_nsb/rtnhdr.h b/sr_unix_nsb/rtnhdr.h index eceb80f..b341116 100644 --- a/sr_unix_nsb/rtnhdr.h +++ b/sr_unix_nsb/rtnhdr.h @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -129,6 +129,9 @@ typedef struct #define CODE_BASE_ADDR(rtnhdr) ((unsigned char *)(rtnhdr)) #define CODE_OFFSET(rtnhdr, addr) ((char *)(addr) - (char *)(rtnhdr)) +#define DYNAMIC_LITERALS_ENABLED(rtnhdr) FALSE +#define RW_REL_START_ADR(rtnhdr) ((char *)LITERAL_ADR(rtnhdr)) + /* Flag values for get_src_line call */ #define VERIFY TRUE #define NOVERIFY FALSE diff --git a/sr_unix_nsb/shrink_jmps.c b/sr_unix_nsb/shrink_jmps.c index 9b3a329..92748df 100644 --- a/sr_unix_nsb/shrink_jmps.c +++ b/sr_unix_nsb/shrink_jmps.c @@ -15,7 +15,7 @@ #include "mdq.h" #include "cgp.h" #include -#include "rtnhdr.h" +#include #include "obj_file.h" GBLREF int4 curr_addr, code_size; diff --git a/sr_unix_nsb/ttt.txt b/sr_unix_nsb/ttt.txt index 577d5ed..a9d35e6 100644 --- a/sr_unix_nsb/ttt.txt +++ b/sr_unix_nsb/ttt.txt @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; -; Copyright 2001, 2012 Fidelity Information Services, Inc ; +; Copyright 2001, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; @@ -173,25 +173,25 @@ OC_FNZFIND: pushab val.0 pushab val.1 calls #4,xfer.xf_fnzfind OC_FNFNUMBER: pushab val.0 + pushl val.4 + pushl val.3 pushab val.2 pushab val.1 - calls #3,xfer.xf_fnfnumber + calls #5,xfer.xf_fnfnumber OC_FNGET: movab val.1,r1 movab val.0,r0 jsb xfer.xf_fnget -OC_FNGET2: pushab val.2 +OC_FNGET2: pushab val.0 + pushab val.2 pushab val.1 - pushab val.0 calls #3,xfer.xf_fnget2 -OC_FNGVGET: pushab val.1 - pushab val.0 - calls #2,xfer.xf_fngvget +OC_FNGVGET: pushab val.0 + calls #1,xfer.xf_fngvget OC_FNGVGET1: pushab val.0 calls #1,xfer.xf_fngvget1 -OC_FNGVGET2: pushab val.2 - pushab val.1 - pushab val.0 - calls #3,xfer.xf_fngvget2 +OC_FNGET1: pushab val.0 + pushab val.1 + calls #2,xfer.xf_fnget1 OC_FNINCR: pushab val.0 ; result of $INCR pushab val.2 ; r->operand[1] = increment pushab val.1 ; r->operand[0] = local-variable to increment @@ -522,18 +522,14 @@ OC_INDDEVPARMS: pushab val.0 pushl val.2 pushab val.1 jsb xfer.xf_inddevparms -OC_INDFNNAME: pushab val.2 ; r->operand[1] - pushab val.1 ; r->operand[0] - pushab val.0 ; result of $NAME +OC_INDFNNAME: pushab val.2 ; r->operand[1] = depth + pushab val.1 ; r->operand[0] = name + pushab val.0 ; r->dst jsb xfer.xf_indfnname OC_INDFUN: pushab val.0 pushl val.2 pushab val.1 jsb xfer.xf_indfun -OC_INDGET: pushab val.2 - pushab val.1 - pushab val.0 - jsb xfer.xf_indget OC_INDGLVN: pushab val.0 pushab val.1 jsb xfer.xf_indglvn @@ -547,16 +543,17 @@ OC_INDLVADR: pushab val.1 OC_INDLVARG: pushab val.0 pushab val.1 jsb xfer.xf_indlvarg -OC_INDNAME: irepab val.2 +OC_INDNAME: pushab val.2 + pushab val.1 pushab val.0 - calls val.1,xfer.xf_indname + calls #3,xfer.xf_indname OC_INDLVNAMADR: pushab val.1 jsb xfer.xf_indlvnamadr movl r0,addr.0 OC_INDO2: pushab val.2 pushab val.1 pushab val.0 - jsb xfer.xf_indo2 + calls #3,xfer.xf_indo2 OC_INDPAT: pushab val.0 pushab val.1 jsb xfer.xf_indpat @@ -576,7 +573,8 @@ OC_IOCONTROL: jsb xfer.xf_restartpc calls val.1,xfer.xf_iocontrol OC_IRETMVAD: movab val.1,r1 jsb xfer.xf_iretmvad -OC_IRETMVAL: pushab val.1 +OC_IRETMVAL: pushab val.2 + pushab val.1 jsb xfer.xf_iretmval OC_JMP-BYTE: brb jmp.1 OC_JMP-LONG: jmp jmp.1 @@ -964,13 +962,55 @@ OC_FNZWIDTH: pushab val.0 ; destination mval OC_ZTRIGGER: calls #0,xfer.xf_ztrigger OC_ZWRITESVN: pushl val.1 calls #1,xfer.xf_zwritesvn -OC_RFRSHINDX: pushl val.2 - pushl val.1 - calls #2,xfer.xf_rfrshindx +OC_FNZWRITE: pushab val.0 ; destination mval + pushab val.1 ; string + calls #2,xfer.xf_fnzwrite +OC_IGETDST: calls #0,xfer.xf_igetdst + movl r0,addr.0 +OC_INDGET1: pushab val.0 + pushab val.1 + calls #2,xfer.xf_indget1 +OC_GLVNPOP: pushab val.1 + calls #1,xfer.xf_glvnpop +OC_GLVNSLOT: pushl val.1 + calls #1,xfer.xf_glvnslot movl r0,addr.0 -OC_SAVPUTINDX: irepab val.2 - calls val.1,xfer.xf_savputindx +OC_INDSAVGLVN: pushl val.3 + pushab val.2 + pushab val.1 + jsb xfer.xf_indsavglvn +OC_INDSAVLVN: pushab val.2 + pushab val.1 + jsb xfer.xf_indsavlvn +OC_RFRSHLVN: pushl val.2 + pushab val.1 + calls #2,xfer.xf_rfrshlvn movl r0,addr.0 -OC_FORFREEINDX: calls #0,xfer.xf_forfreeindx -OC_FORNESTLVL: pushl val.1 - calls #1,xfer.xf_fornestlvl +OC_SAVGVN: irepab val.2 + calls val.1,xfer.xf_savgvn +OC_SAVLVN: irepab val.2 + calls val.1,xfer.xf_savlvn +OC_SHARESLOT: pushl val.2 + pushab val.1 + calls #2,xfer.xf_shareslot +OC_STOGLVN: pushab val.2 + pushab val.1 + calls #2,xfer.xf_stoglvn +OC_RFRSHGVN: pushl val.2 + pushab val.1 + calls #2,xfer.xf_rfrshgvn +OC_INDFNNAME2: pushab val.2 + pushab val.1 + pushab val.0 + calls #3,xfer.xf_indfnname2 +OC_INDGET2: pushab val.1 + pushab val.0 + calls #2,xfer.xf_indget2 +OC_INDMERGE2: pushab val.1 + calls #1,xfer.xf_indmerge2 +OC_FNZPEEK: pushab val.0 + pushab val.4 + pushl val.3 + pushl val.2 + pushab val.1 + calls #5,xfer.xf_fnzpeek diff --git a/sr_x86_64/auto_zlink_sp.c b/sr_x86_64/auto_zlink_sp.c index 30dca2d..2dccb7f 100644 --- a/sr_x86_64/auto_zlink_sp.c +++ b/sr_x86_64/auto_zlink_sp.c @@ -12,9 +12,9 @@ #include "mdef.h" #include "opcode.h" -#include "mdefsp.h" +#include #include "x86_64.h" -#include "auto_zlink_sp.h" +#include #include "i386.h" GBLREF int4 rtnhdr_off, labaddr_off; diff --git a/sr_x86_64/cmerrors_ctl.c b/sr_x86_64/cmerrors_ctl.c index 94db2b9..0d89e8f 100644 --- a/sr_x86_64/cmerrors_ctl.c +++ b/sr_x86_64/cmerrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * diff --git a/sr_x86_64/cmierrors_ctl.c b/sr_x86_64/cmierrors_ctl.c index dbb0d2a..d8493c8 100644 --- a/sr_x86_64/cmierrors_ctl.c +++ b/sr_x86_64/cmierrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * diff --git a/sr_x86_64/compswap.s b/sr_x86_64/compswap.s index 9164243..d8d2c62 100644 --- a/sr_x86_64/compswap.s +++ b/sr_x86_64/compswap.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007 Fidelity Information Services, Inc # +# Copyright 2007, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -34,4 +34,5 @@ ENTRY compswap fail: xor REG32_RET0,REG32_RET0 # return FALSE + pause ret diff --git a/sr_x86_64/emit_code_sp.c b/sr_x86_64/emit_code_sp.c index 2f5665a..3d2cb12 100644 --- a/sr_x86_64/emit_code_sp.c +++ b/sr_x86_64/emit_code_sp.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2007, 2009 Fidelity Information Services, Inc * + * Copyright 2007, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -19,11 +19,12 @@ #include "gtm_stdio.h" #include "opcode.h" #include "mdq.h" -#include "rtnhdr.h" +#include #include "vxi.h" #include "vxt.h" #include "cgp.h" #include "compiler.h" +#include "list_file.h" #include GBLDEF struct emit_base_info emit_base_info; diff --git a/sr_x86_64/error.si b/sr_x86_64/error.si index f930058..a4cb3cd 100644 --- a/sr_x86_64/error.si +++ b/sr_x86_64/error.si @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007 Fidelity Information Services, Inc # +# Copyright 2007, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -22,23 +22,19 @@ chnd_jmp = 24 .data .extern ctxt -.extern active_ch # .text # setjmp is really __sigsetjmp(env,0) #.extern __sigsetjmp +.extern gtm_asm_establish .sbttl error.si ESTABLISH .macro ESTABLISH label - addq $chnd_size,ctxt(REG_IP) # ctxt++ + call gtm_asm_establish movq ctxt(REG_IP),%rax - movq active_ch(REG_IP),%rdx - movq %rdx,chnd_save_active(%rax) # ctxt->save_active_ch = active_ch - movl $0,chnd_ch_active(%rax) # ctxt->ch_active = FALSE - movq %rax,active_ch(REG_IP) # active_ch = ctxt leaq mdb_condition_handler(REG_IP), REG64_SCRATCH1 movq REG64_SCRATCH1, chnd_ch(%rax) # ctxt->ch = x - addq $chnd_jmp,%rax # setjmp(ctxt->jnp) + addq $chnd_jmp,%rax # setjmp(ctxt->jmp) movq $0,%rsi movq %rax,%rdi call __sigsetjmp@PLT diff --git a/sr_x86_64/find_line_call.c b/sr_x86_64/find_line_call.c index caa9945..d70a860 100644 --- a/sr_x86_64/find_line_call.c +++ b/sr_x86_64/find_line_call.c @@ -10,10 +10,10 @@ ****************************************************************/ #include "mdef.h" -#include "emit_code_sp.h" +#include #include "xfer_enum.h" #include "i386.h" -#include "rtnhdr.h" /* Needed by zbreak.h */ +#include /* Needed by zbreak.h */ #include "zbreak.h" int inst_size = 0; diff --git a/sr_x86_64/gdeerrors_ctl.c b/sr_x86_64/gdeerrors_ctl.c index d1253a8..90dc1b3 100644 --- a/sr_x86_64/gdeerrors_ctl.c +++ b/sr_x86_64/gdeerrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -70,6 +70,7 @@ LITDEF err_msg gdeerrors[] = { "NONASCII", "!AD is illegal for a !AD as it contains non-ASCII characters", 4, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "JNLALLOCGROW", "Increased Journal ALLOCATION from [!AD blocks] to [!AD blocks] to match AUTOSWITCHLIMIT for !AD !AD", 8, + "KEYFORBLK", "But block size !AD can only support key size !AD", 4, }; LITDEF int GDE_BLKSIZ512 = 150503435; @@ -129,9 +130,10 @@ LITDEF int GDE_WRITEERROR = 150503859; LITDEF int GDE_NONASCII = 150503866; LITDEF int GDE_CRYPTNOMM = 150503874; LITDEF int GDE_JNLALLOCGROW = 150503883; +LITDEF int GDE_KEYFORBLK = 150503891; GBLDEF err_ctl gdeerrors_ctl = { 248, "GDE", &gdeerrors[0], - 57}; + 58}; diff --git a/sr_x86_64/incr_link_sp.h b/sr_x86_64/incr_link_sp.h index 72d612c..87166fc 100644 --- a/sr_x86_64/incr_link_sp.h +++ b/sr_x86_64/incr_link_sp.h @@ -12,7 +12,7 @@ #ifndef INCR_LINK_SP_INCLUDED #define INCR_LINK_SP_INCLUDED -#include "rtnhdr.h" +#include #include #define NATIVE_HDR_LEN (SIZEOF(Elf64_Ehdr)) diff --git a/sr_x86_64/merrors_ctl.c b/sr_x86_64/merrors_ctl.c index 8db8b9d..a409df6 100644 --- a/sr_x86_64/merrors_ctl.c +++ b/sr_x86_64/merrors_ctl.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001,2012 Fidelity Information Services, Inc * + * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -67,7 +67,7 @@ LITDEF err_msg merrors[] = { "NUMUNXEOR", "!_!AD!/!_!_!_unexpected end of record in numeric subscript", 2, "EXPR", "Expression expected but not found", 0, "STRUNXEOR", "!_!AD!/!_!_!_unexpected end of record in string subscript", 2, - "JNLEXTEND", "Journal file extension error. Journal file !AD closed.", 2, + "JNLEXTEND", "Journal file extension error for file !AD", 2, "FCHARMAXARGS", "Argument count of $CHAR function exceeded the maximum of 255", 0, "FCNSVNEXPECTED", "Function or special variable expected in this context", 0, "FNARGINC", "Format specifiers to $FNUMBER are incompatible: \"!AD\"", 2, @@ -95,7 +95,7 @@ LITDEF err_msg merrors[] = { "GVUNDEF", "Global variable undefined: !AD", 2, "TRANSNEST", "Maximum transaction nesting levels exceeded", 0, "INDEXTRACHARS", "Indirection string contains extra trailing characters", 0, - "INDMAXNEST", "Maximum nesting of indirection expressions exceeded", 0, + "UNUSEDMSG260", "INDMAXNEST Last used in V6.0-000", 0, "INDRMAXLEN", "Maximum length !UL of an indirection argument was exceeded", 1, "INSFFBCNT", "Insufficient byte count quota left for requested operation", 0, "INTEGERRS", "Database integrity errors", 0, @@ -195,7 +195,7 @@ LITDEF err_msg merrors[] = { "TEXTARG", "Invalid argument to $TEXT function", 0, "TMPSTOREMAX", "Maximum space for temporary values exceeded", 0, "VIEWCMD", "View parameter is not valid with VIEW command", 0, - "TXTNEGLIN", "A line prior to line number zero was referenced in $TEXT", 0, + "JNI", "!AD", 2, "TXTSRCFMT", "$TEXT encountered an invalid source program file format", 0, "UIDMSG", "Unidentified message received", 0, "UIDSND", "Unidentified sender PID", 0, @@ -204,9 +204,9 @@ LITDEF err_msg merrors[] = { "VAREXPECTED", "Variable expected in this context", 0, "VARRECBLKSZ", "Blocksize must be at least record size + 4 bytes", 0, "MAXARGCNT", "Maximum number of arguments !UL exceeded", 1, - "WCFAIL", "The database cache is corrupt", 0, + "GTMSECSHRSEMGET", "semget error errno = !UL", 1, "VIEWARGCNT", "View parameter !AD has inappropriate number of subparameters", 2, - "XKILLCNTEXC", "Maximum number of arguments (!UL) to exclusive kill exceeded", 1, + "GTMSECSHRDMNSTARTED", "gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", 5, "ZATTACHERR", "Error attaching to \"!AD\"", 2, "ZDATEFMT", "$ZDATE format string contains invalid character", 0, "ZEDFILSPEC", "Illegal ZEDIT file specification: !AD", 2, @@ -273,14 +273,14 @@ LITDEF err_msg merrors[] = { "MULTFORMPARM", "This formal parameter is multiply defined", 0, "QUITARGUSE", "Quit cannot take an argument in this context", 0, "NAMEEXPECTED", "A local variable name is expected in this context", 0, - "UNUSEDMSG438", "ACTLSTEXP: Last used in V5.4-002B", 0, + "FALLINTOFLST", "Fall-through to a label with formallist is not allowed", 0, "NOTEXTRINSIC", "Quit does not return to an extrinsic function: argument not allowed", 0, - "UNUSEDMSG440", "FMLLSTPRESENT: Last used in V5.4-002B", 0, + "GTMSECSHRREMSEMFAIL", "error removing semaphore errno = !UL", 1, "FMLLSTMISSING", "The formal list is absent from a label called with an actual list: !AD", 2, "ACTLSTTOOLONG", "More actual parameters than formal parameters: !AD", 2, "ACTOFFSET", "Actuallist not allowed with offset", 0, "MAXACTARG", "Maximum number of actual arguments exceeded", 0, - "GTMDUMPFAIL", "Could not create DUMP FILE", 0, + "GTMSECSHRREMSEM", "[client pid !UL] Semaphore (!UL) removed", 2, "JNLTMQUAL2", "Time qualifier LOOKBACK_TIME=\"!AZ\" is later than SINCE_TIME=\"!AZ\"", 2, "GDINVALID", "Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD", 6, "ASSERT", "Assert failed in !AD line !UL for expression (!AD)", 5, @@ -305,8 +305,8 @@ LITDEF err_msg merrors[] = { "DBBLEVMN", "!AD Block level less than zero", 2, "DBBSIZMN", "!AD Block too small", 2, "DBBSIZMX", "!AD Block larger than file block size", 2, - "DBRSIZMN", "!AD Record too small", 2, - "DBRSIZMX", "!AD Record too large", 2, + "DBRSIZMN", "!AD Physical record too small", 2, + "DBRSIZMX", "!AD Physical record too large", 2, "DBCMPNZRO", "!AD First record of block has nonzero compression count", 2, "DBSTARSIZ", "!AD Star record has wrong size", 2, "DBSTARCMP", "!AD Star record has nonzero compression count", 2, @@ -424,13 +424,13 @@ LITDEF err_msg merrors[] = { "BEGINST", "Beginning LOAD at record number: !UL", 1, "INVMVXSZ", "Invalid block size for GOQ load format", 0, "JNLWRTNOWWRTR", "Journal writer attempting another write", 0, - "MUPGDERR", "Command aborted due to global directory errors", 0, + "GTMSECSHRSHMCONCPROC", "More than one process attached to Shared memory segment (!UL) not removed (!UL)", 2, "JNLINVALLOC", "Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.", 3, "JNLINVEXT", "Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2, "MUPCLIERR", "Action not taken due to CLI errors", 0, "JNLTMQUAL4", "Time qualifier BEFORE_TIME=\"!AZ\" is less than AFTER_TIME=\"!AZ\"", 2, - "JNLBUFFTOOLG", "Journal file buffer !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2, - "JNLBUFFTOOSM", "Journal file buffer !UL is less than minimum of database block size in 512 byte pages + 1 (!UL)", 2, + "GTMSECSHRREMSHM", "[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", 3, + "GTMSECSHRREMFILE", "[client pid !UL] File (!AD) removed", 3, "MUNODBNAME", "A database name or the region qualifier must be specified", 0, "FILECREATE", "!AD file !AD created", 4, "FILENOTCREATE", "!AD file !AD not created", 4, @@ -452,7 +452,7 @@ LITDEF err_msg merrors[] = { "WCWRNNOTCHG", "Not all specified database files were changed", 0, "ZCWRONGDESC", "A string longer than 65535 is passed via 32-bit descriptor", 0, "MUTNWARN", "Database file !AD has 0x!16@XQ more transactions to go before reaching the transaction number limit (0x!16@XQ). Renew database with MUPIP INTEG TN_RESET", 4, - "JNLNAMLEN", "Journal file name !AD: for database file !AD exceeds maximum length of !UL", 5, + "GTMSECSHRUPDDBHDR", "[client pid !UL] database fileheader (!AD) updated !AD", 5, "LCKSTIMOUT", "DAL timed lock request expired", 0, "CTLMNEMAXLEN", "The maximum length of a control mnemonic has been exceeded", 0, "CTLMNEXPECTED", "Control mnemonic is expected in this context", 0, @@ -505,7 +505,7 @@ LITDEF err_msg merrors[] = { "CENOINDIR", "Indirection type information not available for compiler escape feature", 0, "COLLATIONUNDEF", "Collation type !UL is not defined", 1, "RBWRNNOTCHG", "Not all specified database files were changed", 0, - "GTMSECSHRSRVF", "!AD - !UL : Attempt to service request failed", 3, + "GTMSECSHRSRVF", "!AD - !UL : Attempt to service request failed (retry = !UL)", 4, "FREEZECTRL", "Control Y or control C encountered during attempt to freeze the database. Aborting freeze.", 0, "JNLFLUSH", "Error flushing journal buffers to journal file !AD", 2, "CCPSIGDMP", "CCP non fatal dump, continuing operation. Report to your GT.M Support Channel.", 0, @@ -542,7 +542,7 @@ LITDEF err_msg merrors[] = { "MUSTANDALONE", "Could not get exclusive access to !AD", 2, "MUNOACTION", "MUPIP unable to perform requested action", 0, "RMBIGSHARE", "File with BIGRECORD specified may only be shared if READONLY", 0, - "TPRESTART", "Database !AD; code: !AD; blk: 0x!XL in glbl: ^!AD; pvtmods: !UL, blkmods: !UL, blklvl: !UL, type: !UL, readset: !UL, writeset: !UL, local_tn: !16@XQ", 14, + "TPRESTART", "Database !AD; code: !AD; blk: 0x!XL in glbl: ^!AD; pvtmods: !UL, blkmods: !UL, blklvl: !UL, type: !UL, readset: !UL, writeset: !UL, local_tn: 0x!16@XQ", 14, "SOCKWRITE", "Write to a TCP/IP socket failed", 0, "DBCNTRLERR", "Database file !AD: control error suspected but not found", 2, "NOTERMENV", "Environment variable TERM not set. Assuming \"unknown.\"", 0, @@ -576,26 +576,26 @@ LITDEF err_msg merrors[] = { "ZCPREALLNUMEX", "Pre-allocation value should be a decimal number", 0, "ZCPREALLVALPAR", "Pre-allocation allowed only for variables passed by reference", 0, "VERMISMATCH", "Attempt to access !AD with version !AD, while already using !AD", 6, - "JNLCNTRL", "Journal control unsynchronized. Journaling closed for !AD.", 2, + "JNLCNTRL", "Journal control unsynchronized for !AD.", 2, "TRIGNAMBAD", "Trigger initialization failed. Error while processing ^#t(\"!AD\",!AD)", 4, "BUFRDTIMEOUT", "Pid [0x!XL] timed out waiting for buffered read of blk [0x!XL] into cr [0x!XL] by process [0x!XL] to complete in database file !AD", 6, "INVALIDRIP", "Invalid read-in-progress field in Cache Record. Resetting and continuing. Region: !AD.", 2, "BLKSIZ512", "Block size !UL rounds to !UL", 2, "MUTEXERR", "Mutual Exclusion subsystem failure", 0, "JNLVSIZE", "Journal File !AD has incorrect virtual_filesize !UL. Allocation : !UL, Extension : !UL, Filesize : !UL, File system block size : !UL", 7, - "MUTEXLCKALERT", "Mutual Exclusion subsystem ALERT - lock attempt threshold crossed for region !AD. Process !UL is in crit.", 3, + "MUTEXLCKALERT", "Mutual Exclusion subsystem ALERT - lock attempt threshold crossed for region !AD. Process !UL is in crit cycle !UL.", 4, "MUTEXFRCDTERM", "Mutual Exclusion subsystem detected forced termination of process !UL. Crit salvaged from region !AD.", 3, "GTMSECSHR", "!UL : Error during gtmsecshr operation", 1, - "GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL.", 6, - "GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD.", 7, - "SOCKACTNA", "Action not appropriate for current socket", 0, + "GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL", 6, + "GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD", 7, + "FREEBLKSLOW", "Only !UL free blocks left out of !UL total blocks for !AD", 4, "PROTNOTSUP", "Protocol !AD not supported", 2, "DELIMSIZNA", "Delimiter size is not appropriate", 0, "INVCTLMNE", "Invalid control mnemonics", 0, "SOCKLISTEN", "Error listening on a socket", 0, "LQLENGTHNA", "Listening queue length !UL not appropriate. Must be between 1 and 5.", 1, "ADDRTOOLONG", "Socket address !AD of length !UL is longer than the maximum permissible length !UL", 4, - "UNUSEDMSG760", "LSNCONNOTCMP Last used in V5.4-002A", 0, + "GTMSECSHRGETSEMFAIL", "error getting semaphore errno = !UL", 1, "CPBEYALLOC", "Attempt to copy beyond the allocated buffer", 0, "DBRDONLY", "Database file !AD read only", 2, "DUPTN", "Duplicate transaction found [TN = 0x!16@XQ] at offset 0x!XL in journal file !AD", 4, @@ -616,7 +616,7 @@ LITDEF err_msg merrors[] = { "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, "JNLMINALIGN", "Journal Record Alignment !UL is less than the minimum value of !UL", 2, - "JNLDSKALIGN", "Journal Record Alignment !UL is not a multiple of 512", 1, + "UNUSEDMSG781", "JNLDSKALIGN : Last used in V4.3-000", 0, "JNLPOOLSETUP", "Journal Pool setup error", 0, "JNLSTATEOFF", "ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON", 2, "RECVPOOLSETUP", "Receive Pool setup error", 0, @@ -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, - "GTMSECSHRLOGF", "!AD - !UL : Error while creating gtmsecshr log file", 3, + "UNUSEDMSG809", "GTMSECSHRLOGF last used in V5.5-000", 0, "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, @@ -679,7 +679,7 @@ LITDEF err_msg merrors[] = { "BUFFLUFAILED", "Error flushing buffers from !AD for database file !AD", 4, "MUQUALINCOMP", "Incompatible qualifiers - FILE and REGION", 0, "DISTPATHMAX", "$gtm_dist path is greater than maximum (!UL)", 1, - "MAXTRACEHEIGHT", "The maximum trace tree height (!UL) has been exceeded. The trace information will be incomplete.", 1, + "UNUSEDMSG844", "MAXTRACEHEIGHT last used in V5.4-002", 0, "IMAGENAME", "The executing module name should be !AD instead of !AD", 4, "GTMSECSHRPERM", "The gtmsecshr module in $gtm_dist does not have the correct permission and uid", 0, "GTMDISTUNDEF", "Environment variable $gtm_dist is not defined", 0, @@ -733,8 +733,8 @@ 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, - "GTMSECSHRLOGSWH", "Error switching gtmsecshr log file gtmsecshr log -- !AD original log -- !AD error phase -- !AD process id -- !UL", 7, - "GTMSECSHRDEFLOG", "$gtm_log is either undefined or not defined to an absolute path, thus gtm_log is set to its default !AD", 2, + "UNUSEDMSG898", "GTMSECSHRLOGSWH last used in V5.5-000", 0, + "UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0, "DBBADNSUB", "!AD Bad numeric subscript", 2, "DBBADKYNM", "!AD Bad key name", 2, "DBBADPNTR", "!AD Bad pointer value in directory", 2, @@ -785,7 +785,7 @@ LITDEF err_msg merrors[] = { "DBMBPFRINT", "!AD Master bit map shows this map has space, agreeing with MUPIP INTEG", 2, "DBMAXKEYEXC", "!AD Maximum key size for database exceeds design maximum", 2, "DBMXRSEXCMIN", "!AD Maximum record size for database is less than the design minimum", 2, - "DBMAXRSEXBL", "!AD Maximum record size for database exceeds what the block size can support", 2, + "UNUSEDMSG950", "DBMAXRSEXBL : Last used in V5.5-000", 0, "DBREADBM", "!AD Read error on bitmap", 2, "DBCOMPTOOLRG", "!AD Record has too large compression count", 2, "DBVERPERFWARN2", "Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance", 2, @@ -807,14 +807,14 @@ LITDEF err_msg merrors[] = { "SEMWT2LONG", "Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL", 7, "REPLINSTOPEN", "Error opening replication instance file !AD", 2, "REPLINSTCLOSE", "Error closing replication instance file !AD", 2, - "JNLNOTFOUND", "File !AD does not exist -- possibly moved or deleted", 2, + "UNUSEDMSG972", "JNLNOTFOUND : Last used in V4.4-000", 0, "DBCRERR8", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16@XQ, expecting 0x!16@XQ -- called from module !AD at line !UL", 11, "NUMPROCESSORS", "Could not determine number of processors", 0, "DBADDRANGE8", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16@XQ was outside !AD range 0x!16@XQ to 0x!16@XQ", 9, "RNDWNSEMFAIL", "Attempting to acquire gds_rundown semaphore when it is already owned", 0, "GTMSECSHRSHUTDN", "gtmsecshr process has received a shutdown request -- shutting down", 0, - "NOSPACECRE", "Not enough space to create database file !AD. !UL blocks are needed, only !UL available.", 4, - "LOWSPACECRE", "Disk space for database file !AD is not enough for !UL future extensions. !UL !UL-byte blocks are needed, only !UL available.", 6, + "NOSPACECRE", "Not enough space to create database file !AD. !@ZQ blocks are needed, only !@ZQ available.", 4, + "LOWSPACECRE", "Disk space for database file !AD is not enough for !UL future extensions. !@ZQ !UL-byte blocks are needed, only !@ZQ available.", 6, "WAITDSKSPACE", "Process 0x!XL will wait !UL seconds for necessary disk space to become available for !AD ", 4, "OUTOFSPACE", "Database file !AD ran out of disk space. Detected by process !UL. !/Exit without clearing shared memory due to the disk space constraints. !/Make space and then perform mupip rundown to ensure database integrity.", 3, "JNLPVTINFO", "Pid 0x!XL!/ cycle 0x!XL fd_mismatch 0x!XL channel 0x!XL sync_io 0x!XL!/ pini_addr 0x!XL qio_active 0x!XL old_channel 0x!XL", 8, @@ -824,16 +824,16 @@ LITDEF err_msg merrors[] = { "RENAMEFAIL", "Rename of file !AD to !AD failed", 4, "FILERENAME", "File !AD is renamed to !AD", 4, "JNLBUFINFO", "Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL", 16, - "JNLQIOLOCKED", "Error obtaining io_in_prog lock on jnl-file !AD", 2, - "JNLEOFPREZERO", "Error while zeroing jnl-file !AD", 2, + "UNUSEDMSG989", "JNLQIOLOCKED : Last used in V4.4-000", 0, + "UNUSEDMSG990", "JNLEOFPREZERO : Last used in V4.4-000", 0, "TPNOTACID", "!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD", 8, "JNLSETDATA2LONG", "SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.", 2, "JNLNEWREC", "Target system cannot recognize journal record of type !UL, last recognized type is !UL", 2, "REPLFTOKSEM", "Error with replication semaphores for instance file !AD", 2, - "GETCWD", "Error getting current working directory for file !AD", 2, + "UNUSEDMSG995", "GETCWD : Last used before V4.0-001E", 0, "EXTRIOERR", "Error writing extract file !AD", 2, "EXTRCLOSEERR", "Error closing extract file !AD", 2, - "TRUNCATE", "Error while truncating jnl-file !AD to length !UL", 3, + "UNUSEDMSG998", "TRUNCATE : Last used in V4.3-001F", 0, "REPLEXITERR", "Replication process encountered an error while exiting", 0, "MUDESTROYSUC", "Global section (!AD) corresponding to file !AD successfully destroyed", 4, "DBRNDWN", "Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.", 2, @@ -846,7 +846,7 @@ LITDEF err_msg merrors[] = { "TCSETATTR", "Error while setting terminal attributes on file descriptor !UL", 1, "IOWRITERR", "IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.", 5, "REPLINSTWRITE", "Error writing [0x!XL] bytes at offset [0x!16@XQ] in replication instance file !AD", 4, - "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL is incorrect, should be 0x!XL. Auto-corrected.", 4, + "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.", 4, "REQ2RESUME", "Request to resume suspended processing received from process !UL owned by userid !UL", 2, "TIMERHANDLER", "Incorrect SIGALRM handler (0x!XJ) found by !AD", 3, "FREEMEMORY", "Error occurred freeing memory from 0x!XJ", 1, @@ -860,7 +860,7 @@ LITDEF err_msg merrors[] = { "REPLACCSEM", "Error with replication access semaphore (id = !UL) for instance file !AD", 3, "JNLFLUSHNOPROG", "No progress while attempting to flush journal file !AD", 2, "REPLINSTCREATE", "Error creating replication instance file !AD", 2, - "SUSPENDING", "Suspending processing on user request or attempt to do terminal I/O while running in the background", 0, + "SUSPENDING", "Process Received Signal !UL. Suspending processing on user request or attempt to do terminal I/O while running in the background", 1, "SOCKBFNOTEMPTY", "Socket buffer size cannot be set to 0x!XL due to 0x!XL bytes of buffered data. Read first.", 2, "ILLESOCKBFSIZE", "The specified socket buffer size is 0x!XL, which is either 0 or too big", 1, "NOSOCKETINDEV", "There is no socket in the current socket device", 0, @@ -914,7 +914,7 @@ LITDEF err_msg merrors[] = { "SYSTEMVALUE", "Invalid value for $SYSTEM (!AD)", 2, "SIZENOTVALID4", "Size (in bytes) must be either 1, 2, or 4", 0, "STRNOTVALID", "Error: cannot convert !AD value to valid value", 2, - "RECNOCREJNL", "Recover could not create new journal file !AD", 2, + "UNUSEDMSG1079", "RECNOCREJNL : Last used in V4.3-001F", 0, "ERRWETRAP", "Error while processing $ETRAP", 0, "TRACINGON", "Tracing already turned on", 0, "CITABENV", "Environment variable for call-in table !AD not set", 2, @@ -942,9 +942,9 @@ LITDEF err_msg merrors[] = { "ZDIROUTOFSYNC", "$ZDIRECTORY !AD is not the same as its cached value !AD", 4, "GBLNOEXIST", "Global !AD no longer exists", 2, "MAXBTLEVEL", "Global !AD reached maximum level", 2, - "JNLSTRESTFL", "Failed to restore journaling state for database !AD", 2, + "UNUSEDMSG1107", "JNLSTRESTFL : found no evidence it ever was used in a production release", 0, "JNLALIGNSZCHG", "Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)", 1, - "MAXTRACELEVEL", "The maximum traceable level of !UL has been exceeded. The frame information will not be maintained.", 1, + "UNUSEDMSG1109", "MAXTRACELEVEL : last used in V5.4-002B", 0, "GVFAILCORE", "A core file is being created for later analysis if necessary", 0, "DBCDBNOCERTIFY", "Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN", 2, "DBFRZRESETSUC", "Freeze released successfully on database file !AD", 2, @@ -966,7 +966,7 @@ LITDEF err_msg merrors[] = { "PREVJNLLINKCUT", "Previous journal file name link set to NULL in new journal file !AD created for database file !AD", 4, "PREVJNLLINKSET", "Previous generation journal file name is changed from !AD to !AD", 4, "FILENAMETOOLONG", "File name too long", 0, - "UNUSEDMSG1131", "JNLCREATERR Last used in V5.4-001", 0, + "REQRECOV", "Error accessing database !AD. Must be recovered on cluster node !AD.", 4, "JNLTRANS2BIG", "Transaction needs an estimated [!UL blocks] in journal file !AD which exceeds the AUTOSWITCHLIMIT of !UL blocks", 4, "JNLSWITCHTOOSM", "Journal AUTOSWITCHLIMIT [!UL blocks] is less than Journal ALLOCATION [!UL blocks] for database file !AD", 4, "JNLSWITCHSZCHG", "Journal AUTOSWITCHLIMIT [!UL blocks] is rounded down to [!UL blocks] to equal the sum of Journal ALLOCATION [!UL blocks] and a multiple of Journal EXTENSION [!UL blocks] for database file !AD", 6, @@ -1090,7 +1090,7 @@ LITDEF err_msg merrors[] = { "REPLINSTSEQORD", "!AD has seqno [0x!16@XQ] which is less than last record seqno [0x!16@XQ] in replication instance file !AD", 6, "REPLINSTSTNDALN", "Could not get exclusive access to replication instance file !AD", 2, "REPLREQROLLBACK", "Replication instance file !AD indicates abnormal shutdown or an incomplete ROLLBACK. Run MUPIP JOURNAL ROLLBACK first", 2, - "UNUSEDMSG1255", "REPLUPGRADEPRI : Last used in V5.4-002B", 0, + "REQROLLBACK", "Error accessing database !AD. Run MUPIP JOURNAL ROLLBACK on cluster node !AD.", 4, "UNUSEDMSG1256", "REPLUPGRADESEC : Last used in V5.4-002B", 0, "SRCSRVEXISTS", "Source server for secondary instance !AD is already running with pid !UL", 3, "SRCSRVNOTEXIST", "Source server for secondary instance !AD is not alive", 2, @@ -1132,7 +1132,7 @@ LITDEF err_msg merrors[] = { "COMMITWAITPID", "Pid !UL waited !UL minute(s) for pid !UL to finish commits to block 0x!XL in database file !AD", 6, "UPDREPLSTATEOFF", "Error replicating global ^!AD as it maps to database !AD which has replication turned OFF", 4, "LITNONGRAPH", "M standard requires graphics in string literals", 0, - "DBFHEADERR8", "Database file !AD: control problem: !AD was 0x!XJ expecting 0x!XJ", 6, + "DBFHEADERR8", "Database file !AD: control problem: !AD was 0x!16@XQ expecting 0x!16@XQ", 6, "MMBEFOREJNL", "BEFORE image journaling cannot be set with MM access method in database file !AD", 2, "MMNOBFORRPL", "Replication cannot be used in database file !AD which uses MM access method and NOBEFORE image journaling", 2, "KILLABANDONED", "Abandoned kills counter is greater than zero for file !AD, !AD", 4, @@ -1145,15 +1145,15 @@ LITDEF err_msg merrors[] = { "DZWRNOALIAS", "$ZWRTAC cannot be aliased", 0, "FREEZEERR", "Error while trying to !AD region !AD", 4, "CLOSEFAIL", "Error while closing file descriptor !SL", 1, - "CRYPTINIT", "Error initializing encryption library. !AD", 2, - "CRYPTOPFAILED", "Encrypt/Decrypt operation failed. !AD", 2, - "CRYPTDLNOOPEN", "Error loading encryption library. !AD", 2, + "CRYPTINIT", "Could not initialize encryption library while opening encrypted file !AD. !AD", 4, + "CRYPTOPFAILED", "Encrypt/Decrypt operation failed for file !AD. !AD", 4, + "CRYPTDLNOOPEN", "Could not load encryption library while opening encrypted file !AD. !AD", 4, "CRYPTNOV4", "!AD is an encrypted database. Cannot downgrade(to V4) with Encryption option enabled.", 2, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "CRYPTJNLWRONGHASH", "Encryption key hash mismatch between journal file !AD and corresponding database file !AD", 4, - "CRYPTKEYFETCHFAILED", "Cannot obtain encryption key for !AD. !AD", 4, - "CRYPTKEYFETCHFAILEDNF", "Cannot obtain encryption key. !AD", 2, - "CRYPTHASHGENFAILED", "Error generating encryption hash. !AD", 2, + "CRYPTKEYFETCHFAILED", "Could not retrieve encryption key corresponding to file !AD. !AD", 4, + "CRYPTKEYFETCHFAILEDNF", "Could not retrieve encryption key during !AD operation key. !AD", 4, + "CRYPTHASHGENFAILED", "Could not generate cryptographic hash for symmetric key corresponding to file !AD. !AD", 4, "CRYPTNOPSWDINTP", "Cannot prompt for password inside a TP transaction.", 0, "BADTAG", "Unable to use file !AD (CCSID !UL) with CCSID !UL", 4, "ICUVERLT36", "!AD !UL.!UL. ICU version greater than or equal to 3.6 should be used", 4, @@ -1189,7 +1189,7 @@ LITDEF err_msg merrors[] = { "TRIGTLVLCHNG", "Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started", 2, "TRIGNAMEUNIQ", "Unable to make trigger name !AD unique beyond !UL versions already loaded", 3, "ZTRIGINVACT", "Missing or invalid parameter in position !UL given to $ZTRIGGER()", 1, - "UNUSEDMSG1354", "ZTRIGNOTP : Last used in V5.4-001", 0, + "INDRCOMPFAIL", "Compilation of indirection failed", 0, "QUITALSINV", "QUIT * return when the extrinsic was not invoked with SET *", 0, "PROCTERM", "!AD process termination due to !AD (return code !UL) from !AD", 7, "SRCLNNTDSP", "Source lines exceeding !UL character width are not displayed", 1, @@ -1202,10 +1202,10 @@ 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@XQ", 7, "TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0, - "TPLOCKRESTMAX", "Transaction restarts due to unavailability of locks not allowed in a final TP retry more than !UL times", 1, + "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0, "GBLEXPECTED", "Global variable reference expected in this context", 0, "GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2, - "UNUSEDMSG1370", "ONLYLDTRIG: Last used in V5.4-001", 0, + "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@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, @@ -1217,7 +1217,7 @@ LITDEF err_msg merrors[] = { "REPLXENDIANFAIL", "!AD side encountered error while doing endian conversion at journal sequence number 0x!16@XQ", 3, "ZGOTOINVLVL2", "ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)", 0, "GTMSECSHRCHDIRF", "gtmsecshr unable to chdir to its temporary directory (!AD)", 2, - "UNUSEDMSG1382", "FORCTRLINDX: Only used in V5.4-002", 0, + "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@XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1, @@ -1248,12 +1248,12 @@ LITDEF err_msg merrors[] = { "NORESYNCUPDATERONLY", "NORESYNC qualifier only allowed on a Supplementary Instance which allows local updates", 0, "NOSUPPLSUPPL", "Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD", 4, "REPL2OLD", "Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD", 4, - "RCVR2MANY", "The instance already has the maximum supportable number of receiver servers [!UL] active", 1, - "RLBKCONFIGBNDRY", "Rollback encountered journal records indicating current source !AD replaced old source !AD; cannot rollback past sequence number 0x!16@XQ", 5, + "EXTRFILEXISTS", "Error opening output file: !AD -- File exists", 2, + "MUUSERECOV", "Abnormal shutdown of journaled database !AD detected", 2, "SECNOTSUPPLEMENTARY", "!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD ", 4, "SUPRCVRNEEDSSUPSRC", "Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD", 4, - "SYNCTOSAMETYPE", "Source instance !AD and receiver instance !AD must either be both supplementary or both non-supplementary for them to synchronize their state", 4, - "TARGINSRUNNING", "Cannot change the instance definition of instance !AD while it is running", 2, + "UNUSEDMSG1417", "SYNCTOSAMETYPE: Never used before so slot free for reuse", 0, + "UNUSEDMSG1418", "TARGINSRUNNING: Never used before so slot free for reuse", 0, "UPDSYNC2MTINS", "Can only UPDATERESYNC with an empty instance file", 0, "UPDSYNCINSTFILE", "Error with instance file name specified in UPDATERESYNC qualifier", 0, "REUSEINSTNAME", "Error with instance name specified in REUSE qualifier", 0, @@ -1272,7 +1272,7 @@ LITDEF err_msg merrors[] = { "ORLBKNOV4BLK", "Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue", 4, "DBROLLEDBACK", "Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid", 0, "DSEWCREINIT", "Database cache reinitialized by DSE for region !AD", 2, - "RNDWNSKIPCNT", "A total of !UL process(es) skipped database rundown due to a concurrent ONLINE ROLLBACK", 1, + "MURNDWNOVRD", "OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD", 2, "REPLONLNRLBK", "ONLINE ROLLBACK detected. Starting afresh", 0, "SRVLCKWT2LNG", "PID !UL is holding the source server lock. Waited for !UL minute(s). Now exiting", 2, "IGNBMPMRKFREE", "Ignoring bitmap free-up operation for region !AD (!AD) due to concurrent ONLINE ROLLBACK", 4, @@ -1295,6 +1295,74 @@ LITDEF err_msg merrors[] = { "STRMSEQMISMTCH", "Unable to play update on Stream !2UL with seqno [0x!16@XQ] as receiving instance has a different stream seqno [0x!16@XQ]", 3, "LOCKSPACEINFO", "Region: !AD: processes on queue: !UL/!UL; LOCK slots in use: !UL/!UL; name space!ADfull", 8, "JRTNULLFAIL", "Applying NULL journal record failed. Failure code: !AD.", 2, + "LOCKSUB2LONG", "Following subscript is !UL bytes long which exceeds 255 byte limit.", 1, + "RESRCWAIT", "Waiting briefly for the !AD semaphore for region !AD (!AD) was held by PID !UL (Sem. ID: !UL).", 8, + "RESRCINTRLCKBYPAS", "!AD with PID !UL bypassing the !AD semaphore for region !AD (!AD) was held by PID !UL.", 10, + "DBFHEADERRANY", "Database file !AD: control problem: !AD was 0x!XJ expecting 0x!XJ", 6, + "REPLINSTFROZEN", "Instance !AZ is now Frozen", 1, + "REPLINSTFREEZECOMMENT", "Freeze Comment: !AZ", 1, + "REPLINSTUNFROZEN", "Instance !AZ is now Unfrozen", 1, + "DSKNOSPCAVAIL", "Attempted write to file !AD failed due to lack of disk space. Retrying indefinitely.", 2, + "DSKNOSPCBLOCKED", "Retry of write to file !AD suspended due to new instance freeze. Waiting for instance to be unfrozen.", 2, + "DSKSPCAVAILABLE", "Write to file !AD succeeded after out-of-space condition cleared", 2, + "ENOSPCQIODEFER", "Write to file !AD deferred due to lack of disk space", 2, + "CUSTOMFILOPERR", "Error while doing !AD operation on file !AD", 4, + "CUSTERRNOTFND", "Error mnemonic !AD specified in custom errors file is not valid for this version of GT.M", 2, + "CUSTERRSYNTAX", "Syntax error in file !AD at line number !UL", 3, + "ORLBKINPROG", "Online ROLLBACK in progress by PID !UL in region !AD", 3, + "DBSPANGLOINCMP", "!AD Spanning node is missing. Block no !UL of spanning node is missing", 3, + "DBSPANCHUNKORD", "!AD Chunk of !UL blocks is out of order", 3, + "DBDATAMX", "!AD Record too large", 2, + "DBIOERR", "Error while doing write operation on region !AD (!AD)", 4, + "INITORRESUME", "UPDATERESYNC on a Supplementary Instance must additionally specify INITIALIZE or RESUME", 0, + "GTMSECSHRNOARG0", "gtmsecshr cannot identify its origin - argv[0] is null", 0, + "GTMSECSHRISNOT", "gtmsecshr is not running as gtmsecshr but !AD - must be gtmsecshr", 2, + "GTMSECSHRBADDIR", "gtmsecshr is not running from $gtm_dist/gtmsecshrdir or $gtm_dist cannot be determined", 0, + "JNLBUFFREGUPD", "Journal file buffer size for region !AD has been adjusted from !UL to !UL.", 4, + "JNLBUFFDBUPD", "Journal file buffer size for database file !AD has been adjusted from !UL to !UL.", 4, + "LOCKINCR2HIGH", "Attempt to increment a LOCK more than !UL times", 1, + "LOCKIS", "!_!_Resource name: !AD", 2, + "LDSPANGLOINCMP", "Incomplete spanning node found during load", 0, + "MUFILRNDWNFL2", "Database section (id = !UL) belonging to database file !AD rundown failed", 3, + "MUINSTFROZEN", "!AD : Instance !AZ is frozen. Waiting for instance to be unfrozen before proceeding with writes to database file !AD", 5, + "MUINSTUNFROZEN", "!AD : Instance !AZ is now Unfrozen. Continuing with writes to database file !AD", 5, + "GTMEISDIR", "!AD : Is a directory", 2, + "SPCLZMSG", "The following error message cannot be driven through ZMESSAGE", 0, + "MUNOTALLINTEG", "At least one region skipped. See the earlier messages", 0, + "BKUPRUNNING", "Process !UL is currently backing up region !AD. Cannot start another backup.", 3, + "MUSIZEINVARG", "MUPIP SIZE : Invalid parameter value for: !AD", 2, + "MUSIZEFAIL", "MUPIP SIZE : failed. Failure code: !AD.", 2, + "SIDEEFFECTEVAL", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in actuallist, function arguments, non-Boolean binary operands or subscripts", 0, + "CRYPTINIT2", "Could not initialize encryption library !AD. !AD", 4, + "CRYPTDLNOOPEN2", "Could not load encryption library !AD. !AD", 4, + "CRYPTBADCONFIG", "Could not retrieve data from encrypted file !AD due to bad encryption configuration. !AD", 4, + "DBCOLLREQ", "JOURNAL EXTRACT proceeding without collation information for globals in database. !AD !AD", 4, + "SETEXTRENV", "Database files are missing or Instance is frozen; supply the database files, wait for the freeze to lift or define gtm_extract_nocol to extract possibly incorrect collation", 0, + "NOTALLDBRNDWN", "Not all regions were successfully rundown", 0, + "TPRESTNESTERR", "TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this", 0, + "JNLFILRDOPN", "Error opening journal file !AD for read for database file !AD", 4, + "SEQNUMSEARCHTIMEOUT", "Timed out trying to find sequence number !@ZQ [0x!16@XQ] in Journal File(s). See above messages for details. Source server exiting", 2, + "FTOKKEY", "FTOK key 0x!XL", 1, + "SEMID", "Semaphore id !UL", 1, + "JNLQIOSALVAGE", "Journal IO lock salvaged", 0, + "FAKENOSPCLEARED", "DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago", 1, + "MMFILETOOLARGE", "Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform", 4, + "BADZPEEKARG", "Missing, invalid or surplus !AD parameter for $ZPEEK()", 2, + "BADZPEEKRANGE", "Access exception raised in memory range given to $ZPEEK()", 0, + "BADZPEEKFMT", "$ZPEEK() value length inappropriate for selected format", 0, + "DBMBMINCFREFIXED", "Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected", 1, + "NULLENTRYREF", "JOB command did not specify entryref", 0, + "ZPEEKNORPLINFO", "$ZPEEK() unable to access requested replication structure", 0, + "MMREGNOACCESS", "Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs", 4, + "MALLOCMAXUNIX", "Exceeded maximum allocation defined by $gtm_max_storalloc", 0, + "MALLOCMAXVMS", "Exceeded maximum allocation defined by GTM_MAX_STORALLOC", 0, + "HOSTCONFLICT", "Host !AD could not open database file !AD because it is marked as already open on node !AD", 6, + "GETADDRINFO", "Error in getting address info", 0, + "GETNAMEINFO", "Error in getting name info", 0, + "SOCKBIND", "Error in binding TCP socket", 0, + "INSTFRZDEFER", "Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict", 4, + "REGOPENRETRY", "Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...", 4, + "REGOPENFAIL", "Failed to open region !AD (!AD) due to conflicting database shutdown activity", 4, }; LITDEF int ERR_ACK = 150372361; @@ -1379,11 +1447,11 @@ LITDEF int ERR_GVSUBOFLOW = 150372986; LITDEF int ERR_GVUNDEF = 150372994; LITDEF int ERR_TRANSNEST = 150373002; LITDEF int ERR_INDEXTRACHARS = 150373010; -LITDEF int ERR_INDMAXNEST = 150373018; +LITDEF int ERR_UNUSEDMSG260 = 150373018; LITDEF int ERR_INDRMAXLEN = 150373026; LITDEF int ERR_INSFFBCNT = 150373034; LITDEF int ERR_INTEGERRS = 150373042; -LITDEF int ERR_INVCMD = 150373050; +LITDEF int ERR_INVCMD = 150373048; LITDEF int ERR_INVFCN = 150373058; LITDEF int ERR_INVOBJ = 150373066; LITDEF int ERR_INVSVN = 150373074; @@ -1479,7 +1547,7 @@ LITDEF int ERR_TERMASTQUOTA = 150373786; LITDEF int ERR_TEXTARG = 150373794; LITDEF int ERR_TMPSTOREMAX = 150373802; LITDEF int ERR_VIEWCMD = 150373810; -LITDEF int ERR_TXTNEGLIN = 150373818; +LITDEF int ERR_JNI = 150373818; LITDEF int ERR_TXTSRCFMT = 150373826; LITDEF int ERR_UIDMSG = 150373834; LITDEF int ERR_UIDSND = 150373842; @@ -1488,9 +1556,9 @@ LITDEF int ERR_UNIMPLOP = 150373858; LITDEF int ERR_VAREXPECTED = 150373866; LITDEF int ERR_VARRECBLKSZ = 150373874; LITDEF int ERR_MAXARGCNT = 150373882; -LITDEF int ERR_WCFAIL = 150373890; +LITDEF int ERR_GTMSECSHRSEMGET = 150373890; LITDEF int ERR_VIEWARGCNT = 150373898; -LITDEF int ERR_XKILLCNTEXC = 150373906; +LITDEF int ERR_GTMSECSHRDMNSTARTED = 150373907; LITDEF int ERR_ZATTACHERR = 150373914; LITDEF int ERR_ZDATEFMT = 150373922; LITDEF int ERR_ZEDFILSPEC = 150373930; @@ -1545,7 +1613,7 @@ LITDEF int ERR_GVRUNDOWN = 150374314; LITDEF int ERR_LKRUNDOWN = 150374322; LITDEF int ERR_IORUNDOWN = 150374330; LITDEF int ERR_FILENOTFND = 150374338; -LITDEF int ERR_MUFILRNDWNFL = 150374347; +LITDEF int ERR_MUFILRNDWNFL = 150374346; LITDEF int ERR_JNLTMQUAL1 = 150374354; LITDEF int ERR_FORCEDHALT = 150374364; LITDEF int ERR_LOADEOF = 150374370; @@ -1557,14 +1625,14 @@ LITDEF int ERR_GVZPREVFAIL = 150374410; LITDEF int ERR_MULTFORMPARM = 150374418; LITDEF int ERR_QUITARGUSE = 150374426; LITDEF int ERR_NAMEEXPECTED = 150374434; -LITDEF int ERR_UNUSEDMSG438 = 150374442; +LITDEF int ERR_FALLINTOFLST = 150374442; LITDEF int ERR_NOTEXTRINSIC = 150374450; -LITDEF int ERR_UNUSEDMSG440 = 150374458; +LITDEF int ERR_GTMSECSHRREMSEMFAIL = 150374458; LITDEF int ERR_FMLLSTMISSING = 150374466; LITDEF int ERR_ACTLSTTOOLONG = 150374474; LITDEF int ERR_ACTOFFSET = 150374482; LITDEF int ERR_MAXACTARG = 150374490; -LITDEF int ERR_GTMDUMPFAIL = 150374498; +LITDEF int ERR_GTMSECSHRREMSEM = 150374498; LITDEF int ERR_JNLTMQUAL2 = 150374506; LITDEF int ERR_GDINVALID = 150374514; LITDEF int ERR_ASSERT = 150374524; @@ -1708,17 +1776,17 @@ LITDEF int ERR_LDGOQFMT = 150375618; LITDEF int ERR_BEGINST = 150375627; LITDEF int ERR_INVMVXSZ = 150375636; LITDEF int ERR_JNLWRTNOWWRTR = 150375642; -LITDEF int ERR_MUPGDERR = 150375650; +LITDEF int ERR_GTMSECSHRSHMCONCPROC = 150375650; LITDEF int ERR_JNLINVALLOC = 150375656; LITDEF int ERR_JNLINVEXT = 150375664; LITDEF int ERR_MUPCLIERR = 150375674; LITDEF int ERR_JNLTMQUAL4 = 150375682; -LITDEF int ERR_JNLBUFFTOOLG = 150375688; -LITDEF int ERR_JNLBUFFTOOSM = 150375696; +LITDEF int ERR_GTMSECSHRREMSHM = 150375691; +LITDEF int ERR_GTMSECSHRREMFILE = 150375699; LITDEF int ERR_MUNODBNAME = 150375706; LITDEF int ERR_FILECREATE = 150375715; LITDEF int ERR_FILENOTCREATE = 150375723; -LITDEF int ERR_JNLPROCSTUCK = 150375731; +LITDEF int ERR_JNLPROCSTUCK = 150375728; LITDEF int ERR_INVGLOBALQUAL = 150375738; LITDEF int ERR_COLLARGLONG = 150375746; LITDEF int ERR_NOPINI = 150375754; @@ -1736,7 +1804,7 @@ LITDEF int ERR_WCERRNOTCHG = 150375842; LITDEF int ERR_WCWRNNOTCHG = 150375848; LITDEF int ERR_ZCWRONGDESC = 150375858; LITDEF int ERR_MUTNWARN = 150375864; -LITDEF int ERR_JNLNAMLEN = 150375874; +LITDEF int ERR_GTMSECSHRUPDDBHDR = 150375875; LITDEF int ERR_LCKSTIMOUT = 150375880; LITDEF int ERR_CTLMNEMAXLEN = 150375890; LITDEF int ERR_CTLMNEXPECTED = 150375898; @@ -1872,14 +1940,14 @@ LITDEF int ERR_MUTEXFRCDTERM = 150376928; LITDEF int ERR_GTMSECSHR = 150376938; LITDEF int ERR_GTMSECSHRSRVFID = 150376944; LITDEF int ERR_GTMSECSHRSRVFIL = 150376952; -LITDEF int ERR_SOCKACTNA = 150376962; +LITDEF int ERR_FREEBLKSLOW = 150376960; LITDEF int ERR_PROTNOTSUP = 150376970; LITDEF int ERR_DELIMSIZNA = 150376978; LITDEF int ERR_INVCTLMNE = 150376986; LITDEF int ERR_SOCKLISTEN = 150376994; LITDEF int ERR_LQLENGTHNA = 150377002; LITDEF int ERR_ADDRTOOLONG = 150377010; -LITDEF int ERR_UNUSEDMSG760 = 150377018; +LITDEF int ERR_GTMSECSHRGETSEMFAIL = 150377018; LITDEF int ERR_CPBEYALLOC = 150377026; LITDEF int ERR_DBRDONLY = 150377034; LITDEF int ERR_DUPTN = 150377040; @@ -1900,7 +1968,7 @@ LITDEF int ERR_BCKUPBUFLUSH = 150377154; LITDEF int ERR_NOFORKCORE = 150377160; LITDEF int ERR_JNLREAD = 150377170; LITDEF int ERR_JNLMINALIGN = 150377176; -LITDEF int ERR_JNLDSKALIGN = 150377184; +LITDEF int ERR_UNUSEDMSG781 = 150377186; LITDEF int ERR_JNLPOOLSETUP = 150377194; LITDEF int ERR_JNLSTATEOFF = 150377202; LITDEF int ERR_RECVPOOLSETUP = 150377210; @@ -1928,7 +1996,7 @@ LITDEF int ERR_MUKILLIP = 150377376; LITDEF int ERR_JNLRDONLY = 150377386; LITDEF int ERR_ANCOMPTINC = 150377394; LITDEF int ERR_ABNCOMPTINC = 150377402; -LITDEF int ERR_GTMSECSHRLOGF = 150377410; +LITDEF int ERR_UNUSEDMSG809 = 150377410; LITDEF int ERR_SOCKNOTFND = 150377418; LITDEF int ERR_CURRSOCKOFR = 150377426; LITDEF int ERR_SOCKETEXIST = 150377434; @@ -1963,7 +2031,7 @@ LITDEF int ERR_RECSIZENOTEVEN = 150377658; LITDEF int ERR_BUFFLUFAILED = 150377666; LITDEF int ERR_MUQUALINCOMP = 150377674; LITDEF int ERR_DISTPATHMAX = 150377682; -LITDEF int ERR_MAXTRACEHEIGHT = 150377691; +LITDEF int ERR_UNUSEDMSG844 = 150377690; LITDEF int ERR_IMAGENAME = 150377698; LITDEF int ERR_GTMSECSHRPERM = 150377706; LITDEF int ERR_GTMDISTUNDEF = 150377714; @@ -2017,8 +2085,8 @@ LITDEF int ERR_SECONDAHEAD = 150378090; LITDEF int ERR_SCNDDBNOUPD = 150378098; LITDEF int ERR_MUINFOUINT4 = 150378107; LITDEF int ERR_NLMISMATCHCALC = 150378114; -LITDEF int ERR_GTMSECSHRLOGSWH = 150378122; -LITDEF int ERR_GTMSECSHRDEFLOG = 150378131; +LITDEF int ERR_UNUSEDMSG898 = 150378122; +LITDEF int ERR_UNUSEDMSG899 = 150378131; LITDEF int ERR_DBBADNSUB = 150378138; LITDEF int ERR_DBBADKYNM = 150378146; LITDEF int ERR_DBBADPNTR = 150378154; @@ -2069,7 +2137,7 @@ LITDEF int ERR_DBMBPFRDLBM = 150378504; LITDEF int ERR_DBMBPFRINT = 150378512; LITDEF int ERR_DBMAXKEYEXC = 150378522; LITDEF int ERR_DBMXRSEXCMIN = 150378530; -LITDEF int ERR_DBMAXRSEXBL = 150378538; +LITDEF int ERR_UNUSEDMSG950 = 150378538; LITDEF int ERR_DBREADBM = 150378546; LITDEF int ERR_DBCOMPTOOLRG = 150378554; LITDEF int ERR_DBVERPERFWARN2 = 150378560; @@ -2091,7 +2159,7 @@ LITDEF int ERR_MUTEXRSRCCLNUP = 150378683; LITDEF int ERR_SEMWT2LONG = 150378690; LITDEF int ERR_REPLINSTOPEN = 150378698; LITDEF int ERR_REPLINSTCLOSE = 150378706; -LITDEF int ERR_JNLNOTFOUND = 150378715; +LITDEF int ERR_UNUSEDMSG972 = 150378714; LITDEF int ERR_DBCRERR8 = 150378723; LITDEF int ERR_NUMPROCESSORS = 150378728; LITDEF int ERR_DBADDRANGE8 = 150378739; @@ -2108,16 +2176,16 @@ LITDEF int ERR_REPLJNLCLOSED = 150378818; LITDEF int ERR_RENAMEFAIL = 150378824; LITDEF int ERR_FILERENAME = 150378835; LITDEF int ERR_JNLBUFINFO = 150378843; -LITDEF int ERR_JNLQIOLOCKED = 150378850; -LITDEF int ERR_JNLEOFPREZERO = 150378858; +LITDEF int ERR_UNUSEDMSG989 = 150378850; +LITDEF int ERR_UNUSEDMSG990 = 150378858; LITDEF int ERR_TPNOTACID = 150378867; LITDEF int ERR_JNLSETDATA2LONG = 150378874; LITDEF int ERR_JNLNEWREC = 150378882; LITDEF int ERR_REPLFTOKSEM = 150378890; -LITDEF int ERR_GETCWD = 150378898; +LITDEF int ERR_UNUSEDMSG995 = 150378898; LITDEF int ERR_EXTRIOERR = 150378906; LITDEF int ERR_EXTRCLOSEERR = 150378914; -LITDEF int ERR_TRUNCATE = 150378922; +LITDEF int ERR_UNUSEDMSG998 = 150378922; LITDEF int ERR_REPLEXITERR = 150378930; LITDEF int ERR_MUDESTROYSUC = 150378939; LITDEF int ERR_DBRNDWN = 150378946; @@ -2130,7 +2198,7 @@ LITDEF int ERR_TCGETATTR = 150378994; LITDEF int ERR_TCSETATTR = 150379002; LITDEF int ERR_IOWRITERR = 150379010; LITDEF int ERR_REPLINSTWRITE = 150379018; -LITDEF int ERR_DBBADFREEBLKCTR = 150379027; +LITDEF int ERR_DBBADFREEBLKCTR = 150379024; LITDEF int ERR_REQ2RESUME = 150379035; LITDEF int ERR_TIMERHANDLER = 150379040; LITDEF int ERR_FREEMEMORY = 150379050; @@ -2138,11 +2206,11 @@ LITDEF int ERR_MUREPLSECDEL = 150379059; LITDEF int ERR_MUREPLSECNOTDEL = 150379067; LITDEF int ERR_MUJPOOLRNDWNSUC = 150379075; LITDEF int ERR_MURPOOLRNDWNSUC = 150379083; -LITDEF int ERR_MUJPOOLRNDWNFL = 150379091; -LITDEF int ERR_MURPOOLRNDWNFL = 150379099; +LITDEF int ERR_MUJPOOLRNDWNFL = 150379090; +LITDEF int ERR_MURPOOLRNDWNFL = 150379098; LITDEF int ERR_MUREPLPOOL = 150379107; LITDEF int ERR_REPLACCSEM = 150379114; -LITDEF int ERR_JNLFLUSHNOPROG = 150379122; +LITDEF int ERR_JNLFLUSHNOPROG = 150379120; LITDEF int ERR_REPLINSTCREATE = 150379130; LITDEF int ERR_SUSPENDING = 150379139; LITDEF int ERR_SOCKBFNOTEMPTY = 150379146; @@ -2198,7 +2266,7 @@ LITDEF int ERR_NOSUBSCRIPT = 150379538; LITDEF int ERR_SYSTEMVALUE = 150379546; LITDEF int ERR_SIZENOTVALID4 = 150379554; LITDEF int ERR_STRNOTVALID = 150379562; -LITDEF int ERR_RECNOCREJNL = 150379571; +LITDEF int ERR_UNUSEDMSG1079 = 150379570; LITDEF int ERR_ERRWETRAP = 150379578; LITDEF int ERR_TRACINGON = 150379587; LITDEF int ERR_CITABENV = 150379594; @@ -2216,7 +2284,7 @@ LITDEF int ERR_SETZDIR = 150379682; LITDEF int ERR_JOBACTREF = 150379690; LITDEF int ERR_ECLOSTMID = 150379696; LITDEF int ERR_ZFF2MANY = 150379706; -LITDEF int ERR_JNLFSYNCLSTCK = 150379715; +LITDEF int ERR_JNLFSYNCLSTCK = 150379712; LITDEF int ERR_DELIMWIDTH = 150379722; LITDEF int ERR_DBBMLCORRUPT = 150379730; LITDEF int ERR_DLCKAVOIDANCE = 150379738; @@ -2226,9 +2294,9 @@ LITDEF int ERR_INVZDIRFORM = 150379762; LITDEF int ERR_ZDIROUTOFSYNC = 150379768; LITDEF int ERR_GBLNOEXIST = 150379779; LITDEF int ERR_MAXBTLEVEL = 150379786; -LITDEF int ERR_JNLSTRESTFL = 150379794; +LITDEF int ERR_UNUSEDMSG1107 = 150379794; LITDEF int ERR_JNLALIGNSZCHG = 150379803; -LITDEF int ERR_MAXTRACELEVEL = 150379811; +LITDEF int ERR_UNUSEDMSG1109 = 150379810; LITDEF int ERR_GVFAILCORE = 150379818; LITDEF int ERR_DBCDBNOCERTIFY = 150379826; LITDEF int ERR_DBFRZRESETSUC = 150379835; @@ -2250,7 +2318,7 @@ LITDEF int ERR_JNLFNF = 150379955; LITDEF int ERR_PREVJNLLINKCUT = 150379963; LITDEF int ERR_PREVJNLLINKSET = 150379971; LITDEF int ERR_FILENAMETOOLONG = 150379978; -LITDEF int ERR_UNUSEDMSG1131 = 150379986; +LITDEF int ERR_REQRECOV = 150379986; LITDEF int ERR_JNLTRANS2BIG = 150379994; LITDEF int ERR_JNLSWITCHTOOSM = 150380002; LITDEF int ERR_JNLSWITCHSZCHG = 150380011; @@ -2374,7 +2442,7 @@ LITDEF int ERR_REPLINSTSECUNDF = 150380946; LITDEF int ERR_REPLINSTSEQORD = 150380954; LITDEF int ERR_REPLINSTSTNDALN = 150380962; LITDEF int ERR_REPLREQROLLBACK = 150380970; -LITDEF int ERR_UNUSEDMSG1255 = 150380978; +LITDEF int ERR_REQROLLBACK = 150380978; LITDEF int ERR_UNUSEDMSG1256 = 150380986; LITDEF int ERR_SRCSRVEXISTS = 150380994; LITDEF int ERR_SRCSRVNOTEXIST = 150381002; @@ -2473,7 +2541,7 @@ LITDEF int ERR_TRIGTCOMMIT = 150381738; LITDEF int ERR_TRIGTLVLCHNG = 150381746; LITDEF int ERR_TRIGNAMEUNIQ = 150381754; LITDEF int ERR_ZTRIGINVACT = 150381762; -LITDEF int ERR_UNUSEDMSG1354 = 150381770; +LITDEF int ERR_INDRCOMPFAIL = 150381770; LITDEF int ERR_QUITALSINV = 150381778; LITDEF int ERR_PROCTERM = 150381784; LITDEF int ERR_SRCLNNTDSP = 150381795; @@ -2486,10 +2554,10 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842; LITDEF int ERR_SSATTACHSHM = 150381850; LITDEF int ERR_TRIGDEFNOSYNC = 150381856; LITDEF int ERR_TRESTMAX = 150381866; -LITDEF int ERR_TPLOCKRESTMAX = 150381874; +LITDEF int ERR_UNUSEDMSG1367 = 150381874; LITDEF int ERR_GBLEXPECTED = 150381882; LITDEF int ERR_GVZTRIGFAIL = 150381890; -LITDEF int ERR_UNUSEDMSG1370 = 150381898; +LITDEF int ERR_MUUSERLBK = 150381898; LITDEF int ERR_SETINSETTRIGONLY = 150381906; LITDEF int ERR_DZTRIGINTRIG = 150381914; LITDEF int ERR_SECNODZTRIGINTP = 150381922; @@ -2501,7 +2569,7 @@ LITDEF int ERR_REPLNOXENDIAN = 150381962; LITDEF int ERR_REPLXENDIANFAIL = 150381970; LITDEF int ERR_ZGOTOINVLVL2 = 150381978; LITDEF int ERR_GTMSECSHRCHDIRF = 150381986; -LITDEF int ERR_UNUSEDMSG1382 = 150381994; +LITDEF int ERR_JNLORDBFLU = 150381994; LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002; LITDEF int ERR_ZCINVALIDKEYWORD = 150382010; LITDEF int ERR_REPLNOMULTILINETRG = 150382018; @@ -2532,12 +2600,12 @@ LITDEF int ERR_NORESYNCSUPPLONLY = 150382210; LITDEF int ERR_NORESYNCUPDATERONLY = 150382218; LITDEF int ERR_NOSUPPLSUPPL = 150382226; LITDEF int ERR_REPL2OLD = 150382234; -LITDEF int ERR_RCVR2MANY = 150382242; -LITDEF int ERR_RLBKCONFIGBNDRY = 150382250; +LITDEF int ERR_EXTRFILEXISTS = 150382242; +LITDEF int ERR_MUUSERECOV = 150382250; LITDEF int ERR_SECNOTSUPPLEMENTARY = 150382258; LITDEF int ERR_SUPRCVRNEEDSSUPSRC = 150382266; -LITDEF int ERR_SYNCTOSAMETYPE = 150382274; -LITDEF int ERR_TARGINSRUNNING = 150382282; +LITDEF int ERR_UNUSEDMSG1417 = 150382275; +LITDEF int ERR_UNUSEDMSG1418 = 150382283; LITDEF int ERR_UPDSYNC2MTINS = 150382290; LITDEF int ERR_UPDSYNCINSTFILE = 150382298; LITDEF int ERR_REUSEINSTNAME = 150382306; @@ -2556,7 +2624,7 @@ LITDEF int ERR_ORLBKFRZOVER = 150382403; LITDEF int ERR_ORLBKNOV4BLK = 150382410; LITDEF int ERR_DBROLLEDBACK = 150382418; LITDEF int ERR_DSEWCREINIT = 150382427; -LITDEF int ERR_RNDWNSKIPCNT = 150382435; +LITDEF int ERR_MURNDWNOVRD = 150382435; LITDEF int ERR_REPLONLNRLBK = 150382442; LITDEF int ERR_SRVLCKWT2LNG = 150382450; LITDEF int ERR_IGNBMPMRKFREE = 150382459; @@ -2579,9 +2647,77 @@ LITDEF int ERR_STRMNUMMISMTCH2 = 150382586; LITDEF int ERR_STRMSEQMISMTCH = 150382594; LITDEF int ERR_LOCKSPACEINFO = 150382603; LITDEF int ERR_JRTNULLFAIL = 150382610; +LITDEF int ERR_LOCKSUB2LONG = 150382618; +LITDEF int ERR_RESRCWAIT = 150382627; +LITDEF int ERR_RESRCINTRLCKBYPAS = 150382635; +LITDEF int ERR_DBFHEADERRANY = 150382643; +LITDEF int ERR_REPLINSTFROZEN = 150382650; +LITDEF int ERR_REPLINSTFREEZECOMMENT = 150382659; +LITDEF int ERR_REPLINSTUNFROZEN = 150382667; +LITDEF int ERR_DSKNOSPCAVAIL = 150382675; +LITDEF int ERR_DSKNOSPCBLOCKED = 150382682; +LITDEF int ERR_DSKSPCAVAILABLE = 150382691; +LITDEF int ERR_ENOSPCQIODEFER = 150382699; +LITDEF int ERR_CUSTOMFILOPERR = 150382706; +LITDEF int ERR_CUSTERRNOTFND = 150382714; +LITDEF int ERR_CUSTERRSYNTAX = 150382722; +LITDEF int ERR_ORLBKINPROG = 150382731; +LITDEF int ERR_DBSPANGLOINCMP = 150382738; +LITDEF int ERR_DBSPANCHUNKORD = 150382746; +LITDEF int ERR_DBDATAMX = 150382754; +LITDEF int ERR_DBIOERR = 150382762; +LITDEF int ERR_INITORRESUME = 150382770; +LITDEF int ERR_GTMSECSHRNOARG0 = 150382778; +LITDEF int ERR_GTMSECSHRISNOT = 150382786; +LITDEF int ERR_GTMSECSHRBADDIR = 150382794; +LITDEF int ERR_JNLBUFFREGUPD = 150382800; +LITDEF int ERR_JNLBUFFDBUPD = 150382808; +LITDEF int ERR_LOCKINCR2HIGH = 150382818; +LITDEF int ERR_LOCKIS = 150382827; +LITDEF int ERR_LDSPANGLOINCMP = 150382834; +LITDEF int ERR_MUFILRNDWNFL2 = 150382842; +LITDEF int ERR_MUINSTFROZEN = 150382851; +LITDEF int ERR_MUINSTUNFROZEN = 150382859; +LITDEF int ERR_GTMEISDIR = 150382866; +LITDEF int ERR_SPCLZMSG = 150382874; +LITDEF int ERR_MUNOTALLINTEG = 150382880; +LITDEF int ERR_BKUPRUNNING = 150382890; +LITDEF int ERR_MUSIZEINVARG = 150382898; +LITDEF int ERR_MUSIZEFAIL = 150382906; +LITDEF int ERR_SIDEEFFECTEVAL = 150382912; +LITDEF int ERR_CRYPTINIT2 = 150382922; +LITDEF int ERR_CRYPTDLNOOPEN2 = 150382930; +LITDEF int ERR_CRYPTBADCONFIG = 150382938; +LITDEF int ERR_DBCOLLREQ = 150382944; +LITDEF int ERR_SETEXTRENV = 150382954; +LITDEF int ERR_NOTALLDBRNDWN = 150382962; +LITDEF int ERR_TPRESTNESTERR = 150382970; +LITDEF int ERR_JNLFILRDOPN = 150382978; +LITDEF int ERR_SEQNUMSEARCHTIMEOUT = 150382986; +LITDEF int ERR_FTOKKEY = 150382995; +LITDEF int ERR_SEMID = 150383003; +LITDEF int ERR_JNLQIOSALVAGE = 150383011; +LITDEF int ERR_FAKENOSPCLEARED = 150383019; +LITDEF int ERR_MMFILETOOLARGE = 150383026; +LITDEF int ERR_BADZPEEKARG = 150383034; +LITDEF int ERR_BADZPEEKRANGE = 150383042; +LITDEF int ERR_BADZPEEKFMT = 150383050; +LITDEF int ERR_DBMBMINCFREFIXED = 150383056; +LITDEF int ERR_NULLENTRYREF = 150383066; +LITDEF int ERR_ZPEEKNORPLINFO = 150383074; +LITDEF int ERR_MMREGNOACCESS = 150383082; +LITDEF int ERR_MALLOCMAXUNIX = 150383090; +LITDEF int ERR_MALLOCMAXVMS = 150383098; +LITDEF int ERR_HOSTCONFLICT = 150383106; +LITDEF int ERR_GETADDRINFO = 150383114; +LITDEF int ERR_GETNAMEINFO = 150383122; +LITDEF int ERR_SOCKBIND = 150383130; +LITDEF int ERR_INSTFRZDEFER = 150383139; +LITDEF int ERR_REGOPENRETRY = 150383147; +LITDEF int ERR_REGOPENFAIL = 150383154; GBLDEF err_ctl merrors_ctl = { 246, "GTM", &merrors[0], - 1282}; + 1350}; diff --git a/sr_x86_64/mum_tstart.s b/sr_x86_64/mum_tstart.s index af5b69f..5d753fa 100644 --- a/sr_x86_64/mum_tstart.s +++ b/sr_x86_64/mum_tstart.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007 Fidelity Information Services, Inc # +# Copyright 2007, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -13,15 +13,15 @@ .include "linkage.si" .include "g_msf.si" -#comment perhaps + .sbttl mum_tstart .data .extern frame_pointer .extern proc_act_type +.extern xfer_table .text .extern trans_code -.extern inst_flush ENTRY mum_tstart addq $8, REG_SP # back up over return address @@ -30,5 +30,4 @@ ENTRY mum_tstart call trans_code l1: getframe leaq xfer_table(REG_IP), REG_XFER_TABLE - call inst_flush # smw 99/11/24 is this needed ret diff --git a/sr_x86_64/mval_def.si b/sr_x86_64/mval_def.si index 7a3b954..92b13f4 100644 --- a/sr_x86_64/mval_def.si +++ b/sr_x86_64/mval_def.si @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2011 Fidelity Information Services, Inc # +# Copyright 2007, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -95,6 +95,19 @@ top = 16 call underr movq REG64_RET0, \mval \label: +.endm + + .sbttl mval_def.si mv_force_defined_strict +# --------------------------------------- +# mv_force_defined_strict(mval, label) +# --------------------------------------- +.macro mv_force_defined_strict mval, label + testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) + jne \label + movq \mval, REG64_ARG0 + movb $0, REG8_ACCUM #variable argument list + call underr_strict +\label: .endm .sbttl mval_def.si mv_force_str diff --git a/sr_x86_64/obj_filesp.c b/sr_x86_64/obj_filesp.c index eeac597..bca0a2a 100644 --- a/sr_x86_64/obj_filesp.c +++ b/sr_x86_64/obj_filesp.c @@ -38,7 +38,7 @@ #include "gtm_stdio.h" #include "compiler.h" -#include "rtnhdr.h" +#include #include "obj_gen.h" #include "cgp.h" #include "mdq.h" diff --git a/sr_x86_64/op_exfun.s b/sr_x86_64/op_exfun.s index ce9dece..31950e1 100644 --- a/sr_x86_64/op_exfun.s +++ b/sr_x86_64/op_exfun.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2012 Fidelity Information Services, Inc # +# Copyright 2007, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -77,7 +77,7 @@ error: movl ERR_GTMCHECK(REG_IP),REG32_ARG1 jmp retlab long: movq REG64_ACCUM,msf_mpc_off(REG64_ARG2) - addl REG32_ARG1, msf_mpc_off(REG64_ARG2) + addq REG64_ARG1,msf_mpc_off(REG64_ARG2) cont: call exfun_frame movl act_cnt(REG_FRAME_POINTER),REG32_ACCUM diff --git a/sr_x86_64/op_fnzextract.s b/sr_x86_64/op_fnzextract.s index efac3c1..06e319e 100644 --- a/sr_x86_64/op_fnzextract.s +++ b/sr_x86_64/op_fnzextract.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2008 Fidelity Information Services, Inc # +# Copyright 2007, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -41,7 +41,7 @@ dest = -32 # PUBLIC op_fnzextract ENTRY op_fnzextract pushq REG_XFER_TABLE - enter $40,$0 # Need to make sure that the SP will be 16 bytes aligned + enter $48,$0 # Need to make sure that the SP will be 16 bytes aligned movl REG32_ARG0,last(REG_FRAME_POINTER) movl REG32_ARG1,first(REG_FRAME_POINTER) movq REG64_ARG3,dest(REG_FRAME_POINTER) diff --git a/sr_x86_64/op_forloop.s b/sr_x86_64/op_forloop.s index 006abc2..32d5971 100644 --- a/sr_x86_64/op_forloop.s +++ b/sr_x86_64/op_forloop.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2008 Fidelity Information Services, Inc # +# Copyright 2007, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -55,7 +55,7 @@ ENTRY op_forloop enter $0, $0 #rbp pushed on stack and then rbp = rsp pushq REG_XFER_TABLE movq indx(REG_FRAME_POINTER),REG64_ARG1 - mv_force_defined REG64_ARG1, l0 + mv_force_defined_strict REG64_ARG1, l0 # disregard NOUNDEF movq REG64_ARG1, indx(REG_FRAME_POINTER) mv_force_num REG64_ARG1, l1 movq indx(REG_FRAME_POINTER),REG64_ARG1 diff --git a/sr_x86_64/op_mprofexfun.s b/sr_x86_64/op_mprofexfun.s index ea257fa..6db6ab1 100644 --- a/sr_x86_64/op_mprofexfun.s +++ b/sr_x86_64/op_mprofexfun.s @@ -1,6 +1,6 @@ ################################################################# # # -# Copyright 2007, 2012 Fidelity Information Services, Inc # +# Copyright 2007, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # @@ -75,7 +75,7 @@ error: movl ERR_GTMCHECK(REG_IP),REG32_ARG1 jmp retlab long: movq REG64_ACCUM,msf_mpc_off(REG64_ARG2) - addl REG32_ARG1, msf_mpc_off(REG64_ARG2) + addq REG64_ARG1,msf_mpc_off(REG64_ARG2) cont: call exfun_frame_sp movq frame_pointer(REG_IP),REG64_SCRATCH1 diff --git a/sr_x86_64/ttt.c b/sr_x86_64/ttt.c index 9814a07..e0bfaf8 100644 --- a/sr_x86_64/ttt.c +++ b/sr_x86_64/ttt.c @@ -1,6 +1,6 @@ /**************************************************************** * * - * Copyright 2001, 2012 Fidelity Information Services, Inc * + * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * @@ -13,662 +13,696 @@ #include "vxi.h" #include "vxt.h" #include "xfer_enum.h" -LITDEF short ttt[4087] = { +LITDEF short ttt[4291] = { -/* 0 */ 0,0,0,0,307,3537,3010,549, -/* 8 */ 2329,2995,3025,2010,403,3487,2131,3111, -/* 16 */ 2208,2199,3720,3757,2172,2181,2247,2193, -/* 24 */ 2238,2217,2154,755,770,782,794,836, -/* 32 */ 854,869,898,934,949,964,982,1141, -/* 40 */ 1054,1087,1120,1198,1249,1579,1612,1627, -/* 48 */ 1657,1723,1753,1777,1840,1861,1876,3552, -/* 56 */ 3574,0,0,0,0,564,0,505, -/* 64 */ 0,1996,0,3097,0,0,0,0, -/* 72 */ 0,0,339,415,2307,2313,2743,2770, -/* 80 */ 2788,2891,2829,2820,2906,3626,3710,3046, -/* 88 */ 0,3076,3177,3140,3125,3155,3501,3353, -/* 96 */ 3632,3644,3659,3683,3692,3677,3668,3386, -/* 104 */ 3753,3766,3788,3825,3837,3858,3882,3948, -/* 112 */ 0,0,2939,2289,3229,4036,643,4039, -/* 120 */ 697,2800,3195,519,525,4042,2405,2497, -/* 128 */ 2379,472,2428,2517,2163,2460,2527,4045, -/* 136 */ 2274,2265,4049,1267,4050,335,331,3377, -/* 144 */ 427,4054,4057,4060,3062,4063,4066,4069, -/* 152 */ 4072,4075,4078,3523,0,2915,2583,2564, -/* 160 */ 1540,2555,2325,2145,2866,2031,722,2856, -/* 168 */ 0,0,2344,3701,3729,1471,3653,2440, -/* 176 */ 2024,534,3849,1825,2256,1183,322,3181, -/* 184 */ 606,675,587,653,3813,1102,3781,3039, -/* 192 */ 2283,2930,3053,625,994,2870,4081,2507, -/* 200 */ 3900,3918,3933,496,2885,3173,1957,3975, -/* 208 */ 3960,1285,3515,578,1642,1711,2472,4084, -/* 216 */ 3586,2543,731,812,3212,3741,3610,3596, -/* 224 */ 3603,3592,707,883,2392,2415,1036,2366, -/* 232 */ 1024,2226,1009,1069,2484,1441,1384,1369, -/* 240 */ 1423,1339,1351,1396,1324,1408,1456,0, -/* 248 */ 3473,0,910,919,3332,1852,3311,2353, -/* 256 */ 2450,2965,2971,2983,2951,1222,1234,1156, -/* 264 */ 1168,1210,3564,1687,1888,0,1297,1483, -/* 272 */ 1561,3407,1594,1672,1699,1810,1789,3449, -/* 280 */ 1735,3428,1921,1495,1510,1984,1903,3239, -/* 288 */ 3251,3263,3275,2779,2794,1528,436,1312, -/* 296 */ 1939,634,3287,3299,3969,3981,3990,4007, -/* 304 */ 4021,4027,3804,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, -/* 312 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 320 */ SIZEOF(char *) * (short int)xf_add,VXT_END, -/* 322 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm, -/* 330 */ VXT_END, -/* 331 */ VXI_INCL,VXT_VAL,1,VXT_END, -/* 335 */ VXI_CLRL,VXT_VAL,0,VXT_END, -/* 339 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END, -/* 343 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP, -/* 351 */ 1,VXT_END, -/* 353 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP, -/* 361 */ 1,VXT_END, -/* 363 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP, -/* 371 */ 1,VXT_END, -/* 373 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP, -/* 381 */ 1,VXT_END, -/* 383 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP, -/* 391 */ 1,VXT_END, -/* 393 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP, -/* 401 */ 1,VXT_END, -/* 403 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 411 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END, -/* 415 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 423 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END, -/* 427 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false, -/* 435 */ VXT_END, -/* 436 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars, -/* 444 */ VXT_END, -/* 445 */ VXI_TSTL,VXT_VAL,1,VXT_END, -/* 449 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool, -/* 457 */ VXT_END, -/* 458 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint, -/* 466 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END, -/* 472 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 480 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END, -/* 482 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1, -/* 490 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END, -/* 496 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num, -/* 504 */ VXT_END, -/* 505 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 513 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END, -/* 519 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END, -/* 525 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn, -/* 533 */ VXT_END, -/* 534 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 542 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END, -/* 549 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 557 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END, -/* 564 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, -/* 572 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END, -/* 578 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul, -/* 586 */ VXT_END, -/* 587 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 595 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_LIT,0,VXI_JSB, -/* 603 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, -/* 606 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 614 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB, -/* 622 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, -/* 625 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret, -/* 633 */ VXT_END, -/* 634 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals, -/* 642 */ VXT_END, -/* 643 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 651 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END, -/* 653 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 661 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 669 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, -/* 675 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 683 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 691 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, -/* 697 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 705 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END, -/* 707 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 715 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END, -/* 722 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch, -/* 730 */ VXT_END, -/* 731 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, -/* 739 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL, -/* 747 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, -/* 755 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 763 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END, -/* 770 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 778 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END, -/* 782 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 790 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END, -/* 794 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 802 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 810 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END, -/* 812 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, -/* 820 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 828 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, -/* 836 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 844 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 852 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END, -/* 854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 862 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END, -/* 869 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, -/* 877 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END, -/* 883 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 891 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END, -/* 898 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 906 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,VXT_END, -/* 910 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1, -/* 918 */ VXT_END, -/* 919 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 927 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget2,VXT_END, -/* 934 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 942 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END, -/* 949 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 957 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END, -/* 964 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 972 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 980 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END, -/* 982 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 990 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END, -/* 994 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1002 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END, -/* 1009 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, -/* 1017 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END, -/* 1024 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1032 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END, -/* 1036 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 1044 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER, -/* 1052 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END, -/* 1054 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1062 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END, -/* 1069 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, -/* 1077 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1085 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END, -/* 1087 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1095 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END, -/* 1102 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1110 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1118 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END, -/* 1120 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 1128 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1136 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END, -/* 1141 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1149 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END, -/* 1156 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1164 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END, -/* 1168 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1176 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END, -/* 1183 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1191 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END, -/* 1198 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1206 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END, -/* 1210 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1218 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END, -/* 1222 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1230 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END, -/* 1234 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1242 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END, -/* 1249 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1257 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1265 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END, -/* 1267 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 0 */ 0,0,0,0,325,3550,3023,567, +/* 8 */ 2347,3008,3038,2028,421,3500,2149,3124, +/* 16 */ 2226,2217,3733,3770,2190,2199,2265,2211, +/* 24 */ 2256,2235,2172,773,788,800,812,854, +/* 32 */ 872,893,922,952,967,982,1000,1159, +/* 40 */ 1072,1105,1138,1216,1267,1597,1630,1645, +/* 48 */ 1675,1741,1771,1795,1858,1879,1894,3565, +/* 56 */ 3587,0,0,0,0,582,0,523, +/* 64 */ 0,2014,0,3110,0,0,0,0, +/* 72 */ 0,0,357,433,2325,2331,2756,2783, +/* 80 */ 2801,2904,2842,2833,2919,3639,3723,3059, +/* 88 */ 0,3089,3190,3153,3138,3168,3514,3366, +/* 96 */ 3645,3657,3672,3696,3705,3690,3681,3399, +/* 104 */ 3766,3779,3801,3838,3850,3871,3895,3961, +/* 112 */ 0,0,2952,2307,3242,4240,661,4243, +/* 120 */ 715,2813,3208,537,543,4246,2410,2507, +/* 128 */ 2397,490,2433,2527,2181,2465,2537,4249, +/* 136 */ 2292,2283,4253,1285,4254,353,349,3390, +/* 144 */ 445,4258,4261,4264,3075,4267,4270,4273, +/* 152 */ 4276,4279,4282,3536,0,2928,2596,2574, +/* 160 */ 1558,2565,2343,2163,2879,2049,740,2869, +/* 168 */ 0,0,2362,3714,3742,1489,3666,2445, +/* 176 */ 2042,552,3862,1843,2274,1201,340,3194, +/* 184 */ 624,693,605,671,3826,1120,3794,3052, +/* 192 */ 2301,2943,3066,643,1012,2883,4285,2517, +/* 200 */ 3913,3931,3946,514,2898,3186,1975,3988, +/* 208 */ 3973,1303,3528,596,1660,1729,2480,4288, +/* 216 */ 3599,2553,749,830,3225,3754,3623,3609, +/* 224 */ 3616,3605,725,907,2420,1054,2384,1042, +/* 232 */ 2244,1027,1087,2492,1459,1402,1387,1441, +/* 240 */ 1357,1369,1414,1342,1426,1474,0,3486, +/* 248 */ 0,931,940,3345,1870,3324,2371,2455, +/* 256 */ 2978,2984,2996,2964,1240,1252,1174,1186, +/* 264 */ 1228,3577,1705,1906,0,1315,1501,1579, +/* 272 */ 3420,1612,1690,1717,1828,1807,3462,1753, +/* 280 */ 3441,1939,1513,1528,2002,4003,1921,3252, +/* 288 */ 3264,3276,3288,2792,2807,1546,454,1330, +/* 296 */ 1957,652,3300,3312,3982,3994,0,0, +/* 304 */ 0,0,3817,4015,4026,4038,4047,4061, +/* 312 */ 4074,4084,4101,4110,4119,4131,4143,4155, +/* 320 */ 4170,4182,4191,4203,4219,VXI_PUSHAB,VXT_VAL,0, +/* 328 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 336 */ 3,VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END, +/* 340 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm, +/* 348 */ VXT_END, +/* 349 */ VXI_INCL,VXT_VAL,1,VXT_END, +/* 353 */ VXI_CLRL,VXT_VAL,0,VXT_END, +/* 357 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END, +/* 361 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP, +/* 369 */ 1,VXT_END, +/* 371 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP, +/* 379 */ 1,VXT_END, +/* 381 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP, +/* 389 */ 1,VXT_END, +/* 391 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP, +/* 399 */ 1,VXT_END, +/* 401 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP, +/* 409 */ 1,VXT_END, +/* 411 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP, +/* 419 */ 1,VXT_END, +/* 421 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 429 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END, +/* 433 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 441 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END, +/* 445 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false, +/* 453 */ VXT_END, +/* 454 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars, +/* 462 */ VXT_END, +/* 463 */ VXI_TSTL,VXT_VAL,1,VXT_END, +/* 467 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool, +/* 475 */ VXT_END, +/* 476 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint, +/* 484 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END, +/* 490 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 498 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END, +/* 500 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1, +/* 508 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END, +/* 514 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num, +/* 522 */ VXT_END, +/* 523 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 531 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END, +/* 537 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END, +/* 543 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn, +/* 551 */ VXT_END, +/* 552 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 560 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END, +/* 567 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 575 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END, +/* 582 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, +/* 590 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END, +/* 596 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul, +/* 604 */ VXT_END, +/* 605 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 613 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_LIT,0,VXI_JSB, +/* 621 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, +/* 624 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 632 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB, +/* 640 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, +/* 643 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret, +/* 651 */ VXT_END, +/* 652 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals, +/* 660 */ VXT_END, +/* 661 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 669 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END, +/* 671 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 679 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 687 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, +/* 693 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 701 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 709 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, +/* 715 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 723 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END, +/* 725 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 733 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END, +/* 740 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch, +/* 748 */ VXT_END, +/* 749 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, +/* 757 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL, +/* 765 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, +/* 773 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 781 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END, +/* 788 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 796 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END, +/* 800 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 808 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END, +/* 812 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 820 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 828 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END, +/* 830 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, +/* 838 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 846 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, +/* 854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 862 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 870 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END, +/* 872 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 880 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 888 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END, +/* 893 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, +/* 901 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END, +/* 907 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 915 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END, +/* 922 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget, +/* 930 */ VXT_END, +/* 931 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1, +/* 939 */ VXT_END, +/* 940 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 948 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END, +/* 952 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 960 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END, +/* 967 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 975 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END, +/* 982 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 990 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 998 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END, +/* 1000 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1008 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END, +/* 1012 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1020 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END, +/* 1027 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, +/* 1035 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END, +/* 1042 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1050 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END, +/* 1054 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 1062 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER, +/* 1070 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END, +/* 1072 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1080 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END, +/* 1087 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, +/* 1095 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1103 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END, +/* 1105 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1113 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END, +/* 1120 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 1128 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1136 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END, +/* 1138 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 1146 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1154 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END, +/* 1159 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1167 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END, +/* 1174 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1182 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END, +/* 1186 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1194 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END, +/* 1201 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1209 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END, +/* 1216 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1224 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END, +/* 1228 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1236 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END, +/* 1240 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1248 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END, +/* 1252 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1260 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END, +/* 1267 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1275 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1283 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END, -/* 1285 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 1293 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END, -/* 1297 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 1305 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END, -/* 1312 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1320 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END, -/* 1324 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1332 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END, -/* 1339 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1347 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END, -/* 1351 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1359 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1367 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END, -/* 1369 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1377 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END, -/* 1384 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1392 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END, -/* 1396 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 1404 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END, -/* 1408 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1416 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END, -/* 1423 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1431 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1439 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END, -/* 1441 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1449 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END, -/* 1456 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 1464 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END, -/* 1471 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 1479 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END, -/* 1483 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 1491 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END, -/* 1495 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1503 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END, -/* 1510 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 1518 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1526 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END, -/* 1528 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1536 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END, -/* 1540 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, -/* 1548 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1556 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END, -/* 1561 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, -/* 1569 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1577 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END, -/* 1579 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1587 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END, -/* 1594 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 1602 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1610 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END, -/* 1612 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1620 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END, -/* 1627 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1635 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END, -/* 1642 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1650 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END, -/* 1657 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1665 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END, -/* 1672 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1680 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END, -/* 1687 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1695 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END, -/* 1699 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1707 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END, -/* 1711 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1719 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END, -/* 1723 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1731 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END, -/* 1735 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1743 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1751 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END, -/* 1753 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, -/* 1761 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 1769 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END, -/* 1777 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1785 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END, -/* 1789 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 1797 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 1805 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END, -/* 1810 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1818 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END, -/* 1825 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1833 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END, -/* 1840 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1848 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END, -/* 1852 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod, -/* 1860 */ VXT_END, -/* 1861 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 1869 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END, -/* 1876 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1884 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END, -/* 1888 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 1896 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END, -/* 1903 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 1911 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1919 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END, -/* 1921 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1283 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END, +/* 1285 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1293 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1301 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END, +/* 1303 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 1311 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END, +/* 1315 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 1323 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END, +/* 1330 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1338 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END, +/* 1342 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1350 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END, +/* 1357 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1365 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END, +/* 1369 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1377 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1385 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END, +/* 1387 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1395 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END, +/* 1402 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1410 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END, +/* 1414 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 1422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END, +/* 1426 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1434 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END, +/* 1441 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1449 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1457 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END, +/* 1459 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1467 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END, +/* 1474 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 1482 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END, +/* 1489 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 1497 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END, +/* 1501 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, +/* 1509 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END, +/* 1513 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1521 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END, +/* 1528 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1536 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1544 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END, +/* 1546 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1554 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END, +/* 1558 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, +/* 1566 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1574 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END, +/* 1579 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, +/* 1587 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1595 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END, +/* 1597 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1605 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END, +/* 1612 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1620 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1628 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END, +/* 1630 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1638 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END, +/* 1645 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1653 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END, +/* 1660 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1668 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END, +/* 1675 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1683 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END, +/* 1690 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1698 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END, +/* 1705 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1713 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END, +/* 1717 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1725 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END, +/* 1729 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1737 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END, +/* 1741 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1749 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END, +/* 1753 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 1761 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1769 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END, +/* 1771 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, +/* 1779 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 1787 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END, +/* 1795 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1803 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END, +/* 1807 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 1815 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 1823 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END, +/* 1828 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1836 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END, +/* 1843 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1851 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END, +/* 1858 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1866 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END, +/* 1870 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod, +/* 1878 */ VXT_END, +/* 1879 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 1887 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END, +/* 1894 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 1902 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END, +/* 1906 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 1914 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END, +/* 1921 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1929 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1937 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END, +/* 1937 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END, /* 1939 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1947 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, -/* 1955 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END, -/* 1957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL, -/* 1965 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB, -/* 1973 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7, -/* 1981 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END, -/* 1984 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 1992 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END, -/* 1996 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 2004 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END, -/* 2010 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, -/* 2018 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END, -/* 2024 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END, -/* 2031 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2039 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END, -/* 2044 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP, -/* 2052 */ 1,VXT_END, -/* 2054 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP, -/* 2062 */ 1,VXT_END, -/* 2064 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP, -/* 2072 */ 1,VXT_END, -/* 2074 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 2082 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 2090 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 2093 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 2101 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 2109 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 2112 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, -/* 2120 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, -/* 2128 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, -/* 2131 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx, -/* 2139 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 2145 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth, -/* 2153 */ VXT_END, -/* 2154 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata, -/* 2162 */ VXT_END, -/* 2163 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam, +/* 1955 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END, +/* 1957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 1965 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, +/* 1973 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END, +/* 1975 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL, +/* 1983 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB, +/* 1991 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7, +/* 1999 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END, +/* 2002 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 2010 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END, +/* 2014 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 2022 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END, +/* 2028 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, +/* 2036 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END, +/* 2042 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END, +/* 2049 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2057 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END, +/* 2062 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP, +/* 2070 */ 1,VXT_END, +/* 2072 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP, +/* 2080 */ 1,VXT_END, +/* 2082 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP, +/* 2090 */ 1,VXT_END, +/* 2092 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 2100 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 2108 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 2111 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 2119 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 2127 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 2130 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, +/* 2138 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, +/* 2146 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, +/* 2149 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx, +/* 2157 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 2163 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth, /* 2171 */ VXT_END, -/* 2172 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget, +/* 2172 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata, /* 2180 */ VXT_END, -/* 2181 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 2189 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END, -/* 2193 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END, -/* 2199 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked, -/* 2207 */ VXT_END, -/* 2208 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname, -/* 2216 */ VXT_END, -/* 2217 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext, +/* 2181 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam, +/* 2189 */ VXT_END, +/* 2190 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget, +/* 2198 */ VXT_END, +/* 2199 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 2207 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END, +/* 2211 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END, +/* 2217 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked, /* 2225 */ VXT_END, -/* 2226 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, -/* 2234 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END, -/* 2238 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder, -/* 2246 */ VXT_END, -/* 2247 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput, -/* 2255 */ VXT_END, -/* 2256 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery, +/* 2226 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname, +/* 2234 */ VXT_END, +/* 2235 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext, +/* 2243 */ VXT_END, +/* 2244 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 2252 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END, +/* 2256 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder, /* 2264 */ VXT_END, -/* 2265 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg, +/* 2265 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput, /* 2273 */ VXT_END, -/* 2274 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg, +/* 2274 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery, /* 2282 */ VXT_END, -/* 2283 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END, -/* 2289 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 2297 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER, -/* 2305 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END, -/* 2307 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END, -/* 2313 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 2321 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END, -/* 2325 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END, -/* 2329 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2337 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END, -/* 2344 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc, -/* 2352 */ VXT_END, -/* 2353 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2361 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END, -/* 2366 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2374 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END, -/* 2379 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2387 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END, -/* 2392 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2400 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indget,VXT_END, -/* 2405 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2413 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END, -/* 2415 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 2423 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END, -/* 2428 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG, -/* 2436 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2440 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2448 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END, -/* 2450 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER, -/* 2458 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END, -/* 2460 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, -/* 2468 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END, -/* 2472 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG, -/* 2480 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2484 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2492 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END, -/* 2497 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2505 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END, -/* 2507 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2515 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END, +/* 2283 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg, +/* 2291 */ VXT_END, +/* 2292 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg, +/* 2300 */ VXT_END, +/* 2301 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END, +/* 2307 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 2315 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER, +/* 2323 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END, +/* 2325 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END, +/* 2331 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 2339 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END, +/* 2343 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END, +/* 2347 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2355 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END, +/* 2362 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc, +/* 2370 */ VXT_END, +/* 2371 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2379 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END, +/* 2384 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2392 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END, +/* 2397 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2405 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END, +/* 2410 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2418 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END, +/* 2420 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 2428 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END, +/* 2433 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG, +/* 2441 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2445 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2453 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END, +/* 2455 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER, +/* 2463 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END, +/* 2465 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2473 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END, +/* 2480 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG, +/* 2488 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2492 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2500 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END, +/* 2507 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2515 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END, /* 2517 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2525 */ SIZEOF(char *) * (short int)xf_indset,VXT_END, -/* 2527 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2535 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END, -/* 2543 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 2551 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END, -/* 2555 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad, -/* 2563 */ VXT_END, -/* 2564 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmval,VXT_END, -/* 2571 */ VXI_BRB,VXT_JMP,1,VXT_END, -/* 2575 */ VXI_JMP,VXT_JMP,1,VXT_END, -/* 2579 */ VXI_BRW,VXT_JMP,1,VXT_END, -/* 2583 */ VXI_JMP,VXT_VAL,1,VXT_END, -/* 2587 */ VXI_BEQL,VXT_JMP,1,VXT_END, -/* 2591 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2598 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2605 */ VXI_BGEQ,VXT_JMP,1,VXT_END, -/* 2609 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2616 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2623 */ VXI_BGTR,VXT_JMP,1,VXT_END, -/* 2627 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2634 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2641 */ VXI_BLEQ,VXT_JMP,1,VXT_END, -/* 2645 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2652 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2659 */ VXI_BLSS,VXT_JMP,1,VXT_END, -/* 2663 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2670 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2677 */ VXI_BNEQ,VXT_JMP,1,VXT_END, -/* 2681 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, -/* 2688 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, -/* 2695 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END, -/* 2701 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, -/* 2709 */ VXT_END, -/* 2710 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, -/* 2718 */ VXT_END, -/* 2719 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END, -/* 2725 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, -/* 2733 */ VXT_END, -/* 2734 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, -/* 2742 */ VXT_END, -/* 2743 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL, -/* 2751 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL, -/* 2759 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1, -/* 2767 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END, -/* 2770 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill, -/* 2778 */ VXT_END, -/* 2779 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias, -/* 2787 */ VXT_END, -/* 2788 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END, -/* 2794 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END, -/* 2800 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 2808 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG, -/* 2816 */ 0x50,VXT_ADDR,0,VXT_END, -/* 2820 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr, -/* 2828 */ VXT_END, -/* 2829 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr, -/* 2837 */ VXT_END, -/* 2838 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2844 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2850 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, -/* 2856 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 2864 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END, -/* 2866 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END, -/* 2870 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 2878 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, -/* 2885 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END, -/* 2891 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2899 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, -/* 2906 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock, -/* 2914 */ VXT_END, -/* 2915 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 2923 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END, -/* 2930 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw, -/* 2938 */ VXT_END, -/* 2939 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 2947 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END, -/* 2951 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx, -/* 2959 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 2965 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END, -/* 2971 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 2979 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, -/* 2983 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 2991 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, -/* 2995 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3003 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END, -/* 3010 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3018 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END, -/* 3025 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, -/* 3033 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END, -/* 3039 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END, -/* 3046 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END, -/* 3053 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp, -/* 3061 */ VXT_END, -/* 3062 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 3070 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END, -/* 3076 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3084 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3092 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END, -/* 3097 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 3105 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END, -/* 3111 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx, -/* 3119 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 3125 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 3133 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END, -/* 3140 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, -/* 3148 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END, -/* 3155 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, -/* 3163 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3171 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END, -/* 3173 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END, -/* 3177 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END, -/* 3181 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2, -/* 3189 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END, -/* 3195 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3203 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 3211 */ VXT_END, -/* 3212 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3220 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 3228 */ VXT_END, -/* 3229 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3237 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END, -/* 3239 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3247 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END, -/* 3251 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3259 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END, -/* 3263 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3271 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END, -/* 3275 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3283 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END, -/* 3287 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3295 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END, -/* 3299 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, -/* 3307 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END, -/* 3311 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3319 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3327 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END, -/* 3332 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3340 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3348 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END, -/* 3353 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3361 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3369 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END, -/* 3377 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true, -/* 3385 */ VXT_END, -/* 3386 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3394 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS, -/* 3402 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END, -/* 3407 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3415 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3423 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END, -/* 3428 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3436 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, -/* 3444 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END, -/* 3449 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, -/* 3457 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3465 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END, -/* 3473 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, -/* 3481 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END, -/* 3487 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx, -/* 3495 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 3501 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, -/* 3509 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, -/* 3515 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END, -/* 3523 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, -/* 3531 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, -/* 3537 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3545 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END, -/* 3552 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3560 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END, -/* 3564 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3572 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END, -/* 3574 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3582 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END, -/* 3586 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END, -/* 3592 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END, -/* 3596 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END, -/* 3603 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END, -/* 3610 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, -/* 3618 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END, -/* 3626 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END, -/* 3632 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3640 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END, -/* 3644 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view, -/* 3652 */ VXT_END, -/* 3653 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END, -/* 3659 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write, -/* 3667 */ VXT_END, -/* 3668 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol, -/* 3676 */ VXT_END, -/* 3677 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END, -/* 3683 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone, -/* 3691 */ VXT_END, -/* 3692 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab, -/* 3700 */ VXT_END, -/* 3701 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill, -/* 3709 */ VXT_END, -/* 3710 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, -/* 3718 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END, -/* 3720 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate, -/* 3728 */ VXT_END, -/* 3729 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3737 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END, -/* 3741 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3749 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END, -/* 3753 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3757 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate, -/* 3765 */ VXT_END, -/* 3766 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, -/* 3774 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END, -/* 3781 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END, -/* 3788 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, -/* 3796 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END, -/* 3804 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt, -/* 3812 */ VXT_END, -/* 3813 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3821 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END, -/* 3825 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3833 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END, -/* 3837 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL, -/* 3845 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END, -/* 3849 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious, -/* 3857 */ VXT_END, -/* 3858 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, -/* 3866 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, -/* 3874 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END, -/* 3882 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL, -/* 3890 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3898 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, -/* 3900 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, -/* 3908 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, -/* 3916 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, -/* 3918 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3926 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3933 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3941 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, -/* 3948 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3956 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END, -/* 3960 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit, -/* 3968 */ VXT_END, -/* 3969 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END, -/* 3975 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END, -/* 3981 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn, -/* 3989 */ VXT_END, -/* 3990 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, -/* 3998 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshindx,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, -/* 4006 */ VXT_END, -/* 4007 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savputindx, -/* 4015 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, -/* 4021 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_forfreeindx,VXT_END, -/* 4027 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fornestlvl, -/* 4035 */ VXT_END, -/* 4036 */ 343,363,353,2571,2579,2575,2838,2850, -/* 4044 */ 2844,0,0,0,482,458,449,0, -/* 4052 */ 0,445,2074,2112,2093,2719,2734,2725, -/* 4060 */ 2695,2710,2701,2587,2598,2591,2677,2688, -/* 4068 */ 2681,2623,2634,2627,2641,2652,2645,2659, -/* 4076 */ 2670,2663,2605,2616,2609,2044,2064,2054, -/* 4084 */ 373,393,383}; +/* 2525 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END, +/* 2527 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2535 */ SIZEOF(char *) * (short int)xf_indset,VXT_END, +/* 2537 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2545 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END, +/* 2553 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 2561 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END, +/* 2565 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad, +/* 2573 */ VXT_END, +/* 2574 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2582 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END, +/* 2584 */ VXI_BRB,VXT_JMP,1,VXT_END, +/* 2588 */ VXI_JMP,VXT_JMP,1,VXT_END, +/* 2592 */ VXI_BRW,VXT_JMP,1,VXT_END, +/* 2596 */ VXI_JMP,VXT_VAL,1,VXT_END, +/* 2600 */ VXI_BEQL,VXT_JMP,1,VXT_END, +/* 2604 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2611 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2618 */ VXI_BGEQ,VXT_JMP,1,VXT_END, +/* 2622 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2629 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2636 */ VXI_BGTR,VXT_JMP,1,VXT_END, +/* 2640 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2647 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2654 */ VXI_BLEQ,VXT_JMP,1,VXT_END, +/* 2658 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2665 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2672 */ VXI_BLSS,VXT_JMP,1,VXT_END, +/* 2676 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2683 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2690 */ VXI_BNEQ,VXT_JMP,1,VXT_END, +/* 2694 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, +/* 2701 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, +/* 2708 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END, +/* 2714 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, +/* 2722 */ VXT_END, +/* 2723 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, +/* 2731 */ VXT_END, +/* 2732 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END, +/* 2738 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, +/* 2746 */ VXT_END, +/* 2747 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, +/* 2755 */ VXT_END, +/* 2756 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL, +/* 2764 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL, +/* 2772 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1, +/* 2780 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END, +/* 2783 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill, +/* 2791 */ VXT_END, +/* 2792 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias, +/* 2800 */ VXT_END, +/* 2801 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END, +/* 2807 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END, +/* 2813 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 2821 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG, +/* 2829 */ 0x50,VXT_ADDR,0,VXT_END, +/* 2833 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr, +/* 2841 */ VXT_END, +/* 2842 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr, +/* 2850 */ VXT_END, +/* 2851 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2857 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2863 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, +/* 2869 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 2877 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END, +/* 2879 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END, +/* 2883 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 2891 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, +/* 2898 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END, +/* 2904 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2912 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, +/* 2919 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock, +/* 2927 */ VXT_END, +/* 2928 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 2936 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END, +/* 2943 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw, +/* 2951 */ VXT_END, +/* 2952 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 2960 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END, +/* 2964 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx, +/* 2972 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 2978 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END, +/* 2984 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 2992 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, +/* 2996 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3004 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, +/* 3008 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3016 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END, +/* 3023 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3031 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END, +/* 3038 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, +/* 3046 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END, +/* 3052 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END, +/* 3059 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END, +/* 3066 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp, +/* 3074 */ VXT_END, +/* 3075 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 3083 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END, +/* 3089 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3097 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3105 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END, +/* 3110 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 3118 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END, +/* 3124 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx, +/* 3132 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 3138 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 3146 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END, +/* 3153 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 3161 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END, +/* 3168 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, +/* 3176 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3184 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END, +/* 3186 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END, +/* 3190 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END, +/* 3194 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2, +/* 3202 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END, +/* 3208 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3216 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 3224 */ VXT_END, +/* 3225 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3233 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 3241 */ VXT_END, +/* 3242 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3250 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END, +/* 3252 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3260 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END, +/* 3264 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3272 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END, +/* 3276 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3284 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END, +/* 3288 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3296 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END, +/* 3300 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3308 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END, +/* 3312 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, +/* 3320 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END, +/* 3324 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3332 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3340 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END, +/* 3345 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3353 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3361 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END, +/* 3366 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3374 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3382 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END, +/* 3390 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true, +/* 3398 */ VXT_END, +/* 3399 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3407 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS, +/* 3415 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END, +/* 3420 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3428 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3436 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END, +/* 3441 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3449 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 3457 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END, +/* 3462 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 3470 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3478 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END, +/* 3486 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, +/* 3494 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END, +/* 3500 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx, +/* 3508 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 3514 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, +/* 3522 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, +/* 3528 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END, +/* 3536 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, +/* 3544 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, +/* 3550 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3558 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END, +/* 3565 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3573 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END, +/* 3577 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3585 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END, +/* 3587 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3595 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END, +/* 3599 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END, +/* 3605 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END, +/* 3609 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END, +/* 3616 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END, +/* 3623 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, +/* 3631 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END, +/* 3639 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END, +/* 3645 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3653 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END, +/* 3657 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view, +/* 3665 */ VXT_END, +/* 3666 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END, +/* 3672 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write, +/* 3680 */ VXT_END, +/* 3681 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol, +/* 3689 */ VXT_END, +/* 3690 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END, +/* 3696 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone, +/* 3704 */ VXT_END, +/* 3705 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab, +/* 3713 */ VXT_END, +/* 3714 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill, +/* 3722 */ VXT_END, +/* 3723 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 3731 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END, +/* 3733 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate, +/* 3741 */ VXT_END, +/* 3742 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3750 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END, +/* 3754 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3762 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END, +/* 3766 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3770 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate, +/* 3778 */ VXT_END, +/* 3779 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 3787 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END, +/* 3794 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END, +/* 3801 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, +/* 3809 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END, +/* 3817 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt, +/* 3825 */ VXT_END, +/* 3826 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3834 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END, +/* 3838 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3846 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END, +/* 3850 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL, +/* 3858 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END, +/* 3862 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious, +/* 3870 */ VXT_END, +/* 3871 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, +/* 3879 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, +/* 3887 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END, +/* 3895 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL, +/* 3903 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3911 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, +/* 3913 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, +/* 3921 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, +/* 3929 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, +/* 3931 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3939 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3946 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3954 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, +/* 3961 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 3969 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END, +/* 3973 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit, +/* 3981 */ VXT_END, +/* 3982 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END, +/* 3988 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END, +/* 3994 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn, +/* 4002 */ VXT_END, +/* 4003 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4011 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END, +/* 4015 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50, +/* 4023 */ VXT_ADDR,0,VXT_END, +/* 4026 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4034 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END, +/* 4038 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop, +/* 4046 */ VXT_END, +/* 4047 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot, +/* 4055 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, +/* 4061 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, +/* 4069 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END, +/* 4074 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, +/* 4082 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END, +/* 4084 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4092 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, +/* 4100 */ VXT_END, +/* 4101 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn, +/* 4109 */ VXT_END, +/* 4110 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn, +/* 4118 */ VXT_END, +/* 4119 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END, +/* 4131 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4139 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END, +/* 4143 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, +/* 4151 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END, +/* 4155 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, +/* 4163 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END, +/* 4170 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 4178 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END, +/* 4182 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2, +/* 4190 */ VXT_END, +/* 4191 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, +/* 4199 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_litc,VXT_END, +/* 4203 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXI_PUSHAB, +/* 4211 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_stolitc,VXT_END, +/* 4219 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, +/* 4227 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, +/* 4235 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpeek,VXT_END, +/* 4240 */ 361,381,371,2584,2592,2588,2851,2863, +/* 4248 */ 2857,0,0,0,500,476,467,0, +/* 4256 */ 0,463,2092,2130,2111,2732,2747,2738, +/* 4264 */ 2708,2723,2714,2600,2611,2604,2690,2701, +/* 4272 */ 2694,2636,2647,2640,2654,2665,2658,2672, +/* 4280 */ 2683,2676,2618,2629,2622,2062,2082,2072, +/* 4288 */ 391,411,401};