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