Renaming calibration classes (A.Colla)
[u/mrichter/AliRoot.git] / STEER / AliCDBLocal.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 /////////////////////////////////////////////////////////////////////////////////////////////////
19 //                                                                                             //
20 // access class to a DB file inside an organized directory structure                           //
21 // file name = "DBFolder/detector/dbType/detSpecType/Run#firstRun-#lastRun _v#version.root"    //                                   
22 //                                                                                             //
23 /////////////////////////////////////////////////////////////////////////////////////////////////
24
25
26 #include <TFile.h>
27 #include <TKey.h>
28 #include <TROOT.h>
29 #include <TSystem.h>
30 #include <TObjArray.h>
31 #include <TObjString.h>
32 #include <TRegexp.h>
33
34 #include "AliLog.h"
35 #include "AliCDBLocal.h"
36
37
38 ClassImp(AliCDBLocal)
39
40 //_____________________________________________________________________________
41 AliCDBLocal::AliCDBLocal(const char* DBFolder) :
42   AliCDBStorage(),
43   fDBFolder(DBFolder)
44 {
45 // constructor
46   gSystem->ExpandPathName(fDBFolder);
47   void *dir=0;
48   if(!(dir=gSystem->OpenDirectory(fDBFolder))){
49     AliFatal(Form("Path %s not a directory",fDBFolder.Data()));
50   }
51   gSystem->FreeDirectory(dir);
52  
53   while(fDBFolder.EndsWith("/")) fDBFolder.Remove(fDBFolder.Last('/')); 
54   fDBFolder+="/";
55 }
56
57 //_____________________________________________________________________________
58 AliCDBLocal::~AliCDBLocal()
59 {
60  // destructor
61
62 }
63
64 //_____________________________________________________________________________
65 AliCDBLocal::AliCDBLocal(const AliCDBLocal& /*db*/) :
66   AliCDBStorage(),
67   fDBFolder("")
68 {
69  // copy constructor
70
71  AliFatal("not implemented");
72 }
73
74 //_____________________________________________________________________________
75 AliCDBLocal& AliCDBLocal::operator = (const AliCDBLocal& /*db*/)
76 {
77 // assignment operator
78
79  AliFatal("not implemented");
80  return *this;
81 }
82
83 //_____________________________________________________________________________
84 AliCDBEntry* AliCDBLocal::GetEntry(AliCDBMetaDataSelect& selMetaData, Int_t runNumber)
85 {
86 // get an object from the data base   
87
88  TDirectory* saveDir = gDirectory;
89
90  // Find the right file in the directory
91  TString prefix="_v"; // development mode: fileName=Run#Run1-#Run2_v#Version.root
92  if(fStorageMode==kProduction) prefix="_Prod"; // production mode: fileName=Run#Run1-#Run2_Prod#Version.root             
93
94  TString buffer(fDBFolder);
95  TString name(selMetaData.GetName());
96  buffer+=name; buffer+='/';
97
98  int selVersion = selMetaData.GetVersion();
99
100  void *dir = gSystem->OpenDirectory(buffer);
101  if(!dir) {
102    AliError(Form("Directory %s not found", name.Data()));
103    AliError(Form("in DB folder %s", fDBFolder.Data()));
104    return NULL;
105  }
106
107  TString fileName="";
108  TString levelContent="";
109  int oldVers=-1;
110  // in this array the "numbers" of the retrieved fileName (Run1, Run2, Version) are stored for later usage
111  int fileNumbers[3]={-1,-1,-1}; 
112  while(levelContent=gSystem->GetDirEntry(dir)){ 
113
114    if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
115    if(!levelContent.Contains("Run") || !levelContent.Contains(prefix)) continue;
116          
117    int numbers[3]={-1,-1,-1}; // numbers[0]=firstRun, numbers[1]=lastRun, numbers[2]=Version 
118    // gets the 3 "numbers" in the file name
119    if(!DecodeFileName(levelContent,numbers, prefix)) continue; // wrong run filename format
120    if(numbers[0]>runNumber ||  numbers[1]<runNumber) continue; // data not valid for run number
121
122    if(selVersion == -1) {
123      if(numbers[2] >= oldVers){
124         if(numbers[2] == oldVers){ 
125            // more than one file valid for the run -> error!   
126            AliError(Form("More than one object valid for run %d, version %d!", runNumber, oldVers));
127            AliError(Form("No object will be returned!"));
128            gSystem->FreeDirectory(dir);
129            return NULL;
130         }
131         fileName=levelContent;
132         oldVers=numbers[2];
133         fileNumbers[0]=numbers[0]; fileNumbers[1]=numbers[1]; fileNumbers[2]=numbers[2]; 
134      }
135    } else {
136      if(numbers[2] == selVersion){
137         if(fileName != ""){ 
138            // filename was already assigned, this means there is more than one file valid for the run -> error!   
139            AliError(Form("More than one object valid for run %d, version %d!", runNumber, selVersion));
140            AliError(Form("No object will be returned!"));
141            gSystem->FreeDirectory(dir);
142            return NULL;
143         }
144         fileName=levelContent;
145         fileNumbers[0]=numbers[0]; fileNumbers[1]=numbers[1]; fileNumbers[2]=numbers[2]; 
146      }
147    }   
148
149  } // end loop on runs    
150  
151  gSystem->FreeDirectory(dir);
152  buffer+=fileName;
153  if(!buffer.EndsWith(".root")){
154     AliError(Form("No DB file matching criteria found!"));
155     return NULL;    
156  }
157  
158  TFile *DBFile = new TFile(buffer.Data(),"READ");
159  if(!DBFile || !DBFile->IsOpen()) {
160     AliError(Form("could not open file %s", buffer.Data()));
161     return NULL;
162  }
163  
164  AliInfo(Form("File %s succesfully opened", buffer.Data()));
165    
166 // get the only AliCDBEntry object from the file
167 // I assume that the object in the file is a AliCDBEntry entry with
168 // name="detSpecType" (set in CDBMetaDataSelect)
169
170  DBFile->cd();
171
172  AliCDBEntry *entry = (AliCDBEntry*) DBFile->Get(selMetaData.GetDetSpecType());
173  
174  if(!entry || !entry->InheritsFrom(AliCDBEntry::Class())) {
175    AliError(Form("No entry named %s found!",selMetaData.GetDetSpecType())); 
176    DBFile->Close(); delete DBFile; DBFile=0; 
177    if (saveDir) saveDir->cd(); else gROOT->cd();
178    return NULL;
179  }
180   
181 // Version 1:
182 // set the run range and version got from the filename 
183 // to the object's metadata!  
184   
185 // entry->SetRunRange(fileNumbers[0],fileNumbers[1]);
186 // entry->SetVersion(fileNumbers[2]);
187
188 // Version 2: The object's metadata are not reset during storage
189 // If object's metadata runRange or version do not match with filename,
190 // it means that someone renamed file by hand. In this case a warning msg is issued.
191  Int_t objFirstRun=(entry->GetCDBMetaData()).GetFirstRun();
192  Int_t objLastRun=(entry->GetCDBMetaData()).GetLastRun();
193  Int_t objVersion=(entry->GetCDBMetaData()).GetVersion();
194  
195  if(objFirstRun != fileNumbers[0] || objLastRun != fileNumbers[1] || objVersion != fileNumbers[2]){
196     AliWarning(Form("Either RunRange or Version in the object's metadata do noth match with fileName numbers:"));
197     AliWarning(Form("someone renamed file by hand!"));
198  }
199
200 // close file, return retieved entry
201
202  DBFile->Close(); delete DBFile; DBFile=0;
203  if (saveDir) saveDir->cd(); else gROOT->cd();
204    
205 //  if(selMetaData.GetVersion() > -1 && fileNumbers[2] != selMetaData.GetVersion()) 
206 //      AliWarning(Form("Warning: selected version (%d) not found, got version %d instead",
207 //             selMetaData.GetVersion(),fileNumbers[2]));
208
209  return entry;
210   
211 }
212
213
214 //_____________________________________________________________________________
215 Bool_t AliCDBLocal::PutEntry(AliCDBEntry* entry)
216 {
217 // puts an object into the database
218
219 // AliCDBEntry entry is composed by the object and its MetaData
220 // this method takes the metaData, reads the name, runRange and Version
221 // creates the directory structure and the file name
222 // looks for runs with same or overlapping runrange, if exist increment version
223 // (therefore version should not be put in the metadata)
224 // if the runrange is different (but overlapping) from a preceding version, a warning message
225 // is issued. 
226 // sets the runrange and version in the object metadata = -1 (to avoid inconsistencies)
227 // open the filem, write the entry in the file.
228 // Note: the key name of the entry is "detSpecType"
229 // return result 
230    
231  if(!entry) return kFALSE;
232  TDirectory* saveDir = gDirectory;
233   
234  Int_t firstRun=entry->GetCDBMetaData().GetFirstRun();
235  Int_t lastRun=entry->GetCDBMetaData().GetLastRun();
236  if(firstRun<0 || lastRun<0 || lastRun<firstRun) {
237     AliError(Form("Run range not set or not valid: %d - %d !", firstRun, lastRun));
238     return kFALSE;
239  }
240
241  TString name(entry->GetName()); 
242  
243  
244  TString detSpecType(name(name.Last('/')+1, name.Length()-name.Last('/')));
245  TString buffer(fDBFolder);
246  
247  void *dir=0;
248  Int_t index = -1;
249  name+='/'; // name=detector/dbType/detSpecType/
250
251  while ((index = name.Index("/")) >= 0) {
252    TString dirName(name(0, index+1));
253    buffer+=dirName;
254    dir=gSystem->OpenDirectory(buffer);
255    if (!dir) {
256      AliWarning(Form("Directory %s does not exist! It will be created...",buffer.Data()));
257      gSystem->mkdir(buffer.Data());
258    }
259    name.Remove(0, index+1);
260    gSystem->FreeDirectory(dir);
261  } 
262  
263  dir = gSystem->OpenDirectory(buffer);
264  TString levelContent="";
265  Int_t maxVersion=-1, run1=-1, run2=-1;
266  int numbers[3]={-1,-1,-1}; // numbers[0]=firstRun, numbers[1]=lastRun, numbers[2]=Version
267  while(levelContent=gSystem->GetDirEntry(dir)){
268    if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
269    if(levelContent.Contains("Run")){
270      if(levelContent.Contains("_Prod")) continue; //skip "Production" links
271      if(!DecodeFileName(levelContent, numbers, "_v")) continue;
272      if((firstRun>=numbers[0] && firstRun<=numbers[1]) ||
273         (lastRun>=numbers[0] && lastRun<=numbers[1]) ||
274         (firstRun<=numbers[0] && lastRun>=numbers[1])) {// overlap!     
275         if(numbers[2]>maxVersion) {
276            maxVersion=numbers[2];
277            run1=numbers[0]; run2=numbers[1];
278         }
279      }
280    }
281  }
282  gSystem->FreeDirectory(dir);
283  
284  if((run1!=-1 && run2!=-1) && (firstRun!=run1 || lastRun!=run2)) 
285     AliWarning(Form("Run range modified w.r.t. preceding version (%d, %d)",run1, run2));
286     
287  TString strfName=EncodeFileName(firstRun, lastRun, maxVersion+1);
288  buffer+=strfName;
289  
290  // opening file
291  TFile *DBFile = new TFile(buffer.Data(),"NEW");
292  if(!DBFile || !DBFile->IsWritable()){
293     AliError(Form("The data base file is not writable. "
294                 "The object %s was not inserted", entry->GetName()));
295     if(!DBFile->IsWritable()) DBFile->Close(); DBFile->Delete(); delete DBFile; DBFile=0;
296     return kFALSE;
297  }
298   
299  DBFile->cd();
300  
301  entry->SetVersion(maxVersion+1);
302  
303  // write object
304  Bool_t result = (entry->Write(detSpecType) != 0); 
305  if (saveDir) saveDir->cd(); else gROOT->cd();
306  DBFile->Close(); DBFile->Delete(); delete DBFile; DBFile=0;
307  if(result) {
308     AliInfo(Form("Run object %s",entry->GetName()));
309     AliInfo(Form("was successfully written into file %s",buffer.Data()));
310  }
311
312  return result;
313
314 }
315
316 /*****************************************************************************/ 
317 TObjArray* AliCDBLocal::FindDBFiles(const char* name, Int_t runNumber){
318 // Find DataBase file name in a local directory. The filename must be in the form: Run#run1-#run2_v#version.root
319 // TRegexp allowed: name can be for example: "detector/*" !!
320
321  TObjArray *FileNameColl=new TObjArray();
322
323  TString prefix="_v"; // development mode: fileName=Run#Run1-#Run2_v#Version.root
324  if(fStorageMode==kProduction) prefix="_Prod"; // production mode: fileName=Run#Run1-#Run2_Prod#Version.root             
325
326  TString buffer(fDBFolder);
327 // gSystem->ExpandPathName(buffer);
328   
329  TString bufftInit=buffer; // buffInit="$ALICE_ROOT/DB/
330  TString levelContent="";
331  
332  AliCDBMetaDataSelect selMetaData(name);
333  
334  TString detector(selMetaData.GetDetector());
335  TString dbType(selMetaData.GetDBType());
336  TString detSpecType(selMetaData.GetDetSpecType());
337  int selVersion = selMetaData.GetVersion();
338
339  void *dirLevInit = gSystem->OpenDirectory(buffer);
340  while(levelContent=gSystem->GetDirEntry(dirLevInit)){ // lev0! In detector directory (ZDC, TPC...)!!
341
342    if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
343    if(!(detector=="*") && !levelContent.Contains(TRegexp(detector)) ) continue;
344
345    buffer=bufftInit+levelContent; buffer+='/'; // buffer="$ALICE_ROOT/DB/detector/
346    TString bufft0=buffer; // bufft0="$ALICE_ROOT/DB/detector/
347
348    void *dirLev0 = gSystem->OpenDirectory(buffer);
349    while(levelContent=gSystem->GetDirEntry(dirLev0)){ // lev1! dbType directory (Calib, Align)!!
350
351      if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
352      if(!(dbType=="*") && !levelContent.Contains(TRegexp(dbType))) continue; 
353
354      buffer=bufft0+levelContent;buffer+='/'; // buffer="$ALICE_ROOT/DB/detector/dbType/
355      TString bufft1=buffer; // bufft1="$ALICE_ROOT/DB/detector/dbType/
356
357      void *dirLev1 = gSystem->OpenDirectory(buffer);
358      while(levelContent=gSystem->GetDirEntry(dirLev1)){ // lev2! detSpecType directory (Pedestals, gain....)!!
359
360        if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
361        if(!(detSpecType=="*") && !levelContent.Contains(TRegexp(detSpecType))) continue; 
362
363        buffer=bufft1+levelContent;buffer+='/'; // buffer="$ALICE_ROOT/DB/detector/dbType/detSpecType/
364        TString bufft2=buffer; // bufft2="$ALICE_ROOT/DB/detector/dbType/detSpecType/
365
366        void *dirLev2 = gSystem->OpenDirectory(buffer);
367        TObjString *str=0;
368        while(levelContent=gSystem->GetDirEntry(dirLev2)){ // lev3! Run directory (Run#XXX-#YYY_v#ZZ.root)!!
369
370          if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
371          if(!levelContent.BeginsWith("Run")) continue;
372          if(!levelContent.Contains(prefix)) continue;
373                  
374          int numbers[3]={-1,-1,-1}; // numbers[0]=firstRun, numbers[1]=lastRun, numbers[2]=Version 
375          if(!DecodeFileName(levelContent,numbers, prefix)) continue; // wrong run filename format!
376          if(numbers[0]>runNumber ||  numbers[1]<runNumber) continue; // data not valid for run number
377
378          if(numbers[2]==selVersion) {
379             buffer=bufft2+levelContent;
380             str=new TObjString(buffer.Data());
381             FileNameColl->Add(str);
382             break;
383          }
384          if(selVersion == -1) { // if version is not specified, collect all versions
385             buffer=bufft2+levelContent;
386             str=new TObjString(buffer.Data());
387             FileNameColl->Add(str);
388            }
389          } // end loop on runs       
390        } // end loop in lev1
391      } // end loop in lev0
392    } // end loop in levInit
393
394  AliInfo(Form("Found %d entries matching requirements", FileNameColl->GetEntriesFast()));
395  ToAliInfo(FileNameColl->ls());
396  return FileNameColl;
397 }
398
399 //_____________________________________________________________________________
400 void AliCDBLocal::TagForProduction(const AliCDBMetaDataSelect& selMetaData, UInt_t prodVers){
401
402 TString workingDir=gSystem->pwd();
403 //Build the file path 
404 TString buffer(fDBFolder); //gSystem->ExpandPathName() already done in ctor
405 TString fName="";
406
407 buffer+=selMetaData.GetName(); buffer+='/';
408 //gSystem->ExpandPathName(dirName);
409
410 if(!gSystem->cd(buffer))
411    {AliError(Form("Directory %s does not exist... check name!", buffer.Data())); gSystem->cd(workingDir.Data()); return;}
412
413 // if version is not specified (=-1), then tag the highest version (BE CAREFUL!!)
414 if(selMetaData.GetVersion() != -1){  
415   //Build the filename
416    fName = EncodeFileName(selMetaData.GetFirstRun(), selMetaData.GetLastRun(), selMetaData.GetVersion());
417 } else {
418    //look in directory for valid DB files, seek highest version
419    void *dir = gSystem->OpenDirectory(buffer);
420    TString levelContent="";
421    int oldVers=-1;
422    while(levelContent=gSystem->GetDirEntry(dir)){ 
423
424       if(levelContent=="." || levelContent=="..") continue; if(levelContent=="") break;
425       if(!levelContent.Contains("Run") || !levelContent.Contains("_v")) continue;
426          
427       int numbers[3]={-1,-1,-1}; // numbers[0]=firstRun, numbers[1]=lastRun, numbers[2]=Version 
428       // gets the 3 "numbers" in the file name
429       if(!DecodeFileName(levelContent,numbers, "_v")) continue; // wrong run filename format!
430       if(numbers[0] != selMetaData.GetFirstRun() ||  numbers[1] != selMetaData.GetLastRun()) continue;
431       if(numbers[2] >= oldVers) {
432          fName=levelContent;
433          oldVers=numbers[2];
434       }   
435    } // end loop on runs    
436 }
437
438    //check that the flename exists
439 if(!gSystem->IsFileInIncludePath(fName.Data())){
440       AliError(Form("File name %s not found... check!", fName.Data())); 
441       gSystem->cd(workingDir.Data()); 
442       return;
443 }
444
445 // file exists: make symbolic link! 
446 TString prodfName=EncodeFileName(selMetaData.GetFirstRun(), selMetaData.GetLastRun(), prodVers, "_Prod");
447 if(gSystem->Symlink(fName.Data(),prodfName.Data())<0){
448     AliError(Form("Link name already existing (%s): linkage failed!",prodfName.Data()));
449 } else {
450     AliError(Form("File %s tagged for production with symlink %s",fName.Data(), prodfName.Data()));
451 }
452
453 gSystem->cd(workingDir);
454 return; 
455
456 }
457
458 //_____________________________________________________________________________
459 Bool_t AliCDBLocal::DecodeFileName(const TString strName, int *numArray, TString prefix)
460 {
461 // Gets the numbers (#Run1, #Run2, #Version) 
462 // from the filename: Run#Run1-#Run2_v#Version.root or  Run#Run1-#Run2_Prod#prodVers.root 
463
464  int indexMinus=strName.Last('-');
465  int indexUScore=strName.Last('_');
466  int indexPoint=strName.Last('.');
467  
468  int nSkipChar=prefix.Length(); // prefix can be either "_v" or "_Prod" depending on fStorageMode 
469  //if(prefix=="_v") {nSkipChar=2;} // development mode: _v# skip 2 characters
470  //else if(prefix=="_Prod") {nSkipChar=5;} // production mode: _Prod# skip 5 characters
471
472  if(indexUScore<0 || indexPoint<0 )
473     {AliDebug(2, Form("Check sintax %s",strName.Data())); return kFALSE;}
474
475  if(indexMinus<0){ // only 1 Run number!
476    TString cRun=strName(3,indexUScore-3);
477    if(!(cRun.IsDigit()))
478       {AliDebug(2, Form("%s not a digit! Check sintax %s",cRun.Data(),strName.Data())); return kFALSE;}
479    numArray[0] = (int) strtol(cRun.Data(),0,10);
480    numArray[1] = numArray[0];
481  }else{
482    TString cFirstRun = strName(3,indexMinus-3);  
483    TString cLastRun = strName(indexMinus+1,indexUScore-(indexMinus+1));  
484    if(!(cFirstRun.IsDigit()) || !(cLastRun.IsDigit()))
485       {AliDebug(2, Form("%s or %s are not digit! Check sintax %s",
486          cFirstRun.Data(), cLastRun.Data(), strName.Data())); return kFALSE;}
487    numArray[0] = (int) strtol(cFirstRun.Data(),0,10);
488    numArray[1] = (int) strtol(cLastRun.Data(),0,10);
489  }
490 // TString cVersion = strName(indexUScore+2,indexPoint-(indexUScore+2));
491  TString cVersion = strName(indexUScore+nSkipChar,indexPoint-(indexUScore+nSkipChar));
492  if(!(cVersion.IsDigit())){
493    AliDebug(2, Form("%s not a digit! Check sintax %s",cVersion.Data(),strName.Data())); return kFALSE;}
494  numArray[2] = (int) strtol(cVersion.Data(),0,10);
495
496  return kTRUE;
497 }
498
499
500 //_____________________________________________________________________________
501 TString AliCDBLocal::EncodeFileName(int firstRun, int lastRun, int version, TString prefix){
502 // Builds a file name of the form: Run#firstRun-#lastRun_v#Version.root
503
504 TString fName="Run"; 
505 if(firstRun==lastRun) {
506    fName+=firstRun;
507 }else{
508    fName+=firstRun; fName+="-"; fName+=lastRun;
509 }
510 fName+=prefix; fName+=version; fName+=".root";
511
512 return fName;
513 }