TDSet.cxx

Go to the documentation of this file.
00001 // @(#)root/proof:$Id: TDSet.cxx 35121 2010-09-02 11:42:26Z ganis $
00002 // Author: Fons Rademakers   11/01/02
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, 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 // TDSet                                                                //
00015 //                                                                      //
00016 // This class implements a data set to be used for PROOF processing.    //
00017 // The TDSet defines the class of which objects will be processed,      //
00018 // the directory in the file where the objects of that type can be      //
00019 // found and the list of files to be processed. The files can be        //
00020 // specified as logical file names (LFN's) or as physical file names    //
00021 // (PFN's). In case of LFN's the resolution to PFN's will be done       //
00022 // according to the currently active GRID interface.                    //
00023 // Examples:                                                            //
00024 //   TDSet treeset("TTree", "AOD");                                     //
00025 //   treeset.Add("lfn:/alien.cern.ch/alice/prod2002/file1");            //
00026 //   ...                                                                //
00027 //   treeset.AddFriend(friendset);                                      //
00028 //                                                                      //
00029 // or                                                                   //
00030 //                                                                      //
00031 //   TDSet objset("MyEvent", "*", "/events");                           //
00032 //   objset.Add("root://cms.cern.ch/user/prod2002/hprod_1.root");       //
00033 //   ...                                                                //
00034 //   objset.Add(set2003);                                               //
00035 //                                                                      //
00036 // Validity of file names will only be checked at processing time       //
00037 // (typically on the PROOF master server), not at creation time.        //
00038 //                                                                      //
00039 //////////////////////////////////////////////////////////////////////////
00040 
00041 #include "TDSet.h"
00042 
00043 #include "Riostream.h"
00044 #include "TChain.h"
00045 #include "TClass.h"
00046 #include "TClassTable.h"
00047 #include "TCut.h"
00048 #include "TDataSetManager.h"
00049 #include "TError.h"
00050 #include "TEntryList.h"
00051 #include "TEnv.h"
00052 #include "TEventList.h"
00053 #include "TFile.h"
00054 #include "TFileInfo.h"
00055 #include "TFileStager.h"
00056 #include "TFriendElement.h"
00057 #include "TKey.h"
00058 #include "THashList.h"
00059 #include "TMap.h"
00060 #include "TROOT.h"
00061 #include "TTimeStamp.h"
00062 #include "TTree.h"
00063 #include "TUrl.h"
00064 #include "TRegexp.h"
00065 #include "TVirtualPerfStats.h"
00066 #include "TProof.h"
00067 #include "TProofChain.h"
00068 #include "TProofServ.h"
00069 #include "TPluginManager.h"
00070 #include "TChain.h"
00071 #include "TChainElement.h"
00072 #include "TSystem.h"
00073 #include "THashList.h"
00074 
00075 #include "TVirtualStreamerInfo.h"
00076 #include "TClassRef.h"
00077 
00078 ClassImp(TDSetElement)
00079 ClassImp(TDSet)
00080 
00081 //______________________________________________________________________________
00082 TDSetElement::TDSetElement() : TNamed("",""),
00083                                fDirectory(), fFirst(0), fNum(0), fMsd(),
00084                                fTDSetOffset(0), fEntryList(0), fValid(kFALSE),
00085                                fEntries(0), fFriends(0), fDataSet(), fAssocObjList(0)
00086 {
00087    // Default constructor
00088    ResetBit(kWriteV3);
00089    ResetBit(kHasBeenLookedUp);
00090    ResetBit(kEmpty);
00091    ResetBit(kCorrupted);
00092    ResetBit(kNewRun);
00093    ResetBit(kNewPacket);
00094 }
00095 
00096 //______________________________________________________________________________
00097 TDSetElement::TDSetElement(const char *file, const char *objname, const char *dir,
00098                            Long64_t first, Long64_t num,
00099                            const char *msd, const char *dataset)
00100              : TNamed(file, objname)
00101 {
00102    // Create a TDSet element.
00103 
00104    if (first < 0) {
00105       Warning("TDSetElement", "first must be >= 0, %lld is not allowed - setting to 0", first);
00106       fFirst = 0;
00107    } else {
00108       fFirst = first;
00109    }
00110    if (num < -1) {
00111       Warning("TDSetElement", "num must be >= -1, %lld is not allowed - setting to -1", num);
00112       fNum   = -1;
00113    } else {
00114       fNum   = num;
00115    }
00116    fMsd         = msd;
00117    fTDSetOffset = 0;
00118    fEntryList   = 0;
00119    fFriends     = 0;
00120    fValid       = kFALSE;
00121    fEntries     = -1;
00122    fDataSet     = dataset;
00123    fAssocObjList = 0;
00124    if (dir)
00125       fDirectory = dir;
00126 
00127    ResetBit(kWriteV3);
00128    ResetBit(kHasBeenLookedUp);
00129    ResetBit(kEmpty);
00130    ResetBit(kCorrupted);
00131    ResetBit(kNewRun);
00132    ResetBit(kNewPacket);
00133 }
00134 
00135 //______________________________________________________________________________
00136 TDSetElement::TDSetElement(const TDSetElement& elem)
00137              : TNamed(elem.GetFileName(), elem.GetObjName())
00138 {
00139    // copy constructor
00140    fDirectory = elem.GetDirectory();
00141    fFirst = elem.fFirst;
00142    fNum = elem.fNum;
00143    fMsd = elem.fMsd;
00144    fTDSetOffset = elem.fTDSetOffset;
00145    fEntryList = 0;
00146    fValid = elem.fValid;
00147    fEntries = elem.fEntries;
00148    fFriends = 0;
00149    fDataSet = elem.fDataSet;
00150    fAssocObjList = 0;
00151    ResetBit(kWriteV3);
00152    ResetBit(kHasBeenLookedUp);
00153    ResetBit(kEmpty);
00154    ResetBit(kCorrupted);
00155    ResetBit(kNewRun);
00156    ResetBit(kNewPacket);
00157 }
00158 
00159 //______________________________________________________________________________
00160 TDSetElement::~TDSetElement()
00161 {
00162    // Clean up the element.
00163    DeleteFriends();
00164    if (fAssocObjList) {
00165       fAssocObjList->SetOwner(kTRUE);
00166       SafeDelete(fAssocObjList);
00167    }
00168 }
00169 
00170 //______________________________________________________________________________
00171 Int_t TDSetElement::MergeElement(TDSetElement *elem)
00172 {
00173    // Check if 'elem' is overlapping or subsequent and, if the case, return
00174    // a merged element.
00175    // Returns:
00176    //     1    if the elements are overlapping
00177    //     0    if the elements are subsequent
00178    //    -1    if the elements are neither overlapping nor subsequent
00179 
00180    // The element must be defined
00181    if (!elem) return -1;
00182 
00183    // The file names and object names must be the same
00184    if (strcmp(GetName(), elem->GetName()) || strcmp(GetTitle(), elem->GetTitle()))
00185       return -1;
00186 
00187    Int_t rc = -1;
00188    // Check the overlap or subsequency
00189    if (fFirst == 0 && fNum == -1) {
00190       // Overlap, since we cover already the full range
00191       rc = 1;
00192    } else if (elem->GetFirst() == 0 && elem->GetNum() == -1) {
00193       // Overlap, since 'elem' cover already the full range
00194       fFirst = 0;
00195       fNum = -1;
00196       fEntries = elem->GetEntries();
00197       rc = 1;
00198    } else if (fFirst >= 0 && fNum > 0 && elem->GetFirst() >= 0 && elem->GetNum() > 0) {
00199       Long64_t last = fFirst + fNum - 1, lastref = 0;
00200       Long64_t lastelem = elem->GetFirst() + elem->GetNum() - 1;
00201       if (elem->GetFirst() == last + 1) {
00202          lastref = lastelem;
00203          rc = 0;
00204       } else if (fFirst == lastelem + 1) {
00205          fFirst += elem->GetFirst();
00206          lastref = last;
00207          rc = 0;
00208       } else if (elem->GetFirst() < last + 1 && elem->GetFirst() >= fFirst) {
00209          lastref = (lastelem > last) ? lastelem : last;
00210          rc = 1;
00211       } else if (fFirst < lastelem + 1 && fFirst >= elem->GetFirst()) {
00212          fFirst += elem->GetFirst();
00213          lastref = (lastelem > last) ? lastelem : last;
00214          rc = 1;
00215       }
00216       fNum = lastref - fFirst + 1;
00217    }
00218    if (rc >= 0 && fEntries < 0 && elem->GetEntries() > 0) fEntries = elem->GetEntries();
00219 
00220    // Done
00221    return rc;
00222 }
00223 
00224 //______________________________________________________________________________
00225 TFileInfo *TDSetElement::GetFileInfo(const char *type)
00226 {
00227    // Return the content of this element in the form of a TFileInfo
00228 
00229    // Create the TFileInfoMeta object
00230    TFileInfoMeta *meta = 0;
00231    if (!strcmp(type, "TTree")) {
00232       meta = new TFileInfoMeta(GetTitle(), "TTree", fEntries, fFirst,
00233                                 fFirst + fEntries - 1);
00234    } else {
00235       meta = new TFileInfoMeta(GetTitle(), fDirectory, type, fEntries, fFirst,
00236                                 fFirst + fEntries - 1);
00237    }
00238    return new TFileInfo(GetName(), 0, 0, 0, meta);
00239 }
00240 
00241 //______________________________________________________________________________
00242 const char *TDSetElement::GetDirectory() const
00243 {
00244    // Return directory where to look for object.
00245 
00246    return fDirectory;
00247 }
00248 
00249 //______________________________________________________________________________
00250 void TDSetElement::Print(Option_t *opt) const
00251 {
00252    // Print a TDSetElement. When option="a" print full data.
00253 
00254    if (opt && opt[0] == 'a') {
00255       Printf("%s file=\"%s\" dir=\"%s\" obj=\"%s\" first=%lld num=%lld msd=\"%s\"",
00256              IsA()->GetName(), GetName(), fDirectory.Data(), GetTitle(),
00257              fFirst, fNum, fMsd.Data());
00258    } else {
00259       Printf("\tLFN: %s", GetName());
00260    }
00261 }
00262 
00263 //______________________________________________________________________________
00264 void TDSetElement::Validate(Bool_t isTree)
00265 {
00266    // Validate by opening the file.
00267 
00268    Long64_t entries = GetEntries(isTree);
00269    if (entries < 0) return; // Error should be reported by GetEntries()
00270    if (fFirst < entries) {
00271       if (fNum == -1) {
00272          fNum = entries - fFirst;
00273          fValid = kTRUE;
00274       } else {
00275          if (fNum <= entries - fFirst) {
00276             fValid = kTRUE;
00277          } else {
00278             Error("Validate", "TDSetElement has only %lld entries starting"
00279                               " with entry %lld, while %lld were requested",
00280                               entries - fFirst, fFirst, fNum);
00281          }
00282       }
00283    } else {
00284       Error("Validate", "TDSetElement has only %lld entries with"
00285             " first entry requested as %lld", entries, fFirst);
00286    }
00287 }
00288 
00289 //______________________________________________________________________________
00290 void TDSetElement::Validate(TDSetElement *elem)
00291 {
00292    // Validate by checking against another element.
00293 
00294    // NOTE: Since this function validates against another TDSetElement,
00295    //       if the other TDSetElement (elem) did not use -1 to request all
00296    //       entries, this TDSetElement may get less than all entries if it
00297    //       requests all (with -1). For the application it was developed for
00298    //       (TProofSuperMaster::ValidateDSet) it works, since the design was
00299    //       to send the elements to their mass storage domain and let them
00300    //       look at the file and send the info back to the supermaster. The
00301    //       ability to set fValid was also required to be only exist in
00302    //       TDSetElement through certain function and not be set externally.
00303    //       TDSetElement may need to be extended for more general applications.
00304 
00305    if (!elem || !elem->GetValid()) {
00306       Error("Validate", "TDSetElement to validate against is not valid");
00307       return;
00308    }
00309 
00310    TString name = TUrl(GetFileName()).GetFileAndOptions();
00311    TString elemname = TUrl(elem->GetFileName()).GetFileAndOptions();
00312    if ((name == elemname) &&
00313        !strcmp(GetDirectory(), elem->GetDirectory()) &&
00314        !strcmp(GetObjName(), elem->GetObjName())) {
00315       Long64_t entries = elem->fFirst + elem->fNum;
00316       if (fFirst < entries) {
00317          if (fNum == -1) {
00318             fNum = entries - fFirst;
00319             fValid = kTRUE;
00320          } else {
00321             if (fNum <= entries - fFirst) {
00322                fValid = kTRUE;
00323             } else {
00324                Error("Validate", "TDSetElement requests %lld entries starting"
00325                                  " with entry %lld, while TDSetElement to validate against"
00326                                  " has only %lld entries", fNum, fFirst, entries);
00327             }
00328          }
00329       } else {
00330          Error("Validate", "TDSetElement to validate against has only %lld"
00331                " entries, but this TDSetElement requested %lld as its first"
00332                " entry", entries, fFirst);
00333       }
00334    } else {
00335       Error("Validate", "TDSetElements do not refer to same objects");
00336    }
00337 }
00338 
00339 //______________________________________________________________________________
00340 Int_t TDSetElement::Compare(const TObject *obj) const
00341 {
00342    //Compare elements by filename (and the fFirst).
00343 
00344    if (this == obj) return 0;
00345 
00346    const TDSetElement *elem = dynamic_cast<const TDSetElement*>(obj);
00347    if (!elem) {
00348       if (obj)
00349          return (strncmp(GetName(),obj->GetName(),strlen(GetName()))) ? 1 : 0;
00350       return -1;
00351    }
00352 
00353    Int_t order = strncmp(GetName(),elem->GetFileName(),strlen(GetName()));
00354    if (order == 0) {
00355       if (GetFirst() < elem->GetFirst())
00356          return -1;
00357       else if (GetFirst() > elem->GetFirst())
00358          return 1;
00359       return 0;
00360    }
00361    return order;
00362 }
00363 
00364 //______________________________________________________________________________
00365 void TDSetElement::AddFriend(TDSetElement *friendElement, const char *alias)
00366 {
00367    // Add friend TDSetElement to this set. The friend element will be copied to this object.
00368 
00369    if (!friendElement) {
00370       Error("AddFriend", "The friend TDSetElement is null!");
00371       return;
00372    }
00373    if (!fFriends) {
00374       fFriends = new TList();
00375       fFriends->SetOwner();
00376    }
00377    // Add alias (if any) as option 'friend_alias=<alias>|'
00378    if (alias && strlen(alias) > 0) {
00379       TUrl uf(friendElement->GetName());
00380       TString uo(uf.GetOptions());
00381       uo += TString::Format("friend_alias=%s|", alias);
00382       uf.SetOptions(uo);
00383       friendElement->SetName(uf.GetUrl());
00384    }
00385    fFriends->Add(new TDSetElement(*friendElement));
00386 }
00387 
00388 //______________________________________________________________________________
00389 void TDSetElement::DeleteFriends()
00390 {
00391    // Deletes the list of friends and all the friends on the list.
00392    if (!fFriends)
00393       return;
00394 
00395    fFriends->SetOwner(kTRUE);
00396    delete fFriends;
00397    fFriends = 0;
00398 }
00399 
00400 //______________________________________________________________________________
00401 TDSetElement *TDSet::Next(Long64_t /*totalEntries*/)
00402 {
00403    // Returns next TDSetElement.
00404 
00405    if (!fIterator) {
00406       fIterator = new TIter(fElements);
00407    }
00408 
00409    fCurrent = (TDSetElement *) fIterator->Next();
00410    return fCurrent;
00411 }
00412 
00413 //______________________________________________________________________________
00414 Long64_t TDSetElement::GetEntries(Bool_t isTree, Bool_t openfile)
00415 {
00416    // Returns number of entries in tree or objects in file.
00417    // If not yet defined and 'openfile' is TRUE, get the number from the file
00418    // (may considerably slow down the application).
00419    // Returns -1 in case of error.
00420 
00421    if (fEntries > -1 || !openfile)
00422       return fEntries;
00423 
00424    Double_t start = 0;
00425    if (gPerfStats) start = TTimeStamp();
00426 
00427    // Take into account possible prefixes
00428    TFile::EFileType typ = TFile::kDefault;
00429    TString fname = gEnv->GetValue("Path.Localroot",""), pfx(fname);
00430    // Get the locality (disable warnings or errors in connection attempts)
00431    Int_t oldLevel = gErrorIgnoreLevel;
00432    gErrorIgnoreLevel = kError+1;
00433    if ((typ = TFile::GetType(GetName(), "", &fname)) != TFile::kLocal) fname = GetName();
00434    gErrorIgnoreLevel = oldLevel;
00435    // Open the file
00436    TFile *file = TFile::Open(fname);
00437 
00438    if (gPerfStats)
00439       gPerfStats->FileOpenEvent(file, GetName(), start);
00440 
00441    if (file == 0) {
00442       ::SysError("TDSetElement::GetEntries",
00443                  "cannot open file %s (type: %d, pfx: %s)", GetName(), typ, pfx.Data());
00444       return -1;
00445    }
00446 
00447    // Record end-point Url and mark as looked-up; be careful to change
00448    // nothing in the file name, otherwise some cross-checks may fail
00449    TUrl *eu = (TUrl *) file->GetEndpointUrl();
00450    eu->SetOptions(TUrl(fname).GetOptions());
00451    eu->SetAnchor(TUrl(fname).GetAnchor());
00452    if (strlen(eu->GetProtocol()) > 0 && strcmp(eu->GetProtocol(), "file"))
00453       fName = eu->GetUrl();
00454    else
00455       fName = eu->GetFileAndOptions();
00456    SetBit(kHasBeenLookedUp);
00457 
00458    TDirectory *dirsave = gDirectory;
00459    if (!file->cd(fDirectory)) {
00460       Error("GetEntries", "cannot cd to %s", fDirectory.Data());
00461       delete file;
00462       return -1;
00463    }
00464 
00465    TDirectory *dir = gDirectory;
00466    dirsave->cd();
00467 
00468    if (isTree) {
00469 
00470       TString on(GetTitle());
00471       TString sreg(GetTitle());
00472       // If a wild card we will use the first object of the type
00473       // requested compatible with the reg expression we got
00474       if (sreg.Length() <= 0 || sreg == "" || sreg.Contains("*")) {
00475          if (sreg.Contains("*"))
00476             sreg.ReplaceAll("*", ".*");
00477          else
00478             sreg = ".*";
00479          TRegexp re(sreg);
00480          if (dir->GetListOfKeys()) {
00481             TIter nxk(dir->GetListOfKeys());
00482             TKey *k = 0;
00483             Bool_t notfound = kTRUE;
00484             while ((k = (TKey *) nxk())) {
00485                if (!strcmp(k->GetClassName(), "TTree")) {
00486                   TString kn(k->GetName());
00487                   if (kn.Index(re) != kNPOS) {
00488                      if (notfound) {
00489                         on = kn;
00490                         notfound = kFALSE;
00491                      } else if (kn != on) {
00492                        Warning("GetEntries",
00493                                "additional tree found in the file: %s", kn.Data());
00494                      }
00495                   }
00496                }
00497             }
00498          }
00499       }
00500 
00501       TKey *key = dir->GetKey(on);
00502       if (key == 0) {
00503          Error("GetEntries", "cannot find tree \"%s\" in %s",
00504                GetTitle(), GetName());
00505          delete file;
00506          return -1;
00507       }
00508       TTree *tree = (TTree *) key->ReadObj();
00509       if (tree == 0) {
00510          // Error always reported?
00511          delete file;
00512          return -1;
00513       }
00514       fEntries = tree->GetEntries();
00515       delete tree;
00516 
00517    } else {
00518       TList *keys = dir->GetListOfKeys();
00519       fEntries = keys->GetSize();
00520    }
00521 
00522    delete file;
00523    return fEntries;
00524 }
00525 
00526 //______________________________________________________________________________
00527 Int_t TDSetElement::Lookup(Bool_t force)
00528 {
00529    // Resolve end-point URL for this element
00530    // Return 0 on success and -1 otherwise
00531    static Int_t xNetPluginOK = -1;
00532    static TFileStager *xStager = 0;
00533    Int_t retVal = 0;
00534 
00535    // Check if required
00536    if (!force && HasBeenLookedUp())
00537       return retVal;
00538 
00539    TUrl url(GetName());
00540    // Save current options and anchor to be set ofthe final end URL
00541    TString anch = url.GetAnchor();
00542    TString opts = url.GetOptions();
00543    // The full path
00544    TString name(url.GetUrl());
00545 
00546    // Depending on the type of backend, it might not make any sense to lookup
00547    Bool_t doit = kFALSE;
00548    TFile::EFileType type = TFile::GetType(name, "");
00549    if (type == TFile::kNet) {
00550       TPluginHandler *h = 0;
00551       // Network files via XROOTD
00552       if (xNetPluginOK == -1) {
00553          // Check the plugin the first time
00554          xNetPluginOK = 0;
00555          if ((h = gROOT->GetPluginManager()->FindHandler("TFile", name)) &&
00556             !strcmp(h->GetClass(),"TXNetFile") && h->LoadPlugin() == 0)
00557             xNetPluginOK = 1;
00558       }
00559       doit = (xNetPluginOK == 1) ? kTRUE : kFALSE;
00560    }
00561 
00562    // Locate the file
00563    if (doit) {
00564       if (!xStager || !xStager->Matches(name)) {
00565          SafeDelete(xStager);
00566          if (!(xStager = TFileStager::Open(name))) {
00567             Error("Lookup", "TFileStager instance cannot be instantiated");
00568             retVal = -1;
00569          }
00570       }
00571       if (xStager && xStager->Locate(name.Data(), name) == 0) {
00572          // Get the effective end-point Url
00573          url.SetUrl(name);
00574          // Restore original options and anchor, if any
00575          url.SetOptions(opts);
00576          url.SetAnchor(anch);
00577          // Save it into the element
00578          fName = url.GetUrl();
00579       } else {
00580          // Failure
00581          Error("Lookup", "couldn't lookup %s", name.Data());
00582          retVal = -1;
00583       }
00584    }
00585 
00586    // Mark has looked-up
00587    SetBit(kHasBeenLookedUp);
00588    return retVal;
00589 }
00590 
00591 //______________________________________________________________________________
00592 void TDSetElement::SetEntryList(TObject *aList, Long64_t first, Long64_t num)
00593 {
00594    // Set entry (or event) list for this element
00595 
00596    if (!aList)
00597       return;
00598 
00599    // Link the proper object
00600    TEventList *evl = 0;
00601    TEntryList *enl = dynamic_cast<TEntryList*>(aList);
00602    if (!enl)
00603       evl = dynamic_cast<TEventList*>(aList);
00604    if (!enl && !evl) {
00605       Error("SetEntryList", "type of input object must be either TEntryList "
00606                             "or TEventList (found: '%s' - do nothing", aList->ClassName());
00607       return;
00608    }
00609 
00610    // Action depends on the type
00611    if (enl) {
00612       enl->SetEntriesToProcess(num);
00613    } else {
00614       for (; num > 0; num--, first++)
00615          evl->Enter(evl->GetEntry((Int_t)first));
00616    }
00617    fEntryList = aList;
00618 
00619    // Done
00620    return;
00621 }
00622 
00623 //______________________________________________________________________________
00624 void TDSetElement::AddAssocObj(TObject *assocobj)
00625 {
00626    // Add an associated object to the list
00627    if (assocobj) {
00628       if (!fAssocObjList) fAssocObjList = new TList;
00629       if (fAssocObjList) fAssocObjList->Add(assocobj);
00630    }
00631 }
00632 
00633 //______________________________________________________________________________
00634 TObject *TDSetElement::GetAssocObj(Long64_t i, Bool_t isentry)
00635 {
00636    // Get i-th associated object.
00637    // If 'isentry' fFirst is subtracted, so that i == fFirst returns the first
00638    // object in the list.
00639    // If there are not enough elements in the list, the element i%list_size is
00640    // returned (if the list has only one element this only one element is always
00641    // returned.
00642    // This method is used when packet processing consist in processing the objects
00643    // in the associated object list.
00644 
00645    TObject *o = 0;
00646    if (!fAssocObjList || fAssocObjList->GetSize() <= 0) return o;
00647 
00648    TString s;
00649    Int_t pos = -1;
00650    if (isentry) {
00651       if (i < fFirst) return o;
00652       s.Form("%lld", i - fFirst);
00653    } else {
00654       if (i < 0) return o;
00655       s.Form("%lld", i);
00656    }
00657    if (!(s.IsDigit())) return o;
00658    pos = s.Atoi();
00659    if (pos > fAssocObjList->GetSize() - 1) pos %= fAssocObjList->GetSize();
00660    return fAssocObjList->At(pos);
00661 }
00662 
00663 //______________________________________________________________________________
00664 TDSet::TDSet()
00665 {
00666    // Default ctor.
00667 
00668    fElements = new THashList;
00669    fElements->SetOwner();
00670    fIsTree    = kFALSE;
00671    fIterator  = 0;
00672    fCurrent   = 0;
00673    fEntryList = 0;
00674    fProofChain = 0;
00675    fSrvMaps = 0;
00676    fSrvMapsIter = 0;
00677    ResetBit(kWriteV3);
00678    ResetBit(kEmpty);
00679    ResetBit(kValidityChecked);
00680    ResetBit(kSomeInvalid);
00681    ResetBit(kMultiDSet);
00682 
00683    // Add to the global list
00684    gROOT->GetListOfDataSets()->Add(this);
00685 }
00686 
00687 //______________________________________________________________________________
00688 TDSet::TDSet(const char *name,
00689              const char *objname, const char *dir, const char *type)
00690 {
00691    // Create a named TDSet object. The "type" defines the class of which objects
00692    // will be processed (default 'TTree'). The optional "objname" argument
00693    // specifies the name of the objects of the specified class.
00694    // If the "objname" is not given the behaviour depends on the 'type':
00695    // for 'TTree' the first TTree is analyzed; for other types, all objects of
00696    // the class found in the specified directory are processed.
00697    // The "dir" argument specifies in which directory the objects are
00698    // to be found, the top level directory ("/") is the default.
00699    // Directories can be specified using wildcards, e.g. "*" or "/*"
00700    // means to look in all top level directories, "/dir/*" in all
00701    // directories under "/dir", and "/*/*" to look in all directories
00702    // two levels deep.
00703    // For backward compatibility the type can also be passed via 'name',
00704    // in which case 'type' is ignored.
00705 
00706    fElements = new THashList;
00707    fElements->SetOwner();
00708    fIterator = 0;
00709    fCurrent  = 0;
00710    fEntryList = 0;
00711    fProofChain = 0;
00712    fSrvMaps = 0;
00713    fSrvMapsIter = 0;
00714    ResetBit(kWriteV3);
00715    ResetBit(kEmpty);
00716    ResetBit(kValidityChecked);
00717    ResetBit(kSomeInvalid);
00718    ResetBit(kMultiDSet);
00719 
00720    fType = "TTree";
00721    TClass *c = 0;
00722    // Check name
00723    if (name && strlen(name) > 0) {
00724       // In the old constructor signature it was the 'type'
00725       if (!type) {
00726          if (TClass::GetClass(name))
00727             fType = name;
00728          else
00729             // Default type is 'TTree'
00730             fName = name;
00731       } else {
00732          // Set name
00733          fName = name;
00734          // Check type
00735          if (strlen(type) > 0)
00736             if (TClass::GetClass(type))
00737                fType = type;
00738       }
00739    } else if (type && strlen(type) > 0) {
00740       // Check the type
00741       if (TClass::GetClass(type))
00742          fType = type;
00743    }
00744    // The correct class type
00745    c = TClass::GetClass(fType);
00746 
00747    fIsTree = (c->InheritsFrom(TTree::Class())) ? kTRUE : kFALSE;
00748 
00749    if (objname)
00750       fObjName = objname;
00751 
00752    if (dir)
00753       fDir = dir;
00754 
00755    // Default name is the object name
00756    if (fName.Length() <= 0)
00757       fName = fObjName;
00758    // We set the default title to the 'type'
00759    fTitle = fType;
00760 
00761    // Add to the global list
00762    gROOT->GetListOfDataSets()->Add(this);
00763 }
00764 
00765 //______________________________________________________________________________
00766 TDSet::TDSet(const TChain &chain, Bool_t withfriends)
00767 {
00768    // Create a named TDSet object from existing TChain 'chain'.
00769    // If 'withfriends' is kTRUE add also friends.
00770    // This constructor substituted the static methods TChain::MakeTDSet
00771    // removing any residual dependence of 'tree' on 'proof'.
00772 
00773    fElements = new THashList;
00774    fElements->SetOwner();
00775    fIterator = 0;
00776    fCurrent  = 0;
00777    fEntryList = 0;
00778    fProofChain = 0;
00779    fSrvMaps = 0;
00780    fSrvMapsIter = 0;
00781    ResetBit(kWriteV3);
00782    ResetBit(kEmpty);
00783    ResetBit(kValidityChecked);
00784    ResetBit(kSomeInvalid);
00785    ResetBit(kMultiDSet);
00786 
00787    fType = "TTree";
00788    fIsTree = kTRUE;
00789    fObjName = chain.GetName();
00790 
00791    // First fill elements without friends()
00792    TIter next(chain.GetListOfFiles());
00793    TChainElement *elem = 0;
00794    TString key;
00795    while ((elem = (TChainElement *)next())) {
00796       TString file(elem->GetTitle());
00797       TString tree(elem->GetName());
00798       Int_t isl = tree.Index("/");
00799       TString dir = "/";
00800       if (isl >= 0) {
00801          // Copy the tree name specification
00802          TString behindSlash = tree(isl + 1, tree.Length() - isl - 1);
00803          // and remove it from basename
00804          tree.Remove(isl);
00805          dir = tree;
00806          tree = behindSlash;
00807       }
00808       // Find MSD if any
00809       TString msd(TUrl(file).GetOptions());
00810       Int_t imsd = kNPOS;
00811       if ((imsd = msd.Index("msd=")) != kNPOS) {
00812          msd.Remove(0, imsd+4);
00813       } else {
00814          // Not an MSD option
00815          msd = "";
00816       }
00817       Long64_t nent = (elem->GetEntries() > 0 &&
00818                        elem->GetEntries() != TChain::kBigNumber) ? elem->GetEntries() : -1;
00819       if (Add(file, tree, dir, 0, nent, ((msd.IsNull()) ? 0 : msd.Data()))) {
00820          if (elem->HasBeenLookedUp()) {
00821             // Save lookup information, if any
00822             TDSetElement *dse = (TDSetElement *) fElements->Last();
00823             if (dse) dse->SetLookedUp();
00824          }
00825       }
00826    }
00827    SetDirectory(0);
00828 
00829    // Add friends now, if requested
00830    if (withfriends) {
00831       TList processed;
00832       TList chainsQueue;
00833       chainsQueue.Add((TObject *)&chain);
00834       processed.Add((TObject *)&chain);
00835       while (chainsQueue.GetSize() > 0) {
00836          TChain *c = (TChain *) chainsQueue.First();
00837          chainsQueue.Remove(c);
00838          TIter friendsIter(c->GetListOfFriends());
00839          while(TFriendElement *fe = dynamic_cast<TFriendElement*> (friendsIter()) ) {
00840             if (TChain *fc = dynamic_cast<TChain*>(fe->GetTree())) {
00841                if (!processed.FindObject(fc)) {    // if not yet processed
00842                   processed.AddFirst(fc);
00843                   AddFriend(new TDSet((const TChain &)(*fc), kFALSE), fe->GetName());
00844                   chainsQueue.Add(fc);                        // for further processing
00845                }
00846             } else {
00847                Reset();
00848                Error("TDSet", "Only TChains supported. Found illegal tree %s",
00849                               fe->GetTree()->GetName());
00850                return;
00851             }
00852          }
00853       }
00854    }
00855 }
00856 
00857 //______________________________________________________________________________
00858 TDSet::~TDSet()
00859 {
00860    // Cleanup.
00861 
00862    SafeDelete(fElements);
00863    SafeDelete(fIterator);
00864    SafeDelete(fProofChain);
00865    fSrvMaps = 0;
00866    fSrvMapsIter = 0;
00867 
00868    gROOT->GetListOfDataSets()->Remove(this);
00869 }
00870 
00871 //______________________________________________________________________________
00872 Long64_t TDSet::Process(const char *selector, Option_t *option, Long64_t nentries,
00873                         Long64_t first, TObject *enl)
00874 {
00875    // Process TDSet on currently active PROOF session.
00876    // The last argument 'enl' specifies an entry- or event-list to be used as
00877    // event selection.
00878    // The return value is -1 in case of error and TSelector::GetStatus() in
00879    // in case of success.
00880 
00881    if (!IsValid() || !fElements->GetSize()) {
00882       Error("Process", "not a correctly initialized TDSet");
00883       return -1;
00884    }
00885 
00886    // Set entry list
00887    SetEntryList(enl);
00888 
00889    if (gProof)
00890       return gProof->Process(this, selector, option, nentries, first);
00891 
00892    Error("Process", "no active PROOF session");
00893    return -1;
00894 }
00895 
00896 //______________________________________________________________________________
00897 void TDSet::AddInput(TObject *obj)
00898 {
00899    // Add objects that might be needed during the processing of
00900    // the selector (see Process()).
00901 
00902    if (gProof) {
00903       gProof->AddInput(obj);
00904    } else {
00905       Error("AddInput","No PROOF session active");
00906    }
00907 }
00908 
00909 //______________________________________________________________________________
00910 void TDSet::ClearInput()
00911 {
00912    // Clear input object list.
00913 
00914    if (gProof)
00915       gProof->ClearInput();
00916 }
00917 
00918 //______________________________________________________________________________
00919 TObject *TDSet::GetOutput(const char *name)
00920 {
00921    // Get specified object that has been produced during the processing
00922    // (see Process()).
00923 
00924    if (gProof)
00925       return gProof->GetOutput(name);
00926    return 0;
00927 }
00928 
00929 //______________________________________________________________________________
00930 TList *TDSet::GetOutputList()
00931 {
00932    // Get list with all object created during processing (see Process()).
00933 
00934    if (gProof)
00935       return gProof->GetOutputList();
00936    return 0;
00937 }
00938 
00939 //______________________________________________________________________________
00940 void TDSet::Print(const Option_t *opt) const
00941 {
00942    // Print TDSet basic or full data. When option="a" print full data.
00943 
00944    Printf("OBJ: %s\ttype %s\t%s\tin %s\telements %d", IsA()->GetName(), GetName(),
00945           fObjName.Data(), GetTitle(), GetListOfElements()->GetSize());
00946 
00947    if (opt && opt[0] == 'a') {
00948       TIter next(GetListOfElements());
00949       TObject *obj;
00950       while ((obj = next())) {
00951          obj->Print(opt);
00952       }
00953    }
00954 }
00955 
00956 //______________________________________________________________________________
00957 void TDSet::SetObjName(const char *objname)
00958 {
00959    // Set/change object name.
00960 
00961    if (objname)
00962       fObjName = objname;
00963 }
00964 
00965 //______________________________________________________________________________
00966 void TDSet::SetDirectory(const char *dir)
00967 {
00968    // Set/change directory.
00969 
00970    if (dir)
00971       fDir = dir;
00972 }
00973 
00974 //______________________________________________________________________________
00975 Bool_t TDSet::Add(const char *file, const char *objname, const char *dir,
00976                   Long64_t first, Long64_t num, const char *msd)
00977 {
00978    // Add file to list of files to be analyzed. Optionally with the
00979    // objname and dir arguments the default, TDSet wide, objname and
00980    // dir can be overridden.
00981 
00982    if (!file || !*file) {
00983       Error("Add", "file name must be specified");
00984       return kFALSE;
00985    }
00986 
00987    TString fn = file;
00988    if (gProof && gProof->IsLite()) {
00989       TUrl u(file, kTRUE);
00990       if (!strcmp(u.GetProtocol(), "file")) {
00991          fn = u.GetFile();
00992          gSystem->ExpandPathName(fn);
00993          if (!gSystem->IsAbsoluteFileName(fn))
00994             gSystem->PrependPathName(gSystem->WorkingDirectory(), fn);
00995       }
00996    }
00997 
00998    // check, if it already exists in the TDSet
00999    TDSetElement *el = (TDSetElement *) fElements->FindObject(fn);
01000    if (!el) {
01001       if (!objname)
01002          objname = GetObjName();
01003       if (!dir)
01004          dir = GetDirectory();
01005       fElements->Add(new TDSetElement(fn, objname, dir, first, num, msd));
01006    } else {
01007       TString msg;
01008       msg.Form("duplication detected: %40s is already in dataset - ignored", fn.Data());
01009       Warning("Add", "%s", msg.Data());
01010       if (gProofServ) {
01011          msg.Insert(0, "WARNING: ");
01012          gProofServ->SendAsynMessage(msg);
01013       }
01014    }
01015 
01016    return kTRUE;
01017 }
01018 
01019 //______________________________________________________________________________
01020 Bool_t TDSet::Add(TDSet *dset)
01021 {
01022    // Add specified data set to the this set.
01023 
01024    if (!dset)
01025       return kFALSE;
01026 
01027    if (TestBit(TDSet::kMultiDSet)) {
01028       fElements->Add(dset);
01029       return kTRUE;
01030    }
01031 
01032    if (fType != dset->GetType()) {
01033       Error("Add", "cannot add a set with a different type");
01034       return kFALSE;
01035    }
01036 
01037    TDSetElement *el;
01038    TIter next(dset->fElements);
01039    TObject *last = (dset == this) ? fElements->Last() : 0;
01040    while ((el = (TDSetElement*) next())) {
01041       Add(el->GetFileName(), el->GetObjName(), el->GetDirectory(),
01042           el->GetFirst(), el->GetNum(), el->GetMsd());
01043       if (el == last) break;
01044    }
01045 
01046    return kTRUE;
01047 }
01048 
01049 //______________________________________________________________________________
01050 Bool_t TDSet::Add(TCollection *filelist, const char *meta, Bool_t availableOnly,
01051                   TCollection *badlist)
01052 {
01053    // Add files passed as list of TFileInfo, TUrl or TObjString objects .
01054    // If TFileInfo, the first entry and the number of entries are also filled.
01055    // The argument 'meta' can be used to specify one of the subsets in the
01056    // file as described in the metadata of TFileInfo. By default the first one
01057    // is taken.
01058    // If 'availableOnly' is true only files available ('staged' and non corrupted)
01059    // are taken: those not satisfying this requirement are added to 'badlist', if
01060    // the latter is defined. By default availableOnly is false.
01061 
01062    if (!filelist)
01063       return kFALSE;
01064 
01065    TObject *o = 0;
01066    TIter next(filelist);
01067    while ((o = next())) {
01068       TString cn(o->ClassName());
01069       if (cn == "TFileInfo") {
01070          TFileInfo *fi = (TFileInfo *)o;
01071          if (!availableOnly ||
01072             (fi->TestBit(TFileInfo::kStaged) &&
01073             !fi->TestBit(TFileInfo::kCorrupted))) {
01074             Int_t nf = fElements->GetSize();
01075             if (!Add(fi, meta)) return kFALSE;
01076             // Duplications count as bad files
01077             if (fElements->GetSize() <= nf) badlist->Add(fi);
01078          } else if (badlist) {
01079             // Return list of non-usable files
01080             badlist->Add(fi);
01081          }
01082       } else if (cn == "TUrl") {
01083          Add(((TUrl *)o)->GetUrl());
01084       } else if (cn == "TObjString") {
01085          Add(((TObjString *)o)->GetName());
01086       } else {
01087          Warning("Add","found object fo unexpected type %s - ignoring", cn.Data());
01088       }
01089    }
01090 
01091    return kTRUE;
01092 }
01093 
01094 //______________________________________________________________________________
01095 void TDSet::SetSrvMaps(TList *srvmaps)
01096 {
01097    // Set (or unset) the list for mapping servers coordinate for files.
01098    // Reinitialize the related iterator if needed.
01099    // Used by TProof.
01100 
01101    fSrvMaps = srvmaps;
01102    SafeDelete(fSrvMapsIter);
01103    if (fSrvMaps) fSrvMapsIter = new TIter(fSrvMaps);
01104 }
01105 
01106 //______________________________________________________________________________
01107 Bool_t TDSet::Add(TFileInfo *fi, const char *meta)
01108 {
01109    // Add file described by 'fi' to list of files to be analyzed.
01110    // The argument 'meta' can be used to specify a subsets in the
01111    // file as described in the metadata of TFileInfo. By default the first one
01112    // is taken.
01113 
01114    if (!fi) {
01115       Error("Add", "TFileInfo object name must be specified");
01116       return kFALSE;
01117    }
01118    TString msg;
01119 
01120    // Check if a remap of the server coordinates is requested
01121    const char *file = fi->GetFirstUrl()->GetUrl();
01122    Bool_t setLookedUp = kTRUE;
01123    TString file1;
01124    if (TDataSetManager::CheckDataSetSrvMaps(fi->GetFirstUrl(), file1, fSrvMaps) &&
01125        !(file1.IsNull())) {
01126       file = file1.Data();
01127       setLookedUp = kFALSE;
01128    }
01129    // Check if it already exists in the TDSet
01130    if (fElements->FindObject(file)) {
01131       msg.Form("duplication detected: %40s is already in dataset - ignored", file);
01132       Warning("Add", "%s", msg.Data());
01133       if (gProofServ) {
01134          msg.Insert(0, "WARNING: ");
01135          gProofServ->SendAsynMessage(msg);
01136       }
01137       return kTRUE;
01138    }
01139 
01140    // If more than one metadata info require the specification of the objpath;
01141    // the order in which they appear is not guaranteed and the error may be
01142    // very difficult to find.
01143    TFileInfoMeta *m = 0;
01144    if (!meta || strlen(meta) <= 0 || !strcmp(meta, "/")) {
01145       TList *fil = 0;
01146       if ((fil = fi->GetMetaDataList()) && fil->GetSize() > 1) {
01147          msg.Form("\n  Object name unspecified and several objects available.\n");
01148          msg += "  Please choose one from the list below:\n";
01149          TIter nx(fil);
01150          while ((m = (TFileInfoMeta *) nx())) {
01151             TString nm(m->GetName());
01152             if (nm.BeginsWith("/")) nm.Remove(0,1);
01153             msg += Form("  %s  ->   TProof::Process(\"%s#%s\",...)\n",
01154                         nm.Data(), GetName(), nm.Data());
01155          }
01156          if (gProofServ)
01157             gProofServ->SendAsynMessage(msg);
01158          else
01159             Warning("Add", "%s", msg.Data());
01160          return kFALSE;
01161       }
01162    }
01163 
01164    // Get the metadata, if any
01165    m = fi->GetMetaData(meta);
01166 
01167    // Create the element
01168    const char *objname = 0;
01169    const char *dir = 0;
01170    Long64_t first = 0;
01171    Long64_t num = -1;
01172    if (!m) {
01173       objname = GetObjName();
01174       dir = GetDirectory();
01175    } else {
01176       objname = (m->GetObject() && strlen(m->GetObject())) ? m->GetObject() : GetObjName();
01177       dir = (m->GetDirectory() && strlen(m->GetDirectory())) ? m->GetDirectory() : GetDirectory();
01178       first = m->GetFirst();
01179       num = m->GetEntries();
01180    }
01181    const char *dataset = 0;
01182    if (strcmp(fi->GetTitle(), "TFileInfo")) dataset = fi->GetTitle();
01183    TDSetElement *el = new TDSetElement(file, objname, dir, first, -1, 0, dataset);
01184    el->SetEntries(num);
01185 
01186    // Set looked-up bit
01187    if (fi->TestBit(TFileInfo::kStaged) && setLookedUp)
01188       el->SetBit(TDSetElement::kHasBeenLookedUp);
01189    if (fi->TestBit(TFileInfo::kCorrupted))
01190       el->SetBit(TDSetElement::kCorrupted);
01191 
01192    // Add the element
01193    fElements->Add(el);
01194 
01195    return kTRUE;
01196 }
01197 
01198 //______________________________________________________________________________
01199 Int_t TDSet::ExportFileList(const char *fpath, Option_t *opt)
01200 {
01201    // Export TDSetElements files as list of TFileInfo objects in file
01202    // 'fpath'. If the file exists already the action fails, unless
01203    // 'opt == "F"'.
01204    // Return 0 on success, -1 otherwise
01205 
01206    if (!fElements)
01207       return -1;
01208    if (fElements->GetSize() <= 0)
01209       return 0;
01210 
01211    Bool_t force = (opt[0] == 'F' || opt[0] == 'f');
01212 
01213    if (gSystem->AccessPathName(fpath, kFileExists) == kFALSE) {
01214       if (force) {
01215          // Try removing the file
01216          if (gSystem->Unlink(fpath)) {
01217             Info("ExportFileList","error removing dataset file: %s", fpath);
01218             return -1;
01219          }
01220       }
01221    }
01222 
01223    // Create the file list
01224    TList *fileinfo = new TList;
01225    fileinfo->SetOwner();
01226 
01227    TDSetElement *dse = 0;
01228    TIter next(fElements);
01229    while ((dse = (TDSetElement *) next())) {
01230       TFileInfoMeta *m = new TFileInfoMeta(dse->GetTitle(), dse->GetDirectory(), GetType(),
01231                                            dse->GetNum(), dse->GetFirst());
01232       TFileInfo *fi = new TFileInfo(dse->GetFileName());
01233       fi->AddMetaData(m);
01234       fileinfo->Add(fi);
01235    }
01236 
01237    // Write to file
01238    TFile *f = TFile::Open(fpath, "RECREATE");
01239    if (f) {
01240       f->cd();
01241       fileinfo->Write("fileList", TObject::kSingleKey);
01242       f->Close();
01243    } else {
01244       Info("ExportFileList","error creating dataset file: %s", fpath);
01245       SafeDelete(fileinfo);
01246       return -1;
01247    }
01248 
01249    // Cleanup
01250    SafeDelete(f);
01251    SafeDelete(fileinfo);
01252 
01253    // We are done
01254    return 0;
01255 }
01256 
01257 //______________________________________________________________________________
01258 void TDSet::AddFriend(TDSet *friendset, const char* alias)
01259 {
01260    // Add friend dataset to this set. Only possible if the TDSet type is
01261    // a TTree or derived class. The friendset will be owned by this class
01262    // and deleted in its destructor.
01263 
01264    if (!friendset) {
01265       Error("AddFriend", "The friend TDSet is null!");
01266       return;
01267    }
01268 
01269    if (!fIsTree) {
01270       Error("AddFriend", "a friend set can only be added to a TTree TDSet");
01271       return;
01272    }
01273    TList *thisList = GetListOfElements();
01274    TList *friendsList = friendset->GetListOfElements();
01275    if (thisList->GetSize() != friendsList->GetSize() && friendsList->GetSize() != 1) {
01276       Error("AddFriend", "the friend dataset has %d elements while the main one has %d",
01277             thisList->GetSize(), friendsList->GetSize());
01278       return;
01279    }
01280    TIter next(thisList);
01281    TIter next2(friendsList);
01282    TDSetElement *friendElem = 0;
01283    if (friendsList->GetSize() == 1)
01284       friendElem = dynamic_cast<TDSetElement*> (friendsList->First());
01285    while(TDSetElement* e = dynamic_cast<TDSetElement*> (next())) {
01286       if (friendElem) // just one elem in the friend TDSet
01287          e->AddFriend(friendElem, alias);
01288       else
01289          e->AddFriend(dynamic_cast<TDSetElement*> (next2()), alias);
01290    }
01291 }
01292 
01293 //______________________________________________________________________________
01294 void TDSet::Reset()
01295 {
01296    // Reset or initialize access to the elements.
01297 
01298    if (!fIterator) {
01299       fIterator = new TIter(fElements);
01300    } else {
01301       fIterator->Reset();
01302    }
01303 }
01304 
01305 //______________________________________________________________________________
01306 Long64_t TDSet::GetEntries(Bool_t isTree, const char *filename, const char *path,
01307                            TString &objname)
01308 {
01309    // Returns number of entries in tree or objects in file. Returns -1 in
01310    // case of error.
01311 
01312    Double_t start = 0;
01313    if (gPerfStats) start = TTimeStamp();
01314 
01315    // Take into acoount possible prefixes
01316    TFile::EFileType typ = TFile::kDefault;
01317    TString fname = gEnv->GetValue("Path.Localroot",""), pfx(fname);
01318    // Get the locality (disable warnings or errors in connection attempts)
01319    Int_t oldLevel = gErrorIgnoreLevel;
01320    gErrorIgnoreLevel = kError+1;
01321    if ((typ = TFile::GetType(filename, "", &fname)) != TFile::kLocal) fname = filename;
01322    gErrorIgnoreLevel = oldLevel;
01323    // Open the file
01324    TFile *file = TFile::Open(fname);
01325 
01326    if (gPerfStats)
01327       gPerfStats->FileOpenEvent(file, filename, start);
01328 
01329    if (file == 0) {
01330       ::SysError("TDSet::GetEntries",
01331                  "cannot open file %s (type: %d, pfx: %s)", filename, typ, pfx.Data());
01332       return -1;
01333    }
01334 
01335    TDirectory *dirsave = gDirectory;
01336    if (!file->cd(path)) {
01337       ::Error("TDSet::GetEntries", "cannot cd to %s", path);
01338       delete file;
01339       return -1;
01340    }
01341 
01342    TDirectory *dir = gDirectory;
01343    dirsave->cd();
01344 
01345    Long64_t entries;
01346    Bool_t fillname = kFALSE;
01347    if (isTree) {
01348 
01349       TString on(objname);
01350       TString sreg(objname);
01351       // If a wild card we will use the first object of the type
01352       // requested compatible with the reg expression we got
01353       if (sreg.Length() <= 0 || sreg == "" || sreg.Contains("*")) {
01354          fillname = kTRUE;
01355          if (sreg.Contains("*"))
01356             sreg.ReplaceAll("*", ".*");
01357          else
01358             sreg = ".*";
01359          TRegexp re(sreg);
01360          if (dir->GetListOfKeys()) {
01361             TIter nxk(dir->GetListOfKeys());
01362             TKey *k = 0;
01363             Bool_t notfound = kTRUE;
01364             while ((k = (TKey *) nxk())) {
01365                if (!strcmp(k->GetClassName(), "TTree")) {
01366                   TString kn(k->GetName());
01367                   if (kn.Index(re) != kNPOS) {
01368                      if (notfound) {
01369                         on = kn;
01370                         notfound = kFALSE;
01371                      } else if (kn != on) {
01372                        ::Warning("TDSet::GetEntries",
01373                                  "additional tree found in the file: %s", kn.Data());
01374                      }
01375                   }
01376                }
01377             }
01378          }
01379       }
01380 
01381       TKey *key = dir->GetKey(on);
01382       if (key == 0) {
01383          ::Error("TDSet::GetEntries", "cannot find tree \"%s\" in %s",
01384                  objname.Data(), filename);
01385          delete file;
01386          return -1;
01387       }
01388       TTree *tree = (TTree *) key->ReadObj();
01389       if (tree == 0) {
01390          // Error always reported?
01391          delete file;
01392          return -1;
01393       }
01394       entries = tree->GetEntries();
01395       delete tree;
01396 
01397       // Return full name in case of wildcards
01398       objname = (fillname) ? on : objname;
01399 
01400    } else {
01401       TList *keys = dir->GetListOfKeys();
01402       entries = keys->GetSize();
01403    }
01404 
01405    delete file;
01406    return entries;
01407 }
01408 
01409 //______________________________________________________________________________
01410 Long64_t TDSet::Draw(const char *varexp, const TCut &selection, Option_t *option,
01411                      Long64_t nentries, Long64_t firstentry)
01412 {
01413    // Draw expression varexp for specified entries.
01414    // Returns -1 in case of error or number of selected events in case of success.
01415    // This function accepts a TCut objects as argument.
01416    // Use the operator+ to concatenate cuts.
01417    // Example:
01418    //   dset.Draw("x",cut1+cut2+cut3);
01419 
01420    return Draw(varexp, selection.GetTitle(), option, nentries, firstentry);
01421 }
01422 
01423 //______________________________________________________________________________
01424 Long64_t TDSet::Draw(const char *varexp, const char *selection, Option_t *option,
01425                      Long64_t nentries, Long64_t firstentry)
01426 {
01427    // Draw expression varexp for specified entries.
01428    // Returns -1 in case of error or number of selected events in case of success.
01429    // For more see TTree::Draw().
01430 
01431    if (!IsValid() || !fElements->GetSize()) {
01432       Error("Draw", "not a correctly initialized TDSet");
01433       return -1;
01434    }
01435 
01436    if (gProof)
01437       return gProof->DrawSelect(this, varexp, selection, option, nentries,
01438                                 firstentry);
01439 
01440    Error("Draw", "no active PROOF session");
01441    return -1;
01442 }
01443 
01444 //_______________________________________________________________________
01445 void TDSet::StartViewer()
01446 {
01447    // Start the TTreeViewer on this TTree.
01448 
01449    if (gROOT->IsBatch()) {
01450       Warning("StartViewer", "viewer cannot run in batch mode");
01451       return;
01452    }
01453 
01454    if (!gProof) {
01455       Error("StartViewer", "no PROOF found");
01456       return;
01457    }
01458    if (!IsTree()) {
01459       Error("StartViewer", "TDSet contents should be of type TTree (or subtype)");
01460       return;
01461    }
01462    fProofChain = new TProofChain(this, kTRUE);
01463 
01464    TPluginHandler *h;
01465    if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualTreeViewer"))) {
01466       if (h->LoadPlugin() == -1)
01467          return;
01468       h->ExecPlugin(1,fProofChain);
01469    }
01470 }
01471 
01472 //_______________________________________________________________________
01473 TTree* TDSet::GetTreeHeader(TProof* proof)
01474 {
01475    // Returns a tree header containing the branches' structure of the dataset.
01476 
01477    return proof->GetTreeHeader(this);
01478 }
01479 
01480 //______________________________________________________________________________
01481 Bool_t TDSet::ElementsValid()
01482 {
01483    // Check if all elements are valid.
01484 
01485    if (TestBit(TDSet::kValidityChecked))
01486       return (TestBit(TDSet::kSomeInvalid) ? kFALSE : kTRUE);
01487 
01488    SetBit(TDSet::kValidityChecked);
01489    ResetBit(TDSet::kSomeInvalid);
01490    TIter nextElem(GetListOfElements());
01491    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem())) {
01492       if (!elem->GetValid()) {
01493          SetBit(TDSet::kSomeInvalid);
01494          return kFALSE;
01495       }
01496    }
01497    return kTRUE;
01498 }
01499 
01500 //______________________________________________________________________________
01501 Int_t TDSet::Remove(TDSetElement *elem, Bool_t deleteElem)
01502 {
01503    // Remove TDSetElement 'elem' from the list.
01504    // Return 0 on success, -1 if the element is not in the list
01505 
01506    if (!elem || !(((THashList *)(GetListOfElements()))->Remove(elem)))
01507       return -1;
01508 
01509    if (deleteElem)
01510       SafeDelete(elem);
01511    return 0;
01512 }
01513 
01514 //______________________________________________________________________________
01515 void TDSet::Validate()
01516 {
01517    // Validate the TDSet by opening files.
01518 
01519    TIter nextElem(GetListOfElements());
01520    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem())) {
01521       if (!elem->GetValid())
01522          elem->Validate(IsTree());
01523    }
01524 }
01525 
01526 //______________________________________________________________________________
01527 void TDSet::Lookup(Bool_t removeMissing, TList **listOfMissingFiles)
01528 {
01529    // Resolve the end-point URL for the current elements of this data set
01530    // If the removeMissing option is set to kTRUE, remove the TDSetElements
01531    // that can not be located.
01532    // The method returns the list of removed TDSetElements in *listOfMissingFiles
01533    // if the latter is defined (the list must be created outside).
01534 
01535    // If an entry- or event- list has been given, assign the relevant portions
01536    // to each element; this allows to look-up only for the elements which have
01537    // something to be processed, so it is better to do it before the real look-up
01538    // operations.
01539    SplitEntryList();
01540 
01541    TString msg("Looking up for exact location of files");
01542    UInt_t n = 0;
01543    UInt_t ng = 0;
01544    UInt_t tot = GetListOfElements()->GetSize();
01545    UInt_t n2 = (tot > 50) ? (UInt_t) tot / 50 : 1;
01546    Bool_t st = kTRUE;
01547    TIter nextElem(GetListOfElements());
01548    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem())) {
01549       if (elem->GetNum() != 0) { // -1 means "all entries"
01550          ng++;
01551          if (!elem->GetValid())
01552             if (elem->Lookup(kFALSE))
01553                if (removeMissing) {
01554                   if (Remove(elem, kFALSE))
01555                      Error("Lookup", "Error removing a missing file");
01556                   if (listOfMissingFiles)
01557                    (*listOfMissingFiles)->Add(elem->GetFileInfo(fType));
01558                }
01559       }
01560       n++;
01561       // Notify the client
01562       if (gProof && (n > 0 && !(n % n2)))
01563          gProof->SendDataSetStatus(msg, n, tot, st);
01564       // Break if we have been asked to stop
01565       if (gProof && gProof->GetRunStatus() != TProof::kRunning)
01566          break;
01567    }
01568    // Notify the client if not all the files have entries to be processed
01569    // (which may happen if an entry-list is used)
01570    if (ng < tot && gProofServ) {
01571       msg = Form("Files with entries to be processed: %d (out of %d)\n", ng, tot);
01572       gProofServ->SendAsynMessage(msg);
01573    } else {
01574       // Final notification to the client
01575       if (gProof) gProof->SendDataSetStatus(msg, n, tot, st);
01576    }
01577    // Done
01578    return;
01579 }
01580 
01581 //______________________________________________________________________________
01582 void TDSet::SetLookedUp()
01583 {
01584    // Flag all the elements as looked-up, so to avoid opening the files
01585    // if the functionality is not supported
01586 
01587    TIter nextElem(GetListOfElements());
01588    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem()))
01589       elem->SetLookedUp();
01590 }
01591 
01592 //______________________________________________________________________________
01593 void TDSet::Validate(TDSet* dset)
01594 {
01595    // Validate the TDSet against another TDSet.
01596    // Only validates elements in common from input TDSet.
01597 
01598    THashList bestElements;
01599    bestElements.SetOwner();
01600    TList namedHolder;
01601    namedHolder.SetOwner();
01602    TIter nextOtherElem(dset->GetListOfElements());
01603    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextOtherElem())) {
01604       if (!elem->GetValid()) continue;
01605       TString dir_file_obj = elem->GetDirectory();
01606       dir_file_obj += "_";
01607       dir_file_obj += TUrl(elem->GetFileName()).GetFileAndOptions();
01608       dir_file_obj += "_";
01609       dir_file_obj += elem->GetObjName();
01610       TPair *p = dynamic_cast<TPair*>(bestElements.FindObject(dir_file_obj));
01611       if (p) {
01612          TDSetElement *prevelem = dynamic_cast<TDSetElement*>(p->Value());
01613          if (prevelem) {
01614             Long64_t entries = prevelem->GetFirst()+prevelem->GetNum();
01615             if (entries<elem->GetFirst()+elem->GetNum()) {
01616                bestElements.Remove(p);
01617                bestElements.Add(new TPair(p->Key(), elem));
01618                delete p;
01619             }
01620          }
01621       } else {
01622          TNamed* named = new TNamed(dir_file_obj, dir_file_obj);
01623          namedHolder.Add(named);
01624          bestElements.Add(new TPair(named, elem));
01625       }
01626    }
01627 
01628    TIter nextElem(GetListOfElements());
01629    while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem())) {
01630       if (!elem->GetValid()) {
01631          TString dir_file_obj = elem->GetDirectory();
01632          dir_file_obj += "_";
01633          dir_file_obj += TUrl(elem->GetFileName()).GetFileAndOptions();
01634          dir_file_obj += "_";
01635          dir_file_obj += elem->GetObjName();
01636          if (TPair *p = dynamic_cast<TPair*>(bestElements.FindObject(dir_file_obj))) {
01637             TDSetElement* validelem = dynamic_cast<TDSetElement*>(p->Value());
01638             elem->Validate(validelem);
01639          }
01640       }
01641    }
01642 }
01643 
01644 //
01645 // To handle requests coming from version 3 client / masters we need
01646 // a special streamer
01647 //______________________________________________________________________________
01648 void TDSetElement::Streamer(TBuffer &R__b)
01649 {
01650    // Stream an object of class TDSetElement.
01651 
01652    if (R__b.IsReading()) {
01653       UInt_t R__s, R__c;
01654       Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
01655       ResetBit(kWriteV3);
01656       if (R__v > 4) {
01657          R__b.ReadClassBuffer(TDSetElement::Class(), this, R__v, R__s, R__c);
01658       } else {
01659          // For version 3 client / masters we need a special streamer
01660          SetBit(kWriteV3);
01661          if (R__v > 3) {
01662             TNamed::Streamer(R__b);
01663          } else {
01664             // Old versions were not deriving from TNamed and had the
01665             // file name and the object type name in the first two members
01666             TObject::Streamer(R__b);
01667             TString name, title;
01668             R__b >> name >> title;
01669             SetNameTitle(name, title);
01670          }
01671          // Now we read the standard part
01672          R__b >> fDirectory;
01673          R__b >> fFirst;
01674          R__b >> fNum;
01675          R__b >> fMsd;
01676          R__b >> fTDSetOffset;
01677          TEventList *evl;
01678          R__b >> evl;
01679          R__b >> fValid;
01680          R__b >> fEntries;
01681 
01682          // Special treatment waiting for proper retrieving of stl containers
01683          FriendsList_t *friends = new FriendsList_t;
01684          static TClassRef classFriendsList = TClass::GetClass(typeid(FriendsList_t));
01685          R__b.ReadClassBuffer( classFriendsList, friends, classFriendsList->GetClassVersion(), 0, 0);
01686          if (friends) {
01687             // Convert friends to a TList (to be written)
01688             fFriends = new TList();
01689             fFriends->SetOwner();
01690             for (FriendsList_t::iterator i = friends->begin();
01691                  i != friends->end(); ++i) {
01692                TDSetElement *dse = (TDSetElement *) i->first->Clone();
01693                fFriends->Add(new TPair(dse, new TObjString(i->second.Data())));
01694             }
01695          }
01696          // the value for fIsTree (only older versions are sending it)
01697          Bool_t tmpIsTree;
01698          R__b >> tmpIsTree;
01699          R__b.CheckByteCount(R__s, R__c, TDSetElement::IsA());
01700       }
01701    } else {
01702       if (TestBit(kWriteV3)) {
01703          // For version 3 client / masters we need a special streamer
01704          R__b << Version_t(3);
01705          TObject::Streamer(R__b);
01706          R__b << TString(GetName());
01707          R__b << TString(GetTitle());
01708          R__b << fDirectory;
01709          R__b << fFirst;
01710          R__b << fNum;
01711          R__b << fMsd;
01712          R__b << fTDSetOffset;
01713          R__b << (TEventList *)0;
01714          R__b << fValid;
01715          R__b << fEntries;
01716 
01717          // Special treatment waiting for proper retrieving of stl containers
01718          FriendsList_t *friends = new FriendsList_t;
01719          if (fFriends) {
01720             TIter nxf(fFriends);
01721             TPair *p = 0;
01722             while ((p = (TPair *)nxf()))
01723                friends->push_back(std::make_pair((TDSetElement *)p->Key(),
01724                                    TString(((TObjString *)p->Value())->GetName())));
01725          }
01726          static TClassRef classFriendsList = TClass::GetClass(typeid(FriendsList_t));
01727          R__b.WriteClassBuffer( classFriendsList, &friends );
01728 
01729          // Older versions had an unused boolean called fIsTree: we fill it
01730          // with its default value
01731          R__b << kFALSE;
01732       } else {
01733          R__b.WriteClassBuffer(TDSetElement::Class(),this);
01734       }
01735    }
01736 }
01737 
01738 //______________________________________________________________________________
01739 void TDSet::Streamer(TBuffer &R__b)
01740 {
01741    // Stream an object of class TDSet.
01742 
01743    if (R__b.IsReading()) {
01744       UInt_t R__s, R__c;
01745       Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
01746       ResetBit(kWriteV3);
01747       if (R__v > 3) {
01748          R__b.ReadClassBuffer(TDSet::Class(), this, R__v, R__s, R__c);
01749       } else {
01750          // For version 3 client / masters we need a special streamer
01751          SetBit(kWriteV3);
01752          TNamed::Streamer(R__b);
01753          R__b >> fDir;
01754          R__b >> fType;
01755          R__b >> fObjName;
01756          TList elems;
01757          elems.Streamer(R__b);
01758          elems.SetOwner(kFALSE);
01759          if (elems.GetSize() > 0) {
01760             fElements = new THashList;
01761             fElements->SetOwner();
01762             TDSetElement *e = 0;
01763             TIter nxe(&elems);
01764             while ((e = (TDSetElement *)nxe())) {
01765                fElements->Add(e);
01766             }
01767          } else {
01768             fElements = 0;
01769          }
01770          R__b >> fIsTree;
01771       }
01772    } else {
01773       if (TestBit(kWriteV3)) {
01774          // For version 3 client / masters we need a special streamer
01775          R__b << Version_t(3);
01776          TNamed::Streamer(R__b);
01777          R__b << fDir;
01778          R__b << fType;
01779          R__b << fObjName;
01780          TList elems;
01781          if (fElements) {
01782             elems.SetOwner(kFALSE);
01783             if (fElements->GetSize() > 0) {
01784                TDSetElement *e = 0;
01785                TIter nxe(fElements);
01786                while ((e = (TDSetElement *)nxe()))
01787                   elems.Add(e);
01788             }
01789          }
01790          elems.Streamer(R__b);
01791          R__b << fIsTree;
01792       } else {
01793          R__b.WriteClassBuffer(TDSet::Class(),this);
01794       }
01795    }
01796 }
01797 
01798 //______________________________________________________________________________
01799 void TDSet::SetWriteV3(Bool_t on)
01800 {
01801    // Set/Reset the 'OldStreamer' bit in this instance and its elements.
01802    // Needed for backward compatibility in talking to old client / masters.
01803 
01804    if (on)
01805       SetBit(TDSet::kWriteV3);
01806    else
01807       ResetBit(TDSet::kWriteV3);
01808    // Loop over dataset elements
01809    TIter nxe(GetListOfElements());
01810    TObject *o = 0;
01811    while ((o = nxe()))
01812       if (on)
01813          o->SetBit(TDSetElement::kWriteV3);
01814       else
01815          o->ResetBit(TDSetElement::kWriteV3);
01816 }
01817 
01818 //______________________________________________________________________________
01819 void TDSet::SetEntryList(TObject *aList)
01820 {
01821    // Set entry (or event) list for this data set
01822 
01823    if (!aList)
01824       return;
01825 
01826    if (TestBit(TDSet::kMultiDSet)) {
01827 
01828       // Global entry list for all the datasets
01829       TIter nxds(fElements);
01830       TDSet *ds = 0;
01831       while ((ds = (TDSet *) nxds()))
01832          ds->SetEntryList(aList);
01833 
01834    } else {
01835 
01836       // Link the proper object
01837       TEventList *evl = 0;
01838       TEntryList *enl = dynamic_cast<TEntryList*>(aList);
01839       if (!enl)
01840          evl = dynamic_cast<TEventList*>(aList);
01841       if (!enl && !evl) {
01842          Error("SetEntryList", "type of input object must be either TEntryList "
01843                               "or TEventList (found: '%s' - do nothing", aList->ClassName());
01844          return;
01845       }
01846 
01847       // Action depends on the type
01848       fEntryList = (enl) ? enl : (TEntryList *)evl;
01849    }
01850    // Done
01851    return;
01852 }
01853 
01854 //______________________________________________________________________________
01855 void TDSet::SplitEntryList()
01856 {
01857    // Splits the main entry (or event) list into sub-lists for the elements of
01858    // thet data set
01859 
01860    if (TestBit(TDSet::kMultiDSet)) {
01861       // Global entry list for all the datasets
01862       TIter nxds(fElements);
01863       TDSet *ds = 0;
01864       while ((ds = (TDSet *) nxds()))
01865          ds->SplitEntryList();
01866       // Done
01867       return;
01868    }
01869 
01870    if (!fEntryList) {
01871       if (gDebug > 0)
01872          Info("SplitEntryList", "no entry- (or event-) list to split - do nothing");
01873       return;
01874    }
01875 
01876    // Action depend on type of list
01877    TEntryList *enl = dynamic_cast<TEntryList *>(fEntryList);
01878    if (enl) {
01879       // TEntryList
01880       TIter next(fElements);
01881       TDSetElement *el=0;
01882       TEntryList *sublist = 0;
01883       while ((el=(TDSetElement*)next())){
01884          sublist = enl->GetEntryList(el->GetObjName(), el->GetFileName());
01885          if (sublist){
01886             el->SetEntryList(sublist);
01887             el->SetNum(sublist->GetN());
01888          } else {
01889             sublist = new TEntryList("", "");
01890             el->SetEntryList(sublist);
01891             el->SetNum(0);
01892          }
01893       }
01894    } else {
01895       TEventList *evl = dynamic_cast<TEventList *>(fEntryList);
01896       if (evl) {
01897          // TEventList
01898          TIter next(fElements);
01899          TDSetElement *el, *prev;
01900 
01901          prev = dynamic_cast<TDSetElement*> (next());
01902          if (!prev)
01903             return;
01904          Long64_t low = prev->GetTDSetOffset();
01905          Long64_t high = low;
01906          Long64_t currPos = 0;
01907          do {
01908             el = dynamic_cast<TDSetElement*> (next());
01909             // kMaxLong64 means infinity
01910             high = (el == 0) ? kMaxLong64 : el->GetTDSetOffset();
01911 #ifdef DEBUG
01912             while (currPos < evl->GetN() && evl->GetEntry(currPos) < low) {
01913                Error("SplitEntryList",
01914                      "TEventList: event outside of the range of any of the TDSetElements");
01915                currPos++;        // unnecessary check
01916             }
01917 #endif
01918             TEventList* nevl = new TEventList();
01919             while (currPos < evl->GetN() && evl->GetEntry((Int_t)currPos) < high) {
01920                nevl->Enter(evl->GetEntry((Int_t)currPos) - low);
01921                currPos++;
01922             }
01923             prev->SetEntryList(nevl);
01924             prev->SetNum(nevl->GetN());
01925             low = high;
01926             prev = el;
01927          } while (el);
01928       }
01929    }
01930 }
01931 
01932 //______________________________________________________________________________
01933 Int_t TDSet::GetNumOfFiles()
01934 {
01935    // Return the number of files in the dataset
01936 
01937    Int_t nf = -1;
01938    if (fElements) {
01939       nf = 0;
01940       if (TestBit(TDSet::kMultiDSet)) {
01941          TIter nxds(fElements);
01942          TDSet *ds = 0;
01943          while ((ds = (TDSet *) nxds()))
01944             if (ds->GetListOfElements()) nf += ds->GetListOfElements()->GetSize();
01945       } else {
01946          nf = fElements->GetSize();
01947       }
01948    }
01949    // Done
01950    return nf;
01951 }

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