The Gaudi Framework  v41r0 (bdbe7744)
Loading...
Searching...
No Matches
RootHistCnv::RCWNTupleCnv Class Reference

Converter of Column-wise NTuple into ROOT format. More...

#include </builds/gaudi/Gaudi/RootHistCnv/src/RCWNTupleCnv.h>

Inheritance diagram for RootHistCnv::RCWNTupleCnv:
Collaboration diagram for RootHistCnv::RCWNTupleCnv:

Classes

struct  Layout
 How the items of a tuple map onto the staging buffer and the TTree branches. More...
struct  Buffered

Public Member Functions

 RCWNTupleCnv (ISvcLocator *svc)
 Standard constructor.
StatusCode initialize () override
StatusCode finalize () override
StatusCode updateRep (IOpaqueAddress *pAddr, DataObject *pObj) override
 Write the TTree; for a disk-buffered tuple, first build it from the buffer file.
Public Member Functions inherited from RootHistCnv::RNTupleCnv
StatusCode initialize () override
 Initialize the converter.
StatusCode finalize () override
 Finalize the converter.
StatusCode createObj (IOpaqueAddress *pAddr, DataObject *&refpObj) override
 Create the transient representation of an object.
StatusCode updateObj (IOpaqueAddress *pAddr, DataObject *refpObj) override
 Update the transient object from the other representation.
StatusCode createRep (DataObject *pObj, IOpaqueAddress *&refpAddr) override
 Convert the transient object to the requested representation.
StatusCode updateRep (IOpaqueAddress *pAddr, DataObject *pObj) override
 Update the converted representation of a transient object.
Public Member Functions inherited from RootHistCnv::RConverter
StatusCode createRep (DataObject *pObj, IOpaqueAddress *&refpAddr) override
 Convert the transient object to the requested representation.
long repSvcType () const override
StatusCode error (const std::string &msg)
StatusCode regTFile (const std::string &, const TFile *)
StatusCode findTFile (const std::string &, TFile *&)
std::string diskDirectory (const std::string &loc)
std::string directory (const std::string &loc)
void setDirectory (const std::string &loc)
void setDiskDirectory (const std::string &loc)
StatusCode createDirectory (const std::string &loc)
StatusCode createDiskDirectory (const std::string &loc)
std::string getDirectory ()
std::string convertId (const std::string &)
Public Member Functions inherited from Converter
StatusCode initialize () override
 Initialize the converter.
StatusCode finalize () override
 Initialize the converter.
StatusCode setDataProvider (IDataProviderSvc *svc) override
 Set Data provider service.
SmartIF< IDataProviderSvc > & dataProvider () const override
 Get Data provider service.
StatusCode setConversionSvc (IConversionSvc *svc) override
 Set conversion service the converter is connected to.
SmartIF< IConversionSvc > conversionSvc () override
 Get conversion service the converter is connected to.
StatusCode setAddressCreator (IAddressCreator *creator) override
 Set address creator facility.
SmartIF< IAddressCreator > & addressCreator () const override
 Retrieve address creator facility.
const CLID & objType () const override
 Retrieve the class type of objects the converter produces.
virtual long i_repSvcType () const
 Retrieve the class type of the data store the converter uses.
StatusCode createObj (IOpaqueAddress *pAddress, DataObject *&refpObject) override
 Create the transient representation of an object.
StatusCode fillObjRefs (IOpaqueAddress *pAddress, DataObject *pObject) override
 Resolve the references of the created transient object.
StatusCode updateObj (IOpaqueAddress *pAddress, DataObject *refpObject) override
 Update the transient object from the other representation.
StatusCode updateObjRefs (IOpaqueAddress *pAddress, DataObject *pObject) override
 Update the references of an updated transient object.
StatusCode createRep (DataObject *pObject, IOpaqueAddress *&refpAddress) override
 Convert the transient object to the requested representation.
StatusCode fillRepRefs (IOpaqueAddress *pAddress, DataObject *pObject) override
 Resolve the references of the converted object.
StatusCode updateRep (IOpaqueAddress *pAddress, DataObject *pObject) override
 Update the converted representation of a transient object.
StatusCode updateRepRefs (IOpaqueAddress *pAddress, DataObject *pObject) override
 Update the references of an already converted object.
 Converter (long storage_type, const CLID &class_type, ISvcLocator *svc=0)
 Standard Constructor.
SmartIF< IService > service (const std::string &name, const bool createIf=true) const
 Return a pointer to the service identified by name (or "type/name").
Public Member Functions inherited from implements< IConverter >
void const * i_cast (const InterfaceID &tid) const override
 Implementation of IInterface::i_cast.
StatusCode queryInterface (const InterfaceID &ti, void **pp) override
 Implementation of IInterface::queryInterface.
std::vector< std::string > getInterfaceNames () const override
 Implementation of IInterface::getInterfaceNames.
 implements ()=default
 Default constructor.
implements & operator= (const implements &)
 Assignment operator (do not touch the reference count).
unsigned long addRef () const override
 Reference Interface instance.
unsigned long release () const override
 Release Interface instance.
unsigned long refCount () const override
 Current reference count.

Static Public Member Functions

static const CLID & classID ()
 Inquire class type.
Static Public Member Functions inherited from RootHistCnv::RConverter
static long storageType ()
 Inquire storage type.

Protected Member Functions

StatusCode load (TTree *tree, INTuple *&refpObject) override
 Create the transient representation of an object.
StatusCode book (const std::string &desc, INTuple *pObject, TTree *&tree) override
 Book the N tuple.
StatusCode writeData (TTree *rtree, INTuple *pObject) override
 Write N tuple data.
