diff --git a/io/io/inc/ROOT/TBufferMerger.hxx b/io/io/inc/ROOT/TBufferMerger.hxx index 060bcb926e6d7..c3dbcbba251d1 100644 --- a/io/io/inc/ROOT/TBufferMerger.hxx +++ b/io/io/inc/ROOT/TBufferMerger.hxx @@ -79,7 +79,7 @@ private: std::mutex fWriteMutex; //< Mutex used for the condition variable std::condition_variable fCV; //< Condition variable used to wait for data std::queue fQueue; //< Queue to which data is pushed and merged - std::unique_ptr fFile; //< Output file, owned by the user + std::unique_ptr fFile; //< Output file, owned by this class std::unique_ptr fMergingThread; //< Worker thread that writes to disk std::vector> fAttachedFiles; //< Attached files diff --git a/io/io/src/TBufferMerger.cxx b/io/io/src/TBufferMerger.cxx index 24dcc851c74fd..538716f1ad457 100644 --- a/io/io/src/TBufferMerger.cxx +++ b/io/io/src/TBufferMerger.cxx @@ -280,6 +280,7 @@ TBufferMerger::~TBufferMerger() fCV.notify_one(); fMergingThread->join(); + fFile->Close(); } std::shared_ptr TBufferMerger::GetFile() diff --git a/tree/treeplayer/inc/ROOT/TDataFrameInterface.hxx b/tree/treeplayer/inc/ROOT/TDataFrameInterface.hxx index 86cee48c6b850..fa0f182ee32fd 100644 --- a/tree/treeplayer/inc/ROOT/TDataFrameInterface.hxx +++ b/tree/treeplayer/inc/ROOT/TDataFrameInterface.hxx @@ -12,6 +12,7 @@ #define ROOT_TDATAFRAME_INTERFACE #include "ROOT/TActionResultProxy.hxx" +#include "ROOT/TBufferMerger.hxx" #include "ROOT/TDFNodes.hxx" #include "ROOT/TDFOperations.hxx" #include "ROOT/TDFUtils.hxx" @@ -1066,26 +1067,33 @@ protected: } { - std::unique_ptr ofile(TFile::Open(filename.c_str(), "RECREATE")); - TTree t(treename.c_str(), treename.c_str()); + auto df = GetDataFrameChecked(); + unsigned int nSlots = df->GetNSlots(); + TBufferMerger merger(filename.c_str(), "RECREATE"); + std::vector> files(nSlots); + std::vector> trees(nSlots); - static bool firstEvt = true; + auto fillTree = [&merger, &trees, &files, &bnames, &treename](unsigned int slot, Args &... args) { + if (!trees[slot]) { + files[slot] = merger.GetFile(); + trees[slot].reset(new TTree(treename.c_str(), treename.c_str())); - auto fillTree = [&t, &bnames](Args &... args) { - if (firstEvt) { // hack to call TTree::Branch on all variadic template arguments - std::initializer_list expander = {(t.Branch(bnames[S].c_str(), &args), 0)..., 0}; + std::initializer_list expander = {(trees[slot]->Branch(bnames[S].c_str(), &args), 0)..., 0}; (void)expander; // avoid unused variable warnings for older compilers such as gcc 4.9 - firstEvt = false; } - t.Fill(); + + trees[slot]->Fill(); }; - Foreach(fillTree, {bnames[S]...}); + ForeachSlot(fillTree, {bnames[S]...}); + + for (auto &&tree : trees) tree->Write(); + for (auto &&file : files) file->Write(); - t.Write(); - firstEvt = true; + trees.clear(); + files.clear(); } // Now we mimic a constructor for the TDataFrame. We cannot invoke it here // since this would introduce a cyclic headers dependency.