37#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
38# include <Compression.h>
39static int s_compressionLevel = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 4 );
41static int s_compressionLevel = 1;
44#define ROOT_HAS_630_FWD_COMPAT ROOT_VERSION_CODE > ROOT_VERSION( 6, 30, 4 )
47#include <fmt/format.h>
57static const string s_empty;
58static const string s_local =
"<localDB>";
60#ifdef __POOL_COMPATIBILITY
66 std::array<char, 256> init_table() {
67 std::array<char, 256> table;
68 std::iota( std::begin( table ), std::end( table ), 0 );
73 const char* name()
const override {
return "RootDataConnection"; }
80 return "ROOT_READ_ERROR";
82 return "ROOT_OPEN_ERROR";
89 static bool match_wild(
const char* str,
const char* pat ) {
93 static const auto table = init_table();
97 for ( s = str, p = pat; *s; ++s, ++p ) {
100 if ( *s ==
'.' )
goto starCheck;
105 do { ++pat; }
while ( *pat ==
'*' );
106 if ( !*pat )
return true;
109 if ( table[*s] != table[*p] )
goto starCheck;
113 while ( *p ==
'*' ) ++p;
117 if ( !star )
return false;
127#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
128 int res = 0, level = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 6 );
130 if ( idx != string::npos ) {
132 ROOT::RCompressionSetting::EAlgorithm::EValues alg_code = ROOT::RCompressionSetting::EAlgorithm::kUseGlobal;
133 if ( alg.size() == 4 && strncasecmp( alg.data(),
"ZLIB", 4 ) == 0 )
134 alg_code = ROOT::RCompressionSetting::EAlgorithm::kZLIB;
135 else if ( alg.size() == 4 && strncasecmp( alg.data(),
"LZMA", 4 ) == 0 )
136 alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZMA;
137 else if ( alg.size() == 3 && strncasecmp( alg.data(),
"LZ4", 3 ) == 0 )
138 alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZ4;
139# if ROOT_VERSION_CODE >= ROOT_VERSION( 6, 20, 0 )
140 else if ( alg.size() == 4 && strncasecmp( alg.data(),
"ZSTD", 4 ) == 0 )
141 alg_code = ROOT::RCompressionSetting::EAlgorithm::kZSTD;
144 throw runtime_error(
"ERROR: request to set unknown ROOT compression algorithm:" + std::string{ alg } );
145 res = ::sscanf( std::string{
compression.substr( idx + 1 ) }.c_str(),
"%d",
148 s_compressionLevel = ROOT::CompressionSettings( alg_code, level );
151 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:" +
153 }
else if ( 1 == ::sscanf( std::string{
compression }.c_str(),
"%d", &level ) ) {
155 s_compressionLevel = level;
158 throw runtime_error(
"ERROR: request to set unknown ROOT compression mechanism:" + std::string{
compression } );
176 std::shared_ptr<RootConnectionSetup> setup )
180 if ( fname.size() == 36 && fname[8] ==
'-' && fname[13] ==
'-' && fname[18] ==
'-' && fname[23] ==
'-' ) {
182 m_name.append( fname.data(), fname.size() );
214 if ( !statisticsFile.empty() )
m_statistics->SaveAs( std::string{ statisticsFile }.c_str() );
224 m_statistics.reset(
new TTreePerfStats( ( std::string{ section } +
"_ioperf" ).c_str(), t ) );
237#ifdef __POOL_COMPATIBILITY
238 else if (
m_file->Get(
"##Links" ) !=
nullptr )
261#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
273 if ( elem.first ==
"FID" ) {
275 if ( elem.second !=
m_fid ) {
297 std::string spec =
m_pfn;
298 if (
m_setup->produceReproducibleFiles ) spec +=
"?reproducible";
302 m_file.reset( TFile::Open( spec.c_str(),
"CREATE",
"Root event data", compress ) );
303#if ROOT_HAS_630_FWD_COMPAT
304 if (
m_file &&
m_setup->root630ForwardCompatibility )
m_file->SetBit( TFile::k630forwardCompatibility );
306 m_refs =
new TTree(
"Refs",
"Root reference data" );
314 m_file.reset( TFile::Open( spec.c_str(),
"RECREATE",
"Root event data", compress ) );
315#if ROOT_HAS_630_FWD_COMPAT
316 if (
m_file &&
m_setup->root630ForwardCompatibility )
m_file->SetBit( TFile::k630forwardCompatibility );
319 m_refs =
new TTree(
"Refs",
"Root reference data" );
326 m_file.reset( TFile::Open( spec.c_str(),
"UPDATE",
"Root event data", compress ) );
333#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
340 TDirectory::TContext ctxt(
m_file.get() );
341 m_refs =
new TTree(
"Refs",
"Root reference data" );
357 if ( !
m_file->IsZombie() ) {
358 if (
m_file->IsWritable() ) {
360 TDirectory::TContext ctxt(
m_file.get() );
367 if ( i.second->Write() < 0 )
badWriteError(
"Write section:" + i.first );
368 msgSvc() <<
"Disconnect section " << i.first <<
" " << i.second->GetName() <<
endmsg;
389 TTree* t = ( it !=
m_sections.end() ? it->second :
nullptr );
391 t = (TTree*)
m_file->Get( std::string{ section }.c_str() );
392 if ( !t && create ) {
393 TDirectory::TContext ctxt(
m_file.get() );
394 t =
new TTree( std::string{ section }.c_str(),
"Root data for Gaudi" );
397 int cacheSize =
m_setup->cacheSize;
401 if ( section ==
m_setup->loadSection && cacheSize > -2 ) {
403 int learnEntries =
m_setup->learnEntries;
404 t->SetCacheSize( cacheSize );
405 t->SetCacheLearnEntries( learnEntries );
408 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
412 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
413 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
415 if ( cB.empty() && vB.empty() ) {
416 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
417 t->AddBranchToCache(
"*", kTRUE );
419 if ( cB.size() == 1 && cB[0] ==
"*" ) {
420 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
421 t->AddBranchToCache(
"*", kTRUE );
423 for ( TIter it( t->GetListOfBranches() ); it.Next(); ) {
424 const char* n = ( (TNamed*)( *it ) )->GetName();
425 bool add =
false, veto =
false;
426 for (
const auto& i : cB ) {
427 if ( !match_wild( n, ( i ).c_str() ) )
continue;
431 for (
auto i = vB.cbegin(); !add && i != vB.cend(); ++i ) {
432 if ( !match_wild( n, ( *i ).c_str() ) )
continue;
436 if ( add && !veto ) {
437 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
438 t->AddBranchToCache( n, kTRUE );
440 msg <<
"Do not cache branch " << n <<
endmsg;
450 auto key =
m_file->GetKey( std::string{ section }.c_str() );
462 int buff_siz,
int split_lvl ) {
463 string n = std::string{ branch_name };
465 begin( n ), end( n ), [](
const char c ) {
return !isalnum( c ); },
'_' );
468 TBranch* b = t->GetBranch( n.c_str() );
469 if ( !b && cl &&
m_file->IsWritable() ) {
470 b = t->Branch( n.c_str(), cl->GetName(), (
void*)( ptr ? &ptr :
nullptr ), buff_siz, split_lvl );
472 if ( !b ) b = t->GetBranch( std::string{ branch_name }.c_str() );
473 if ( b ) b->SetAutoDelete( kFALSE );
479 auto ip = std::find( std::begin(
m_links ), std::end(
m_links ), p );
480 if ( ip != std::end(
m_links ) )
return std::distance( std::begin(
m_links ), ip );
481 m_links.push_back( std::string{ p } );
487 if ( ( which >= 0 ) && (
size_t( which ) <
m_dbs.size() ) ) {
488 if ( *(
m_dbs.begin() + which ) == s_local )
return m_fid;
489 return *(
m_dbs.begin() + which );
499 DataObject* pObj,
int minBufferSize,
int maxBufferSize,
500 int approxEventsPerBasket,
int split_lvl,
bool fill ) {
501 DataObjectPush push( pObj );
502 return save( section, cnt, cl, pObj, minBufferSize, maxBufferSize, approxEventsPerBasket, split_lvl, fill );
507 void* pObj,
int minBufferSize,
int maxBufferSize,
508 int approxEventsPerBasket,
int split_lvl,
bool fill_missing ) {
510 TBranch* b =
getBranch( section, cnt, cl, pObj ? &pObj :
nullptr, minBufferSize, split_lvl );
512 Long64_t evt = b->GetEntries();
515 bool set_buffer_size = ( evt == 0 );
516 if ( fill_missing ) {
517 Long64_t num, nevt = b->GetTree()->GetEntries();
519 set_buffer_size =
true;
520 b->SetAddress(
nullptr );
526 msgSvc() <<
MSG::DEBUG <<
"Added " << long( nevt - evt ) <<
" / Tree: " << nevt
527 <<
" / Branch: " << b->GetEntries() + 1 <<
" NULL entries to:" << cnt <<
endmsg;
528 evt = b->GetEntries();
531 if ( set_buffer_size ) {
532 auto dummy_file = make_unique<TMemFile>(
"dummy.root",
"CREATE" );
533 auto dummy_tree = make_unique<TTree>(
"DummyTree",
"DummyTree", split_lvl, dummy_file->GetDirectory(
"/" ) );
534 TBranch* dummy_branch = dummy_tree->Branch(
"DummyBranch", cl->GetName(), &pObj, minBufferSize, split_lvl );
535 Int_t nWritten = dummy_branch->Fill();
536 if ( nWritten < 0 )
return { nWritten, evt };
537 Int_t newBasketSize = nWritten * approxEventsPerBasket;
539 if ( std::numeric_limits<Int_t>::max() / approxEventsPerBasket < nWritten ) {
540 newBasketSize = std::numeric_limits<Int_t>::max();
542 b->SetBasketSize( std::min( maxBufferSize, std::max( minBufferSize, newBasketSize ) ) );
545 b->SetAddress( &pObj );
546 return { b->Fill(), evt };
557 TClass* cl = gROOT->GetClass( b->GetClassName(), kTRUE );
562 DataObjectPush push( pObj );
563 b->SetAddress( &pObj );
564 if ( section ==
m_setup->loadSection ) {
565 TTree* t = b->GetTree();
566 if ( Long64_t( entry ) != t->GetReadEntry() ) { t->LoadTree( Long64_t( entry ) ); }
568 nb = b->GetEntry( entry );
570 if (
msgSvc().isActive() ) {
571 msgSvc() <<
"Load [" << entry <<
"] --> " << section <<
":" << cnt <<
" " << nb <<
" bytes." <<
endmsg;
574#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
578 }
else if ( nb == 0 && pObj->
clID() == CLID_DataObject ) {
579 TFile* f = b->GetFile();
580 int vsn = f->GetVersion();
585 }
else if ( vsn > 1000000 && ( vsn % 1000000 ) < 52400 ) {
605 int nbytes =
m_tool->loadRefs( section, cnt, entry, refs );
606#if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
619pair<const RootRef*, const RootDataConnection::ContainerSection*>
627 for (
auto j = s.cbegin(); j != s.cend(); ++j, ++cnt ) {
629 if ( entry >= c.start && entry < ( c.start + c.length ) ) {
631 if (
msgSvc().isActive() ) {
640 msgSvc() <<
MSG::DEBUG <<
"Return INVALID MergeSection for:" << container <<
" [" << entry <<
"]" <<
endmsg
642 return {
nullptr,
nullptr };
653 std::string_view cnt,
int entry,
RootRef& ref ) {
654 auto db = ( dbase ==
m_fid ? std::string_view{ s_local } : dbase );
659 auto idb = std::find_if(
m_dbs.begin(),
m_dbs.end(), [&](
const std::string& i ) { return i == db; } );
660 cdb = std::distance(
m_dbs.begin(), idb );
661 if ( idb ==
m_dbs.end() )
m_dbs.push_back( std::string{ db } );
665 if ( !cnt.empty() ) {
666 auto icnt = std::find_if(
m_conts.begin(),
m_conts.end(), [&](
const std::string& i ) { return i == cnt; } );
667 ccnt = std::distance(
m_conts.begin(), icnt );
668 if ( icnt ==
m_conts.end() )
m_conts.push_back( std::string{ cnt } );
672 if ( !
name.empty() ) {
673 auto ilnk = std::find_if(
m_links.begin(),
m_links.end(), [&](
const std::string& i ) { return i == name; } );
674 clnk = std::distance(
m_links.begin(), ilnk );
679 ref.container = ccnt;
const long POOL_ROOTKEY_StorageType
const long POOL_ROOT_StorageType
const long POOL_ROOTTREE_StorageType
const long ROOT_StorageType
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
#define STATUSCODE_ENUM_IMPL(...)
Assign a category to the StatusCode enum declared with STATUSCODE_ENUM_DECL( ENUM )
A DataObject is the base class of any identifiable object on any data store.
virtual const CLID & clID() const
Retrieve reference to class definition structure.
std::string m_fid
File ID of the connection.
const IInterface * owner() const
Owner instance.
void resetAge()
Reset age.
std::string m_pfn
Physical file name of the connection.
const std::string & fid() const
Access file id.
std::string m_name
Connection name/identifier.
const std::string & name() const
Connection name.
IDataConnection(const IInterface *own, std::string nam)
Standard constructor.
const std::string & pfn() const
Access physical file name.
IoType
I/O Connection types.
RootConnectionSetup()=default
Standard constructor.
SmartIF< IIncidentSvc > m_incidentSvc
Reference to incident service.
void setMessageSvc(MsgStream *m)
Set message service reference.
static int compression()
Access to global compression level.
void setIncidentSvc(IIncidentSvc *m)
Set incident service reference.
static StatusCode setCompression(std::string_view compression)
Set the global compression level.
std::unique_ptr< MsgStream > m_msgSvc
Reference to message service.
Sections m_sections
Tree sections in TFile.
LinkSections m_linkSects
Database link sections.
void addClient(const IInterface *client)
Add new client to this data source.
Tool * makeTool()
Create file access tool to encapsulate POOL compatibiliy.
StringVec m_links
Map containing internal links names.
const std::string & empty() const
Empty string reference.
MsgStream & msgSvc() const
Allow access to printer service.
std::vector< std::string > StringVec
Type definition for string maps.
std::vector< ContainerSection > ContainerSections
Definition of container sections to handle merged files.
RootDataConnection(const IInterface *own, std::string_view nam, std::shared_ptr< RootConnectionSetup > setup)
Standard constructor.
std::unique_ptr< TTreePerfStats > m_statistics
I/O read statistics from TTree.
std::unique_ptr< Tool > m_tool
Clients m_clients
Client list.
ParamMap m_params
Parameter map for file parameters.
TTree * getSection(std::string_view sect, bool create=false)
Access TTree section from section name. The section is created if required.
std::unique_ptr< TFile > m_file
Reference to ROOT file.
std::pair< int, unsigned long > save(std::string_view section, std::string_view cnt, TClass *cl, void *pObj, int minBufferSize, int maxBufferSize, int approxEventsPerBasket, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
MergeSections m_mergeSects
Database section map for merged files.
StatusCode disconnect() override
Release data stream and release implementation dependent resources.
StatusCode connectRead() override
Open data stream in read mode.
int makeLink(std::string_view p)
Convert path string to path index.
StringVec m_conts
Map containing external container names.
bool lookupClient(const IInterface *client) const
Lookup client for this data source.
StatusCode connectWrite(IoType typ) override
Open data stream in write mode.
void saveStatistics(std::string_view statisticsFile)
Save TTree access statistics if required.
TBranch * getBranch(std::string_view section, std::string_view branch_name)
Access data branch by name: Get existing branch in read only mode.
StringVec m_mergeFIDs
Map containing merge FIDs.
StringVec m_dbs
Map containing external database file names (fids)
std::shared_ptr< RootConnectionSetup > m_setup
Reference to the setup structure.
void makeRef(const IRegistry &pA, RootRef &ref)
Create reference object from registry entry.
const std::string & getDb(int which) const
Access database/file name from saved index.
void enableStatistics(std::string_view section)
Enable TTreePerStats.
std::pair< int, unsigned long > saveObj(std::string_view section, std::string_view cnt, TClass *cl, DataObject *pObj, int minBufferSize, int maxBufferSize, int approxEventsPerBasket, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
int loadRefs(std::string_view section, std::string_view cnt, unsigned long entry, RootObjectRefs &refs)
Load references object.
std::pair< const RootRef *, const ContainerSection * > getMergeSection(std::string_view container, int entry) const
Access link section for single container and entry.
void badWriteError(std::string_view msg) const
Error handler when bad write statements occur.
int loadObj(std::string_view section, std::string_view cnt, unsigned long entry, DataObject *&pObj)
Load object.
IIncidentSvc * incidentSvc() const
TTree * m_refs
Pointer to the reference tree.
size_t removeClient(const IInterface *client)
Remove client from this data source.
The interface implemented by the IncidentSvc service.
virtual void fireIncident(const Incident &incident)=0
Fire an Incident.
Definition of the basic interface.
Opaque address interface definition.
virtual long svcType() const =0
Retrieve service type.
virtual const CLID & clID() const =0
Retrieve class information from link.
virtual const std::string * par() const =0
Retrieve String parameters.
The IRegistry represents the entry door to the environment any data object residing in a transient da...
virtual const name_type & name() const =0
Name of the directory (or key)
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
Base class for all Incidents (computing events).
Definition of the MsgStream class used to transmit messages.
This class is used for returning status codes from appropriate routines.
static const Category & default_category() noexcept
Default Gaudi StatusCode category.
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
unsigned long code_t
type of StatusCode value
constexpr static const auto SUCCESS
constexpr static const auto FAILURE
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Internal helper class, which described a TBranch section in a ROOT file.
Persistent reference object containing all leafs and links corresponding to a Gaudi DataObject.
Persistent reference object.
The category assigned to a StatusCode.
virtual std::string message(code_t code) const
Description for code within this category.