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