fix reporting of writing speed when interrupted by signal.
[u/mrichter/AliRoot.git] / RAW / AliRawEvent.cxx
1 // @(#)alimdc:$Name$:$Id$
2 // Author: Fons Rademakers  26/11/99
3 // Updated: Dario Favretto  15/04/2003
4
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #if defined(__DECCXX)
8 #include <sys/statvfs.h>
9 #else
10 #if defined(__APPLE__)
11 #include <sys/param.h>
12 #include <sys/mount.h>
13 #else
14 #include <sys/vfs.h>
15 #endif
16 #endif
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <fcntl.h>
20 #include <errno.h>
21
22 #include <TBuffer.h>
23 #include <TSystem.h>
24 #include <TError.h>
25 #include <TStopwatch.h>
26 #include <TSQLServer.h>
27 #include <TSQLResult.h>
28 #include <TUrl.h>
29 #include <TGrid.h>
30
31 #if defined(__APPLE__)
32 #undef Free
33 #endif
34 #include "AliRawEvent.h"
35
36 // Good for Linux
37 #define long32 int
38 #include "DateEvent.h"
39
40 #ifdef USE_EB
41 #include "libDateEb.h"
42 #endif
43
44
45 ClassImp(AliRawEvent)
46 ClassImp(AliRawEventHeader)
47 ClassImp(AliRawEquipmentHeader)
48 ClassImp(AliRawData)
49 ClassImp(AliStats)
50 ClassImp(AliRawDB)
51 ClassImp(AliRawRFIODB)
52 ClassImp(AliRawCastorDB)
53 ClassImp(AliRawRootdDB)
54 ClassImp(AliRawNullDB)
55 ClassImp(AliTagDB)
56 ClassImp(AliTagNullDB)
57 ClassImp(AliRunDB)
58 ClassImp(AliMDC)
59
60 // Which MDC is this...
61 const Int_t kMDC = 5;
62
63 // Fixed file system locations for the different DB's
64 #ifdef USE_RDM
65 const char *kFifo       = "/tmp/alimdc.fifo";
66 const char *kRawDBFS[2] = { "/tmp/mdc1", "/tmp/mdc2" };
67 const char *kTagDBFS    = "/tmp/mdc1/tags";
68 const char *kRunDBFS    = "/tmp/mdc1/meta";
69 const char *kRFIOFS     = "rfio:/castor/cern.ch/user/r/rdm";
70 const char *kCastorFS   = "castor:/castor/cern.ch/user/r/rdm";
71 const char *kRootdFS    = "root://localhost//tmp/mdc1";
72 const char *kAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
73 const char *kAlienDir   = "/alice_mdc/DC";
74 #else
75 const char *kFifo       = "/tmp/alimdc.fifo";
76 const char *kRawDBFS[2] = { "/data1/mdc", "/data2/mdc" };
77 const char *kTagDBFS    = "/data1/mdc/tags";
78 const char *kRunDBFS    = "/data1/mdc/meta";
79 const char *kRFIOFS     = "rfio:/castor/cern.ch/lcg/dc5";
80 const char *kCastorFS   = "castor:/castor/cern.ch/lcg/dc5";
81 const char *kRootdFS    = "root://localhost//tmp/mdc1";
82 const char *kAlienHost  = "alien://aliens7.cern.ch:15000/?direct";
83 const char *kAlienDir   = "/alice_mdc/DC";
84 #endif
85
86 // Maximum size of tag db files
87 const Double_t kMaxTagFileSize = 2.5e8;    // 250MB
88
89 Bool_t AliMDC::fgDeleteFiles = kFALSE;
90
91 AliMDC *gAliMDC = 0;
92
93
94 //______________________________________________________________________________
95 Bool_t AliRawEventHeader::DataIsSwapped() const
96 {
97    // Returns true if event data is swapped.
98
99    if (TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_EVENT_SWAPPED))
100       return kTRUE;
101    return kFALSE;
102 }
103
104 //______________________________________________________________________________
105 void AliRawEventHeader::Swap()
106 {
107    // Swap header data.
108
109    if (IsSwapped()) {
110       fSize         = net2host(fSize);
111       fMagic        = net2host(fMagic);
112       fHeadLen      = net2host(fHeadLen);
113       fVersion      = net2host(fVersion);
114       fType         = net2host(fType);
115       fRunNb        = net2host(fRunNb);
116       for (int i = 0; i < kIdWords; i++)
117          fId[i] = net2host(fId[i]);
118       for (int i = 0; i < kTriggerWords; i++)
119          fTriggerPattern[i] = net2host(fTriggerPattern[i]);
120       for (int i = 0; i < kDetectorWords; i++)
121          fDetectorPattern[i] = net2host(fDetectorPattern[i]);
122       for (int i = 0; i < kAttributeWords; i++)
123          fTypeAttribute[i] = net2host(fTypeAttribute[i]);
124       fLDCId        = net2host(fLDCId);
125       fGDCId        = net2host(fGDCId);
126    }
127 }
128
129 //______________________________________________________________________________
130 UInt_t AliRawEventHeader::GetEventInRun() const
131 {
132    // Get event number in run. Correct for fixed target mode which is used
133    // in the Data Challenge Setup.
134
135    if (!TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_ORBIT_BC)) {
136       return EVENT_ID_GET_NB_IN_RUN(fId);
137    }
138    return 0;
139 }
140
141 //______________________________________________________________________________
142 const char *AliRawEventHeader::GetTypeName() const
143 {
144    // Get event type as a string.
145
146    switch (GetType()) {
147       case kStartOfRun:
148          return "START_OF_RUN";
149          break;
150       case kEndOfRun:
151          return "END_OF_RUN";
152          break;
153       case kStartOfRunFiles:
154          return "START_OF_RUN_FILES";
155          break;
156       case kEndOfRunFiles:
157          return "END_OF_RUN_FILES";
158          break;
159       case kStartOfBurst:
160          return "START_OF_BURST";
161          break;
162       case kEndOfBurst:
163          return "END_OF_BURST";
164          break;
165       case kPhysicsEvent:
166          return "PHYSICS_EVENT";
167          break;
168       case kCalibrationEvent:
169          return "CALIBRATION_EVENT";
170          break;
171       case kFormatError:
172          return "EVENT_FORMAT_ERROR";
173          break;
174       default:
175          return "*** UNKNOWN EVENT TYPE ***";
176          break;
177    }
178 }
179
180
181 //______________________________________________________________________________
182 void AliRawEquipmentHeader::Swap()
183 {
184    // Swap equipment header data. There is no way to see if the data
185    // has already been swapped. This method is only called when the
186    // header is read from the DATE event builder (GDC).
187
188    fSize                 = net2host(fSize);
189    fEquipmentType        = net2host(fEquipmentType);
190    fEquipmentID          = net2host(fEquipmentID);
191    fBasicElementSizeType = net2host(fBasicElementSizeType);
192    for (int i = 0; i < kAttributeWords; i++)
193       fTypeAttribute[i] = net2host(fTypeAttribute[i]);
194 }
195
196
197 //______________________________________________________________________________
198 AliRawEvent::AliRawEvent()
199 {
200    // Create ALICE event object. If ownData is kFALSE we will use a static
201    // raw data object, otherwise a private copy will be made.
202
203    fNSubEvents = 0;
204    fEvtHdr     = new AliRawEventHeader;
205    fEqpHdr     = 0;
206    fRawData    = 0;
207    fSubEvents  = 0;
208 }
209
210 //______________________________________________________________________________
211 AliRawEquipmentHeader *AliRawEvent::GetEquipmentHeader()
212 {
213    // Get equipment header part of AliRawEvent.
214
215    if (!fEqpHdr)
216       fEqpHdr = new AliRawEquipmentHeader;
217
218    return fEqpHdr;
219 }
220
221 //______________________________________________________________________________
222 AliRawData *AliRawEvent::GetRawData()
223 {
224    // Get raw data part of AliRawEvent.
225
226    if (!fRawData)
227       fRawData = new AliRawData;
228
229    return fRawData;
230 }
231
232 //______________________________________________________________________________
233 AliRawEvent *AliRawEvent::NextSubEvent()
234 {
235    // Returns next sub-event object.
236
237    if (!fSubEvents)
238       fSubEvents = new TObjArray(100); // arbitrary, probably enough to prevent resizing
239
240    if (fSubEvents->GetSize() <= fNSubEvents) {
241       fSubEvents->Expand(fNSubEvents+10);
242       Warning("NextSubEvent", "expanded fSubEvents by 10 to %d",
243               fSubEvents->GetSize());
244    }
245
246    AliRawEvent *ev;
247    if (!(ev = (AliRawEvent *)fSubEvents->At(fNSubEvents))) {
248       ev = new AliRawEvent;
249       fSubEvents->AddAt(ev, fNSubEvents);
250    }
251
252    fNSubEvents++;
253
254    return ev;
255 }
256
257 //______________________________________________________________________________
258 AliRawEvent *AliRawEvent::GetSubEvent(Int_t index) const
259 {
260    // Get specified sub event. Returns 0 if sub event does not exist.
261
262    if (!fSubEvents)
263       return 0;
264
265    return (AliRawEvent *) fSubEvents->At(index);
266 }
267
268 //______________________________________________________________________________
269 void AliRawEvent::Reset()
270 {
271    // Reset the event in case it needs to be re-used (avoiding costly
272    // new/delete cycle). We reset the size marker for the AliRawData
273    // objects and the sub event counter.
274
275    for (int i = 0; i < fNSubEvents; i++) {
276       AliRawEvent *ev = (AliRawEvent *)fSubEvents->At(i);
277       ev->GetRawData()->SetSize(0);
278    }
279    fNSubEvents = 0;
280 }
281
282 //______________________________________________________________________________
283 AliRawEvent::~AliRawEvent()
284 {
285    // Clean up event object. Delete also, possible, private raw data.
286
287    delete fEvtHdr;
288    delete fEqpHdr;
289    delete fRawData;
290    if (fSubEvents)
291       fSubEvents->Delete();
292    delete fSubEvents;
293 }
294
295 //______________________________________________________________________________
296 AliStats::AliStats(const char *filename, Int_t compmode, Bool_t filter)
297 {
298    // Create statistics object.
299
300    fEvents     = 0;
301    fFirstRun   = 0;
302    fFirstEvent = 0;
303    fLastRun    = 0;
304    fLastEvent  = 0;
305    fChunk      = -0.5;
306    fFileName   = filename;
307    fCompMode   = compmode;
308    fFilter     = filter;
309    fRTHist     = 0;
310 }
311
312 //______________________________________________________________________________
313 AliStats::~AliStats()
314 {
315    // Cleanup stats object.
316
317    delete fRTHist;
318 }
319
320 //______________________________________________________________________________
321 AliStats &AliStats::operator=(const AliStats &rhs)
322 {
323    // AliStats assignment operator.
324
325    if (this != &rhs) {
326       TObject::operator=(rhs);
327       fEvents     = rhs.fEvents;
328       fFirstRun   = rhs.fFirstRun;
329       fFirstEvent = rhs.fFirstEvent;
330       fLastRun    = rhs.fLastRun;
331       fLastEvent  = rhs.fLastEvent;
332       fBegin      = rhs.fBegin;
333       fEnd        = rhs.fEnd;
334       fFileName   = rhs.fFileName;
335       fFileSize   = rhs.fFileSize;
336       fCompFactor = rhs.fCompFactor;
337       fCompMode   = rhs.fCompMode;
338       fFilter     = rhs.fFilter;
339       fRTHist     = rhs.fRTHist ? (TH1F*) rhs.fRTHist->Clone() : 0;
340       fChunk      = rhs.fChunk;
341    }
342    return *this;
343 }
344
345 //______________________________________________________________________________
346 void AliStats::Fill(Float_t time)
347 {
348    // Fill histogram. This histogram shows the (hopefully constant) time
349    // it takes to fill the ROOT DB.
350    // Expects to be called 100 times for each file.
351
352    if (!fRTHist) {
353       fRTHist = new TH1F("rtime","Real-time to write data chunk", 100, 0, 100);
354       fRTHist->SetDirectory(0);
355    }
356
357    fRTHist->Fill(fChunk, time);
358    fChunk += 1.0;
359 }
360
361 //______________________________________________________________________________
362 void AliStats::WriteToDB(AliRawDB *rawdb)
363 {
364    // Write stats to raw DB, local run DB and global MySQL DB.
365
366    AliRawEventHeader &header = *rawdb->GetEvent()->GetHeader();
367
368    // Write stats into RawDB
369    TDirectory *ds = gDirectory;
370    rawdb->GetDB()->cd();
371    SetEvents(rawdb->GetEvents());
372    SetLastId(header.GetRunNumber(), header.GetEventInRun());
373    SetFileSize(rawdb->GetBytesWritten());
374    SetCompressionFactor(rawdb->GetCompressionFactor());
375    SetEndTime();
376    Write("stats");
377    ds->cd();
378
379    // Write stats also in the bookkeeping RunDB
380    AliRunDB *rundb = new AliRunDB(kTRUE);
381    rundb->Update(this);
382    rundb->UpdateRDBMS(this);
383    rundb->UpdateAliEn(this);
384    delete rundb;
385 }
386
387 //______________________________________________________________________________
388 AliRawDB::AliRawDB(AliRawEvent *event, Double_t maxsize, Int_t compress,
389                    Bool_t create)
390 {
391    // Create a new raw DB containing at most maxsize bytes.
392
393    fEvent    = event;
394    fMaxSize  = maxsize;
395    fCompress = compress;
396
397    // Consistency check with DATE header file
398    if (fEvent->GetHeader()->HeaderSize() != EVENT_HEAD_BASE_SIZE) {
399       Error("AliRawDB", "inconsistency between DATE and AliRawEvent headers");
400       MakeZombie();
401       return;
402    }
403
404    if (create) {
405       if (!Create())
406          MakeZombie();
407    }
408 }
409
410 //______________________________________________________________________________
411 Bool_t AliRawDB::FSHasSpace(const char *fs)
412 {
413    // Check for at least fMaxSize bytes of free space on the file system.
414    // If the space is not available return kFALSE, kTRUE otherwise.
415
416    Long_t id, bsize, blocks, bfree;
417
418    if (gSystem->GetFsInfo(fs, &id, &bsize, &blocks, &bfree) == 1) {
419       Error("FSHasSpace", "could not stat file system %s", fs);
420       return kFALSE;
421    }
422
423    // Leave 5 percent of diskspace free
424    Double_t avail = Double_t(bfree) * 0.95;
425    if (avail*bsize > fMaxSize)
426       return kTRUE;
427
428    Warning("FSHasSpace", "no space on file system %s", fs);
429    return kFALSE;
430 }
431
432 //______________________________________________________________________________
433 const char *AliRawDB::GetFileName()
434 {
435    // Return filename based on hostname and date and time. This will make
436    // each file unique. Also makes sure (via FSHasSpace()) that there is
437    // enough space on the file system to store the file. Returns 0 in
438    // case of error or interrupt signal.
439
440    static TString fname;
441    static Bool_t  fstoggle = kFALSE;
442
443    TString fs = fstoggle ? kRawDBFS[1] : kRawDBFS[0];
444    TDatime dt;
445
446    TString hostname = gSystem->HostName();
447    Int_t pos;
448    if ((pos = hostname.Index(".")) != kNPOS)
449       hostname.Remove(pos);
450
451    if (!FSHasSpace(fs)) {
452       while (1) {
453          fstoggle = !fstoggle;
454          fs = fstoggle ? kRawDBFS[1] : kRawDBFS[0];
455          if (FSHasSpace(fs)) break;
456          Info("GetFileName", "sleeping 30 seconds before retrying...");
457          gSystem->Sleep(30000);   // sleep for 30 seconds
458          if (gAliMDC && gAliMDC->StopLoop())
459             return 0;
460       }
461    }
462
463    fname = fs + "/" + hostname + "_";
464    fname += dt.GetDate();
465    fname += "_";
466    fname += dt.GetTime();
467    fname += ".root";
468
469    fstoggle = !fstoggle;
470
471    return fname;
472 }
473
474 //______________________________________________________________________________
475 Bool_t AliRawDB::Create()
476 {
477    // Create a new raw DB.
478
479 again:
480    const char *fname = GetFileName();
481    if (!fname) return kFALSE;
482
483    fRawDB = TFile::Open(fname, "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(Bool_t noLocalDB)
1038 {
1039    // Open run database, and get or create tree.
1040
1041    fRunDB = 0;
1042
1043    if (noLocalDB) return;
1044
1045    // Get hostname
1046    char hostname[64], filename[64];
1047    const char *fs = kRunDBFS;
1048
1049    // check that fs exists (crude check fails if fs is a file)
1050    gSystem->MakeDirectory(fs);
1051
1052    strcpy(hostname, gSystem->HostName());
1053
1054    char *s;
1055    if ((s = strchr(hostname, '.')))
1056       *s = 0;
1057
1058    sprintf(filename, "%s/%s_rundb.root", fs, hostname);
1059
1060    if (!gSystem->AccessPathName(filename, kFileExists))
1061       fRunDB = new TFile(filename, "UPDATE");
1062    else
1063       fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", kMDC));
1064 }
1065
1066 //______________________________________________________________________________
1067 void AliRunDB::Update(AliStats *stats)
1068 {
1069    // Add stats object to database.
1070
1071    if (!stats || !fRunDB) return;
1072
1073    TDirectory *ds = gDirectory;
1074    fRunDB->cd();
1075
1076    char sname[64];
1077    char *s = (char*)strrchr(stats->GetFileName(), '/');
1078    if (s) {
1079       s++;
1080       strcpy(sname, s);
1081    } else
1082       strcpy(sname, stats->GetFileName());
1083    s = strchr(sname, '.');
1084    if (s) *s = 0;
1085
1086    stats->Write(sname);
1087
1088    ds->cd();
1089 }
1090
1091 //______________________________________________________________________________
1092 void AliRunDB::UpdateRDBMS(AliStats *stats)
1093 {
1094    // Add stats object to central MySQL DB.
1095
1096    if (!stats) return;
1097
1098    char sql[4096];
1099    char bt[25], et[25];
1100
1101    strcpy(bt, stats->GetBeginTime().AsSQLString());
1102    strcpy(et, stats->GetEndTime().AsSQLString());
1103
1104    sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
1105            "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", kMDC,
1106            stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
1107            stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
1108            stats->GetLastEvent(), stats->GetCompressionMode(),
1109            stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
1110            bt, et);
1111
1112    // open connection to MySQL server on pcsalo
1113    TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");
1114
1115    if (!db || db->IsZombie()) {
1116       Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
1117       printf("%s\n", sql);
1118       delete db;
1119       return;
1120    }
1121
1122    TSQLResult *res = db->Query(sql);
1123
1124    if (!res) {
1125       Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", kMDC));
1126       printf("%s\n", sql);
1127    }
1128
1129    delete res;
1130    delete db;
1131 }
1132
1133 //______________________________________________________________________________
1134 void AliRunDB::UpdateAliEn(AliStats *stats)
1135 {
1136    // Record file in AliEn catalog.
1137
1138    if (!stats) return;
1139
1140    TGrid *g = TGrid::Connect(kAlienHost, "");
1141
1142    TString lfn = kAlienDir;
1143    lfn += "/";
1144    lfn += gSystem->BaseName(stats->GetFileName());
1145
1146    //printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
1147    //       (int)stats->GetFileSize());
1148
1149    g->AddFile(lfn, stats->GetFileName(), (int)stats->GetFileSize());
1150
1151    delete g;
1152 }
1153
1154 //______________________________________________________________________________
1155 void AliRunDB::Close()
1156 {
1157    // Close run database.
1158
1159    if (fRunDB) fRunDB->Close();
1160    delete fRunDB;
1161 }
1162
1163 //----------------- Use SIGUSR1 to interupt endless loop -----------------------
1164 class AliMDCInterruptHandler : public TSignalHandler {
1165 private:
1166    AliMDC *fMDC;   // alimdc to signal
1167 public:
1168    AliMDCInterruptHandler(AliMDC *mdc) : TSignalHandler(kSigUser1, kFALSE), fMDC(mdc) { }
1169    Bool_t Notify() {
1170       Info("Notify", "received a SIGUSR1 signal");
1171       fMDC->SetStopLoop();
1172       return kTRUE;
1173    }
1174 };
1175
1176 //______________________________________________________________________________
1177 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
1178                EWriteMode mode, Bool_t useLoop, Bool_t delFiles)
1179 {
1180    // Create MDC processor object.
1181
1182    fFd           = fd;
1183    fCompress     = compress;
1184    fMaxFileSize  = maxFileSize;
1185    fUseFilter    = useFilter;
1186    fWriteMode    = mode;
1187    fUseLoop      = useLoop;
1188    fUseFifo      = kFALSE;
1189    fUseEb        = kFALSE;
1190    fStopLoop     = kFALSE;
1191    fNumEvents    = 0;
1192    fDebugLevel   = 0;
1193    fgDeleteFiles = delFiles;
1194
1195    if (fFd == -1) {
1196 #ifdef USE_EB
1197      if (!ebRegister()) {
1198         Error("AliMDC", "cannot register with the event builder (%s)",
1199               ebGetLastError());
1200         return;
1201      }
1202      fUseEb = kTRUE;
1203 #else
1204      if ((mkfifo(kFifo, 0644) < 0) && (errno != EEXIST)) {
1205          Error("AliMDC", "cannot create fifo %s", kFifo);
1206          return;
1207       }
1208       if ((chmod(kFifo, 0666) == -1) && (errno != EPERM)) {
1209          Error("AliMDC", "cannot change permission of fifo %s", kFifo);
1210          return;
1211       }
1212       if ((fFd = open(kFifo, O_RDONLY)) == -1) {
1213          Error("AliMDC", "cannot open input file %s", kFifo);
1214          return;
1215       }
1216       fUseFifo = kTRUE;
1217 #endif
1218       fUseLoop = kFALSE;
1219    }
1220
1221    printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
1222           "looping = %s, compression = %d, delete files = %s",
1223           fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
1224           fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
1225           fgDeleteFiles ? "yes" : "no");
1226    if (fWriteMode == kRFIO)
1227       printf(", use RFIO\n");
1228    else if (fWriteMode == kROOTD)
1229       printf(", use rootd\n");
1230    else if (fWriteMode == kCASTOR)
1231       printf(", use CASTOR/rootd\n");
1232    else if (fWriteMode == kDEVNULL)
1233       printf(", write raw data to /dev/null\n");
1234    else
1235       printf("\n");
1236
1237    // install SIGUSR1 handler to allow clean interrupts
1238    gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
1239
1240    gAliMDC = this;
1241 }
1242
1243 //______________________________________________________________________________
1244 Int_t AliMDC::Run()
1245 {
1246    // Run the MDC processor. Read from the input stream and only return
1247    // when the input gave and EOF or a fatal error occured. On success 0
1248    // is returned, 1 in case of a fatality.
1249
1250    TStopwatch timer;
1251    Int_t status;
1252
1253    // Make sure needed directories exist
1254    const char *dirs[4];
1255    dirs[0] = kRawDBFS[0];
1256    dirs[1] = kRawDBFS[1];
1257    dirs[2] = kTagDBFS;
1258    dirs[3] = kRunDBFS;
1259    for (int idir = 0; idir < 4; idir++) {
1260       gSystem->ResetErrno();
1261       gSystem->MakeDirectory(dirs[idir]);
1262       if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
1263          SysError("Run", "mkdir %s", dirs[idir]);
1264          return 1;
1265       }
1266    }
1267
1268    // Used for statistics
1269    timer.Start();
1270    Double_t told = 0, tnew = 0;
1271    Float_t  chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
1272
1273    // Event object used to store event data.
1274    AliRawEvent *event = new AliRawEvent;
1275
1276    // Create new raw DB.
1277    AliRawDB *rawdb;
1278    if (fWriteMode == kRFIO)
1279       rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
1280    else if (fWriteMode == kROOTD)
1281       rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
1282    else if (fWriteMode == kCASTOR)
1283       rawdb = new AliRawCastorDB(event, fMaxFileSize, fCompress);
1284    else if (fWriteMode == kDEVNULL)
1285       rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
1286    else
1287       rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
1288
1289    if (rawdb->IsZombie()) return 1;
1290    printf("Filling raw DB %s\n", rawdb->GetDBName());
1291
1292    // Create new tag DB.
1293    AliTagDB *tagdb = 0;
1294 #if 0
1295    // no tagdb for the time being to get maximum speed
1296    if (fWriteMode == kDEVNULL)
1297       tagdb = new AliTagNullDB(event->GetHeader(), kMaxTagFileSize);
1298    else
1299       tagdb = new AliTagDB(event->GetHeader(), kMaxTagFileSize);
1300    if (tagdb->IsZombie())
1301       tagdb = 0;
1302    else
1303       printf("Filling tag DB %s\n", tagdb->GetDBName());
1304 #endif
1305
1306    // Create AliStats object
1307    AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1308
1309    // Shortcut for easy header access
1310    AliRawEventHeader &header = *event->GetHeader();
1311
1312    // Process input stream
1313 #ifdef USE_EB
1314    while (!ebEor()) {
1315       struct iovec *ebvec;
1316       if ((ebvec = ebGetNextEvent()) == (void *)-1) {
1317          Error("Run", "error getting next event (%s)", ebGetLastError());
1318          break;
1319       }
1320       if (ebvec == 0) {
1321          // no event, sleep for 1 second and try again
1322          gSystem->Sleep(1000);
1323          continue;
1324       }
1325       char *ebdata = (char *) ebvec[0].iov_base;
1326 #else
1327    while (1) {
1328       char *ebdata = 0;
1329 #endif
1330
1331       // Read event header
1332       if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
1333          if (status == 0) {
1334             if (fUseLoop) {
1335 #ifndef USE_EB
1336                ::lseek(fFd, 0, SEEK_SET);
1337 #endif
1338                continue;
1339             }
1340             printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
1341             break;
1342          }
1343          return 1;
1344       }
1345
1346       // If we were in looping mode stop directly after a SIGUSR1 signal
1347       if (StopLoop()) {
1348          Info("Run", "Stopping loop, processed %d events", fNumEvents);
1349          break;
1350       }
1351
1352       // Check if event has any hard track flagged
1353       Bool_t callFilter = kFALSE;
1354       // This needs to be re-engineered for the next ADC...
1355       //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
1356       //   callFilter = kTRUE;
1357
1358       // Check event type and skip "Start of Run", "End of Run",
1359       // "Start of Run Files" and "End of Run Files"
1360       switch (header.GetType()) {
1361          case kStartOfRun:
1362          case kEndOfRun:
1363          case kStartOfRunFiles:
1364          case kEndOfRunFiles:
1365             {
1366                Int_t skip = header.GetEventSize() - header.HeaderSize();
1367 #ifndef USE_EB
1368                ::lseek(fFd, skip, SEEK_CUR);
1369 #endif
1370                ALIDEBUG(1)
1371                   Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
1372                continue;
1373             }
1374             break;
1375          default:
1376             ALIDEBUG(1) {
1377                Int_t s = header.GetEventSize() - header.HeaderSize();
1378                Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
1379             }
1380       }
1381
1382       // Amount of data left to read for this event
1383       Int_t toRead = header.GetEventSize() - header.HeaderSize();
1384
1385       // If there is less data for this event than the next sub-event
1386       // header, something is wrong. Skip to next event...
1387       if (toRead < header.HeaderSize()) {
1388          if ((status = DumpEvent(toRead)) != toRead) {
1389             if (status == 0)
1390                break;
1391             return 1;
1392          }
1393          Error("Run", "discarding event %d (too little data for header)", fNumEvents);
1394          continue;
1395       }
1396
1397       // Loop over all sub-events... (LDCs)
1398       while (toRead > 0) {
1399          Int_t nsub = 1;
1400 #ifdef USE_EB
1401          ebdata = (char *)ebvec[nsub].iov_base;
1402 #endif
1403
1404          ALIDEBUG(1)
1405             Info("Run", "reading LDC %d", nsub);
1406
1407          AliRawEvent *subEvent = event->NextSubEvent();
1408
1409          // Read sub-event header
1410          AliRawEventHeader &subHeader = *subEvent->GetHeader();
1411          if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
1412             if (status == 0) {
1413                Error("Run", "unexpected EOF reading sub-event header");
1414                break;
1415             }
1416             return 1;
1417          }
1418
1419          toRead -= subHeader.HeaderSize();
1420
1421 #ifdef USE_EB
1422          ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
1423 #endif
1424
1425          Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
1426
1427          // Read Equipment Header (in case of physics or calibration event)
1428          if (header.GetType() == kPhysicsEvent ||
1429              header.GetType() == kCalibrationEvent) {
1430             AliRawEquipmentHeader &equipment = *subEvent->GetEquipmentHeader();
1431             Int_t equipHeaderSize = equipment.HeaderSize();
1432             if ((status = ReadEquipmentHeader(equipment, header.DataIsSwapped(),
1433                                               ebdata)) != equipHeaderSize) {
1434                if (status == 0) {
1435                   Error("Run", "unexpected EOF reading equipment-header");
1436                   break;
1437                }
1438                return 1;
1439             }
1440             toRead  -= equipHeaderSize;
1441             rawSize -= equipHeaderSize;
1442 #ifdef USE_EB
1443             ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize() +
1444                      equipHeaderSize;
1445 #endif
1446          }
1447
1448          // Make sure raw data less than left over bytes for current event
1449          if (rawSize > toRead) {
1450             if ((status = DumpEvent(toRead)) != toRead) {
1451                if (status == 0)
1452                   break;
1453                return 1;
1454             }
1455             Error("Run", "discarding event %d (too much data)", fNumEvents);
1456             continue;
1457          }
1458
1459          // Read sub-event raw data
1460          AliRawData &subRaw = *subEvent->GetRawData();
1461          if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
1462             if (status == 0) {
1463                Error("Run", "unexpected EOF reading sub-event raw data");
1464                break;
1465             }
1466             return 1;
1467          }
1468
1469          if (callFilter) {
1470             if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
1471                Filter(subRaw);
1472             else {
1473                // set size of all sectors without hard track flag to 0
1474                subRaw.SetSize(0);
1475             }
1476          }
1477
1478          toRead -= rawSize;
1479          nsub++;
1480       }
1481
1482       // Set stat info for first event of this file
1483       if (rawdb->GetEvents() == 0)
1484          stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
1485
1486       // Store raw event in tree
1487       rawdb->Fill();
1488
1489       // Store header in tree
1490       if (tagdb) tagdb->Fill();
1491
1492       fNumEvents++;
1493
1494       if (!(fNumEvents%10))
1495          printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
1496
1497       // Filling time statistics
1498       if (rawdb->GetBytesWritten() > nextChunk) {
1499          tnew = timer.RealTime();
1500          stats->Fill(tnew-told);
1501          told = tnew;
1502          timer.Continue();
1503          nextChunk += chunkSize;
1504       }
1505
1506       // Check size of raw db. If bigger than maxFileSize, close file
1507       // and continue with new file.
1508       if (rawdb->FileFull()) {
1509
1510          printf("Written raw DB at a rate of %.1f MB/s\n",
1511                 rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1512
1513          // Write stats object to raw db, run db and MySQL
1514          stats->WriteToDB(rawdb);
1515          delete stats;
1516
1517          if (!rawdb->NextFile()) return 1;
1518
1519          printf("Filling raw DB %s\n", rawdb->GetDBName());
1520          stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1521
1522          timer.Start();
1523          told = 0, tnew = 0;
1524          nextChunk = chunkSize;
1525       }
1526
1527       // Check size of tag db
1528       if (tagdb && tagdb->FileFull()) {
1529          if (!tagdb->NextFile())
1530             tagdb = 0;
1531          else
1532             printf("Filling tag DB %s\n", tagdb->GetDBName());
1533       }
1534
1535       // Make top event object ready for next event data
1536       //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
1537       event->Reset();
1538
1539 #ifdef USE_EB
1540       if (!ebReleaseEvent(ebvec)) {
1541          Error("Run", "problem releasing event (%s)", ebGetLastError());
1542          break;
1543       }
1544 #endif
1545    }
1546
1547    printf("Written raw DB at a rate of %.1f MB/s\n",
1548           rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1549
1550    // Write stats to raw db and run db and delete stats object
1551    stats->WriteToDB(rawdb);
1552    delete stats;
1553
1554    // Close the raw DB
1555    delete rawdb;
1556
1557    // Close the tag DB
1558    delete tagdb;
1559
1560    // Close input source
1561    close(fFd);
1562
1563 #if 0
1564    // Cleanup fifo
1565    if (fUseFifo && ::unlink(kFifo) == -1) {
1566       SysError("Run", "unlink");
1567       return 1;
1568    }
1569 #endif
1570
1571    return 0;
1572 }
1573
1574 //______________________________________________________________________________
1575 Int_t AliMDC::Read(void *buffer, Int_t length)
1576 {
1577    // Read exactly length bytes into buffer. Returns number of bytes
1578    // received, returns -1 in case of error and 0 for EOF.
1579
1580    errno = 0;
1581
1582    if (fFd < 0) return -1;
1583
1584    Int_t n, nrecv = 0;
1585    char *buf = (char *)buffer;
1586
1587    for (n = 0; n < length; n += nrecv) {
1588       if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
1589          if (nrecv == 0)
1590             break;        // EOF
1591          if (errno != EINTR)
1592             SysError("Read", "read");
1593          return -1;
1594       }
1595    }
1596    return n;
1597 }
1598
1599 //______________________________________________________________________________
1600 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
1601 {
1602    // Read header info from DATE data stream. Returns bytes read (i.e.
1603    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1604
1605    Int_t nrecv;
1606
1607    if (eb) {
1608       // read from event builder memory area
1609       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1610       nrecv = header.HeaderSize();
1611    } else {
1612       // read from fifo or file
1613       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1614            header.HeaderSize()) {
1615          if (nrecv == 0)
1616             return 0;
1617          return -1;
1618       }
1619    }
1620
1621    // Swap header data if needed
1622    if (header.IsSwapped())
1623       header.Swap();
1624
1625    // Is header valid...
1626    if (!header.IsValid()) {
1627       Error("ReadHeader", "invalid header format");
1628       // try recovery... how?
1629       return -1;
1630    }
1631    if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
1632       Error("ReadHeader", "invalid header size");
1633       // try recovery... how?
1634       return -1;
1635    }
1636
1637    return nrecv;
1638 }
1639
1640 //______________________________________________________________________________
1641 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
1642                                   Bool_t isSwapped, void *eb)
1643 {
1644    // Read equipment header info from DATE data stream. Returns bytes read
1645    // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
1646    // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
1647    // and we will swap the header to host format.
1648
1649    Int_t nrecv;
1650
1651    if (eb) {
1652       // read from event builder memory area
1653       memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1654       nrecv = header.HeaderSize();
1655    } else {
1656       // read from fifo or file
1657       if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1658            header.HeaderSize()) {
1659          if (nrecv == 0)
1660             return 0;
1661          return -1;
1662       }
1663    }
1664
1665    // Swap equipment header data if needed
1666    if (isSwapped)
1667       header.Swap();
1668
1669    if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
1670       Error("ReadEquipmentHeader", "invalid equipment header size");
1671       // try recovery... how?
1672       return -1;
1673    }
1674
1675    return nrecv;
1676 }
1677
1678 //______________________________________________________________________________
1679 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
1680 {
1681    // Read raw data from DATE data stream. Returns bytes read (i.e.
1682    // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1683
1684    Int_t nrecv;
1685
1686    if (eb) {
1687       // read from event builder memory area
1688       raw.SetBuffer(eb, size);
1689       nrecv = size;
1690    } else {
1691       // read from fifo or file
1692       raw.SetSize(size);
1693       if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
1694          if (nrecv == 0) {
1695             Error("ReadRawData", "unexpected EOF");
1696             return 0;
1697          }
1698          return -1;
1699       }
1700    }
1701
1702    return nrecv;
1703 }
1704
1705 //______________________________________________________________________________
1706 Int_t AliMDC::DumpEvent(Int_t toRead)
1707 {
1708    // This case should not happen, but if it does try to handle it
1709    // gracefully by reading the rest of the event and discarding it.
1710    // Returns bytes read, -1 in case of fatal error and 0 for EOF.
1711
1712    Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
1713
1714    Int_t nrecv;
1715    char *tbuf = new char[toRead];
1716    if ((nrecv = Read(tbuf, toRead)) != toRead) {
1717       if (nrecv == 0) {
1718          Error("DumpEvent", "unexpected EOF");
1719          return 0;
1720       }
1721       return -1;
1722    }
1723    delete [] tbuf;
1724
1725    return nrecv;
1726 }
1727
1728 #ifdef USE_HLT
1729 #include <AliTPCL3Tunnel.h>
1730 #endif
1731
1732 //______________________________________________________________________________
1733 Int_t AliMDC::Filter(AliRawData &raw)
1734 {
1735    // Call 3rd level filter for this raw data segment.
1736
1737 #ifdef USE_HLT
1738    AliTPCL3Tunnel *tunnel = 0;
1739    if (!tunnel) {
1740       // initialisation
1741       tunnel = new AliTPCL3Tunnel(Form("%s/TPCparams.root",
1742                                        gSystem->Getenv("ALITPC")));
1743    }
1744
1745    Int_t obytes, nbytes;
1746    obytes = nbytes = raw.GetSize();
1747    char *outbuf = tunnel->EvalTrack((char *)raw.GetBuffer(), nbytes);
1748
1749    raw.SetSize(nbytes);
1750    memcpy(raw.GetBuffer(), outbuf, nbytes);
1751
1752    printf("Filter called for event %d: reduced from %d to %d\n", fNumEvents,
1753           obytes, nbytes);
1754
1755 #else
1756
1757    raw.GetSize();
1758    printf("Filter called for event %d\n", fNumEvents);
1759
1760 #endif
1761
1762    return 0;
1763 }