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;
136 m_incidentSvc.reset(s);
144 if ( fname.length() == 36 && fname[8]==
'-'&&fname[13]==
'-'&&fname[18]==
'-'&&fname[23]==
'-' ) {
145 m_name =
"FID:"+fname;
179 if ( !statisticsFile.empty() )
190 m_statistics.reset(
new TTreePerfStats((section+
"_ioperf").c_str(),t) );
204 #ifdef __POOL_COMPATIBILITY
205 else if (
m_file->Get(
"##Links") != nullptr )
228 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
242 if ( elem.first ==
"FID" ) {
244 if ( elem.second !=
m_fid ) {
245 msgSvc() << MSG::DEBUG <<
"Check FID param:" << elem.second <<
endmsg;
252 if ( !need_fid && fid !=
m_fid ) {
257 msgSvc() << MSG::DEBUG <<
"Using FID " <<
m_fid <<
" from params table...." <<
endmsg
269 m_file.reset(TFile::Open(
m_pfn.c_str(),
"CREATE",
"Root event data",compress));
270 m_refs =
new TTree(
"Refs",
"Root reference data");
280 m_file.reset(TFile::Open(
m_pfn.c_str(),
"RECREATE",
"Root event data",compress));
282 m_refs =
new TTree(
"Refs",
"Root reference data");
291 m_file.reset(TFile::Open(
m_pfn.c_str(),
"UPDATE",
"Root event data",compress));
298 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
307 TDirectory::TContext ctxt(
m_file.get());
308 m_refs =
new TTree(
"Refs",
"Root reference data");
324 if ( !
m_file->IsZombie() ) {
325 if (
m_file->IsWritable() ) {
327 TDirectory::TContext ctxt(
m_file.get());
335 msgSvc() <<
"Disconnect section " <<
i.first <<
" " <<
i.second->GetName() <<
endmsg;
357 t = (TTree*)
m_file->Get(section.c_str());
358 if ( !t && create ) {
359 TDirectory::TContext ctxt(
m_file.get());
360 t =
new TTree(section.c_str(),
"Root data for Gaudi");
363 int cacheSize =
m_setup->cacheSize;
367 if ( section ==
m_setup->loadSection && cacheSize>-2 ) {
369 int learnEntries =
m_setup->learnEntries;
370 t->SetCacheSize(cacheSize);
371 t->SetCacheLearnEntries(learnEntries);
374 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
379 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
380 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
382 if ( cB.empty() && vB.empty()) {
383 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
384 t->AddBranchToCache(
"*",kTRUE);
386 if ( cB.size()==1 && cB[0]==
"*" ) {
387 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
388 t->AddBranchToCache(
"*",kTRUE);
391 for(TIter it(t->GetListOfBranches()); it.Next(); ) {
392 const char*
n = ((TNamed*)(*it))->GetName();
393 bool add =
false, veto =
false;
394 for(
const auto&
i : cB ) {
395 if ( !match_wild(n,(
i).c_str()) )
continue;
399 for(
auto i=vB.cbegin(); !add &&
i!=vB.cend();++
i) {
400 if ( !match_wild(n,(*i).c_str()) )
continue;
404 if ( add && !veto ) {
405 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
406 t->AddBranchToCache(n,kTRUE);
409 msg <<
"Do not cache branch " << n <<
endmsg;
423 string n = branch_name;
425 [](
const char c) {
return !isalnum(c); },
429 TBranch* b = t->GetBranch(n.c_str());
430 if ( !b && cl &&
m_file->IsWritable() ) {
431 b = t->Branch(n.c_str(),cl->GetName(),(
void*)(ptr ? &ptr :
nullptr),buff_siz,split_lvl);
433 if ( !b ) b = t->GetBranch(branch_name.c_str());
434 if ( b ) b->SetAutoDelete(kFALSE);
448 if ( (which>=0) && (
size_t(which)<
m_dbs.size()) ) {
461 pair<int,unsigned long>
463 DataObjectPush push(pObj);
464 return save(section,cnt,cl,pObj,buff_siz,split_lvl,fill);
468 pair<int,unsigned long>
471 TBranch* b =
getBranch(section, cnt, cl, pObj ? &pObj :
nullptr, buff_siz, split_lvl);
473 Long64_t
evt = b->GetEntries();
476 if ( fill_missing ) {
477 Long64_t num,
nevt = b->GetTree()->GetEntries();
479 b->SetAddress(
nullptr);
481 while( num > 0 ) { b->Fill(); --num; }
482 msgSvc() << MSG::DEBUG <<
"Added " << long(nevt-evt)
483 <<
" / Tree: " << nevt <<
" / Branch: " << b->GetEntries()+1
484 <<
" NULL entries to:" << cnt <<
endmsg;
485 evt = b->GetEntries();
488 b->SetAddress(&pObj);
489 return {b->Fill(),evt};
501 TClass* cl = gROOT->GetClass(b->GetClassName(),kTRUE);
506 DataObjectPush push(pObj);
507 b->SetAddress(&pObj);
508 if ( section ==
m_setup->loadSection ) {
509 TTree* t = b->GetTree();
510 if ( Long64_t(entry) != t->GetReadEntry() ) {
511 t->LoadTree(Long64_t(entry));
514 nb = b->GetEntry(entry);
516 if (
msgSvc().isActive() ) {
517 msgSvc() <<
"Load [" << entry <<
"] --> " << section
518 <<
":" << cnt <<
" " << nb <<
" bytes."
522 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
529 else if ( nb == 0 && pObj->
clID() == CLID_DataObject) {
530 TFile* f = b->GetFile();
531 int vsn = f->GetVersion();
537 else if ( vsn>1000000 && (vsn%1000000)<52400 ) {
558 int nbytes =
m_tool->loadRefs(section,cnt,entry,refs);
559 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
574 pair<const RootRef*,const RootDataConnection::ContainerSection*>
582 for(
auto j=s.cbegin(); j != s.cend(); ++j,++cnt) {
588 <<
" [" << entry <<
"]" << endmsg
596 msgSvc() << MSG::DEBUG <<
"Return INVALID MergeSection for:" << container
597 <<
" [" << entry <<
"]" << endmsg
599 return {
nullptr,
nullptr };
611 if ( db ==
m_fid ) db = s_local;
616 auto idb = std::find_if(
m_dbs.begin(),
m_dbs.end(),
617 [&](
const std::string&
i) {
return i == db; } );
618 cdb = std::distance(
m_dbs.begin(),idb);
619 if ( idb ==
m_dbs.end() )
m_dbs.push_back(db);
623 if ( !cnt.empty() ) {
625 [&](
const std::string&
i) {
return i == cnt; } );
626 ccnt = std::distance(
m_conts.begin(),icnt);
631 if ( !name.empty() ) {
633 [&](
const std::string&
i) {
return i ==
name; } );
634 clnk = std::distance(
m_links.begin(), ilnk);
void addClient(const IInterface *client)
Add new client to this data source.
const long POOL_ROOTTREE_StorageType
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
void saveStatistics(const std::string &statisticsFile)
Save TTree access statistics if required.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
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.
std::string m_fid
File ID of the connection.
bool isSuccess() const
Test for a status code of SUCCESS.
auto begin(reverse_wrapper< T > &w)
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.
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.
virtual const name_type & name() const =0
Name of the directory (or key)
std::vector< std::string > StringVec
Type definition for string maps.
void setMessageSvc(MsgStream *m)
Set message service reference.
const long POOL_ROOTKEY_StorageType
StatusCode connectWrite(IoType typ) override
Open data stream in write mode.
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.
std::shared_ptr< RootConnectionSetup > m_setup
Reference to the setup structure.
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...
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.
RootDataConnection(const IInterface *own, const std::string &nam, std::shared_ptr< RootConnectionSetup > setup)
Standard constructor.
StatusCode connectRead() override
Open data stream in read mode.
ABC describing basic data connection.
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.
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)
StatusCode disconnect() override
Release data stream and release implementation dependent resources.
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.
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.
const long ROOT_StorageType
const long POOL_ROOT_StorageType