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