StatusCode readData (TTree *rtree, INTuple *pObject, long ievt) override
 Read N tuple data.
Protected Member Functions inherited from RootHistCnv::RNTupleCnv
 RNTupleCnv (ISvcLocator *svc, const CLID &clid)
 Standard constructor.
virtual std::string rootVarType (int)
 Return ROOT type info:
Protected Member Functions inherited from RootHistCnv::RConverter
 RConverter (const CLID &clid, ISvcLocator *svc)
 Standard constructor.
virtual StatusCode readObject (IOpaqueAddress *pAddr, DataObject *&refpObj)
 Create the transient representation of an object.
virtual TObject * createPersistent (DataObject *pObj)
 Create the persistent representation of an object.
StatusCode createAddress (DataObject *pObject, TDirectory *pDir, TObject *pTObject, IOpaqueAddress *&refpAddr)
 Create address of the transient object according to the requested representation.
StatusCode createAddress (const std::string &rzdir, const CLID &clid, long id, TObject *pTobj, IOpaqueAddress *&refpAddress)
StatusCode createAddress (const std::string &rzdir, const CLID &clid, const std::string &title, TObject *pTobj, IOpaqueAddress *&refpAddress)
TDirectory * changeDirectory (DataObject *pObject)
 Switch to object directory (=Parent directory).
Protected Member Functions inherited from Converter
SmartIF< ISvcLocator > & serviceLocator () const
 Retrieve pointer to service locator.
SmartIF< IMessageSvc > & msgSvc () const
 Retrieve pointer to message service.
SmartIF< IDataManagerSvc > & dataManager () const
 Get Data Manager service.
Protected Member Functions inherited from implements< IConverter >
unsigned long decRef () const override

Private Member Functions

Layout analyse (const INTuple &nt)
StatusCode createTree (const std::string &desc, INTuple *nt, const Layout &layout, TTree *&rtree)
StatusCode bookBuffered (const std::string &desc, INTuple *nt, Layout layout)
StatusCode writeBuffered (Buffered &b, INTuple *nt)
StatusCode replay (IOpaqueAddress *pAddr, INTuple *nt, Buffered &b)
StatusCode bufferDirectory (std::filesystem::path &dir)
void releaseBufferDir ()
Buffered * buffered (INTuple *nt)
bool replayed (INTuple *nt)

Private Attributes

std::mutex m_mutex
 guards m_buffered, m_replayed and m_bufferDir
std::map< INTuple *, Buffered > m_buffered
std::set< INTuple * > m_replayed
 tuples whose tree has been built; cannot be written again
std::filesystem::path m_bufferDir
unsigned m_nextBufferId { 0 }
bool m_bookDirect { false }
 force the columnar path in book()
bool m_diskBuffer { false }
 NTupleSvc.DiskBuffer* of the service owning this stream, read once in initialize().
std::string m_diskBufferDirectory
int m_diskBufferLevel { 0 }
std::size_t m_diskBufferBlockSize { 0 }

Additional Inherited Members

Public Types inherited from Converter
using Factory = Gaudi::PluginService::Factory<IConverter*( ISvcLocator* )>
Public Types inherited from implements< IConverter >
using base_class
 Typedef to this class.
using extend_interfaces_base
 Typedef to the base of this class.
using iids
Public Types inherited from extend_interfaces< Interfaces... >
using ext_iids
 take union of the ext_iids of all Interfaces...
Protected Attributes inherited from RootHistCnv::RNTupleCnv
SmartIF< INTupleSvc > m_ntupleSvc
 Reference to N tuple service.
Protected Attributes inherited from implements< IConverter >
std::atomic_ulong m_refCount
 Reference counter.

Detailed Description

Converter of Column-wise NTuple into ROOT format.

Author
Charles Leggett

Definition at line 37 of file RCWNTupleCnv.h.

Constructor & Destructor Documentation

◆ RCWNTupleCnv()

RootHistCnv::RCWNTupleCnv::RCWNTupleCnv ( ISvcLocator * svc)
inline

Standard constructor.

Definition at line 42 of file RCWNTupleCnv.h.

42: RNTupleCnv( svc, classID() ) {}
static const CLID & classID()
Inquire class type.
RNTupleCnv(ISvcLocator *svc, const CLID &clid)
Standard constructor.

Member Function Documentation

◆ analyse()

RootHistCnv::RCWNTupleCnv::Layout RootHistCnv::RCWNTupleCnv::analyse ( const INTuple & nt)
private

Definition at line 225 of file RCWNTupleCnv.cpp.

227{
228 MsgStream log( msgSvc(), "RCWNTupleCnv" );
229 Layout layout;
230 const auto& items = nt.items();
231 layout.items.reserve( items.size() );
232 long size = 0;
233
234 for ( const auto& i : items ) {
235 Layout::Item li;
236 const long oldsize = size;
237
238 visit( *i, [&]( const auto& data ) {
239 analyzeItem( this->rootVarType( data.type() ), &data, li.leaflist, li.block, li.name, li.rangeLower,
240 li.rangeUpper, size );
241 } );
242
243 li.bufPos = oldsize;
244 li.bufLen = size - oldsize;
245 if ( i->hasIndex() ) {
246 auto idx = std::find( items.begin(), items.end(), i->indexItem() );
247 li.indexPos = idx != items.end() ? idx - items.begin() : -1;
248 }
249 const long elemBytes = i->length() > 0 ? i->size() / i->length() : 0;
250 li.unitBytes = elemBytes * ( i->ndim() == 2 ? i->dim( 0 ) : 1 ); // a matrix is counted in columns
251 li.maxUnits = li.unitBytes > 0 ? li.bufLen / li.unitBytes : 0;
252
253 log << MSG::VERBOSE << "item: " << li.leaflist << " type " << i->type() << " blk: " << li.block
254 << " var: " << li.name << " rng: " << li.rangeLower << " " << li.rangeUpper << " sz: " << size << " "
255 << li.bufLen << " buf_pos: " << li.bufPos << endmsg;
256
257 layout.items.push_back( std::move( li ) );
258 }
259 layout.rowBytes = size;
260 return layout;
261}
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
SmartIF< IMessageSvc > & msgSvc() const
Retrieve pointer to message service.
virtual ItemContainer & items()=0
Access item container.
virtual std::string rootVarType(int)
Return ROOT type info:
@ VERBOSE
Definition IMessageSvc.h:22
constexpr auto size(const T &, Args &&...) noexcept
How the items of a tuple map onto the staging buffer and the TTree branches.

