TAlienFile.cxx

Go to the documentation of this file.
00001 // @(#)root/alien:$Id: TAlienFile.cxx 27745 2009-03-10 11:38:26Z rdm $
00002 // Author: Andreas Peters 11/09/2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2003, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TAlienFile                                                           //
00015 //                                                                      //
00016 // A TAlienFile is like a normal TFile except that it reads and writes  //
00017 // it's data via TXNetFile and gets authorization and the TXNetFile     //
00018 // URL from an alien service.                                           //
00019 //                                                                      //
00020 // Filenames are standard URL format with protocol "alien".             //
00021 // The following are valid TAlienFile URL's:                            //
00022 //                                                                      //
00023 //    alien:///alice/cern.ch/user/p/peters/test.root                    //
00024 //    /alien/alice/cern.ch/user/p/peters/test.root                      //
00025 //                                                                      //
00026 //    - notice that URLs like /alien/alice... are converted internally  //
00027 //      to alien://alice...                                             //
00028 //                                                                      //
00029 //////////////////////////////////////////////////////////////////////////
00030 
00031 #include "TAlienFile.h"
00032 #include "TAlienResult.h"
00033 #include "TAlien.h"
00034 #include "TROOT.h"
00035 #include "TObjString.h"
00036 #include "TMap.h"
00037 #include "TObjArray.h"
00038 #include "TString.h"
00039 #include "Rtypes.h"
00040 #include "TSystem.h"
00041 #include "TVirtualMonitoring.h"
00042 #include "TVirtualMutex.h"
00043 #include "TProcessUUID.h"
00044 #include "TUrl.h"
00045 #include "TError.h"
00046 #include <cstdlib>
00047 
00048 ClassImp(TAlienFile)
00049 
00050 #define MAX_FILE_IMAGES 16
00051 
00052 //______________________________________________________________________________
00053 TAlienFile::TAlienFile(const char *purl, Option_t *option,
00054                        const char *ftitle, Int_t compress,
00055                        Bool_t parallelopen, const char *lurl,
00056                        const char *authz) :
00057    TXNetFile(purl, option, ftitle, compress, 0, parallelopen, lurl)
00058 {
00059    // Create an Alien File Object. An AliEn File is the same as a TFile
00060    // except that its real tranfer URL is resolved via an Alien service. The url
00061    // argument must be of the form: alien:/[machine]/path/file.root
00062    // Using the option access, another access protocol (PFN) can be
00063    // specified for an LFN e.g.:
00064    //     "alien:///alice/test.root"
00065    // If you want to write a file on specific storage element use the syntax
00066    //     "alien:///alice/test.root?&se=Alice::CERN::Storage"
00067    // The default SE is specified by the enviroment variable alien_CLOSE_SE
00068    //
00069    // If you read a file, the closest file image to alien_CLOSE_SE is taken.
00070    // If the file cannot opened from the closest image, the next image is tried,
00071    // until there is no image location left to be tried.
00072    //
00073    // If the file specified in the URL does not exist, is not accessable
00074    // or can not be created the kZombie bit will be set in the TAlienFile
00075    // object. Use IsZombie() to see if the file is accessable.
00076    // For a description of the option and other arguments see the TFile ctor.
00077    // The preferred interface to this constructor is via TFile::Open().
00078    //
00079    // Warning: TAlienFile objects should only be created through the factory functions:
00080    //    TFile::Open("alien://...");
00081    // or
00082    //    TAlienFile::Open("alien://...");
00083    //
00084    // Don't use "new TAlienFile" directly unless you know, what you are doing
00085    //
00086 
00087    TUrl logicalurl(lurl);
00088    fLfn = logicalurl.GetFile();
00089    fAuthz = authz;
00090 }
00091 
00092 //______________________________________________________________________________
00093 TAlienFile *TAlienFile::Open(const char *url, Option_t *option,
00094                              const char *ftitle, Int_t compress,
00095                              Bool_t parallelopen)
00096 {
00097    // Static method used to create a TAlienFile object. For options see
00098    // TAlienFile ctor.
00099 
00100    if (!gGrid) {
00101       ::Error("TAlienFileAccess", "No GRID connection available!");
00102       return 0;
00103    }
00104    TUrl lUrl(url);
00105 
00106    // Report this open phase as a temp one, since we have no object yet
00107    if (gMonitoringWriter)
00108       gMonitoringWriter->SendFileOpenProgress(0, 0, "alienopen", kFALSE);
00109 
00110    TString name(TString("alien://") + TString(lUrl.GetFile()));
00111    TString fAName = name;
00112    TString fAOption = option;
00113    TUrl fAUrl;
00114    Bool_t fAWritable;
00115    fAWritable = kFALSE;
00116    TString authz;
00117 
00118    // Access a URL.
00119 
00120    TString stmp;
00121    Bool_t create;
00122    Bool_t recreate;
00123    Bool_t update;
00124    Bool_t read;
00125 
00126    TUrl purl(url);
00127 
00128    // find out the storage element and the lfn from the given url
00129    TString storageelement;
00130    storageelement = "";
00131    TString file = purl.GetFile();
00132 
00133    Bool_t publicaccess = kFALSE;
00134    storageelement = gSystem->Getenv("alien_CLOSE_SE");
00135 
00136    // get the options and set the storage element
00137    TString urloptions = purl.GetOptions();
00138    TObjArray *objOptions = urloptions.Tokenize("&");
00139    for (Int_t n = 0; n < objOptions->GetEntries(); n++) {
00140       TString loption = ((TObjString *) objOptions->At(n))->GetName();
00141       TObjArray *objTags = loption.Tokenize("=");
00142       if (objTags->GetEntries() == 2) {
00143          TString key = ((TObjString *) objTags->At(0))->GetName();
00144          TString value = ((TObjString *) objTags->At(1))->GetName();
00145          if (!key.CompareTo("se", TString::kIgnoreCase)) {
00146             storageelement = value;
00147          }
00148          if (!key.CompareTo("publicaccess")) {
00149             if (atoi(value.Data()))
00150                publicaccess = kTRUE;
00151          }
00152       }
00153       delete objTags;
00154    }
00155    delete objOptions;
00156 
00157    fAOption = option;
00158    fAOption.ToUpper();
00159 
00160    TObjString *urlStr = 0;
00161    TObjString *authzStr = 0;
00162    TObjString *seStr = 0;
00163 
00164    TString command;
00165    TString repcommand;
00166    TIterator *iter = 0;
00167    TObject *object = 0;
00168 
00169    TGridResult *result;
00170    TAlienResult *alienResult;
00171    TList *list;
00172 
00173    TString stringurl;
00174    TString anchor;
00175    TObjArray *tokens;
00176    anchor = "";
00177 
00178    TString newurl;
00179    if (fAOption == "NEW")
00180       fAOption = "CREATE";
00181 
00182    create = (fAOption == "CREATE") ? kTRUE : kFALSE;
00183    recreate = (fAOption == "RECREATE") ? kTRUE : kFALSE;
00184    update = (fAOption == "UPDATE") ? kTRUE : kFALSE;
00185    read = (fAOption == "READ") ? kTRUE : kFALSE;
00186 
00187    if (!create && !recreate && !update && !read) {
00188       read = kTRUE;
00189       fAOption = "READ";
00190    }
00191 
00192    if (create || recreate || update) {
00193       fAWritable = kTRUE;
00194    }
00195 
00196    if (recreate) {
00197       fAOption = "RECREATE";
00198       create = kTRUE;
00199    }
00200    /////////////////////////////////////////////////////////////////////////////////////////
00201    // first get an active Grid connection
00202 
00203    if (!gGrid) {
00204       // no TAlien existing ....
00205       ::Error("TAlienFile::Open", "no active GRID connection found");
00206       fAUrl = "";
00207 
00208       // Reset the temp monitoring info
00209       if (gMonitoringWriter)
00210          gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00211 
00212       return 0;
00213    } else {
00214       if ((strcmp(gGrid->GetGrid(), "alien"))) {
00215          ::Error("TAlienFile::Open", "you don't have an active <alien> grid!");
00216          fAUrl = "";
00217 
00218          // Reset the temp monitoring info
00219          if (gMonitoringWriter)
00220             gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00221 
00222          return 0;
00223       }
00224    }
00225 
00226    /////////////////////////////////////////////////////////////////////////////////////////
00227    // get the authorization from the catalogue
00228 
00229    if (read) {
00230       // get the read access
00231       if (publicaccess)
00232          command = TString("access -p read ");
00233       else
00234          command = TString("access read ");
00235    }
00236 
00237    if (create) {
00238       command = TString("access write-once ");
00239    }
00240 
00241    if (recreate) {
00242       command = TString("access write-version ");
00243    }
00244 
00245    if (update) {
00246       command = TString("access write-version ");
00247    }
00248 
00249    command += file;
00250 
00251    if (fAWritable) {
00252       // append the storage element environment variable
00253       command += " ";
00254       command += storageelement;
00255    }
00256 
00257    TString fALfn = file;
00258 
00259    int imagenr = 0;
00260 
00261    do {
00262       imagenr++;
00263       repcommand = command;
00264       if (!fAWritable) {
00265          // in the read case, try all image locations
00266          if (storageelement != "") {
00267             repcommand += " ";
00268             repcommand += storageelement;
00269          } else {
00270             repcommand += " ";
00271             repcommand += "unknown";
00272          }
00273          repcommand += " 0 ";
00274          repcommand += imagenr;
00275       }
00276 
00277       result = gGrid->Command(repcommand.Data(), kFALSE, TAlien::kOUTPUT);
00278       alienResult = dynamic_cast < TAlienResult * >(result);
00279       list = dynamic_cast < TList * >(alienResult);
00280       if (!list) {
00281 
00282          if (seStr)
00283             ::Error("TAlienFile::Open",
00284                     "cannot get the access envelope for %s and image %u in SE <%s>",
00285                     purl.GetUrl(), imagenr, seStr->GetName());
00286          else
00287             ::Error("TAlienFile::Open",
00288                     "cannot get the access envelope for %s and image %u",
00289                     purl.GetUrl(), imagenr);
00290          fAUrl = "";
00291          if (result) {
00292             delete result;
00293          }
00294 
00295          // Reset the temp monitoring info
00296          if (gMonitoringWriter)
00297             gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00298 
00299          return 0;
00300       }
00301 
00302       iter = list->MakeIterator();
00303       object = 0;
00304 
00305       Bool_t imageeof = kFALSE;
00306 
00307       while ((object = iter->Next()) != 0) {
00308          TMap *map = dynamic_cast < TMap * >(object);
00309 
00310          TObject *urlObject = map->GetValue("url");
00311          urlStr = dynamic_cast < TObjString * >(urlObject);
00312 
00313          TObject *authzObject = map->GetValue("envelope");
00314          authzStr = dynamic_cast < TObjString * >(authzObject);
00315 
00316          TObject *seObject = map->GetValue("se");
00317          seStr = dynamic_cast < TObjString * >(seObject);
00318 
00319          if (map->GetValue("eof")) {
00320             imageeof = kTRUE;
00321             // there is only one result line .... in case it is at all ....
00322          }
00323          break;
00324       }
00325 
00326       if ((!urlStr) || (!authzStr)) {
00327          if (fAWritable) {
00328             ::Error("TAlienFile::Open",
00329                     "didn't get the authorization to write %s",
00330                     purl.GetUrl());
00331          } else {
00332             if (!imageeof) {
00333                ::Error("TAlienFile::Open",
00334                        "didn't get the authorization to read %s from location %u",
00335                        purl.GetUrl(), imagenr);
00336             }
00337          }
00338          if (!imageeof) {
00339             ::Info("TAlienFile::Open",
00340                "Command::Stdout !!!");
00341             gGrid->Stdout();
00342             ::Info("TAlienFile::Open",
00343                "Command::Stderr !!!");
00344             gGrid->Stderr();
00345             ::Info("TAlienFile::Open",
00346                "End of Output   !!!");
00347          }
00348          delete iter;
00349          delete result;
00350          fAUrl = "";
00351          if (!imageeof) {
00352             continue;
00353          } else {
00354             // if the service signals eof, it makes no sense to check more replicas
00355             ::Error("TAlienFile::Open",
00356                     "No more images to try - giving up");
00357 
00358             // Reset the temp monitoring info
00359             if (gMonitoringWriter)
00360                gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00361 
00362             return 0;
00363          }
00364       }
00365 
00366       delete iter;
00367 
00368       authz = authzStr->GetName();
00369       stringurl = urlStr->GetName();
00370 
00371       tokens = stringurl.Tokenize("#");
00372 
00373       if (tokens->GetEntries() == 2) {
00374          anchor = ((TObjString *) tokens->At(1))->GetName();
00375          urlStr->SetString(((TObjString *) tokens->At(0))->GetName());
00376       }
00377 
00378       if (tokens) {
00379          delete tokens;
00380       }
00381 
00382       newurl = urlStr->GetName();
00383       stmp = purl.GetAnchor();
00384       newurl += TString("?&authz=");
00385       newurl += authzStr->GetName();
00386 
00387       if (!fAWritable) {
00388          if (seStr)
00389             ::Info("TAlienFile::Open", "Accessing image %u of %s in SE <%s>",
00390                    imagenr, purl.GetUrl(), seStr->GetName());
00391          else
00392             ::Info("TAlienFile::Open", "Accessing image %u of %s", imagenr, purl.GetUrl());
00393       }
00394       // the treatement of ZIP files is done in the following way:
00395       // LFNs in AliEn pointing to files in ZIP archives don't contain the .zip suffix in the file name
00396       // to tell TArchiveFile about the ZIP nature, we add to the URL options 'zip=<member>'
00397       // This options are not visible in the file name, they are passed through TXNetFile to TNetFile to TArchiveFile
00398 
00399       if (stmp != "") {
00400          newurl += "#";
00401          newurl += purl.GetAnchor();
00402          TString lUrlfile = lUrl.GetFile();
00403          TString lUrloption;
00404          lUrloption = "zip=";
00405          lUrloption += purl.GetAnchor();
00406          lUrloption += "&mkpath=1";
00407          lUrl.SetFile(lUrlfile);
00408          lUrl.SetOptions(lUrloption);
00409       } else {
00410          if (anchor.Length()) {
00411             newurl += "#";
00412             newurl += anchor;
00413             TString lUrlfile = lUrl.GetFile();
00414             TString lUrloption;
00415             lUrloption = "zip=";
00416             lUrloption += anchor;
00417             lUrloption += "&mkpath=1";
00418             lUrl.SetFile(lUrlfile);
00419             // lUrl.SetAnchor(anchor);
00420             lUrl.SetOptions(lUrloption);
00421          } else {
00422             TString loption;
00423             loption = lUrl.GetOptions();
00424             if (loption.Length()) {
00425                loption += "&mkpath=1";
00426                lUrl.SetOptions(loption.Data());
00427             } else {
00428                lUrl.SetOptions("mkpath=1");
00429             }
00430          }
00431       }
00432 
00433       fAUrl = TUrl(newurl);
00434 
00435       // append the original options
00436       TString oldopt;
00437       TString newopt;
00438 
00439       if (TString(fAUrl.GetUrl()) == "") {
00440          // error in file opening occured
00441 
00442           // Reset the temp monitoring info
00443          if (gMonitoringWriter)
00444             gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00445 
00446          return 0;
00447       }
00448 
00449       TUrl nUrl = fAUrl;
00450       TUrl oUrl(url);
00451 
00452       oldopt = oUrl.GetOptions();
00453       newopt = nUrl.GetOptions();
00454 
00455       // add the original options from the alien URL
00456       if (oldopt.Length()) {
00457          nUrl.SetOptions(newopt + TString("&") + oldopt);
00458       } else {
00459          nUrl.SetOptions(newopt);
00460       }
00461 
00462       fAUrl = nUrl;
00463       delete result;
00464       if (gDebug > 1)
00465          ::Info("TAlienFile","Opening AUrl <%s> lUrl <%s>",fAUrl.GetUrl(),lUrl.GetUrl());
00466       TAlienFile *alienfile =
00467           new TAlienFile(fAUrl.GetUrl(), fAOption, ftitle, compress,
00468                          parallelopen, lUrl.GetUrl(), authz);
00469       if (alienfile->IsZombie()) {
00470          delete alienfile;
00471          if (fAWritable) {
00472             // for the moment we support only 1 try during writing - no alternative locations
00473             break;
00474          }
00475          continue;
00476       } else {
00477          return alienfile;
00478       }
00479    } while (imagenr < MAX_FILE_IMAGES);
00480 
00481    if (!fAWritable) {
00482       ::Error("TAlienFile::Open",
00483               "Couldn't open any of the file images of %s", lUrl.GetUrl());
00484    }
00485 
00486    // Reset the temp monitoring info
00487    if (gMonitoringWriter)
00488       gMonitoringWriter->SendFileOpenProgress(0, 0, 0, kFALSE);
00489 
00490    return 0;
00491 }
00492 
00493 //______________________________________________________________________________
00494 TAlienFile::~TAlienFile()
00495 {
00496    // TAlienFile file dtor.
00497 
00498    if (IsOpen()) {
00499       Close();
00500    }
00501    if (gDebug)
00502       Info("~TAlienFile", "dtor called for %s", GetName());
00503 }
00504 
00505 //______________________________________________________________________________
00506 void TAlienFile::Close(Option_t * option)
00507 {
00508    // Close the file.
00509 
00510    if (!IsOpen()) return;
00511 
00512 
00513    // Close file
00514    TXNetFile::Close(option);
00515 
00516    if (fOption == "READ")
00517       return;
00518 
00519    // set GCLIENT_EXTRA_ARG environment
00520    gSystem->Setenv("GCLIENT_EXTRA_ARG", fAuthz.Data());
00521 
00522    // commit the envelope
00523    TString command("commit ");
00524 
00525    Long64_t siz = GetSize();
00526    if (siz <= 0)
00527       Error("Close", "the reported size of the written file is <= 0");
00528 
00529    command += siz;
00530    command += " ";
00531    command += fLfn;
00532 
00533    TGridResult *result = gGrid->Command(command, kFALSE, TAlien::kOUTPUT);
00534    TAlienResult *alienResult = dynamic_cast < TAlienResult * >(result);
00535    TList *list = dynamic_cast < TList * >(alienResult);
00536    if (!list) {
00537       if (result) {
00538          delete result;
00539       }
00540       Error("Close", "cannot commit envelope for %s", fLfn.Data());
00541       gSystem->Unlink(fLfn);
00542    }
00543    TIterator *iter = list->MakeIterator();
00544    TObject *object = 0;
00545    if (fWritable) {
00546       while ((object = iter->Next()) != 0) {
00547          TMap *map = dynamic_cast < TMap * >(object);
00548          TObject *commitObject = map->GetValue(fLfn.Data());
00549          if (commitObject) {
00550             TObjString *commitStr =
00551                 dynamic_cast < TObjString * >(commitObject);
00552             if (!(strcmp(commitStr->GetName(), "1"))) {
00553                // the file has been committed
00554                break;
00555             }
00556          }
00557 
00558          Error("Close", "cannot register %s!", fLfn.Data());
00559          gSystem->Unlink(fLfn);
00560          // there is only one result line .... in case it is at all ....
00561          break;
00562       }
00563       delete iter;
00564       delete result;
00565    }
00566 
00567    gSystem->Unsetenv("GCLIENT_EXTRA_ARG");
00568 
00569 }
00570 
00571 //______________________________________________________________________________
00572 TString TAlienFile::SUrl(const char *lfn)
00573 {
00574    // Get surl from lfn by asking AliEn catalog.
00575 
00576    TString command;
00577    TString surl;
00578 
00579    if (!lfn) {
00580       return surl;
00581    }
00582 
00583    TUrl lurl(lfn);
00584    command = "access -p read ";
00585    command += lurl.GetFile();
00586 
00587    TGridResult* result;
00588 
00589    if (!gGrid) {
00590       ::Error("TAlienFile::SUrl","no grid connection");
00591       return surl;
00592    }
00593 
00594    result = gGrid->Command(command.Data(), kFALSE, TAlien::kOUTPUT);
00595    if (!result) {
00596       ::Error("TAlienFile::SUrl","couldn't get access URL for alien file %s", lfn);
00597       return surl;
00598    }
00599 
00600    TIterator *iter = result->MakeIterator();
00601    TObject *object=0;
00602    TObjString *urlStr=0;
00603 
00604    object = iter->Next();
00605    if (object) {
00606       TMap *map = dynamic_cast < TMap * >(object);
00607       TObject *urlObject = map->GetValue("url");
00608       urlStr = dynamic_cast < TObjString * >(urlObject);
00609 
00610       if (urlStr) {
00611          surl = urlStr->GetName();
00612          delete object;
00613          return surl;
00614       }
00615    }
00616 
00617    ::Error("TAlienFile::SUrl","couldn't get surl for alien file %s", lfn);
00618    return surl;
00619 }

Generated on Tue Jul 5 14:45:30 2011 for ROOT_528-00b_version by  doxygen 1.5.1