Fix for coverity (AdC)
[u/mrichter/AliRoot.git] / RAW / AliRawDB.cxx
1 // @(#)alimdc:$Name:  $:$Id$
2 // Author: Fons Rademakers  26/11/99
3
4 /**************************************************************************
5  * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
6  *                                                                        *
7  * Author: The ALICE Off-line Project.                                    *
8  * Contributors are mentioned in the code where appropriate.              *
9  *                                                                        *
10  * Permission to use, copy, modify and distribute this software and its   *
11  * documentation strictly for non-commercial purposes is hereby granted   *
12  * without fee, provided that the above copyright notice appears in all   *
13  * copies and that both the copyright notice and this permission notice   *
14  * appear in the supporting documentation. The authors make no claims     *
15  * about the suitability of this software for any purpose. It is          *
16  * provided "as is" without express or implied warranty.                  *
17  **************************************************************************/
18
19 //////////////////////////////////////////////////////////////////////////
20 //                                                                      //
21 // AliRawDB                                                             //
22 //                                                                      //
23 //////////////////////////////////////////////////////////////////////////
24
25 #include <errno.h>
26 #include <Riostream.h>
27 #include <RVersion.h>
28
29 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,15,0)
30 #include <TBufferFile.h>
31 #else
32 #include <TBuffer.h>
33 #endif
34
35 #include <TSystem.h>
36 #include <TKey.h>
37
38 #include <TObjString.h>
39
40 #include <TBranch.h>
41
42 #include "AliESDEvent.h"
43 #include "AliRawEventV2.h"
44 #include "AliRawDataArrayV2.h"
45 #include "AliRawEventHeaderBase.h"
46 #include "AliRawEquipmentHeader.h"
47
48 #include "AliRawDB.h"
49
50 using std::ofstream;
51
52 ClassImp(AliRawDB)
53
54 const char *AliRawDB::fgkAliRootTag = "$Rev$";
55
56 // Split TPC into 18 branches in order to avoid problems with big memory
57 // consumption in case of TPC events w/o zero-suppression
58 Int_t AliRawDB::fgkDetBranches[AliDAQ::kNDetectors+1] = {
59    1, /*  1 ITSSPD */
60    1, /*  2 ITSSDD */
61    1, /*  3 ITSSSD */
62   18, /*  4 TPC */
63    1, /*  5 TRD */
64    1, /*  6 TOF */
65    1, /*  7 HMPID */
66    1, /*  8 PHOS */
67    1, /*  9 CPV */
68    1, /* 10 PMD */
69    1, /* 11 MUONTRK */
70    1, /* 12 MUONTRG */
71    1, /* 13 FMD */
72    1, /* 14 T0 */
73    1, /* 15 VZERO */
74    1, /* 16 ZDC */
75    1, /* 17 ACORDE */
76    1, /* 18 TRG */
77    1, /* 19 EMCAL */
78    1, /* 20 DAQ_TEST */
79    1, /* 21 MFT */
80    1, /* 22 FIT */
81    10, /* 23 HLT */
82    1 /* 24 --- */
83 };
84
85 //______________________________________________________________________________
86 AliRawDB::AliRawDB(AliRawEventV2 *event,
87                    AliESDEvent *esd, 
88                    Int_t compress,
89                    const char* fileName,
90                    Int_t basketsize) :
91   fRawDB(NULL),
92   fTree(NULL),
93   fEvent(event),
94   fESDTree(NULL),
95   fESD(esd),
96   fCompress(compress),
97   fBasketSize(basketsize),
98   fMaxSize(-1),
99   fFS1(""),
100   fFS2(""),
101   fDeleteFiles(kFALSE),
102   fStop(kFALSE)
103 {
104    // Create a new raw DB
105
106   for (Int_t iDet = 0; iDet < AliDAQ::kNDetectors; iDet++) {
107     fDetRawData[iDet] = new AliRawDataArrayV2*[fgkDetBranches[iDet]];
108     Int_t nDDLsPerBranch = AliDAQ::NumberOfDdls(iDet)/fgkDetBranches[iDet];
109     for (Int_t iBranch = 0; iBranch < fgkDetBranches[iDet]; iBranch++)
110       fDetRawData[iDet][iBranch] = new AliRawDataArrayV2(nDDLsPerBranch);
111   }
112
113   fDetRawData[AliDAQ::kNDetectors] = new AliRawDataArrayV2*[fgkDetBranches[AliDAQ::kNDetectors]];
114   for (Int_t iBranch = 0; iBranch < fgkDetBranches[AliDAQ::kNDetectors]; iBranch++)
115     fDetRawData[AliDAQ::kNDetectors][iBranch] = new AliRawDataArrayV2(100);
116
117    if (fileName) {
118       if (!Create(fileName))
119          MakeZombie();
120    }
121 }
122
123
124 //______________________________________________________________________________
125 AliRawDB::~AliRawDB() {
126   // Destructor
127
128   if(Close()==-1) Error("~AliRawDB", "cannot close output file!");
129
130   for (Int_t iDet = 0; iDet < (AliDAQ::kNDetectors + 1); iDet++) {
131     for (Int_t iBranch = 0; iBranch < fgkDetBranches[iDet]; iBranch++)
132       delete fDetRawData[iDet][iBranch];
133     delete [] fDetRawData[iDet];
134   }
135 }
136
137 //______________________________________________________________________________
138 Bool_t AliRawDB::FSHasSpace(const char *fs) const
139 {
140    // Check for at least fMaxSize bytes of free space on the file system.
141    // If the space is not available return kFALSE, kTRUE otherwise.
142
143    Long_t id, bsize, blocks, bfree;
144
145    if (gSystem->GetFsInfo(fs, &id, &bsize, &blocks, &bfree) == 1) {
146       Error("FSHasSpace", "could not stat file system %s", fs);
147       return kFALSE;
148    }
149
150    // Leave 5 percent of diskspace free
151    Double_t avail = Double_t(bfree) * 0.95;
152    if (avail*bsize > fMaxSize)
153       return kTRUE;
154
155    Warning("FSHasSpace", "no space on file system %s", fs);
156    return kFALSE;
157 }
158
159 //______________________________________________________________________________
160 const char *AliRawDB::GetFileName() const
161 {
162    // Return filename based on hostname and date and time. This will make
163    // each file unique. Also makes sure (via FSHasSpace()) that there is
164    // enough space on the file system to store the file. Returns 0 in
165    // case of error or interrupt signal.
166
167    static TString fname;
168    static Bool_t  fstoggle = kFALSE;
169
170    TString fs = fstoggle ? fFS2 : fFS1;
171    TDatime dt;
172
173    TString hostname = gSystem->HostName();
174    Int_t pos;
175    if ((pos = hostname.Index(".")) != kNPOS)
176       hostname.Remove(pos);
177
178    if (!FSHasSpace(fs)) {
179       while (1) {
180          fstoggle = !fstoggle;
181          fs = fstoggle ? fFS2 : fFS1;
182          if (FSHasSpace(fs)) break;
183          Info("GetFileName", "sleeping 30 seconds before retrying...");
184          gSystem->Sleep(30000);   // sleep for 30 seconds
185          if (fStop) return 0;
186       }
187    }
188
189    fname = fs + "/" + hostname + "_";
190    fname += dt.GetDate();
191    fname += "_";
192    fname += dt.GetTime();
193    fname += ".root";
194
195    fstoggle = !fstoggle;
196
197    return fname;
198 }
199
200 //______________________________________________________________________________
201 void AliRawDB::SetFS(const char* fs1, const char* fs2)
202 {
203 // set the file system location
204
205   fFS1 = fs1;
206   if (fs1 && !fFS1.Contains(":")) {
207     gSystem->ResetErrno();
208     gSystem->MakeDirectory(fs1);
209     if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
210       SysError("SetFS", "mkdir %s", fs1);
211     }
212   }
213
214   fFS2 = fs2;
215   if (fs2) {
216     gSystem->ResetErrno();
217     gSystem->MakeDirectory(fs2);
218     if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
219       SysError("SetFS", "mkdir %s", fs2);
220     }
221   }
222 }
223
224 //______________________________________________________________________________
225 Bool_t AliRawDB::Create(const char* fileName)
226 {
227    // Create a new raw DB.
228
229    const Int_t kMaxRetry = 1;
230    const Int_t kMaxSleep = 1;      // seconds
231    const Int_t kMaxSleepLong = 10; // seconds
232    Int_t retry = 0;
233
234 again:
235    if (fStop) return kFALSE;
236
237    const char *fname = fileName;
238    if (!fname) fname = GetFileName();
239    if (!fname) {
240       Error("Create", "error getting raw DB file name");
241       return kFALSE;
242    }
243
244    retry++;
245
246    fRawDB = TFile::Open(fname, GetOpenOption(),
247                         Form("ALICE raw-data file (%s)", GetAliRootTag()), fCompress,
248                         GetNetopt());
249    if (!fRawDB) {
250       if (retry < kMaxRetry) {
251          Warning("Create", "failure to open file, sleeping %d %s before retrying...",
252                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
253          gSystem->Sleep(kMaxSleep*1000);
254          goto again;
255       }
256       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
257       return kFALSE;
258    }
259    if (retry > 1)
260       Warning("Create", "succeeded to open file after %d retries", retry);
261
262    if (fRawDB->IsZombie()) {
263       if (fRawDB->GetErrno() == ENOSPC ||
264           fRawDB->GetErrno() == 1018   ||   // SECOMERR
265           fRawDB->GetErrno() == 1027) {     // SESYSERR
266          fRawDB->ResetErrno();
267          delete fRawDB;
268          Warning("Create", "file is a zombie (no space), sleeping %d %s before retrying...",
269                  kMaxSleepLong, kMaxSleepLong==1 ? "second" : "seconds");
270          gSystem->Sleep(kMaxSleepLong*1000);   // sleep 10 seconds before retrying
271          goto again;
272       }
273       Error("Create", "file %s is zombie", fname);
274       fRawDB->ResetErrno();
275       delete fRawDB;
276       fRawDB = 0;
277       if (retry < kMaxRetry) {
278          Warning("Create", "file is a zombie, sleeping %d %s before retrying...",
279                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
280          gSystem->Sleep(kMaxSleep*1000);
281          goto again;
282       }
283       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
284       return kFALSE;
285    }
286
287    return kTRUE;
288 }
289
290 static void BranchResetBit(TBranch *b) 
291 {
292   // Reset MapObject on this branch and all the sub-branches
293
294   b->ResetBit( kBranchObject | kBranchAny ); // Or in newer ROOT: b->ResetBit( kMapObject )
295   TIter next( b->GetListOfBranches() );
296   TBranch *sub = 0;
297   while ( (sub = (TBranch*)next() ) ) {
298     BranchResetBit( sub );
299   }
300 }
301
302 //______________________________________________________________________________
303 void AliRawDB::MakeTree()
304 {
305    // Create ROOT Tree object container.
306
307    fTree = new TTree("RAW", Form("ALICE raw-data tree (%s)", GetAliRootTag()));
308    fTree->SetAutoSave(21000000000LL);  // autosave when 21 Gbyte written
309
310    fTree->BranchRef();
311
312    Int_t split   = 99;
313    TBranch *b = fTree->Branch("rawevent", "AliRawEventV2", &fEvent, fBasketSize, split);
314    BranchResetBit(b);
315
316    // Make brach for each sub-detector
317    for (Int_t iDet = 0; iDet < AliDAQ::kNDetectors; iDet++) {
318      for (Int_t iBranch = 0; iBranch < fgkDetBranches[iDet]; iBranch++) {
319        b = fTree->Branch(Form("%s%d",AliDAQ::DetectorName(iDet),iBranch),"AliRawDataArrayV2",
320                          &fDetRawData[iDet][iBranch],fBasketSize,split);
321        BranchResetBit(b);
322      }
323    }
324    // Make special branch for unrecognized raw-data payloads
325    for (Int_t iBranch = 0; iBranch < fgkDetBranches[AliDAQ::kNDetectors]; iBranch++) {
326      b = fTree->Branch(Form("Common%d",iBranch),"AliRawDataArrayV2",
327                        &fDetRawData[AliDAQ::kNDetectors][iBranch],fBasketSize,split);
328      BranchResetBit(b);
329    }
330
331    // Create tree which will contain the HLT ESD information
332
333    if (fESD) {
334      fESDTree = new TTree("esdTree", Form("ALICE HLT ESD tree (%s)", GetAliRootTag()));
335      fESDTree->SetAutoSave(21000000000LL);  // autosave when 21 Gbyte written
336      split   = 0;
337      fESDTree->Branch("ESD", "AliESDEvent", &fESD, fBasketSize, split);
338    }
339
340 }
341
342 //______________________________________________________________________________
343 Long64_t AliRawDB::Close()
344 {
345    // Close raw DB.
346    if (!fRawDB) return 0;
347
348    if (!fRawDB->IsOpen()) return 0;
349
350    fRawDB->cd();
351
352    // Write the tree.
353    Bool_t error = kFALSE;
354    if (fTree)
355      if (fTree->Write() == 0)
356        error = kTRUE;
357    if (fESDTree)
358      if (fESDTree->Write() == 0)
359        error = kTRUE;
360
361    // Close DB, this also deletes the fTree
362    fRawDB->Close();
363
364    fTree = NULL;
365
366    Long64_t filesize = fRawDB->GetEND();
367
368    if (fDeleteFiles) {
369       gSystem->Unlink(fRawDB->GetName());
370       delete fRawDB;
371       fRawDB = 0;
372       if(!error)
373         return filesize;
374       else
375         return -1;
376    }
377
378    delete fRawDB;
379    fRawDB = 0;
380    if(!error)
381      return filesize;
382    else
383      return -1;
384 }
385
386 //______________________________________________________________________________
387 Int_t AliRawDB::Fill()
388 {
389   // Fill the trees and return the number of written bytes
390
391   // Create raw data TTree if it not yet done
392   if (!fTree) MakeTree();
393
394    Double_t bytes = fRawDB->GetBytesWritten();
395    Bool_t error = kFALSE;
396    if (fTree->Fill() == -1)
397      error = kTRUE;
398    if (fESDTree) 
399      if (fESDTree->Fill() == -1)
400        error = kTRUE;
401    if(!error)
402      return Int_t(fRawDB->GetBytesWritten() - bytes);
403    else
404      return -1;
405 }
406
407 //______________________________________________________________________________
408 Long64_t AliRawDB::GetTotalSize()
409 {
410    // Return the total size of the trees
411   Long64_t total = 0;
412
413   if (fTree) {
414     Int_t skey = 0;
415     TDirectory *dir = fTree->GetDirectory();
416     if (dir) {
417       TKey *key = dir->GetKey(fTree->GetName());
418       if (key) skey = key->GetKeylen();
419     }
420     total += (Long64_t)skey + fTree->GetZipBytes();
421   }
422
423   if(fESDTree)
424     {
425       Int_t skey = 0;
426       TDirectory *dir = fESDTree->GetDirectory();
427       if (dir) {
428         TKey *key = dir->GetKey(fESDTree->GetName());
429         if (key) skey = key->GetKeylen();
430       }
431       total += (Long64_t)skey + fESDTree->GetZipBytes();
432     }
433
434   return total;
435 }
436
437 //______________________________________________________________________________
438 Long64_t AliRawDB::AutoSave()
439 {
440   // Auto-save the raw-data and
441   // esd (if any) trees
442
443   Long64_t nbytes = fTree->AutoSave();
444
445   if (fESDTree) nbytes += fESDTree->AutoSave();
446
447   return nbytes;
448 }
449
450 //______________________________________________________________________________
451 Bool_t AliRawDB::NextFile(const char* fileName)
452 {
453    // Close te current file and open a new one.
454    // Returns kFALSE in case opening failed.
455
456    Close();
457
458    if (!Create(fileName)) return kFALSE;
459    return kTRUE;
460 }
461
462 //______________________________________________________________________________
463 Float_t AliRawDB::GetCompressionFactor() const
464 {
465    // Return compression factor.
466
467    if (fTree->GetZipBytes() == 0.)
468       return 1.0;
469    else
470       return fTree->GetTotBytes()/fTree->GetZipBytes();
471 }
472
473 //______________________________________________________________________________
474 const char *AliRawDB::GetAliRootTag()
475 {
476   // Return the aliroot tag (version)
477   // used to generate the raw data file.
478   // Stored in the raw-data file title.
479
480   static TString version = fgkAliRootTag;
481   version.Remove(TString::kBoth,'$');
482   version.ReplaceAll("Rev","AliRoot version");
483
484   return version.Data();
485 }
486
487 //______________________________________________________________________________
488 Bool_t AliRawDB::WriteGuidFile(TString &guidFileFolder)
489 {
490   // Write the guid file
491   // in the specified folder or
492   // in the folder where the raw data
493   // file is.
494
495    TString guidFileName;
496    if (!guidFileFolder.IsNull()) {
497      guidFileName = guidFileFolder;
498
499      TString pathStr = fRawDB->GetName();
500      TObjArray *pathArr = pathStr.Tokenize('/');
501      guidFileName.Append("/");
502      guidFileName.Append(((TObjString *)pathArr->Last())->String());
503      pathArr->Delete();
504      delete pathArr;
505    }
506    else
507      guidFileName = fRawDB->GetName();
508
509    guidFileName += ".guid";
510
511    ofstream fguid(guidFileName.Data());
512    if (!fguid.is_open()) {
513      Error("WriteGuidFile", "failure to open guid file %s", guidFileName.Data());
514      return kFALSE;
515    }
516    TString guid = fRawDB->GetUUID().AsString();
517    fguid << "guid: \t" << guid.Data();
518    fguid.close();
519
520    return kTRUE;
521 }
522
523
524 //______________________________________________________________________________
525 void AliRawDB::Reset()
526 {
527   // Clear the raw-data arrays
528   // Should be done before processing the raw-data event
529
530   for (Int_t iDet = 0; iDet < (AliDAQ::kNDetectors + 1); iDet++)
531     for (Int_t iBranch = 0; iBranch < fgkDetBranches[iDet]; iBranch++)
532       fDetRawData[iDet][iBranch]->ClearData();
533 }
534
535 //______________________________________________________________________________
536 AliRawDataArrayV2 *AliRawDB::GetRawDataArray(UInt_t eqSize, UInt_t eqId) const
537 {
538   // Return the corresponding raw-datra array (branch)
539   // depending on the equipment ID
540
541   Int_t iDet = AliDAQ::kNDetectors;
542   Int_t iBranch = 0; // can we split somehow the unrecognized data??? For the moment - no
543   if(eqSize) {
544     Int_t ddlIndex = -1;
545     iDet = AliDAQ::DetectorIDFromDdlID(eqId,ddlIndex);
546     if (iDet < 0 || iDet >= AliDAQ::kNDetectors)
547       iDet = AliDAQ::kNDetectors;
548     else
549       iBranch = (ddlIndex * fgkDetBranches[iDet])/AliDAQ::NumberOfDdls(iDet);
550   }
551
552   return fDetRawData[iDet][iBranch];
553 }
554