◆ book()

StatusCode RootHistCnv::RCWNTupleCnv::book ( const std::string & desc,
INTuple * pObject,
TTree *& tree )
overrideprotectedvirtual

Book the N tuple.

Implements RootHistCnv::RNTupleCnv.

Definition at line 361 of file RCWNTupleCnv.cpp.

363{
364 rtree = nullptr;
365 Layout layout = analyse( *nt );
366
367 if ( m_diskBuffer && !m_bookDirect ) return bookBuffered( desc, nt, std::move( layout ) );
368
369 StatusCode sc = createTree( desc, nt, layout, rtree );
370 if ( sc ) {
371 MsgStream log( msgSvc(), "RCWNTupleCnv" );
372 log << MSG::INFO << "Booked TTree with ID: " << desc << " \"" << nt->title() << "\" in directory " << getDirectory()
373 << endmsg;
374 }
375 return sc;
376}
StatusCode createTree(const std::string &desc, INTuple *nt, const Layout &layout, TTree *&rtree)
bool m_diskBuffer
NTupleSvc.DiskBuffer* of the service owning this stream, read once in initialize().
StatusCode bookBuffered(const std::string &desc, INTuple *nt, Layout layout)
Layout analyse(const INTuple &nt)
bool m_bookDirect
force the columnar path in book()
std::string getDirectory()
@ INFO
Definition IMessageSvc.h:22

◆ bookBuffered()

StatusCode RootHistCnv::RCWNTupleCnv::bookBuffered ( const std::string & desc,
INTuple * nt,
Layout layout )
private

Definition at line 428 of file RCWNTupleCnv.cpp.

