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