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