30#include <Compression.h>
39static int s_compressionLevel = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 4 );
41#define ROOT_HAS_630_FWD_COMPAT ROOT_VERSION_CODE > ROOT_VERSION( 6, 30, 4 )
54static const string s_empty;
55static const string s_local =
"<localDB>";
57#ifdef __POOL_COMPATIBILITY
63 std::array<char, 256> init_table() {
64 std::array<char, 256> table;
65 std::iota( std::begin( table ), std::end( table ), 0 );
70 const char* name()
const override {
return "RootDataConnection"; }
77 return "ROOT_READ_ERROR";
79 return "ROOT_OPEN_ERROR";
86 static bool match_wild(
const char* str,
const char* pat ) {
90 static const auto table = init_table();
94 for ( s = str, p = pat; *s; ++s, ++p ) {
97 if ( *s ==
'.' )
goto starCheck;
102 do { ++pat; }
while ( *pat ==
'*' );
103 if ( !*pat )
return true;
106 if ( table[*s] != table[*p] )
goto starCheck;
110 while ( *p ==
'*' ) ++p;
114 if ( !star )
return false;
124 int res = 0, level = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 6 );
126 if ( idx != string::npos ) {
128 ROOT::RCompressionSetting::EAlgorithm::EValues alg_code = ROOT::RCompressionSetting::EAlgorithm::kUseGlobal;
129 if ( alg.size() == 4 && strncasecmp( alg.data(),
"ZLIB", 4 ) == 0 )
130 alg_code = ROOT::RCompressionSetting::EAlgorithm::kZLIB;
131 else if ( alg.size() == 4 && strncasecmp( alg.data(),
"LZMA", 4 ) == 0 )
132 alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZMA;
133 else if ( alg.size() == 3 && strncasecmp( alg.data(),
"LZ4", 3 ) == 0 )
134 alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZ4;
135 else if ( alg.size() == 4 && strncasecmp( alg.data(),
"ZSTD", 4 ) == 0 )
136 alg_code = ROOT::RCompressionSetting::EAlgorithm::kZSTD;
138 throw runtime_error(
"ERROR: request to set unknown ROOT compression algorithm:" + std::string{ alg } );
139 res = ::sscanf( std::string{
compression.substr( idx + 1 ) }.c_str(),
"%d",
142 s_compressionLevel = ROOT::CompressionSettings( alg_code, level );
145 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:" +
147 }
else if ( 1 == ::sscanf( std::string{
compression }.c_str(),
"%d", &level ) ) {
149 s_compressionLevel = level;
152 throw runtime_error(
"ERROR: request to set unknown ROOT compression mechanism:" + std::string{
compression } );
166 std::shared_ptr<RootConnectionSetup> setup )
170 if ( fname.size() == 36 && fname[8] ==
'-' && fname[13] ==
'-' && fname[18] ==
'-' && fname[23] ==
'-' ) {
172 m_name.append( fname.data(), fname.size() );
204 if ( !statisticsFile.empty() )
m_statistics->SaveAs( std::string{ statisticsFile }.c_str() );
214 m_statistics.reset(
new TTreePerfStats( ( std::string{ section } +
"_ioperf" ).c_str(), t ) );
227#ifdef __POOL_COMPATIBILITY
228 else if (
m_file->Get(
"##Links" ) !=
nullptr )
261 if ( elem.first ==
"FID" ) {
263 if ( elem.second !=
m_fid ) {
285 std::string spec =
m_pfn;
286 if (
m_setup->produceReproducibleFiles ) spec +=
"?reproducible";
290 m_file.reset( TFile::Open( spec.c_str(),
"CREATE",
"Root event data", compress ) );
291#if ROOT_HAS_630_FWD_COMPAT
292 if (
m_file &&
m_setup->root630ForwardCompatibility )
m_file->SetBit( TFile::k630forwardCompatibility );
294 m_refs =
new TTree(
"Refs",
"Root reference data" );
302 m_file.reset( TFile::Open( spec.c_str(),
"RECREATE",
"Root event data", compress ) );
303#if ROOT_HAS_630_FWD_COMPAT
304 if (
m_file &&
m_setup->root630ForwardCompatibility )
m_file->SetBit( TFile::k630forwardCompatibility );
307 m_refs =
new TTree(
"Refs",
"Root reference data" );
314 m_file.reset( TFile::Open( spec.c_str(),
"UPDATE",
"Root event data", compress ) );
326 TDirectory::TContext ctxt(
m_file.get() );
327 m_refs =
new TTree(
"Refs",
"Root reference data" );
343 if ( !
m_file->IsZombie() ) {
344 if (
m_file->IsWritable() ) {
346 TDirectory::TContext ctxt(
m_file.get() );
353 if ( i.second->Write() < 0 )
badWriteError(
"Write section:" + i.first );
354 msgSvc() <<
"Disconnect section " << i.first <<
" " << i.second->GetName() <<
endmsg;
375 TTree* t = ( it !=
m_sections.end() ? it->second :
nullptr );
377 t = (TTree*)
m_file->Get( std::string{ section }.c_str() );
378 if ( !t && create ) {
379 TDirectory::TContext ctxt(
m_file.get() );
380 t =
new TTree( std::string{ section }.c_str(),
"Root data for Gaudi" );
383 int cacheSize =
m_setup->cacheSize;
387 if ( section ==
m_setup->loadSection && cacheSize > -2 ) {
389 int learnEntries =
m_setup->learnEntries;
390 t->SetCacheSize( cacheSize );
391 t->SetCacheLearnEntries( learnEntries );
394 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
398 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
399 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
401 if ( cB.empty() && vB.empty() ) {
402 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
403 t->AddBranchToCache(
"*", kTRUE );
405 if ( cB.size() == 1 && cB[0] ==
"*" ) {
406 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
407 t->AddBranchToCache(
"*", kTRUE );
409 for ( TIter it( t->GetListOfBranches() ); it.Next(); ) {
410 const char* n = ( (TNamed*)( *it ) )->GetName();
411 bool add =
false, veto =
false;
412 for (
const auto& i : cB ) {
413 if ( !match_wild( n, ( i ).c_str() ) )
continue;
417 for (
auto i = vB.cbegin(); !add && i != vB.cend(); ++i ) {
418 if ( !match_wild( n, ( *i ).c_str() ) )
continue;
422 if ( add && !veto ) {
423 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
424 t->AddBranchToCache( n, kTRUE );
426 msg <<
"Do not cache branch " << n <<
endmsg;
436 auto key =
m_file->GetKey( std::string{ section }.c_str() );
448 int buff_siz,
int split_lvl ) {
449 string n = std::string{ branch_name };
451 begin( n ), end( n ), [](
const char c ) {
return !isalnum( c ); },
'_' );
454 TBranch* b = t->GetBranch( n.c_str() );
455 if ( !b && cl &&
m_file->IsWritable() ) {
456 b = t->Branch( n.c_str(), cl->GetName(), (
void*)( ptr ? &ptr :
nullptr ), buff_siz, split_lvl );
458 if ( !b ) b = t->GetBranch( std::string{ branch_name }.c_str() );
459 if ( b ) b->SetAutoDelete( kFALSE );
465 auto ip = std::find( std::begin(
m_links ), std::end(
m_links ), p );
466 if ( ip != std::end(
m_links ) )
return std::distance( std::begin(
m_links ), ip );
467 m_links.push_back( std::string{ p } );
473 if ( ( which >= 0 ) && (
size_t( which ) <
m_dbs.size() ) ) {
474 if ( *(
m_dbs.begin() + which ) == s_local )
return m_fid;
475 return *(
m_dbs.begin() + which );
485 DataObject* pObj,
int minBufferSize,
int maxBufferSize,
486 int approxEventsPerBasket,
int split_lvl,
bool fill ) {
487 DataObjectPush push( pObj );
488 return save( section, cnt, cl, pObj, minBufferSize, maxBufferSize, approxEventsPerBasket, split_lvl, fill );
493 void* pObj,
int minBufferSize,
int maxBufferSize,
494 int approxEventsPerBasket,
int split_lvl,
bool fill_missing ) {
496 TBranch* b =
getBranch( section, cnt, cl, pObj ? &pObj :
nullptr, minBufferSize, split_lvl );
498 Long64_t evt = b->GetEntries();
501 bool set_buffer_size = ( evt == 0 );
502 if ( fill_missing ) {
503 Long64_t num, nevt = b->GetTree()->GetEntries();
505 set_buffer_size =
true;
506 b->SetAddress(
nullptr );
512 msgSvc() <<
MSG::DEBUG <<
"Added " << long( nevt - evt ) <<
" / Tree: " << nevt
513 <<
" / Branch: " << b->GetEntries() + 1 <<
" NULL entries to:" << cnt <<
endmsg;
514 evt = b->GetEntries();
517 if ( set_buffer_size ) {
518 auto dummy_file = make_unique<TMemFile>(
"dummy.root",
"CREATE" );
519 auto dummy_tree = make_unique<TTree>(
"DummyTree",
"DummyTree", split_lvl, dummy_file->GetDirectory(
"/" ) );
520 TBranch* dummy_branch = dummy_tree->Branch(
"DummyBranch", cl->GetName(), &pObj, minBufferSize, split_lvl );
521 Int_t nWritten = dummy_branch->Fill();
522 if ( nWritten < 0 )
return { nWritten, evt };
523 Int_t newBasketSize = nWritten * approxEventsPerBasket;
525 if ( std::numeric_limits<Int_t>::max() / approxEventsPerBasket < nWritten ) {
526 newBasketSize = std::numeric_limits<Int_t>::max();
528 b->SetBasketSize( std::min( maxBufferSize, std::max( minBufferSize, newBasketSize ) ) );
531 b->SetAddress( &pObj );
532 return { b->Fill(), evt };
543 TClass* cl = gROOT->GetClass( b->GetClassName(), kTRUE );
548 DataObjectPush push( pObj );
549 b->SetAddress( &pObj );
550 if ( section ==
m_setup->loadSection ) {
551 TTree* t = b->GetTree();
552 if ( Long64_t( entry ) != t->GetReadEntry() ) { t->LoadTree( Long64_t( entry ) ); }
554 nb = b->GetEntry( entry );
556 if (
msgSvc().isActive() ) {
557 msgSvc() <<
"Load [" << entry <<
"] --> " << section <<
":" << cnt <<
" " << nb <<
" bytes." <<
endmsg;
562 }
else if ( nb == 0 && pObj->
clID() == CLID_DataObject ) {
563 TFile* f = b->GetFile();
564 int vsn = f->GetVersion();
569 }
else if ( vsn > 1000000 && ( vsn % 1000000 ) < 52400 ) {
589 int nbytes =
m_tool->loadRefs( section, cnt, entry, refs );
601pair<const RootRef*, const RootDataConnection::ContainerSection*>
609 for (
auto j = s.cbegin(); j != s.cend(); ++j, ++cnt ) {
611 if ( entry >= c.start && entry < ( c.start + c.length ) ) {
613 if (
msgSvc().isActive() ) {
622 msgSvc() <<
MSG::DEBUG <<
"Return INVALID MergeSection for:" << container <<
" [" << entry <<
"]" <<
endmsg
624 return {
nullptr,
nullptr };
635 std::string_view cnt,
int entry,
RootRef& ref ) {
636 auto db = ( dbase ==
m_fid ? std::string_view{ s_local } : dbase );
641 auto idb = std::find_if(
m_dbs.begin(),
m_dbs.end(), [&](
const std::string& i ) { return i == db; } );
642 cdb = std::distance(
m_dbs.begin(), idb );
643 if ( idb ==
m_dbs.end() )
m_dbs.push_back( std::string{ db } );
647 if ( !cnt.empty() ) {
648 auto icnt = std::find_if(
m_conts.begin(),
m_conts.end(), [&](
const std::string& i ) { return i == cnt; } );
649 ccnt = std::distance(
m_conts.begin(), icnt );
650 if ( icnt ==
m_conts.end() )
m_conts.push_back( std::string{ cnt } );
654 if ( !
name.empty() ) {
655 auto ilnk = std::find_if(
m_links.begin(),
m_links.end(), [&](
const std::string& i ) { return i == name; } );
656 clnk = std::distance(
m_links.begin(), ilnk );
661 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.