11 #include "RootCnv/RootDataConnection.h"
13 #include "GaudiKernel/IOpaqueAddress.h"
14 #include "GaudiKernel/IIncidentSvc.h"
15 #include "GaudiKernel/LinkManager.h"
16 #include "GaudiKernel/strcasecmp.h"
17 #include "GaudiKernel/DataObject.h"
18 #include "GaudiKernel/IRegistry.h"
19 #include "GaudiKernel/Incident.h"
20 #include "GaudiKernel/MsgStream.h"
28 #include "TTreePerfStats.h"
29 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
30 #include "Compression.h"
31 static int s_compressionLevel = ROOT::CompressionSettings(ROOT::kLZMA,6);
33 static int s_compressionLevel = 1;
39 using namespace Gaudi;
41 typedef const string&
CSTR;
43 static string s_empty;
44 static string s_local =
"<localDB>";
46 #ifdef __POOL_COMPATIBILITY
51 static bool match_wild(
const char *str,
const char *pat) {
55 static char table[256];
56 static bool first =
true;
60 for (
int i = 0;
i < 256; ++
i) table[
i] =
char(
i);
64 for (s = str, p = pat; *
s; ++
s, ++p) {
67 if (*s ==
'.')
goto starCheck;
72 do { ++pat; }
while (*pat ==
'*');
73 if (!*pat)
return true;
76 if ( *(table+*s) != *(table+*p) )
81 while (*p ==
'*') ++p;
85 if (!star)
return false;
91 RootConnectionSetup::RootConnectionSetup() : refCount(1), m_msgSvc(0), m_incidentSvc(0)
96 RootConnectionSetup::~RootConnectionSetup() {
97 if ( m_incidentSvc ) m_incidentSvc->release();
103 long RootConnectionSetup::setCompression(
const std::string& compression) {
104 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
105 int res = 0,
level = ROOT::CompressionSettings(ROOT::kLZMA,6);
106 size_t idx = compression.find(
':');
107 if ( idx != string::npos ) {
108 string alg = compression.substr(0,idx);
109 ROOT::ECompressionAlgorithm alg_code = ROOT::kUseGlobalSetting;
110 if ( strcasecmp(alg.c_str(),
"ZLIB") == 0 )
111 alg_code = ROOT::kZLIB;
112 else if ( strcasecmp(alg.c_str(),
"LZMA") == 0 )
113 alg_code = ROOT::kLZMA;
115 throw runtime_error(
"ERROR: request to set unknown ROOT compression algorithm:"+alg);
116 res = ::sscanf(compression.c_str()+idx+1,
"%d",&
level);
118 s_compressionLevel = ROOT::CompressionSettings(alg_code,
level);
121 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:"+compression.substr(idx+1));
123 else if ( 1==::sscanf(compression.c_str(),
"%d",&
level) ) {
124 s_compressionLevel =
level;
127 throw runtime_error(
"ERROR: request to set unknown ROOT compression mechanism:"+compression);
129 if ( !compression.empty() ) {}
135 int RootConnectionSetup::compression() {
136 return s_compressionLevel;
140 void RootConnectionSetup::addRef() {
145 void RootConnectionSetup::release() {
146 int tmp = --refCount;
163 if ( m_incidentSvc ) m_incidentSvc->addRef();
169 :
IDataConnection(owner,fname), m_setup(setup), m_statistics(0), m_tool(0)
172 if ( fname.length() == 36 && fname[8]==
'-'&&fname[13]==
'-'&&fname[18]==
'-'&&fname[23]==
'-' ) {
173 m_name =
"FID:"+fname;
183 RootDataConnection::~RootDataConnection() {
189 void RootDataConnection::addClient(
const IInterface* client) {
190 m_clients.insert(client);
194 size_t RootDataConnection::removeClient(
const IInterface* client) {
195 Clients::iterator
i=m_clients.find(client);
196 if ( i != m_clients.end() ) m_clients.erase(i);
197 return m_clients.size();
201 bool RootDataConnection::lookupClient(
const IInterface* client)
const {
202 Clients::const_iterator
i=m_clients.find(client);
203 return i != m_clients.end();
207 void RootDataConnection::badWriteError(
const string&
msg)
const {
208 msgSvc() <<
MSG::ERROR <<
"File:" << fid() <<
"Failed action:" << msg <<
endmsg;
212 void RootDataConnection::saveStatistics(
CSTR statisticsFile) {
213 if ( m_statistics ) {
214 m_statistics->Print();
215 if ( !statisticsFile.empty() )
216 m_statistics->SaveAs(statisticsFile.c_str());
217 deletePtr(m_statistics);
222 void RootDataConnection::enableStatistics(
CSTR section) {
223 if ( 0 == m_statistics ) {
224 TTree* t=getSection(section,
false);
226 m_statistics =
new TTreePerfStats((section+
"_ioperf").c_str(),t);
229 msgSvc() <<
MSG::WARNING <<
"Failed to enable perfstats for tree:" << section <<
endmsg;
238 if ( !m_refs ) m_refs = (TTree*)m_file->Get(
"Refs");
241 #ifdef __POOL_COMPATIBILITY
242 else if ( m_file->Get(
"##Links") != 0 )
250 m_file = TFile::Open(m_pfn.c_str());
251 if ( m_file && !m_file->IsZombie() ) {
254 if ( msgSvc().isActive() ) m_file->ls();
256 if ( msgSvc().isActive() ) m_file->Print();
258 sc = m_tool->readRefs();
260 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
261 if ( sc.
getCode() == ROOT_READ_ERROR ) {
270 bool need_fid = m_fid == m_pfn;
273 for(
size_t i=0,
n=m_params.size();
i<
n; ++
i) {
274 if ( m_params[
i].first ==
"FID" ) {
275 m_mergeFIDs.push_back(m_params[
i].second);
276 if ( m_params[
i].second != m_fid ) {
277 msgSvc() << MSG::DEBUG <<
"Check FID param:" << m_params[
i].second <<
endmsg;
279 m_fid = m_params[
i].second;
284 if ( !need_fid && fid != m_fid ) {
285 msgSvc() <<
MSG::ERROR <<
"FID mismatch:" << fid <<
"(Catalog) != " << m_fid <<
"(file)" <<
endmsg
286 <<
"for PFN:" << m_pfn <<
endmsg;
289 msgSvc() << MSG::DEBUG <<
"Using FID " << m_fid <<
" from params table...." <<
endmsg
290 <<
"for PFN:" << m_pfn <<
endmsg;
302 int compress = RootConnectionSetup::compression();
307 m_file = TFile::Open(m_pfn.c_str(),
"CREATE",
"Root event data",compress);
308 m_refs =
new TTree(
"Refs",
"Root reference data");
309 msgSvc() <<
"Opened file " << m_pfn <<
" in mode CREATE. [" << m_fid <<
"]" <<
endmsg;
310 m_params.push_back(make_pair(
"PFN",m_pfn));
311 if ( m_fid != m_pfn ) {
312 m_params.push_back(make_pair(
"FID",m_fid));
318 m_file = TFile::Open(m_pfn.c_str(),
"RECREATE",
"Root event data",compress);
319 msgSvc() <<
"Opened file " << m_pfn <<
" in mode RECREATE. [" << m_fid <<
"]" <<
endmsg;
320 m_refs =
new TTree(
"Refs",
"Root reference data");
321 m_params.push_back(make_pair(
"PFN",m_pfn));
322 if ( m_fid != m_pfn ) {
323 m_params.push_back(make_pair(
"FID",m_fid));
329 m_file = TFile::Open(m_pfn.c_str(),
"UPDATE",
"Root event data",compress);
330 msgSvc() <<
"Opened file " << m_pfn <<
" in mode UPDATE. [" << m_fid <<
"]" <<
endmsg;
331 if ( m_file && !m_file->IsZombie() ) {
335 if ( sc.
getCode() == ROOT_READ_ERROR ) {
336 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
345 TDirectory::TContext ctxt(m_file);
346 m_refs =
new TTree(
"Refs",
"Root reference data");
362 if ( !m_file->IsZombie() ) {
363 if ( m_file->IsWritable() ) {
365 TDirectory::TContext ctxt(m_file);
367 if ( !m_tool->saveRefs().isSuccess() ) badWriteError(
"Saving References");
368 if ( m_refs->Write() < 0 ) badWriteError(
"Write Reference branch");
370 for(Sections::iterator
i=m_sections.begin();
i!= m_sections.end();++
i) {
372 if ( (*i).second->Write() < 0 ) badWriteError(
"Write section:"+(*i).first);
373 msgSvc() <<
"Disconnect section " << (*i).first <<
" " << (*i).second->GetName() <<
endmsg;
379 if ( msgSvc().isActive() ) m_file->ls();
381 if ( msgSvc().isActive() ) m_file->Print();
384 msgSvc() <<
MSG::DEBUG <<
"Disconnected file " << m_pfn <<
" " << m_file->GetName() <<
endmsg;
392 TTree* RootDataConnection::getSection(
CSTR section,
bool create) {
393 TTree* t = m_sections[section];
395 t = (TTree*)m_file->Get(section.c_str());
396 if ( !t && create ) {
397 TDirectory::TContext ctxt(m_file);
398 t =
new TTree(section.c_str(),
"Root data for Gaudi");
401 int cacheSize = m_setup->cacheSize;
405 if ( section == m_setup->loadSection && cacheSize>-2 ) {
407 int learnEntries = m_setup->learnEntries;
408 t->SetCacheSize(cacheSize);
409 t->SetCacheLearnEntries(learnEntries);
412 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
415 const StringVec& vB = m_setup->vetoBranches;
416 const StringVec& cB = m_setup->cacheBranches;
417 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
418 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
420 if ( cB.size()==0 && vB.size()== 0 ) {
421 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
422 t->AddBranchToCache(
"*",kTRUE);
424 if ( cB.size()==1 && cB[0]==
"*" ) {
425 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
426 t->AddBranchToCache(
"*",kTRUE);
429 StringVec::const_iterator
i;
430 for(TIter it(t->GetListOfBranches()); it.Next(); ) {
431 const char*
n = ((TNamed*)(*it))->GetName();
432 bool add =
false, veto =
false;
433 for(i=cB.begin(); i != cB.end();++
i) {
434 if ( !match_wild(n,(*i).c_str()) )
continue;
438 for(i=vB.begin(); !add && i!=vB.end();++
i) {
439 if ( !match_wild(n,(*i).c_str()) )
continue;
443 if ( add && !veto ) {
444 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
445 t->AddBranchToCache(n,kTRUE);
448 msg <<
"Do not cache branch " << n <<
endmsg;
454 m_sections[section] = t;
461 TBranch* RootDataConnection::getBranch(
CSTR section,
CSTR branch_name, TClass* cl,
void* ptr,
int buff_siz,
int split_lvl) {
462 string n = branch_name+
".";
463 for(
int i=0, m=n.length()-1; i<
m; ++
i)
if ( !isalnum(n[i]) ) n[i]=
'_';
464 TTree* t = getSection(section,
true);
465 TBranch* b = t->GetBranch(n.c_str());
466 if ( !b && cl && m_file->IsWritable() ) {
467 b = t->Branch(n.c_str(),cl->GetName(),(
void*)(ptr ? &ptr : 0),buff_siz,split_lvl);
470 b = t->GetBranch(branch_name.c_str());
473 b->SetAutoDelete(kFALSE);
479 int RootDataConnection::makeLink(
CSTR p) {
481 StringVec::iterator ip;
482 for(ip=m_links.begin();ip!=m_links.end();++ip,++cnt) {
483 if( (*ip) == p )
return cnt;
485 m_links.push_back(p);
486 return m_links.size()-1;
491 if ( (which>=0) && (
size_t(which)<m_dbs.size()) ) {
492 if ( *(m_dbs.begin()+
which) == s_local )
return m_fid;
493 return *(m_dbs.begin()+
which);
499 CSTR RootDataConnection::empty()
const {
504 pair<int,unsigned long>
505 RootDataConnection::saveObj(
CSTR section,
CSTR cnt, TClass* cl,
DataObject* pObj,
int buff_siz,
int split_lvl,
bool fill) {
506 DataObjectPush push(pObj);
507 return save(section,cnt,cl,pObj,buff_siz,split_lvl,fill);
511 pair<int,unsigned long>
512 RootDataConnection::save(
CSTR section,
CSTR cnt, TClass* cl,
void* pObj,
int buff_siz,
int split_lvl,
bool fill_missing) {
514 TBranch* b = getBranch(section, cnt, cl, (
void*)(pObj ? &pObj : 0),buff_siz,split_lvl);
516 Long64_t
evt = b->GetEntries();
519 if ( fill_missing ) {
520 Long64_t num,
nevt = b->GetTree()->GetEntries();
524 while( num > 0 ) { b->Fill(); --num; }
525 msgSvc() << MSG::DEBUG <<
"Added " << long(nevt-evt)
526 <<
" / Tree: " << nevt <<
" / Branch: " << b->GetEntries()+1
527 <<
" NULL entries to:" << cnt <<
endmsg;
528 evt = b->GetEntries();
531 b->SetAddress(&pObj);
532 return make_pair(b->Fill(),(
unsigned long)evt);
534 else if ( 0 != pObj ) {
535 msgSvc() <<
MSG::ERROR <<
"Failed to access branch " << m_name <<
"/" << cnt <<
endmsg;
537 return make_pair(-1,~0);
541 int RootDataConnection::loadObj(
CSTR section,
CSTR cnt,
unsigned long entry,
DataObject*& pObj) {
542 TBranch* b = getBranch(section,cnt);
544 TClass* cl = gROOT->GetClass(b->GetClassName(),kTRUE);
549 DataObjectPush push(pObj);
550 b->SetAddress(&pObj);
551 if ( section == m_setup->loadSection ) {
552 TTree* t = b->GetTree();
553 if ( Long64_t(entry) != t->GetReadEntry() ) {
554 t->LoadTree(Long64_t(entry));
557 nb = b->GetEntry(entry);
559 if ( msgSvc().isActive() ) {
560 msgSvc() <<
"Load [" << entry <<
"] --> " << section
561 <<
":" << cnt <<
" " << nb <<
" bytes."
565 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
572 else if ( nb == 0 && pObj->
clID() == CLID_DataObject) {
573 TFile* f = b->GetFile();
574 int vsn = f->GetVersion();
580 else if ( vsn>1000000 && (vsn%1000000)<52400 ) {
598 int RootDataConnection::loadRefs(
const std::string& section,
const std::string& cnt,
601 int nbytes = m_tool->loadRefs(section,cnt,entry,refs);
602 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,33,0)
617 pair<const RootRef*,const RootDataConnection::ContainerSection*>
618 RootDataConnection::getMergeSection(
const string& container,
int entry)
const {
621 MergeSections::const_iterator i=m_mergeSects.find(container);
622 if ( i != m_mergeSects.end() ) {
625 for(ContainerSections::const_iterator j=s.begin(); j != s.end(); ++j,++cnt) {
628 if ( m_linkSects.size() > cnt ) {
629 if ( msgSvc().isActive() ) {
630 msgSvc() <<
MSG::VERBOSE <<
"MergeSection for:" << container
631 <<
" [" << entry <<
"]" << endmsg
632 <<
"FID:" << m_fid <<
" -> PFN:" << m_pfn <<
endmsg;
634 return make_pair(&(m_linkSects[cnt]), &c);
639 msgSvc() << MSG::DEBUG <<
"Return INVALID MergeSection for:" << container
640 <<
" [" << entry <<
"]" << endmsg
641 <<
"FID:" << m_fid <<
" -> PFN:" << m_pfn <<
endmsg;
652 void RootDataConnection::makeRef(
CSTR name,
long clid,
int tech,
CSTR dbase,
CSTR cnt,
int entry,
RootRef& ref) {
654 int cdb=-1, ccnt=-1, clnk=-1;
655 StringVec::iterator idb, icnt, ilnk;
661 for(cdb=0,idb=m_dbs.begin(); idb!=m_dbs.end();++idb,++cdb)
662 if( (*idb) == db )
break;
663 if ( idb == m_dbs.end() ) {
668 if ( !cnt.empty() ) {
669 for(ccnt=0,icnt=m_conts.begin(); icnt!=m_conts.end();++icnt,++ccnt)
670 if( (*icnt) == cnt )
break;
671 if ( icnt == m_conts.end() ) {
672 ccnt = m_conts.size();
673 m_conts.push_back(cnt);
676 if ( !name.empty() ) {
677 for(clnk=0,ilnk=m_links.begin(); ilnk!=m_links.end();++ilnk,++clnk)
678 if( (*ilnk) == name )
break;
679 if ( ilnk == m_links.end() ) {
680 clnk = m_links.size();
681 m_links.push_back(name);