diff --git a/Control/DataModelTest/DataModelRunTests/test/CondReadWriteCrest.py b/Control/DataModelTest/DataModelRunTests/test/CondReadWriteCrest.py new file mode 100755 index 0000000000000000000000000000000000000000..ddf59a1f390678c8063c0bd6a77ccf8960c997fa --- /dev/null +++ b/Control/DataModelTest/DataModelRunTests/test/CondReadWriteCrest.py @@ -0,0 +1,63 @@ +#!/usr/bin/env athena.py --CA +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration. +# +# File: DataModelRunTests/test/CondReadWriteCrest.py +# Date: Mar 2024, modeled after the CondReadWrite.py +# Purpose: Test reading of CREST conditions that are written during runtime (aka Extensible Folders) +# + +from DataModelRunTests.DataModelTestConfig import \ + DataModelTestFlags, DataModelTestCfg, TestOutputCfg + +def CondReadWriteCrestCfg (flags): + from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator + acc = ComponentAccumulator() + + from AthenaConfiguration.ComponentFactory import CompFactory + DMTest = CompFactory.DMTest + + ## Setup writer alg that writes new conditions on given LB + ## --- Keep these lines commented for now. Uncomment when the CREST version of CondWriterExtAlg is implemented + # cmds = { 6 : "dmtest_condwriter.py --rs=0 --ls=8 'sqlite://;schema=condtest_rw_test.db;dbname=OFLP200' AttrList_noTag_15 42" } + # acc.addEventAlgo (DMTest.CondWriterExtAlg( Commands = cmds )) + acc.addEventAlgo (DMTest.CondReaderAlg( S2Key = "")) + acc.addCondAlgo (DMTest.CondAlg1()) + return acc + +flags = DataModelTestFlags() +flags.fillFromArgs() +if flags.Concurrency.NumThreads >= 1: + flags.Scheduler.ShowDataDeps = True +flags.lock() + +cfg = DataModelTestCfg (flags, 'CondReadWriteCrest', + # Increment LBN every two events. + EventsPerLB= 2) + +# This is how we currently configure the IOV(Db)Svc in the HLT +from AthenaConfiguration.ComponentFactory import CompFactory +cfg.addService (CompFactory.IOVSvc (updateInterval = 'RUN', + forceResetAtBeginRun = False)) + +from IOVDbSvc.IOVDbSvcConfig import addFolders +cfg.merge (addFolders (flags, '/DMTest/TestAttrList', 'CALO_OFL', + tag = 'AttrList_noTag_25', + className = 'AthenaAttributeList')) +# extensible = True)) ---- eventually we want to make this folder extensible + +iovdbsvc = cfg.getService ('IOVDbSvc') +iovdbsvc.Source='CREST' +iovdbsvc.GlobalTag='CREST-Marcelo-2' +iovdbsvc.OutputLevel=2 +iovdbsvc.DBInstance="" + +iovdbsvc.CacheAlign = 0 +iovdbsvc.CacheRun = 0 +iovdbsvc.CacheTime = 0 + +cfg.merge (CondReadWriteCrestCfg (flags)) + +sc = cfg.run (flags.Exec.MaxEvents) +import sys +sys.exit (sc.isFailure()) + diff --git a/Database/IOVDbSvc/src/IOVDbFolder.cxx b/Database/IOVDbSvc/src/IOVDbFolder.cxx index 56d3f96328e046d9627dc8736b7365ef6f01a585..41e441144a1e00453ede0f49d4cc92060c071b8d 100644 --- a/Database/IOVDbSvc/src/IOVDbFolder.cxx +++ b/Database/IOVDbSvc/src/IOVDbFolder.cxx @@ -259,9 +259,6 @@ IOVDbFolder::loadCache(const cool::ValidityKey vkey, } ++m_ndbread; auto [changedCacheLo, changedCacheHi] = m_iovs.getCacheBounds(); - // - // - //new if (cacheDiv>0) { // quantise queries on boundaries that are sub-multiples of cache length unsigned long long cacheq=m_cachelength/cacheDiv; @@ -310,7 +307,6 @@ IOVDbFolder::loadCache(const cool::ValidityKey vkey, } bool retrievedone=false; unsigned int nChannelsExpected = (m_chanrange.empty())? (m_nchan) : (IOVDbNamespace::countSelectedChannels(m_channums, m_chansel)); - if (m_source == "COOL_DATABASE"){ // query to fill cache - request for database activates connection if (not m_conn->open()) { @@ -435,36 +431,38 @@ IOVDbFolder::loadCache(const cool::ValidityKey vkey, return false; } - BasicFolder& basicFolder = *crestObjs.begin(); + unsigned int iadd = 0; + if (!resolveTag(nullptr,globalTag)) return false; ATH_MSG_DEBUG( "loadCache: Expecting to see " << nChannelsExpected << " channels" ); - if (!resolveTag(nullptr,globalTag)) return false; - const auto & channelNumbers=basicFolder.channelIds(); - ATH_MSG_DEBUG( "ChannelIds is " << channelNumbers.size() << " long" ); - unsigned int iadd{}; - for (const auto & chan: channelNumbers){ - m_cachechan.push_back(chan); - addIOVtoCache(basicFolder.iov().first, basicFolder.iov().second); - if (basicFolder.isVectorPayload()) { - const auto & vPayload = basicFolder.getVectorPayload(chan); - const unsigned int istart=m_cacheattr.size(); - for (const auto & attList:vPayload){ + + for(BasicFolder& basicFolder : crestObjs) { + const auto & channelNumbers=basicFolder.channelIds(); + ATH_MSG_DEBUG( "ChannelIds is " << channelNumbers.size() << " long" ); + for (const auto & chan: channelNumbers){ + addIOVtoCache(basicFolder.iov().first, basicFolder.iov().second); + m_cachechan.push_back(chan); + if (basicFolder.isVectorPayload()) { + const auto & vPayload = basicFolder.getVectorPayload(chan); + const unsigned int istart=m_cacheattr.size(); + for (const auto & attList:vPayload){ + if (m_cachespec==nullptr) setSharedSpec(attList); + m_cacheattr.emplace_back(*m_cachespec,true);// maybe needs to be cleared before + m_cacheattr.back().fastCopyData(attList); + m_nbytesread+=IOVDbNamespace::attributeListSize(attList); + } + m_cacheccstart.push_back(istart); + m_cacheccend.push_back(m_cacheattr.size()); + ++iadd; + } else { + auto const & attList = basicFolder.getPayload(chan); if (m_cachespec==nullptr) setSharedSpec(attList); - m_cacheattr.emplace_back(*m_cachespec,true);// maybe needs to be cleared before + const coral::AttributeList c(*m_cachespec,true); + m_cacheattr.push_back(c);// maybe needs to be cleared before m_cacheattr.back().fastCopyData(attList); m_nbytesread+=IOVDbNamespace::attributeListSize(attList); + ++iadd; } - m_cacheccstart.push_back(istart); - m_cacheccend.push_back(m_cacheattr.size()); - ++iadd; - } else { - auto const & attList = basicFolder.getPayload(chan); - if (m_cachespec==nullptr) setSharedSpec(attList); - const coral::AttributeList c(*m_cachespec,true); - m_cacheattr.push_back(c);// maybe needs to be cleared before - m_cacheattr.back().fastCopyData(attList); - m_nbytesread+=IOVDbNamespace::attributeListSize(attList); - ++iadd; } } retrievedone=true; @@ -474,7 +472,7 @@ IOVDbFolder::loadCache(const cool::ValidityKey vkey, if (!retrievedone) { const auto & [since,until] = m_iovs.getCacheBounds(); - ATH_MSG_ERROR( "Could not retrieve COOL data for folder " << + ATH_MSG_ERROR( "Could not retrieve Cond data for folder " << m_foldername << " tag " << m_tag << " validityKeys [" << since << "," << until << "]" ); return false; @@ -1257,14 +1255,13 @@ void IOVDbFolder::dumpFile(const std::string& dumpName myFile<<s_closeJson; } -std::vector<BasicFolder> IOVDbFolder::fetchCrestObjects(cool::ValidityKey /*since*/ - , cool::ValidityKey /*until*/ +std::vector<BasicFolder> IOVDbFolder::fetchCrestObjects(cool::ValidityKey since + , cool::ValidityKey until , bool vectorPayloadFlag - , cool::ValidityKey vkey /* Temporary! */ + , cool::ValidityKey vkey , const std::string& nodeDesc) { CrestFunctions cfunctions(m_crestServer); - std::vector<BasicFolder> retVector; std::string crestPayloadType="crest-json-single-iov"; nlohmann::json tagProperties = cfunctions.getTagProperties(m_crestTag); @@ -1272,36 +1269,10 @@ std::vector<BasicFolder> IOVDbFolder::fetchCrestObjects(cool::ValidityKey /*sinc && tagProperties.contains("payloadSpec")) { crestPayloadType=tagProperties["payloadSpec"].get<std::string>(); } - ATH_MSG_INFO("CREST payload type: "<<crestPayloadType); - - // Vector of non-overlapping IOVs + corresponding Hashes - std::vector<IOVHash> iovHashVect = fetchCrestIOVs(); - - int indIOV = iovHashVect.empty() ? -1 : 0; - for(const auto& iovhash : iovHashVect) { - if(vkey >= iovhash.first.second) { - ++indIOV; - continue; - } - if(vkey < iovhash.first.first) { - ATH_MSG_WARNING("Load cache failed for " << m_foldername - << ". VKey " << vkey << " is earlier than the start of the first IOV retrieved from the DB"); - indIOV = -1; - } - break; - } - - if(indIOV>=0) { - ATH_MSG_DEBUG("Found IOV for " << m_foldername << " and VKEY " << vkey << " " - << iovHashVect[indIOV].first); - } - - std::string reply = indIOV==-1 - ? std::string{} - : cfunctions.getPayloadForHash(iovHashVect[indIOV].second); if(crestPayloadType.compare("crest-json-multi-iov")==0) { - try { +/* + try { nlohmann::json multiPayload = nlohmann::json::parse(reply); nlohmann::json jsIovs=multiPayload["obj"]; std::vector<IOV2Index> iov2IndexVect; @@ -1383,26 +1354,106 @@ std::vector<BasicFolder> IOVDbFolder::fetchCrestObjects(cool::ValidityKey /*sinc const std::string& specString = cfunctions.getTagInfoElement(m_tag_info,"payload_spec"); if (specString.empty()) { std::string errorMessage = "Reading payload spec from "+m_foldername+" failed."; +*/ + // Support for this type of payload will be added later + std::string errorMessage = m_foldername + ": has multi-iov payload. Folders with multi-iov payloads currently not supported!"; ATH_MSG_FATAL(errorMessage); throw std::runtime_error{errorMessage}; } - //basic folder now contains the info - BasicFolder basicFolder; - basicFolder.setVectorPayloadFlag(vectorPayloadFlag); - if(!reply.empty()) { //this also takes care of the case if indIOV<0, since reply is empty in this case + const std::string& specString = cfunctions.getTagInfoElement(m_tag_info,"payload_spec"); + if (specString.empty()) { + std::string errorMessage = "Reading payload spec from " + m_foldername + " failed."; + ATH_MSG_FATAL(errorMessage); + throw std::runtime_error{errorMessage}; + } + + std::vector<BasicFolder> retVector; + + // Vector of non-overlapping IOVs + corresponding Hashes + std::vector<IOVHash> iovHashVect = fetchCrestIOVs(); + + if(iovHashVect.empty() || until<=iovHashVect[0].first.first) { + if(iovHashVect.empty()) { + ATH_MSG_INFO("NO IOVs retrieved for the folder "+ m_foldername); + } + else { + ATH_MSG_INFO("Cache boundaries outside available IOVs for the folder "+ m_foldername); + } + BasicFolder basicFolder; + basicFolder.setVectorPayloadFlag(vectorPayloadFlag); + retVector.push_back(basicFolder); + return retVector; + } + + unsigned indIOVStart = 0; + for(const auto& iovhash : iovHashVect) { + if(since < iovhash.first.first) break; // 'since' is earlier that the first IOV segment. indIOVStart=0 + if(since < iovhash.first.second + && since >= iovhash.first.first) { + break; + } + ++indIOVStart; + } + unsigned indIOVEnd = indIOVStart; + while(indIOVEnd < iovHashVect.size()) { + if(iovHashVect[indIOVEnd].first.first < until + && iovHashVect[indIOVEnd].first.second >= until) { + break; + } + ++indIOVEnd; + } + + for(unsigned ind = indIOVStart; ind <= indIOVEnd; ++ind) { + std::string reply = cfunctions.getPayloadForHash(iovHashVect[ind].second); + + if (m_crestToFile) { + unsigned long long sinceT = iovHashVect[ind].first.first; + + std::string crest_work_dir=std::filesystem::current_path(); + crest_work_dir += "/crest_data"; + bool crest_rewrite = true; + Crest::CrestClient crestFSClient = Crest::CrestClient(crest_rewrite, crest_work_dir); + + nlohmann::json js = + { + {"name", m_crestTag} + }; + + try{ + crestFSClient.createTag(js); + ATH_MSG_INFO("Tag " << m_crestTag << " saved to disk."); + ATH_MSG_INFO("CREST Dump dir = " << crest_work_dir); + } + catch (const std::exception& e) { + ATH_MSG_WARNING("Data saving for tag " << m_crestTag << " failed: " << e.what()); + } + + try{ + crestFSClient.storePayloadDump(m_crestTag, sinceT, reply); + ATH_MSG_INFO("Data (payload and IOV) saved for tag " << m_crestTag << "."); + } + catch (const std::exception& e) { + ATH_MSG_WARNING("Data (payload and IOV) saving for tag " << m_crestTag<<" failed; " << e.what()); + } + } + + //basic folder now contains the info + BasicFolder basicFolder; + basicFolder.setVectorPayloadFlag(vectorPayloadFlag); std::istringstream ss(reply); - Json2Cool inputJson(ss, basicFolder, specString, &(iovHashVect[indIOV].first)); + Json2Cool inputJson(ss, basicFolder, specString, &(iovHashVect[ind].first)); if (basicFolder.empty()){ std::string errorMessage = "Reading channel data from "+m_foldername+" failed."; ATH_MSG_FATAL(errorMessage); throw std::runtime_error{errorMessage}; } - } - if(m_crestCoolToFile) { - dumpFile("crest_dump",vkey,nullptr,false,&basicFolder,nodeDesc,specString); - } - retVector.push_back(basicFolder); + if(m_crestCoolToFile) { + dumpFile("crest_dump",vkey,nullptr,false,&basicFolder,nodeDesc,specString); + } + + retVector.push_back(basicFolder); + } return retVector; }