]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliRawDB.cxx
Correct tree size in case of compressed raw data (Fons)
[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
28 #if ROOT_VERSION_CODE >= ROOT_VERSION(5,15,0)
29 #include <TBufferFile.h>
30 #else
31 #include <TBuffer.h>
32 #endif
33
34 #include <TSystem.h>
35 #include <TKey.h>
36
37 #include <TObjString.h>
38
39 #include "AliESD.h"
40 #include "AliRawEvent.h"
41 #include "AliRawDataArray.h"
42 #include "AliRawEventHeaderBase.h"
43 #include "AliRawEquipment.h"
44 #include "AliRawEquipmentHeader.h"
45 #include "AliStats.h"
46
47 #include "AliRawDB.h"
48
49
50 ClassImp(AliRawDB)
51
52 const char *AliRawDB::fgkAliRootTag = "$Name$";
53
54 //______________________________________________________________________________
55 AliRawDB::AliRawDB(AliRawEvent *event,
56                    AliESD *esd, 
57                    Int_t compress,
58                    const char* fileName) :
59   fRawDB(NULL),
60   fTree(NULL),
61   fEvent(event),
62   fESDTree(NULL),
63   fESD(esd),
64   fCompress(compress),
65   fMaxSize(-1),
66   fFS1(""),
67   fFS2(""),
68   fDeleteFiles(kFALSE),
69   fStop(kFALSE),
70   fGuidFileFolder(NULL)
71 {
72    // Create a new raw DB
73
74   for (Int_t iDet = 0; iDet < AliDAQ::kNDetectors; iDet++)
75     fDetRawData[iDet] = new AliRawDataArray(AliDAQ::NumberOfDdls(iDet));
76
77   fDetRawData[AliDAQ::kNDetectors] = new AliRawDataArray(100);
78
79    if (fileName) {
80       if (!Create(fileName))
81          MakeZombie();
82    }
83 }
84
85
86 //______________________________________________________________________________
87 AliRawDB::~AliRawDB() {
88   // Destructor
89
90   if(Close()==-1) Error("~AliRawDB", "cannot close output file!");
91
92   for (Int_t iDet = 0; iDet < (AliDAQ::kNDetectors + 1); iDet++)
93     delete fDetRawData[iDet];
94 }
95
96 //______________________________________________________________________________
97 Bool_t AliRawDB::FSHasSpace(const char *fs) const
98 {
99    // Check for at least fMaxSize bytes of free space on the file system.
100    // If the space is not available return kFALSE, kTRUE otherwise.
101
102    Long_t id, bsize, blocks, bfree;
103
104    if (gSystem->GetFsInfo(fs, &id, &bsize, &blocks, &bfree) == 1) {
105       Error("FSHasSpace", "could not stat file system %s", fs);
106       return kFALSE;
107    }
108
109    // Leave 5 percent of diskspace free
110    Double_t avail = Double_t(bfree) * 0.95;
111    if (avail*bsize > fMaxSize)
112       return kTRUE;
113
114    Warning("FSHasSpace", "no space on file system %s", fs);
115    return kFALSE;
116 }
117
118 //______________________________________________________________________________
119 const char *AliRawDB::GetFileName() const
120 {
121    // Return filename based on hostname and date and time. This will make
122    // each file unique. Also makes sure (via FSHasSpace()) that there is
123    // enough space on the file system to store the file. Returns 0 in
124    // case of error or interrupt signal.
125
126    static TString fname;
127    static Bool_t  fstoggle = kFALSE;
128
129    TString fs = fstoggle ? fFS2 : fFS1;
130    TDatime dt;
131
132    TString hostname = gSystem->HostName();
133    Int_t pos;
134    if ((pos = hostname.Index(".")) != kNPOS)
135       hostname.Remove(pos);
136
137    if (!FSHasSpace(fs)) {
138       while (1) {
139          fstoggle = !fstoggle;
140          fs = fstoggle ? fFS2 : fFS1;
141          if (FSHasSpace(fs)) break;
142          Info("GetFileName", "sleeping 30 seconds before retrying...");
143          gSystem->Sleep(30000);   // sleep for 30 seconds
144          if (fStop) return 0;
145       }
146    }
147
148    fname = fs + "/" + hostname + "_";
149    fname += dt.GetDate();
150    fname += "_";
151    fname += dt.GetTime();
152    fname += ".root";
153
154    fstoggle = !fstoggle;
155
156    return fname;
157 }
158
159 //______________________________________________________________________________
160 void AliRawDB::SetFS(const char* fs1, const char* fs2)
161 {
162 // set the file system location
163
164   fFS1 = fs1;
165   if (fs1 && !fFS1.Contains(":")) {
166     gSystem->ResetErrno();
167     gSystem->MakeDirectory(fs1);
168     if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
169       SysError("SetFS", "mkdir %s", fs1);
170     }
171   }
172
173   fFS2 = fs2;
174   if (fs2) {
175     gSystem->ResetErrno();
176     gSystem->MakeDirectory(fs2);
177     if (gSystem->GetErrno() && gSystem->GetErrno() != EEXIST) {
178       SysError("SetFS", "mkdir %s", fs2);
179     }
180   }
181 }
182
183 //______________________________________________________________________________
184 Bool_t AliRawDB::Create(const char* fileName)
185 {
186    // Create a new raw DB.
187
188    const Int_t kMaxRetry = 1;
189    const Int_t kMaxSleep = 1;      // seconds
190    const Int_t kMaxSleepLong = 10; // seconds
191    Int_t retry = 0;
192
193 again:
194    if (fStop) return kFALSE;
195
196    const char *fname = fileName;
197    if (!fname) fname = GetFileName();
198    if (!fname) {
199       Error("Create", "error getting raw DB file name");
200       return kFALSE;
201    }
202
203    retry++;
204
205    fRawDB = TFile::Open(fname, GetOpenOption(),
206                         Form("ALICE raw-data file (%s)", GetAliRootTag()), fCompress,
207                         GetNetopt());
208    if (!fRawDB) {
209       if (retry < kMaxRetry) {
210          Warning("Create", "failure to open file, sleeping %d %s before retrying...",
211                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
212          gSystem->Sleep(kMaxSleep*1000);
213          goto again;
214       }
215       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
216       return kFALSE;
217    }
218    if (retry > 1)
219       Warning("Create", "succeeded to open file after %d retries", retry);
220
221    if (fRawDB->IsZombie()) {
222       if (fRawDB->GetErrno() == ENOSPC ||
223           fRawDB->GetErrno() == 1018   ||   // SECOMERR
224           fRawDB->GetErrno() == 1027) {     // SESYSERR
225          fRawDB->ResetErrno();
226          delete fRawDB;
227          Warning("Create", "file is a zombie (no space), sleeping %d %s before retrying...",
228                  kMaxSleepLong, kMaxSleepLong==1 ? "second" : "seconds");
229          gSystem->Sleep(kMaxSleepLong*1000);   // sleep 10 seconds before retrying
230          goto again;
231       }
232       Error("Create", "file %s is zombie", fname);
233       fRawDB->ResetErrno();
234       delete fRawDB;
235       fRawDB = 0;
236       if (retry < kMaxRetry) {
237          Warning("Create", "file is a zombie, sleeping %d %s before retrying...",
238                  kMaxSleep, kMaxSleep==1 ? "second" : "seconds");
239          gSystem->Sleep(kMaxSleep*1000);
240          goto again;
241       }
242       Error("Create", "failure to open file %s after %d tries", fname, kMaxRetry);
243       return kFALSE;
244    }
245
246    // Create raw data TTree
247    MakeTree();
248
249    return kTRUE;
250 }
251
252 //______________________________________________________________________________
253 void AliRawDB::MakeTree()
254 {
255    // Create ROOT Tree object container.
256
257    fTree = new TTree("RAW", Form("ALICE raw-data tree (%s)", GetAliRootTag()));
258    fTree->SetAutoSave(2000000000);  // autosave when 2 Gbyte written
259
260    fTree->BranchRef();
261
262    Int_t bufsize = 256000;
263    // splitting 29.6 MB/s, no splitting 35.3 MB/s on P4 2GHz 15k SCSI
264    //Int_t split   = 1;
265    Int_t split   = 0;
266    fTree->Branch("rawevent", "AliRawEvent", &fEvent, bufsize, split);
267
268    // Make brach for each sub-detector
269    for (Int_t iDet = 0; iDet < AliDAQ::kNDetectors; iDet++) {
270      fTree->Branch(AliDAQ::DetectorName(iDet),"AliRawDataArray",
271                    &fDetRawData[iDet],bufsize,split);
272    }
273    // Make special branch for unrecognized raw-data payloads
274    fTree->Branch("Common","AliRawDataArray",
275                    &fDetRawData[AliDAQ::kNDetectors],bufsize,split);
276
277    // Create tree which will contain the HLT ESD information
278
279    if (fESD) {
280      fESDTree = new TTree("esdTree", Form("ALICE HLT ESD tree (%s)", GetAliRootTag()));
281      fESDTree->SetAutoSave(2000000000);  // autosave when 2 Gbyte written
282      split   = 0;
283      fESDTree->Branch("ESD", "AliESD", &fESD, bufsize, split);
284    }
285
286 }
287
288 //______________________________________________________________________________
289 Int_t AliRawDB::Close()
290 {
291    // Close raw DB.
292    if (!fRawDB) return 0;
293
294    if (!fRawDB->IsOpen()) return 0;
295
296    fRawDB->cd();
297
298    // Write the tree.
299    Bool_t error = kFALSE;
300    if (fTree->Write() == 0)
301      error = kTRUE;
302    if (fESDTree)
303      if (fESDTree->Write() == 0)
304        error = kTRUE;
305
306    // Close DB, this also deletes the fTree
307    fRawDB->Close();
308
309    Int_t filesize = fRawDB->GetEND();
310
311    if (fDeleteFiles) {
312       gSystem->Unlink(fRawDB->GetName());
313       delete fRawDB;
314       fRawDB = 0;
315       if(!error)
316         return filesize;
317       else
318         return -1;
319    }
320
321    // Write a text file with file GUID
322    // in the specified folder
323    WriteGuidFile();
324
325    delete fRawDB;
326    fRawDB = 0;
327    if(!error)
328      return filesize;
329    else
330      return -1;
331 }
332
333 //______________________________________________________________________________
334 Int_t AliRawDB::Fill()
335 {
336    // Fill the trees and return the number of written bytes
337
338   for (Int_t iDet = 0; iDet < (AliDAQ::kNDetectors + 1); iDet++)
339     fDetRawData[iDet]->ClearData();
340
341    // Move the raw-data payloads to the corresponding branches
342   for(Int_t iSubEvent = 0; iSubEvent < fEvent->GetNSubEvents(); iSubEvent++) {
343     AliRawEvent *subEvent = fEvent->GetSubEvent(iSubEvent);
344     for(Int_t iEquipment = 0; iEquipment < subEvent->GetNEquipments(); iEquipment++) {
345       AliRawEquipment *equipment = subEvent->GetEquipment(iEquipment);
346       UInt_t eqId = equipment->GetEquipmentHeader()->GetId();
347       Int_t ddlIndex;
348       Int_t iDet = AliDAQ::DetectorIDFromDdlID(eqId,ddlIndex);
349       if (iDet < 0 || iDet > AliDAQ::kNDetectors)
350         iDet = AliDAQ::kNDetectors;
351       equipment->SetRawDataRef(fDetRawData[iDet]);
352     }
353   }
354
355    Double_t bytes = fRawDB->GetBytesWritten();
356    Bool_t error = kFALSE;
357    if (fTree->Fill() == -1)
358      error = kTRUE;
359    if (fESDTree) 
360      if (fESDTree->Fill() == -1)
361        error = kTRUE;
362    if(!error)
363      return Int_t(fRawDB->GetBytesWritten() - bytes);
364    else
365      return -1;
366 }
367
368 //______________________________________________________________________________
369 Int_t AliRawDB::GetTotalSize()
370 {
371    // Return the total size of the trees
372   Int_t total = 0;
373
374   {
375     Int_t skey = 0;
376     TDirectory *dir = fTree->GetDirectory();
377     if (dir) {
378       TKey *key = dir->GetKey(fTree->GetName());
379       if (key) skey = key->GetKeylen();
380     }
381     total += skey + fTree->GetZipBytes();
382   }
383
384   if(fESDTree)
385     {
386       Int_t skey = 0;
387       TDirectory *dir = fESDTree->GetDirectory();
388       if (dir) {
389         TKey *key = dir->GetKey(fESDTree->GetName());
390         if (key) skey = key->GetKeylen();
391       }
392       total += skey + fESDTree->GetZipBytes();
393     }
394
395   return total;
396 }
397
398 //______________________________________________________________________________
399 void AliRawDB::WriteStats(AliStats* stats)
400 {
401    // Write stats to raw DB, local run DB and global MySQL DB.
402
403    AliRawEventHeaderBase &header = *GetEvent()->GetHeader();
404
405    // Write stats into RawDB
406    TDirectory *ds = gDirectory;
407    GetDB()->cd();
408    stats->SetEvents(GetEvents());
409    stats->SetLastId(header.GetP("Id")[0]);
410    stats->SetFileSize(GetBytesWritten());
411    stats->SetCompressionFactor(GetCompressionFactor());
412    stats->SetEndTime();
413    stats->Write("stats");
414    ds->cd();
415 }
416
417 //______________________________________________________________________________
418 Bool_t AliRawDB::NextFile(const char* fileName)
419 {
420    // Close te current file and open a new one.
421    // Returns kFALSE in case opening failed.
422
423    Close();
424
425    if (!Create(fileName)) return kFALSE;
426    return kTRUE;
427 }
428
429 //______________________________________________________________________________
430 Float_t AliRawDB::GetCompressionFactor() const
431 {
432    // Return compression factor.
433
434    if (fTree->GetZipBytes() == 0.)
435       return 1.0;
436    else
437       return fTree->GetTotBytes()/fTree->GetZipBytes();
438 }
439
440 //______________________________________________________________________________
441 const char *AliRawDB::GetAliRootTag()
442 {
443   // Return the aliroot tag (version)
444   // used to generate the raw data file.
445   // Stored in the raw-data file title.
446
447   TString version = fgkAliRootTag;
448   version.Remove(TString::kBoth,'$');
449   version.ReplaceAll("Name","AliRoot version");
450
451   return version.Data();
452 }
453
454 //______________________________________________________________________________
455 void AliRawDB::WriteGuidFile()
456 {
457   // Write the guid file
458   // in the specified folder
459
460    TString guidFileName;
461    if (fGuidFileFolder) {
462      guidFileName = fGuidFileFolder;
463
464      TString pathStr = fRawDB->GetName();
465      TObjArray *pathArr = pathStr.Tokenize('/');
466      guidFileName.Append("/");
467      guidFileName.Append(((TObjString *)pathArr->Last())->String());
468      pathArr->Delete();
469      delete pathArr;
470    }
471    else
472      guidFileName = fRawDB->GetName();
473
474    guidFileName += ".guid";
475
476    ofstream fguid(guidFileName.Data());
477    TString guid = fRawDB->GetUUID().AsString();
478    fguid << "guid: \t" << guid.Data();
479    fguid.close();
480 }