The Gaudi Framework  master (37c0b60a)
RootDataConnection.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 //====================================================================
12 // RootDataConnection.cpp
13 //--------------------------------------------------------------------
14 //
15 // Author : M.Frank
16 //====================================================================
17 
18 // Framework include files
19 #include "RootUtils.h"
20 #include <GaudiKernel/DataObject.h>
24 #include <GaudiKernel/IRegistry.h>
25 #include <GaudiKernel/Incident.h>
27 #include <GaudiKernel/MsgStream.h>
28 #include <GaudiKernel/strcasecmp.h>
30 // ROOT include files
31 #include <TBranch.h>
32 #include <TClass.h>
33 #include <TFile.h>
34 #include <TLeaf.h>
35 #include <TMemFile.h>
36 #include <TROOT.h>
37 #include <TTree.h>
38 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
39 # include <Compression.h>
40 static int s_compressionLevel = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 4 );
41 #else
42 static int s_compressionLevel = 1;
43 #endif
44 
45 #define ROOT_HAS_630_FWD_COMPAT ROOT_VERSION_CODE > ROOT_VERSION( 6, 30, 4 )
46 
47 // C/C++ include files
48 #include <fmt/format.h>
49 #include <limits>
50 #include <numeric>
51 #include <stdexcept>
52 
53 using namespace Gaudi;
54 using namespace std;
55 typedef const string& CSTR;
56 
57 static const string s_empty;
58 static const string s_local = "<localDB>";
59 
60 #ifdef __POOL_COMPATIBILITY
61 # include "PoolTool.h"
62 #endif
63 #include "RootTool.h"
64 
65 namespace {
66  std::array<char, 256> init_table() {
68  std::iota( std::begin( table ), std::end( table ), 0 );
69  return table;
70  }
71 
72  struct RootDataConnectionCategory : StatusCode::Category {
73  const char* name() const override { return "RootDataConnection"; }
74 
75  bool isRecoverable( StatusCode::code_t ) const override { return false; }
76 
77  std::string message( StatusCode::code_t code ) const override {
78  switch ( static_cast<RootDataConnection::Status>( code ) ) {
80  return "ROOT_READ_ERROR";
82  return "ROOT_OPEN_ERROR";
83  default:
84  return StatusCode::default_category().message( code );
85  }
86  }
87  };
88 
89  static bool match_wild( const char* str, const char* pat ) {
90  //
91  // Credits: Code from Alessandro Felice Cantatore.
92  //
93  static const auto table = init_table();
94  const char * s, *p;
95  bool star = false;
96  loopStart:
97  for ( s = str, p = pat; *s; ++s, ++p ) {
98  switch ( *p ) {
99  case '?':
100  if ( *s == '.' ) goto starCheck;
101  break;
102  case '*':
103  star = true;
104  str = s, pat = p;
105  do { ++pat; } while ( *pat == '*' );
106  if ( !*pat ) return true;
107  goto loopStart;
108  default:
109  if ( table[*s] != table[*p] ) goto starCheck;
110  break;
111  } /* endswitch */
112  } /* endfor */
113  while ( *p == '*' ) ++p;
114  return ( !*p );
115 
116  starCheck:
117  if ( !star ) return false;
118  str++;
119  goto loopStart;
120  }
121 } // namespace
122 
123 STATUSCODE_ENUM_IMPL( Gaudi::RootDataConnection::Status, RootDataConnectionCategory )
124 
125 StatusCode RootConnectionSetup::setCompression( std::string_view compression ) {
127 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
128  int res = 0, level = ROOT::CompressionSettings( ROOT::RCompressionSetting::EAlgorithm::kLZMA, 6 );
129  auto idx = compression.find( ':' );
130  if ( idx != string::npos ) {
131  auto alg = compression.substr( 0, idx );
132  ROOT::RCompressionSetting::EAlgorithm::EValues alg_code = ROOT::RCompressionSetting::EAlgorithm::kUseGlobal;
133  if ( alg.size() == 4 && strncasecmp( alg.data(), "ZLIB", 4 ) == 0 )
134  alg_code = ROOT::RCompressionSetting::EAlgorithm::kZLIB;
135  else if ( alg.size() == 4 && strncasecmp( alg.data(), "LZMA", 4 ) == 0 )
136  alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZMA;
137  else if ( alg.size() == 3 && strncasecmp( alg.data(), "LZ4", 3 ) == 0 )
138  alg_code = ROOT::RCompressionSetting::EAlgorithm::kLZ4;
139 # if ROOT_VERSION_CODE >= ROOT_VERSION( 6, 20, 0 )
140  else if ( alg.size() == 4 && strncasecmp( alg.data(), "ZSTD", 4 ) == 0 )
141  alg_code = ROOT::RCompressionSetting::EAlgorithm::kZSTD;
142 # endif
143  else
144  throw runtime_error( "ERROR: request to set unknown ROOT compression algorithm:" + std::string{ alg } );
145  res = ::sscanf( std::string{ compression.substr( idx + 1 ) }.c_str(), "%d",
146  &level ); // TODO: use C++17 std::from_chars instead...
147  if ( res == 1 ) {
148  s_compressionLevel = ROOT::CompressionSettings( alg_code, level );
149  return StatusCode::SUCCESS;
150  }
151  throw runtime_error( "ERROR: request to set unknown ROOT compression level:" +
152  std::string{ compression.substr( idx + 1 ) } );
153  } else if ( 1 == ::sscanf( std::string{ compression }.c_str(), "%d", &level ) ) { // TODO: use C++17 std::from_chars
154  // instead
155  s_compressionLevel = level;
156  return StatusCode::SUCCESS;
157  }
158  throw runtime_error( "ERROR: request to set unknown ROOT compression mechanism:" + std::string{ compression } );
159 #else
160  if ( !compression.empty() ) {}
161  return StatusCode::SUCCESS;
162 #endif
163 }
164 
166 int RootConnectionSetup::compression() { return s_compressionLevel; }
167 
169 void RootConnectionSetup::setMessageSvc( MsgStream* m ) { m_msgSvc.reset( m ); }
170 
172 void RootConnectionSetup::setIncidentSvc( IIncidentSvc* s ) { m_incidentSvc.reset( s ); }
173 
175 RootDataConnection::RootDataConnection( const IInterface* owner, std::string_view fname,
177  : IDataConnection( owner, std::string{ fname } ), m_setup( std::move( setup ) ) {
178  // 01234567890123456789012345678901234567890
179  // Check if FID: A82A3BD8-7ECB-DC11-8DC0-000423D950B0
180  if ( fname.size() == 36 && fname[8] == '-' && fname[13] == '-' && fname[18] == '-' && fname[23] == '-' ) {
181  m_name = "FID:";
182  m_name.append( fname.data(), fname.size() );
183  }
184  m_age = 0;
185  m_file.reset();
186  addClient( owner );
187 }
188 
190 void RootDataConnection::addClient( const IInterface* client ) { m_clients.insert( client ); }
191 
194  auto i = m_clients.find( client );
195  if ( i != m_clients.end() ) m_clients.erase( i );
196  return m_clients.size();
197 }
198 
200 bool RootDataConnection::lookupClient( const IInterface* client ) const {
201  auto i = m_clients.find( client );
202  return i != m_clients.end();
203 }
204 
206 void RootDataConnection::badWriteError( std::string_view msg ) const {
207  msgSvc() << MSG::ERROR << "File:" << fid() << "Failed action:" << msg << endmsg;
208 }
209 
211 void RootDataConnection::saveStatistics( std::string_view statisticsFile ) {
212  if ( m_statistics ) {
213  m_statistics->Print();
214  if ( !statisticsFile.empty() ) m_statistics->SaveAs( std::string{ statisticsFile }.c_str() );
216  }
217 }
218 
220 void RootDataConnection::enableStatistics( std::string_view section ) {
221  if ( m_statistics ) {
222  TTree* t = getSection( section, false );
223  if ( t ) {
224  m_statistics.reset( new TTreePerfStats( ( std::string{ section } + "_ioperf" ).c_str(), t ) );
225  return;
226  }
227  msgSvc() << MSG::WARNING << "Failed to enable perfstats for tree:" << section << endmsg;
228  return;
229  }
230  msgSvc() << MSG::INFO << "Perfstats are ALREADY ENABLED." << endmsg;
231 }
232 
235  if ( !m_refs ) m_refs = (TTree*)m_file->Get( "Refs" );
236  if ( m_refs ) m_tool.reset( new RootTool( this ) );
237 #ifdef __POOL_COMPATIBILITY
238  else if ( m_file->Get( "##Links" ) != nullptr )
239  m_tool.reset( new PoolTool( this ) );
240 #endif
241  else
242  m_tool.reset();
243  return m_tool.get();
244 }
245 
248  m_file.reset( TFile::Open( m_pfn.c_str() ) );
249  if ( !m_file || m_file->IsZombie() ) {
250  m_file.reset();
251  return StatusCode::FAILURE;
252  }
254  msgSvc() << MSG::DEBUG << "Opened file " << m_pfn << " in mode READ. [" << m_fid << "]" << endmsg << MSG::DEBUG;
255  if ( msgSvc().isActive() ) m_file->ls();
256  msgSvc() << MSG::VERBOSE;
257  if ( msgSvc().isActive() ) m_file->Print();
258  if ( makeTool() ) {
259  sc = m_tool->readRefs();
260  sc.ignore();
261 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
262  if ( sc == Status::ROOT_READ_ERROR ) {
263  IIncidentSvc* inc = m_setup->incidentSvc();
264  if ( inc ) { inc->fireIncident( Incident( pfn(), IncidentType::CorruptedInputFile ) ); }
265  }
266 #endif
267  }
268  if ( !sc.isSuccess() ) return sc;
269  bool need_fid = m_fid == m_pfn;
270  string fid = m_fid;
271  m_mergeFIDs.clear();
272  for ( auto& elem : m_params ) {
273  if ( elem.first == "FID" ) {
274  m_mergeFIDs.push_back( elem.second );
275  if ( elem.second != m_fid ) {
276  msgSvc() << MSG::DEBUG << "Check FID param:" << elem.second << endmsg;
277  // if ( m_fid == m_pfn ) {
278  m_fid = elem.second;
279  //}
280  }
281  }
282  }
283  if ( !need_fid && fid != m_fid ) {
284  msgSvc() << MSG::ERROR << "FID mismatch:" << fid << "(Catalog) != " << m_fid << "(file)" << endmsg
285  << "for PFN:" << m_pfn << endmsg;
286  return StatusCode::FAILURE;
287  }
288  msgSvc() << MSG::DEBUG << "Using FID " << m_fid << " from params table...." << endmsg << "for PFN:" << m_pfn
289  << endmsg;
290  return sc;
291 }
292 
295  int compress = RootConnectionSetup::compression();
296  msgSvc() << MSG::DEBUG;
297  std::string spec = m_pfn;
298  if ( m_setup->produceReproducibleFiles ) spec += "?reproducible"; // https://root.cern.ch/doc/master/classTFile.html
299  switch ( typ ) {
300  case CREATE:
301  resetAge();
302  m_file.reset( TFile::Open( spec.c_str(), "CREATE", "Root event data", compress ) );
303 #if ROOT_HAS_630_FWD_COMPAT
304  if ( m_file && m_setup->root630ForwardCompatibility ) m_file->SetBit( TFile::k630forwardCompatibility );
305 #endif
306  m_refs = new TTree( "Refs", "Root reference data" );
307  msgSvc() << "Opened file " << m_pfn << " in mode CREATE. [" << m_fid << "]" << endmsg;
308  m_params.emplace_back( "PFN", m_pfn );
309  if ( m_fid != m_pfn ) { m_params.emplace_back( "FID", m_fid ); }
310  makeTool();
311  break;
312  case RECREATE:
313  resetAge();
314  m_file.reset( TFile::Open( spec.c_str(), "RECREATE", "Root event data", compress ) );
315 #if ROOT_HAS_630_FWD_COMPAT
316  if ( m_file && m_setup->root630ForwardCompatibility ) m_file->SetBit( TFile::k630forwardCompatibility );
317 #endif
318  msgSvc() << "Opened file " << m_pfn << " in mode RECREATE. [" << m_fid << "]" << endmsg;
319  m_refs = new TTree( "Refs", "Root reference data" );
320  m_params.emplace_back( "PFN", m_pfn );
321  if ( m_fid != m_pfn ) { m_params.emplace_back( "FID", m_fid ); }
322  makeTool();
323  break;
324  case UPDATE:
325  resetAge();
326  m_file.reset( TFile::Open( spec.c_str(), "UPDATE", "Root event data", compress ) );
327  msgSvc() << "Opened file " << m_pfn << " in mode UPDATE. [" << m_fid << "]" << endmsg;
328  if ( m_file && !m_file->IsZombie() ) {
329  if ( makeTool() ) {
330  StatusCode sc = m_tool->readRefs();
331  sc.ignore();
332  if ( sc == Status::ROOT_READ_ERROR ) {
333 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
334  IIncidentSvc* inc = m_setup->incidentSvc();
335  if ( inc ) { inc->fireIncident( Incident( pfn(), IncidentType::CorruptedInputFile ) ); }
336 #endif
337  }
338  return sc;
339  }
340  TDirectory::TContext ctxt( m_file.get() );
341  m_refs = new TTree( "Refs", "Root reference data" );
342  makeTool();
343  return StatusCode::SUCCESS;
344  }
345  break;
346  default:
347  m_refs = nullptr;
348  m_file.reset();
349  return StatusCode::FAILURE;
350  }
352 }
353 
356  if ( m_file ) {
357  if ( !m_file->IsZombie() ) {
358  if ( m_file->IsWritable() ) {
359  msgSvc() << MSG::DEBUG;
360  TDirectory::TContext ctxt( m_file.get() );
361  if ( m_refs ) {
362  if ( !m_tool->saveRefs().isSuccess() ) badWriteError( "Saving References" );
363  if ( m_refs->Write() < 0 ) badWriteError( "Write Reference branch" );
364  }
365  for ( auto& i : m_sections ) {
366  if ( i.second ) {
367  if ( i.second->Write() < 0 ) badWriteError( "Write section:" + i.first );
368  msgSvc() << "Disconnect section " << i.first << " " << i.second->GetName() << endmsg;
369  }
370  }
371  m_sections.clear();
372  }
373  msgSvc() << MSG::DEBUG;
374  if ( msgSvc().isActive() ) m_file->ls();
375  msgSvc() << MSG::VERBOSE;
376  if ( msgSvc().isActive() ) m_file->Print();
377  m_file->Close();
378  }
379  msgSvc() << MSG::DEBUG << "Disconnected file " << m_pfn << " " << m_file->GetName() << endmsg;
380  m_file.reset();
381  m_tool.reset();
382  }
383  return StatusCode::SUCCESS;
384 }
385 
387 TTree* RootDataConnection::getSection( std::string_view section, bool create ) {
388  auto it = m_sections.find( section );
389  TTree* t = ( it != m_sections.end() ? it->second : nullptr );
390  if ( !t ) {
391  t = (TTree*)m_file->Get( std::string{ section }.c_str() );
392  if ( !t && create ) {
393  TDirectory::TContext ctxt( m_file.get() );
394  t = new TTree( std::string{ section }.c_str(), "Root data for Gaudi" );
395  }
396  if ( t ) {
397  int cacheSize = m_setup->cacheSize;
398  if ( create ) {
399  // t->SetAutoFlush(100);
400  }
401  if ( section == m_setup->loadSection && cacheSize > -2 ) {
402  MsgStream& msg = msgSvc();
403  int learnEntries = m_setup->learnEntries;
404  t->SetCacheSize( cacheSize );
405  t->SetCacheLearnEntries( learnEntries );
406  msg << MSG::DEBUG;
407  if ( create ) {
408  msg << "Tree:" << section << "Setting up tree cache:" << cacheSize << endmsg;
409  } else {
410  const StringVec& vB = m_setup->vetoBranches;
411  const StringVec& cB = m_setup->cacheBranches;
412  msg << "Tree:" << section << " Setting up tree cache:" << cacheSize << " Add all branches." << endmsg;
413  msg << "Tree:" << section << " Learn for " << learnEntries << " entries." << endmsg;
414 
415  if ( cB.empty() && vB.empty() ) {
416  msg << "Adding (default) all branches to tree cache." << endmsg;
417  t->AddBranchToCache( "*", kTRUE );
418  }
419  if ( cB.size() == 1 && cB[0] == "*" ) {
420  msg << "Adding all branches to tree cache according to option \"CacheBranches\"." << endmsg;
421  t->AddBranchToCache( "*", kTRUE );
422  } else {
423  for ( TIter it( t->GetListOfBranches() ); it.Next(); ) {
424  const char* n = ( (TNamed*)( *it ) )->GetName();
425  bool add = false, veto = false;
426  for ( const auto& i : cB ) {
427  if ( !match_wild( n, ( i ).c_str() ) ) continue;
428  add = true;
429  break;
430  }
431  for ( auto i = vB.cbegin(); !add && i != vB.cend(); ++i ) {
432  if ( !match_wild( n, ( *i ).c_str() ) ) continue;
433  veto = true;
434  break;
435  }
436  if ( add && !veto ) {
437  msg << "Add " << n << " to branch cache." << endmsg;
438  t->AddBranchToCache( n, kTRUE );
439  } else {
440  msg << "Do not cache branch " << n << endmsg;
441  }
442  }
443  }
444  }
445  }
446  m_sections[std::string{ section }] = t;
447  } else {
448  // in some rare cases we do have the entry we expect, but we cannot read it
449  // https://gitlab.cern.ch/gaudi/Gaudi/-/issues/301
450  auto key = m_file->GetKey( std::string{ section }.c_str() );
451  if ( key ) {
452  incidentSvc()->fireIncident( Incident( pfn(), IncidentType::CorruptedInputFile ) );
453  msgSvc() << MSG::ERROR << fmt::format( "failed to get TTree '{}' in {}", section, pfn() ) << endmsg;
454  }
455  }
456  }
457  return t;
458 }
459 
461 TBranch* RootDataConnection::getBranch( std::string_view section, std::string_view branch_name, TClass* cl, void* ptr,
462  int buff_siz, int split_lvl ) {
463  string n = std::string{ branch_name };
465  begin( n ), end( n ), []( const char c ) { return !isalnum( c ); }, '_' );
466  n += ".";
467  TTree* t = getSection( section, true );
468  TBranch* b = t->GetBranch( n.c_str() );
469  if ( !b && cl && m_file->IsWritable() ) {
470  b = t->Branch( n.c_str(), cl->GetName(), (void*)( ptr ? &ptr : nullptr ), buff_siz, split_lvl );
471  }
472  if ( !b ) b = t->GetBranch( std::string{ branch_name }.c_str() );
473  if ( b ) b->SetAutoDelete( kFALSE );
474  return b;
475 }
476 
478 int RootDataConnection::makeLink( std::string_view p ) {
479  auto ip = std::find( std::begin( m_links ), std::end( m_links ), p );
480  if ( ip != std::end( m_links ) ) return std::distance( std::begin( m_links ), ip );
481  m_links.push_back( std::string{ p } );
482  return m_links.size() - 1;
483 }
484 
487  if ( ( which >= 0 ) && ( size_t( which ) < m_dbs.size() ) ) {
488  if ( *( m_dbs.begin() + which ) == s_local ) return m_fid;
489  return *( m_dbs.begin() + which );
490  }
491  return s_empty;
492 }
493 
495 CSTR RootDataConnection::empty() const { return s_empty; }
496 
498 pair<int, unsigned long> RootDataConnection::saveObj( std::string_view section, std::string_view cnt, TClass* cl,
499  DataObject* pObj, int minBufferSize, int maxBufferSize,
500  int approxEventsPerBasket, int split_lvl, bool fill ) {
501  DataObjectPush push( pObj );
502  return save( section, cnt, cl, pObj, minBufferSize, maxBufferSize, approxEventsPerBasket, split_lvl, fill );
503 }
504 
506 pair<int, unsigned long> RootDataConnection::save( std::string_view section, std::string_view cnt, TClass* cl,
507  void* pObj, int minBufferSize, int maxBufferSize,
508  int approxEventsPerBasket, int split_lvl, bool fill_missing ) {
509  split_lvl = 0;
510  TBranch* b = getBranch( section, cnt, cl, pObj ? &pObj : nullptr, minBufferSize, split_lvl );
511  if ( b ) {
512  Long64_t evt = b->GetEntries();
513  // msgSvc() << MSG::DEBUG << cnt.c_str() << " Obj:" << (void*)pObj
514  // << " Split:" << split_lvl << " Buffer size:" << minBufferSize << endl;
515  bool set_buffer_size = ( evt == 0 );
516  if ( fill_missing ) {
517  Long64_t num, nevt = b->GetTree()->GetEntries();
518  if ( nevt > evt ) {
519  set_buffer_size = true;
520  b->SetAddress( nullptr );
521  num = nevt - evt;
522  while ( num > 0 ) {
523  b->Fill();
524  --num;
525  }
526  msgSvc() << MSG::DEBUG << "Added " << long( nevt - evt ) << " / Tree: " << nevt
527  << " / Branch: " << b->GetEntries() + 1 << " NULL entries to:" << cnt << endmsg;
528  evt = b->GetEntries();
529  }
530  }
531  if ( set_buffer_size ) {
532  auto dummy_file = make_unique<TMemFile>( "dummy.root", "CREATE" );
533  auto dummy_tree = make_unique<TTree>( "DummyTree", "DummyTree", split_lvl, dummy_file->GetDirectory( "/" ) );
534  TBranch* dummy_branch = dummy_tree->Branch( "DummyBranch", cl->GetName(), &pObj, minBufferSize, split_lvl );
535  Int_t nWritten = dummy_branch->Fill();
536  if ( nWritten < 0 ) return { nWritten, evt };
537  Int_t newBasketSize = nWritten * approxEventsPerBasket;
538  // Ensure that newBasketSize doesn't wrap around
539  if ( std::numeric_limits<Int_t>::max() / approxEventsPerBasket < nWritten ) {
540  newBasketSize = std::numeric_limits<Int_t>::max();
541  }
542  b->SetBasketSize( std::min( maxBufferSize, std::max( minBufferSize, newBasketSize ) ) );
543  msgSvc() << MSG::DEBUG << "Setting basket size to " << newBasketSize << " for " << cnt << endmsg;
544  }
545  b->SetAddress( &pObj );
546  return { b->Fill(), evt };
547  }
548  if ( pObj ) { msgSvc() << MSG::ERROR << "Failed to access branch " << m_name << "/" << cnt << endmsg; }
549  return { -1, ~0 };
550 }
551 
553 int RootDataConnection::loadObj( std::string_view section, std::string_view cnt, unsigned long entry,
554  DataObject*& pObj ) {
555  TBranch* b = getBranch( section, cnt );
556  if ( b ) {
557  TClass* cl = gROOT->GetClass( b->GetClassName(), kTRUE );
558  if ( cl ) {
559  int nb = -1;
560  pObj = (DataObject*)cl->New();
561  {
562  DataObjectPush push( pObj );
563  b->SetAddress( &pObj );
564  if ( section == m_setup->loadSection ) {
565  TTree* t = b->GetTree();
566  if ( Long64_t( entry ) != t->GetReadEntry() ) { t->LoadTree( Long64_t( entry ) ); }
567  }
568  nb = b->GetEntry( entry );
569  msgSvc() << MSG::VERBOSE;
570  if ( msgSvc().isActive() ) {
571  msgSvc() << "Load [" << entry << "] --> " << section << ":" << cnt << " " << nb << " bytes." << endmsg;
572  }
573  if ( nb < 0 ) { // This is definitely an error...ROOT says if reads fail, -1 is issued.
574 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
575  IIncidentSvc* inc = m_setup->incidentSvc();
576  if ( inc ) { inc->fireIncident( Incident( pfn(), IncidentType::CorruptedInputFile ) ); }
577 #endif
578  } else if ( nb == 0 && pObj->clID() == CLID_DataObject ) {
579  TFile* f = b->GetFile();
580  int vsn = f->GetVersion();
581  if ( vsn < 52400 ) {
582  // For Gaudi v21r5 (ROOT 5.24.00b) DataObject::m_version was not written!
583  // Still this call be well be successful.
584  nb = 1;
585  } else if ( vsn > 1000000 && ( vsn % 1000000 ) < 52400 ) {
586  // dto. Some POOL files have for unknown reasons a version
587  // not according to ROOT standards. Hack this explicitly.
588  nb = 1;
589  }
590  }
591  if ( nb < 0 ) {
592  delete pObj;
593  pObj = nullptr;
594  }
595  }
596  return nb;
597  }
598  }
599  return -1;
600 }
601 
603 int RootDataConnection::loadRefs( std::string_view section, std::string_view cnt, unsigned long entry,
604  RootObjectRefs& refs ) {
605  int nbytes = m_tool->loadRefs( section, cnt, entry, refs );
606 #if ROOT_VERSION_CODE >= ROOT_VERSION( 5, 33, 0 )
607  if ( nbytes < 0 ) {
608  // This is definitely an error:
609  // -- Either branch not present at all or
610  // -- ROOT I/O error, which issues -1
611  IIncidentSvc* inc = m_setup->incidentSvc();
612  if ( inc ) { inc->fireIncident( Incident( pfn(), IncidentType::CorruptedInputFile ) ); }
613  }
614 #endif
615  return nbytes;
616 }
617 
620 RootDataConnection::getMergeSection( std::string_view container, int entry ) const {
621  // size_t idx = cont.find('/',1);
622  // string container = cont[0]=='/' ? cont.substr(1,idx==string::npos?idx:idx-1) : cont;
623  auto i = m_mergeSects.find( container );
624  if ( i != m_mergeSects.end() ) {
625  size_t cnt = 0;
626  const ContainerSections& s = ( *i ).second;
627  for ( auto j = s.cbegin(); j != s.cend(); ++j, ++cnt ) {
628  const ContainerSection& c = *j;
629  if ( entry >= c.start && entry < ( c.start + c.length ) ) {
630  if ( m_linkSects.size() > cnt ) {
631  if ( msgSvc().isActive() ) {
632  msgSvc() << MSG::VERBOSE << "MergeSection for:" << container << " [" << entry << "]" << endmsg
633  << "FID:" << m_fid << " -> PFN:" << m_pfn << endmsg;
634  }
635  return { &( m_linkSects[cnt] ), &c };
636  }
637  }
638  }
639  }
640  msgSvc() << MSG::DEBUG << "Return INVALID MergeSection for:" << container << " [" << entry << "]" << endmsg
641  << "FID:" << m_fid << " -> PFN:" << m_pfn << endmsg;
642  return { nullptr, nullptr };
643 }
644 
647  IOpaqueAddress* pA = pR.address();
648  makeRef( pR.name(), pA->clID(), pA->svcType(), pA->par()[0], pA->par()[1], -1, ref );
649 }
650 
652 void RootDataConnection::makeRef( std::string_view name, long clid, int tech, std::string_view dbase,
653  std::string_view cnt, int entry, RootRef& ref ) {
654  auto db = ( dbase == m_fid ? std::string_view{ s_local } : dbase );
655  ref.entry = entry;
656 
657  int cdb = -1;
658  if ( !db.empty() ) {
659  auto idb = std::find_if( m_dbs.begin(), m_dbs.end(), [&]( const std::string& i ) { return i == db; } );
660  cdb = std::distance( m_dbs.begin(), idb );
661  if ( idb == m_dbs.end() ) m_dbs.push_back( std::string{ db } );
662  }
663 
664  int ccnt = -1;
665  if ( !cnt.empty() ) {
666  auto icnt = std::find_if( m_conts.begin(), m_conts.end(), [&]( const std::string& i ) { return i == cnt; } );
667  ccnt = std::distance( m_conts.begin(), icnt );
668  if ( icnt == m_conts.end() ) m_conts.push_back( std::string{ cnt } );
669  }
670 
671  int clnk = -1;
672  if ( !name.empty() ) {
673  auto ilnk = std::find_if( m_links.begin(), m_links.end(), [&]( const std::string& i ) { return i == name; } );
674  clnk = std::distance( m_links.begin(), ilnk );
675  if ( ilnk == m_links.end() ) m_links.push_back( std::string{ name } );
676  }
677 
678  ref.dbase = cdb;
679  ref.container = ccnt;
680  ref.link = clnk;
681  ref.clid = clid;
682  ref.svc = tech;
683  if ( ref.svc == POOL_ROOT_StorageType || ref.svc == POOL_ROOTKEY_StorageType ||
684  ref.svc == POOL_ROOTTREE_StorageType ) {
685  ref.svc = ROOT_StorageType;
686  }
687 }
IOTest.evt
evt
Definition: IOTest.py:107
MSG::DEBUG
@ DEBUG
Definition: IMessageSvc.h:25
Gaudi::IDataConnection::name
const std::string & name() const
Connection name.
Definition: IIODataManager.h:59
precedence.message
message
Definition: precedence.py:19
Gaudi::RootDataConnection::removeClient
size_t removeClient(const IInterface *client)
Remove client from this data source.
Definition: RootDataConnection.cpp:193
std::string
STL class.
std::shared_ptr
STL class.
Gaudi::RootDataConnection::m_clients
Clients m_clients
Client list.
Definition: RootDataConnection.h:192
Gaudi::RootDataConnection::enableStatistics
void enableStatistics(std::string_view section)
Enable TTreePerStats.
Definition: RootDataConnection.cpp:220
IOpaqueAddress::par
virtual const std::string * par() const =0
Retrieve String parameters.
Gaudi::RootConnectionSetup::setMessageSvc
void setMessageSvc(MsgStream *m)
Set message service reference.
Definition: RootDataConnection.cpp:169
StatusCode::default_category
static const Category & default_category() noexcept
Default Gaudi StatusCode category.
Definition: StatusCode.h:310
Gaudi::RootDataConnection::disconnect
StatusCode disconnect() override
Release data stream and release implementation dependent resources.
Definition: RootDataConnection.cpp:355
Gaudi::RootTool
Definition: RootTool.h:26
std::move
T move(T... args)
StatusCode::isSuccess
bool isSuccess() const
Definition: StatusCode.h:314
MSG::INFO
@ INFO
Definition: IMessageSvc.h:25
Gaudi::RootDataConnection::badWriteError
void badWriteError(std::string_view msg) const
Error handler when bad write statements occur.
Definition: RootDataConnection.cpp:206
Gaudi::IDataConnection
Definition: IIODataManager.h:34
std::pair
GaudiException.h
gaudirun.s
string s
Definition: gaudirun.py:346
IOpaqueAddress
Definition: IOpaqueAddress.h:33
std::vector< std::string >
std::set::find
T find(T... args)
strcasecmp.h
std::set::size
T size(T... args)
IOpaqueAddress::svcType
virtual long svcType() const =0
Retrieve service type.
Gaudi::IDataConnection::RECREATE
@ RECREATE
Definition: IIODataManager.h:49
Gaudi::IDataConnection::resetAge
void resetAge()
Reset age.
Definition: IIODataManager.h:71
GaudiMP.FdsRegistry.msg
msg
Definition: FdsRegistry.py:19
Gaudi::RootDataConnection::connectRead
StatusCode connectRead() override
Open data stream in read mode.
Definition: RootDataConnection.cpp:247
Gaudi::RootDataConnection::m_file
std::unique_ptr< TFile > m_file
Reference to ROOT file.
Definition: RootDataConnection.h:172
std::unique_ptr::get
T get(T... args)
std::distance
T distance(T... args)
Gaudi::RootDataConnection::saveObj
std::pair< int, unsigned long > saveObj(std::string_view section, std::string_view cnt, TClass *cl, DataObject *pObj, int minBufferSize, int maxBufferSize, int approxEventsPerBasket, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
Definition: RootDataConnection.cpp:498
MSG::WARNING
@ WARNING
Definition: IMessageSvc.h:25
Gaudi::RootDataConnection::ContainerSection
Definition: RootDataConnection.h:126
Gaudi::RootDataConnection::m_params
ParamMap m_params
Parameter map for file parameters.
Definition: RootDataConnection.h:186
std::isalnum
T isalnum(T... args)
RootTool.h
std::sscanf
T sscanf(T... args)
gaudirun.c
c
Definition: gaudirun.py:525
IRegistry
Definition: IRegistry.h:32
StatusCode::code_t
unsigned long code_t
type of StatusCode value
Definition: StatusCode.h:67
RootDataConnection.h
std::unique_ptr::reset
T reset(T... args)
IIncidentSvc::fireIncident
virtual void fireIncident(const Incident &incident)=0
Fire an Incident.
Gaudi::RootDataConnection::m_dbs
StringVec m_dbs
Map containing external database file names (fids)
Definition: RootDataConnection.h:178
std::vector::clear
T clear(T... args)
std::fill
T fill(T... args)
Gaudi::RootObjectRefs
Definition: RootRefs.h:68
std::replace_if
T replace_if(T... args)
IIncidentSvc.h
std::vector::push_back
T push_back(T... args)
ManySmallAlgs.alg
alg
Definition: ManySmallAlgs.py:81
bug_34121.t
t
Definition: bug_34121.py:31
Gaudi::RootDataConnection::m_linkSects
LinkSections m_linkSects
Database link sections.
Definition: RootDataConnection.h:190
Gaudi::IDataConnection::CREATE
@ CREATE
Definition: IIODataManager.h:49
IRegistry::name
virtual const name_type & name() const =0
Name of the directory (or key)
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:136
Gaudi::RootDataConnection::getDb
const std::string & getDb(int which) const
Access database/file name from saved index.
Definition: RootDataConnection.cpp:486
StatusCode
Definition: StatusCode.h:65
StatusCode::Category
Definition: StatusCode.h:78
Gaudi::RootDataConnection::m_mergeFIDs
StringVec m_mergeFIDs
Map containing merge FIDs.
Definition: RootDataConnection.h:184
Gaudi::RootDataConnection::m_setup
std::shared_ptr< RootConnectionSetup > m_setup
Reference to the setup structure.
Definition: RootDataConnection.h:168
Gaudi::Units::m
constexpr double m
Definition: SystemOfUnits.h:108
ProduceConsume.j
j
Definition: ProduceConsume.py:104
Gaudi::RootDataConnection::Status::ROOT_READ_ERROR
@ ROOT_READ_ERROR
IOpaqueAddress.h
POOL_ROOT_StorageType
const long POOL_ROOT_StorageType
Definition: ClassID.h:78
GaudiTesting.BaseTest.which
def which(executable)
Definition: BaseTest.py:798
Gaudi::RootDataConnection::Status::ROOT_OPEN_ERROR
@ ROOT_OPEN_ERROR
Gaudi::RootDataConnection::m_mergeSects
MergeSections m_mergeSects
Database section map for merged files.
Definition: RootDataConnection.h:188
std::string::c_str
T c_str(T... args)
POOL_ROOTKEY_StorageType
const long POOL_ROOTKEY_StorageType
Definition: ClassID.h:79
Gaudi::RootConnectionSetup::setIncidentSvc
void setIncidentSvc(IIncidentSvc *m)
Set incident service reference.
Definition: RootDataConnection.cpp:172
IOpaqueAddress::clID
virtual const CLID & clID() const =0
Retrieve class information from link.
Gaudi::IDataConnection::UPDATE
@ UPDATE
Definition: IIODataManager.h:49
std::array
STL class.
Gaudi::RootDataConnection::m_statistics
std::unique_ptr< TTreePerfStats > m_statistics
I/O read statistics from TTree.
Definition: RootDataConnection.h:170
Gaudi::RootRef
Definition: RootRefs.h:40
Gaudi::IDataConnection::m_name
std::string m_name
Connection name/identifier.
Definition: IIODataManager.h:37
GaudiPython.Bindings.nullptr
nullptr
Definition: Bindings.py:87
Gaudi::RootConnectionSetup::setCompression
static StatusCode setCompression(std::string_view compression)
Set the global compression level.
Definition: RootDataConnection.cpp:126
std::set::erase
T erase(T... args)
Gaudi::IDataConnection::IoType
IoType
I/O Connection types.
Definition: IIODataManager.h:49
std::runtime_error
STL class.
Gaudi::RootDataConnection::lookupClient
bool lookupClient(const IInterface *client) const
Lookup client for this data source.
Definition: RootDataConnection.cpp:200
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:202
Gaudi::RootDataConnection::makeRef
void makeRef(const IRegistry &pA, RootRef &ref)
Create reference object from registry entry.
Definition: RootDataConnection.cpp:646
ROOT_StorageType
const long ROOT_StorageType
Definition: ClassID.h:62
Gaudi::RootDataConnection::m_tool
std::unique_ptr< Tool > m_tool
Definition: RootDataConnection.h:253
Gaudi::RootDataConnection::m_conts
StringVec m_conts
Map containing external container names.
Definition: RootDataConnection.h:180
Gaudi::IDataConnection::m_fid
std::string m_fid
File ID of the connection.
Definition: IIODataManager.h:39
gaudirun.level
level
Definition: gaudirun.py:364
IRegistry.h
Gaudi::RootDataConnection::Status
Status
Definition: RootDataConnection.h:114
MsgStream
Definition: MsgStream.h:33
Gaudi::PoolTool
Definition: PoolTool.h:28
Gaudi
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition: __init__.py:1
cpluginsvc.n
n
Definition: cpluginsvc.py:234
Gaudi::RootDataConnection::incidentSvc
IIncidentSvc * incidentSvc() const
Definition: RootDataConnection.h:164
StatusCode::ignore
const StatusCode & ignore() const
Allow discarding a StatusCode without warning.
Definition: StatusCode.h:139
Gaudi::RootDataConnection::makeLink
int makeLink(std::string_view p)
Convert path string to path index.
Definition: RootDataConnection.cpp:478
std::min
T min(T... args)
std::string::substr
T substr(T... args)
IRegistry::address
virtual IOpaqueAddress * address() const =0
Retrieve opaque storage address.
std::vector::emplace_back
T emplace_back(T... args)
Gaudi::RootDataConnection::saveStatistics
void saveStatistics(std::string_view statisticsFile)
Save TTree access statistics if required.
Definition: RootDataConnection.cpp:211
MSG::VERBOSE
@ VERBOSE
Definition: IMessageSvc.h:25
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:100
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
DataObject.h
Gaudi::RootDataConnection::loadRefs
int loadRefs(std::string_view section, std::string_view cnt, unsigned long entry, RootObjectRefs &refs)
Load references object.
Definition: RootDataConnection.cpp:603
POOL_ROOTTREE_StorageType
const long POOL_ROOTTREE_StorageType
Definition: ClassID.h:80
Gaudi::RootDataConnection::save
std::pair< int, unsigned long > save(std::string_view section, std::string_view cnt, TClass *cl, void *pObj, int minBufferSize, int maxBufferSize, int approxEventsPerBasket, int split_lvl, bool fill_missing=false)
Save object of a given class to section and container.
Definition: RootDataConnection.cpp:506
std::begin
T begin(T... args)
STATUSCODE_ENUM_IMPL
#define STATUSCODE_ENUM_IMPL(...)
Assign a category to the StatusCode enum declared with STATUSCODE_ENUM_DECL( ENUM )
Definition: StatusCode.h:295
std
STL namespace.
std::set::insert
T insert(T... args)
Gaudi::RootDataConnection::getSection
TTree * getSection(std::string_view sect, bool create=false)
Access TTree section from section name. The section is created if required.
Definition: RootDataConnection.cpp:387
MSG::ERROR
@ ERROR
Definition: IMessageSvc.h:25
IInterface
Definition: IInterface.h:239
Gaudi::RootDataConnection::RootDataConnection
RootDataConnection(const IInterface *own, std::string_view nam, std::shared_ptr< RootConnectionSetup > setup)
Standard constructor.
Definition: RootDataConnection.cpp:175
std::iota
T iota(T... args)
DataObject
Definition: DataObject.h:36
Gaudi::RootDataConnection::getMergeSection
std::pair< const RootRef *, const ContainerSection * > getMergeSection(std::string_view container, int entry) const
Access link section for single container and entry.
Definition: RootDataConnection.cpp:620
Gaudi::IDataConnection::fid
const std::string & fid() const
Access file id.
Definition: IIODataManager.h:63
RootUtils.h
std::vector::empty
T empty(T... args)
Gaudi::RootDataConnection::m_links
StringVec m_links
Map containing internal links names.
Definition: RootDataConnection.h:182
Gaudi::RootDataConnection::loadObj
int loadObj(std::string_view section, std::string_view cnt, unsigned long entry, DataObject *&pObj)
Load object.
Definition: RootDataConnection.cpp:553
std::end
T end(T... args)
IOTest.end
end
Definition: IOTest.py:125
Gaudi::IDataConnection::m_pfn
std::string m_pfn
Physical file name of the connection.
Definition: IIODataManager.h:41
Gaudi::IDataConnection::pfn
const std::string & pfn() const
Access physical file name.
Definition: IIODataManager.h:65
compareRootHistos.ref
ref
Definition: compareRootHistos.py:27
Gaudi::RootDataConnection::addClient
void addClient(const IInterface *client)
Add new client to this data source.
Definition: RootDataConnection.cpp:190
Gaudi::RootDataConnection::makeTool
Tool * makeTool()
Create file access tool to encapsulate POOL compatibiliy.
Definition: RootDataConnection.cpp:234
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:101
Gaudi::RootDataConnection::empty
const std::string & empty() const
Empty string reference.
Definition: RootDataConnection.cpp:495
std::numeric_limits::max
T max(T... args)
PoolTool.h
Incident.h
IIncidentSvc
Definition: IIncidentSvc.h:33
Gaudi::RootDataConnection::m_sections
Sections m_sections
Tree sections in TFile.
Definition: RootDataConnection.h:176
Gaudi::RootDataConnection::getBranch
TBranch * getBranch(std::string_view section, std::string_view branch_name)
Access data branch by name: Get existing branch in read only mode.
Definition: RootDataConnection.h:326
Incident
Definition: Incident.h:27
DataObject::clID
virtual const CLID & clID() const
Retrieve reference to class definition structure.
Definition: DataObject.cpp:66
Gaudi::RootConnectionSetup::compression
static int compression()
Access to global compression level.
Definition: RootDataConnection.cpp:166
Gaudi::RootDataConnection::msgSvc
MsgStream & msgSvc() const
Allow access to printer service.
Definition: RootDataConnection.h:163
ProduceConsume.key
key
Definition: ProduceConsume.py:84
std::numeric_limits
Gaudi::RootDataConnection::connectWrite
StatusCode connectWrite(IoType typ) override
Open data stream in write mode.
Definition: RootDataConnection.cpp:294
Gaudi::RootDataConnection::m_refs
TTree * m_refs
Pointer to the reference tree.
Definition: RootDataConnection.h:174
GaudiPython.Persistency.add
def add(instance)
Definition: Persistency.py:50
MsgStream.h
Gaudi::RootDataConnection::Tool
Definition: RootDataConnection.h:212
StatusCode::Category::message
virtual std::string message(code_t code) const
Description for code within this category.
Definition: StatusCode.h:86
CSTR
const string & CSTR
Definition: RootDataConnection.cpp:55