| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
RootDataConnection.cpp
Go to the documentation of this file.
1 // $Id: RootDataConnection.cpp,v 1.16 2010-09-27 15:43:53 frankb Exp $
2 //====================================================================
3 // RootDataConnection.cpp
4 //--------------------------------------------------------------------
5 //
6 // Author : M.Frank
7 //====================================================================
8 // $Header: /afs/cern.ch/project/cvs/reps/lhcb/Online/RootCnv/src/RootDataConnection.cpp,v 1.16 2010-09-27 15:43:53 frankb Exp $
9
10 // Framework include files
11 #include "RootCnv/RootDataConnection.h"
12 #include "RootUtils.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"
21 // ROOT include files
22 #include "TROOT.h"
23 #include "TFile.h"
24 #include "TTree.h"
25 #include "TLeaf.h"
26 #include "TClass.h"
27 #include "TBranch.h"
28 #include "Compression.h"
29 #include "TTreePerfStats.h"
30
31 // C/C++ include files
32 #include <stdexcept>
33
34 using namespace Gaudi;
35 using namespace std;
36 typedef const string& CSTR;
37
38 static string s_empty;
39 static string s_local = "<localDB>";
40
41 #ifdef __POOL_COMPATIBILITY
42 #include "PoolTool.h"
43 #endif
44 #include "RootTool.h"
45
46 static int s_compressionLevel = ROOT::CompressionSettings(ROOT::kLZMA,6);
47
48 static bool match_wild(const char *str, const char *pat) {
49 //
50 // Credits: Code from Alessandro Felice Cantatore.
51 //
52 static char table[256];
53 static bool first = true;
54 const char *s, *p;
55 bool star = false;
56 if ( first ) {
57 for (int i = 0; i < 256; ++i) table[i] = char(i);
58 first = false;
59 }
60 loopStart:
61 for (s = str, p = pat; *s; ++s, ++p) {
62 switch (*p) {
63 case '?':
64 if (*s == '.') goto starCheck;
65 break;
66 case '*':
67 star = true;
68 str = s, pat = p;
69 do { ++pat; } while (*pat == '*');
70 if (!*pat) return true;
71 goto loopStart;
72 default:
73 if ( *(table+*s) != *(table+*p) )
74 goto starCheck;
75 break;
76 } /* endswitch */
77 } /* endfor */
78 while (*p == '*') ++p;
79 return (!*p);
80
81 starCheck:
82 if (!star) return false;
83 str++;
84 goto loopStart;
85 }
86
88 RootConnectionSetup::RootConnectionSetup() : refCount(1), m_msgSvc(0), m_incidentSvc(0)
89 {
90 }
91
93 RootConnectionSetup::~RootConnectionSetup() {
94 if ( m_incidentSvc ) m_incidentSvc->release();
95 m_incidentSvc = 0;
96 deletePtr(m_msgSvc);
97 }
98
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;
110 else
111 throw runtime_error("ERROR: request to set unknown ROOT compression algorithm:"+alg);
112 res = ::sscanf(compression.c_str()+idx+1,"%d",&level);
113 if ( res == 1 ) {
114 s_compressionLevel = ROOT::CompressionSettings(alg_code,level);
115 return StatusCode::SUCCESS;
116 }
117 throw runtime_error("ERROR: request to set unknown ROOT compression level:"+compression.substr(idx+1));
118 }
119 else if ( 1==::sscanf(compression.c_str(),"%d",&level) ) {
120 s_compressionLevel = level;
121 return StatusCode::SUCCESS;
122 }
123 throw runtime_error("ERROR: request to set unknown ROOT compression mechanism:"+compression);
124 }
125
127 int RootConnectionSetup::compression() {
128 return s_compressionLevel;
129 }
130
132 void RootConnectionSetup::addRef() {
133 ++refCount;
134 }
135
137 void RootConnectionSetup::release() {
138 int tmp = --refCount;
139 if ( tmp <= 0 ) {
140 delete this;
141 }
142 }
143
145 void RootConnectionSetup::setMessageSvc(MsgStream* m) {
146 MsgStream* tmp = m_msgSvc;
147 m_msgSvc = m;
148 deletePtr(tmp);
149 }
150
152 void RootConnectionSetup::setIncidentSvc(IIncidentSvc* s) {
153 IIncidentSvc* tmp = m_incidentSvc;
154 m_incidentSvc = s;
155 if ( m_incidentSvc ) m_incidentSvc->addRef();
156 if ( tmp ) tmp->release();
157 }
158
160 RootDataConnection::RootDataConnection(const IInterface* owner, CSTR fname, RootConnectionSetup* setup)
161 : IDataConnection(owner,fname), m_setup(setup), m_statistics(0), m_tool(0)
162 { // 01234567890123456789012345678901234567890
163 // Check if FID: A82A3BD8-7ECB-DC11-8DC0-000423D950B0
164 if ( fname.length() == 36 && fname[8]=='-'&&fname[13]=='-'&&fname[18]=='-'&&fname[23]=='-' ) {
165 m_name = "FID:"+fname;
166 }
167 m_setup->addRef();
168 m_age = 0;
169 m_file = 0;
170 m_refs = 0;
171 addClient(owner);
172 }
173
175 RootDataConnection::~RootDataConnection() {
176 m_setup->release();
177 releasePtr(m_tool);
178 }
179
181 void RootDataConnection::addClient(const IInterface* client) {
182 m_clients.insert(client);
183 }
184
186 size_t RootDataConnection::removeClient(const IInterface* client) {
187 Clients::iterator i=m_clients.find(client);
188 if ( i != m_clients.end() ) m_clients.erase(i);
189 return m_clients.size();
190 }
191
193 bool RootDataConnection::lookupClient(const IInterface* client) const {
194 Clients::const_iterator i=m_clients.find(client);
195 return i != m_clients.end();
196 }
197
199 void RootDataConnection::badWriteError(const string& msg) const {
200 msgSvc() << MSG::ERROR << "File:" << fid() << "Failed action:" << msg << endmsg;
201 }
202
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);
210 }
211 }
212
214 void RootDataConnection::enableStatistics(CSTR section) {
215 if ( 0 == m_statistics ) {
216 TTree* t=getSection(section,false);
217 if ( t ) {
218 m_statistics = new TTreePerfStats((section+"_ioperf").c_str(),t);
219 return;
220 }
221 msgSvc() << MSG::WARNING << "Failed to enable perfstats for tree:" << section << endmsg;
222 return;
223 }
224 msgSvc() << MSG::INFO << "Perfstats are ALREADY ENABLED." << endmsg;
225 }
226
228 RootDataConnection::Tool* RootDataConnection::makeTool() {
229 releasePtr(m_tool);
230 if ( !m_refs ) m_refs = (TTree*)m_file->Get("Refs");
231 if ( m_refs )
232 m_tool = new RootTool(this);
233 #ifdef __POOL_COMPATIBILITY
234 else if ( m_file->Get("##Links") != 0 )
235 m_tool = new PoolTool(this);
236 #endif
237 return m_tool;
238 }
239
241 StatusCode RootDataConnection::connectRead() {
242 m_file = TFile::Open(m_pfn.c_str());
243 if ( m_file && !m_file->IsZombie() ) {
244 StatusCode sc = StatusCode::FAILURE;
245 msgSvc() << MSG::DEBUG << "Opened file " << m_pfn << " in mode READ. [" << m_fid << "]" << endmsg << MSG::DEBUG;
246 if ( msgSvc().isActive() ) m_file->ls();
247 msgSvc() << MSG::VERBOSE;
248 if ( msgSvc().isActive() ) m_file->Print();
249 if ( makeTool() ) {
250 sc = m_tool->readRefs();
251 sc.ignore();
252 if ( sc.getCode() == ROOT_READ_ERROR ) {
253 IIncidentSvc* inc = m_setup->incidentSvc();
254 if ( inc ) {
255 inc->fireIncident(Incident(pfn(),IncidentType::CorruptedInputFile));
256 }
257 }
258 }
259 if ( sc.isSuccess() ) {
260 bool need_fid = m_fid == m_pfn;
261 string fid = m_fid;
262 m_mergeFIDs.clear();
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;
268 //if ( m_fid == m_pfn ) {
269 m_fid = m_params[i].second;
270 //}
271 }
272 }
273 }
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;
277 return StatusCode::FAILURE;
278 }
279 msgSvc() << MSG::DEBUG << "Using FID " << m_fid << " from params table...." << endmsg
280 << "for PFN:" << m_pfn << endmsg;
281 return sc;
282 }
283 }
284 else if ( m_file ) {
285 deletePtr(m_file);
286 }
287 return StatusCode::FAILURE;
288 }
289
291 StatusCode RootDataConnection::connectWrite(IoType typ) {
292 int compress = RootConnectionSetup::compression();
293 msgSvc() << MSG::DEBUG;
294 switch(typ) {
295 case CREATE:
296 resetAge();
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));
303 }
304 makeTool();
305 break;
306 case RECREATE:
307 resetAge();
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));
314 }
315 makeTool();
316 break;
317 case UPDATE:
318 resetAge();
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() ) {
322 if ( makeTool() ) {
323 StatusCode sc = m_tool->readRefs();
324 sc.ignore();
325 if ( sc.getCode() == ROOT_READ_ERROR ) {
326 IIncidentSvc* inc = m_setup->incidentSvc();
327 if ( inc ) {
328 inc->fireIncident(Incident(pfn(),IncidentType::CorruptedInputFile));
329 }
330 }
331 return sc;
332 }
333 TDirectory::TContext ctxt(m_file);
334 m_refs = new TTree("Refs","Root reference data");
335 makeTool();
336 return StatusCode::SUCCESS;
337 }
338 break;
339 default:
340 m_refs = 0;
341 m_file = 0;
342 return StatusCode::FAILURE;
343 }
344 return 0==m_file ? StatusCode::FAILURE : StatusCode::SUCCESS;
345 }
346
348 StatusCode RootDataConnection::disconnect() {
349 if ( m_file ) {
350 if ( !m_file->IsZombie() ) {
351 if ( m_file->IsWritable() ) {
352 msgSvc() << MSG::DEBUG;
353 TDirectory::TContext ctxt(m_file);
354 if ( m_refs ) {
355 if ( !m_tool->saveRefs().isSuccess() ) badWriteError("Saving References");
356 if ( m_refs->Write() < 0 ) badWriteError("Write Reference branch");
357 }
358 for(Sections::iterator i=m_sections.begin(); i!= m_sections.end();++i) {
359 if ( (*i).second ) {
360 if ( (*i).second->Write() < 0 ) badWriteError("Write section:"+(*i).first);
361 msgSvc() << "Disconnect section " << (*i).first << " " << (*i).second->GetName() << endmsg;
362 }
363 }
364 m_sections.clear();
365 }
366 msgSvc() << MSG::DEBUG;
367 if ( msgSvc().isActive() ) m_file->ls();
368 msgSvc() << MSG::VERBOSE;
369 if ( msgSvc().isActive() ) m_file->Print();
370 m_file->Close();
371 }
372 msgSvc() << MSG::DEBUG << "Disconnected file " << m_pfn << " " << m_file->GetName() << endmsg;
373 deletePtr(m_file);
374 releasePtr(m_tool);
375 }
376 return StatusCode::SUCCESS;
377 }
378
380 TTree* RootDataConnection::getSection(CSTR section, bool create) {
381 TTree* t = m_sections[section];
382 if ( !t ) {
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");
387 }
388 if ( t ) {
389 int cacheSize = m_setup->cacheSize;
390 if ( create ) {
391 //t->SetAutoFlush(100);
392 }
393 if ( section == m_setup->loadSection && cacheSize>-2 ) {
394 MsgStream& msg = msgSvc();
395 int learnEntries = m_setup->learnEntries;
396 t->SetCacheSize(cacheSize);
397 t->SetCacheLearnEntries(learnEntries);
398 msg << MSG::DEBUG;
399 if ( create ) {
400 msg << "Tree:" << section << "Setting up tree cache:" << cacheSize << endmsg;
401 }
402 else {
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;
407
408 if ( cB.size()==0 && vB.size()== 0 ) {
409 msg << "Adding (default) all branches to tree cache." << endmsg;
410 t->AddBranchToCache("*",kTRUE);
411 }
412 if ( cB.size()==1 && cB[0]=="*" ) {
413 msg << "Adding all branches to tree cache according to option \"CacheBranches\"." << endmsg;
414 t->AddBranchToCache("*",kTRUE);
415 }
416 else {
417 StringVec::const_iterator i;
418 for(TIter it(t->GetListOfBranches()); it.Next(); ) {
419 const char* n = ((TNamed*)(*it))->GetName();
420 bool add = false, veto = false;
421 for(i=cB.begin(); i != cB.end();++i) {
422 if ( !match_wild(n,(*i).c_str()) ) continue;
423 add = true;
424 break;
425 }
426 for(i=vB.begin(); !add && i!=vB.end();++i) {
427 if ( !match_wild(n,(*i).c_str()) ) continue;
428 veto = true;
429 break;
430 }
431 if ( add && !veto ) {
432 msg << "Add " << n << " to branch cache." << endmsg;
433 t->AddBranchToCache(n,kTRUE);
434 }
435 else {
436 msg << "Do not cache branch " << n << endmsg;
437 }
438 }
439 }
440 }
441 }
442 m_sections[section] = t;
443 }
444 }
445 return t;
446 }
447
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);
456 }
457 if ( !b ) {
458 b = t->GetBranch(branch_name.c_str());
459 }
460 if ( b ) {
461 b->SetAutoDelete(kFALSE);
462 }
463 return b;
464 }
465
467 int RootDataConnection::makeLink(CSTR p) {
468 int cnt = 0;
469 StringVec::iterator ip;
470 for(ip=m_links.begin();ip!=m_links.end();++ip,++cnt) {
471 if( (*ip) == p ) return cnt;
472 }
473 m_links.push_back(p);
474 return m_links.size()-1;
475 }
476
478 CSTR RootDataConnection::getDb(int which) const {
479 if ( (which>=0) && (size_t(which)<m_dbs.size()) ) {
480 if ( *(m_dbs.begin()+which) == s_local ) return m_fid;
481 return *(m_dbs.begin()+which);
482 }
483 return s_empty;
484 }
485
487 CSTR RootDataConnection::empty() const {
488 return s_empty;
489 }
490
492 pair<int,unsigned long>
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);
496 }
497
499 pair<int,unsigned long>
500 RootDataConnection::save(CSTR section, CSTR cnt, TClass* cl, void* pObj, int buff_siz, int split_lvl, bool fill_missing) {
501 split_lvl = 0;
502 TBranch* b = getBranch(section, cnt, cl, (void*)(pObj ? &pObj : 0),buff_siz,split_lvl);
503 if ( b ) {
504 Long64_t evt = b->GetEntries();
505 //msgSvc() << MSG::DEBUG << cnt.c_str() << " Obj:" << (void*)pObj
506 // << " Split:" << split_lvl << " Buffer size:" << buff_siz << endl;
507 if ( fill_missing ) {
508 Long64_t num, nevt = b->GetTree()->GetEntries();
509 if ( nevt > evt ) {
510 b->SetAddress(0);
511 num = nevt - evt;
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();
517 }
518 }
519 b->SetAddress(&pObj);
520 return make_pair(b->Fill(),(unsigned long)evt);
521 }
522 else if ( 0 != pObj ) {
523 msgSvc() << MSG::ERROR << "Failed to access branch " << m_name << "/" << cnt << endmsg;
524 }
525 return make_pair(-1,~0);
526 }
527
529 int RootDataConnection::loadObj(CSTR section, CSTR cnt, unsigned long entry, DataObject*& pObj) {
530 TBranch* b = getBranch(section,cnt);
531 if ( b ) {
532 TClass* cl = gROOT->GetClass(b->GetClassName(),kTRUE);
533 if ( cl ) {
534 int nb = -1;
535 pObj = (DataObject*)cl->New();
536 {
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));
543 }
544 }
545 nb = b->GetEntry(entry);
546 msgSvc() << MSG::VERBOSE;
547 if ( msgSvc().isActive() ) {
548 msgSvc() << "Load [" << entry << "] --> " << section
549 << ":" << cnt << " " << nb << " bytes."
550 << endmsg;
551 }
552 if ( nb < 0 ) { // This is definitely an error...ROOT says if reads fail, -1 is issued.
553 IIncidentSvc* inc = m_setup->incidentSvc();
554 if ( inc ) {
555 inc->fireIncident(Incident(pfn(),IncidentType::CorruptedInputFile));
556 }
557 }
558 else if ( nb == 0 && pObj->clID() == CLID_DataObject) {
559 TFile* f = b->GetFile();
560 int vsn = f->GetVersion();
561 if ( vsn < 52400 ) {
562 // For Gaudi v21r5 (ROOT 5.24.00b) DataObject::m_version was not written!
563 // Still this call be well be successful.
564 nb = 1;
565 }
566 else if ( vsn>1000000 && (vsn%1000000)<52400 ) {
567 // dto. Some POOL files have for unknown reasons a version
568 // not according to ROOT standards. Hack this explicitly.
569 nb = 1;
570 }
571 }
572 if ( nb < 0 ) {
573 delete pObj;
574 pObj = 0;
575 }
576 }
577 return nb;
578 }
579 }
580 return -1;
581 }
582
584 int RootDataConnection::loadRefs(const std::string& section, const std::string& cnt,
585 unsigned long entry, RootObjectRefs& refs)
586 {
587 int nbytes = m_tool->loadRefs(section,cnt,entry,refs);
588 if ( nbytes < 0 ) {
589 // This is definitely an error:
590 // -- Either branch not preesent at all or
591 // -- ROOT I/O error, which issues -1
592 IIncidentSvc* inc = m_setup->incidentSvc();
593 if ( inc ) {
594 inc->fireIncident(Incident(pfn(),IncidentType::CorruptedInputFile));
595 }
596 }
597 return nbytes;
598 }
599
601 pair<const RootRef*,const RootDataConnection::ContainerSection*>
602 RootDataConnection::getMergeSection(const string& container, int entry) const {
603 //size_t idx = cont.find('/',1);
604 //string container = cont[0]=='/' ? cont.substr(1,idx==string::npos?idx:idx-1) : cont;
605 MergeSections::const_iterator i=m_mergeSects.find(container);
606 if ( i != m_mergeSects.end() ) {
607 size_t cnt = 0;
608 const ContainerSections& s = (*i).second;
609 for(ContainerSections::const_iterator j=s.begin(); j != s.end(); ++j,++cnt) {
610 const ContainerSection& c = *j;
611 if ( entry >= c.start && entry < (c.start+c.length) ) {
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;
617 }
618 return make_pair(&(m_linkSects[cnt]), &c);
619 }
620 }
621 }
622 }
623 msgSvc() << MSG::DEBUG << "Return INVALID MergeSection for:" << container
624 << " [" << entry << "]" << endmsg
625 << "FID:" << m_fid << " -> PFN:" << m_pfn << endmsg;
626 return make_pair((const RootRef*)0,(const ContainerSection*)0);
627 }
628
630 void RootDataConnection::makeRef(IRegistry* pR, RootRef& ref) {
631 IOpaqueAddress* pA = pR->address();
632 makeRef(pR->name(),pA->clID(),pA->svcType(),pA->par()[0],pA->par()[1],-1,ref);
633 }
634
636 void RootDataConnection::makeRef(CSTR name, long clid, int tech, CSTR dbase, CSTR cnt, int entry, RootRef& ref) {
637 string db(dbase);
638 int cdb=-1, ccnt=-1, clnk=-1;
639 StringVec::iterator idb, icnt, ilnk;
640 if ( db == m_fid ) {
641 db = s_local;
642 }
643 ref.entry = entry;
644 if ( !db.empty() ) {
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() ) {
648 cdb = m_dbs.size();
649 m_dbs.push_back(db);
650 }
651 }
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);
658 }
659 }
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);
666 }
667 }
668 ref.dbase = cdb;
669 ref.container = ccnt;
670 ref.link = clnk;
671 ref.clid = clid;
672 ref.svc = tech;
673 if ( ref.svc == POOL_ROOT_StorageType ||
674 ref.svc == POOL_ROOTKEY_StorageType ||
675 ref.svc == POOL_ROOTTREE_StorageType ) {
676 ref.svc = ROOT_StorageType;
677 }
678 }
679