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