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 AliRawEventV2//
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 AliRawEventV2s. The number of //
30 // sub-events depends on the number of DATE LDC's. //
31 // The AliRawEventV2 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 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. //
42 //////////////////////////////////////////////////////////////////////////
44 #include <sys/types.h>
51 #include <TStopwatch.h>
52 #include <TPluginManager.h>
53 #include <TBufferFile.h>
57 #include "libDateEb.h"
63 #include <AliESDEvent.h>
65 #include "AliRawEventV2.h"
66 #include "AliRawEventHeaderBase.h"
67 #include "AliRawEquipmentV2.h"
68 #include "AliRawEquipmentHeader.h"
69 #include "AliRawDataArrayV2.h"
70 #include "AliRawData.h"
72 #include "AliRawRFIODB.h"
73 #include "AliRawCastorDB.h"
74 #include "AliRawRootdDB.h"
75 #include "AliRawNullDB.h"
77 #include "AliRawEventTag.h"
78 #include "AliFilter.h"
86 const char* const AliMDC::fgkFilterName[kNFilters] = {"AliHoughFilter"};
88 //______________________________________________________________________________
89 AliMDC::AliMDC(Int_t compress, Bool_t deleteFiles, EFilterMode filterMode,
90 Double_t maxSizeTagDB, const char* fileNameTagDB,
91 const char *guidFileFolder,
93 fEvent(new AliRawEventV2),
97 fEventTag(new AliRawEventTag),
99 fBasketSize(basketsize),
100 fDeleteFiles(deleteFiles),
101 fFilterMode(filterMode),
104 fIsTagDBCreated(kFALSE),
105 fMaxSizeTagDB(maxSizeTagDB),
106 fFileNameTagDB(fileNameTagDB),
107 fGuidFileFolder(guidFileFolder)
109 // Create MDC processor object.
110 // compress is the file compression mode.
111 // If deleteFiles is kTRUE the raw data files will be deleted after they
113 // If the filterMode if kFilterOff no filter algorithm will be, if it is
114 // kFilterTransparent the algorthims will be run but no events will be
115 // rejected, if it is kFilterOn the filters will be run and the event will
116 // be rejected if all filters return kFALSE.
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.
121 // Optional 'guidFileFolder' specifies the folder in which *.guid files
122 // will be stored. In case this option is not given, the *.guid files
123 // will be written to the same folder as the raw-data files.
125 // Set the maximum tree size to 19GB
126 // in order to allow big raw data files
127 TTree::SetMaxTreeSize(20000000000LL);
129 AliRawEquipmentHeader::Class()->IgnoreTObjectStreamer();
130 AliRawEquipmentV2::Class()->IgnoreTObjectStreamer();
131 AliRawEventV2::Class()->IgnoreTObjectStreamer();
132 AliRawDataArrayV2::Class()->IgnoreTObjectStreamer();
134 TBufferFile::SetGlobalReadParam(5);
136 // This line is needed in case of a stand-alone application w/o
137 // $ROOTSYS/etc/system.rootrc file
138 gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
144 if (fFilterMode != kFilterOff) {
145 fESD = new AliESDEvent();
148 // Create the guid files folder if it does not exist
149 if (!fGuidFileFolder.IsNull()) {
150 gSystem->ResetErrno();
151 gSystem->MakeDirectory(fGuidFileFolder.Data());
152 if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
153 SysError("AliMDC", "mkdir %s", fGuidFileFolder.Data());
157 // install SIGUSR1 handler to allow clean interrupts
158 gSystem->AddSignalHandler(new AliMDCInterruptHandler(this));
160 // create the high level filters
161 if (fFilterMode != kFilterOff) {
162 for (Int_t iFilter = 0; iFilter < kNFilters; iFilter++) {
163 TClass* filterClass = gROOT->GetClass(fgkFilterName[iFilter]);
165 Warning("AliMDC", "no filter class %s found", fgkFilterName[iFilter]);
168 AliFilter* filter = (AliFilter*) filterClass->New();
170 Warning("AliMDC", "creation of filter %s failed", fgkFilterName[iFilter]);
173 fFilters.Add(filter);
178 //______________________________________________________________________________
184 if(fTagDB) delete fTagDB;
191 //______________________________________________________________________________
192 Int_t AliMDC::Open(EWriteMode mode, const char* fileName,
193 Double_t maxFileSize,
194 const char* fs1, const char* fs2)
196 // open a new raw DB file
199 fRawDB = new AliRawRFIODB(fEvent, fESD, fCompress, fileName, fBasketSize);
200 else if (mode == kROOTD)
201 fRawDB = new AliRawRootdDB(fEvent, fESD, fCompress, fileName, fBasketSize);
202 else if (mode == kCASTOR)
203 fRawDB = new AliRawCastorDB(fEvent, fESD, fCompress, fileName, fBasketSize);
204 else if (mode == kDEVNULL)
205 fRawDB = new AliRawNullDB(fEvent, fESD, fCompress, fileName, fBasketSize);
207 fRawDB = new AliRawDB(fEvent, fESD, fCompress, fileName, fBasketSize);
208 fRawDB->SetDeleteFiles(fDeleteFiles);
210 if (fRawDB->IsZombie()) {
216 if (fileName == NULL) {
217 fRawDB->SetMaxSize(maxFileSize);
218 fRawDB->SetFS(fs1, fs2);
219 if (!fRawDB->Create()) {
226 if (!fRawDB->WriteGuidFile(fGuidFileFolder)) {
232 Info("Open", "Filling raw DB %s\n", fRawDB->GetDBName());
237 //______________________________________________________________________________
238 Int_t AliMDC::ProcessEvent(void* event, Bool_t isIovecArray)
240 // Convert the DATE event to an AliRawEventV2 object and store it in the raw DB,
241 // optionally also run the filter.
242 // event is either a pointer to the streamlined event
243 // or, if isIovecArray is kTRUE, a pointer to an array of iovecs with one
244 // iovec per subevent (used by the event builder).
245 // The return value is the number of written bytes or an error code
246 const Long64_t kFileSizeErrorLevel = 19000000000LL;
248 Long64_t currentFileSize = GetTotalSize();
249 // AliDebug(1,Form("current file size is %lld bytes",currentFileSize));
250 if(currentFileSize > kFileSizeErrorLevel) {
251 Error("ProcessEvent", "file size (%lld) exceeds the limit "
257 char* data = (char*) event;
258 if (isIovecArray) data = (char*) ((iovec*) event)[0].iov_base;
260 // Shortcut for easy header access
261 AliRawEventHeaderBase *header = fEvent->GetHeader(data);
264 if ((status = header->ReadHeader(data)) != (Int_t)header->GetHeadSize()) {
265 Error("ProcessEvent","Wrong event header format (%d != %d)",
266 status,(Int_t)header->GetHeadSize());
270 // if (AliDebugLevel() > 2) ToAliDebug(3, header->Dump(););
272 // Check event type and skip "Start of Run", "End of Run",
273 // "Start of Run Files" and "End of Run Files"
274 Int_t size = header->GetEventSize() - header->GetHeadSize();
275 UInt_t eventType = header->Get("Type");
277 // AliDebug(1, Form("Processing %s (%d bytes)", header->GetTypeName(), size));
279 // Amount of data left to read for this event
282 // StartOfRun, EndOfRun etc. events have no payload
283 // Nevertheless, store the event headers in the tree
286 // If there is less data for this event than the next sub-event
287 // header, something is wrong. Skip to next event...
288 if (toRead < (Int_t)header->GetHeadSize()) {
289 Error("ProcessEvent", "header size (%d) exceeds number of bytes "
290 "to read (%d)", header->GetHeadSize(), toRead);
291 if (AliDebugLevel() > 0) ToAliDebug(1, header->Dump(););
292 return kErrHeaderSize;
295 // Loop over all sub-events... (LDCs)
298 if (isIovecArray) data = (char*) ((iovec*) event)[nsub].iov_base;
300 // AliDebug(1, Form("reading LDC %d", nsub));
302 AliRawEventV2 *subEvent = fEvent->NextSubEvent();
304 // Read sub-event header
305 AliRawEventHeaderBase *subHeader = subEvent->GetHeader(data);
306 if ((status = subHeader->ReadHeader(data)) != (Int_t)subHeader->GetHeadSize()) {
307 return kErrSubHeader;
310 // if (AliDebugLevel() > 2) ToAliDebug(3, subHeader->Dump(););
312 toRead -= subHeader->GetHeadSize();
314 Int_t rawSize = subHeader->GetEventSize() - subHeader->GetHeadSize();
316 // Make sure raw data less than left over bytes for current event
317 if (rawSize > toRead) {
318 Warning("ProcessEvent", "raw data size (%d) exceeds number of "
319 "bytes to read (%d)\n", rawSize, toRead);
320 if (AliDebugLevel() > 0) ToAliDebug(1, subHeader->Dump(););
324 // Read Equipment Headers (in case of physics or calibration event)
325 if (eventType == AliRawEventHeaderBase::kPhysicsEvent ||
326 eventType == AliRawEventHeaderBase::kCalibrationEvent ||
327 eventType == AliRawEventHeaderBase::kSystemSoftwareTriggerEvent ||
328 eventType == AliRawEventHeaderBase::kDetectorSoftwareTriggerEvent ||
329 eventType == AliRawEventHeaderBase::kStartOfData ||
330 eventType == AliRawEventHeaderBase::kEndOfData) {
331 while (rawSize > 0) {
332 AliRawEquipmentV2 &equipment = *subEvent->NextEquipment();
333 AliRawEquipmentHeader &equipmentHeader =
334 *equipment.GetEquipmentHeader();
335 Int_t equipHeaderSize = equipmentHeader.HeaderSize();
336 if ((status = ReadEquipmentHeader(equipmentHeader, header->DataIsSwapped(),
337 data)) != equipHeaderSize) {
338 return kErrEquipmentHeader;
341 // if (AliDebugLevel() > 2) ToAliDebug(3, equipmentHeader.Dump(););
343 toRead -= equipHeaderSize;
344 rawSize -= equipHeaderSize;
346 // Read equipment raw data
347 AliRawDataArrayV2 *arr = fRawDB->GetRawDataArray(equipmentHeader.GetEquipmentSize(),
348 equipmentHeader.GetId());
349 AliRawData &subRaw = *equipment.NextRawData(arr);
351 Int_t eqSize = equipmentHeader.GetEquipmentSize() - equipHeaderSize;
352 if ((status = ReadRawData(subRaw, eqSize, data)) != eqSize) {
353 return kErrEquipment;
360 } else { // Read only raw data but no equipment header
362 AliRawEquipmentV2 &equipment = *subEvent->NextEquipment();
363 AliRawEquipmentHeader &equipmentHeader =
364 *equipment.GetEquipmentHeader();
365 equipmentHeader.Reset();
366 AliRawDataArrayV2 *arr = fRawDB->GetRawDataArray(equipmentHeader.GetEquipmentSize(),
367 equipmentHeader.GetId());
368 AliRawData &subRaw = *equipment.NextRawData(arr);
369 if ((status = ReadRawData(subRaw, rawSize, data)) != rawSize) {
370 return kErrEquipment;
380 // High Level Event Filter
381 if (fFilterMode != kFilterOff) {
382 if (eventType == AliRawEventHeaderBase::kPhysicsEvent ||
383 eventType == AliRawEventHeaderBase::kCalibrationEvent ||
384 eventType == AliRawEventHeaderBase::kSystemSoftwareTriggerEvent ||
385 eventType == AliRawEventHeaderBase::kDetectorSoftwareTriggerEvent ||
386 eventType == AliRawEventHeaderBase::kStartOfData ||
387 eventType == AliRawEventHeaderBase::kEndOfData) {
388 Bool_t result = kFALSE;
389 for (Int_t iFilter = 0; iFilter < fFilters.GetEntriesFast(); iFilter++) {
390 AliFilter* filter = (AliFilter*) fFilters[iFilter];
391 if (!filter) continue;
392 if (filter->Filter(fEvent, fESD)) result = kTRUE;
394 if ((fFilterMode == kFilterOn) && !result) return kFilterReject;
398 // Store raw event in tree
399 Int_t nBytes = fRawDB->Fill();
401 // Fill the event tag object
402 fEventTag->SetHeader(header);
403 fEventTag->SetGUID(fRawDB->GetDB()->GetUUID().AsString());
404 fEventTag->SetEventNumber(fRawDB->GetEvents()-1);
406 // Create Tag DB here only after the raw data header
407 // version was already identified
408 if (!fIsTagDBCreated) {
409 if (!fFileNameTagDB.IsNull()) {
410 if (fMaxSizeTagDB > 0) {
411 fTagDB = new AliTagDB(fEventTag, NULL);
412 fTagDB->SetMaxSize(fMaxSizeTagDB);
413 fTagDB->SetFS(fFileNameTagDB.Data());
414 if (!fTagDB->Create()) return kErrTagFile;
416 fTagDB = new AliTagDB(fEventTag, fFileNameTagDB.Data());
417 if (fTagDB->IsZombie()) return kErrTagFile;
420 fIsTagDBCreated = kTRUE;
423 // Store event tag in tree
424 if (fTagDB) fTagDB->Fill();
426 // Make top event object ready for next event data
430 // Clean up HLT ESD for the next event
431 if (fESD) fESD->Reset();
439 //______________________________________________________________________________
440 Long64_t AliMDC::GetTotalSize()
442 // return the total current raw DB file size
444 if (!fRawDB) return -1;
446 return fRawDB->GetTotalSize();
449 //______________________________________________________________________________
450 Long64_t AliMDC::Close()
452 // close the current raw DB file
454 if (!fRawDB) return -1;
456 Long64_t filesize = fRawDB->Close();
462 //______________________________________________________________________________
463 Long64_t AliMDC::AutoSave()
465 // Auto-save the raw-data
466 // and esd (if any) trees
468 if (!fRawDB) return -1;
470 return fRawDB->AutoSave();
473 //______________________________________________________________________________
474 Int_t AliMDC::Run(const char* inputFile, Bool_t loop,
475 EWriteMode mode, Double_t maxFileSize,
476 const char* fs1, const char* fs2)
478 // Run the MDC processor. Read from the input stream and only return
479 // when the input gave and EOF or a fatal error occured. On success 0
480 // is returned, 1 in case of a fatality.
481 // inputFile is the name of the DATE input file; if NULL the input will
482 // be taken from the event builder.
483 // If loop is set the same input file will be reused in an infinite loop.
484 // mode specifies the type of the raw DB.
485 // maxFileSize is the maximal size of the raw DB.
486 // fs1 and fs2 are the file system locations of the raw DB.
488 Info("Run", "input = %s, rawdb size = %f, filter = %s, "
489 "looping = %s, compression = %d, delete files = %s",
490 inputFile ? inputFile : "event builder", maxFileSize,
491 fFilterMode == kFilterOff ? "off" :
492 (fFilterMode == kFilterOn ? "on" : "transparent"),
493 loop ? "yes" : "no", fCompress, fDeleteFiles ? "yes" : "no");
495 // Open the input file
498 if ((fd = open(inputFile, O_RDONLY)) == -1) {
499 Error("Run", "cannot open input file %s", inputFile);
504 // Used for statistics
507 Float_t chunkSize = maxFileSize/100, nextChunk = chunkSize;
509 // Create new raw DB.
512 if (Open(mode,NULL,maxFileSize,fs1,fs2) < 0) {
513 if (fd>-1) close(fd);
516 // Process input stream
521 UInt_t eventSize = 0;
524 AliRawEventHeaderBase header;
525 AliRawEventHeaderBase *hdr = NULL;
529 // If we were in looping mode stop directly after a SIGUSR1 signal
531 Info("Run", "Stopping loop, processed %d events", numEvents);
535 if (!inputFile) { // get data from event builder
537 if ((eorFlag = ebEor())) break;
538 if ((event = (char*)ebGetNextEvent()) == (char*)-1) {
539 Error("Run", "error getting next event (%s)", ebGetLastError());
543 // no event, sleep for 1 second and try again
544 gSystem->Sleep(1000);
548 Error("Run", "AliMDC was compiled without event builder support");
554 } else { // get data from a file
557 if ((nrecv = Read(fd, header.HeaderBaseBegin(), header.HeaderBaseSize())) !=
558 header.HeaderBaseSize()) {
559 if (nrecv == 0) { // eof
561 ::lseek(fd, 0, SEEK_SET);
567 Error("Run", "error reading base header");
570 if (fd>-1) close(fd);
575 char *data = (char *)header.HeaderBaseBegin();
577 hdr = AliRawEventHeaderBase::Create(data);
580 memcpy(hdr->HeaderBaseBegin(), header.HeaderBaseBegin(), header.HeaderBaseSize());
583 if ((nrecv = Read(fd, hdr->HeaderBegin(), hdr->HeaderSize())) !=
585 if (nrecv == 0) { // eof
587 ::lseek(fd, 0, SEEK_SET);
595 Error("Run", "error reading header");
599 if (fd>-1) close(fd);
603 if (eventSize < hdr->GetEventSize()) {
605 eventSize = 2 * hdr->GetEventSize();
606 event = new char[eventSize];
608 memcpy(event, header.HeaderBaseBegin(), header.HeaderBaseSize());
609 memcpy(event+hdr->HeaderBaseSize(), hdr->HeaderBegin(), hdr->HeaderSize());
610 if (hdr->GetExtendedDataSize() != 0)
611 memcpy(event+hdr->HeaderBaseSize()+hdr->HeaderSize(),
612 hdr->GetExtendedData(), hdr->GetExtendedDataSize());
613 Int_t size = hdr->GetEventSize() - hdr->GetHeadSize();
614 if (Read(fd, event + hdr->GetHeadSize(), size) != size) {
615 Error("Run", "error reading data");
619 if (fd>-1) close(fd);
624 Int_t result = ProcessEvent(event, !inputFile);
626 Error("Run", "error writing data. Error code: %d",result);
633 // Filling time statistics
634 if (fRawDB->GetBytesWritten() > nextChunk) {
635 nextChunk += chunkSize;
638 // Check size of raw db. If bigger than maxFileSize, close file
639 // and continue with new file.
640 if (fRawDB->GetBytesWritten() > maxFileSize) {
642 printf("Written raw DB at a rate of %.1f MB/s\n",
643 fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
645 if (!fRawDB->NextFile()) {
646 Error("Run", "error opening next raw data file");
648 if (inputFile) delete[] event;
650 if (fd>-1) close(fd);
654 printf("Filling raw DB %s\n", fRawDB->GetDBName());
656 nextChunk = chunkSize;
659 // Check size of tag db
660 if (fTagDB && fTagDB->FileFull()) {
661 if (!fTagDB->NextFile()) {
665 printf("Filling tag DB %s\n", fTagDB->GetDBName());
670 // Make top event object ready for next event data
671 //printf("Event %d has %d sub-events\n", numEvents, fEvent->GetNSubEvents());
673 // Clean up HLT ESD for the next event
674 // if (fESD) fESD->Reset();
678 if (!ebReleaseEvent((iovec*)event)) {
679 Error("Run", "problem releasing event (%s)", ebGetLastError());
688 printf("Written raw DB at a rate of %.1f MB/s\n",
689 fRawDB->GetBytesWritten() / timer.RealTime() / 1000000.);
691 // Write stats to raw db and run db and delete stats object
698 Info("Run", "event builder reported end of run (%d)", eorFlag);
702 // Close input source
703 if (fd>-1) close(fd);
710 //______________________________________________________________________________
711 Int_t AliMDC::Read(Int_t fd, void *buffer, Int_t length)
713 // Read exactly length bytes into buffer. Returns number of bytes
714 // received, returns -1 in case of error and 0 for EOF.
718 if (fd < 0) return -1;
721 char *buf = (char *)buffer;
723 for (n = 0; n < length; n += nrecv) {
724 if ((nrecv = read(fd, buf+n, length-n)) <= 0) {
728 SysError("Read", "read");
735 //______________________________________________________________________________
736 Int_t AliMDC::ReadEquipmentHeader(AliRawEquipmentHeader &header,
737 Bool_t isSwapped, char*& data)
739 // Read equipment header info from DATE data stream. Returns bytes read
740 // (i.e. AliRawEquipmentHeader::HeaderSize()), -1 in case of error and
741 // 0 for EOF. If isSwapped is kTRUE the event data is byte swapped
742 // and we will swap the header to host format.
744 memcpy(header.HeaderBegin(), data, header.HeaderSize());
745 data += header.HeaderSize();
747 // Swap equipment header data if needed
751 if (header.GetEquipmentSize() < (UInt_t)header.HeaderSize()) {
752 Error("ReadEquipmentHeader", "invalid equipment header size");
753 // try recovery... how?
757 return header.HeaderSize();
760 //______________________________________________________________________________
761 Int_t AliMDC::ReadRawData(AliRawData &raw, Int_t size, char*& data)
763 // Read raw data from DATE data stream. Returns bytes read (i.e.
764 // size), -1 in case of error and 0 for EOF.
766 raw.SetBuffer(data, size);
772 //______________________________________________________________________________
775 // Stop the event loop
778 if (fRawDB) fRawDB->Stop();