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