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