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