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