1 // @(#)alimdc:$Name$:$Id$
2 // Author: Fons Rademakers 26/11/99
3 // Updated: Dario Favretto 15/04/2003
5 /**************************************************************************
6 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
8 * Author: The ALICE Off-line Project. *
9 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
22 //////////////////////////////////////////////////////////////////////////
26 // Set of classes defining the ALICE RAW event format. The AliRawEvent //
27 // class defines a RAW event. It consists of an AliEventHeader object //
28 // an AliEquipmentHeader object, an AliRawData object and an array of //
29 // sub-events, themselves also being AliRawEvents. The number of //
30 // sub-events depends on the number of DATE LDC's. //
31 // The AliRawEvent objects are written to a ROOT file using different //
32 // technologies, i.e. to local disk via AliRawDB or via rfiod using //
33 // AliRawRFIODB or via rootd using AliRawRootdDB or to CASTOR via //
34 // rootd using AliRawCastorDB (and for performance testing there is //
35 // also AliRawNullDB). //
36 // The AliRunDB class provides the interface to the run and file //
37 // catalogues (AliEn or plain MySQL). //
38 // The AliStats class provides statics information that is added as //
39 // a single keyed object to each raw file. //
40 // The AliTagDB provides an interface to a TAG database. //
41 // The AliMDC class is usid by the "alimdc" stand-alone program //
42 // that reads data directly from DATE. //
44 //////////////////////////////////////////////////////////////////////////
46 #include <sys/types.h>
53 #include <TStopwatch.h>
57 #include "libDateEb.h"
63 #include "AliRawEvent.h"
64 #include "AliRawEventHeader.h"
65 #include "AliRawEquipment.h"
66 #include "AliRawEquipmentHeader.h"
67 #include "AliRawData.h"
70 #include "AliRawRFIODB.h"
71 #include "AliRawCastorDB.h"
72 #include "AliRawRootdDB.h"
73 #include "AliRawNullDB.h"
76 #include "AliFilter.h"
85 const char* const AliMDC::fgkFilterName[kNFilters] = {"AliHoughFilter"};
87 //______________________________________________________________________________
88 AliMDC::AliMDC(Int_t compress, Bool_t deleteFiles, EFilterMode filterMode,
89 const char* localRunDB, Bool_t rdbmsRunDB,
90 const char* alienHostRunDB, const char* alienDirRunDB,
91 Double_t maxSizeTagDB, const char* fileNameTagDB) :
92 fEvent(new AliRawEvent),
96 fRunDB(new AliRunDB(localRunDB, rdbmsRunDB, alienHostRunDB, alienDirRunDB)),
99 fDeleteFiles(deleteFiles),
100 fFilterMode(filterMode),
104 // Create MDC processor object.
105 // compress is the file compression mode.
106 // If deleteFiles is kTRUE the raw data files will be deleted after they
108 // If the filterMode if kFilterOff no filter algorithm will be, if it is
109 // kFilterTransparent the algorthims will be run but no events will be
110 // rejected, if it is kFilterOn the filters will be run and the event will
111 // be rejected if all filters return kFALSE.
112 // localRunDB is the file name of the local run DB; if NULL no local run DB
114 // The filling of a MySQL run DB can be switch on or off with rdbmsRunDB.
115 // The host and directory name of the alien run DB can be specified by
116 // alienHostRunDB and alienDirRunDB; if NULL no alien DB will be filled.
117 // If maxSizeTagDB is greater than 0 it determines the maximal size of the
118 // tag DB and then fileNameTagDB is the directory name for the tag DB.
119 // Otherwise fileNameTagDB is the file name of the tag DB. If it is NULL
120 // no tag DB will be created.
123 if (fFilterMode != kFilterOff) {
128 if (maxSizeTagDB > 0) {
129 fTagDB = new AliTagDB(fEvent->GetHeader(), NULL);
130 fTagDB->SetMaxSize(maxSizeTagDB);
131 fTagDB->SetFS(fileNameTagDB);
134 fTagDB = new AliTagDB(fEvent->GetHeader(), fileNameTagDB);
138 // install SIGUSR1 handler to allow clean interrupts
139 gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
141 // create the high level filters
142 if (fFilterMode != kFilterOff) {
143 for (Int_t iFilter = 0; iFilter < kNFilters; iFilter++) {
144 TClass* filterClass = gROOT->GetClass(fgkFilterName[iFilter]);
146 Warning("AliMDC", "no filter class %s found", fgkFilterName[iFilter]);
149 AliFilter* filter = (AliFilter*) filterClass->New();
151 Warning("AliMDC", "creation of filter %s failed", fgkFilterName[iFilter]);
154 fFilters.Add(filter);
159 //______________________________________________________________________________
173 //______________________________________________________________________________
174 AliMDC::AliMDC(const AliMDC& mdc): TObject(mdc)
178 Fatal("AliMDC", "copy constructor not implemented");
181 //______________________________________________________________________________
182 AliMDC& AliMDC::operator = (const AliMDC& /*mdc*/)
184 // assignment operator
186 Fatal("operator =", "assignment operator not implemented");
191 //______________________________________________________________________________
192 Int_t AliMDC::Open(EWriteMode mode, const char* fileName)
194 // open a new raw DB file
197 fRawDB = new AliRawRFIODB(fEvent, fESD, fCompress, fileName);
198 else if (mode == kROOTD)
199 fRawDB = new AliRawRootdDB(fEvent, fESD, fCompress, fileName);
200 else if (mode == kCASTOR)
201 fRawDB = new AliRawCastorDB(fEvent, fESD, fCompress, fileName);
202 else if (mode == kDEVNULL)
203 fRawDB = new AliRawNullDB(fEvent, fESD, fCompress, fileName);
205 fRawDB = new AliRawDB(fEvent, fESD, fCompress, fileName);
206 fRawDB->SetDeleteFiles(fDeleteFiles);
208 if (fRawDB->IsZombie()) {
213 Info("Open", "Filling raw DB %s\n", fRawDB->GetDBName());
215 // Create AliStats object
216 fStats = new AliStats(fRawDB->GetDBName(), fCompress,
217 fFilterMode != kFilterOff);
221 //______________________________________________________________________________
222 Int_t AliMDC::ProcessEvent(void* event, Bool_t isIovecArray)
224 // Convert the DATE event to an AliRawEvent object and store it in the raw DB,
225 // optionally also run the filter.
226 // event is either a pointer to the streamlined event
227 // or, if isIovecArray is kTRUE, a pointer to an array of iovecs with one
228 // iovec per subevent (used by the event builder).
229 // The return value is the number of written bytes or an error code
232 char* data = (char*) event;
233 if (isIovecArray) data = (char*) ((iovec*) event)[0].iov_base;
235 // Shortcut for easy header access
236 AliRawEventHeader &header = *fEvent->GetHeader();
239 if ((status = ReadHeader(header, data)) != header.HeaderSize()) {
243 if (AliDebugLevel() > 2) ToAliDebug(3, header.Dump(););
245 // Check event type and skip "Start of Run", "End of Run",
246 // "Start of Run Files" and "End of Run Files"
247 Int_t size = header.GetEventSize() - header.HeaderSize();
248 switch (header.GetType()) {
249 case AliRawEventHeader::kStartOfRun:
250 case AliRawEventHeader::kEndOfRun:
251 case AliRawEventHeader::kStartOfRunFiles:
252 case AliRawEventHeader::kEndOfRunFiles:
254 AliDebug(1, Form("Skipping %s (%d bytes)", header.GetTypeName(), size));
255 return kErrStartEndRun;
259 AliDebug(1, Form("Processing %s (%d bytes)", header.GetTypeName(), size));
263 // Amount of data left to read for this event
266 // If there is less data for this event than the next sub-event
267 // header, something is wrong. Skip to next event...
268 if (toRead < header.HeaderSize()) {
269 Error("ProcessEvent", "header size (%d) exceeds number of bytes "
270 "to read (%d)", header.HeaderSize(), toRead);
271 if (AliDebugLevel() > 0) ToAliDebug(1, header.Dump(););
272 return kErrHeaderSize;
275 // Loop over all sub-events... (LDCs)
278 if (isIovecArray) data = (char*) ((iovec*) event)[nsub].iov_base;
280 AliDebug(1, Form("reading LDC %d", nsub));
282 AliRawEvent *subEvent = fEvent->NextSubEvent();
284 // Read sub-event header
285 AliRawEventHeader &subHeader = *subEvent->GetHeader();
286 if ((status = ReadHeader(subHeader, data)) != subHeader.HeaderSize()) {
287 return kErrSubHeader;
290 if (AliDebugLevel() > 2) ToAliDebug(3, subHeader.Dump(););
292 toRead -= subHeader.HeaderSize();
294 Int_t rawSize = subHeader.GetEventSize() - subHeader.HeaderSize();
296 // Make sure raw data less than left over bytes for current event
297 if (rawSize > toRead) {
298 Warning("ProcessEvent", "raw data size (%d) exceeds number of "
299 "bytes to read (%d)\n", rawSize, toRead);
300 if (AliDebugLevel() > 0) ToAliDebug(1, subHeader.Dump(););
304 // Read Equipment Headers (in case of physics or calibration event)
305 if (header.GetType() == AliRawEventHeader::kPhysicsEvent ||
306 header.GetType() == AliRawEventHeader::kCalibrationEvent) {
307 while (rawSize > 0) {
308 AliRawEquipment &equipment = *subEvent->NextEquipment();
309 AliRawEquipmentHeader &equipmentHeader =
310 *equipment.GetEquipmentHeader();
311 Int_t equipHeaderSize = equipmentHeader.HeaderSize();
312 if ((status = ReadEquipmentHeader(equipmentHeader, header.DataIsSwapped(),
313 data)) != equipHeaderSize) {
314 return kErrEquipmentHeader;
316 toRead -= equipHeaderSize;
317 rawSize -= equipHeaderSize;
319 // Read equipment raw data
320 AliRawData &subRaw = *equipment.GetRawData();
322 Int_t eqSize = equipmentHeader.GetEquipmentSize() - equipHeaderSize;
323 if ((status = ReadRawData(subRaw, eqSize, data)) != eqSize) {
324 return kErrEquipment;
331 } else { // Read only raw data but no equipment header
332 AliRawEquipment &equipment = *subEvent->NextEquipment();
333 AliRawData &subRaw = *equipment.GetRawData();
334 if ((status = ReadRawData(subRaw, rawSize, data)) != rawSize) {
335 return kErrEquipment;
344 // High Level Event Filter
345 if (fFilterMode != kFilterOff) {
346 if (header.GetType() == AliRawEventHeader::kPhysicsEvent ||
347 header.GetType() == AliRawEventHeader::kCalibrationEvent) {
348 Bool_t result = kFALSE;
349 for (Int_t iFilter = 0; iFilter < fFilters.GetEntriesFast(); iFilter++) {
350 AliFilter* filter = (AliFilter*) fFilters[iFilter];
351 if (!filter) continue;
352 if (filter->Filter(fEvent, fESD)) result = kTRUE;
354 if ((fFilterMode == kFilterOn) && !result) return kFilterReject;
358 // Set stat info for first event of this file
359 if (fRawDB->GetEvents() == 0)
360 fStats->SetFirstId(header.GetRunNumber(), header.GetEventInRun());
362 // Store raw event in tree
363 Int_t nBytes = fRawDB->Fill();
365 // Store header in tree
366 if (fTagDB) fTagDB->Fill();
368 // Make top event object ready for next event data
370 // Clean up HLT ESD for the next event
371 if (fESD) fESD->Reset();
376 //______________________________________________________________________________
377 Int_t AliMDC::Close()
379 // close the current raw DB file
381 if (!fRawDB) return 1;
383 fRawDB->WriteStats(fStats);
384 fRunDB->Update(fStats);
392 //______________________________________________________________________________
393 Int_t AliMDC::Run(const char* inputFile, Bool_t loop,
394 EWriteMode mode, Double_t maxFileSize,
395 const char* fs1, const char* fs2)
397 // Run the MDC processor. Read from the input stream and only return
398 // when the input gave and EOF or a fatal error occured. On success 0
399 // is returned, 1 in case of a fatality.
400 // inputFile is the name of the DATE input file; if NULL the input will
401 // be taken from the event builder.
402 // If loop is set the same input file will be reused in an infinite loop.
403 // mode specifies the type of the raw DB.
404 // maxFileSize is the maximal size of the raw DB.
405 // fs1 and fs2 are the file system locations of the raw DB.
407 Info("Run", "input = %s, rawdb size = %f, filter = %s, "
408 "looping = %s, compression = %d, delete files = %s",
409 inputFile ? inputFile : "event builder", maxFileSize,
410 fFilterMode == kFilterOff ? "off" :
411 (fFilterMode == kFilterOn ? "on" : "transparent"),
412 loop ? "yes" : "no", fCompress, fDeleteFiles ? "yes" : "no");
414 // Open the input file
417 if ((fd = open(inputFile, O_RDONLY)) == -1) {
418 Error("Run", "cannot open input file %s", inputFile);
423 // Used for statistics
426 Double_t told = 0, tnew = 0;
427 Float_t chunkSize = maxFileSize/100, nextChunk = chunkSize;
429 // Create new raw DB.
432 fRawDB = new AliRawRFIODB(fEvent, fESD, fCompress, NULL);
433 } else if (mode == kROOTD) {
434 fRawDB = new AliRawRootdDB(fEvent, fESD, fCompress, NULL);
435 } else if (mode == kCASTOR) {
436 fRawDB = new AliRawCastorDB(fEvent, fESD, fCompress, NULL);
437 } else if (mode == kDEVNULL) {
438 fRawDB = new AliRawNullDB(fEvent, fESD, fCompress, NULL);
440 fRawDB = new AliRawDB(fEvent, fESD, fCompress, NULL);
442 fRawDB->SetMaxSize(maxFileSize);
443 fRawDB->SetFS(fs1, fs2);
444 fRawDB->SetDeleteFiles(fDeleteFiles);
447 if (fRawDB->IsZombie()) {
452 printf("Filling raw DB %s\n", fRawDB->GetDBName());
454 // Create AliStats object
455 fStats = new AliStats(fRawDB->GetDBName(), fCompress,
456 fFilterMode != kFilterOff);
458 // Process input stream
463 UInt_t eventSize = 0;
468 // If we were in looping mode stop directly after a SIGUSR1 signal
470 Info("Run", "Stopping loop, processed %d events", numEvents);
474 if (!inputFile) { // get data from event builder
476 if ((eorFlag = ebEor())) break;
477 if ((event = (char*)ebGetNextEvent()) == (char*)-1) {
478 Error("Run", "error getting next event (%s)", ebGetLastError());
482 // no event, sleep for 1 second and try again
483 gSystem->Sleep(1000);
487 Error("Run", "AliMDC was compiled without event builder support");
495 } else { // get data from a file
496 AliRawEventHeader header;
498 if ((nrecv = Read(fd, header.HeaderBegin(), header.HeaderSize())) !=
499 header.HeaderSize()) {
500 if (nrecv == 0) { // eof
502 ::lseek(fd, 0, SEEK_SET);
508 Error("Run", "error reading header");
514 if (eventSize < header.GetEventSize()) {
516 eventSize = 2 * header.GetEventSize();
517 event = new char[eventSize];
519 memcpy(event, header.HeaderBegin(), header.HeaderSize());
520 Int_t size = header.GetEventSize() - header.HeaderSize();
521 if (Read(fd, event + header.HeaderSize(), size) != size) {
522 Error("Run", "error reading data");
529 Int_t result = ProcessEvent(event, !inputFile);
534 printf("Processed event %d (%d)\n", numEvents, fRawDB->GetEvents());
538 // Filling time statistics
539 if (fRawDB->GetBytesWritten() > nextChunk) {
540 tnew = timer.RealTime();
541 fStats->Fill(tnew-told);
544 nextChunk += chunkSize;
547 // Check size of raw db. If bigger than maxFileSize, close file
548 // and continue with new file.
549 if (fRawDB->GetBytesWritten() > maxFileSize) {
551 printf("Written raw DB at a rate of %.1f MB/s\n",
552 fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
554 // Write stats object to raw db, run db, MySQL and AliEn
555 fRawDB->WriteStats(fStats);
556 if (fRunDB) fRunDB->Update(fStats);
560 if (!fRawDB->NextFile()) {
561 Error("Run", "error opening next raw data file");
563 if (inputFile) delete[] event;
567 printf("Filling raw DB %s\n", fRawDB->GetDBName());
568 fStats = new AliStats(fRawDB->GetDBName(), fCompress,
569 fFilterMode != kFilterOff);
573 nextChunk = chunkSize;
576 // Check size of tag db
577 if (fTagDB && fTagDB->FileFull()) {
578 if (!fTagDB->NextFile()) {
582 printf("Filling tag DB %s\n", fTagDB->GetDBName());
587 // Make top event object ready for next event data
588 //printf("Event %d has %d sub-events\n", numEvents, fEvent->GetNSubEvents());
590 // Clean up HLT ESD for the next event
591 // if (fESD) fESD->Reset();
595 if (!ebReleaseEvent((iovec*)event)) {
596 Error("Run", "problem releasing event (%s)", ebGetLastError());
603 printf("Written raw DB at a rate of %.1f MB/s\n",
604 fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
606 // Write stats to raw db and run db and delete stats object
613 Info("Run", "event builder reported end of run (%d)", eorFlag);
617 // Close input source
624 //______________________________________________________________________________
625 Int_t AliMDC::Read(Int_t fd, void *buffer, Int_t length)
627 // Read exactly length bytes into buffer. Returns number of bytes
628 // received, returns -1 in case of error and 0 for EOF.
632 if (fd < 0) return -1;
635 char *buf = (char *)buffer;
637 for (n = 0; n < length; n += nrecv) {
638 if ((nrecv = read(fd, buf+n, length-n)) <= 0) {
642 SysError("Read", "read");
649 //______________________________________________________________________________
650 Int_t AliMDC::ReadHeader(AliRawEventHeader &header, char*& data)
652 // Read header info from DATE data stream. Returns bytes read (i.e.
653 // AliRawEventHeader::HeaderSize()), -1 in case of error and 0 for EOF.
655 memcpy(header.HeaderBegin(), data, header.HeaderSize());
656 data += header.HeaderSize();
658 // Swap header data if needed
659 if (header.IsSwapped())
662 // Is header valid...
663 if (!header.IsValid()) {
664 Error("ReadHeader", "invalid header format");
665 // try recovery... how?
668 if (header.GetEventSize() < (UInt_t)header.HeaderSize()) {
669 Error("ReadHeader", "invalid header size");
670 // try recovery... how?
674 return header.HeaderSize();
677 //______________________________________________________________________________
678 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
679 Bool_t isSwapped, char*& data)
681 // Read equipment header info from DATE data stream. Returns bytes read
682 // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
683 // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
684 // and we will swap the header to host format.
686 memcpy(header.HeaderBegin(), data, header.HeaderSize());
687 data += header.HeaderSize();
689 // Swap equipment header data if needed
693 if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
694 Error("ReadEquipmentHeader", "invalid equipment header size");
695 // try recovery... how?
699 return header.HeaderSize();
702 //______________________________________________________________________________
703 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, char*& data)
705 // Read raw data from DATE data stream. Returns bytes read (i.e.
706 // size), -1 in case of error and 0 for EOF.
708 raw.SetBuffer(data, size);
714 //______________________________________________________________________________
717 // Stop the event loop
720 if (fRawDB) fRawDB->Stop();
724 //______________________________________________________________________________
725 AliMDC::AliMDCInterruptHandler::AliMDCInterruptHandler(const
726 AliMDCInterruptHandler&
728 TSignalHandler(handler)
732 Fatal("AliMDCInterruptHandler", "copy constructor not implemented");
735 //______________________________________________________________________________
736 AliMDC::AliMDCInterruptHandler&
737 AliMDC::AliMDCInterruptHandler::operator = (const AliMDCInterruptHandler&
740 // assignment operator
742 Fatal("operator =", "assignment operator not implemented");