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