430{
431 MsgStream log( msgSvc(), "RCWNTupleCnv" );
432 const auto& items = nt->items();
433 for ( size_t k = 0; k < items.size(); ++k ) {
434 const auto& li = layout.items[k];
435 if ( items[k]->hasIndex() && ( li.indexPos < 0 || li.indexPos >= long( k ) ) ) {
436 log << MSG::ERROR << "DiskBuffer: index " << items[k]->index() << " must be added before " << items[k]->name()
437 << " in " << desc << endmsg;
438 return StatusCode::FAILURE;
439 }
440 }
441 std::string id = desc;
442 if ( auto obj = dynamic_cast<DataObject*>( nt ); obj && obj->registry() ) id = obj->registry()->identifier();
443
444 std::lock_guard lock( m_mutex );
445 fs::path dir;
446 if ( auto sc = bufferDirectory( dir ); !sc ) return sc;
447 const fs::path path = dir / fmt::format( "{:04}.ntbuf", m_nextBufferId++ );
448
449 Buffered b{ desc, std::move( layout ), nullptr };
450 try {
451 b.writer = std::make_unique<DiskBuffer::Writer>( path, describe( id, *nt, b.layout ), m_diskBufferLevel,
453 } catch ( const DiskBuffer::Error& e ) {
454 log << MSG::ERROR << e.what() << endmsg;
455 return StatusCode::FAILURE;
456 }
457 log << MSG::INFO << "Buffering TTree with ID: " << desc << " \"" << nt->title() << "\" in directory "
458 << getDirectory() << " to " << path.string() << endmsg;
459 m_buffered.emplace( nt, std::move( b ) );
460 return StatusCode::SUCCESS;
461}
virtual const std::string & title() const =0
Object title.
std::size_t m_diskBufferBlockSize
std::map< INTuple *, Buffered > m_buffered
std::mutex m_mutex
guards m_buffered, m_replayed and m_bufferDir
StatusCode bufferDirectory(std::filesystem::path &dir)
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
GAUDI_API std::string path(const AIDA::IBaseHistogram *aida)
get the path in THS for AIDA histogram
@ ERROR
Definition IMessageSvc.h:22

◆ bufferDirectory()

StatusCode RootHistCnv::RCWNTupleCnv::bufferDirectory ( std::filesystem::path & dir)
private

Definition at line 379 of file RCWNTupleCnv.cpp.

381{
382 if ( !m_bufferDir.empty() ) {
383 dir = m_bufferDir;
384 return StatusCode::SUCCESS;
385 }
386 MsgStream log( msgSvc(), "RCWNTupleCnv" );
387
388 TFile* file = gDirectory ? gDirectory->GetFile() : nullptr;
389 if ( !file ) {
390 log << MSG::ERROR << "DiskBuffer: " << getDirectory() << " is not inside a file" << endmsg;
391 return StatusCode::FAILURE;
392 }
393 TUrl url( file->GetName(), kTRUE );
394 fs::path base;
395 if ( m_diskBufferDirectory.empty() && std::string_view( url.GetProtocol() ) == "file" ) {
396 base = url.GetFile();
397 } else {
398 base =
399 fs::path( m_diskBufferDirectory.empty() ? "." : m_diskBufferDirectory ) / fs::path( url.GetFile() ).filename();
400 }
401 base += ".ntbuf";
402
403 {
404 std::lock_guard lock( s_dirsMutex );
405 if ( !s_claimedDirs.insert( base ).second ) {
406 log << MSG::ERROR << "DiskBuffer directory " << base << " is already used by another output stream" << endmsg;
407 return StatusCode::FAILURE;
408 }
409 }
410 std::error_code ec;
411 if ( fs::exists( base, ec ) ) {
412 log << MSG::WARNING << "Removing stale DiskBuffer directory " << base << endmsg;
413 fs::remove_all( base, ec );
414 }
415 if ( !ec ) fs::create_directories( base, ec );
416 if ( ec ) {
417 log << MSG::ERROR << "Cannot create DiskBuffer directory " << base << ": " << ec.message() << endmsg;
418 std::lock_guard lock( s_dirsMutex );
419 s_claimedDirs.erase( base );
420 return StatusCode::FAILURE;
421 }
423 dir = base;
424 return StatusCode::SUCCESS;
425}
std::filesystem::path m_bufferDir
std::string m_diskBufferDirectory
@ WARNING
Definition IMessageSvc.h:22

◆ buffered()

RootHistCnv::RCWNTupleCnv::Buffered * RootHistCnv::RCWNTupleCnv::buffered ( INTuple * nt)
private

Definition at line 464 of file RCWNTupleCnv.cpp.

466{
467 std::lock_guard lock( m_mutex );
468 auto it = m_buffered.find( nt );
469 return it != m_buffered.end() ? &it->second : nullptr;
470}

◆ classID()

const CLID & RootHistCnv::RCWNTupleCnv::classID ( )
inlinestatic

Inquire class type.

Definition at line 40 of file RCWNTupleCnv.h.

40{ return CLID_ColumnWiseTuple; }

◆ createTree()

StatusCode RootHistCnv::RCWNTupleCnv::createTree ( const std::string & desc,
INTuple * nt,
const Layout & layout,
TTree *& rtree )
private

Definition at line 264 of file RCWNTupleCnv.cpp.

267{
268 MsgStream log( msgSvc(), "RCWNTupleCnv" );
269 rtree = new TTree( desc.c_str(), nt->title().c_str() );
270 log << MSG::VERBOSE << "created tree id: " << rtree->GetName() << " title: " << nt->title() << " desc: " << desc
271 << endmsg;
272
273 // Make a new buffer, and tell the ntuple where it is
274 const long size = layout.rowBytes;
275 char* buff = nt->setBuffer( new char[size] );
276
277 log << MSG::VERBOSE << "Created buffer size: " << size << " at " << (void*)buff << endmsg;
278
279 // Zero out the buffer to make ROOT happy
280 std::fill_n( buff, size, 0 );
281
282 Gaudi::Property<int> basket_size( "BasketSize", 32000 );
283 m_ntupleSvc.as<IProperty>()->getProperty( &basket_size ).ignore();
284
285 // Loop over items, creating a new branch for each one;
286 for ( const auto& li : layout.items ) {
287
288 char* buf_pos = buff + li.bufPos;
289
290 auto br = new TBranch( rtree, li.name.c_str(), buf_pos, li.leaflist.c_str(), basket_size );
291 if ( li.block != "AUTO_BLK" ) {
292 std::string title = li.block + "::" + br->GetTitle();
293 br->SetTitle( title.c_str() );
294 }
295
296 log << MSG::DEBUG << "adding TBranch " << br->GetTitle() << " at " << (void*)buf_pos << endmsg;
297
298 // for index items with a limited range. Must be a TLeafI!
299 if ( li.rangeLower < li.rangeUpper ) {
300 TLeafI* index = nullptr;
301 TObject* tobj = br->GetListOfLeaves()->FindObject( li.name.c_str() );
302 if ( tobj->IsA()->InheritsFrom( "TLeafI" ) ) {
303 index = dynamic_cast<TLeafI*>( tobj );
304
305 if ( index ) {
306 index->SetMaximum( li.rangeUpper );
307 // FIXME -- add for next version of ROOT
308 // index->SetMinimum( li.rangeLower );
309 } else {
310 log << MSG::ERROR << "Could dynamic cast to TLeafI: " << li.name << endmsg;
311 }
312 }
313 }
314
315 rtree->GetListOfBranches()->Add( br );
316 }
317
318 return StatusCode::SUCCESS;
319}
const char *PyHelper getProperty(IInterface *p, char *name)
virtual char * setBuffer(char *buff)=0
Attach data buffer.
SmartIF< INTupleSvc > m_ntupleSvc
Reference to N tuple service.
Definition RNTupleCnv.h:63
size_t index(const Gaudi::ParticleProperty *property, const Gaudi::Interfaces::IParticlePropertySvc *service)
helper utility for mapping of Gaudi::ParticleProperty object into non-negative integral sequential id...
@ DEBUG
Definition IMessageSvc.h:22

◆ finalize()

StatusCode RootHistCnv::RCWNTupleCnv::finalize ( )
override

Definition at line 635 of file RCWNTupleCnv.cpp.

637{
638 {
639 std::lock_guard lock( m_mutex );
640 if ( !m_buffered.empty() ) {
641 MsgStream log( msgSvc(), "RCWNTupleCnv" );
642 for ( auto& [nt, b] : m_buffered ) {
643 // flush first, so the file left behind holds every row that was written
644 try {
645 b.writer->close();
646 } catch ( const DiskBuffer::Error& e ) { log << MSG::ERROR << e.what() << endmsg; }
647 log << MSG::ERROR << "TTree " << b.desc << " was never built from its disk buffer " << b.writer->path().string()
648 << endmsg;
649 }
650 m_buffered.clear();
651 }
652 m_replayed.clear();
654 }
655 return RNTupleCnv::finalize();
656}
std::set< INTuple * > m_replayed
tuples whose tree has been built; cannot be written again
StatusCode finalize() override
Finalize the converter.

◆ initialize()

StatusCode RootHistCnv::RCWNTupleCnv::initialize ( )
override

Definition at line 322 of file RCWNTupleCnv.cpp.

324{
325 StatusCode sc = RNTupleCnv::initialize();
326 if ( !sc ) return sc;
327 MsgStream log( msgSvc(), "RCWNTupleCnv" );
328
329 // the DiskBuffer properties belong to the tuple service owning this stream, which is our data provider
330 SmartIF<IProperty> owner = dataProvider().as<IProperty>();
331 if ( !owner ) owner = m_ntupleSvc.as<IProperty>(); // not owned by a tuple service: keep the lookup by name
332 Gaudi::Property<bool> diskBuffer( "DiskBuffer", false );
333 Gaudi::Property<std::string> directory( "DiskBufferDirectory", "" );
334 Gaudi::Property<int> level( "DiskBufferCompression", 3 );
335 Gaudi::Property<int> blockSize( "DiskBufferBlockSize", 64 * 1024 );
336 if ( owner ) {
337 for ( auto* p :
338 std::initializer_list<Gaudi::Details::PropertyBase*>{ &diskBuffer, &directory, &level, &blockSize } )
339 owner->getProperty( p ).ignore();
340 }
341
342 m_diskBuffer = diskBuffer;
345 m_diskBufferBlockSize = static_cast<std::size_t>( blockSize.value() );
346 if ( !m_diskBuffer ) return sc;
347
348 if ( m_diskBufferLevel != 0 && !DiskBuffer::zstdAvailable() ) {
349 log << MSG::WARNING << "DiskBuffer: zstd not available in this build, not compressing" << endmsg;
351 }
352 if ( blockSize <= 0 || m_diskBufferBlockSize > DiskBuffer::maxBlockSize() ) {
353 log << MSG::ERROR << "DiskBuffer: DiskBufferBlockSize must be between 1 and " << DiskBuffer::maxBlockSize()
354 << endmsg;
355 return StatusCode::FAILURE;
356 }
357 return sc;
358}
SmartIF< IDataProviderSvc > & dataProvider() const override
Get Data provider service.
Definition Converter.cpp:77
std::string directory(const std::string &loc)
StatusCode initialize() override
Initialize the converter.
SmartIF< IFace > as() const
return a new SmartIF instance to another interface
Definition SmartIF.h:110

◆ load()

StatusCode RootHistCnv::RCWNTupleCnv::load ( TTree * tree,
INTuple *& refpObject )
overrideprotectedvirtual

Create the transient representation of an object.

Implements RootHistCnv::RNTupleCnv.

Definition at line 688 of file RCWNTupleCnv.cpp.

690{
691 MsgStream log( msgSvc(), "RCWNTupleCnv::load" );
692
693 StatusCode status;
694
695 NTuple::Tuple* pObj = nullptr;
696
697 std::string title = tree->GetTitle();
698 log << MSG::VERBOSE << "loading CWNT " << title << " at: " << tree << endmsg;
699
700 status = m_ntupleSvc->create( CLID_ColumnWiseTuple, title, pObj );
701 INTuple* ntup = dynamic_cast<INTuple*>( pObj );
702 if ( !ntup ) { log << MSG::ERROR << "cannot dynamic cast to INTuple" << endmsg; }
703
704 INTupleItem* item = nullptr;
705
706 std::string itemName, indexName, item_type, itemTitle, blockName;
707 // long numEnt, numVar;
708 long size, totsize = 0;
709 std::vector<std::pair<TLeaf*, int>> itemList;
710
711 // numEnt = (int)tree->GetEntries();
712 // numVar = tree->GetNbranches();
713
714 // loop over all branches (==leaves)
715 TObjArray* lbr = tree->GetListOfBranches();
716 TIter bitr( lbr );
717 while ( TObject* tobjb = bitr() ) {
718
719 TBranch* br = dynamic_cast<TBranch*>( tobjb );
720 itemTitle = br->GetTitle();
721
722 int ipos = itemTitle.find( "::" );
723 if ( ipos >= 0 ) {
724 blockName = itemTitle.substr( 0, ipos );
725 } else {
726 blockName = "";
727 }
728
729 TObjArray* lf = br->GetListOfLeaves();
730
731 TIter litr( lf );
732 while ( TObject* tobj = litr() ) {
733
734 bool hasRange = false;
735 int indexRange = 0;
736 int itemSize;
737 item = nullptr;
738
739 TLeaf* tl = dynamic_cast<TLeaf*>( tobj );
740 if ( !tl ) {
741 log << MSG::ERROR << "cannot dynamic cast to TLeaf" << endmsg;
742 return StatusCode::FAILURE;
743 }
744 itemName = tl->GetName();
745
746 if ( blockName != "" ) {
747 log << MSG::DEBUG << "loading NTuple item " << blockName << "/" << itemName;
748 } else {
749 log << MSG::DEBUG << "loading NTuple item " << itemName;
750 }
751
752 int arraySize{ 0 };
753 TLeaf* indexLeaf = tl->GetLeafCounter( arraySize );
754
755 if ( arraySize == 0 ) { log << MSG::ERROR << "TLeaf counter size = 0. This should not happen!" << endmsg; }
756
757 if ( indexLeaf ) {
758 // index Arrays and Matrices
759
760 indexName = indexLeaf->GetName();
761 indexRange = indexLeaf->GetMaximum();
762 itemSize = indexRange * tl->GetLenType() * arraySize;
763
764 log << "[" << indexName;
765
766 // Just for Matrices
767 if ( arraySize != 1 ) { log << "][" << arraySize; }
768 log << "]";
769
770 } else {
771 itemSize = tl->GetLenType() * arraySize;
772
773 indexName = "";
774
775 if ( arraySize == 1 ) {
776 // Simple items
777 } else {
778 // Arrays of constant size
779 log << "[" << arraySize << "]";
780 }
781 }
782
783 log << endmsg;
784
785 size = itemSize;
786 totsize += size;
787
788 hasRange = tl->IsRange();
789
790 itemList.emplace_back( tl, itemSize );
791
792 // Integer
793 if ( tobj->IsA()->InheritsFrom( "TLeafI" ) ) {
794
795 TLeafI* tli = dynamic_cast<TLeafI*>( tobj );
796 if ( tli ) {
797 if ( tli->IsUnsigned() ) {
798 unsigned long min = 0, max = 0;
799 if ( hasRange ) {
800 min = tli->GetMinimum();
801 max = tli->GetMaximum();
802 }
803
804 item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup, hasRange );
805 } else {
806 long min = 0, max = 0;
807 if ( hasRange ) {
808 min = tli->GetMinimum();
809 max = tli->GetMaximum();
810 }
811
812 item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup, hasRange );
813 }
814 } else {
815 log << MSG::ERROR << "cannot dynamic cast to TLeafI" << endmsg;
816 }
817
818 // Float
819 } else if ( tobj->IsA()->InheritsFrom( "TLeafF" ) ) {
820 float min = 0., max = 0.;
821
822 TLeafF* tlf = dynamic_cast<TLeafF*>( tobj );
823 if ( tlf ) {
824 if ( hasRange ) {
825 min = float( tlf->GetMinimum() );
826 max = float( tlf->GetMaximum() );
827 }
828 } else {
829 log << MSG::ERROR << "cannot dynamic cast to TLeafF" << endmsg;
830 }
831
832 item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup, hasRange );
833
834 // Double
835 } else if ( tobj->IsA()->InheritsFrom( "TLeafD" ) ) {
836 double min = 0., max = 0.;
837
838 TLeafD* tld = dynamic_cast<TLeafD*>( tobj );
839 if ( tld ) {
840 if ( hasRange ) {
841 min = tld->GetMinimum();
842 max = tld->GetMaximum();
843 }
844 } else {
845 log << MSG::ERROR << "cannot dynamic cast to TLeafD" << endmsg;
846 }
847
848 item = createNTupleItem( itemName, blockName, indexName, indexRange, arraySize, min, max, ntup, hasRange );
849
850 } else {
851 log << MSG::ERROR << "Uknown data type" << endmsg;
852 }
853
854 if ( item ) {
855 ntup->add( item ).ignore();
856 } else {
857 log << MSG::ERROR << "Unable to create ntuple item \"" << itemName << "\"" << endmsg;
858 }
859
860 } // end litr
861 } // end bitr
862
863 log << MSG::DEBUG << "Total buffer size of NTuple: " << totsize << " Bytes." << endmsg;
864
865 char* buf = ntup->setBuffer( new char[totsize] );
866 char* bufpos = buf;
867
868 int ts = 0;
869 for ( const auto& iitr : itemList ) {
870 TLeaf* leaf = iitr.first;
871 int isize = iitr.second;
872
873 log << MSG::VERBOSE << "setting TBranch " << leaf->GetBranch()->GetName() << " buffer at " << (void*)bufpos
874 << endmsg;
875
876 leaf->GetBranch()->SetAddress( (void*)bufpos );
877
878 // //testing
879 // if (leaf->IsA()->InheritsFrom("TLeafI")) {
880 // for (int ievt=0; ievt<5; ievt++) {
881 // leaf->GetBranch()->GetEvent(ievt);
882 // int *idat = (int*)bufpos;
883 // log << MSG::WARNING << leaf->GetName() << ": " << ievt << " "
884 // << *idat << endmsg;
885
886 // }
887 // }
888
889 ts += isize;
890
891 bufpos += isize;
892 }
893
894 if ( totsize != ts ) { log << MSG::ERROR << "buffer size mismatch: " << ts << " " << totsize << endmsg; }
895
896 refpObject = ntup;
897
898 return StatusCode::SUCCESS;
899}
virtual StatusCode add(INTupleItem *item)=0
Add an item row to the N tuple.
void ignore() const
Allow discarding a StatusCode without warning.
Definition StatusCode.h:128
INTupleItem * createNTupleItem(const std::string &itemName, const std::string &blockName, const std::string &indexName, int indexRange, int arraySize, TYP min, TYP max, INTuple *ntup, bool hasRange)
Add an item of a given type to the N tuple.

