Closing a file contain merged trees (TChain) causes segmentation violation

Hello
I’m trying to merge trees from different root files into one file.
I use TChain to do the jobs

{
...
	TChain *trees_chain = new TChain( tree_name );
	trees_chain -> CanDeleteRefs( true );
	for ( int i=0; i<number_of_subtrees; i++ )
	{
		trees_chain -> Add ( subtree_files[i].data( ) );
		printf( "|  |  added: %s\n", subtree_files[i].data( ) );
	}

	long target_tree_size = trees_chain->GetEntries( );
	TFile* output_file = new TFile( target_path, merge_mode );
	output_file -> cd( );
	trees_chain -> Merge( output_file, 0, "fast" );
	printf ( "|  |_ merged [%ld] event to: %s\n", target_tree_size, target_path );
	output_file -> Close( );
...
}

here subtree_files is just a std::vector<string> containing the files’ names I want to merge.
I managed to merge the trees into the target file, but when I close it, I got segmentation violation error.

===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007f92b4366337 in __GI___waitpid (pid=27692, stat_loc=stat_loc
entry=0x7ffdf7aadde8, options=options
entry=0) at ../sysdeps/unix/sysv/linux/waitpid.c:30
#1  0x00007f92b42d1047 in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:149
#2  0x00007f92b58760f3 in TUnixSystem::StackTrace() () from /home/longhoa/ROOT_Source/ROOT_v06_24_00/lib/libCore.so.6.24
#3  0x00007f92b5878be5 in TUnixSystem::DispatchSignals(ESignals) () from /home/longhoa/ROOT_Source/ROOT_v06_24_00/lib/libCore.so.6.24
#4  <signal handler called>
#5  0x0000561cc5cc0ac9 in main ()
===========================================================


The lines below might hint at the cause of the crash.
You may get help by asking at the ROOT forum https://root.cern.ch/forum
Only if you are really convinced it is a bug in ROOT then please submit a
report at https://root.cern.ch/bugs Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.
===========================================================
#5  0x0000561cc5cc0ac9 in main ()
===========================================================

I even tried

trees_chain -> SetDirectory( 0 );

But it still doesn’t help.

How do I avoid this error? Thank you very much.


Update
I managed to avoid the segmentation violation by using

trees_chain->Write( "fast", TObject::kOverwrite ); //not sure if 'fast' is a valid option here

instead of

trees_chain->Merge( output_file, 0, "fast" );

But I’m not sure if this is the proper way to save the chain, as this is not instructed in the TChain class reference.


Solution update
As @dastudillo pointed out, the output file is closed and deleted automatically, so any action on output_file after the Merge( ) will result in error.


ROOT Version: 6.24/00
Platform: Ubuntu 18.04LTS
Compiler: g++


Just out of curiosity, did you try hadd?

1 Like

Yes, I tried hadd before.
Problem is I plan to add different trees with different types of content into a target file, so I need to write my own code.

OK, then maybe @pcanal can help

I try your suggestion but the seg error stays.
I can delete the trees_chain with no issue, but

output_file->Close( )

or

delete output_file;

Will given me the segmentation error

No, still doesn’t work.
Even the line output_file -> Write( ) causes seg violation.

https://root.cern/doc/master/classTChain.html#aa004818ef40d96c8514af314e5d21aa1
(or this, for Ver. 6.24)
As per the important note 2: The output file is automatically closed and deleted. So you don’t need to close or delete it, since Merge does it. Also, ROOT may complain if the output file does not already exist, so if you get an error that it does not exist, try also

	TFile* output_file = new TFile( target_path, "RECREATE");

or “update” (don’t know what is the value of “merge_mode” in your code).

2 Likes

Thank you, it works!
merge_mode includes “recreate” in case the output does not exist.
May I ask which is the better option to write the chain to file, Write( ) or Merge( )

The 2 are completely different. Write would only write to the disk the list of file name. I.e. you really want/need Merge

1 Like

Thanks @pcanal, I think I was not clear in my question. What I mention is TChain::Write( ) , as why I do:

trees_chain -> Write( "fast", TObject::kOverwrite );

instead of

trees_chain -> Merge( output_file, 0, "fast" );

I still get the merge tree as I expected. So I’m curious what is the difference between TChain::Marge( ) and TChain::Write( )

I am very confused. Write and Merge in this context will produce completely different output. You should not be getting the "merge treeswithWrite` unless I misunderstood something completely. For example I just did:

rootsrv1:ninja pcanal$ ls -lart /var/tmp/output.root 
-rw-r--r-- 1 pcanal pcanal 5159 Apr 18 11:32 /var/tmp/output.root
rootsrv1:ninja pcanal$ root.exe -b -l 
root [0] c = new TChain("ntuple");
root [1] c->Add("tutorials/hsimple.root")
(int) 1
root [2] c->Add("tutorials/hsimple.root")
(int) 1
root [3] of = TFile::Open("/var/tmp/output.root", "RECREATE");
root [4] c->Write("fast", TObject::kOverwrite );
root [5] of->ls()
TFile**         /var/tmp/output.root
 TFile*         /var/tmp/output.root
  KEY: TChain   fast;1  
root [6] .q
rootsrv1:ninja pcanal$ ls -lart /var/tmp/output.root tutorials/hsimple.root 
-rw-r--r-- 1 pcanal pcanal 414816 Mar  7 14:06 tutorials/hsimple.root
-rw-r--r-- 1 pcanal pcanal   5307 Apr 18 11:32 /var/tmp/output.root

as you can see the output file contains a TChain (not a TTree) called fast (name completely unrelated to the input TTree) and the output file is tiny (because it contains only the name of the files) compare to the input file (where in my example the merge should be about twice as big).

What am I missing?

1 Like

Yes, you are correct. I overlooked the size of the output file created by Write( ).
Turns out the file is way smaller than expected, and the object saved in the file is TChain, not TTree. I was confused because when I process that TChain object by, for example, GetEntries( ) or Draw( ), I still get the result I expected.
Thank you very much for clarifying.

I guess the saved TChain will provide “references” to the original files.

1 Like

Yes, it is “references” to the original files, if the original files are rename or remove, it will affect the merged result. So yes, Merge( ) is the right function to call.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.