From ec035930754cd19244486963581ed4f04459d4c8 Mon Sep 17 00:00:00 2001 From: Philippe Canal <pcanal@fnal.gov> Date: Thu, 11 Feb 2021 16:22:20 -0600 Subject: [PATCH] TBufferMergerFile: Call FlushBasket in unlocked thread. Add new enum for TObject::Write: kOnlyPrepStep = BIT(3) ///< Just prepare the objects do not write them (i.e. call TTree::FlushBaskets) --- core/base/inc/TObject.h | 11 ++++++++++- core/base/src/TObject.cxx | 3 +++ io/io/src/TBufferMergerFile.cxx | 4 ++++ io/io/src/TDirectoryFile.cxx | 3 ++- tree/tree/src/TTree.cxx | 2 ++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/base/inc/TObject.h b/core/base/inc/TObject.h index 58c09609f69..f3646aa4f4c 100644 --- a/core/base/inc/TObject.h +++ b/core/base/inc/TObject.h @@ -86,7 +86,16 @@ public: enum { kSingleKey = BIT(0), ///< write collection with single key kOverwrite = BIT(1), ///< overwrite existing object with same name - kWriteDelete = BIT(2) ///< write object, then delete previous key with same name + kWriteDelete = BIT(2), ///< write object, then delete previous key with same name + + ///< Used to request that the class specific implementation of `TObject::Write` + ///< just prepare the objects to be ready to be written but do not actually write + ///< them into the TBuffer. This is just for example by TBufferMerger to request + ///< that the TTree inside the file calls `TTree::FlushBaskets` (outside of the merging lock) + ///< and TBufferMerger will later ask for the write (inside the merging lock). + ///< To take advantage of this feature the class needs to overload `TObject::Write` + ///< and use this enum value accordingly. (See `TTree::Write` and `TObject::Write`) + kOnlyPrepStep = BIT(3) }; TObject(); diff --git a/core/base/src/TObject.cxx b/core/base/src/TObject.cxx index 8d5cf8ba115..e9e54301d11 100644 --- a/core/base/src/TObject.cxx +++ b/core/base/src/TObject.cxx @@ -771,6 +771,9 @@ void TObject::UseCurrentStyle() Int_t TObject::Write(const char *name, Int_t option, Int_t bufsize) const { + if (R__unlikely(option & kOnlyPrepStep)) + return 0; + TString opt = ""; if (option & kSingleKey) opt += "SingleKey"; if (option & kOverwrite) opt += "OverWrite"; diff --git a/io/io/src/TBufferMergerFile.cxx b/io/io/src/TBufferMergerFile.cxx index 249882bfc67..634fa8a5064 100644 --- a/io/io/src/TBufferMergerFile.cxx +++ b/io/io/src/TBufferMergerFile.cxx @@ -29,6 +29,10 @@ TBufferMergerFile::~TBufferMergerFile() Int_t TBufferMergerFile::Write(const char *name, Int_t opt, Int_t bufsize) { + // Make sure the compression of the basket is done in the unlocked thread and + // not in the locked section. + TMemFile::Write(name, opt | TObject::kOnlyPrepStep, bufsize); + // Instead of Writing the TTree, doing a memcpy, Pushing to the queue // then Reading and then deleting, let's see if we can just merge using // the live TTree. diff --git a/io/io/src/TDirectoryFile.cxx b/io/io/src/TDirectoryFile.cxx index 15ae3e635c1..b4dc18fff3e 100644 --- a/io/io/src/TDirectoryFile.cxx +++ b/io/io/src/TDirectoryFile.cxx @@ -1785,7 +1785,8 @@ Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize) while ((obj=next())) { nbytes += obj->Write(0,opt,bufsize); } - SaveSelf(kTRUE); // force save itself + if (R__likely(!(opt & kOnlyPrepStep))) + SaveSelf(kTRUE); // force save itself return nbytes; } diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 31240e96517..99837711e20 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -9576,6 +9576,8 @@ void TTree::UseCurrentStyle() Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const { FlushBasketsImpl(); + if (R__unlikely(option & kOnlyPrepStep)) + return 0; return TObject::Write(name, option, bufsize); } -- GitLab