bugfix: instead of unloading from the cache, retrieve the latest version and subversi...
[u/mrichter/AliRoot.git] / HLT / rec / AliHLTEsdManagerImplementation.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /** @file   AliHLTEsdManagerImplementation.cxx
20     @author Matthias Richter
21     @date   
22     @brief  Manager for merging and writing of HLT ESDs
23 */
24
25 #include "AliHLTEsdManagerImplementation.h"
26 #include "AliHLTComponent.h"
27 #include "AliESDEvent.h"
28 #include "AliHLTMessage.h"
29 #include "AliESDEvent.h"
30 #include "AliESDtrack.h"
31 #include "TFile.h"
32 #include "TTree.h"
33 #include "TClass.h"
34 #include "TObject.h"
35 #include "TObjectTable.h"
36 #include "TSystem.h"
37 #include "TChain.h"
38 #include "TList.h"
39
40 /** ROOT macro for the implementation of ROOT specific class methods */
41 ClassImp(AliHLTEsdManagerImplementation)
42
43 AliHLTEsdManagerImplementation::AliHLTEsdManagerImplementation()
44   :
45   fESDs()
46   , fDirectory()
47   , fWriteLocal(false)
48 {
49   // see header file for class documentation
50   // or
51   // refer to README to build package
52   // or
53   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
54 }
55
56 AliHLTEsdManagerImplementation::~AliHLTEsdManagerImplementation()
57 {
58   // see header file for class documentation
59   for (unsigned int i=0; i<fESDs.size(); i++) {
60     if (fESDs[i]) {
61       delete fESDs[i];
62     }
63     fESDs[i]=NULL;
64   }
65 }
66
67 int AliHLTEsdManagerImplementation::SetOption(const char* option)
68 {
69   // see header file for class documentation
70   int iResult=0;
71   TString strOptions=option;
72   TObjArray* pTokens=strOptions.Tokenize(" ");
73   if (pTokens) {
74     if (pTokens->GetEntriesFast()>0) {
75       for (int n=0; n<pTokens->GetEntriesFast(); n++) {
76         TString data=((TObjString*)pTokens->At(n))->GetString();
77         if (data.IsNull()) continue;
78
79         if (data.CompareTo("-writelocal")==0) {
80           fWriteLocal=true;
81         } else if (data.Contains("-directory=")) {
82           data.ReplaceAll("-directory=", "");
83           SetDirectory(data.Data());
84         } else {
85           HLTError("unknown argument %s", data.Data());
86           iResult=-EINVAL;
87           break;
88         }
89       }
90     }
91     delete pTokens;
92   }
93   return iResult;
94 }
95
96 AliHLTEsdManagerImplementation::AliHLTEsdListEntry* AliHLTEsdManagerImplementation::Find(AliHLTComponentDataType dt) const
97 {
98   // see header file for class documentation
99   AliHLTEsdListEntry* pEntry=NULL;
100   for (unsigned int i=0; i<fESDs.size(); i++) {
101     if (fESDs[i] && *(fESDs[i])==dt) {
102       pEntry=const_cast<AliHLTEsdListEntry*>(fESDs[i]);
103     }
104   }
105   return pEntry;
106 }
107
108 int AliHLTEsdManagerImplementation::WriteESD(const AliHLTUInt8_t* pBuffer, AliHLTUInt32_t size,
109                                AliHLTComponentDataType dt, AliESDEvent* tgtesd, int eventno)
110 {
111   // see header file for class documentation
112   if (!pBuffer && size<=0) return -EINVAL;
113   int iResult=0;
114   AliHLTUInt32_t firstWord=*((AliHLTUInt32_t*)pBuffer);
115   if (firstWord==size-sizeof(AliHLTUInt32_t)) {
116     HLTDebug("create object from block %s size %d", AliHLTComponent::DataType2Text(dt).c_str(), size);
117     AliHLTMessage msg(const_cast<AliHLTUInt8_t*>(pBuffer), size);
118     TClass* objclass=msg.GetClass();
119     TObject* pObj=msg.ReadObject(objclass);
120     if (pObj && objclass) {
121       HLTDebug("object %p type %s created", pObj, objclass->GetName());
122       AliESDEvent* pESD=dynamic_cast<AliESDEvent*>(pObj);
123       TTree* pTree=NULL;
124       if (!pESD) {
125         pTree=dynamic_cast<TTree*>(pObj);
126         if (pTree) {
127           pESD=new AliESDEvent;
128           pESD->CreateStdContent();
129           if (pTree->GetEntries()>0) {
130             if (pTree->GetEntries()>1) {
131               HLTWarning("only one entry allowed for ESD embedded into tree, data block %s contains tree with %d entires, taking first entry",
132                          AliHLTComponent::DataType2Text(dt).c_str(), pTree->GetEntries());
133             }
134             pESD->ReadFromTree(pTree);
135             pTree->GetEvent(0);
136           }
137         } else {
138           HLTWarning("tree of data block %s has no events, skipping data block", AliHLTComponent::DataType2Text(dt).c_str());
139         }
140       }
141       if (pESD) {
142         AliHLTEsdListEntry* entry=Find(dt);
143         if (!entry) {
144           if ((entry=new AliHLTEsdListEntry(dt))!=NULL) {
145             if (!fDirectory.IsNull()) {
146               entry->SetDirectory(fDirectory);
147             }
148             fESDs.push_back(entry);
149           }
150         }
151         if (entry) {
152           if (tgtesd) {
153 #if !defined(HAVE_NOT_ESD_COPY)
154             Merge(tgtesd, pESD);
155 #else //HAVE_NOT_ESD_COPY
156             static bool warningPrinted=false;
157             if (!warningPrinted) {
158               HLTWarning("old version of AliESDEvent does not provide assignment operator, skip merging to global hltEsd");
159             }
160             warningPrinted=true;
161 #endif //HAVE_NOT_ESD_COPY
162           }
163
164           // Matthias 2009-06-06: writing of individual ESD files for the different origins was a
165           // first attempt when functionality was missing in the AliRoot framework and remained as
166           // debugging feature. ESD merging is now implemented and data written to the hltEsd, so
167           // the feature is now disabled by default because it causes increasing memory consumption.
168           // Presumably not because of a memory leak but the way the internal TTree is used and kept
169           // in memory.
170           // Writing of local files can be optionally switched on as e.g. by the EsdCollector component.
171           if (fWriteLocal) entry->WriteESD(pESD, eventno);
172         } else {
173           HLTError("internal mismatch, can not create list entry");
174           iResult=-ENOMEM;
175         }
176       } else {
177         HLTWarning("data block %s is not of class type AliESDEvent, ignoring ...", AliHLTComponent::DataType2Text(dt).c_str());
178       }
179       if (pTree) {
180         // ESD has been created and must be cleaned up
181         pESD->Reset();
182         delete pESD;
183         pESD=NULL;
184       }
185       delete pObj;
186       pObj=NULL;
187     } else {
188     }
189   }
190   return iResult;
191 }
192
193 int AliHLTEsdManagerImplementation::PadESDs(int eventno)
194 {
195   // see header file for class documentation
196   int iResult=0;
197   for (unsigned int i=0; i<fESDs.size(); i++) {
198     if (fESDs[i]) {
199       int res=fESDs[i]->WriteESD(NULL, eventno);
200       if (res<0 && iResult>=0) iResult=res;
201     }
202   }
203   return iResult;
204 }
205
206 void AliHLTEsdManagerImplementation::SetDirectory(const char* directory)
207 {
208   // see header file for class documentation
209   if (!directory) return;
210   fDirectory=directory;
211   for (unsigned int i=0; i<fESDs.size(); i++) {
212     if (fESDs[i]) {
213       fESDs[i]->SetDirectory(directory);
214     }
215   }
216 }
217
218 TString AliHLTEsdManagerImplementation::GetFileNames(AliHLTComponentDataType dt) const
219 {
220   TString result;
221   for (unsigned int i=0; i<fESDs.size(); i++) {
222     if (fESDs[i] && *(fESDs[i])==dt) {
223       if (!result.IsNull()) result+=" ";
224       result+=fESDs[i]->GetFileName();
225     }
226   }
227   return result;
228 }
229
230 TTree* AliHLTEsdManagerImplementation::EmbedIntoTree(AliESDEvent* pESD, const char* name, const char* title)
231 {
232   // see header file for class documentation
233   int iResult=0;
234   TTree* pTree=new TTree(name, title);
235   if (pTree) {
236     pESD->WriteToTree(pTree);
237     pTree->Fill();
238     pTree->GetUserInfo()->Add(pESD);
239   } else {
240     iResult=-ENOMEM;
241   }
242
243   if (iResult<0) {
244     pTree->GetUserInfo()->Clear();
245     delete pTree;
246   }
247
248   return pTree;
249 }
250
251 AliHLTEsdManagerImplementation::AliHLTEsdListEntry::AliHLTEsdListEntry(AliHLTComponentDataType dt)
252   :
253   fName(),
254   fDirectory(),
255   fDt(dt),
256   fpFile(NULL),
257   fpTree(NULL),
258   fpEsd(NULL),
259   fPrefix()
260 {
261   // see header file for class documentation
262 }
263
264 AliHLTEsdManagerImplementation::AliHLTEsdListEntry::~AliHLTEsdListEntry()
265 {
266   // see header file for class documentation
267   if (fpEsd) delete fpEsd;
268   fpEsd=NULL;
269
270   if (fpTree) delete fpTree;
271   fpTree=NULL;
272
273   if (fpFile) {
274     fpFile->Close();
275     delete fpFile;
276   }
277   fpFile=NULL;
278 }
279
280 bool AliHLTEsdManagerImplementation::AliHLTEsdListEntry::operator==(AliHLTComponentDataType dt) const
281 {
282   // see header file for class documentation
283   return fDt==dt;
284 }
285
286 int AliHLTEsdManagerImplementation::AliHLTEsdListEntry::WriteESD(AliESDEvent* pSrcESD, int eventno)
287 {
288   // see header file for class documentation
289   int iResult=0;
290
291 #ifndef HAVE_NOT_ESD_COPY
292   if (fName.IsNull()) {
293     // this is the first event, create the file name
294     fName="";
295     if (!fDirectory.IsNull()) {
296       fName+=fDirectory; fName+="/";
297     }
298     fName+="Ali"; fName+=GetPrefix();
299     if (fDt!=kAliHLTDataTypeESDObject &&
300         fDt!=kAliHLTDataTypeESDTree) {
301
302       HLTWarning("non-standard ESD type %s", AliHLTComponent::DataType2Text(fDt).c_str());
303       TString id;
304       id.Insert(0, fDt.fID, kAliHLTComponentDataTypefIDsize);
305       id.Remove(TString::kTrailing, ' ');
306       id.ToUpper();
307       fName+="_"; fName+=id; fName+=".root";
308     } else {
309       fName+="ESDs.root";
310     }
311
312     fpFile=new TFile(fName, "RECREATE");
313     fpTree=new TTree("esdTree", "Tree with HLT ESD objects");
314     fpTree->SetDirectory(0);
315     fpEsd=new AliESDEvent;
316     if (fpEsd) {
317       fpEsd->CreateStdContent();
318       *fpEsd=*pSrcESD;
319       if (fpTree) {
320         fpEsd->WriteToTree(fpTree);
321       }
322     }
323   }
324
325   if (fpFile && fpTree && fpEsd) {
326     // synchronize and add empty events
327     fpEsd->Reset();
328     int nofCurrentEvents=fpTree->GetEntries();
329     if (nofCurrentEvents<eventno) {
330       iResult=1; // indicate tree to be written
331       HLTDebug("adding %d empty events to file %s", eventno-nofCurrentEvents, fName.Data());
332       for (int i=nofCurrentEvents; i<eventno; i++) {
333         fpTree->Fill();
334       }
335     }
336
337     if (iResult>=0 && pSrcESD) {
338       int nofObjects=fpEsd->GetList()->GetEntries();
339       *fpEsd=*pSrcESD;
340       if (nofObjects!=fpEsd->GetList()->GetEntries()) {
341         // The source ESD contains object not present in the target ESD
342         // before. Those objects will not be written to the tree since
343         // the branch layout has been created earlier.
344         // Create new tree with the additional branches, copy the entries
345         // of the current tree into the new tree, and continue.
346         TTree* pNewTree=new TTree("esdTree", "Tree with HLT ESD objects");
347         pNewTree->SetDirectory(0);
348         AliESDEvent* readESD=new AliESDEvent;
349         readESD->CreateStdContent();
350         readESD->ReadFromTree(fpTree);
351         fpEsd->Reset();
352         fpEsd->WriteToTree(pNewTree);
353         HLTDebug("cloning tree with %d entries", fpTree->GetEntries());
354         for (int event=0; event<fpTree->GetEntries(); event++) {
355           fpTree->GetEntry(event);
356           *fpEsd=*readESD;
357           pNewTree->Fill();
358           fpEsd->Reset();
359         }
360         fpFile->Close();
361         delete fpFile;
362         delete readESD;
363         delete fpTree;
364         fpFile=new TFile(fName, "RECREATE");
365         fpTree=pNewTree;
366         *fpEsd=*pSrcESD;
367         HLTDebug("new ESD with %d objects", fpEsd->GetList()->GetEntries());
368       }
369       fpTree->Fill();
370       iResult=1; // indicate tree to be written
371     }
372
373     if (iResult>0) {
374       fpFile->cd();
375       fpTree->GetUserInfo()->Add(fpEsd);
376       fpTree->Write(fpTree->GetName(),TObject::kOverwrite);
377       fpTree->GetUserInfo()->Clear();
378     }
379   }
380 #else //HAVE_NOT_ESD_COPY
381   // this is the old workaround, necessary for older AliRoot versions
382   // version<=v4-12-Release
383
384   // we need to copy the ESD, I did not find an approptiate
385   // method, the workaround is to save the ESD in a temporary
386   // tree, read the content back into the ESD structure
387   // used for filling.
388   // Unfortunately the following code crashes at the second event.
389   // The expert on the ESD (Christian Klein Boesig) does not have
390   // a solution either. It seems to be a problem in ROOT.
391   //  TTree* dummy=new TTree("dummy","dummy");
392   //  dummy->SetDirectory(0);
393   //  pESD->WriteToTree(dummy);
394   //  dummy->Fill();
395   //  dummy->GetUserInfo()->Add(pESD);
396   //  fpEsd->ReadFromTree(dummy);
397   //  dummy->GetEvent(0);
398   //  fpEsd->WriteToTree(fpTree);
399   //  fpTree->Fill();
400   //  dummy->GetUserInfo()->Clear();
401   //  delete dummy;
402   //
403   // The only way is via TChain, which is working on files only at the
404   // time of writing.
405   // We use temporary files for the new event to be copied into the
406   // existing tree.
407   //
408   if (fName.IsNull()) {
409     // this is the first event, create the file on disk and write ESD
410     TString origin;
411     origin.Insert(0, fDt.fOrigin, kAliHLTComponentDataTypefOriginSize);
412     origin.Remove(TString::kTrailing, ' ');
413     origin.ToUpper();
414     fName="";
415     if (!fDirectory.IsNull()) {
416       fName+=fDirectory; fName+="/";
417     }
418     fName+="AliHLT"; fName+=origin;
419     if (fDt!=kAliHLTDataTypeESDObject &&
420         fDt!=kAliHLTDataTypeESDTree) {
421
422       HLTWarning("non-standard ESD type %s", AliHLTComponent::DataType2Text(fDt).c_str());
423       TString id;
424       id.Insert(0, fDt.fID, kAliHLTComponentDataTypefIDsize);
425       id.Remove(TString::kTrailing, ' ');
426       id.ToUpper();
427       fName+="_"; fName+=id; fName+=".root";
428     } else {
429       fName+="ESDs.root";
430     }
431
432     if (!gSystem->AccessPathName(fName)) {
433       // file exists, delete
434       TString shellcmd="rm -f ";
435       shellcmd+=fName;
436       gSystem->Exec(shellcmd);
437     }
438   }
439
440   TChain chain("esdTree");
441   TList cleanup;
442   cleanup.SetOwner();
443
444   int nofCurrentEvents=0;
445   if (iResult>=0) {
446     if (!gSystem->AccessPathName(fName)) {
447       // these are the other events, use the target file and temporary files to merge
448       // with TChain
449       chain.Add(fName);
450
451       if (eventno>=0) {
452         TFile file(fName);
453         if (!file.IsZombie()) {
454           TTree* pSrcTree;
455           file.GetObject("esdTree", pSrcTree);
456           if (pSrcTree) {
457             nofCurrentEvents=pSrcTree->GetEntries();
458           }
459           file.Close();
460         }
461       }
462     }
463   }
464
465   // synchronize and add empty events
466   if (nofCurrentEvents<eventno) {
467     iResult=1; // indicate files to merge
468     TTree* pTgtTree=new TTree("esdTree", "Tree with HLT ESD objects");
469     if (pTgtTree) {
470       pTgtTree->SetDirectory(0);
471       AliESDEvent* pTmpESD=new AliESDEvent;
472       if (pTmpESD) {
473         TString tmpfilename;
474         FILE* pTmpFile=gSystem->TempFileName(tmpfilename);
475         if (pTmpFile) {
476           fclose(pTmpFile);
477           pTmpFile=NULL;
478           cleanup.Add(new TObjString(tmpfilename));
479           TFile emptyevents(tmpfilename, "RECREATE");
480           if (!emptyevents.IsZombie()) {
481             pTmpESD->CreateStdContent();
482             pTmpESD->WriteToTree(pTgtTree);
483             HLTDebug("adding %d empty events to file %s", eventno-nofCurrentEvents, fName.Data());
484             for (int i=nofCurrentEvents; i<eventno; i++) {
485               pTgtTree->Fill();
486             }
487             pTgtTree->GetUserInfo()->Add(pTmpESD);
488             emptyevents.cd();
489             pTgtTree->Write();
490             emptyevents.Close();
491             chain.Add(tmpfilename);
492             pTgtTree->GetUserInfo()->Clear();
493           }
494         }
495         delete pTmpESD;
496       } else {
497         iResult=-ENOMEM;
498       }
499       delete pTgtTree;
500     } else {
501       iResult=-ENOMEM;
502     }
503   }
504
505   if (iResult>=0 && pSrcESD) {
506     // add the new event to the chain
507     iResult=1; // indicate files to merge
508     TString tmpfilename=WriteTempFile(pSrcESD);
509     if (!tmpfilename.IsNull()) {
510       chain.Add(tmpfilename);
511       cleanup.Add(new TObjString(tmpfilename));
512     }
513   }
514
515   if (iResult>0) {
516     // build temporary file name for chain output
517     TString tgtName;
518     FILE* pTmpFile=gSystem->TempFileName(tgtName);
519     if (pTmpFile) {
520       fclose(pTmpFile);
521       pTmpFile=NULL;
522
523       // there have been problems with the memory consumption when using
524       // TChain::Merge
525       // but using a separate loop soemtimes crashes in AliESDEvent::ReadFromTree
526       // since this is for backward compatiblity only, we take the TChain::Merge
527       chain.Merge(tgtName);
528 //       TFile tgtFile(tgtName, "RECREATE");
529 //       TTree* pTgtTree=new TTree("esdTree", "Tree with HLT ESD objects");
530 //       AliESDEvent* pTgtESD=new AliESDEvent;
531 //       if (pTgtTree && pTgtESD) {
532 //      pTgtESD->ReadFromTree(&chain);
533 //      pTgtESD->WriteToTree(pTgtTree);
534
535 //      int nofEvents=chain.GetEntries();
536 //      for (int event=0; event<nofEvents; event++) {
537 //        chain.GetEntry(event);
538 //        pTgtTree->Fill();
539 //      }
540
541 //      pTgtTree->GetUserInfo()->Add(pTgtESD);
542 //      tgtFile.cd();
543 //      pTgtTree->Write();
544 //      pTgtTree->GetUserInfo()->Clear();
545 //       } else {
546 //      iResult=-ENOMEM;
547 //       }
548
549 //       if (pTgtTree) delete pTgtTree;
550 //       if (pTgtESD) delete pTgtESD;
551 //       tgtFile.Close();
552
553       // rename the merged file to the original file
554       TString shellcmd="mv ";
555       shellcmd+=tgtName + " " + fName;
556       if (gSystem->Exec(shellcmd)==0) {
557         HLTDebug("renaming %s to %s", tgtName.Data(), fName.Data());
558       } else {
559         HLTError("can not rename temporary file %s to %s", tgtName.Data(), fName.Data());
560       }
561     } else {
562       HLTError("can not get temporary file name from system");
563       iResult=-EBADF;
564     }
565   }
566
567   // delete temporary files
568   // the list objects are cleaned up by the TList destructor as the
569   // list is owner
570   TIter entry(&cleanup);
571   while (TObject* pObj=entry.Next()) {
572     if (dynamic_cast<TObjString*>(pObj)) {
573       TString shellcmd="rm -f ";
574       shellcmd+=(dynamic_cast<TObjString*>(pObj))->GetString();
575       gSystem->Exec(shellcmd);
576     }
577   }
578 #endif //HAVE_NOT_ESD_COPY
579
580   return iResult;
581 }
582
583 TString AliHLTEsdManagerImplementation::AliHLTEsdListEntry::WriteTempFile(AliESDEvent* pESD) const
584 {
585   // see header file for class documentation
586   int iResult=0;
587   TString tmpfilename;
588   FILE* pTmpFile=gSystem->TempFileName(tmpfilename);
589   if (pTmpFile) {
590     fclose(pTmpFile);
591     pTmpFile=NULL;
592
593     TFile file(tmpfilename, "RECREATE");
594     if (!file.IsZombie()) {
595       TTree* pTree=AliHLTEsdManagerImplementation::EmbedIntoTree(pESD);
596       if (pTree) {
597         file.cd();
598         if (pTree->Write()>0) {
599         } else {
600           HLTError("can not write esd tree to temporary file %s", tmpfilename.Data());
601         }
602
603         pTree->GetUserInfo()->Clear();
604         delete pTree;
605       } else {
606         iResult=-ENOMEM;
607       }
608       file.Close();
609     } else {
610       HLTError("can not open file %s", tmpfilename.Data());
611       iResult=-EBADF;
612     }
613   } else {
614     HLTError("can not get temporary file name from system");
615     iResult=-EBADF;
616   }
617
618   if (iResult<0) {
619     if (gSystem->AccessPathName(tmpfilename)==0) {
620       TString shellcmd="rm -f ";
621       shellcmd+=tmpfilename;
622       gSystem->Exec(shellcmd);
623     }
624     tmpfilename="";
625   }
626   return tmpfilename;
627 }
628
629 void AliHLTEsdManagerImplementation::AliHLTEsdListEntry::SetDirectory(const char* directory)
630 {
631   // see header file for class documentation
632   if (!directory) return;
633   if (!fName.IsNull()) {
634     HLTWarning("ESD entry already in writing mode (%s), ignoring directory", fName.Data());
635     return;
636   }
637   fDirectory=directory;
638 }
639
640 void AliHLTEsdManagerImplementation::AliHLTEsdListEntry::Delete()
641 {
642   // see header file for class documentation
643   if (fName.IsNull()) return;
644   if (gSystem->AccessPathName(fName)!=0) return;
645
646   TString shellcmd="rm -f ";
647   shellcmd+=fName;
648   gSystem->Exec(shellcmd);
649   fName="";
650 }
651
652 const char* AliHLTEsdManagerImplementation::AliHLTEsdListEntry::GetFileName() const
653 {
654   // see header file for class documentation
655   return fName.Data();
656 }
657
658 const char* AliHLTEsdManagerImplementation::AliHLTEsdListEntry::GetPrefix()
659 {
660   // see header file for class documentation
661   if (fPrefix.IsNull()) {
662     fPrefix.Insert(0, fDt.fOrigin, kAliHLTComponentDataTypefOriginSize);
663     fPrefix.Remove(TString::kTrailing, ' ');
664     fPrefix.ToUpper();
665     if (!fPrefix.Contains("HLT")) {
666       fPrefix.Insert(0, "HLT");
667     }
668   }
669   return fPrefix.Data();
670 }
671
672 int AliHLTEsdManagerImplementation::Merge(AliESDEvent* pTgt, AliESDEvent* pSrc) const
673 {
674   // see header file for class documentation
675   int iResult=0;
676   if (!pTgt || !pSrc) return -EINVAL;
677
678   TIter next(pSrc->GetList());
679   TObject* pSrcObject=NULL;
680   static int warningCount=0;
681   while ((pSrcObject=next())) {
682     if(!pSrcObject->InheritsFrom("TCollection")){
683       // simple objects
684       TString name=pSrcObject->GetName();
685       if(pSrcObject->InheritsFrom("AliHLTTriggerDecision")){
686         //pSrcObject->Print();
687         TObject* pTgtObject=pTgt->FindListObject(name);
688         if (pTgtObject) {
689           pSrcObject->Copy(*pTgtObject);
690         } else {
691           pTgt->AddObject(pSrcObject->Clone());
692         }
693       } else {
694         // TODO: implement the handling of other objects, some kind of mapping
695       }
696     } else if(pSrcObject->InheritsFrom("TClonesArray")){
697       TClonesArray* pTClA=dynamic_cast<TClonesArray*>(pSrcObject);
698       if (pTClA!=NULL && pTClA->GetEntriesFast()>0) {
699         TString name=pTClA->GetName();
700         TObject* pTgtObject=pTgt->GetList()->FindObject(name);
701         TClonesArray* pTgtArray=NULL;
702         if (pTgtObject!=NULL && pTgtObject->InheritsFrom("TClonesArray")){
703           pTgtArray=dynamic_cast<TClonesArray*>(pTgtObject);
704           if (pTgtArray) {
705             TString classType=pTClA->Class()->GetName();
706             if (classType.CompareTo(pTgtArray->Class()->GetName())==0) {
707               if (pTgtArray->GetEntries()==0) {
708                 pTgtArray->ExpandCreate(pTClA->GetEntries());
709                 for(int i=0; i<pTClA->GetEntriesFast(); ++i){
710                   (*pTClA)[i]->Copy(*((*pTgtArray)[i]));
711                 }
712               } else {
713                 if (warningCount++<10) {
714                   HLTWarning("TClonesArray \"%s\"  in target ESD %p is already filled with %d entries",
715                              name.Data(), pTgt, pTgtArray->GetEntries());
716                 }
717                 iResult=-EBUSY;
718               }
719             } else {
720               if (warningCount++<10) {
721                 HLTWarning("TClonesArray \"%s\" exists in target ESD %p, but describes incompatible class type %s instead of %s",
722                            name.Data(), pTgt, pTgtArray->GetClass()->GetName(), pTClA->GetClass()->GetName());
723               }
724               iResult=-EBUSY;
725             }
726           } else {
727             if (warningCount++<10) {
728               HLTError("internal error: dynamic cast failed for object %s %p", pTgtObject->GetName(), pTgtObject);
729             }
730             iResult=-EBUSY;
731           }
732         } else if (pTgtObject) {
733           if (warningCount++<10) {
734             HLTWarning("object \"%s\" does already exist in target ESD %p, but is %s rather than TClonesArray"
735                        " skipping data",
736                        name.Data(), pTgt, pTgtObject->Class()->GetName());
737           }
738           iResult=-EBUSY;
739         } else {
740           if (warningCount++<10) {
741             HLTWarning("object \"%s\" does not exist in target ESD %p, data can not be copied because it will be lost when filling the tree",
742                        name.Data(), pTgt);
743           }
744           iResult=-ENOENT;
745         }
746       }
747     }
748   }
749   return iResult;
750 }