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