]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliMDC.cxx
Protection against special particle types.
[u/mrichter/AliRoot.git] / RAW / AliMDC.cxx
1 // @(#)alimdc:$Name$:$Id$
2 // Author: Fons Rademakers  26/11/99
3 // Updated: Dario Favretto  15/04/2003
4
5 /**************************************************************************
6  * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
7  *                                                                        *
8  * Author: The ALICE Off-line Project.                                    *
9  * Contributors are mentioned in the code where appropriate.              *
10  *                                                                        *
11  * Permission to use, copy, modify and distribute this software and its   *
12  * documentation strictly for non-commercial purposes is hereby granted   *
13  * without fee, provided that the above copyright notice appears in all   *
14  * copies and that both the copyright notice and this permission notice   *
15  * appear in the supporting documentation. The authors make no claims     *
16  * about the suitability of this software for any purpose. It is          *
17  * provided "as is" without express or implied warranty.                  *
18  **************************************************************************/
19
20 /* $Id$ */
21
22 //////////////////////////////////////////////////////////////////////////
23 //                                                                      //
24 // AliMDC                                                               //
25 //                                                                      //
26 // Set of classes defining the ALICE RAW event format. The AliRawEvent  //
27 // class defines a RAW event. It consists of an AliEventHeader object   //
28 // an AliEquipmentHeader object, an AliRawData object and an array of   //
29 // sub-events, themselves also being AliRawEvents. The number of        //
30 // sub-events depends on the number of DATE LDC's.                      //
31 // The AliRawEvent objects are written to a ROOT file using different   //
32 // technologies, i.e. to local disk via AliRawDB or via rfiod using     //
33 // AliRawRFIODB or via rootd using AliRawRootdDB or to CASTOR via       //
34 // rootd using AliRawCastorDB (and for performance testing there is     //
35 // also AliRawNullDB).                                                  //
36 // The AliStats class provides statics information that is added as     //
37 // a single keyed object to each raw file.                              //
38 // The AliTagDB provides an interface to a TAG database.                //
39 // The AliMDC class is usid by the "alimdc" stand-alone program         //
40 // that reads data directly from DATE.                                  //
41 //                                                                      //
42 //////////////////////////////////////////////////////////////////////////
43
44 #include <sys/types.h>
45 #include <sys/stat.h>
46
47 #include <errno.h>
48
49 #include <TSystem.h>
50 #include <TROOT.h>
51 #include <TStopwatch.h>
52 #include <TPluginManager.h>
53
54 #include <sys/uio.h>
55 #ifdef USE_EB
56 #include "libDateEb.h"
57 #endif
58
59 #include <AliLog.h>
60 #include <AliESD.h>
61
62 #include "AliRawEvent.h"
63 #include "AliRawEventHeaderBase.h"
64 #include "AliRawEquipment.h"
65 #include "AliRawEquipmentHeader.h"
66 #include "AliRawData.h"
67 #include "AliStats.h"
68 #include "AliRawDB.h"
69 #include "AliRawRFIODB.h"
70 #include "AliRawCastorDB.h"
71 #include "AliRawRootdDB.h"
72 #include "AliRawNullDB.h"
73 #include "AliTagDB.h"
74 #include "AliRawEventTag.h"
75 #include "AliFilter.h"
76
77 #include "AliMDC.h"
78
79 ClassImp(AliMDC)
80
81
82 // Filter names
83 const char* const AliMDC::fgkFilterName[kNFilters] = {"AliHoughFilter"};
84
85 //______________________________________________________________________________
86 AliMDC::AliMDC(Int_t compress, Bool_t deleteFiles, EFilterMode filterMode, 
87                Double_t maxSizeTagDB, const char* fileNameTagDB,
88                const char *guidFileFolder) :
89   fEvent(new AliRawEvent),
90   fESD(NULL),
91   fStats(NULL),
92   fRawDB(NULL),
93   fTagDB(NULL),
94   fEventTag(new AliRawEventTag),
95   fCompress(compress),
96   fDeleteFiles(deleteFiles),
97   fFilterMode(filterMode),
98   fFilters(),
99   fStop(kFALSE),
100   fIsTagDBCreated(kFALSE),
101   fMaxSizeTagDB(maxSizeTagDB),
102   fFileNameTagDB(fileNameTagDB),
103   fGuidFileFolder(guidFileFolder)
104 {
105   // Create MDC processor object.
106   // compress is the file compression mode.
107   // If deleteFiles is kTRUE the raw data files will be deleted after they
108   // were closed.
109   // If the filterMode if kFilterOff no filter algorithm will be, if it is
110   // kFilterTransparent the algorthims will be run but no events will be
111   // rejected, if it is kFilterOn the filters will be run and the event will
112   // be rejected if all filters return kFALSE.
113   // If maxSizeTagDB is greater than 0 it determines the maximal size of the
114   // tag DB and then fileNameTagDB is the directory name for the tag DB.
115   // Otherwise fileNameTagDB is the file name of the tag DB. If it is NULL
116   // no tag DB will be created.
117   // Optional 'guidFileFolder' specifies the folder in which *.guid files
118   // will be stored. In case this option is not given, the *.guid files
119   // will be written to the same folder as the raw-data files.
120  
121   // This line is needed in case of a stand-alone application w/o
122   // $ROOTSYS/etc/system.rootrc file
123   gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
124                                         "*",
125                                         "TStreamerInfo",
126                                         "RIO",
127                                         "TStreamerInfo()");
128
129   if (fFilterMode != kFilterOff) {
130     fESD = new AliESD;
131   }
132
133 // Tag DB is now created at the point where the header version is
134 // already known
135 //   if (fileNameTagDB) {
136 //     if (maxSizeTagDB > 0) {
137 //       fTagDB = new AliTagDB(fEvent->GetHeader(), NULL);
138 //       fTagDB->SetMaxSize(maxSizeTagDB);
139 //       fTagDB->SetFS(fileNameTagDB);
140 //       fTagDB->Create();
141 //     } else {
142 //       fTagDB = new AliTagDB(fEvent->GetHeader(), fileNameTagDB);
143 //     }
144 //   }
145
146   // Create the guid files folder if it does not exist
147   if (fGuidFileFolder) {
148     gSystem->ResetErrno();
149     gSystem->MakeDirectory(fGuidFileFolder);
150     if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
151       SysError("AliMDC", "mkdir %s", fGuidFileFolder);
152     }
153   }
154
155   // install SIGUSR1 handler to allow clean interrupts
156   gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
157
158   // create the high level filters
159   if (fFilterMode != kFilterOff) {
160     for (Int_t iFilter = 0; iFilter < kNFilters; iFilter++) {
161       TClass* filterClass = gROOT->GetClass(fgkFilterName[iFilter]);
162       if (!filterClass) {
163         Warning("AliMDC", "no filter class %s found", fgkFilterName[iFilter]);
164         continue;
165       }
166       AliFilter* filter = (AliFilter*) filterClass->New();
167       if (!filter) {
168         Warning("AliMDC", "creation of filter %s failed", fgkFilterName[iFilter]);
169         continue;
170       }
171       fFilters.Add(filter);
172     }
173   }
174 }
175
176 //______________________________________________________________________________
177 AliMDC::~AliMDC()
178 {
179 // destructor
180
181   fFilters.Delete();
182   if(fTagDB) delete fTagDB;
183   delete fRawDB;
184   delete fStats;
185   delete fESD;
186   delete fEvent;
187   delete fEventTag;
188 }
189  
190 //______________________________________________________________________________
191 Int_t AliMDC::Open(EWriteMode mode, const char* fileName,
192                    Double_t maxFileSize,
193                    const char* fs1, const char* fs2)
194 {
195 // open a new raw DB file
196
197   if (mode == kRFIO)
198     fRawDB = new AliRawRFIODB(fEvent, fESD, fCompress, fileName);
199   else if (mode == kROOTD)
200     fRawDB = new AliRawRootdDB(fEvent, fESD, fCompress, fileName);
201   else if (mode == kCASTOR)
202     fRawDB = new AliRawCastorDB(fEvent, fESD, fCompress, fileName);
203   else if (mode == kDEVNULL)
204     fRawDB = new AliRawNullDB(fEvent, fESD, fCompress, fileName);
205   else
206     fRawDB = new AliRawDB(fEvent, fESD, fCompress, fileName);
207   fRawDB->SetDeleteFiles(fDeleteFiles);
208
209   if (fileName == NULL) {
210     fRawDB->SetMaxSize(maxFileSize);
211     fRawDB->SetFS(fs1, fs2);
212     fRawDB->Create();
213   }
214
215   if (fGuidFileFolder) fRawDB->SetGuidFileFolder(fGuidFileFolder);
216
217   if (fRawDB->IsZombie()) {
218     delete fRawDB;
219     fRawDB = NULL;
220     return -1;
221   }
222   Info("Open", "Filling raw DB %s\n", fRawDB->GetDBName());
223
224   // Create AliStats object
225   fStats = new AliStats(fRawDB->GetDBName(), fCompress, 
226                         fFilterMode != kFilterOff);
227   return 0;
228 }
229
230 //______________________________________________________________________________
231 Int_t AliMDC::ProcessEvent(void* event, Bool_t isIovecArray)
232 {
233 // Convert the DATE event to an AliRawEvent object and store it in the raw DB,
234 // optionally also run the filter.
235 // event is either a pointer to the streamlined event 
236 // or, if isIovecArray is kTRUE, a pointer to an array of iovecs with one
237 // iovec per subevent (used by the event builder).
238 // The return value is the number of written bytes or an error code
239   const UInt_t kFileSizeErrorLevel   = 1900000000;
240
241   UInt_t currentFileSize = GetTotalSize();
242   if(currentFileSize > kFileSizeErrorLevel) {
243     Error("ProcessEvent", "file size (%u) exceeds the limit "
244           , currentFileSize);
245     return kErrFileSize;
246   }
247
248   Int_t status;
249   char* data = (char*) event;
250   if (isIovecArray) data = (char*) ((iovec*) event)[0].iov_base;
251
252   // Shortcut for easy header access
253   AliRawEventHeaderBase *header = fEvent->GetHeader(data);
254
255   // Read event header
256   if ((status = header->ReadHeader(data)) != (Int_t)header->GetHeadSize()) {
257     return kErrHeader;
258   }
259
260   if (AliDebugLevel() > 2) ToAliDebug(3, header->Dump(););
261
262   // Check event type and skip "Start of Run", "End of Run",
263   // "Start of Run Files" and "End of Run Files"
264   Int_t size = header->GetEventSize() - header->GetHeadSize();
265   
266   AliDebug(1, Form("Processing %s (%d bytes)", header->GetTypeName(), size));
267
268   // Amount of data left to read for this event
269   Int_t toRead = size;
270
271   // StartOfRun, EndOfRun etc. events have no payload
272   // Nevertheless, store the event headers in the tree
273   if (toRead > 0) {
274
275     // If there is less data for this event than the next sub-event
276     // header, something is wrong. Skip to next event...
277     if (toRead < (Int_t)header->GetHeadSize()) {
278       Error("ProcessEvent", "header size (%d) exceeds number of bytes "
279             "to read (%d)", header->GetHeadSize(), toRead);
280       if (AliDebugLevel() > 0) ToAliDebug(1, header->Dump(););
281       return kErrHeaderSize;
282     }
283   
284     // Loop over all sub-events... (LDCs)
285     Int_t nsub = 1;
286     while (toRead > 0) {
287       if (isIovecArray) data = (char*) ((iovec*) event)[nsub].iov_base;
288
289       AliDebug(1, Form("reading LDC %d", nsub));
290
291       AliRawEvent *subEvent = fEvent->NextSubEvent();
292
293       // Read sub-event header
294       AliRawEventHeaderBase *subHeader = subEvent->GetHeader(data);
295       if ((status = subHeader->ReadHeader(data)) != (Int_t)subHeader->GetHeadSize()) {
296         return kErrSubHeader;
297       }
298
299       if (AliDebugLevel() > 2) ToAliDebug(3, subHeader->Dump(););
300
301       toRead -= subHeader->GetHeadSize();
302
303       Int_t rawSize = subHeader->GetEventSize() - subHeader->GetHeadSize();
304
305       // Make sure raw data less than left over bytes for current event
306       if (rawSize > toRead) {
307         Warning("ProcessEvent", "raw data size (%d) exceeds number of "
308                 "bytes to read (%d)\n", rawSize, toRead);
309         if (AliDebugLevel() > 0) ToAliDebug(1, subHeader->Dump(););
310         return kErrDataSize;
311       }
312
313       // Read Equipment Headers (in case of physics or calibration event)
314       if (header->Get("Type") == AliRawEventHeaderBase::kPhysicsEvent ||
315           header->Get("Type") == AliRawEventHeaderBase::kCalibrationEvent ||
316           header->Get("Type") == AliRawEventHeaderBase::kSystemSoftwareTriggerEvent ||
317           header->Get("Type") == AliRawEventHeaderBase::kDetectorSoftwareTriggerEvent) {
318         while (rawSize > 0) {
319           AliRawEquipment &equipment = *subEvent->NextEquipment();
320           AliRawEquipmentHeader &equipmentHeader = 
321             *equipment.GetEquipmentHeader();
322           Int_t equipHeaderSize = equipmentHeader.HeaderSize();
323           if ((status = ReadEquipmentHeader(equipmentHeader, header->DataIsSwapped(),
324                                             data)) != equipHeaderSize) {
325             return kErrEquipmentHeader;
326           }
327
328           if (AliDebugLevel() > 2) ToAliDebug(3, equipmentHeader.Dump(););
329
330           toRead  -= equipHeaderSize;
331           rawSize -= equipHeaderSize;
332
333           // Read equipment raw data
334           AliRawData &subRaw = *equipment.GetRawData();
335
336           Int_t eqSize = equipmentHeader.GetEquipmentSize() - equipHeaderSize;
337           if ((status = ReadRawData(subRaw, eqSize, data)) != eqSize) {
338             return kErrEquipment;
339           }
340           toRead  -= eqSize;
341           rawSize -= eqSize;
342
343         }
344
345       } else {  // Read only raw data but no equipment header
346         if (rawSize) {
347           AliRawEquipment &equipment = *subEvent->NextEquipment();
348           AliRawData &subRaw = *equipment.GetRawData();
349           if ((status = ReadRawData(subRaw, rawSize, data)) != rawSize) {
350             return kErrEquipment;
351           }
352           toRead  -= rawSize;
353         }
354       }
355
356       nsub++;
357     }
358   }
359
360   // High Level Event Filter
361   if (fFilterMode != kFilterOff) {
362     if (header->Get("Type") == AliRawEventHeaderBase::kPhysicsEvent ||
363         header->Get("Type") == AliRawEventHeaderBase::kCalibrationEvent ||
364         header->Get("Type") == AliRawEventHeaderBase::kSystemSoftwareTriggerEvent ||
365         header->Get("Type") == AliRawEventHeaderBase::kDetectorSoftwareTriggerEvent) {
366       Bool_t result = kFALSE;
367       for (Int_t iFilter = 0; iFilter < fFilters.GetEntriesFast(); iFilter++) {
368         AliFilter* filter = (AliFilter*) fFilters[iFilter];
369         if (!filter) continue;
370         if (filter->Filter(fEvent, fESD)) result = kTRUE;
371       }
372       if ((fFilterMode == kFilterOn) && !result) return kFilterReject;
373     }
374   }
375
376   // Set stat info for first event of this file
377   if (fRawDB->GetEvents() == 0)
378     fStats->SetFirstId(header->Get("RunNb"), header->GetP("Id")[0]);
379
380   // Store raw event in tree
381   Int_t nBytes = fRawDB->Fill();
382
383   // Fill the event tag object
384   fEventTag->SetHeader(fEvent->GetHeader());
385   fEventTag->SetGUID(fRawDB->GetDB()->GetUUID().AsString());
386   fEventTag->SetEventNumber(fRawDB->GetEvents()-1);
387
388   // Create Tag DB here only after the raw data header
389   // version was already identified
390   if (!fIsTagDBCreated) {
391     if (fFileNameTagDB) {
392       if (fMaxSizeTagDB > 0) {
393         fTagDB = new AliTagDB(fEventTag, NULL);
394         fTagDB->SetMaxSize(fMaxSizeTagDB);
395         fTagDB->SetFS(fFileNameTagDB);
396         fTagDB->Create();
397       } else {
398         fTagDB = new AliTagDB(fEventTag, fFileNameTagDB);
399       }
400     }
401     fIsTagDBCreated = kTRUE;
402   }
403
404   // Store event tag in tree
405   if (fTagDB) fTagDB->Fill();
406
407   // Make top event object ready for next event data
408   fEvent->Reset();
409   // Clean up HLT ESD for the next event
410   if (fESD) fESD->Reset();
411
412   if(nBytes >= 0)
413     return nBytes;
414   else
415     return kErrWriting;
416 }
417
418 //______________________________________________________________________________
419 Int_t AliMDC::GetTotalSize()
420 {
421 // return the total current raw DB file size
422
423   if (!fRawDB) return -1;
424
425   return fRawDB->GetTotalSize();
426 }
427
428 //______________________________________________________________________________
429 Int_t AliMDC::Close()
430 {
431 // close the current raw DB file
432
433   if (!fRawDB) return -1;
434
435   fRawDB->WriteStats(fStats);
436   Int_t filesize = fRawDB->Close();
437   delete fRawDB;
438   fRawDB = NULL;
439   delete fStats;
440   fStats = NULL;
441   return filesize;
442 }
443
444 //______________________________________________________________________________
445 Int_t AliMDC::Run(const char* inputFile, Bool_t loop,
446                   EWriteMode mode, Double_t maxFileSize, 
447                   const char* fs1, const char* fs2)
448 {
449   // Run the MDC processor. Read from the input stream and only return
450   // when the input gave and EOF or a fatal error occured. On success 0
451   // is returned, 1 in case of a fatality.
452   // inputFile is the name of the DATE input file; if NULL the input will
453   // be taken from the event builder.
454   // If loop is set the same input file will be reused in an infinite loop.
455   // mode specifies the type of the raw DB.
456   // maxFileSize is the maximal size of the raw DB.
457   // fs1 and fs2 are the file system locations of the raw DB.
458
459   Info("Run", "input = %s, rawdb size = %f, filter = %s, "
460        "looping = %s, compression = %d, delete files = %s",
461        inputFile ? inputFile : "event builder", maxFileSize,
462        fFilterMode == kFilterOff ? "off" : 
463        (fFilterMode == kFilterOn ? "on" : "transparent"), 
464        loop ? "yes" : "no", fCompress, fDeleteFiles ? "yes" : "no");
465
466   // Open the input file
467   Int_t fd = -1;
468   if (inputFile) {
469     if ((fd = open(inputFile, O_RDONLY)) == -1) {
470       Error("Run", "cannot open input file %s", inputFile);
471       return 1;
472     }
473   }
474
475   // Used for statistics
476   TStopwatch timer;
477   timer.Start();
478   Double_t told = 0, tnew = 0;
479   Float_t  chunkSize = maxFileSize/100, nextChunk = chunkSize;
480
481   // Create new raw DB.
482   if (fRawDB) Close();
483
484   if (Open(mode,NULL,maxFileSize,fs1,fs2) < 0) return 1;
485
486   // Process input stream
487 #ifdef USE_EB
488   Int_t eorFlag = 0;
489 #endif
490   char* event = NULL;
491   UInt_t eventSize = 0;
492   Int_t numEvents = 0;
493
494   AliRawEventHeaderBase header;
495
496   while (kTRUE) {
497
498     // If we were in looping mode stop directly after a SIGUSR1 signal
499     if (fStop) {
500       Info("Run", "Stopping loop, processed %d events", numEvents);
501       break;
502     }
503
504     if (!inputFile) {  // get data from event builder
505 #ifdef USE_EB
506       if ((eorFlag = ebEor())) break;
507       if ((event = (char*)ebGetNextEvent()) == (char*)-1) {
508         Error("Run", "error getting next event (%s)", ebGetLastError());
509         break;
510       }
511       if (event == 0) {
512         // no event, sleep for 1 second and try again
513         gSystem->Sleep(1000);
514         continue;
515       }
516 #else
517       Error("Run", "AliMDC was compiled without event builder support");
518       delete fRawDB;
519       fRawDB = NULL;
520       delete fStats;
521       fStats = NULL;
522       return 1;
523 #endif
524
525     } else {  // get data from a file
526       {
527         Int_t nrecv;
528         if ((nrecv = Read(fd, header.HeaderBaseBegin(), header.HeaderBaseSize())) !=
529             header.HeaderBaseSize()) {
530           if (nrecv == 0) {  // eof
531             if (loop) {
532               ::lseek(fd, 0, SEEK_SET);
533               continue;
534             } else {
535               break;
536             }
537           } else {
538             Error("Run", "error reading base header");
539             Close();
540             delete[] event;
541             return 1;
542           }
543         }
544       }
545       char *data = (char *)header.HeaderBaseBegin();
546       AliRawEventHeaderBase *hdr = AliRawEventHeaderBase::Create(data);
547       Int_t nrecv;
548       if ((nrecv = Read(fd, hdr->HeaderBegin(), hdr->HeaderSize())) !=
549           hdr->HeaderSize()) {
550         if (nrecv == 0) {  // eof
551           if (loop) {
552             ::lseek(fd, 0, SEEK_SET);
553             delete hdr;
554             continue;
555           } else {
556             delete hdr;
557             break;
558           }
559         } else {
560           Error("Run", "error reading header");
561           Close();
562           delete[] event;
563           delete hdr;
564           return 1;
565         }
566       }
567       if (eventSize < hdr->GetEventSize()) {
568         delete[] event;
569         eventSize = 2 * hdr->GetEventSize();
570         event = new char[eventSize];
571       }
572       memcpy(event, hdr->HeaderBaseBegin(), hdr->HeaderBaseSize());
573       memcpy(event+hdr->HeaderBaseSize(), hdr->HeaderBegin(), hdr->HeaderSize());
574       if (hdr->GetExtendedDataSize() != 0)
575         memcpy(event+hdr->HeaderBaseSize()+hdr->HeaderSize(),
576                hdr->GetExtendedData(), hdr->GetExtendedDataSize());
577       Int_t size = hdr->GetEventSize() - hdr->GetHeadSize();
578       if (Read(fd, event + hdr->GetHeadSize(), size) != size) {
579         Error("Run", "error reading data");
580         Close();
581         delete[] event;
582         delete hdr;
583         return 1;
584       }
585       delete hdr;
586     }
587
588     Int_t result = ProcessEvent(event, !inputFile);
589     if(result < -1)
590       Error("Run", "error writing data. Error code: %d",result);
591
592     if (result >= 0) {
593       numEvents++;
594       if (!(numEvents%10))
595         printf("Processed event %d (%d)\n", numEvents, fRawDB->GetEvents());
596     }
597
598     if (result > 0) {
599       // Filling time statistics
600       if (fRawDB->GetBytesWritten() > nextChunk) {
601         tnew = timer.RealTime();
602         fStats->Fill(tnew-told);
603         told = tnew;
604         timer.Continue();
605         nextChunk += chunkSize;
606       }
607
608       // Check size of raw db. If bigger than maxFileSize, close file
609       // and continue with new file.
610       if (fRawDB->GetBytesWritten() > maxFileSize) {
611
612         printf("Written raw DB at a rate of %.1f MB/s\n",
613                fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
614
615         // Write stats object to raw db, run db, MySQL and AliEn
616         fRawDB->WriteStats(fStats);
617         delete fStats;
618         fStats = NULL;
619
620         if (!fRawDB->NextFile()) {
621           Error("Run", "error opening next raw data file");
622           Close();
623           if (inputFile) delete[] event;
624           return 1;
625         }
626
627         printf("Filling raw DB %s\n", fRawDB->GetDBName());
628         fStats = new AliStats(fRawDB->GetDBName(), fCompress, 
629                               fFilterMode != kFilterOff);
630
631         timer.Start();
632         told = 0, tnew = 0;
633         nextChunk = chunkSize;
634       }
635
636       // Check size of tag db
637       if (fTagDB && fTagDB->FileFull()) {
638         if (!fTagDB->NextFile()) {
639           delete fTagDB;
640           fTagDB = 0;
641         } else {
642           printf("Filling tag DB %s\n", fTagDB->GetDBName());
643         }
644       }
645     }
646
647     // Make top event object ready for next event data
648     //printf("Event %d has %d sub-events\n", numEvents, fEvent->GetNSubEvents());
649     //    fEvent->Reset();
650     // Clean up HLT ESD for the next event
651     //    if (fESD) fESD->Reset();
652
653     if (!inputFile) {
654 #ifdef USE_EB
655       if (!ebReleaseEvent((iovec*)event)) {
656         Error("Run", "problem releasing event (%s)", ebGetLastError());
657         break;
658       }
659 #endif
660     }
661   }
662
663   printf("Written raw DB at a rate of %.1f MB/s\n",
664          fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
665
666   // Write stats to raw db and run db and delete stats object
667   Close();
668
669   if (!inputFile) {
670 #ifdef USE_EB
671     // Print eor flag
672     if (eorFlag) {
673       Info("Run", "event builder reported end of run (%d)", eorFlag);
674     }
675 #endif
676   } else {
677     // Close input source
678     close(fd);
679     delete [] event;
680   }
681
682   return 0;
683 }
684
685 //______________________________________________________________________________
686 Int_t AliMDC::Read(Int_t fd, void *buffer, Int_t length)
687 {
688    // Read exactly length bytes into buffer. Returns number of bytes
689    // received, returns -1 in case of error and 0 for EOF.
690
691    errno = 0;
692
693    if (fd < 0) return -1;
694
695    Int_t n, nrecv = 0;
696    char *buf = (char *)buffer;
697
698    for (n = 0; n < length; n += nrecv) {
699       if ((nrecv = read(fd, buf+n, length-n)) <= 0) {
700          if (nrecv == 0)
701             break;        // EOF
702          if (errno != EINTR)
703             SysError("Read", "read");
704          return -1;
705       }
706    }
707    return n;
708 }
709
710 //______________________________________________________________________________
711 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
712                                   Bool_t isSwapped, char*& data)
713 {
714   // Read equipment header info from DATE data stream. Returns bytes read
715   // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
716   // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
717   // and we will swap the header to host format.
718
719   memcpy(header.HeaderBegin(), data, header.HeaderSize());
720   data += header.HeaderSize();
721
722   // Swap equipment header data if needed
723   if (isSwapped)
724     header.Swap();
725
726   if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
727     Error("ReadEquipmentHeader", "invalid equipment header size");
728     // try recovery... how?
729     return -1;
730   }
731
732   return header.HeaderSize();
733 }
734
735 //______________________________________________________________________________
736 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, char*& data)
737 {
738   // Read raw data from DATE data stream. Returns bytes read (i.e.
739   // size), -1 in case of error and 0 for EOF.
740
741   raw.SetBuffer(data, size);
742   data += size;
743
744   return size;
745 }
746
747 //______________________________________________________________________________
748 void AliMDC::Stop()
749 {
750   // Stop the event loop
751  
752   fStop = kTRUE; 
753   if (fRawDB) fRawDB->Stop(); 
754 }
755
756