]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliRawEvent.cxx
Update for station2:
[u/mrichter/AliRoot.git] / RAW / AliRawEvent.cxx
1 // @(#)alimdc:$Name$:$Id$
2 // Author: Fons Rademakers  26/11/99
3 // Updated: Dario Favretto  15/04/2003
4
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #if defined(__DECCXX)
8 #include <sys/statvfs.h>
9 #else
10 #if defined(__APPLE__)
11 #include <sys/param.h>
12 #include <sys/mount.h>
13 #else
14 #include <sys/vfs.h>
15 #endif
16 #endif
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <errno.h>
21
22 #include <TBuffer.h>
23 #include <TH1.h>
24 #include <TSystem.h>
25 #include <TError.h>
26 #include <TStopwatch.h>
27 #include <TSQLServer.h>
28 #include <TSQLResult.h>
29
30 #if defined(__APPLE__)
31 #undef Free
32 #endif
33 #include "AliRawEvent.h"
34
35 // Good for Linux
36 #define long32 int
37 #include "DateEvent.h"
38
39 #ifdef USE_EB
40 #include "libDateEb.h"
41 #endif
42
43
44 ClassImp(AliRawEvent)
45 ClassImp(AliRawEventHeader)
46 ClassImp(AliRawEquipmentHeader)
47 ClassImp(AliRawData)
48 ClassImp(AliStats)
49 ClassImp(AliRawDB)
50 ClassImp(AliRawRFIODB)
51 ClassImp(AliRawRootdDB)
52 ClassImp(AliRawNullDB)
53 ClassImp(AliTagDB)
54 ClassImp(AliTagNullDB)
55 ClassImp(AliRunDB)
56 ClassImp(AliMDC)
57
58 // Which MDC is this...
59 const Int_t kMDC = 4;
60
61 // Fixed file system locations for the different DB's
62 #ifdef USE_RDM
63 const char *kFifo       = "/tmp/alimdc.fifo";
64 const char *kRawDBFS[2] = { "/tmp/mdc1", "/tmp/mdc2" };
65 const char *kTagDBFS    = "/tmp/mdc1/tags";
66 const char *kRunDBFS    = "/tmp/mdc1/meta";
67 const char *kRFIOFS     = "rfio:/castor/cern.ch/user/r/rdm";
68 const char *kRootdFS    = "root://localhost//tmp/mdc1";
69 #else
70 const char *kFifo       = "/tmp/alimdc.fifo";
71 const char *kRawDBFS[2] = { "/scratch/mdc1", "/scratch/mdc2" };
72 const char *kTagDBFS    = "/scratch/mdc1/tags";
73 const char *kRunDBFS    = "/scratch/mdc1/meta";
74 const char *kRFIOFS     = "rfio:/castor/cern.ch/lcg/alicemdc4";
75 const char *kRootdFS    = "root://localhost//tmp/mdc1";
76 #endif
77
78 // Maximum size of tag db files
79 const Double_t kMaxTagFileSize = 2.5e8;    // 250MB
80
81 Bool_t AliMDC::fgDeleteFiles = kFALSE;
82
83 AliMDC *gAliMDC = 0;
84
85
86 //______________________________________________________________________________
87 Bool_t AliRawEventHeader::DataIsSwapped() const
88 {
89    // Returns true if event data is swapped.
90
91    if (TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_EVENT_SWAPPED))
92       return kTRUE;
93    return kFALSE;
94 }
95
96 //______________________________________________________________________________
97 void AliRawEventHeader::Swap()
98 {
99    // Swap header data.
100
101    if (IsSwapped()) {
102       fSize         = net2host(fSize);
103       fMagic        = net2host(fMagic);
104       fHeadLen      = net2host(fHeadLen);
105       fVersion      = net2host(fVersion);
106       fType         = net2host(fType);
107       fRunNb        = net2host(fRunNb);
108       for (int i = 0; i < kIdWords; i++)
109          fId[i] = net2host(fId[i]);
110       for (int i = 0; i < kTriggerWords; i++)
111          fTriggerPattern[i] = net2host(fTriggerPattern[i]);
112       for (int i = 0; i < kDetectorWords; i++)
113          fDetectorPattern[i] = net2host(fDetectorPattern[i]);
114       for (int i = 0; i < kAttributeWords; i++)
115          fTypeAttribute[i] = net2host(fTypeAttribute[i]);
116       fLDCId        = net2host(fLDCId);
117       fGDCId        = net2host(fGDCId);
118    }
119 }
120
121 //______________________________________________________________________________
122 UInt_t AliRawEventHeader::GetEventInRun() const
123 {
124    // Get event number in run. Correct for fixed target mode which is used
125    // in the Data Challenge Setup.
126
127    if (!TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_ORBIT_BC)) {
128       return EVENT_ID_GET_NB_IN_RUN(fId);
129    }
130    return 0;
131 }
132
133 //______________________________________________________________________________
134 const char *AliRawEventHeader::GetTypeName() const
135 {
136    // Get event type as a string.
137
138    switch (GetType()) {
139       case kStartOfRun:
140          return "START_OF_RUN";
141          break;
142       case kEndOfRun:
143          return "END_OF_RUN";
144          break;
145       case kStartOfRunFiles:
146          return "START_OF_RUN_FILES";
147          break;
148       case kEndOfRunFiles:
149          return "END_OF_RUN_FILES";
150          break;
151       case kStartOfBurst:
152          return "START_OF_BURST";
153          break;
154       case kEndOfBurst:
155          return "END_OF_BURST";
156          break;
157       case kPhysicsEvent:
158          return "PHYSICS_EVENT";
159          break;
160       case kCalibrationEvent:
161          return "CALIBRATION_EVENT";
162          break;
163       case kFormatError:
164          return "EVENT_FORMAT_ERROR";
165          break;
166       default:
167          return "*** UNKNOWN EVENT TYPE ***";
168          break;
169    }
170 }
171
172
173 //______________________________________________________________________________
174 void AliRawEquipmentHeader::Swap()
175 {
176    // Swap equipment header data. There is no way to see if the data
177    // has already been swapped. This method is only called when the
178    // header is read from the DATE event builder (GDC).
179                                                                                 
180    fSize                 = net2host(fSize);
181    fEquipmentType        = net2host(fEquipmentType);
182    fEquipmentID          = net2host(fEquipmentID);
183    fBasicElementSizeType = net2host(fBasicElementSizeType);
184    for (int i = 0; i < kAttributeWords; i++)
185       fTypeAttribute[i] = net2host(fTypeAttribute[i]);
186 }
187
188
189 //______________________________________________________________________________
190 AliRawEvent::AliRawEvent()
191 {
192    // Create ALICE event object. If ownData is kFALSE we will use a static
193    // raw data object, otherwise a private copy will be made.
194
195    fNSubEvents = 0;
196    fEvtHdr     = new AliRawEventHeader;
197    fEqpHdr     = 0;
198    fRawData    = 0;
199    fSubEvents  = 0;
200 }
201
202 //______________________________________________________________________________
203 AliRawEquipmentHeader *AliRawEvent::GetEquipmentHeader()
204 {
205    // Get equipment header part of AliRawEvent.
206
207    if (!fEqpHdr)
208       fEqpHdr = new AliRawEquipmentHeader;
209
210    return fEqpHdr;
211 }
212
213 //______________________________________________________________________________
214 AliRawData *AliRawEvent::GetRawData()
215 {
216    // Get raw data part of AliRawEvent.
217
218    if (!fRawData)
219       fRawData = new AliRawData;
220
221    return fRawData;
222 }
223
224 //______________________________________________________________________________
225 AliRawEvent *AliRawEvent::NextSubEvent()
226 {
227    // Returns next sub-event object.
228
229    if (!fSubEvents)
230       fSubEvents = new TObjArray(100); // arbitrary, probably enough to prevent resizing
231
232    if (fSubEvents->GetSize() <= fNSubEvents) {
233       fSubEvents->Expand(fNSubEvents+10);
234       Warning("NextSubEvent", "expanded fSubEvents by 10 to %d",
235               fSubEvents->GetSize());
236    }
237
238    AliRawEvent *ev;
239    if (!(ev = (AliRawEvent *)fSubEvents->At(fNSubEvents))) {
240       ev = new AliRawEvent;
241       fSubEvents->AddAt(ev, fNSubEvents);
242    }
243
244    fNSubEvents++;
245
246    return ev;
247 }
248
249 //______________________________________________________________________________
250 AliRawEvent *AliRawEvent::GetSubEvent(Int_t index)
251 {
252   return (AliRawEvent *)fSubEvents->At(index);
253 }
254
255 //______________________________________________________________________________
256 void AliRawEvent::Reset()
257 {
258    // Reset the event in case it needs to be re-used (avoiding costly
259    // new/delete cycle). We reset the size marker for the AliRawData
260    // objects and the sub event counter.
261
262    for (int i = 0; i < fNSubEvents; i++) {
263       AliRawEvent *ev = (AliRawEvent *)fSubEvents->At(i);
264       ev->GetRawData()->SetSize(0);
265    }
266    fNSubEvents = 0;
267 }
268
269 //______________________________________________________________________________
270 AliRawEvent::~AliRawEvent()
271 {
272    // Clean up event object. Delete also, possible, private raw data.
273
274    delete fEvtHdr;
275    delete fEqpHdr;
276    delete fRawData;
277    if (fSubEvents)
278       fSubEvents->Delete();
279    delete fSubEvents;
280 }
281
282 //______________________________________________________________________________
283 AliStats::AliStats(const char *filename, Int_t compmode, Bool_t filter)
284 {
285    // Create statistics object.
286
287    fEvents     = 0;
288    fFirstRun   = 0;
289    fFirstEvent = 0;
290    fLastRun    = 0;
291    fLastEvent  = 0;
292    fChunk      = -0.5;
293    fFileName   = filename;
294    fCompMode   = compmode;
295    fFilter     = filter;
296    fRTHist     = 0;
297 }
298
299 //______________________________________________________________________________
300 AliStats::~AliStats()
301 {
302    // Cleanup stats object.
303
304    delete fRTHist;
305 }
306
307 //______________________________________________________________________________
308 AliStats &AliStats::operator=(const AliStats &rhs)
309 {
310    // AliStats assignment operator.
311
312    if (this != &rhs) {
313       TObject::operator=(rhs);
314       fEvents     = rhs.fEvents;
315       fFirstRun   = rhs.fFirstRun;
316       fFirstEvent = rhs.fFirstEvent;
317       fLastRun    = rhs.fLastRun;
318       fLastEvent  = rhs.fLastEvent;
319       fBegin      = rhs.fBegin;
320       fEnd        = rhs.fEnd;
321       fFileName   = rhs.fFileName;
322       fFileSize   = rhs.fFileSize;
323       fCompFactor = rhs.fCompFactor;
324       fCompMode   = rhs.fCompMode;
325       fFilter     = rhs.fFilter;
326       fRTHist     = rhs.fRTHist ? (TH1F*) rhs.fRTHist->Clone() : 0;
327       fChunk      = rhs.fChunk;
328    }
329    return *this;
330 }
331
332 //______________________________________________________________________________
333 void AliStats::Fill(Float_t time)
334 {
335    // Fill histogram. This histogram shows the (hopefully constant) time
336    // it takes to fill the ROOT DB.
337    // Expects to be called 100 times for each file.
338
339    if (!fRTHist) {
340       fRTHist = new TH1F("rtime","Real-time to write data chunk", 100, 0, 100);
341       fRTHist->SetDirectory(0);
342    }
343
344    fRTHist->Fill(fChunk, time);
345    fChunk += 1.0;
346 }
347
348 //______________________________________________________________________________
349 void AliStats::WriteToDB(AliRawDB *rawdb)
350 {
351    // Write stats to raw DB, local run DB and global MySQL DB.
352
353    AliRawEventHeader &header = *rawdb->GetEvent()->GetHeader();
354
355    // Write stats into RawDB
356    TDirectory *ds = gDirectory;
357    rawdb->GetDB()->cd();
358    SetEvents(rawdb->GetEvents());
359    SetLastId(header.GetRunNumber(), header.GetEventInRun());
360    SetFileSize(rawdb->GetBytesWritten());
361    SetCompressionFactor(rawdb->GetCompressionFactor());
362    SetEndTime();
363    Write("stats");
364    ds->cd();
365
366    // Write stats also in the bookkeeping RunDB
367    AliRunDB *rundb = new AliRunDB;
368    rundb->Update(this);
369    rundb->UpdateRDBMS(this);
370    delete rundb;
371 }
372
373 //______________________________________________________________________________
374 AliRawDB::AliRawDB(AliRawEvent *event, Double_t maxsize, Int_t compress,
375                    Bool_t create)
376 {
377    // Create a new raw DB containing at most maxsize bytes.
378
379    fEvent    = event;
380    fMaxSize  = maxsize;
381    fCompress = compress;
382
383    // Consistency check with DATE header file
384    if (fEvent->GetHeader()->HeaderSize() != EVENT_HEAD_BASE_SIZE) {
385       Error("AliRawDB", "inconsistency between DATE and AliRawEvent headers");
386       MakeZombie();
387       return;
388    }
389
390    if (create) {
391       if (!Create())
392          MakeZombie();
393    }
394 }
395
396 //______________________________________________________________________________
397 Bool_t AliRawDB::FSHasSpace(const char *fs)
398 {
399    // Check for at least fMaxSize bytes of free space on the file system.
400    // If the space is not available return kFALSE, kTRUE otherwise.
401
402    Long_t id, bsize, blocks, bfree;
403
404    if (gSystem->GetFsInfo(fs, &id, &bsize, &blocks, &bfree) == 1) {
405       Error("FSHasSpace", "could not stat file system %s", fs);
406       return kFALSE;
407    }
408
409    // Leave 5 percent of diskspace free
410    Double_t avail = Double_t(bfree) * 0.95;
411    if (avail*bsize > fMaxSize)
412       return kTRUE;
413
414    Warning("FSHasSpace", "no space on file system %s", fs);
415    return kFALSE;
416 }
417
418 //______________________________________________________________________________
419 const char *AliRawDB::GetFileName()
420 {
421    // Return filename based on hostname and date and time. This will make
422    // each file unique. Also makes sure (via FSHasSpace()) that there is
423    // enough space on the file system to store the file. Returns 0 in
424    // case of error or interrupt signal.
425
426    static TString fname;
427    static Bool_t  fstoggle = kFALSE;
428
429    TString fs = fstoggle ? kRawDBFS[1] : kRawDBFS[0];
430    TDatime dt;
431
432    TString hostname = gSystem->HostName();
433    Int_t pos;
434    if ((pos = hostname.Index(".")) != kNPOS)
435       hostname.Remove(pos);
436
437    if (!FSHasSpace(fs)) {
438       while (1) {
439          fstoggle = !fstoggle;
440          fs = fstoggle ? kRawDBFS[1] : kRawDBFS[0];
441          if (FSHasSpace(fs)) break;
442          Info("GetFileName", "sleeping 30 seconds before retrying...");
443          gSystem->Sleep(30000);   // sleep for 30 seconds
444          if (gAliMDC && gAliMDC->StopLoop())
445             return 0;
446       }
447    }
448
449    fname = fs + "/" + hostname + "_";
450    fname += dt.GetDate();
451    fname += "_";
452    fname += dt.GetTime();
453    fname += ".root";
454
455    fstoggle = !fstoggle;
456
457    return fname;
458 }
459
460 //______________________________________________________________________________
461 Bool_t AliRawDB::Create()
462 {
463    // Create a new raw DB.
464
465 again:
466    const char *fname = GetFileName();
467    if (!fname) return kFALSE;
468
469    fRawDB = TFile::Open(fname, "RECREATE",
470                         Form("ALICE MDC%d raw DB", kMDC), fCompress);
471    if (!fRawDB) {
472       Error("Create", "did not find right plugin to open file");
473       return kFALSE;
474    }
475    if (fRawDB->IsZombie()) {
476       if (fRawDB->GetErrno() == ENOSPC ||
477           fRawDB->GetErrno() == 1018   ||   // SECOMERR
478           fRawDB->GetErrno() == 1027) {     // SESYSERR
479          fRawDB->ResetErrno();
480          delete fRawDB;
481          Warning("Create", "file is zombie, sleeping 10 seconds before retrying...");
482          gSystem->Sleep(10000);   // sleep 10 seconds before retrying
483          goto again;
484       }
485       Error("Create", "error opening raw DB");
486       fRawDB = 0;
487       return kFALSE;
488    }
489
490    // Create raw data TTree
491    MakeTree();
492
493    return kTRUE;
494 }
495
496 //______________________________________________________________________________
497 void AliRawDB::MakeTree()
498 {
499    // Create ROOT Tree object container.
500
501    fTree = new TTree("RAW", Form("ALICE MDC%d raw data tree", kMDC));
502    fTree->SetAutoSave(2000000000);  // autosave when 2 Gbyte written
503
504    Int_t bufsize = 256000;
505    // splitting 29.6 MB/s, no splitting 35.3 MB/s on P4 2GHz 15k SCSI
506    //Int_t split   = 1;
507    Int_t split   = 0;
508    fTree->Branch("rawevent", "AliRawEvent", &fEvent, bufsize, split);
509 }
510
511 //______________________________________________________________________________
512 void AliRawDB::Close()
513 {
514    // Close raw DB.
515
516    if (!fRawDB) return;
517
518    fRawDB->cd();
519
520    // Write the tree.
521    fTree->Write();
522
523    // Close DB, this also deletes the fTree
524    fRawDB->Close();
525
526    if (AliMDC::DeleteFiles()) {
527       gSystem->Unlink(fRawDB->GetName());
528       delete fRawDB;
529       fRawDB = 0;
530       return;
531    }
532
533    // Create semaphore to say this file is finished
534    Int_t tfd = ::creat(Form("%s.done", fRawDB->GetName()), 0644);
535    close(tfd);
536
537    delete fRawDB;
538    fRawDB = 0;
539 }
540
541 //______________________________________________________________________________
542 Bool_t AliRawDB::NextFile()
543 {
544    // Close te current file and open a new one.
545    // Returns kFALSE in case opening failed.
546
547    Close();
548
549    if (!Create()) return kFALSE;
550    return kTRUE;
551 }
552
553 //______________________________________________________________________________
554 Float_t AliRawDB::GetCompressionFactor() const
555 {
556    // Return compression factor.
557
558    if (fTree->GetZipBytes() == 0.)
559       return 1.0;
560    else
561       return fTree->GetTotBytes()/fTree->GetZipBytes();
562 }
563
564
565 //______________________________________________________________________________
566 AliRawRFIODB::AliRawRFIODB(AliRawEvent *event, Double_t maxsize, Int_t compress)
567    : AliRawDB(event, maxsize, compress, kFALSE)
568 {
569    // Create a new raw DB that will be accessed via RFIO.
570
571 #ifndef USE_RDM
572    static int init = 0;
573    // Set STAGE_POOL environment variable to current host
574    if (!init) {
575       // THESE ENVIRONMENT SYMBOLS ARE NOW DEFINED BY THE ALICE DATE SETUP
576       // THEREFORE WE SHALL NOT USE ANY HARDCODED VALUES BUT RATHER USE
577       // WHATEVER HAS BEEN SET IN THE DATE SITE
578       //gSystem->Setenv("STAGE_POOL", "mdc4");
579       //gSystem->Setenv("STAGE_HOST", "lxshare003d");
580       init = 1;
581    }
582 #endif
583
584    if (!Create())
585       MakeZombie();
586    else
587       fRawDB->UseCache(50, 0x200000);  //0x100000 = 1MB)
588 }
589
590 //______________________________________________________________________________
591 const char *AliRawRFIODB::GetFileName()
592 {
593    // Return filename based on hostname and date and time. This will make
594    // each file unique. Also the directory will be made unique for each
595    // day by adding the date to the fs. Assumes there is always enough
596    // space on the device.
597
598    static TString fname;
599
600    TString fs = kRFIOFS;
601    TDatime dt;
602
603    // make a new subdirectory for each day
604    fs += "/adc-";
605    fs += dt.GetDate();
606
607    Long_t id, size, flags, time;
608    if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
609       // directory does not exist, create it
610       if (gSystem->mkdir(fs, kTRUE) == -1) {
611          Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
612                kRFIOFS);
613          fs = kRFIOFS;
614       }
615    }
616    // FIXME: should check if fs is a directory
617
618    TString hostname = gSystem->HostName();
619    Int_t pos;
620    if ((pos = hostname.Index(".")) != kNPOS)
621       hostname.Remove(pos);
622
623    fname = fs + "/" + hostname + "_";
624    fname += dt.GetDate();
625    fname += "_";
626    fname += dt.GetTime();
627    fname += ".root";
628
629    return fname;
630 }
631
632 //______________________________________________________________________________
633 void AliRawRFIODB::Close()
634 {
635    // Close raw RFIO DB.
636
637    if (!fRawDB) return;
638
639    fRawDB->cd();
640
641    // Write the tree.
642    fTree->Write();
643
644    // Close DB, this also deletes the fTree
645    fRawDB->Close();
646
647    if (AliMDC::DeleteFiles())
648       gSystem->Exec(Form("rfrm %s", fRawDB->GetName()));
649
650    delete fRawDB;
651    fRawDB = 0;
652 }
653
654
655 //______________________________________________________________________________
656 AliRawRootdDB::AliRawRootdDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
657    : AliRawDB(event, maxsize, compress, kFALSE)
658 {
659    // Create a new raw DB that will be accessed via rootd daemon.
660
661    if (!Create())
662       MakeZombie();
663    else
664       fRawDB->UseCache(50, 0x200000);  //0x100000 = 1MB)
665 }
666
667 //______________________________________________________________________________
668 const char *AliRawRootdDB::GetFileName()
669 {
670    // Return filename based on hostname and date and time. This will make
671    // each file unique. Also the directory will be made unique for each
672    // day by adding the date to the fs. Assumes there is always enough
673    // space on the device.
674
675    static TString fname;
676
677    TString fs = kRootdFS;
678    TDatime dt;
679
680 #if 0
681    // make a new subdirectory for each day
682    fs += "/adc-";
683    fs += dt.GetDate();
684
685    Long_t id, size, flags, time;
686    if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
687       // directory does not exist, create it
688       if (gSystem->mkdir(fs, kTRUE) == -1) {
689          Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
690                kRootdFS);
691          fs = kRootdFS;
692       }
693    }
694    // FIXME: should check if fs is a directory
695 #endif
696
697    TString hostname = gSystem->HostName();
698    Int_t pos;
699    if ((pos = hostname.Index(".")) != kNPOS)
700       hostname.Remove(pos);
701
702    fname = fs + "/" + hostname + "_";
703    fname += dt.GetDate();
704    fname += "_";
705    fname += dt.GetTime();
706    fname += ".root";
707
708    return fname;
709 }
710
711 //______________________________________________________________________________
712 void AliRawRootdDB::Close()
713 {
714    // Close raw rootd DB.
715
716    if (!fRawDB) return;
717
718    fRawDB->cd();
719
720    // Write the tree.
721    fTree->Write();
722
723    // Close DB, this also deletes the fTree
724    fRawDB->Close();
725
726 #if 0
727    // can use services of TFTP
728    if (AliMDC::DeleteFiles())
729       gSystem->Exec(Form("rfrm %s", fRawDB->GetName()));
730 #endif
731
732    delete fRawDB;
733    fRawDB = 0;
734 }
735
736
737 //______________________________________________________________________________
738 AliRawNullDB::AliRawNullDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
739    : AliRawDB(event, maxsize, compress, kFALSE)
740 {
741    // Create a new raw DB that will wrtie to /dev/null.
742
743    if (!Create())
744       MakeZombie();
745 }
746
747 //______________________________________________________________________________
748 const char *AliRawNullDB::GetFileName()
749 {
750    // Return /dev/null as filename.
751
752    return "/dev/null";
753 }
754
755 //______________________________________________________________________________
756 void AliRawNullDB::Close()
757 {
758    // Close raw RFIO DB.
759
760    if (!fRawDB) return;
761
762    fRawDB->cd();
763
764    // Write the tree.
765    fTree->Write();
766
767    // Close DB, this also deletes the fTree
768    fRawDB->Close();
769
770    delete fRawDB;
771    fRawDB = 0;
772 }
773
774
775 //______________________________________________________________________________
776 AliTagDB::AliTagDB(AliRawEventHeader *header, Double_t maxsize, Bool_t create)
777 {
778    // Create tag DB.
779
780    fHeader   = header;
781    fMaxSize  = maxsize;
782
783    if (create) {
784       if (!Create())
785          MakeZombie();
786    }
787 }
788
789 //______________________________________________________________________________
790 Bool_t AliTagDB::Create()
791 {
792    // Create a new tag DB.
793
794    fTagDB = new TFile(GetFileName(), "RECREATE",
795                       Form("ALICE MDC%d tag DB", kMDC), 1);
796    if (fTagDB->IsZombie()) {
797       Error("Create", "error opening tag DB");
798       fTagDB = 0;
799       return kFALSE;
800    }
801
802    // Create ROOT Tree object container
803    fTree = new TTree("TAG", Form("ALICE MDC%d header data tree", kMDC));
804    fTree->SetAutoSave(100000000);  // autosave when 100 Mbyte written
805
806    Int_t bufsize = 32000;
807    Int_t split   = 1;
808    fTree->Branch("header", "AliRawEventHeader", &fHeader, bufsize, split);
809
810    return kTRUE;
811 }
812
813 //______________________________________________________________________________
814 void AliTagDB::Close()
815 {
816    // Close tag DB.
817
818    if (!fTagDB) return;
819
820    fTagDB->cd();
821
822    // Write the tree.
823    fTree->Write();
824
825    // Close DB, this also deletes the fTree
826    fTagDB->Close();
827
828    if (AliMDC::DeleteFiles())
829       gSystem->Unlink(fTagDB->GetName());
830
831    delete fTagDB;
832    fTagDB = 0;
833 }
834
835 //______________________________________________________________________________
836 Bool_t AliTagDB::NextFile()
837 {
838    // Close te current file and open a new one.
839    // Returns kFALSE in case opening failed.
840
841    Close();
842
843    if (!Create()) return kFALSE;
844    return kTRUE;
845 }
846
847 //______________________________________________________________________________
848 Float_t AliTagDB::GetCompressionFactor() const
849 {
850    // Return compression factor.
851
852    if (fTree->GetZipBytes() == 0.)
853       return 1.0;
854    else
855       return fTree->GetTotBytes()/fTree->GetZipBytes();
856 }
857
858 //______________________________________________________________________________
859 const char *AliTagDB::GetFileName()
860 {
861    // Return filename based on hostname and date and time. This will make
862    // each file unique. The tags will be stored in the /data1/tags directory.
863
864    static char fname[64];
865    const char *fs = kTagDBFS;
866
867    // check that fs exists (crude check fails if fs is a file)
868    gSystem->MakeDirectory(fs);
869
870    char hostname[64];
871
872    strcpy(hostname, gSystem->HostName());
873
874    char *s;
875    if ((s = strchr(hostname, '.')))
876       *s = 0;
877
878    TDatime dt;
879
880    sprintf(fname, "%s/%s_%d_%d.root", fs, hostname, dt.GetDate(), dt.GetTime());
881
882    return fname;
883 }
884
885
886 //______________________________________________________________________________
887 AliTagNullDB::AliTagNullDB(AliRawEventHeader *header, Double_t maxsize) :
888    AliTagDB(header, maxsize, kFALSE)
889 {
890    // Create tag db writing to /dev/null.
891
892    if (!Create())
893       MakeZombie();
894 }
895
896 //______________________________________________________________________________
897 const char *AliTagNullDB::GetFileName()
898 {
899    // Return /dev/null as filename.
900
901    return "/dev/null";
902 }
903
904 //______________________________________________________________________________
905 void AliTagNullDB::Close()
906 {
907    // Close null tag DB.
908
909    if (!fTagDB) return;
910
911    fTagDB->cd();
912
913    // Write the tree.
914    fTree->Write();
915
916    // Close DB, this also deletes the fTree
917    fTagDB->Close();
918
919    delete fTagDB;
920    fTagDB = 0;
921 }
922
923
924 //______________________________________________________________________________
925 AliRunDB::AliRunDB()
926 {
927    // Open run database, and get or create tree.
928
929    // Get hostname
930    char hostname[64], filename[64];
931    const char *fs = kRunDBFS;
932
933    // check that fs exists (crude check fails if fs is a file)
934    gSystem->MakeDirectory(fs);
935
936    strcpy(hostname, gSystem->HostName());
937
938    char *s;
939    if ((s = strchr(hostname, '.')))
940       *s = 0;
941
942    sprintf(filename, "%s/%s_rundb.root", fs, hostname);
943
944    if (!gSystem->AccessPathName(filename, kFileExists))
945       fRunDB = new TFile(filename, "UPDATE");
946    else
947       fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", kMDC));
948 }
949
950 //______________________________________________________________________________
951 void AliRunDB::Update(AliStats *stats)
952 {
953    // Add stats object to database.
954
955    TDirectory *ds = gDirectory;
956    fRunDB->cd();
957
958    char sname[64];
959    char *s = (char*)strrchr(stats->GetFileName(), '/');
960    if (s) {
961       s++;
962       strcpy(sname, s);
963    } else
964       strcpy(sname, stats->GetFileName());
965    s = strchr(sname, '.');
966    if (s) *s = 0;
967
968    stats->Write(sname);
969
970    ds->cd();
971 }
972
973 //______________________________________________________________________________
974 void AliRunDB::UpdateRDBMS(AliStats *stats)
975 {
976    // Add stats object to central MySQL DB.
977
978    char sql[4096];
979    char bt[25], et[25];
980
981    strcpy(bt, stats->GetBeginTime().AsSQLString());
982    strcpy(et, stats->GetEndTime().AsSQLString());
983
984    sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
985            "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", kMDC,
986            stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
987            stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
988            stats->GetLastEvent(), stats->GetCompressionMode(),
989            stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
990            bt, et);
991
992    // open connection to MySQL server on pcsalo
993    TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");
994
995    if (!db || db->IsZombie()) {
996       Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
997       printf("%s\n", sql);
998       delete db;
999       return;
1000    }
1001
1002    TSQLResult *res = db->Query(sql);
1003
1004    if (!res) {
1005       Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", kMDC));
1006       printf("%s\n", sql);
1007    }
1008
1009    delete res;
1010    delete db;
1011 }
1012
1013 //______________________________________________________________________________
1014 void AliRunDB::Close()
1015 {
1016    // Close run database.
1017
1018    fRunDB->Close();
1019    delete fRunDB;
1020 }
1021
1022 //----------------- Use SIGUSR1 to interupt endless loop -----------------------
1023 class AliMDCInterruptHandler : public TSignalHandler {
1024 private:
1025    AliMDC *fMDC;   // alimdc to signal
1026 public:
1027    AliMDCInterruptHandler(AliMDC *mdc) : TSignalHandler(kSigUser1, kFALSE), fMDC(mdc) { }
1028    Bool_t Notify() { fMDC->SetStopLoop(); return kTRUE; }
1029 };
1030
1031 //______________________________________________________________________________
1032 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
1033                Bool_t useRFIO, Bool_t useROOTD, Bool_t useDEVNULL,
1034                Bool_t useLoop, Bool_t delFiles)
1035 {
1036    // Create MDC processor object.
1037
1038    fFd           = fd;
1039    fCompress     = compress;
1040    fMaxFileSize  = maxFileSize;
1041    fUseFilter    = useFilter;
1042    fUseRFIO      = useRFIO;
1043    fUseRootd     = useROOTD;
1044    fUseDevNull   = useDEVNULL;
1045    fUseLoop      = useLoop;
1046    fUseFifo      = kFALSE;
1047    fUseEb        = kFALSE;
1048    fStopLoop     = kFALSE;
1049    fNumEvents    = 0;
1050    fDebugLevel   = 0;
1051    fgDeleteFiles = delFiles;
1052
1053    if (fFd == -1) {
1054 #ifdef USE_EB
1055      if (!ebRegister()) {
1056         Error("AliMDC", "cannot register with the event builder (%s)",
1057               ebGetLastError());
1058         return;
1059      }
1060      fUseEb = kTRUE;
1061 #else
1062      if ((mkfifo(kFifo, 0644) < 0) && (errno != EEXIST)) {
1063          Error("AliMDC", "cannot create fifo %s", kFifo);
1064          return;
1065       }
1066       if ((chmod(kFifo, 0666) == -1) && (errno != EPERM)) {
1067          Error("AliMDC", "cannot change permission of fifo %s", kFifo);
1068          return;
1069       }
1070       if ((fFd = open(kFifo, O_RDONLY)) == -1) {
1071          Error("AliMDC", "cannot open input file %s", kFifo);
1072          return;
1073       }
1074       fUseFifo = kTRUE;
1075 #endif
1076       fUseLoop = kFALSE;
1077    }
1078
1079    printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
1080           "looping = %s, compression = %d, delete files = %s",
1081           fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
1082           fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
1083           fgDeleteFiles ? "yes" : "no");
1084    if (fUseRFIO)
1085       printf(", use RFIO\n");
1086    else if (fUseRootd)
1087       printf(", use rootd\n");
1088    else if (fUseDevNull)
1089       printf(", write raw data to /dev/null\n");
1090    else
1091       printf("\n");
1092
1093    // install SIGUSR1 handler to allow clean interrupts
1094    gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
1095
1096    gAliMDC = this;
1097 }
1098
1099 //______________________________________________________________________________
1100 Int_t AliMDC::Run()
1101 {
1102    // Run the MDC processor. Read from the input stream and only return
1103    // when the input gave and EOF or a fatal error occured. On success 0
1104    // is returned, 1 in case of a fatality.
1105
1106    TStopwatch timer;
1107    Int_t status;
1108
1109    // Make sure needed directories exist
1110    const char *dirs[4];
1111    dirs[0] = kRawDBFS[0];
1112    dirs[1] = kRawDBFS[1];
1113    dirs[2] = kTagDBFS;
1114    dirs[3] = kRunDBFS;
1115    for (int idir = 0; idir < 4; idir++) {
1116       gSystem->ResetErrno();
1117       gSystem->MakeDirectory(dirs[idir]);
1118       if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
1119          SysError("Run", "mkdir %s", dirs[idir]);
1120          return 1;
1121       }
1122    }
1123
1124    // Used for statistics
1125    timer.Start();
1126    Double_t told = 0, tnew = 0;
1127    Float_t  chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
1128
1129    // Event object used to store event data.
1130    AliRawEvent *event = new AliRawEvent;
1131
1132    // Create new raw DB.
1133    AliRawDB *rawdb;
1134    if (fUseRFIO)
1135       rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
1136    else if (fUseRootd)
1137       rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
1138    else if (fUseDevNull)
1139       rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
1140    else
1141       rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
1142
1143    if (rawdb->IsZombie()) return 1;
1144    printf("Filling raw DB %s\n", rawdb->GetDBName());
1145
1146    // Create new tag DB.
1147    AliTagDB *tagdb;
1148    if (fUseDevNull)
1149       tagdb = new AliTagNullDB(event->GetHeader(), kMaxTagFileSize);
1150    else
1151       tagdb = new AliTagDB(event->GetHeader(), kMaxTagFileSize);
1152    if (tagdb->IsZombie())
1153       tagdb = 0;
1154    else
1155       printf("Filling tag DB %s\n", tagdb->GetDBName());
1156
1157    // Create AliStats object
1158    AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1159
1160    // Shortcut for easy header access
1161    AliRawEventHeader &header = *event->GetHeader();
1162
1163    // Process input stream
1164 #ifdef USE_EB
1165    while (!ebEor()) {
1166       struct iovec *ebvec;
1167       if ((ebvec = ebGetNextEvent()) == (void *)-1) {
1168          Error("Run", "error getting next event (%s)", ebGetLastError());
1169          break;
1170       }
1171       if (ebvec == 0) {
1172          // no event, sleep for 1 second and try again
1173          gSystem->Sleep(1000);
1174          continue;
1175       }
1176       char *ebdata = (char *) ebvec[0].iov_base;
1177 #else
1178    while (1) {
1179       char *ebdata = 0;
1180 #endif
1181
1182       // Read event header
1183       if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
1184          if (status == 0) {
1185             if (fUseLoop) {
1186 #ifndef USE_EB
1187                ::lseek(fFd, 0, SEEK_SET);
1188 #endif
1189                continue;
1190             }
1191             printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
1192             break;
1193          }
1194          return 1;
1195       }
1196
1197       // If we were in looping mode stop directly after a SIGUSR1 signal
1198       if (StopLoop()) {
1199          Info("Run", "SIGUSR1, processed %d events", fNumEvents);
1200          break;
1201       }
1202
1203       // Check if event has any hard track flagged
1204       Bool_t callFilter = kFALSE;
1205       // This needs to be re-engineered for the next ADC...
1206       //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
1207       //   callFilter = kTRUE;
1208
1209       // Check event type and skip "Start of Run", "End of Run",
1210       // "Start of Run Files" and "End of Run Files"
1211       switch (header.GetType()) {
1212          case kStartOfRun:
1213          case kEndOfRun:
1214          case kStartOfRunFiles:
1215          case kEndOfRunFiles:
1216             {
1217                Int_t skip = header.GetEventSize() - header.HeaderSize();
1218 #ifndef USE_EB
1219                ::lseek(fFd, skip, SEEK_CUR);
1220 #endif
1221                ALIDEBUG(1)
1222                   Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
1223                continue;
1224             }
1225             break;
1226          default:
1227             ALIDEBUG(1) {
1228                Int_t s = header.GetEventSize() - header.HeaderSize();
1229                Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
1230             }
1231       }
1232
1233       // Amount of data left to read for this event
1234       Int_t toRead = header.GetEventSize() - header.HeaderSize();
1235
1236       // If there is less data for this event than the next sub-event
1237       // header, something is wrong. Skip to next event...
1238       if (toRead < header.HeaderSize()) {
1239          if ((status = DumpEvent(toRead)) != toRead) {
1240             if (status == 0)
1241                break;
1242             return 1;
1243          }
1244          Error("Run", "discarding event %d (too little data for header)", fNumEvents);
1245          continue;
1246       }
1247
1248       // Loop over all sub-events... (LDCs)
1249       while (toRead > 0) {
1250          Int_t nsub = 1;
1251 #ifdef USE_EB
1252          ebdata = (char *)ebvec[nsub].iov_base;
1253 #endif
1254  
1255          ALIDEBUG(1)
1256             Info("Run", "reading LDC %d", nsub);
1257
1258          AliRawEvent *subEvent = event->NextSubEvent();
1259
1260          // Read sub-event header
1261          AliRawEventHeader &subHeader = *subEvent->GetHeader();
1262          if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
1263             if (status == 0) {
1264                Error("Run", "unexpected EOF reading sub-event header");
1265                break;
1266             }
1267             return 1;
1268          }
1269
1270          toRead -= subHeader.HeaderSize();
1271
1272 #ifdef USE_EB
1273          ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
1274 #endif
1275
1276          Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
1277
1278          // Read Equipment Header (in case of physics or calibration event)
1279          if (header.GetType() == kPhysicsEvent ||
1280              header.GetType() == kCalibrationEvent) {
1281             AliRawEquipmentHeader &equipment = *subEvent->GetEquipmentHeader();
1282             Int_t equipHeaderSize = equipment.HeaderSize();
1283             if ((status = ReadEquipmentHeader(equipment, header.DataIsSwapped(),
1284                                               ebdata)) != equipHeaderSize) {
1285                if (status == 0) {
1286                   Error("Run", "unexpected EOF reading equipment-header");
1287                   break;
1288                }
1289                return 1;
1290             }
1291             toRead  -= equipHeaderSize;
1292             rawSize -= equipHeaderSize;
1293 #ifdef USE_EB
1294             ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize() +
1295                      equipHeaderSize;
1296 #endif
1297          }
1298
1299          // Make sure raw data less than left over bytes for current event
1300          if (rawSize > toRead) {
1301             if ((status = DumpEvent(toRead)) != toRead) {
1302                if (status == 0)
1303                   break;
1304                return 1;
1305             }
1306             Error("Run", "discarding event %d (too much data)", fNumEvents);
1307             continue;
1308          }
1309
1310          // Read sub-event raw data
1311          AliRawData &subRaw = *subEvent->GetRawData();
1312          if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
1313             if (status == 0) {
1314                Error("Run", "unexpected EOF reading sub-event raw data");
1315                break;
1316             }
1317             return 1;
1318          }
1319
1320          if (callFilter) {
1321             if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
1322                Filter(subRaw);
1323             else {
1324                // set size of all sectors without hard track flag to 0
1325                subRaw.SetSize(0);
1326             }
1327          }
1328
1329          toRead -= rawSize;
1330          nsub++;
1331       }
1332
1333       // Set stat info for first event of this file
1334       if (rawdb->GetEvents() == 0)
1335          stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
1336
1337       // Store raw event in tree
1338       rawdb->Fill();
1339
1340       // Store header in tree
1341       if (tagdb) tagdb->Fill();
1342
1343       fNumEvents++;
1344
1345       if (!(fNumEvents%10))
1346          printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
1347
1348       // Filling time statistics
1349       if (rawdb->GetBytesWritten() > nextChunk) {
1350          tnew = timer.RealTime();
1351          stats->Fill(tnew-told);
1352          told = tnew;
1353          timer.Continue();
1354          nextChunk += chunkSize;
1355       }
1356
1357       // Check size of raw db. If bigger than maxFileSize, close file
1358       // and continue with new file.
1359       if (rawdb->FileFull()) {
1360
1361          printf("Written raw DB at a rate of %.1f MB/s\n",
1362                 Float_t(fMaxFileSize / timer.RealTime() / 1000000.));
1363
1364          // Write stats object to raw db, run db and MySQL
1365          stats->WriteToDB(rawdb);
1366          delete stats;
1367
1368          if (!rawdb->NextFile()) return 1;
1369
1370          printf("Filling raw DB %s\n", rawdb->GetDBName());
1371          stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1372
1373          timer.Start();
1374          told = 0, tnew = 0;
1375          nextChunk = chunkSize;
1376       }
1377
1378       // Check size of tag db
1379       if (tagdb->FileFull()) {
1380          if (!tagdb->NextFile())
1381             tagdb = 0;
1382          else
1383             printf("Filling tag DB %s\n", tagdb->GetDBName());
1384       }
1385
1386       // Make top event object ready for next event data
1387       //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
1388       event->Reset();
1389
1390 #ifdef USE_EB
1391       if (!ebReleaseEvent(ebvec)) {
1392          Error("Run", "problem releasing event (%s)", ebGetLastError());
1393          break;
1394       }
1395 #endif
1396    }
1397
1398    printf("Written raw DB at a rate of %.1f MB/s\n",
1399           Float_t(fMaxFileSize / timer.RealTime() / 1000000.));
1400
1401    // Write stats to raw db and run db and delete stats object
1402    stats->WriteToDB(rawdb);
1403    delete stats;
1404
1405    // Close the raw DB
1406    delete rawdb;
1407
1408    // Close the tag DB
1409    delete tagdb;
1410
1411    // Close input source
1412    close(fFd);
1413
1414 #if 0
1415    // Cleanup fifo
1416    if (fUseFifo && ::unlink(kFifo) == -1) {
1417       SysError("Run", "unlink");
1418       return 1;
1419    }
1420 #endif
1421
1422    return 0;
1423 }
1424
1425 //______________________________________________________________________________
1426 Int_t AliMDC::Read(void *buffer, Int_t length)
1427 {
1428    // Read exactly length bytes into buffer. Returns number of bytes
1429    // received, returns -1 in case of error and 0 for EOF.
1430
1431    errno = 0;
1432
1433    if (fFd < 0) return -1;
1434
1435    Int_t n, nrecv = 0;
1436    char *buf = (char *)buffer;
1437
1438    for (n = 0; n < length; n += nrecv) {
1439       if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
1440          if (nrecv == 0)
1441             break;        // EOF
1442          if (errno != EINTR)
1443             SysError("Read", "read");
1444          return -1;
1445       }
1446    }
1447    return n;
1448 }
1449
1450 //______________________________________________________________________________
1451 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
1452 {
1453    // Read header info from DATE data stream. Returns bytes read (i.e.
1454    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1455
1456    Int_t nrecv;
1457
1458    if (eb) {
1459       // read from event builder memory area
1460       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1461       nrecv = header.HeaderSize();
1462    } else {
1463       // read from fifo or file
1464       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1465            header.HeaderSize()) {
1466          if (nrecv == 0)
1467             return 0;
1468          return -1;
1469       }
1470    }
1471
1472    // Swap header data if needed
1473    if (header.IsSwapped())
1474       header.Swap();
1475
1476    // Is header valid...
1477    if (!header.IsValid()) {
1478       Error("ReadHeader", "invalid header format");
1479       // try recovery... how?
1480       return -1;
1481    }
1482    if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
1483       Error("ReadHeader", "invalid header size");
1484       // try recovery... how?
1485       return -1;
1486    }
1487
1488    return nrecv;
1489 }
1490
1491 //______________________________________________________________________________
1492 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
1493                                   Bool_t isSwapped, void *eb)
1494 {
1495    // Read equipment header info from DATE data stream. Returns bytes read
1496    // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
1497    // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
1498    // and we will swap the header to host format.
1499
1500    Int_t nrecv;
1501
1502    if (eb) {
1503       // read from event builder memory area
1504       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1505       nrecv = header.HeaderSize();
1506    } else {
1507       // read from fifo or file
1508       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1509            header.HeaderSize()) {
1510          if (nrecv == 0)
1511             return 0;
1512          return -1;
1513       }
1514    }
1515
1516    // Swap equipment header data if needed
1517    if (isSwapped)
1518       header.Swap();
1519
1520    if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
1521       Error("ReadEquipmentHeader", "invalid equipment header size");
1522       // try recovery... how?
1523       return -1;
1524    }
1525
1526    return nrecv;
1527 }
1528
1529 //______________________________________________________________________________
1530 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
1531 {
1532    // Read raw data from DATE data stream. Returns bytes read (i.e.
1533    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1534
1535    Int_t nrecv;
1536
1537    if (eb) {
1538       // read from event builder memory area
1539       raw.SetBuffer(eb, size);
1540       nrecv = size;
1541    } else {
1542       // read from fifo or file
1543       raw.SetSize(size);
1544       if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
1545          if (nrecv == 0) {
1546             Error("ReadRawData", "unexpected EOF");
1547             return 0;
1548          }
1549          return -1;
1550       }
1551    }
1552
1553    return nrecv;
1554 }
1555
1556 //______________________________________________________________________________
1557 Int_t AliMDC::DumpEvent(Int_t toRead)
1558 {
1559    // This case should not happen, but if it does try to handle it
1560    // gracefully by reading the rest of the event and discarding it.
1561    // Returns bytes read, -1 in case of fatal error and 0 for EOF.
1562
1563    Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
1564
1565    Int_t nrecv;
1566    char *tbuf = new char[toRead];
1567    if ((nrecv = Read(tbuf, toRead)) != toRead) {
1568       if (nrecv == 0) {
1569          Error("DumpEvent", "unexpected EOF");
1570          return 0;
1571       }
1572       return -1;
1573    }
1574    delete [] tbuf;
1575
1576    return nrecv;
1577 }
1578
1579 #ifdef USE_HLT
1580 #include <AliTPCL3Tunnel.h>
1581 #endif
1582
1583 //______________________________________________________________________________
1584 Int_t AliMDC::Filter(AliRawData &raw)
1585 {
1586    // Call 3rd level filter for this raw data segment.
1587
1588 #ifdef USE_HLT
1589    AliTPCL3Tunnel *tunnel = 0;
1590    if (!tunnel) {
1591       // initialisation
1592       tunnel = new AliTPCL3Tunnel(Form("%s/TPCparams.root",
1593                                        gSystem->Getenv("ALITPC")));
1594    }
1595
1596    Int_t obytes, nbytes;
1597    obytes = nbytes = raw.GetSize();
1598    char *outbuf = tunnel->EvalTrack((char *)raw.GetBuffer(), nbytes);
1599
1600    raw.SetSize(nbytes);
1601    memcpy(raw.GetBuffer(), outbuf, nbytes);
1602
1603    printf("Filter called for event %d: reduced from %d to %d\n", fNumEvents,
1604           obytes, nbytes);
1605
1606 #else
1607
1608    raw.GetSize();
1609    printf("Filter called for event %d\n", fNumEvents);
1610
1611 #endif
1612
1613    return 0;
1614 }