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