* AliHLTRootFilePublisher
[u/mrichter/AliRoot.git] / HLT / BASE / util / AliHLTFilePublisher.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   AliHLTFilePublisher.cxx
20     @author Matthias Richter
21     @date   
22     @brief  HLT file publisher component implementation. */
23
24 // see header file for class documentation
25 // or
26 // refer to README to build package
27 // or
28 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
29
30 #if __GNUC__>= 3
31 using namespace std;
32 #endif
33
34 #include "AliHLTFilePublisher.h"
35 #include "AliLog.h"
36 //#include <TObjString.h>
37 #include <TMath.h>
38 #include <TFile.h>
39
40
41 /** ROOT macro for the implementation of ROOT specific class methods */
42 ClassImp(AliHLTFilePublisher)
43
44 AliHLTFilePublisher::AliHLTFilePublisher()
45   :
46   AliHLTDataSource(),
47   fpCurrent(NULL),
48   fEvents(),
49   fMaxSize(0),
50   fOpenFilesAtStart(false),
51   fOutputDataTypes(),
52   fIsRaw(kTRUE)
53 {
54   // see header file for class documentation
55   // or
56   // refer to README to build package
57   // or
58   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
59
60   // make the lists owners of their objects in order to automatically
61   // de-allocate the objects
62   fEvents.SetOwner();
63 }
64
65 AliHLTFilePublisher::~AliHLTFilePublisher()
66 {
67   // see header file for class documentation
68
69   // file list and file name list are owner of their objects and
70   // delete all the objects
71 }
72
73 const char* AliHLTFilePublisher::GetComponentID()
74 {
75   // see header file for class documentation
76   return "FilePublisher";
77 }
78
79 AliHLTComponentDataType AliHLTFilePublisher::GetOutputDataType()
80 {
81   // see header file for class documentation
82   if (fOutputDataTypes.size()==0) return kAliHLTVoidDataType;
83   else if (fOutputDataTypes.size()==1) return fOutputDataTypes[0];
84   return kAliHLTMultipleDataType;
85 }
86
87 int AliHLTFilePublisher::GetOutputDataTypes(AliHLTComponentDataTypeList& tgtList)
88 {
89   // see header file for class documentation
90   tgtList.assign(fOutputDataTypes.begin(), fOutputDataTypes.end());
91   HLTInfo("%s %p provides %d output data types", GetComponentID(), this, fOutputDataTypes.size());
92   return fOutputDataTypes.size();
93 }
94
95 void AliHLTFilePublisher::GetOutputDataSize( unsigned long& constBase, double& inputMultiplier )
96 {
97   // see header file for class documentation
98   constBase=fMaxSize;
99   inputMultiplier=1.0;
100 }
101
102 AliHLTComponent* AliHLTFilePublisher::Spawn()
103 {
104   // see header file for class documentation
105   return new AliHLTFilePublisher;
106 }
107
108 int AliHLTFilePublisher::DoInit( int argc, const char** argv )
109 {
110   // see header file for class documentation
111
112   //HLTDebug("%d %s", argc, argv[0]);
113   int iResult=0;
114   TString argument="";
115   int bMissingParam=0;
116   int bHaveDatatype=0;
117   int bHaveSpecification=0;
118   fOpenFilesAtStart = false;
119   AliHLTComponentDataType currDataType=kAliHLTVoidDataType;
120   AliHLTUInt32_t          currSpecification=kAliHLTVoidDataSpec;
121   EventFiles*             pCurrEvent=NULL;
122   for (int i=0; i<argc && iResult>=0; i++) {
123     argument=argv[i];
124     if (argument.IsNull()) continue;
125
126     // -datafile
127     if (argument.CompareTo("-datafile")==0) {
128       if ((bMissingParam=(++i>=argc))) break;
129       if (!bHaveDatatype) {
130         HLTWarning("no data type available so far, please set data type and specification before the file name. The first available data type will be set for all files preceding it");
131       }
132       FileDesc* pDesc=new FileDesc(argv[i], currDataType, currSpecification, fIsRaw);
133       if (pDesc) {
134         iResult=InsertFile(pCurrEvent, pDesc);
135       } else {
136         iResult=-ENOMEM;
137       }
138
139       // -datafilelist
140     } else if (argument.CompareTo("-datafilelist")==0) {
141       if ((bMissingParam=(++i>=argc))) break;
142       HLTWarning("-datafilelist option not yet implemented");
143
144       // -datatype
145     } else if (argument.CompareTo("-datatype")==0) {
146       currDataType=kAliHLTVoidDataType;
147       if ((bMissingParam=(++i>=argc))) break;
148       memcpy(&currDataType.fID, argv[i], TMath::Min(kAliHLTComponentDataTypefIDsize, (Int_t)strlen(argv[i])));
149       if ((bMissingParam=(++i>=argc))) break;
150       memcpy(&currDataType.fOrigin, argv[i], TMath::Min(kAliHLTComponentDataTypefOriginSize, (Int_t)strlen(argv[i])));
151
152       // add all different data types to the list
153       AliHLTComponentDataTypeList::iterator element=fOutputDataTypes.begin();
154       while (element!=fOutputDataTypes.end() && *element!=currDataType) element++;
155       if (element==fOutputDataTypes.end()) fOutputDataTypes.push_back(currDataType);
156
157       if (bHaveDatatype==0 && pCurrEvent && iResult>=0) {
158         // this is a workaround to make old tutorials working which contain
159         // the arguments in the wrong sequence
160         TList& files=*pCurrEvent; // type conversion operator defined
161         TObjLink *flnk=files.FirstLink();
162         while (flnk) {
163           FileDesc* pFileDesc=dynamic_cast<FileDesc*>(flnk->GetObject());
164           if (pFileDesc) {
165             pFileDesc->SetDataType(currDataType);
166           }
167           flnk=flnk->Next();
168         }
169       }
170       bHaveDatatype=1;
171
172       // -dataspec
173     } else if (argument.CompareTo("-dataspec")==0) {
174       if ((bMissingParam=(++i>=argc))) break;
175       TString parameter(argv[i]);
176       parameter.Remove(TString::kLeading, ' '); // remove all blanks
177       if (parameter.IsDigit()) {
178         currSpecification=(AliHLTUInt32_t)parameter.Atoi();
179       } else if (parameter.BeginsWith("0x") &&
180                  parameter.Replace(0,2,"",0).IsHex()) {
181         sscanf(parameter.Data(),"%x", &currSpecification);
182       } else {
183         HLTError("wrong parameter for argument %s, number expected", argument.Data());
184         iResult=-EINVAL;
185       }
186       if (bHaveSpecification==0 && pCurrEvent && iResult>=0) {
187         // this is a workaround to make old tutorials working which contain
188         // the arguments in the wrong sequence
189         TList& files=*pCurrEvent; // type conversion operator defined
190         TObjLink *flnk=files.FirstLink();
191         while (flnk) {
192           FileDesc* pFileDesc=dynamic_cast<FileDesc*>(flnk->GetObject());
193           if (pFileDesc) {
194             pFileDesc->SetSpecification(currSpecification);
195           }
196           flnk=flnk->Next();
197         }
198       }
199       bHaveSpecification=1;
200       // -nextevent
201     } else if (argument.CompareTo("-nextevent")==0) {
202       InsertEvent(pCurrEvent);
203     } else if (argument.CompareTo("-open_files_at_start")==0) {
204       fOpenFilesAtStart = true;
205     } else {
206       if ((iResult=ScanArgument(argc-i, &argv[i]))==-EINVAL) {
207         HLTError("unknown argument %s", argument.Data());
208         break;
209       } else if (iResult==-EPROTO) {
210         bMissingParam=1;
211         break;
212       } else if (iResult>=0) {
213         i+=iResult;
214         iResult=0;
215       }
216     }
217   }
218   InsertEvent(pCurrEvent);
219
220   if (bMissingParam) {
221     HLTError("missing parameter for argument %s", argument.Data());
222     iResult=-EINVAL;
223   }
224   if (fEvents.GetSize()==0) {
225     HLTError("the publisher needs at least one file argument");
226     iResult=-EINVAL;
227   }
228   if (iResult>=0) iResult=OpenFiles(fOpenFilesAtStart);
229   if (iResult<0) {
230     fEvents.Clear();
231   }
232   return iResult;
233 }
234
235 int AliHLTFilePublisher::InsertFile(EventFiles* &pCurrEvent, FileDesc* pDesc)
236 {
237   // see header file for class documentation
238   int iResult=0;
239   if (pDesc) {
240     if (pCurrEvent==NULL) {
241       pCurrEvent=new EventFiles;
242       if (pCurrEvent!=NULL) {
243       } else {
244         iResult=-ENOMEM;
245       }
246     }
247     if (iResult>=0 && pCurrEvent!=NULL) {
248       HLTDebug("Insert file %p to event %p", pDesc, pCurrEvent);
249       pCurrEvent->Add(pDesc);
250     }
251   } else {
252     iResult=-EINVAL;
253   }
254   return iResult;
255 }
256
257 int AliHLTFilePublisher::InsertEvent(EventFiles* &pEvent)
258 {
259   // see header file for class documentation
260   int iResult=0;
261   if (pEvent) {
262     HLTDebug("Inserted event %p", pEvent);
263     fEvents.Add(pEvent);
264     pEvent=NULL;
265   }
266   return iResult;
267 }
268
269 int AliHLTFilePublisher::ScanArgument(int argc, const char** argv)
270 {
271   // see header file for class documentation
272
273   // there are no other arguments than the standard ones
274   if (argc==0 && argv==NULL) {
275     // this is just to get rid of the warning "unused parameter"
276   }
277   return -EINVAL;
278 }
279
280 int AliHLTFilePublisher::OpenFiles(bool keepOpen)
281 {
282   // see header file for class documentation
283   int iResult=0;
284   TObjLink *lnk=fEvents.FirstLink();
285   while (lnk && iResult>=0) {
286     EventFiles* pEventDesc=dynamic_cast<EventFiles*>(lnk->GetObject());
287     if (pEventDesc) {
288       HLTDebug("open files for event %p", pEventDesc);
289       TList& files=*pEventDesc; // type conversion operator defined
290       TObjLink *flnk=files.FirstLink();
291       int eventSize=0;
292       while (flnk && iResult>=0) {
293         FileDesc* pFileDesc=dynamic_cast<FileDesc*>(flnk->GetObject());
294         if (pFileDesc) {
295           int size=pFileDesc->OpenFile();
296           if (not keepOpen) pFileDesc->CloseFile();
297           if (size<0) {
298             iResult=size;
299             HLTError("can not open file %s", pFileDesc->GetName());
300           } else {
301             eventSize+=size;
302           }
303         }
304         flnk=flnk->Next();
305       }
306       HLTDebug("event %p size %d", pEventDesc, eventSize);
307       if (fMaxSize<eventSize) fMaxSize=eventSize;
308     } else {
309       HLTError("can not get event descriptor for TObjLink");
310     }
311     lnk = lnk->Next();
312   }
313
314   return iResult;
315 }
316
317 int AliHLTFilePublisher::DoDeinit()
318 {
319   // see header file for class documentation
320   int iResult=0;
321   fEvents.Clear();
322   return iResult;
323 }
324
325 int AliHLTFilePublisher::GetEvent( const AliHLTComponentEventData& /*evtData*/,
326                                    AliHLTComponentTriggerData& /*trigData*/,
327                                    AliHLTUInt8_t* outputPtr, 
328                                    AliHLTUInt32_t& size,
329                                    AliHLTComponentBlockDataList& outputBlocks )
330 {
331   // see header file for class documentation
332
333   // process data events only
334   if (!IsDataEvent()) return 0;
335   AliHLTUInt32_t capacity=size;
336   size=0;
337
338   int iResult=0;
339   TObjLink *lnk=fpCurrent;
340   if (lnk==NULL) lnk=fEvents.FirstLink();
341   fpCurrent=lnk;
342   if (lnk) {
343     EventFiles* pEventDesc=dynamic_cast<EventFiles*>(lnk->GetObject());
344     if (pEventDesc) {
345       HLTDebug("publishing files for event %p", pEventDesc);
346       TList& files=*pEventDesc; // type conversion operator defined
347       TObjLink *flnk=files.FirstLink();
348       int iTotalSize=0;
349       while (flnk && iResult>=0) {
350         FileDesc* pFileDesc=dynamic_cast<FileDesc*>(flnk->GetObject());
351         if (not fOpenFilesAtStart) pFileDesc->OpenFile();
352         TFile* pFile=NULL;
353         if (pFileDesc && (pFile=*pFileDesc)!=NULL) {
354           int iCopy=pFile->GetSize();
355           pFile->Seek(0);
356           if (iCopy+iTotalSize<=(int)capacity) {
357             if (pFile->ReadBuffer((char*)outputPtr+iTotalSize, iCopy)!=0) {
358               // ReadBuffer returns 1 in case of failure and 0 in case of success
359               iResult=-EIO;
360             } else {
361               AliHLTComponentBlockData bd;
362               FillBlockData(bd);
363               bd.fPtr=outputPtr;
364               bd.fOffset=iTotalSize;
365               bd.fSize=iCopy;
366               bd.fDataType=*pFileDesc;      // type conversion operator defined
367               bd.fSpecification=*pFileDesc; // type conversion operator defined
368               outputBlocks.push_back(bd);
369               iTotalSize+=iCopy;
370 //            TString msg;
371 //            msg.Form("get file %s ", pFile->GetName());
372 //            msg+="data type \'%s\'";
373 //            PrintDataTypeContent(bd.fDataType, msg.Data());
374             }
375           } else {
376             // output buffer too small, update GetOutputDataSize for the second trial
377             fMaxSize=iCopy;
378             iResult=-ENOSPC;
379           }
380           if (not fOpenFilesAtStart) pFileDesc->CloseFile();
381         } else {
382           HLTError("no file available");
383           iResult=-EFAULT;
384         }
385         flnk=flnk->Next();
386       }
387       size=iTotalSize;
388     } else {
389       HLTError("can not get event descriptor from list link");
390       iResult=-EFAULT;
391     }
392   } else {
393     iResult=-ENOENT;
394   }
395   if (iResult>=0 && fpCurrent) fpCurrent=fpCurrent->Next();
396
397   return iResult;
398 }
399
400 // AliHLTComponentDataType AliHLTFilePublisher::GetCurrentDataType() const
401 // {
402 //   return kAliHLTVoidDataType;
403 // }
404
405 // AliHLTUInt32_t          AliHLTFilePublisher::GetCurrentSpecification() const
406 // {
407 //   return 0;
408 // }
409
410 AliHLTFilePublisher::FileDesc::FileDesc(const char* name, AliHLTComponentDataType dt, AliHLTUInt32_t spec, Bool_t isRaw)
411   :
412   TObject(),
413   fIsRaw(isRaw),
414   fName(name),
415   fpInstance(NULL),
416   fDataType(dt),
417   fSpecification(spec)
418 {
419   // see header file for class documentation
420   // or
421   // refer to README to build package
422   // or
423   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
424 }
425
426 AliHLTFilePublisher::FileDesc::~FileDesc()
427 {
428   // see header file for class documentation
429   CloseFile();
430 }
431
432 void AliHLTFilePublisher::FileDesc::CloseFile()
433 {
434   // see header file for class documentation
435   if (fpInstance)
436   {
437     // Unfortunately had to use AliLog mechanisms rather that AliHLTLogging because
438     // AliHLTFilePublisher::FileDesc does not derive from AliHLTLogging. It would
439     // become a rather heavy class if it did.
440 #ifdef __DEBUG
441     AliDebugGeneral("AliHLTFilePublisher::FileDesc",
442       2, Form("File %s has been closed.", fName.Data())
443     );
444 #endif
445     delete fpInstance;
446   }
447   fpInstance=NULL;
448 }
449
450 int AliHLTFilePublisher::FileDesc::OpenFile()
451 {
452   // see header file for class documentation
453   int iResult=0;
454   
455   TString fullFN="";
456
457   if ( fIsRaw ) fullFN = fName + "?filetype=raw";
458   else fullFN = fName;
459
460   fpInstance = new TFile(fullFN);
461   if (fpInstance) {
462     if (fpInstance->IsZombie()==0) {
463       iResult=fpInstance->GetSize();
464 #ifdef __DEBUG
465       AliDebugGeneral("AliHLTFilePublisher::FileDesc",
466         2, Form("File %s has been opened.", fName.Data())
467       );
468 #endif
469     } else {
470       iResult=-ENOENT;
471     }
472   }
473   return iResult;
474 }