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