diff --git a/core/base/inc/TObject.h b/core/base/inc/TObject.h index 58c09609f6989ff7cad62cccf5d8126d5e3277ed..f3646aa4f4c5bc5953aa338eeef533b6f265c45c 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 8d5cf8ba115865afcd7611d0f1a80b53fc9b5440..e9e54301d11098f373f5e5aa3a25fe195a2d207d 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 249882bfc67c2c9c654f7cd4eb4bfaf4fe8fcdcc..634fa8a50645bdff1dc74d1a3ac3b38517361feb 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 15ae3e635c16f6e03b20d82f8f6080fdbd51f3f5..b4dc18fff3ef82f550b9fa0b93141b60372830fd 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 31240e9651789af7efe8a4710d7defac75dad5f8..99837711e203b9c07dbc0315703d87970b203bc8 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); }