]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/BASE/util/AliHLTFileWriter.cxx
2686b5a8852ebf0b1d8c3fa3926e9bb3ba1a750a
[u/mrichter/AliRoot.git] / HLT / BASE / util / AliHLTFileWriter.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   AliHLTFileWriter.cxx
20     @author Matthias Richter
21     @date   
22     @brief  HLT file writer component implementation. */
23
24 #if __GNUC__>= 3
25 using namespace std;
26 #endif
27
28 #include "AliHLTFileWriter.h"
29 #include "AliHLTBlockDataCollection.h"
30 #include <TObjArray.h>
31 #include <TObjString.h>
32 #include <TSystem.h>
33 //#include <TMath.h>
34 //#include <TFile.h>
35 #include <cassert>
36
37 /** ROOT macro for the implementation of ROOT specific class methods */
38 ClassImp(AliHLTFileWriter)
39
40 AliHLTFileWriter::AliHLTFileWriter()
41   :
42   AliHLTDataSink(),
43   fpBlockDataCollection(NULL),
44   fBaseName(""),
45   fExtension(""),
46   fDirectory(""),
47   fSubDirFormat(""),
48   fIdFormat("_0x%08x"),
49   fSpecFormat(""),
50   fBlcknoFormat("_0x%02x"),
51   fCurrentFileName(""),
52   fMode(0)
53   , fpBurstBuffer(NULL)
54   , fBurstBufferSize(0)
55   , fBurstBlocks()
56   , fBurstBlockEvents()
57 {
58   // see header file for class documentation
59   // or
60   // refer to README to build package
61   // or
62   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
63 }
64
65 AliHLTFileWriter::~AliHLTFileWriter()
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 int AliHLTFileWriter::SetDefaults()
74 {
75   // see header file for class documentation
76   fBaseName="";
77   fExtension="";
78   fDirectory="";
79   fSubDirFormat="";
80   fIdFormat="_0x%08x";
81   fSpecFormat="";
82   fBlcknoFormat="_0x%02x";
83   fCurrentFileName="";
84   fMode=0;
85   fpBurstBuffer=NULL;
86   fBurstBufferSize=0;
87   fBurstBlocks.clear();
88   fBurstBlockEvents.clear();
89   return 0;
90 }
91
92 const char* AliHLTFileWriter::GetComponentID()
93 {
94   // see header file for class documentation
95   return "FileWriter";
96 }
97
98 void AliHLTFileWriter::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
99 {
100   // see header file for class documentation
101   list.clear();
102   list.push_back(kAliHLTAllDataTypes);
103 }
104
105 AliHLTComponent* AliHLTFileWriter::Spawn()
106 {
107   // see header file for class documentation
108   return new AliHLTFileWriter;
109 }
110
111 int AliHLTFileWriter::DoInit( int argc, const char** argv )
112 {
113   // see header file for class documentation
114   int iResult=0;
115   fpBlockDataCollection=new AliHLTBlockDataCollection;
116   TString argument="";
117   int bMissingParam=0;
118   char* cpErr=NULL;
119   int i=0;
120   for (; i<argc && iResult>=0; i++) {
121     cpErr=NULL;
122     argument=argv[i];
123     if (argument.IsNull()) continue;
124
125     // -basename
126     if (argument.CompareTo("-datafile")==0) {
127       if ((bMissingParam=(++i>=argc))) break;
128       fBaseName=argv[i];
129       TObjArray* pTokens=fBaseName.Tokenize(".");
130       if (pTokens) {
131         int iEntries=pTokens->GetEntries();
132         if (iEntries>1) {
133           int n=0;
134           fBaseName=((TObjString*)pTokens->At(n++))->GetString();
135           while (n<iEntries-1) {
136             fBaseName+="." + ((TObjString*)pTokens->At(n++))->GetString();
137           }
138           fExtension=((TObjString*)pTokens->At(n))->GetString();
139         }
140         delete pTokens;
141       }
142
143       // -directory
144     } else if (argument.CompareTo("-directory")==0) {
145       if ((bMissingParam=(++i>=argc))) break;
146       fDirectory=argv[i];
147
148       // -subdir
149     } else if (argument.BeginsWith("-subdir")) {
150       argument.ReplaceAll("-subdir", "");
151       if (argument.BeginsWith("=")) {
152         fSubDirFormat=argument.Replace(0,1,"");
153         if (strchr(fSubDirFormat.Data(), '%')==NULL) {
154           fSubDirFormat+="%lu";
155         }
156       } else {
157         fSubDirFormat="event%03lu";
158       }
159       // no additional eventno in the filename unless set again
160       // the sub dir contains the id
161       fIdFormat="";
162
163       // -idfmt
164     } else if (argument.BeginsWith("-idfmt")) {
165       argument.ReplaceAll("-idfmt", "");
166       if (argument.BeginsWith("=")) {
167         fIdFormat=argument.Replace(0,1,"");
168       }
169
170       // -specfmt
171     } else if (argument.BeginsWith("-specfmt")) {
172       argument.ReplaceAll("-specfmt", "");
173       if (argument.BeginsWith("=")) {
174         fSpecFormat=argument.Replace(0,1,"");
175       } else {
176         fSpecFormat="_0x%08x";
177       }
178
179       // -blocknofmt
180     } else if (argument.BeginsWith("-blcknofmt") || 
181                argument.BeginsWith("-blocknofmt")) {
182       // for the sake of backward compatibility we consider also the
183       // old argument with typo for a while
184       argument.ReplaceAll("-blcknofmt", "");
185       argument.ReplaceAll("-blocknofmt", "");
186       if (argument.BeginsWith("=")) {
187         fBlcknoFormat=argument.Replace(0,1,"");
188       } else {
189         fBlcknoFormat="_0x%02x";
190       }
191
192       // -enumeration
193     } else if (argument.CompareTo("-enumerate")==0) {
194       SetMode(kEnumerate);
195
196       // -concatenate-blocks
197     } else if (argument.CompareTo("-concatenate-blocks")==0) {
198       SetMode(kConcatenateBlocks);
199
200       // -concatenate-events
201     } else if (argument.CompareTo("-concatenate-events")==0) {
202       SetMode(kConcatenateEvents);
203
204       // -write-all-events
205     } else if (argument.CompareTo("-write-all-events")==0) {
206       SetMode(kWriteAllEvents);
207
208       // -write-all-blocks
209     } else if (argument.CompareTo("-write-all-blocks")==0) {
210       SetMode(kWriteAllBlocks);
211
212       // -write-all
213     } else if (argument.CompareTo("-write-all")==0) {
214       SetMode(kWriteAllEvents);
215       SetMode(kWriteAllBlocks);
216
217       // -burst-buffer
218     } else if (argument.CompareTo("-burst-buffer")==0) {
219       if ((bMissingParam=(++i>=argc))) break;
220       fBurstBufferSize = strtoul( argv[i], &cpErr ,0);
221       if ( *cpErr ) break;
222
223       // -skip-datatype
224     } else if(argument.CompareTo("-skip-datatype")==0){
225       SetMode(kSkipDataType);
226
227       // check for selection arguments (AliHLTBlockDataCollection)
228     } else if (fpBlockDataCollection && 
229                (iResult=fpBlockDataCollection->ScanArgument(argc-i, &argv[i]))>0) {
230         i+=iResult-1;
231         iResult=0;
232     } else {
233       if ((iResult=ScanArgument(argc-i, &argv[i]))==-EINVAL) {
234         HLTError("unknown argument %s", argument.Data());
235         break;
236       } else if (iResult==-EPROTO) {
237         bMissingParam=1;
238         break;
239       } else if (iResult>0) {
240         i+=iResult-1;
241         iResult=0;
242       }
243     }
244   }
245
246   if (cpErr && *cpErr) {
247     HLTError("Cannot convert specifier '%s' for argument '%s'", argv[i], argument.Data());
248     iResult=-EINVAL;
249   } else if (bMissingParam) {
250     HLTError("missing parameter for argument %s", argument.Data());
251     iResult=-EINVAL;
252   }
253   if (fpBlockDataCollection &&
254       (iResult<0 || fpBlockDataCollection->IsEmpty())) {
255     delete fpBlockDataCollection;
256     fpBlockDataCollection=NULL;
257   }
258   if (iResult>=0 && fBurstBufferSize>0) {
259     if (!CheckMode(kConcatenateBlocks) || !CheckMode(kConcatenateEvents)) {
260       HLTError("burst write currently only supported for mode kConcatenateBlocks AND kConcatenateEvents");
261       iResult=-EINVAL;
262     } else {
263     fpBurstBuffer=new AliHLTUInt8_t[fBurstBufferSize];
264     if (!fpBurstBuffer) {
265       iResult=-ENOMEM;
266       fBurstBufferSize=0;
267     }
268     }
269   }
270
271   if (iResult>=0) {
272     iResult=InitWriter();
273     if (!fDirectory.IsNull()) {
274       gSystem->mkdir(fDirectory);
275     }
276   }
277
278   return iResult;
279 }
280
281 int AliHLTFileWriter::InitWriter()
282 {
283   // see header file for class documentation
284   
285   // fCurrentFileName is used in dump event, just touched her to avoid
286   // coding convention violation RC11. The function can not be declared
287   // const since it is just the default implementation, overloaded
288   // virtual function might not be const
289   fCurrentFileName="";
290   return 0; // note: this doesn't mean 'error'
291 }
292
293 int AliHLTFileWriter::ScanArgument(int /*argc*/, const char** /*argv*/)
294 {
295   // see header file for class documentation
296
297   // there are no other arguments than the standard ones
298   // fCurrentFileName is used in dump event, just touched her to avoid
299   // coding convention violation RC11. The function can not be declared
300   // const since it is just the default implementation, overloaded
301   // virtual function might not be const
302   fCurrentFileName="";
303   return -EINVAL;
304 }
305
306 int AliHLTFileWriter::DoDeinit()
307 {
308   // see header file for class documentation
309   int iResult=0;
310   if (fpBurstBuffer) {
311     if ((iResult=BurstWrite())<0) {
312       HLTError("failed BurstWrite");
313     }
314     delete [] fpBurstBuffer;
315     fpBurstBuffer=NULL;
316     fBurstBufferSize=0;
317     fBurstBlocks.clear();
318     fBurstBlockEvents.clear();
319   }
320
321   iResult=CloseWriter();
322   ClearMode(kEnumerate);
323
324   if (fpBlockDataCollection) delete fpBlockDataCollection;
325   fpBlockDataCollection=NULL;
326
327   SetDefaults();
328   return iResult;
329 }
330
331 int AliHLTFileWriter::CloseWriter()
332 {
333   // see header file for class documentation
334
335   // fCurrentFileName is used in dump event, just touched her to avoid
336   // coding convention violation RC11. The function can not be declared
337   // const since it is just the default implementation, overloaded
338   // virtual function might not be const
339   fCurrentFileName="";
340   return 0;
341 }
342
343 int AliHLTFileWriter::DumpEvent( const AliHLTComponentEventData& evtData,
344                          AliHLTComponentTriggerData& /*trigData*/ )
345 {
346   // see header file for class documentation
347   int iResult=0;
348   if (!IsDataEvent() && !CheckMode(kWriteAllEvents)) return 0;
349
350   if (CheckMode(kConcatenateEvents)==0) {
351     // reset the current file name in order to open a new file
352     // for the first block. If events are concatenated, the current
353     // file name stays in order to be opended in append mode.
354     fCurrentFileName="";
355   }
356   const AliHLTComponentBlockData* pDesc=NULL;
357
358   int blockno=0;
359   for (pDesc=GetFirstInputBlock(); pDesc!=NULL; pDesc=GetNextInputBlock(), blockno++) {
360     if (fpBlockDataCollection) {
361       if (!fpBlockDataCollection->IsSelected(*pDesc)) continue;
362     } else if (pDesc->fDataType==(kAliHLTAnyDataType|kAliHLTDataOriginPrivate) && !CheckMode(kWriteAllBlocks))
363       continue;
364     HLTDebug("block %d out of %d", blockno, evtData.fBlockCnt);
365     iResult=ScheduleBlock(blockno, evtData.fEventID, pDesc);
366   }
367   return iResult;
368 }
369
370 int AliHLTFileWriter::BuildFileName(const AliHLTEventID_t eventID, const int blockID,
371                                     const AliHLTComponentDataType& dataType,
372                                     const AliHLTUInt32_t specification,
373                                     TString& filename)
374 {
375   // see header file for class documentation
376   int iResult=0;
377   //HLTDebug("build file name for event %d block %d", eventID, blockID);
378   filename="";
379
380   AliHLTUInt32_t eventType=gkAliEventTypeUnknown;
381
382   if (!fDirectory.IsNull()) {
383     filename+=fDirectory;
384     if (!filename.EndsWith("/"))
385       filename+="/";
386   }
387   if (!fSubDirFormat.IsNull()) {
388     filename+=Form(fSubDirFormat, eventID);
389     if (!filename.EndsWith("/"))
390       filename+="/";
391   }
392   if (filename.EndsWith("/")) {
393     gSystem->mkdir(filename);
394   }
395
396   IsDataEvent(&eventType);
397   if (eventType==gkAliEventTypeStartOfRun && CheckMode(kWriteAllEvents)) filename+="SOR_";
398   else if (eventType==gkAliEventTypeEndOfRun && CheckMode(kWriteAllEvents)) filename+="EOR_";
399
400   if (!fBaseName.IsNull())
401     filename+=fBaseName;
402   else
403     filename+="event";
404   if (!CheckMode(kConcatenateEvents)) {
405     if (!CheckMode(kEnumerate)) {
406       if (eventID!=kAliHLTVoidEventID && !fIdFormat.IsNull()) {
407         filename+=Form(fIdFormat, eventID);
408       }
409     } else {
410       filename+=Form("_%d", GetEventCount());
411     }
412   }
413   if (blockID>=0 && !CheckMode(kConcatenateBlocks)) {
414     if (!fBlcknoFormat.IsNull())
415       filename+=Form(fBlcknoFormat, blockID);
416     if (dataType!=kAliHLTVoidDataType &&
417         !CheckMode(kSkipDataType)) {
418       filename+="_";
419       filename+=AliHLTComponent::DataType2Text(dataType).data();
420     }
421     if (!fSpecFormat.IsNull())
422       filename+=Form(fSpecFormat, specification);
423   }
424   if (!fExtension.IsNull())
425     filename+="." + fExtension;
426   filename.ReplaceAll(" ", "");
427   return iResult;
428 }
429
430 int AliHLTFileWriter::SetMode(Short_t mode) 
431 {
432   // see header file for class documentation
433   fMode|=mode;
434   //HLTDebug("mode set to 0x%x", fMode);
435   return fMode;
436 }
437
438 int AliHLTFileWriter::ClearMode(Short_t mode)
439 {
440   // see header file for class documentation
441   fMode&=~mode;
442   //HLTDebug("mode set to 0x%x", fMode);
443   return fMode;
444 }
445
446 int AliHLTFileWriter::CheckMode(Short_t mode) const
447 {
448   // see header file for class documentation
449
450   //HLTDebug("check mode 0x%x for flag 0x%x: %d", fMode, mode, (fMode&mode)!=0);
451   return (fMode&mode)!=0;
452 }
453
454 int AliHLTFileWriter::ScheduleBlock(int blockno, const AliHLTEventID_t& eventID,
455                                     const AliHLTComponentBlockData* pDesc)
456 {
457   // see header file for class documentation
458   int iResult=0;
459   if (fpBurstBuffer==NULL ||
460       (fBurstBlocks.size()==0 && pDesc->fSize>fBurstBufferSize) ) {
461     return WriteBlock(blockno, eventID, pDesc);
462   }
463   AliHLTComponentBlockData bd=*pDesc;
464   bd.fPtr=NULL;
465   if (fBurstBlocks.size()>0) {
466     bd.fOffset=fBurstBlocks.back().fOffset+fBurstBlocks.back().fSize;
467   } else {
468     bd.fOffset=0;
469   }
470   if (bd.fOffset+bd.fSize>fBurstBufferSize) {
471     if ((iResult=BurstWrite())>=0) {
472       iResult=WriteBlock(blockno, eventID, pDesc);
473     }
474   } else {
475     memcpy(fpBurstBuffer+bd.fOffset, pDesc->fPtr, bd.fSize);
476     fBurstBlocks.push_back(bd);
477     fBurstBlockEvents.push_back(eventID);
478   }
479
480   return iResult;
481 }
482
483 int AliHLTFileWriter::BurstWrite()
484 {
485   // see header file for class documentation
486   int iResult=0;
487   if (fBurstBlocks.size()==0) return 0;
488   assert(fBurstBlocks.size()==fBurstBlockEvents.size());
489   HLTDebug("writing %d postponed blocks", fBurstBlocks.size());
490   int blockno=0;
491   AliHLTComponentBlockDataList::iterator block=fBurstBlocks.begin();
492   AliHLTComponentBlockDataList::iterator firstBlock=block;
493   vector<AliHLTEventID_t>::iterator event=fBurstBlockEvents.begin();
494   if (CheckMode(kConcatenateEvents)) {
495     block=fBurstBlocks.end()-1;
496     event=fBurstBlockEvents.end()-1;
497   }
498   for (; block!=fBurstBlocks.end() && iResult>=0; block++, event++, blockno++) {
499     if (event!=fBurstBlockEvents.begin() && *event!=*(event-1)) {
500       blockno=0;
501     }
502     if (CheckMode(kConcatenateEvents)) {
503       // all blocks in the burst buffer are written in one go
504       // just the block descriptor is updated appropriately
505       (*block).fSize+=(*block).fOffset;
506       (*block).fPtr=fpBurstBuffer;
507     } else if (CheckMode(kConcatenateBlocks)) {
508       // all blocks of the same event are written in one go
509       // just the block descriptor is updated appropriately
510       if (event+1==fBurstBlockEvents.end() ||
511           *event!=*(event+1)) {
512         (*block).fSize+=(*block).fOffset-(*firstBlock).fOffset;
513         (*block).fPtr=fpBurstBuffer+(*firstBlock).fOffset;
514         firstBlock=block+1;
515       } else {
516         // coninue if it wasn't the last block of this event
517         continue;
518       }
519     } else {
520       (*block).fPtr=fpBurstBuffer+(*block).fOffset;
521     }
522     (*block).fOffset=0;
523     iResult=WriteBlock(blockno, *event, &(*block));
524   }
525   fBurstBlocks.clear();
526   fBurstBlockEvents.clear();
527
528   return iResult;
529 }
530
531 int AliHLTFileWriter::WriteBlock(int blockno, const AliHLTEventID_t& eventID,
532                                  const AliHLTComponentBlockData* pDesc)
533 {
534   // see header file for class documentation
535   int iResult=0;
536   TString filename;
537   HLTDebug("dataspec 0x%x", pDesc->fSpecification);
538   iResult=BuildFileName(eventID, blockno, pDesc->fDataType, pDesc->fSpecification, filename);
539   ios::openmode filemode=(ios::openmode)0;
540   if (fCurrentFileName.CompareTo(filename)==0) {
541     // append to the file
542     filemode=ios::app;
543   } else {
544     // store the file for the next block
545     fCurrentFileName=filename;
546   }
547   if (iResult>=0) {
548     ofstream dump(filename.Data(), filemode);
549     if (dump.good()) {
550       dump.write((static_cast<const char*>(pDesc->fPtr)), pDesc->fSize);
551       HLTDebug("wrote %d byte(s) to file %s", pDesc->fSize, filename.Data());
552     } else {
553       HLTError("can not open file %s for writing", filename.Data());
554       iResult=-EBADF;
555     }
556     dump.close();
557   }
558   return iResult;
559 }