◆ readData()

StatusCode RootHistCnv::RCWNTupleCnv::readData ( TTree * rtree,
INTuple * pObject,
long ievt )
overrideprotectedvirtual

Read N tuple data.

Implements RootHistCnv::RNTupleCnv.

Definition at line 659 of file RCWNTupleCnv.cpp.

661{
662 if ( !rtree ) {
663 MsgStream log( msgSvc(), "RCWNTupleCnv::readData" );
664 log << MSG::ERROR << "cannot read a disk-buffered N-tuple: its TTree is only built at finalize" << endmsg;
665 return StatusCode::FAILURE;
666 }
667 if ( ievt >= rtree->GetEntries() ) {
668 MsgStream log( msgSvc(), "RCWNTupleCnv::readData" );
669 log << MSG::ERROR << "no more entries in tree to read. max: " << rtree->GetEntries() << " current: " << ievt
670 << endmsg;
671 return StatusCode::FAILURE;
672 }
673
674 rtree->GetEvent( ievt );
675 ievt++;
676
677 // copy data from ntup->buffer() to ntup->items()->buffer()
678 auto& items = ntup->items();
679 std::accumulate( begin( items ), end( items ), const_cast<const char*>( ntup->buffer() ),
680 []( const char* src, INTupleItem* i ) {
681 return src + visit( *i, [src]( auto& item ) { return loadItem( src, item ); } );
682 } );
683
684 return StatusCode::SUCCESS;
685}
AttribStringParser::Iterator begin(const AttribStringParser &parser)

