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