10#include "GaudiKernel/IAlgManager.h"
22#include "TServerSocket.h"
33 if (!cl)
return nullptr;
35 void*& map_ptr = cache[cl];
49 std::unordered_map<TClass*, void*> *
m_cache;
51 ParallelFileMerger(
const char *filename, std::unordered_map<TClass*, void*>* cache,
int compress = ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault
54 fMerger.OutputFile(filename,
"RECREATE", compress);
75 const TObjArray* fromBranches = fromTree->GetListOfBranches();
76 const TObjArray* toBranches = toTree->GetListOfBranches();
77 int nBranches = fromBranches->GetEntriesFast();
78 int nEntries = toTree->GetEntries();
79 for (
int k = 0; k < nBranches; ++k) {
80 TBranch* branch =
static_cast<TBranch*
>(fromBranches->UncheckedAt(k));
81 if (toBranches->FindObject(branch->GetName()) ==
nullptr) {
82 TBranch* newBranch =
nullptr;
83 TClass* cl = TClass::GetClass(branch->GetClassName());
85 newBranch = toTree->Branch(branch->GetName(), branch->GetClassName(),
nullptr, branch->GetBasketSize(), branch->GetSplitLevel());
87 newBranch->SetAddress(objectAddress);
89 TObjArray* outLeaves = branch->GetListOfLeaves();
90 TLeaf* leaf =
static_cast<TLeaf*
>(outLeaves->UncheckedAt(0));
91 std::string_view attr = leaf->GetName();
92 std::string_view
type = leaf->GetTypeName();
93 std::string branchSpec(attr);
95 if (
type ==
"Int_t") branchSpec +=
'I';
96 else if (
type ==
"Short_t") branchSpec +=
'S';
97 else if (
type ==
"Long_t") branchSpec +=
'L';
98 else if (
type ==
"UInt_t") branchSpec +=
'i';
99 else if (
type ==
"UShort_t") branchSpec+=
's';
100 else if (
type ==
"ULong_t") branchSpec +=
'l';
101 else if (
type ==
"Float_t") branchSpec +=
'F';
102 else if (
type ==
"Double_t") branchSpec+=
'D';
103 else if (
type ==
"Char_t") branchSpec +=
'B';
104 else if (
type ==
"UChar_t") branchSpec +=
'b';
105 else if (
type ==
"Bool_t") branchSpec +=
'O';
106 else { branchSpec +=
type; }
107 newBranch = toTree->Branch(branch->GetName(),
static_cast<void*
>(
nullptr), branchSpec.c_str(), 2048);
109 for (
int m = 0; m < nEntries; ++m) {
110 newBranch->BackFill();
121 TIter nextKey(input->GetListOfKeys());
122 while (TKey* key =
static_cast<TKey*
>(nextKey())) {
123 TClass* cl = TClass::GetClass(key->GetClassName());
124 if (cl !=
nullptr && cl->InheritsFrom(
"TTree")) {
125 TTree* outCollTree =
static_cast<TTree*
>(
fMerger.GetOutputFile()->
Get(key->GetName()));
126 TTree* inCollTree =
static_cast<TTree*
>(input->Get(key->GetName()));
127 if (inCollTree !=
nullptr && outCollTree !=
nullptr) {
136 Bool_t result =
fMerger.PartialMerge(TFileMerger::kIncremental | TFileMerger::kResetable | TFileMerger::kKeepCompression);
137 nextKey = input->GetListOfKeys();
138 while (TKey* key =
static_cast<TKey*
>(nextKey())) {
139 TClass* cl = TClass::GetClass(key->GetClassName());
140 if (cl !=
nullptr && 0 != cl->GetResetAfterMerge()) {
142 input->GetListOfKeys()->Remove(key);
152 : base_class(name, pSvcLocator)
161 IProperty* propertyServer =
dynamic_cast<IProperty*
>(
m_cnvSvc.get());
162 if (propertyServer ==
nullptr) {
163 ATH_MSG_ERROR(
"Unable to cast conversion service to IProperty");
164 return StatusCode::FAILURE;
166 std::string propertyName =
"ParallelCompression";
167 bool parallelCompression(
false);
168 BooleanProperty parallelCompressionProp(propertyName, parallelCompression);
169 if (propertyServer->getProperty(¶llelCompressionProp).isFailure()) {
170 ATH_MSG_INFO(
"Conversion service does not have ParallelCompression property");
171 }
else if (parallelCompressionProp.value()) {
172 propertyName =
"StreamPortString";
173 std::string streamPortString(
"");
174 StringProperty streamPortStringProp(propertyName, streamPortString);
175 if (propertyServer->getProperty(&streamPortStringProp).isFailure()) {
176 ATH_MSG_INFO(
"Conversion service does not have StreamPortString property, using default TCP port: 0");
177 streamPortStringProp.setValue(
"?pmerge=localhost:0");
179 const std::string& pmergeProperty = streamPortStringProp.value();
180 const std::size_t eqPos = pmergeProperty.find(
'=');
181 if (eqPos == std::string::npos) {
182 ATH_MSG_FATAL(
"Malformed StreamPortString property (missing '='): " << pmergeProperty);
183 return StatusCode::FAILURE;
185 const std::string pmergePrefix = pmergeProperty.substr(0, eqPos + 1);
186 const std::string pmergeArg = pmergeProperty.substr(eqPos + 1);
187 if (pmergeArg.empty()) {
188 ATH_MSG_FATAL(
"Malformed StreamPortString property (empty value after '='): " << pmergeProperty);
189 return StatusCode::FAILURE;
191 std::string newStreamPortString;
195 if (pmergeArg.find(
':') == std::string::npos) {
196 TString socketPath = pmergeArg.c_str();
197 FILE* reservedFile = gSystem->TempFileName(socketPath);
198 if (reservedFile ==
nullptr) {
199 ATH_MSG_FATAL(
"Could not create temporary file for UNIX domain socket: " << pmergeArg);
200 return StatusCode::FAILURE;
205 std::fclose(reservedFile);
209 return StatusCode::FAILURE;
212 ATH_MSG_DEBUG(
"Successfully created ROOT TServerSocket (UNIX domain socket) and added it to TMonitor: ready to accept connections, " <<
m_socketPath);
214 const std::size_t colonPos = pmergeArg.find(
':');
215 int streamPort = atoi(pmergeArg.substr(colonPos + 1).c_str());
216 m_rootServerSocket =
new TServerSocket(streamPort, (streamPort == 0 ?
false :
true), 100, -1, ESocketBindOption::kInaddrLoopback);
218 ATH_MSG_FATAL(
"Could not create ROOT TServerSocket: " << streamPort);
219 return StatusCode::FAILURE;
222 newStreamPortString = pmergePrefix + pmergeArg.substr(0, colonPos + 1) + std::to_string(streamPort);
223 ATH_MSG_DEBUG(
"Successfully created ROOT TServerSocket and added it to TMonitor: ready to accept connections, " << streamPort);
225 if (propertyServer->setProperty(propertyName,newStreamPortString).isFailure()) {
226 ATH_MSG_FATAL(
"Could not set Conversion Service property " << propertyName <<
" from " << streamPortString <<
" to " << newStreamPortString);
227 return StatusCode::FAILURE;
234 const IAlgManager* algMgr = Gaudi::svcLocator()->as<IAlgManager>();
235 for (
const auto& alg : algMgr->getAlgorithms()) {
236 if (alg->type() ==
"AthenaOutputStream") {
237 ATH_MSG_DEBUG(
"Counting " << alg->name() <<
" as an output stream algorithm");
242 ATH_MSG_WARNING(
"No output stream algorithm found, setting the number of streams to 1");
248 return StatusCode::SUCCESS;
253 StatusCode
sc =
m_cnvSvc->commitOutput(
"",
false);
258 while (
sc.isSuccess() ||
sc.isRecoverable() || anyActiveClients) {
259 if (
sc.isSuccess()) {
263 if (socket !=
nullptr && socket != (TSocket*)-1) {
265 if (socket->IsA() == TServerSocket::Class()) {
266 TSocket* client = (
static_cast<TServerSocket*
>(socket))->
Accept();
276 client->Close(
"force");
280 TMessage* message =
nullptr;
281 Int_t result = socket->Recv(message);
283 ATH_MSG_ERROR(
"ROOT Monitor got an error while receiving the message from the socket: " << result);
284 return StatusCode::FAILURE;
286 if (message ==
nullptr) {
287 ATH_MSG_WARNING(
"ROOT Monitor got no message from socket: " << socket);
288 }
else if (message->What() == kMESS_STRING) {
290 message->ReadString(
str, 64);
293 ATH_MSG_DEBUG(
"ROOT Monitor client: " << socket <<
", " << socket->GetBytesRecv() <<
", " << socket->GetBytesSent());
298 anyActiveClients =
false;
299 ATH_MSG_INFO(
"ROOT Monitor: No more active clients...");
301 motherClient =
false;
302 ATH_MSG_INFO(
"ROOT Monitor: Mother process is done...");
303 if (!
m_cnvSvc->commitCatalog().isSuccess()) {
305 return StatusCode::FAILURE;
309 }
else if (message->What() == kMESS_ANY) {
313 message->ReadInt(clientId);
314 message->ReadTString(filename);
315 message->ReadLong64(
length);
316 ATH_MSG_DEBUG(
"ROOT Monitor client: " << socket <<
", " << clientId <<
": " << filename <<
", " <<
length);
317 std::unique_ptr<TMemFile> transient(
new TMemFile(filename, message->Buffer() + message->Length(),
length,
"UPDATE"));
318 message->SetBufferOffset(message->Length() +
length);
323 ATH_MSG_INFO(
"ROOT Monitor ParallelFileMerger: " << info <<
", for: " << filename);
325 info->MergeTrees(transient.get());
327 delete message; message =
nullptr;
334 if (
sc.isSuccess() ||
sc.isRecoverable()) {
336 if (
sc.isFailure() && !
sc.isRecoverable()) {
339 ATH_MSG_INFO(
"ROOT Monitor: No clients, terminating the loop...");
340 anyActiveClients =
false;
346 return StatusCode::SUCCESS;
351 return StatusCode::SUCCESS;
364 cl->Destructor(ptr,
false);
368 return StatusCode::SUCCESS;
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
void * getCachedObjectAddress(TClass *cl, std::unordered_map< TClass *, void * > &cache)
This file contains the class definition for the AthenaRootSharedWriterSvc class.
Templated class containing a cut, name of cut and description of cut(optional) Typically,...
virtual StatusCode stop() override
std::unordered_map< TClass *, void * > m_cachedObjects
virtual StatusCode finalize() override
virtual StatusCode share(int numClients=0, bool motherClient=false) override
virtual StatusCode initialize() override
Gaudi Service Interface method implementations:
AthenaRootSharedWriterSvc(const std::string &name, ISvcLocator *pSvcLocator)
Standard Service Constructor.
std::string m_socketPath
Path of the UNIX domain socket file, if used, removed on finalize.
TServerSocket * m_rootServerSocket
ServiceHandle< AthenaPoolSharedIOCnvSvc > m_cnvSvc
T * Get(TFile &f, const std::string &n, const std::string &dir="", const chainmap_t *chainmap=0, std::vector< std::string > *saved=0)
get a histogram given a path, and an optional initial directory if histogram is not found,...
DataModel_detail::iterator< DVL > remove(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, const T &value)
Specialization of remove for DataVector/List.
const char * GetName() const
bool syncBranches(TTree *fromTree, TTree *toTree)
ParallelFileMerger(const char *filename, std::unordered_map< TClass *, void * > *cache, int compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault)
std::unordered_map< TClass *, void * > * m_cache
Bool_t MergeTrees(TFile *input)