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