diff --git a/Framework/CMakeLists.txt b/Framework/CMakeLists.txt index 5f48077f10..06214282f2 100644 --- a/Framework/CMakeLists.txt +++ b/Framework/CMakeLists.txt @@ -90,6 +90,7 @@ add_library(O2QualityControl src/TaskRunner.cxx src/TaskRunnerFactory.cxx src/TaskInterface.cxx + src/CtpScalers.cxx src/UserCodeInterface.cxx src/RepositoryBenchmark.cxx src/RepoPathUtils.cxx @@ -169,6 +170,7 @@ target_link_libraries(O2QualityControl O2::DataFormatsQualityControl O2::DetectorsBase O2::GlobalTracking + O2::DataFormatsCTP O2QualityControlKafkaProtos ${RDKAFKA_LIB} PRIVATE Boost::system @@ -180,6 +182,7 @@ add_root_dictionary(O2QualityControl HEADERS include/QualityControl/CheckInterface.h include/QualityControl/TaskInterface.h + include/QualityControl/CtpScalers.h include/QualityControl/UserCodeInterface.h include/QualityControl/AggregatorInterface.h include/QualityControl/PostProcessingInterface.h diff --git a/Framework/basic.json b/Framework/basic.json index d61ac6285d..068d684b5e 100644 --- a/Framework/basic.json +++ b/Framework/basic.json @@ -10,7 +10,7 @@ "maxObjectSize": "2097152", "": "[Bytes, default=2MB] Maximum size allowed, larger objects are rejected." }, "Activity": { - "number": "42", + "number": "561253", "type": "NONE", "periodName": "", "": "Period name - e.g. LHC22c, LHC22c1b_test", "passName": "", "": "Pass type - e.g. spass, cpass1", @@ -23,17 +23,23 @@ "url": "" }, "conditionDB": { - "url": "ccdb-test.cern.ch:8080" + "url": "alice-ccdb.cern.ch" }, "infologger": { "": "Configuration of the Infologger (optional).", "filterDiscardDebug": "false", "": "Set to true to discard debug and trace messages (default: false)", - "filterDiscardLevel": "12", "": "Message at this level or above are discarded (default: 21 - Trace)", + "filterDiscardLevel": "21", "": "Message at this level or above are discarded (default: 21 - Trace)", "filterDiscardFile": "/tmp/_ID_.txt", "": ["If set, the messages discarded because of filterDiscardLevel", "will go to this file (default: ); The keyword _ID_ is replaced by the device id. Discarded Debug ", "messages won't go there."] }, "bookkeeping": { "url": "" + }, + "ctpscalers": { + "sourceRepo": { + "implementation": "CCDB", + "host": "ali-qcdb-gpn.cern.ch:8083" + } } }, "tasks": { diff --git a/Framework/include/QualityControl/CommonSpec.h b/Framework/include/QualityControl/CommonSpec.h index 7041c346fa..2d8d39cae4 100644 --- a/Framework/include/QualityControl/CommonSpec.h +++ b/Framework/include/QualityControl/CommonSpec.h @@ -44,6 +44,7 @@ struct CommonSpec { LogDiscardParameters infologgerDiscardParameters; double postprocessingPeriod = 30.0; std::string bookkeepingUrl; + std::unordered_map ctpScalersSourceRepo; }; } // namespace o2::quality_control::core diff --git a/Framework/include/QualityControl/ConditionAccess.h b/Framework/include/QualityControl/ConditionAccess.h index e1ed6346f0..02bd8a2b5e 100644 --- a/Framework/include/QualityControl/ConditionAccess.h +++ b/Framework/include/QualityControl/ConditionAccess.h @@ -30,6 +30,7 @@ class ConditionAccess void setCcdbUrl(const std::string& url) { o2::ccdb::BasicCCDBManager::instance().setURL(url); + o2::ccdb::BasicCCDBManager::instance().setFatalWhenNull(false); } /** @@ -43,7 +44,6 @@ template T* ConditionAccess::retrieveConditionAny(std::string const& path, std::map const& metadata, long timestamp) { auto& mgr = o2::ccdb::BasicCCDBManager::instance(); - mgr.setFatalWhenNull(false); mgr.setTimestamp(timestamp); return mgr.getSpecific(path, mgr.getTimestamp(), metadata); } diff --git a/Framework/include/QualityControl/CtpScalers.h b/Framework/include/QualityControl/CtpScalers.h new file mode 100644 index 0000000000..7303b3e251 --- /dev/null +++ b/Framework/include/QualityControl/CtpScalers.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file CtpScalers.h +/// \author Barthelemy von Haller +/// + +#ifndef QUALITYCONTROL_CTPSCALERS_H +#define QUALITYCONTROL_CTPSCALERS_H + +#include +#include "QualityControl/DatabaseInterface.h" + +namespace o2::ctp +{ +class CTPRateFetcher; +} + +namespace o2::quality_control::core +{ + +class CtpScalers +{ + public: + CtpScalers() = default; + virtual ~CtpScalers() = default; + + /// \brief Call it to enable the retrieval of CTP scalers and use `getScalers` later + void enableCtpScalers(size_t runNumber); + /// \brief Get the scalers's value for the given source + double getScalersValue(std::string sourceName, size_t runNumber); + + void setScalersRepo(std::shared_ptr database) + { + mScalersRepo = database; + } + + private: + /// \brief Retrieve fresh scalers from the QCDB (with cache) + /// \return true if success, false if failure + bool updateScalers(size_t runNumber); + + std::shared_ptr mCtpFetcher; + std::chrono::steady_clock::time_point mScalersLastUpdate; + bool mScalersEnabled = false; + std::shared_ptr mScalersRepo; //! where to get the scalers from + + ClassDef(CtpScalers, 1) +}; + +} // namespace o2::quality_control::core + +#endif // QUALITYCONTROL_USERCODEINTERFACE_H \ No newline at end of file diff --git a/Framework/include/QualityControl/DatabaseInterface.h b/Framework/include/QualityControl/DatabaseInterface.h index 066f459390..cc3d45a2d3 100644 --- a/Framework/include/QualityControl/DatabaseInterface.h +++ b/Framework/include/QualityControl/DatabaseInterface.h @@ -18,7 +18,6 @@ #define QC_REPOSITORY_DATABASEINTERFACE_H #include -#include #include #include diff --git a/Framework/include/QualityControl/LinkDef.h b/Framework/include/QualityControl/LinkDef.h index 08fde33986..0468378da0 100644 --- a/Framework/include/QualityControl/LinkDef.h +++ b/Framework/include/QualityControl/LinkDef.h @@ -7,6 +7,7 @@ #pragma link C++ namespace o2::quality_control::checker; #pragma link C++ namespace o2::quality_control::postprocessing; +#pragma link C++ class o2::quality_control::core::CtpScalers + ; #pragma link C++ class o2::quality_control::core::UserCodeInterface + ; #pragma link C++ class o2::quality_control::checker::CheckInterface + ; #pragma link C++ class o2::quality_control::core::TaskInterface + ; diff --git a/Framework/include/QualityControl/UserCodeConfig.h b/Framework/include/QualityControl/UserCodeConfig.h index b57241fdad..ee5716246b 100644 --- a/Framework/include/QualityControl/UserCodeConfig.h +++ b/Framework/include/QualityControl/UserCodeConfig.h @@ -18,7 +18,6 @@ #define QUALITYCONTROL_USERCODECONFIG_H #include "QualityControl/CustomParameters.h" -#include "QualityControl/stringUtils.h" namespace o2::quality_control::core { @@ -32,6 +31,7 @@ struct UserCodeConfig { CustomParameters customParameters; std::string ccdbUrl; std::unordered_map repository; // we need the full config of the database to build the database in the subclasses + std::unordered_map ctpScalersSourceRepo; }; } // namespace o2::quality_control::core diff --git a/Framework/include/QualityControl/UserCodeInterface.h b/Framework/include/QualityControl/UserCodeInterface.h index 8cd26dd310..68dc8c1b12 100644 --- a/Framework/include/QualityControl/UserCodeInterface.h +++ b/Framework/include/QualityControl/UserCodeInterface.h @@ -18,15 +18,16 @@ #define QUALITYCONTROL_USERCODEINTERFACE_H #include -#include #include #include "QualityControl/ConditionAccess.h" #include "QualityControl/CustomParameters.h" #include "QualityControl/DatabaseInterface.h" +#include "QualityControl/CtpScalers.h" namespace o2::quality_control::core { +class UserCodeConfig; /// \brief Common interface for Check and Task Interfaces. /// @@ -39,8 +40,6 @@ class UserCodeInterface : public ConditionAccess /// Destructor virtual ~UserCodeInterface() = default; - void setCustomParameters(const CustomParameters& parameters); - /// \brief Configure the object. /// /// Users can use this method to configure their object. @@ -49,16 +48,24 @@ class UserCodeInterface : public ConditionAccess const std::string& getName() const; void setName(const std::string& name); - void setDatabase(std::unordered_map dbConfig); + void setConfig(const UserCodeConfig& config); protected: + /// \brief Call it to enable the retrieval of CTP scalers and use `getScalers` later + void enableCtpScalers(size_t runNumber); + /// \brief Get the scalers's value for the given source + double getScalersValue(std::string sourceName, size_t runNumber); + + void setDatabase(std::unordered_map dbConfig); + CustomParameters mCustomParameters; std::string mName; - std::shared_ptr mDatabase; + std::shared_ptr mDatabase; //! the repository used by the Framework + CtpScalers mCtpScalers; - ClassDef(UserCodeInterface, 4) + ClassDef(UserCodeInterface, 5) }; } // namespace o2::quality_control::core -#endif // QUALITYCONTROL_USERCODEINTERFACE_H +#endif // QUALITYCONTROL_USERCODEINTERFACE_H \ No newline at end of file diff --git a/Framework/src/Aggregator.cxx b/Framework/src/Aggregator.cxx index ac76398dfd..c8b1891ebe 100644 --- a/Framework/src/Aggregator.cxx +++ b/Framework/src/Aggregator.cxx @@ -50,9 +50,7 @@ void Aggregator::init() mAggregatorInterface = root_class_factory::create(mAggregatorConfig.moduleName, mAggregatorConfig.className); mAggregatorInterface->setName(mAggregatorConfig.name); - mAggregatorInterface->setCustomParameters(mAggregatorConfig.customParameters); - mAggregatorInterface->setCcdbUrl(mAggregatorConfig.ccdbUrl); - mAggregatorInterface->setDatabase(mAggregatorConfig.repository); + mAggregatorInterface->setConfig(mAggregatorConfig); mAggregatorInterface->configure(); } catch (...) { std::string diagnostic = boost::current_exception_diagnostic_information(); @@ -225,6 +223,7 @@ AggregatorConfig Aggregator::extractConfig(const core::CommonSpec& commonSpec, c aggregatorSpec.customParameters, commonSpec.conditionDBUrl, commonSpec.database, + commonSpec.ctpScalersSourceRepo, aggregatorSpec.aggregatorName, updatePolicy, std::move(objectNames), diff --git a/Framework/src/Check.cxx b/Framework/src/Check.cxx index 1e07661c0e..142c2b9662 100644 --- a/Framework/src/Check.cxx +++ b/Framework/src/Check.cxx @@ -71,9 +71,7 @@ void Check::init() try { mCheckInterface = root_class_factory::create(mCheckConfig.moduleName, mCheckConfig.className); mCheckInterface->setName(mCheckConfig.name); - mCheckInterface->setDatabase(mCheckConfig.repository); - mCheckInterface->setCustomParameters(mCheckConfig.customParameters); - mCheckInterface->setCcdbUrl(mCheckConfig.ccdbUrl); + mCheckInterface->setConfig(mCheckConfig); } catch (...) { std::string diagnostic = boost::current_exception_diagnostic_information(); ILOG(Fatal, Ops) << "Unexpected exception, diagnostic information follows: " @@ -259,6 +257,7 @@ CheckConfig Check::extractConfig(const CommonSpec& commonSpec, const CheckSpec& checkSpec.customParameters, commonSpec.conditionDBUrl, commonSpec.database, + commonSpec.ctpScalersSourceRepo, checkSpec.checkName, updatePolicy, std::move(objectNames), diff --git a/Framework/src/CtpScalers.cxx b/Framework/src/CtpScalers.cxx new file mode 100644 index 0000000000..8d40c9db7d --- /dev/null +++ b/Framework/src/CtpScalers.cxx @@ -0,0 +1,107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file CtpScalers.cxx +/// \author Barthelemy von Haller +/// + +#include "QualityControl/CtpScalers.h" +#include +#include "QualityControl/QcInfoLogger.h" +#include "QualityControl/DatabaseFactory.h" + +using namespace o2::ccdb; +using namespace std; + +namespace o2::quality_control::core +{ +void CtpScalers::enableCtpScalers(size_t runNumber) +{ + // bail if we are in async + auto deploymentMode = framework::DefaultsHelpers::deploymentMode(); + if (deploymentMode == framework::DeploymentMode::Grid) { + ILOG(Info, Ops) << "Async mode detected, CTP scalers cannot be enabled." << ENDM; + return; + } + + ILOG(Debug, Devel) << "Enabling CTP scalers" << ENDM; + mCtpFetcher = make_shared(); + mScalersEnabled = true; + auto& ccdbManager = o2::ccdb::BasicCCDBManager::instance(); + mCtpFetcher->setupRun(runNumber, &ccdbManager, /*1726300234140*/ getCurrentTimestamp(), false); + + mScalersLastUpdate = std::chrono::steady_clock::time_point::min(); + if (updateScalers(runNumber)) { // initial value + ILOG(Debug, Devel) << "Enabled CTP scalers" << ENDM; + } else { + ILOG(Debug, Devel) << "CTP scalers not enabled, failure to get them." << ENDM; + } +} + +bool CtpScalers::updateScalers(size_t runNumber) +{ + if (!mScalersEnabled) { + ILOG(Error, Ops) << "CTP scalers not enabled, impossible to update them." << ENDM; + return false; + } + ILOG(Debug, Devel) << "Updating scalers." << ENDM; + + if (!mScalersRepo) { + ILOG(Error, Devel) << "Database not set ! Cannot update scalers." << ENDM; + mScalersEnabled = false; + return false; + } + + auto now = std::chrono::steady_clock::now(); + auto minutesSinceLast = std::chrono::duration_cast(now - mScalersLastUpdate); + + // TODO get the interval from config + if (minutesSinceLast.count() >= 0 /*first time it is neg*/ && minutesSinceLast.count() < 5) { + ILOG(Debug, Devel) << "getScalers was called less than 5 minutes ago, use the cached value" << ENDM; + return true; + } + + std::map meta; + meta["runNumber"] = std::to_string(runNumber); + std::map headers; + auto validity = mScalersRepo->getLatestObjectValidity("qc/CTP/Scalers", meta); + void* rawResult = mScalersRepo->retrieveAny(typeid(o2::ctp::CTPRunScalers), "qc/CTP/Scalers", meta, validity.getMax() - 1, &headers); + if (!rawResult) { + ILOG(Error, Devel) << "Could not retrieve the CTP Scalers" << ENDM; + return false; + } else { + ILOG(Debug, Devel) << "object retrieved" << ENDM; + } + + o2::ctp::CTPRunScalers* ctpScalers = static_cast(rawResult); + mCtpFetcher->updateScalers(*ctpScalers); + mScalersLastUpdate = now; + ILOG(Debug, Devel) << "Scalers updated." << ENDM; + return true; +} + +double CtpScalers::getScalersValue(std::string sourceName, size_t runNumber) +{ + if (!mScalersEnabled) { + ILOG(Error, Ops) << "CTP scalers not enabled, impossible to get the value." << ENDM; + return 0; + } + if (!updateScalers(runNumber)) { // from QCDB + ILOG(Debug, Devel) << "Could not update the scalers, returning 0" << ENDM; + return 0; + } + auto result = mCtpFetcher->fetchNoPuCorr(&o2::ccdb::BasicCCDBManager::instance(), getCurrentTimestamp() * 1000, runNumber, sourceName); + ILOG(Debug, Devel) << "Returning scaler value : " << result << ENDM; + return result; +} + +} // namespace o2::quality_control::core \ No newline at end of file diff --git a/Framework/src/InfrastructureSpecReader.cxx b/Framework/src/InfrastructureSpecReader.cxx index d22d140229..02c7842e88 100644 --- a/Framework/src/InfrastructureSpecReader.cxx +++ b/Framework/src/InfrastructureSpecReader.cxx @@ -81,7 +81,9 @@ CommonSpec InfrastructureSpecReader::readSpecEntry(const std::string }; spec.postprocessingPeriod = commonTree.get("postprocessing.periodSeconds", spec.postprocessingPeriod); spec.bookkeepingUrl = commonTree.get("bookkeeping.url", spec.bookkeepingUrl); - + for (const auto& [key, value] : commonTree.get_child("ctpscalers.sourceRepo")) { + spec.ctpScalersSourceRepo.emplace(key, value.get_value()); + } return spec; } diff --git a/Framework/src/PostProcessingFactory.cxx b/Framework/src/PostProcessingFactory.cxx index 7b7e2e9348..19a516ffe9 100644 --- a/Framework/src/PostProcessingFactory.cxx +++ b/Framework/src/PostProcessingFactory.cxx @@ -28,8 +28,7 @@ namespace o2::quality_control::postprocessing PostProcessingInterface* PostProcessingFactory::create(const PostProcessingConfig& config) { auto* result = root_class_factory::create(config.moduleName, config.className); - result->setCustomParameters(config.customParameters); - result->setDatabase(config.repository); + result->setConfig(config); return result; } diff --git a/Framework/src/PostProcessingRunner.cxx b/Framework/src/PostProcessingRunner.cxx index b2a7636c82..197683cd94 100644 --- a/Framework/src/PostProcessingRunner.cxx +++ b/Framework/src/PostProcessingRunner.cxx @@ -113,8 +113,6 @@ void PostProcessingRunner::init(const PostProcessingRunnerConfig& runnerConfig, mTask->setObjectsManager(mObjectManager); mTask->setID(mTaskConfig.id); mTask->setName(mTaskConfig.taskName); - mTask->setCustomParameters(mTaskConfig.customParameters); - mTask->setCcdbUrl(mTaskConfig.ccdbUrl); mTask->configure(mRunnerConfig.configTree); } else { throw std::runtime_error("Failed to create the task '" + mTaskConfig.taskName + "' (det " + mTaskConfig.detectorName + ")"); diff --git a/Framework/src/TaskFactory.cxx b/Framework/src/TaskFactory.cxx index ea77ca5356..8e6d939ce3 100644 --- a/Framework/src/TaskFactory.cxx +++ b/Framework/src/TaskFactory.cxx @@ -26,8 +26,7 @@ TaskInterface* TaskFactory::create(const TaskRunnerConfig& taskConfig, std::shar auto* result = root_class_factory::create(taskConfig.moduleName, taskConfig.className); result->setName(taskConfig.taskName); result->setObjectsManager(objectsManager); - result->setCustomParameters(taskConfig.customParameters); - result->setCcdbUrl(taskConfig.ccdbUrl); + result->setConfig(taskConfig); return result; } diff --git a/Framework/src/TaskRunner.cxx b/Framework/src/TaskRunner.cxx index 8450c7f580..835c007c19 100644 --- a/Framework/src/TaskRunner.cxx +++ b/Framework/src/TaskRunner.cxx @@ -74,7 +74,6 @@ using namespace AliceO2::Common; TaskRunner::TaskRunner(const TaskRunnerConfig& config) : mTaskConfig(config) { - o2::ccdb::BasicCCDBManager::instance().setFatalWhenNull(false); } TaskRunner::~TaskRunner() @@ -123,7 +122,6 @@ void TaskRunner::init(InitContext& iCtx) mTask.reset(TaskFactory::create(mTaskConfig, mObjectsManager)); mTask->setMonitoring(mCollector); mTask->setGlobalTrackingDataRequest(mTaskConfig.globalTrackingDataRequest); - mTask->setDatabase(mTaskConfig.repository); // load config params if (!ConfigParamGlo::keyValues.empty()) { diff --git a/Framework/src/TaskRunnerFactory.cxx b/Framework/src/TaskRunnerFactory.cxx index 654dcb1bae..533dcfc2ac 100644 --- a/Framework/src/TaskRunnerFactory.cxx +++ b/Framework/src/TaskRunnerFactory.cxx @@ -175,6 +175,7 @@ TaskRunnerConfig TaskRunnerFactory::extractConfig(const CommonSpec& globalConfig taskSpec.customParameters, globalConfig.conditionDBUrl, globalConfig.database, + globalConfig.ctpScalersSourceRepo, deviceName, taskSpec.taskName, multipleCycleDurations, diff --git a/Framework/src/UserCodeInterface.cxx b/Framework/src/UserCodeInterface.cxx index 96ee5bcdb3..a02da63219 100644 --- a/Framework/src/UserCodeInterface.cxx +++ b/Framework/src/UserCodeInterface.cxx @@ -15,9 +15,10 @@ /// #include "QualityControl/UserCodeInterface.h" -#include +#include #include "QualityControl/QcInfoLogger.h" #include "QualityControl/DatabaseFactory.h" +#include "QualityControl/UserCodeConfig.h" using namespace o2::ccdb; using namespace std; @@ -25,9 +26,23 @@ using namespace std; namespace o2::quality_control::core { -void UserCodeInterface::setCustomParameters(const CustomParameters& parameters) +void UserCodeInterface::setConfig(const UserCodeConfig& config) { - mCustomParameters = parameters; + setDatabase(config.repository); + setCcdbUrl(config.ccdbUrl); + + // if a specific repository is provided as source for the scalers we use it otherwise we use the normal database + std::shared_ptr ctpSourceRepo; + if (auto ctpScalersSourceRepo = config.ctpScalersSourceRepo; + ctpScalersSourceRepo.size() > 0 && ctpScalersSourceRepo.contains("implementation") && config.ctpScalersSourceRepo.contains("host")) { + ctpSourceRepo = repository::DatabaseFactory::create(ctpScalersSourceRepo.at("implementation")); + ctpSourceRepo->connect(ctpScalersSourceRepo); + } else { + ctpSourceRepo = mDatabase; + } + mCtpScalers.setScalersRepo(ctpSourceRepo); + + mCustomParameters = config.customParameters; configure(); } @@ -41,6 +56,16 @@ void UserCodeInterface::setName(const std::string& name) mName = name; } +void UserCodeInterface::enableCtpScalers(size_t runNumber) +{ + mCtpScalers.enableCtpScalers(runNumber); +} + +double UserCodeInterface::getScalersValue(std::string sourceName, size_t runNumber) +{ + return mCtpScalers.getScalersValue(sourceName, runNumber); +} + void UserCodeInterface::setDatabase(std::unordered_map dbConfig) { if (dbConfig.count("implementation") == 0 || dbConfig.count("host") == 0) { diff --git a/Framework/test/testCheck.cxx b/Framework/test/testCheck.cxx index 06a74f8bf8..ec4d43881d 100644 --- a/Framework/test/testCheck.cxx +++ b/Framework/test/testCheck.cxx @@ -149,8 +149,9 @@ TEST_CASE("test_check_activity") "TST", "", {}, - "", - { { "implementation", "CCDB" }, { "host", "" } }, + "alice-ccdb.cern.ch", + { { "implementation", "CCDB" }, { "host", "ccdb-test.cern.ch:8080" } }, + { { "implementation", "CCDB" }, { "host", "ccdb-test.cern.ch:8080" } }, "test", UpdatePolicyType::OnAny, {}, diff --git a/Framework/test/testSharedConfig.json b/Framework/test/testSharedConfig.json index 2fba174e91..83684b393f 100644 --- a/Framework/test/testSharedConfig.json +++ b/Framework/test/testSharedConfig.json @@ -14,6 +14,9 @@ }, "monitoring": { "url": "infologger:///debug?qc" + }, + "conditionDB": { + "url": "alice-ccdb.cern.ch" } }, "tasks": { diff --git a/Framework/test/testTaskInterface.cxx b/Framework/test/testTaskInterface.cxx index 7b93b3ad21..f6fc612934 100644 --- a/Framework/test/testTaskInterface.cxx +++ b/Framework/test/testTaskInterface.cxx @@ -172,8 +172,9 @@ TEST_CASE("test_task_factory") "TST", "", {}, - "", - {}, + "alice-ccdb.cern.ch", + { { "implementation", "CCDB" }, { "host", "ccdb-test.cern.ch:8080" } }, + { { "implementation", "CCDB" }, { "host", "ccdb-test.cern.ch:8080" } }, "SkeletonTaskRunner", "skeletonTask", { { 10, 1 } }, diff --git a/Framework/test/testUserCodeInterface.cxx b/Framework/test/testUserCodeInterface.cxx index d7f287cefe..0a7d046ed0 100644 --- a/Framework/test/testUserCodeInterface.cxx +++ b/Framework/test/testUserCodeInterface.cxx @@ -20,6 +20,8 @@ #define BOOST_TEST_MAIN #define BOOST_TEST_DYN_LINK +#include "QualityControl/UserCodeConfig.h" + #include #include #include @@ -82,19 +84,18 @@ BOOST_AUTO_TEST_CASE(test_invoke_all_methods) auto taskName = "Test/pid" + pid; shared_ptr mo1 = make_shared(h1, taskName, "task", "TST"); auto backend = std::make_unique(); - backend->connect("ccdb-test.cern.ch:8080", "", "", ""); + backend->connect("ccdb-test.cern.ch:8080", "QCDB", "", ""); backend->storeMO(mo1); // setting custom parameters should configure CustomParameters customParameters; customParameters["test"] = "asdf"; - testInterface.setCustomParameters(customParameters); + UserCodeConfig config; + config.customParameters = customParameters; + config.repository = { { "host", "ccdb-test.cern.ch:8080" }, { "implementation", "CCDB" } }; + testInterface.setConfig(config); BOOST_CHECK_EQUAL(testInterface.configured, true); BOOST_CHECK_EQUAL(testInterface.get("test"), "asdf"); - - testInterface.setCcdbUrl("ccdb-test.cern.ch:8080"); - auto obj = testInterface.retrieveConditionAny("qc/TST/MO/" + taskName + "/asdf"); - BOOST_CHECK_NE(obj, nullptr); } } /* namespace test */ } /* namespace o2::quality_control */ \ No newline at end of file diff --git a/Modules/Common/test/testMeanIsAbove.cxx b/Modules/Common/test/testMeanIsAbove.cxx index fe4a5964e9..6fb0f76103 100644 --- a/Modules/Common/test/testMeanIsAbove.cxx +++ b/Modules/Common/test/testMeanIsAbove.cxx @@ -22,6 +22,8 @@ #define BOOST_TEST_DYN_LINK #include "QualityControl/MonitorObject.h" +#include "QualityControl/UserCodeConfig.h" + #include #include #include @@ -41,7 +43,10 @@ BOOST_AUTO_TEST_CASE(test_checks) MeanIsAbove check; CustomParameters customParameters; customParameters["meanThreshold"] = "1.0"; - check.setCustomParameters(customParameters); + UserCodeConfig config; + config.customParameters = customParameters; + config.repository = { { "host", "ccdb-test.cern.ch:8080" }, { "implementation", "CCDB" } }; + check.setConfig(config); Quality quality = check.check(&moMap); BOOST_CHECK_EQUAL(quality, Quality::Bad); diff --git a/Modules/Example/test/testFactory.cxx b/Modules/Example/test/testFactory.cxx index fb4faea2a5..a272630d8a 100644 --- a/Modules/Example/test/testFactory.cxx +++ b/Modules/Example/test/testFactory.cxx @@ -30,6 +30,7 @@ BOOST_AUTO_TEST_CASE(Task_Factory) config.moduleName = "QcCommon"; config.className = "o2::quality_control_modules::example::ExampleTask"; config.detectorName = "DAQ"; + config.repository = { { "host", "ccdb-test.cern.ch:8080" }, { "implementation", "CCDB" } }; auto manager = make_shared(config.taskName, config.className, config.detectorName, config.consulUrl, 0, true); try { gSystem->AddDynamicPath("lib:../../lib:../../../lib:.:"); // add local paths for the test diff --git a/Modules/Skeleton/src/SkeletonCheck.cxx b/Modules/Skeleton/src/SkeletonCheck.cxx index 8f1f1cbf99..222d996a1e 100644 --- a/Modules/Skeleton/src/SkeletonCheck.cxx +++ b/Modules/Skeleton/src/SkeletonCheck.cxx @@ -21,7 +21,6 @@ // ROOT #include -#include #include using namespace std; @@ -49,6 +48,9 @@ Quality SkeletonCheck::check(std::mapmId); + ILOG(Info, Devel) << "\"T0VTX\" : " << t0vtx << ENDM; + // This is an example of accessing the histogram 'example' created by SkeletonTask for (auto& [moName, mo] : *moMap) { if (mo->getName() == "example") { @@ -124,6 +126,7 @@ void SkeletonCheck::startOfActivity(const Activity& activity) // THUS FUNCTION BODY IS AN EXAMPLE. PLEASE REMOVE EVERYTHING YOU DO NOT NEED. ILOG(Debug, Devel) << "SkeletonCheck::start : " << activity.mId << ENDM; mActivity = make_shared(activity); + enableCtpScalers(activity.mId); } void SkeletonCheck::endOfActivity(const Activity& activity) diff --git a/doc/Advanced.md b/doc/Advanced.md index 38c67576e5..1c249e2281 100644 --- a/doc/Advanced.md +++ b/doc/Advanced.md @@ -1679,6 +1679,12 @@ the "tasks" path. "canProcessClusters" : "TPC", "": "clusters that the QC task can process", "requestClusters" : "TPC", "": "clusters that the QC task should process", "mc" : "false", "": "mc boolean flag for the data request" + }, + "ctpscalers": { + "sourceRepo": { + "implementation": "CCDB", + "host": "ali-qcdb-gpn.cern.ch:8083" + } } } } @@ -1996,8 +2002,60 @@ The values are relative to the canvas size, so in the example above the label wi In consul go to `o2/runtime/aliecs/defaults` and modify the file corresponding to the detector: [det]_qc_shm_segment_size +## CTP Scalers + +### Usage + +User code can access CTP scalers in the following way : +``` +// in start of activity + enableCtpScalers(activity.mId); + +// in your e.g. check(...) + auto t0vtx = getScalersValue("T0VTX", mActivity->mId); + ILOG(Info, Devel) << "\"T0VTX\" : " << t0vtx << ENDM; +``` + +By default the Scalers are pulled from the QCDB. However, for the purpose of testing, one can also set a different +repo for it : +``` + "ctpscalers": { + "sourceRepo": { + "implementation": "CCDB", + "host": "ali-qcdb-gpn.cern.ch:8083" + } + } +``` +This way, the data can be pulled from production but the storage is still in the test database. + +### Limitations + +It does not work in async. + +### Implementation details + +`CTP proxy` publishes the scalers every 5 minutes into the QCDB at [`qc/CTP/Scalers`](http://ali-qcdb-gpn.cern.ch:8083/browse/qc/CTP/Scalers?report=true). They are cleaned up after 3 days. +Thus we query from the QCDB yet we also need access to CCDB to setup the `CTPRateFetcher`. + +When enabling the scalers we instantiate `CTPRateFetcher` and call `setupRun()` __using the current timestamp__. +When asking for the scalers, they are retrieved from the QCDB or a cached version is used (cache of 5 minutes). +### Development and test + +* Get a certificate : https://alice-doc.github.io/alice-analysis-tutorial/start/cert.html#test-your-certificate +* Build JAlien-ROOT : `aliBuild build JAliEn-ROOT [--defaults o2-dataflow]` +* Build AliEn-Runtime : `aliBuild build xjalienfs [--defaults o2-dataflow]` +* Use a combined environment : `alienv enter QualityControl/latest JAliEn-ROOT/latest xjalienfs/latest` + +Then change the run number in the config file (`basic.json` to match a recent run otherwise it won't work as the CTP scalers are deleted after 3 days). + +``` +alien-token-init + +``` +How do we do if there are no current runs ? we end up with some data in CCDB but the scalers in QCDB are missing. +Could we specify a file instead ? ---