#include <fstream>
#include "AliCDBManager.h"
#include "AliCDBStorage.h"
#include "AliLog.h"
#include "AliCDBDump.h"
#include "AliCDBLocal.h"
#include "AliCDBGrid.h"
#include "AliCDBEntry.h"
#include "AliCDBHandler.h"
#include <TObjString.h>
#include <TSAXParser.h>
#include <TFile.h>
#include <TKey.h>
#include <TUUID.h>
#include <TGrid.h>
#include "TMessage.h"
#include "TObject.h"
#include "TRegexp.h"
ClassImp(AliCDBParam)
ClassImp(AliCDBManager)
TString AliCDBManager::fgkCondUri("alien://folder=/alice/cern.ch/user/a/aliprod/testCDB/CDB?user=aliprod");
TString AliCDBManager::fgkRefUri("alien://folder=/alice/cern.ch/user/a/aliprod/testCDB/Reference?user=aliprod");
TString AliCDBManager::fgkMCIdealStorage("alien://folder=/alice/simulation/2008/v4-15-Release/Ideal");
TString AliCDBManager::fgkMCFullStorage("alien://folder=/alice/simulation/2008/v4-15-Release/Full");
TString AliCDBManager::fgkMCResidualStorage("alien://folder=/alice/simulation/2008/v4-15-Release/Residual");
TString AliCDBManager::fgkOCDBFolderXMLfile("alien:///alice/data/OCDBFoldervsRunRange.xml");
AliCDBManager* AliCDBManager::fgInstance = 0x0;
AliCDBManager* AliCDBManager::Instance(TMap *entryCache, Int_t run) {
if (!fgInstance) {
fgInstance = new AliCDBManager();
if (!entryCache)
fgInstance->Init();
else
fgInstance->InitFromCache(entryCache,run);
}
return fgInstance;
}
void AliCDBManager::Init() {
RegisterFactory(new AliCDBDumpFactory());
RegisterFactory(new AliCDBLocalFactory());
if(!gSystem->Exec("root-config --has-alien 2>/dev/null |grep yes 2>&1 > /dev/null")){
AliInfo("AliEn classes enabled in Root. AliCDBGrid factory registered.");
RegisterFactory(new AliCDBGridFactory());
fCondParam = CreateParameter(fgkCondUri);
fRefParam = CreateParameter(fgkRefUri);
}
InitShortLived();
}
void AliCDBManager::InitFromCache(TMap *entryCache, Int_t run) {
SetRun(run);
TIter iter(entryCache->GetTable());
TPair* pair = 0;
while((pair = dynamic_cast<TPair*> (iter.Next()))){
fEntryCache.Add(pair->Key(),pair->Value());
}
fEntryCache.SetOwnerKeyValue(kTRUE,kTRUE);
entryCache->SetOwnerKeyValue(kFALSE,kFALSE);
AliInfo(Form("%d cache entries have been loaded",fEntryCache.GetEntries()));
}
void AliCDBManager::DumpToSnapshotFile(const char* snapshotFileName, Bool_t singleKeys) const {
TFile *f = TFile::Open(snapshotFileName,"RECREATE");
if (!f || f->IsZombie()){
AliError(Form("Cannot open file %s",snapshotFileName));
return;
}
AliInfo(Form("Dumping entriesMap (entries'cache) with %d entries!\n", fEntryCache.GetEntries()));
AliInfo(Form("Dumping entriesList with %d entries!\n", fIds->GetEntries()));
f->cd();
if(singleKeys){
f->WriteObject(&fEntryCache,"CDBentriesMap");
f->WriteObject(fIds,"CDBidsList");
}else{
TIter iter(fEntryCache.GetTable());
TPair* pair = 0;
while((pair = dynamic_cast<TPair*> (iter.Next()))){
TObjString *os = dynamic_cast<TObjString*>(pair->Key());
if (!os) continue;
TString path = os->GetString();
AliCDBEntry *entry = dynamic_cast<AliCDBEntry*>(pair->Value());
if (!entry) continue;
path.ReplaceAll("/","*");
entry->Write(path.Data());
}
}
f->Close();
delete f;
}
void AliCDBManager::DumpToLightSnapshotFile(const char* lightSnapshotFileName) const {
TFile *f = TFile::Open(lightSnapshotFileName,"RECREATE");
if (!f || f->IsZombie()){
AliError(Form("Cannot open file %s",lightSnapshotFileName));
return;
}
AliInfo(Form("Dumping map of storages with %d entries!\n", fStorageMap->GetEntries()));
AliInfo(Form("Dumping entriesList with %d entries!\n", fIds->GetEntries()));
f->WriteObject(fStorageMap,"cdbStoragesMap");
f->WriteObject(fIds,"CDBidsList");
f->Close();
delete f;
}
Bool_t AliCDBManager::InitFromSnapshot(const char* snapshotFileName, Bool_t overwrite){
if(fLock) {
AliError("Being locked I cannot initialize from the snapshot!");
return kFALSE;
}
TString snapshotFile(snapshotFileName);
if(snapshotFile.BeginsWith("alien://")){
if(!gGrid) {
TGrid::Connect("alien://","");
if(!gGrid) {
AliError("Connection to alien failed!");
return kFALSE;
}
}
}
TFile *f = TFile::Open(snapshotFileName);
if (!f || f->IsZombie()){
AliError(Form("Cannot open file %s",snapshotFileName));
return kFALSE;
}
TMap *entriesMap = 0;
TIter next(f->GetListOfKeys());
TKey *key;
while ((key = (TKey*)next())) {
if (strcmp(key->GetClassName(),"TMap") != 0) continue;
entriesMap = (TMap*)key->ReadObj();
break;
}
if (!entriesMap || entriesMap->GetEntries()==0){
AliError("Cannot get valid map of CDB entries from snapshot file");
return kFALSE;
}
TList *idsList = 0;
TIter nextKey(f->GetListOfKeys());
TKey *keyN;
while ((keyN = (TKey*)nextKey())) {
if (strcmp(keyN->GetClassName(),"TList") != 0) continue;
idsList = (TList*)keyN->ReadObj();
break;
}
if (!idsList || idsList->GetEntries()==0){
AliError("Cannot get valid list of CDB entries from snapshot file");
return kFALSE;
}
TIter iterObj(entriesMap->GetTable());
TPair* pair = 0;
Int_t nAdded=0;
while((pair = dynamic_cast<TPair*> (iterObj.Next()))){
TObjString* os = (TObjString*) pair->Key();
TString path = os->GetString();
TIter iterId(idsList);
AliCDBId* id=0;
AliCDBId* correspondingId=0;
while((id = dynamic_cast<AliCDBId*> (iterId.Next()))){
TString idpath(id->GetPath());
if(idpath==path){
correspondingId=id;
break;
}
}
if(!correspondingId){
AliError(Form("id for \"%s\" not found in the snapshot (while entry was). This entry is skipped!",path.Data()));
break;
}
Bool_t cached = fEntryCache.Contains(path.Data());
Bool_t registeredId = kFALSE;
TIter iter(fIds);
AliCDBId *idT = 0;
while((idT = dynamic_cast<AliCDBId*> (iter.Next()))){
if(idT->GetPath()==path){
registeredId = kTRUE;
break;
}
}
if(overwrite){
if(cached || registeredId){
AliWarning(Form("An entry was already cached for \"%s\". Removing it before caching from snapshot",path.Data()));
UnloadFromCache(path.Data());
}
fEntryCache.Add(pair->Key(),pair->Value());
fIds->Add(id);
nAdded++;
}else{
if(cached || registeredId){
AliWarning(Form("An entry was already cached for \"%s\". Not adding this object from snapshot",path.Data()));
}else{
fEntryCache.Add(pair->Key(),pair->Value());
fIds->Add(id);
nAdded++;
}
}
}
fEntryCache.SetOwnerKeyValue(kTRUE,kTRUE);
entriesMap->SetOwnerKeyValue(kFALSE,kFALSE);
fIds->SetOwner(kTRUE);
idsList->SetOwner(kFALSE);
AliInfo(Form("%d new (entry,id) cached. Total number %d",nAdded,fEntryCache.GetEntries()));
f->Close();
delete f;
return kTRUE;
}
void AliCDBManager::Destroy() {
if (fgInstance) {
delete fgInstance;
fgInstance = 0x0;
}
}
AliCDBManager::AliCDBManager():
TObject(),
fFactories(),
fActiveStorages(),
fSpecificStorages(),
fEntryCache(),
fIds(0),
fStorageMap(0),
fShortLived(0),
fDefaultStorage(NULL),
fDrainStorage(NULL),
fCondParam(0),
fRefParam(0),
fRun(-1),
fCache(kTRUE),
fLock(kFALSE),
fSnapshotMode(kFALSE),
fSnapshotFile(0),
fOCDBUploadMode(kFALSE),
fRaw(kFALSE),
fCvmfsOcdb(""),
fStartRunLHCPeriod(-1),
fEndRunLHCPeriod(-1),
fLHCPeriod(""),
fKey(0)
{
fFactories.SetOwner(1);
fActiveStorages.SetOwner(1);
fSpecificStorages.SetOwner(1);
fEntryCache.SetName("CDBEntryCache");
fEntryCache.SetOwnerKeyValue(kTRUE,kTRUE);
fStorageMap = new TMap();
fStorageMap->SetOwner(1);
fIds = new TList();
fIds->SetOwner(1);
}
AliCDBManager::~AliCDBManager() {
ClearCache();
DestroyActiveStorages();
fFactories.Delete();
fDrainStorage = 0x0;
fDefaultStorage = 0x0;
delete fStorageMap; fStorageMap = 0;
delete fIds; fIds = 0;
delete fCondParam;
delete fRefParam;
delete fShortLived; fShortLived = 0x0;
if(fSnapshotMode){
fSnapshotFile->Close();
fSnapshotFile = 0;
}
}
void AliCDBManager::PutActiveStorage(AliCDBParam* param, AliCDBStorage* storage){
fActiveStorages.Add(param, storage);
AliDebug(1, Form("Active storages: %d", fActiveStorages.GetEntries()));
}
void AliCDBManager::RegisterFactory(AliCDBStorageFactory* factory) {
if (!fFactories.Contains(factory)) {
fFactories.Add(factory);
}
}
Bool_t AliCDBManager::HasStorage(const char* dbString) const {
TIter iter(&fFactories);
AliCDBStorageFactory* factory=0;
while ((factory = (AliCDBStorageFactory*) iter.Next())) {
if (factory->Validate(dbString)) {
return kTRUE;
}
}
return kFALSE;
}
AliCDBParam* AliCDBManager::CreateParameter(const char* dbString) const {
TString uriString(dbString);
if ( !fCvmfsOcdb.IsNull() && uriString.BeginsWith("alien://")) {
AlienToCvmfsUri(uriString);
}
TIter iter(&fFactories);
AliCDBStorageFactory* factory=0;
while ((factory = (AliCDBStorageFactory*) iter.Next())) {
AliCDBParam* param = factory->CreateParameter(uriString);
if(param) return param;
}
return NULL;
}
void AliCDBManager::AlienToCvmfsUri(TString& uriString) const {
TObjArray *arr = uriString.Tokenize('?');
TIter iter(arr);
TObjString *str = 0;
TString entryKey = "";
TString entryValue = "";
TString newUriString = "";
while((str = (TObjString*) iter.Next())){
TString entry(str->String());
Int_t indeq = entry.Index('=');
entryKey = entry(0, indeq+1);
entryValue = entry(indeq+1, entry.Length()-indeq);
if ( entryKey.Contains("folder", TString::kIgnoreCase) )
{
TRegexp re_RawFolder("^/alice/data/20[0-9]+/OCDB");
TRegexp re_MCFolder("^/alice/simulation/2008/v4-15-Release");
TString rawFolder = entryValue(re_RawFolder);
TString mcFolder = entryValue(re_MCFolder);
if ( !rawFolder.IsNull() ){
entryValue.Replace(0, 6, "/cvmfs/alice-ocdb.cern.ch/calibration");
} else if ( !mcFolder.IsNull() ){
entryValue.Replace(0,36,"/cvmfs/alice-ocdb.cern.ch/calibration/MC");
} else {
AliFatal(Form("Environment variable for cvmfs OCDB folder set for an invalid OCDB storage:\n %s", entryValue.Data()));
}
} else {
newUriString += entryKey;
}
newUriString += entryValue;
newUriString += '?';
}
newUriString.Prepend("local://");
newUriString.Remove(TString::kTrailing, '?');
uriString = newUriString;
}
AliCDBStorage* AliCDBManager::GetStorage(const char* dbString) {
TString uriString(dbString);
if (uriString.EqualTo("raw://")) {
if (!fLHCPeriod.IsNull() && !fLHCPeriod.IsWhitespace()) {
return GetDefaultStorage();
} else {
TString lhcPeriod("");
Int_t startRun = -1, endRun = -1;
GetLHCPeriodAgainstAlienFile(fRun, lhcPeriod, startRun, endRun);
return GetStorage(lhcPeriod.Data());
}
}
AliCDBParam* param = CreateParameter(dbString);
if (!param) {
AliError(Form("Failed to activate requested storage! Check URI: %s", dbString));
return NULL;
}
AliCDBStorage* aStorage = GetStorage(param);
delete param;
return aStorage;
}
AliCDBStorage* AliCDBManager::GetStorage(const AliCDBParam* param) {
AliCDBStorage* aStorage = GetActiveStorage(param);
if (aStorage) {
return aStorage;
}
if(fLock) {
if (fDefaultStorage) {
AliFatal("Lock is ON, and default storage is already set: "
"cannot reset it or activate more storages!");
}
}
TIter iter(&fFactories);
AliCDBStorageFactory* factory=0;
while ((factory = (AliCDBStorageFactory*) iter.Next())) {
aStorage = factory->Create(param);
if (aStorage) {
PutActiveStorage(param->CloneParam(), aStorage);
aStorage->SetURI(param->GetURI());
if(fRun >= 0) {
if( aStorage->GetType() == "alien" || aStorage->GetType() == "local" )
aStorage->QueryCDB(fRun);
}
return aStorage;
}
}
AliError(Form("Failed to activate requested storage! Check URI: %s", param->GetURI().Data()));
return NULL;
}
AliCDBStorage* AliCDBManager::GetActiveStorage(const AliCDBParam* param) {
return dynamic_cast<AliCDBStorage*> (fActiveStorages.GetValue(param));
}
TList* AliCDBManager::GetActiveStorages() {
TList* result = new TList();
TIter iter(fActiveStorages.GetTable());
TPair* aPair=0;
while ((aPair = (TPair*) iter.Next())) {
result->Add(aPair->Value());
}
return result;
}
void AliCDBManager::SetDrain(const char* dbString) {
fDrainStorage = GetStorage(dbString);
}
void AliCDBManager::SetDrain(const AliCDBParam* param) {
fDrainStorage = GetStorage(param);
}
void AliCDBManager::SetDrain(AliCDBStorage* storage) {
fDrainStorage = storage;
}
Bool_t AliCDBManager::Drain(AliCDBEntry *entry) {
AliDebug(2, "Draining into drain storage...");
return fDrainStorage->Put(entry);
}
Bool_t AliCDBManager::SetOCDBUploadMode() {
TString cvmfsUploadExecutable("$HOME/bin/ocdb-cvmfs");
gSystem->ExpandPathName(cvmfsUploadExecutable);
if ( gSystem->AccessPathName(cvmfsUploadExecutable) )
return kFALSE;
fOCDBUploadMode = kTRUE;
return kTRUE;
}
void AliCDBManager::SetDefaultStorage(const char* storageUri) {
TString cvmfsOcdb(gSystem->Getenv("OCDB_PATH"));
if (! cvmfsOcdb.IsNull()){
fCvmfsOcdb = cvmfsOcdb;
ValidateCvmfsCase();
}
TString uriTemp(storageUri);
if (uriTemp == "raw://") {
fRaw = kTRUE;
AliInfo("Setting the run-number will set the corresponding OCDB for raw data reconstruction.");
return;
}
AliCDBStorage* bckStorage = fDefaultStorage;
fDefaultStorage = GetStorage(storageUri);
if(!fDefaultStorage) return;
if(bckStorage && (fDefaultStorage != bckStorage)){
AliWarning("Existing default storage replaced: clearing cache!");
ClearCache();
}
if (fStorageMap->Contains("default")) {
delete fStorageMap->Remove(((TPair*)fStorageMap->FindObject("default"))->Key());
}
fStorageMap->Add(new TObjString("default"), new TObjString(fDefaultStorage->GetURI()));
}
void AliCDBManager::SetDefaultStorage(const AliCDBParam* param) {
AliCDBStorage* bckStorage = fDefaultStorage;
fDefaultStorage = GetStorage(param);
if(!fDefaultStorage) return;
if(bckStorage && (fDefaultStorage != bckStorage)){
AliWarning("Existing default storage replaced: clearing cache!");
ClearCache();
}
if (fStorageMap->Contains("default")) {
delete fStorageMap->Remove(((TPair*)fStorageMap->FindObject("default"))->Key());
}
fStorageMap->Add(new TObjString("default"), new TObjString(fDefaultStorage->GetURI()));
}
void AliCDBManager::SetDefaultStorage(AliCDBStorage* storage) {
if(fLock) {
if (fDefaultStorage) {
AliFatal("Lock is ON, and default storage is already set: "
"cannot reset it or activate more storages!");
}
}
if (!storage) {
UnsetDefaultStorage();
return;
}
AliCDBStorage* bckStorage = fDefaultStorage;
fDefaultStorage = storage;
if(bckStorage && (fDefaultStorage != bckStorage)){
AliWarning("Existing default storage replaced: clearing cache!");
ClearCache();
}
if (fStorageMap->Contains("default")) {
delete fStorageMap->Remove(((TPair*)fStorageMap->FindObject("default"))->Key());
}
fStorageMap->Add(new TObjString("default"), new TObjString(fDefaultStorage->GetURI()));
}
void AliCDBManager::SetDefaultStorage(const char* mcString, const char* simType) {
TString strmcString(mcString);
TString strsimType(simType);
TString dbString;
if (strmcString != "MC"){
AliFatal("Method requires first string to be MC!");
}
else {
if (strsimType == "Ideal"){
dbString = fgkMCIdealStorage;
}
else if (strsimType == "Full"){
dbString = fgkMCFullStorage;
}
else if (strsimType == "Residual"){
dbString = fgkMCResidualStorage;
}
else {
AliFatal("Error in setting the storage for MC data, second argument MUST be either \"Ideal\" or \"Full\" or \"Residual\".");
}
SetDefaultStorage(dbString.Data());
fStartRunLHCPeriod=0;
fEndRunLHCPeriod=AliCDBRunRange::Infinity();
if(!fDefaultStorage) AliFatal(Form("%s storage not there! Please check!",dbString.Data()));
}
}
void AliCDBManager::ValidateCvmfsCase() const {
if (! fCvmfsOcdb.BeginsWith("/cvmfs"))
AliFatal(Form("OCDB_PATH set to an invalid path: %s", fCvmfsOcdb.Data()));
TString cvmfsUri(fCvmfsOcdb);
gSystem->ExpandPathName(cvmfsUri);
if (gSystem->AccessPathName(cvmfsUri))
AliFatal(Form("OCDB_PATH set to an invalid path: %s", cvmfsUri.Data()));
AliDebug(3, "OCDB_PATH envvar is set. Changing OCDB storage from alien:// to local:///cvmfs type.");
cvmfsUri = cvmfsUri.Strip(TString::kTrailing, '/');
cvmfsUri.Append("/bin/getOCDBFilesPerRun.sh");
if (gSystem->AccessPathName(cvmfsUri))
AliFatal(Form("Cannot find valid script: %s", cvmfsUri.Data()));
}
void AliCDBManager::SetDefaultStorageFromRun(Int_t run) {
if(fLock) {
if (fDefaultStorage) {
AliFatal("Lock is ON, and default storage is already set: "
"cannot activate default storage from run number");
}
}
TString lhcPeriod("");
Int_t startRun = 0, endRun = 0;
if (! fCvmfsOcdb.IsNull()) {
GetLHCPeriodAgainstCvmfsFile(run, lhcPeriod, startRun, endRun);
} else {
GetLHCPeriodAgainstAlienFile(run, lhcPeriod, startRun, endRun);
}
fLHCPeriod = lhcPeriod;
fStartRunLHCPeriod = startRun;
fEndRunLHCPeriod = endRun;
SetDefaultStorage(fLHCPeriod.Data());
if(!fDefaultStorage) AliFatal(Form("%s storage not there! Please check!",fLHCPeriod.Data()));
}
void AliCDBManager::GetLHCPeriodAgainstAlienFile(Int_t run, TString& lhcPeriod, Int_t& startRun, Int_t& endRun) {
if(!gGrid) {
TGrid::Connect("alien://","");
if(!gGrid) {
AliError("Connection to alien failed!");
return;
}
}
TUUID uuid;
TString rndname = gSystem->TempDirectory();
rndname += "/";
rndname += "OCDBFolderXML.";
rndname += uuid.AsString();
rndname += ".xml";
AliDebug(2, Form("file to be copied = %s", fgkOCDBFolderXMLfile.Data()));
if (!TFile::Cp(fgkOCDBFolderXMLfile.Data(), rndname.Data())) {
AliFatal(Form("Cannot make a local copy of OCDBFolder xml file in %s",rndname.Data()));
}
AliCDBHandler* saxcdb = new AliCDBHandler();
saxcdb->SetRun(run);
TSAXParser *saxParser = new TSAXParser();
saxParser->ConnectToHandler("AliCDBHandler", saxcdb);
saxParser->ParseFile(rndname.Data());
AliInfo(Form(" LHC folder = %s", saxcdb->GetOCDBFolder().Data()));
AliInfo(Form(" LHC period start run = %d", saxcdb->GetStartRunRange()));
AliInfo(Form(" LHC period end run = %d", saxcdb->GetEndRunRange()));
lhcPeriod = saxcdb->GetOCDBFolder();
startRun = saxcdb->GetStartRunRange();
endRun = saxcdb->GetEndRunRange();
}
void AliCDBManager::GetLHCPeriodAgainstCvmfsFile(Int_t run, TString& lhcPeriod, Int_t& startRun, Int_t& endRun) {
TString getYearScript(fCvmfsOcdb);
getYearScript = getYearScript.Strip(TString::kTrailing, '/');
getYearScript.Append("/bin/getUriFromYear.sh");
if (gSystem->AccessPathName(getYearScript))
AliFatal(Form("Cannot find valid script: %s", getYearScript.Data()));
TString inoutFile(gSystem->WorkingDirectory());
inoutFile += "/uri_range_";
inoutFile += TString::Itoa(run,10);
TString command(getYearScript);
command += ' ';
command += TString::Itoa(run,10);
command += Form(" > %s", inoutFile.Data());
AliDebug(3, Form("Running command: \"%s\"",command.Data()));
Int_t result = gSystem->Exec(command.Data());
if(result != 0) {
AliFatal(Form("Was not able to execute \"%s\"", command.Data()));
}
std::ifstream file(inoutFile.Data());
if (!file.is_open()) {
AliFatal(Form("Error opening file \"%s\"!", inoutFile.Data()));
}
TString line;
TObjArray* oStringsArray = 0;
while (line.ReadLine(file)){
oStringsArray = line.Tokenize(' ');
}
TObjString *oStrUri = dynamic_cast<TObjString*> (oStringsArray->At(0));
TObjString *oStrFirst = dynamic_cast<TObjString*> (oStringsArray->At(1));
TString firstRun = oStrFirst->GetString();
TObjString *oStrLast = dynamic_cast<TObjString*> (oStringsArray->At(2));
TString lastRun = oStrLast->GetString();
lhcPeriod = oStrUri->GetString();
startRun = firstRun.Atoi();
endRun = lastRun.Atoi();
file.close();
}
void AliCDBManager::UnsetDefaultStorage() {
if(fLock) {
if (fDefaultStorage) {
AliFatal("Lock is ON: cannot unset default storage!");
}
}
if (fDefaultStorage) {
AliWarning("Clearing cache!");
ClearCache();
}
fRun = fStartRunLHCPeriod = fEndRunLHCPeriod = -1;
fRaw = kFALSE;
fDefaultStorage = 0x0;
}
void AliCDBManager::SetSpecificStorage(const char* calibType, const char* dbString, Int_t version, Int_t subVersion) {
AliCDBParam *aPar = CreateParameter(dbString);
if(!aPar) return;
SetSpecificStorage(calibType, aPar, version, subVersion);
delete aPar;
}
void AliCDBManager::SetSpecificStorage(const char* calibType, const AliCDBParam* param, Int_t version, Int_t subVersion) {
if(!fDefaultStorage && !fRaw) {
AliError("Please activate a default storage first!");
return;
}
AliCDBPath aPath(calibType);
if(!aPath.IsValid()){
AliError(Form("Not a valid path: %s", calibType));
return;
}
TObjString *objCalibType = new TObjString(aPath.GetPath());
if(fSpecificStorages.Contains(objCalibType)){
AliWarning(Form("Storage \"%s\" already activated! It will be replaced by the new one",
calibType));
AliCDBParam *checkPar = dynamic_cast<AliCDBParam*> (fSpecificStorages.GetValue(calibType));
if(checkPar) delete checkPar;
delete fSpecificStorages.Remove(objCalibType);
}
AliCDBStorage *aStorage = GetStorage(param);
if(!aStorage) return;
UInt_t uId = ((subVersion+1)<<16) + (version+1);
AliCDBParam *specificParam = param->CloneParam();
specificParam->SetUniqueID(uId);
fSpecificStorages.Add(objCalibType, specificParam);
if(fStorageMap->Contains(objCalibType)){
delete fStorageMap->Remove(objCalibType);
}
fStorageMap->Add(objCalibType->Clone(), new TObjString(param->GetURI()));
}
AliCDBStorage* AliCDBManager::GetSpecificStorage(const char* calibType) {
AliCDBPath calibPath(calibType);
if(!calibPath.IsValid()) return NULL;
AliCDBParam *checkPar = (AliCDBParam*) fSpecificStorages.GetValue(calibPath.GetPath());
if(!checkPar){
AliError(Form("%s storage not found!", calibType));
return NULL;
} else {
return GetStorage(checkPar);
}
}
AliCDBParam* AliCDBManager::SelectSpecificStorage(const TString& path) {
AliCDBPath aPath(path);
if(!aPath.IsValid()) return NULL;
TIter iter(&fSpecificStorages);
TObjString *aCalibType=0;
AliCDBPath tmpPath("null/null/null");
AliCDBParam* aPar=0;
while((aCalibType = (TObjString*) iter.Next())){
AliCDBPath calibTypePath(aCalibType->GetName());
if(calibTypePath.Comprises(aPath)) {
if(calibTypePath.Comprises(tmpPath)) continue;
aPar = (AliCDBParam*) fSpecificStorages.GetValue(aCalibType);
tmpPath.SetPath(calibTypePath.GetPath());
}
}
return aPar;
}
AliCDBEntry* AliCDBManager::Get(const AliCDBPath& path, Int_t runNumber,
Int_t version, Int_t subVersion) {
if(runNumber < 0){
if (fRun < 0){
AliError("Run number neither specified in query nor set in AliCDBManager! Use AliCDBManager::SetRun.");
return NULL;
}
runNumber = fRun;
}
return Get(AliCDBId(path, runNumber, runNumber, version, subVersion));
}
AliCDBEntry* AliCDBManager::Get(const AliCDBPath& path,
const AliCDBRunRange& runRange, Int_t version,
Int_t subVersion) {
return Get(AliCDBId(path, runRange, version, subVersion));
}
AliCDBEntry* AliCDBManager::Get(const AliCDBId& queryId, Bool_t forceCaching) {
if (!queryId.IsValid()) {
AliError(Form("Invalid query: %s", queryId.ToString().Data()));
return NULL;
}
if (!queryId.IsSpecified()) {
AliError(Form("Unspecified query: %s",
queryId.ToString().Data()));
return NULL;
}
if(fLock && !(fRun >= queryId.GetFirstRun() && fRun <= queryId.GetLastRun()))
AliFatal("Lock is ON: cannot use different run number than the internal one!");
if(fCache && !(fRun >= queryId.GetFirstRun() && fRun <= queryId.GetLastRun()))
AliWarning("Run number explicitly set in query: CDB cache temporarily disabled!");
AliCDBEntry *entry=0;
if(fCache && queryId.GetFirstRun() == fRun)
entry = (AliCDBEntry*) fEntryCache.GetValue(queryId.GetPath());
if(entry) {
AliDebug(2, Form("Object %s retrieved from cache !!",queryId.GetPath().Data()));
return entry;
}
AliCDBParam *aPar=SelectSpecificStorage(queryId.GetPath());
if(!aPar){
if(fSnapshotMode && queryId.GetFirstRun() == fRun)
{
entry = GetEntryFromSnapshot(queryId.GetPath());
if(entry) {
AliInfo(Form("Object \"%s\" retrieved from the snapshot.",queryId.GetPath().Data()));
if(queryId.GetFirstRun() == fRun)
CacheEntry(queryId.GetPath(), entry);
if(!fIds->Contains(&entry->GetId()))
fIds->Add(entry->GetId().Clone());
return entry;
}
}
}
if(!fDefaultStorage) {
AliError("No storage set!");
return NULL;
}
Int_t version = -1, subVersion = -1;
AliCDBStorage *aStorage=0;
if(aPar) {
aStorage=GetStorage(aPar);
TString str = aPar->GetURI();
UInt_t uId = aPar->GetUniqueID();
version = Int_t(uId&0xffff) - 1;
subVersion = Int_t(uId>>16) - 1;
AliDebug(2,Form("Looking into storage: %s",str.Data()));
} else {
aStorage=GetDefaultStorage();
AliDebug(2,"Looking into default storage");
}
AliCDBId finalQueryId(queryId);
if(version >= 0) {
AliDebug(2,Form("Specific version set to: %d", version));
finalQueryId.SetVersion(version);
}
if(subVersion >= 0) {
AliDebug(2,Form("Specific subversion set to: %d", subVersion));
finalQueryId.SetSubVersion(subVersion);
}
entry = aStorage->Get(finalQueryId);
if(entry && fCache && (queryId.GetFirstRun()==fRun || forceCaching)){
CacheEntry(queryId.GetPath(), entry);
}
if(entry && !fIds->Contains(&entry->GetId())){
fIds->Add(entry->GetId().Clone());
}
return entry;
}
AliCDBEntry* AliCDBManager::GetEntryFromSnapshot(const char* path) {
TString sPath(path);
sPath.ReplaceAll("/","*");
if(!fSnapshotFile){
AliError("No snapshot file is open!");
return 0;
}
AliCDBEntry *entry = dynamic_cast<AliCDBEntry*>(fSnapshotFile->Get(sPath.Data()));
if(!entry){
AliDebug(2,Form("Cannot get a CDB entry for \"%s\" from snapshot file",path));
return 0;
}
return entry;
}
Bool_t AliCDBManager::SetSnapshotMode(const char* snapshotFileName) {
if(!fCache){
AliError("Cannot set the CDB manage in snapshot mode if the cache is not active!");
return kFALSE;
}
TString snapshotFile(snapshotFileName);
if(snapshotFile.BeginsWith("alien://")){
if(!gGrid) {
TGrid::Connect("alien://","");
if(!gGrid) {
AliError("Connection to alien failed!");
return kFALSE;
}
}
}
fSnapshotFile = TFile::Open(snapshotFileName);
if (!fSnapshotFile || fSnapshotFile->IsZombie()){
AliError(Form("Cannot open file %s",snapshotFileName));
return kFALSE;
}
AliInfo("The CDB manager is set in snapshot mode!");
fSnapshotMode = kTRUE;
return kTRUE;
}
const char* AliCDBManager::GetURI(const char* path) {
if(!IsDefaultStorageSet()) return 0;
AliCDBParam *aPar=SelectSpecificStorage(path);
if(aPar) {
return aPar->GetURI().Data();
} else {
return GetDefaultStorage()->GetURI().Data();
}
return 0;
}
Int_t AliCDBManager::GetStartRunLHCPeriod(){
if(fStartRunLHCPeriod==-1)
AliWarning("Run-range not yet set for the current LHC period.");
return fStartRunLHCPeriod;
}
Int_t AliCDBManager::GetEndRunLHCPeriod(){
if(fEndRunLHCPeriod==-1)
AliWarning("Run-range not yet set for the current LHC period.");
return fEndRunLHCPeriod;
}
TString AliCDBManager::GetLHCPeriod(){
if(fLHCPeriod.IsWhitespace() || fLHCPeriod.IsNull())
AliWarning("LHC period (OCDB folder) not yet set");
return fLHCPeriod;
}
AliCDBId* AliCDBManager::GetId(const AliCDBPath& path, Int_t runNumber,
Int_t version, Int_t subVersion) {
if(runNumber < 0){
if (fRun < 0){
AliError("Run number neither specified in query nor set in AliCDBManager! Use AliCDBManager::SetRun.");
return NULL;
}
runNumber = fRun;
}
return GetId(AliCDBId(path, runNumber, runNumber, version, subVersion));
}
AliCDBId* AliCDBManager::GetId(const AliCDBPath& path,
const AliCDBRunRange& runRange, Int_t version,
Int_t subVersion) {
return GetId(AliCDBId(path, runRange, version, subVersion));
}
AliCDBId* AliCDBManager::GetId(const AliCDBId& query) {
if(!fDefaultStorage) {
AliError("No storage set!");
return NULL;
}
if (!query.IsValid()) {
AliError(Form("Invalid query: %s", query.ToString().Data()));
return NULL;
}
if (!query.IsSpecified()) {
AliError(Form("Unspecified query: %s",
query.ToString().Data()));
return NULL;
}
if(fCache && query.GetFirstRun() != fRun)
AliWarning("Run number explicitly set in query: CDB cache temporarily disabled!");
AliCDBEntry* entry = 0;
if(fCache && query.GetFirstRun() == fRun)
entry = (AliCDBEntry*) fEntryCache.GetValue(query.GetPath());
if(entry) {
AliDebug(2, Form("Object %s retrieved from cache !!",query.GetPath().Data()));
return dynamic_cast<AliCDBId*> (entry->GetId().Clone());
}
AliCDBStorage *aStorage=0;
AliCDBParam *aPar=SelectSpecificStorage(query.GetPath());
if(aPar) {
aStorage=GetStorage(aPar);
TString str = aPar->GetURI();
AliDebug(2,Form("Looking into storage: %s",str.Data()));
} else {
aStorage=GetDefaultStorage();
AliDebug(2,"Looking into default storage");
}
return aStorage->GetId(query);
}
TList* AliCDBManager::GetAll(const AliCDBPath& path, Int_t runNumber,
Int_t version, Int_t subVersion) {
if(runNumber < 0){
if (fRun < 0){
AliError("Run number neither specified in query nor set in AliCDBManager! Use AliCDBManager::SetRun.");
return NULL;
}
runNumber = fRun;
}
return GetAll(AliCDBId(path, runNumber, runNumber, version,
subVersion));
}
TList* AliCDBManager::GetAll(const AliCDBPath& path,
const AliCDBRunRange& runRange, Int_t version, Int_t subVersion) {
return GetAll(AliCDBId(path, runRange, version, subVersion));
}
TList* AliCDBManager::GetAll(const AliCDBId& query) {
if(!fDefaultStorage) {
AliError("No storage set!");
return NULL;
}
if (!query.IsValid()) {
AliError(Form("Invalid query: %s", query.ToString().Data()));
return NULL;
}
if((fSpecificStorages.GetEntries()>0) && query.GetPath().BeginsWith('*')){
AliError("Query too generic in this context!");
return NULL;
}
if (query.IsAnyRange()) {
AliError(Form("Unspecified run or runrange: %s",
query.ToString().Data()));
return NULL;
}
if(fLock && query.GetFirstRun() != fRun)
AliFatal("Lock is ON: cannot use different run number than the internal one!");
AliCDBParam *aPar=SelectSpecificStorage(query.GetPath());
AliCDBStorage *aStorage;
if(aPar) {
aStorage=GetStorage(aPar);
AliDebug(2,Form("Looking into storage: %s", aPar->GetURI().Data()));
} else {
aStorage=GetDefaultStorage();
AliDebug(2,Form("Looking into default storage: %s", aStorage->GetURI().Data()));
}
TList *result = 0;
if(aStorage) result = aStorage->GetAll(query);
if(!result) return 0;
if(fSpecificStorages.GetEntries()>0 && ! (fSpecificStorages.GetEntries() == 1 && aPar)) {
AliInfo("Now look into all other specific storages...");
TIter iter(result);
AliCDBEntry* chkEntry=0;
while((chkEntry = dynamic_cast<AliCDBEntry*> (iter.Next()))){
AliCDBId& chkId = chkEntry->GetId();
AliDebug(2, Form("Checking id %s ", chkId.GetPath().Data()));
AliCDBParam *chkPar=SelectSpecificStorage(chkId.GetPath());
if (!chkPar || aPar == chkPar) continue;
AliCDBStorage *chkStorage = GetStorage(chkPar);
AliDebug(2, Form("Found specific storage! %s", chkPar->GetURI().Data()));
AliCDBEntry *newEntry=0;
chkId.SetRunRange(query.GetFirstRun(), query.GetLastRun());
chkId.SetVersion(query.GetVersion());
chkId.SetSubVersion(query.GetSubVersion());
if(chkStorage) newEntry = chkStorage->Get(chkId);
if(!newEntry) continue;
chkEntry->SetOwner(1);
delete result->Remove(chkEntry);
result->AddFirst(newEntry);
}
Int_t nEntries = result->GetEntries();
AliInfo("After look into other specific storages, result list is:");
for(int i=0; i<nEntries;i++){
AliCDBEntry *entry = (AliCDBEntry*) result->At(i);
AliInfo(Form("%s",entry->GetId().ToString().Data()));
}
}
TIter iter(result);
AliCDBEntry* entry=0;
while((entry = dynamic_cast<AliCDBEntry*> (iter.Next()))){
if(!fIds->Contains(&entry->GetId())){
fIds->Add(entry->GetId().Clone());
}
if(fCache && (query.GetFirstRun() == fRun)){
CacheEntry(entry->GetId().GetPath(), entry);
}
}
return result;
}
Bool_t AliCDBManager::Put(TObject* object, const AliCDBId& id, AliCDBMetaData* metaData, const char* mirrors, DataType type){
if (object==0x0) {
AliError("Null Entry! No storage will be done!");
return kFALSE;
}
AliCDBEntry anEntry(object, id, metaData);
return Put(&anEntry, mirrors, type);
}
Bool_t AliCDBManager::Put(AliCDBEntry* entry, const char* mirrors, DataType type){
if(type == kPrivate && !fDefaultStorage) {
AliError("No storage set!");
return kFALSE;
}
if (!entry){
AliError("No entry!");
return kFALSE;
}
if (entry->GetObject()==0x0){
AliError("No valid object in CDB entry!");
return kFALSE;
}
if (!entry->GetId().IsValid()) {
AliError(Form("Invalid entry ID: %s",
entry->GetId().ToString().Data()));
return kFALSE;
}
if (!entry->GetId().IsSpecified()) {
AliError(Form("Unspecified entry ID: %s",
entry->GetId().ToString().Data()));
return kFALSE;
}
AliCDBId id = entry->GetId();
AliCDBParam *aPar = SelectSpecificStorage(id.GetPath());
AliCDBStorage *aStorage=0;
if(aPar) {
aStorage=GetStorage(aPar);
} else {
switch(type){
case kCondition:
aStorage = GetStorage(fCondParam);
break;
case kReference:
aStorage = GetStorage(fRefParam);
break;
case kPrivate:
aStorage = GetDefaultStorage();
break;
}
}
AliDebug(2,Form("Storing object into storage: %s", aStorage->GetURI().Data()));
TString strMirrors(mirrors);
Bool_t result = kFALSE;
if(!strMirrors.IsNull() && !strMirrors.IsWhitespace())
result = aStorage->Put(entry, mirrors, type);
else
result = aStorage->Put(entry, "", type);
if(fRun >= 0) QueryCDB();
return result;
}
void AliCDBManager::SetMirrorSEs(const char* mirrors) {
if(fDefaultStorage->GetType() != "alien"){
AliInfo("The default storage is not of type \"alien\". Settings for Storage Elements are not taken into account!");
return;
}
fDefaultStorage->SetMirrorSEs(mirrors);
}
const char* AliCDBManager::GetMirrorSEs() const {
if(fDefaultStorage->GetType() != "alien"){
AliInfo("The default storage is not of type \"alien\". Settings for Storage Elements are not taken into account!");
return "";
}
return fDefaultStorage->GetMirrorSEs();
}
void AliCDBManager::CacheEntry(const char* path, AliCDBEntry* entry) {
AliCDBEntry *chkEntry = dynamic_cast<AliCDBEntry*> (fEntryCache.GetValue(path));
if(chkEntry) {
AliDebug(2, Form("Object %s already in cache !!", path));
return;
} else {
AliDebug(2,Form("Caching entry %s", path));
}
fEntryCache.Add(new TObjString(path), entry);
AliDebug(2,Form("Cache entries: %d", fEntryCache.GetEntries()));
}
void AliCDBManager::Print(Option_t* ) const {
TString output=Form("Run number = %d; ",fRun);
output += "Cache is ";
if(!fCache) output += "NOT ";
output += Form("ACTIVE; Number of active storages: %d\n",fActiveStorages.GetEntries());
if(fDefaultStorage) {
output += Form("\t*** Default Storage URI: \"%s\"\n",fDefaultStorage->GetURI().Data());
}
if(fSpecificStorages.GetEntries()>0) {
TIter iter(fSpecificStorages.GetTable());
TPair *aPair=0;
Int_t i=1;
while((aPair = (TPair*) iter.Next())){
output += Form("\t*** Specific storage %d: Path \"%s\" -> URI \"%s\"\n",
i++, ((TObjString*) aPair->Key())->GetName(),
((AliCDBParam*) aPair->Value())->GetURI().Data());
}
}
if(fDrainStorage) {
output += Form("*** Drain Storage URI: %s\n",fDrainStorage->GetURI().Data());
}
AliInfo(output.Data());
}
void AliCDBManager::SetRun(Int_t run) {
if(fRun == run)
return;
if(fLock && fRun >= 0) {
AliFatal("Lock is ON, cannot reset run number!");
}
fRun = run;
if (fRaw) {
if (fStartRunLHCPeriod <= run && fEndRunLHCPeriod >= run){
AliInfo("LHCPeriod alien folder for current run already in memory");
}else{
SetDefaultStorageFromRun(fRun);
if(fEntryCache.GetEntries()!=0) ClearCache();
return;
}
}
ClearCache();
QueryCDB();
}
void AliCDBManager::ClearCache(){
AliDebug(2, Form("Cache entries to be deleted: %d",fEntryCache.GetEntries()));
fEntryCache.DeleteAll();
AliDebug(2, Form("After deleting - Cache entries: %d",fEntryCache.GetEntries()));
}
void AliCDBManager::UnloadFromCache(const char* path){
if(!fActiveStorages.GetEntries()) {
AliDebug(2, Form("No active storages. Object \"%s\" is not unloaded from cache", path));
return;
}
AliCDBPath queryPath(path);
if(!queryPath.IsValid()) return;
if(!queryPath.IsWildcard()) {
if(fEntryCache.Contains(path)){
AliDebug(2, Form("Unloading object \"%s\" from cache and from list of ids", path));
TObjString pathStr(path);
delete fEntryCache.Remove(&pathStr);
} else {
AliWarning(Form("Cache does not contain object \"%s\"!", path));
}
AliDebug(2, Form("Cache entries: %d",fEntryCache.GetEntries()));
return;
}
TIter iter(fEntryCache.GetTable());
TPair* pair = 0;
Int_t removed=0;
while((pair = dynamic_cast<TPair*> (iter.Next()))){
AliCDBPath entryPath = pair->Key()->GetName();
if(queryPath.Comprises(entryPath)) {
AliDebug(2, Form("Unloading object \"%s\" from cache and from list of ids", entryPath.GetPath().Data()));
TObjString pathStr(entryPath.GetPath());
delete fEntryCache.Remove(&pathStr);
removed++;
}
}
AliDebug(2,Form("Cache entries and ids removed: %d Remaining: %d",removed,fEntryCache.GetEntries()));
}
void AliCDBManager::DestroyActiveStorages() {
fActiveStorages.DeleteAll();
fSpecificStorages.DeleteAll();
}
void AliCDBManager::DestroyActiveStorage(AliCDBStorage* ) {
}
void AliCDBManager::QueryCDB() {
if (fRun < 0){
AliError("Run number not yet set! Use AliCDBManager::SetRun.");
return;
}
if (!fDefaultStorage){
AliError("Default storage is not set! Use AliCDBManager::SetDefaultStorage");
return;
}
if(fDefaultStorage->GetType() == "alien" || fDefaultStorage->GetType() == "local"){
fDefaultStorage->QueryCDB(fRun);
}
TIter iter(&fSpecificStorages);
TObjString *aCalibType=0;
AliCDBParam* aPar=0;
while((aCalibType = dynamic_cast<TObjString*> (iter.Next()))){
aPar = (AliCDBParam*) fSpecificStorages.GetValue(aCalibType);
if(aPar) {
AliDebug(2,Form("Querying specific storage %s",aCalibType->GetName()));
AliCDBStorage *aStorage = GetStorage(aPar);
if(aStorage->GetType() == "alien" || aStorage->GetType() == "local"){
aStorage->QueryCDB(fRun, aCalibType->GetName());
} else {
AliDebug(2,
"Skipping query for valid files, it is used only in grid...");
}
}
}
}
const char* AliCDBManager::GetDataTypeName(DataType type) {
switch (type){
case kCondition: return "Conditions";
case kReference: return "Reference";
case kPrivate: return "Private";
}
return 0;
}
Bool_t AliCDBManager::DiffObjects(const char *cdbFile1, const char *cdbFile2) const {
TString f1Str(cdbFile1);
TString f2Str(cdbFile2);
if (!gGrid && ( f1Str.BeginsWith("alien://") || f2Str.BeginsWith("alien://") ))
TGrid::Connect("alien://");
TFile * f1 = TFile::Open(cdbFile1);
if (!f1){
Printf("Cannot open file \"%s\"",cdbFile1);
return kFALSE;
}
TFile * f2 = TFile::Open(cdbFile2);
if (!f2){
Printf("Cannot open file \"%s\"",cdbFile2);
return kFALSE;
}
AliCDBEntry * entry1 = (AliCDBEntry*)f1->Get("AliCDBEntry");
if (!entry1){
Printf("Cannot get CDB entry from file \"%s\"",cdbFile1);
return kFALSE;
}
AliCDBEntry * entry2 = (AliCDBEntry*)f2->Get("AliCDBEntry");
if (!entry2){
Printf("Cannot get CDB entry from file \"%s\"",cdbFile2);
return kFALSE;
}
TObject* object1 = entry1->GetObject();
TObject* object2 = entry2->GetObject();
TMessage * file1 = new TMessage(TBuffer::kWrite);
file1->WriteObject(object1);
Int_t size1 = file1->Length();
TMessage * file2 = new TMessage(TBuffer::kWrite);
file2->WriteObject(object2);
Int_t size2 = file2->Length();
if (size1!=size2){
Printf("Problem 2: OCDB entry of different size (%d,%d)",size1,size2);
return kFALSE;
}
Int_t countDiff=0;
char* buf1 = file1->Buffer();
char* buf2 = file2->Buffer();
for(Int_t i=0; i<size1; i++)
if (buf1[i]!=buf2[i]) countDiff++;
if (countDiff>0){
Printf("The CDB objects differ by %d bytes.", countDiff);
return kFALSE;
}
Printf("The CDB objects are the same in the two files.");
return kTRUE;
}
void AliCDBManager::InitShortLived() {
fShortLived=0x0;
}
Bool_t AliCDBManager::IsShortLived(const char* path) {
if(!fShortLived) return kFALSE;
AliCDBPath aPath(path);
if(!aPath.IsValid()){
AliError(Form("Not a valid path: %s", path));
return kFALSE;
}
return fShortLived->Contains(path);
}
ULong64_t AliCDBManager::SetLock(Bool_t lock, ULong64_t key){
if (fLock == lock) return 0;
if (lock) {
if (fKey) {
if (fKey != key) {
AliFatal("Wrong key provided to lock CDB. Please remove CDB lock access from your code !");
return 0;
}
}
fKey = gSystem->Now();
fLock = kTRUE;
return fKey;
}
if (key != fKey) {
AliFatal("Lock is ON: wrong key provided");
return 0;
}
fLock = kFALSE;
return key;
}
AliCDBParam::AliCDBParam():
fType(),
fURI()
{
}
AliCDBParam::~AliCDBParam() {
}
void AliCDBManager::ExtractBaseFolder(TString& url)
{
TString sbs;
if (!(sbs=url("\\?User=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
if (!(sbs=url("\\?DBFolder=[^?]*")).IsNull()) url.ReplaceAll("?DB","");
if (!(sbs=url("\\?SE=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
if (!(sbs=url("\\?CacheFolder=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
if (!(sbs=url("\\?OperateDisconnected=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
if (!(sbs=url("\\?CacheSize=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
if (!(sbs=url("\\?CleanupInterval=[^?]*")).IsNull()) url.ReplaceAll(sbs,"");
Bool_t slash=kFALSE,space=kFALSE;
while ( (slash=url.EndsWith("/")) || (space=url.EndsWith(" ")) ) {
if (slash) url = url.Strip(TString::kTrailing,'/');
if (space) url = url.Strip(TString::kTrailing,' ');
}
}