]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliRawEvent.cxx
add support for TCastorFile (use CASTOR over rootd) and use
[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;
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, "RECREATE",
484                         Form("ALICE MDC%d raw DB", kMDC), fCompress);
485    if (!fRawDB) {
486       Error("Create", "did not find right plugin to open file");
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()
1038 {
1039    // Open run database, and get or create tree.
1040
1041    // Get hostname
1042    char hostname[64], filename[64];
1043    const char *fs = kRunDBFS;
1044
1045    // check that fs exists (crude check fails if fs is a file)
1046    gSystem->MakeDirectory(fs);
1047
1048    strcpy(hostname, gSystem->HostName());
1049
1050    char *s;
1051    if ((s = strchr(hostname, '.')))
1052       *s = 0;
1053
1054    sprintf(filename, "%s/%s_rundb.root", fs, hostname);
1055
1056    if (!gSystem->AccessPathName(filename, kFileExists))
1057       fRunDB = new TFile(filename, "UPDATE");
1058    else
1059       fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", kMDC));
1060 }
1061
1062 //______________________________________________________________________________
1063 void AliRunDB::Update(AliStats *stats)
1064 {
1065    // Add stats object to database.
1066
1067    TDirectory *ds = gDirectory;
1068    fRunDB->cd();
1069
1070    char sname[64];
1071    char *s = (char*)strrchr(stats->GetFileName(), '/');
1072    if (s) {
1073       s++;
1074       strcpy(sname, s);
1075    } else
1076       strcpy(sname, stats->GetFileName());
1077    s = strchr(sname, '.');
1078    if (s) *s = 0;
1079
1080    stats->Write(sname);
1081
1082    ds->cd();
1083 }
1084
1085 //______________________________________________________________________________
1086 void AliRunDB::UpdateRDBMS(AliStats *stats)
1087 {
1088    // Add stats object to central MySQL DB.
1089
1090    char sql[4096];
1091    char bt[25], et[25];
1092
1093    strcpy(bt, stats->GetBeginTime().AsSQLString());
1094    strcpy(et, stats->GetEndTime().AsSQLString());
1095
1096    sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
1097            "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", kMDC,
1098            stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
1099            stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
1100            stats->GetLastEvent(), stats->GetCompressionMode(),
1101            stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
1102            bt, et);
1103
1104    // open connection to MySQL server on pcsalo
1105    TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");
1106
1107    if (!db || db->IsZombie()) {
1108       Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
1109       printf("%s\n", sql);
1110       delete db;
1111       return;
1112    }
1113
1114    TSQLResult *res = db->Query(sql);
1115
1116    if (!res) {
1117       Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", kMDC));
1118       printf("%s\n", sql);
1119    }
1120
1121    delete res;
1122    delete db;
1123 }
1124
1125 //______________________________________________________________________________
1126 void AliRunDB::UpdateAliEn(AliStats *stats)
1127 {
1128    // Record file in AliEn catalog.
1129
1130    TGrid *g = TGrid::Connect(kAlienHost, "");
1131
1132    TString lfn = kAlienDir;
1133    lfn += "/";
1134    lfn += gSystem->BaseName(stats->GetFileName());
1135
1136 printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
1137        (int)stats->GetFileSize());
1138
1139    // crashes on ia64
1140    //g->AddFile(lfn, stats->GetFileName(), (int)stats->GetFileSize());
1141
1142    delete g;
1143 }
1144
1145 //______________________________________________________________________________
1146 void AliRunDB::Close()
1147 {
1148    // Close run database.
1149
1150    fRunDB->Close();
1151    delete fRunDB;
1152 }
1153
1154 //----------------- Use SIGUSR1 to interupt endless loop -----------------------
1155 class AliMDCInterruptHandler : public TSignalHandler {
1156 private:
1157    AliMDC *fMDC;   // alimdc to signal
1158 public:
1159    AliMDCInterruptHandler(AliMDC *mdc) : TSignalHandler(kSigUser1, kFALSE), fMDC(mdc) { }
1160    Bool_t Notify() { fMDC->SetStopLoop(); return kTRUE; }
1161 };
1162
1163 //______________________________________________________________________________
1164 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
1165                EWriteMode mode, Bool_t useLoop, Bool_t delFiles)
1166 {
1167    // Create MDC processor object.
1168
1169    fFd           = fd;
1170    fCompress     = compress;
1171    fMaxFileSize  = maxFileSize;
1172    fUseFilter    = useFilter;
1173    fWriteMode    = mode;
1174    fUseLoop      = useLoop;
1175    fUseFifo      = kFALSE;
1176    fUseEb        = kFALSE;
1177    fStopLoop     = kFALSE;
1178    fNumEvents    = 0;
1179    fDebugLevel   = 0;
1180    fgDeleteFiles = delFiles;
1181
1182    if (fFd == -1) {
1183 #ifdef USE_EB
1184      if (!ebRegister()) {
1185         Error("AliMDC", "cannot register with the event builder (%s)",
1186               ebGetLastError());
1187         return;
1188      }
1189      fUseEb = kTRUE;
1190 #else
1191      if ((mkfifo(kFifo, 0644) < 0) && (errno != EEXIST)) {
1192          Error("AliMDC", "cannot create fifo %s", kFifo);
1193          return;
1194       }
1195       if ((chmod(kFifo, 0666) == -1) && (errno != EPERM)) {
1196          Error("AliMDC", "cannot change permission of fifo %s", kFifo);
1197          return;
1198       }
1199       if ((fFd = open(kFifo, O_RDONLY)) == -1) {
1200          Error("AliMDC", "cannot open input file %s", kFifo);
1201          return;
1202       }
1203       fUseFifo = kTRUE;
1204 #endif
1205       fUseLoop = kFALSE;
1206    }
1207
1208    printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
1209           "looping = %s, compression = %d, delete files = %s",
1210           fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
1211           fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
1212           fgDeleteFiles ? "yes" : "no");
1213    if (fWriteMode == kRFIO)
1214       printf(", use RFIO\n");
1215    else if (fWriteMode == kROOTD)
1216       printf(", use rootd\n");
1217    else if (fWriteMode == kCASTOR)
1218       printf(", use CASTOR/rootd\n");
1219    else if (fWriteMode == kDEVNULL)
1220       printf(", write raw data to /dev/null\n");
1221    else
1222       printf("\n");
1223
1224    // install SIGUSR1 handler to allow clean interrupts
1225    gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
1226
1227    gAliMDC = this;
1228 }
1229
1230 //______________________________________________________________________________
1231 Int_t AliMDC::Run()
1232 {
1233    // Run the MDC processor. Read from the input stream and only return
1234    // when the input gave and EOF or a fatal error occured. On success 0
1235    // is returned, 1 in case of a fatality.
1236
1237    TStopwatch timer;
1238    Int_t status;
1239
1240    // Make sure needed directories exist
1241    const char *dirs[4];
1242    dirs[0] = kRawDBFS[0];
1243    dirs[1] = kRawDBFS[1];
1244    dirs[2] = kTagDBFS;
1245    dirs[3] = kRunDBFS;
1246    for (int idir = 0; idir < 4; idir++) {
1247       gSystem->ResetErrno();
1248       gSystem->MakeDirectory(dirs[idir]);
1249       if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
1250          SysError("Run", "mkdir %s", dirs[idir]);
1251          return 1;
1252       }
1253    }
1254
1255    // Used for statistics
1256    timer.Start();
1257    Double_t told = 0, tnew = 0;
1258    Float_t  chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
1259
1260    // Event object used to store event data.
1261    AliRawEvent *event = new AliRawEvent;
1262
1263    // Create new raw DB.
1264    AliRawDB *rawdb;
1265    if (fWriteMode == kRFIO)
1266       rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
1267    else if (fWriteMode == kROOTD)
1268       rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
1269    else if (fWriteMode == kCASTOR)
1270       rawdb = new AliRawCastorDB(event, fMaxFileSize, fCompress);
1271    else if (fWriteMode == kDEVNULL)
1272       rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
1273    else
1274       rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
1275
1276    if (rawdb->IsZombie()) return 1;
1277    printf("Filling raw DB %s\n", rawdb->GetDBName());
1278
1279    // Create new tag DB.
1280    AliTagDB *tagdb = 0;
1281 #if 0
1282    // no tagdb for the time being to get maximum speed
1283    if (fWriteMode == kDEVNULL)
1284       tagdb = new AliTagNullDB(event->GetHeader(), kMaxTagFileSize);
1285    else
1286       tagdb = new AliTagDB(event->GetHeader(), kMaxTagFileSize);
1287    if (tagdb->IsZombie())
1288       tagdb = 0;
1289    else
1290       printf("Filling tag DB %s\n", tagdb->GetDBName());
1291 #endif
1292
1293    // Create AliStats object
1294    AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1295
1296    // Shortcut for easy header access
1297    AliRawEventHeader &header = *event->GetHeader();
1298
1299    // Process input stream
1300 #ifdef USE_EB
1301    while (!ebEor()) {
1302       struct iovec *ebvec;
1303       if ((ebvec = ebGetNextEvent()) == (void *)-1) {
1304          Error("Run", "error getting next event (%s)", ebGetLastError());
1305          break;
1306       }
1307       if (ebvec == 0) {
1308          // no event, sleep for 1 second and try again
1309          gSystem->Sleep(1000);
1310          continue;
1311       }
1312       char *ebdata = (char *) ebvec[0].iov_base;
1313 #else
1314    while (1) {
1315       char *ebdata = 0;
1316 #endif
1317
1318       // Read event header
1319       if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
1320          if (status == 0) {
1321             if (fUseLoop) {
1322 #ifndef USE_EB
1323                ::lseek(fFd, 0, SEEK_SET);
1324 #endif
1325                continue;
1326             }
1327             printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
1328             break;
1329          }
1330          return 1;
1331       }
1332
1333       // If we were in looping mode stop directly after a SIGUSR1 signal
1334       if (StopLoop()) {
1335          Info("Run", "SIGUSR1, processed %d events", fNumEvents);
1336          break;
1337       }
1338
1339       // Check if event has any hard track flagged
1340       Bool_t callFilter = kFALSE;
1341       // This needs to be re-engineered for the next ADC...
1342       //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
1343       //   callFilter = kTRUE;
1344
1345       // Check event type and skip "Start of Run", "End of Run",
1346       // "Start of Run Files" and "End of Run Files"
1347       switch (header.GetType()) {
1348          case kStartOfRun:
1349          case kEndOfRun:
1350          case kStartOfRunFiles:
1351          case kEndOfRunFiles:
1352             {
1353                Int_t skip = header.GetEventSize() - header.HeaderSize();
1354 #ifndef USE_EB
1355                ::lseek(fFd, skip, SEEK_CUR);
1356 #endif
1357                ALIDEBUG(1)
1358                   Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
1359                continue;
1360             }
1361             break;
1362          default:
1363             ALIDEBUG(1) {
1364                Int_t s = header.GetEventSize() - header.HeaderSize();
1365                Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
1366             }
1367       }
1368
1369       // Amount of data left to read for this event
1370       Int_t toRead = header.GetEventSize() - header.HeaderSize();
1371
1372       // If there is less data for this event than the next sub-event
1373       // header, something is wrong. Skip to next event...
1374       if (toRead < header.HeaderSize()) {
1375          if ((status = DumpEvent(toRead)) != toRead) {
1376             if (status == 0)
1377                break;
1378             return 1;
1379          }
1380          Error("Run", "discarding event %d (too little data for header)", fNumEvents);
1381          continue;
1382       }
1383
1384       // Loop over all sub-events... (LDCs)
1385       while (toRead > 0) {
1386          Int_t nsub = 1;
1387 #ifdef USE_EB
1388          ebdata = (char *)ebvec[nsub].iov_base;
1389 #endif
1390
1391          ALIDEBUG(1)
1392             Info("Run", "reading LDC %d", nsub);
1393
1394          AliRawEvent *subEvent = event->NextSubEvent();
1395
1396          // Read sub-event header
1397          AliRawEventHeader &subHeader = *subEvent->GetHeader();
1398          if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
1399             if (status == 0) {
1400                Error("Run", "unexpected EOF reading sub-event header");
1401                break;
1402             }
1403             return 1;
1404          }
1405
1406          toRead -= subHeader.HeaderSize();
1407
1408 #ifdef USE_EB
1409          ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
1410 #endif
1411
1412          Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
1413
1414          // Read Equipment Header (in case of physics or calibration event)
1415          if (header.GetType() == kPhysicsEvent ||
1416              header.GetType() == kCalibrationEvent) {
1417             AliRawEquipmentHeader &equipment = *subEvent->GetEquipmentHeader();
1418             Int_t equipHeaderSize = equipment.HeaderSize();
1419             if ((status = ReadEquipmentHeader(equipment, header.DataIsSwapped(),
1420                                               ebdata)) != equipHeaderSize) {
1421                if (status == 0) {
1422                   Error("Run", "unexpected EOF reading equipment-header");
1423                   break;
1424                }
1425                return 1;
1426             }
1427             toRead  -= equipHeaderSize;
1428             rawSize -= equipHeaderSize;
1429 #ifdef USE_EB
1430             ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize() +
1431                      equipHeaderSize;
1432 #endif
1433          }
1434
1435          // Make sure raw data less than left over bytes for current event
1436          if (rawSize > toRead) {
1437             if ((status = DumpEvent(toRead)) != toRead) {
1438                if (status == 0)
1439                   break;
1440                return 1;
1441             }
1442             Error("Run", "discarding event %d (too much data)", fNumEvents);
1443             continue;
1444          }
1445
1446          // Read sub-event raw data
1447          AliRawData &subRaw = *subEvent->GetRawData();
1448          if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
1449             if (status == 0) {
1450                Error("Run", "unexpected EOF reading sub-event raw data");
1451                break;
1452             }
1453             return 1;
1454          }
1455
1456          if (callFilter) {
1457             if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
1458                Filter(subRaw);
1459             else {
1460                // set size of all sectors without hard track flag to 0
1461                subRaw.SetSize(0);
1462             }
1463          }
1464
1465          toRead -= rawSize;
1466          nsub++;
1467       }
1468
1469       // Set stat info for first event of this file
1470       if (rawdb->GetEvents() == 0)
1471          stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
1472
1473       // Store raw event in tree
1474       rawdb->Fill();
1475
1476       // Store header in tree
1477       if (tagdb) tagdb->Fill();
1478
1479       fNumEvents++;
1480
1481       if (!(fNumEvents%10))
1482          printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
1483
1484       // Filling time statistics
1485       if (rawdb->GetBytesWritten() > nextChunk) {
1486          tnew = timer.RealTime();
1487          stats->Fill(tnew-told);
1488          told = tnew;
1489          timer.Continue();
1490          nextChunk += chunkSize;
1491       }
1492
1493       // Check size of raw db. If bigger than maxFileSize, close file
1494       // and continue with new file.
1495       if (rawdb->FileFull()) {
1496
1497          printf("Written raw DB at a rate of %.1f MB/s\n",
1498                 Float_t(fMaxFileSize / timer.RealTime() / 1000000.));
1499
1500          // Write stats object to raw db, run db and MySQL
1501          stats->WriteToDB(rawdb);
1502          delete stats;
1503
1504          if (!rawdb->NextFile()) return 1;
1505
1506          printf("Filling raw DB %s\n", rawdb->GetDBName());
1507          stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1508
1509          timer.Start();
1510          told = 0, tnew = 0;
1511          nextChunk = chunkSize;
1512       }
1513
1514       // Check size of tag db
1515       if (tagdb && tagdb->FileFull()) {
1516          if (!tagdb->NextFile())
1517             tagdb = 0;
1518          else
1519             printf("Filling tag DB %s\n", tagdb->GetDBName());
1520       }
1521
1522       // Make top event object ready for next event data
1523       //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
1524       event->Reset();
1525
1526 #ifdef USE_EB
1527       if (!ebReleaseEvent(ebvec)) {
1528          Error("Run", "problem releasing event (%s)", ebGetLastError());
1529          break;
1530       }
1531 #endif
1532    }
1533
1534    printf("Written raw DB at a rate of %.1f MB/s\n",
1535           Float_t(fMaxFileSize / timer.RealTime() / 1000000.));
1536
1537    // Write stats to raw db and run db and delete stats object
1538    stats->WriteToDB(rawdb);
1539    delete stats;
1540
1541    // Close the raw DB
1542    delete rawdb;
1543
1544    // Close the tag DB
1545    delete tagdb;
1546
1547    // Close input source
1548    close(fFd);
1549
1550 #if 0
1551    // Cleanup fifo
1552    if (fUseFifo && ::unlink(kFifo) == -1) {
1553       SysError("Run", "unlink");
1554       return 1;
1555    }
1556 #endif
1557
1558    return 0;
1559 }
1560
1561 //______________________________________________________________________________
1562 Int_t AliMDC::Read(void *buffer, Int_t length)
1563 {
1564    // Read exactly length bytes into buffer. Returns number of bytes
1565    // received, returns -1 in case of error and 0 for EOF.
1566
1567    errno = 0;
1568
1569    if (fFd < 0) return -1;
1570
1571    Int_t n, nrecv = 0;
1572    char *buf = (char *)buffer;
1573
1574    for (n = 0; n < length; n += nrecv) {
1575       if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
1576          if (nrecv == 0)
1577             break;        // EOF
1578          if (errno != EINTR)
1579             SysError("Read", "read");
1580          return -1;
1581       }
1582    }
1583    return n;
1584 }
1585
1586 //______________________________________________________________________________
1587 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
1588 {
1589    // Read header info from DATE data stream. Returns bytes read (i.e.
1590    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1591
1592    Int_t nrecv;
1593
1594    if (eb) {
1595       // read from event builder memory area
1596       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1597       nrecv = header.HeaderSize();
1598    } else {
1599       // read from fifo or file
1600       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1601            header.HeaderSize()) {
1602          if (nrecv == 0)
1603             return 0;
1604          return -1;
1605       }
1606    }
1607
1608    // Swap header data if needed
1609    if (header.IsSwapped())
1610       header.Swap();
1611
1612    // Is header valid...
1613    if (!header.IsValid()) {
1614       Error("ReadHeader", "invalid header format");
1615       // try recovery... how?
1616       return -1;
1617    }
1618    if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
1619       Error("ReadHeader", "invalid header size");
1620       // try recovery... how?
1621       return -1;
1622    }
1623
1624    return nrecv;
1625 }
1626
1627 //______________________________________________________________________________
1628 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
1629                                   Bool_t isSwapped, void *eb)
1630 {
1631    // Read equipment header info from DATE data stream. Returns bytes read
1632    // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
1633    // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
1634    // and we will swap the header to host format.
1635
1636    Int_t nrecv;
1637
1638    if (eb) {
1639       // read from event builder memory area
1640       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1641       nrecv = header.HeaderSize();
1642    } else {
1643       // read from fifo or file
1644       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1645            header.HeaderSize()) {
1646          if (nrecv == 0)
1647             return 0;
1648          return -1;
1649       }
1650    }
1651
1652    // Swap equipment header data if needed
1653    if (isSwapped)
1654       header.Swap();
1655
1656    if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
1657       Error("ReadEquipmentHeader", "invalid equipment header size");
1658       // try recovery... how?
1659       return -1;
1660    }
1661
1662    return nrecv;
1663 }
1664
1665 //______________________________________________________________________________
1666 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
1667 {
1668    // Read raw data from DATE data stream. Returns bytes read (i.e.
1669    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1670
1671    Int_t nrecv;
1672
1673    if (eb) {
1674       // read from event builder memory area
1675       raw.SetBuffer(eb, size);
1676       nrecv = size;
1677    } else {
1678       // read from fifo or file
1679       raw.SetSize(size);
1680       if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
1681          if (nrecv == 0) {
1682             Error("ReadRawData", "unexpected EOF");
1683             return 0;
1684          }
1685          return -1;
1686       }
1687    }
1688
1689    return nrecv;
1690 }
1691
1692 //______________________________________________________________________________
1693 Int_t AliMDC::DumpEvent(Int_t toRead)
1694 {
1695    // This case should not happen, but if it does try to handle it
1696    // gracefully by reading the rest of the event and discarding it.
1697    // Returns bytes read, -1 in case of fatal error and 0 for EOF.
1698
1699    Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
1700
1701    Int_t nrecv;
1702    char *tbuf = new char[toRead];
1703    if ((nrecv = Read(tbuf, toRead)) != toRead) {
1704       if (nrecv == 0) {
1705          Error("DumpEvent", "unexpected EOF");
1706          return 0;
1707       }
1708       return -1;
1709    }
1710    delete [] tbuf;
1711
1712    return nrecv;
1713 }
1714
1715 #ifdef USE_HLT
1716 #include <AliTPCL3Tunnel.h>
1717 #endif
1718
1719 //______________________________________________________________________________
1720 Int_t AliMDC::Filter(AliRawData &raw)
1721 {
1722    // Call 3rd level filter for this raw data segment.
1723
1724 #ifdef USE_HLT
1725    AliTPCL3Tunnel *tunnel = 0;
1726    if (!tunnel) {
1727       // initialisation
1728       tunnel = new AliTPCL3Tunnel(Form("%s/TPCparams.root",
1729                                        gSystem->Getenv("ALITPC")));
1730    }
1731
1732    Int_t obytes, nbytes;
1733    obytes = nbytes = raw.GetSize();
1734    char *outbuf = tunnel->EvalTrack((char *)raw.GetBuffer(), nbytes);
1735
1736    raw.SetSize(nbytes);
1737    memcpy(raw.GetBuffer(), outbuf, nbytes);
1738
1739    printf("Filter called for event %d: reduced from %d to %d\n", fNumEvents,
1740           obytes, nbytes);
1741
1742 #else
1743
1744    raw.GetSize();
1745    printf("Filter called for event %d\n", fNumEvents);
1746
1747 #endif
1748
1749    return 0;
1750 }