38 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
39 # include <Compression.h>
40 static int s_compressionLevel = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 4 );
42 static int s_compressionLevel = 1;
45 #define ROOT_HAS_630_FWD_COMPAT ROOT_VERSION_CODE > ROOT_VERSION( 6, 30, 4 )
48 #include <fmt/format.h>
53 using namespace Gaudi;
55 typedef const string&
CSTR;
57 static const string s_empty;
58 static const string s_local =
"<localDB>";
60 #ifdef __POOL_COMPATIBILITY
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 );
129 auto idx = compression.find(
':' );
130 if ( idx != string::npos ) {
131 auto alg = compression.substr( 0, idx );
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;
148 s_compressionLevel = ROOT::CompressionSettings( alg_code,
level );
151 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:" +
155 s_compressionLevel =
level;
160 if ( !compression.empty() ) {}
180 if ( fname.size() == 36 && fname[8] ==
'-' && fname[13] ==
'-' && fname[18] ==
'-' && fname[23] ==
'-' ) {
182 m_name.append( fname.data(), fname.size() );
237 #ifdef __POOL_COMPATIBILITY
261 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
273 if ( elem.first ==
"FID" ) {
275 if ( elem.second !=
m_fid ) {
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;
392 if ( !
t && create ) {
393 TDirectory::TContext ctxt(
m_file.
get() );
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;
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;
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 );
461 TBranch* RootDataConnection::getBranch( std::string_view section, std::string_view branch_name, TClass* cl,
void* ptr,
462 int buff_siz,
int split_lvl ) {
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 );
473 if ( b ) b->SetAutoDelete( kFALSE );
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 );
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;
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 )
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 );
665 if ( !cnt.empty() ) {
679 ref.container = ccnt;