◆ releaseBufferDir()

void RootHistCnv::RCWNTupleCnv::releaseBufferDir ( )
private

Definition at line 625 of file RCWNTupleCnv.cpp.

627{
628 if ( m_bufferDir.empty() ) return;
629 std::lock_guard lock( s_dirsMutex );
630 s_claimedDirs.erase( m_bufferDir );
631 m_bufferDir.clear();
632}

◆ replay()

StatusCode RootHistCnv::RCWNTupleCnv::replay ( IOpaqueAddress * pAddr,
INTuple * nt,
Buffered & b )
private

Definition at line 553 of file RCWNTupleCnv.cpp.

555{
556 MsgStream log( msgSvc(), "RCWNTupleCnv" );
557 GlobalDirectoryRestore restore;
558 const auto t0 = std::chrono::steady_clock::now();
559 const std::string desc = b.desc;
560 const fs::path path = b.writer->path();
561 TDirectory* pDir = (TDirectory*)pAddr->ipar()[0];
562 TTree* tree = nullptr;
563 StatusCode sc = StatusCode::SUCCESS;
564 std::uint64_t entries = 0, bytes = 0, stored = 0;
565
566 try {
567 b.writer->close();
568 entries = b.writer->entries();
569 bytes = b.writer->bytes();
570 stored = b.writer->storedBytes();
571 b.writer.reset(); // free its write cache before the tree is built
572 if ( nt->items().size() != b.layout.items.size() )
573 throw std::runtime_error( "N-tuple changed shape after its first write" );
574 if ( !pDir ) throw std::runtime_error( "no output directory" );
575 pDir->cd();
576 sc = createTree( desc, nt, b.layout, tree );
577 if ( sc ) {
578 const auto& items = nt->items();
579 char* buf = nt->buffer();
580 // the part of a slot not stored in a record is whatever reset() leaves there
581 nt->reset();
582 std::vector<char> defaults( b.layout.rowBytes );
583 for ( size_t k = 0; k < items.size(); ++k )
584 std::memcpy( defaults.data() + b.layout.items[k].bufPos, items[k]->buffer(), b.layout.items[k].bufLen );
585
586 DiskBuffer::Reader reader( path );
587 std::span<const char> rec;
588 while ( reader.next( rec ) ) {
589 unpackRow( rec, b.layout, items, buf, defaults.data() );
590 tree->Fill();
591 }
592 if ( reader.entries() != entries )
593 throw std::runtime_error( fmt::format( "expected {} entries, found {}", entries, reader.entries() ) );
594 if ( tree->Write( "", TObject::kOverwrite ) == 0 ) throw std::runtime_error( "TTree::Write failed" );
595 }
596 } catch ( const std::exception& e ) {
597 log << MSG::ERROR << "Failed to build TTree " << desc << " from disk buffer " << path.string() << ": " << e.what()
598 << endmsg;
600 }
601 delete tree;
602 nt->setBuffer( nullptr );
603
604 std::error_code ec;
605 if ( sc ) fs::remove( path, ec );
606 {
607 std::lock_guard lock( m_mutex );
608 m_buffered.erase( nt );
609 m_replayed.insert( nt );
610 if ( m_buffered.empty() ) {
611 fs::remove( m_bufferDir, ec ); // only when empty, i.e. nothing was left behind for inspection
613 }
614 }
615 if ( sc ) {
616 const double secs = std::chrono::duration<double>( std::chrono::steady_clock::now() - t0 ).count();
617 log << MSG::INFO << "Built TTree with ID: " << desc << " \"" << nt->title() << "\" in directory " << pDir->GetPath()
618 << " from disk buffer: " << entries << " entries, " << bytes << " bytes (" << stored << " on disk), "
619 << fmt::format( "{:.2f}", secs ) << " s" << endmsg;
620 }
621 return sc;
622}
virtual void reset()=0
Reset all entries to their default values.
virtual const char * buffer() const =0
Access data buffer (CONST).
virtual const unsigned long * ipar() const =0
Access to generic link parameters.
rec(o, path=None, lst=None)

