diff --git a/.github/install-dependency-packages.sh b/.github/install-dependency-packages.sh index 6ba2f927..d3838662 100755 --- a/.github/install-dependency-packages.sh +++ b/.github/install-dependency-packages.sh @@ -36,6 +36,7 @@ GENERAL_PACKAGE_LIST_LINUX=( davix ### RCDB dependencies mariadb + sqlite ) IGUANA_PACKAGE_LIST_LINUX=( fmt @@ -60,6 +61,7 @@ GENERAL_PACKAGE_LIST_MACOS=( gsl ### RCDB dependencies mariadb + sqlite ) IGUANA_PACKAGE_LIST_MACOS=( fmt @@ -143,6 +145,9 @@ case $runner in ### link homebrew's gcc, for gfortran brew unlink gcc brew link gcc + ### link homebrew's sqlite, for RCDB + brew unlink sqlite + brew link --force sqlite ### kluge ssl linker issue (see, e.g., https://github.com/brianmario/mysql2/issues/795) echo "LIBRARY_PATH=${LIBRARY_PATH:+${LIBRARY_PATH}:}$(pkg-config libssl --variable libdir)" | tee -a $GITHUB_ENV ;; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc4cbc9f..5ba29fe3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -445,6 +445,7 @@ jobs: # echo '- to compare to the report from the `main` branch, see ' >> $GITHUB_STEP_SUMMARY ### test relocatability - name: test relocatability + if: ${{ matrix.id == 'cpp' }} # don't bother re-running santizers, etc. run: | mv iguana relocated source relocated/bin/this_iguana.sh --verbose # do not use --githubCI option, since we want this environment to be for only this step diff --git a/meson.build b/meson.build index aa7e1222..50a6bb97 100644 --- a/meson.build +++ b/meson.build @@ -189,6 +189,7 @@ project_test_env.set( 'halt_on_error=1', 'abort_on_error=1', 'print_summary=1', + 'suppressions=' + meson.project_source_root() / 'meson' / 'asan.supp', ) project_test_env.set( 'LSAN_OPTIONS', diff --git a/meson/asan.supp b/meson/asan.supp new file mode 100644 index 00000000..2ef9592d --- /dev/null +++ b/meson/asan.supp @@ -0,0 +1,2 @@ +# RCDB's SQLite header +odr_violation:SQLite::* diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc index 06ab4781..2d008db7 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc @@ -35,7 +35,7 @@ namespace iguana::physics { i_targetM = result_schema.getEntryOrder("targetM"); // instantiate RCDB reader - m_rcdb = std::make_unique("RCDB|" + GetName()); + m_rcdb = std::make_unique("RCDB|" + GetName(), m_log->GetLevel()); // parse config file ParseYAMLConfig(); diff --git a/src/iguana/services/GlobalParam.cc b/src/iguana/services/GlobalParam.cc index cfb64d8f..14813381 100644 --- a/src/iguana/services/GlobalParam.cc +++ b/src/iguana/services/GlobalParam.cc @@ -4,6 +4,7 @@ namespace iguana { // default param values GlobalParam GlobalConcurrencyModel{"none"}; + GlobalParam GlobalRcdbUrl{""}; // template specializations template class GlobalParam; diff --git a/src/iguana/services/GlobalParam.h b/src/iguana/services/GlobalParam.h index b5669a70..3d541535 100644 --- a/src/iguana/services/GlobalParam.h +++ b/src/iguana/services/GlobalParam.h @@ -64,4 +64,8 @@ namespace iguana { /// option will be _chosen_ by `ConcurrentParamFactory::Create` instead extern GlobalParam GlobalConcurrencyModel; + /// @brief Path to the RCDB + /// @see `iguana::RCDBReader` for details + extern GlobalParam GlobalRcdbUrl; + } diff --git a/src/iguana/services/Object.cc b/src/iguana/services/Object.cc index b449c691..e0bacef0 100644 --- a/src/iguana/services/Object.cc +++ b/src/iguana/services/Object.cc @@ -2,9 +2,9 @@ namespace iguana { - Object::Object(std::string_view name) + Object::Object(std::string_view name, Logger::Level lev) : m_name(name) - , m_log(std::make_unique(m_name)) + , m_log(std::make_unique(m_name, lev)) {} std::unique_ptr& Object::Log() diff --git a/src/iguana/services/Object.h b/src/iguana/services/Object.h index 97a12d78..a4e23a2e 100644 --- a/src/iguana/services/Object.h +++ b/src/iguana/services/Object.h @@ -14,7 +14,8 @@ namespace iguana { public: /// @param name the name of this object - Object(std::string_view name = ""); + /// @param lev the log level + Object(std::string_view name = "", Logger::Level lev = Logger::DEFAULT_LEVEL); ~Object() {} /// Get the logger diff --git a/src/iguana/services/RCDBReader.cc b/src/iguana/services/RCDBReader.cc index a096eb51..88924bda 100644 --- a/src/iguana/services/RCDBReader.cc +++ b/src/iguana/services/RCDBReader.cc @@ -1,14 +1,34 @@ #include "RCDBReader.h" +#include "GlobalParam.h" namespace iguana { - RCDBReader::RCDBReader(std::string_view name) : Object(name) + RCDBReader::RCDBReader(std::string_view name, Logger::Level lev) : Object(name, lev) { #ifdef USE_RCDB - auto url_ptr = std::getenv("RCDB_CONNECTION"); - m_url = url_ptr != nullptr ? std::string(url_ptr) : default_url; - m_log->Debug("RCDB URL: {}", m_url); + + // choose the RCDB URL, from the following priority ordering + // 1. try `GlobalRcdbUrl` + m_url = GlobalRcdbUrl(); + if(!m_url.empty()) + m_log->Debug("RCDB URL set from 'iguana::GlobalRcdbUrl': {:?}", m_url); + else { + // 2. try env var `RCDB_CONNECTION` + if(auto url_ptr{std::getenv("RCDB_CONNECTION")}; url_ptr != nullptr) + m_url = std::string(url_ptr); + if(!m_url.empty()) + m_log->Debug("RCDB URL set from env var 'RCDB_CONNECTION': {:?}", m_url); + else { + // 3. fallback to default value + m_log->Warn("RCDB URL not set; you may choose a URL with the environment variable 'RCDB_CONNECTION' or with the global parameter 'iguana::GlobalRcdbUrl'; for now, let's proceed with the URL set to {:?}", m_default_url); + m_url = m_default_url; + m_log->Debug("RCDB URL set from default fallback: {:?}", m_url); + } + } + + // then start the connection m_rcdb_connection = std::make_unique(m_url, true); + #endif } diff --git a/src/iguana/services/RCDBReader.h b/src/iguana/services/RCDBReader.h index 72a397f4..18a5d320 100644 --- a/src/iguana/services/RCDBReader.h +++ b/src/iguana/services/RCDBReader.h @@ -10,22 +10,35 @@ namespace iguana { /// @brief RCDB reader + /// + /// This class interfaces to the RCDB. The database connection path is chosen from one of the following, in order: + /// - The global variable `iguana::GlobalRcdbUrl`; by default this is not set to any value (its type is `iguana::GlobalParam`) + /// - The environment variable `RCDB_CONNECTION` (which is likely set if you are on `ifarm`) + /// - A default URL, which will be printed in a warning; see `iguana::RCDBReader::m_default_url` + /// + /// RCDB will automatically use `mariadb` / `mysql` or `sqlite`, depending on the above RCDB database path, + /// and whether you have satisfied the dependencies. class RCDBReader : public Object { public: /// @param name the name of this reader - RCDBReader(std::string_view name = "rcdb"); + /// @param lev the log level + RCDBReader(std::string_view name = "rcdb", Logger::Level lev = Logger::DEFAULT_LEVEL); /// @param runnum run number /// @returns the beam energy in GeV double GetBeamEnergy(int const runnum); + protected: + + /// @brief default RCDB URL, used as a last resort + std::string const m_default_url = "mysql://rcdb@clasdb.jlab.org/rcdb"; + private: std::string m_url; - std::string const default_url = "mysql://rcdb@clasdb.jlab.org/rcdb"; std::once_flag m_error_once; #ifdef USE_RCDB diff --git a/subprojects/rcdb/meson.build b/subprojects/rcdb/meson.build index 027d07d2..4ab2ffaa 100644 --- a/subprojects/rcdb/meson.build +++ b/subprojects/rcdb/meson.build @@ -18,19 +18,26 @@ else error(f'RCDB not found; set build option "rcdb:home" to the RCDB installation (e.g., to "$RCDB_HOME"); @require_message@') endif -# RCDB dependencies: either mysql or sqlite -# - looking for mysql here, since clas12root uses this -# - prioritizing mariadb, an open source fork of mysql -backend_list = ['mariadb', 'mysql', 'mysqlclient'] -foreach backend_name : backend_list - rcdb_backend_dep = dependency(backend_name, required: false) - if rcdb_backend_dep.found() - message(f'using "@backend_name@" for the RCDB backend') - break - endif +# RCDB dependencies: a database management system (DBMS), mysql and/or sqlite +dbms_args = [] +dbms_deps = [] +dbms_dict = { + 'mysql': [ 'mariadb', 'mysql', 'mysqlclient' ], # prioritizing mariadb, an open source fork of mysql + 'sqlite': [ 'sqlite3' ], +} +foreach dbms, pkgs : dbms_dict + foreach pkg : pkgs + dep = dependency(pkg, required: false) + if dep.found() + dbms_deps += dep + dbms_args += { 'mysql': '-DRCDB_MYSQL', 'sqlite': '-DRCDB_SQLITE' }[dbms] + message(f'using @pkg@ for RCDB DBMS') + break + endif + endforeach endforeach -if not rcdb_backend_dep.found() - error('none of the backends (' + ', '.join(backend_list) + ') were found, so RCDB will not be used in this build; ' + require_message) +if dbms_deps.length() == 0 + error('none of the DBMSs (' + ', '.join(dbms_dict.keys()) + ') were found, so RCDB will not be used in this build; ' + require_message) endif rcdb_dep = declare_dependency( @@ -43,6 +50,6 @@ rcdb_dep = declare_dependency( rcdb_includedir, is_system: true, # suppress consumer warnings ), - compile_args: ['-DRCDB_MYSQL' ], - dependencies: [ rcdb_backend_dep ], + compile_args: dbms_args, + dependencies: dbms_deps, )