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