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