28 #include "Compression.h"
29 #include "TTreePerfStats.h"
34 using namespace Gaudi;
36 typedef const string&
CSTR;
41 #ifdef __POOL_COMPATIBILITY
48 static bool match_wild(
const char *str,
const char *pat) {
52 static char table[256];
53 static bool first =
true;
57 for (
int i = 0;
i < 256; ++
i) table[
i] =
char(
i);
61 for (s = str, p = pat; *
s; ++
s, ++p) {
64 if (*s ==
'.')
goto starCheck;
69 do { ++pat; }
while (*pat ==
'*');
70 if (!*pat)
return true;
73 if ( *(table+*s) != *(table+*p) )
78 while (*p ==
'*') ++p;
82 if (!star)
return false;
88 RootConnectionSetup::RootConnectionSetup() : refCount(1), m_msgSvc(0), m_incidentSvc(0)
93 RootConnectionSetup::~RootConnectionSetup() {
94 if ( m_incidentSvc ) m_incidentSvc->release();
100 long RootConnectionSetup::setCompression(
const std::string& compression) {
101 int res = 0,
level = ROOT::CompressionSettings(ROOT::kLZMA,6);
102 size_t idx = compression.find(
':');
103 if ( idx != string::npos ) {
104 string alg = compression.substr(0,idx);
105 ROOT::ECompressionAlgorithm alg_code = ROOT::kUseGlobalSetting;
106 if ( strcasecmp(alg.c_str(),
"ZLIB") == 0 )
107 alg_code = ROOT::kZLIB;
108 else if ( strcasecmp(alg.c_str(),
"LZMA") == 0 )
109 alg_code = ROOT::kLZMA;
111 throw runtime_error(
"ERROR: request to set unknown ROOT compression algorithm:"+alg);
112 res = ::sscanf(compression.c_str()+idx+1,
"%d",&
level);
117 throw runtime_error(
"ERROR: request to set unknown ROOT compression level:"+compression.substr(idx+1));
119 else if ( 1==::sscanf(compression.c_str(),
"%d",&
level) ) {
123 throw runtime_error(
"ERROR: request to set unknown ROOT compression mechanism:"+compression);
127 int RootConnectionSetup::compression() {
132 void RootConnectionSetup::addRef() {
137 void RootConnectionSetup::release() {
138 int tmp = --refCount;
155 if ( m_incidentSvc ) m_incidentSvc->addRef();
161 :
IDataConnection(owner,fname), m_setup(setup), m_statistics(0), m_tool(0)
164 if ( fname.length() == 36 && fname[8]==
'-'&&fname[13]==
'-'&&fname[18]==
'-'&&fname[23]==
'-' ) {
175 RootDataConnection::~RootDataConnection() {
181 void RootDataConnection::addClient(
const IInterface* client) {
182 m_clients.insert(client);
186 size_t RootDataConnection::removeClient(
const IInterface* client) {
188 if ( i != m_clients.end() ) m_clients.
erase(i);
189 return m_clients.size();
193 bool RootDataConnection::lookupClient(
const IInterface* client)
const {
195 return i != m_clients.
end();
199 void RootDataConnection::badWriteError(
const string&
msg)
const {
200 msgSvc() <<
MSG::ERROR <<
"File:" << fid() <<
"Failed action:" << msg <<
endmsg;
204 void RootDataConnection::saveStatistics(
CSTR statisticsFile) {
205 if ( m_statistics ) {
206 m_statistics->Print();
207 if ( !statisticsFile.empty() )
208 m_statistics->SaveAs(statisticsFile.c_str());
209 deletePtr(m_statistics);
214 void RootDataConnection::enableStatistics(
CSTR section) {
215 if ( 0 == m_statistics ) {
216 TTree* t=getSection(section,
false);
218 m_statistics =
new TTreePerfStats((section+
"_ioperf").c_str(),t);
221 msgSvc() <<
MSG::WARNING <<
"Failed to enable perfstats for tree:" << section <<
endmsg;
230 if ( !m_refs ) m_refs = (TTree*)m_file->Get(
"Refs");
233 #ifdef __POOL_COMPATIBILITY
234 else if ( m_file->Get(
"##Links") != 0 )
242 m_file = TFile::Open(m_pfn.c_str());
243 if ( m_file && !m_file->IsZombie() ) {
246 if ( msgSvc().isActive() ) m_file->ls();
248 if ( msgSvc().isActive() ) m_file->Print();
250 sc = m_tool->readRefs();
252 if ( sc.
getCode() == ROOT_READ_ERROR ) {
260 bool need_fid = m_fid == m_pfn;
263 for(
size_t i=0, n=m_params.
size();
i<n; ++
i) {
264 if ( m_params[
i].first ==
"FID" ) {
265 m_mergeFIDs.push_back(m_params[
i].
second);
266 if ( m_params[
i].second != m_fid ) {
267 msgSvc() << MSG::DEBUG <<
"Check FID param:" << m_params[
i].second <<
endmsg;
269 m_fid = m_params[
i].second;
274 if ( !need_fid && fid != m_fid ) {
275 msgSvc() <<
MSG::ERROR <<
"FID mismatch:" << fid <<
"(Catalog) != " << m_fid <<
"(file)" <<
endmsg
276 <<
"for PFN:" << m_pfn <<
endmsg;
279 msgSvc() << MSG::DEBUG <<
"Using FID " << m_fid <<
" from params table...." <<
endmsg
280 <<
"for PFN:" << m_pfn <<
endmsg;
292 int compress = RootConnectionSetup::compression();
297 m_file = TFile::Open(m_pfn.c_str(),
"CREATE",
"Root event data",compress);
298 m_refs =
new TTree(
"Refs",
"Root reference data");
299 msgSvc() <<
"Opened file " << m_pfn <<
" in mode CREATE. [" << m_fid <<
"]" <<
endmsg;
300 m_params.push_back(
make_pair(
"PFN",m_pfn));
301 if ( m_fid != m_pfn ) {
302 m_params.push_back(
make_pair(
"FID",m_fid));
308 m_file = TFile::Open(m_pfn.c_str(),
"RECREATE",
"Root event data",compress);
309 msgSvc() <<
"Opened file " << m_pfn <<
" in mode RECREATE. [" << m_fid <<
"]" <<
endmsg;
310 m_refs =
new TTree(
"Refs",
"Root reference data");
311 m_params.push_back(
make_pair(
"PFN",m_pfn));
312 if ( m_fid != m_pfn ) {
313 m_params.push_back(
make_pair(
"FID",m_fid));
319 m_file = TFile::Open(m_pfn.c_str(),
"UPDATE",
"Root event data",compress);
320 msgSvc() <<
"Opened file " << m_pfn <<
" in mode UPDATE. [" << m_fid <<
"]" <<
endmsg;
321 if ( m_file && !m_file->IsZombie() ) {
325 if ( sc.
getCode() == ROOT_READ_ERROR ) {
333 TDirectory::TContext ctxt(m_file);
334 m_refs =
new TTree(
"Refs",
"Root reference data");
350 if ( !m_file->IsZombie() ) {
351 if ( m_file->IsWritable() ) {
353 TDirectory::TContext ctxt(m_file);
355 if ( !m_tool->saveRefs().isSuccess() ) badWriteError(
"Saving References");
356 if ( m_refs->Write() < 0 ) badWriteError(
"Write Reference branch");
360 if ( (*i).second->Write() < 0 ) badWriteError(
"Write section:"+(*i).first);
361 msgSvc() <<
"Disconnect section " << (*i).first <<
" " << (*i).second->GetName() <<
endmsg;
367 if ( msgSvc().isActive() ) m_file->ls();
369 if ( msgSvc().isActive() ) m_file->Print();
372 msgSvc() <<
MSG::DEBUG <<
"Disconnected file " << m_pfn <<
" " << m_file->GetName() <<
endmsg;
380 TTree* RootDataConnection::getSection(
CSTR section,
bool create) {
381 TTree* t = m_sections[section];
383 t = (TTree*)m_file->Get(section.c_str());
384 if ( !t && create ) {
385 TDirectory::TContext ctxt(m_file);
386 t =
new TTree(section.c_str(),
"Root data for Gaudi");
389 int cacheSize = m_setup->cacheSize;
393 if ( section == m_setup->loadSection && cacheSize>-2 ) {
395 int learnEntries = m_setup->learnEntries;
396 t->SetCacheSize(cacheSize);
397 t->SetCacheLearnEntries(learnEntries);
400 msg <<
"Tree:" << section <<
"Setting up tree cache:" << cacheSize <<
endmsg;
403 const StringVec& vB = m_setup->vetoBranches;
404 const StringVec& cB = m_setup->cacheBranches;
405 msg <<
"Tree:" << section <<
" Setting up tree cache:" << cacheSize <<
" Add all branches." <<
endmsg;
406 msg <<
"Tree:" << section <<
" Learn for " << learnEntries <<
" entries." <<
endmsg;
408 if ( cB.
size()==0 && vB.
size()== 0 ) {
409 msg <<
"Adding (default) all branches to tree cache." <<
endmsg;
410 t->AddBranchToCache(
"*",kTRUE);
412 if ( cB.
size()==1 && cB[0]==
"*" ) {
413 msg <<
"Adding all branches to tree cache according to option \"CacheBranches\"." <<
endmsg;
414 t->AddBranchToCache(
"*",kTRUE);
418 for(TIter it(t->GetListOfBranches()); it.Next(); ) {
419 const char* n = ((TNamed*)(*it))->GetName();
420 bool add =
false, veto =
false;
426 for(i=vB.
begin(); !add && i!=vB.
end();++
i) {
431 if ( add && !veto ) {
432 msg <<
"Add " << n <<
" to branch cache." <<
endmsg;
433 t->AddBranchToCache(n,kTRUE);
436 msg <<
"Do not cache branch " << n <<
endmsg;
442 m_sections[section] = t;
449 TBranch* RootDataConnection::getBranch(
CSTR section,
CSTR branch_name, TClass* cl,
void* ptr,
int buff_siz,
int split_lvl) {
450 string n = branch_name+
".";
451 for(
int i=0,
m=n.length()-1;
i<
m; ++
i)
if ( !
isalnum(n[
i]) ) n[i]=
'_';
452 TTree* t = getSection(section,
true);
453 TBranch* b = t->GetBranch(n.c_str());
454 if ( !b && cl && m_file->IsWritable() ) {
455 b = t->Branch(n.c_str(),cl->GetName(),(
void*)(ptr ? &ptr : 0),buff_siz,split_lvl);
458 b = t->GetBranch(branch_name.c_str());
461 b->SetAutoDelete(kFALSE);
467 int RootDataConnection::makeLink(
CSTR p) {
470 for(ip=m_links.begin();ip!=m_links.end();++ip,++cnt) {
471 if( (*ip) == p )
return cnt;
473 m_links.push_back(p);
474 return m_links.size()-1;
479 if ( (which>=0) && (
size_t(which)<m_dbs.size()) ) {
481 return *(m_dbs.begin()+
which);
493 RootDataConnection::saveObj(
CSTR section,
CSTR cnt, TClass* cl,
DataObject* pObj,
int buff_siz,
int split_lvl,
bool fill) {
494 DataObjectPush push(pObj);
495 return save(section,cnt,cl,pObj,buff_siz,split_lvl,fill);
500 RootDataConnection::save(
CSTR section,
CSTR cnt, TClass* cl,
void* pObj,
int buff_siz,
int split_lvl,
bool fill_missing) {
502 TBranch* b = getBranch(section, cnt, cl, (
void*)(pObj ? &pObj : 0),buff_siz,split_lvl);
504 Long64_t
evt = b->GetEntries();
507 if ( fill_missing ) {
508 Long64_t num,
nevt = b->GetTree()->GetEntries();
512 while( num > 0 ) { b->Fill(); --num; }
513 msgSvc() <<
MSG::DEBUG <<
"Added " << long(nevt-evt)
514 <<
" / Tree: " << nevt <<
" / Branch: " << b->GetEntries()+1
515 <<
" NULL entries to:" << cnt <<
endmsg;
516 evt = b->GetEntries();
519 b->SetAddress(&pObj);
520 return make_pair(b->Fill(),(
unsigned long)evt);
522 else if ( 0 != pObj ) {
523 msgSvc() <<
MSG::ERROR <<
"Failed to access branch " << m_name <<
"/" << cnt <<
endmsg;
530 TBranch* b = getBranch(section,cnt);
532 TClass* cl = gROOT->GetClass(b->GetClassName(),kTRUE);
537 DataObjectPush push(pObj);
538 b->SetAddress(&pObj);
539 if ( section == m_setup->loadSection ) {
540 TTree* t = b->GetTree();
541 if ( Long64_t(entry) != t->GetReadEntry() ) {
542 t->LoadTree(Long64_t(entry));
545 nb = b->GetEntry(entry);
547 if ( msgSvc().isActive() ) {
548 msgSvc() <<
"Load [" << entry <<
"] --> " << section
549 <<
":" << cnt <<
" " << nb <<
" bytes."
559 TFile* f = b->GetFile();
560 int vsn = f->GetVersion();
566 else if ( vsn>1000000 && (vsn%1000000)<52400 ) {
587 int nbytes = m_tool->loadRefs(section,cnt,entry,refs);
602 RootDataConnection::getMergeSection(
const string& container,
int entry)
const {
606 if ( i != m_mergeSects.end() ) {
609 for(ContainerSections::const_iterator j=s.
begin(); j != s.
end(); ++j,++cnt) {
612 if ( m_linkSects.size() > cnt ) {
613 if ( msgSvc().isActive() ) {
614 msgSvc() <<
MSG::VERBOSE <<
"MergeSection for:" << container
615 <<
" [" << entry <<
"]" <<
endmsg
616 <<
"FID:" << m_fid <<
" -> PFN:" << m_pfn <<
endmsg;
618 return make_pair(&(m_linkSects[cnt]), &c);
623 msgSvc() <<
MSG::DEBUG <<
"Return INVALID MergeSection for:" << container
624 <<
" [" << entry <<
"]" <<
endmsg
625 <<
"FID:" << m_fid <<
" -> PFN:" << m_pfn <<
endmsg;
636 void RootDataConnection::makeRef(
CSTR name,
long clid,
int tech,
CSTR dbase,
CSTR cnt,
int entry,
RootRef& ref) {
638 int cdb=-1, ccnt=-1, clnk=-1;
639 StringVec::iterator idb, icnt, ilnk;
645 for(cdb=0,idb=m_dbs.begin(); idb!=m_dbs.end();++idb,++cdb)
646 if( (*idb) == db )
break;
647 if ( idb == m_dbs.end() ) {
652 if ( !cnt.empty() ) {
653 for(ccnt=0,icnt=m_conts.begin(); icnt!=m_conts.end();++icnt,++ccnt)
654 if( (*icnt) == cnt )
break;
655 if ( icnt == m_conts.end() ) {
656 ccnt = m_conts.size();
657 m_conts.push_back(cnt);
660 if ( !name.empty() ) {
661 for(clnk=0,ilnk=m_links.begin(); ilnk!=m_links.end();++ilnk,++clnk)
662 if( (*ilnk) == name )
break;
663 if ( ilnk == m_links.end() ) {
664 clnk = m_links.size();
665 m_links.push_back(name);