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