support multiple equipments per sub event in the root raw data format
[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 <TError.h>
53 #include <TStopwatch.h>
54
55 #ifdef ALI_DATE
56 #include "event.h"
57 #endif
58 #ifdef USE_EB
59 #include "libDateEb.h"
60 #endif
61
62 #include "AliRawEvent.h"
63 #include "AliRawEventHeader.h"
64 #include "AliRawEquipment.h"
65 #include "AliRawEquipmentHeader.h"
66 #include "AliRawData.h"
67 #include "AliStats.h"
68 #include "AliRawDB.h"
69 #include "AliRawRFIODB.h"
70 #include "AliRawCastorDB.h"
71 #include "AliRawRootdDB.h"
72 #include "AliRawNullDB.h"
73 #include "AliTagDB.h"
74
75 #include "AliMDC.h"
76
77
78 ClassImp(AliMDC)
79
80
81 #define ALIDEBUG(level) \
82    if (AliMDC::Instance() && (AliMDC::Instance()->GetDebugLevel() >= (level)))
83
84
85 // Fixed file system locations for the different DB's
86 #ifdef USE_RDM
87 const char* const AliMDC::fgkFifo       = "/tmp/alimdc.fifo";
88 const char* const AliMDC::fgkRawDBFS[2] = { "/tmp/mdc1", "/tmp/mdc2" };
89 const char* const AliMDC::fgkTagDBFS    = "/tmp/mdc1/tags";
90 const char* const AliMDC::fgkRunDBFS    = "/tmp/mdc1/meta";
91 const char* const AliMDC::fgkRFIOFS     = "rfio:/castor/cern.ch/user/r/rdm";
92 const char* const AliMDC::fgkCastorFS   = "castor:/castor/cern.ch/user/r/rdm";
93 const char* const AliMDC::fgkRootdFS    = "root://localhost//tmp/mdc1";
94 const char* const AliMDC::fgkAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
95 const char* const AliMDC::fgkAlienDir   = "/alice_mdc/DC";
96 #else
97 const char* const AliMDC::fgkFifo       = "/tmp/alimdc.fifo";
98 const char* const AliMDC::fgkRawDBFS[2] = { "/data1/mdc", "/data2/mdc" };
99 const char* const AliMDC::fgkTagDBFS    = "/data1/mdc/tags";
100 const char* const AliMDC::fgkRunDBFS    = "/data1/mdc/meta";
101 const char* const AliMDC::fgkRFIOFS     = "rfio:/castor/cern.ch/lcg/dc5";
102 const char* const AliMDC::fgkCastorFS   = "castor:/castor/cern.ch/lcg/dc5";
103 const char* const AliMDC::fgkRootdFS    = "root://localhost//tmp/mdc1";
104 const char* const AliMDC::fgkAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
105 const char* const AliMDC::fgkAlienDir   = "/alice_mdc/DC";
106 #endif
107
108 // Maximum size of tag db files
109 const Double_t AliMDC::fgkMaxTagFileSize = 2.5e8;    // 250MB
110
111 Bool_t AliMDC::fgDeleteFiles = kFALSE;
112 AliMDC* AliMDC::fgInstance = NULL;
113
114
115 //______________________________________________________________________________
116 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
117                EWriteMode mode, Bool_t useLoop, Bool_t delFiles)
118 {
119    // Create MDC processor object.
120
121    fFd           = fd;
122    fCompress     = compress;
123    fMaxFileSize  = maxFileSize;
124    fUseFilter    = useFilter;
125    fWriteMode    = mode;
126    fUseLoop      = useLoop;
127    fUseFifo      = kFALSE;
128    fUseEb        = kFALSE;
129    fStopLoop     = kFALSE;
130    fNumEvents    = 0;
131    fDebugLevel   = 0;
132    fgDeleteFiles = delFiles;
133
134    if (fFd == -1) {
135 #ifdef USE_EB
136      if (!ebRegister()) {
137         Error("AliMDC", "cannot register with the event builder (%s)",
138               ebGetLastError());
139         return;
140      }
141      fUseEb = kTRUE;
142 #else
143      if ((mkfifo(fgkFifo, 0644) < 0) && (errno != EEXIST)) {
144          Error("AliMDC", "cannot create fifo %s", fgkFifo);
145          return;
146       }
147       if ((chmod(fgkFifo, 0666) == -1) && (errno != EPERM)) {
148          Error("AliMDC", "cannot change permission of fifo %s", fgkFifo);
149          return;
150       }
151       if ((fFd = open(fgkFifo, O_RDONLY)) == -1) {
152          Error("AliMDC", "cannot open input file %s", fgkFifo);
153          return;
154       }
155       fUseFifo = kTRUE;
156 #endif
157       fUseLoop = kFALSE;
158    }
159
160    printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
161           "looping = %s, compression = %d, delete files = %s",
162           fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
163           fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
164           fgDeleteFiles ? "yes" : "no");
165    if (fWriteMode == kRFIO)
166       printf(", use RFIO\n");
167    else if (fWriteMode == kROOTD)
168       printf(", use rootd\n");
169    else if (fWriteMode == kCASTOR)
170       printf(", use CASTOR/rootd\n");
171    else if (fWriteMode == kDEVNULL)
172       printf(", write raw data to /dev/null\n");
173    else
174       printf("\n");
175
176    // install SIGUSR1 handler to allow clean interrupts
177    gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
178
179    fgInstance = this;
180 }
181
182 //______________________________________________________________________________
183 AliMDC::AliMDC(const AliMDC& mdc): TObject(mdc)
184 {
185 // copy constructor
186
187   Fatal("AliMDC", "copy constructor not implemented");
188 }
189
190 //______________________________________________________________________________
191 AliMDC& AliMDC::operator = (const AliMDC& /*mdc*/)
192 {
193 // assignment operator
194
195   Fatal("operator =", "assignment operator not implemented");
196   return *this;
197 }
198
199 //______________________________________________________________________________
200 Int_t AliMDC::Run()
201 {
202    // Run the MDC processor. Read from the input stream and only return
203    // when the input gave and EOF or a fatal error occured. On success 0
204    // is returned, 1 in case of a fatality.
205
206    TStopwatch timer;
207    Int_t status;
208
209    // Make sure needed directories exist
210    const char *dirs[4];
211    dirs[0] = fgkRawDBFS[0];
212    dirs[1] = fgkRawDBFS[1];
213    dirs[2] = fgkTagDBFS;
214    dirs[3] = fgkRunDBFS;
215    for (int idir = 0; idir < 4; idir++) {
216       gSystem->ResetErrno();
217       gSystem->MakeDirectory(dirs[idir]);
218       if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
219          SysError("Run", "mkdir %s", dirs[idir]);
220          return 1;
221       }
222    }
223
224    // Used for statistics
225    timer.Start();
226    Double_t told = 0, tnew = 0;
227    Float_t  chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
228
229    // Event object used to store event data.
230    AliRawEvent *event = new AliRawEvent;
231
232    // Create new raw DB.
233    AliRawDB *rawdb;
234    if (fWriteMode == kRFIO)
235       rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
236    else if (fWriteMode == kROOTD)
237       rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
238    else if (fWriteMode == kCASTOR)
239       rawdb = new AliRawCastorDB(event, fMaxFileSize, fCompress);
240    else if (fWriteMode == kDEVNULL)
241       rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
242    else
243       rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
244
245    if (rawdb->IsZombie()) return 1;
246    printf("Filling raw DB %s\n", rawdb->GetDBName());
247
248    // Create new tag DB.
249    AliTagDB *tagdb = 0;
250 #if 0
251    // no tagdb for the time being to get maximum speed
252    if (fWriteMode == fgkDEVNULL)
253       tagdb = new AliTagNullDB(event->GetHeader(), fgkMaxTagFileSize);
254    else
255       tagdb = new AliTagDB(event->GetHeader(), fgkMaxTagFileSize);
256    if (tagdb->IsZombie())
257       tagdb = 0;
258    else
259       printf("Filling tag DB %s\n", tagdb->GetDBName());
260 #endif
261
262    // Create AliStats object
263    AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
264
265    // Shortcut for easy header access
266    AliRawEventHeader &header = *event->GetHeader();
267
268    // Process input stream
269 #ifdef USE_EB
270    Int_t eorFlag = 0;
271    while (!(eorFlag = ebEor())) {
272       struct iovec *ebvec;
273       if ((ebvec = ebGetNextEvent()) == (void *)-1) {
274          Error("Run", "error getting next event (%s)", ebGetLastError());
275          break;
276       }
277       if (ebvec == 0) {
278          // no event, sleep for 1 second and try again
279          gSystem->Sleep(1000);
280          continue;
281       }
282       char *ebdata = (char *) ebvec[0].iov_base;
283 #else
284    while (1) {
285       char *ebdata = 0;
286 #endif
287
288       // Read event header
289       if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
290          if (status == 0) {
291             if (fUseLoop) {
292 #ifndef USE_EB
293                ::lseek(fFd, 0, SEEK_SET);
294 #endif
295                continue;
296             }
297             printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
298             break;
299          }
300          return 1;
301       }
302       ALIDEBUG(3)
303          header.Dump();
304
305       // If we were in looping mode stop directly after a SIGUSR1 signal
306       if (StopLoop()) {
307          Info("Run", "Stopping loop, processed %d events", fNumEvents);
308          break;
309       }
310
311       // Check if event has any hard track flagged
312       Bool_t callFilter = kFALSE;
313       // This needs to be re-engineered for the next ADC...
314       //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
315       //   callFilter = kTRUE;
316
317       // Check event type and skip "Start of Run", "End of Run",
318       // "Start of Run Files" and "End of Run Files"
319       switch (header.GetType()) {
320          case AliRawEventHeader::kStartOfRun:
321          case AliRawEventHeader::kEndOfRun:
322          case AliRawEventHeader::kStartOfRunFiles:
323          case AliRawEventHeader::kEndOfRunFiles:
324             {
325                Int_t skip = header.GetEventSize() - header.HeaderSize();
326 #ifndef USE_EB
327                ::lseek(fFd, skip, SEEK_CUR);
328 #endif
329                ALIDEBUG(1)
330                   Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
331                continue;
332             }
333          default:
334             ALIDEBUG(1) {
335                Int_t s = header.GetEventSize() - header.HeaderSize();
336                Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
337             }
338       }
339
340       // Amount of data left to read for this event
341       Int_t toRead = header.GetEventSize() - header.HeaderSize();
342
343       // If there is less data for this event than the next sub-event
344       // header, something is wrong. Skip to next event...
345       if (toRead < header.HeaderSize()) {
346          ALIDEBUG(1) {
347             Warning("Run",
348                     "header size (%d) exceeds number of bytes to read (%d)\n",
349                     header.HeaderSize(), toRead);
350             header.Dump();
351          }
352          if ((status = DumpEvent(toRead)) != toRead) {
353             if (status == 0)
354                break;
355             return 1;
356          }
357          Error("Run", "discarding event %d (too little data for header)", fNumEvents);
358          continue;
359       }
360
361       // Loop over all sub-events... (LDCs)
362       Int_t nsub = 1;
363       while (toRead > 0) {
364 #ifdef USE_EB
365          ebdata = (char *)ebvec[nsub].iov_base;
366 #endif
367
368          ALIDEBUG(1)
369             Info("Run", "reading LDC %d", nsub);
370
371          AliRawEvent *subEvent = event->NextSubEvent();
372
373          // Read sub-event header
374          AliRawEventHeader &subHeader = *subEvent->GetHeader();
375          if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
376             if (status == 0) {
377                Error("Run", "unexpected EOF reading sub-event header");
378                break;
379             }
380             return 1;
381          }
382
383          ALIDEBUG(3)
384             subHeader.Dump();
385
386          toRead -= subHeader.HeaderSize();
387
388 #ifdef USE_EB
389          ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
390 #endif
391
392          Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
393
394          // Make sure raw data less than left over bytes for current event
395          if (rawSize > toRead) {
396             ALIDEBUG(1) {
397                Warning("Run", "raw data size (%d) exceeds number of "
398                        "bytes to read (%d)\n", rawSize, toRead);
399                subHeader.Dump();
400             }
401             if ((status = DumpEvent(toRead)) != toRead) {
402                if (status == 0)
403                   break;
404                return 1;
405             }
406             Error("Run", "discarding event %d (too much data)", fNumEvents);
407             continue;
408          }
409
410          // Read Equipment Headers (in case of physics or calibration event)
411          if (header.GetType() == AliRawEventHeader::kPhysicsEvent ||
412              header.GetType() == AliRawEventHeader::kCalibrationEvent) {
413             while (rawSize > 0) {
414                AliRawEquipment &equipment = *subEvent->NextEquipment();
415                AliRawEquipmentHeader &equipmentHeader = 
416                   *equipment.GetEquipmentHeader();
417                Int_t equipHeaderSize = equipmentHeader.HeaderSize();
418                if ((status = ReadEquipmentHeader(equipmentHeader, header.DataIsSwapped(),
419                                                  ebdata)) != equipHeaderSize) {
420                   if (status == 0) {
421                      Error("Run", "unexpected EOF reading equipment-header");
422                      break;
423                   }
424                   return 1;
425                }
426                toRead  -= equipHeaderSize;
427                rawSize -= equipHeaderSize;
428 #ifdef USE_EB
429                ebdata = (char *)(ebvec[nsub].iov_base) +
430                         subHeader.HeaderSize() + equipHeaderSize;
431 #endif
432
433                // Read equipment raw data
434                AliRawData &subRaw = *equipment.GetRawData();
435                Int_t eqSize = equipmentHeader.GetEquipmentSize() -
436                               equipHeaderSize;
437                if ((status = ReadRawData(subRaw, eqSize, ebdata)) != eqSize) {
438                   if (status == 0) {
439                      Error("Run", "unexpected EOF reading sub-event raw data");
440                      break;
441                   }
442                   return 1;
443                }
444                toRead  -= eqSize;
445                rawSize -= eqSize;
446
447                if (callFilter) {
448 #ifdef ALI_DATE
449                   if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
450                      Filter(subRaw);
451                   else {
452                      // set size of all sectors without hard track flag to 0
453                      subRaw.SetSize(0);
454                   }
455 #endif
456                }
457             }
458
459          } else {  // Read only raw data but no equipment header
460             AliRawEquipment &equipment = *subEvent->NextEquipment();
461             AliRawData &subRaw = *equipment.GetRawData();
462             if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
463                if (status == 0) {
464                   Error("Run", "unexpected EOF reading sub-event raw data");
465                   break;
466                }
467                return 1;
468             }
469             toRead  -= rawSize;
470
471             if (callFilter) {
472 #ifdef ALI_DATE
473                if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
474                   Filter(subRaw);
475                else {
476                   // set size of all sectors without hard track flag to 0
477                   subRaw.SetSize(0);
478                }
479 #endif
480             }
481          }
482
483          nsub++;
484       }
485
486       // Set stat info for first event of this file
487       if (rawdb->GetEvents() == 0)
488          stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
489
490       // Store raw event in tree
491       rawdb->Fill();
492
493       // Store header in tree
494       if (tagdb) tagdb->Fill();
495
496       fNumEvents++;
497
498       if (!(fNumEvents%10))
499          printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
500
501       // Filling time statistics
502       if (rawdb->GetBytesWritten() > nextChunk) {
503          tnew = timer.RealTime();
504          stats->Fill(tnew-told);
505          told = tnew;
506          timer.Continue();
507          nextChunk += chunkSize;
508       }
509
510       // Check size of raw db. If bigger than maxFileSize, close file
511       // and continue with new file.
512       if (rawdb->FileFull()) {
513
514          printf("Written raw DB at a rate of %.1f MB/s\n",
515                 rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
516
517          // Write stats object to raw db, run db, MySQL and AliEn
518          stats->WriteToDB(rawdb);
519          delete stats;
520
521          if (!rawdb->NextFile()) {
522             Error("Run", "error opening next raw data file");
523             return 1;
524          }
525
526          printf("Filling raw DB %s\n", rawdb->GetDBName());
527          stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
528
529          timer.Start();
530          told = 0, tnew = 0;
531          nextChunk = chunkSize;
532       }
533
534       // Check size of tag db
535       if (tagdb && tagdb->FileFull()) {
536          if (!tagdb->NextFile())
537             tagdb = 0;
538          else
539             printf("Filling tag DB %s\n", tagdb->GetDBName());
540       }
541
542       // Make top event object ready for next event data
543       //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
544       event->Reset();
545
546 #ifdef USE_EB
547       if (!ebReleaseEvent(ebvec)) {
548          Error("Run", "problem releasing event (%s)", ebGetLastError());
549          break;
550       }
551 #endif
552    }
553
554    printf("Written raw DB at a rate of %.1f MB/s\n",
555           rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
556
557    // Write stats to raw db and run db and delete stats object
558    stats->WriteToDB(rawdb);
559    delete stats;
560
561    // Close the raw DB
562    delete rawdb;
563
564    // Close the tag DB
565    delete tagdb;
566
567    // Close input source
568    close(fFd);
569
570 #if 0
571    // Cleanup fifo
572    if (fUseFifo && ::unlink(fgkFifo) == -1) {
573       SysError("Run", "unlink");
574       return 1;
575    }
576 #endif
577
578 #ifdef USE_EB
579    // Print eor flag
580    if (eorFlag) {
581       Info("Run", "event builder reported end of run (%d)", eorFlag);
582    }
583 #endif
584
585    return 0;
586 }
587
588 //______________________________________________________________________________
589 Int_t AliMDC::Read(void *buffer, Int_t length)
590 {
591    // Read exactly length bytes into buffer. Returns number of bytes
592    // received, returns -1 in case of error and 0 for EOF.
593
594    errno = 0;
595
596    if (fFd < 0) return -1;
597
598    Int_t n, nrecv = 0;
599    char *buf = (char *)buffer;
600
601    for (n = 0; n < length; n += nrecv) {
602       if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
603          if (nrecv == 0)
604             break;        // EOF
605          if (errno != EINTR)
606             SysError("Read", "read");
607          return -1;
608       }
609    }
610    return n;
611 }
612
613 //______________________________________________________________________________
614 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
615 {
616    // Read header info from DATE data stream. Returns bytes read (i.e.
617    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
618
619    Int_t nrecv;
620
621    if (eb) {
622       // read from event builder memory area
623       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
624       nrecv = header.HeaderSize();
625    } else {
626       // read from fifo or file
627       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
628            header.HeaderSize()) {
629          if (nrecv == 0)
630             return 0;
631          return -1;
632       }
633    }
634
635    // Swap header data if needed
636    if (header.IsSwapped())
637       header.Swap();
638
639    // Is header valid...
640    if (!header.IsValid()) {
641       Error("ReadHeader", "invalid header format");
642       // try recovery... how?
643       return -1;
644    }
645    if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
646       Error("ReadHeader", "invalid header size");
647       // try recovery... how?
648       return -1;
649    }
650
651    return nrecv;
652 }
653
654 //______________________________________________________________________________
655 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
656                                   Bool_t isSwapped, void *eb)
657 {
658    // Read equipment header info from DATE data stream. Returns bytes read
659    // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
660    // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
661    // and we will swap the header to host format.
662
663    Int_t nrecv;
664
665    if (eb) {
666       // read from event builder memory area
667       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
668       nrecv = header.HeaderSize();
669    } else {
670       // read from fifo or file
671       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
672            header.HeaderSize()) {
673          if (nrecv == 0)
674             return 0;
675          return -1;
676       }
677    }
678
679    // Swap equipment header data if needed
680    if (isSwapped)
681       header.Swap();
682
683    if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
684       Error("ReadEquipmentHeader", "invalid equipment header size");
685       // try recovery... how?
686       return -1;
687    }
688
689    return nrecv;
690 }
691
692 //______________________________________________________________________________
693 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
694 {
695    // Read raw data from DATE data stream. Returns bytes read (i.e.
696    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
697
698    Int_t nrecv;
699
700    if (eb) {
701       // read from event builder memory area
702       raw.SetBuffer(eb, size);
703       nrecv = size;
704    } else {
705       // read from fifo or file
706       raw.SetSize(size);
707       if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
708          if (nrecv == 0) {
709             Error("ReadRawData", "unexpected EOF");
710             return 0;
711          }
712          return -1;
713       }
714    }
715
716    return nrecv;
717 }
718
719 //______________________________________________________________________________
720 Int_t AliMDC::DumpEvent(Int_t toRead)
721 {
722    // This case should not happen, but if it does try to handle it
723    // gracefully by reading the rest of the event and discarding it.
724    // Returns bytes read, -1 in case of fatal error and 0 for EOF.
725
726    Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
727
728    Int_t nrecv;
729    char *tbuf = new char[toRead];
730    if ((nrecv = Read(tbuf, toRead)) != toRead) {
731       if (nrecv == 0) {
732          Error("DumpEvent", "unexpected EOF");
733          return 0;
734       }
735       return -1;
736    }
737    delete [] tbuf;
738
739    return nrecv;
740 }
741
742 //______________________________________________________________________________
743 Int_t AliMDC::Filter(AliRawData &raw)
744 {
745    // Call 3rd level filter for this raw data segment.
746
747 #ifdef USE_HLT
748
749    // Add HLT code here
750
751 #else
752
753    raw.GetSize();
754    printf("Filter called for event %d\n", fNumEvents);
755
756 #endif
757
758    return 0;
759 }
760
761 //______________________________________________________________________________
762 AliMDC::AliMDCInterruptHandler::AliMDCInterruptHandler(const 
763                                                        AliMDCInterruptHandler&
764                                                        handler): 
765   TSignalHandler(handler) 
766 {
767 // copy constructor
768
769   Fatal("AliMDCInterruptHandler", "copy constructor not implemented");
770 }
771
772 //______________________________________________________________________________
773 AliMDC::AliMDCInterruptHandler& 
774   AliMDC::AliMDCInterruptHandler::operator = (const AliMDCInterruptHandler& 
775                                               /*handler*/)
776 {
777 // assignment operator
778
779   Fatal("operator =", "assignment operator not implemented");
780   return *this;
781 }