9 #include "RootCnv/RootDataConnection.h"
11 #include "GaudiKernel/IOpaqueAddress.h"
12 #include "GaudiKernel/IIncidentSvc.h"
13 #include "GaudiKernel/LinkManager.h"
14 #include "GaudiKernel/strcasecmp.h"
15 #include "GaudiKernel/DataObject.h"
16 #include "GaudiKernel/IRegistry.h"
17 #include "GaudiKernel/Incident.h"
18 #include "GaudiKernel/MsgStream.h"
26 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
27 #include "Compression.h"
28 static int s_compressionLevel = ROOT::CompressionSettings(ROOT::kLZMA,6);
30 static int s_compressionLevel = 1;
36 using namespace Gaudi;
38 typedef const string&
CSTR;
40 static const string s_empty;
41 static const string s_local =
"<localDB>";
43 #ifdef __POOL_COMPATIBILITY
49 std::array<char,256> init_table() {
50 std::array<char,256> table;
57 static bool match_wild(
const char *str,
const char *pat) {
61 static const std::array<char,256> table = init_table();
65 for (s = str, p = pat; *
s; ++
s, ++p) {
68 if (*s ==
'.')
goto starCheck;
73 do { ++pat; }
while (*pat ==
'*');
74 if (!*pat)
return true;
77 if ( table[*s] != table[*p] )
82 while (*p ==
'*') ++p;
86 if (!star)
return false;
93 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
94 int res = 0,
level = ROOT::CompressionSettings(ROOT::kLZMA,6);
95 auto idx = compression.find(
':');
96 if ( idx != string::npos ) {
97 string alg = compression.substr(0,idx);
98 ROOT::ECompressionAlgorithm alg_code = ROOT::kUseGlobalSetting;
99 if ( strcasecmp(alg.c_str(),
"ZLIB") == 0 )
100 alg_code = ROOT::kZLIB;
101 else if ( strcasecmp(alg.c_str(),
"LZMA") == 0 )
102 alg_code = ROOT::kLZMA;
104 throw runtime_error(
"ERROR: request to set unknown ROOT compression algorithm:"+alg);
105 res = ::sscanf(compression.c_str()+idx+1,
"%d",&
level);
107 s_compressionLevel = ROOT::CompressionSettings(alg_code,
level);
110 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:"+compression.substr(idx+1));
112 else if ( 1==::sscanf(compression.c_str(),
"%d",&
level) ) {
113 s_compressionLevel =
level;
116 throw runtime_error(
"ERROR: request to set unknown ROOT compression mechanism:"+compression);
118 if ( !compression.empty() ) {}
125 return s_compressionLevel;
135 int tmp = --refCount;
148 m_incidentSvc.reset(s);
156 if ( fname.length() == 36 && fname[8]==
'-'&&fname[13]==
'-'&&fname[18]==
'-'&&fname[23]==
'-' ) {
157 m_name =
"FID:"+fname;
191 if ( !statisticsFile.empty() )
202 m_statistics.reset(
new TTreePerfStats((section+
"_ioperf").c_str(),t) );
216 #ifdef __POOL_COMPATIBILITY
217 else if (
m_file->Get(
"##Links") != 0 )
240 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
264 if ( !need_fid && fid !=
m_fid ) {
269 msgSvc() << MSG::DEBUG <<
"Using FID " <<
m_fid <<
" from params table...." <<
endmsg
281 m_file.reset(TFile::Open(
m_pfn.c_str(),
"CREATE",
"Root event data",compress));
282 m_refs =
new TTree(
"Refs",
"Root reference data");
292 m_file.reset(TFile::Open(
m_pfn.c_str(),
"RECREATE",
"Root event data",compress));
294 m_refs =
new TTree(
"Refs",
"Root reference data");
303 m_file.reset(TFile::Open(
m_pfn.c_str(),
"UPDATE",
"Root event data",compress));
310 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
319 TDirectory::TContext ctxt(
m_file.get());
320 m_refs =
new TTree(
"Refs",
"Root reference data");
336 if ( !
m_file->IsZombie() ) {
337 if (
m_file->IsWritable() ) {
339 TDirectory::TContext ctxt(
m_file.get());
347 msgSvc() <<
"Disconnect section " <<
i.first <<
" " <<
i.second->GetName() <<
endmsg;
369 t = (TTree*)
m_file->Get(section.c_str());
370 if ( !t && create ) {
371 TDirectory::TContext ctxt(
m_file.get());
372 t =
new TTree(section.c_str(),
"Root data for Gaudi");
375 int cacheSize =
m_setup->cacheSize;
379 if ( section ==
m_setup->loadSection && cacheSize>-2 ) {
381 int learnEntries =
m_setup->learnEntries;
382 t->SetCacheSize(cacheSize);
383 t->SetCacheLearnEntries(learnEntries);
386 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
391 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
392 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
394 if ( cB.empty() && vB.empty()) {
395 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
396 t->AddBranchToCache(
"*",kTRUE);
398 if ( cB.size()==1 && cB[0]==
"*" ) {
399 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
400 t->AddBranchToCache(
"*",kTRUE);
403 for(TIter it(t->GetListOfBranches()); it.Next(); ) {
404 const char*
n = ((TNamed*)(*it))->GetName();
405 bool add =
false, veto =
false;
406 for(
const auto&
i : cB ) {
407 if ( !match_wild(n,(
i).c_str()) )
continue;
411 for(
auto i=vB.cbegin(); !add &&
i!=vB.cend();++
i) {
412 if ( !match_wild(n,(*i).c_str()) )
continue;
416 if ( add && !veto ) {
417 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
418 t->AddBranchToCache(n,kTRUE);
421 msg <<
"Do not cache branch " << n <<
endmsg;
435 string n = branch_name;
437 [](
const char c) {
return !isalnum(c); },
441 TBranch* b = t->GetBranch(n.c_str());
442 if ( !b && cl &&
m_file->IsWritable() ) {
443 b = t->Branch(n.c_str(),cl->GetName(),(
void*)(ptr ? &ptr : 0),buff_siz,split_lvl);
445 if ( !b ) b = t->GetBranch(branch_name.c_str());
446 if ( b ) b->SetAutoDelete(kFALSE);
460 if ( (which>=0) && (
size_t(which)<
m_dbs.size()) ) {
473 pair<int,unsigned long>
475 DataObjectPush push(pObj);
476 return save(section,cnt,cl,pObj,buff_siz,split_lvl,fill);
480 pair<int,unsigned long>
483 TBranch* b =
getBranch(section, cnt, cl, (
void*)(pObj ? &pObj : 0),buff_siz,split_lvl);
485 Long64_t
evt = b->GetEntries();
488 if ( fill_missing ) {
489 Long64_t num,
nevt = b->GetTree()->GetEntries();
493 while( num > 0 ) { b->Fill(); --num; }
494 msgSvc() << MSG::DEBUG <<
"Added " << long(nevt-evt)
495 <<
" / Tree: " << nevt <<
" / Branch: " << b->GetEntries()+1
496 <<
" NULL entries to:" << cnt <<
endmsg;
497 evt = b->GetEntries();
500 b->SetAddress(&pObj);
501 return make_pair(b->Fill(),(
unsigned long)evt);
503 else if ( 0 != pObj ) {
506 return make_pair(-1,~0);
513 TClass* cl = gROOT->GetClass(b->GetClassName(),kTRUE);
518 DataObjectPush push(pObj);
519 b->SetAddress(&pObj);
520 if ( section ==
m_setup->loadSection ) {
521 TTree* t = b->GetTree();
522 if ( Long64_t(entry) != t->GetReadEntry() ) {
523 t->LoadTree(Long64_t(entry));
526 nb = b->GetEntry(entry);
528 if (
msgSvc().isActive() ) {
529 msgSvc() <<
"Load [" << entry <<
"] --> " << section
530 <<
":" << cnt <<
" " << nb <<
" bytes."
534 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
541 else if ( nb == 0 && pObj->
clID() == CLID_DataObject) {
542 TFile* f = b->GetFile();
543 int vsn = f->GetVersion();
549 else if ( vsn>1000000 && (vsn%1000000)<52400 ) {
570 int nbytes =
m_tool->loadRefs(section,cnt,entry,refs);
571 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
586 pair<const RootRef*,const RootDataConnection::ContainerSection*>
594 for(
auto j=s.cbegin(); j != s.cend(); ++j,++cnt) {
600 <<
" [" << entry <<
"]" << endmsg
608 msgSvc() << MSG::DEBUG <<
"Return INVALID MergeSection for:" << container
609 <<
" [" << entry <<
"]" << endmsg
611 return {
nullptr,
nullptr };
623 int cdb=-1, ccnt=-1, clnk=-1;
624 StringVec::iterator idb, icnt, ilnk;
630 for(cdb=0,idb=
m_dbs.begin(); idb!=
m_dbs.end();++idb,++cdb)
631 if( (*idb) == db )
break;
632 if ( idb ==
m_dbs.end() ) {
637 if ( !cnt.empty() ) {
638 for(ccnt=0,icnt=
m_conts.begin(); icnt!=
m_conts.end();++icnt,++ccnt)
639 if( (*icnt) == cnt )
break;
645 if ( !name.empty() ) {
646 for(clnk=0,ilnk=
m_links.begin(); ilnk!=
m_links.end();++ilnk,++clnk)
647 if( (*ilnk) ==
name )
break;
void addClient(const IInterface *client)
Add new client to this data source.
void addRef()
Increase reference count.
void enableStatistics(const std::string §ion)
Enable TTreePerStats.
bool lookupClient(const IInterface *client) const
Lookup client for this data source.
virtual const std::string * par() const =0
Retrieve String parameters.
MergeSections m_mergeSects
Database section map for merged files.
Definition of the MsgStream class used to transmit messages.
GAUDI_API void fill(AIDA::IHistogram1D *histo, const double value, const double weight=1.0)
simple function to fill AIDA::IHistogram1D objects
const long POOL_ROOTKEY_StorageType
void saveStatistics(const std::string &statisticsFile)
Save TTree access statistics if required.
std::pair< int, unsigned long > save(const std::string §ion, const std::string &cnt, TClass *cl, void *pObj, int buff_siz, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
const std::string & fid() const
Access file id.
std::vector< ContainerSection > ContainerSections
Definition of container sections to handle merged files.
std::string m_name
Connection name/identifier.
IoType
I/O Connection types.
std::unique_ptr< TFile > m_file
Reference to ROOT file.
unsigned long getCode() const
Get the status code by value.
std::unique_ptr< Tool > m_tool
const std::string & getDb(int which) const
Access database/file name from saved index.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
auto begin(reverse_wrapper< T > &w)
std::string m_fid
File ID of the connection.
bool isSuccess() const
Test for a status code of SUCCESS.
int loadObj(const std::string §ion, const std::string &cnt, unsigned long entry, DataObject *&pObj)
Load object.
std::unique_ptr< TTreePerfStats > m_statistics
I/O read statistics from TTree.
static int compression()
Access to global compression level.
Clients m_clients
Client list.
int length
The length of the section.
void release()
Decrease reference count.
int start
The start entry of the section.
size_t removeClient(const IInterface *client)
Remove client from this data source.
bool isActive() const
Accessor: is MsgStream active.
const long ROOT_StorageType
virtual const name_type & name() const =0
Name of the directory (or key)
const long POOL_ROOTTREE_StorageType
std::vector< std::string > StringVec
Type definition for string maps.
void setMessageSvc(MsgStream *m)
Set message service reference.
virtual long svcType() const =0
Retrieve service type.
const std::string & pfn() const
Access physical file name.
int loadRefs(const std::string §ion, const std::string &cnt, unsigned long entry, RootObjectRefs &refs)
Load references object.
Persistent reference object containing all leafs and links corresponding to a Gaudi DataObject...
StringVec m_links
Map containing internal links names.
ParamMap m_params
Parameter map for file parameters.
StringVec m_mergeFIDs
Map containing merge FIDs.
std::string m_pfn
Physical file name of the connection.
int dbase
Data members to define object location in the persistent world.
Persistent reference object.
virtual void fireIncident(const Incident &incident)=0
Fire an Incident.
virtual const CLID & clID() const
Retrieve reference to class definition structure.
virtual const CLID & clID() const =0
Retrieve class information from link.
const std::string & name() const
Connection name.
TTree * m_refs
Pointer to the reference tree.
auto end(reverse_wrapper< T > &w)
This class is used for returning status codes from appropriate routines.
void clear(STATE_TYPE _i=std::ios_base::failbit)
Definition of the basic interface.
TBranch * getBranch(const std::string §ion, const std::string &branch_name)
Access data branch by name: Get existing branch in read only mode.
void makeRef(IRegistry *pA, RootRef &ref)
Create reference object from registry entry.
StringVec m_conts
Map containing external container names.
const std::string & empty() const
Empty string reference.
Sections m_sections
Tree sections in TFile.
std::pair< const RootRef *, const ContainerSection * > getMergeSection(const std::string &container, int entry) const
Access link section for single container and entry.
The IRegistry represents the entry door to the environment any data object residing in a transient da...
SmartIF< RootConnectionSetup > m_setup
Reference to the setup structure.
RootDataConnection(const IInterface *own, const std::string &nam, RootConnectionSetup *setup)
Standard constructor.
std::pair< int, unsigned long > saveObj(const std::string §ion, const std::string &cnt, TClass *cl, DataObject *pObj, int buff_siz, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
Tool * makeTool()
Create file access tool to encapsulate POOL compatibiliy.
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
const long POOL_ROOT_StorageType
ABC describing basic data connection.
virtual StatusCode disconnect()
Release data stream and release implementation dependent resources.
virtual StatusCode connectRead()
Open data stream in read mode.
LinkSections m_linkSects
Database link sections.
void resetAge()
Reset age.
Base class for all Incidents (computing events).
MsgStream & msgSvc() const
Allow access to printer service.
virtual StatusCode connectWrite(IoType typ)
Open data stream in write mode.
static long setCompression(const std::string &compression)
Set the global compression level.
int makeLink(const std::string &p)
Convert path string to path index.
Opaque address interface definition.
StringVec m_dbs
Map containing external database file names (fids)
void setIncidentSvc(IIncidentSvc *m)
Set incident service reference.
A DataObject is the base class of any identifiable object on any data store.
Helper functions to set/get the application return code.
Internal helper class, which described a TBranch section in a ROOT file.
const std::string CorruptedInputFile
the input file has shown a corruption
The interface implemented by the IncidentSvc service.
TTree * getSection(const std::string §, bool create=false)
Access TTree section from section name. The section is created if required.
void badWriteError(const std::string &msg) const
Error handler when bad write statements occur.