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