-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Teach TFileMerger to work with TFile* handles. #1073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3b3edd6
9257fff
9be0fd1
e8a02a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| ROOT_ADD_GTEST(testTBufferMerger TBufferMerger.cxx LIBRARIES RIO Tree) | ||
| ROOT_ADD_GTEST(IOTests TBufferMerger.cxx TFileMergerTests.cxx LIBRARIES RIO Tree) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| #include "TFileMerger.h" | ||
|
|
||
| #include "TMemFile.h" | ||
| #include "TTree.h" | ||
|
|
||
| #include "gtest/gtest.h" | ||
|
|
||
| namespace { | ||
| using testing::internal::GetCapturedStderr; | ||
| using testing::internal::CaptureStderr; | ||
| using testing::internal::RE; | ||
| class ExpectedErrorRAII { | ||
| std::string ExpectedRegex; | ||
| void pop() | ||
| { | ||
| std::string Seen = GetCapturedStderr(); | ||
| bool match = RE::FullMatch(Seen, RE(ExpectedRegex)); | ||
| EXPECT_TRUE(match); | ||
| if (!match) { | ||
| std::string msg = "Match failed!\nSeen: '" + Seen + "'\nRegex: '" + ExpectedRegex + "'\n"; | ||
| GTEST_NONFATAL_FAILURE_(msg.c_str()); | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| ExpectedErrorRAII(std::string E) : ExpectedRegex(E) { CaptureStderr(); } | ||
| ~ExpectedErrorRAII() { pop(); } | ||
| }; | ||
| } | ||
|
|
||
| #define EXPECT_ROOT_ERROR(expression, expected_error) \ | ||
| { \ | ||
| ExpectedErrorRAII EE(expected_error); \ | ||
| expression; \ | ||
| } | ||
|
|
||
| static void CreateATuple(TMemFile &file, const char *name, double value) | ||
| { | ||
| auto mytree = new TTree(name, "A tree"); | ||
| // FIXME: We inherit EnableImplicitIMT from TBufferMerger tests (we are sharing the same executable) where we call | ||
| // EnableThreadSafety(). Here, we hit a race condition in TBranch::FlushBaskets. Once we get that fixed we probably | ||
| // should re-enable implicit MT. | ||
| // | ||
| // In general, we should probably have a way to conditionally enable/disable thread safety. | ||
| mytree->SetImplicitMT(false); | ||
|
|
||
| mytree->SetDirectory(&file); | ||
| mytree->Branch(name, &value); | ||
| mytree->Fill(); | ||
| file.Write(); | ||
| } | ||
|
|
||
| static void CheckTree(TMemFile &file, const char *name, double expectedValue) | ||
| { | ||
| auto t = static_cast<TTree *>(file.Get(name)); | ||
| ASSERT_TRUE(t != nullptr); | ||
|
|
||
| double d; | ||
| t->SetBranchAddress(name, &d); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting branch address to a stack address requires to either call
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does that mean that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In the case of a TTree, the point is an implicit shared pointer. You can delete it (and the TFile will be informed) and you can let the TFile delete it (but your are not directly inform when it does unless you are registered in the list of cleanups).
Yes, you can as long as you make sure that the lifetime of the unique_ptr is less or equal to the litetime of the TFile.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be done. |
||
| t->GetEntry(0); | ||
| EXPECT_EQ(expectedValue, d); | ||
| // Setting branch address to a stack address requires to either call ResetBranchAddresses or delete the tree. | ||
| t->ResetBranchAddresses(); | ||
| } | ||
|
|
||
| TEST(TFileMerger, CreateWithTFilePointer) | ||
| { | ||
| TMemFile a("a.root", "RECREATE"); | ||
| CreateATuple(a, "a_tree", 1.); | ||
|
|
||
| TMemFile b("b.root", "RECREATE"); | ||
| CreateATuple(b, "b_tree", 2.); | ||
|
|
||
| TFileMerger merger; | ||
| auto output = std::unique_ptr<TMemFile>(new TMemFile("output.root", "CREATE")); | ||
| bool success = merger.OutputFile(std::move(output)); | ||
|
|
||
| ASSERT_TRUE(success); | ||
|
|
||
| merger.AddFile(&a, false); | ||
| merger.AddFile(&b, false); | ||
| // FIXME: Calling merger.Merge() will call Close() and *delete* output. | ||
| merger.PartialMerge(); | ||
|
|
||
| auto &result = *static_cast<TMemFile *>(merger.GetOutputFile()); | ||
| CheckTree(result, "a_tree", 1); | ||
| CheckTree(result, "b_tree", 2); | ||
| } | ||
|
|
||
| TEST(TFileMerger, CreateWithUnwritableTFilePointer) | ||
| { | ||
| TFileMerger merger; | ||
| auto output = std::unique_ptr<TMemFile>(new TMemFile("output.root", "RECREATE")); | ||
| // FIXME: The ctor of TMemFile sets the 'zombie' flag to all TMemFiles whose options are different than CREATE and | ||
| // RECREATE. We should probably fix the API but until then work around it. | ||
| output->SetWritable(false); | ||
| EXPECT_ROOT_ERROR(merger.OutputFile(std::move(output)), "Error in .* output file output.root is not writable\n"); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change this? This only matters for classes that are streamed. This should have remained as 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, when you have a ClassDef and you change data members you also should bump the ClassDef version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only when you change a persistent member :) ... and version == 0 means that all data members are implicitly marked transient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall I revert it back to 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, done. I don't understand how is that a non persistent data member but you are the expert.