28b711306f0a298de87610d1ccc75856e485d918
[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* const kFifo       = "/tmp/alimdc.fifo";
66 const char* const kRawDBFS[2] = { "/tmp/mdc1", "/tmp/mdc2" };
67 const char* const kTagDBFS    = "/tmp/mdc1/tags";
68 const char* const kRunDBFS    = "/tmp/mdc1/meta";
69 const char* const kRFIOFS     = "rfio:/castor/cern.ch/user/r/rdm";
70 const char* const kCastorFS   = "castor:/castor/cern.ch/user/r/rdm";
71 const char* const kRootdFS    = "root://localhost//tmp/mdc1";
72 const char* const kAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
73 const char* const kAlienDir   = "/alice_mdc/DC";
74 #else
75 const char* const kFifo       = "/tmp/alimdc.fifo";
76 const char* const kRawDBFS[2] = { "/data1/mdc", "/data2/mdc" };
77 const char* const kTagDBFS    = "/data1/mdc/tags";
78 const char* const kRunDBFS    = "/data1/mdc/meta";
79 const char* const kRFIOFS     = "rfio:/castor/cern.ch/lcg/dc5";
80 const char* const kCastorFS   = "castor:/castor/cern.ch/lcg/dc5";
81 const char* const kRootdFS    = "root://localhost//tmp/mdc1";
82 const char* const kAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
83 const char* const 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) const
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() const
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 kMaxRetry = 200;
491    const Int_t kMaxSleep = 1;      // seconds
492    const Int_t kMaxSleepLong = 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                         GetNetopt());
510    if (!fRawDB) {
511       if (retry < kMaxRetry) {
512          Warning("Create", "failure to open file, sleeping %d %s before retrying...",
513                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
514          gSystem->Sleep(kMaxSleep*1000);
515          goto again;
516       }
517       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
518       return kFALSE;
519    }
520    if (fRawDB->IsZombie()) {
521       if (fRawDB->GetErrno() == ENOSPC ||
522           fRawDB->GetErrno() == 1018   ||   // SECOMERR
523           fRawDB->GetErrno() == 1027) {     // SESYSERR
524          fRawDB->ResetErrno();
525          delete fRawDB;
526          Warning("Create", "file is a zombie (no space), sleeping %d %s before retrying...",
527                  kMaxSleepLong, kMaxSleepLong==1 ? "second" : "seconds");
528          gSystem->Sleep(kMaxSleepLong*1000);   // sleep 10 seconds before retrying
529          goto again;
530       }
531       Error("Create", "file %s is zombie", fname);
532       fRawDB->ResetErrno();
533       delete fRawDB;
534       fRawDB = 0;
535       if (retry < kMaxRetry) {
536          Warning("Create", "file is a zombie, sleeping %d %s before retrying...",
537                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
538          gSystem->Sleep(kMaxSleep*1000);
539          goto again;
540       }
541       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
542       return kFALSE;
543    }
544
545    // Create raw data TTree
546    MakeTree();
547
548    return kTRUE;
549 }
550
551 //______________________________________________________________________________
552 void AliRawDB::MakeTree()
553 {
554    // Create ROOT Tree object container.
555
556    fTree = new TTree("RAW", Form("ALICE MDC%d raw data tree", kMDC));
557    fTree->SetAutoSave(2000000000);  // autosave when 2 Gbyte written
558
559    Int_t bufsize = 256000;
560    // splitting 29.6 MB/s, no splitting 35.3 MB/s on P4 2GHz 15k SCSI
561    //Int_t split   = 1;
562    Int_t split   = 0;
563    fTree->Branch("rawevent", "AliRawEvent", &fEvent, bufsize, split);
564 }
565
566 //______________________________________________________________________________
567 void AliRawDB::Close()
568 {
569    // Close raw DB.
570
571    if (!fRawDB) return;
572
573    fRawDB->cd();
574
575    // Write the tree.
576    fTree->Write();
577
578    // Close DB, this also deletes the fTree
579    fRawDB->Close();
580
581    if (AliMDC::DeleteFiles()) {
582       gSystem->Unlink(fRawDB->GetName());
583       delete fRawDB;
584       fRawDB = 0;
585       return;
586    }
587
588    // Create semaphore to say this file is finished
589    Int_t tfd = ::creat(Form("%s.done", fRawDB->GetName()), 0644);
590    close(tfd);
591
592    delete fRawDB;
593    fRawDB = 0;
594 }
595
596 //______________________________________________________________________________
597 Bool_t AliRawDB::NextFile()
598 {
599    // Close te current file and open a new one.
600    // Returns kFALSE in case opening failed.
601
602    Close();
603
604    if (!Create()) return kFALSE;
605    return kTRUE;
606 }
607
608 //______________________________________________________________________________
609 Float_t AliRawDB::GetCompressionFactor() const
610 {
611    // Return compression factor.
612
613    if (fTree->GetZipBytes() == 0.)
614       return 1.0;
615    else
616       return fTree->GetTotBytes()/fTree->GetZipBytes();
617 }
618
619
620 //______________________________________________________________________________
621 AliRawRFIODB::AliRawRFIODB(AliRawEvent *event, Double_t maxsize, Int_t compress)
622    : AliRawDB(event, maxsize, compress, kFALSE)
623 {
624    // Create a new raw DB that will be accessed via RFIO.
625
626 #ifndef USE_RDM
627    static int init = 0;
628    // Set STAGE_POOL environment variable to current host
629    if (!init) {
630       // THESE ENVIRONMENT SYMBOLS ARE NOW DEFINED BY THE ALICE DATE SETUP
631       // THEREFORE WE SHALL NOT USE ANY HARDCODED VALUES BUT RATHER USE
632       // WHATEVER HAS BEEN SET IN THE DATE SITE
633       //gSystem->Setenv("STAGE_POOL", "lcg00");
634       //gSystem->Setenv("STAGE_HOST", "stage013");
635       init = 1;
636    }
637 #endif
638
639    if (!Create())
640       MakeZombie();
641    else
642       fRawDB->UseCache(50, 0x200000);  //0x100000 = 1MB)
643 }
644
645 //______________________________________________________________________________
646 const char *AliRawRFIODB::GetFileName() const
647 {
648    // Return filename based on hostname and date and time. This will make
649    // each file unique. Also the directory will be made unique for each
650    // day by adding the date to the fs. Assumes there is always enough
651    // space on the device.
652
653    static TString fname;
654
655    TString fs = kRFIOFS;
656    TDatime dt;
657
658    // make a new subdirectory for each day
659    fs += "/adc-";
660    fs += dt.GetDate();
661
662    Long_t id, size, flags, time;
663    if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
664       // directory does not exist, create it
665       if (gSystem->mkdir(fs, kTRUE) == -1) {
666          Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
667                kRFIOFS);
668          fs = kRFIOFS;
669       }
670    }
671    // FIXME: should check if fs is a directory
672
673    TString hostname = gSystem->HostName();
674    Int_t pos;
675    if ((pos = hostname.Index(".")) != kNPOS)
676       hostname.Remove(pos);
677
678    fname = fs + "/" + hostname + "_";
679    fname += dt.GetDate();
680    fname += "_";
681    fname += dt.GetTime();
682    fname += ".root";
683
684    return fname;
685 }
686
687 //______________________________________________________________________________
688 void AliRawRFIODB::Close()
689 {
690    // Close raw RFIO DB.
691
692    if (!fRawDB) return;
693
694    fRawDB->cd();
695
696    // Write the tree.
697    fTree->Write();
698
699    // Close DB, this also deletes the fTree
700    fRawDB->Close();
701
702    if (AliMDC::DeleteFiles()) {
703       TUrl u(fRawDB->GetName());
704       gSystem->Exec(Form("rfrm %s", u.GetFile()));
705    }
706
707    delete fRawDB;
708    fRawDB = 0;
709 }
710
711
712 //______________________________________________________________________________
713 AliRawCastorDB::AliRawCastorDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
714    : AliRawDB(event, maxsize, compress, kFALSE)
715 {
716    // Create a new raw DB that will be accessed via CASTOR and rootd.
717
718 #ifndef USE_RDM
719    static int init = 0;
720    // Set STAGE_POOL environment variable to current host
721    if (!init) {
722       // THESE ENVIRONMENT SYMBOLS ARE NOW DEFINED BY THE ALICE DATE SETUP
723       // THEREFORE WE SHALL NOT USE ANY HARDCODED VALUES BUT RATHER USE
724       // WHATEVER HAS BEEN SET IN THE DATE SITE
725       //gSystem->Setenv("STAGE_POOL", "lcg00");
726       //gSystem->Setenv("STAGE_HOST", "stage013");
727       init = 1;
728    }
729 #endif
730
731    if (!Create())
732       MakeZombie();
733    else
734       fRawDB->UseCache(50, 0x200000);  //0x100000 = 1MB)
735 }
736
737 //______________________________________________________________________________
738 const char *AliRawCastorDB::GetFileName() const
739 {
740    // Return filename based on hostname and date and time. This will make
741    // each file unique. Also the directory will be made unique for each
742    // day by adding the date to the fs. Assumes there is always enough
743    // space on the device.
744
745    static TString fname;
746
747    TString fs  = kCastorFS;
748    TString fsr = kRFIOFS;
749    TDatime dt;
750
751    // make a new subdirectory for each day
752    fs += "/adc-";
753    fs += dt.GetDate();
754
755    fsr += "/adc-";
756    fsr += dt.GetDate();
757
758    Long_t id, size, flags, time;
759    if (gSystem->GetPathInfo(fsr, &id, &size, &flags, &time) == 1) {
760       // directory does not exist, create it
761       if (gSystem->mkdir(fsr, kTRUE) == -1) {
762          Error("GetFileName", "cannot create dir %s, using %s", fsr.Data(),
763                kRFIOFS);
764          fs = kCastorFS;
765       }
766    }
767    // FIXME: should check if fs is a directory
768
769    TString hostname = gSystem->HostName();
770    Int_t pos;
771    if ((pos = hostname.Index(".")) != kNPOS)
772       hostname.Remove(pos);
773
774    fname = fs + "/" + hostname + "_";
775    fname += dt.GetDate();
776    fname += "_";
777    fname += dt.GetTime();
778    fname += ".root";
779
780    return fname;
781 }
782
783 //______________________________________________________________________________
784 void AliRawCastorDB::Close()
785 {
786    // Close raw CASTOR/rootd DB.
787
788    if (!fRawDB) return;
789
790    fRawDB->cd();
791
792    // Write the tree.
793    fTree->Write();
794
795    // Close DB, this also deletes the fTree
796    fRawDB->Close();
797
798    if (AliMDC::DeleteFiles()) {
799       TUrl u(fRawDB->GetName());
800       gSystem->Exec(Form("rfrm %s", u.GetFile()));
801    }
802
803    delete fRawDB;
804    fRawDB = 0;
805 }
806
807
808 //______________________________________________________________________________
809 AliRawRootdDB::AliRawRootdDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
810    : AliRawDB(event, maxsize, compress, kFALSE)
811 {
812    // Create a new raw DB that will be accessed via rootd daemon.
813
814    if (!Create())
815       MakeZombie();
816    else
817       fRawDB->UseCache(50, 0x200000);  //0x100000 = 1MB)
818 }
819
820 //______________________________________________________________________________
821 const char *AliRawRootdDB::GetFileName() const
822 {
823    // Return filename based on hostname and date and time. This will make
824    // each file unique. Also the directory will be made unique for each
825    // day by adding the date to the fs. Assumes there is always enough
826    // space on the device.
827
828    static TString fname;
829
830    TString fs = kRootdFS;
831    TDatime dt;
832
833 #if 0
834    // make a new subdirectory for each day
835    fs += "/adc-";
836    fs += dt.GetDate();
837
838    Long_t id, size, flags, time;
839    if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
840       // directory does not exist, create it
841       if (gSystem->mkdir(fs, kTRUE) == -1) {
842          Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
843                kRootdFS);
844          fs = kRootdFS;
845       }
846    }
847    // FIXME: should check if fs is a directory
848 #endif
849
850    TString hostname = gSystem->HostName();
851    Int_t pos;
852    if ((pos = hostname.Index(".")) != kNPOS)
853       hostname.Remove(pos);
854
855    fname = fs + "/" + hostname + "_";
856    fname += dt.GetDate();
857    fname += "_";
858    fname += dt.GetTime();
859    fname += ".root";
860
861    return fname;
862 }
863
864 //______________________________________________________________________________
865 void AliRawRootdDB::Close()
866 {
867    // Close raw rootd DB.
868
869    if (!fRawDB) return;
870
871    fRawDB->cd();
872
873    // Write the tree.
874    fTree->Write();
875
876    // Close DB, this also deletes the fTree
877    fRawDB->Close();
878
879 #if 0
880    // can use services of TFTP
881    if (AliMDC::DeleteFiles())
882       gSystem->Exec(Form("rfrm %s", fRawDB->GetName()));
883 #endif
884
885    delete fRawDB;
886    fRawDB = 0;
887 }
888
889
890 //______________________________________________________________________________
891 AliRawNullDB::AliRawNullDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
892    : AliRawDB(event, maxsize, compress, kFALSE)
893 {
894    // Create a new raw DB that will wrtie to /dev/null.
895
896    if (!Create())
897       MakeZombie();
898 }
899
900 //______________________________________________________________________________
901 const char *AliRawNullDB::GetFileName() const
902 {
903    // Return /dev/null as filename.
904
905    return "/dev/null";
906 }
907
908 //______________________________________________________________________________
909 void AliRawNullDB::Close()
910 {
911    // Close raw RFIO DB.
912
913    if (!fRawDB) return;
914
915    fRawDB->cd();
916
917    // Write the tree.
918    fTree->Write();
919
920    // Close DB, this also deletes the fTree
921    fRawDB->Close();
922
923    delete fRawDB;
924    fRawDB = 0;
925 }
926
927
928 //______________________________________________________________________________
929 AliTagDB::AliTagDB(AliRawEventHeader *header, Double_t maxsize, Bool_t create)
930 {
931    // Create tag DB.
932
933    fHeader   = header;
934    fMaxSize  = maxsize;
935
936    if (create) {
937       if (!Create())
938          MakeZombie();
939    }
940 }
941
942 //______________________________________________________________________________
943 Bool_t AliTagDB::Create()
944 {
945    // Create a new tag DB.
946
947    fTagDB = new TFile(GetFileName(), "RECREATE",
948                       Form("ALICE MDC%d tag DB", kMDC), 1);
949    if (fTagDB->IsZombie()) {
950       Error("Create", "error opening tag DB");
951       fTagDB = 0;
952       return kFALSE;
953    }
954
955    // Create ROOT Tree object container
956    fTree = new TTree("TAG", Form("ALICE MDC%d header data tree", kMDC));
957    fTree->SetAutoSave(100000000);  // autosave when 100 Mbyte written
958
959    Int_t bufsize = 32000;
960    Int_t split   = 1;
961    fTree->Branch("header", "AliRawEventHeader", &fHeader, bufsize, split);
962
963    return kTRUE;
964 }
965
966 //______________________________________________________________________________
967 void AliTagDB::Close()
968 {
969    // Close tag DB.
970
971    if (!fTagDB) return;
972
973    fTagDB->cd();
974
975    // Write the tree.
976    fTree->Write();
977
978    // Close DB, this also deletes the fTree
979    fTagDB->Close();
980
981    if (AliMDC::DeleteFiles())
982       gSystem->Unlink(fTagDB->GetName());
983
984    delete fTagDB;
985    fTagDB = 0;
986 }
987
988 //______________________________________________________________________________
989 Bool_t AliTagDB::NextFile()
990 {
991    // Close te current file and open a new one.
992    // Returns kFALSE in case opening failed.
993
994    Close();
995
996    if (!Create()) return kFALSE;
997    return kTRUE;
998 }
999
1000 //______________________________________________________________________________
1001 Float_t AliTagDB::GetCompressionFactor() const
1002 {
1003    // Return compression factor.
1004
1005    if (fTree->GetZipBytes() == 0.)
1006       return 1.0;
1007    else
1008       return fTree->GetTotBytes()/fTree->GetZipBytes();
1009 }
1010
1011 //______________________________________________________________________________
1012 const char *AliTagDB::GetFileName() const
1013 {
1014    // Return filename based on hostname and date and time. This will make
1015    // each file unique. The tags will be stored in the /data1/tags directory.
1016
1017    static char fname[64];
1018    const char *fs = kTagDBFS;
1019
1020    // check that fs exists (crude check fails if fs is a file)
1021    gSystem->MakeDirectory(fs);
1022
1023    char hostname[64];
1024
1025    strcpy(hostname, gSystem->HostName());
1026
1027    char *s;
1028    if ((s = strchr(hostname, '.')))
1029       *s = 0;
1030
1031    TDatime dt;
1032
1033    sprintf(fname, "%s/%s_%d_%d.root", fs, hostname, dt.GetDate(), dt.GetTime());
1034
1035    return fname;
1036 }
1037
1038
1039 //______________________________________________________________________________
1040 AliTagNullDB::AliTagNullDB(AliRawEventHeader *header, Double_t maxsize) :
1041    AliTagDB(header, maxsize, kFALSE)
1042 {
1043    // Create tag db writing to /dev/null.
1044
1045    if (!Create())
1046       MakeZombie();
1047 }
1048
1049 //______________________________________________________________________________
1050 const char *AliTagNullDB::GetFileName() const
1051 {
1052    // Return /dev/null as filename.
1053
1054    return "/dev/null";
1055 }
1056
1057 //______________________________________________________________________________
1058 void AliTagNullDB::Close()
1059 {
1060    // Close null tag DB.
1061
1062    if (!fTagDB) return;
1063
1064    fTagDB->cd();
1065
1066    // Write the tree.
1067    fTree->Write();
1068
1069    // Close DB, this also deletes the fTree
1070    fTagDB->Close();
1071
1072    delete fTagDB;
1073    fTagDB = 0;
1074 }
1075
1076
1077 //______________________________________________________________________________
1078 AliRunDB::AliRunDB(Bool_t noLocalDB)
1079 {
1080    // Open run database, and get or create tree.
1081
1082    fRunDB = 0;
1083
1084    if (noLocalDB) return;
1085
1086    // Get hostname
1087    char hostname[64], filename[64];
1088    const char *fs = kRunDBFS;
1089
1090    // check that fs exists (crude check fails if fs is a file)
1091    gSystem->MakeDirectory(fs);
1092
1093    strcpy(hostname, gSystem->HostName());
1094
1095    char *s;
1096    if ((s = strchr(hostname, '.')))
1097       *s = 0;
1098
1099    sprintf(filename, "%s/%s_rundb.root", fs, hostname);
1100
1101    if (!gSystem->AccessPathName(filename, kFileExists))
1102       fRunDB = new TFile(filename, "UPDATE");
1103    else
1104       fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", kMDC));
1105 }
1106
1107 //______________________________________________________________________________
1108 void AliRunDB::Update(AliStats *stats)
1109 {
1110    // Add stats object to database.
1111
1112    if (!stats || !fRunDB) return;
1113
1114    TDirectory *ds = gDirectory;
1115    fRunDB->cd();
1116
1117    char sname[64];
1118    char *s = (char*)strrchr(stats->GetFileName(), '/');
1119    if (s) {
1120       s++;
1121       strcpy(sname, s);
1122    } else
1123       strcpy(sname, stats->GetFileName());
1124    s = strchr(sname, '.');
1125    if (s) *s = 0;
1126
1127    stats->Write(sname);
1128
1129    ds->cd();
1130 }
1131
1132 //______________________________________________________________________________
1133 void AliRunDB::UpdateRDBMS(AliStats *stats)
1134 {
1135    // Add stats object to central MySQL DB.
1136
1137    if (!stats) return;
1138
1139    char sql[4096];
1140    char bt[25], et[25];
1141
1142    strcpy(bt, stats->GetBeginTime().AsSQLString());
1143    strcpy(et, stats->GetEndTime().AsSQLString());
1144
1145    sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
1146            "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", kMDC,
1147            stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
1148            stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
1149            stats->GetLastEvent(), stats->GetCompressionMode(),
1150            stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
1151            bt, et);
1152
1153    // open connection to MySQL server on pcsalo
1154    TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");
1155
1156    if (!db || db->IsZombie()) {
1157       Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
1158       printf("%s\n", sql);
1159       delete db;
1160       return;
1161    }
1162
1163    TSQLResult *res = db->Query(sql);
1164
1165    if (!res) {
1166       Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", kMDC));
1167       printf("%s\n", sql);
1168    }
1169
1170    delete res;
1171    delete db;
1172 }
1173
1174 //______________________________________________________________________________
1175 void AliRunDB::UpdateAliEn(AliStats *stats)
1176 {
1177    // Record file in AliEn catalog.
1178
1179    if (!stats) return;
1180
1181    TGrid *g = TGrid::Connect(kAlienHost, "");
1182
1183    TString lfn = kAlienDir;
1184    TDatime dt;
1185
1186    // make a subdirectory for each day
1187    lfn += "/adc-";
1188    lfn += dt.GetDate();
1189
1190    // check if directory exists, if not create it
1191    if (!g->OpenDir(lfn)) {
1192       // directory does not exist, create it
1193       if (g->Mkdir(lfn, kTRUE) == -1) {
1194          Error("UpdateAliEn", "cannot create directory %s", lfn.Data());
1195          lfn = kAlienDir;
1196       }
1197    }
1198
1199    lfn += "/";
1200    lfn += gSystem->BaseName(stats->GetFileName());
1201
1202    Int_t result = g->AddFile(lfn, stats->GetFileName(),
1203                              (int)stats->GetFileSize());
1204
1205    if (result == -1) {
1206       Error("UpdateAliEn", "error adding file to AliEn catalog");
1207       printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
1208              (int)stats->GetFileSize());
1209    }
1210
1211    delete g;
1212 }
1213
1214 //______________________________________________________________________________
1215 void AliRunDB::Close()
1216 {
1217    // Close run database.
1218
1219    if (fRunDB) fRunDB->Close();
1220    delete fRunDB;
1221 }
1222
1223 //----------------- Use SIGUSR1 to interupt endless loop -----------------------
1224 class AliMDCInterruptHandler : public TSignalHandler {
1225 public:
1226    AliMDCInterruptHandler(AliMDC *mdc) : TSignalHandler(kSigUser1, kFALSE), fMDC(mdc) { }
1227    Bool_t Notify() {
1228       Info("Notify", "received a SIGUSR1 signal");
1229       fMDC->SetStopLoop();
1230       return kTRUE;
1231    }
1232 private:
1233    AliMDC *fMDC;   // alimdc to signal
1234
1235    AliMDCInterruptHandler(const AliMDCInterruptHandler &);
1236    void operator=(const AliMDCInterruptHandler &);
1237 };
1238
1239 //______________________________________________________________________________
1240 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
1241                EWriteMode mode, Bool_t useLoop, Bool_t delFiles)
1242 {
1243    // Create MDC processor object.
1244
1245    fFd           = fd;
1246    fCompress     = compress;
1247    fMaxFileSize  = maxFileSize;
1248    fUseFilter    = useFilter;
1249    fWriteMode    = mode;
1250    fUseLoop      = useLoop;
1251    fUseFifo      = kFALSE;
1252    fUseEb        = kFALSE;
1253    fStopLoop     = kFALSE;
1254    fNumEvents    = 0;
1255    fDebugLevel   = 0;
1256    fgDeleteFiles = delFiles;
1257
1258    if (fFd == -1) {
1259 #ifdef USE_EB
1260      if (!ebRegister()) {
1261         Error("AliMDC", "cannot register with the event builder (%s)",
1262               ebGetLastError());
1263         return;
1264      }
1265      fUseEb = kTRUE;
1266 #else
1267      if ((mkfifo(kFifo, 0644) < 0) && (errno != EEXIST)) {
1268          Error("AliMDC", "cannot create fifo %s", kFifo);
1269          return;
1270       }
1271       if ((chmod(kFifo, 0666) == -1) && (errno != EPERM)) {
1272          Error("AliMDC", "cannot change permission of fifo %s", kFifo);
1273          return;
1274       }
1275       if ((fFd = open(kFifo, O_RDONLY)) == -1) {
1276          Error("AliMDC", "cannot open input file %s", kFifo);
1277          return;
1278       }
1279       fUseFifo = kTRUE;
1280 #endif
1281       fUseLoop = kFALSE;
1282    }
1283
1284    printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
1285           "looping = %s, compression = %d, delete files = %s",
1286           fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
1287           fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
1288           fgDeleteFiles ? "yes" : "no");
1289    if (fWriteMode == kRFIO)
1290       printf(", use RFIO\n");
1291    else if (fWriteMode == kROOTD)
1292       printf(", use rootd\n");
1293    else if (fWriteMode == kCASTOR)
1294       printf(", use CASTOR/rootd\n");
1295    else if (fWriteMode == kDEVNULL)
1296       printf(", write raw data to /dev/null\n");
1297    else
1298       printf("\n");
1299
1300    // install SIGUSR1 handler to allow clean interrupts
1301    gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
1302
1303    gAliMDC = this;
1304 }
1305
1306 //______________________________________________________________________________
1307 Int_t AliMDC::Run()
1308 {
1309    // Run the MDC processor. Read from the input stream and only return
1310    // when the input gave and EOF or a fatal error occured. On success 0
1311    // is returned, 1 in case of a fatality.
1312
1313    TStopwatch timer;
1314    Int_t status;
1315
1316    // Make sure needed directories exist
1317    const char *dirs[4];
1318    dirs[0] = kRawDBFS[0];
1319    dirs[1] = kRawDBFS[1];
1320    dirs[2] = kTagDBFS;
1321    dirs[3] = kRunDBFS;
1322    for (int idir = 0; idir < 4; idir++) {
1323       gSystem->ResetErrno();
1324       gSystem->MakeDirectory(dirs[idir]);
1325       if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
1326          SysError("Run", "mkdir %s", dirs[idir]);
1327          return 1;
1328       }
1329    }
1330
1331    // Used for statistics
1332    timer.Start();
1333    Double_t told = 0, tnew = 0;
1334    Float_t  chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
1335
1336    // Event object used to store event data.
1337    AliRawEvent *event = new AliRawEvent;
1338
1339    // Create new raw DB.
1340    AliRawDB *rawdb;
1341    if (fWriteMode == kRFIO)
1342       rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
1343    else if (fWriteMode == kROOTD)
1344       rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
1345    else if (fWriteMode == kCASTOR)
1346       rawdb = new AliRawCastorDB(event, fMaxFileSize, fCompress);
1347    else if (fWriteMode == kDEVNULL)
1348       rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
1349    else
1350       rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
1351
1352    if (rawdb->IsZombie()) return 1;
1353    printf("Filling raw DB %s\n", rawdb->GetDBName());
1354
1355    // Create new tag DB.
1356    AliTagDB *tagdb = 0;
1357 #if 0
1358    // no tagdb for the time being to get maximum speed
1359    if (fWriteMode == kDEVNULL)
1360       tagdb = new AliTagNullDB(event->GetHeader(), kMaxTagFileSize);
1361    else
1362       tagdb = new AliTagDB(event->GetHeader(), kMaxTagFileSize);
1363    if (tagdb->IsZombie())
1364       tagdb = 0;
1365    else
1366       printf("Filling tag DB %s\n", tagdb->GetDBName());
1367 #endif
1368
1369    // Create AliStats object
1370    AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1371
1372    // Shortcut for easy header access
1373    AliRawEventHeader &header = *event->GetHeader();
1374
1375    // Process input stream
1376 #ifdef USE_EB
1377    Int_t eorFlag = 0;
1378    while (!(eorFlag = ebEor())) {
1379       struct iovec *ebvec;
1380       if ((ebvec = ebGetNextEvent()) == (void *)-1) {
1381          Error("Run", "error getting next event (%s)", ebGetLastError());
1382          break;
1383       }
1384       if (ebvec == 0) {
1385          // no event, sleep for 1 second and try again
1386          gSystem->Sleep(1000);
1387          continue;
1388       }
1389       char *ebdata = (char *) ebvec[0].iov_base;
1390 #else
1391    while (1) {
1392       char *ebdata = 0;
1393 #endif
1394
1395       // Read event header
1396       if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
1397          if (status == 0) {
1398             if (fUseLoop) {
1399 #ifndef USE_EB
1400                ::lseek(fFd, 0, SEEK_SET);
1401 #endif
1402                continue;
1403             }
1404             printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
1405             break;
1406          }
1407          return 1;
1408       }
1409       ALIDEBUG(3)
1410          header.Dump();
1411
1412       // If we were in looping mode stop directly after a SIGUSR1 signal
1413       if (StopLoop()) {
1414          Info("Run", "Stopping loop, processed %d events", fNumEvents);
1415          break;
1416       }
1417
1418       // Check if event has any hard track flagged
1419       Bool_t callFilter = kFALSE;
1420       // This needs to be re-engineered for the next ADC...
1421       //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
1422       //   callFilter = kTRUE;
1423
1424       // Check event type and skip "Start of Run", "End of Run",
1425       // "Start of Run Files" and "End of Run Files"
1426       switch (header.GetType()) {
1427          case kStartOfRun:
1428          case kEndOfRun:
1429          case kStartOfRunFiles:
1430          case kEndOfRunFiles:
1431             {
1432                Int_t skip = header.GetEventSize() - header.HeaderSize();
1433 #ifndef USE_EB
1434                ::lseek(fFd, skip, SEEK_CUR);
1435 #endif
1436                ALIDEBUG(1)
1437                   Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
1438                continue;
1439             }
1440             break;
1441          default:
1442             ALIDEBUG(1) {
1443                Int_t s = header.GetEventSize() - header.HeaderSize();
1444                Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
1445             }
1446       }
1447
1448       // Amount of data left to read for this event
1449       Int_t toRead = header.GetEventSize() - header.HeaderSize();
1450
1451       // If there is less data for this event than the next sub-event
1452       // header, something is wrong. Skip to next event...
1453       if (toRead < header.HeaderSize()) {
1454          ALIDEBUG(1) {
1455             Warning("Run",
1456                     "header size (%d) exceeds number of bytes to read (%d)\n",
1457                     header.HeaderSize(), toRead);
1458             header.Dump();
1459          }
1460          if ((status = DumpEvent(toRead)) != toRead) {
1461             if (status == 0)
1462                break;
1463             return 1;
1464          }
1465          Error("Run", "discarding event %d (too little data for header)", fNumEvents);
1466          continue;
1467       }
1468
1469       // Loop over all sub-events... (LDCs)
1470       Int_t nsub = 1;
1471       while (toRead > 0) {
1472 #ifdef USE_EB
1473          ebdata = (char *)ebvec[nsub].iov_base;
1474 #endif
1475
1476          ALIDEBUG(1)
1477             Info("Run", "reading LDC %d", nsub);
1478
1479          AliRawEvent *subEvent = event->NextSubEvent();
1480
1481          // Read sub-event header
1482          AliRawEventHeader &subHeader = *subEvent->GetHeader();
1483          if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
1484             if (status == 0) {
1485                Error("Run", "unexpected EOF reading sub-event header");
1486                break;
1487             }
1488             return 1;
1489          }
1490
1491          ALIDEBUG(3)
1492             subHeader.Dump();
1493
1494          toRead -= subHeader.HeaderSize();
1495
1496 #ifdef USE_EB
1497          ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
1498 #endif
1499
1500          Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
1501
1502          // Read Equipment Header (in case of physics or calibration event)
1503          if (header.GetType() == kPhysicsEvent ||
1504              header.GetType() == kCalibrationEvent) {
1505             AliRawEquipmentHeader &equipment = *subEvent->GetEquipmentHeader();
1506             Int_t equipHeaderSize = equipment.HeaderSize();
1507             if ((status = ReadEquipmentHeader(equipment, header.DataIsSwapped(),
1508                                               ebdata)) != equipHeaderSize) {
1509                if (status == 0) {
1510                   Error("Run", "unexpected EOF reading equipment-header");
1511                   break;
1512                }
1513                return 1;
1514             }
1515             toRead  -= equipHeaderSize;
1516             rawSize -= equipHeaderSize;
1517 #ifdef USE_EB
1518             ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize() +
1519                      equipHeaderSize;
1520 #endif
1521          }
1522
1523          // Make sure raw data less than left over bytes for current event
1524          if (rawSize > toRead) {
1525             ALIDEBUG(1) {
1526                Warning("Run", "raw data size (%d) exceeds number of bytes "
1527                        "to read (%d)\n", rawSize, toRead);
1528                subHeader.Dump();
1529             }
1530             if ((status = DumpEvent(toRead)) != toRead) {
1531                if (status == 0)
1532                   break;
1533                return 1;
1534             }
1535             Error("Run", "discarding event %d (too much data)", fNumEvents);
1536             continue;
1537          }
1538
1539          // Read sub-event raw data
1540          AliRawData &subRaw = *subEvent->GetRawData();
1541          if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
1542             if (status == 0) {
1543                Error("Run", "unexpected EOF reading sub-event raw data");
1544                break;
1545             }
1546             return 1;
1547          }
1548
1549          if (callFilter) {
1550             if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
1551                Filter(subRaw);
1552             else {
1553                // set size of all sectors without hard track flag to 0
1554                subRaw.SetSize(0);
1555             }
1556          }
1557
1558          toRead -= rawSize;
1559          nsub++;
1560       }
1561
1562       // Set stat info for first event of this file
1563       if (rawdb->GetEvents() == 0)
1564          stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
1565
1566       // Store raw event in tree
1567       rawdb->Fill();
1568
1569       // Store header in tree
1570       if (tagdb) tagdb->Fill();
1571
1572       fNumEvents++;
1573
1574       if (!(fNumEvents%10))
1575          printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
1576
1577       // Filling time statistics
1578       if (rawdb->GetBytesWritten() > nextChunk) {
1579          tnew = timer.RealTime();
1580          stats->Fill(tnew-told);
1581          told = tnew;
1582          timer.Continue();
1583          nextChunk += chunkSize;
1584       }
1585
1586       // Check size of raw db. If bigger than maxFileSize, close file
1587       // and continue with new file.
1588       if (rawdb->FileFull()) {
1589
1590          printf("Written raw DB at a rate of %.1f MB/s\n",
1591                 rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1592
1593          // Write stats object to raw db, run db, MySQL and AliEn
1594          stats->WriteToDB(rawdb);
1595          delete stats;
1596
1597          if (!rawdb->NextFile()) {
1598             Error("Run", "error opening next raw data file");
1599             return 1;
1600          }
1601
1602          printf("Filling raw DB %s\n", rawdb->GetDBName());
1603          stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1604
1605          timer.Start();
1606          told = 0, tnew = 0;
1607          nextChunk = chunkSize;
1608       }
1609
1610       // Check size of tag db
1611       if (tagdb && tagdb->FileFull()) {
1612          if (!tagdb->NextFile())
1613             tagdb = 0;
1614          else
1615             printf("Filling tag DB %s\n", tagdb->GetDBName());
1616       }
1617
1618       // Make top event object ready for next event data
1619       //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
1620       event->Reset();
1621
1622 #ifdef USE_EB
1623       if (!ebReleaseEvent(ebvec)) {
1624          Error("Run", "problem releasing event (%s)", ebGetLastError());
1625          break;
1626       }
1627 #endif
1628    }
1629
1630    printf("Written raw DB at a rate of %.1f MB/s\n",
1631           rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1632
1633    // Write stats to raw db and run db and delete stats object
1634    stats->WriteToDB(rawdb);
1635    delete stats;
1636
1637    // Close the raw DB
1638    delete rawdb;
1639
1640    // Close the tag DB
1641    delete tagdb;
1642
1643    // Close input source
1644    close(fFd);
1645
1646 #if 0
1647    // Cleanup fifo
1648    if (fUseFifo && ::unlink(kFifo) == -1) {
1649       SysError("Run", "unlink");
1650       return 1;
1651    }
1652 #endif
1653
1654 #ifdef USE_EB
1655    // Print eor flag
1656    if (eorFlag) {
1657       Info("Run", "event builder reported end of run (%d)", eorFlag);
1658    }
1659 #endif
1660
1661    return 0;
1662 }
1663
1664 //______________________________________________________________________________
1665 Int_t AliMDC::Read(void *buffer, Int_t length)
1666 {
1667    // Read exactly length bytes into buffer. Returns number of bytes
1668    // received, returns -1 in case of error and 0 for EOF.
1669
1670    errno = 0;
1671
1672    if (fFd < 0) return -1;
1673
1674    Int_t n, nrecv = 0;
1675    char *buf = (char *)buffer;
1676
1677    for (n = 0; n < length; n += nrecv) {
1678       if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
1679          if (nrecv == 0)
1680             break;        // EOF
1681          if (errno != EINTR)
1682             SysError("Read", "read");
1683          return -1;
1684       }
1685    }
1686    return n;
1687 }
1688
1689 //______________________________________________________________________________
1690 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
1691 {
1692    // Read header info from DATE data stream. Returns bytes read (i.e.
1693    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1694
1695    Int_t nrecv;
1696
1697    if (eb) {
1698       // read from event builder memory area
1699       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1700       nrecv = header.HeaderSize();
1701    } else {
1702       // read from fifo or file
1703       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1704            header.HeaderSize()) {
1705          if (nrecv == 0)
1706             return 0;
1707          return -1;
1708       }
1709    }
1710
1711    // Swap header data if needed
1712    if (header.IsSwapped())
1713       header.Swap();
1714
1715    // Is header valid...
1716    if (!header.IsValid()) {
1717       Error("ReadHeader", "invalid header format");
1718       // try recovery... how?
1719       return -1;
1720    }
1721    if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
1722       Error("ReadHeader", "invalid header size");
1723       // try recovery... how?
1724       return -1;
1725    }
1726
1727    return nrecv;
1728 }
1729
1730 //______________________________________________________________________________
1731 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
1732                                   Bool_t isSwapped, void *eb)
1733 {
1734    // Read equipment header info from DATE data stream. Returns bytes read
1735    // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
1736    // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
1737    // and we will swap the header to host format.
1738
1739    Int_t nrecv;
1740
1741    if (eb) {
1742       // read from event builder memory area
1743       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1744       nrecv = header.HeaderSize();
1745    } else {
1746       // read from fifo or file
1747       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1748            header.HeaderSize()) {
1749          if (nrecv == 0)
1750             return 0;
1751          return -1;
1752       }
1753    }
1754
1755    // Swap equipment header data if needed
1756    if (isSwapped)
1757       header.Swap();
1758
1759    if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
1760       Error("ReadEquipmentHeader", "invalid equipment header size");
1761       // try recovery... how?
1762       return -1;
1763    }
1764
1765    return nrecv;
1766 }
1767
1768 //______________________________________________________________________________
1769 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
1770 {
1771    // Read raw data from DATE data stream. Returns bytes read (i.e.
1772    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1773
1774    Int_t nrecv;
1775
1776    if (eb) {
1777       // read from event builder memory area
1778       raw.SetBuffer(eb, size);
1779       nrecv = size;
1780    } else {
1781       // read from fifo or file
1782       raw.SetSize(size);
1783       if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
1784          if (nrecv == 0) {
1785             Error("ReadRawData", "unexpected EOF");
1786             return 0;
1787          }
1788          return -1;
1789       }
1790    }
1791
1792    return nrecv;
1793 }
1794
1795 //______________________________________________________________________________
1796 Int_t AliMDC::DumpEvent(Int_t toRead)
1797 {
1798    // This case should not happen, but if it does try to handle it
1799    // gracefully by reading the rest of the event and discarding it.
1800    // Returns bytes read, -1 in case of fatal error and 0 for EOF.
1801
1802    Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
1803
1804    Int_t nrecv;
1805    char *tbuf = new char[toRead];
1806    if ((nrecv = Read(tbuf, toRead)) != toRead) {
1807       if (nrecv == 0) {
1808          Error("DumpEvent", "unexpected EOF");
1809          return 0;
1810       }
1811       return -1;
1812    }
1813    delete [] tbuf;
1814
1815    return nrecv;
1816 }
1817
1818 #ifdef USE_HLT
1819 #include <AliTPCL3Tunnel.h>
1820 #endif
1821
1822 //______________________________________________________________________________
1823 Int_t AliMDC::Filter(AliRawData &raw)
1824 {
1825    // Call 3rd level filter for this raw data segment.
1826
1827 #ifdef USE_HLT
1828    AliTPCL3Tunnel *tunnel = 0;
1829    if (!tunnel) {
1830       // initialisation
1831       tunnel = new AliTPCL3Tunnel(Form("%s/TPCparams.root",
1832                                        gSystem->Getenv("ALITPC")));
1833    }
1834
1835    Int_t obytes, nbytes;
1836    obytes = nbytes = raw.GetSize();
1837    char *outbuf = tunnel->EvalTrack((char *)raw.GetBuffer(), nbytes);
1838
1839    raw.SetSize(nbytes);
1840    memcpy(raw.GetBuffer(), outbuf, nbytes);
1841
1842    printf("Filter called for event %d: reduced from %d to %d\n", fNumEvents,
1843           obytes, nbytes);
1844
1845 #else
1846
1847    raw.GetSize();
1848    printf("Filter called for event %d\n", fNumEvents);
1849
1850 #endif
1851
1852    return 0;
1853 }