]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/AliCDBGrid.cxx
bug
[u/mrichter/AliRoot.git] / STEER / AliCDBGrid.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 /////////////////////////////////////////////////////////////////////////////////////////////////
17 //                                                                                             //
18 // AliCDBGrid                                                                                  //
19 // access class to a DataBase in an AliEn storage                                              //
20 //                                                                                             //
21 /////////////////////////////////////////////////////////////////////////////////////////////////
22
23
24 #include <TGrid.h>
25 #include <TGridResult.h>
26 #include <TFile.h>
27 #include <TKey.h>
28 #include <TROOT.h>
29 #include <TList.h>
30 #include <TObjArray.h>
31 #include <TObjString.h>
32 #include <TRegexp.h>
33
34 #include "AliLog.h"
35 #include "AliCDBEntry.h"
36 #include "AliCDBGrid.h"
37 #include "AliCDBManager.h"
38
39
40 ClassImp(AliCDBGrid)
41
42 //_____________________________________________________________________________
43 AliCDBGrid::AliCDBGrid(const char *gridUrl, const char *user, const char *dbFolder,
44                        const char *se, const char* cacheFolder, Bool_t operateDisconnected,
45                        Long64_t cacheSize, Long_t cleanupInterval) :
46 AliCDBStorage(),
47 fGridUrl(gridUrl),
48 fUser(user),
49 fDBFolder(dbFolder),
50 fSE(se),
51 fCacheFolder(cacheFolder),
52 fOperateDisconnected(operateDisconnected),
53 fCacheSize(cacheSize),
54 fCleanupInterval(cleanupInterval)
55 {
56 // constructor //
57
58         // if the same Grid is alreay active, skip connection
59         if (!gGrid || fGridUrl != gGrid->GridUrl()
60              || (( fUser != "" ) && ( fUser != gGrid->GetUser() )) ) {
61                 // connection to the Grid
62                 AliInfo("Connection to the Grid...");
63                 if(gGrid){
64                         AliInfo(Form("gGrid = %x; fGridUrl = %s; gGrid->GridUrl() = %s",gGrid,fGridUrl.Data(), gGrid->GridUrl()));
65                         AliInfo(Form("fUser = %s; gGrid->GetUser() = %s",fUser.Data(), gGrid->GetUser()));
66                 }
67                 TGrid::Connect(fGridUrl.Data(),fUser.Data());
68         }
69
70         if(!gGrid) {
71                 AliError("Connection failed!");
72                 return;
73         }
74
75         TString initDir(gGrid->Pwd(0));
76         if (fDBFolder[0] != '/') {
77                 fDBFolder.Prepend(initDir);
78         }
79
80         // check DBFolder: trying to cd to DBFolder; if it does not exist, create it
81         if(!gGrid->Cd(fDBFolder.Data(),0)){
82                 AliDebug(2,Form("Creating new folder <%s> ...",fDBFolder.Data()));
83                 TGridResult* res = gGrid->Command(Form("mkdir -p %s",fDBFolder.Data()));
84                 TString result = res->GetKey(0,"__result__");
85                 if(result == "0"){
86                         AliFatal(Form("Cannot create folder <%s> !",fDBFolder.Data()));
87                         return;
88                 }
89         } else {
90                 AliDebug(2,Form("Folder <%s> found",fDBFolder.Data()));
91         }
92
93         // removes any '/' at the end of path, then append one '/'
94         while(fDBFolder.EndsWith("/")) fDBFolder.Remove(fDBFolder.Last('/')); 
95         fDBFolder+="/";
96
97         fType="alien";
98         fBaseFolder = fDBFolder;
99
100         // Setting the cache
101
102         // Check if local cache folder is already defined
103         TString origCache(TFile::GetCacheFileDir());
104         if(fCacheFolder.Length() > 0) {
105                 if(origCache.Length() == 0) {
106                         AliInfo(Form("Setting local cache to: %s", fCacheFolder.Data()));
107                 } else if(fCacheFolder != origCache) {
108                         AliWarning(Form("Local cache folder was already defined, changing it to: %s",
109                                         fCacheFolder.Data()));
110                 }
111
112                 // default settings are: operateDisconnected=kTRUE, forceCacheread = kFALSE
113                 if(!TFile::SetCacheFileDir(fCacheFolder.Data(), fOperateDisconnected)) {
114                         AliError(Form("Could not set cache folder %s !", fCacheFolder.Data()));
115                         fCacheFolder = "";
116                 } else {
117                         // reset fCacheFolder because the function may have
118                         // slightly changed the folder name (e.g. '/' added)
119                         fCacheFolder = TFile::GetCacheFileDir();
120                 }
121
122                 // default settings are: cacheSize=1GB, cleanupInterval = 0
123                 if(!TFile::ShrinkCacheFileDir(fCacheSize, fCleanupInterval)) {
124                         AliError(Form("Could not set following values "
125                                 "to ShrinkCacheFileDir: cacheSize = %d, cleanupInterval = %d !",
126                                 fCacheSize, fCleanupInterval));
127                 }
128         }
129
130         // return to the initial directory
131         gGrid->Cd(initDir.Data(),0);
132 }
133
134 //_____________________________________________________________________________
135 AliCDBGrid::~AliCDBGrid()
136 {
137 // destructor
138         delete gGrid; gGrid=0;
139
140 }
141
142 //_____________________________________________________________________________
143 Bool_t AliCDBGrid::FilenameToId(TString& filename, AliCDBId& id) {
144 // build AliCDBId from full path filename (fDBFolder/path/Run#x_#y_v#z_s0.root)
145
146         if(filename.Contains(fDBFolder)){
147                 filename = filename(fDBFolder.Length(),filename.Length()-fDBFolder.Length());
148         }
149
150         TString idPath = filename(0,filename.Last('/'));
151         id.SetPath(idPath);
152         if(!id.IsValid()) return kFALSE;
153
154         filename=filename(idPath.Length()+1,filename.Length()-idPath.Length());
155
156         Ssiz_t mSize;
157         // valid filename: Run#firstRun_#lastRun_v#version_s0.root
158         TRegexp keyPattern("^Run[0-9]+_[0-9]+_v[0-9]+_s0.root$");
159         keyPattern.Index(filename, &mSize);
160         if (!mSize) {
161
162                 // TODO backward compatibility ... maybe remove later!
163                 Ssiz_t oldmSize;
164                 TRegexp oldKeyPattern("^Run[0-9]+_[0-9]+_v[0-9]+.root$");
165                 oldKeyPattern.Index(filename, &oldmSize);
166                 if(!oldmSize) {
167                         AliDebug(2,Form("Bad filename <%s>.", filename.Data()));
168                         return kFALSE;
169                 } else {
170                         AliDebug(2,Form("Old filename format <%s>.", filename.Data()));
171                         id.SetSubVersion(-11); // TODO trick to ensure backward compatibility
172                 }
173
174         } else {
175                 id.SetSubVersion(-1); // TODO trick to ensure backward compatibility
176         }
177
178         filename.Resize(filename.Length() - sizeof(".root") + 1);
179
180         TObjArray* strArray = (TObjArray*) filename.Tokenize("_");
181
182         TString firstRunString(((TObjString*) strArray->At(0))->GetString());
183         id.SetFirstRun(atoi(firstRunString.Data() + 3));
184         id.SetLastRun(atoi(((TObjString*) strArray->At(1))->GetString()));
185
186         TString verString(((TObjString*) strArray->At(2))->GetString());
187         id.SetVersion(atoi(verString.Data() + 1));
188
189         delete strArray;
190
191         return kTRUE;
192 }
193
194 //_____________________________________________________________________________
195 Bool_t AliCDBGrid::IdToFilename(const AliCDBId& id, TString& filename) const {
196 // build file name from AliCDBId (path, run range, version) and fDBFolder
197
198         if (!id.GetAliCDBRunRange().IsValid()) {
199                 AliDebug(2,Form("Invalid run range <%d, %d>.",
200                         id.GetFirstRun(), id.GetLastRun()));
201                 return kFALSE;
202         }
203
204         if (id.GetVersion() < 0) {
205                 AliDebug(2,Form("Invalid version <%d>.", id.GetVersion()));
206                 return kFALSE;
207         }
208
209         filename = Form("Run%d_%d_v%d",
210                                 id.GetFirstRun(),
211                                 id.GetLastRun(),
212                                 id.GetVersion());
213
214         if (id.GetSubVersion() != -11) filename += "_s0"; // TODO to ensure backward compatibility
215         filename += ".root";
216
217         filename.Prepend(fDBFolder + id.GetPath() + '/');
218
219         return kTRUE;
220 }
221
222 //_____________________________________________________________________________
223 Bool_t AliCDBGrid::PrepareId(AliCDBId& id) {
224 // prepare id (version) of the object that will be stored (called by PutEntry)
225
226         TString initDir(gGrid->Pwd(0));
227
228         TString dirName(fDBFolder);
229
230         Bool_t dirExist=kFALSE;
231
232
233
234         // go to the path; if directory does not exist, create it
235         for(int i=0;i<3;i++){
236                 dirName+=Form("%s/",id.GetPathLevel(i).Data());
237                 dirExist=gGrid->Cd(dirName,0);
238                 if (!dirExist) {
239                         AliDebug(2,Form("Creating new folder <%s> ...",dirName.Data()));
240                         if(!gGrid->Mkdir(dirName,"",0)){
241                                 AliError(Form("Cannot create directory <%s> !",dirName.Data()));
242                                 gGrid->Cd(initDir.Data());
243                         return kFALSE;
244                         }
245
246                         // if folders are new add tags to them
247                         if(i == 1) {
248                                 // TODO Currently disabled
249                                 // add short lived tag!
250                                 // AliInfo("Tagging level 1 folder with \"ShortLived\" tag");
251                                 // if(!AddTag(dirName,"ShortLived_try")){
252                                 //      AliError(Form("Could not tag folder %s !", dirName.Data()));
253                                 //      if(!gGrid->Rmdir(dirName.Data())){
254                                 //              AliError(Form("Unexpected: could not remove %s directory!", dirName.Data()));
255                                 //      }
256                                 //      return 0;
257                                 //}
258
259                         } else if(i == 2) {
260                                 AliDebug(2,"Tagging level 2 folder with \"CDB\" and \"CDB_MD\" tag");
261                                 if(!AddTag(dirName,"CDB")){
262                                         AliError(Form("Could not tag folder %s !", dirName.Data()));
263                                         if(!gGrid->Rmdir(dirName.Data())){
264                                                 AliError(Form("Unexpected: could not remove %s directory!", dirName.Data()));
265                                         }
266                                         return 0;
267                                 }
268                                 if(!AddTag(dirName,"CDB_MD")){
269                                         AliError(Form("Could not tag folder %s !", dirName.Data()));
270                                         if(!gGrid->Rmdir(dirName.Data())){
271                                                 AliError(Form("Unexpected: could not remove %s directory!", dirName.Data()));
272                                         }
273                                         return 0;
274                                 }
275
276                                 // TODO Currently disabled
277                                 // add short lived tag!
278                                 // TString path=id.GetPath();
279                                 // if(AliCDBManager::Instance()->IsShortLived(path.Data())) {
280                                 //      AliInfo(Form("Tagging %s as short lived", dirName.Data()));
281                                 //      if(!TagShortLived(dirName, kTRUE)){
282                                 //              AliError(Form("Could not tag folder %s !", dirName.Data()));
283                                 //              if(!gGrid->Rmdir(dirName.Data())){
284                                 //                      AliError(Form("Unexpected: could not remove %s directory!", dirName.Data()));
285                                 //              }
286                                 //              return 0;
287                                 //      }
288                                 // } else {
289                                 //      AliInfo(Form("Tagging %s as long lived", dirName.Data()));
290                                 //      if(!TagShortLived(dirName, kFALSE)){
291                                 //              AliError(Form("Could not tag folder %s !", dirName.Data()));
292                                 //              if(!gGrid->Rmdir(dirName.Data())){
293                                 //                      AliError(Form("Unexpected: could not remove %s directory!", dirName.Data()));
294                                 //              }
295                                 //              return 0;
296                                 //      }
297                                 // }
298                         }
299                 }
300         }
301         gGrid->Cd(initDir,0);
302
303         TString filename;
304         AliCDBId anId; // the id got from filename
305         AliCDBRunRange lastRunRange(-1,-1); // highest runRange found
306         Int_t lastVersion=0; // highest version found
307
308         TGridResult *res = gGrid->Ls(dirName);
309
310         //loop on the files in the directory, look for highest version
311         for(int i=0; i < res->GetEntries(); i++){
312                 filename=res->GetFileNamePath(i);
313                 if (!FilenameToId(filename, anId)) continue;
314                 if (anId.GetAliCDBRunRange().Overlaps(id.GetAliCDBRunRange()) && anId.GetVersion() > lastVersion) {
315                         lastVersion = anId.GetVersion();
316                         lastRunRange = anId.GetAliCDBRunRange();
317                 }
318
319         }
320         delete res;
321
322         id.SetVersion(lastVersion + 1);
323         id.SetSubVersion(0);
324
325         TString lastStorage = id.GetLastStorage();
326         if(lastStorage.Contains(TString("new"), TString::kIgnoreCase) && id.GetVersion() > 1 ){
327                 AliDebug(2, Form("A NEW object is being stored with version %d",
328                                         id.GetVersion()));
329                 AliDebug(2, Form("and it will hide previously stored object with version %d!",
330                                         id.GetVersion()-1));
331         }
332
333         if(!lastRunRange.IsAnyRange() && !(lastRunRange.IsEqual(&id.GetAliCDBRunRange())))
334                 AliWarning(Form("Run range modified w.r.t. previous version (Run%d_%d_v%d)",
335                         lastRunRange.GetFirstRun(), lastRunRange.GetLastRun(), id.GetVersion()));
336
337         return kTRUE;
338 }
339
340 //_____________________________________________________________________________
341 AliCDBId* AliCDBGrid::GetId(const TObjArray& validFileIds, const AliCDBId& query) {
342 // look for the Id that matches query's requests (highest or exact version)
343
344         if(validFileIds.GetEntriesFast() < 1) {
345                 return NULL;
346         } else if (validFileIds.GetEntriesFast() == 1) {
347                 return dynamic_cast<AliCDBId*> (validFileIds.At(0)->Clone());
348         }
349
350         TIter iter(&validFileIds);
351
352         AliCDBId *anIdPtr=0;
353         AliCDBId* result=0;
354
355         while((anIdPtr = dynamic_cast<AliCDBId*> (iter.Next()))){
356                 if(anIdPtr->GetPath() != query.GetPath()) continue;
357
358                 //if(!CheckVersion(query, anIdPtr, result)) return NULL;
359
360                 if (!query.HasVersion()){ // look for highest version
361                         if(result && result->GetVersion() > anIdPtr->GetVersion()) continue;
362                         if(result && result->GetVersion() == anIdPtr->GetVersion()) {
363                                 AliError(Form("More than one object valid for run %d, version %d!",
364                                         query.GetFirstRun(), anIdPtr->GetVersion()));
365                                 return NULL;
366                         }
367                         result = anIdPtr;
368                 } else { // look for specified version
369                         if(query.GetVersion() != anIdPtr->GetVersion()) continue;
370                         if(result && result->GetVersion() == anIdPtr->GetVersion()){
371                                 AliError(Form("More than one object valid for run %d, version %d!",
372                                         query.GetFirstRun(), anIdPtr->GetVersion()));
373                                 return NULL;
374                         }
375                         result = anIdPtr;
376                 }
377
378         }
379         
380         if (!result) return NULL;
381
382         return dynamic_cast<AliCDBId*> (result->Clone());
383 }
384
385 //_____________________________________________________________________________
386 AliCDBId* AliCDBGrid::GetEntryId(const AliCDBId& queryId) {
387 // get AliCDBId from the database
388 // User must delete returned object
389
390         AliCDBId* dataId=0;
391
392         AliCDBId selectedId(queryId);
393         if (!selectedId.HasVersion()) {
394                 // if version is not specified, first check the selection criteria list
395                 GetSelection(&selectedId);
396         }
397
398         TObjArray validFileIds;
399         validFileIds.SetOwner(1);
400
401         // look for file matching query requests (path, runRange, version)
402         if(selectedId.GetFirstRun() == fRun &&
403                         fPathFilter.Comprises(selectedId.GetAliCDBPath()) && fVersion < 0 && !fMetaDataFilter){
404                 // look into list of valid files previously loaded with AliCDBStorage::FillValidFileIds()
405                 AliDebug(2, Form("List of files valid for run %d and for path %s was loaded. Looking there!",
406                                         selectedId.GetFirstRun(), selectedId.GetPath().Data()));
407                 dataId = GetId(fValidFileIds, selectedId);
408
409         } else {
410                 // List of files valid for reqested run was not loaded. Looking directly into CDB
411                 AliDebug(2, Form("List of files valid for run %d and for path %s was not loaded. Looking directly into CDB!",
412                                         selectedId.GetFirstRun(), selectedId.GetPath().Data()));
413
414                 TString filter;
415                 MakeQueryFilter(selectedId.GetFirstRun(), selectedId.GetLastRun(), 0, filter);
416
417                 TString pattern = Form("%s/Run*", selectedId.GetPath().Data());
418                 if(selectedId.GetVersion() >= 0) pattern += Form("_v%d*",selectedId.GetVersion());
419                 pattern += ".root";
420                 AliDebug(2,Form("pattern: %s", pattern.Data()));
421
422                 TGridResult *res = gGrid->Query(fDBFolder, pattern, filter, "");
423                 if (res) {
424                         AliCDBId validFileId;
425                         for(int i=0; i<res->GetEntries(); i++){
426                                 TString filename = res->GetKey(i, "lfn");
427                                 if(filename == "") continue;
428                                 if(FilenameToId(filename, validFileId))
429                                                 validFileIds.AddLast(validFileId.Clone());
430                         }
431                         delete res;
432                 }       
433                 dataId = GetId(validFileIds, selectedId);
434         }
435
436         return dataId;
437 }
438
439 //_____________________________________________________________________________
440 AliCDBEntry* AliCDBGrid::GetEntry(const AliCDBId& queryId) {
441 // get AliCDBEntry from the database
442
443         AliCDBId* dataId = GetEntryId(queryId);
444
445         if (!dataId) return NULL;
446
447         TString filename;
448         if (!IdToFilename(*dataId, filename)) {
449                 AliDebug(2,Form("Bad data ID encountered! Subnormal error!"));
450                 delete dataId;
451                 return NULL;
452         }
453
454         AliCDBEntry* anEntry = GetEntryFromFile(filename, dataId);
455
456         delete dataId;
457         return anEntry;
458 }
459
460 //_____________________________________________________________________________
461 AliCDBEntry* AliCDBGrid::GetEntryFromFile(TString& filename, AliCDBId* dataId){
462 // Get AliCBEntry object from file "filename"
463
464         AliDebug(2,Form("Opening file: %s",filename.Data()));
465
466         filename.Prepend("/alien");
467
468         // if option="CACHEREAD" TFile will use the local caching facility!
469         TString option="READ";
470         if(fCacheFolder != ""){
471
472                 // Check if local cache folder was changed in the meanwhile
473                 TString origCache(TFile::GetCacheFileDir());
474                 if(fCacheFolder != origCache) {
475                         AliWarning(Form("Local cache folder has been overwritten!! fCacheFolder = %s origCache = %s",
476                                         fCacheFolder.Data(), origCache.Data()));
477                         TFile::SetCacheFileDir(fCacheFolder.Data(), fOperateDisconnected);
478                         TFile::ShrinkCacheFileDir(fCacheSize, fCleanupInterval);
479                 }
480
481                 option.Prepend("CACHE");
482         }
483
484         AliDebug(2, Form("Option: %s", option.Data()));
485
486         TFile *file = TFile::Open(filename, option);
487         if (!file) {
488                 AliDebug(2,Form("Can't open file <%s>!", filename.Data()));
489                 return NULL;
490         }
491
492         // get the only AliCDBEntry object from the file
493         // the object in the file is an AliCDBEntry entry named "AliCDBEntry"
494
495         AliCDBEntry* anEntry = dynamic_cast<AliCDBEntry*> (file->Get("AliCDBEntry"));
496
497         if (!anEntry) {
498                 AliDebug(2,Form("Bad storage data: file does not contain an AliCDBEntry object!"));
499                 file->Close();
500                 return NULL;
501         }
502
503         // The object's Id is not reset during storage
504         // If object's Id runRange or version do not match with filename,
505         // it means that someone renamed file by hand. In this case a warning msg is issued.
506
507         if(anEntry){
508                 AliCDBId entryId = anEntry->GetId();
509                 Int_t tmpSubVersion = dataId->GetSubVersion();
510                 dataId->SetSubVersion(entryId.GetSubVersion()); // otherwise filename and id may mismatch
511                 if(!entryId.IsEqual(dataId)){
512                         AliWarning(Form("Mismatch between file name and object's Id!"));
513                         AliWarning(Form("File name: %s", dataId->ToString().Data()));
514                         AliWarning(Form("Object's Id: %s", entryId.ToString().Data()));
515                 }
516                 dataId->SetSubVersion(tmpSubVersion);
517         }
518
519         anEntry->SetLastStorage("grid");
520
521         // Check whether entry contains a TTree. In case load the tree in memory!
522         LoadTreeFromFile(anEntry);
523
524         // close file, return retieved entry
525         file->Close(); delete file; file=0;
526
527         return anEntry;
528 }
529
530 //_____________________________________________________________________________
531 TList* AliCDBGrid::GetEntries(const AliCDBId& queryId) {
532 // multiple request (AliCDBStorage::GetAll)
533
534         TList* result = new TList();
535         result->SetOwner();
536
537         TObjArray validFileIds;
538         validFileIds.SetOwner(1);
539
540         Bool_t alreadyLoaded = kFALSE;
541
542         // look for file matching query requests (path, runRange)
543         if(queryId.GetFirstRun() == fRun &&
544                         fPathFilter.Comprises(queryId.GetAliCDBPath()) && fVersion < 0 && !fMetaDataFilter){
545                 // look into list of valid files previously loaded with AliCDBStorage::FillValidFileIds()
546                 AliDebug(2,Form("List of files valid for run %d and for path %s was loaded. Looking there!",
547                                         queryId.GetFirstRun(), queryId.GetPath().Data()));
548
549                 alreadyLoaded = kTRUE;
550
551         } else {
552                 // List of files valid for reqested run was not loaded. Looking directly into CDB
553                 AliDebug(2,Form("List of files valid for run %d and for path %s was not loaded. Looking directly into CDB!",
554                                         queryId.GetFirstRun(), queryId.GetPath().Data()));
555
556                 TString filter;
557                 MakeQueryFilter(queryId.GetFirstRun(), queryId.GetLastRun(), 0, filter);
558
559                 TString pattern = Form("%s/Run*.root", queryId.GetPath().Data());
560                 AliDebug(2,Form("pattern: %s", pattern.Data()));
561
562                 TGridResult *res = gGrid->Query(fDBFolder, pattern, filter, "");
563
564                 AliCDBId validFileId;
565                 for(int i=0; i<res->GetEntries(); i++){
566                         TString filename = res->GetKey(i, "lfn");
567                         if(filename == "") continue;
568                         if(FilenameToId(filename, validFileId))
569                                         validFileIds.AddLast(validFileId.Clone());
570                 }
571                 delete res;
572         }
573
574         TIter *iter=0;
575         if(alreadyLoaded){
576                 iter = new TIter(&fValidFileIds);
577         } else {
578                 iter = new TIter(&validFileIds);
579         }
580
581         TObjArray selectedIds;
582         selectedIds.SetOwner(1);
583
584         // loop on list of valid Ids to select the right version to get.
585         // According to query and to the selection criteria list, version can be the highest or exact
586         AliCDBPath pathCopy;
587         AliCDBId* anIdPtr=0;
588         AliCDBId* dataId=0;
589         AliCDBPath queryPath = queryId.GetAliCDBPath();
590         while((anIdPtr = dynamic_cast<AliCDBId*> (iter->Next()))){
591                 AliCDBPath thisCDBPath = anIdPtr->GetAliCDBPath();
592                 if(!(queryPath.Comprises(thisCDBPath)) || pathCopy.GetPath() == thisCDBPath.GetPath()) continue;
593                 pathCopy = thisCDBPath;
594
595                 // check the selection criteria list for this query
596                 AliCDBId thisId(*anIdPtr);
597                 thisId.SetVersion(queryId.GetVersion());
598                 if(!thisId.HasVersion()) GetSelection(&thisId);
599
600                 if(alreadyLoaded){
601                         dataId = GetId(fValidFileIds, thisId);
602                 } else {
603                         dataId = GetId(validFileIds, thisId);
604                 }
605                 if(dataId) selectedIds.Add(dataId);
606         }
607
608         delete iter; iter=0;
609
610         // selectedIds contains the Ids of the files matching all requests of query!
611         // All the objects are now ready to be retrieved
612         iter = new TIter(&selectedIds);
613         while((anIdPtr = dynamic_cast<AliCDBId*> (iter->Next()))){
614                 TString filename;
615                 if (!IdToFilename(*anIdPtr, filename)) {
616                         AliDebug(2,Form("Bad data ID encountered! Subnormal error!"));
617                         continue;
618                 }
619
620                 AliCDBEntry* anEntry = GetEntryFromFile(filename, anIdPtr);
621
622                 if(anEntry) result->Add(anEntry);
623
624         }
625         delete iter; iter=0;
626
627         return result;
628 }
629
630 //_____________________________________________________________________________
631 Bool_t AliCDBGrid::PutEntry(AliCDBEntry* entry) {
632 // put an AliCDBEntry object into the database
633
634         AliCDBId& id = entry->GetId();
635
636         // set version for the entry to be stored
637         if (!PrepareId(id)) return kFALSE;
638
639         // build filename from entry's id
640         TString filename;
641         if (!IdToFilename(id, filename)) {
642                 AliError("Bad ID encountered! Subnormal error!");
643                 return kFALSE;
644         }
645
646         TString folderToTag = Form("%s%s",
647                                         fDBFolder.Data(),
648                                         id.GetPath().Data());
649
650         TDirectory* saveDir = gDirectory;
651
652         TString fullFilename = Form("/alien%s", filename.Data());
653         // specify SE to filename
654         if (fSE != "default") fullFilename += Form("?se=%s",fSE.Data());
655
656         // open file
657         TFile *file = TFile::Open(fullFilename,"CREATE");
658         if(!file || !file->IsWritable()){
659                 AliError(Form("Can't open file <%s>!", filename.Data()));
660                 if(file && !file->IsWritable()) file->Close(); delete file; file=0;
661                 return kFALSE;
662         }
663
664         file->cd();
665
666         //SetTreeToFile(entry, file);
667
668         entry->SetVersion(id.GetVersion());
669
670         // write object (key name: "AliCDBEntry")
671         Bool_t result = (file->WriteTObject(entry, "AliCDBEntry") != 0);
672         if (!result) AliError(Form("Can't write entry to file <%s>!", filename.Data()));
673
674
675         if (saveDir) saveDir->cd(); else gROOT->cd();
676         file->Close(); delete file; file=0;
677
678         if(result) {
679         
680                 if(!TagFileId(filename, &id)){
681                         AliInfo(Form("CDB tagging failed. Deleting file %s!",filename.Data()));
682                         if(!gGrid->Rm(filename.Data()))
683                                 AliError("Can't delete file!");
684                         return kFALSE;
685                 }
686
687                 TagFileMetaData(filename, entry->GetMetaData());
688         }
689
690         AliInfo(Form("CDB object stored into file %s", filename.Data()));
691         AliInfo(Form("Storage Element: %s", fSE.Data()));
692         return result;
693 }
694 //_____________________________________________________________________________
695 Bool_t AliCDBGrid::AddTag(TString& folderToTag, const char* tagname){
696 // add "tagname" tag (CDB or CDB_MD) to folder where object will be stored
697
698         Bool_t result = kTRUE;
699         AliDebug(2, Form("adding %s tag to folder %s", tagname, folderToTag.Data()));
700         TString addTag = Form("addTag %s %s", folderToTag.Data(), tagname);
701         TGridResult *gridres = gGrid->Command(addTag.Data());
702         const char* resCode = gridres->GetKey(0,"__result__"); // '1' if success
703         if(resCode[0] != '1') {
704                 AliError(Form("Couldn't add %s tags to folder %s !",
705                                                 tagname, folderToTag.Data()));
706                 result = kFALSE;
707         }
708         delete gridres;
709         return result;
710 }
711
712 //_____________________________________________________________________________
713 Bool_t AliCDBGrid::TagFileId(TString& filename, const AliCDBId* id){
714 // tag stored object in CDB table using object Id's parameters
715
716         TString addTagValue1 = Form("addTagValue %s CDB ", filename.Data());
717         TString addTagValue2 = Form("first_run=%d last_run=%d version=%d ",
718                                         id->GetFirstRun(),
719                                         id->GetLastRun(),
720                                         id->GetVersion());
721         TString addTagValue3 = Form("path_level_0=\"%s\" path_level_1=\"%s\" path_level_2=\"%s\"",
722                                         id->GetPathLevel(0).Data(),
723                                         id->GetPathLevel(1).Data(),
724                                         id->GetPathLevel(2).Data());
725         TString addTagValue = Form("%s%s%s",
726                                         addTagValue1.Data(),
727                                         addTagValue2.Data(),
728                                         addTagValue3.Data());
729
730         Bool_t result = kFALSE;
731         AliDebug(2, Form("Tagging file. Tag command: %s", addTagValue.Data()));
732         TGridResult* res = gGrid->Command(addTagValue.Data());
733         const char* resCode = res->GetKey(0,"__result__"); // '1' if success
734         if(resCode[0] != '1') {
735                 AliError(Form("Couldn't add CDB tag value to file %s !",
736                                                 filename.Data()));
737                 result = kFALSE;
738         } else {
739                 AliDebug(2, "Object successfully tagged.");
740                 result = kTRUE;
741         }
742         delete res;
743         return result;
744
745 }
746
747 //_____________________________________________________________________________
748 Bool_t AliCDBGrid::TagShortLived(TString& filename, Bool_t value){
749 // tag folder with ShortLived tag
750
751         TString addTagValue = Form("addTagValue %s ShortLived_try value=%d", filename.Data(), value);
752
753         Bool_t result = kFALSE;
754         AliDebug(2, Form("Tagging file. Tag command: %s", addTagValue.Data()));
755         TGridResult* res = gGrid->Command(addTagValue.Data());
756         const char* resCode = res->GetKey(0,"__result__"); // '1' if success
757         if(resCode[0] != '1') {
758                 AliError(Form("Couldn't add ShortLived tag value to file %s !", filename.Data()));
759                 result = kFALSE;
760         } else {
761                 AliDebug(2,"Object successfully tagged.");
762                 result = kTRUE;
763         }
764         delete res;
765         return result;
766
767 }
768
769 //_____________________________________________________________________________
770 Bool_t AliCDBGrid::TagFileMetaData(TString& filename, const AliCDBMetaData* md){
771 // tag stored object in CDB table using object Id's parameters
772
773         TString addTagValue1 = Form("addTagValue %s CDB_MD ", filename.Data());
774         TString addTagValue2 = Form("object_classname=\"%s\" responsible=\"%s\" beam_period=%d ",
775                                         md->GetObjectClassName(),
776                                         md->GetResponsible(),
777                                         md->GetBeamPeriod());
778         TString addTagValue3 = Form("aliroot_version=\"%s\" comment=\"%s\"",
779                                         md->GetAliRootVersion(),
780                                         md->GetComment());
781         TString addTagValue = Form("%s%s%s",
782                                         addTagValue1.Data(),
783                                         addTagValue2.Data(),
784                                         addTagValue3.Data());
785
786         Bool_t result = kFALSE;
787         AliDebug(2, Form("Tagging file. Tag command: %s", addTagValue.Data()));
788         TGridResult* res = gGrid->Command(addTagValue.Data());
789         const char* resCode = res->GetKey(0,"__result__"); // '1' if success
790         if(resCode[0] != '1') {
791                 AliWarning(Form("Couldn't add CDB_MD tag value to file %s !",
792                                                 filename.Data()));
793                 result = kFALSE;
794         } else {
795                 AliDebug(2,"Object successfully tagged.");
796                 result = kTRUE;
797         }
798         return result;
799 }
800
801 //_____________________________________________________________________________
802 TList* AliCDBGrid::GetIdListFromFile(const char* fileName){
803
804         TString turl(fileName);
805         turl.Prepend("/alien" + fDBFolder);
806         turl += "?se="; turl += fSE.Data();
807         TFile *file = TFile::Open(turl);
808         if (!file) {
809                 AliError(Form("Can't open selection file <%s>!", turl.Data()));
810                 return NULL;
811         }
812
813         TList *list = new TList();
814         list->SetOwner();
815         int i=0;
816         TString keycycle;
817
818         AliCDBId *id;
819         while(1){
820                 i++;
821                 keycycle = "AliCDBId;";
822                 keycycle+=i;
823                 
824                 id = (AliCDBId*) file->Get(keycycle);
825                 if(!id) break;
826                 list->AddFirst(id);
827         }
828         file->Close(); delete file; file=0;
829         
830         return list;
831
832
833 }
834
835 //_____________________________________________________________________________
836 Bool_t AliCDBGrid::Contains(const char* path) const{
837 // check for path in storage's DBFolder
838
839         TString initDir(gGrid->Pwd(0));
840         TString dirName(fDBFolder);
841         dirName += path; // dirName = fDBFolder/path
842         Bool_t result=kFALSE;
843         if (gGrid->Cd(dirName,0)) result=kTRUE;
844         gGrid->Cd(initDir.Data(),0);
845         return result;
846 }
847
848 //_____________________________________________________________________________
849 void AliCDBGrid::QueryValidFiles()
850 {
851 // Query the CDB for files valid for AliCDBStorage::fRun
852 // fills list fValidFileIds with AliCDBId objects created from file name
853
854         TString filter;
855         MakeQueryFilter(fRun, fRun, fMetaDataFilter, filter);
856
857         TString pattern = Form("%s/Run*", fPathFilter.GetPath().Data());
858         if(fVersion >= 0) pattern += Form("_v%d*", fVersion);
859         pattern += ".root";
860         AliDebug(2,Form("pattern: %s", pattern.Data()));
861
862         TGridResult *res = gGrid->Query(fDBFolder, pattern, filter, "");
863
864         if (!res) {
865                 AliError("Grid query failed");
866                 return;
867         }
868
869         AliCDBId validFileId;
870         for(int i=0; i<res->GetEntries(); i++){
871                 TString filename = res->GetKey(i, "lfn");
872                 if(filename == "") continue;
873                 AliDebug(2,Form("Found valid file: %s", filename.Data()));
874                 Bool_t result = FilenameToId(filename, validFileId);
875                 if(result) {
876                         fValidFileIds.AddLast(validFileId.Clone());
877                 }
878         }
879         delete res;
880
881 }
882
883 //_____________________________________________________________________________
884 void AliCDBGrid::MakeQueryFilter(Int_t firstRun, Int_t lastRun,
885                                         const AliCDBMetaData* md, TString& result) const
886 {
887 // create filter for file query
888
889         result = Form("CDB:first_run<=%d and CDB:last_run>=%d", firstRun, lastRun);
890
891 //      if(version >= 0) {
892 //              result += Form(" and CDB:version=%d", version);
893 //      }
894 //      if(pathFilter.GetLevel0() != "*") {
895 //              result += Form(" and CDB:path_level_0=\"%s\"", pathFilter.GetLevel0().Data());
896 //      }
897 //      if(pathFilter.GetLevel1() != "*") {
898 //              result += Form(" and CDB:path_level_1=\"%s\"", pathFilter.GetLevel1().Data());
899 //      }
900 //      if(pathFilter.GetLevel2() != "*") {
901 //              result += Form(" and CDB:path_level_2=\"%s\"", pathFilter.GetLevel2().Data());
902 //      }
903
904         if(md){
905                 if(md->GetObjectClassName()[0] != '\0') {
906                         result += Form(" and CDB_MD:object_classname=\"%s\"", md->GetObjectClassName());
907                 }
908                 if(md->GetResponsible()[0] != '\0') {
909                         result += Form(" and CDB_MD:responsible=\"%s\"", md->GetResponsible());
910                 }
911                 if(md->GetBeamPeriod() != 0) {
912                         result += Form(" and CDB_MD:beam_period=%d", md->GetBeamPeriod());
913                 }
914                 if(md->GetAliRootVersion()[0] != '\0') {
915                         result += Form(" and CDB_MD:aliroot_version=\"%s\"", md->GetAliRootVersion());
916                 }
917                 if(md->GetComment()[0] != '\0') {
918                         result += Form(" and CDB_MD:comment=\"%s\"", md->GetComment());
919                 }
920         }
921         AliDebug(2, Form("filter: %s",result.Data()));
922
923 }
924
925 //_____________________________________________________________________________
926 Int_t AliCDBGrid::GetLatestVersion(const char* path, Int_t run){
927 // get last version found in the database valid for run and path
928
929         AliCDBPath aCDBPath(path);
930         if(!aCDBPath.IsValid() || aCDBPath.IsWildcard()) {
931                 AliError(Form("Invalid path in request: %s", path));
932                 return -1;
933         }
934         AliCDBId query(path, run, run, -1, -1);
935         AliCDBId* dataId = 0;
936
937         // look for file matching query requests (path, runRange, version)
938         if(run == fRun && fPathFilter.Comprises(aCDBPath) && fVersion < 0){
939                 // look into list of valid files previously loaded with AliCDBStorage::FillValidFileIds()
940                 AliDebug(2, Form("List of files valid for run %d and for path %s was loaded. Looking there!",
941                                         run, path));
942                 dataId = GetId(fValidFileIds, query);
943                 if (!dataId) return -1;
944                 Int_t version = dataId->GetVersion();
945                 delete dataId;
946                 return version;
947
948         }
949         // List of files valid for reqested run was not loaded. Looking directly into CDB
950         AliDebug(2, Form("List of files valid for run %d and for path %s was not loaded. Looking directly into CDB!",
951                                 run, path));
952
953         TObjArray validFileIds;
954         validFileIds.SetOwner(1);
955
956         TString filter;
957         MakeQueryFilter(run, run, 0, filter);
958
959         TString pattern = Form("%s/Run*.root", path);
960         AliDebug(2,Form("pattern: %s", pattern.Data()));
961
962         TGridResult *res = gGrid->Query(fDBFolder, pattern, filter, "");
963         AliCDBId validFileId;
964         for(int i=0; i<res->GetEntries(); i++){
965                 TString filename = res->GetKey(i, "lfn");
966                 if(filename == "") continue;
967                 if(FilenameToId(filename, validFileId))
968                                 validFileIds.AddLast(validFileId.Clone());
969         }
970         delete res;
971
972         dataId = GetId(validFileIds, query);
973         if (!dataId) return -1;
974
975         Int_t version = dataId->GetVersion();
976         delete dataId;
977         return version;
978
979 }
980
981 //_____________________________________________________________________________
982 Int_t AliCDBGrid::GetLatestSubVersion(const char* /*path*/, Int_t /*run*/, Int_t /*version*/){
983 // get last subversion found in the database valid for run and path
984         AliError("Objects in GRID storage have no sub version!");
985         return -1;
986 }
987
988
989 /////////////////////////////////////////////////////////////////////////////////////////////////
990 //                                                                                             //
991 // AliCDBGrid factory                                                                          //
992 //                                                                                             //
993 /////////////////////////////////////////////////////////////////////////////////////////////////
994
995 ClassImp(AliCDBGridFactory)
996
997 //_____________________________________________________________________________
998 Bool_t AliCDBGridFactory::Validate(const char* gridString) {
999 // check if the string is valid Grid URI
1000
1001         TRegexp gridPattern("^alien://.+$");
1002
1003         return TString(gridString).Contains(gridPattern);
1004 }
1005
1006 //_____________________________________________________________________________
1007 AliCDBParam* AliCDBGridFactory::CreateParameter(const char* gridString) {
1008 // create AliCDBGridParam class from the URI string
1009
1010         if (!Validate(gridString)) {
1011                 return NULL;
1012         }
1013
1014         TString buffer(gridString);
1015
1016         TString gridUrl         = "alien://";
1017         TString user            = "";
1018         TString dbFolder        = "";
1019         TString se              = "default";
1020         TString cacheFolder     = "";
1021         Bool_t  operateDisconnected = kTRUE;
1022         Long64_t cacheSize          = (UInt_t) 1024*1024*1024; // 1GB
1023         Long_t cleanupInterval      = 0;
1024
1025         TObjArray *arr = buffer.Tokenize('?');
1026         TIter iter(arr);
1027         TObjString *str = 0;
1028
1029         while((str = (TObjString*) iter.Next())){
1030                 TString entry(str->String());
1031                 Int_t indeq = entry.Index('=');
1032                 if(indeq == -1) {
1033                         if(entry.BeginsWith("alien://")) { // maybe it's a gridUrl!
1034                                 gridUrl = entry;
1035                                 continue;
1036                         } else {
1037                                 AliError(Form("Invalid entry! %s",entry.Data()));
1038                                 continue;
1039                         }
1040                 }
1041                 
1042                 TString key = entry(0,indeq);
1043                 TString value = entry(indeq+1,entry.Length()-indeq);
1044
1045                 if(key.Contains("grid",TString::kIgnoreCase)) {
1046                         gridUrl += value;
1047                 }
1048                 else if (key.Contains("user",TString::kIgnoreCase)){
1049                         user = value;
1050                 }
1051                 else if (key.Contains("se",TString::kIgnoreCase)){
1052                         se = value;
1053                 }
1054                 else if (key.Contains("cacheF",TString::kIgnoreCase)){
1055                         cacheFolder = value;
1056                         if (!cacheFolder.EndsWith("/"))
1057                                 cacheFolder += "/";
1058                 }
1059                 else if (key.Contains("folder",TString::kIgnoreCase)){
1060                         dbFolder = value;
1061                 }
1062                 else if (key.Contains("operateDisc",TString::kIgnoreCase)){
1063                         if(value == "kTRUE") {
1064                                 operateDisconnected = kTRUE;
1065                         } else if (value == "kFALSE") {
1066                                 operateDisconnected = kFALSE;
1067                         } else if (value == "0" || value == "1") {
1068                                 operateDisconnected = (Bool_t) value.Atoi();
1069                         } else {
1070                                 AliError(Form("Invalid entry! %s",entry.Data()));
1071                                 return NULL;
1072                         }
1073                 }
1074                 else if (key.Contains("cacheS",TString::kIgnoreCase)){
1075                         if(value.IsDigit()) {
1076                                 cacheSize = value.Atoi();
1077                         } else {
1078                                 AliError(Form("Invalid entry! %s",entry.Data()));
1079                                 return NULL;
1080                         }
1081                 }
1082                 else if (key.Contains("cleanupInt",TString::kIgnoreCase)){
1083                         if(value.IsDigit()) {
1084                                 cleanupInterval = value.Atoi();
1085                         } else {
1086                                 AliError(Form("Invalid entry! %s",entry.Data()));
1087                                 return NULL;
1088                         }
1089                 }
1090                 else{
1091                         AliError(Form("Invalid entry! %s",entry.Data()));
1092                         return NULL;
1093                 }
1094         }
1095         delete arr; arr=0;
1096
1097         AliDebug(2, Form("gridUrl:      %s", gridUrl.Data()));
1098         AliDebug(2, Form("user: %s", user.Data()));
1099         AliDebug(2, Form("dbFolder:     %s", dbFolder.Data()));
1100         AliDebug(2, Form("s.e.: %s", se.Data()));
1101         AliDebug(2, Form("local cache folder: %s", cacheFolder.Data()));
1102         AliDebug(2, Form("local cache operate disconnected: %d", operateDisconnected));
1103         AliDebug(2, Form("local cache size: %d", cacheSize));
1104         AliDebug(2, Form("local cache cleanup interval: %d", cleanupInterval));
1105
1106         if(dbFolder == ""){
1107                 AliError("Base folder must be specified!");
1108                 return NULL;
1109         }
1110
1111         return new AliCDBGridParam(gridUrl.Data(), user.Data(),
1112                           dbFolder.Data(), se.Data(), cacheFolder.Data(),
1113                           operateDisconnected, cacheSize, cleanupInterval);
1114 }
1115
1116 //_____________________________________________________________________________
1117 AliCDBStorage* AliCDBGridFactory::Create(const AliCDBParam* param) {
1118 // create AliCDBGrid storage instance from parameters
1119         
1120         AliCDBGrid *grid = 0;
1121         if (AliCDBGridParam::Class() == param->IsA()) {
1122
1123                 const AliCDBGridParam* gridParam = (const AliCDBGridParam*) param;
1124                 grid = new AliCDBGrid(gridParam->GridUrl().Data(),
1125                                       gridParam->GetUser().Data(),
1126                                       gridParam->GetDBFolder().Data(),
1127                                       gridParam->GetSE().Data(),
1128                                       gridParam->GetCacheFolder().Data(),
1129                                       gridParam->GetOperateDisconnected(),
1130                                       gridParam->GetCacheSize(),
1131                                       gridParam->GetCleanupInterval());
1132
1133         }
1134
1135         if(!gGrid && grid) {
1136                 delete grid; grid=0;
1137         }
1138
1139         return grid;
1140 }
1141
1142 /////////////////////////////////////////////////////////////////////////////////////////////////
1143 //                                                                                             //
1144 // AliCDBGrid Parameter class                                                                  //                                         //
1145 //                                                                                             //
1146 /////////////////////////////////////////////////////////////////////////////////////////////////
1147
1148 ClassImp(AliCDBGridParam)
1149
1150 //_____________________________________________________________________________
1151 AliCDBGridParam::AliCDBGridParam():
1152  AliCDBParam(),
1153  fGridUrl(),
1154  fUser(),
1155  fDBFolder(),
1156  fSE(),
1157  fCacheFolder(),
1158  fOperateDisconnected(),
1159  fCacheSize(),
1160  fCleanupInterval()
1161
1162  {
1163 // default constructor
1164
1165 }
1166
1167 //_____________________________________________________________________________
1168 AliCDBGridParam::AliCDBGridParam(const char* gridUrl, const char* user, const char* dbFolder,
1169                                 const char* se, const char* cacheFolder, Bool_t operateDisconnected,
1170                                 Long64_t cacheSize, Long_t cleanupInterval):
1171  AliCDBParam(),
1172  fGridUrl(gridUrl),
1173  fUser(user),
1174  fDBFolder(dbFolder),
1175  fSE(se),
1176  fCacheFolder(cacheFolder),
1177  fOperateDisconnected(operateDisconnected),
1178  fCacheSize(cacheSize),
1179  fCleanupInterval(cleanupInterval)
1180 {
1181 // constructor
1182
1183         SetType("alien");
1184
1185         TString uri = Form("%s?User=%s?DBFolder=%s?SE=%s?CacheFolder=%s"
1186                         "?OperateDisconnected=%d?CacheSize=%d?CleanupInterval=%d",
1187                         fGridUrl.Data(), fUser.Data(),
1188                         fDBFolder.Data(), fSE.Data(), fCacheFolder.Data(),
1189                         fOperateDisconnected, fCacheSize, fCleanupInterval);
1190
1191         SetURI(uri.Data());
1192 }
1193
1194 //_____________________________________________________________________________
1195 AliCDBGridParam::~AliCDBGridParam() {
1196 // destructor
1197
1198 }
1199
1200 //_____________________________________________________________________________
1201 AliCDBParam* AliCDBGridParam::CloneParam() const {
1202 // clone parameter
1203
1204         return new AliCDBGridParam(fGridUrl.Data(), fUser.Data(),
1205                                         fDBFolder.Data(), fSE.Data(), fCacheFolder.Data(),
1206                                         fOperateDisconnected, fCacheSize, fCleanupInterval);
1207 }
1208
1209 //_____________________________________________________________________________
1210 ULong_t AliCDBGridParam::Hash() const {
1211 // return Hash function
1212
1213         return fGridUrl.Hash()+fUser.Hash()+fDBFolder.Hash()+fSE.Hash()+fCacheFolder.Hash();
1214 }
1215
1216 //_____________________________________________________________________________
1217 Bool_t AliCDBGridParam::IsEqual(const TObject* obj) const {
1218 // check if this object is equal to AliCDBParam obj
1219
1220         if (this == obj) {
1221                 return kTRUE;
1222         }
1223
1224         if (AliCDBGridParam::Class() != obj->IsA()) {
1225                 return kFALSE;
1226         }
1227
1228         AliCDBGridParam* other = (AliCDBGridParam*) obj;
1229
1230         if(fGridUrl != other->fGridUrl) return kFALSE;
1231         if(fUser != other->fUser) return kFALSE;
1232         if(fDBFolder != other->fDBFolder) return kFALSE;
1233         if(fSE != other->fSE) return kFALSE;
1234         if(fCacheFolder != other->fCacheFolder) return kFALSE;
1235         if(fOperateDisconnected != other->fOperateDisconnected) return kFALSE;
1236         if(fCacheSize != other->fCacheSize) return kFALSE;
1237         if(fCleanupInterval != other->fCleanupInterval) return kFALSE;
1238         return kTRUE;
1239 }
1240