◆ replayed()

bool RootHistCnv::RCWNTupleCnv::replayed ( INTuple * nt)
private

Definition at line 473 of file RCWNTupleCnv.cpp.

475{
476 std::lock_guard lock( m_mutex );
477 return m_replayed.count( nt ) != 0;
478}

◆ updateRep()

StatusCode RootHistCnv::RCWNTupleCnv::updateRep ( IOpaqueAddress * pAddr,
DataObject * pObj )
override

Write the TTree; for a disk-buffered tuple, first build it from the buffer file.

Definition at line 534 of file RCWNTupleCnv.cpp.

536{
537 if ( !pAddr ) {
538 // never written: the base class books it and writes one default row; keep that on the direct path
539 m_bookDirect = true;
540 StatusCode sc = RNTupleCnv::updateRep( pAddr, pObj );
541 m_bookDirect = false;
542 return sc;
543 }
544 INTuple* nt = dynamic_cast<INTuple*>( pObj );
545 Buffered* b = nt ? buffered( nt ) : nullptr;
546 if ( b ) return replay( pAddr, nt, *b );
547 // an earlier save() already built and wrote the tree, there is nothing left to do
548 if ( nt && replayed( nt ) ) return StatusCode::SUCCESS;
549 return RNTupleCnv::updateRep( pAddr, pObj );
550}
Buffered * buffered(INTuple *nt)
StatusCode replay(IOpaqueAddress *pAddr, INTuple *nt, Buffered &b)
bool replayed(INTuple *nt)
StatusCode updateRep(IOpaqueAddress *pAddr, DataObject *pObj) override
Update the converted representation of a transient object.

