1 // @(#)alimdc:$Name$:$Id$
2 // Author: Fons Rademakers 26/11/99
3 // Updated: Dario Favretto 15/04/2003
8 #include <sys/statvfs.h>
10 #if defined(__APPLE__)
11 #include <sys/param.h>
12 #include <sys/mount.h>
25 #include <TStopwatch.h>
26 #include <TSQLServer.h>
27 #include <TSQLResult.h>
31 #if defined(__APPLE__)
34 #include "AliRawEvent.h"
38 #include "DateEvent.h"
41 #include "libDateEb.h"
46 ClassImp(AliRawEventHeader)
47 ClassImp(AliRawEquipmentHeader)
51 ClassImp(AliRawRFIODB)
52 ClassImp(AliRawCastorDB)
53 ClassImp(AliRawRootdDB)
54 ClassImp(AliRawNullDB)
56 ClassImp(AliTagNullDB)
60 // Which MDC is this...
63 // Fixed file system locations for the different DB's
65 const char *kFifo = "/tmp/alimdc.fifo";
66 const char *kRawDBFS[2] = { "/tmp/mdc1", "/tmp/mdc2" };
67 const char *kTagDBFS = "/tmp/mdc1/tags";
68 const char *kRunDBFS = "/tmp/mdc1/meta";
69 const char *kRFIOFS = "rfio:/castor/cern.ch/user/r/rdm";
70 const char *kCastorFS = "castor:/castor/cern.ch/user/r/rdm";
71 const char *kRootdFS = "root://localhost//tmp/mdc1";
72 const char *kAlienHost = "alien://aliens7.cern.ch:15000/?direct";
73 const char *kAlienDir = "/alice_mdc/DC";
75 const char *kFifo = "/tmp/alimdc.fifo";
76 const char *kRawDBFS[2] = { "/data1/mdc", "/data2/mdc" };
77 const char *kTagDBFS = "/data1/mdc/tags";
78 const char *kRunDBFS = "/data1/mdc/meta";
79 const char *kRFIOFS = "rfio:/castor/cern.ch/lcg/dc5";
80 const char *kCastorFS = "castor:/castor/cern.ch/lcg/dc5";
81 const char *kRootdFS = "root://localhost//tmp/mdc1";
82 const char *kAlienHost = "alien://aliens7.cern.ch:15000/?direct";
83 const char *kAlienDir = "/alice_mdc/DC";
86 // Maximum size of tag db files
87 const Double_t kMaxTagFileSize = 2.5e8; // 250MB
89 Bool_t AliMDC::fgDeleteFiles = kFALSE;
94 //______________________________________________________________________________
95 Bool_t AliRawEventHeader::DataIsSwapped() const
97 // Returns true if event data is swapped.
99 if (TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_EVENT_SWAPPED))
104 //______________________________________________________________________________
105 void AliRawEventHeader::Swap()
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);
129 //______________________________________________________________________________
130 UInt_t AliRawEventHeader::GetEventInRun() const
132 // Get event number in run. Correct for fixed target mode which is used
133 // in the Data Challenge Setup.
135 if (!TEST_SYSTEM_ATTRIBUTE(fTypeAttribute, ATTR_ORBIT_BC)) {
136 return EVENT_ID_GET_NB_IN_RUN(fId);
141 //______________________________________________________________________________
142 const char *AliRawEventHeader::GetTypeName() const
144 // Get event type as a string.
148 return "START_OF_RUN";
153 case kStartOfRunFiles:
154 return "START_OF_RUN_FILES";
157 return "END_OF_RUN_FILES";
160 return "START_OF_BURST";
163 return "END_OF_BURST";
166 return "PHYSICS_EVENT";
168 case kCalibrationEvent:
169 return "CALIBRATION_EVENT";
172 return "EVENT_FORMAT_ERROR";
175 return "*** UNKNOWN EVENT TYPE ***";
181 //______________________________________________________________________________
182 void AliRawEquipmentHeader::Swap()
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).
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]);
197 //______________________________________________________________________________
198 AliRawEvent::AliRawEvent()
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.
210 //______________________________________________________________________________
211 AliRawEventHeader *AliRawEvent::GetHeader()
213 // Get event header part of AliRawEvent.
216 fEvtHdr = new AliRawEventHeader;
221 //______________________________________________________________________________
222 AliRawEquipmentHeader *AliRawEvent::GetEquipmentHeader()
224 // Get equipment header part of AliRawEvent.
227 fEqpHdr = new AliRawEquipmentHeader;
232 //______________________________________________________________________________
233 AliRawData *AliRawEvent::GetRawData()
235 // Get raw data part of AliRawEvent.
238 fRawData = new AliRawData;
243 //______________________________________________________________________________
244 AliRawEvent *AliRawEvent::NextSubEvent()
246 // Returns next sub-event object.
249 fSubEvents = new TObjArray(100); // arbitrary, probably enough to prevent resizing
251 if (fSubEvents->GetSize() <= fNSubEvents) {
252 fSubEvents->Expand(fNSubEvents+10);
253 Warning("NextSubEvent", "expanded fSubEvents by 10 to %d",
254 fSubEvents->GetSize());
258 if (!(ev = (AliRawEvent *)fSubEvents->At(fNSubEvents))) {
259 ev = new AliRawEvent;
260 fSubEvents->AddAt(ev, fNSubEvents);
268 //______________________________________________________________________________
269 AliRawEvent *AliRawEvent::GetSubEvent(Int_t index) const
271 // Get specified sub event. Returns 0 if sub event does not exist.
276 return (AliRawEvent *) fSubEvents->At(index);
279 //______________________________________________________________________________
280 void AliRawEvent::Reset()
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.
286 for (int i = 0; i < fNSubEvents; i++) {
287 AliRawEvent *ev = (AliRawEvent *)fSubEvents->At(i);
288 ev->GetRawData()->SetSize(0);
293 //______________________________________________________________________________
294 AliRawEvent::~AliRawEvent()
296 // Clean up event object. Delete also, possible, private raw data.
302 fSubEvents->Delete();
306 //______________________________________________________________________________
307 AliStats::AliStats(const char *filename, Int_t compmode, Bool_t filter)
309 // Create statistics object.
317 fFileName = filename;
318 fCompMode = compmode;
323 //______________________________________________________________________________
324 AliStats::~AliStats()
326 // Cleanup stats object.
331 //______________________________________________________________________________
332 AliStats &AliStats::operator=(const AliStats &rhs)
334 // AliStats assignment operator.
337 TObject::operator=(rhs);
338 fEvents = rhs.fEvents;
339 fFirstRun = rhs.fFirstRun;
340 fFirstEvent = rhs.fFirstEvent;
341 fLastRun = rhs.fLastRun;
342 fLastEvent = rhs.fLastEvent;
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;
356 //______________________________________________________________________________
357 void AliStats::Fill(Float_t time)
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.
364 fRTHist = new TH1F("rtime","Real-time to write data chunk", 100, 0, 100);
365 fRTHist->SetDirectory(0);
368 fRTHist->Fill(fChunk, time);
372 //______________________________________________________________________________
373 void AliStats::WriteToDB(AliRawDB *rawdb)
375 // Write stats to raw DB, local run DB and global MySQL DB.
377 AliRawEventHeader &header = *rawdb->GetEvent()->GetHeader();
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());
390 // Write stats also in the bookkeeping RunDB
391 AliRunDB *rundb = new AliRunDB(kTRUE);
393 rundb->UpdateRDBMS(this);
394 rundb->UpdateAliEn(this);
398 //______________________________________________________________________________
399 AliRawDB::AliRawDB(AliRawEvent *event, Double_t maxsize, Int_t compress,
402 // Create a new raw DB containing at most maxsize bytes.
406 fCompress = compress;
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");
421 //______________________________________________________________________________
422 Bool_t AliRawDB::FSHasSpace(const char *fs)
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.
427 Long_t id, bsize, blocks, bfree;
429 if (gSystem->GetFsInfo(fs, &id, &bsize, &blocks, &bfree) == 1) {
430 Error("FSHasSpace", "could not stat file system %s", fs);
434 // Leave 5 percent of diskspace free
435 Double_t avail = Double_t(bfree) * 0.95;
436 if (avail*bsize > fMaxSize)
439 Warning("FSHasSpace", "no space on file system %s", fs);
443 //______________________________________________________________________________
444 const char *AliRawDB::GetFileName()
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.
451 static TString fname;
452 static Bool_t fstoggle = kFALSE;
454 TString fs = fstoggle ? kRawDBFS[1] : kRawDBFS[0];
457 TString hostname = gSystem->HostName();
459 if ((pos = hostname.Index(".")) != kNPOS)
460 hostname.Remove(pos);
462 if (!FSHasSpace(fs)) {
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())
474 fname = fs + "/" + hostname + "_";
475 fname += dt.GetDate();
477 fname += dt.GetTime();
480 fstoggle = !fstoggle;
485 //______________________________________________________________________________
486 Bool_t AliRawDB::Create()
488 // Create a new raw DB.
490 const Int_t maxRetry = 200;
491 const Int_t maxSleep = 1; // seconds
492 const Int_t maxSleepLong = 10; // seconds
496 if (gAliMDC && gAliMDC->StopLoop())
499 const char *fname = GetFileName();
501 Error("Create", "error getting raw DB file name");
507 fRawDB = TFile::Open(fname, GetOpenOption(),
508 Form("ALICE MDC%d raw DB", kMDC), fCompress);
510 if (retry < maxRetry) {
511 Warning("Create", "failure to open file, sleeping %d %s before retrying...",
512 maxSleep, maxSleep==1 ? "second" : "seconds");
513 gSystem->Sleep(maxSleep*1000);
516 Error("Create", "failure to open file %s after %d tries", fname, maxRetry);
519 if (fRawDB->IsZombie()) {
520 if (fRawDB->GetErrno() == ENOSPC ||
521 fRawDB->GetErrno() == 1018 || // SECOMERR
522 fRawDB->GetErrno() == 1027) { // SESYSERR
523 fRawDB->ResetErrno();
525 Warning("Create", "file is a zombie (no space), sleeping %d %s before retrying...",
526 maxSleepLong, maxSleepLong==1 ? "second" : "seconds");
527 gSystem->Sleep(maxSleepLong*1000); // sleep 10 seconds before retrying
530 Error("Create", "file %s is zombie", fname);
531 fRawDB->ResetErrno();
534 if (retry < maxRetry) {
535 Warning("Create", "file is a zombie, sleeping %d %s before retrying...",
536 maxSleep, maxSleep==1 ? "second" : "seconds");
537 gSystem->Sleep(maxSleep*1000);
540 Error("Create", "failure to open file %s after %d tries", fname, maxRetry);
544 // Create raw data TTree
550 //______________________________________________________________________________
551 void AliRawDB::MakeTree()
553 // Create ROOT Tree object container.
555 fTree = new TTree("RAW", Form("ALICE MDC%d raw data tree", kMDC));
556 fTree->SetAutoSave(2000000000); // autosave when 2 Gbyte written
558 Int_t bufsize = 256000;
559 // splitting 29.6 MB/s, no splitting 35.3 MB/s on P4 2GHz 15k SCSI
562 fTree->Branch("rawevent", "AliRawEvent", &fEvent, bufsize, split);
565 //______________________________________________________________________________
566 void AliRawDB::Close()
577 // Close DB, this also deletes the fTree
580 if (AliMDC::DeleteFiles()) {
581 gSystem->Unlink(fRawDB->GetName());
587 // Create semaphore to say this file is finished
588 Int_t tfd = ::creat(Form("%s.done", fRawDB->GetName()), 0644);
595 //______________________________________________________________________________
596 Bool_t AliRawDB::NextFile()
598 // Close te current file and open a new one.
599 // Returns kFALSE in case opening failed.
603 if (!Create()) return kFALSE;
607 //______________________________________________________________________________
608 Float_t AliRawDB::GetCompressionFactor() const
610 // Return compression factor.
612 if (fTree->GetZipBytes() == 0.)
615 return fTree->GetTotBytes()/fTree->GetZipBytes();
619 //______________________________________________________________________________
620 AliRawRFIODB::AliRawRFIODB(AliRawEvent *event, Double_t maxsize, Int_t compress)
621 : AliRawDB(event, maxsize, compress, kFALSE)
623 // Create a new raw DB that will be accessed via RFIO.
627 // Set STAGE_POOL environment variable to current host
629 // THESE ENVIRONMENT SYMBOLS ARE NOW DEFINED BY THE ALICE DATE SETUP
630 // THEREFORE WE SHALL NOT USE ANY HARDCODED VALUES BUT RATHER USE
631 // WHATEVER HAS BEEN SET IN THE DATE SITE
632 //gSystem->Setenv("STAGE_POOL", "lcg00");
633 //gSystem->Setenv("STAGE_HOST", "stage013");
641 fRawDB->UseCache(50, 0x200000); //0x100000 = 1MB)
644 //______________________________________________________________________________
645 const char *AliRawRFIODB::GetFileName()
647 // Return filename based on hostname and date and time. This will make
648 // each file unique. Also the directory will be made unique for each
649 // day by adding the date to the fs. Assumes there is always enough
650 // space on the device.
652 static TString fname;
654 TString fs = kRFIOFS;
657 // make a new subdirectory for each day
661 Long_t id, size, flags, time;
662 if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
663 // directory does not exist, create it
664 if (gSystem->mkdir(fs, kTRUE) == -1) {
665 Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
670 // FIXME: should check if fs is a directory
672 TString hostname = gSystem->HostName();
674 if ((pos = hostname.Index(".")) != kNPOS)
675 hostname.Remove(pos);
677 fname = fs + "/" + hostname + "_";
678 fname += dt.GetDate();
680 fname += dt.GetTime();
686 //______________________________________________________________________________
687 void AliRawRFIODB::Close()
689 // Close raw RFIO DB.
698 // Close DB, this also deletes the fTree
701 if (AliMDC::DeleteFiles()) {
702 TUrl u(fRawDB->GetName());
703 gSystem->Exec(Form("rfrm %s", u.GetFile()));
711 //______________________________________________________________________________
712 AliRawCastorDB::AliRawCastorDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
713 : AliRawDB(event, maxsize, compress, kFALSE)
715 // Create a new raw DB that will be accessed via CASTOR and rootd.
719 // Set STAGE_POOL environment variable to current host
721 // THESE ENVIRONMENT SYMBOLS ARE NOW DEFINED BY THE ALICE DATE SETUP
722 // THEREFORE WE SHALL NOT USE ANY HARDCODED VALUES BUT RATHER USE
723 // WHATEVER HAS BEEN SET IN THE DATE SITE
724 //gSystem->Setenv("STAGE_POOL", "lcg00");
725 //gSystem->Setenv("STAGE_HOST", "stage013");
733 fRawDB->UseCache(50, 0x200000); //0x100000 = 1MB)
736 //______________________________________________________________________________
737 const char *AliRawCastorDB::GetFileName()
739 // Return filename based on hostname and date and time. This will make
740 // each file unique. Also the directory will be made unique for each
741 // day by adding the date to the fs. Assumes there is always enough
742 // space on the device.
744 static TString fname;
746 TString fs = kCastorFS;
747 TString fsr = kRFIOFS;
750 // make a new subdirectory for each day
757 Long_t id, size, flags, time;
758 if (gSystem->GetPathInfo(fsr, &id, &size, &flags, &time) == 1) {
759 // directory does not exist, create it
760 if (gSystem->mkdir(fsr, kTRUE) == -1) {
761 Error("GetFileName", "cannot create dir %s, using %s", fsr.Data(),
766 // FIXME: should check if fs is a directory
768 TString hostname = gSystem->HostName();
770 if ((pos = hostname.Index(".")) != kNPOS)
771 hostname.Remove(pos);
773 fname = fs + "/" + hostname + "_";
774 fname += dt.GetDate();
776 fname += dt.GetTime();
782 //______________________________________________________________________________
783 void AliRawCastorDB::Close()
785 // Close raw CASTOR/rootd DB.
794 // Close DB, this also deletes the fTree
797 if (AliMDC::DeleteFiles()) {
798 TUrl u(fRawDB->GetName());
799 gSystem->Exec(Form("rfrm %s", u.GetFile()));
807 //______________________________________________________________________________
808 AliRawRootdDB::AliRawRootdDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
809 : AliRawDB(event, maxsize, compress, kFALSE)
811 // Create a new raw DB that will be accessed via rootd daemon.
816 fRawDB->UseCache(50, 0x200000); //0x100000 = 1MB)
819 //______________________________________________________________________________
820 const char *AliRawRootdDB::GetFileName()
822 // Return filename based on hostname and date and time. This will make
823 // each file unique. Also the directory will be made unique for each
824 // day by adding the date to the fs. Assumes there is always enough
825 // space on the device.
827 static TString fname;
829 TString fs = kRootdFS;
833 // make a new subdirectory for each day
837 Long_t id, size, flags, time;
838 if (gSystem->GetPathInfo(fs, &id, &size, &flags, &time) == 1) {
839 // directory does not exist, create it
840 if (gSystem->mkdir(fs, kTRUE) == -1) {
841 Error("GetFileName", "cannot create dir %s, using %s", fs.Data(),
846 // FIXME: should check if fs is a directory
849 TString hostname = gSystem->HostName();
851 if ((pos = hostname.Index(".")) != kNPOS)
852 hostname.Remove(pos);
854 fname = fs + "/" + hostname + "_";
855 fname += dt.GetDate();
857 fname += dt.GetTime();
863 //______________________________________________________________________________
864 void AliRawRootdDB::Close()
866 // Close raw rootd DB.
875 // Close DB, this also deletes the fTree
879 // can use services of TFTP
880 if (AliMDC::DeleteFiles())
881 gSystem->Exec(Form("rfrm %s", fRawDB->GetName()));
889 //______________________________________________________________________________
890 AliRawNullDB::AliRawNullDB(AliRawEvent *event, Double_t maxsize, Int_t compress)
891 : AliRawDB(event, maxsize, compress, kFALSE)
893 // Create a new raw DB that will wrtie to /dev/null.
899 //______________________________________________________________________________
900 const char *AliRawNullDB::GetFileName()
902 // Return /dev/null as filename.
907 //______________________________________________________________________________
908 void AliRawNullDB::Close()
910 // Close raw RFIO DB.
919 // Close DB, this also deletes the fTree
927 //______________________________________________________________________________
928 AliTagDB::AliTagDB(AliRawEventHeader *header, Double_t maxsize, Bool_t create)
941 //______________________________________________________________________________
942 Bool_t AliTagDB::Create()
944 // Create a new tag DB.
946 fTagDB = new TFile(GetFileName(), "RECREATE",
947 Form("ALICE MDC%d tag DB", kMDC), 1);
948 if (fTagDB->IsZombie()) {
949 Error("Create", "error opening tag DB");
954 // Create ROOT Tree object container
955 fTree = new TTree("TAG", Form("ALICE MDC%d header data tree", kMDC));
956 fTree->SetAutoSave(100000000); // autosave when 100 Mbyte written
958 Int_t bufsize = 32000;
960 fTree->Branch("header", "AliRawEventHeader", &fHeader, bufsize, split);
965 //______________________________________________________________________________
966 void AliTagDB::Close()
977 // Close DB, this also deletes the fTree
980 if (AliMDC::DeleteFiles())
981 gSystem->Unlink(fTagDB->GetName());
987 //______________________________________________________________________________
988 Bool_t AliTagDB::NextFile()
990 // Close te current file and open a new one.
991 // Returns kFALSE in case opening failed.
995 if (!Create()) return kFALSE;
999 //______________________________________________________________________________
1000 Float_t AliTagDB::GetCompressionFactor() const
1002 // Return compression factor.
1004 if (fTree->GetZipBytes() == 0.)
1007 return fTree->GetTotBytes()/fTree->GetZipBytes();
1010 //______________________________________________________________________________
1011 const char *AliTagDB::GetFileName()
1013 // Return filename based on hostname and date and time. This will make
1014 // each file unique. The tags will be stored in the /data1/tags directory.
1016 static char fname[64];
1017 const char *fs = kTagDBFS;
1019 // check that fs exists (crude check fails if fs is a file)
1020 gSystem->MakeDirectory(fs);
1024 strcpy(hostname, gSystem->HostName());
1027 if ((s = strchr(hostname, '.')))
1032 sprintf(fname, "%s/%s_%d_%d.root", fs, hostname, dt.GetDate(), dt.GetTime());
1038 //______________________________________________________________________________
1039 AliTagNullDB::AliTagNullDB(AliRawEventHeader *header, Double_t maxsize) :
1040 AliTagDB(header, maxsize, kFALSE)
1042 // Create tag db writing to /dev/null.
1048 //______________________________________________________________________________
1049 const char *AliTagNullDB::GetFileName()
1051 // Return /dev/null as filename.
1056 //______________________________________________________________________________
1057 void AliTagNullDB::Close()
1059 // Close null tag DB.
1061 if (!fTagDB) return;
1068 // Close DB, this also deletes the fTree
1076 //______________________________________________________________________________
1077 AliRunDB::AliRunDB(Bool_t noLocalDB)
1079 // Open run database, and get or create tree.
1083 if (noLocalDB) return;
1086 char hostname[64], filename[64];
1087 const char *fs = kRunDBFS;
1089 // check that fs exists (crude check fails if fs is a file)
1090 gSystem->MakeDirectory(fs);
1092 strcpy(hostname, gSystem->HostName());
1095 if ((s = strchr(hostname, '.')))
1098 sprintf(filename, "%s/%s_rundb.root", fs, hostname);
1100 if (!gSystem->AccessPathName(filename, kFileExists))
1101 fRunDB = new TFile(filename, "UPDATE");
1103 fRunDB = new TFile(filename, "CREATE", Form("ALICE MDC%d Run DB", kMDC));
1106 //______________________________________________________________________________
1107 void AliRunDB::Update(AliStats *stats)
1109 // Add stats object to database.
1111 if (!stats || !fRunDB) return;
1113 TDirectory *ds = gDirectory;
1117 char *s = (char*)strrchr(stats->GetFileName(), '/');
1122 strcpy(sname, stats->GetFileName());
1123 s = strchr(sname, '.');
1126 stats->Write(sname);
1131 //______________________________________________________________________________
1132 void AliRunDB::UpdateRDBMS(AliStats *stats)
1134 // Add stats object to central MySQL DB.
1139 char bt[25], et[25];
1141 strcpy(bt, stats->GetBeginTime().AsSQLString());
1142 strcpy(et, stats->GetEndTime().AsSQLString());
1144 sprintf(sql, "INSERT INTO mdc%dcatalog VALUES (0, '%s', %d, "
1145 "%d, %d, %d, %d, %d, %d, %.2f, '%s', '%s', '%s')", kMDC,
1146 stats->GetFileName(), (int)stats->GetFileSize(), stats->GetEvents(),
1147 stats->GetFirstRun(), stats->GetFirstEvent(), stats->GetLastRun(),
1148 stats->GetLastEvent(), stats->GetCompressionMode(),
1149 stats->GetCompressionFactor(), stats->GetFilterState() ? "on" : "off",
1152 // open connection to MySQL server on pcsalo
1153 TSQLServer *db = TSQLServer::Connect("mysql://pcsalo.cern.ch/mdc", "alice", "amdc");
1155 if (!db || db->IsZombie()) {
1156 Error("UpdateRDBMS", "failed to connect to MySQL server on pcsalo");
1157 printf("%s\n", sql);
1162 TSQLResult *res = db->Query(sql);
1165 Error("UpdateRDBMS", Form("insert into mdc%dcatalog failed", kMDC));
1166 printf("%s\n", sql);
1173 //______________________________________________________________________________
1174 void AliRunDB::UpdateAliEn(AliStats *stats)
1176 // Record file in AliEn catalog.
1180 TGrid *g = TGrid::Connect(kAlienHost, "");
1182 TString lfn = kAlienDir;
1184 lfn += gSystem->BaseName(stats->GetFileName());
1186 Int_t result = g->AddFile(lfn, stats->GetFileName(),
1187 (int)stats->GetFileSize());
1190 Error("UpdateAliEn", "error adding file to AliEn catalog");
1191 printf("AliEn: AddFile(%s, %s, %d)\n", lfn.Data(), stats->GetFileName(),
1192 (int)stats->GetFileSize());
1198 //______________________________________________________________________________
1199 void AliRunDB::Close()
1201 // Close run database.
1203 if (fRunDB) fRunDB->Close();
1207 //----------------- Use SIGUSR1 to interupt endless loop -----------------------
1208 class AliMDCInterruptHandler : public TSignalHandler {
1210 AliMDC *fMDC; // alimdc to signal
1212 AliMDCInterruptHandler(AliMDC *mdc) : TSignalHandler(kSigUser1, kFALSE), fMDC(mdc) { }
1214 Info("Notify", "received a SIGUSR1 signal");
1215 fMDC->SetStopLoop();
1220 //______________________________________________________________________________
1221 AliMDC::AliMDC(Int_t fd, Int_t compress, Double_t maxFileSize, Bool_t useFilter,
1222 EWriteMode mode, Bool_t useLoop, Bool_t delFiles)
1224 // Create MDC processor object.
1227 fCompress = compress;
1228 fMaxFileSize = maxFileSize;
1229 fUseFilter = useFilter;
1237 fgDeleteFiles = delFiles;
1241 if (!ebRegister()) {
1242 Error("AliMDC", "cannot register with the event builder (%s)",
1248 if ((mkfifo(kFifo, 0644) < 0) && (errno != EEXIST)) {
1249 Error("AliMDC", "cannot create fifo %s", kFifo);
1252 if ((chmod(kFifo, 0666) == -1) && (errno != EPERM)) {
1253 Error("AliMDC", "cannot change permission of fifo %s", kFifo);
1256 if ((fFd = open(kFifo, O_RDONLY)) == -1) {
1257 Error("AliMDC", "cannot open input file %s", kFifo);
1265 printf("<AliMDC::AliMDC>: input = %s, rawdb size = %f, filter = %s, "
1266 "looping = %s, compression = %d, delete files = %s",
1267 fUseFifo ? "fifo" : (fUseEb ? "eb" : "file"), fMaxFileSize,
1268 fUseFilter ? "on" : "off", fUseLoop ? "yes" : "no", fCompress,
1269 fgDeleteFiles ? "yes" : "no");
1270 if (fWriteMode == kRFIO)
1271 printf(", use RFIO\n");
1272 else if (fWriteMode == kROOTD)
1273 printf(", use rootd\n");
1274 else if (fWriteMode == kCASTOR)
1275 printf(", use CASTOR/rootd\n");
1276 else if (fWriteMode == kDEVNULL)
1277 printf(", write raw data to /dev/null\n");
1281 // install SIGUSR1 handler to allow clean interrupts
1282 gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
1287 //______________________________________________________________________________
1290 // Run the MDC processor. Read from the input stream and only return
1291 // when the input gave and EOF or a fatal error occured. On success 0
1292 // is returned, 1 in case of a fatality.
1297 // Make sure needed directories exist
1298 const char *dirs[4];
1299 dirs[0] = kRawDBFS[0];
1300 dirs[1] = kRawDBFS[1];
1303 for (int idir = 0; idir < 4; idir++) {
1304 gSystem->ResetErrno();
1305 gSystem->MakeDirectory(dirs[idir]);
1306 if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
1307 SysError("Run", "mkdir %s", dirs[idir]);
1312 // Used for statistics
1314 Double_t told = 0, tnew = 0;
1315 Float_t chunkSize = fMaxFileSize/100, nextChunk = chunkSize;
1317 // Event object used to store event data.
1318 AliRawEvent *event = new AliRawEvent;
1320 // Create new raw DB.
1322 if (fWriteMode == kRFIO)
1323 rawdb = new AliRawRFIODB(event, fMaxFileSize, fCompress);
1324 else if (fWriteMode == kROOTD)
1325 rawdb = new AliRawRootdDB(event, fMaxFileSize, fCompress);
1326 else if (fWriteMode == kCASTOR)
1327 rawdb = new AliRawCastorDB(event, fMaxFileSize, fCompress);
1328 else if (fWriteMode == kDEVNULL)
1329 rawdb = new AliRawNullDB(event, fMaxFileSize, fCompress);
1331 rawdb = new AliRawDB(event, fMaxFileSize, fCompress);
1333 if (rawdb->IsZombie()) return 1;
1334 printf("Filling raw DB %s\n", rawdb->GetDBName());
1336 // Create new tag DB.
1337 AliTagDB *tagdb = 0;
1339 // no tagdb for the time being to get maximum speed
1340 if (fWriteMode == kDEVNULL)
1341 tagdb = new AliTagNullDB(event->GetHeader(), kMaxTagFileSize);
1343 tagdb = new AliTagDB(event->GetHeader(), kMaxTagFileSize);
1344 if (tagdb->IsZombie())
1347 printf("Filling tag DB %s\n", tagdb->GetDBName());
1350 // Create AliStats object
1351 AliStats *stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1353 // Shortcut for easy header access
1354 AliRawEventHeader &header = *event->GetHeader();
1356 // Process input stream
1359 while (!(eorFlag = ebEor())) {
1360 struct iovec *ebvec;
1361 if ((ebvec = ebGetNextEvent()) == (void *)-1) {
1362 Error("Run", "error getting next event (%s)", ebGetLastError());
1366 // no event, sleep for 1 second and try again
1367 gSystem->Sleep(1000);
1370 char *ebdata = (char *) ebvec[0].iov_base;
1376 // Read event header
1377 if ((status = ReadHeader(header, ebdata)) != header.HeaderSize()) {
1381 ::lseek(fFd, 0, SEEK_SET);
1385 printf("<AliMDC::Run>: EOF, processed %d events\n", fNumEvents);
1393 // If we were in looping mode stop directly after a SIGUSR1 signal
1395 Info("Run", "Stopping loop, processed %d events", fNumEvents);
1399 // Check if event has any hard track flagged
1400 Bool_t callFilter = kFALSE;
1401 // This needs to be re-engineered for the next ADC...
1402 //if (fUseFilter && TEST_USER_ATTRIBUTE(header.GetTypeAttribute(), 0))
1403 // callFilter = kTRUE;
1405 // Check event type and skip "Start of Run", "End of Run",
1406 // "Start of Run Files" and "End of Run Files"
1407 switch (header.GetType()) {
1410 case kStartOfRunFiles:
1411 case kEndOfRunFiles:
1413 Int_t skip = header.GetEventSize() - header.HeaderSize();
1415 ::lseek(fFd, skip, SEEK_CUR);
1418 Info("Run", "Skipping %s (%d bytes)", header.GetTypeName(), skip);
1424 Int_t s = header.GetEventSize() - header.HeaderSize();
1425 Info("Run", "Processing %s (%d bytes)", header.GetTypeName(), s);
1429 // Amount of data left to read for this event
1430 Int_t toRead = header.GetEventSize() - header.HeaderSize();
1432 // If there is less data for this event than the next sub-event
1433 // header, something is wrong. Skip to next event...
1434 if (toRead < header.HeaderSize()) {
1437 "header size (%d) exceeds number of bytes to read (%d)\n",
1438 header.HeaderSize(), toRead);
1441 if ((status = DumpEvent(toRead)) != toRead) {
1446 Error("Run", "discarding event %d (too little data for header)", fNumEvents);
1450 // Loop over all sub-events... (LDCs)
1452 while (toRead > 0) {
1454 ebdata = (char *)ebvec[nsub].iov_base;
1458 Info("Run", "reading LDC %d", nsub);
1460 AliRawEvent *subEvent = event->NextSubEvent();
1462 // Read sub-event header
1463 AliRawEventHeader &subHeader = *subEvent->GetHeader();
1464 if ((status = ReadHeader(subHeader, ebdata)) != subHeader.HeaderSize()) {
1466 Error("Run", "unexpected EOF reading sub-event header");
1475 toRead -= subHeader.HeaderSize();
1478 ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize();
1481 Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
1483 // Read Equipment Header (in case of physics or calibration event)
1484 if (header.GetType() == kPhysicsEvent ||
1485 header.GetType() == kCalibrationEvent) {
1486 AliRawEquipmentHeader &equipment = *subEvent->GetEquipmentHeader();
1487 Int_t equipHeaderSize = equipment.HeaderSize();
1488 if ((status = ReadEquipmentHeader(equipment, header.DataIsSwapped(),
1489 ebdata)) != equipHeaderSize) {
1491 Error("Run", "unexpected EOF reading equipment-header");
1496 toRead -= equipHeaderSize;
1497 rawSize -= equipHeaderSize;
1499 ebdata = (char *)(ebvec[nsub].iov_base) + subHeader.HeaderSize() +
1504 // Make sure raw data less than left over bytes for current event
1505 if (rawSize > toRead) {
1507 Warning("Run", "raw data size (%d) exceeds number of bytes "
1508 "to read (%d)\n", rawSize, toRead);
1511 if ((status = DumpEvent(toRead)) != toRead) {
1516 Error("Run", "discarding event %d (too much data)", fNumEvents);
1520 // Read sub-event raw data
1521 AliRawData &subRaw = *subEvent->GetRawData();
1522 if ((status = ReadRawData(subRaw, rawSize, ebdata)) != rawSize) {
1524 Error("Run", "unexpected EOF reading sub-event raw data");
1531 if (TEST_USER_ATTRIBUTE(subHeader.GetTypeAttribute(), 0))
1534 // set size of all sectors without hard track flag to 0
1543 // Set stat info for first event of this file
1544 if (rawdb->GetEvents() == 0)
1545 stats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
1547 // Store raw event in tree
1550 // Store header in tree
1551 if (tagdb) tagdb->Fill();
1555 if (!(fNumEvents%10))
1556 printf("Processed event %d (%d)\n", fNumEvents, rawdb->GetEvents());
1558 // Filling time statistics
1559 if (rawdb->GetBytesWritten() > nextChunk) {
1560 tnew = timer.RealTime();
1561 stats->Fill(tnew-told);
1564 nextChunk += chunkSize;
1567 // Check size of raw db. If bigger than maxFileSize, close file
1568 // and continue with new file.
1569 if (rawdb->FileFull()) {
1571 printf("Written raw DB at a rate of %.1f MB/s\n",
1572 rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1574 // Write stats object to raw db, run db, MySQL and AliEn
1575 stats->WriteToDB(rawdb);
1578 if (!rawdb->NextFile()) {
1579 Error("Run", "error opening next raw data file");
1583 printf("Filling raw DB %s\n", rawdb->GetDBName());
1584 stats = new AliStats(rawdb->GetDBName(), fCompress, fUseFilter);
1588 nextChunk = chunkSize;
1591 // Check size of tag db
1592 if (tagdb && tagdb->FileFull()) {
1593 if (!tagdb->NextFile())
1596 printf("Filling tag DB %s\n", tagdb->GetDBName());
1599 // Make top event object ready for next event data
1600 //printf("Event %d has %d sub-events\n", fNumEvents, event->GetNSubEvents());
1604 if (!ebReleaseEvent(ebvec)) {
1605 Error("Run", "problem releasing event (%s)", ebGetLastError());
1611 printf("Written raw DB at a rate of %.1f MB/s\n",
1612 rawdb->GetBytesWritten() / timer.RealTime() / 1000000.);
1614 // Write stats to raw db and run db and delete stats object
1615 stats->WriteToDB(rawdb);
1624 // Close input source
1629 if (fUseFifo && ::unlink(kFifo) == -1) {
1630 SysError("Run", "unlink");
1638 Info("Run", "event builder reported end of run (%d)", eorFlag);
1645 //______________________________________________________________________________
1646 Int_t AliMDC::Read(void *buffer, Int_t length)
1648 // Read exactly length bytes into buffer. Returns number of bytes
1649 // received, returns -1 in case of error and 0 for EOF.
1653 if (fFd < 0) return -1;
1656 char *buf = (char *)buffer;
1658 for (n = 0; n < length; n += nrecv) {
1659 if ((nrecv = read(fFd, buf+n, length-n)) <= 0) {
1663 SysError("Read", "read");
1670 //______________________________________________________________________________
1671 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, void *eb)
1673 // Read header info from DATE data stream. Returns bytes read (i.e.
1674 // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1679 // read from event builder memory area
1680 memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1681 nrecv = header.HeaderSize();
1683 // read from fifo or file
1684 if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1685 header.HeaderSize()) {
1692 // Swap header data if needed
1693 if (header.IsSwapped())
1696 // Is header valid...
1697 if (!header.IsValid()) {
1698 Error("ReadHeader", "invalid header format");
1699 // try recovery... how?
1702 if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
1703 Error("ReadHeader", "invalid header size");
1704 // try recovery... how?
1711 //______________________________________________________________________________
1712 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
1713 Bool_t isSwapped, void *eb)
1715 // Read equipment header info from DATE data stream. Returns bytes read
1716 // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
1717 // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
1718 // and we will swap the header to host format.
1723 // read from event builder memory area
1724 memcpy(header.HeaderBegin(), eb, header.HeaderSize());
1725 nrecv = header.HeaderSize();
1727 // read from fifo or file
1728 if ((nrecv = Read(header.HeaderBegin(), header.HeaderSize())) !=
1729 header.HeaderSize()) {
1736 // Swap equipment header data if needed
1740 if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
1741 Error("ReadEquipmentHeader", "invalid equipment header size");
1742 // try recovery... how?
1749 //______________________________________________________________________________
1750 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, void *eb)
1752 // Read raw data from DATE data stream. Returns bytes read (i.e.
1753 // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
1758 // read from event builder memory area
1759 raw.SetBuffer(eb, size);
1762 // read from fifo or file
1764 if ((nrecv = Read(raw.GetBuffer(), size)) != size) {
1766 Error("ReadRawData", "unexpected EOF");
1776 //______________________________________________________________________________
1777 Int_t AliMDC::DumpEvent(Int_t toRead)
1779 // This case should not happen, but if it does try to handle it
1780 // gracefully by reading the rest of the event and discarding it.
1781 // Returns bytes read, -1 in case of fatal error and 0 for EOF.
1783 Error("DumpEvent", "dumping %d bytes of event %d", toRead, fNumEvents);
1786 char *tbuf = new char[toRead];
1787 if ((nrecv = Read(tbuf, toRead)) != toRead) {
1789 Error("DumpEvent", "unexpected EOF");
1800 #include <AliTPCL3Tunnel.h>
1803 //______________________________________________________________________________
1804 Int_t AliMDC::Filter(AliRawData &raw)
1806 // Call 3rd level filter for this raw data segment.
1809 AliTPCL3Tunnel *tunnel = 0;
1812 tunnel = new AliTPCL3Tunnel(Form("%s/TPCparams.root",
1813 gSystem->Getenv("ALITPC")));
1816 Int_t obytes, nbytes;
1817 obytes = nbytes = raw.GetSize();
1818 char *outbuf = tunnel->EvalTrack((char *)raw.GetBuffer(), nbytes);
1820 raw.SetSize(nbytes);
1821 memcpy(raw.GetBuffer(), outbuf, nbytes);
1823 printf("Filter called for event %d: reduced from %d to %d\n", fNumEvents,
1829 printf("Filter called for event %d\n", fNumEvents);