◆ writeBuffered()

StatusCode RootHistCnv::RCWNTupleCnv::writeBuffered ( Buffered & b,
INTuple * nt )
private

Definition at line 513 of file RCWNTupleCnv.cpp.

515{
516 const auto& items = nt->items();
517 if ( items.size() != b.layout.items.size() ) {
518 MsgStream log( msgSvc(), "RCWNTupleCnv" );
519 log << MSG::ERROR << "N-tuple " << b.desc << " changed shape after its first write" << endmsg;
520 return StatusCode::FAILURE;
521 }
522 try {
523 packRow( *b.writer, b.layout, items );
524 } catch ( const DiskBuffer::Error& e ) {
525 MsgStream log( msgSvc(), "RCWNTupleCnv" );
526 log << MSG::ERROR << "Disk buffer write failed: " << e.what() << endmsg;
527 return StatusCode::FAILURE;
528 }
529 nt->reset();
530 return StatusCode::SUCCESS;
531}

◆ writeData()

StatusCode RootHistCnv::RCWNTupleCnv::writeData ( TTree * rtree,
INTuple * pObject )
overrideprotectedvirtual

Write N tuple data.

Implements RootHistCnv::RNTupleCnv.

Definition at line 483 of file RCWNTupleCnv.cpp.

485{
486 if ( !rtree ) {
487 if ( Buffered* b = buffered( nt ) ) return writeBuffered( *b, nt );
488 MsgStream log( msgSvc(), "RCWNTupleCnv" );
489 if ( replayed( nt ) ) {
490 // save() built the tree and closed the buffer; there is nowhere to put this row
491 log << MSG::ERROR << "N-tuple \"" << nt->title()
492 << "\" was already written from its disk buffer: with NTupleSvc.DiskBuffer a tuple cannot be filled after "
493 "it has been saved. Row lost."
494 << endmsg;
495 } else {
496 log << MSG::ERROR << "No TTree and no disk buffer for N-tuple \"" << nt->title() << "\"" << endmsg;
497 }
498 return StatusCode::FAILURE;
499 }
500
501 // Fill the tree;
502 const auto& items = nt->items();
503 std::accumulate( begin( items ), end( items ), nt->buffer(), []( char* dest, const INTupleItem* i ) {
504 return dest + visit( *i, [dest]( const auto& item ) { return saveItem( dest, item ); } );
505 } );
506
507 rtree->Fill();
508 nt->reset();
509 return StatusCode::SUCCESS;
510}
StatusCode writeBuffered(Buffered &b, INTuple *nt)

Member Data Documentation

◆ m_bookDirect

bool RootHistCnv::RCWNTupleCnv::m_bookDirect { false }
private

force the columnar path in book()

Definition at line 99 of file RCWNTupleCnv.h.

99{ false };

◆ m_bufferDir

std::filesystem::path RootHistCnv::RCWNTupleCnv::m_bufferDir
private

Definition at line 97 of file RCWNTupleCnv.h.

◆ m_buffered

std::map<INTuple*, Buffered> RootHistCnv::RCWNTupleCnv::m_buffered
private

Definition at line 95 of file RCWNTupleCnv.h.

◆ m_diskBuffer

bool RootHistCnv::RCWNTupleCnv::m_diskBuffer { false }
private

NTupleSvc.DiskBuffer* of the service owning this stream, read once in initialize().

Definition at line 102 of file RCWNTupleCnv.h.

102{ false };

◆ m_diskBufferBlockSize

std::size_t RootHistCnv::RCWNTupleCnv::m_diskBufferBlockSize { 0 }
private

Definition at line 105 of file RCWNTupleCnv.h.

105{ 0 };

◆ m_diskBufferDirectory

std::string RootHistCnv::RCWNTupleCnv::m_diskBufferDirectory
private

Definition at line 103 of file RCWNTupleCnv.h.

◆ m_diskBufferLevel

int RootHistCnv::RCWNTupleCnv::m_diskBufferLevel { 0 }
private

Definition at line 104 of file RCWNTupleCnv.h.

104{ 0 };

◆ m_mutex

std::mutex RootHistCnv::RCWNTupleCnv::m_mutex
private

guards m_buffered, m_replayed and m_bufferDir

Definition at line 94 of file RCWNTupleCnv.h.

◆ m_nextBufferId

unsigned RootHistCnv::RCWNTupleCnv::m_nextBufferId { 0 }
private

Definition at line 98 of file RCWNTupleCnv.h.

98{ 0 };

◆ m_replayed

std::set<INTuple*> RootHistCnv::RCWNTupleCnv::m_replayed
private

tuples whose tree has been built; cannot be written again

Definition at line 96 of file RCWNTupleCnv.h.


The documentation for this class was generated from the following files: