TProof.cxx

Go to the documentation of this file.
00001 // @(#)root/proof:$Id: TProof.cxx 38146 2011-02-18 12:23:01Z ganis $
00002 // Author: Fons Rademakers   13/02/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 // TProof                                                               //
00015 //                                                                      //
00016 // This class controls a Parallel ROOT Facility, PROOF, cluster.        //
00017 // It fires the worker servers, it keeps track of how many workers are  //
00018 // running, it keeps track of the workers running status, it broadcasts //
00019 // messages to all workers, it collects results, etc.                   //
00020 //                                                                      //
00021 //////////////////////////////////////////////////////////////////////////
00022 
00023 #include <stdlib.h>
00024 #include <fcntl.h>
00025 #include <errno.h>
00026 #ifdef WIN32
00027 #   include <io.h>
00028 #   include <sys/stat.h>
00029 #   include <sys/types.h>
00030 #   include "snprintf.h"
00031 #else
00032 #   include <unistd.h>
00033 #endif
00034 #include <vector>
00035 
00036 #include "RConfigure.h"
00037 #include "Riostream.h"
00038 #include "Getline.h"
00039 #include "TBrowser.h"
00040 #include "TChain.h"
00041 #include "TCondor.h"
00042 #include "TDSet.h"
00043 #include "TError.h"
00044 #include "TEnv.h"
00045 #include "TEntryList.h"
00046 #include "TEventList.h"
00047 #include "TFile.h"
00048 #include "TFileInfo.h"
00049 #include "TFunction.h"
00050 #include "TFTP.h"
00051 #include "THashList.h"
00052 #include "TInterpreter.h"
00053 #include "TKey.h"
00054 #include "TMap.h"
00055 #include "TMath.h"
00056 #include "TMessage.h"
00057 #include "TMethodArg.h"
00058 #include "TMethodCall.h"
00059 #include "TMonitor.h"
00060 #include "TMutex.h"
00061 #include "TObjArray.h"
00062 #include "TObjString.h"
00063 #include "TParameter.h"
00064 #include "TProof.h"
00065 #include "TProofNodeInfo.h"
00066 #include "TVirtualProofPlayer.h"
00067 #include "TVirtualPacketizer.h"
00068 #include "TProofServ.h"
00069 #include "TPluginManager.h"
00070 #include "TQueryResult.h"
00071 #include "TRandom.h"
00072 #include "TRegexp.h"
00073 #include "TROOT.h"
00074 #include "TSemaphore.h"
00075 #include "TSlave.h"
00076 #include "TSocket.h"
00077 #include "TSortedList.h"
00078 #include "TSystem.h"
00079 #include "TThread.h"
00080 #include "TTree.h"
00081 #include "TUrl.h"
00082 #include "TFileCollection.h"
00083 #include "TDataSetManager.h"
00084 #include "TMacro.h"
00085 
00086 TProof *gProof = 0;
00087 TVirtualMutex *gProofMutex = 0;
00088 
00089 // Rotating indicator
00090 char TProofMergePrg::fgCr[4] = {'-', '\\', '|', '/'};
00091 
00092 TList   *TProof::fgProofEnvList = 0;          // List of env vars for proofserv
00093 TPluginHandler *TProof::fgLogViewer = 0;      // Log viewer handler
00094 
00095 ClassImp(TProof)
00096 
00097 //----- PROOF Interrupt signal handler -----------------------------------------
00098 //______________________________________________________________________________
00099 Bool_t TProofInterruptHandler::Notify()
00100 {
00101    // TProof interrupt handler.
00102 
00103    if (isatty(0) == 0 || isatty(1) == 0 || fProof->GetRemoteProtocol() < 22) {
00104 
00105       // Cannot ask the user : abort any remote processing
00106       fProof->StopProcess(kTRUE);
00107 
00108    } else {
00109       // Real stop or request to switch to asynchronous?
00110       char *a = 0;
00111       if (fProof->GetRemoteProtocol() < 22) {
00112          a = Getline("\nSwith to asynchronous mode not supported remotely:"
00113                      "\nEnter S/s to stop, Q/q to quit, any other key to continue: ");
00114       } else {
00115          a = Getline("\nEnter A/a to switch asynchronous, S/s to stop, Q/q to quit,"
00116                      " any other key to continue: ");
00117       }
00118       if (a[0] == 'Q' || a[0] == 'S' || a[0] == 'q' || a[0] == 's') {
00119 
00120          Info("Notify","Processing interrupt signal ... %c", a[0]);
00121 
00122          // Stop or abort any remote processing
00123          Bool_t abort = (a[0] == 'Q' || a[0] == 'q') ? kTRUE : kFALSE;
00124          fProof->StopProcess(abort);
00125 
00126       } else if ((a[0] == 'A' || a[0] == 'a') && fProof->GetRemoteProtocol() >= 22) {
00127          // Stop any remote processing
00128          fProof->GoAsynchronous();
00129       }
00130    }
00131 
00132    return kTRUE;
00133 }
00134 
00135 //----- Input handler for messages from TProofServ -----------------------------
00136 //______________________________________________________________________________
00137 TProofInputHandler::TProofInputHandler(TProof *p, TSocket *s)
00138                    : TFileHandler(s->GetDescriptor(),1),
00139                      fSocket(s), fProof(p)
00140 {
00141    // Constructor
00142 }
00143 
00144 //______________________________________________________________________________
00145 Bool_t TProofInputHandler::Notify()
00146 {
00147    // Handle input
00148 
00149    fProof->CollectInputFrom(fSocket);
00150    return kTRUE;
00151 }
00152 
00153 
00154 //------------------------------------------------------------------------------
00155 
00156 ClassImp(TSlaveInfo)
00157 
00158 //______________________________________________________________________________
00159 Int_t TSlaveInfo::Compare(const TObject *obj) const
00160 {
00161    // Used to sort slaveinfos by ordinal.
00162 
00163    if (!obj) return 1;
00164 
00165    const TSlaveInfo *si = dynamic_cast<const TSlaveInfo*>(obj);
00166 
00167    if (!si) return fOrdinal.CompareTo(obj->GetName());
00168 
00169    const char *myord = GetOrdinal();
00170    const char *otherord = si->GetOrdinal();
00171    while (myord && otherord) {
00172       Int_t myval = atoi(myord);
00173       Int_t otherval = atoi(otherord);
00174       if (myval < otherval) return 1;
00175       if (myval > otherval) return -1;
00176       myord = strchr(myord, '.');
00177       if (myord) myord++;
00178       otherord = strchr(otherord, '.');
00179       if (otherord) otherord++;
00180    }
00181    if (myord) return -1;
00182    if (otherord) return 1;
00183    return 0;
00184 }
00185 
00186 //______________________________________________________________________________
00187 void TSlaveInfo::Print(Option_t *opt) const
00188 {
00189    // Print slave info. If opt = "active" print only the active
00190    // slaves, if opt="notactive" print only the not active slaves,
00191    // if opt = "bad" print only the bad slaves, else
00192    // print all slaves.
00193 
00194    TString stat = fStatus == kActive ? "active" :
00195                   fStatus == kBad ? "bad" :
00196                   "not active";
00197 
00198    Bool_t newfmt = kFALSE;
00199    TString oo(opt);
00200    if (oo.Contains("N")) {
00201       newfmt = kTRUE;
00202       oo.ReplaceAll("N","");
00203    }
00204    if (oo == "active" && fStatus != kActive) return;
00205    if (oo == "notactive" && fStatus != kNotActive) return;
00206    if (oo == "bad" && fStatus != kBad) return;
00207 
00208    if (newfmt) {
00209       TString msd, si, datadir;
00210       if (!(fMsd.IsNull())) msd.Form("| msd: %s ", fMsd.Data());
00211       if (!(fDataDir.IsNull())) datadir.Form("| datadir: %s ", fDataDir.Data());
00212       if (fSysInfo.fCpus > 0) {
00213          si.Form("| %s, %d cores, %d MB ram", fHostName.Data(),
00214                fSysInfo.fCpus, fSysInfo.fPhysRam);
00215       } else {
00216          si.Form("| %s", fHostName.Data());
00217       }
00218       Printf("Worker: %9s %s %s%s| %s", fOrdinal.Data(), si.Data(), msd.Data(), datadir.Data(), stat.Data());
00219 
00220    } else {
00221       TString msd  = fMsd.IsNull() ? "<null>" : fMsd.Data();
00222 
00223       cout << "Slave: "          << fOrdinal
00224          << "  hostname: "     << fHostName
00225          << "  msd: "          << msd
00226          << "  perf index: "   << fPerfIndex
00227          << "  "               << stat
00228          << endl;
00229    }
00230 }
00231 
00232 //______________________________________________________________________________
00233 void TSlaveInfo::SetSysInfo(SysInfo_t si)
00234 {
00235    // Setter for fSysInfo
00236 
00237    fSysInfo.fOS       = si.fOS;          // OS
00238    fSysInfo.fModel    = si.fModel;       // computer model
00239    fSysInfo.fCpuType  = si.fCpuType;     // type of cpu
00240    fSysInfo.fCpus     = si.fCpus;        // number of cpus
00241    fSysInfo.fCpuSpeed = si.fCpuSpeed;    // cpu speed in MHz
00242    fSysInfo.fBusSpeed = si.fBusSpeed;    // bus speed in MHz
00243    fSysInfo.fL2Cache  = si.fL2Cache;     // level 2 cache size in KB
00244    fSysInfo.fPhysRam  = si.fPhysRam;     // Physical RAM
00245 }
00246 
00247 //------------------------------------------------------------------------------
00248 
00249 //______________________________________________________________________________
00250 static char *CollapseSlashesInPath(const char *path)
00251 {
00252    // Get rid of spare slashes in a path. Returned path must be deleted[]
00253    // by the user.
00254 
00255    if (path) {
00256       Int_t i = 1; // current index as we go along the string
00257       Int_t j = 0; // current end of new path in newPath
00258       char *newPath = new char [strlen(path) + 1];
00259       newPath[0] = path[0];
00260       while (path[i]) {
00261          if (path[i] != '/' || newPath[j] != '/') {
00262             j++;
00263             newPath[j] = path[i];
00264          }
00265          i++;
00266       }
00267       if (newPath[j] != '/')
00268          j++;
00269       newPath[j] = 0; // We have to terminate the new path.
00270       return newPath;
00271    }
00272    return 0;
00273 }
00274 
00275 ClassImp(TProof)
00276 
00277 TSemaphore    *TProof::fgSemaphore = 0;
00278 
00279 //------------------------------------------------------------------------------
00280 
00281 //______________________________________________________________________________
00282 TMergerInfo::~TMergerInfo()
00283 {
00284    // Destructor
00285 
00286    // Just delete the list, the objects are owned by other list
00287    if (fWorkers) {
00288       fWorkers->SetOwner(kFALSE);
00289       SafeDelete(fWorkers);
00290    }
00291 }
00292 //______________________________________________________________________________
00293 void TMergerInfo::SetMergedWorker()
00294 {
00295    // Increase number of already merged workers by 1
00296 
00297    if (AreAllWorkersMerged())
00298       Error("SetMergedWorker", "all workers have been already merged before!");
00299    else
00300       fMergedWorkers++;
00301 }
00302 
00303 //______________________________________________________________________________
00304 void TMergerInfo::AddWorker(TSlave *sl)
00305 {
00306    // Add new worker to the list of workers to be merged by this merger
00307 
00308    if (!fWorkers)
00309       fWorkers = new TList();
00310    if (fWorkersToMerge == fWorkers->GetSize()) {
00311       Error("AddWorker", "all workers have been already assigned to this merger");
00312       return;
00313    }
00314    fWorkers->Add(sl);
00315 }
00316 
00317 //______________________________________________________________________________
00318 Bool_t TMergerInfo::AreAllWorkersMerged()
00319 {
00320    // Return if merger has already merged all workers, i.e. if it has finished its merging job
00321 
00322    return (fWorkersToMerge == fMergedWorkers);
00323 }
00324 
00325 //______________________________________________________________________________
00326 Bool_t TMergerInfo::AreAllWorkersAssigned()
00327 {
00328       // Return if the determined number of workers has been already assigned to this merger
00329 
00330       if (!fWorkers)
00331          return kFALSE;
00332 
00333       return (fWorkers->GetSize() == fWorkersToMerge);
00334 }
00335 
00336 //------------------------------------------------------------------------------
00337 TProof::TProof(const char *masterurl, const char *conffile, const char *confdir,
00338                Int_t loglevel, const char *alias, TProofMgr *mgr)
00339        : fUrl(masterurl)
00340 {
00341    // Create a PROOF environment. Starting PROOF involves either connecting
00342    // to a master server, which in turn will start a set of slave servers, or
00343    // directly starting as master server (if master = ""). Masterurl is of
00344    // the form: [proof[s]://]host[:port]. Conffile is the name of the config
00345    // file describing the remote PROOF cluster (this argument alows you to
00346    // describe different cluster configurations).
00347    // The default is proof.conf. Confdir is the directory where the config
00348    // file and other PROOF related files are (like motd and noproof files).
00349    // Loglevel is the log level (default = 1). User specified custom config
00350    // files will be first looked for in $HOME/.conffile.
00351 
00352    // Default initializations
00353    InitMembers();
00354 
00355    // This may be needed during init
00356    fManager = mgr;
00357 
00358    // Default server type
00359    fServType = TProofMgr::kXProofd;
00360 
00361    // Default query mode
00362    fQueryMode = kSync;
00363 
00364    // Parse the main URL, adjusting the missing fields and setting the relevant
00365    // bits
00366    ResetBit(TProof::kIsClient);
00367    ResetBit(TProof::kIsMaster);
00368 
00369    // Protocol and Host
00370    if (!masterurl || strlen(masterurl) <= 0) {
00371       fUrl.SetProtocol("proof");
00372       fUrl.SetHost("__master__");
00373    } else if (!(strstr(masterurl, "://"))) {
00374       fUrl.SetProtocol("proof");
00375    }
00376    if (!strcmp(fUrl.GetHost(), "localhost") ||
00377        !strncmp(fUrl.GetHost(), "localhost.", strlen("localhost.")))
00378       fUrl.SetHost(gSystem->HostName());
00379 
00380    // Port
00381    if (fUrl.GetPort() == TUrl(" ").GetPort())
00382       fUrl.SetPort(TUrl("proof:// ").GetPort());
00383 
00384    // User
00385    if (strlen(fUrl.GetUser()) <= 0) {
00386       // Get user logon name
00387       UserGroup_t *pw = gSystem->GetUserInfo();
00388       if (pw) {
00389          fUrl.SetUser(pw->fUser);
00390          delete pw;
00391       }
00392    }
00393 
00394    // Make sure to store the FQDN, so to get a solid reference for subsequent checks
00395    if (!strcmp(fUrl.GetHost(), "__master__"))
00396       fMaster = fUrl.GetHost();
00397    else if (!strlen(fUrl.GetHost()))
00398       fMaster = gSystem->GetHostByName(gSystem->HostName()).GetHostName();
00399    else
00400       fMaster = gSystem->GetHostByName(fUrl.GetHost()).GetHostName();
00401 
00402    // Server type
00403    if (strlen(fUrl.GetOptions()) > 0) {
00404       TString opts(fUrl.GetOptions());
00405       if (!(strncmp(fUrl.GetOptions(),"std",3))) {
00406          fServType = TProofMgr::kProofd;
00407          opts.Remove(0,3);
00408          fUrl.SetOptions(opts.Data());
00409       } else if (!(strncmp(fUrl.GetOptions(),"lite",4))) {
00410          fServType = TProofMgr::kProofLite;
00411          opts.Remove(0,4);
00412          fUrl.SetOptions(opts.Data());
00413       }
00414    }
00415 
00416    // Instance type
00417    fMasterServ = kFALSE;
00418    SetBit(TProof::kIsClient);
00419    ResetBit(TProof::kIsMaster);
00420    if (fMaster == "__master__") {
00421       fMasterServ = kTRUE;
00422       ResetBit(TProof::kIsClient);
00423       SetBit(TProof::kIsMaster);
00424    } else if (fMaster == "prooflite") {
00425       // Client and master are merged
00426       fMasterServ = kTRUE;
00427       SetBit(TProof::kIsMaster);
00428    }
00429    // Flag that we are a client
00430    if (TestBit(TProof::kIsClient))
00431       if (!gSystem->Getenv("ROOTPROOFCLIENT")) gSystem->Setenv("ROOTPROOFCLIENT","");
00432 
00433    Init(masterurl, conffile, confdir, loglevel, alias);
00434 
00435    // If called by a manager, make sure it stays in last position
00436    // for cleaning
00437    if (mgr) {
00438       R__LOCKGUARD2(gROOTMutex);
00439       gROOT->GetListOfSockets()->Remove(mgr);
00440       gROOT->GetListOfSockets()->Add(mgr);
00441    }
00442 
00443    // Old-style server type: we add this to the list and set the global pointer
00444    if (IsProofd() || TestBit(TProof::kIsMaster))
00445       if (!gROOT->GetListOfProofs()->FindObject(this))
00446          gROOT->GetListOfProofs()->Add(this);
00447 
00448    // Still needed by the packetizers: needs to be changed
00449    gProof = this;
00450 }
00451 
00452 //______________________________________________________________________________
00453 TProof::TProof() : fUrl(""), fServType(TProofMgr::kXProofd)
00454 {
00455    // Protected constructor to be used by classes deriving from TProof
00456    // (they have to call Init themselves and override StartSlaves
00457    // appropriately).
00458    //
00459    // This constructor simply closes any previous gProof and sets gProof
00460    // to this instance.
00461 
00462    // Default initializations
00463    InitMembers();
00464 
00465    if (!gROOT->GetListOfProofs()->FindObject(this))
00466       gROOT->GetListOfProofs()->Add(this);
00467 
00468    gProof = this;
00469 }
00470 
00471 //______________________________________________________________________________
00472 void TProof::InitMembers()
00473 {
00474    // Default initializations
00475 
00476    fValid = kFALSE;
00477    fRecvMessages = 0;
00478    fSlaveInfo = 0;
00479    fMasterServ = kFALSE;
00480    fSendGroupView = kFALSE;
00481    fActiveSlaves = 0;
00482    fInactiveSlaves = 0;
00483    fUniqueSlaves = 0;
00484    fAllUniqueSlaves = 0;
00485    fNonUniqueMasters = 0;
00486    fActiveMonitor = 0;
00487    fUniqueMonitor = 0;
00488    fAllUniqueMonitor = 0;
00489    fCurrentMonitor = 0;
00490    fBytesRead = 0;
00491    fRealTime = 0;
00492    fCpuTime = 0;
00493    fIntHandler = 0;
00494    fProgressDialog = 0;
00495    fProgressDialogStarted = kFALSE;
00496    SetBit(kUseProgressDialog);
00497    fPlayer = 0;
00498    fFeedback = 0;
00499    fChains = 0;
00500    fDSet = 0;
00501    fNotIdle = 0;
00502    fSync = kTRUE;
00503    fRunStatus = kRunning;
00504    fIsWaiting = kFALSE;
00505    fRedirLog = kFALSE;
00506    fLogFileW = 0;
00507    fLogFileR = 0;
00508    fLogToWindowOnly = kFALSE;
00509 
00510    fWaitingSlaves = 0;
00511    fQueries = 0;
00512    fOtherQueries = 0;
00513    fDrawQueries = 0;
00514    fMaxDrawQueries = 1;
00515    fSeqNum = 0;
00516 
00517    fSessionID = -1;
00518    fEndMaster = kFALSE;
00519 
00520    fGlobalPackageDirList = 0;
00521    fPackageLock = 0;
00522    fEnabledPackagesOnClient = 0;
00523 
00524    fInputData = 0;
00525 
00526    fPrintProgress = 0;
00527 
00528    fLoadedMacros = 0;
00529 
00530    fProtocol = -1;
00531    fSlaves = 0;
00532    fBadSlaves = 0;
00533    fAllMonitor = 0;
00534    fDataReady = kFALSE;
00535    fBytesReady = 0;
00536    fTotalBytes = 0;
00537    fAvailablePackages = 0;
00538    fEnabledPackages = 0;
00539    fRunningDSets = 0;
00540 
00541    fCollectTimeout = -1;
00542 
00543    fManager = 0;
00544    fQueryMode = kSync;
00545    fDynamicStartup = kFALSE;
00546 
00547    fCloseMutex = 0;
00548 
00549    fMergersSet = kFALSE;
00550    fMergers = 0;
00551    fMergersCount = -1;
00552    fLastAssignedMerger = 0;
00553    fWorkersToMerge = 0;
00554    fFinalizationRunning = kFALSE;
00555 
00556    // Check if the user defined a list of environment variables to send over:
00557    // include them into the dedicated list
00558    if (gSystem->Getenv("PROOF_ENVVARS")) {
00559       TString envs(gSystem->Getenv("PROOF_ENVVARS")), env, envsfound;
00560       Int_t from = 0;
00561       while (envs.Tokenize(env, from, ",")) {
00562          if (!env.IsNull()) {
00563             if (!gSystem->Getenv(env)) {
00564                Warning("Init", "request for sending over undefined environemnt variable '%s' - ignoring", env.Data());
00565             } else {
00566                if (!envsfound.IsNull()) envsfound += ",";
00567                envsfound += env;
00568                TProof::DelEnvVar(env);
00569                TProof::AddEnvVar(env, gSystem->Getenv(env));
00570             }
00571          }
00572       }
00573       if (envsfound.IsNull()) {
00574          Warning("Init", "none of the requested env variables were found: '%s'", envs.Data());
00575       } else {
00576          Info("Init", "the following environment variables have been added to the list to be sent to the nodes: '%s'", envsfound.Data());
00577       }
00578    }
00579 
00580    // Done
00581    return;
00582 }
00583 
00584 //______________________________________________________________________________
00585 TProof::~TProof()
00586 {
00587    // Clean up PROOF environment.
00588 
00589    if (fChains) {
00590       while (TChain *chain = dynamic_cast<TChain*> (fChains->First()) ) {
00591          // remove "chain" from list
00592          chain->SetProof(0);
00593          RemoveChain(chain);
00594       }
00595    }
00596 
00597    // remove links to packages enabled on the client
00598    if (TestBit(TProof::kIsClient)) {
00599       // iterate over all packages
00600       TIter nextpackage(fEnabledPackagesOnClient);
00601       while (TObjString *package = dynamic_cast<TObjString*>(nextpackage())) {
00602          FileStat_t stat;
00603          gSystem->GetPathInfo(package->String(), stat);
00604          // check if symlink, if so unlink
00605          // NOTE: GetPathInfo() returns 1 in case of symlink that does not point to
00606          // existing file or to a directory, but if fIsLink is true the symlink exists
00607          if (stat.fIsLink)
00608             gSystem->Unlink(package->String());
00609       }
00610    }
00611 
00612    Close();
00613    SafeDelete(fIntHandler);
00614    SafeDelete(fSlaves);
00615    SafeDelete(fActiveSlaves);
00616    SafeDelete(fInactiveSlaves);
00617    SafeDelete(fUniqueSlaves);
00618    SafeDelete(fAllUniqueSlaves);
00619    SafeDelete(fNonUniqueMasters);
00620    SafeDelete(fBadSlaves);
00621    SafeDelete(fAllMonitor);
00622    SafeDelete(fActiveMonitor);
00623    SafeDelete(fUniqueMonitor);
00624    SafeDelete(fAllUniqueMonitor);
00625    SafeDelete(fSlaveInfo);
00626    SafeDelete(fChains);
00627    SafeDelete(fPlayer);
00628    SafeDelete(fFeedback);
00629    SafeDelete(fWaitingSlaves);
00630    SafeDelete(fAvailablePackages);
00631    SafeDelete(fEnabledPackages);
00632    SafeDelete(fEnabledPackagesOnClient);
00633    SafeDelete(fLoadedMacros);
00634    SafeDelete(fPackageLock);
00635    SafeDelete(fGlobalPackageDirList);
00636    SafeDelete(fRecvMessages);
00637    SafeDelete(fInputData);
00638    SafeDelete(fRunningDSets);
00639    SafeDelete(fCloseMutex);
00640 
00641    // remove file with redirected logs
00642    if (TestBit(TProof::kIsClient)) {
00643       if (fLogFileR)
00644          fclose(fLogFileR);
00645       if (fLogFileW)
00646          fclose(fLogFileW);
00647       if (fLogFileName.Length() > 0)
00648          gSystem->Unlink(fLogFileName);
00649    }
00650 
00651    // Remove for the global list
00652    gROOT->GetListOfProofs()->Remove(this);
00653    // ... and from the manager list
00654    if (fManager && fManager->IsValid())
00655       fManager->DiscardSession(this);
00656 
00657    if (gProof && gProof == this) {
00658       // Set previous as default
00659       TIter pvp(gROOT->GetListOfProofs(), kIterBackward);
00660       while ((gProof = (TProof *)pvp())) {
00661          if (gProof->InheritsFrom(TProof::Class()))
00662             break;
00663       }
00664    }
00665 
00666    // For those interested in our destruction ...
00667    Emit("~TProof()");
00668 }
00669 
00670 //______________________________________________________________________________
00671 Int_t TProof::Init(const char *, const char *conffile,
00672                    const char *confdir, Int_t loglevel, const char *alias)
00673 {
00674    // Start the PROOF environment. Starting PROOF involves either connecting
00675    // to a master server, which in turn will start a set of slave servers, or
00676    // directly starting as master server (if master = ""). For a description
00677    // of the arguments see the TProof ctor. Returns the number of started
00678    // master or slave servers, returns 0 in case of error, in which case
00679    // fValid remains false.
00680 
00681    R__ASSERT(gSystem);
00682 
00683    fValid = kFALSE;
00684 
00685    // If in attach mode, options is filled with additional info
00686    Bool_t attach = kFALSE;
00687    if (strlen(fUrl.GetOptions()) > 0) {
00688       attach = kTRUE;
00689       // A flag from the GUI
00690       TString opts = fUrl.GetOptions();
00691       if (opts.Contains("GUI")) {
00692          SetBit(TProof::kUsingSessionGui);
00693          opts.Remove(opts.Index("GUI"));
00694          fUrl.SetOptions(opts);
00695       }
00696    }
00697 
00698    if (TestBit(TProof::kIsMaster)) {
00699       // Fill default conf file and conf dir
00700       if (!conffile || strlen(conffile) == 0)
00701          fConfFile = kPROOF_ConfFile;
00702       if (!confdir  || strlen(confdir) == 0)
00703          fConfDir  = kPROOF_ConfDir;
00704       // The group; the client receives it in the kPROOF_SESSIONTAG message
00705       if (gProofServ) fGroup = gProofServ->GetGroup();
00706    } else {
00707       fConfDir     = confdir;
00708       fConfFile    = conffile;
00709    }
00710 
00711    // Analysise the conffile field
00712    ParseConfigField(fConfFile);
00713 
00714    fWorkDir        = gSystem->WorkingDirectory();
00715    fLogLevel       = loglevel;
00716    fProtocol       = kPROOF_Protocol;
00717    fSendGroupView  = kTRUE;
00718    fImage          = fMasterServ ? "" : "<local>";
00719    fIntHandler     = 0;
00720    fStatus         = 0;
00721    fRecvMessages   = new TList;
00722    fRecvMessages->SetOwner(kTRUE);
00723    fSlaveInfo      = 0;
00724    fChains         = new TList;
00725    fAvailablePackages = 0;
00726    fEnabledPackages = 0;
00727    fRunningDSets   = 0;
00728    fEndMaster      = TestBit(TProof::kIsMaster) ? kTRUE : kFALSE;
00729    fInputData      = 0;
00730    ResetBit(TProof::kNewInputData);
00731    fPrintProgress  = 0;
00732 
00733    // Timeout for some collect actions
00734    fCollectTimeout = gEnv->GetValue("Proof.CollectTimeout", -1);
00735 
00736    // Should the workers be started dynamically; default: no
00737    fDynamicStartup = gEnv->GetValue("Proof.DynamicStartup", kFALSE);
00738 
00739    // Default entry point for the data pool is the master
00740    if (TestBit(TProof::kIsClient))
00741       fDataPoolUrl.Form("root://%s", fMaster.Data());
00742    else
00743       fDataPoolUrl = "";
00744 
00745    fProgressDialog        = 0;
00746    fProgressDialogStarted = kFALSE;
00747 
00748    // Default alias is the master name
00749    TString      al = (alias) ? alias : fMaster.Data();
00750    SetAlias(al);
00751 
00752    // Client logging of messages from the master and slaves
00753    fRedirLog = kFALSE;
00754    if (TestBit(TProof::kIsClient)) {
00755       fLogFileName.Form("%s/ProofLog_%d", gSystem->TempDirectory(), gSystem->GetPid());
00756       if ((fLogFileW = fopen(fLogFileName, "w")) == 0)
00757          Error("Init", "could not create temporary logfile");
00758       if ((fLogFileR = fopen(fLogFileName, "r")) == 0)
00759          Error("Init", "could not open temp logfile for reading");
00760    }
00761    fLogToWindowOnly = kFALSE;
00762 
00763    // Status of cluster
00764    fNotIdle = 0;
00765    // Query type
00766    fSync = (attach) ? kFALSE : kTRUE;
00767    // Not enqueued
00768    fIsWaiting = kFALSE;
00769 
00770    // Counters
00771    fBytesRead = 0;
00772    fRealTime = 0;
00773    fCpuTime = 0;
00774 
00775    // List of queries
00776    fQueries = 0;
00777    fOtherQueries = 0;
00778    fDrawQueries = 0;
00779    fMaxDrawQueries = 1;
00780    fSeqNum = 0;
00781 
00782    // Remote ID of the session
00783    fSessionID = -1;
00784 
00785    // Part of active query
00786    fWaitingSlaves = 0;
00787 
00788    // Make remote PROOF player
00789    fPlayer = 0;
00790    MakePlayer();
00791 
00792    fFeedback = new TList;
00793    fFeedback->SetOwner();
00794    fFeedback->SetName("FeedbackList");
00795    AddInput(fFeedback);
00796 
00797    // sort slaves by descending performance index
00798    fSlaves           = new TSortedList(kSortDescending);
00799    fActiveSlaves     = new TList;
00800    fInactiveSlaves   = new TList;
00801    fUniqueSlaves     = new TList;
00802    fAllUniqueSlaves  = new TList;
00803    fNonUniqueMasters = new TList;
00804    fBadSlaves        = new TList;
00805    fAllMonitor       = new TMonitor;
00806    fActiveMonitor    = new TMonitor;
00807    fUniqueMonitor    = new TMonitor;
00808    fAllUniqueMonitor = new TMonitor;
00809    fCurrentMonitor   = 0;
00810 
00811    fPackageLock             = 0;
00812    fEnabledPackagesOnClient = 0;
00813    fLoadedMacros            = 0;
00814    fGlobalPackageDirList    = 0;
00815 
00816    // Enable optimized sending of streamer infos to use embedded backward/forward
00817    // compatibility support between different ROOT versions and different versions of
00818    // users classes
00819    Bool_t enableSchemaEvolution = gEnv->GetValue("Proof.SchemaEvolution",1);
00820    if (enableSchemaEvolution) {
00821       TMessage::EnableSchemaEvolutionForAll();
00822    } else {
00823       Info("TProof", "automatic schema evolution in TMessage explicitely disabled");
00824    }
00825 
00826    if (IsMaster()) {
00827       // to make UploadPackage() method work on the master as well.
00828       fPackageDir = gProofServ->GetPackageDir();
00829    } else {
00830 
00831       TString sandbox = gEnv->GetValue("Proof.Sandbox", "");
00832       if (sandbox.IsNull()) sandbox.Form("~/%s", kPROOF_WorkDir);
00833       gSystem->ExpandPathName(sandbox);
00834       if (AssertPath(sandbox, kTRUE) != 0) {
00835          Error("Init", "failure asserting directory %s", sandbox.Data());
00836          return 0;
00837       }
00838 
00839       // Package Dir
00840       fPackageDir = gEnv->GetValue("Proof.PackageDir", "");
00841       if (fPackageDir.IsNull())
00842          fPackageDir.Form("%s/%s", sandbox.Data(), kPROOF_PackDir);
00843       if (AssertPath(fPackageDir, kTRUE) != 0) {
00844          Error("Init", "failure asserting directory %s", fPackageDir.Data());
00845          return 0;
00846       }
00847    }
00848 
00849    if (!IsMaster()) {
00850       // List of directories where to look for global packages
00851       TString globpack = gEnv->GetValue("Proof.GlobalPackageDirs","");
00852       if (globpack.Length() > 0) {
00853          Int_t ng = 0;
00854          Int_t from = 0;
00855          TString ldir;
00856          while (globpack.Tokenize(ldir, from, ":")) {
00857             if (gSystem->AccessPathName(ldir, kReadPermission)) {
00858                Warning("Init", "directory for global packages %s does not"
00859                                " exist or is not readable", ldir.Data());
00860             } else {
00861                // Add to the list, key will be "G<ng>", i.e. "G0", "G1", ...
00862                TString key = Form("G%d", ng++);
00863                if (!fGlobalPackageDirList) {
00864                   fGlobalPackageDirList = new THashList();
00865                   fGlobalPackageDirList->SetOwner();
00866                }
00867                fGlobalPackageDirList->Add(new TNamed(key,ldir));
00868             }
00869          }
00870       }
00871 
00872       TString lockpath(fPackageDir);
00873       lockpath.ReplaceAll("/", "%");
00874       lockpath.Insert(0, Form("%s/%s", gSystem->TempDirectory(), kPROOF_PackageLockFile));
00875       fPackageLock = new TProofLockPath(lockpath.Data());
00876 
00877       fEnabledPackagesOnClient = new TList;
00878       fEnabledPackagesOnClient->SetOwner();
00879    }
00880 
00881    // Master may want dynamic startup
00882    if (fDynamicStartup) {
00883       if (!IsMaster()) {
00884          // If on client - start the master
00885          if (!StartSlaves(attach))
00886             return 0;
00887       }
00888    } else {
00889 
00890       // Master Only mode (for operations requiring only the master, e.g. dataset browsing,
00891       // result retrieving, ...)
00892       Bool_t masterOnly = gEnv->GetValue("Proof.MasterOnly", kFALSE);
00893       if (!IsMaster() || !masterOnly) {
00894          // Start slaves (the old, static, per-session way)
00895          if (!StartSlaves(attach))
00896             return 0;
00897       }
00898    }
00899 
00900    if (fgSemaphore)
00901       SafeDelete(fgSemaphore);
00902 
00903    // we are now properly initialized
00904    fValid = kTRUE;
00905 
00906    // De-activate monitor (will be activated in Collect)
00907    fAllMonitor->DeActivateAll();
00908 
00909    // By default go into parallel mode
00910    GoParallel(9999, attach);
00911 
00912    // Send relevant initial state to slaves
00913    if (!attach)
00914       SendInitialState();
00915    else if (!IsIdle())
00916       // redirect log
00917       fRedirLog = kTRUE;
00918 
00919    // Done at this point, the alias will be communicated to the coordinator, if any
00920    if (TestBit(TProof::kIsClient))
00921       SetAlias(al);
00922 
00923    SetActive(kFALSE);
00924 
00925    if (IsValid()) {
00926 
00927       // Activate input handler
00928       ActivateAsyncInput();
00929 
00930       R__LOCKGUARD2(gROOTMutex);
00931       gROOT->GetListOfSockets()->Add(this);
00932    }
00933    return fActiveSlaves->GetSize();
00934 }
00935 
00936 //______________________________________________________________________________
00937 void TProof::ParseConfigField(const char *config)
00938 {
00939    // The config file field may contain special instructions which need to be
00940    // parsed at the beginning, e.g. for debug runs with valgrind.
00941 
00942    TString sconf(config);
00943 
00944    // Analysise the field
00945    const char *cq = (IsLite()) ? "\"" : "";
00946    Int_t ivg = kNPOS;
00947    if ((ivg = sconf.Index("valgrind")) != kNPOS) {
00948       Int_t jvg = sconf.Index(',', ivg);
00949       Int_t lvg = (jvg != kNPOS) ? (jvg-ivg) : sconf.Length();
00950       TString vgconf = sconf(ivg, lvg);
00951       // Any existing valgrind setting? User can give full settings, which we fully respect,
00952       // or pass additional options for valgrind by prefixing 'valgrind_opts:'. For example,
00953       //    TProof::AddEnvVar("PROOF_MASTER_WRAPPERCMD", "valgrind_opts:--time-stamp --leak-check=full"
00954       // will add option "--time-stamp --leak-check=full" to our default options
00955       TString mst, wrk, all;
00956       TList *envs = fgProofEnvList;
00957       TNamed *n = 0;
00958       if (envs) {
00959          if ((n = (TNamed *) envs->FindObject("PROOF_WRAPPERCMD")))
00960             all = n->GetTitle();
00961          if ((n = (TNamed *) envs->FindObject("PROOF_MASTER_WRAPPERCMD")))
00962             mst = n->GetTitle();
00963          if ((n = (TNamed *) envs->FindObject("PROOF_SLAVE_WRAPPERCMD")))
00964             wrk = n->GetTitle();
00965       }
00966       if (all != "" && mst == "") mst = all;
00967       if (all != "" && wrk == "") wrk = all;
00968       if (all != "" && all.BeginsWith("valgrind_opts:")) {
00969          // The field is used to add an option Reset the setting
00970          Info("ParseConfigField","valgrind run: resetting 'PROOF_WRAPPERCMD':"
00971                                  " must be set again for next run , if any");
00972          TProof::DelEnvVar("PROOF_WRAPPERCMD");
00973       }
00974       TString var, cmd;
00975       cmd.Form("%svalgrind -v --suppressions=<rootsys>/etc/valgrind-root.supp", cq);
00976       TString mstlab("NO"), wrklab("NO");
00977       if (vgconf == "valgrind" || vgconf.Contains("master")) {
00978          if (!IsLite()) {
00979             // Check if we have to add a var
00980             if (mst == "" || mst.BeginsWith("valgrind_opts:")) {
00981                mst.ReplaceAll("valgrind_opts:","");
00982                var.Form("%s --log-file=<logfilemst>.valgrind.log %s", cmd.Data(), mst.Data());
00983                TProof::AddEnvVar("PROOF_MASTER_WRAPPERCMD", var);
00984                mstlab = "YES";
00985             } else if (mst != "") {
00986                mstlab = "YES";
00987             }
00988          } else {
00989             if (vgconf.Contains("master")) {
00990                Warning("ParseConfigField",
00991                        "master valgrinding does not make sense for PROOF-Lite: ignoring");
00992                vgconf.ReplaceAll("master", "");
00993                if (!vgconf.Contains("workers")) return;
00994             }
00995             if (vgconf == "valgrind" || vgconf == "valgrind=") vgconf = "valgrind=workers";
00996          }
00997       }
00998       if (vgconf.Contains("=workers") || vgconf.Contains("+workers")) {
00999          // Check if we have to add a var
01000          if (wrk == "" || wrk.BeginsWith("valgrind_opts:")) {
01001             wrk.ReplaceAll("valgrind_opts:","");
01002             var.Form("%s --log-file=<logfilewrk>.valgrind.log %s%s", cmd.Data(), wrk.Data(), cq);
01003             TProof::AddEnvVar("PROOF_SLAVE_WRAPPERCMD", var);
01004             TString nwrks("2");
01005             Int_t inw = vgconf.Index('#');
01006             if (inw != kNPOS) {
01007                nwrks = vgconf(inw+1, vgconf.Length());
01008                if (!nwrks.IsDigit()) nwrks = "2";
01009             }
01010             // Set the relevant variables
01011             if (!IsLite()) {
01012                TProof::AddEnvVar("PROOF_NWORKERS", nwrks);
01013             } else {
01014                gEnv->SetValue("ProofLite.Workers", nwrks.Atoi());
01015             }
01016             wrklab = nwrks;
01017             // Register the additional worker log in the session file
01018             // (for the master is done automatically)
01019             TProof::AddEnvVar("PROOF_ADDITIONALLOG", "valgrind.log*");
01020          } else if (wrk != "") {
01021             wrklab = "ALL";
01022          }
01023       }
01024       // Increase the relevant timeouts
01025       if (!IsLite()) {
01026          TProof::AddEnvVar("PROOF_INTWAIT", "5000");
01027          gEnv->SetValue("Proof.SocketActivityTimeout", 6000);
01028       } else {
01029          gEnv->SetValue("ProofLite.StartupTimeOut", 5000);
01030       }
01031       // Warn for slowness
01032       Printf(" ");
01033       if (!IsLite()) {
01034          Printf(" ---> Starting a debug run with valgrind (master:%s, workers:%s)", mstlab.Data(), wrklab.Data());
01035       } else {
01036          Printf(" ---> Starting a debug run with valgrind (workers:%s)", wrklab.Data());
01037       }
01038       Printf(" ---> Please be patient: startup may be VERY slow ...");
01039       Printf(" ---> Logs will be available as special tags in the log window (from the progress dialog or TProof::LogViewer()) ");
01040       Printf(" ---> (Reminder: this debug run makes sense only if you are running a debug version of ROOT)");
01041       Printf(" ");
01042 
01043    } else if (sconf.BeginsWith("workers=")) {
01044 
01045       // Request for a given number of workers (within the max) or worker
01046       // startup combination:
01047       //      workers=5         start max 5 workers (or less, if less are assigned)
01048       //      workers=2x        start max 2 workers (or less, if less are assigned)
01049       sconf.ReplaceAll("workers=","");
01050       TProof::AddEnvVar("PROOF_NWORKERS", sconf);
01051    }
01052 }
01053 
01054 //______________________________________________________________________________
01055 Int_t TProof::AssertPath(const char *inpath, Bool_t writable)
01056 {
01057    // Make sure that 'path' exists; if 'writable' is kTRUE, make also sure
01058    // that the path is writable
01059 
01060    if (!inpath || strlen(inpath) <= 0) {
01061       Error("AssertPath", "undefined input path");
01062       return -1;
01063    }
01064 
01065    TString path(inpath);
01066    gSystem->ExpandPathName(path);
01067 
01068    if (gSystem->AccessPathName(path, kFileExists)) {
01069       if (gSystem->mkdir(path, kTRUE) != 0) {
01070          Error("AssertPath", "could not create path %s", path.Data());
01071          return -1;
01072       }
01073    }
01074    // It must be writable
01075    if (gSystem->AccessPathName(path, kWritePermission) && writable) {
01076       if (gSystem->Chmod(path, 0666) != 0) {
01077          Error("AssertPath", "could not make path %s writable", path.Data());
01078          return -1;
01079       }
01080    }
01081 
01082    // Done
01083    return 0;
01084 }
01085 
01086 //______________________________________________________________________________
01087 void TProof::SetManager(TProofMgr *mgr)
01088 {
01089    // Set manager and schedule its destruction after this for clean
01090    // operations.
01091 
01092    fManager = mgr;
01093 
01094    if (mgr) {
01095       R__LOCKGUARD2(gROOTMutex);
01096       gROOT->GetListOfSockets()->Remove(mgr);
01097       gROOT->GetListOfSockets()->Add(mgr);
01098    }
01099 }
01100 
01101 //______________________________________________________________________________
01102 Int_t TProof::AddWorkers(TList *workerList)
01103 {
01104    // Works on the master node only.
01105    // It starts workers on the machines in workerList and sets the paths,
01106    // packages and macros as on the master.
01107    // It is a subbstitute for StartSlaves(...)
01108    // The code is mostly the master part of StartSlaves,
01109    // with the parallel startup removed.
01110 
01111    if (!IsMaster()) {
01112       Error("AddWorkers", "AddWorkers can only be called on the master!");
01113       return -1;
01114    }
01115 
01116    if (!workerList || !(workerList->GetSize())) {
01117       Error("AddWorkers", "empty list of workers!");
01118       return -2;
01119    }
01120 
01121    // Code taken from master part of StartSlaves with the parllel part removed
01122 
01123    fImage = gProofServ->GetImage();
01124    if (fImage.IsNull())
01125       fImage.Form("%s:%s", TUrl(gSystem->HostName()).GetHostFQDN(), gProofServ->GetWorkDir());
01126 
01127    // Get all workers
01128    UInt_t nSlaves = workerList->GetSize();
01129    UInt_t nSlavesDone = 0;
01130    Int_t ord = 0;
01131 
01132    // Loop over all workers and start them
01133 
01134    // a list of TSlave objects for workers that are being added
01135    TList *addedWorkers = new TList();
01136    if (!addedWorkers) {
01137       // This is needed to silence Coverity ...
01138       Error("AddWorkers", "cannot create new list for the workers to be added");
01139       return -2;
01140    }
01141    addedWorkers->SetOwner(kFALSE);
01142    TListIter next(workerList);
01143    TObject *to;
01144    TProofNodeInfo *worker;
01145    while ((to = next())) {
01146       // Get the next worker from the list
01147       worker = (TProofNodeInfo *)to;
01148 
01149       // Read back worker node info
01150       const Char_t *image = worker->GetImage().Data();
01151       const Char_t *workdir = worker->GetWorkDir().Data();
01152       Int_t perfidx = worker->GetPerfIndex();
01153       Int_t sport = worker->GetPort();
01154       if (sport == -1)
01155          sport = fUrl.GetPort();
01156 
01157       // Create worker server
01158       TString fullord;
01159       if (worker->GetOrdinal().Length() > 0) {
01160          fullord.Form("%s.%s", gProofServ->GetOrdinal(), worker->GetOrdinal().Data());
01161       } else {
01162          fullord.Form("%s.%d", gProofServ->GetOrdinal(), ord);
01163       }
01164 
01165       // Create worker server
01166       TString wn(worker->GetNodeName());
01167       if (wn == "localhost" || wn.BeginsWith("localhost.")) wn = gSystem->HostName();
01168       TUrl u(TString::Format("%s:%d", wn.Data(), sport));
01169       // Add group info in the password firdl, if any
01170       if (strlen(gProofServ->GetGroup()) > 0) {
01171          // Set also the user, otherwise the password is not exported
01172          if (strlen(u.GetUser()) <= 0)
01173             u.SetUser(gProofServ->GetUser());
01174          u.SetPasswd(gProofServ->GetGroup());
01175       }
01176       TSlave *slave = CreateSlave(u.GetUrl(), fullord, perfidx,
01177                                   image, workdir);
01178 
01179       // Add to global list (we will add to the monitor list after
01180       // finalizing the server startup)
01181       Bool_t slaveOk = kTRUE;
01182       if (slave->IsValid()) {
01183          fSlaves->Add(slave);
01184          addedWorkers->Add(slave);
01185       } else {
01186          slaveOk = kFALSE;
01187          fBadSlaves->Add(slave);
01188       }
01189 
01190       PDB(kGlobal,3)
01191          Info("StartSlaves", "worker on host %s created"
01192               " and added to list", worker->GetNodeName().Data());
01193 
01194       // Notify opening of connection
01195       nSlavesDone++;
01196       TMessage m(kPROOF_SERVERSTARTED);
01197       m << TString("Opening connections to workers") << nSlaves
01198         << nSlavesDone << slaveOk;
01199       gProofServ->GetSocket()->Send(m);
01200 
01201       ord++;
01202    } //end of the worker loop
01203 
01204    // Cleanup
01205    SafeDelete(workerList);
01206 
01207    nSlavesDone = 0;
01208 
01209    // Here we finalize the server startup: in this way the bulk
01210    // of remote operations are almost parallelized
01211    TIter nxsl(addedWorkers);
01212    TSlave *sl = 0;
01213    while ((sl = (TSlave *) nxsl())) {
01214 
01215       // Finalize setup of the server
01216       if (sl->IsValid())
01217           sl->SetupServ(TSlave::kSlave, 0);
01218 
01219       // Monitor good slaves
01220       Bool_t slaveOk = kTRUE;
01221       if (sl->IsValid()) {
01222          fAllMonitor->Add(sl->GetSocket());
01223       } else {
01224          slaveOk = kFALSE;
01225          fBadSlaves->Add(sl);
01226       }
01227 
01228       // Notify end of startup operations
01229       nSlavesDone++;
01230       TMessage m(kPROOF_SERVERSTARTED);
01231       m << TString("Setting up worker servers") << nSlaves
01232         << nSlavesDone << slaveOk;
01233       gProofServ->GetSocket()->Send(m);
01234    }
01235 
01236    // Now set new state on the added workers (on all workers for simplicity)
01237    // use fEnabledPackages, fLoadedMacros,
01238    // gSystem->GetDynamicPath() and gSystem->GetIncludePath()
01239    // no need to load packages that are only loaded and not enabled (dyn mode)
01240 
01241    SetParallel(99999, 0);
01242 
01243    TList *tmpEnabledPackages = gProofServ->GetEnabledPackages();
01244 
01245    if (tmpEnabledPackages && tmpEnabledPackages->GetSize() > 0) {
01246       TIter nxp(tmpEnabledPackages);
01247       TObjString *os = 0;
01248       while ((os = (TObjString *) nxp())) {
01249          // Upload and Enable methods are intelligent and avoid
01250          // re-uploading or re-enabling of a package to a node that has it.
01251          UploadPackage(os->GetName());
01252          EnablePackage(os->GetName(), (TList *)0, kTRUE);
01253       }
01254    }
01255 
01256 
01257    if (fLoadedMacros) {
01258       TIter nxp(fLoadedMacros);
01259       TObjString *os = 0;
01260       while ((os = (TObjString *) nxp())) {
01261          Printf("Loading a macro : %s", os->GetName());
01262          Load(os->GetName(), kTRUE, kTRUE, addedWorkers);
01263       }
01264    }
01265 
01266    TString dyn = gSystem->GetDynamicPath();
01267    dyn.ReplaceAll(":", " ");
01268    dyn.ReplaceAll("\"", " ");
01269    AddDynamicPath(dyn, kFALSE, addedWorkers);
01270    TString inc = gSystem->GetIncludePath();
01271    inc.ReplaceAll("-I", " ");
01272    inc.ReplaceAll("\"", " ");
01273    AddIncludePath(inc, kFALSE, addedWorkers);
01274 
01275    // Cleanup
01276    delete addedWorkers;
01277 
01278    // Inform the client that the number of workers is changed
01279    if (fDynamicStartup && gProofServ)
01280       gProofServ->SendParallel(kTRUE);
01281 
01282    return 0;
01283 }
01284 
01285 //______________________________________________________________________________
01286 Int_t TProof::RemoveWorkers(TList *workerList)
01287 {
01288    // Used for shuting down the workres after a query is finished.
01289    // Sends each of the workers from the workerList, a kPROOF_STOP message.
01290    // If the workerList == 0, shutdown all the workers.
01291 
01292    if (!IsMaster()) {
01293       Error("RemoveWorkers", "RemoveWorkers can only be called on the master!");
01294       return -1;
01295    }
01296 
01297    fFileMap.clear(); // This could be avoided if CopyFromCache was used in SendFile
01298 
01299    if (!workerList) {
01300       // shutdown all the workers
01301       TIter nxsl(fSlaves);
01302       TSlave *sl = 0;
01303       while ((sl = (TSlave *) nxsl())) {
01304          // Shut down the worker assumig that it is not processing
01305          TerminateWorker(sl);
01306       }
01307 
01308    } else {
01309       if (!(workerList->GetSize())) {
01310          Error("RemoveWorkers", "The list of workers should not be empty!");
01311          return -2;
01312       }
01313 
01314       // Loop over all the workers and stop them
01315       TListIter next(workerList);
01316       TObject *to;
01317       TProofNodeInfo *worker;
01318       while ((to = next())) {
01319          TSlave *sl = 0;
01320          if (!strcmp(to->ClassName(), "TProofNodeInfo")) {
01321             // Get the next worker from the list
01322             worker = (TProofNodeInfo *)to;
01323             TIter nxsl(fSlaves);
01324             while ((sl = (TSlave *) nxsl())) {
01325                // Shut down the worker assumig that it is not processing
01326                if (sl->GetName() == worker->GetNodeName())
01327                   break;
01328             }
01329          } else if (to->InheritsFrom(TSlave::Class())) {
01330             sl = (TSlave *) to;
01331          } else {
01332             Warning("RemoveWorkers","unknown object type: %s - it should be"
01333                   " TProofNodeInfo or inheriting from TSlave", to->ClassName());
01334          }
01335          // Shut down the worker assumig that it is not processing
01336          if (sl) {
01337             if (gDebug > 0)
01338                Info("RemoveWorkers","terminating worker %s", sl->GetOrdinal());
01339             TerminateWorker(sl);
01340          }
01341       }
01342    }
01343 
01344    // Update also the master counter
01345    if (gProofServ && fSlaves->GetSize() <= 0) gProofServ->ReleaseWorker("master");
01346 
01347    return 0;
01348 }
01349 
01350 //______________________________________________________________________________
01351 Bool_t TProof::StartSlaves(Bool_t attach)
01352 {
01353    // Start up PROOF slaves.
01354 
01355    // If this is a master server, find the config file and start slave
01356    // servers as specified in the config file
01357    if (TestBit(TProof::kIsMaster)) {
01358 
01359       Int_t pc = 0;
01360       TList *workerList = new TList;
01361       // Get list of workers
01362       if (gProofServ->GetWorkers(workerList, pc) == TProofServ::kQueryStop) {
01363          TString emsg("no resource currently available for this session: please retry later");
01364          if (gDebug > 0) Info("StartSlaves", "%s", emsg.Data());
01365          gProofServ->SendAsynMessage(emsg.Data());
01366          return kFALSE;
01367       }
01368 
01369       // Setup the workers
01370       if (AddWorkers(workerList) < 0)
01371          return kFALSE;
01372 
01373    } else {
01374 
01375       // create master server
01376       Printf("Starting master: opening connection ...");
01377       TSlave *slave = CreateSubmaster(fUrl.GetUrl(), "0", "master", 0);
01378 
01379       if (slave->IsValid()) {
01380 
01381          // Notify
01382          fprintf(stderr,"Starting master:"
01383                         " connection open: setting up server ...             \r");
01384          StartupMessage("Connection to master opened", kTRUE, 1, 1);
01385 
01386          if (!attach) {
01387 
01388             // Set worker interrupt handler
01389             slave->SetInterruptHandler(kTRUE);
01390 
01391             // Finalize setup of the server
01392             slave->SetupServ(TSlave::kMaster, fConfFile);
01393 
01394             if (slave->IsValid()) {
01395 
01396                // Notify
01397                Printf("Starting master: OK                                     ");
01398                StartupMessage("Master started", kTRUE, 1, 1);
01399 
01400                // check protocol compatibility
01401                // protocol 1 is not supported anymore
01402                if (fProtocol == 1) {
01403                   Error("StartSlaves",
01404                         "client and remote protocols not compatible (%d and %d)",
01405                         kPROOF_Protocol, fProtocol);
01406                   slave->Close("S");
01407                   delete slave;
01408                   return kFALSE;
01409                }
01410 
01411                fSlaves->Add(slave);
01412                fAllMonitor->Add(slave->GetSocket());
01413 
01414                // Unset worker interrupt handler
01415                slave->SetInterruptHandler(kFALSE);
01416 
01417                // Set interrupt PROOF handler from now on
01418                fIntHandler = new TProofInterruptHandler(this);
01419 
01420                // Give-up after 5 minutes
01421                Int_t rc = Collect(slave, 300);
01422                Int_t slStatus = slave->GetStatus();
01423                if (slStatus == -99 || slStatus == -98 || rc == 0) {
01424                   fSlaves->Remove(slave);
01425                   fAllMonitor->Remove(slave->GetSocket());
01426                   if (slStatus == -99)
01427                      Error("StartSlaves", "no resources available or problems setting up workers (check logs)");
01428                   else if (slStatus == -98)
01429                      Error("StartSlaves", "could not setup output redirection on master");
01430                   else
01431                      Error("StartSlaves", "setting up master");
01432                   slave->Close("S");
01433                   delete slave;
01434                   return 0;
01435                }
01436 
01437                if (!slave->IsValid()) {
01438                   fSlaves->Remove(slave);
01439                   fAllMonitor->Remove(slave->GetSocket());
01440                   slave->Close("S");
01441                   delete slave;
01442                   Error("StartSlaves",
01443                         "failed to setup connection with PROOF master server");
01444                   return kFALSE;
01445                }
01446 
01447                if (!gROOT->IsBatch() && TestBit(kUseProgressDialog)) {
01448                   if ((fProgressDialog =
01449                      gROOT->GetPluginManager()->FindHandler("TProofProgressDialog")))
01450                      if (fProgressDialog->LoadPlugin() == -1)
01451                         fProgressDialog = 0;
01452                }
01453             } else {
01454                // Notify
01455                Printf("Starting master: failure");
01456             }
01457          } else {
01458 
01459             // Notify
01460             Printf("Starting master: OK                                     ");
01461             StartupMessage("Master attached", kTRUE, 1, 1);
01462 
01463             if (!gROOT->IsBatch() && TestBit(kUseProgressDialog)) {
01464                if ((fProgressDialog =
01465                   gROOT->GetPluginManager()->FindHandler("TProofProgressDialog")))
01466                   if (fProgressDialog->LoadPlugin() == -1)
01467                      fProgressDialog = 0;
01468             }
01469 
01470             fSlaves->Add(slave);
01471             fIntHandler = new TProofInterruptHandler(this);
01472          }
01473 
01474       } else {
01475          delete slave;
01476          // Notify only if verbosity is on: most likely the failure has already been notified
01477          if (gDebug > 0)
01478             Error("StartSlaves", "failed to create (or connect to) the PROOF master server");
01479          return kFALSE;
01480       }
01481    }
01482 
01483    return kTRUE;
01484 }
01485 
01486 //______________________________________________________________________________
01487 void TProof::Close(Option_t *opt)
01488 {
01489    // Close all open slave servers.
01490    // Client can decide to shutdown the remote session by passing option is 'S'
01491    // or 's'. Default for clients is detach, if supported. Masters always
01492    // shutdown the remote counterpart.
01493 
01494    {  R__LOCKGUARD2(fCloseMutex);
01495 
01496       fValid = kFALSE;
01497       if (fSlaves) {
01498          if (fIntHandler)
01499             fIntHandler->Remove();
01500 
01501          TIter nxs(fSlaves);
01502          TSlave *sl = 0;
01503          while ((sl = (TSlave *)nxs()))
01504             sl->Close(opt);
01505 
01506          fActiveSlaves->Clear("nodelete");
01507          fUniqueSlaves->Clear("nodelete");
01508          fAllUniqueSlaves->Clear("nodelete");
01509          fNonUniqueMasters->Clear("nodelete");
01510          fBadSlaves->Clear("nodelete");
01511          fSlaves->Delete();
01512       }
01513    }
01514 
01515    {
01516       R__LOCKGUARD2(gROOTMutex);
01517       gROOT->GetListOfSockets()->Remove(this);
01518 
01519       if (IsProofd()) {
01520 
01521          gROOT->GetListOfProofs()->Remove(this);
01522          if (gProof && gProof == this) {
01523             // Set previous proofd-related as default
01524             TIter pvp(gROOT->GetListOfProofs(), kIterBackward);
01525             while ((gProof = (TProof *)pvp())) {
01526                if (gProof->IsProofd())
01527                   break;
01528             }
01529          }
01530       }
01531    }
01532 }
01533 
01534 //______________________________________________________________________________
01535 TSlave *TProof::CreateSlave(const char *url, const char *ord,
01536                             Int_t perf, const char *image, const char *workdir)
01537 {
01538    // Create a new TSlave of type TSlave::kSlave.
01539    // Note: creation of TSlave is private with TProof as a friend.
01540    // Derived classes must use this function to create slaves.
01541 
01542    TSlave* sl = TSlave::Create(url, ord, perf, image,
01543                                this, TSlave::kSlave, workdir, 0);
01544 
01545    if (sl->IsValid()) {
01546       sl->SetInputHandler(new TProofInputHandler(this, sl->GetSocket()));
01547       // must set fParallel to 1 for slaves since they do not
01548       // report their fParallel with a LOG_DONE message
01549       sl->fParallel = 1;
01550    }
01551 
01552    return sl;
01553 }
01554 
01555 
01556 //______________________________________________________________________________
01557 TSlave *TProof::CreateSubmaster(const char *url, const char *ord,
01558                                 const char *image, const char *msd)
01559 {
01560    // Create a new TSlave of type TSlave::kMaster.
01561    // Note: creation of TSlave is private with TProof as a friend.
01562    // Derived classes must use this function to create slaves.
01563 
01564    TSlave *sl = TSlave::Create(url, ord, 100, image, this,
01565                                TSlave::kMaster, 0, msd);
01566 
01567    if (sl->IsValid()) {
01568       sl->SetInputHandler(new TProofInputHandler(this, sl->GetSocket()));
01569    }
01570 
01571    return sl;
01572 }
01573 
01574 //______________________________________________________________________________
01575 TSlave *TProof::FindSlave(TSocket *s) const
01576 {
01577    // Find slave that has TSocket s. Returns 0 in case slave is not found.
01578 
01579    TSlave *sl;
01580    TIter   next(fSlaves);
01581 
01582    while ((sl = (TSlave *)next())) {
01583       if (sl->IsValid() && sl->GetSocket() == s)
01584          return sl;
01585    }
01586    return 0;
01587 }
01588 
01589 //______________________________________________________________________________
01590 void TProof::FindUniqueSlaves()
01591 {
01592    // Add to the fUniqueSlave list the active slaves that have a unique
01593    // (user) file system image. This information is used to transfer files
01594    // only once to nodes that share a file system (an image). Submasters
01595    // which are not in fUniqueSlaves are put in the fNonUniqueMasters
01596    // list. That list is used to trigger the transferring of files to
01597    // the submaster's unique slaves without the need to transfer the file
01598    // to the submaster.
01599 
01600    fUniqueSlaves->Clear();
01601    fUniqueMonitor->RemoveAll();
01602    fAllUniqueSlaves->Clear();
01603    fAllUniqueMonitor->RemoveAll();
01604    fNonUniqueMasters->Clear();
01605 
01606    TIter next(fActiveSlaves);
01607 
01608    while (TSlave *sl = dynamic_cast<TSlave*>(next())) {
01609       if (fImage == sl->fImage) {
01610          if (sl->GetSlaveType() == TSlave::kMaster) {
01611             fNonUniqueMasters->Add(sl);
01612             fAllUniqueSlaves->Add(sl);
01613             fAllUniqueMonitor->Add(sl->GetSocket());
01614          }
01615          continue;
01616       }
01617 
01618       TIter next2(fUniqueSlaves);
01619       TSlave *replace_slave = 0;
01620       Bool_t add = kTRUE;
01621       while (TSlave *sl2 = dynamic_cast<TSlave*>(next2())) {
01622          if (sl->fImage == sl2->fImage) {
01623             add = kFALSE;
01624             if (sl->GetSlaveType() == TSlave::kMaster) {
01625                if (sl2->GetSlaveType() == TSlave::kSlave) {
01626                   // give preference to master
01627                   replace_slave = sl2;
01628                   add = kTRUE;
01629                } else if (sl2->GetSlaveType() == TSlave::kMaster) {
01630                   fNonUniqueMasters->Add(sl);
01631                   fAllUniqueSlaves->Add(sl);
01632                   fAllUniqueMonitor->Add(sl->GetSocket());
01633                } else {
01634                   Error("FindUniqueSlaves", "TSlave is neither Master nor Slave");
01635                   R__ASSERT(0);
01636                }
01637             }
01638             break;
01639          }
01640       }
01641 
01642       if (add) {
01643          fUniqueSlaves->Add(sl);
01644          fAllUniqueSlaves->Add(sl);
01645          fUniqueMonitor->Add(sl->GetSocket());
01646          fAllUniqueMonitor->Add(sl->GetSocket());
01647          if (replace_slave) {
01648             fUniqueSlaves->Remove(replace_slave);
01649             fAllUniqueSlaves->Remove(replace_slave);
01650             fUniqueMonitor->Remove(replace_slave->GetSocket());
01651             fAllUniqueMonitor->Remove(replace_slave->GetSocket());
01652          }
01653       }
01654    }
01655 
01656    // will be actiavted in Collect()
01657    fUniqueMonitor->DeActivateAll();
01658    fAllUniqueMonitor->DeActivateAll();
01659 }
01660 
01661 //______________________________________________________________________________
01662 Int_t TProof::GetNumberOfSlaves() const
01663 {
01664    // Return number of slaves as described in the config file.
01665 
01666    return fSlaves->GetSize();
01667 }
01668 
01669 //______________________________________________________________________________
01670 Int_t TProof::GetNumberOfActiveSlaves() const
01671 {
01672    // Return number of active slaves, i.e. slaves that are valid and in
01673    // the current computing group.
01674 
01675    return fActiveSlaves->GetSize();
01676 }
01677 
01678 //______________________________________________________________________________
01679 Int_t TProof::GetNumberOfInactiveSlaves() const
01680 {
01681    // Return number of inactive slaves, i.e. slaves that are valid but not in
01682    // the current computing group.
01683 
01684    return fInactiveSlaves->GetSize();
01685 }
01686 
01687 //______________________________________________________________________________
01688 Int_t TProof::GetNumberOfUniqueSlaves() const
01689 {
01690    // Return number of unique slaves, i.e. active slaves that have each a
01691    // unique different user files system.
01692 
01693    return fUniqueSlaves->GetSize();
01694 }
01695 
01696 //______________________________________________________________________________
01697 Int_t TProof::GetNumberOfBadSlaves() const
01698 {
01699    // Return number of bad slaves. This are slaves that we in the config
01700    // file, but refused to startup or that died during the PROOF session.
01701 
01702    return fBadSlaves->GetSize();
01703 }
01704 
01705 //______________________________________________________________________________
01706 void TProof::AskStatistics()
01707 {
01708    // Ask the for the statistics of the slaves.
01709 
01710    if (!IsValid()) return;
01711 
01712    Broadcast(kPROOF_GETSTATS, kActive);
01713    Collect(kActive, fCollectTimeout);
01714 }
01715 
01716 //______________________________________________________________________________
01717 void TProof::GetStatistics(Bool_t verbose)
01718 {
01719    // Get statistics about CPU time, real time and bytes read.
01720    // If verbose, print the resuls (always available via GetCpuTime(), GetRealTime()
01721    // and GetBytesRead()
01722 
01723    if (fProtocol > 27) {
01724       // This returns the correct result
01725       AskStatistics();
01726    } else {
01727       // AskStatistics is buggy: parse the output of Print()
01728       RedirectHandle_t rh;
01729       gSystem->RedirectOutput(fLogFileName, "a", &rh);
01730       Print();
01731       gSystem->RedirectOutput(0, 0, &rh);
01732       TMacro *mp = GetLastLog();
01733       if (mp) {
01734          // Look for global directories
01735          TIter nxl(mp->GetListOfLines());
01736          TObjString *os = 0;
01737          while ((os = (TObjString *) nxl())) {
01738             TString s(os->GetName());
01739             if (s.Contains("Total MB's processed:")) {
01740                s.ReplaceAll("Total MB's processed:", "");
01741                if (s.IsFloat()) fBytesRead = (Long64_t) s.Atof() * (1024*1024);
01742             } else if (s.Contains("Total real time used (s):")) {
01743                s.ReplaceAll("Total real time used (s):", "");
01744                if (s.IsFloat()) fRealTime = s.Atof();
01745             } else if (s.Contains("Total CPU time used (s):")) {
01746                s.ReplaceAll("Total CPU time used (s):", "");
01747                if (s.IsFloat()) fCpuTime = s.Atof();
01748             }
01749          }
01750          delete mp;
01751       }
01752    }
01753 
01754    if (verbose) {
01755       Printf(" Real/CPU time (s): %.3f / %.3f; workers: %d; processed: %.2f MBs",
01756              GetRealTime(), GetCpuTime(), GetParallel(), float(GetBytesRead())/(1024*1024));
01757    }
01758 }
01759 
01760 //______________________________________________________________________________
01761 void TProof::AskParallel()
01762 {
01763    // Ask the for the number of parallel slaves.
01764 
01765    if (!IsValid()) return;
01766 
01767    Broadcast(kPROOF_GETPARALLEL, kActive);
01768    Collect(kActive, fCollectTimeout);
01769 }
01770 
01771 //______________________________________________________________________________
01772 TList *TProof::GetListOfQueries(Option_t *opt)
01773 {
01774    // Ask the master for the list of queries.
01775 
01776    if (!IsValid() || TestBit(TProof::kIsMaster)) return (TList *)0;
01777 
01778    Bool_t all = ((strchr(opt,'A') || strchr(opt,'a'))) ? kTRUE : kFALSE;
01779    TMessage m(kPROOF_QUERYLIST);
01780    m << all;
01781    Broadcast(m, kActive);
01782    Collect(kActive, fCollectTimeout);
01783 
01784    // This should have been filled by now
01785    return fQueries;
01786 }
01787 
01788 //______________________________________________________________________________
01789 Int_t TProof::GetNumberOfQueries()
01790 {
01791    // Number of queries processed by this session
01792 
01793    if (fQueries)
01794       return fQueries->GetSize() - fOtherQueries;
01795    return 0;
01796 }
01797 
01798 //______________________________________________________________________________
01799 void TProof::SetMaxDrawQueries(Int_t max)
01800 {
01801    // Set max number of draw queries whose results are saved
01802 
01803    if (max > 0) {
01804       if (fPlayer)
01805          fPlayer->SetMaxDrawQueries(max);
01806       fMaxDrawQueries = max;
01807    }
01808 }
01809 
01810 //______________________________________________________________________________
01811 void TProof::GetMaxQueries()
01812 {
01813    // Get max number of queries whose full results are kept in the
01814    // remote sandbox
01815 
01816    TMessage m(kPROOF_MAXQUERIES);
01817    m << kFALSE;
01818    Broadcast(m, kActive);
01819    Collect(kActive, fCollectTimeout);
01820 }
01821 
01822 //______________________________________________________________________________
01823 TList *TProof::GetQueryResults()
01824 {
01825    // Return pointer to the list of query results in the player
01826 
01827    return (fPlayer ? fPlayer->GetListOfResults() : (TList *)0);
01828 }
01829 
01830 //______________________________________________________________________________
01831 TQueryResult *TProof::GetQueryResult(const char *ref)
01832 {
01833    // Return pointer to the full TQueryResult instance owned by the player
01834    // and referenced by 'ref'. If ref = 0 or "", return the last query result.
01835 
01836    return (fPlayer ? fPlayer->GetQueryResult(ref) : (TQueryResult *)0);
01837 }
01838 
01839 //______________________________________________________________________________
01840 void TProof::ShowQueries(Option_t *opt)
01841 {
01842    // Ask the master for the list of queries.
01843    // Options:
01844    //           "A"     show information about all the queries known to the
01845    //                   server, i.e. even those processed by other sessions
01846    //           "L"     show only information about queries locally available
01847    //                   i.e. already retrieved. If "L" is specified, "A" is
01848    //                   ignored.
01849    //           "F"     show all details available about queries
01850    //           "H"     print help menu
01851    // Default ""
01852 
01853    Bool_t help = ((strchr(opt,'H') || strchr(opt,'h'))) ? kTRUE : kFALSE;
01854    if (help) {
01855 
01856       // Help
01857 
01858       Printf("+++");
01859       Printf("+++ Options: \"A\" show all queries known to server");
01860       Printf("+++          \"L\" show retrieved queries");
01861       Printf("+++          \"F\" full listing of query info");
01862       Printf("+++          \"H\" print this menu");
01863       Printf("+++");
01864       Printf("+++ (case insensitive)");
01865       Printf("+++");
01866       Printf("+++ Use Retrieve(<#>) to retrieve the full"
01867              " query results from the master");
01868       Printf("+++     e.g. Retrieve(8)");
01869 
01870       Printf("+++");
01871 
01872       return;
01873    }
01874 
01875    if (!IsValid()) return;
01876 
01877    Bool_t local = ((strchr(opt,'L') || strchr(opt,'l'))) ? kTRUE : kFALSE;
01878 
01879    TObject *pq = 0;
01880    if (!local) {
01881       GetListOfQueries(opt);
01882 
01883       if (!fQueries) return;
01884 
01885       TIter nxq(fQueries);
01886 
01887       // Queries processed by other sessions
01888       if (fOtherQueries > 0) {
01889          Printf("+++");
01890          Printf("+++ Queries processed during other sessions: %d", fOtherQueries);
01891          Int_t nq = 0;
01892          while (nq++ < fOtherQueries && (pq = nxq()))
01893             pq->Print(opt);
01894       }
01895 
01896       // Queries processed by this session
01897       Printf("+++");
01898       Printf("+++ Queries processed during this session: selector: %d, draw: %d",
01899               GetNumberOfQueries(), fDrawQueries);
01900       while ((pq = nxq()))
01901          pq->Print(opt);
01902 
01903    } else {
01904 
01905       // Queries processed by this session
01906       Printf("+++");
01907       Printf("+++ Queries processed during this session: selector: %d, draw: %d",
01908               GetNumberOfQueries(), fDrawQueries);
01909 
01910       // Queries available locally
01911       TList *listlocal = fPlayer ? fPlayer->GetListOfResults() : (TList *)0;
01912       if (listlocal) {
01913          Printf("+++");
01914          Printf("+++ Queries available locally: %d", listlocal->GetSize());
01915          TIter nxlq(listlocal);
01916          while ((pq = nxlq()))
01917             pq->Print(opt);
01918       }
01919    }
01920    Printf("+++");
01921 }
01922 
01923 //______________________________________________________________________________
01924 Bool_t TProof::IsDataReady(Long64_t &totalbytes, Long64_t &bytesready)
01925 {
01926    // See if the data is ready to be analyzed.
01927 
01928    if (!IsValid()) return kFALSE;
01929 
01930    TList submasters;
01931    TIter nextSlave(GetListOfActiveSlaves());
01932    while (TSlave *sl = dynamic_cast<TSlave*>(nextSlave())) {
01933       if (sl->GetSlaveType() == TSlave::kMaster) {
01934          submasters.Add(sl);
01935       }
01936    }
01937 
01938    fDataReady = kTRUE; //see if any submasters set it to false
01939    fBytesReady = 0;
01940    fTotalBytes = 0;
01941    //loop over submasters and see if data is ready
01942    if (submasters.GetSize() > 0) {
01943       Broadcast(kPROOF_DATA_READY, &submasters);
01944       Collect(&submasters);
01945    }
01946 
01947    bytesready = fBytesReady;
01948    totalbytes = fTotalBytes;
01949 
01950    EmitVA("IsDataReady(Long64_t,Long64_t)", 2, totalbytes, bytesready);
01951 
01952    //PDB(kGlobal,2)
01953    Info("IsDataReady", "%lld / %lld (%s)",
01954         bytesready, totalbytes, fDataReady?"READY":"NOT READY");
01955 
01956    return fDataReady;
01957 }
01958 
01959 //______________________________________________________________________________
01960 void TProof::Interrupt(EUrgent type, ESlaves list)
01961 {
01962    // Send interrupt to master or slave servers.
01963 
01964    if (!IsValid()) return;
01965 
01966    TList *slaves = 0;
01967    if (list == kAll)       slaves = fSlaves;
01968    if (list == kActive)    slaves = fActiveSlaves;
01969    if (list == kUnique)    slaves = fUniqueSlaves;
01970    if (list == kAllUnique) slaves = fAllUniqueSlaves;
01971 
01972    if (slaves->GetSize() == 0) return;
01973 
01974    TSlave *sl;
01975    TIter   next(slaves);
01976 
01977    while ((sl = (TSlave *)next())) {
01978       if (sl->IsValid()) {
01979 
01980          // Ask slave to progate the interrupt request
01981          sl->Interrupt((Int_t)type);
01982       }
01983    }
01984 }
01985 
01986 //______________________________________________________________________________
01987 Int_t TProof::GetParallel() const
01988 {
01989    // Returns number of slaves active in parallel mode. Returns 0 in case
01990    // there are no active slaves. Returns -1 in case of error.
01991 
01992    if (!IsValid()) return -1;
01993 
01994    // iterate over active slaves and return total number of slaves
01995    TIter nextSlave(GetListOfActiveSlaves());
01996    Int_t nparallel = 0;
01997    while (TSlave* sl = dynamic_cast<TSlave*>(nextSlave()))
01998       if (sl->GetParallel() >= 0)
01999          nparallel += sl->GetParallel();
02000 
02001    return nparallel;
02002 }
02003 
02004 //______________________________________________________________________________
02005 TList *TProof::GetListOfSlaveInfos()
02006 {
02007    // Returns list of TSlaveInfo's. In case of error return 0.
02008 
02009    if (!IsValid()) return 0;
02010 
02011    if (fSlaveInfo == 0) {
02012       fSlaveInfo = new TSortedList(kSortDescending);
02013       fSlaveInfo->SetOwner();
02014    } else {
02015       fSlaveInfo->Delete();
02016    }
02017 
02018    TList masters;
02019    TIter next(GetListOfSlaves());
02020    TSlave *slave;
02021 
02022    while ((slave = (TSlave *) next()) != 0) {
02023       if (slave->GetSlaveType() == TSlave::kSlave) {
02024          const char *name = IsLite() ? gSystem->HostName() : slave->GetName();
02025          TSlaveInfo *slaveinfo = new TSlaveInfo(slave->GetOrdinal(),
02026                                                 name,
02027                                                 slave->GetPerfIdx());
02028          fSlaveInfo->Add(slaveinfo);
02029 
02030          TIter nextactive(GetListOfActiveSlaves());
02031          TSlave *activeslave;
02032          while ((activeslave = (TSlave *) nextactive())) {
02033             if (TString(slaveinfo->GetOrdinal()) == activeslave->GetOrdinal()) {
02034                slaveinfo->SetStatus(TSlaveInfo::kActive);
02035                break;
02036             }
02037          }
02038 
02039          TIter nextbad(GetListOfBadSlaves());
02040          TSlave *badslave;
02041          while ((badslave = (TSlave *) nextbad())) {
02042             if (TString(slaveinfo->GetOrdinal()) == badslave->GetOrdinal()) {
02043                slaveinfo->SetStatus(TSlaveInfo::kBad);
02044                break;
02045             }
02046          }
02047          // Get system info if supported
02048          if (slave->IsValid()) {
02049             if (slave->GetSocket()->Send(kPROOF_GETSLAVEINFO) == -1)
02050                MarkBad(slave, "could not send kPROOF_GETSLAVEINFO message");
02051             else
02052                masters.Add(slave);
02053          }
02054 
02055       } else if (slave->GetSlaveType() == TSlave::kMaster) {
02056          if (slave->IsValid()) {
02057             if (slave->GetSocket()->Send(kPROOF_GETSLAVEINFO) == -1)
02058                MarkBad(slave, "could not send kPROOF_GETSLAVEINFO message");
02059             else
02060                masters.Add(slave);
02061          }
02062       } else {
02063          Error("GetSlaveInfo", "TSlave is neither Master nor Slave");
02064          R__ASSERT(0);
02065       }
02066    }
02067    if (masters.GetSize() > 0) Collect(&masters);
02068 
02069    return fSlaveInfo;
02070 }
02071 
02072 //______________________________________________________________________________
02073 void TProof::Activate(TList *slaves)
02074 {
02075    // Activate slave server list.
02076 
02077    TMonitor *mon = fAllMonitor;
02078    mon->DeActivateAll();
02079 
02080    slaves = !slaves ? fActiveSlaves : slaves;
02081 
02082    TIter next(slaves);
02083    TSlave *sl;
02084    while ((sl = (TSlave*) next())) {
02085       if (sl->IsValid())
02086          mon->Activate(sl->GetSocket());
02087    }
02088 }
02089 
02090 //______________________________________________________________________________
02091 void TProof::SetMonitor(TMonitor *mon, Bool_t on)
02092 {
02093    // Activate (on == TRUE) or deactivate (on == FALSE) all sockets
02094    // monitored by 'mon'.
02095 
02096    TMonitor *m = (mon) ? mon : fCurrentMonitor;
02097    if (m) {
02098       if (on)
02099          m->ActivateAll();
02100       else
02101          m->DeActivateAll();
02102    }
02103 }
02104 
02105 //______________________________________________________________________________
02106 Int_t TProof::BroadcastGroupPriority(const char *grp, Int_t priority, TList *workers)
02107 {
02108    // Broadcast the group priority to all workers in the specified list. Returns
02109    // the number of workers the message was successfully sent to.
02110    // Returns -1 in case of error.
02111 
02112    if (!IsValid()) return -1;
02113 
02114    if (workers->GetSize() == 0) return 0;
02115 
02116    int   nsent = 0;
02117    TIter next(workers);
02118 
02119    TSlave *wrk;
02120    while ((wrk = (TSlave *)next())) {
02121       if (wrk->IsValid()) {
02122          if (wrk->SendGroupPriority(grp, priority) == -1)
02123             MarkBad(wrk, "could not send group priority");
02124          else
02125             nsent++;
02126       }
02127    }
02128 
02129    return nsent;
02130 }
02131 
02132 //______________________________________________________________________________
02133 Int_t TProof::BroadcastGroupPriority(const char *grp, Int_t priority, ESlaves list)
02134 {
02135    // Broadcast the group priority to all workers in the specified list. Returns
02136    // the number of workers the message was successfully sent to.
02137    // Returns -1 in case of error.
02138 
02139    TList *workers = 0;
02140    if (list == kAll)       workers = fSlaves;
02141    if (list == kActive)    workers = fActiveSlaves;
02142    if (list == kUnique)    workers = fUniqueSlaves;
02143    if (list == kAllUnique) workers = fAllUniqueSlaves;
02144 
02145    return BroadcastGroupPriority(grp, priority, workers);
02146 }
02147 
02148 //______________________________________________________________________________
02149 void TProof::ResetMergePrg()
02150 {
02151    // Reset the merge progress notificator
02152 
02153    fMergePrg.Reset(fActiveSlaves->GetSize());
02154 }
02155 
02156 //______________________________________________________________________________
02157 Int_t TProof::Broadcast(const TMessage &mess, TList *slaves)
02158 {
02159    // Broadcast a message to all slaves in the specified list. Returns
02160    // the number of slaves the message was successfully sent to.
02161    // Returns -1 in case of error.
02162 
02163    if (!IsValid()) return -1;
02164 
02165    if (!slaves || slaves->GetSize() == 0) return 0;
02166 
02167    int   nsent = 0;
02168    TIter next(slaves);
02169 
02170    TSlave *sl;
02171    while ((sl = (TSlave *)next())) {
02172       if (sl->IsValid()) {
02173          if (sl->GetSocket()->Send(mess) == -1)
02174             MarkBad(sl, "could not broadcast request");
02175          else
02176             nsent++;
02177       }
02178    }
02179 
02180    return nsent;
02181 }
02182 
02183 //______________________________________________________________________________
02184 Int_t TProof::Broadcast(const TMessage &mess, ESlaves list)
02185 {
02186    // Broadcast a message to all slaves in the specified list (either
02187    // all slaves or only the active slaves). Returns the number of slaves
02188    // the message was successfully sent to. Returns -1 in case of error.
02189 
02190    TList *slaves = 0;
02191    if (list == kAll)       slaves = fSlaves;
02192    if (list == kActive)    slaves = fActiveSlaves;
02193    if (list == kUnique)    slaves = fUniqueSlaves;
02194    if (list == kAllUnique) slaves = fAllUniqueSlaves;
02195 
02196    return Broadcast(mess, slaves);
02197 }
02198 
02199 //______________________________________________________________________________
02200 Int_t TProof::Broadcast(const char *str, Int_t kind, TList *slaves)
02201 {
02202    // Broadcast a character string buffer to all slaves in the specified
02203    // list. Use kind to set the TMessage what field. Returns the number of
02204    // slaves the message was sent to. Returns -1 in case of error.
02205 
02206    TMessage mess(kind);
02207    if (str) mess.WriteString(str);
02208    return Broadcast(mess, slaves);
02209 }
02210 
02211 //______________________________________________________________________________
02212 Int_t TProof::Broadcast(const char *str, Int_t kind, ESlaves list)
02213 {
02214    // Broadcast a character string buffer to all slaves in the specified
02215    // list (either all slaves or only the active slaves). Use kind to
02216    // set the TMessage what field. Returns the number of slaves the message
02217    // was sent to. Returns -1 in case of error.
02218 
02219    TMessage mess(kind);
02220    if (str) mess.WriteString(str);
02221    return Broadcast(mess, list);
02222 }
02223 
02224 //______________________________________________________________________________
02225 Int_t TProof::BroadcastObject(const TObject *obj, Int_t kind, TList *slaves)
02226 {
02227    // Broadcast an object to all slaves in the specified list. Use kind to
02228    // set the TMEssage what field. Returns the number of slaves the message
02229    // was sent to. Returns -1 in case of error.
02230 
02231    TMessage mess(kind);
02232    mess.WriteObject(obj);
02233    return Broadcast(mess, slaves);
02234 }
02235 
02236 //______________________________________________________________________________
02237 Int_t TProof::BroadcastObject(const TObject *obj, Int_t kind, ESlaves list)
02238 {
02239    // Broadcast an object to all slaves in the specified list. Use kind to
02240    // set the TMEssage what field. Returns the number of slaves the message
02241    // was sent to. Returns -1 in case of error.
02242 
02243    TMessage mess(kind);
02244    mess.WriteObject(obj);
02245    return Broadcast(mess, list);
02246 }
02247 
02248 //______________________________________________________________________________
02249 Int_t TProof::BroadcastRaw(const void *buffer, Int_t length, TList *slaves)
02250 {
02251    // Broadcast a raw buffer of specified length to all slaves in the
02252    // specified list. Returns the number of slaves the buffer was sent to.
02253    // Returns -1 in case of error.
02254 
02255    if (!IsValid()) return -1;
02256 
02257    if (slaves->GetSize() == 0) return 0;
02258 
02259    int   nsent = 0;
02260    TIter next(slaves);
02261 
02262    TSlave *sl;
02263    while ((sl = (TSlave *)next())) {
02264       if (sl->IsValid()) {
02265          if (sl->GetSocket()->SendRaw(buffer, length) == -1)
02266             MarkBad(sl, "could not send broadcast-raw request");
02267          else
02268             nsent++;
02269       }
02270    }
02271 
02272    return nsent;
02273 }
02274 
02275 //______________________________________________________________________________
02276 Int_t TProof::BroadcastRaw(const void *buffer, Int_t length, ESlaves list)
02277 {
02278    // Broadcast a raw buffer of specified length to all slaves in the
02279    // specified list. Returns the number of slaves the buffer was sent to.
02280    // Returns -1 in case of error.
02281 
02282    TList *slaves = 0;
02283    if (list == kAll)       slaves = fSlaves;
02284    if (list == kActive)    slaves = fActiveSlaves;
02285    if (list == kUnique)    slaves = fUniqueSlaves;
02286    if (list == kAllUnique) slaves = fAllUniqueSlaves;
02287 
02288    return BroadcastRaw(buffer, length, slaves);
02289 }
02290 
02291 //______________________________________________________________________________
02292 Int_t TProof::BroadcastFile(const char *file, Int_t opt, const char *rfile, TList *wrks)
02293 {
02294    // Broadcast file to all workers in the specified list. Returns the number of workers
02295    // the buffer was sent to.
02296    // Returns -1 in case of error.
02297 
02298    if (!IsValid()) return -1;
02299 
02300    if (wrks->GetSize() == 0) return 0;
02301 
02302    int   nsent = 0;
02303    TIter next(wrks);
02304 
02305    TSlave *wrk;
02306    while ((wrk = (TSlave *)next())) {
02307       if (wrk->IsValid()) {
02308          if (SendFile(file, opt, rfile, wrk) < 0)
02309             Error("BroadcastFile",
02310                   "problems sending file to worker %s (%s)",
02311                   wrk->GetOrdinal(), wrk->GetName());
02312          else
02313             nsent++;
02314       }
02315    }
02316 
02317    return nsent;
02318 }
02319 
02320 //______________________________________________________________________________
02321 Int_t TProof::BroadcastFile(const char *file, Int_t opt, const char *rfile, ESlaves list)
02322 {
02323    // Broadcast file to all workers in the specified list. Returns the number of workers
02324    // the buffer was sent to.
02325    // Returns -1 in case of error.
02326 
02327    TList *wrks = 0;
02328    if (list == kAll)       wrks = fSlaves;
02329    if (list == kActive)    wrks = fActiveSlaves;
02330    if (list == kUnique)    wrks = fUniqueSlaves;
02331    if (list == kAllUnique) wrks = fAllUniqueSlaves;
02332 
02333    return BroadcastFile(file, opt, rfile, wrks);
02334 }
02335 
02336 //______________________________________________________________________________
02337 void TProof::ReleaseMonitor(TMonitor *mon)
02338 {
02339    // Release the used monitor to be used, making sure to delete newly created
02340    // monitors.
02341 
02342    if (mon && (mon != fAllMonitor) && (mon != fActiveMonitor)
02343            && (mon != fUniqueMonitor) && (mon != fAllUniqueMonitor)) {
02344       delete mon;
02345    }
02346 }
02347 
02348 //______________________________________________________________________________
02349 Int_t TProof::Collect(const TSlave *sl, Long_t timeout, Int_t endtype, Bool_t deactonfail)
02350 {
02351    // Collect responses from slave sl. Returns the number of slaves that
02352    // responded (=1).
02353    // If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
02354    // which means wait forever).
02355    // If defined (>= 0) endtype is the message that stops this collection.
02356 
02357    Int_t rc = 0;
02358 
02359    TMonitor *mon = 0;
02360    if (!sl->IsValid()) return 0;
02361 
02362    if (fCurrentMonitor == fAllMonitor) {
02363       mon = new TMonitor;
02364    } else {
02365       mon = fAllMonitor;
02366       mon->DeActivateAll();
02367    }
02368    mon->Activate(sl->GetSocket());
02369 
02370    rc = Collect(mon, timeout, endtype, deactonfail);
02371    ReleaseMonitor(mon);
02372    return rc;
02373 }
02374 
02375 //______________________________________________________________________________
02376 Int_t TProof::Collect(TList *slaves, Long_t timeout, Int_t endtype, Bool_t deactonfail)
02377 {
02378    // Collect responses from the slave servers. Returns the number of slaves
02379    // that responded.
02380    // If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
02381    // which means wait forever).
02382    // If defined (>= 0) endtype is the message that stops this collection.
02383 
02384    Int_t rc = 0;
02385 
02386    TMonitor *mon = 0;
02387 
02388    if (fCurrentMonitor == fAllMonitor) {
02389       mon = new TMonitor;
02390    } else {
02391       mon = fAllMonitor;
02392       mon->DeActivateAll();
02393    }
02394    TIter next(slaves);
02395    TSlave *sl;
02396    while ((sl = (TSlave*) next())) {
02397       if (sl->IsValid())
02398          mon->Activate(sl->GetSocket());
02399    }
02400 
02401    rc = Collect(mon, timeout, endtype, deactonfail);
02402    ReleaseMonitor(mon);
02403    return rc;
02404 }
02405 
02406 //______________________________________________________________________________
02407 Int_t TProof::Collect(ESlaves list, Long_t timeout, Int_t endtype, Bool_t deactonfail)
02408 {
02409    // Collect responses from the slave servers. Returns the number of slaves
02410    // that responded.
02411    // If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
02412    // which means wait forever).
02413    // If defined (>= 0) endtype is the message that stops this collection.
02414 
02415    Int_t rc = 0;
02416    TMonitor *mon = 0;
02417 
02418    if (list == kAll)       mon = fAllMonitor;
02419    if (list == kActive)    mon = fActiveMonitor;
02420    if (list == kUnique)    mon = fUniqueMonitor;
02421    if (list == kAllUnique) mon = fAllUniqueMonitor;
02422    if (fCurrentMonitor == mon) {
02423       // Get a copy
02424       mon = new TMonitor(*mon);
02425    }
02426    mon->ActivateAll();
02427 
02428    rc = Collect(mon, timeout, endtype, deactonfail);
02429    ReleaseMonitor(mon);
02430    return rc;
02431 }
02432 
02433 //______________________________________________________________________________
02434 Int_t TProof::Collect(TMonitor *mon, Long_t timeout, Int_t endtype, Bool_t deactonfail)
02435 {
02436    // Collect responses from the slave servers. Returns the number of messages
02437    // received. Can be 0 if there are no active slaves.
02438    // If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
02439    // which means wait forever).
02440    // If defined (>= 0) endtype is the message that stops this collection.
02441 
02442    // Reset the status flag and clear the messages in the list, if any
02443    fStatus = 0;
02444    fRecvMessages->Clear();
02445 
02446    Long_t actto = (Long_t)(gEnv->GetValue("Proof.SocketActivityTimeout", -1) * 1000);
02447 
02448    if (!mon->GetActive(actto)) return 0;
02449 
02450    DeActivateAsyncInput();
02451 
02452    // Used by external code to know what we are monitoring
02453    TMonitor *savedMonitor = 0;
02454    if (fCurrentMonitor) {
02455       savedMonitor = fCurrentMonitor;
02456       fCurrentMonitor = mon;
02457    } else {
02458       fCurrentMonitor = mon;
02459       fBytesRead = 0;
02460       fRealTime  = 0.0;
02461       fCpuTime   = 0.0;
02462    }
02463 
02464    // We want messages on the main window during synchronous collection,
02465    // but we save the present status to restore it at the end
02466    Bool_t saveRedirLog = fRedirLog;
02467    if (!IsIdle() && !IsSync())
02468       fRedirLog = kFALSE;
02469 
02470    int cnt = 0, rc = 0;
02471 
02472    // Timeout counter
02473    Long_t nto = timeout;
02474    PDB(kCollect, 2)
02475       Info("Collect","active: %d", mon->GetActive());
02476 
02477    // On clients, handle Ctrl-C during collection
02478    if (fIntHandler)
02479       fIntHandler->Add();
02480 
02481    // Sockets w/o activity during the last 'sto' millisecs are deactivated
02482    Int_t nact = 0;
02483    Long_t sto = -1;
02484    Int_t nsto = 60;
02485    mon->ResetInterrupt();
02486    while ((nact = mon->GetActive(sto)) && (nto < 0 || nto > 0)) {
02487 
02488       // Dump last waiting sockets, if in debug mode
02489       PDB(kCollect, 2) {
02490          if (nact < 4) {
02491             TList *al = mon->GetListOfActives();
02492             if (al && al->GetSize() > 0) {
02493                Info("Collect"," %d node(s) still active:", al->GetSize());
02494                TIter nxs(al);
02495                TSocket *xs = 0;
02496                while ((xs = (TSocket *)nxs())) {
02497                   TSlave *wrk = FindSlave(xs);
02498                   if (wrk)
02499                      Info("Collect","   %s (%s)", wrk->GetName(), wrk->GetOrdinal());
02500                   else
02501                      Info("Collect","   %p: %s:%d", xs, xs->GetInetAddress().GetHostName(),
02502                                                         xs->GetInetAddress().GetPort());
02503                }
02504             }
02505          }
02506       }
02507 
02508       // Wait for a ready socket
02509       TSocket *s = mon->Select(1000);
02510 
02511       if (s && s != (TSocket *)(-1)) {
02512          // Get and analyse the info it did receive
02513          rc = CollectInputFrom(s, endtype, deactonfail);
02514          if (rc  == 1 || (rc == 2 && !savedMonitor)) {
02515             // Deactivate it if we are done with it
02516             mon->DeActivate(s);
02517             PDB(kCollect, 2)
02518                Info("Collect","deactivating %p (active: %d, %p)",
02519                               s, mon->GetActive(),
02520                               mon->GetListOfActives()->First());
02521          } else if (rc == 2) {
02522             // This end message was for the saved monitor
02523             // Deactivate it if we are done with it
02524             if (savedMonitor) {
02525                savedMonitor->DeActivate(s);
02526                PDB(kCollect, 2)
02527                   Info("Collect","save monitor: deactivating %p (active: %d, %p)",
02528                                  s, savedMonitor->GetActive(),
02529                                  savedMonitor->GetListOfActives()->First());
02530             }
02531          }
02532 
02533          // Update counter (if no error occured)
02534          if (rc >= 0)
02535             cnt++;
02536       } else {
02537          // If not timed-out, exit if not stopped or not aborted
02538          // (player exits status is finished in such a case); otherwise,
02539          // we still need to collect the partial output info
02540          if (!s)
02541             if (fPlayer && (fPlayer->GetExitStatus() == TVirtualProofPlayer::kFinished))
02542                mon->DeActivateAll();
02543          // Decrease the timeout counter if requested
02544          if (s == (TSocket *)(-1) && nto > 0)
02545             nto--;
02546       }
02547       // Check if we need to check the socket activity (we do it every 10 cycles ~ 10 sec)
02548       sto = -1;
02549       if (--nsto <= 0) {
02550          sto = (Long_t) actto;
02551          nsto = 60;
02552       }
02553    }
02554 
02555    // If timed-out, deactivate the remaining sockets
02556    if (nto == 0) {
02557       TList *al = mon->GetListOfActives();
02558       if (al && al->GetSize() > 0) {
02559          // Notify the name of those which did timeout
02560          Info("Collect"," %d node(s) went in timeout:", al->GetSize());
02561          TIter nxs(al);
02562          TSocket *xs = 0;
02563          while ((xs = (TSocket *)nxs())) {
02564             TSlave *wrk = FindSlave(xs);
02565             if (wrk)
02566                Info("Collect","   %s", wrk->GetName());
02567             else
02568                Info("Collect","   %p: %s:%d", xs, xs->GetInetAddress().GetHostName(),
02569                                                   xs->GetInetAddress().GetPort());
02570          }
02571       }
02572       mon->DeActivateAll();
02573    }
02574 
02575    // Deactivate Ctrl-C special handler
02576    if (fIntHandler)
02577       fIntHandler->Remove();
02578 
02579    // make sure group view is up to date
02580    SendGroupView();
02581 
02582    // Restore redirection setting
02583    fRedirLog = saveRedirLog;
02584 
02585    // Restore the monitor
02586    fCurrentMonitor = savedMonitor;
02587 
02588    ActivateAsyncInput();
02589 
02590    return cnt;
02591 }
02592 
02593 //______________________________________________________________________________
02594 void TProof::CleanGDirectory(TList *ol)
02595 {
02596    // Remove links to objects in list 'ol' from gDirectory
02597 
02598    if (ol) {
02599       TIter nxo(ol);
02600       TObject *o = 0;
02601       while ((o = nxo()))
02602          gDirectory->RecursiveRemove(o);
02603    }
02604 }
02605 
02606 //______________________________________________________________________________
02607 Int_t TProof::CollectInputFrom(TSocket *s, Int_t endtype, Bool_t deactonfail)
02608 {
02609    // Collect and analyze available input from socket s.
02610    // Returns 0 on success, -1 if any failure occurs.
02611 
02612    TMessage *mess;
02613 
02614    Int_t recvrc = 0;
02615    if ((recvrc = s->Recv(mess)) < 0) {
02616       PDB(kCollect,2)
02617          Info("CollectInputFrom","%p: got %d from Recv()", s, recvrc);
02618       Bool_t bad = kTRUE;
02619       if (recvrc == -5) {
02620          // Broken connection: try reconnection
02621          if (fCurrentMonitor) fCurrentMonitor->Remove(s);
02622          if (s->Reconnect() == 0) {
02623             if (fCurrentMonitor) fCurrentMonitor->Add(s);
02624             bad = kFALSE;
02625          }
02626       }
02627       if (bad)
02628          MarkBad(s, "problems receiving a message in TProof::CollectInputFrom(...)");
02629       // Ignore this wake up
02630       return -1;
02631    }
02632    if (!mess) {
02633       // we get here in case the remote server died
02634       MarkBad(s, "undefined message in TProof::CollectInputFrom(...)");
02635       return -1;
02636    }
02637    Int_t rc = 0;
02638 
02639    Int_t what = mess->What();
02640    TSlave *sl = FindSlave(s);
02641    rc = HandleInputMessage(sl, mess, deactonfail);
02642    if (rc == 1 && (endtype >= 0) && (what != endtype))
02643       // This message was for the base monitor in recursive case
02644       rc = 2;
02645 
02646    // We are done successfully
02647    return rc;
02648 }
02649 
02650 //______________________________________________________________________________
02651 Int_t TProof::HandleInputMessage(TSlave *sl, TMessage *mess, Bool_t deactonfail)
02652 {
02653    // Analyze the received message.
02654    // Returns 0 on success (1 if this the last message from this socket), -1 if
02655    // any failure occurs.
02656 
02657    char str[512];
02658    TObject *obj;
02659    Int_t rc = 0;
02660 
02661    if (!mess || !sl) {
02662       Warning("HandleInputMessage", "given an empty message or undefined worker");
02663       return -1;
02664    }
02665    Bool_t delete_mess = kTRUE;
02666    TSocket *s = sl->GetSocket();
02667    if (!s) {
02668       Warning("HandleInputMessage", "worker socket is undefined");
02669       return -1;
02670    }
02671 
02672    // The message type
02673    Int_t what = mess->What();
02674 
02675    PDB(kCollect,3)
02676       Info("HandleInputMessage", "got type %d from '%s'", what, sl->GetOrdinal());
02677 
02678    switch (what) {
02679 
02680       case kMESS_OK:
02681          // Add the message to the list
02682          fRecvMessages->Add(mess);
02683          delete_mess = kFALSE;
02684          break;
02685 
02686       case kMESS_OBJECT:
02687          if (fPlayer) fPlayer->HandleRecvHisto(mess);
02688          break;
02689 
02690       case kPROOF_FATAL:
02691          {  TString msg;
02692             if ((mess->BufferSize() > mess->Length()))
02693                (*mess) >> msg;
02694             if (msg.IsNull()) {
02695                MarkBad(s, "received kPROOF_FATAL");
02696             } else {
02697                MarkBad(s, msg);
02698             }
02699          }
02700          if (fProgressDialogStarted) {
02701             // Finalize the progress dialog
02702             Emit("StopProcess(Bool_t)", kTRUE);
02703          }
02704          break;
02705 
02706       case kPROOF_STOP:
02707          // Stop collection from this worker
02708          Info("HandleInputMessage", "received kPROOF_STOP from %s: disabling any further collection this worker",
02709               sl->GetOrdinal());
02710          rc = 1;
02711          break;
02712 
02713       case kPROOF_GETTREEHEADER:
02714          // Add the message to the list
02715          fRecvMessages->Add(mess);
02716          delete_mess = kFALSE;
02717          rc = 1;
02718          break;
02719 
02720       case kPROOF_TOUCH:
02721          // send a request for touching the remote admin file
02722          {
02723             sl->Touch();
02724          }
02725          break;
02726 
02727       case kPROOF_GETOBJECT:
02728          // send slave object it asks for
02729          mess->ReadString(str, sizeof(str));
02730          obj = gDirectory->Get(str);
02731          if (obj)
02732             s->SendObject(obj);
02733          else
02734             s->Send(kMESS_NOTOK);
02735          break;
02736 
02737       case kPROOF_GETPACKET:
02738          {
02739             TDSetElement *elem = 0;
02740             elem = fPlayer ? fPlayer->GetNextPacket(sl, mess) : 0;
02741 
02742             if (elem != (TDSetElement*) -1) {
02743                TMessage answ(kPROOF_GETPACKET);
02744                answ << elem;
02745                s->Send(answ);
02746 
02747                while (fWaitingSlaves != 0 && fWaitingSlaves->GetSize()) {
02748                   TPair *p = (TPair*) fWaitingSlaves->First();
02749                   s = (TSocket*) p->Key();
02750                   TMessage *m = (TMessage*) p->Value();
02751 
02752                   elem = fPlayer ? fPlayer->GetNextPacket(sl, m) : 0;
02753                   if (elem != (TDSetElement*) -1) {
02754                      TMessage a(kPROOF_GETPACKET);
02755                      a << elem;
02756                      s->Send(a);
02757                      // remove has to happen via Links because TPair does not have
02758                      // a Compare() function and therefore RemoveFirst() and
02759                      // Remove(TObject*) do not work
02760                      fWaitingSlaves->Remove(fWaitingSlaves->FirstLink());
02761                      delete p;
02762                      delete m;
02763                   } else {
02764                      break;
02765                   }
02766                }
02767             } else {
02768                if (fWaitingSlaves == 0) fWaitingSlaves = new TList;
02769                fWaitingSlaves->Add(new TPair(s, mess));
02770                delete_mess = kFALSE;
02771             }
02772          }
02773          break;
02774 
02775       case kPROOF_LOGFILE:
02776          {
02777             Int_t size;
02778             (*mess) >> size;
02779             PDB(kGlobal,2)
02780                Info("HandleInputMessage","%s: kPROOF_LOGFILE: size: %d", sl->GetOrdinal(), size);
02781             RecvLogFile(s, size);
02782          }
02783          break;
02784 
02785       case kPROOF_LOGDONE:
02786          (*mess) >> sl->fStatus >> sl->fParallel;
02787          PDB(kCollect,2)
02788             Info("HandleInputMessage","%s: kPROOF_LOGDONE: status %d  parallel %d",
02789                  sl->GetOrdinal(), sl->fStatus, sl->fParallel);
02790          if (sl->fStatus != 0) {
02791             // Return last nonzero status
02792             fStatus = sl->fStatus;
02793             // Deactivate the worker, if required
02794             if (deactonfail) DeactivateWorker(sl->fOrdinal);
02795          }
02796          rc = 1;
02797          break;
02798 
02799       case kPROOF_GETSTATS:
02800          {
02801             (*mess) >> sl->fBytesRead >> sl->fRealTime >> sl->fCpuTime
02802                   >> sl->fWorkDir >> sl->fProofWorkDir;
02803             TString img;
02804             if ((mess->BufferSize() > mess->Length()))
02805                (*mess) >> img;
02806             // Set image
02807             if (img.IsNull()) {
02808                if (sl->fImage.IsNull())
02809                   sl->fImage = Form("%s:%s", TUrl(sl->fName).GetHostFQDN(),
02810                                              sl->fProofWorkDir.Data());
02811             } else {
02812                sl->fImage = img;
02813             }
02814             PDB(kGlobal,2)
02815                Info("HandleInputMessage",
02816                         "kPROOF_GETSTATS:%s image: %s", sl->GetOrdinal(), sl->GetImage());
02817 
02818             fBytesRead += sl->fBytesRead;
02819             fRealTime  += sl->fRealTime;
02820             fCpuTime   += sl->fCpuTime;
02821             rc = 1;
02822          }
02823          break;
02824 
02825       case kPROOF_GETPARALLEL:
02826          {
02827             Bool_t async = kFALSE;
02828             (*mess) >> sl->fParallel;
02829             if ((mess->BufferSize() > mess->Length()))
02830                (*mess) >> async;
02831             rc = (async) ? 0 : 1;
02832          }
02833          break;
02834 
02835       case kPROOF_CHECKFILE:
02836          {  // New servers (>= 5.22) send the status
02837             if ((mess->BufferSize() > mess->Length())) {
02838                (*mess) >> fCheckFileStatus;
02839             } else {
02840                // Form old servers this meant success (failure was signaled with the
02841                // dangerous kPROOF_FATAL)
02842                fCheckFileStatus = 1;
02843             }
02844             rc = 1;
02845          }
02846          break;
02847 
02848       case kPROOF_SENDFILE:
02849          {  // New server: signals ending of sendfile operation
02850             rc = 1;
02851          }
02852          break;
02853 
02854       case kPROOF_PACKAGE_LIST:
02855          {
02856             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_PACKAGE_LIST: enter");
02857             Int_t type = 0;
02858             (*mess) >> type;
02859             switch (type) {
02860             case TProof::kListEnabledPackages:
02861                SafeDelete(fEnabledPackages);
02862                fEnabledPackages = (TList *) mess->ReadObject(TList::Class());
02863                if (fEnabledPackages) {
02864                   fEnabledPackages->SetOwner();
02865                } else {
02866                   Error("HandleInputMessage",
02867                         "kPROOF_PACKAGE_LIST: kListEnabledPackages: TList not found in message!");
02868                }
02869                break;
02870             case TProof::kListPackages:
02871                SafeDelete(fAvailablePackages);
02872                fAvailablePackages = (TList *) mess->ReadObject(TList::Class());
02873                if (fAvailablePackages) {
02874                   fAvailablePackages->SetOwner();
02875                } else {
02876                   Error("HandleInputMessage",
02877                         "kPROOF_PACKAGE_LIST: kListPackages: TList not found in message!");
02878                }
02879                break;
02880             default:
02881                Error("HandleInputMessage", "kPROOF_PACKAGE_LIST: unknown type: %d", type);
02882             }
02883          }
02884          break;
02885 
02886       case kPROOF_OUTPUTOBJECT:
02887          {
02888             PDB(kGlobal,2)
02889                Info("HandleInputMessage","kPROOF_OUTPUTOBJECT: enter");
02890             Int_t type = 0;
02891             const char *prefix = gProofServ ? gProofServ->GetPrefix() : "Lite-0";
02892             if (!TestBit(TProof::kIsClient) && !fMergersSet && !fFinalizationRunning) {
02893                Info("HandleInputMessage", "finalization on %s started ...", prefix);
02894                fFinalizationRunning = kTRUE;
02895             }
02896 
02897             while ((mess->BufferSize() > mess->Length())) {
02898                (*mess) >> type;
02899                // If a query result header, add it to the player list
02900                if (fPlayer) {
02901                   if (type == 0) {
02902                      // Retrieve query result instance (output list not filled)
02903                      TQueryResult *pq =
02904                         (TQueryResult *) mess->ReadObject(TQueryResult::Class());
02905                      if (pq) {
02906                         // Add query to the result list in TProofPlayer
02907                         fPlayer->AddQueryResult(pq);
02908                         fPlayer->SetCurrentQuery(pq);
02909                         // And clear the output list, as we start merging a new set of results
02910                         if (fPlayer->GetOutputList())
02911                            fPlayer->GetOutputList()->Clear();
02912                         // Add the unique query tag as TNamed object to the input list
02913                         // so that it is available in TSelectors for monitoring
02914                         fPlayer->AddInput(new TNamed("PROOF_QueryTag",
02915                                           Form("%s:%s",pq->GetTitle(),pq->GetName())));
02916                      } else {
02917                         Warning("HandleInputMessage","kPROOF_OUTPUTOBJECT: query result missing");
02918                      }
02919                   } else if (type > 0) {
02920                      // Read object
02921                      TObject *o = mess->ReadObject(TObject::Class());
02922                      // Increment counter on the client side
02923                      fMergePrg.IncreaseIdx();
02924                      TString msg;
02925                      msg.Form("%s: merging output objects ... %s", prefix, fMergePrg.Export());
02926                      if (gProofServ)
02927                         gProofServ->SendAsynMessage(msg.Data(), kFALSE);
02928                      else
02929                         fprintf(stderr, "%s\r", msg.Data());
02930                      // Add or merge it
02931                      if ((fPlayer->AddOutputObject(o) == 1)) {
02932                         // Remove the object if it has been merged
02933                         SafeDelete(o);
02934                      }
02935                      if (type > 1) {
02936                         // Update the merger progress info
02937                         fMergePrg.DecreaseNWrks();
02938                         if (TestBit(TProof::kIsClient) && !IsLite()) {
02939                            // In PROOFLite this has to be done once only in TProofLite::Process
02940                            TQueryResult *pq = fPlayer->GetCurrentQuery();
02941                            pq->SetOutputList(fPlayer->GetOutputList(), kFALSE);
02942                            // Add input objects (do not override remote settings, if any)
02943                            TObject *xo = 0;
02944                            TIter nxin(fPlayer->GetInputList());
02945                            // Servers prior to 5.28/00 do not create the input list in the TQueryResult
02946                            if (!pq->GetInputList()) pq->SetInputList(new TList());
02947                            while ((xo = nxin()))
02948                               if (!pq->GetInputList()->FindObject(xo->GetName())) pq->AddInput(xo->Clone());                             
02949                            // If the last object, notify the GUI that the result arrived
02950                            QueryResultReady(Form("%s:%s", pq->GetTitle(), pq->GetName()));
02951                            // Processing is over
02952                            UpdateDialog();
02953                         }
02954                      }
02955                   }
02956                } else {
02957                   Warning("HandleInputMessage", "kPROOF_OUTPUTOBJECT: player undefined!");
02958                }
02959             }
02960          }
02961          break;
02962 
02963       case kPROOF_OUTPUTLIST:
02964          {
02965             PDB(kGlobal,2)
02966                Info("HandleInputMessage","%s: kPROOF_OUTPUTLIST: enter", sl->GetOrdinal());
02967             TList *out = 0;
02968             if (fPlayer) {
02969                if (TestBit(TProof::kIsMaster) || fProtocol < 7) {
02970                   out = (TList *) mess->ReadObject(TList::Class());
02971                } else {
02972                   TQueryResult *pq =
02973                      (TQueryResult *) mess->ReadObject(TQueryResult::Class());
02974                   if (pq) {
02975                      // Add query to the result list in TProofPlayer
02976                      fPlayer->AddQueryResult(pq);
02977                      fPlayer->SetCurrentQuery(pq);
02978                      // To avoid accidental cleanups from anywhere else
02979                      // remove objects from gDirectory and clone the list
02980                      out = pq->GetOutputList();
02981                      CleanGDirectory(out);
02982                      out = (TList *) out->Clone();
02983                      // Notify the GUI that the result arrived
02984                      QueryResultReady(Form("%s:%s", pq->GetTitle(), pq->GetName()));
02985                   } else {
02986                      PDB(kGlobal,2)
02987                         Info("HandleInputMessage",
02988                              "%s: kPROOF_OUTPUTLIST: query result missing", sl->GetOrdinal());
02989                   }
02990                }
02991                if (out) {
02992                   out->SetOwner();
02993                   fPlayer->AddOutput(out); // Incorporate the list
02994                   SafeDelete(out);
02995                } else {
02996                   PDB(kGlobal,2)
02997                      Info("HandleInputMessage",
02998                           "%s: kPROOF_OUTPUTLIST: ouputlist is empty", sl->GetOrdinal());
02999                }
03000             } else {
03001                Warning("HandleInputMessage",
03002                        "%s: kPROOF_OUTPUTLIST: player undefined!", sl->GetOrdinal());
03003             }
03004             // On clients at this point processing is over
03005             if (TestBit(TProof::kIsClient) && !IsLite())
03006                UpdateDialog();
03007          }
03008          break;
03009 
03010       case kPROOF_QUERYLIST:
03011          {
03012             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_QUERYLIST: enter");
03013             (*mess) >> fOtherQueries >> fDrawQueries;
03014             if (fQueries) {
03015                fQueries->Delete();
03016                delete fQueries;
03017                fQueries = 0;
03018             }
03019             fQueries = (TList *) mess->ReadObject(TList::Class());
03020          }
03021          break;
03022 
03023       case kPROOF_RETRIEVE:
03024          {
03025             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_RETRIEVE: enter");
03026             TQueryResult *pq =
03027                (TQueryResult *) mess->ReadObject(TQueryResult::Class());
03028             if (pq && fPlayer) {
03029                fPlayer->AddQueryResult(pq);
03030                // Notify the GUI that the result arrived
03031                QueryResultReady(Form("%s:%s", pq->GetTitle(), pq->GetName()));
03032             } else {
03033                PDB(kGlobal,2)
03034                   Info("HandleInputMessage","kPROOF_RETRIEVE: query result missing or player undefined");
03035             }
03036          }
03037          break;
03038 
03039       case kPROOF_MAXQUERIES:
03040          {
03041             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_MAXQUERIES: enter");
03042             Int_t max = 0;
03043 
03044             (*mess) >> max;
03045             Printf("Number of queries fully kept remotely: %d", max);
03046          }
03047          break;
03048 
03049       case kPROOF_SERVERSTARTED:
03050          {
03051             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_SERVERSTARTED: enter");
03052 
03053             UInt_t tot = 0, done = 0;
03054             TString action;
03055             Bool_t st = kTRUE;
03056 
03057             (*mess) >> action >> tot >> done >> st;
03058 
03059             if (TestBit(TProof::kIsClient)) {
03060                if (tot) {
03061                   TString type = (action.Contains("submas")) ? "submasters"
03062                                                              : "workers";
03063                   Int_t frac = (Int_t) (done*100.)/tot;
03064                   char msg[512] = {0};
03065                   if (frac >= 100) {
03066                      snprintf(msg, 512, "%s: OK (%d %s)                 \n",
03067                              action.Data(),tot, type.Data());
03068                   } else {
03069                      snprintf(msg, 512, "%s: %d out of %d (%d %%)\r",
03070                              action.Data(), done, tot, frac);
03071                   }
03072                   if (fSync)
03073                      fprintf(stderr,"%s", msg);
03074                   else
03075                      NotifyLogMsg(msg, 0);
03076                }
03077                // Notify GUIs
03078                StartupMessage(action.Data(), st, (Int_t)done, (Int_t)tot);
03079             } else {
03080 
03081                // Just send the message one level up
03082                TMessage m(kPROOF_SERVERSTARTED);
03083                m << action << tot << done << st;
03084                gProofServ->GetSocket()->Send(m);
03085             }
03086          }
03087          break;
03088 
03089       case kPROOF_DATASET_STATUS:
03090          {
03091             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_DATASET_STATUS: enter");
03092 
03093             UInt_t tot = 0, done = 0;
03094             TString action;
03095             Bool_t st = kTRUE;
03096 
03097             (*mess) >> action >> tot >> done >> st;
03098 
03099             if (TestBit(TProof::kIsClient)) {
03100                if (tot) {
03101                   TString type = "files";
03102                   Int_t frac = (Int_t) (done*100.)/tot;
03103                   char msg[512] = {0};
03104                   if (frac >= 100) {
03105                      snprintf(msg, 512, "%s: OK (%d %s)                 \n",
03106                              action.Data(),tot, type.Data());
03107                   } else {
03108                      snprintf(msg, 512, "%s: %d out of %d (%d %%)\r",
03109                              action.Data(), done, tot, frac);
03110                   }
03111                   if (fSync)
03112                      fprintf(stderr,"%s", msg);
03113                   else
03114                      NotifyLogMsg(msg, 0);
03115                }
03116                // Notify GUIs
03117                DataSetStatus(action.Data(), st, (Int_t)done, (Int_t)tot);
03118             } else {
03119 
03120                // Just send the message one level up
03121                TMessage m(kPROOF_DATASET_STATUS);
03122                m << action << tot << done << st;
03123                gProofServ->GetSocket()->Send(m);
03124             }
03125          }
03126          break;
03127 
03128       case kPROOF_STARTPROCESS:
03129          {
03130             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_STARTPROCESS: enter");
03131 
03132             // For Proof-Lite this variable is the number of workers and is set
03133             // by the player
03134             if (!IsLite()) {
03135                fNotIdle = 1;
03136                fIsWaiting = kFALSE;
03137             }
03138 
03139             // Redirect the output, if needed
03140             fRedirLog = (fSync) ? fRedirLog : kTRUE;
03141 
03142             // The signal is used on masters by XrdProofdProtocol to catch
03143             // the start of processing; on clients it allows to update the
03144             // progress dialog
03145             if (!TestBit(TProof::kIsMaster)) {
03146                TString selec;
03147                Int_t dsz = -1;
03148                Long64_t first = -1, nent = -1;
03149                (*mess) >> selec >> dsz >> first >> nent;
03150                // Start or reset the progress dialog
03151                if (!gROOT->IsBatch()) {
03152                   if (fProgressDialog &&
03153                       !TestBit(kUsingSessionGui) && TestBit(kUseProgressDialog)) {
03154                      if (!fProgressDialogStarted) {
03155                         fProgressDialog->ExecPlugin(5, this,
03156                                                    selec.Data(), dsz, first, nent);
03157                         fProgressDialogStarted = kTRUE;
03158                      } else {
03159                         ResetProgressDialog(selec, dsz, first, nent);
03160                      }
03161                   }
03162                   ResetBit(kUsingSessionGui);
03163                }
03164             }
03165          }
03166          break;
03167 
03168       case kPROOF_ENDINIT:
03169          {
03170             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_ENDINIT: enter");
03171 
03172             if (TestBit(TProof::kIsMaster)) {
03173                if (fPlayer)
03174                   fPlayer->SetInitTime();
03175             }
03176          }
03177          break;
03178 
03179       case kPROOF_SETIDLE:
03180          {
03181             PDB(kGlobal,2)
03182                Info("HandleInputMessage","kPROOF_SETIDLE: enter");
03183 
03184             // The session is idle
03185             if (IsLite()) {
03186                if (fNotIdle > 0) {
03187                   fNotIdle--;
03188                } else {
03189                   Warning("HandleInputMessage", "got kPROOF_SETIDLE but no running workers ! protocol error?");
03190                }
03191             } else {
03192                fNotIdle = 0;
03193                // Check if the query has been enqueued
03194                if ((mess->BufferSize() > mess->Length()))
03195                   (*mess) >> fIsWaiting;
03196             }
03197          }
03198          break;
03199 
03200       case kPROOF_QUERYSUBMITTED:
03201          {
03202             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_QUERYSUBMITTED: enter");
03203 
03204             // We have received the sequential number
03205             (*mess) >> fSeqNum;
03206             Bool_t sync = fSync;
03207             if ((mess->BufferSize() > mess->Length()))
03208                (*mess) >> sync;
03209             if (sync !=  fSync && fSync) {
03210                // The server required to switch to asynchronous mode
03211                Activate();
03212                fSync = kFALSE;
03213             }
03214             DisableGoAsyn();
03215             // Check if the query has been enqueued
03216             fIsWaiting = kTRUE;
03217             // For Proof-Lite this variable is the number of workers and is set by the player
03218             if (!IsLite())
03219                fNotIdle = 1;
03220 
03221             rc = 1;
03222          }
03223          break;
03224 
03225       case kPROOF_SESSIONTAG:
03226          {
03227             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_SESSIONTAG: enter");
03228 
03229             // We have received the unique tag and save it as name of this object
03230             TString stag;
03231             (*mess) >> stag;
03232             SetName(stag);
03233             // In the TSlave object
03234             sl->SetSessionTag(stag);
03235             // New servers send also the group
03236             if ((mess->BufferSize() > mess->Length()))
03237                (*mess) >> fGroup;
03238          }
03239          break;
03240 
03241       case kPROOF_FEEDBACK:
03242          {
03243             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_FEEDBACK: enter");
03244             TList *out = (TList *) mess->ReadObject(TList::Class());
03245             out->SetOwner();
03246             if (fPlayer)
03247                fPlayer->StoreFeedback(sl, out); // Adopts the list
03248             else
03249                // Not yet ready: stop collect asap
03250                rc = 1;
03251          }
03252          break;
03253 
03254       case kPROOF_AUTOBIN:
03255          {
03256             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_AUTOBIN: enter");
03257 
03258             TString name;
03259             Double_t xmin, xmax, ymin, ymax, zmin, zmax;
03260 
03261             (*mess) >> name >> xmin >> xmax >> ymin >> ymax >> zmin >> zmax;
03262 
03263             if (fPlayer) fPlayer->UpdateAutoBin(name,xmin,xmax,ymin,ymax,zmin,zmax);
03264 
03265             TMessage answ(kPROOF_AUTOBIN);
03266 
03267             answ << name << xmin << xmax << ymin << ymax << zmin << zmax;
03268 
03269             s->Send(answ);
03270          }
03271          break;
03272 
03273       case kPROOF_PROGRESS:
03274          {
03275             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_PROGRESS: enter");
03276 
03277             if (GetRemoteProtocol() > 25) {
03278                // New format
03279                TProofProgressInfo *pi = 0;
03280                (*mess) >> pi;
03281                fPlayer->Progress(sl,pi);
03282             } else if (GetRemoteProtocol() > 11) {
03283                Long64_t total, processed, bytesread;
03284                Float_t initTime, procTime, evtrti, mbrti;
03285                (*mess) >> total >> processed >> bytesread
03286                      >> initTime >> procTime
03287                      >> evtrti >> mbrti;
03288                if (fPlayer)
03289                   fPlayer->Progress(sl, total, processed, bytesread,
03290                                     initTime, procTime, evtrti, mbrti);
03291 
03292             } else {
03293                // Old format
03294                Long64_t total, processed;
03295                (*mess) >> total >> processed;
03296                if (fPlayer)
03297                   fPlayer->Progress(sl, total, processed);
03298             }
03299          }
03300          break;
03301 
03302       case kPROOF_STOPPROCESS:
03303          {
03304             // This message is sent from a worker that finished processing.
03305             // We determine whether it was asked to finish by the
03306             // packetizer or stopped during processing a packet
03307             // (by TProof::RemoveWorkers() or by an external signal).
03308             // In the later case call packetizer->MarkBad.
03309             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_STOPPROCESS: enter");
03310 
03311             Long64_t events = 0;
03312             Bool_t abort = kFALSE;
03313             TProofProgressStatus *status = 0;
03314 
03315             if ((mess->BufferSize() > mess->Length()) && (fProtocol > 18)) {
03316                (*mess) >> status >> abort;
03317             } else if ((mess->BufferSize() > mess->Length()) && (fProtocol > 8)) {
03318                (*mess) >> events >> abort;
03319             } else {
03320                (*mess) >> events;
03321             }
03322             if (!abort && fPlayer) {
03323                if (fProtocol > 18) {
03324                   TList *listOfMissingFiles = 0;
03325                   if (!(listOfMissingFiles = (TList *)GetOutput("MissingFiles"))) {
03326                      listOfMissingFiles = new TList();
03327                      listOfMissingFiles->SetName("MissingFiles");
03328                      if (fPlayer)
03329                         fPlayer->AddOutputObject(listOfMissingFiles);
03330                   }
03331                   if (fPlayer->GetPacketizer()) {
03332                      Int_t ret =
03333                         fPlayer->GetPacketizer()->AddProcessed(sl, status, 0, &listOfMissingFiles);
03334                      if (ret > 0)
03335                         fPlayer->GetPacketizer()->MarkBad(sl, status, &listOfMissingFiles);
03336                      // This object is now owned by the packetizer
03337                      status = 0;
03338                   }
03339                } else {
03340                   fPlayer->AddEventsProcessed(events);
03341                }
03342             }
03343             SafeDelete(status);
03344             if (!TestBit(TProof::kIsMaster))
03345                Emit("StopProcess(Bool_t)", abort);
03346             break;
03347          }
03348 
03349       case kPROOF_SUBMERGER:
03350          {
03351             PDB(kGlobal,2) Info("HandleInputMessage", "kPROOF_SUBMERGER: enter");
03352             HandleSubmerger(mess, sl);
03353          }
03354          break;
03355 
03356       case kPROOF_GETSLAVEINFO:
03357          {
03358             PDB(kGlobal,2) Info("HandleInputMessage", "kPROOF_GETSLAVEINFO: enter");
03359 
03360             Bool_t active = (GetListOfActiveSlaves()->FindObject(sl) != 0);
03361             Bool_t bad = (GetListOfBadSlaves()->FindObject(sl) != 0);
03362             TList* tmpinfo = 0;
03363             (*mess) >> tmpinfo;
03364             if (tmpinfo == 0) {
03365                Error("HandleInputMessage", "kPROOF_GETSLAVEINFO: no list received!");
03366             } else {
03367                tmpinfo->SetOwner(kFALSE);
03368                Int_t nentries = tmpinfo->GetSize();
03369                for (Int_t i=0; i<nentries; i++) {
03370                   TSlaveInfo* slinfo =
03371                      dynamic_cast<TSlaveInfo*>(tmpinfo->At(i));
03372                   if (slinfo) {
03373                      // If PROOF-Lite
03374                      if (IsLite()) slinfo->fHostName = gSystem->HostName();
03375                      // Check if we have already a instance for this worker
03376                      TIter nxw(fSlaveInfo);
03377                      TSlaveInfo *ourwi = 0;
03378                      while ((ourwi = (TSlaveInfo *)nxw())) {
03379                         if (!strcmp(ourwi->GetOrdinal(), slinfo->GetOrdinal())) {
03380                            ourwi->SetSysInfo(slinfo->GetSysInfo());
03381                            ourwi->fHostName = slinfo->GetName();
03382                            if (slinfo->GetDataDir() && (strlen(slinfo->GetDataDir()) > 0))
03383                            ourwi->fDataDir = slinfo->GetDataDir();
03384                            break;
03385                         }
03386                      }
03387                      if (!ourwi) {
03388                         fSlaveInfo->Add(slinfo);
03389                      } else {
03390                         slinfo = ourwi;
03391                      }
03392                      if (slinfo->fStatus != TSlaveInfo::kBad) {
03393                         if (!active) slinfo->SetStatus(TSlaveInfo::kNotActive);
03394                         if (bad) slinfo->SetStatus(TSlaveInfo::kBad);
03395                      }
03396                      if (sl->GetMsd() && (strlen(sl->GetMsd()) > 0))
03397                         slinfo->fMsd = sl->GetMsd();
03398                   }
03399                }
03400                delete tmpinfo;
03401                rc = 1;
03402             }
03403          }
03404          break;
03405 
03406       case kPROOF_VALIDATE_DSET:
03407          {
03408             PDB(kGlobal,2)
03409                Info("HandleInputMessage", "kPROOF_VALIDATE_DSET: enter");
03410             TDSet* dset = 0;
03411             (*mess) >> dset;
03412             if (!fDSet)
03413                Error("HandleInputMessage", "kPROOF_VALIDATE_DSET: fDSet not set");
03414             else
03415                fDSet->Validate(dset);
03416             delete dset;
03417          }
03418          break;
03419 
03420       case kPROOF_DATA_READY:
03421          {
03422             PDB(kGlobal,2) Info("HandleInputMessage", "kPROOF_DATA_READY: enter");
03423             Bool_t dataready = kFALSE;
03424             Long64_t totalbytes, bytesready;
03425             (*mess) >> dataready >> totalbytes >> bytesready;
03426             fTotalBytes += totalbytes;
03427             fBytesReady += bytesready;
03428             if (dataready == kFALSE) fDataReady = dataready;
03429          }
03430          break;
03431 
03432       case kPROOF_PING:
03433          // do nothing (ping is already acknowledged)
03434          break;
03435 
03436       case kPROOF_MESSAGE:
03437          {
03438             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_MESSAGE: enter");
03439 
03440             // We have received the unique tag and save it as name of this object
03441             TString msg;
03442             (*mess) >> msg;
03443             Bool_t lfeed = kTRUE;
03444             if ((mess->BufferSize() > mess->Length()))
03445                (*mess) >> lfeed;
03446 
03447             if (TestBit(TProof::kIsClient)) {
03448 
03449                if (fSync) {
03450                   // Notify locally
03451                   fprintf(stderr,"%s%c", msg.Data(), (lfeed ? '\n' : '\r'));
03452                } else {
03453                   // Notify locally taking care of redirection, windows logs, ...
03454                   NotifyLogMsg(msg, (lfeed ? "\n" : "\r"));
03455                }
03456             } else {
03457 
03458                // The message is logged for debugging purposes.
03459                fprintf(stderr,"%s%c", msg.Data(), (lfeed ? '\n' : '\r'));
03460                if (gProofServ) {
03461                   // We hide it during normal operations
03462                   gProofServ->FlushLogFile();
03463 
03464                   // And send the message one level up
03465                   gProofServ->SendAsynMessage(msg, lfeed);
03466                }
03467             }
03468          }
03469          break;
03470 
03471       case kPROOF_VERSARCHCOMP:
03472          {
03473             TString vac;
03474             (*mess) >> vac;
03475             PDB(kGlobal,2) Info("HandleInputMessage","kPROOF_VERSARCHCOMP: %s", vac.Data());
03476             Int_t from = 0;
03477             TString vers, archcomp;
03478             if (vac.Tokenize(vers, from, "|"))
03479                vac.Tokenize(archcomp, from, "|");
03480             sl->SetArchCompiler(archcomp);
03481             vers.ReplaceAll(":","|");
03482             sl->SetROOTVersion(vers);
03483          }
03484          break;
03485 
03486       default:
03487          {
03488             Error("HandleInputMessage", "unknown command received from '%s' (what = %d)",
03489                                         sl->GetOrdinal(), what);
03490          }
03491          break;
03492    }
03493 
03494    // Cleanup
03495    if (delete_mess)
03496       delete mess;
03497 
03498    // We are done successfully
03499    return rc;
03500 }
03501 
03502 //______________________________________________________________________________
03503 void TProof::HandleSubmerger(TMessage *mess, TSlave *sl)
03504 {
03505    // Process a message of type kPROOF_SUBMERGER
03506 
03507    // Message sub-type
03508    Int_t type = 0;
03509    (*mess) >> type;
03510    TSocket *s = sl->GetSocket();
03511 
03512    switch (type) {
03513       case kOutputSent:
03514          {
03515             if (IsEndMaster()) {
03516                Int_t  merger_id = -1;
03517                (*mess) >> merger_id;
03518 
03519                PDB(kSubmerger, 2)
03520                   Info("HandleSubmerger", "kOutputSent: Worker %s:%d:%s had sent its output to merger #%d",
03521                                           sl->GetName(), sl->GetPort(), sl->GetOrdinal(), merger_id);
03522 
03523                if (!fMergers || fMergers->GetSize() <= merger_id) {
03524                   Error("HandleSubmerger", "kOutputSize: #%d not in list ", merger_id);
03525                   break;
03526                }
03527                TMergerInfo * mi = (TMergerInfo *) fMergers->At(merger_id);
03528                mi->SetMergedWorker();
03529                if (mi->AreAllWorkersMerged()) {
03530                   mi->Deactivate();
03531                   if (GetActiveMergersCount() == 0) {
03532                      fMergers->Clear();
03533                      delete fMergers;
03534                      fMergersSet = kFALSE;
03535                      fMergersCount = -1;
03536                      fLastAssignedMerger = 0;
03537                      PDB(kSubmerger, 2) Info("HandleSubmerger", "all mergers removed ... ");
03538                   }
03539                }
03540             } else {
03541                PDB(kSubmerger, 2) Error("HandleSubmerger","kOutputSent: received not on endmaster!");
03542             }
03543          }
03544          break;
03545 
03546       case kMergerDown:
03547          {
03548             Int_t  merger_id = -1;
03549             (*mess) >> merger_id;
03550 
03551             PDB(kSubmerger, 2) Info("HandleSubmerger", "kMergerDown: #%d ", merger_id);
03552 
03553             if (!fMergers || fMergers->GetSize() <= merger_id) {
03554                Error("HandleSubmerger", "kMergerDown: #%d not in list ", merger_id);
03555                break;
03556             }
03557 
03558             TMergerInfo * mi = (TMergerInfo *) fMergers->At(merger_id);
03559             if (!mi->IsActive()) {
03560                break;
03561             } else {
03562                mi->Deactivate();
03563             }
03564 
03565             // Stop the invalid merger in the case it is still listening
03566             TMessage stop(kPROOF_SUBMERGER);
03567             stop << Int_t(kStopMerging);
03568             stop <<  0;
03569             s->Send(stop);
03570 
03571             // Ask for results from merger (only original results from this node as worker are returned)
03572             AskForOutput(mi->GetMerger());
03573 
03574             // Ask for results from all workers assigned to this merger
03575             TIter nxo(mi->GetWorkers());
03576             TObject * o = 0;
03577             while ((o = nxo())) {
03578                AskForOutput((TSlave *)o);
03579             }
03580             PDB(kSubmerger, 2) Info("HandleSubmerger", "kMergerDown:%d: exit", merger_id);
03581          }
03582          break;
03583 
03584       case kOutputSize:
03585          {
03586             if (IsEndMaster()) {
03587                PDB(kSubmerger, 2)
03588                   Info("HandleSubmerger", "worker %s reported as finished ", sl->GetOrdinal());
03589 
03590                const char *prefix = gProofServ ? gProofServ->GetPrefix() : "Lite-0";
03591                if (!fFinalizationRunning) {
03592                   Info("HandleSubmerger", "finalization on %s started ...", prefix);
03593                   fFinalizationRunning = kTRUE;
03594                }
03595 
03596                Int_t  output_size = 0;
03597                Int_t  merging_port = 0;
03598                (*mess) >> output_size >> merging_port;
03599 
03600                PDB(kSubmerger, 2) Info("HandleSubmerger",
03601                                        "kOutputSize: Worker %s:%d:%s reports %d output objects (+ available port %d)",
03602                                        sl->GetName(), sl->GetPort(), sl->GetOrdinal(), output_size, merging_port);
03603                TString msg;
03604                if (!fMergersSet) {
03605 
03606                   Int_t activeWorkers = fCurrentMonitor ? fCurrentMonitor->GetActive() : GetNumberOfActiveSlaves();
03607                   
03608                   // First pass - setting number of mergers according to user or dynamically
03609                   fMergersCount = -1; // No mergers used if not set by user
03610                   TParameter<Int_t> *mc = dynamic_cast<TParameter<Int_t> *>(GetParameter("PROOF_UseMergers"));
03611                   if (mc) fMergersCount = mc->GetVal(); // Value set by user
03612 
03613                   // Mergers count specified by user but not valid
03614                   if (fMergersCount < 0 || (fMergersCount > (activeWorkers/2) )) {
03615                      msg.Form("%s: Invalid request: cannot start %d mergers for %d workers",
03616                               prefix, fMergersCount, activeWorkers);
03617                      if (gProofServ)
03618                         gProofServ->SendAsynMessage(msg);
03619                      else
03620                         Printf("%s",msg.Data());
03621                      fMergersCount = 0;
03622                   }
03623                   // Mergers count will be set dynamically
03624                   if (fMergersCount == 0) {
03625                      if (activeWorkers > 1) {
03626                         fMergersCount = TMath::Nint(TMath::Sqrt(activeWorkers));
03627                         if (activeWorkers / fMergersCount < 2)
03628                            fMergersCount = (Int_t) TMath::Sqrt(activeWorkers);
03629                      }
03630                      if (fMergersCount > 1)
03631                         msg.Form("%s: Number of mergers set dynamically to %d (for %d workers)",
03632                                  prefix, fMergersCount, activeWorkers);
03633                      else {
03634                         msg.Form("%s: No mergers will be used for %d workers",
03635                                  prefix, activeWorkers);
03636                         fMergersCount = -1;
03637                      }
03638                      if (gProofServ)
03639                         gProofServ->SendAsynMessage(msg);
03640                      else
03641                         Printf("%s",msg.Data());
03642                   } else {
03643                      msg.Form("%s: Number of mergers set by user to %d (for %d workers)",
03644                               prefix, fMergersCount, activeWorkers);
03645                      if (gProofServ)
03646                         gProofServ->SendAsynMessage(msg);
03647                      else
03648                         Printf("%s",msg.Data());
03649                   }
03650                   if (fMergersCount > 0) {
03651 
03652                      fMergers = new TList();
03653                      fLastAssignedMerger = 0;
03654                      // Total number of workers, which will not act as mergers ('pure workers')
03655                      fWorkersToMerge = (activeWorkers - fMergersCount);
03656                      // Establish the first merger
03657                      if (!CreateMerger(sl, merging_port)) {
03658                         // Cannot establish first merger
03659                         AskForOutput(sl);
03660                         fWorkersToMerge--;
03661                         fMergersCount--;
03662                      }
03663                      if (IsLite()) fMergePrg.SetNWrks(fMergersCount);
03664                   } else {
03665                      AskForOutput(sl);
03666                   }
03667                   fMergersSet = kTRUE;
03668                } else {
03669                   // Multiple pass
03670                   if (fMergersCount == -1) {
03671                      // No mergers. Workers send their outputs directly to master
03672                      AskForOutput(sl);
03673                   } else {
03674                      if (fRedirectNext > 0 ) {
03675                         RedirectWorker(s, sl, output_size);
03676                         fRedirectNext--;
03677                      } else {
03678                         if (fMergersCount > fMergers->GetSize()) {
03679                            // Still not enough mergers established
03680                            if (!CreateMerger(sl, merging_port)) {
03681                               // Cannot establish a merger
03682                               AskForOutput(sl);
03683                               fWorkersToMerge--;
03684                               fMergersCount--;
03685                            }
03686                         } else
03687                            RedirectWorker(s, sl, output_size);
03688                      }
03689                   }
03690                }
03691             } else {
03692                Error("HandleSubMerger","kOutputSize received not on endmaster!");
03693             }
03694          }
03695       break;
03696    }
03697 }
03698 
03699 //______________________________________________________________________________
03700 void TProof::RedirectWorker(TSocket *s, TSlave * sl, Int_t output_size)
03701 {
03702    // Redirect output of worker sl to some merger
03703 
03704    Int_t merger_id = FindNextFreeMerger();
03705    if (merger_id == -1) {
03706       // No free merger (probably it had crashed before)
03707       AskForOutput(sl);
03708    } else {
03709       TMessage sendoutput(kPROOF_SUBMERGER);
03710       sendoutput << Int_t(kSendOutput);
03711       PDB(kSubmerger, 2)
03712          Info("RedirectWorker", "redirecting worker %s to merger %d", sl->GetOrdinal(), merger_id);
03713 
03714        PDB(kSubmerger, 2) Info("RedirectWorker", "redirecting output to merger #%d",  merger_id);
03715        if (!fMergers || fMergers->GetSize() <= merger_id) {
03716           Error("RedirectWorker", "#%d not in list ", merger_id);
03717           return;
03718        }
03719        TMergerInfo * mi = (TMergerInfo *) fMergers->At(merger_id);
03720 
03721        TString hname = (IsLite()) ? "localhost" : mi->GetMerger()->GetName();
03722        sendoutput <<  merger_id;
03723        sendoutput << hname;
03724        sendoutput << mi->GetPort();
03725        s->Send(sendoutput);
03726        mi->AddMergedObjects(output_size);
03727        mi->AddWorker(sl);
03728    }
03729 }
03730 
03731 //______________________________________________________________________________
03732 Int_t TProof::FindNextFreeMerger()
03733 {
03734    // Return a merger, which is both active and still accepts some workers to be
03735    // assigned to it. It works on the 'round-robin' basis.
03736 
03737    while (fLastAssignedMerger < fMergers->GetSize() &&
03738          (!((TMergerInfo*)fMergers->At(fLastAssignedMerger))->IsActive() ||
03739            ((TMergerInfo*)fMergers->At(fLastAssignedMerger))->AreAllWorkersAssigned())) {
03740       fLastAssignedMerger++;
03741    }
03742 
03743    if (fLastAssignedMerger == fMergers->GetSize()) {
03744       fLastAssignedMerger = 0;
03745    } else {
03746       return fLastAssignedMerger++;
03747    }
03748 
03749    while (fLastAssignedMerger < fMergers->GetSize() &&
03750          (!((TMergerInfo*)fMergers->At(fLastAssignedMerger))->IsActive() ||
03751            ((TMergerInfo*)fMergers->At(fLastAssignedMerger))->AreAllWorkersAssigned())) {
03752       fLastAssignedMerger++;
03753    }
03754 
03755    if (fLastAssignedMerger == fMergers->GetSize()) {
03756       return -1;
03757    } else {
03758       return fLastAssignedMerger++;
03759    }
03760 }
03761 
03762 //______________________________________________________________________________
03763 void TProof::AskForOutput(TSlave *sl)
03764 {
03765    // Master asks for output from worker sl
03766 
03767    TMessage sendoutput(kPROOF_SUBMERGER);
03768    sendoutput << Int_t(kSendOutput);
03769 
03770    PDB(kSubmerger, 2) Info("AskForOutput",
03771                            "worker %s was asked to send its output to master",
03772                             sl->GetOrdinal());
03773 
03774    sendoutput << -1;
03775    sendoutput << TString("master");
03776    sendoutput << -1;
03777    sl->GetSocket()->Send(sendoutput);
03778    if (IsLite()) fMergePrg.IncreaseNWrks();
03779 }
03780 
03781 //______________________________________________________________________________
03782 void TProof::UpdateDialog()
03783 {
03784    // Final update of the progress dialog
03785 
03786    if (!fPlayer) return;
03787 
03788    // Handle abort ...
03789    if (fPlayer->GetExitStatus() == TVirtualProofPlayer::kAborted) {
03790       if (fSync)
03791          Info("UpdateDialog",
03792               "processing was aborted - %lld events processed",
03793               fPlayer->GetEventsProcessed());
03794 
03795       if (GetRemoteProtocol() > 11) {
03796          // New format
03797          Progress(-1, fPlayer->GetEventsProcessed(), -1, -1., -1., -1., -1.);
03798       } else {
03799          Progress(-1, fPlayer->GetEventsProcessed());
03800       }
03801       Emit("StopProcess(Bool_t)", kTRUE);
03802    }
03803 
03804    // Handle stop ...
03805    if (fPlayer->GetExitStatus() == TVirtualProofPlayer::kStopped) {
03806       if (fSync)
03807          Info("UpdateDialog",
03808               "processing was stopped - %lld events processed",
03809               fPlayer->GetEventsProcessed());
03810 
03811       if (GetRemoteProtocol() > 25) {
03812          // New format
03813          Progress(-1, fPlayer->GetEventsProcessed(), -1, -1., -1., -1., -1., -1, -1, -1.);
03814       } else if (GetRemoteProtocol() > 11) {
03815          Progress(-1, fPlayer->GetEventsProcessed(), -1, -1., -1., -1., -1.);
03816       } else {
03817          Progress(-1, fPlayer->GetEventsProcessed());
03818       }
03819       Emit("StopProcess(Bool_t)", kFALSE);
03820    }
03821 
03822    // Final update of the dialog box
03823    if (GetRemoteProtocol() > 25) {
03824       // New format
03825       EmitVA("Progress(Long64_t,Long64_t,Long64_t,Float_t,Float_t,Float_t,Float_t,Int_t,Int_t,Float_t)",
03826               10, (Long64_t)(-1), (Long64_t)(-1), (Long64_t)(-1),(Float_t)(-1.),(Float_t)(-1.),
03827                   (Float_t)(-1.),(Float_t)(-1.),(Int_t)(-1),(Int_t)(-1),(Float_t)(-1.));
03828    } else if (GetRemoteProtocol() > 11) {
03829       // New format
03830       EmitVA("Progress(Long64_t,Long64_t,Long64_t,Float_t,Float_t,Float_t,Float_t)",
03831                7, (Long64_t)(-1), (Long64_t)(-1), (Long64_t)(-1),
03832                   (Float_t)(-1.),(Float_t)(-1.),(Float_t)(-1.),(Float_t)(-1.));
03833    } else {
03834       EmitVA("Progress(Long64_t,Long64_t)", 2, (Long64_t)(-1), (Long64_t)(-1));
03835    }
03836 }
03837 
03838 //______________________________________________________________________________
03839 void TProof::ActivateAsyncInput()
03840 {
03841    // Activate the a-sync input handler.
03842 
03843    TIter next(fSlaves);
03844    TSlave *sl;
03845 
03846    while ((sl = (TSlave*) next()))
03847       if (sl->GetInputHandler())
03848          sl->GetInputHandler()->Add();
03849 }
03850 
03851 //______________________________________________________________________________
03852 void TProof::DeActivateAsyncInput()
03853 {
03854    // De-activate a-sync input handler.
03855 
03856    TIter next(fSlaves);
03857    TSlave *sl;
03858 
03859    while ((sl = (TSlave*) next()))
03860       if (sl->GetInputHandler())
03861          sl->GetInputHandler()->Remove();
03862 }
03863 
03864 //______________________________________________________________________________
03865 Int_t TProof::GetActiveMergersCount()
03866 {
03867    // Get the active mergers count
03868 
03869    if (!fMergers) return 0;
03870 
03871    Int_t active_mergers = 0;
03872 
03873    TIter mergers(fMergers);
03874    TMergerInfo *mi = 0;
03875    while ((mi = (TMergerInfo *)mergers())) {
03876       if (mi->IsActive()) active_mergers++;
03877    }
03878 
03879    return active_mergers;
03880 }
03881 
03882 //______________________________________________________________________________
03883 Bool_t TProof::CreateMerger(TSlave *sl, Int_t port)
03884 {
03885    // Create a new merger
03886 
03887    PDB(kSubmerger, 2)
03888       Info("CreateMerger", "worker %s will be merger ", sl->GetOrdinal());
03889 
03890    PDB(kSubmerger, 2) Info("CreateMerger","Begin");
03891 
03892    if (port <= 0) {
03893       PDB(kSubmerger,2)
03894          Info("CreateMerger", "cannot create merger on port %d - exit", port);
03895       return kFALSE;
03896    }
03897    Int_t mergersToCreate = fMergersCount - fMergers->GetSize();
03898 
03899    // Number of pure workers, which are not simply divisible by mergers
03900    Int_t rest = fWorkersToMerge % mergersToCreate;
03901 
03902    // We add one more worker for each of the first 'rest' mergers being established
03903    if (rest > 0 && fMergers->GetSize() < rest) {
03904       rest = 1;
03905    } else {
03906       rest = 0;
03907    }
03908 
03909    Int_t workers = (fWorkersToMerge / mergersToCreate) + rest;
03910 
03911    TMergerInfo * merger = new TMergerInfo(sl, port, workers);
03912 
03913    TMessage bemerger(kPROOF_SUBMERGER);
03914    bemerger << Int_t(kBeMerger);
03915    bemerger <<  fMergers->GetSize();
03916    bemerger <<  workers;
03917    sl->GetSocket()->Send(bemerger);
03918 
03919    PDB(kSubmerger,2) Info("CreateMerger",
03920                           "merger #%d (port: %d) for %d workers started",
03921                           fMergers->GetSize(), port, workers);
03922 
03923    fMergers->Add(merger);
03924    fWorkersToMerge = fWorkersToMerge - workers;
03925 
03926    fRedirectNext = workers / 2;
03927 
03928    PDB(kSubmerger, 2) Info("CreateMerger", "exit");
03929    return kTRUE;
03930 }
03931 
03932 //______________________________________________________________________________
03933 void TProof::MarkBad(TSlave *wrk, const char *reason)
03934 {
03935    // Add a bad slave server to the bad slave list and remove it from
03936    // the active list and from the two monitor objects. Assume that the work
03937    // done by this worker was lost and ask packerizer to reassign it.
03938 
03939    R__LOCKGUARD2(fCloseMutex);
03940 
03941 
03942    // We may have been invalidated in the meanwhile: nothing to do in such a case
03943    if (!IsValid()) return;
03944 
03945    if (!wrk) {
03946       Error("MarkBad", "worker instance undefined: protocol error? ");
03947       return;
03948    }
03949 
03950    // Local URL
03951    static TString thisurl;
03952    if (thisurl.IsNull()) {
03953       if (IsMaster()) {
03954          Int_t port = gEnv->GetValue("ProofServ.XpdPort",-1);
03955          thisurl = (port > 0) ? Form("%s:%d", TUrl(gSystem->HostName()).GetHostFQDN(), port)
03956                               : TUrl(gSystem->HostName()).GetHostFQDN();
03957       } else {
03958          thisurl = Form("%s@%s:%d", fUrl.GetUser(), fUrl.GetHost(), fUrl.GetPort());
03959       }
03960    }
03961 
03962    if (!reason || (strcmp(reason, kPROOF_TerminateWorker) && strcmp(reason, kPROOF_WorkerIdleTO))) {
03963       // Message for notification
03964       const char *mastertype = (gProofServ && gProofServ->IsTopMaster()) ? "top master" : "master";
03965       TString src = IsMaster() ? Form("%s at %s", mastertype, thisurl.Data()) : "local session";
03966       TString msg(Form("\n +++ Message from %s : ", src.Data()));
03967       msg += Form("marking %s:%d (%s) as bad\n +++ Reason: %s",
03968                   wrk->GetName(), wrk->GetPort(), wrk->GetOrdinal(),
03969                   (reason && strlen(reason)) ? reason : "unknown");
03970       Info("MarkBad", "%s", msg.Data());
03971       // Notify one level up, if the case
03972       // Add some hint for diagnostics
03973       if (gProofServ) {
03974          msg += Form("\n\n +++ Most likely your code crashed on worker %s at %s:%d.\n",
03975                      wrk->GetOrdinal(), wrk->GetName(), wrk->GetPort());
03976       } else {
03977          msg = Form("\n\n +++ Most likely your code crashed\n");
03978       }
03979       msg += Form(" +++ Please check the session logs for error messages either using\n");
03980       msg += Form(" +++ the 'Show logs' button or executing\n");
03981       msg += Form(" +++\n");
03982       if (gProofServ) {
03983          msg += Form(" +++ root [] TProof::Mgr(\"%s\")->GetSessionLogs()->Display(\"%s\",0)\n\n",
03984                      thisurl.Data(), wrk->GetOrdinal());
03985          gProofServ->SendAsynMessage(msg, kTRUE);
03986       } else {
03987          msg += Form(" +++ root [] TProof::Mgr(\"%s\")->GetSessionLogs()->Display(\"*\")\n\n",
03988                      thisurl.Data());
03989          Printf("%s", msg.Data());
03990       }
03991    } else if (reason) {
03992       if (gDebug > 0 && strcmp(reason, kPROOF_WorkerIdleTO)) {
03993          Info("MarkBad", "worker %s at %s:%d asked to terminate",
03994                          wrk->GetOrdinal(), wrk->GetName(), wrk->GetPort());
03995       }
03996    }
03997 
03998    if (IsMaster() && reason) {
03999       if (strcmp(reason, kPROOF_TerminateWorker)) {
04000          // if the reason was not a planned termination
04001          TList *listOfMissingFiles = 0;
04002          if (!(listOfMissingFiles = (TList *)GetOutput("MissingFiles"))) {
04003             listOfMissingFiles = new TList();
04004             listOfMissingFiles->SetName("MissingFiles");
04005             if (fPlayer)
04006                fPlayer->AddOutputObject(listOfMissingFiles);
04007          }
04008          // If a query is being processed, assume that the work done by
04009          // the worker was lost and needs to be reassigned.
04010          TVirtualPacketizer *packetizer = fPlayer ? fPlayer->GetPacketizer() : 0;
04011          if (packetizer) {
04012             // the worker was lost so do resubmit the packets
04013             packetizer->MarkBad(wrk, 0, &listOfMissingFiles);
04014          }
04015       } else {
04016          // Tell the coordinator that we are gone
04017          if (gProofServ) {
04018             TString ord(wrk->GetOrdinal());
04019             Int_t id = ord.Last('.');
04020             if (id != kNPOS) ord.Remove(0, id+1);
04021             gProofServ->ReleaseWorker(ord.Data());
04022          }
04023       }
04024    } else if (TestBit(TProof::kIsClient) && reason && !strcmp(reason, kPROOF_WorkerIdleTO)) {
04025       // We are invalid after this
04026       fValid = kFALSE;
04027    }
04028 
04029    fActiveSlaves->Remove(wrk);
04030    FindUniqueSlaves();
04031 
04032    fAllMonitor->Remove(wrk->GetSocket());
04033    fActiveMonitor->Remove(wrk->GetSocket());
04034 
04035    fSendGroupView = kTRUE;
04036 
04037    if (IsMaster()) {
04038       if (reason && !strcmp(reason, kPROOF_TerminateWorker)) {
04039          // if the reason was a planned termination then delete the worker and
04040          // remove it from all the lists
04041          fSlaves->Remove(wrk);
04042          fBadSlaves->Remove(wrk);
04043          fActiveSlaves->Remove(wrk);
04044          fInactiveSlaves->Remove(wrk);
04045          fUniqueSlaves->Remove(wrk);
04046          fAllUniqueSlaves->Remove(wrk);
04047          fNonUniqueMasters->Remove(wrk);
04048          delete wrk;
04049       } else {
04050          fBadSlaves->Add(wrk);
04051          fActiveSlaves->Remove(wrk);
04052          fUniqueSlaves->Remove(wrk);
04053          fAllUniqueSlaves->Remove(wrk);
04054          fNonUniqueMasters->Remove(wrk);
04055          if (fCurrentMonitor) fCurrentMonitor->DeActivate(wrk->GetSocket());
04056          wrk->Close();
04057          // Update the mergers count, if needed
04058          if (fMergersSet) {
04059             Int_t mergersCount = -1;
04060             TParameter<Int_t> *mc = dynamic_cast<TParameter<Int_t> *>(GetParameter("PROOF_UseMergers"));
04061             if (mc) mergersCount = mc->GetVal(); // Value set by user
04062             // Mergers count is set dynamically: recalculate it
04063             if (mergersCount == 0) {
04064                Int_t activeWorkers = fCurrentMonitor ? fCurrentMonitor->GetActive() : GetNumberOfActiveSlaves();
04065                if (activeWorkers > 1) {
04066                   fMergersCount = TMath::Nint(TMath::Sqrt(activeWorkers));
04067                   if (activeWorkers / fMergersCount < 2)
04068                      fMergersCount = (Int_t) TMath::Sqrt(activeWorkers);
04069                }
04070             }
04071          }
04072       }
04073 
04074       // Update session workers files
04075       SaveWorkerInfo();
04076    } else {
04077       // On clients the proof session should be removed from the lists
04078       // and deleted, since it is not valid anymore
04079       fSlaves->Remove(wrk);
04080       if (fManager)
04081          fManager->DiscardSession(this);
04082    }
04083 }
04084 
04085 //______________________________________________________________________________
04086 void TProof::MarkBad(TSocket *s, const char *reason)
04087 {
04088    // Add slave with socket s to the bad slave list and remove if from
04089    // the active list and from the two monitor objects.
04090 
04091    R__LOCKGUARD2(fCloseMutex);
04092 
04093    // We may have been invalidated in the meanwhile: nothing to do in such a case
04094    if (!IsValid()) return;
04095 
04096    TSlave *wrk = FindSlave(s);
04097    MarkBad(wrk, reason);
04098 }
04099 
04100 //______________________________________________________________________________
04101 void TProof::TerminateWorker(TSlave *wrk)
04102 {
04103    // Ask an active worker 'wrk' to terminate, i.e. to shutdown
04104 
04105    if (!wrk) {
04106       Warning("TerminateWorker", "worker instance undefined: protocol error? ");
04107       return;
04108    }
04109 
04110    // Send stop message
04111    if (wrk->GetSocket() && wrk->GetSocket()->IsValid()) {
04112       TMessage mess(kPROOF_STOP);
04113       wrk->GetSocket()->Send(mess);
04114    } else {
04115       if (gDebug > 0)
04116          Info("TerminateWorker", "connection to worker is already down: cannot"
04117                                  " send termination message");
04118    }
04119 
04120    // This is a bad worker from now on
04121    MarkBad(wrk, kPROOF_TerminateWorker);
04122 }
04123 
04124 //______________________________________________________________________________
04125 void TProof::TerminateWorker(const char *ord)
04126 {
04127    // Ask an active worker 'ord' to terminate, i.e. to shutdown
04128 
04129    if (ord && strlen(ord) > 0) {
04130       Bool_t all = (ord[0] == '*') ? kTRUE : kFALSE;
04131       if (IsMaster()) {
04132          TIter nxw(fSlaves);
04133          TSlave *wrk = 0;
04134          while ((wrk = (TSlave *)nxw())) {
04135             if (all || !strcmp(wrk->GetOrdinal(), ord)) {
04136                TerminateWorker(wrk);
04137                if (!all) break;
04138             }
04139          }
04140       } else {
04141          TMessage mess(kPROOF_STOP);
04142          mess << TString(ord);
04143          Broadcast(mess);
04144       }
04145    }
04146 }
04147 
04148 //______________________________________________________________________________
04149 Int_t TProof::Ping()
04150 {
04151    // Ping PROOF. Returns 1 if master server responded.
04152 
04153    return Ping(kActive);
04154 }
04155 
04156 //______________________________________________________________________________
04157 Int_t TProof::Ping(ESlaves list)
04158 {
04159    // Ping PROOF slaves. Returns the number of slaves that responded.
04160 
04161    TList *slaves = 0;
04162    if (list == kAll)       slaves = fSlaves;
04163    if (list == kActive)    slaves = fActiveSlaves;
04164    if (list == kUnique)    slaves = fUniqueSlaves;
04165    if (list == kAllUnique) slaves = fAllUniqueSlaves;
04166 
04167    if (slaves->GetSize() == 0) return 0;
04168 
04169    int   nsent = 0;
04170    TIter next(slaves);
04171 
04172    TSlave *sl;
04173    while ((sl = (TSlave *)next())) {
04174       if (sl->IsValid()) {
04175          if (sl->Ping() == -1) {
04176             MarkBad(sl, "ping unsuccessful");
04177          } else {
04178             nsent++;
04179          }
04180       }
04181    }
04182 
04183    return nsent;
04184 }
04185 
04186 //______________________________________________________________________________
04187 void TProof::Touch()
04188 {
04189    // Ping PROOF slaves. Returns the number of slaves that responded.
04190 
04191    TList *slaves = fSlaves;
04192 
04193    if (slaves->GetSize() == 0) return;
04194 
04195    TIter next(slaves);
04196 
04197    TSlave *sl;
04198    while ((sl = (TSlave *)next())) {
04199       if (sl->IsValid()) {
04200          sl->Touch();
04201       }
04202    }
04203 
04204    return;
04205 }
04206 
04207 //______________________________________________________________________________
04208 void TProof::Print(Option_t *option) const
04209 {
04210    // Print status of PROOF cluster.
04211 
04212    TString secCont;
04213 
04214    if (TestBit(TProof::kIsClient)) {
04215       Printf("Connected to:             %s (%s)", GetMaster(),
04216                                              IsValid() ? "valid" : "invalid");
04217       Printf("Port number:              %d", GetPort());
04218       Printf("User:                     %s", GetUser());
04219       if (gROOT->GetSvnRevision() > 0)
04220          Printf("ROOT version|rev:         %s|r%d", gROOT->GetVersion(), gROOT->GetSvnRevision());
04221       else
04222          Printf("ROOT version:             %s", gROOT->GetVersion());
04223       Printf("Architecture-Compiler:    %s-%s", gSystem->GetBuildArch(),
04224                                                 gSystem->GetBuildCompilerVersion());
04225       TSlave *sl = (TSlave *)fActiveSlaves->First();
04226       if (sl) {
04227          TString sc;
04228          if (sl->GetSocket()->GetSecContext())
04229             Printf("Security context:         %s",
04230                                       sl->GetSocket()->GetSecContext()->AsString(sc));
04231          Printf("Proofd protocol version:  %d", sl->GetSocket()->GetRemoteProtocol());
04232       } else {
04233          Printf("Security context:         Error - No connection");
04234          Printf("Proofd protocol version:  Error - No connection");
04235       }
04236       Printf("Client protocol version:  %d", GetClientProtocol());
04237       Printf("Remote protocol version:  %d", GetRemoteProtocol());
04238       Printf("Log level:                %d", GetLogLevel());
04239       Printf("Session unique tag:       %s", IsValid() ? GetSessionTag() : "");
04240       Printf("Default data pool:        %s", IsValid() ? GetDataPoolUrl() : "");
04241       if (IsValid())
04242          const_cast<TProof*>(this)->SendPrint(option);
04243    } else {
04244       const_cast<TProof*>(this)->AskStatistics();
04245       if (IsParallel())
04246          Printf("*** Master server %s (parallel mode, %d workers):",
04247                 gProofServ->GetOrdinal(), GetParallel());
04248       else
04249          Printf("*** Master server %s (sequential mode):",
04250                 gProofServ->GetOrdinal());
04251 
04252       Printf("Master host name:           %s", gSystem->HostName());
04253       Printf("Port number:                %d", GetPort());
04254       if (strlen(gProofServ->GetGroup()) > 0) {
04255          Printf("User/Group:                 %s/%s", GetUser(), gProofServ->GetGroup());
04256       } else {
04257          Printf("User:                       %s", GetUser());
04258       }
04259       TString ver(gROOT->GetVersion());
04260       if (gROOT->GetSvnRevision() > 0)
04261          ver += Form("|r%d", gROOT->GetSvnRevision());
04262       if (gSystem->Getenv("ROOTVERSIONTAG"))
04263          ver += Form("|%s", gSystem->Getenv("ROOTVERSIONTAG"));
04264       Printf("ROOT version|rev|tag:       %s", ver.Data());
04265       Printf("Architecture-Compiler:      %s-%s", gSystem->GetBuildArch(),
04266                                                   gSystem->GetBuildCompilerVersion());
04267       Printf("Protocol version:           %d", GetClientProtocol());
04268       Printf("Image name:                 %s", GetImage());
04269       Printf("Working directory:          %s", gSystem->WorkingDirectory());
04270       Printf("Config directory:           %s", GetConfDir());
04271       Printf("Config file:                %s", GetConfFile());
04272       Printf("Log level:                  %d", GetLogLevel());
04273       Printf("Number of workers:          %d", GetNumberOfSlaves());
04274       Printf("Number of active workers:   %d", GetNumberOfActiveSlaves());
04275       Printf("Number of unique workers:   %d", GetNumberOfUniqueSlaves());
04276       Printf("Number of inactive workers: %d", GetNumberOfInactiveSlaves());
04277       Printf("Number of bad workers:      %d", GetNumberOfBadSlaves());
04278       Printf("Total MB's processed:       %.2f", float(GetBytesRead())/(1024*1024));
04279       Printf("Total real time used (s):   %.3f", GetRealTime());
04280       Printf("Total CPU time used (s):    %.3f", GetCpuTime());
04281       if (TString(option).Contains("a", TString::kIgnoreCase) && GetNumberOfSlaves()) {
04282          Printf("List of workers:");
04283          TList masters;
04284          TIter nextslave(fSlaves);
04285          while (TSlave* sl = dynamic_cast<TSlave*>(nextslave())) {
04286             if (!sl->IsValid()) continue;
04287 
04288             if (sl->GetSlaveType() == TSlave::kSlave) {
04289                sl->Print(option);
04290             } else if (sl->GetSlaveType() == TSlave::kMaster) {
04291                TMessage mess(kPROOF_PRINT);
04292                mess.WriteString(option);
04293                if (sl->GetSocket()->Send(mess) == -1)
04294                   const_cast<TProof*>(this)->MarkBad(sl, "could not send kPROOF_PRINT request");
04295                else
04296                   masters.Add(sl);
04297             } else {
04298                Error("Print", "TSlave is neither Master nor Worker");
04299                R__ASSERT(0);
04300             }
04301          }
04302          const_cast<TProof*>(this)->Collect(&masters, fCollectTimeout);
04303       }
04304    }
04305 }
04306 
04307 //______________________________________________________________________________
04308 Long64_t TProof::Process(TDSet *dset, const char *selector, Option_t *option,
04309                          Long64_t nentries, Long64_t first)
04310 {
04311    // Process a data set (TDSet) using the specified selector (.C) file.
04312    // Entry- or event-lists should be set in the data set object using
04313    // TDSet::SetEntryList.
04314    // The return value is -1 in case of error and TSelector::GetStatus() in
04315    // in case of success.
04316 
04317    if (!IsValid() || !fPlayer) return -1;
04318 
04319    // Set PROOF to running state
04320    SetRunStatus(TProof::kRunning);
04321 
04322    // Resolve query mode
04323    fSync = (GetQueryMode(option) == kSync);
04324 
04325    TString opt(option);
04326    if (fSync && (!IsIdle() || IsWaiting())) {
04327       // Already queued or processing queries: switch to asynchronous mode
04328       Info("Process", "session is in waiting or processing status: switch to asynchronous mode");
04329       fSync = kFALSE;
04330       opt.ReplaceAll("SYNC","");
04331       opt += "ASYN";
04332    }
04333 
04334    // Cleanup old temporary datasets
04335    if ((IsIdle() && !IsWaiting()) && fRunningDSets && fRunningDSets->GetSize() > 0) {
04336       fRunningDSets->SetOwner(kTRUE);
04337       fRunningDSets->Delete();
04338    }
04339 
04340    // deactivate the default application interrupt handler
04341    // ctrl-c's will be forwarded to PROOF to stop the processing
04342    TSignalHandler *sh = 0;
04343    if (fSync) {
04344       if (gApplication)
04345          sh = gSystem->RemoveSignalHandler(gApplication->GetSignalHandler());
04346    }
04347 
04348    Long64_t rv = fPlayer->Process(dset, selector, opt.Data(), nentries, first);
04349 
04350    if (fSync) {
04351       // reactivate the default application interrupt handler
04352       if (sh)
04353          gSystem->AddSignalHandler(sh);
04354    }
04355 
04356    return rv;
04357 }
04358 
04359 //______________________________________________________________________________
04360 Long64_t TProof::Process(TFileCollection *fc, const char *selector,
04361                          Option_t *option, Long64_t nentries, Long64_t first)
04362 {
04363    // Process a data set (TFileCollection) using the specified selector (.C) file.
04364    // The default tree is analyzed (i.e. the first one found). To specify another
04365    // tree, the default tree can be changed using TFileCollection::SetDefaultMetaData .
04366    // The return value is -1 in case of error and TSelector::GetStatus() in
04367    // in case of success.
04368 
04369    if (!IsValid() || !fPlayer) return -1;
04370 
04371    if (fProtocol < 17) {
04372       Info("Process", "server version < 5.18/00:"
04373                       " processing of TFileCollection not supported");
04374       return -1;
04375    }
04376 
04377    // We include the TFileCollection to the input list and we create a
04378    // fake TDSet with infor about it
04379    TDSet *dset = new TDSet(Form("TFileCollection:%s", fc->GetName()), 0, 0, "");
04380    fPlayer->AddInput(fc);
04381    Long64_t retval = Process(dset, selector, option, nentries, first);
04382    fPlayer->GetInputList()->Remove(fc); // To avoid problems in future
04383 
04384    // Cleanup
04385    if (IsLite() && !fSync) {
04386       if (!fRunningDSets) fRunningDSets = new TList;
04387       fRunningDSets->Add(dset);
04388    } else {
04389       delete dset;
04390    }
04391 
04392    return retval;
04393 }
04394 
04395 //______________________________________________________________________________
04396 Long64_t TProof::Process(const char *dsetname, const char *selector,
04397                          Option_t *option, Long64_t nentries,
04398                          Long64_t first, TObject *elist)
04399 {
04400    // Process a dataset which is stored on the master with name 'dsetname'.
04401    // The syntax for dsetname is name[#[dir/]objname], e.g.
04402    //   "mydset"       analysis of the first tree in the top dir of the dataset
04403    //                  named "mydset"
04404    //   "mydset#T"     analysis tree "T" in the top dir of the dataset
04405    //                  named "mydset"
04406    //   "mydset#adir/T" analysis tree "T" in the dir "adir" of the dataset
04407    //                  named "mydset"
04408    //   "mydset#adir/" analysis of the first tree in the dir "adir" of the
04409    //                  dataset named "mydset"
04410    // The component 'name' in its more general form contains also the group and
04411    // user name following "/<group>/<user>/<dsname>". Each of these components
04412    // can contain one or more wildcards '*', in which case all the datasets matching
04413    // the expression are added together as a global dataset (wildcard support has
04414    // been added in version 5.27/02).
04415    // The last argument 'elist' specifies an entry- or event-list to be used as
04416    // event selection.
04417    // It is also possible (starting w/ version 5.27/02) to run on multiple datasets
04418    // at once in a more flexible way that the one provided by wildcarding. There
04419    // are three possibilities:
04420    //    1) specifying the dataset names separated by the OR operator '|', e.g.
04421    //          dsetname = "<dset1>|<dset2>|<dset3>|..."
04422    //       in this case the datasets are a seen as a global unique dataset
04423    //    2) specifying the dataset names separated by a ',' or a ' ', e.g.
04424    //          dsetname = "<dset1>,<dset2> <dset3>,..."
04425    //       in this case the datasets are processed one after the other and the
04426    //       selector is notified when switching dataset via a bit in the current
04427    //       processed element.
04428    //    3) giving the path of a textfile where the dataset names are specified
04429    //       on one or multiple lines; the lines found are joined as in 1), unless
04430    //       the filepath is followed by a ',' (i.e. p->Process("datasets.txt,",...)
04431    //       with the dataset names listed in 'datasets.txt') in which case they are
04432    //       treated as in 2); the file is open in raw mode with TFile::Open and
04433    //       therefore it cane be remote, e.g. on a Web server.
04434    // Each <dsetj> has the format specified above for the single dataset processing,
04435    // included wildcarding (the name of the tree and subdirectory must be same for
04436    // all the datasets).
04437    // In the case of multiple datasets, 'elist' is treated a global entry list.
04438    // It is possible to specify per-dataset entry lists using the syntax
04439    //   "mydset[#adir/[T]]?enl=entrylist"
04440    // or
04441    //   "mydset[#adir/[T]]<<entrylist"
04442    // Here 'entrylist' is a tag identifying, in the order :
04443    //   i. a named entry-list in the input list or in the input data list
04444    //  ii. a named entry-list in memory (in gDirectory)
04445    // iii. the path of a file containing the entry-list to be used
04446    // In the case ii) and iii) the entry-list object(s) is(are) added to the input
04447    // data list.
04448    // The return value is -1 in case of error and TSelector::GetStatus() in
04449    // in case of success.
04450 
04451    if (fProtocol < 13) {
04452       Info("Process", "processing 'by name' not supported by the server");
04453       return -1;
04454    }
04455 
04456    TString dsname, fname(dsetname);
04457    // If the 'dsetname' corresponds to an existing and readable file we will try to
04458    // interpretate its content as names of datasets to be processed. One line can contain
04459    // more datasets, separated by ',' or '|'. By default the dataset lines will be added
04460    // (i.e. joined as in option '|'); if the file name ends with ',' the dataset lines are
04461    // joined with ','.
04462    const char *separator = (fname.EndsWith(",")) ? "," : "|";
04463    if (!strcmp(separator, ",") || fname.EndsWith("|")) fname.Remove(fname.Length()-1, 1);
04464    if (!(gSystem->AccessPathName(fname, kReadPermission))) {
04465       TUrl uf(fname, kTRUE);
04466       uf.SetOptions(TString::Format("%sfiletype=raw", uf.GetOptions()));
04467       TFile *f = TFile::Open(uf.GetUrl());
04468       if (f && !(f->IsZombie())) {
04469          const Int_t blen = 8192;
04470          char buf[blen];
04471          Long64_t rest = f->GetSize();
04472          while (rest > 0) {
04473             Long64_t len = (rest > blen - 1) ? blen - 1 : rest;
04474             if (f->ReadBuffer(buf, len)) {
04475                Error("Process", "problems reading from file '%s'", fname.Data());
04476                dsname = "";
04477                break;
04478             }
04479             buf[len] = '\0';
04480             dsname += buf;
04481             rest -= len;
04482          }
04483          f->Close();
04484          SafeDelete(f);
04485          // We fail if a failure occured
04486          if (rest > 0) return -1;
04487       } else {
04488          Error("Process", "could not open file '%s'", fname.Data());
04489          return -1;
04490       }
04491    }
04492    if (dsname.IsNull()) {
04493       dsname = dsetname;
04494    } else {
04495       // Remove trailing '\n'
04496       if (dsname.EndsWith("\n")) dsname.Remove(dsname.Length()-1, 1);
04497       // Replace all '\n' with the proper separator
04498       dsname.ReplaceAll("\n", separator);
04499       if (gDebug > 0) {
04500          Info("Process", "processing multi-dataset read from file '%s':", fname.Data());
04501          Info("Process", "  '%s'", dsname.Data());
04502       }
04503    }
04504 
04505    TString names(dsname), name, enl, newname;
04506    // If multi-dataset check if server supports it
04507    if (fProtocol < 28 && names.Index(TRegexp("[, |]")) != kNPOS) {
04508       Info("Process", "multi-dataset processing not supported by the server");
04509       return -1;
04510    }
04511 
04512    TEntryList *el = 0;
04513    TString dsobj, dsdir;
04514    Int_t from = 0;
04515    while (names.Tokenize(name, from, "[, |]")) {
04516 
04517       newname = name;
04518       // Extract the specific entry-list, if any
04519       enl = "";
04520       Int_t ienl = name.Index("?enl=");
04521       if (ienl == kNPOS) {
04522          ienl = name.Index("<<");
04523          if (ienl != kNPOS) {
04524             newname.Remove(ienl);
04525             ienl += strlen("<<");
04526          }
04527       } else {
04528          newname.Remove(ienl);
04529          ienl += strlen("?enl=");
04530       }
04531 
04532       // Check the name syntax first
04533       TString obj, dir("/");
04534       Int_t idxc = newname.Index("#");
04535       if (idxc != kNPOS) {
04536          Int_t idxs = newname.Index("/", 1, idxc, TString::kExact);
04537          if (idxs != kNPOS) {
04538             obj = newname(idxs+1, newname.Length());
04539             dir = newname(idxc+1, newname.Length());
04540             dir.Remove(dir.Index("/") + 1);
04541             newname.Remove(idxc);
04542          } else {
04543             obj = newname(idxc+1, newname.Length());
04544             newname.Remove(idxc);
04545          }
04546       } else if (newname.Index(":") != kNPOS && newname.Index("://") == kNPOS) {
04547          // protection against using ':' instead of '#'
04548          Error("Process", "bad name syntax (%s): please use"
04549                           " a '#' after the dataset name", name.Data());
04550          dsname.ReplaceAll(name, "");
04551          continue;
04552       }
04553       if (dsobj.IsNull() && dsdir.IsNull()) {
04554          // The first one specifies obj and dir
04555          dsobj = obj;
04556          dsdir = dir;
04557       } else if (obj != dsobj || dir != dsdir) {
04558          // Inconsistent specification: not supported
04559          Warning("Process", "'obj' or 'dir' specification not consistent w/ the first given: ignore");
04560       }
04561       // Process the entry-list name, if any
04562       if (ienl != kNPOS) {
04563          // Get entrylist name or path
04564          enl = name(ienl, name.Length());
04565          // If not in the input list ...
04566          el = (GetInputList()) ? dynamic_cast<TEntryList *>(GetInputList()->FindObject(enl)) : 0;
04567          // ... check the heap
04568          if (!el && gDirectory) {
04569             if ((el = dynamic_cast<TEntryList *>(gDirectory->FindObject(enl)))) {
04570                // Add to the input list (input data not available on master where
04571                // this info will be processed)
04572                if (fProtocol >= 28) {
04573                   if (!(GetInputList()->FindObject(el->GetName()))) AddInput(el);
04574                }
04575             }
04576          }
04577          // If not in the heap, check a file, if any
04578          if (!el) {
04579             if (!gSystem->AccessPathName(enl)) {
04580                TFile *f = TFile::Open(enl);
04581                if (f && !(f->IsZombie()) && f->GetListOfKeys()) {
04582                   TIter nxk(f->GetListOfKeys());
04583                   TKey *k = 0;
04584                   while ((k = (TKey *) nxk())) {
04585                      if (!strcmp(k->GetClassName(), "TEntryList")) {
04586                         if (!el) {
04587                            if ((el = dynamic_cast<TEntryList *>(f->Get(k->GetName())))) {
04588                               // Add to the input list (input data not available on master where
04589                               // this info will be processed)
04590                               if (fProtocol >= 28) {
04591                                  if (!(GetInputList()->FindObject(el->GetName()))) {
04592                                     el = (TEntryList *) el->Clone();
04593                                     AddInput(el);
04594                                  }
04595                               } else {
04596                                  el = (TEntryList *) el->Clone();
04597                               }
04598                            }
04599                         } else if (strcmp(el->GetName(), k->GetName())) {
04600                            Warning("Process", "multiple entry lists found in file '%s': the first one is taken;\n"
04601                                               "if this is not what you want, load first the content in memory"
04602                                               "and select it by name  ", enl.Data());
04603                         }
04604                      }
04605                   }
04606                } else {
04607                   Warning("Process","file '%s' cannot be open or is empty - ignoring", enl.Data());
04608                }
04609             }
04610          }
04611          // Transmit the information
04612          if (fProtocol >= 28) {
04613             newname += "?enl=";
04614             if (el) {
04615                // An entry list object is avalaible in the input list: add its name
04616                newname += el->GetName();
04617             } else {
04618                // The entry list object was not found: send the name, the future entry list manager will
04619                // find it on the server side
04620                newname += enl;
04621             }
04622          }
04623       }
04624       // Adjust the name for this dataset
04625       dsname.ReplaceAll(name, newname);
04626    }
04627 
04628    // Create the dataset object
04629    TDSet *dset = new TDSet(dsname, dsobj, dsdir);
04630    // Set entry list
04631    if (el && fProtocol < 28) {
04632       dset->SetEntryList(el);
04633    } else {
04634       dset->SetEntryList(elist);
04635    }
04636    // Run
04637    Long64_t retval = Process(dset, selector, option, nentries, first);
04638    // Cleanup
04639    if (IsLite() && !fSync) {
04640       if (!fRunningDSets) fRunningDSets = new TList;
04641       fRunningDSets->Add(dset);
04642    } else {
04643       delete dset;
04644    }
04645    return retval;
04646 }
04647 
04648 //______________________________________________________________________________
04649 Long64_t TProof::Process(const char *selector, Long64_t n, Option_t *option)
04650 {
04651    // Generic (non-data based) selector processing: the Process() method of the
04652    // specified selector (.C) is called 'n' times.
04653    // The return value is -1 in case of error and TSelector::GetStatus() in
04654    // in case of success.
04655 
04656    if (!IsValid()) return -1;
04657 
04658    if (fProtocol < 16) {
04659       Info("Process", "server version < 5.17/04: generic processing not supported");
04660       return -1;
04661    }
04662 
04663    // Fake data set
04664    TDSet *dset = new TDSet;
04665    dset->SetBit(TDSet::kEmpty);
04666 
04667    Long64_t retval = Process(dset, selector, option, n);
04668 
04669    // Cleanup
04670    if (IsLite() && !fSync) {
04671       if (!fRunningDSets) fRunningDSets = new TList;
04672       fRunningDSets->Add(dset);
04673    } else {
04674       delete dset;
04675    }
04676    return retval;
04677 }
04678 
04679 //______________________________________________________________________________
04680 Int_t TProof::GetQueryReference(Int_t qry, TString &ref)
04681 {
04682    // Get reference for the qry-th query in fQueries (as
04683    // displayed by ShowQueries).
04684 
04685    ref = "";
04686    if (qry > 0) {
04687       if (!fQueries)
04688          GetListOfQueries();
04689       if (fQueries) {
04690          TIter nxq(fQueries);
04691          TQueryResult *qr = 0;
04692          while ((qr = (TQueryResult *) nxq()))
04693             if (qr->GetSeqNum() == qry) {
04694                ref = Form("%s:%s", qr->GetTitle(), qr->GetName());
04695                return 0;
04696             }
04697       }
04698    }
04699    return -1;
04700 }
04701 
04702 //______________________________________________________________________________
04703 Long64_t TProof::Finalize(Int_t qry, Bool_t force)
04704 {
04705    // Finalize the qry-th query in fQueries.
04706    // If force, force retrieval if the query is found in the local list
04707    // but has already been finalized (default kFALSE).
04708    // If query < 0, finalize current query.
04709    // Return 0 on success, -1 on error
04710 
04711    if (fPlayer) {
04712       if (qry > 0) {
04713          TString ref;
04714          if (GetQueryReference(qry, ref) == 0) {
04715             return Finalize(ref, force);
04716          } else {
04717             Info("Finalize", "query #%d not found", qry);
04718          }
04719       } else {
04720          // The last query
04721          return Finalize("", force);
04722       }
04723    }
04724    return -1;
04725 }
04726 
04727 //______________________________________________________________________________
04728 Long64_t TProof::Finalize(const char *ref, Bool_t force)
04729 {
04730    // Finalize query with reference ref.
04731    // If force, force retrieval if the query is found in the local list
04732    // but has already been finalized (default kFALSE).
04733    // If ref = 0, finalize current query.
04734    // Return 0 on success, -1 on error
04735 
04736    if (fPlayer) {
04737       // Get the pointer to the query
04738       TQueryResult *qr = (ref && strlen(ref) > 0) ? fPlayer->GetQueryResult(ref)
04739                                                   : GetQueryResult();
04740       Bool_t retrieve = kFALSE;
04741       TString xref(ref);
04742       if (!qr) {
04743          if (!xref.IsNull()) {
04744             retrieve =  kTRUE;
04745          }
04746       } else {
04747          if (qr->IsFinalized()) {
04748             if (force) {
04749                retrieve = kTRUE;
04750             } else {
04751                Info("Finalize","query already finalized:"
04752                      " use Finalize(<qry>,kTRUE) to force new retrieval");
04753                qr = 0;
04754             }
04755          } else {
04756             retrieve = kTRUE;
04757             xref.Form("%s:%s", qr->GetTitle(), qr->GetName());
04758          }
04759       }
04760       if (retrieve) {
04761          Retrieve(xref.Data());
04762          qr = fPlayer->GetQueryResult(xref.Data());
04763       }
04764       if (qr)
04765          return fPlayer->Finalize(qr);
04766    }
04767    return -1;
04768 }
04769 
04770 //______________________________________________________________________________
04771 Int_t TProof::Retrieve(Int_t qry, const char *path)
04772 {
04773    // Send retrieve request for the qry-th query in fQueries.
04774    // If path is defined save it to path.
04775 
04776    if (qry > 0) {
04777       TString ref;
04778       if (GetQueryReference(qry, ref) == 0)
04779          return Retrieve(ref, path);
04780       else
04781          Info("Retrieve", "query #%d not found", qry);
04782    } else {
04783       Info("Retrieve","positive argument required - do nothing");
04784    }
04785    return -1;
04786 }
04787 
04788 //______________________________________________________________________________
04789 Int_t TProof::Retrieve(const char *ref, const char *path)
04790 {
04791    // Send retrieve request for the query specified by ref.
04792    // If path is defined save it to path.
04793    // Generic method working for all queries known by the server.
04794 
04795    if (ref) {
04796       TMessage m(kPROOF_RETRIEVE);
04797       m << TString(ref);
04798       Broadcast(m, kActive);
04799       Collect(kActive, fCollectTimeout);
04800 
04801       // Archive it locally, if required
04802       if (path) {
04803 
04804          // Get pointer to query
04805          TQueryResult *qr = fPlayer ? fPlayer->GetQueryResult(ref) : 0;
04806 
04807          if (qr) {
04808 
04809             TFile *farc = TFile::Open(path,"UPDATE");
04810             if (!(farc->IsOpen())) {
04811                Info("Retrieve", "archive file cannot be open (%s)", path);
04812                return 0;
04813             }
04814             farc->cd();
04815 
04816             // Update query status
04817             qr->SetArchived(path);
04818 
04819             // Write to file
04820             qr->Write();
04821 
04822             farc->Close();
04823             SafeDelete(farc);
04824 
04825          } else {
04826             Info("Retrieve", "query not found after retrieve");
04827             return -1;
04828          }
04829       }
04830 
04831       return 0;
04832    }
04833    return -1;
04834 }
04835 
04836 //______________________________________________________________________________
04837 Int_t TProof::Remove(Int_t qry, Bool_t all)
04838 {
04839    // Send remove request for the qry-th query in fQueries.
04840 
04841    if (qry > 0) {
04842       TString ref;
04843       if (GetQueryReference(qry, ref) == 0)
04844          return Remove(ref, all);
04845       else
04846          Info("Remove", "query #%d not found", qry);
04847    } else {
04848       Info("Remove","positive argument required - do nothing");
04849    }
04850    return -1;
04851 }
04852 
04853 //______________________________________________________________________________
04854 Int_t TProof::Remove(const char *ref, Bool_t all)
04855 {
04856    // Send remove request for the query specified by ref.
04857    // If all = TRUE remove also local copies of the query, if any.
04858    // Generic method working for all queries known by the server.
04859    // This method can be also used to reset the list of queries
04860    // waiting to be processed: for that purpose use ref == "cleanupqueue".
04861 
04862    if (all) {
04863       // Remove also local copies, if any
04864       if (fPlayer)
04865          fPlayer->RemoveQueryResult(ref);
04866    }
04867 
04868    if (IsLite()) return 0;
04869 
04870    if (ref) {
04871       TMessage m(kPROOF_REMOVE);
04872       m << TString(ref);
04873       Broadcast(m, kActive);
04874       Collect(kActive, fCollectTimeout);
04875       return 0;
04876    }
04877    return -1;
04878 }
04879 
04880 //______________________________________________________________________________
04881 Int_t TProof::Archive(Int_t qry, const char *path)
04882 {
04883    // Send archive request for the qry-th query in fQueries.
04884 
04885    if (qry > 0) {
04886       TString ref;
04887       if (GetQueryReference(qry, ref) == 0)
04888          return Archive(ref, path);
04889       else
04890          Info("Archive", "query #%d not found", qry);
04891    } else {
04892       Info("Archive","positive argument required - do nothing");
04893    }
04894    return -1;
04895 }
04896 
04897 //______________________________________________________________________________
04898 Int_t TProof::Archive(const char *ref, const char *path)
04899 {
04900    // Send archive request for the query specified by ref.
04901    // Generic method working for all queries known by the server.
04902    // If ref == "Default", path is understood as a default path for
04903    // archiving.
04904 
04905    if (ref) {
04906       TMessage m(kPROOF_ARCHIVE);
04907       m << TString(ref) << TString(path);
04908       Broadcast(m, kActive);
04909       Collect(kActive, fCollectTimeout);
04910       return 0;
04911    }
04912    return -1;
04913 }
04914 
04915 //______________________________________________________________________________
04916 Int_t TProof::CleanupSession(const char *sessiontag)
04917 {
04918    // Send cleanup request for the session specified by tag.
04919 
04920    if (sessiontag) {
04921       TMessage m(kPROOF_CLEANUPSESSION);
04922       m << TString(sessiontag);
04923       Broadcast(m, kActive);
04924       Collect(kActive, fCollectTimeout);
04925       return 0;
04926    }
04927    return -1;
04928 }
04929 
04930 //_____________________________________________________________________________
04931 void TProof::SetQueryMode(EQueryMode mode)
04932 {
04933    // Change query running mode to the one specified by 'mode'.
04934 
04935    fQueryMode = mode;
04936 
04937    if (gDebug > 0)
04938       Info("SetQueryMode","query mode is set to: %s", fQueryMode == kSync ?
04939            "Sync" : "Async");
04940 }
04941 
04942 //______________________________________________________________________________
04943 TProof::EQueryMode TProof::GetQueryMode(Option_t *mode) const
04944 {
04945    // Find out the query mode based on the current setting and 'mode'.
04946 
04947    EQueryMode qmode = fQueryMode;
04948 
04949    if (mode && (strlen(mode) > 0)) {
04950       TString m(mode);
04951       m.ToUpper();
04952       if (m.Contains("ASYN")) {
04953          qmode = kAsync;
04954       } else if (m.Contains("SYNC")) {
04955          qmode = kSync;
04956       }
04957    }
04958 
04959    if (gDebug > 0)
04960       Info("GetQueryMode","query mode is set to: %s", qmode == kSync ?
04961            "Sync" : "Async");
04962 
04963    return qmode;
04964 }
04965 
04966 //______________________________________________________________________________
04967 Long64_t TProof::DrawSelect(TDSet *dset, const char *varexp,
04968                             const char *selection, Option_t *option,
04969                             Long64_t nentries, Long64_t first)
04970 {
04971    // Execute the specified drawing action on a data set (TDSet).
04972    // Event- or Entry-lists should be set in the data set object using
04973    // TDSet::SetEntryList.
04974    // Returns -1 in case of error or number of selected events otherwise.
04975 
04976    if (!IsValid() || !fPlayer) return -1;
04977 
04978    // Make sure that asynchronous processing is not active
04979    if (!IsIdle()) {
04980       Info("DrawSelect","not idle, asynchronous Draw not supported");
04981       return -1;
04982    }
04983    TString opt(option);
04984    Int_t idx = opt.Index("ASYN", 0, TString::kIgnoreCase);
04985    if (idx != kNPOS)
04986       opt.Replace(idx,4,"");
04987 
04988    return fPlayer->DrawSelect(dset, varexp, selection, opt, nentries, first);
04989 }
04990 
04991 //______________________________________________________________________________
04992 Long64_t TProof::DrawSelect(const char *dsetname, const char *varexp,
04993                             const char *selection, Option_t *option,
04994                             Long64_t nentries, Long64_t first, TObject *enl)
04995 {
04996    // Execute the specified drawing action on a data set which is stored on the
04997    // master with name 'dsetname'.
04998    // The syntax for dsetname is name[#[dir/]objname], e.g.
04999    //   "mydset"       analysis of the first tree in the top dir of the dataset
05000    //                  named "mydset"
05001    //   "mydset#T"     analysis tree "T" in the top dir of the dataset
05002    //                  named "mydset"
05003    //   "mydset#adir/T" analysis tree "T" in the dir "adir" of the dataset
05004    //                  named "mydset"
05005    //   "mydset#adir/" analysis of the first tree in the dir "adir" of the
05006    //                  dataset named "mydset"
05007    // The last argument 'enl' specifies an entry- or event-list to be used as
05008    // event selection.
05009    // The return value is -1 in case of error and TSelector::GetStatus() in
05010    // in case of success.
05011 
05012    if (fProtocol < 13) {
05013       Info("Process", "processing 'by name' not supported by the server");
05014       return -1;
05015    }
05016 
05017    TString name(dsetname);
05018    TString obj;
05019    TString dir = "/";
05020    Int_t idxc = name.Index("#");
05021    if (idxc != kNPOS) {
05022       Int_t idxs = name.Index("/", 1, idxc, TString::kExact);
05023       if (idxs != kNPOS) {
05024          obj = name(idxs+1, name.Length());
05025          dir = name(idxc+1, name.Length());
05026          dir.Remove(dir.Index("/") + 1);
05027          name.Remove(idxc);
05028       } else {
05029          obj = name(idxc+1, name.Length());
05030          name.Remove(idxc);
05031       }
05032    } else if (name.Index(":") != kNPOS && name.Index("://") == kNPOS) {
05033       // protection against using ':' instead of '#'
05034       Error("DrawSelect", "bad name syntax (%s): please use"
05035                        " a '#' after the dataset name", dsetname);
05036       return -1;
05037    }
05038 
05039    TDSet *dset = new TDSet(name, obj, dir);
05040    // Set entry-list, if required
05041    dset->SetEntryList(enl);
05042    Long64_t retval = DrawSelect(dset, varexp, selection, option, nentries, first);
05043    delete dset;
05044    return retval;
05045 }
05046 
05047 //______________________________________________________________________________
05048 void TProof::StopProcess(Bool_t abort, Int_t timeout)
05049 {
05050    // Send STOPPROCESS message to master and workers.
05051 
05052    PDB(kGlobal,2)
05053       Info("StopProcess","enter %d", abort);
05054 
05055    if (!IsValid())
05056       return;
05057 
05058    // Flag that we have been stopped
05059    ERunStatus rst = abort ? TProof::kAborted : TProof::kStopped;
05060    SetRunStatus(rst);
05061 
05062    if (fPlayer)
05063       fPlayer->StopProcess(abort, timeout);
05064 
05065    // Stop any blocking 'Collect' request; on masters we do this only if
05066    // aborting; when stopping, we still need to receive the results
05067    if (TestBit(TProof::kIsClient) || abort)
05068       InterruptCurrentMonitor();
05069 
05070    if (fSlaves->GetSize() == 0)
05071       return;
05072 
05073    // Notify the remote counterpart
05074    TSlave *sl;
05075    TIter   next(fSlaves);
05076    while ((sl = (TSlave *)next()))
05077       if (sl->IsValid())
05078          // Ask slave to progate the stop/abort request
05079          sl->StopProcess(abort, timeout);
05080 }
05081 
05082 //______________________________________________________________________________
05083 void TProof::DisableGoAsyn()
05084 {
05085    // Signal to disable related switches
05086 
05087    Emit("DisableGoAsyn()");
05088 }
05089 
05090 //______________________________________________________________________________
05091 void TProof::GoAsynchronous()
05092 {
05093    // Send GOASYNC message to the master.
05094 
05095    if (!IsValid()) return;
05096 
05097    if (GetRemoteProtocol() < 22) {
05098       Info("GoAsynchronous", "functionality not supported by the server - ignoring");
05099       return;
05100    }
05101 
05102    if (fSync && !IsIdle()) {
05103       TMessage m(kPROOF_GOASYNC);
05104       Broadcast(m);
05105    } else {
05106       Info("GoAsynchronous", "either idle or already in asynchronous mode - ignoring");
05107    }
05108 }
05109 
05110 //______________________________________________________________________________
05111 void TProof::RecvLogFile(TSocket *s, Int_t size)
05112 {
05113    // Receive the log file of the slave with socket s.
05114 
05115    const Int_t kMAXBUF = 16384;  //32768  //16384  //65536;
05116    char buf[kMAXBUF];
05117 
05118    // Append messages to active logging unit
05119    Int_t fdout = -1;
05120    if (!fLogToWindowOnly) {
05121       fdout = (fRedirLog) ? fileno(fLogFileW) : fileno(stdout);
05122       if (fdout < 0) {
05123          Warning("RecvLogFile", "file descriptor for outputs undefined (%d):"
05124                  " will not log msgs", fdout);
05125          return;
05126       }
05127       lseek(fdout, (off_t) 0, SEEK_END);
05128    }
05129 
05130    Int_t  left, rec, r;
05131    Long_t filesize = 0;
05132 
05133    while (filesize < size) {
05134       left = Int_t(size - filesize);
05135       if (left >= kMAXBUF)
05136          left = kMAXBUF-1;
05137       rec = s->RecvRaw(&buf, left);
05138       filesize = (rec > 0) ? (filesize + rec) : filesize;
05139       if (!fLogToWindowOnly) {
05140          if (rec > 0) {
05141 
05142             char *p = buf;
05143             r = rec;
05144             while (r) {
05145                Int_t w;
05146 
05147                w = write(fdout, p, r);
05148 
05149                if (w < 0) {
05150                   SysError("RecvLogFile", "error writing to unit: %d", fdout);
05151                   break;
05152                }
05153                r -= w;
05154                p += w;
05155             }
05156          } else if (rec < 0) {
05157             Error("RecvLogFile", "error during receiving log file");
05158             break;
05159          }
05160       }
05161       if (rec > 0) {
05162          buf[rec] = 0;
05163          EmitVA("LogMessage(const char*,Bool_t)", 2, buf, kFALSE);
05164       }
05165    }
05166 
05167    // If idle restore logs to main session window
05168    if (fRedirLog && IsIdle() && !TestBit(TProof::kIsMaster))
05169       fRedirLog = kFALSE;
05170 }
05171 
05172 //______________________________________________________________________________
05173 void TProof::NotifyLogMsg(const char *msg, const char *sfx)
05174 {
05175    // Notify locally 'msg' to the appropriate units (file, stdout, window)
05176    // If defined, 'sfx' is added after 'msg' (typically a line-feed);
05177 
05178    // Must have somenthing to notify
05179    Int_t len = 0;
05180    if (!msg || (len = strlen(msg)) <= 0)
05181       return;
05182 
05183    // Get suffix length if any
05184    Int_t lsfx = (sfx) ? strlen(sfx) : 0;
05185 
05186    // Append messages to active logging unit
05187    Int_t fdout = -1;
05188    if (!fLogToWindowOnly) {
05189       fdout = (fRedirLog) ? fileno(fLogFileW) : fileno(stdout);
05190       if (fdout < 0) {
05191          Warning("NotifyLogMsg", "file descriptor for outputs undefined (%d):"
05192                  " will not notify msgs", fdout);
05193          return;
05194       }
05195       lseek(fdout, (off_t) 0, SEEK_END);
05196    }
05197 
05198    if (!fLogToWindowOnly) {
05199       // Write to output unit (stdout or a log file)
05200       if (len > 0) {
05201          char *p = (char *)msg;
05202          Int_t r = len;
05203          while (r) {
05204             Int_t w = write(fdout, p, r);
05205             if (w < 0) {
05206                SysError("NotifyLogMsg", "error writing to unit: %d", fdout);
05207                break;
05208             }
05209             r -= w;
05210             p += w;
05211          }
05212          // Add a suffix, if requested
05213          if (lsfx > 0)
05214             if (write(fdout, sfx, lsfx) != lsfx)
05215                SysError("NotifyLogMsg", "error writing to unit: %d", fdout);
05216       }
05217    }
05218    if (len > 0) {
05219       // Publish the message to the separate window (if the latter is missing
05220       // the message will just get lost)
05221       EmitVA("LogMessage(const char*,Bool_t)", 2, msg, kFALSE);
05222    }
05223 
05224    // If idle restore logs to main session window
05225    if (fRedirLog && IsIdle())
05226       fRedirLog = kFALSE;
05227 }
05228 
05229 //______________________________________________________________________________
05230 void TProof::LogMessage(const char *msg, Bool_t all)
05231 {
05232    // Log a message into the appropriate window by emitting a signal.
05233 
05234    PDB(kGlobal,1)
05235       Info("LogMessage","Enter ... %s, 'all: %s", msg ? msg : "",
05236            all ? "true" : "false");
05237 
05238    if (gROOT->IsBatch()) {
05239       PDB(kGlobal,1) Info("LogMessage","GUI not started - use TProof::ShowLog()");
05240       return;
05241    }
05242 
05243    if (msg)
05244       EmitVA("LogMessage(const char*,Bool_t)", 2, msg, all);
05245 
05246    // Re-position at the beginning of the file, if requested.
05247    // This is used by the dialog when it re-opens the log window to
05248    // provide all the session messages
05249    if (all)
05250       lseek(fileno(fLogFileR), (off_t) 0, SEEK_SET);
05251 
05252    const Int_t kMAXBUF = 32768;
05253    char buf[kMAXBUF];
05254    Int_t len;
05255    do {
05256       while ((len = read(fileno(fLogFileR), buf, kMAXBUF-1)) < 0 &&
05257              TSystem::GetErrno() == EINTR)
05258          TSystem::ResetErrno();
05259 
05260       if (len < 0) {
05261          Error("LogMessage", "error reading log file");
05262          break;
05263       }
05264 
05265       if (len > 0) {
05266          buf[len] = 0;
05267          EmitVA("LogMessage(const char*,Bool_t)", 2, buf, kFALSE);
05268       }
05269 
05270    } while (len > 0);
05271 }
05272 
05273 //______________________________________________________________________________
05274 Int_t TProof::SendGroupView()
05275 {
05276    // Send to all active slaves servers the current slave group size
05277    // and their unique id. Returns number of active slaves.
05278    // Returns -1 in case of error.
05279 
05280    if (!IsValid()) return -1;
05281    if (TestBit(TProof::kIsClient)) return 0;
05282    if (!fSendGroupView) return 0;
05283    fSendGroupView = kFALSE;
05284 
05285    TIter   next(fActiveSlaves);
05286    TSlave *sl;
05287 
05288    int  bad = 0, cnt = 0, size = GetNumberOfActiveSlaves();
05289    char str[32];
05290 
05291    while ((sl = (TSlave *)next())) {
05292       snprintf(str, 32, "%d %d", cnt, size);
05293       if (sl->GetSocket()->Send(str, kPROOF_GROUPVIEW) == -1) {
05294          MarkBad(sl, "could not send kPROOF_GROUPVIEW message");
05295          bad++;
05296       } else
05297          cnt++;
05298    }
05299 
05300    // Send the group view again in case there was a change in the
05301    // group size due to a bad slave
05302 
05303    if (bad) SendGroupView();
05304 
05305    return GetNumberOfActiveSlaves();
05306 }
05307 
05308 //______________________________________________________________________________
05309 Bool_t TProof::GetFileInCmd(const char *cmd, TString &fn)
05310 {
05311    // Static method to extract the filename (if any) form a CINT command.
05312    // Returns kTRUE and the filename in 'fn'; returns kFALSE if not found or not
05313    // appliable.
05314 
05315    TString s = cmd;
05316    s = s.Strip(TString::kBoth);
05317 
05318    if (s.Length() > 0 &&
05319       (s.BeginsWith(".L") || s.BeginsWith(".x") || s.BeginsWith(".X"))) {
05320       TString file = s(2, s.Length());
05321       TString acm, arg, io;
05322       fn = gSystem->SplitAclicMode(file, acm, arg, io);
05323       if (!fn.IsNull())
05324          return kTRUE;
05325    }
05326 
05327    // Not found
05328    return kFALSE;
05329 }
05330 
05331 //______________________________________________________________________________
05332 Int_t TProof::Exec(const char *cmd, Bool_t plusMaster)
05333 {
05334    // Send command to be executed on the PROOF master and/or slaves.
05335    // If plusMaster is kTRUE then exeucte on slaves and master too.
05336    // Command can be any legal command line command. Commands like
05337    // ".x file.C" or ".L file.C" will cause the file file.C to be send
05338    // to the PROOF cluster. Returns -1 in case of error, >=0 in case of
05339    // succes.
05340 
05341    return Exec(cmd, kActive, plusMaster);
05342 }
05343 
05344 //______________________________________________________________________________
05345 Int_t TProof::Exec(const char *cmd, ESlaves list, Bool_t plusMaster)
05346 {
05347    // Send command to be executed on the PROOF master and/or slaves.
05348    // Command can be any legal command line command. Commands like
05349    // ".x file.C" or ".L file.C" will cause the file file.C to be send
05350    // to the PROOF cluster. Returns -1 in case of error, >=0 in case of
05351    // succes.
05352 
05353    if (!IsValid()) return -1;
05354 
05355    TString s = cmd;
05356    s = s.Strip(TString::kBoth);
05357 
05358    if (!s.Length()) return 0;
05359 
05360    // check for macro file and make sure the file is available on all slaves
05361    TString filename;
05362    if (TProof::GetFileInCmd(s.Data(), filename)) {
05363       char *fn = gSystem->Which(TROOT::GetMacroPath(), filename, kReadPermission);
05364       if (fn) {
05365          if (GetNumberOfUniqueSlaves() > 0) {
05366             if (SendFile(fn, kAscii | kForward | kCpBin) < 0) {
05367                Error("Exec", "file %s could not be transfered", fn);
05368                delete [] fn;
05369                return -1;
05370             }
05371          } else {
05372             TString scmd = s(0,3) + fn;
05373             Int_t n = SendCommand(scmd, list);
05374             delete [] fn;
05375             return n;
05376          }
05377       } else {
05378          Error("Exec", "macro %s not found", filename.Data());
05379          return -1;
05380       }
05381       delete [] fn;
05382    }
05383 
05384    if (plusMaster) {
05385       if (IsLite()) {
05386          gROOT->ProcessLine(cmd);
05387       } else {
05388          Int_t n = GetParallel();
05389          SetParallelSilent(0);
05390          Int_t res = SendCommand(cmd, list);
05391          SetParallelSilent(n);
05392          if (res < 0)
05393             return res;
05394       }
05395    }
05396    return SendCommand(cmd, list);
05397 }
05398 
05399 //______________________________________________________________________________
05400 Int_t TProof::SendCommand(const char *cmd, ESlaves list)
05401 {
05402    // Send command to be executed on the PROOF master and/or slaves.
05403    // Command can be any legal command line command, however commands
05404    // like ".x file.C" or ".L file.C" will not cause the file.C to be
05405    // transfered to the PROOF cluster. In that case use TProof::Exec().
05406    // Returns the status send by the remote server as part of the
05407    // kPROOF_LOGDONE message. Typically this is the return code of the
05408    // command on the remote side. Returns -1 in case of error.
05409 
05410    if (!IsValid()) return -1;
05411 
05412    Broadcast(cmd, kMESS_CINT, list);
05413    Collect(list);
05414 
05415    return fStatus;
05416 }
05417 
05418 //______________________________________________________________________________
05419 Int_t TProof::SendCurrentState(ESlaves list)
05420 {
05421    // Transfer the current state of the master to the active slave servers.
05422    // The current state includes: the current working directory, etc.
05423    // Returns the number of active slaves. Returns -1 in case of error.
05424 
05425    if (!IsValid()) return -1;
05426 
05427    // Go to the new directory, reset the interpreter environment and
05428    // tell slave to delete all objects from its new current directory.
05429    Broadcast(gDirectory->GetPath(), kPROOF_RESET, list);
05430 
05431    return GetParallel();
05432 }
05433 
05434 //______________________________________________________________________________
05435 Int_t TProof::SendInitialState()
05436 {
05437    // Transfer the initial (i.e. current) state of the master to all
05438    // slave servers. Currently the initial state includes: log level.
05439    // Returns the number of active slaves. Returns -1 in case of error.
05440 
05441    if (!IsValid()) return -1;
05442 
05443    SetLogLevel(fLogLevel, gProofDebugMask);
05444 
05445    return GetNumberOfActiveSlaves();
05446 }
05447 
05448 //______________________________________________________________________________
05449 Bool_t TProof::CheckFile(const char *file, TSlave *slave, Long_t modtime, Int_t cpopt)
05450 {
05451    // Check if a file needs to be send to the slave. Use the following
05452    // algorithm:
05453    //   - check if file appears in file map
05454    //     - if yes, get file's modtime and check against time in map,
05455    //       if modtime not same get md5 and compare against md5 in map,
05456    //       if not same return kTRUE.
05457    //     - if no, get file's md5 and modtime and store in file map, ask
05458    //       slave if file exists with specific md5, if yes return kFALSE,
05459    //       if no return kTRUE.
05460    // The options 'cpopt' define if to copy things from cache to sandbox and what.
05461    // To retrieve from the cache the binaries associated with the file TProof::kCpBin
05462    // must be set in cpopt; the default is copy everything.
05463    // Returns kTRUE in case file needs to be send, returns kFALSE in case
05464    // file is already on remote node.
05465 
05466    Bool_t sendto = kFALSE;
05467 
05468    // create worker based filename
05469    TString sn = slave->GetName();
05470    sn += ":";
05471    sn += slave->GetOrdinal();
05472    sn += ":";
05473    sn += gSystem->BaseName(file);
05474 
05475    // check if file is in map
05476    FileMap_t::const_iterator it;
05477    if ((it = fFileMap.find(sn)) != fFileMap.end()) {
05478       // file in map
05479       MD5Mod_t md = (*it).second;
05480       if (md.fModtime != modtime) {
05481          TMD5 *md5 = TMD5::FileChecksum(file);
05482          if (md5) {
05483             if ((*md5) != md.fMD5) {
05484                sendto       = kTRUE;
05485                md.fMD5      = *md5;
05486                md.fModtime  = modtime;
05487                fFileMap[sn] = md;
05488                // When on the master, the master and/or slaves may share
05489                // their file systems and cache. Therefore always make a
05490                // check for the file. If the file already exists with the
05491                // expected md5 the kPROOF_CHECKFILE command will cause the
05492                // file to be copied from cache to slave sandbox.
05493                if (TestBit(TProof::kIsMaster)) {
05494                   sendto = kFALSE;
05495                   TMessage mess(kPROOF_CHECKFILE);
05496                   mess << TString(gSystem->BaseName(file)) << md.fMD5 << cpopt;
05497                   slave->GetSocket()->Send(mess);
05498 
05499                   fCheckFileStatus = 0;
05500                   Collect(slave, fCollectTimeout, kPROOF_CHECKFILE);
05501                   sendto = (fCheckFileStatus == 0) ? kTRUE : kFALSE;
05502                }
05503             }
05504             delete md5;
05505          } else {
05506             Error("CheckFile", "could not calculate local MD5 check sum - dont send");
05507             return kFALSE;
05508          }
05509       }
05510    } else {
05511       // file not in map
05512       TMD5 *md5 = TMD5::FileChecksum(file);
05513       MD5Mod_t md;
05514       if (md5) {
05515          md.fMD5      = *md5;
05516          md.fModtime  = modtime;
05517          fFileMap[sn] = md;
05518          delete md5;
05519       } else {
05520          Error("CheckFile", "could not calculate local MD5 check sum - dont send");
05521          return kFALSE;
05522       }
05523       TMessage mess(kPROOF_CHECKFILE);
05524       mess << TString(gSystem->BaseName(file)) << md.fMD5 << cpopt;
05525       slave->GetSocket()->Send(mess);
05526 
05527       fCheckFileStatus = 0;
05528       Collect(slave, fCollectTimeout, kPROOF_CHECKFILE);
05529       sendto = (fCheckFileStatus == 0) ? kTRUE : kFALSE;
05530    }
05531 
05532    return sendto;
05533 }
05534 
05535 //______________________________________________________________________________
05536 Int_t TProof::SendFile(const char *file, Int_t opt, const char *rfile, TSlave *wrk)
05537 {
05538    // Send a file to master or slave servers. Returns number of slaves
05539    // the file was sent to, maybe 0 in case master and slaves have the same
05540    // file system image, -1 in case of error.
05541    // If defined, send to worker 'wrk' only.
05542    // If defined, the full path of the remote path will be rfile.
05543    // If rfile = "cache" the file is copied to the remote cache instead of the sandbox
05544    // (to copy to the cache on a different name use rfile = "cache:newname").
05545    // The mask 'opt' is an or of ESendFileOpt:
05546    //
05547    //       kAscii  (0x0)      if set true ascii file transfer is used
05548    //       kBinary (0x1)      if set true binary file transfer is used
05549    //       kForce  (0x2)      if not set an attempt is done to find out
05550    //                          whether the file really needs to be downloaded
05551    //                          (a valid copy may already exist in the cache
05552    //                          from a previous run); the bit is set by
05553    //                          UploadPackage, since the check is done elsewhere.
05554    //       kForward (0x4)     if set, ask server to forward the file to slave
05555    //                          or submaster (meaningless for slave servers).
05556    //       kCpBin   (0x8)     Retrieve from the cache the binaries associated
05557    //                          with the file
05558    //       kCp      (0x10)    Retrieve the files from the cache
05559    //
05560 
05561    if (!IsValid()) return -1;
05562 
05563    // Use the active slaves list ...
05564    TList *slaves = (rfile && !strcmp(rfile, "cache")) ? fUniqueSlaves : fActiveSlaves;
05565    // ... or the specified slave, if any
05566    if (wrk) {
05567       slaves = new TList();
05568       slaves->Add(wrk);
05569    }
05570 
05571    if (slaves->GetSize() == 0) return 0;
05572 
05573 #ifndef R__WIN32
05574    Int_t fd = open(file, O_RDONLY);
05575 #else
05576    Int_t fd = open(file, O_RDONLY | O_BINARY);
05577 #endif
05578    if (fd < 0) {
05579       SysError("SendFile", "cannot open file %s", file);
05580       return -1;
05581    }
05582 
05583    // Get info about the file
05584    Long64_t size;
05585    Long_t id, flags, modtime;
05586    if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 1) {
05587       Error("SendFile", "cannot stat file %s", file);
05588       return -1;
05589    }
05590    if (size == 0) {
05591       Error("SendFile", "empty file %s", file);
05592       return -1;
05593    }
05594 
05595    // Decode options
05596    Bool_t bin   = (opt & kBinary)  ? kTRUE : kFALSE;
05597    Bool_t force = (opt & kForce)   ? kTRUE : kFALSE;
05598    Bool_t fw    = (opt & kForward) ? kTRUE : kFALSE;
05599 
05600    // Copy options
05601    Int_t cpopt  = 0;
05602    if ((opt & kCp)) cpopt |= kCp;
05603    if ((opt & kCpBin)) cpopt |= (kCp | kCpBin);
05604 
05605    const Int_t kMAXBUF = 32768;  //16384  //65536;
05606    char buf[kMAXBUF];
05607    Int_t nsl = 0;
05608 
05609    TIter next(slaves);
05610    TSlave *sl;
05611    TString fnam(rfile);
05612    if (fnam == "cache") {
05613       fnam += Form(":%s", gSystem->BaseName(file));
05614    } else if (fnam.IsNull()) {
05615       fnam = gSystem->BaseName(file);
05616    }
05617    // List on which we will collect the results
05618    while ((sl = (TSlave *)next())) {
05619       if (!sl->IsValid())
05620          continue;
05621 
05622       Bool_t sendto = force ? kTRUE : CheckFile(file, sl, modtime, cpopt);
05623       // Don't send the kPROOF_SENDFILE command to real slaves when sendto
05624       // is false. Masters might still need to send the file to newly added
05625       // slaves.
05626       PDB(kPackage,2) {
05627          const char *snd = (sl->fSlaveType == TSlave::kSlave && sendto) ? "" : "not";
05628          Info("SendFile", "%s sending file %s to: %s:%s (%d)", snd,
05629                     file, sl->GetName(), sl->GetOrdinal(), sendto);
05630       }
05631       if (sl->fSlaveType == TSlave::kSlave && !sendto)
05632          continue;
05633       // The value of 'size' is used as flag remotely, so we need to
05634       // reset it to 0 if we are not going to send the file
05635       Long64_t siz = sendto ? size : 0;
05636       snprintf(buf, kMAXBUF, "%s %d %lld %d", fnam.Data(), bin, siz, fw);
05637       if (sl->GetSocket()->Send(buf, kPROOF_SENDFILE) == -1) {
05638          MarkBad(sl, "could not send kPROOF_SENDFILE request");
05639          continue;
05640       }
05641 
05642       if (sendto) {
05643 
05644          lseek(fd, 0, SEEK_SET);
05645 
05646          Int_t len;
05647          do {
05648             while ((len = read(fd, buf, kMAXBUF)) < 0 && TSystem::GetErrno() == EINTR)
05649                TSystem::ResetErrno();
05650 
05651             if (len < 0) {
05652                SysError("SendFile", "error reading from file %s", file);
05653                Interrupt(kSoftInterrupt, kActive);
05654                close(fd);
05655                return -1;
05656             }
05657 
05658             if (len > 0 && sl->GetSocket()->SendRaw(buf, len) == -1) {
05659                SysError("SendFile", "error writing to slave %s:%s (now offline)",
05660                         sl->GetName(), sl->GetOrdinal());
05661                MarkBad(sl, "sendraw failure");
05662                sl = 0;
05663                break;
05664             }
05665 
05666          } while (len > 0);
05667 
05668          nsl++;
05669       }
05670       // Wait for the operation to be done
05671       if (sl)
05672          Collect(sl, fCollectTimeout, kPROOF_SENDFILE);
05673    }
05674 
05675    close(fd);
05676 
05677    // Cleanup temporary list, if any
05678    if (slaves != fActiveSlaves && slaves != fUniqueSlaves)
05679       SafeDelete(slaves);
05680 
05681    return nsl;
05682 }
05683 
05684 //______________________________________________________________________________
05685 Int_t TProof::SendObject(const TObject *obj, ESlaves list)
05686 {
05687    // Send object to master or slave servers. Returns number of slaves object
05688    // was sent to, -1 in case of error.
05689 
05690    if (!IsValid() || !obj) return -1;
05691 
05692    TMessage mess(kMESS_OBJECT);
05693 
05694    mess.WriteObject(obj);
05695    return Broadcast(mess, list);
05696 }
05697 
05698 //______________________________________________________________________________
05699 Int_t TProof::SendPrint(Option_t *option)
05700 {
05701    // Send print command to master server. Returns number of slaves message
05702    // was sent to. Returns -1 in case of error.
05703 
05704    if (!IsValid()) return -1;
05705 
05706    Broadcast(option, kPROOF_PRINT, kActive);
05707    return Collect(kActive, fCollectTimeout);
05708 }
05709 
05710 //______________________________________________________________________________
05711 void TProof::SetLogLevel(Int_t level, UInt_t mask)
05712 {
05713    // Set server logging level.
05714 
05715    char str[32];
05716    fLogLevel        = level;
05717    gProofDebugLevel = level;
05718    gProofDebugMask  = (TProofDebug::EProofDebugMask) mask;
05719    snprintf(str, 32, "%d %u", level, mask);
05720    Broadcast(str, kPROOF_LOGLEVEL, kAll);
05721 }
05722 
05723 //______________________________________________________________________________
05724 void TProof::SetRealTimeLog(Bool_t on)
05725 {
05726    // Switch ON/OFF the real-time logging facility. When this option is
05727    // ON, log messages from processing are sent back as they come, instead of
05728    // being sent back at the end in one go. This may help debugging or monitoring
05729    // in some cases, but, depending on the amount of log, it may have significant
05730    // consequencies on the load over the network, so it must be used with care.
05731 
05732    if (IsValid()) {
05733       TMessage mess(kPROOF_REALTIMELOG);
05734       mess << on;
05735       Broadcast(mess);
05736    } else {
05737       Warning("SetRealTimeLog","session is invalid - do nothing");
05738    }
05739 }
05740 
05741 //______________________________________________________________________________
05742 Int_t TProof::SetParallelSilent(Int_t nodes, Bool_t random)
05743 {
05744    // Tell PROOF how many slaves to use in parallel. If random is TRUE a random
05745    // selection is done (if nodes is less than the available nodes).
05746    // Returns the number of parallel slaves. Returns -1 in case of error.
05747 
05748    if (!IsValid()) return -1;
05749 
05750    if (TestBit(TProof::kIsMaster)) {
05751       GoParallel(nodes, kFALSE, random);
05752       return SendCurrentState();
05753    } else {
05754       PDB(kGlobal,1) Info("SetParallelSilent", "request %d node%s", nodes,
05755           nodes == 1 ? "" : "s");
05756       TMessage mess(kPROOF_PARALLEL);
05757       mess << nodes << random;
05758       Broadcast(mess);
05759       Collect(kActive, fCollectTimeout);
05760       Int_t n = GetParallel();
05761       PDB(kGlobal,1) Info("SetParallelSilent", "got %d node%s", n, n == 1 ? "" : "s");
05762       return n;
05763    }
05764 }
05765 
05766 //______________________________________________________________________________
05767 Int_t TProof::SetParallel(Int_t nodes, Bool_t random)
05768 {
05769    // Tell PROOF how many slaves to use in parallel. Returns the number of
05770    // parallel slaves. Returns -1 in case of error.
05771 
05772    Int_t n = SetParallelSilent(nodes, random);
05773    if (TestBit(TProof::kIsClient)) {
05774       if (n < 1) {
05775          Printf("PROOF set to sequential mode");
05776       } else {
05777          TString subfix = (n == 1) ? "" : "s";
05778          if (random)
05779             subfix += ", randomly selected";
05780          Printf("PROOF set to parallel mode (%d worker%s)", n, subfix.Data());
05781       }
05782    }
05783    return n;
05784 }
05785 
05786 //______________________________________________________________________________
05787 Int_t TProof::GoParallel(Int_t nodes, Bool_t attach, Bool_t random)
05788 {
05789    // Go in parallel mode with at most "nodes" slaves. Since the fSlaves
05790    // list is sorted by slave performace the active list will contain first
05791    // the most performant nodes. Returns the number of active slaves.
05792    // If random is TRUE, and nodes is less than the number of available workers,
05793    // a random selection is done.
05794    // Returns -1 in case of error.
05795 
05796    if (!IsValid()) return -1;
05797 
05798    if (nodes < 0) nodes = 0;
05799 
05800    fActiveSlaves->Clear();
05801    fActiveMonitor->RemoveAll();
05802 
05803    // Prepare the list of candidates first.
05804    // Algorithm depends on random option.
05805    TSlave *sl = 0;
05806    TList *wlst = new TList;
05807    TIter nxt(fSlaves);
05808    fInactiveSlaves->Clear();
05809    while ((sl = (TSlave *)nxt())) {
05810       if (sl->IsValid() && !fBadSlaves->FindObject(sl)) {
05811          if (strcmp("IGNORE", sl->GetImage()) == 0) continue;
05812          if ((sl->GetSlaveType() != TSlave::kSlave) &&
05813              (sl->GetSlaveType() != TSlave::kMaster)) {
05814             Error("GoParallel", "TSlave is neither Master nor Slave");
05815             R__ASSERT(0);
05816          }
05817          // Good candidate
05818          wlst->Add(sl);
05819          // Set it inactive
05820          fInactiveSlaves->Add(sl);
05821          sl->SetStatus(TSlave::kInactive);
05822       }
05823    }
05824    Int_t nwrks = (nodes > wlst->GetSize()) ? wlst->GetSize() : nodes;
05825    int cnt = 0;
05826    fEndMaster = TestBit(TProof::kIsMaster) ? kTRUE : kFALSE;
05827    while (cnt < nwrks) {
05828       // Random choice, if requested
05829       if (random) {
05830          Int_t iwrk = (Int_t) (gRandom->Rndm() * wlst->GetSize());
05831          sl = (TSlave *) wlst->At(iwrk);
05832       } else {
05833          // The first available
05834          sl = (TSlave *) wlst->First();
05835       }
05836       if (!sl) {
05837          Error("GoParallel", "attaching to candidate!");
05838          break;
05839       }
05840       // Remove from the list
05841       wlst->Remove(sl);
05842 
05843       Int_t slavenodes = 0;
05844       if (sl->GetSlaveType() == TSlave::kSlave) {
05845          sl->SetStatus(TSlave::kActive);
05846          fActiveSlaves->Add(sl);
05847          fInactiveSlaves->Remove(sl);
05848          fActiveMonitor->Add(sl->GetSocket());
05849          slavenodes = 1;
05850       } else if (sl->GetSlaveType() == TSlave::kMaster) {
05851          fEndMaster = kFALSE;
05852          TMessage mess(kPROOF_PARALLEL);
05853          if (!attach) {
05854             mess << nodes-cnt;
05855          } else {
05856             // To get the number of slaves
05857             mess.SetWhat(kPROOF_LOGFILE);
05858             mess << -1 << -1;
05859          }
05860          if (sl->GetSocket()->Send(mess) == -1) {
05861             MarkBad(sl, "could not send kPROOF_PARALLEL or kPROOF_LOGFILE request");
05862             slavenodes = 0;
05863          } else {
05864             Collect(sl, fCollectTimeout);
05865             if (sl->IsValid()) {
05866                sl->SetStatus(TSlave::kActive);
05867                fActiveSlaves->Add(sl);
05868                fInactiveSlaves->Remove(sl);
05869                fActiveMonitor->Add(sl->GetSocket());
05870                if (sl->GetParallel() > 0) {
05871                   slavenodes = sl->GetParallel();
05872                } else {
05873                   // Sequential mode: the master acts as a worker
05874                   slavenodes = 1;
05875                }
05876             } else {
05877                MarkBad(sl, "collect failed after kPROOF_PARALLEL or kPROOF_LOGFILE request");
05878                slavenodes = 0;
05879             }
05880          }
05881       }
05882       // 'slavenodes' may be different than 1 in multimaster setups
05883       cnt += slavenodes;
05884    }
05885 
05886    // Cleanup list
05887    wlst->SetOwner(0);
05888    SafeDelete(wlst);
05889 
05890    // Get slave status (will set the slaves fWorkDir correctly)
05891    AskStatistics();
05892 
05893    // Find active slaves with unique image
05894    FindUniqueSlaves();
05895 
05896    // Send new group-view to slaves
05897    if (!attach)
05898       SendGroupView();
05899 
05900    Int_t n = GetParallel();
05901 
05902    if (TestBit(TProof::kIsClient)) {
05903       if (n < 1)
05904          printf("PROOF set to sequential mode\n");
05905       else
05906          printf("PROOF set to parallel mode (%d worker%s)\n",
05907                 n, n == 1 ? "" : "s");
05908    }
05909 
05910    PDB(kGlobal,1) Info("GoParallel", "got %d node%s", n, n == 1 ? "" : "s");
05911    return n;
05912 }
05913 
05914 //______________________________________________________________________________
05915 void TProof::ShowData()
05916 {
05917    // List contents of the data directory in the sandbox.
05918    // This is the place where files produced by the client queries are kept
05919 
05920    if (!IsValid() || !fManager) return;
05921 
05922    // This is run via the manager
05923    fManager->Find("~/data", "-type f", "all");
05924 }
05925 
05926 //______________________________________________________________________________
05927 void TProof::ClearData(UInt_t what, const char *dsname)
05928 {
05929    // Remove files for the data directory.
05930    // The option 'what' can take the values:
05931    //     kPurge                 remove all files and directories under '~/data'
05932    //     kUnregistered          remove only files not in registered datasets (default)
05933    //     kDataset               remove files belonging to dataset 'dsname'
05934    // User is prompt for confirmation, unless kForceClear is ORed with the option
05935 
05936    if (!IsValid() || !fManager) return;
05937 
05938    // Check whether we need to prompt
05939    TString prompt, a("Y");
05940    Bool_t force = (what & kForceClear) ? kTRUE : kFALSE;
05941    Bool_t doask = (!force && isatty(0) != 0 && isatty(1) != 0) ? kTRUE : kFALSE;
05942 
05943    // If all just send the request
05944    if ((what & TProof::kPurge)) {
05945       // Prompt, if requested
05946       if (doask && !Prompt("Do you really want to remove all data files")) return;
05947       if (fManager->Rm("~/data/*", "-rf", "all") < 0)
05948          Warning("ClearData", "problems purging data directory");
05949       return;
05950    } else if ((what & TProof::kDataset)) {
05951       // We must have got a name
05952       if (!dsname || strlen(dsname) <= 0) {
05953          Error("ClearData", "dataset name mandatory when removing a full dataset");
05954          return;
05955       }
05956       // Check if the dataset is registered
05957       if (!ExistsDataSet(dsname)) {
05958          Error("ClearData", "dataset '%s' does not exists", dsname);
05959          return;
05960       }
05961       // Get the file content
05962       TFileCollection *fc = GetDataSet(dsname);
05963       if (!fc) {
05964          Error("ClearData", "could not retrieve info about dataset '%s'", dsname);
05965          return;
05966       }
05967       // Prompt, if requested
05968       if (doask && !Prompt(TString::Format("Do you really want to remove all data files"
05969                                            " of dataset '%s'", dsname))) return;
05970       // Loop through the files
05971       Bool_t rmds = kTRUE;
05972       TIter nxf(fc->GetList());
05973       TFileInfo *fi = 0;
05974       Int_t rfiles = 0, nfiles = fc->GetList()->GetSize();
05975       while ((fi = (TFileInfo *) nxf())) {
05976          // Fill the host info
05977          TString host, file;
05978          // Take info from the current url
05979          TUrl uf(*(fi->GetFirstUrl()));
05980          file = uf.GetFile();
05981          host = uf.GetHost();
05982          // Now search for any "file:" url
05983          Int_t nurl = fi->GetNUrls();
05984          fi->ResetUrl();
05985          TUrl *up = 0;
05986          while (nurl-- && fi->NextUrl()) {
05987             up = fi->GetCurrentUrl();
05988             if (!strcmp(up->GetProtocol(), "file")) {
05989                TString opt(up->GetOptions());
05990                if (opt.BeginsWith("node=")) {
05991                   host=opt;
05992                   host.ReplaceAll("node=","");
05993                   file = up->GetFile();
05994                   break;
05995                }
05996             }
05997          }
05998          // Issue a remove request now
05999          if (fManager->Rm(file.Data(), "-f", host.Data()) != 0) {
06000             Error("ClearData", "problems removing '%s'", file.Data());
06001             // Some files not removed: keep the meta info about this dataset
06002             rmds = kFALSE;
06003          }
06004          rfiles++;
06005          ClearDataProgress(rfiles, nfiles);
06006       }
06007       fprintf(stderr, "\n");
06008       if (rmds) {
06009          // All files were removed successfully: remove also the dataset meta info
06010          RemoveDataSet(dsname);
06011       }
06012    } else if (what & TProof::kUnregistered) {
06013 
06014       // Get the existing files
06015       TString outtmp("ProofClearData_");
06016       FILE *ftmp = gSystem->TempFileName(outtmp);
06017       if (!ftmp) {
06018          Error("ClearData", "cannot create temp file for logs");
06019          return;
06020       }
06021       fclose(ftmp);
06022       RedirectHandle_t h;
06023       gSystem->RedirectOutput(outtmp.Data(), "w", &h);
06024       ShowData();
06025       gSystem->RedirectOutput(0, 0, &h);
06026       // Parse the output file now
06027       ifstream in;
06028       in.open(outtmp.Data());
06029       if (!in.is_open()) {
06030          Error("ClearData", "could not open temp file for logs: %s", outtmp.Data());
06031          gSystem->Unlink(outtmp);
06032          return;
06033       }
06034       // Go through
06035       Int_t nfiles = 0;
06036       TMap *afmap = new TMap;
06037       TString line, host, file;
06038       Int_t from = 0;
06039       while (in.good()) {
06040          line.ReadLine(in);
06041          if (line.IsNull()) continue;
06042          while (line.EndsWith("\n")) { line.Strip(TString::kTrailing, '\n'); }
06043          from = 0;
06044          if (line.Tokenize(host, from, "| ")) line.Tokenize(file, from, "| ");
06045          if (!host.IsNull() && !file.IsNull()) {
06046             TList *fl = (TList *) afmap->GetValue(host.Data());
06047             if (!fl) {
06048                fl = new TList();
06049                fl->SetName(host);
06050                afmap->Add(new TObjString(host), fl);
06051             }
06052             fl->Add(new TObjString(file));
06053             nfiles++;
06054             PDB(kDataset,2)
06055                Info("ClearData", "added info for: h:%s, f:%s", host.Data(), file.Data());
06056          } else {
06057             Warning("ClearData", "found incomplete line: '%s'", line.Data());
06058          }
06059       }
06060       // Close and remove the file
06061       in.close();
06062       gSystem->Unlink(outtmp);
06063 
06064       // Get registered data files
06065       TString sel = TString::Format("/%s/%s/", GetGroup(), GetUser());
06066       TMap *fcmap = GetDataSets(sel);
06067       if (!fcmap || (fcmap && fcmap->GetSize() <= 0)) {
06068          PDB(kDataset,1)
06069          Warning("ClearData", "no dataset beloning to '%s'", sel.Data());
06070          SafeDelete(fcmap);
06071       }
06072 
06073       // Go thorugh and prepare the lists per node
06074       TString opt;
06075       TObjString *os = 0;
06076       if (fcmap) {
06077          TIter nxfc(fcmap);
06078          while ((os = (TObjString *) nxfc())) {
06079             TFileCollection *fc = 0;
06080             if ((fc = (TFileCollection *) fcmap->GetValue(os))) {
06081                TFileInfo *fi = 0;
06082                TIter nxfi(fc->GetList());
06083                while ((fi = (TFileInfo *) nxfi())) {
06084                   // Get special "file:" url
06085                   fi->ResetUrl();
06086                   Int_t nurl = fi->GetNUrls();
06087                   TUrl *up = 0;
06088                   while (nurl-- && fi->NextUrl()) {
06089                      up = fi->GetCurrentUrl();
06090                      if (!strcmp(up->GetProtocol(), "file")) {
06091                         opt = up->GetOptions();
06092                         if (opt.BeginsWith("node=")) {
06093                            host=opt;
06094                            host.ReplaceAll("node=","");
06095                            file = up->GetFile();
06096                            PDB(kDataset,2)
06097                               Info("ClearData", "found: host: %s, file: %s", host.Data(), file.Data());
06098                            // Remove this from the full list, if there
06099                            TList *fl = (TList *) afmap->GetValue(host.Data());
06100                            if (fl) {
06101                               TObjString *fn = (TObjString *) fl->FindObject(file.Data());
06102                               if (fn) {
06103                                  fl->Remove(fn);
06104                                  SafeDelete(fn);
06105                                  nfiles--;
06106                               } else {
06107                                  Warning("ClearData",
06108                                        "registered file '%s' not found in the full list!", file.Data());
06109                               }
06110                            }
06111                            break;
06112                         }
06113                      }
06114                   }
06115                }
06116             }
06117          }
06118          // Clean up the the received map
06119          if (fcmap) fcmap->SetOwner(kTRUE);
06120          SafeDelete(fcmap);
06121       }
06122       // List of the files to be removed
06123       Info("ClearData", "%d unregistered files to be removed:", nfiles);
06124       afmap->Print();
06125       // Prompt, if requested
06126       if (doask && !Prompt(TString::Format("Do you really want to remove all %d"
06127                                            " unregistered data files", nfiles))) return;
06128       // Remove one by one; we may implement a bloc remove in the future
06129       Int_t rfiles = 0;
06130       TIter nxls(afmap);
06131       while ((os = (TObjString *) nxls())) {
06132          TList *fl = 0;
06133          if ((fl = (TList *) afmap->GetValue(os))) {
06134             TIter nxf(fl);
06135             TObjString *fn = 0;
06136             while ((fn = (TObjString *) nxf())) {
06137                // Issue a remove request now
06138                if (fManager->Rm(fn->GetName(), "-f", os->GetName()) != 0) {
06139                   Error("ClearData", "problems removing '%s' on host '%s'", fn->GetName(), os->GetName());
06140                }
06141                rfiles++;
06142                ClearDataProgress(rfiles, nfiles);
06143             }
06144          }
06145       }
06146       fprintf(stderr, "\n");
06147       // Final cleanup
06148       afmap->SetOwner(kTRUE);
06149       SafeDelete(afmap);
06150    }
06151 }
06152 
06153 //______________________________________________________________________________
06154 Bool_t TProof::Prompt(const char *p)
06155 {
06156    // Prompt the question 'p' requiring an answer y,Y,n,N
06157    // Return kTRUE is the answer was y or Y, kFALSE in all other cases.
06158 
06159    TString pp(p);
06160    if (!pp.Contains("?")) pp += "?";
06161    if (!pp.Contains("[y/N]")) pp += " [y/N]";
06162    TString a = Getline(pp.Data());
06163    if (a != "\n" && a[0] != 'y' &&  a[0] != 'Y' &&  a[0] != 'n' &&  a[0] != 'N') {
06164       Printf("Please answer y, Y, n or N");
06165       // Unclear answer: assume negative
06166       return kFALSE;
06167    } else if (a == "\n" || a[0] == 'n' ||  a[0] == 'N') {
06168       // Explicitly Negative answer
06169       return kFALSE;
06170    }
06171    // Explicitly Positive answer
06172    return kTRUE;
06173 }
06174 
06175 //______________________________________________________________________________
06176 void TProof::ClearDataProgress(Int_t r, Int_t t)
06177 {
06178    // Progress bar for clear data
06179 
06180    fprintf(stderr, "[TProof::ClearData] Total %5d files\t|", t);
06181    for (Int_t l = 0; l < 20; l++) {
06182       if (r > 0 && t > 0) {
06183          if (l < 20*r/t)
06184             fprintf(stderr, "=");
06185          else if (l == 20*r/t)
06186             fprintf(stderr, ">");
06187          else if (l > 20*r/t)
06188             fprintf(stderr, ".");
06189       } else
06190          fprintf(stderr, "=");
06191    }
06192    fprintf(stderr, "| %.02f %%      \r", 100.0*(t ? (r/t) : 1));
06193 }
06194 
06195 //______________________________________________________________________________
06196 void TProof::ShowCache(Bool_t all)
06197 {
06198    // List contents of file cache. If all is true show all caches also on
06199    // slaves. If everything is ok all caches are to be the same.
06200 
06201    if (!IsValid()) return;
06202 
06203    TMessage mess(kPROOF_CACHE);
06204    mess << Int_t(kShowCache) << all;
06205    Broadcast(mess, kUnique);
06206 
06207    if (all) {
06208       TMessage mess2(kPROOF_CACHE);
06209       mess2 << Int_t(kShowSubCache) << all;
06210       Broadcast(mess2, fNonUniqueMasters);
06211 
06212       Collect(kAllUnique, fCollectTimeout);
06213    } else {
06214       Collect(kUnique, fCollectTimeout);
06215    }
06216 }
06217 
06218 //______________________________________________________________________________
06219 void TProof::ClearCache(const char *file)
06220 {
06221    // Remove file from all file caches. If file is 0 or "" or "*", remove all
06222    // the files
06223 
06224    if (!IsValid()) return;
06225 
06226    TMessage mess(kPROOF_CACHE);
06227    mess << Int_t(kClearCache) << TString(file);
06228    Broadcast(mess, kUnique);
06229 
06230    TMessage mess2(kPROOF_CACHE);
06231    mess2 << Int_t(kClearSubCache) << TString(file);
06232    Broadcast(mess2, fNonUniqueMasters);
06233 
06234    Collect(kAllUnique);
06235 
06236    // clear file map so files get send again to remote nodes
06237    fFileMap.clear();
06238 }
06239 
06240 //______________________________________________________________________________
06241 void TProof::SystemCmd(const char *cmd, Int_t fdout)
06242 {
06243    // Exec system command 'cmd'. If fdout > -1, append the output to fdout.
06244 
06245    if (fdout < 0) {
06246       // Exec directly the command
06247       gSystem->Exec(cmd);
06248    } else {
06249       // Exec via a pipe
06250       FILE *fin = gSystem->OpenPipe(cmd, "r");
06251       if (fin) {
06252          // Now we go
06253          char line[2048];
06254          while (fgets(line, 2048, fin)) {
06255             Int_t r = strlen(line);
06256             if (r > 0) {
06257                if (write(fdout, line, r) < 0) {
06258                   ::Warning("TProof::SystemCmd",
06259                             "errno %d writing to file descriptor %d",
06260                             TSystem::GetErrno(), fdout);
06261                }
06262             } else {
06263                // Done
06264                break;
06265             }
06266          }
06267          gSystem->ClosePipe(fin);
06268       }
06269    }
06270 }
06271 
06272 //______________________________________________________________________________
06273 void TProof::ShowPackages(Bool_t all, Bool_t redirlog)
06274 {
06275    // List contents of package directory. If all is true show all package
06276    // directories also on slaves. If everything is ok all package directories
06277    // should be the same. If redir is kTRUE the result is redirected to the log
06278    // file (option available for internal actions).
06279 
06280    if (!IsValid()) return;
06281 
06282    Bool_t oldredir = fRedirLog;
06283    if (redirlog) fRedirLog = kTRUE;
06284 
06285    // Active logging unit
06286    FILE *fout = (fRedirLog) ? fLogFileW : stdout;
06287    if (!fout) {
06288       Warning("ShowPackages", "file descriptor for outputs undefined (%p):"
06289               " will not log msgs", fout);
06290       return;
06291    }
06292    lseek(fileno(fout), (off_t) 0, SEEK_END);
06293 
06294    if (TestBit(TProof::kIsClient)) {
06295       if (fGlobalPackageDirList && fGlobalPackageDirList->GetSize() > 0) {
06296          // Scan the list of global packages dirs
06297          TIter nxd(fGlobalPackageDirList);
06298          TNamed *nm = 0;
06299          while ((nm = (TNamed *)nxd())) {
06300             fprintf(fout, "*** Global Package cache %s client:%s ***\n",
06301                            nm->GetName(), nm->GetTitle());
06302             fflush(fout);
06303             SystemCmd(Form("%s %s", kLS, nm->GetTitle()), fileno(fout));
06304             fprintf(fout, "\n");
06305             fflush(fout);
06306          }
06307       }
06308       fprintf(fout, "*** Package cache client:%s ***\n", fPackageDir.Data());
06309       fflush(fout);
06310       SystemCmd(Form("%s %s", kLS, fPackageDir.Data()), fileno(fout));
06311       fprintf(fout, "\n");
06312    }
06313 
06314    // Nothing more to do if we are a Lite-session
06315    if (IsLite()) {
06316       fRedirLog = oldredir;
06317       return;
06318    }
06319 
06320    TMessage mess(kPROOF_CACHE);
06321    mess << Int_t(kShowPackages) << all;
06322    Broadcast(mess, kUnique);
06323 
06324    if (all) {
06325       TMessage mess2(kPROOF_CACHE);
06326       mess2 << Int_t(kShowSubPackages) << all;
06327       Broadcast(mess2, fNonUniqueMasters);
06328 
06329       Collect(kAllUnique, fCollectTimeout);
06330    } else {
06331       Collect(kUnique, fCollectTimeout);
06332    }
06333    // Restore logging option
06334    fRedirLog = oldredir;
06335 }
06336 
06337 //______________________________________________________________________________
06338 void TProof::ShowEnabledPackages(Bool_t all)
06339 {
06340    // List which packages are enabled. If all is true show enabled packages
06341    // for all active slaves. If everything is ok all active slaves should
06342    // have the same packages enabled.
06343 
06344    if (!IsValid()) return;
06345 
06346    if (TestBit(TProof::kIsClient)) {
06347       printf("*** Enabled packages on client on %s\n", gSystem->HostName());
06348       TIter next(fEnabledPackagesOnClient);
06349       while (TObjString *str = (TObjString*) next())
06350          printf("%s\n", str->GetName());
06351    }
06352 
06353    // Nothing more to do if we are a Lite-session
06354    if (IsLite()) return;
06355 
06356    TMessage mess(kPROOF_CACHE);
06357    mess << Int_t(kShowEnabledPackages) << all;
06358    Broadcast(mess);
06359    Collect(kActive, fCollectTimeout);
06360 }
06361 
06362 //______________________________________________________________________________
06363 Int_t TProof::ClearPackages()
06364 {
06365    // Remove all packages.
06366    // Returns 0 in case of success and -1 in case of error.
06367 
06368    if (!IsValid()) return -1;
06369 
06370    if (UnloadPackages() == -1)
06371       return -1;
06372 
06373    if (DisablePackages() == -1)
06374       return -1;
06375 
06376    return fStatus;
06377 }
06378 
06379 //______________________________________________________________________________
06380 Int_t TProof::ClearPackage(const char *package)
06381 {
06382    // Remove a specific package.
06383    // Returns 0 in case of success and -1 in case of error.
06384 
06385    if (!IsValid()) return -1;
06386 
06387    if (!package || !strlen(package)) {
06388       Error("ClearPackage", "need to specify a package name");
06389       return -1;
06390    }
06391 
06392    // if name, erroneously, is a par pathname strip off .par and path
06393    TString pac = package;
06394    if (pac.EndsWith(".par"))
06395       pac.Remove(pac.Length()-4);
06396    pac = gSystem->BaseName(pac);
06397 
06398    if (UnloadPackage(pac) == -1)
06399       return -1;
06400 
06401    if (DisablePackage(pac) == -1)
06402       return -1;
06403 
06404    return fStatus;
06405 }
06406 
06407 //______________________________________________________________________________
06408 Int_t TProof::DisablePackage(const char *package)
06409 {
06410    // Remove a specific package.
06411    // Returns 0 in case of success and -1 in case of error.
06412 
06413    if (!IsValid()) return -1;
06414 
06415    if (!package || !strlen(package)) {
06416       Error("DisablePackage", "need to specify a package name");
06417       return -1;
06418    }
06419 
06420    // if name, erroneously, is a par pathname strip off .par and path
06421    TString pac = package;
06422    if (pac.EndsWith(".par"))
06423       pac.Remove(pac.Length()-4);
06424    pac = gSystem->BaseName(pac);
06425 
06426    if (DisablePackageOnClient(pac) == -1)
06427       return -1;
06428 
06429    // Nothing more to do if we are a Lite-session
06430    if (IsLite()) return 0;
06431 
06432    Int_t st = -1;
06433    Bool_t done = kFALSE;
06434    if (fManager) {
06435       // Try to do it via XROOTD (new way)
06436       TString path;
06437       path.Form("~/packages/%s", package);
06438       if (fManager->Rm(path, "-rf", "all") != -1) {
06439          path.Append(".par");
06440          if (fManager->Rm(path, "-f", "all") != -1) {
06441             done = kTRUE;
06442             st = 0;
06443          }
06444       }
06445    }
06446    if (!done) {
06447       // Try via TProofServ (old way)
06448       TMessage mess(kPROOF_CACHE);
06449       mess << Int_t(kDisablePackage) << pac;
06450       Broadcast(mess, kUnique);
06451 
06452       TMessage mess2(kPROOF_CACHE);
06453       mess2 << Int_t(kDisableSubPackage) << pac;
06454       Broadcast(mess2, fNonUniqueMasters);
06455 
06456       Collect(kAllUnique);
06457       st = fStatus;
06458    }
06459 
06460    // Done
06461    return st;
06462 }
06463 
06464 //______________________________________________________________________________
06465 Int_t TProof::DisablePackageOnClient(const char *package)
06466 {
06467    // Remove a specific package from the client.
06468    // Returns 0 in case of success and -1 in case of error.
06469 
06470    if (TestBit(TProof::kIsClient)) {
06471       // Remove the package directory and the par file locally
06472       fPackageLock->Lock();
06473       gSystem->Exec(Form("%s %s/%s", kRM, fPackageDir.Data(), package));
06474       gSystem->Exec(Form("%s %s/%s.par", kRM, fPackageDir.Data(), package));
06475       gSystem->Exec(Form("%s %s/%s/%s.par", kRM, fPackageDir.Data(), kPROOF_PackDownloadDir, package));
06476       fPackageLock->Unlock();
06477       if (!gSystem->AccessPathName(Form("%s/%s/%s.par", fPackageDir.Data(), kPROOF_PackDownloadDir, package)))
06478          Warning("DisablePackageOnClient", "unable to remove cached package PAR file for %s", package);
06479       if (!gSystem->AccessPathName(Form("%s/%s.par", fPackageDir.Data(), package)))
06480          Warning("DisablePackageOnClient", "unable to remove package PAR file for %s", package);
06481       if (!gSystem->AccessPathName(Form("%s/%s", fPackageDir.Data(), package)))
06482          Warning("DisablePackageOnClient", "unable to remove package directory for %s", package);
06483    }
06484 
06485    return 0;
06486 }
06487 
06488 //______________________________________________________________________________
06489 Int_t TProof::DisablePackages()
06490 {
06491    // Remove all packages.
06492    // Returns 0 in case of success and -1 in case of error.
06493 
06494    if (!IsValid()) return -1;
06495 
06496    // remove all packages on client
06497    if (TestBit(TProof::kIsClient)) {
06498       fPackageLock->Lock();
06499       gSystem->Exec(Form("%s %s/*", kRM, fPackageDir.Data()));
06500       fPackageLock->Unlock();
06501    }
06502 
06503    // Nothing more to do if we are a Lite-session
06504    if (IsLite()) return 0;
06505 
06506    TMessage mess(kPROOF_CACHE);
06507    mess << Int_t(kDisablePackages);
06508    Broadcast(mess, kUnique);
06509 
06510    TMessage mess2(kPROOF_CACHE);
06511    mess2 << Int_t(kDisableSubPackages);
06512    Broadcast(mess2, fNonUniqueMasters);
06513 
06514    Collect(kAllUnique);
06515 
06516    return fStatus;
06517 }
06518 
06519 //______________________________________________________________________________
06520 Int_t TProof::BuildPackage(const char *package, EBuildPackageOpt opt)
06521 {
06522    // Build specified package. Executes the PROOF-INF/BUILD.sh
06523    // script if it exists on all unique nodes. If opt is kBuildOnSlavesNoWait
06524    // then submit build command to slaves, but don't wait
06525    // for results. If opt is kCollectBuildResults then collect result
06526    // from slaves. To be used on the master.
06527    // If opt = kBuildAll (default) then submit and wait for results
06528    // (to be used on the client).
06529    // Returns 0 in case of success and -1 in case of error.
06530 
06531    if (!IsValid()) return -1;
06532 
06533    if (!package || !strlen(package)) {
06534       Error("BuildPackage", "need to specify a package name");
06535       return -1;
06536    }
06537 
06538    // if name, erroneously, is a par pathname strip off .par and path
06539    TString pac = package;
06540    if (pac.EndsWith(".par"))
06541       pac.Remove(pac.Length()-4);
06542    pac = gSystem->BaseName(pac);
06543 
06544    Bool_t buildOnClient = kTRUE;
06545    if (opt == kDontBuildOnClient) {
06546       buildOnClient = kFALSE;
06547       opt = kBuildAll;
06548    }
06549    // Prepare the local package
06550    TString pdir;
06551    Int_t st = 0;
06552    if (buildOnClient) {
06553       if (TestBit(TProof::kIsClient) && fPackageLock) fPackageLock->Lock();
06554       if ((st = BuildPackageOnClient(pac, 1, &pdir) != 0)) {
06555          if (TestBit(TProof::kIsClient) && fPackageLock) fPackageLock->Unlock();
06556          return -1;
06557       }
06558    }
06559 
06560    if (opt <= kBuildAll && (!IsLite() || !buildOnClient)) {
06561       TMessage mess(kPROOF_CACHE);
06562       mess << Int_t(kBuildPackage) << pac;
06563       Broadcast(mess, kUnique);
06564 
06565       TMessage mess2(kPROOF_CACHE);
06566       mess2 << Int_t(kBuildSubPackage) << pac;
06567       Broadcast(mess2, fNonUniqueMasters);
06568    }
06569 
06570    if (opt >= kBuildAll) {
06571       // by first forwarding the build commands to the master and slaves
06572       // and only then building locally we build in parallel
06573       if (buildOnClient) {
06574          st = BuildPackageOnClient(pac, 2, &pdir);
06575          if (TestBit(TProof::kIsClient) && fPackageLock) fPackageLock->Unlock();
06576       }
06577 
06578       fStatus = 0;
06579       if (!IsLite() || !buildOnClient)
06580          Collect(kAllUnique);
06581 
06582       if (fStatus < 0 || st < 0)
06583          return -1;
06584    }
06585 
06586    return 0;
06587 }
06588 
06589 //______________________________________________________________________________
06590 Int_t TProof::BuildPackageOnClient(const char *pack, Int_t opt, TString *path)
06591 {
06592    // Build specified package on the client. Executes the PROOF-INF/BUILD.sh
06593    // script if it exists on the client.
06594    // If opt == 0, both the preparation and building phases are run.
06595    // If opt == 1, only the preparation phase (asserting and, eventually, downloading
06596    //              of the package) is done; '*path' contains the full path to the
06597    //              package to be passed in the next call
06598    // If opt == 2, only the building phase is run using *path .
06599    // Returns 0 in case of success and -1 in case of error.
06600    // The code is equivalent to the one in TProofServ.cxx (TProof::kBuildPackage
06601    // case). Keep in sync in case of changes.
06602 
06603    TString downloaddir;
06604    downloaddir.Form("%s/%s", fPackageDir.Data(), kPROOF_PackDownloadDir);
06605 
06606    if (opt != 0 && !path) {
06607       Error("BuildPackageOnClient", "for opt=%d != 0 'patyh' must be defined", opt);
06608       return -1;
06609    }
06610 
06611    if (TestBit(TProof::kIsClient)) {
06612       Int_t status = 0;
06613       TString pdir, ocwd;
06614 
06615       if (opt == 0 || opt == 1) {
06616          // Package path
06617          pdir.Form("%s/%s", fPackageDir.Data(), pack);
06618          if (gSystem->AccessPathName(pdir, kReadPermission) ||
06619             gSystem->AccessPathName(pdir + "/PROOF-INF", kReadPermission)) {
06620             pdir = "";
06621             // Is there a global package with this name?
06622             if (fGlobalPackageDirList && fGlobalPackageDirList->GetSize() > 0) {
06623                // Scan the list of global packages dirs
06624                TIter nxd(fGlobalPackageDirList);
06625                TNamed *nm = 0;
06626                while ((nm = (TNamed *)nxd())) {
06627                   pdir = Form("%s/%s", nm->GetTitle(), pack);
06628                   if (!gSystem->AccessPathName(pdir, kReadPermission) &&
06629                      !gSystem->AccessPathName(pdir + "/PROOF-INF", kReadPermission)) {
06630                      // Package found, stop searching
06631                      break;
06632                   }
06633                   pdir = "";
06634                }
06635             }
06636          } else {
06637             // Check if the related PAR file still exists (private versions could have gone:
06638             // in such a case we should take the reference from the repository, by first cleaning
06639             // the existing directory)
06640             TString tpar(pdir);
06641             if (!tpar.EndsWith(".par")) tpar += ".par";
06642             Bool_t badPAR = kTRUE;
06643             FileStat_t stpar;
06644             if (gSystem->GetPathInfo(tpar, stpar) == 0) {
06645 #ifndef WIN32
06646                char ctmp[1024];
06647                if (!R_ISLNK(stpar.fMode) || readlink(tpar.Data(), ctmp, 1024) > 0) {
06648                   // The file exists
06649                   badPAR = kFALSE;
06650                }
06651 #else
06652                // The file exists
06653                badPAR = kFALSE;
06654 #endif
06655             }
06656             // Cleanup, if bad
06657             if (badPAR) {
06658                // Remove package directory
06659                gSystem->Exec(Form("%s %s", kRM, pdir.Data()));
06660                // Remove link or bad file
06661                gSystem->Exec(Form("%s %s", kRM, tpar.Data()));
06662                // Reset variable
06663                pdir = "";
06664             }
06665          }
06666          // Check if the package was downloaded from the master
06667          Bool_t wasDownloaded = kFALSE;
06668          TString dlpar;
06669          dlpar.Form("%s/%s", downloaddir.Data(), gSystem->BaseName(pack));
06670          if (!dlpar.EndsWith(".par")) dlpar += ".par";
06671          if (!pdir.IsNull()) {
06672             if (!gSystem->AccessPathName(dlpar, kFileExists))
06673                wasDownloaded = kTRUE;
06674          }
06675          if (pdir.IsNull() || wasDownloaded) {
06676             // Try to download it
06677             if (DownloadPackage(pack, downloaddir) != 0) {
06678                Error("BuildPackageOnClient",
06679                      "PAR file '%s.par' not found and could not be downloaded", pack);
06680                return -1;
06681             } else {
06682                TMD5 *md5 = TMD5::FileChecksum(dlpar);
06683                if (UploadPackageOnClient(dlpar, kUntar, md5) == -1) {
06684                   Error("BuildPackageOnClient",
06685                         "PAR file '%s.par' not found and could not be unpacked locally", pack);
06686                   delete md5;
06687                   return -1;
06688                }
06689                delete md5;
06690                // The package is now linked from the default package dir
06691                pdir.Form("%s/%s", fPackageDir.Data(), pack);
06692             }
06693          } else if (pdir.IsNull()) {
06694             Error("BuildPackageOnClient", "PAR file '%s.par' not found", pack);
06695             return -1;
06696          }
06697          PDB(kPackage, 1)
06698             Info("BuildPackageOnClient", "package %s exists and has PROOF-INF directory", pack);
06699          // We are done if only prepare was requested
06700          if (opt == 1) {
06701             *path = pdir;
06702             return 0;
06703          }
06704       }
06705 
06706       if (opt == 0 || opt == 2) {
06707          if (opt == 2) pdir = path->Data();
06708 
06709          ocwd = gSystem->WorkingDirectory();
06710          gSystem->ChangeDirectory(pdir);
06711 
06712          // check for BUILD.sh and execute
06713          if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
06714 
06715             // read version from file proofvers.txt, and if current version is
06716             // not the same do a "BUILD.sh clean"
06717             Bool_t savever = kFALSE;
06718             Int_t rev = -1;
06719             TString v;
06720             FILE *f = fopen("PROOF-INF/proofvers.txt", "r");
06721             if (f) {
06722                TString r;
06723                v.Gets(f);
06724                r.Gets(f);
06725                rev = (!r.IsNull() && r.IsDigit()) ? r.Atoi() : -1;
06726                fclose(f);
06727             }
06728             if (!f || v != gROOT->GetVersion() ||
06729                (gROOT->GetSvnRevision() > 0 && rev != gROOT->GetSvnRevision())) {
06730                savever = kTRUE;
06731                Info("BuildPackageOnClient",
06732                   "%s: version change (current: %s:%d, build: %s:%d): cleaning ... ",
06733                   pack, gROOT->GetVersion(), gROOT->GetSvnRevision(), v.Data(), rev);
06734                // Hard cleanup: go up the dir tree
06735                gSystem->ChangeDirectory(fPackageDir);
06736                // remove package directory
06737                gSystem->Exec(Form("%s %s", kRM, pdir.Data()));
06738                // find gunzip...
06739                char *gunzip = gSystem->Which(gSystem->Getenv("PATH"), kGUNZIP, kExecutePermission);
06740                if (gunzip) {
06741                   TString par = Form("%s.par", pdir.Data());
06742                   // untar package
06743                   TString cmd(Form(kUNTAR3, gunzip, par.Data()));
06744                   status = gSystem->Exec(cmd);
06745                   if ((status = gSystem->Exec(cmd))) {
06746                      Error("BuildPackageOnClient", "failure executing: %s", cmd.Data());
06747                   } else {
06748                      // Go down to the package directory
06749                      gSystem->ChangeDirectory(pdir);
06750                   }
06751                   delete [] gunzip;
06752                } else {
06753                   Error("BuildPackageOnClient", "%s not found", kGUNZIP);
06754                   status = -1;
06755                }
06756             }
06757 
06758             if (gSystem->Exec("export ROOTPROOFCLIENT=\"1\" ; PROOF-INF/BUILD.sh")) {
06759                Error("BuildPackageOnClient", "building package %s on the client failed", pack);
06760                status = -1;
06761             }
06762 
06763             if (savever && !status) {
06764                f = fopen("PROOF-INF/proofvers.txt", "w");
06765                if (f) {
06766                   fputs(gROOT->GetVersion(), f);
06767                   fputs(Form("\n%d",gROOT->GetSvnRevision()), f);
06768                   fclose(f);
06769                }
06770             }
06771          } else {
06772             PDB(kPackage, 1)
06773                Info("BuildPackageOnClient",
06774                   "package %s exists but has no PROOF-INF/BUILD.sh script", pack);
06775          }
06776 
06777          gSystem->ChangeDirectory(ocwd);
06778 
06779          return status;
06780       }
06781    }
06782    return 0;
06783 }
06784 
06785 //______________________________________________________________________________
06786 Int_t TProof::LoadPackage(const char *package, Bool_t notOnClient, TList *loadopts)
06787 {
06788    // Load specified package. Executes the PROOF-INF/SETUP.C script
06789    // on all active nodes. If notOnClient = true, don't load package
06790    // on the client. The default is to load the package also on the client.
06791    // The argument 'loadopts' specify a list of objects to be passed to the SETUP.
06792    // The objects in the list must be streamable; the SETUP macro will be executed
06793    // like this: SETUP.C(loadopts).
06794    // Returns 0 in case of success and -1 in case of error.
06795 
06796    if (!IsValid()) return -1;
06797 
06798    if (!package || !strlen(package)) {
06799       Error("LoadPackage", "need to specify a package name");
06800       return -1;
06801    }
06802 
06803    // if name, erroneously, is a par pathname strip off .par and path
06804    TString pac = package;
06805    if (pac.EndsWith(".par"))
06806       pac.Remove(pac.Length()-4);
06807    pac = gSystem->BaseName(pac);
06808 
06809    if (!notOnClient)
06810       if (LoadPackageOnClient(pac, loadopts) == -1)
06811          return -1;
06812 
06813    TMessage mess(kPROOF_CACHE);
06814    mess << Int_t(kLoadPackage) << pac;
06815    if (loadopts) mess << loadopts;
06816    Broadcast(mess);
06817    // On the master, workers that fail are deactivated
06818    Bool_t deactivateOnFailure = (IsMaster()) ? kTRUE : kFALSE;
06819    Collect(kActive, -1, -1, deactivateOnFailure);
06820 
06821    return fStatus;
06822 }
06823 
06824 //______________________________________________________________________________
06825 Int_t TProof::LoadPackageOnClient(const char *pack, TList *loadopts)
06826 {
06827    // Load specified package in the client. Executes the PROOF-INF/SETUP.C
06828    // script on the client. Returns 0 in case of success and -1 in case of error.
06829    // The code is equivalent to the one in TProofServ.cxx (TProof::kLoadPackage
06830    // case). Keep in sync in case of changes.
06831    // The argument 'loadopts' specify a list of objects to be passed to the SETUP.
06832    // The objects in the list must be streamable; the SETUP macro will be executed
06833    // like this: SETUP.C(loadopts).
06834    // Returns 0 in case of success and -1 in case of error.
06835 
06836    if (TestBit(TProof::kIsClient)) {
06837       Int_t status = 0;
06838       TString pdir, ocwd;
06839       // If already loaded don't do it again
06840       if (fEnabledPackagesOnClient->FindObject(pack)) {
06841          Info("LoadPackageOnClient", "package %s already loaded", pack);
06842          return 0;
06843       }
06844 
06845       // always follows BuildPackage so no need to check for PROOF-INF
06846       pdir.Form("%s/%s", fPackageDir.Data(), pack);
06847 
06848       if (gSystem->AccessPathName(pdir, kReadPermission)) {
06849          // Is there a global package with this name?
06850          if (fGlobalPackageDirList && fGlobalPackageDirList->GetSize() > 0) {
06851             // Scan the list of global packages dirs
06852             TIter nxd(fGlobalPackageDirList);
06853             TNamed *nm = 0;
06854             while ((nm = (TNamed *)nxd())) {
06855                pdir = Form("%s/%s", nm->GetTitle(), pack);
06856                if (!gSystem->AccessPathName(pdir, kReadPermission)) {
06857                   // Package found, stop searching
06858                   break;
06859                }
06860                pdir = "";
06861             }
06862             if (pdir.Length() <= 0) {
06863                // Package not found
06864                Error("LoadPackageOnClient", "failure locating %s ...", pack);
06865                return -1;
06866             }
06867          }
06868       }
06869 
06870       ocwd = gSystem->WorkingDirectory();
06871       gSystem->ChangeDirectory(pdir);
06872 
06873       // check for SETUP.C and execute
06874       if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
06875 
06876          // We need to change the name of the function to avoid problems when we load more packages
06877          TString setup, setupfn;
06878          setup.Form("SETUP_%x", TString(pack).Hash());
06879          setupfn.Form("%s/%s.C", gSystem->TempDirectory(), setup.Data());
06880          TMacro setupmc("PROOF-INF/SETUP.C");
06881          TObjString *setupline = setupmc.GetLineWith("SETUP(");
06882          if (setupline) {
06883             TString setupstring(setupline->GetString());
06884             setupstring.ReplaceAll("SETUP(", TString::Format("%s(", setup.Data()));
06885             setupline->SetString(setupstring);
06886          } else {
06887             // Macro does not contain SETUP()
06888             Warning("LoadPackageOnClient", "macro '%s/PROOF-INF/SETUP.C' does not contain a SETUP()"
06889                                            " function", pack);
06890          }
06891          setupmc.SaveSource(setupfn.Data());
06892          // Load the macro
06893          if (gROOT->LoadMacro(setupfn.Data()) != 0) {
06894             // Macro could not be loaded
06895             Error("LoadPackageOnClient", "macro '%s/PROOF-INF/SETUP.C' could not be loaded:"
06896                                          " cannot continue", pack);
06897             status = -1;
06898          } else {
06899             // Check the signature
06900             TFunction *fun = (TFunction *) gROOT->GetListOfGlobalFunctions()->FindObject(setup);
06901             if (!fun) {
06902                // Notify the upper level
06903                Error("LoadPackageOnClient", "function SETUP() not found in macro '%s/PROOF-INF/SETUP.C':"
06904                                             " cannot continue", pack);
06905                status = -1;
06906             } else {
06907                TMethodCall callEnv;
06908                // Check the number of arguments
06909                if (fun->GetNargs() == 0) {
06910                   // No arguments (basic signature)
06911                   callEnv.InitWithPrototype(setup,"");
06912                   // Warn that the argument (if any) if ignored
06913                   if (loadopts)
06914                      Warning("LoadPackageOnClient", "loaded SETUP() does not take any argument:"
06915                                                     " the specified TList object will be ignored");
06916                } else if (fun->GetNargs() == 1) {
06917                   TMethodArg *arg = (TMethodArg *) fun->GetListOfMethodArgs()->First();
06918                   if (arg) {
06919                      // Check argument type
06920                      TString argsig(arg->GetTitle());
06921                      if (argsig.BeginsWith("TList")) {
06922                         callEnv.InitWithPrototype(setup,"TList *");
06923                         callEnv.ResetParam();
06924                         callEnv.SetParam((Long_t) loadopts);
06925                      } else if (argsig.BeginsWith("const char")) {
06926                         callEnv.InitWithPrototype(setup,"const char *");
06927                         callEnv.ResetParam();
06928                         TObjString *os = loadopts ? dynamic_cast<TObjString *>(loadopts->First()) : 0;
06929                         if (os) {
06930                            callEnv.SetParam((Long_t) os->GetName());
06931                         } else {
06932                            if (loadopts && loadopts->First()) {
06933                               Warning("LoadPackageOnClient", "found object argument of type %s:"
06934                                                              " SETUP expects 'const char *': ignoring",
06935                                                              loadopts->First()->ClassName());
06936                            }
06937                            callEnv.SetParam((Long_t) 0);
06938                         }
06939                      } else {
06940                         // Notify the upper level
06941                         Error("LoadPackageOnClient", "unsupported SETUP signature: SETUP(%s)"
06942                                                      " cannot continue", arg->GetTitle());
06943                         status = -1;
06944                      }
06945                   } else {
06946                      // Notify the upper level
06947                      Error("LoadPackageOnClient", "cannot get information about the SETUP() argument:"
06948                                                   " cannot continue");
06949                      status = -1;
06950                   }
06951                } else if (fun->GetNargs() > 1) {
06952                   // Notify the upper level
06953                   Error("LoadPackageOnClient", "function SETUP() can have at most a 'TList *' argument:"
06954                                                " cannot continue");
06955                   status = -1;
06956                }
06957                // Execute
06958                Long_t setuprc = (status == 0) ? 0 : -1;
06959                if (status == 0) {
06960                   callEnv.Execute(setuprc);
06961                   if (setuprc < 0) status = -1;
06962                }
06963             }
06964          }
06965          // Remove the temporary macro file
06966          if (!gSystem->AccessPathName(setupfn.Data())) gSystem->Unlink(setupfn.Data());
06967       } else {
06968          PDB(kPackage, 1)
06969             Info("LoadPackageOnClient",
06970                  "package %s exists but has no PROOF-INF/SETUP.C script", pack);
06971       }
06972 
06973       gSystem->ChangeDirectory(ocwd);
06974 
06975       if (status == 0) {
06976          // create link to package in working directory
06977 
06978          fPackageLock->Lock();
06979 
06980          FileStat_t stat;
06981          Int_t st = gSystem->GetPathInfo(pack, stat);
06982          // check if symlink, if so unlink, if not give error
06983          // NOTE: GetPathnfo() returns 1 in case of symlink that does not point to
06984          // existing file or to a directory, but if fIsLink is true the symlink exists
06985          if (stat.fIsLink)
06986             gSystem->Unlink(pack);
06987          else if (st == 0) {
06988             Error("LoadPackageOnClient", "cannot create symlink %s in %s on client, "
06989                   "another item with same name already exists", pack, ocwd.Data());
06990             fPackageLock->Unlock();
06991             return -1;
06992          }
06993          gSystem->Symlink(pdir, pack);
06994 
06995          fPackageLock->Unlock();
06996 
06997          // add package to list of include directories to be searched by ACliC
06998          gSystem->AddIncludePath(TString("-I") + pack);
06999 
07000          // add package to list of include directories to be searched by CINT
07001          gROOT->ProcessLine(TString(".include ") + pack);
07002 
07003          fEnabledPackagesOnClient->Add(new TObjString(pack));
07004          PDB(kPackage, 1)
07005             Info("LoadPackageOnClient", "package %s successfully loaded", pack);
07006       } else
07007          Error("LoadPackageOnClient", "loading package %s on client failed", pack);
07008 
07009       return status;
07010    }
07011    return 0;
07012 }
07013 
07014 //______________________________________________________________________________
07015 Int_t TProof::UnloadPackage(const char *package)
07016 {
07017    // Unload specified package.
07018    // Returns 0 in case of success and -1 in case of error.
07019 
07020    if (!IsValid()) return -1;
07021 
07022    if (!package || !strlen(package)) {
07023       Error("UnloadPackage", "need to specify a package name");
07024       return -1;
07025    }
07026 
07027    // if name, erroneously, is a par pathname strip off .par and path
07028    TString pac = package;
07029    if (pac.EndsWith(".par"))
07030       pac.Remove(pac.Length()-4);
07031    pac = gSystem->BaseName(pac);
07032 
07033    if (UnloadPackageOnClient(pac) == -1)
07034       return -1;
07035 
07036    // Nothing more to do if we are a Lite-session
07037    if (IsLite()) return 0;
07038 
07039    TMessage mess(kPROOF_CACHE);
07040    mess << Int_t(kUnloadPackage) << pac;
07041    Broadcast(mess);
07042    Collect();
07043 
07044    return fStatus;
07045 }
07046 
07047 //______________________________________________________________________________
07048 Int_t TProof::UnloadPackageOnClient(const char *package)
07049 {
07050    // Unload a specific package on the client.
07051    // Returns 0 in case of success and -1 in case of error.
07052    // The code is equivalent to the one in TProofServ.cxx (TProof::UnloadPackage
07053    // case). Keep in sync in case of changes.
07054 
07055    if (TestBit(TProof::kIsClient)) {
07056       TObjString *pack = (TObjString *) fEnabledPackagesOnClient->FindObject(package);
07057       if (pack) {
07058          // Remove entry from include path
07059          TString aclicincpath = gSystem->GetIncludePath();
07060          TString cintincpath = gInterpreter->GetIncludePath();
07061          // remove interpreter part of gSystem->GetIncludePath()
07062          aclicincpath.Remove(aclicincpath.Length() - cintincpath.Length() - 1);
07063          // remove package's include path
07064          aclicincpath.ReplaceAll(TString(" -I") + package, "");
07065          gSystem->SetIncludePath(aclicincpath);
07066 
07067          //TODO reset interpreter include path
07068 
07069          // remove entry from enabled packages list
07070          fEnabledPackagesOnClient->Remove(pack);
07071       }
07072 
07073       // cleanup the link
07074       if (!gSystem->AccessPathName(package))
07075          if (gSystem->Unlink(package) != 0)
07076             Warning("UnloadPackageOnClient", "unable to remove symlink to %s", package);
07077 
07078       // delete entry
07079       delete pack;
07080    }
07081    return 0;
07082 }
07083 
07084 //______________________________________________________________________________
07085 Int_t TProof::UnloadPackages()
07086 {
07087    // Unload all packages.
07088    // Returns 0 in case of success and -1 in case of error.
07089 
07090    if (!IsValid()) return -1;
07091 
07092    if (TestBit(TProof::kIsClient)) {
07093       // Iterate over packages on the client and remove each package
07094       TIter nextpackage(fEnabledPackagesOnClient);
07095       while (TObjString *objstr = dynamic_cast<TObjString*>(nextpackage()))
07096          if (UnloadPackageOnClient(objstr->String()) == -1 )
07097             return -1;
07098    }
07099 
07100    // Nothing more to do if we are a Lite-session
07101    if (IsLite()) return 0;
07102 
07103    TMessage mess(kPROOF_CACHE);
07104    mess << Int_t(kUnloadPackages);
07105    Broadcast(mess);
07106    Collect();
07107 
07108    return fStatus;
07109 }
07110 
07111 //______________________________________________________________________________
07112 Int_t TProof::EnablePackage(const char *package, Bool_t notOnClient)
07113 {
07114    // Enable specified package. Executes the PROOF-INF/BUILD.sh
07115    // script if it exists followed by the PROOF-INF/SETUP.C script.
07116    // In case notOnClient = true, don't enable the package on the client.
07117    // The default is to enable packages also on the client.
07118    // Returns 0 in case of success and -1 in case of error.
07119    // Provided for backward compatibility.
07120 
07121    return EnablePackage(package, (TList *)0, notOnClient);
07122 }
07123 
07124 //______________________________________________________________________________
07125 Int_t TProof::EnablePackage(const char *package, const char *loadopts,
07126                             Bool_t notOnClient)
07127 {
07128    // Enable specified package. Executes the PROOF-INF/BUILD.sh
07129    // script if it exists followed by the PROOF-INF/SETUP.C script.
07130    // In case notOnClient = true, don't enable the package on the client.
07131    // The default is to enable packages also on the client.
07132    // It is is possible to specify options for the loading step via 'loadopts';
07133    // the string will be passed passed as argument to SETUP.
07134    // Returns 0 in case of success and -1 in case of error.
07135 
07136    TList *optls = 0;
07137    if (loadopts && strlen(loadopts)) {
07138       if (fProtocol > 28) {
07139          optls = new TList;
07140          optls->Add(new TObjString(loadopts));
07141          optls->SetOwner(kTRUE);
07142       } else {
07143          // Notify
07144          Warning("EnablePackage", "remote server does not support options: ignoring the option string");
07145       }
07146    }
07147    // Run
07148    Int_t rc = EnablePackage(package, optls, notOnClient);
07149    // Clean up
07150    SafeDelete(optls);
07151    // Done
07152    return rc;
07153 }
07154 
07155 //______________________________________________________________________________
07156 Int_t TProof::EnablePackage(const char *package, TList *loadopts,
07157                             Bool_t notOnClient)
07158 {
07159    // Enable specified package. Executes the PROOF-INF/BUILD.sh
07160    // script if it exists followed by the PROOF-INF/SETUP.C script.
07161    // In case notOnClient = true, don't enable the package on the client.
07162    // The default is to enable packages also on the client.
07163    // It is is possible to specify a list of objects to be passed to the SETUP
07164    // functions via 'loadopts'; the objects must be streamable.
07165    // Returns 0 in case of success and -1 in case of error.
07166 
07167    if (!IsValid()) return -1;
07168 
07169    if (!package || !strlen(package)) {
07170       Error("EnablePackage", "need to specify a package name");
07171       return -1;
07172    }
07173 
07174    // if name, erroneously, is a par pathname strip off .par and path
07175    TString pac = package;
07176    if (pac.EndsWith(".par"))
07177       pac.Remove(pac.Length()-4);
07178    pac = gSystem->BaseName(pac);
07179 
07180    EBuildPackageOpt opt = kBuildAll;
07181    if (notOnClient)
07182       opt = kDontBuildOnClient;
07183 
07184    if (BuildPackage(pac, opt) == -1)
07185       return -1;
07186 
07187    TList *optls = loadopts;
07188    if (optls && fProtocol <= 28) {
07189       Warning("EnablePackage", "remote server does not support options: ignoring the option list");
07190       optls = 0;
07191    }
07192 
07193    if (LoadPackage(pac, notOnClient, optls) == -1)
07194       return -1;
07195 
07196    return 0;
07197 }
07198 
07199 //______________________________________________________________________________
07200 Int_t TProof::DownloadPackage(const char *pack, const char *dstdir)
07201 {
07202    // Download a PROOF archive (PAR file) from the master package repository.
07203    // The PAR file is downloaded in the current directory or in the directory
07204    // specified by 'dstdir'. If a package with the same name already exists
07205    // at destination, a check on the MD5 sum is done and the user warned or
07206    // prompted for action, depending is the file is equal or different.
07207    // Returns 0 in case of success and -1 in case of error.
07208 
07209    if (!fManager || !(fManager->IsValid())) {
07210       Error("DownloadPackage", "the manager is undefined!");
07211       return -1;
07212    }
07213 
07214    // Create the default source and destination paths
07215    TString parname(gSystem->BaseName(pack)), src, dst;
07216    if (!parname.EndsWith(".par")) parname += ".par";
07217    src.Form("packages/%s", parname.Data());
07218    if (!dstdir || strlen(dstdir) <= 0) {
07219       dst.Form("./%s", parname.Data());
07220    } else {
07221       // Check the destination directory
07222       FileStat_t st;
07223       if (gSystem->GetPathInfo(dstdir, st) != 0) {
07224          // Directory does not exit: create it
07225          if (gSystem->mkdir(dstdir, kTRUE) != 0) {
07226             Error("DownloadPackage",
07227                   "could not create the destination directory '%s' (errno: %d)",
07228                    dstdir, TSystem::GetErrno());
07229             return -1;
07230          }
07231       } else if (!R_ISDIR(st.fMode) && !R_ISLNK(st.fMode)) {
07232          Error("DownloadPackage",
07233                "destination path '%s' exist but is not a directory!", dstdir);
07234          return -1;
07235       }
07236       dst.Form("%s/%s", dstdir, parname.Data());
07237    }
07238 
07239    // Make sure the source file exists
07240    FileStat_t stsrc;
07241    RedirectHandle_t rh;
07242    if (gSystem->RedirectOutput(fLogFileName, "a", &rh) != 0)
07243       Warning("DownloadPackage", "problems redirecting output to '%s'", fLogFileName.Data());
07244    Int_t rc = fManager->Stat(src, stsrc);
07245    if (gSystem->RedirectOutput(0, 0, &rh) != 0)
07246       Warning("DownloadPackage", "problems restoring output");
07247    if (rc != 0) {
07248       // Check if there is another possible source
07249       ShowPackages(kFALSE, kTRUE);
07250       TMacro *mp = GetLastLog();
07251       if (mp) {
07252          // Look for global directories
07253          Bool_t isGlobal = kFALSE;
07254          TIter nxl(mp->GetListOfLines());
07255          TObjString *os = 0;
07256          TString globaldir;
07257          while ((os = (TObjString *) nxl())) {
07258             TString s(os->GetName());
07259             if (s.Contains("*** Global Package cache")) {
07260                // Get the directory
07261                s.Remove(0, s.Last(':') + 1);
07262                s.Remove(s.Last(' '));
07263                globaldir = s;
07264                isGlobal = kTRUE;
07265             } else if (s.Contains("*** Package cache")) {
07266                isGlobal = kFALSE;
07267                globaldir = "";
07268             }
07269             // Check for the package
07270             if (isGlobal && s.Contains(parname)) {
07271                src.Form("%s/%s", globaldir.Data(), parname.Data());
07272                break;
07273             }
07274          }
07275          // Cleanup
07276          delete mp;
07277       }
07278    }
07279 
07280    // Do it via the manager
07281    if (fManager->GetFile(src, dst, "silent") != 0) {
07282       Error("DownloadPackage", "problems downloading '%s' (src:%s, dst:%s)",
07283                                 pack, src.Data(), dst.Data());
07284       return -1;
07285    } else {
07286       Info("DownloadPackage", "'%s' cross-checked against master repository (local path: %s)",
07287                                 pack, dst.Data());
07288    }
07289    // Done
07290    return 0;
07291 }
07292 
07293 //______________________________________________________________________________
07294 Int_t TProof::UploadPackage(const char *pack, EUploadPackageOpt opt)
07295 {
07296    // Upload a PROOF archive (PAR file). A PAR file is a compressed
07297    // tar file with one special additional directory, PROOF-INF
07298    // (blatantly copied from Java's jar format). It must have the extension
07299    // .par. A PAR file can be directly a binary or a source with a build
07300    // procedure. In the PROOF-INF directory there can be a build script:
07301    // BUILD.sh to be called to build the package, in case of a binary PAR
07302    // file don't specify a build script or make it a no-op. Then there is
07303    // SETUP.C which sets the right environment variables to use the package,
07304    // like LD_LIBRARY_PATH, etc.
07305    // The 'opt' allows to specify whether the .PAR should be just unpacked
07306    // in the existing dir (opt = kUntar, default) or a remove of the existing
07307    // directory should be executed (opt = kRemoveOld), so triggering a full
07308    // re-build. The option if effective only for PROOF protocol > 8 .
07309    // The lab 'dirlab' (e.g. 'G0') indicates that the package is to uploaded to
07310    // an alternative global directory for global usage. This may require special
07311    // privileges.
07312    // If download is kTRUE and the package is not found locally, then it is downloaded
07313    // from the master repository.
07314    // Returns 0 in case of success and -1 in case of error.
07315 
07316    if (!IsValid()) return -1;
07317 
07318    TString par = pack;
07319    if (!par.EndsWith(".par"))
07320       // The client specified only the name: add the extension
07321       par += ".par";
07322 
07323    // Default location is the local working dir; then the package dir
07324    gSystem->ExpandPathName(par);
07325    if (gSystem->AccessPathName(par, kReadPermission)) {
07326       TString tried = par;
07327       // Try the package dir
07328       par = Form("%s/%s", fPackageDir.Data(), gSystem->BaseName(par));
07329       if (gSystem->AccessPathName(par, kReadPermission)) {
07330          // Is the package a global one
07331          if (fGlobalPackageDirList && fGlobalPackageDirList->GetSize() > 0) {
07332             // Scan the list of global packages dirs
07333             TIter nxd(fGlobalPackageDirList);
07334             TNamed *nm = 0;
07335             TString pdir;
07336             while ((nm = (TNamed *)nxd())) {
07337                pdir = Form("%s/%s", nm->GetTitle(), pack);
07338                if (!gSystem->AccessPathName(pdir, kReadPermission)) {
07339                   // Package found, stop searching
07340                   break;
07341                }
07342                pdir = "";
07343             }
07344             if (pdir.Length() > 0) {
07345                // Package is in the global dirs
07346                if (gDebug > 0)
07347                   Info("UploadPackage", "global package found (%s): no upload needed",
07348                                         pdir.Data());
07349                return 0;
07350             }
07351          }
07352          Error("UploadPackage", "PAR file '%s' not found; paths tried: %s, %s",
07353                                 gSystem->BaseName(par), tried.Data(), par.Data());
07354          return -1;
07355       }
07356    }
07357 
07358    // Strategy:
07359    // On the client:
07360    // get md5 of package and check if it is different
07361    // from the one stored in the local package directory. If it is lock
07362    // the package directory and copy the package, unlock the directory.
07363    // On the masters:
07364    // get md5 of package and check if it is different from the
07365    // one stored on the remote node. If it is different lock the remote
07366    // package directory and use TFTP or SendFile to ftp the package to the
07367    // remote node, unlock the directory.
07368 
07369    TMD5 *md5 = TMD5::FileChecksum(par);
07370 
07371    if (!md5 || (md5 && UploadPackageOnClient(par, opt, md5) == -1)) {
07372       if (md5) delete md5;
07373       return -1;
07374    }
07375 
07376    // Nothing more to do if we are a Lite-session
07377    if (IsLite()) {
07378       delete md5;
07379       return 0;
07380    }
07381 
07382    TString smsg;
07383    smsg.Form("+%s", gSystem->BaseName(par));
07384 
07385    TMessage mess(kPROOF_CHECKFILE);
07386    mess << smsg << (*md5);
07387    TMessage mess2(kPROOF_CHECKFILE);
07388    smsg.Replace(0, 1, "-");
07389    mess2 << smsg << (*md5);
07390    TMessage mess3(kPROOF_CHECKFILE);
07391    smsg.Replace(0, 1, "=");
07392    mess3 << smsg << (*md5);
07393 
07394    delete md5;
07395 
07396    if (fProtocol > 8) {
07397       // Send also the option
07398       mess << (UInt_t) opt;
07399       mess2 << (UInt_t) opt;
07400       mess3 << (UInt_t) opt;
07401    }
07402 
07403    // loop over all selected nodes
07404    TIter next(fUniqueSlaves);
07405    TSlave *sl = 0;
07406    while ((sl = (TSlave *) next())) {
07407       if (!sl->IsValid())
07408          continue;
07409 
07410       sl->GetSocket()->Send(mess);
07411 
07412       fCheckFileStatus = 0;
07413       Collect(sl, fCollectTimeout, kPROOF_CHECKFILE);
07414       if (fCheckFileStatus == 0) {
07415 
07416          if (fProtocol > 5) {
07417             // remote directory is locked, upload file over the open channel
07418             smsg.Form("%s/%s/%s", sl->GetProofWorkDir(), kPROOF_PackDir,
07419                                   gSystem->BaseName(par));
07420             if (SendFile(par, (kBinary | kForce | kCpBin | kForward), smsg.Data(), sl) < 0) {
07421                Error("UploadPackage", "%s: problems uploading file %s",
07422                                       sl->GetOrdinal(), par.Data());
07423                return -1;
07424             }
07425          } else {
07426             // old servers receive it via TFTP
07427             TFTP ftp(TString("root://")+sl->GetName(), 1);
07428             if (!ftp.IsZombie()) {
07429                smsg.Form("%s/%s", sl->GetProofWorkDir(), kPROOF_PackDir);
07430                ftp.cd(smsg.Data());
07431                ftp.put(par, gSystem->BaseName(par));
07432             }
07433          }
07434 
07435          // install package and unlock dir
07436          sl->GetSocket()->Send(mess2);
07437          fCheckFileStatus = 0;
07438          Collect(sl, fCollectTimeout, kPROOF_CHECKFILE);
07439          if (fCheckFileStatus == 0) {
07440             Error("UploadPackage", "%s: unpacking of package %s failed",
07441                                    sl->GetOrdinal(), gSystem->BaseName(par));
07442             return -1;
07443          }
07444       }
07445    }
07446 
07447    // loop over all other master nodes
07448    TIter nextmaster(fNonUniqueMasters);
07449    TSlave *ma;
07450    while ((ma = (TSlave *) nextmaster())) {
07451       if (!ma->IsValid())
07452          continue;
07453 
07454       ma->GetSocket()->Send(mess3);
07455 
07456       fCheckFileStatus = 0;
07457       Collect(ma, fCollectTimeout, kPROOF_CHECKFILE);
07458       if (fCheckFileStatus == 0) {
07459          // error -> package should have been found
07460          Error("UploadPackage", "package %s did not exist on submaster %s",
07461                par.Data(), ma->GetOrdinal());
07462          return -1;
07463       }
07464    }
07465 
07466    return 0;
07467 }
07468 
07469 //______________________________________________________________________________
07470 Int_t TProof::UploadPackageOnClient(const char *parpack, EUploadPackageOpt opt, TMD5 *md5)
07471 {
07472    // Upload a package on the client in ~/.proof/packages.
07473    // The 'opt' allows to specify whether the .PAR should be just unpacked
07474    // in the existing dir (opt = kUntar, default) or a remove of the existing
07475    // directory should be executed (opt = kRemoveOld), thereby triggering a full
07476    // re-build. This option if effective only for PROOF protocol > 8.
07477    // Returns 0 in case of success and -1 in case of error.
07478 
07479    // Strategy:
07480    // get md5 of package and check if it is different
07481    // from the one stored in the local package directory. If it is lock
07482    // the package directory and copy the package, unlock the directory.
07483 
07484    Int_t status = 0;
07485 
07486    if (TestBit(TProof::kIsClient)) {
07487       // Make sure that 'par' is the real path and not a symlink
07488       TString par(parpack);
07489 #ifndef WIN32
07490       char ctmp[4096];
07491       ssize_t sz = readlink(par.Data(), ctmp, 4096);
07492       if (sz >= 4096) sz = 4095;
07493       if (sz > 0) {
07494          ctmp[sz] = '\0';
07495          par = ctmp;
07496       } else if (TSystem::GetErrno() != EINVAL) {
07497          Warning("UploadPackageOnClient",
07498                  "could not resolve the symbolik link '%s'", par.Data());
07499       }
07500 #endif
07501       // The fPackageDir directory exists (has been created in Init());
07502       // create symlink to the par file in the fPackageDir (needed by
07503       // master in case we run on the localhost)
07504       fPackageLock->Lock();
07505 
07506       // Check if the requested PAR has been downloaded: if not, clean any
07507       // existing downloaded file with the same name: this is because now
07508       // the client has its own version of the package and should not check
07509       // the master repository anymore for updates
07510       TString downloadpath;
07511       downloadpath.Form("%s/%s/%s", fPackageDir.Data(), kPROOF_PackDownloadDir, gSystem->BaseName(par));
07512       if (!gSystem->AccessPathName(downloadpath, kFileExists) && downloadpath != par) {
07513          if (gSystem->Unlink(downloadpath) != 0) {
07514             Warning("UploadPackageOnClient",
07515                     "problems removing downloaded version of '%s' (%s):\n"
07516                     "may imply inconsistencies in subsequent updates",
07517                     gSystem->BaseName(par), downloadpath.Data());
07518          }
07519       }
07520       TString lpar;
07521       lpar.Form("%s/%s", fPackageDir.Data(), gSystem->BaseName(par));
07522       FileStat_t stat;
07523       Int_t st = gSystem->GetPathInfo(lpar, stat);
07524       // check if symlink, if so unlink, if not give error
07525       // NOTE: GetPathInfo() returns 1 in case of symlink that does not point to
07526       // existing file, but if fIsLink is true the symlink exists
07527       if (stat.fIsLink)
07528          gSystem->Unlink(lpar);
07529       else if (st == 0) {
07530          Error("UploadPackageOnClient", "cannot create symlink %s on client, "
07531                "another item with same name already exists",
07532                lpar.Data());
07533          fPackageLock->Unlock();
07534          return -1;
07535       }
07536       if (!gSystem->IsAbsoluteFileName(par)) {
07537          TString fpar = par;
07538          gSystem->Symlink(gSystem->PrependPathName(gSystem->WorkingDirectory(), fpar), lpar);
07539       } else
07540          gSystem->Symlink(par, lpar);
07541       // TODO: On Windows need to copy instead of symlink
07542 
07543       // compare md5
07544       TString packnam = par(0, par.Length() - 4);  // strip off ".par"
07545       packnam = gSystem->BaseName(packnam);        // strip off path
07546       TString md5f = fPackageDir + "/" + packnam + "/PROOF-INF/md5.txt";
07547       TMD5 *md5local = TMD5::ReadChecksum(md5f);
07548       if (!md5local || (*md5) != (*md5local)) {
07549          // if not, unzip and untar package in package directory
07550          if ((opt & TProof::kRemoveOld)) {
07551             // remove any previous package directory with same name
07552             if (gSystem->Exec(Form("%s %s/%s", kRM, fPackageDir.Data(),
07553                                    packnam.Data())))
07554                Error("UploadPackageOnClient", "failure executing: %s %s/%s",
07555                      kRM, fPackageDir.Data(), packnam.Data());
07556          }
07557          // find gunzip
07558          char *gunzip = gSystem->Which(gSystem->Getenv("PATH"), kGUNZIP,
07559                                        kExecutePermission);
07560          if (gunzip) {
07561             // untar package
07562             if (gSystem->Exec(Form(kUNTAR2, gunzip, par.Data(), fPackageDir.Data())))
07563                Error("Uploadpackage", "failure executing: %s",
07564                      Form(kUNTAR2, gunzip, par.Data(), fPackageDir.Data()));
07565             delete [] gunzip;
07566          } else
07567             Error("UploadPackageOnClient", "%s not found", kGUNZIP);
07568 
07569          // check that fPackageDir/packnam now exists
07570          if (gSystem->AccessPathName(fPackageDir + "/" + packnam, kWritePermission)) {
07571             // par file did not unpack itself in the expected directory, failure
07572             Error("UploadPackageOnClient",
07573                   "package %s did not unpack into %s/%s", par.Data(), fPackageDir.Data(),
07574                   packnam.Data());
07575             status = -1;
07576          } else {
07577             // store md5 in package/PROOF-INF/md5.txt
07578             TMD5::WriteChecksum(md5f, md5);
07579          }
07580       }
07581       fPackageLock->Unlock();
07582       delete md5local;
07583    }
07584    return status;
07585 }
07586 
07587 //______________________________________________________________________________
07588 Int_t TProof::Load(const char *macro, Bool_t notOnClient, Bool_t uniqueWorkers,
07589                    TList *wrks)
07590 {
07591    // Load the specified macro on master, workers and, if notOnClient is
07592    // kFALSE, on the client. The macro file is uploaded if new or updated.
07593    // Additional files to be uploaded (or updated, if needed) can be specified
07594    // after a comma, e.g. "mymacro.C+,thisheader.h,thatheader.h".
07595    // If existing in the same directory, a header basename(macro).h or .hh, is also
07596    // uploaded.
07597    // The default is to load the macro also on the client; notOnClient can be used
07598    // to avoid loading on the client.
07599    // On masters, if uniqueWorkers is kTRUE, the macro is loaded on unique workers
07600    // only, and collection is not done; if uniqueWorkers is kFALSE, collection
07601    // from the previous request is done, and broadcasting + collection from the
07602    // other workers is done.
07603    // The wrks arg can be used on the master to limit the set of workers.
07604    // Returns 0 in case of success and -1 in case of error.
07605 
07606    if (!IsValid()) return -1;
07607 
07608    if (!macro || !strlen(macro)) {
07609       Error("Load", "need to specify a macro name");
07610       return -1;
07611    }
07612 
07613    if (TestBit(TProof::kIsClient)) {
07614       if (wrks) {
07615          Error("Load", "the 'wrks' arg can be used only on the master");
07616          return -1;
07617       }
07618 
07619       // Extract the file implementation name first
07620       TString addsname, implname = macro;
07621       Ssiz_t icom = implname.Index(",");
07622       if (icom != kNPOS) {
07623          addsname = implname(icom + 1, implname.Length());
07624          implname.Remove(icom);
07625       }
07626       TString basemacro = gSystem->BaseName(implname), mainmacro(implname);
07627       TString acmode, args, io;
07628       implname = gSystem->SplitAclicMode(implname, acmode, args, io);
07629 
07630       // Macro names must have a standard format
07631       Int_t dot = implname.Last('.');
07632       if (dot == kNPOS) {
07633          Info("Load", "macro '%s' does not contain a '.': do nothing", macro);
07634          return -1;
07635       }
07636 
07637       // Is there any associated header file
07638       Bool_t hasHeader = kTRUE;
07639       TString headname = implname;
07640       headname.Remove(dot);
07641       headname += ".h";
07642       if (gSystem->AccessPathName(headname, kReadPermission)) {
07643          TString h = headname;
07644          headname.Remove(dot);
07645          headname += ".hh";
07646          if (gSystem->AccessPathName(headname, kReadPermission)) {
07647             hasHeader = kFALSE;
07648             if (gDebug > 0)
07649                Info("Load", "no associated header file found: tried: %s %s",
07650                             h.Data(), headname.Data());
07651          }
07652       }
07653       
07654       // Is there any additional file ?
07655       TString addincs;
07656       TList addfiles;
07657       if (!addsname.IsNull()) {
07658          TString fn;
07659          Int_t from = 0;
07660          while (addsname.Tokenize(fn, from, ",")) {
07661             if (gSystem->AccessPathName(fn, kReadPermission)) {
07662                Error("Load", "additional file '%s' not found", fn.Data());
07663                return -1;
07664             }
07665             // Create the additional include statement
07666             if (!notOnClient) {
07667                TString dirn(gSystem->DirName(fn));
07668                if (addincs.IsNull()) {
07669                   addincs.Form("-I%s", dirn.Data());
07670                } else if (!addincs.Contains(dirn)) {
07671                   addincs += TString::Format(" -I%s", dirn.Data());
07672                }
07673             }
07674             // Remember these files ...
07675             addfiles.Add(new TObjString(fn));
07676          }
07677       }
07678 
07679       // Send files now; the md5 check is run here; see SendFile for more
07680       // details.
07681       if (SendFile(implname, kAscii | kForward , "cache") == -1) {
07682          Error("Load", "problems sending implementation file %s", implname.Data());
07683          return -1;
07684       }
07685       if (hasHeader)
07686          if (SendFile(headname, kAscii | kForward , "cache") == -1) {
07687             Error("Load", "problems sending header file %s", headname.Data());
07688             return -1;
07689          }
07690       // Additional files
07691       if (addfiles.GetSize() > 0) {
07692          TIter nxfn(&addfiles);
07693          TObjString *os = 0;
07694          while ((os = (TObjString *) nxfn())) {
07695             if (SendFile(os->GetName(), kAscii | kForward , "cache") == -1) {
07696                Error("Load", "problems sending additional file %s", os->GetName());
07697                return -1;
07698             }
07699          }
07700          addfiles.SetOwner(kTRUE);
07701       }
07702          
07703       // The files are now on the workers: now we send the loading request
07704       TMessage mess(kPROOF_CACHE);
07705       mess << Int_t(kLoadMacro) << basemacro;
07706       Broadcast(mess, kActive);
07707 
07708       // Load locally, if required
07709       if (!notOnClient) {
07710          // Mofify the include path
07711          TString oldincs = gSystem->GetIncludePath();
07712          if (!addincs.IsNull()) gSystem->AddIncludePath(addincs);
07713          
07714          // By first forwarding the load command to the master and workers
07715          // and only then loading locally we load/build in parallel
07716          gROOT->ProcessLine(Form(".L %s", mainmacro.Data()));
07717          
07718          // Restore include path
07719          if (!addincs.IsNull()) gSystem->SetIncludePath(oldincs);
07720 
07721          // Update the macro path
07722          TString mp(TROOT::GetMacroPath());
07723          TString np(gSystem->DirName(macro));
07724          if (!np.IsNull()) {
07725             np += ":";
07726             if (!mp.BeginsWith(np) && !mp.Contains(":"+np)) {
07727                Int_t ip = (mp.BeginsWith(".:")) ? 2 : 0;
07728                mp.Insert(ip, np);
07729                TROOT::SetMacroPath(mp);
07730                if (gDebug > 0)
07731                   Info("Load", "macro path set to '%s'", TROOT::GetMacroPath());
07732             }
07733          }
07734       }
07735 
07736       // Wait for master and workers to be done
07737       Collect(kActive);
07738 
07739    } else {
07740       // On master
07741 
07742       // The files are now on the workers: now we send the loading request first
07743       // to the unique workers, so that the eventual compilation occurs only once.
07744       TString basemacro = gSystem->BaseName(macro);
07745       TMessage mess(kPROOF_CACHE);
07746 
07747       if (uniqueWorkers) {
07748          mess << Int_t(kLoadMacro) << basemacro;
07749          if (wrks)
07750             Broadcast(mess, wrks);
07751          else
07752             Broadcast(mess, kUnique);
07753       } else {
07754          // Wait for the result of the previous sending
07755          Collect(kUnique);
07756 
07757          // We then send a tuned loading request to the other workers
07758          TList others;
07759          TSlave *wrk = 0;
07760          TIter nxw(fActiveSlaves);
07761          while ((wrk = (TSlave *)nxw())) {
07762             if (!fUniqueSlaves->FindObject(wrk)) {
07763                others.Add(wrk);
07764             }
07765          }
07766 
07767          // Do not force compilation, if it was requested
07768          Int_t ld = basemacro.Last('.');
07769          if (ld != kNPOS) {
07770             Int_t lpp = basemacro.Index("++", ld);
07771             if (lpp != kNPOS) basemacro.Replace(lpp, 2, "+");
07772          }
07773          mess << Int_t(kLoadMacro) << basemacro;
07774          Broadcast(mess, &others);
07775          Collect(&others);
07776       }
07777 
07778       PDB(kGlobal, 1) Info("Load", "adding loaded macro: %s", macro);
07779       if (!fLoadedMacros) {
07780          fLoadedMacros = new TList();
07781          fLoadedMacros->SetOwner();
07782       }
07783       // if wrks is specified the macro should already be loaded on the master.
07784       if (!wrks)
07785          fLoadedMacros->Add(new TObjString(macro));
07786    }
07787 
07788    // Done
07789    return 0;
07790 }
07791 
07792 //______________________________________________________________________________
07793 Int_t TProof::AddDynamicPath(const char *libpath, Bool_t onClient, TList *wrks)
07794 {
07795    // Add 'libpath' to the lib path search.
07796    // Multiple paths can be specified at once separating them with a comma or
07797    // a blank.
07798    // Return 0 on success, -1 otherwise
07799 
07800    if ((!libpath || !strlen(libpath))) {
07801       if (gDebug > 0)
07802          Info("AddDynamicPath", "list is empty - nothing to do");
07803       return 0;
07804    }
07805 
07806    // Do it also on clients, if required
07807    if (onClient)
07808       HandleLibIncPath("lib", kTRUE, libpath);
07809 
07810    TMessage m(kPROOF_LIB_INC_PATH);
07811    m << TString("lib") << (Bool_t)kTRUE;
07812 
07813    // Add paths
07814    if (libpath && strlen(libpath))
07815       m << TString(libpath);
07816    else
07817       m << TString("-");
07818 
07819    // Forward the request
07820    if (wrks)
07821       Broadcast(m, wrks);
07822    else
07823       Broadcast(m);
07824    Collect(kActive, fCollectTimeout);
07825 
07826    return 0;
07827 }
07828 
07829 //______________________________________________________________________________
07830 Int_t TProof::AddIncludePath(const char *incpath, Bool_t onClient, TList *wrks)
07831 {
07832    // Add 'incpath' to the inc path search.
07833    // Multiple paths can be specified at once separating them with a comma or
07834    // a blank.
07835    // Return 0 on success, -1 otherwise
07836 
07837    if ((!incpath || !strlen(incpath))) {
07838       if (gDebug > 0)
07839          Info("AddIncludePath", "list is empty - nothing to do");
07840       return 0;
07841    }
07842 
07843    // Do it also on clients, if required
07844    if (onClient)
07845       HandleLibIncPath("inc", kTRUE, incpath);
07846 
07847    TMessage m(kPROOF_LIB_INC_PATH);
07848    m << TString("inc") << (Bool_t)kTRUE;
07849 
07850    // Add paths
07851    if (incpath && strlen(incpath))
07852       m << TString(incpath);
07853    else
07854       m << TString("-");
07855 
07856    // Forward the request
07857    if (wrks)
07858       Broadcast(m, wrks);
07859    else
07860       Broadcast(m);
07861    Collect(kActive, fCollectTimeout);
07862 
07863    return 0;
07864 }
07865 
07866 //______________________________________________________________________________
07867 Int_t TProof::RemoveDynamicPath(const char *libpath, Bool_t onClient)
07868 {
07869    // Remove 'libpath' from the lib path search.
07870    // Multiple paths can be specified at once separating them with a comma or
07871    // a blank.
07872    // Return 0 on success, -1 otherwise
07873 
07874    if ((!libpath || !strlen(libpath))) {
07875       if (gDebug > 0)
07876          Info("RemoveDynamicPath", "list is empty - nothing to do");
07877       return 0;
07878    }
07879 
07880    // Do it also on clients, if required
07881    if (onClient)
07882       HandleLibIncPath("lib", kFALSE, libpath);
07883 
07884    TMessage m(kPROOF_LIB_INC_PATH);
07885    m << TString("lib") <<(Bool_t)kFALSE;
07886 
07887    // Add paths
07888    if (libpath && strlen(libpath))
07889       m << TString(libpath);
07890    else
07891       m << TString("-");
07892 
07893    // Forward the request
07894    Broadcast(m);
07895    Collect(kActive, fCollectTimeout);
07896 
07897    return 0;
07898 }
07899 
07900 //______________________________________________________________________________
07901 Int_t TProof::RemoveIncludePath(const char *incpath, Bool_t onClient)
07902 {
07903    // Remove 'incpath' from the inc path search.
07904    // Multiple paths can be specified at once separating them with a comma or
07905    // a blank.
07906    // Return 0 on success, -1 otherwise
07907 
07908    if ((!incpath || !strlen(incpath))) {
07909       if (gDebug > 0)
07910          Info("RemoveIncludePath", "list is empty - nothing to do");
07911       return 0;
07912    }
07913 
07914    // Do it also on clients, if required
07915    if (onClient)
07916       HandleLibIncPath("in", kFALSE, incpath);
07917 
07918    TMessage m(kPROOF_LIB_INC_PATH);
07919    m << TString("inc") << (Bool_t)kFALSE;
07920 
07921    // Add paths
07922    if (incpath && strlen(incpath))
07923       m << TString(incpath);
07924    else
07925       m << TString("-");
07926 
07927    // Forward the request
07928    Broadcast(m);
07929    Collect(kActive, fCollectTimeout);
07930 
07931    return 0;
07932 }
07933 
07934 //______________________________________________________________________________
07935 void TProof::HandleLibIncPath(const char *what, Bool_t add, const char *dirs)
07936 {
07937    // Handle lib, inc search paths modification request
07938 
07939    TString type(what);
07940    TString path(dirs);
07941 
07942    // Check type of action
07943    if ((type != "lib") && (type != "inc")) {
07944       Error("HandleLibIncPath","unknown action type: %s - protocol error?", type.Data());
07945       return;
07946    }
07947 
07948    // Separators can be either commas or blanks
07949    path.ReplaceAll(","," ");
07950 
07951    // Decompose lists
07952    TObjArray *op = 0;
07953    if (path.Length() > 0 && path != "-") {
07954       if (!(op = path.Tokenize(" "))) {
07955          Warning("HandleLibIncPath","decomposing path %s", path.Data());
07956          return;
07957       }
07958    }
07959 
07960    if (add) {
07961 
07962       if (type == "lib") {
07963 
07964          // Add libs
07965          TIter nxl(op, kIterBackward);
07966          TObjString *lib = 0;
07967          while ((lib = (TObjString *) nxl())) {
07968             // Expand path
07969             TString xlib = lib->GetName();
07970             gSystem->ExpandPathName(xlib);
07971             // Add to the dynamic lib search path if it exists and can be read
07972             if (!gSystem->AccessPathName(xlib, kReadPermission)) {
07973                TString newlibpath = gSystem->GetDynamicPath();
07974                // In the first position after the working dir
07975                Int_t pos = 0;
07976                if (newlibpath.BeginsWith(".:"))
07977                   pos = 2;
07978                if (newlibpath.Index(xlib) == kNPOS) {
07979                   newlibpath.Insert(pos,Form("%s:", xlib.Data()));
07980                   gSystem->SetDynamicPath(newlibpath);
07981                }
07982             } else {
07983                if (gDebug > 0)
07984                   Info("HandleLibIncPath",
07985                        "libpath %s does not exist or cannot be read - not added", xlib.Data());
07986             }
07987          }
07988 
07989       } else {
07990 
07991          // Add incs
07992          TIter nxi(op);
07993          TObjString *inc = 0;
07994          while ((inc = (TObjString *) nxi())) {
07995             // Expand path
07996             TString xinc = inc->GetName();
07997             gSystem->ExpandPathName(xinc);
07998             // Add to the dynamic lib search path if it exists and can be read
07999             if (!gSystem->AccessPathName(xinc, kReadPermission)) {
08000                TString curincpath = gSystem->GetIncludePath();
08001                if (curincpath.Index(xinc) == kNPOS)
08002                   gSystem->AddIncludePath(Form("-I%s", xinc.Data()));
08003             } else
08004                if (gDebug > 0)
08005                    Info("HandleLibIncPath",
08006                         "incpath %s does not exist or cannot be read - not added", xinc.Data());
08007          }
08008       }
08009 
08010 
08011    } else {
08012 
08013       if (type == "lib") {
08014 
08015          // Remove libs
08016          TIter nxl(op);
08017          TObjString *lib = 0;
08018          while ((lib = (TObjString *) nxl())) {
08019             // Expand path
08020             TString xlib = lib->GetName();
08021             gSystem->ExpandPathName(xlib);
08022             // Remove from the dynamic lib search path
08023             TString newlibpath = gSystem->GetDynamicPath();
08024             newlibpath.ReplaceAll(Form("%s:", xlib.Data()),"");
08025             gSystem->SetDynamicPath(newlibpath);
08026          }
08027 
08028       } else {
08029 
08030          // Remove incs
08031          TIter nxi(op);
08032          TObjString *inc = 0;
08033          while ((inc = (TObjString *) nxi())) {
08034             TString newincpath = gSystem->GetIncludePath();
08035             newincpath.ReplaceAll(Form("-I%s", inc->GetName()),"");
08036             // Remove the interpreter path (added anyhow internally)
08037             newincpath.ReplaceAll(gInterpreter->GetIncludePath(),"");
08038             gSystem->SetIncludePath(newincpath);
08039          }
08040       }
08041    }
08042 }
08043 
08044 //______________________________________________________________________________
08045 TList *TProof::GetListOfPackages()
08046 {
08047    // Get from the master the list of names of the packages available.
08048 
08049    if (!IsValid())
08050       return (TList *)0;
08051 
08052    TMessage mess(kPROOF_CACHE);
08053    mess << Int_t(kListPackages);
08054    Broadcast(mess);
08055    Collect(kActive, fCollectTimeout);
08056 
08057    return fAvailablePackages;
08058 }
08059 
08060 //______________________________________________________________________________
08061 TList *TProof::GetListOfEnabledPackages()
08062 {
08063    // Get from the master the list of names of the packages enabled.
08064 
08065    if (!IsValid())
08066       return (TList *)0;
08067 
08068    TMessage mess(kPROOF_CACHE);
08069    mess << Int_t(kListEnabledPackages);
08070    Broadcast(mess);
08071    Collect(kActive, fCollectTimeout);
08072 
08073    return fEnabledPackages;
08074 }
08075 
08076 //______________________________________________________________________________
08077 void TProof::PrintProgress(Long64_t total, Long64_t processed,
08078                            Float_t procTime, Long64_t bytesread)
08079 {
08080    // Print a progress bar on stderr. Used in batch mode.
08081 
08082    if (fPrintProgress) {
08083       Bool_t redirlog = fRedirLog;
08084       fRedirLog = kFALSE;
08085       // Call the external function
08086       (*fPrintProgress)(total, processed, procTime, bytesread);
08087       fRedirLog = redirlog;
08088       return;
08089    }
08090 
08091    fprintf(stderr, "[TProof::Progress] Total %lld events\t|", total);
08092 
08093    for (int l = 0; l < 20; l++) {
08094       if (total > 0) {
08095          if (l < 20*processed/total)
08096             fprintf(stderr, "=");
08097          else if (l == 20*processed/total)
08098             fprintf(stderr, ">");
08099          else if (l > 20*processed/total)
08100             fprintf(stderr, ".");
08101       } else
08102          fprintf(stderr, "=");
08103    }
08104    Float_t evtrti = (procTime > 0. && processed > 0) ? processed / procTime : -1.;
08105    Float_t mbsrti = (procTime > 0. && bytesread > 0) ? bytesread / procTime : -1.;
08106    if (evtrti > 0.) {
08107       if (mbsrti > 0.) {
08108          TString sunit("B/s");
08109          const Float_t toK = 1024., toM = 1048576., toG = 1073741824.;
08110          if (mbsrti >= toG) {
08111             mbsrti /= toG;
08112             sunit = "GB/s";
08113          } else if (mbsrti >= toM) {
08114             mbsrti /= toM;
08115             sunit = "MB/s";
08116          } else if (mbsrti >= toK) {
08117             mbsrti /= toK;
08118             sunit = "kB/s";
08119          }
08120          fprintf(stderr, "| %.02f %% [%.1f evts/s, %.1f %s]\r",
08121                 (total ? ((100.0*processed)/total) : 100.0), evtrti, mbsrti, sunit.Data());
08122       } else {
08123          fprintf(stderr, "| %.02f %% [%.1f evts/s]\r",
08124                 (total ? ((100.0*processed)/total) : 100.0), evtrti);
08125       }
08126    } else {
08127       fprintf(stderr, "| %.02f %%\r",
08128               (total ? ((100.0*processed)/total) : 100.0));
08129    }
08130    if (processed >= total)
08131       fprintf(stderr, "\n");
08132 }
08133 
08134 //______________________________________________________________________________
08135 void TProof::Progress(Long64_t total, Long64_t processed)
08136 {
08137    // Get query progress information. Connect a slot to this signal
08138    // to track progress.
08139 
08140    if (fPrintProgress) {
08141       // Call the external function
08142       return (*fPrintProgress)(total, processed, -1., -1);
08143    }
08144 
08145    PDB(kGlobal,1)
08146       Info("Progress","%2f (%lld/%lld)", 100.*processed/total, processed, total);
08147 
08148    if (gROOT->IsBatch()) {
08149       // Simple progress bar
08150       if (total > 0)
08151          PrintProgress(total, processed);
08152    } else {
08153       EmitVA("Progress(Long64_t,Long64_t)", 2, total, processed);
08154    }
08155 }
08156 
08157 //______________________________________________________________________________
08158 void TProof::Progress(Long64_t total, Long64_t processed, Long64_t bytesread,
08159                       Float_t initTime, Float_t procTime,
08160                       Float_t evtrti, Float_t mbrti)
08161 {
08162    // Get query progress information. Connect a slot to this signal
08163    // to track progress.
08164 
08165    PDB(kGlobal,1)
08166       Info("Progress","%lld %lld %lld %f %f %f %f", total, processed, bytesread,
08167                                 initTime, procTime, evtrti, mbrti);
08168 
08169    if (gROOT->IsBatch()) {
08170       // Simple progress bar
08171       if (total > 0)
08172          PrintProgress(total, processed, procTime, bytesread);
08173    } else {
08174       EmitVA("Progress(Long64_t,Long64_t,Long64_t,Float_t,Float_t,Float_t,Float_t)",
08175              7, total, processed, bytesread, initTime, procTime, evtrti, mbrti);
08176    }
08177 }
08178 
08179 //______________________________________________________________________________
08180 void TProof::Progress(Long64_t total, Long64_t processed, Long64_t bytesread,
08181                       Float_t initTime, Float_t procTime,
08182                       Float_t evtrti, Float_t mbrti, Int_t actw, Int_t tses, Float_t eses)
08183 {
08184    // Get query progress information. Connect a slot to this signal
08185    // to track progress.
08186 
08187    PDB(kGlobal,1)
08188       Info("Progress","%lld %lld %lld %f %f %f %f %d %f", total, processed, bytesread,
08189                                 initTime, procTime, evtrti, mbrti, actw, eses);
08190 
08191    if (gROOT->IsBatch()) {
08192       // Simple progress bar
08193       if (total > 0)
08194          PrintProgress(total, processed, procTime, bytesread);
08195    } else {
08196       EmitVA("Progress(Long64_t,Long64_t,Long64_t,Float_t,Float_t,Float_t,Float_t,Int_t,Int_t,Float_t)",
08197              10, total, processed, bytesread, initTime, procTime, evtrti, mbrti, actw, tses, eses);
08198    }
08199 }
08200 
08201 //______________________________________________________________________________
08202 void TProof::Feedback(TList *objs)
08203 {
08204    // Get list of feedback objects. Connect a slot to this signal
08205    // to monitor the feedback object.
08206 
08207    PDB(kGlobal,1)
08208       Info("Feedback","%d objects", objs->GetSize());
08209    PDB(kFeedback,1) {
08210       Info("Feedback","%d objects", objs->GetSize());
08211       objs->ls();
08212    }
08213 
08214    Emit("Feedback(TList *objs)", (Long_t) objs);
08215 }
08216 
08217 //______________________________________________________________________________
08218 void TProof::CloseProgressDialog()
08219 {
08220    // Close progress dialog.
08221 
08222    PDB(kGlobal,1)
08223       Info("CloseProgressDialog",
08224            "called: have progress dialog: %d", fProgressDialogStarted);
08225 
08226    // Nothing to do if not there
08227    if (!fProgressDialogStarted)
08228       return;
08229 
08230    Emit("CloseProgressDialog()");
08231 }
08232 
08233 //______________________________________________________________________________
08234 void TProof::ResetProgressDialog(const char *sel, Int_t sz, Long64_t fst,
08235                                  Long64_t ent)
08236 {
08237    // Reset progress dialog.
08238 
08239    PDB(kGlobal,1)
08240       Info("ResetProgressDialog","(%s,%d,%lld,%lld)", sel, sz, fst, ent);
08241 
08242    EmitVA("ResetProgressDialog(const char*,Int_t,Long64_t,Long64_t)",
08243           4, sel, sz, fst, ent);
08244 }
08245 
08246 //______________________________________________________________________________
08247 void TProof::StartupMessage(const char *msg, Bool_t st, Int_t done, Int_t total)
08248 {
08249    // Send startup message.
08250 
08251    PDB(kGlobal,1)
08252       Info("StartupMessage","(%s,%d,%d,%d)", msg, st, done, total);
08253 
08254    EmitVA("StartupMessage(const char*,Bool_t,Int_t,Int_t)",
08255           4, msg, st, done, total);
08256 }
08257 
08258 //______________________________________________________________________________
08259 void TProof::DataSetStatus(const char *msg, Bool_t st, Int_t done, Int_t total)
08260 {
08261    // Send dataset preparation status.
08262 
08263    PDB(kGlobal,1)
08264       Info("DataSetStatus","(%s,%d,%d,%d)", msg, st, done, total);
08265 
08266    EmitVA("DataSetStatus(const char*,Bool_t,Int_t,Int_t)",
08267           4, msg, st, done, total);
08268 }
08269 
08270 //______________________________________________________________________________
08271 void TProof::SendDataSetStatus(const char *action, UInt_t done,
08272                                UInt_t tot, Bool_t st)
08273 {
08274    // Send or notify data set status
08275 
08276    if (IsLite()) {
08277       if (tot) {
08278          TString type = "files";
08279          Int_t frac = (Int_t) (done*100.)/tot;
08280          char msg[512] = {0};
08281          if (frac >= 100) {
08282             snprintf(msg, 512, "%s: OK (%d %s)                 \n",
08283                      action,tot, type.Data());
08284          } else {
08285             snprintf(msg, 512, "%s: %d out of %d (%d %%)\r",
08286                      action, done, tot, frac);
08287          }
08288          if (fSync)
08289             fprintf(stderr,"%s", msg);
08290          else
08291             NotifyLogMsg(msg, 0);
08292       }
08293       return;
08294    }
08295 
08296    if (TestBit(TProof::kIsMaster)) {
08297       TMessage mess(kPROOF_DATASET_STATUS);
08298       mess << TString(action) << tot << done << st;
08299       gProofServ->GetSocket()->Send(mess);
08300    }
08301 }
08302 
08303 //______________________________________________________________________________
08304 void TProof::QueryResultReady(const char *ref)
08305 {
08306    // Notify availability of a query result.
08307 
08308    PDB(kGlobal,1)
08309       Info("QueryResultReady","ref: %s", ref);
08310 
08311    Emit("QueryResultReady(const char*)",ref);
08312 }
08313 
08314 //______________________________________________________________________________
08315 void TProof::ValidateDSet(TDSet *dset)
08316 {
08317    // Validate a TDSet.
08318 
08319    if (dset->ElementsValid()) return;
08320 
08321    TList nodes;
08322    nodes.SetOwner();
08323 
08324    TList slholder;
08325    slholder.SetOwner();
08326    TList elemholder;
08327    elemholder.SetOwner();
08328 
08329    // build nodelist with slaves and elements
08330    TIter nextSlave(GetListOfActiveSlaves());
08331    while (TSlave *sl = dynamic_cast<TSlave*>(nextSlave())) {
08332       TList *sllist = 0;
08333       TPair *p = dynamic_cast<TPair*>(nodes.FindObject(sl->GetName()));
08334       if (!p) {
08335          sllist = new TList;
08336          sllist->SetName(sl->GetName());
08337          slholder.Add(sllist);
08338          TList *elemlist = new TList;
08339          elemlist->SetName(TString(sl->GetName())+"_elem");
08340          elemholder.Add(elemlist);
08341          nodes.Add(new TPair(sllist, elemlist));
08342       } else {
08343          sllist = dynamic_cast<TList*>(p->Key());
08344       }
08345       if (sllist) sllist->Add(sl);
08346    }
08347 
08348    // add local elements to nodes
08349    TList nonLocal; // list of nonlocal elements
08350    // make two iterations - first add local elements - then distribute nonlocals
08351    for (Int_t i = 0; i < 2; i++) {
08352       Bool_t local = i>0?kFALSE:kTRUE;
08353       TIter nextElem(local ? dset->GetListOfElements() : &nonLocal);
08354       while (TDSetElement *elem = dynamic_cast<TDSetElement*>(nextElem())) {
08355          if (elem->GetValid()) continue;
08356          TPair *p = dynamic_cast<TPair*>(local?nodes.FindObject(TUrl(elem->GetFileName()).GetHost()):nodes.At(0));
08357          if (p) {
08358             TList *eli = dynamic_cast<TList*>(p->Value());
08359             TList *sli = dynamic_cast<TList*>(p->Key());
08360             if (eli && sli) {
08361                eli->Add(elem);
08362 
08363                // order list by elements/slave
08364                TPair *p2 = p;
08365                Bool_t stop = kFALSE;
08366                while (!stop) {
08367                   TPair *p3 = dynamic_cast<TPair*>(nodes.After(p2->Key()));
08368                   if (p3) {
08369                      TList *p3v = dynamic_cast<TList*>(p3->Value());
08370                      TList *p3k = dynamic_cast<TList*>(p3->Key());
08371                      if (p3v && p3k) {
08372                         Int_t nelem = p3v->GetSize();
08373                         Int_t nsl = p3k->GetSize();
08374                         if (nelem*sli->GetSize() < eli->GetSize()*nsl) p2 = p3;
08375                         else stop = kTRUE;
08376                      }
08377                   } else {
08378                      stop = kTRUE;
08379                   }
08380                }
08381 
08382                if (p2!=p) {
08383                   nodes.Remove(p->Key());
08384                   nodes.AddAfter(p2->Key(), p);
08385                }
08386             } else {
08387                Warning("ValidateDSet", "invalid values from TPair! Protocol error?");
08388                continue;
08389             }
08390 
08391          } else {
08392             if (local) {
08393                nonLocal.Add(elem);
08394             } else {
08395                Warning("ValidateDSet", "no node to allocate TDSetElement to - ignoring");
08396             }
08397          }
08398       }
08399    }
08400 
08401    // send to slaves
08402    TList usedslaves;
08403    TIter nextNode(&nodes);
08404    SetDSet(dset); // set dset to be validated in Collect()
08405    while (TPair *node = dynamic_cast<TPair*>(nextNode())) {
08406       TList *slaves = dynamic_cast<TList*>(node->Key());
08407       TList *setelements = dynamic_cast<TList*>(node->Value());
08408       if (!slaves || !setelements) continue;
08409       // distribute elements over the slaves
08410       Int_t nslaves = slaves->GetSize();
08411       Int_t nelements = setelements->GetSize();
08412       for (Int_t i=0; i<nslaves; i++) {
08413 
08414          TDSet copyset(dset->GetType(), dset->GetObjName(),
08415                        dset->GetDirectory());
08416          for (Int_t j = (i*nelements)/nslaves;
08417                     j < ((i+1)*nelements)/nslaves;
08418                     j++) {
08419             TDSetElement *elem =
08420                dynamic_cast<TDSetElement*>(setelements->At(j));
08421             if (elem) {
08422                copyset.Add(elem->GetFileName(), elem->GetObjName(),
08423                            elem->GetDirectory(), elem->GetFirst(),
08424                            elem->GetNum(), elem->GetMsd());
08425             }
08426          }
08427 
08428          if (copyset.GetListOfElements()->GetSize()>0) {
08429             TMessage mesg(kPROOF_VALIDATE_DSET);
08430             mesg << &copyset;
08431 
08432             TSlave *sl = dynamic_cast<TSlave*>(slaves->At(i));
08433             if (sl) {
08434                PDB(kGlobal,1) Info("ValidateDSet",
08435                                  "Sending TDSet with %d elements to slave %s"
08436                                  " to be validated",
08437                                  copyset.GetListOfElements()->GetSize(),
08438                                  sl->GetOrdinal());
08439                sl->GetSocket()->Send(mesg);
08440                usedslaves.Add(sl);
08441             }
08442          }
08443       }
08444    }
08445 
08446    PDB(kGlobal,1)
08447       Info("ValidateDSet","Calling Collect");
08448    Collect(&usedslaves);
08449    SetDSet(0);
08450 }
08451 
08452 //______________________________________________________________________________
08453 void TProof::AddInputData(TObject *obj, Bool_t push)
08454 {
08455    // Add data objects that might be needed during the processing of
08456    // the selector (see Process()). This object can be very large, so they
08457    // are distributed in an optimized way using a dedicated file.
08458    // If push is TRUE the input data are sent over even if no apparent change
08459    // occured to the list.
08460 
08461    if (obj) {
08462       if (!fInputData) fInputData = new TList;
08463       if (!fInputData->FindObject(obj)) {
08464          fInputData->Add(obj);
08465          SetBit(TProof::kNewInputData);
08466       }
08467    }
08468    if (push) SetBit(TProof::kNewInputData);
08469 }
08470 
08471 //______________________________________________________________________________
08472 void TProof::ClearInputData(TObject *obj)
08473 {
08474    // Remove obj form the input data list; if obj is null (default), clear the
08475    // input data info.
08476 
08477    if (!obj) {
08478       if (fInputData) {
08479          fInputData->SetOwner(kTRUE);
08480          SafeDelete(fInputData);
08481       }
08482       ResetBit(TProof::kNewInputData);
08483 
08484       // Also remove any info about input data in the input list
08485       TObject *o = 0;
08486       TList *in = GetInputList();
08487       while ((o = GetInputList()->FindObject("PROOF_InputDataFile")))
08488          in->Remove(o);
08489       while ((o = GetInputList()->FindObject("PROOF_InputData")))
08490          in->Remove(o);
08491 
08492       // ... and reset the file
08493       fInputDataFile = "";
08494       gSystem->Unlink(kPROOF_InputDataFile);
08495 
08496    } else if (fInputData) {
08497       Int_t sz = fInputData->GetSize();
08498       while (fInputData->FindObject(obj))
08499          fInputData->Remove(obj);
08500       // Flag for update, if anything changed
08501       if (sz != fInputData->GetSize())
08502          SetBit(TProof::kNewInputData);
08503    }
08504 }
08505 
08506 //______________________________________________________________________________
08507 void TProof::ClearInputData(const char *name)
08508 {
08509    // Remove obj 'name' form the input data list;
08510 
08511    TObject *obj = (fInputData && name) ? fInputData->FindObject(name) : 0;
08512    if (obj) ClearInputData(obj);
08513 }
08514 
08515 //______________________________________________________________________________
08516 void TProof::SetInputDataFile(const char *datafile)
08517 {
08518    // Set the file to be used to optimally distribute the input data objects.
08519    // If the file exists the object in the file are added to those in the
08520    // fInputData list. If the file path is null, a default file will be created
08521    // at the moment of sending the processing request with the content of
08522    // the fInputData list. See also SendInputDataFile.
08523 
08524    if (datafile && strlen(datafile) > 0) {
08525       if (fInputDataFile != datafile && strcmp(datafile, kPROOF_InputDataFile))
08526          SetBit(TProof::kNewInputData);
08527       fInputDataFile = datafile;
08528    } else {
08529       if (!fInputDataFile.IsNull())
08530          SetBit(TProof::kNewInputData);
08531       fInputDataFile = "";
08532    }
08533    // Make sure that the chosen file is readable
08534    if (fInputDataFile != kPROOF_InputDataFile && !fInputDataFile.IsNull() &&
08535       gSystem->AccessPathName(fInputDataFile, kReadPermission)) {
08536       fInputDataFile = "";
08537    }
08538 }
08539 
08540 //______________________________________________________________________________
08541 void TProof::SendInputDataFile()
08542 {
08543    // Send the input data objects to the master; the objects are taken from the
08544    // dedicated list and / or the specified file.
08545    // If the fInputData is empty the specified file is sent over.
08546    // If there is no specified file, a file named "inputdata.root" is created locally
08547    // with the content of fInputData and sent over to the master.
08548    // If both fInputData and the specified file are not empty, a copy of the file
08549    // is made locally and augmented with the content of fInputData.
08550 
08551    // Prepare the file
08552    TString dataFile;
08553    PrepareInputDataFile(dataFile);
08554 
08555    // Send it, if not empty
08556    if (dataFile.Length() > 0) {
08557 
08558       Info("SendInputDataFile", "broadcasting %s", dataFile.Data());
08559       BroadcastFile(dataFile.Data(), kBinary, "cache", kActive);
08560 
08561       // Set the name in the input list
08562       AddInput(new TNamed("PROOF_InputDataFile", Form("cache:%s", gSystem->BaseName(dataFile))));
08563    }
08564 }
08565 
08566 //______________________________________________________________________________
08567 void TProof::PrepareInputDataFile(TString &dataFile)
08568 {
08569    // Prepare the file with the input data objects to be sent the master; the
08570    // objects are taken from the dedicated list and / or the specified file.
08571    // If the fInputData is empty the specified file is sent over.
08572    // If there is no specified file, a file named "inputdata.root" is created locally
08573    // with the content of fInputData and sent over to the master.
08574    // If both fInputData and the specified file are not empty, a copy of the file
08575    // is made locally and augmented with the content of fInputData.
08576 
08577    // Save info about new data for usage in this call;
08578    Bool_t newdata = TestBit(TProof::kNewInputData) ? kTRUE : kFALSE;
08579    // Next time we need some change
08580    ResetBit(TProof::kNewInputData);
08581 
08582    // Check the list
08583    Bool_t list_ok = (fInputData && fInputData->GetSize() > 0) ? kTRUE : kFALSE;
08584    // Check the file
08585    Bool_t file_ok = kFALSE;
08586    if (fInputDataFile != kPROOF_InputDataFile && !fInputDataFile.IsNull() &&
08587       !gSystem->AccessPathName(fInputDataFile, kReadPermission)) {
08588       // It must contain something
08589       TFile *f = TFile::Open(fInputDataFile);
08590       if (f && f->GetListOfKeys() && f->GetListOfKeys()->GetSize() > 0)
08591          file_ok = kTRUE;
08592    }
08593 
08594    // Remove any info about input data in the input list
08595    TObject *o = 0;
08596    TList *in = GetInputList();
08597    while ((o = GetInputList()->FindObject("PROOF_InputDataFile")))
08598       in->Remove(o);
08599    while ((o = GetInputList()->FindObject("PROOF_InputData")))
08600       in->Remove(o);
08601 
08602    // We must have something to send
08603    dataFile = "";
08604    if (!list_ok && !file_ok) return;
08605 
08606    // Three cases:
08607    if (file_ok && !list_ok) {
08608       // Just send the file
08609       dataFile = fInputDataFile;
08610    } else if (!file_ok && list_ok) {
08611       fInputDataFile = kPROOF_InputDataFile;
08612       // Nothing to do, if no new data
08613       if (!newdata && !gSystem->AccessPathName(fInputDataFile)) return;
08614       // Create the file first
08615       TFile *f = TFile::Open(fInputDataFile, "RECREATE");
08616       if (f) {
08617          f->cd();
08618          TIter next(fInputData);
08619          TObject *obj;
08620          while ((obj = next())) {
08621             obj->Write(0, TObject::kSingleKey, 0);
08622          }
08623          f->Close();
08624          SafeDelete(f);
08625       } else {
08626          Error("PrepareInputDataFile", "could not (re-)create %s", fInputDataFile.Data());
08627          return;
08628       }
08629       dataFile = fInputDataFile;
08630    } else if (file_ok && list_ok) {
08631       dataFile = kPROOF_InputDataFile;
08632       // Create the file if not existing or there are new data
08633       if (newdata || gSystem->AccessPathName(dataFile)) {
08634          // Cleanup previous file if obsolete
08635          if (!gSystem->AccessPathName(dataFile))
08636             gSystem->Unlink(dataFile);
08637          if (dataFile != fInputDataFile) {
08638             // Make a local copy first
08639             if (gSystem->CopyFile(fInputDataFile, dataFile, kTRUE) != 0) {
08640                Error("PrepareInputDataFile", "could not make local copy of %s", fInputDataFile.Data());
08641                return;
08642             }
08643          }
08644          // Add the input data list
08645          TFile *f = TFile::Open(dataFile, "UPDATE");
08646          if (f) {
08647             f->cd();
08648             TIter next(fInputData);
08649             TObject *obj = 0;
08650             while ((obj = next())) {
08651                obj->Write(0, TObject::kSingleKey, 0);
08652             }
08653             f->Close();
08654             SafeDelete(f);
08655          } else {
08656             Error("PrepareInputDataFile", "could not open %s for updating", dataFile.Data());
08657             return;
08658          }
08659       }
08660    }
08661 
08662    //  Done
08663    return;
08664 }
08665 
08666 //______________________________________________________________________________
08667 void TProof::AddInput(TObject *obj)
08668 {
08669    // Add objects that might be needed during the processing of
08670    // the selector (see Process()).
08671 
08672    if (fPlayer) fPlayer->AddInput(obj);
08673 }
08674 
08675 //______________________________________________________________________________
08676 void TProof::ClearInput()
08677 {
08678    // Clear input object list.
08679 
08680    if (fPlayer) fPlayer->ClearInput();
08681 
08682    // the system feedback list is always in the input list
08683    AddInput(fFeedback);
08684 }
08685 
08686 //______________________________________________________________________________
08687 TList *TProof::GetInputList()
08688 {
08689    // Get input list.
08690 
08691    return (fPlayer ? fPlayer->GetInputList() : (TList *)0);
08692 }
08693 
08694 //______________________________________________________________________________
08695 TObject *TProof::GetOutput(const char *name)
08696 {
08697    // Get specified object that has been produced during the processing
08698    // (see Process()).
08699 
08700    // Can be called by MarkBad on the master before the player is initialized
08701    return (fPlayer) ? fPlayer->GetOutput(name) : (TObject *)0;
08702 }
08703 
08704 //______________________________________________________________________________
08705 TList *TProof::GetOutputList()
08706 {
08707    // Get list with all object created during processing (see Process()).
08708 
08709    return (fPlayer ? fPlayer->GetOutputList() : (TList *)0);
08710 }
08711 
08712 //______________________________________________________________________________
08713 void TProof::SetParameter(const char *par, const char *value)
08714 {
08715    // Set input list parameter. If the parameter is already
08716    // set it will be set to the new value.
08717 
08718    if (!fPlayer) {
08719       Warning("SetParameter", "player undefined! Ignoring");
08720       return;
08721    }
08722 
08723    TList *il = fPlayer->GetInputList();
08724    TObject *item = il->FindObject(par);
08725    if (item) {
08726       il->Remove(item);
08727       delete item;
08728    }
08729    il->Add(new TNamed(par, value));
08730 }
08731 
08732 //______________________________________________________________________________
08733 void TProof::SetParameter(const char *par, Int_t value)
08734 {
08735    // Set an input list parameter.
08736 
08737    if (!fPlayer) {
08738       Warning("SetParameter", "player undefined! Ignoring");
08739       return;
08740    }
08741 
08742    TList *il = fPlayer->GetInputList();
08743    TObject *item = il->FindObject(par);
08744    if (item) {
08745       il->Remove(item);
08746       delete item;
08747    }
08748    il->Add(new TParameter<Int_t>(par, value));
08749 }
08750 
08751 //______________________________________________________________________________
08752 void TProof::SetParameter(const char *par, Long_t value)
08753 {
08754    // Set an input list parameter.
08755 
08756    if (!fPlayer) {
08757       Warning("SetParameter", "player undefined! Ignoring");
08758       return;
08759    }
08760 
08761    TList *il = fPlayer->GetInputList();
08762    TObject *item = il->FindObject(par);
08763    if (item) {
08764       il->Remove(item);
08765       delete item;
08766    }
08767    il->Add(new TParameter<Long_t>(par, value));
08768 }
08769 
08770 //______________________________________________________________________________
08771 void TProof::SetParameter(const char *par, Long64_t value)
08772 {
08773    // Set an input list parameter.
08774 
08775    if (!fPlayer) {
08776       Warning("SetParameter", "player undefined! Ignoring");
08777       return;
08778    }
08779 
08780    TList *il = fPlayer->GetInputList();
08781    TObject *item = il->FindObject(par);
08782    if (item) {
08783       il->Remove(item);
08784       delete item;
08785    }
08786    il->Add(new TParameter<Long64_t>(par, value));
08787 }
08788 
08789 //______________________________________________________________________________
08790 void TProof::SetParameter(const char *par, Double_t value)
08791 {
08792    // Set an input list parameter.
08793 
08794    if (!fPlayer) {
08795       Warning("SetParameter", "player undefined! Ignoring");
08796       return;
08797    }
08798 
08799    TList *il = fPlayer->GetInputList();
08800    TObject *item = il->FindObject(par);
08801    if (item) {
08802       il->Remove(item);
08803       delete item;
08804    }
08805    il->Add(new TParameter<Double_t>(par, value));
08806 }
08807 
08808 //______________________________________________________________________________
08809 TObject *TProof::GetParameter(const char *par) const
08810 {
08811    // Get specified parameter. A parameter set via SetParameter() is either
08812    // a TParameter or a TNamed or 0 in case par is not defined.
08813 
08814    if (!fPlayer) {
08815       Warning("GetParameter", "player undefined! Ignoring");
08816       return (TObject *)0;
08817    }
08818 
08819    TList *il = fPlayer->GetInputList();
08820    return il->FindObject(par);
08821 }
08822 
08823 //______________________________________________________________________________
08824 void TProof::DeleteParameters(const char *wildcard)
08825 {
08826    // Delete the input list parameters specified by a wildcard (e.g. PROOF_*)
08827    // or exact name (e.g. PROOF_MaxSlavesPerNode).
08828 
08829    if (!fPlayer) return;
08830 
08831    if (!wildcard) wildcard = "";
08832    TRegexp re(wildcard, kTRUE);
08833    Int_t nch = strlen(wildcard);
08834 
08835    TList *il = fPlayer->GetInputList();
08836    if (il) {
08837       TObject *p = 0;
08838       TIter next(il);
08839       while ((p = next())) {
08840          TString s = p->GetName();
08841          if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
08842          il->Remove(p);
08843          delete p;
08844       }
08845    }
08846 }
08847 
08848 //______________________________________________________________________________
08849 void TProof::ShowParameters(const char *wildcard) const
08850 {
08851    // Show the input list parameters specified by the wildcard.
08852    // Default is the special PROOF control parameters (PROOF_*).
08853 
08854    if (!fPlayer) return;
08855 
08856    if (!wildcard) wildcard = "";
08857    TRegexp re(wildcard, kTRUE);
08858    Int_t nch = strlen(wildcard);
08859 
08860    TList *il = fPlayer->GetInputList();
08861    TObject *p;
08862    TIter next(il);
08863    while ((p = next())) {
08864       TString s = p->GetName();
08865       if (nch && s != wildcard && s.Index(re) == kNPOS) continue;
08866       if (p->IsA() == TNamed::Class()) {
08867          Printf("%s\t\t\t%s", s.Data(), p->GetTitle());
08868       } else if (p->IsA() == TParameter<Long_t>::Class()) {
08869          Printf("%s\t\t\t%ld", s.Data(), dynamic_cast<TParameter<Long_t>*>(p)->GetVal());
08870       } else if (p->IsA() == TParameter<Long64_t>::Class()) {
08871          Printf("%s\t\t\t%lld", s.Data(), dynamic_cast<TParameter<Long64_t>*>(p)->GetVal());
08872       } else if (p->IsA() == TParameter<Double_t>::Class()) {
08873          Printf("%s\t\t\t%f", s.Data(), dynamic_cast<TParameter<Double_t>*>(p)->GetVal());
08874       } else {
08875          Printf("%s\t\t\t%s", s.Data(), p->GetTitle());
08876       }
08877    }
08878 }
08879 
08880 //______________________________________________________________________________
08881 void TProof::AddFeedback(const char *name)
08882 {
08883    // Add object to feedback list.
08884 
08885    PDB(kFeedback, 3)
08886       Info("AddFeedback", "Adding object \"%s\" to feedback", name);
08887    if (fFeedback->FindObject(name) == 0)
08888       fFeedback->Add(new TObjString(name));
08889 }
08890 
08891 //______________________________________________________________________________
08892 void TProof::RemoveFeedback(const char *name)
08893 {
08894    // Remove object from feedback list.
08895 
08896    TObject *obj = fFeedback->FindObject(name);
08897    if (obj != 0) {
08898       fFeedback->Remove(obj);
08899       delete obj;
08900    }
08901 }
08902 
08903 //______________________________________________________________________________
08904 void TProof::ClearFeedback()
08905 {
08906    // Clear feedback list.
08907 
08908    fFeedback->Delete();
08909 }
08910 
08911 //______________________________________________________________________________
08912 void TProof::ShowFeedback() const
08913 {
08914    // Show items in feedback list.
08915 
08916    if (fFeedback->GetSize() == 0) {
08917       Info("","no feedback requested");
08918       return;
08919    }
08920 
08921    fFeedback->Print();
08922 }
08923 
08924 //______________________________________________________________________________
08925 TList *TProof::GetFeedbackList() const
08926 {
08927    // Return feedback list.
08928 
08929    return fFeedback;
08930 }
08931 
08932 //______________________________________________________________________________
08933 TTree *TProof::GetTreeHeader(TDSet *dset)
08934 {
08935    // Creates a tree header (a tree with nonexisting files) object for
08936    // the DataSet.
08937 
08938    TList *l = GetListOfActiveSlaves();
08939    TSlave *sl = (TSlave*) l->First();
08940    if (sl == 0) {
08941       Error("GetTreeHeader", "No connection");
08942       return 0;
08943    }
08944 
08945    TSocket *soc = sl->GetSocket();
08946    TMessage msg(kPROOF_GETTREEHEADER);
08947 
08948    msg << dset;
08949 
08950    soc->Send(msg);
08951 
08952    TMessage *reply;
08953    Int_t d = -1;
08954    if (fProtocol >= 20) {
08955       Collect(sl, fCollectTimeout, kPROOF_GETTREEHEADER);
08956       reply = (TMessage *) fRecvMessages->First();
08957    } else {
08958       d = soc->Recv(reply);
08959    }
08960    if (!reply) {
08961       Error("GetTreeHeader", "Error getting a replay from the master.Result %d", (int) d);
08962       return 0;
08963    }
08964 
08965    TString s1;
08966    TTree *t = 0;
08967    (*reply) >> s1;
08968    if (s1 == "Success")
08969       (*reply) >> t;
08970 
08971    PDB(kGlobal, 1) {
08972       if (t) {
08973          Info("GetTreeHeader", "%s, message size: %d, entries: %d",
08974                                s1.Data(), reply->BufferSize(), (int) t->GetMaxEntryLoop());
08975       } else {
08976          Info("GetTreeHeader", "tree header retrieval failed");
08977       }
08978    }
08979    delete reply;
08980 
08981    return t;
08982 }
08983 
08984 //______________________________________________________________________________
08985 TDrawFeedback *TProof::CreateDrawFeedback()
08986 {
08987    // Draw feedback creation proxy. When accessed via TProof avoids
08988    // link dependency on libProofPlayer.
08989 
08990    return (fPlayer ? fPlayer->CreateDrawFeedback(this) : (TDrawFeedback *)0);
08991 }
08992 
08993 //______________________________________________________________________________
08994 void TProof::SetDrawFeedbackOption(TDrawFeedback *f, Option_t *opt)
08995 {
08996    // Set draw feedback option.
08997 
08998    if (fPlayer) fPlayer->SetDrawFeedbackOption(f, opt);
08999 }
09000 
09001 //______________________________________________________________________________
09002 void TProof::DeleteDrawFeedback(TDrawFeedback *f)
09003 {
09004    // Delete draw feedback object.
09005 
09006    if (fPlayer) fPlayer->DeleteDrawFeedback(f);
09007 }
09008 
09009 //______________________________________________________________________________
09010 TList *TProof::GetOutputNames()
09011 {
09012    //   FIXME: to be written
09013 
09014    return 0;
09015 /*
09016    TMessage msg(kPROOF_GETOUTPUTLIST);
09017    TList* slaves = fActiveSlaves;
09018    Broadcast(msg, slaves);
09019    TMonitor mon;
09020    TList* outputList = new TList();
09021 
09022    TIter    si(slaves);
09023    TSlave   *slave;
09024    while ((slave = (TSlave*)si.Next()) != 0) {
09025       PDB(kGlobal,4) Info("GetOutputNames","Socket added to monitor: %p (%s)",
09026           slave->GetSocket(), slave->GetName());
09027       mon.Add(slave->GetSocket());
09028    }
09029    mon.ActivateAll();
09030    ((TProof*)gProof)->DeActivateAsyncInput();
09031    ((TProof*)gProof)->fCurrentMonitor = &mon;
09032 
09033    while (mon.GetActive() != 0) {
09034       TSocket *sock = mon.Select();
09035       if (!sock) {
09036          Error("GetOutputList","TMonitor::.Select failed!");
09037          break;
09038       }
09039       mon.DeActivate(sock);
09040       TMessage *reply;
09041       if (sock->Recv(reply) <= 0) {
09042          MarkBad(slave, "receive failed after kPROOF_GETOUTPUTLIST request");
09043 //         Error("GetOutputList","Recv failed! for slave-%d (%s)",
09044 //               slave->GetOrdinal(), slave->GetName());
09045          continue;
09046       }
09047       if (reply->What() != kPROOF_GETOUTPUTNAMES ) {
09048 //         Error("GetOutputList","unexpected message %d from slawe-%d (%s)",  reply->What(),
09049 //               slave->GetOrdinal(), slave->GetName());
09050          MarkBad(slave, "wrong reply to kPROOF_GETOUTPUTLIST request");
09051          continue;
09052       }
09053       TList* l;
09054 
09055       (*reply) >> l;
09056       TIter next(l);
09057       TNamed *n;
09058       while ( (n = dynamic_cast<TNamed*> (next())) ) {
09059          if (!outputList->FindObject(n->GetName()))
09060             outputList->Add(n);
09061       }
09062       delete reply;
09063    }
09064    ((TProof*)gProof)->fCurrentMonitor = 0;
09065 
09066    return outputList;
09067 */
09068 }
09069 
09070 //______________________________________________________________________________
09071 void TProof::Browse(TBrowser *b)
09072 {
09073    // Build the PROOF's structure in the browser.
09074 
09075    b->Add(fActiveSlaves, fActiveSlaves->Class(), "fActiveSlaves");
09076    b->Add(&fMaster, fMaster.Class(), "fMaster");
09077    b->Add(fFeedback, fFeedback->Class(), "fFeedback");
09078    b->Add(fChains, fChains->Class(), "fChains");
09079 
09080    if (fPlayer) {
09081       b->Add(fPlayer->GetInputList(), fPlayer->GetInputList()->Class(), "InputList");
09082       if (fPlayer->GetOutputList())
09083          b->Add(fPlayer->GetOutputList(), fPlayer->GetOutputList()->Class(), "OutputList");
09084       if (fPlayer->GetListOfResults())
09085          b->Add(fPlayer->GetListOfResults(),
09086                fPlayer->GetListOfResults()->Class(), "ListOfResults");
09087    }
09088 }
09089 
09090 //______________________________________________________________________________
09091 void TProof::SetPlayer(TVirtualProofPlayer *player)
09092 {
09093    // Set a new PROOF player.
09094 
09095    if (fPlayer)
09096       delete fPlayer;
09097    fPlayer = player;
09098 };
09099 
09100 //______________________________________________________________________________
09101 TVirtualProofPlayer *TProof::MakePlayer(const char *player, TSocket *s)
09102 {
09103    // Construct a TProofPlayer object. The player string specifies which
09104    // player should be created: remote, slave, sm (supermaster) or base.
09105    // Default is remote. Socket is needed in case a slave player is created.
09106 
09107    if (!player)
09108       player = "remote";
09109 
09110    SetPlayer(TVirtualProofPlayer::Create(player, this, s));
09111    return GetPlayer();
09112 }
09113 
09114 //______________________________________________________________________________
09115 void TProof::AddChain(TChain *chain)
09116 {
09117    // Add chain to data set
09118 
09119    fChains->Add(chain);
09120 }
09121 
09122 //______________________________________________________________________________
09123 void TProof::RemoveChain(TChain *chain)
09124 {
09125    // Remove chain from data set
09126 
09127    fChains->Remove(chain);
09128 }
09129 
09130 //______________________________________________________________________________
09131 void TProof::GetLog(Int_t start, Int_t end)
09132 {
09133    // Ask for remote logs in the range [start, end]. If start == -1 all the
09134    // messages not yet received are sent back.
09135 
09136    if (!IsValid() || TestBit(TProof::kIsMaster)) return;
09137 
09138    TMessage msg(kPROOF_LOGFILE);
09139 
09140    msg << start << end;
09141 
09142    Broadcast(msg, kActive);
09143    Collect(kActive, fCollectTimeout);
09144 }
09145 
09146 //______________________________________________________________________________
09147 TMacro *TProof::GetLastLog()
09148 {
09149    // Fill a TMacro with the log lines since the last reading (fLogFileR)
09150    // Return (TMacro *)0 if no line was logged.
09151    // The returned TMacro must be deleted by the caller.
09152 
09153    TMacro *maclog = 0;
09154 
09155    // Save present offset
09156    off_t nowlog = lseek(fileno(fLogFileR), (off_t) 0, SEEK_CUR);
09157    if (nowlog < 0) {
09158       SysError("GetLastLog",
09159                "problem lseeking log file to current position (errno: %d)", TSystem::GetErrno());
09160       return maclog;
09161    }
09162 
09163    // Get extremes
09164    off_t startlog = nowlog;
09165    off_t endlog = lseek(fileno(fLogFileR), (off_t) 0, SEEK_END);
09166    if (endlog < 0) {
09167       SysError("GetLastLog",
09168                "problem lseeking log file to end position (errno: %d)", TSystem::GetErrno());
09169       return maclog;
09170    }
09171 
09172    // Perhaps nothing to log
09173    UInt_t tolog = (UInt_t)(endlog - startlog);
09174    if (tolog <= 0) return maclog;
09175 
09176    // Set starting point
09177    if (lseek(fileno(fLogFileR), startlog, SEEK_SET) < 0) {
09178       SysError("GetLastLog",
09179                "problem lseeking log file to start position (errno: %d)", TSystem::GetErrno());
09180       return maclog;
09181    }
09182 
09183    // Create the output object
09184    maclog = new TMacro;
09185 
09186    // Now we go
09187    char line[2048];
09188    Int_t wanted = (tolog > sizeof(line)) ? sizeof(line) : tolog;
09189    while (fgets(line, wanted, fLogFileR)) {
09190       Int_t r = strlen(line);
09191       if (r > 0) {
09192          if (line[r-1] == '\n') line[r-1] = '\0';
09193          maclog->AddLine(line);
09194       } else {
09195          // Done
09196          break;
09197       }
09198       tolog -= r;
09199       wanted = (tolog > sizeof(line)) ? sizeof(line) : tolog;
09200    }
09201 
09202    // Restore original pointer
09203    if (lseek(fileno(fLogFileR), nowlog, SEEK_SET) < 0) {
09204       Warning("GetLastLog",
09205               "problem lseeking log file to original position (errno: %d)", TSystem::GetErrno());
09206    }
09207 
09208    // Done
09209    return maclog;
09210 }
09211 
09212 //______________________________________________________________________________
09213 void TProof::PutLog(TQueryResult *pq)
09214 {
09215    // Display log of query pq into the log window frame
09216 
09217    if (!pq) return;
09218 
09219    TList *lines = pq->GetLogFile()->GetListOfLines();
09220    if (lines) {
09221       TIter nxl(lines);
09222       TObjString *l = 0;
09223       while ((l = (TObjString *)nxl()))
09224          EmitVA("LogMessage(const char*,Bool_t)", 2, l->GetName(), kFALSE);
09225    }
09226 }
09227 
09228 //______________________________________________________________________________
09229 void TProof::ShowLog(const char *queryref)
09230 {
09231    // Display on screen the content of the temporary log file for query
09232    // in reference
09233 
09234    // Make sure we have all info (GetListOfQueries retrieves the
09235    // head info only)
09236    Retrieve(queryref);
09237 
09238    if (fPlayer) {
09239       if (queryref) {
09240          if (fPlayer->GetListOfResults()) {
09241             TIter nxq(fPlayer->GetListOfResults());
09242             TQueryResult *qr = 0;
09243             while ((qr = (TQueryResult *) nxq()))
09244                if (strstr(queryref, qr->GetTitle()) &&
09245                    strstr(queryref, qr->GetName()))
09246                   break;
09247             if (qr) {
09248                PutLog(qr);
09249                return;
09250             }
09251 
09252          }
09253       }
09254    }
09255 }
09256 
09257 //______________________________________________________________________________
09258 void TProof::ShowLog(Int_t qry)
09259 {
09260    // Display on screen the content of the temporary log file.
09261    // If qry == -2 show messages from the last (current) query.
09262    // If qry == -1 all the messages not yet displayed are shown (default).
09263    // If qry == 0, all the messages in the file are shown.
09264    // If qry  > 0, only the messages related to query 'qry' are shown.
09265    // For qry != -1 the original file offset is restored at the end
09266 
09267    // Save present offset
09268    off_t nowlog = lseek(fileno(fLogFileR), (off_t) 0, SEEK_CUR);
09269    if (nowlog < 0) {
09270       SysError("ShowLog", "problem lseeking log file (errno: %d)", TSystem::GetErrno());
09271       return;
09272    }
09273 
09274    // Get extremes
09275    off_t startlog = nowlog;
09276    off_t endlog = lseek(fileno(fLogFileR), (off_t) 0, SEEK_END);
09277    if (endlog < 0) {
09278       SysError("ShowLog", "problem lseeking log file (errno: %d)", TSystem::GetErrno());
09279       return;
09280    }
09281 
09282    lseek(fileno(fLogFileR), nowlog, SEEK_SET);
09283    if (qry == 0) {
09284       startlog = 0;
09285       lseek(fileno(fLogFileR), (off_t) 0, SEEK_SET);
09286    } else if (qry != -1) {
09287 
09288       TQueryResult *pq = 0;
09289       if (qry == -2) {
09290          // Pickup the last one
09291          pq = (GetQueryResults()) ? ((TQueryResult *)(GetQueryResults()->Last())) : 0;
09292          if (!pq) {
09293             GetListOfQueries();
09294             if (fQueries)
09295                pq = (TQueryResult *)(fQueries->Last());
09296          }
09297       } else if (qry > 0) {
09298          TList *queries = GetQueryResults();
09299          if (queries) {
09300             TIter nxq(queries);
09301             while ((pq = (TQueryResult *)nxq()))
09302                if (qry == pq->GetSeqNum())
09303                   break;
09304          }
09305          if (!pq) {
09306             queries = GetListOfQueries();
09307             TIter nxq(queries);
09308             while ((pq = (TQueryResult *)nxq()))
09309                if (qry == pq->GetSeqNum())
09310                   break;
09311          }
09312       }
09313       if (pq) {
09314          PutLog(pq);
09315          return;
09316       } else {
09317          if (gDebug > 0)
09318             Info("ShowLog","query %d not found in list", qry);
09319          qry = -1;
09320       }
09321    }
09322 
09323    // Number of bytes to log
09324    UInt_t tolog = (UInt_t)(endlog - startlog);
09325 
09326    // Perhaps nothing
09327    if (tolog <= 0)
09328 
09329    // Set starting point
09330    lseek(fileno(fLogFileR), startlog, SEEK_SET);
09331 
09332    // Now we go
09333    Int_t np = 0;
09334    char line[2048];
09335    Int_t wanted = (tolog > sizeof(line)) ? sizeof(line) : tolog;
09336    while (fgets(line, wanted, fLogFileR)) {
09337 
09338       Int_t r = strlen(line);
09339       if (!SendingLogToWindow()) {
09340          if (line[r-1] != '\n') line[r-1] = '\n';
09341          if (r > 0) {
09342             char *p = line;
09343             while (r) {
09344                Int_t w = write(fileno(stdout), p, r);
09345                if (w < 0) {
09346                   SysError("ShowLog", "error writing to stdout");
09347                   break;
09348                }
09349                r -= w;
09350                p += w;
09351             }
09352          }
09353          tolog -= strlen(line);
09354          np++;
09355 
09356          // Ask if more is wanted
09357          if (!(np%10)) {
09358             char *opt = Getline("More (y/n)? [y]");
09359             if (opt[0] == 'n')
09360                break;
09361          }
09362 
09363          // We may be over
09364          if (tolog <= 0)
09365             break;
09366 
09367          // Update wanted bytes
09368          wanted = (tolog > sizeof(line)) ? sizeof(line) : tolog;
09369       } else {
09370          // Log to window
09371          if (line[r-1] == '\n') line[r-1] = 0;
09372          LogMessage(line, kFALSE);
09373       }
09374    }
09375    if (!SendingLogToWindow()) {
09376       // Avoid screwing up the prompt
09377       if (write(fileno(stdout), "\n", 1) != 1)
09378          SysError("ShowLog", "error writing to stdout");
09379    }
09380 
09381    // Restore original pointer
09382    if (qry > -1)
09383       lseek(fileno(fLogFileR), nowlog, SEEK_SET);
09384 }
09385 
09386 //______________________________________________________________________________
09387 void TProof::cd(Int_t id)
09388 {
09389    // Set session with 'id' the default one. If 'id' is not found in the list,
09390    // the current session is set as default
09391 
09392    if (GetManager()) {
09393       TProofDesc *d = GetManager()->GetProofDesc(id);
09394       if (d) {
09395          if (d->GetProof()) {
09396             gProof = d->GetProof();
09397             return;
09398          }
09399       }
09400 
09401       // Id not found or undefined: set as default this session
09402       gProof = this;
09403    }
09404 
09405    return;
09406 }
09407 
09408 //______________________________________________________________________________
09409 void TProof::Detach(Option_t *opt)
09410 {
09411    // Detach this instance to its proofserv.
09412    // If opt is 'S' or 's' the remote server is shutdown
09413 
09414    // Nothing to do if not in contact with proofserv
09415    if (!IsValid()) return;
09416 
09417    // Get worker and socket instances
09418    TSlave *sl = (TSlave *) fActiveSlaves->First();
09419    TSocket *s = 0;
09420    if (!sl || !(sl->IsValid()) || !(s = sl->GetSocket())) {
09421       Error("Detach","corrupted worker instance: wrk:%p, sock:%p", sl, s);
09422       return;
09423    }
09424 
09425    Bool_t shutdown = (strchr(opt,'s') || strchr(opt,'S')) ? kTRUE : kFALSE;
09426 
09427    // If processing, try to stop processing first
09428    if (shutdown && !IsIdle()) {
09429       // Remove pending requests
09430       Remove("cleanupqueue");
09431       // Do not wait for ever, but al least 20 seconds
09432       Long_t timeout = gEnv->GetValue("Proof.ShutdownTimeout", 60);
09433       timeout = (timeout > 20) ? timeout : 20;
09434       // Send stop signal
09435       StopProcess(kFALSE, (Long_t) (timeout / 2));
09436       // Receive results
09437       Collect(kActive, timeout);
09438    }
09439 
09440    // Avoid spurious messages: deactivate new inputs ...
09441    DeActivateAsyncInput();
09442 
09443    // ... and discard existing ones
09444    sl->FlushSocket();
09445 
09446    // Close session (we always close the connection)
09447    Close(opt);
09448 
09449    // Close the progress dialog, if any
09450    if (fProgressDialogStarted)
09451       CloseProgressDialog();
09452 
09453    // Update info in the table of our manager, if any
09454    if (GetManager() && GetManager()->QuerySessions("L")) {
09455       TIter nxd(GetManager()->QuerySessions("L"));
09456       TProofDesc *d = 0;
09457       while ((d = (TProofDesc *)nxd())) {
09458          if (d->GetProof() == this) {
09459             d->SetProof(0);
09460             GetManager()->QuerySessions("L")->Remove(d);
09461             break;
09462          }
09463       }
09464    }
09465 
09466    // Invalidate this instance
09467    fValid = kFALSE;
09468 
09469    return;
09470 }
09471 
09472 //______________________________________________________________________________
09473 void TProof::SetAlias(const char *alias)
09474 {
09475    // Set an alias for this session. If reconnection is supported, the alias
09476    // will be communicated to the remote coordinator so that it can be recovered
09477    // when reconnecting
09478 
09479    // Set it locally
09480    TNamed::SetTitle(alias);
09481    if (TestBit(TProof::kIsMaster))
09482       // Set the name at the same value
09483       TNamed::SetName(alias);
09484 
09485    // Nothing to do if not in contact with coordinator
09486    if (!IsValid()) return;
09487 
09488    if (!IsProofd() && TestBit(TProof::kIsClient)) {
09489       TSlave *sl = (TSlave *) fActiveSlaves->First();
09490       if (sl)
09491          sl->SetAlias(alias);
09492    }
09493 
09494    return;
09495 }
09496 
09497 //______________________________________________________________________________
09498 Int_t TProof::UploadDataSet(const char *dataSetName,
09499                             TList *files,
09500                             const char *desiredDest,
09501                             Int_t opt,
09502                             TList *skippedFiles)
09503 {
09504    // Upload a set of files and save the list of files by name dataSetName.
09505    // The 'files' argument is a list of TFileInfo objects describing the files
09506    // as first url.
09507    // The mask 'opt' is a combination of EUploadOpt:
09508    //   kAppend             (0x1)   if set true files will be appended to
09509    //                               the dataset existing by given name
09510    //   kOverwriteDataSet   (0x2)   if dataset with given name exited it
09511    //                               would be overwritten
09512    //   kNoOverwriteDataSet (0x4)   do not overwirte if the dataset exists
09513    //   kOverwriteAllFiles  (0x8)   overwrite all files that may exist
09514    //   kOverwriteNoFiles   (0x10)  overwrite none
09515    //   kAskUser            (0x0)   ask user before overwriteng dataset/files
09516    // The default value is kAskUser.
09517    // The user will be asked to confirm overwriting dataset or files unless
09518    // specified opt provides the answer!
09519    // If kOverwriteNoFiles is set, then a pointer to TList must be passed as
09520    // skippedFiles argument. The function will add to this list TFileInfo
09521    // objects describing all files that existed on the cluster and were
09522    // not uploaded.
09523    //
09524    // Communication Summary
09525    // Client                             Master
09526    //    |------------>DataSetName----------->|
09527    //    |<-------kMESS_OK/kMESS_NOTOK<-------| (Name OK/file exist)
09528    // (*)|-------> call RegisterDataSet ------->|
09529    // (*) - optional
09530 
09531    if (!IsValid()) {
09532       Error("UploadDataSet", "not connected");
09533       return -1;
09534    }
09535 
09536    if (fProtocol < 15) {
09537       Info("UploadDataSet", "functionality not available: the server has an"
09538                             " incompatible version of TFileInfo");
09539       return -1;
09540    }
09541 
09542    if (IsLite()) {
09543       Info("UploadDataSet", "Lite-session: functionality not needed - do nothing");
09544       return -1;
09545    }
09546 
09547    // check if  dataSetName is not excluded
09548    if (strchr(dataSetName, '/')) {
09549       if (strstr(dataSetName, "public") != dataSetName) {
09550          Error("UploadDataSet",
09551                "Name of public dataset should start with public/");
09552          return kError;
09553       }
09554    }
09555    if ((opt & kOverwriteAllFiles && opt & kOverwriteNoFiles) ||
09556        (opt & kNoOverwriteDataSet && opt & kAppend) ||
09557        (opt & kOverwriteDataSet && opt & kAppend) ||
09558        (opt & kNoOverwriteDataSet && opt & kOverwriteDataSet)) {
09559       Error("UploadDataSet", "you specified contradicting options.");
09560       return kError;
09561    }
09562 
09563    // Decode options
09564    Int_t overwriteAll = (opt & kOverwriteAllFiles) ? kTRUE : kFALSE;
09565    Int_t overwriteNone = (opt & kOverwriteNoFiles) ? kTRUE : kFALSE;
09566    Int_t goodName = (opt & (kOverwriteDataSet | kAppend)) ? 1 : -1;
09567    Int_t appendToDataSet = (opt & kAppend) ? kTRUE : kFALSE;
09568    Int_t overwriteNoDataSet = (opt & kNoOverwriteDataSet) ? kTRUE : kFALSE;
09569 
09570 
09571    //If skippedFiles is not provided we can not return list of skipped files.
09572    if (!skippedFiles && overwriteNone) {
09573       Error("UploadDataSet",
09574             "Provide pointer to TList object as skippedFiles argument when using kOverwriteNoFiles option.");
09575       return kError;
09576    }
09577    //If skippedFiles is provided but did not point to a TList the have to STOP
09578    if (skippedFiles) {
09579       if (skippedFiles->Class() != TList::Class()) {
09580          Error("UploadDataSet",
09581                "Provided skippedFiles argument does not point to a TList object.");
09582          return kError;
09583       }
09584    }
09585 
09586    Int_t fileCount = 0; // return value
09587    if (goodName == -1) { // -1 for undefined
09588       // First check whether this dataset already exists unless
09589       // kAppend or kOverWriteDataSet
09590       TMessage nameMess(kPROOF_DATASETS);
09591       nameMess << Int_t(kCheckDataSetName);
09592       nameMess << TString(dataSetName);
09593       Broadcast(nameMess);
09594       Collect(kActive, fCollectTimeout); //after each call to HandleDataSets
09595       if (fStatus == -1) {
09596          //We ask user to agree on overwriting the dataset name
09597          while (goodName == -1 && !overwriteNoDataSet) {
09598             Info("UploadDataSet", "dataset %s already exist. ",
09599                    dataSetName);
09600             Info("UploadDataSet", "do you want to overwrite it[Yes/No/Append]?");
09601             TString answer;
09602             answer.ReadToken(cin);
09603             if (!strncasecmp(answer.Data(), "y", 1)) {
09604                goodName = 1;
09605             } else if (!strncasecmp(answer.Data(), "n", 1)) {
09606                goodName = 0;
09607             } else if (!strncasecmp(answer.Data(), "a", 1)) {
09608                goodName = 1;
09609                appendToDataSet = kTRUE;
09610             }
09611          }
09612       } else {
09613          goodName = 1;
09614       }
09615    } // if (goodName == -1)
09616    if (goodName == 1) {  //must be == 1 as -1 was used for a bad name!
09617       //Code for enforcing writing in user "home dir" only
09618       char *relativeDestDir = Form("%s/%s/",
09619                                    gSystem->GetUserInfo()->fUser.Data(),
09620                                    desiredDest?desiredDest:"");
09621                                    //Consider adding dataSetName to the path
09622 
09623       relativeDestDir = CollapseSlashesInPath(relativeDestDir);
09624       TString dest = Form("%s/%s", GetDataPoolUrl(), relativeDestDir);
09625 
09626       delete[] relativeDestDir;
09627 
09628       // Now we will actually copy files and create the TList object
09629       TFileCollection *fileList = new TFileCollection();
09630       TIter next(files);
09631       while (TFileInfo *fileInfo = ((TFileInfo*)next())) {
09632          TUrl *fileUrl = fileInfo->GetFirstUrl();
09633          if (gSystem->AccessPathName(fileUrl->GetUrl()) == kFALSE) {
09634             //matching dir entry
09635             //getting the file name from the path represented by fileUrl
09636             const char *ent = gSystem->BaseName(fileUrl->GetFile());
09637 
09638             Int_t goodFileName = 1;
09639             if (!overwriteAll &&
09640                gSystem->AccessPathName(Form("%s/%s", dest.Data(), ent), kFileExists)
09641                   == kFALSE) {  //Destination file exists
09642                goodFileName = -1;
09643                while (goodFileName == -1 && !overwriteAll && !overwriteNone) {
09644                   Info("UploadDataSet", "file %s already exists. ", Form("%s/%s", dest.Data(), ent));
09645                   Info("UploadDataSet", "do you want to overwrite it [Yes/No/all/none]?");
09646                   TString answer;
09647                   answer.ReadToken(cin);
09648                   if (!strncasecmp(answer.Data(), "y", 1))
09649                      goodFileName = 1;
09650                   else if (!strncasecmp(answer.Data(), "all", 3))
09651                      overwriteAll = kTRUE;
09652                   else if (!strncasecmp(answer.Data(), "none", 4))
09653                      overwriteNone = kTRUE;
09654                   else if (!strncasecmp(answer.Data(), "n", 1))
09655                      goodFileName = 0;
09656                }
09657             } //if file exists
09658 
09659             // Copy the file to the redirector indicated
09660             if (goodFileName == 1 || overwriteAll) {
09661                //must be == 1 as -1 was meant for bad name!
09662                Info("UploadDataSet", "Uploading %s to %s/%s",
09663                       fileUrl->GetUrl(), dest.Data(), ent);
09664                if (TFile::Cp(fileUrl->GetUrl(), Form("%s/%s", dest.Data(), ent))) {
09665                   fileList->GetList()->Add(new TFileInfo(Form("%s/%s", dest.Data(), ent)));
09666                } else
09667                   Error("UploadDataSet", "file %s was not copied", fileUrl->GetUrl());
09668             } else {  // don't overwrite, but file exist and must be included
09669                fileList->GetList()->Add(new TFileInfo(Form("%s/%s", dest.Data(), ent)));
09670                if (skippedFiles) {
09671                   // user specified the TList *skippedFiles argument so we create
09672                   // the list of skipped files
09673                   skippedFiles->Add(new TFileInfo(fileUrl->GetUrl()));
09674                }
09675             }
09676          } //if matching dir entry
09677       } //while
09678 
09679       if ((fileCount = fileList->GetList()->GetSize()) == 0) {
09680          Info("UploadDataSet", "no files were copied. The dataset will not be saved");
09681       } else {
09682          TString o = (appendToDataSet) ? "" : "O";
09683          if (!RegisterDataSet(dataSetName, fileList, o)) {
09684             Error("UploadDataSet", "Error while saving dataset: %s", dataSetName);
09685             fileCount = kError;
09686          }
09687       }
09688       delete fileList;
09689    } else if (overwriteNoDataSet) {
09690       Info("UploadDataSet", "dataset %s already exists", dataSetName);
09691       return kDataSetExists;
09692    } //if(goodName == 1)
09693 
09694    return fileCount;
09695 }
09696 
09697 //______________________________________________________________________________
09698 Int_t TProof::UploadDataSet(const char *dataSetName,
09699                             const char *files,
09700                             const char *desiredDest,
09701                             Int_t opt,
09702                             TList *skippedFiles)
09703 {
09704    // Upload a set of files and save the list of files by name dataSetName.
09705    // The mask 'opt' is a combination of EUploadOpt:
09706    //   kAppend             (0x1)   if set true files will be appended to
09707    //                               the dataset existing by given name
09708    //   kOverwriteDataSet   (0x2)   if dataset with given name exited it
09709    //                               would be overwritten
09710    //   kNoOverwriteDataSet (0x4)   do not overwirte if the dataset exists
09711    //   kOverwriteAllFiles  (0x8)   overwrite all files that may exist
09712    //   kOverwriteNoFiles   (0x10)  overwrite none
09713    //   kAskUser            (0x0)   ask user before overwriteng dataset/files
09714    // The default value is kAskUser.
09715    // The user will be asked to confirm overwriting dataset or files unless
09716    // specified opt provides the answer!
09717    // If kOverwriteNoFiles is set, then a pointer to TList must be passed as
09718    // skippedFiles argument. The function will add to this list TFileInfo
09719    // objects describing all files that existed on the cluster and were
09720    // not uploaded.
09721    //
09722 
09723    if (fProtocol < 15) {
09724       Info("UploadDataSet", "functionality not available: the server has an"
09725                             " incompatible version of TFileInfo");
09726       return -1;
09727    }
09728 
09729    TList fileList;
09730    fileList.SetOwner();
09731    void *dataSetDir = gSystem->OpenDirectory(gSystem->DirName(files));
09732    const char* ent;
09733    TString filesExp(gSystem->BaseName(files));
09734    filesExp.ReplaceAll("*",".*");
09735    TRegexp rg(filesExp);
09736    while ((ent = gSystem->GetDirEntry(dataSetDir))) {
09737       TString entryString(ent);
09738       if (entryString.Index(rg) != kNPOS) {
09739          // Matching dir entry: add to the list
09740          TString u(Form("file://%s/%s", gSystem->DirName(files), ent));
09741          if (gSystem->AccessPathName(u, kReadPermission) == kFALSE)
09742             fileList.Add(new TFileInfo(u));
09743       } //if matching dir entry
09744    } //while
09745    Int_t fileCount;
09746    if ((fileCount = fileList.GetSize()) == 0)
09747       Printf("No files match your selection. The dataset will not be saved");
09748    else
09749       fileCount = UploadDataSet(dataSetName, &fileList, desiredDest,
09750                                 opt, skippedFiles);
09751    return fileCount;
09752 }
09753 
09754 //______________________________________________________________________________
09755 Int_t TProof::UploadDataSetFromFile(const char *dataset, const char *file,
09756                                     const char *dest, Int_t opt,
09757                                     TList *skippedFiles)
09758 {
09759    // Upload files listed in "file" to PROOF cluster.
09760    // Where file = name of file containing list of files and
09761    // dataset = dataset name and opt is a combination of EUploadOpt bits.
09762    // Each file description (line) can include wildcards.
09763    // Check TFileInfo compatibility
09764 
09765    if (fProtocol < 15) {
09766       Info("UploadDataSetFromFile", "functionality not available: the server has an"
09767                                     " incompatible version of TFileInfo");
09768       return -1;
09769    }
09770 
09771    Int_t fileCount = -1;
09772    // Create the list to feed UploadDataSet(char *dataset, TList *l, ...)
09773    TList fileList;
09774    fileList.SetOwner();
09775    ifstream f;
09776    f.open(gSystem->ExpandPathName(file), ifstream::out);
09777    if (f.is_open()) {
09778       while (f.good()) {
09779          TString line;
09780          line.ReadToDelim(f);
09781          line.Strip(TString::kTrailing, '\n');
09782          if (gSystem->AccessPathName(line, kReadPermission) == kFALSE)
09783             fileList.Add(new TFileInfo(line));
09784       }
09785       f.close();
09786       if ((fileCount = fileList.GetSize()) == 0)
09787          Info("UploadDataSetFromFile",
09788               "no files match your selection. The dataset will not be saved");
09789       else
09790          fileCount = UploadDataSet(dataset, &fileList, dest,
09791                                    opt, skippedFiles);
09792    } else {
09793       Error("UploadDataSetFromFile", "unable to open the specified file");
09794    }
09795    // Done
09796    return fileCount;
09797 }
09798 
09799 //______________________________________________________________________________
09800 Bool_t TProof::RegisterDataSet(const char *dataSetName,
09801                                TFileCollection *dataSet, const char* optStr)
09802 {
09803    // Register the 'dataSet' on the cluster under the current
09804    // user, group and the given 'dataSetName'.
09805    // If a dataset with the same name already exists the action fails unless 'opts'
09806    // contains 'O', in which case the old dataset is overwritten, or contains 'U',
09807    // in which case 'newDataSet' is added to the existing dataset (duplications are
09808    // ignored, if any).
09809    // If 'opts' contains 'V' the dataset files are also verified (if the dataset manager
09810    // is configured to allow so). By default the dataset is not verified.
09811    // If 'opts' contains 'T' the in the dataset object (status bits, meta,...)
09812    // is trusted, i.e. not reset (if the dataset manager is configured to allow so).
09813    // Returns kTRUE on success.
09814 
09815    // Check TFileInfo compatibility
09816    if (fProtocol < 17) {
09817       Info("RegisterDataSet",
09818            "functionality not available: the server does not have dataset support");
09819       return kFALSE;
09820    }
09821 
09822    if (!dataSetName || strlen(dataSetName) <= 0) {
09823       Info("RegisterDataSet", "specifying a dataset name is mandatory");
09824       return kFALSE;
09825    }
09826 
09827    TMessage mess(kPROOF_DATASETS);
09828    mess << Int_t(kRegisterDataSet);
09829    mess << TString(dataSetName);
09830    mess << TString(optStr);
09831    mess.WriteObject(dataSet);
09832    Broadcast(mess);
09833 
09834    Bool_t result = kTRUE;
09835    Collect();
09836    if (fStatus != 0) {
09837       Error("RegisterDataSet", "dataset was not saved");
09838       result = kFALSE;
09839    }
09840    return result;
09841 }
09842 
09843 //______________________________________________________________________________
09844 Int_t TProof::SetDataSetTreeName(const char *dataset, const char *treename)
09845 {
09846    // Set/Change the name of the default tree. The tree name may contain
09847    // subdir specification in the form "subdir/name".
09848    // Returns 0 on success, -1 otherwise.
09849 
09850    // Check TFileInfo compatibility
09851    if (fProtocol < 23) {
09852       Info("SetDataSetTreeName", "functionality not supported by the server");
09853       return -1;
09854    }
09855 
09856    if (!dataset || strlen(dataset) <= 0) {
09857       Info("SetDataSetTreeName", "specifying a dataset name is mandatory");
09858       return -1;
09859    }
09860 
09861    if (!treename || strlen(treename) <= 0) {
09862       Info("SetDataSetTreeName", "specifying a tree name is mandatory");
09863       return -1;
09864    }
09865 
09866    TUri uri(dataset);
09867    TString fragment(treename);
09868    if (!fragment.BeginsWith("/")) fragment.Insert(0, "/");
09869    uri.SetFragment(fragment);
09870 
09871    TMessage mess(kPROOF_DATASETS);
09872    mess << Int_t(kSetDefaultTreeName);
09873    mess << uri.GetUri();
09874    Broadcast(mess);
09875 
09876    Collect();
09877    if (fStatus != 0) {
09878       Error("SetDataSetTreeName", "some error occured: default tree name not changed");
09879       return -1;
09880    }
09881    return 0;
09882 }
09883 
09884 //______________________________________________________________________________
09885 TMap *TProof::GetDataSets(const char *uri, const char *optStr)
09886 {
09887    // Lists all datasets that match given uri.
09888    // The 'optStr' can contain a comma-separated list of servers for which the
09889    // information is wanted. If ':lite:' (case insensitive) is specified in 'optStr'
09890    // only the global information in the TFileCollection is retrieved; useful to only
09891    // get the list of available datasets.
09892    
09893    if (fProtocol < 15) {
09894       Info("GetDataSets",
09895            "functionality not available: the server does not have dataset support");
09896       return 0;
09897    }
09898    if (fProtocol < 31 && strstr(optStr, ":lite:"))
09899       Warning("GetDataSets", "'lite' option not supported by the server");
09900 
09901    TMessage mess(kPROOF_DATASETS);
09902    mess << Int_t(kGetDataSets);
09903    mess << TString(uri ? uri : "");
09904    mess << TString(optStr ? optStr : "");
09905    Broadcast(mess);
09906    Collect(kActive, fCollectTimeout);
09907 
09908    TMap *dataSetMap = 0;
09909    if (fStatus != 0) {
09910       Error("GetDataSets", "error receiving datasets information");
09911    } else {
09912       // Look in the list
09913       TMessage *retMess = (TMessage *) fRecvMessages->First();
09914       if (retMess && retMess->What() == kMESS_OK) {
09915          if (!(dataSetMap = (TMap *)(retMess->ReadObject(TMap::Class()))))
09916             Error("GetDataSets", "error receiving datasets");
09917       } else
09918          Error("GetDataSets", "message not found or wrong type (%p)", retMess);
09919    }
09920 
09921    return dataSetMap;
09922 }
09923 
09924 //______________________________________________________________________________
09925 void TProof::ShowDataSets(const char *uri, const char* optStr)
09926 {
09927    // Shows datasets in locations that match the uri.
09928    // By default shows the user's datasets and global ones
09929 
09930    if (fProtocol < 15) {
09931       Info("ShowDataSets",
09932            "functionality not available: the server does not have dataset support");
09933       return;
09934    }
09935 
09936    TMessage mess(kPROOF_DATASETS);
09937    mess << Int_t(kShowDataSets);
09938    mess << TString(uri ? uri : "");
09939    mess << TString(optStr ? optStr : "");
09940    Broadcast(mess);
09941 
09942    Collect(kActive, fCollectTimeout);
09943    if (fStatus != 0)
09944       Error("ShowDataSets", "error receiving datasets information");
09945 }
09946 
09947 //______________________________________________________________________________
09948 Bool_t TProof::ExistsDataSet(const char *dataset)
09949 {
09950    // Returns kTRUE if 'dataset' exists, kFALSE otherwise
09951 
09952    if (fProtocol < 15) {
09953       Info("ExistsDataSet", "functionality not available: the server has an"
09954                             " incompatible version of TFileInfo");
09955       return kFALSE;
09956    }
09957 
09958    if (!dataset || strlen(dataset) <= 0) {
09959       Error("ExistsDataSet", "dataset name missing");
09960       return kFALSE;
09961    }
09962 
09963    TMessage msg(kPROOF_DATASETS);
09964    msg << Int_t(kCheckDataSetName) << TString(dataset);
09965    Broadcast(msg);
09966    Collect(kActive, fCollectTimeout);
09967    if (fStatus == -1) {
09968       // The dataset exists
09969       return kTRUE;
09970    }
09971    // The dataset does not exists
09972    return kFALSE;
09973 }
09974 
09975 //______________________________________________________________________________
09976 void TProof::ClearDataSetCache(const char *dataset)
09977 {
09978    // Clear the content of the dataset cache, if any (matching 'dataset', if defined).
09979 
09980    if (fProtocol < 28) {
09981       Info("ClearDataSetCache", "functionality not available on server");
09982       return;
09983    }
09984 
09985    TMessage msg(kPROOF_DATASETS);
09986    msg << Int_t(kCache) << TString(dataset) << TString("clear");
09987    Broadcast(msg);
09988    Collect(kActive, fCollectTimeout);
09989    // Done
09990    return;
09991 }
09992 
09993 //______________________________________________________________________________
09994 void TProof::ShowDataSetCache(const char *dataset)
09995 {
09996    // Display the content of the dataset cache, if any (matching 'dataset', if defined).
09997 
09998    if (fProtocol < 28) {
09999       Info("ShowDataSetCache", "functionality not available on server");
10000       return;
10001    }
10002 
10003    TMessage msg(kPROOF_DATASETS);
10004    msg << Int_t(kCache) << TString(dataset) << TString("show");
10005    Broadcast(msg);
10006    Collect(kActive, fCollectTimeout);
10007    // Done
10008    return;
10009 }
10010 
10011 //______________________________________________________________________________
10012 TFileCollection *TProof::GetDataSet(const char *uri, const char *optStr)
10013 {
10014    // Get a list of TFileInfo objects describing the files of the specified
10015    // dataset.
10016    // To get the short version (containing only the global meta information)
10017    // specify optStr = "S:" or optStr = "short:".
10018    // To get the sub-dataset of files located on a given server(s) specify
10019    // the list of servers (comma-separated) in the 'optStr' field.
10020 
10021    if (fProtocol < 15) {
10022       Info("GetDataSet", "functionality not available: the server has an"
10023                          " incompatible version of TFileInfo");
10024       return 0;
10025    }
10026 
10027    if (!uri || strlen(uri) <= 0) {
10028       Info("GetDataSet", "specifying a dataset name is mandatory");
10029       return 0;
10030    }
10031 
10032    TMessage nameMess(kPROOF_DATASETS);
10033    nameMess << Int_t(kGetDataSet);
10034    nameMess << TString(uri);
10035    nameMess << TString(optStr ? optStr: "");
10036    if (Broadcast(nameMess) < 0)
10037       Error("GetDataSet", "sending request failed");
10038 
10039    Collect(kActive, fCollectTimeout);
10040    TFileCollection *fileList = 0;
10041    if (fStatus != 0) {
10042       Error("GetDataSet", "error receiving datasets information");
10043    } else {
10044       // Look in the list
10045       TMessage *retMess = (TMessage *) fRecvMessages->First();
10046       if (retMess && retMess->What() == kMESS_OK) {
10047          if (!(fileList = (TFileCollection*)(retMess->ReadObject(TFileCollection::Class()))))
10048             Error("GetDataSet", "error reading list of files");
10049       } else
10050          Error("GetDataSet", "message not found or wrong type (%p)", retMess);
10051    }
10052 
10053    return fileList;
10054 }
10055 
10056 //______________________________________________________________________________
10057 void TProof::ShowDataSet(const char *uri, const char* opt)
10058 {
10059    // display meta-info for given dataset usi
10060 
10061    TFileCollection *fileList = 0;
10062    if ((fileList = GetDataSet(uri))) {
10063       fileList->Print(opt);
10064       delete fileList;
10065    } else
10066       Warning("ShowDataSet","no such dataset: %s", uri);
10067 }
10068 
10069 //______________________________________________________________________________
10070 Int_t TProof::RemoveDataSet(const char *uri, const char* optStr)
10071 {
10072    // Remove the specified dataset from the PROOF cluster.
10073    // Files are not deleted.
10074 
10075    TMessage nameMess(kPROOF_DATASETS);
10076    nameMess << Int_t(kRemoveDataSet);
10077    nameMess << TString(uri?uri:"");
10078    nameMess << TString(optStr?optStr:"");
10079    if (Broadcast(nameMess) < 0)
10080       Error("RemoveDataSet", "sending request failed");
10081    Collect(kActive, fCollectTimeout);
10082 
10083    if (fStatus != 0)
10084       return -1;
10085    else
10086       return 0;
10087 }
10088 
10089 //______________________________________________________________________________
10090 TList* TProof::FindDataSets(const char* /*searchString*/, const char* /*optStr*/)
10091 {
10092    // Find datasets, returns in a TList all found datasets.
10093 
10094    Error ("FindDataSets", "not yet implemented");
10095    return (TList *) 0;
10096 }
10097 
10098 //______________________________________________________________________________
10099 Int_t TProof::VerifyDataSet(const char *uri, const char* optStr)
10100 {
10101    // Verify if all files in the specified dataset are available.
10102    // Print a list and return the number of missing files.
10103 
10104    if (fProtocol < 15) {
10105       Info("VerifyDataSet", "functionality not available: the server has an"
10106                             " incompatible version of TFileInfo");
10107       return kError;
10108    }
10109 
10110    Int_t nMissingFiles = 0;
10111    TMessage nameMess(kPROOF_DATASETS);
10112    nameMess << Int_t(kVerifyDataSet);
10113    nameMess << TString(uri ? uri : "");
10114    nameMess << TString(optStr ? optStr : "");
10115    Broadcast(nameMess);
10116 
10117    Collect(kActive, fCollectTimeout);
10118 
10119    if (fStatus < 0) {
10120       Info("VerifyDataSet", "no such dataset %s", uri);
10121       return  -1;
10122    } else
10123       nMissingFiles = fStatus;
10124    return nMissingFiles;
10125 }
10126 
10127 //______________________________________________________________________________
10128 TMap *TProof::GetDataSetQuota(const char* optStr)
10129 {
10130    // returns a map of the quotas of all groups
10131 
10132    if (IsLite()) {
10133       Info("UploadDataSet", "Lite-session: functionality not implemented");
10134       return (TMap *)0;
10135    }
10136 
10137    TMessage mess(kPROOF_DATASETS);
10138    mess << Int_t(kGetQuota);
10139    mess << TString(optStr?optStr:"");
10140    Broadcast(mess);
10141 
10142    Collect(kActive, fCollectTimeout);
10143    TMap *groupQuotaMap = 0;
10144    if (fStatus < 0) {
10145       Info("GetDataSetQuota", "could not receive quota");
10146    } else {
10147       // Look in the list
10148       TMessage *retMess = (TMessage *) fRecvMessages->First();
10149       if (retMess && retMess->What() == kMESS_OK) {
10150          if (!(groupQuotaMap = (TMap*)(retMess->ReadObject(TMap::Class()))))
10151             Error("GetDataSetQuota", "error getting quotas");
10152       } else
10153          Error("GetDataSetQuota", "message not found or wrong type (%p)", retMess);
10154    }
10155 
10156    return groupQuotaMap;
10157 }
10158 
10159 //_____________________________________________________________________________
10160 void TProof::ShowDataSetQuota(Option_t* opt)
10161 {
10162    // shows the quota and usage of all groups
10163    // if opt contains "U" shows also distribution of usage on user-level
10164 
10165    if (fProtocol < 15) {
10166       Info("ShowDataSetQuota",
10167            "functionality not available: the server does not have dataset support");
10168       return;
10169    }
10170 
10171    if (IsLite()) {
10172       Info("UploadDataSet", "Lite-session: functionality not implemented");
10173       return;
10174    }
10175 
10176    TMessage mess(kPROOF_DATASETS);
10177    mess << Int_t(kShowQuota);
10178    mess << TString(opt?opt:"");
10179    Broadcast(mess);
10180 
10181    Collect();
10182    if (fStatus != 0)
10183       Error("ShowDataSetQuota", "error receiving quota information");
10184 }
10185 
10186 //_____________________________________________________________________________
10187 void TProof::InterruptCurrentMonitor()
10188 {
10189    // If in active in a monitor set ready state
10190    if (fCurrentMonitor)
10191       fCurrentMonitor->Interrupt();
10192 }
10193 
10194 //_____________________________________________________________________________
10195 void TProof::ActivateWorker(const char *ord)
10196 {
10197    // Make sure that the worker identified by the ordinal number 'ord' is
10198    // in the active list. The request will be forwarded to the master
10199    // in direct contact with the worker. If needed, this master will move
10200    // the worker from the inactive to the active list and rebuild the list
10201    // of unique workers.
10202    // Use ord = "*" to activate all inactive workers.
10203 
10204    ModifyWorkerLists(ord, kTRUE);
10205 }
10206 
10207 //_____________________________________________________________________________
10208 void TProof::DeactivateWorker(const char *ord)
10209 {
10210    // Remove the worker identified by the ordinal number 'ord' from the
10211    // the active list. The request will be forwarded to the master
10212    // in direct contact with the worker. If needed, this master will move
10213    // the worker from the active to the inactive list and rebuild the list
10214    // of unique workers.
10215    // Use ord = "*" to deactivate all active workers.
10216 
10217    ModifyWorkerLists(ord, kFALSE);
10218 }
10219 
10220 //_____________________________________________________________________________
10221 void TProof::ModifyWorkerLists(const char *ord, Bool_t add)
10222 {
10223    // Modify the worker active/inactive list by making the worker identified by
10224    // the ordinal number 'ord' active (add == TRUE) or inactive (add == FALSE).
10225    // If needed, the request will be forwarded to the master in direct contact
10226    // with the worker. The end-master will move the worker from one list to the
10227    // other active and rebuild the list of unique active workers.
10228    // Use ord = "*" to deactivate all active workers.
10229 
10230    // Make sure the input make sense
10231    if (!ord || strlen(ord) <= 0) {
10232       Info("ModifyWorkerLists",
10233            "An ordinal number - e.g. \"0.4\" or \"*\" for all - is required as input");
10234       return;
10235    }
10236 
10237    Bool_t fw = kTRUE;    // Whether to forward one step down
10238    Bool_t rs = kFALSE;   // Whether to rescan for unique workers
10239 
10240    // Appropriate list pointing
10241    TList *in = (add) ? fInactiveSlaves : fActiveSlaves;
10242    TList *out = (add) ? fActiveSlaves : fInactiveSlaves;
10243 
10244    if (TestBit(TProof::kIsMaster)) {
10245       fw = IsEndMaster() ? kFALSE : kTRUE;
10246       // Look for the worker in the inactive list
10247       if (in->GetSize() > 0) {
10248          TIter nxw(in);
10249          TSlave *wrk = 0;
10250          while ((wrk = (TSlave *) nxw())) {
10251             if (ord[0] == '*' || !strncmp(wrk->GetOrdinal(), ord, strlen(ord))) {
10252                // Add it to the inactive list
10253                if (!out->FindObject(wrk)) {
10254                   out->Add(wrk);
10255                   if (add)
10256                      fActiveMonitor->Add(wrk->GetSocket());
10257                }
10258                // Remove it from the active list
10259                in->Remove(wrk);
10260                if (!add) {
10261                   fActiveMonitor->Remove(wrk->GetSocket());
10262                   wrk->SetStatus(TSlave::kInactive);
10263                } else
10264                   wrk->SetStatus(TSlave::kActive);
10265 
10266                // Nothing to forward (ord is unique)
10267                fw = kFALSE;
10268                // Rescan for unique workers (active list modified)
10269                rs = kTRUE;
10270                // We are done, if not option 'all'
10271                if (ord[0] != '*')
10272                   break;
10273             }
10274          }
10275       }
10276    }
10277 
10278    // Rescan for unique workers
10279    if (rs)
10280       FindUniqueSlaves();
10281 
10282    // Forward the request one step down, if needed
10283    Int_t action = (add) ? (Int_t) kActivateWorker : (Int_t) kDeactivateWorker;
10284    if (fw) {
10285       TMessage mess(kPROOF_WORKERLISTS);
10286       mess << action << TString(ord);
10287       Broadcast(mess);
10288       Collect(kActive, fCollectTimeout);
10289    }
10290 }
10291 
10292 //_____________________________________________________________________________
10293 TProof *TProof::Open(const char *cluster, const char *conffile,
10294                                           const char *confdir, Int_t loglevel)
10295 {
10296    // Start a PROOF session on a specific cluster. If cluster is 0 (the
10297    // default) then the PROOF Session Viewer GUI pops up and 0 is returned.
10298    // If cluster is "" (empty string) then we connect to a PROOF session
10299    // on the localhost ("proof://localhost"). Via conffile a specific
10300    // PROOF config file in the confir directory can be specified.
10301    // Use loglevel to set the default loging level for debugging.
10302    // The appropriate instance of TProofMgr is created, if not
10303    // yet existing. The instantiated TProof object is returned.
10304    // Use TProof::cd() to switch between PROOF sessions.
10305    // For more info on PROOF see the TProof ctor.
10306 
10307    const char *pn = "TProof::Open";
10308 
10309    // Make sure libProof and dependents are loaded and TProof can be created,
10310    // dependents are loaded via the information in the [system].rootmap file
10311    if (!cluster) {
10312 
10313       TPluginManager *pm = gROOT->GetPluginManager();
10314       if (!pm) {
10315          ::Error(pn, "plugin manager not found");
10316          return 0;
10317       }
10318 
10319       if (gROOT->IsBatch()) {
10320          ::Error(pn, "we are in batch mode, cannot show PROOF Session Viewer");
10321          return 0;
10322       }
10323       // start PROOF Session Viewer
10324       TPluginHandler *sv = pm->FindHandler("TSessionViewer", "");
10325       if (!sv) {
10326          ::Error(pn, "no plugin found for TSessionViewer");
10327          return 0;
10328       }
10329       if (sv->LoadPlugin() == -1) {
10330          ::Error(pn, "plugin for TSessionViewer could not be loaded");
10331          return 0;
10332       }
10333       sv->ExecPlugin(0);
10334       return 0;
10335 
10336    } else {
10337 
10338       TString clst(cluster);
10339       if (clst.BeginsWith("workers=") || clst.BeginsWith("tunnel="))
10340          clst.Insert(0, "/?");
10341 
10342       // Parse input URL
10343       TUrl u(clst);
10344 
10345       // Parse any tunning info ("<cluster>/?tunnel=[<tunnel_host>:]tunnel_port)
10346       TString opts(u.GetOptions());
10347       if (!opts.IsNull()) {
10348          Int_t it = opts.Index("tunnel=");
10349          if (it != kNPOS) {
10350             TString sport = opts(it + strlen("tunnel="), opts.Length());
10351             TString host("127.0.0.1");
10352             Int_t port = -1;
10353             Int_t ic = sport.Index(":");
10354             if (ic != kNPOS) {
10355                // Isolate the host
10356                host = sport(0, ic);
10357                sport.Remove(0, ic + 1);
10358             }
10359             if (!sport.IsDigit()) {
10360                // Remove the non digit part
10361                TRegexp re("[^0-9]");
10362                Int_t ind = sport.Index(re);
10363                if (ind != kNPOS)
10364                   sport.Remove(ind);
10365             }
10366             // Set the port
10367             if (sport.IsDigit())
10368                port = sport.Atoi();
10369             if (port > 0) {
10370                // Set the relevant variables
10371                ::Info("TProof::Open","using tunnel at %s:%d", host.Data(), port);
10372                gEnv->SetValue("XNet.SOCKS4Host", host);
10373                gEnv->SetValue("XNet.SOCKS4Port", port);
10374             } else {
10375                // Warn parsing problems
10376                ::Warning("TProof::Open",
10377                          "problems parsing tunnelling info from options: %s", opts.Data());
10378             }
10379          }
10380       }
10381 
10382       // Find out if we are required to attach to a specific session
10383       Int_t locid = -1;
10384       Bool_t create = kFALSE;
10385       if (opts.Length() > 0) {
10386          if (opts.BeginsWith("N",TString::kIgnoreCase)) {
10387             create = kTRUE;
10388             opts.Remove(0,1);
10389             u.SetOptions(opts);
10390          } else if (opts.IsDigit()) {
10391             locid = opts.Atoi();
10392          }
10393       }
10394 
10395       // Attach-to or create the appropriate manager
10396       TProofMgr *mgr = TProofMgr::Create(u.GetUrl());
10397 
10398       TProof *proof = 0;
10399       if (mgr && mgr->IsValid()) {
10400 
10401          // If XProofd we always attempt an attach first (unless
10402          // explicitely not requested).
10403          Bool_t attach = (create || mgr->IsProofd() || mgr->IsLite()) ? kFALSE : kTRUE;
10404          if (attach) {
10405             TProofDesc *d = 0;
10406             if (locid < 0)
10407                // Get the list of sessions
10408                d = (TProofDesc *) mgr->QuerySessions("")->First();
10409             else
10410                d = (TProofDesc *) mgr->GetProofDesc(locid);
10411             if (d) {
10412                proof = (TProof*) mgr->AttachSession(d);
10413                if (!proof || !proof->IsValid()) {
10414                   if (locid)
10415                      ::Error(pn, "new session could not be attached");
10416                   SafeDelete(proof);
10417                }
10418             }
10419          }
10420 
10421          // start the PROOF session
10422          if (!proof) {
10423             proof = (TProof*) mgr->CreateSession(conffile, confdir, loglevel);
10424             if (!proof || !proof->IsValid()) {
10425                ::Error(pn, "new session could not be created");
10426                SafeDelete(proof);
10427             }
10428          }
10429       }
10430       return proof;
10431    }
10432 }
10433 
10434 //_____________________________________________________________________________
10435 TProofMgr *TProof::Mgr(const char *url)
10436 {
10437    // Get instance of the effective manager for 'url'
10438    // Return 0 on failure.
10439 
10440    if (!url)
10441       return (TProofMgr *)0;
10442 
10443    // Attach or create the relevant instance
10444    return TProofMgr::Create(url);
10445 }
10446 
10447 //_____________________________________________________________________________
10448 void TProof::Reset(const char *url, Bool_t hard)
10449 {
10450    // Wrapper around TProofMgr::Reset(...).
10451 
10452    if (url) {
10453       TProofMgr *mgr = TProof::Mgr(url);
10454       if (mgr && mgr->IsValid())
10455          mgr->Reset(hard);
10456       else
10457          ::Error("TProof::Reset",
10458                  "unable to initialize a valid manager instance");
10459    }
10460 }
10461 
10462 //_____________________________________________________________________________
10463 const TList *TProof::GetEnvVars()
10464 {
10465    // Get environemnt variables.
10466 
10467    return fgProofEnvList;
10468 }
10469 
10470 //_____________________________________________________________________________
10471 void TProof::AddEnvVar(const char *name, const char *value)
10472 {
10473    // Add an variable to the list of environment variables passed to proofserv
10474    // on the master and slaves
10475 
10476    if (gDebug > 0) ::Info("TProof::AddEnvVar","%s=%s", name, value);
10477 
10478    if (fgProofEnvList == 0) {
10479       // initialize the list if needed
10480       fgProofEnvList = new TList;
10481       fgProofEnvList->SetOwner();
10482    } else {
10483       // replace old entries with the same name
10484       TObject *o = fgProofEnvList->FindObject(name);
10485       if (o != 0) {
10486          fgProofEnvList->Remove(o);
10487       }
10488    }
10489    fgProofEnvList->Add(new TNamed(name, value));
10490 }
10491 
10492 //_____________________________________________________________________________
10493 void TProof::DelEnvVar(const char *name)
10494 {
10495    // Remove an variable from the list of environment variables passed to proofserv
10496    // on the master and slaves
10497 
10498    if (fgProofEnvList == 0) return;
10499 
10500    TObject *o = fgProofEnvList->FindObject(name);
10501    if (o != 0) {
10502       fgProofEnvList->Remove(o);
10503    }
10504 }
10505 
10506 //_____________________________________________________________________________
10507 void TProof::ResetEnvVars()
10508 {
10509    // Clear the list of environment variables passed to proofserv
10510    // on the master and slaves
10511 
10512    if (fgProofEnvList == 0) return;
10513 
10514    SafeDelete(fgProofEnvList);
10515 }
10516 
10517 //______________________________________________________________________________
10518 void TProof::SaveWorkerInfo()
10519 {
10520    // Save informations about the worker set in the file .workers in the working
10521    // dir. Called each time there is a change in the worker setup, e.g. by
10522    // TProof::MarkBad().
10523 
10524    // We must be masters
10525    if (TestBit(TProof::kIsClient))
10526       return;
10527 
10528    // We must have a server defined
10529    if (!gProofServ) {
10530       Error("SaveWorkerInfo","gProofServ undefined");
10531       return;
10532    }
10533 
10534    // The relevant lists must be defined
10535    if (!fSlaves && !fBadSlaves) {
10536       Warning("SaveWorkerInfo","all relevant worker lists is undefined");
10537       return;
10538    }
10539 
10540    // Create or truncate the file first
10541    TString fnwrk = Form("%s/.workers",
10542                         gSystem->DirName(gProofServ->GetSessionDir()));
10543    FILE *fwrk = fopen(fnwrk.Data(),"w");
10544    if (!fwrk) {
10545       Error("SaveWorkerInfo",
10546             "cannot open %s for writing (errno: %d)", fnwrk.Data(), errno);
10547       return;
10548    }
10549 
10550    // Do we need to register an additional line for another log?
10551    TString addlogext;
10552    if (gSystem->Getenv("PROOF_ADDITIONALLOG")) {
10553       addlogext = gSystem->Getenv("PROOF_ADDITIONALLOG");
10554       if (gDebug > 0)
10555          Info("SaveWorkerInfo", "request for additional line with ext: '%s'",  addlogext.Data());
10556    }
10557 
10558    // Loop over the list of workers (active is any worker not flagged as bad)
10559    TIter nxa(fSlaves);
10560    TSlave *wrk = 0;
10561    while ((wrk = (TSlave *) nxa())) {
10562       Int_t status = (fBadSlaves && fBadSlaves->FindObject(wrk)) ? 0 : 1;
10563       // Write out record for this worker
10564       fprintf(fwrk,"%s@%s:%d %d %s %s.log\n",
10565                    wrk->GetUser(), wrk->GetName(), wrk->GetPort(), status,
10566                    wrk->GetOrdinal(), wrk->GetWorkDir());
10567       // Additional line, if required
10568       if (addlogext.Length() > 0) {
10569          fprintf(fwrk,"%s@%s:%d %d %s %s.%s\n",
10570                      wrk->GetUser(), wrk->GetName(), wrk->GetPort(), status,
10571                      wrk->GetOrdinal(), wrk->GetWorkDir(), addlogext.Data());
10572       }
10573    }
10574 
10575    // Close file
10576    fclose(fwrk);
10577 
10578    // We are done
10579    return;
10580 }
10581 
10582 //______________________________________________________________________________
10583 Int_t TProof::GetParameter(TCollection *c, const char *par, TString &value)
10584 {
10585    // Get the value from the specified parameter from the specified collection.
10586    // Returns -1 in case of error (i.e. list is 0, parameter does not exist
10587    // or value type does not match), 0 otherwise.
10588 
10589    TObject *obj = c ? c->FindObject(par) : (TObject *)0;
10590    if (obj) {
10591       TNamed *p = dynamic_cast<TNamed*>(obj);
10592       if (p) {
10593          value = p->GetTitle();
10594          return 0;
10595       }
10596    }
10597    return -1;
10598 
10599 }
10600 
10601 //______________________________________________________________________________
10602 Int_t TProof::GetParameter(TCollection *c, const char *par, Int_t &value)
10603 {
10604    // Get the value from the specified parameter from the specified collection.
10605    // Returns -1 in case of error (i.e. list is 0, parameter does not exist
10606    // or value type does not match), 0 otherwise.
10607 
10608    TObject *obj = c ? c->FindObject(par) : (TObject *)0;
10609    if (obj) {
10610       TParameter<Int_t> *p = dynamic_cast<TParameter<Int_t>*>(obj);
10611       if (p) {
10612          value = p->GetVal();
10613          return 0;
10614       }
10615    }
10616    return -1;
10617 }
10618 
10619 //______________________________________________________________________________
10620 Int_t TProof::GetParameter(TCollection *c, const char *par, Long_t &value)
10621 {
10622    // Get the value from the specified parameter from the specified collection.
10623    // Returns -1 in case of error (i.e. list is 0, parameter does not exist
10624    // or value type does not match), 0 otherwise.
10625 
10626    TObject *obj = c ? c->FindObject(par) : (TObject *)0;
10627    if (obj) {
10628       TParameter<Long_t> *p = dynamic_cast<TParameter<Long_t>*>(obj);
10629       if (p) {
10630          value = p->GetVal();
10631          return 0;
10632       }
10633    }
10634    return -1;
10635 }
10636 
10637 //______________________________________________________________________________
10638 Int_t TProof::GetParameter(TCollection *c, const char *par, Long64_t &value)
10639 {
10640    // Get the value from the specified parameter from the specified collection.
10641    // Returns -1 in case of error (i.e. list is 0, parameter does not exist
10642    // or value type does not match), 0 otherwise.
10643 
10644    TObject *obj = c ? c->FindObject(par) : (TObject *)0;
10645    if (obj) {
10646       TParameter<Long64_t> *p = dynamic_cast<TParameter<Long64_t>*>(obj);
10647       if (p) {
10648          value = p->GetVal();
10649          return 0;
10650       }
10651    }
10652    return -1;
10653 }
10654 
10655 //______________________________________________________________________________
10656 Int_t TProof::GetParameter(TCollection *c, const char *par, Double_t &value)
10657 {
10658    // Get the value from the specified parameter from the specified collection.
10659    // Returns -1 in case of error (i.e. list is 0, parameter does not exist
10660    // or value type does not match), 0 otherwise.
10661 
10662    TObject *obj = c ? c->FindObject(par) : (TObject *)0;
10663    if (obj) {
10664       TParameter<Double_t> *p = dynamic_cast<TParameter<Double_t>*>(obj);
10665       if (p) {
10666          value = p->GetVal();
10667          return 0;
10668       }
10669    }
10670    return -1;
10671 }
10672 
10673 //______________________________________________________________________________
10674 Int_t TProof::AssertDataSet(TDSet *dset, TList *input,
10675                             TDataSetManager *mgr, TString &emsg)
10676 {
10677    // Make sure that dataset is in the form to be processed. This may mean
10678    // retrieving the relevant info from the dataset manager or from the
10679    // attached input list.
10680    // Returns 0 on success, -1 on error
10681 
10682    emsg = "";
10683 
10684    // We must have something to process
10685    if (!dset || !input || !mgr) {
10686       emsg.Form("invalid inputs (%p, %p, %p)", dset, input, mgr);
10687       return -1;
10688    }
10689 
10690    TList *datasets = new TList;
10691    TFileCollection *dataset = 0;
10692    TString lookupopt;
10693    TString dsname(dset->GetName());
10694    // The dataset maybe in the form of a TFileCollection in the input list
10695    if (dsname.BeginsWith("TFileCollection:")) {
10696       // Isolate the real name
10697       dsname.ReplaceAll("TFileCollection:", "");
10698       // Get the object
10699       dataset = (TFileCollection *) input->FindObject(dsname);
10700       if (!dataset) {
10701          emsg.Form("TFileCollection %s not found in input list", dset->GetName());
10702          return -1;
10703       }
10704       // Remove from everywhere
10705       input->RecursiveRemove(dataset);
10706       // Add it to the local list
10707       datasets->Add(new TPair(dataset, new TObjString("")));
10708       // Make sure we lookup everything (unless the client or the administartor
10709       // required something else)
10710       if (TProof::GetParameter(input, "PROOF_LookupOpt", lookupopt) != 0) {
10711          lookupopt = gEnv->GetValue("Proof.LookupOpt", "all");
10712          input->Add(new TNamed("PROOF_LookupOpt", lookupopt.Data()));
10713       }
10714    }
10715 
10716    // This is the name we parse for additional specifications, such directory
10717    // and object name; for multiple datasets we assume that the directory and
10718    // and object name are the same for all datasets
10719    TString dsnparse;
10720    // The received message included an empty dataset, with only the name
10721    // defined: assume that a dataset, stored on the PROOF master by that
10722    // name, should be processed.
10723    if (!dataset) {
10724       TString dsns(dsname.Data()), dsn1;
10725       Int_t from1 = 0;
10726       while (dsns.Tokenize(dsn1, from1, "[, ]")) {
10727          TString dsn2, enl;
10728          Int_t from2 = 0;
10729          TFileCollection *fc = 0;
10730          while (dsn1.Tokenize(dsn2, from2, "|")) {
10731             enl = "";
10732             Int_t ienl = dsn2.Index("?enl=");
10733             if (ienl != kNPOS) {
10734                enl = dsn2(ienl + 5, dsn2.Length());
10735                dsn2.Remove(ienl);
10736             }
10737             if ((fc = mgr->GetDataSet(dsn2.Data()))) {
10738                dsnparse = dsn2;
10739                if (!dataset) {
10740                   // This is our dataset
10741                   dataset = fc;
10742                } else {
10743                   // Add it to the dataset
10744                   dataset->Add(fc);
10745                   SafeDelete(fc);
10746                }
10747             }
10748          }
10749          // The dataset name(s) in the first element
10750          if (dataset) {
10751             if (dataset->GetList()->First())
10752                ((TFileInfo *)(dataset->GetList()->First()))->SetTitle(dsn1.Data());
10753             // Add it to the local list
10754             if (enl.IsNull()) {
10755                datasets->Add(new TPair(dataset, new TObjString("")));
10756             } else {
10757                datasets->Add(new TPair(dataset, new TObjString(enl.Data())));
10758             }
10759          }
10760          // Reset the pointer
10761          dataset = 0;
10762       }
10763       if (!datasets || datasets->GetSize() <= 0) {
10764          emsg.Form("no dataset(s) found on the master corresponding to: %s", dsname.Data());
10765          return -1;
10766       } else {
10767          // Make 'dataset' to point to the first one in the list
10768          if (!(dataset = (TFileCollection *) ((TPair *)(datasets->First()))->Key())) {
10769             emsg.Form("dataset pointer is null: corruption? - aborting");
10770             return -1;
10771          }
10772       }
10773       // Apply the lookup option requested by the client or the administartor
10774       // (by default we trust the information in the dataset)
10775       if (TProof::GetParameter(input, "PROOF_LookupOpt", lookupopt) != 0) {
10776          lookupopt = gEnv->GetValue("Proof.LookupOpt", "stagedOnly");
10777          input->Add(new TNamed("PROOF_LookupOpt", lookupopt.Data()));
10778       }
10779    } else {
10780       // We were given a named, single, TFileCollection
10781       dsnparse = dsname;
10782    }
10783 
10784    // Logic for the subdir/obj names: try first to see if the dataset name contains
10785    // some info; if not check the settings in the TDSet object itself; if still empty
10786    // check the default tree name / path in the TFileCollection object; if still empty
10787    // use the default as the flow will determine
10788    TString dsTree;
10789    // Get the [subdir/]tree, if any
10790    mgr->ParseUri(dsnparse.Data(), 0, 0, 0, &dsTree);
10791    if (dsTree.IsNull()) {
10792       // Use what we have in the original dataset; we need this to locate the
10793       // meta data information
10794       dsTree += dset->GetDirectory();
10795       dsTree += dset->GetObjName();
10796    }
10797    if (!dsTree.IsNull() && dsTree != "/") {
10798       TString tree(dsTree);
10799       Int_t idx = tree.Index("/");
10800       if (idx != kNPOS) {
10801          TString dir = tree(0, idx+1);
10802          tree.Remove(0, idx);
10803          dset->SetDirectory(dir);
10804       }
10805       dset->SetObjName(tree);
10806    } else {
10807       // Use the default obj name from the TFileCollection
10808       dsTree = dataset->GetDefaultTreeName();
10809    }
10810 
10811    // Pass dataset server mapping instructions, if any
10812    TList *srvmapsref = TDataSetManager::GetDataSetSrvMaps();
10813    TList *srvmapslist = srvmapsref;
10814    TString srvmaps;
10815    if (TProof::GetParameter(input, "PROOF_DataSetSrvMaps", srvmaps) == 0) {
10816       srvmapslist = TDataSetManager::ParseDataSetSrvMaps(srvmaps);
10817       if (gProofServ) {
10818          TString msg;
10819          if (srvmapsref && !srvmapslist) {
10820             msg.Form("+++ Info: dataset server mapping(s) DISABLED by user");
10821          } else if (srvmapsref && srvmapslist && srvmapslist != srvmapsref) {
10822             msg.Form("+++ Info: dataset server mapping(s) modified by user");
10823          } else if (!srvmapsref && srvmapslist) {
10824             msg.Form("+++ Info: dataset server mapping(s) added by user");
10825          }
10826          gProofServ->SendAsynMessage(msg.Data());
10827       }
10828    }
10829 
10830    // Flag multi-datasets
10831    if (datasets->GetSize() > 1) dset->SetBit(TDSet::kMultiDSet);
10832    // Loop over the list of datasets
10833    TList *listOfMissingFiles = new TList;
10834    TEntryList *entrylist = 0;
10835    TPair *pair = 0;
10836    TIter nxds(datasets);
10837    while ((pair = (TPair *) nxds())) {
10838       // File Collection
10839       dataset = (TFileCollection *) pair->Key();
10840       // Entry list, if any
10841       TEntryList *enl = 0;
10842       TObjString *os = (TObjString *) pair->Value();
10843       if (strlen(os->GetName())) {
10844          if (!(enl = dynamic_cast<TEntryList *>(input->FindObject(os->GetName())))) {
10845             if (gProofServ)
10846                gProofServ->SendAsynMessage(TString::Format("+++ Warning:"
10847                                            " entry list %s not found", os->GetName()));
10848          }
10849          if (enl && (!(enl->GetLists()) || enl->GetLists()->GetSize() <= 0)) {
10850             if (gProofServ)
10851                gProofServ->SendAsynMessage(TString::Format("+++ Warning:"
10852                                            " no sub-lists in entry-list!"));
10853          }
10854       }
10855       TList *missingFiles = new TList;
10856       TSeqCollection* files = dataset->GetList();
10857       if (gDebug > 0) files->Print();
10858       Bool_t availableOnly = (lookupopt != "all") ? kTRUE : kFALSE;
10859       if (dset->TestBit(TDSet::kMultiDSet)) {
10860          TDSet *ds = new TDSet(dataset->GetName(), dset->GetObjName(), dset->GetDirectory());
10861          ds->SetSrvMaps(srvmapslist);
10862          if (!ds->Add(files, dsTree, availableOnly, missingFiles)) {
10863             emsg.Form("error integrating dataset %s", dataset->GetName());
10864             continue;
10865          }
10866          // Add the TDSet object to the multi-dataset
10867          dset->Add(ds);
10868          // Add entry list if any
10869          if (enl) ds->SetEntryList(enl);
10870       } else {
10871          dset->SetSrvMaps(srvmapslist);
10872          if (!dset->Add(files, dsTree, availableOnly, missingFiles)) {
10873             emsg.Form("error integrating dataset %s", dataset->GetName());
10874             continue;
10875          }
10876          if (enl) entrylist = enl;
10877       }
10878       if (missingFiles) {
10879          // The missing files objects have to be removed from the dataset
10880          // before delete.
10881          TIter next(missingFiles);
10882          TObject *file;
10883          while ((file = next())) {
10884             dataset->GetList()->Remove(file);
10885             listOfMissingFiles->Add(file);
10886          }
10887          missingFiles->SetOwner(kFALSE);
10888          missingFiles->Clear();
10889       }
10890       SafeDelete(missingFiles);
10891    }
10892    // Cleanup; we need to do this because pairs do no delete their content
10893    nxds.Reset();
10894    while ((pair = (TPair *) nxds())) {
10895       if (pair->Key()) delete pair->Key();
10896       if (pair->Value()) delete pair->Value();
10897    }
10898    datasets->SetOwner(kTRUE);
10899    SafeDelete(datasets);
10900 
10901    // Cleanup the server mapping list, if created by the user
10902    if (srvmapslist && srvmapslist != srvmapsref) {
10903       srvmapslist->SetOwner(kTRUE);
10904       SafeDelete(srvmapslist);
10905    }
10906 
10907    // Set the global entrylist, if required
10908    if (entrylist) dset->SetEntryList(entrylist);
10909 
10910    // Make sure it will be sent back merged with other similar lists created
10911    // during processing; this list will be transferred by the player to the
10912    // output list, once the latter has been created (see TProofPlayerRemote::Process)
10913    if (listOfMissingFiles && listOfMissingFiles->GetSize() > 0) {
10914       listOfMissingFiles->SetName("MissingFiles");
10915       input->Add(listOfMissingFiles);
10916    }
10917 
10918    // Done
10919    return 0;
10920 }
10921 
10922 //______________________________________________________________________________
10923 Int_t TProof::SaveInputData(TQueryResult *qr, const char *cachedir, TString &emsg)
10924 {
10925    // Save input data file from 'cachedir' into the sandbox or create a the file
10926    // with input data objects
10927 
10928    TList *input = 0;
10929 
10930    // We must have got something to process
10931    if (!qr || !(input = qr->GetInputList()) ||
10932        !cachedir || strlen(cachedir) <= 0) return 0;
10933 
10934    // There must be some input data or input data file
10935    TNamed *data = (TNamed *) input->FindObject("PROOF_InputDataFile");
10936    TList *inputdata = (TList *) input->FindObject("PROOF_InputData");
10937    if (!data && !inputdata) return 0;
10938    // Default dstination filename
10939    if (!data)
10940       input->Add((data = new TNamed("PROOF_InputDataFile", kPROOF_InputDataFile)));
10941 
10942    TString dstname(data->GetTitle()), srcname;
10943    Bool_t fromcache = kFALSE;
10944    if (dstname.BeginsWith("cache:")) {
10945       fromcache = kTRUE;
10946       dstname.ReplaceAll("cache:", "");
10947       srcname.Form("%s/%s", cachedir, dstname.Data());
10948       if (gSystem->AccessPathName(srcname)) {
10949          emsg.Form("input data file not found in cache (%s)", srcname.Data());
10950          return -1;
10951       }
10952    }
10953 
10954    // If from cache, just move the cache file
10955    if (fromcache) {
10956       if (gSystem->CopyFile(srcname, dstname, kTRUE) != 0) {
10957          emsg.Form("problems copying %s to %s", srcname.Data(), dstname.Data());
10958          return -1;
10959       }
10960    } else {
10961       // Create the file
10962       if (inputdata && inputdata->GetSize() > 0) {
10963          TFile *f = TFile::Open(dstname.Data(), "RECREATE");
10964          if (f) {
10965             f->cd();
10966             inputdata->Write();
10967             f->Close();
10968             delete f;
10969          } else {
10970             emsg.Form("could not create %s", dstname.Data());
10971             return -1;
10972          }
10973       } else {
10974          emsg.Form("no input data!");
10975          return -1;
10976       }
10977    }
10978    ::Info("TProof::SaveInputData", "input data saved to %s", dstname.Data());
10979 
10980    // Save the file name and clean up the data list
10981    data->SetTitle(dstname);
10982    if (inputdata) {
10983       input->Remove(inputdata);
10984       inputdata->SetOwner();
10985       delete inputdata;
10986    }
10987 
10988    // Done
10989    return 0;
10990 }
10991 
10992 //______________________________________________________________________________
10993 Int_t TProof::SendInputData(TQueryResult *qr, TProof *p, TString &emsg)
10994 {
10995    // Send the input data file to the workers
10996 
10997    TList *input = 0;
10998 
10999    // We must have got something to process
11000    if (!qr || !(input = qr->GetInputList())) return 0;
11001 
11002    // There must be some input data or input data file
11003    TNamed *inputdata = (TNamed *) input->FindObject("PROOF_InputDataFile");
11004    if (!inputdata) return 0;
11005 
11006    TString fname(inputdata->GetTitle());
11007    if (gSystem->AccessPathName(fname)) {
11008       emsg.Form("input data file not found in sandbox (%s)", fname.Data());
11009       return -1;
11010    }
11011 
11012    // PROOF session must available
11013    if (!p || !p->IsValid()) {
11014       emsg.Form("TProof object undefined or invalid: protocol error!");
11015       return -1;
11016    }
11017 
11018    // Send to unique workers and submasters
11019    p->BroadcastFile(fname, TProof::kBinary, "cache");
11020 
11021    // Done
11022    return 0;
11023 }
11024 
11025 //______________________________________________________________________________
11026 Int_t TProof::GetInputData(TList *input, const char *cachedir, TString &emsg)
11027 {
11028    // Get the input data from the file defined in the input list
11029 
11030    // We must have got something to process
11031    if (!input || !cachedir || strlen(cachedir) <= 0) return 0;
11032 
11033    // There must be some input data or input data file
11034    TNamed *inputdata = (TNamed *) input->FindObject("PROOF_InputDataFile");
11035    if (!inputdata) return 0;
11036 
11037    TString fname;
11038    fname.Form("%s/%s", cachedir, inputdata->GetTitle());
11039    if (gSystem->AccessPathName(fname)) {
11040       emsg.Form("input data file not found in cache (%s)", fname.Data());
11041       return -1;
11042    }
11043 
11044    // Read the input data into the input list
11045    TFile *f = TFile::Open(fname.Data());
11046    if (f) {
11047       TList *keys = (TList *) f->GetListOfKeys();
11048       if (!keys) {
11049          emsg.Form("could not get list of object keys from file");
11050          return -1;
11051       }
11052       TIter nxk(keys);
11053       TKey *k = 0;
11054       while ((k = (TKey *)nxk())) {
11055          TObject *o = f->Get(k->GetName());
11056          if (o) input->Add(o);
11057       }
11058       f->Close();
11059       delete f;
11060    } else {
11061       emsg.Form("could not open %s", fname.Data());
11062       return -1;
11063    }
11064 
11065    // Done
11066    return 0;
11067 }
11068 
11069 //______________________________________________________________________________
11070 void TProof::LogViewer(const char *url, Int_t idx)
11071 {
11072    // Start the log viewer window usign the plugin manager
11073 
11074    if (!gROOT->IsBatch()) {
11075       // Get the handler, if not yet done
11076       if (!fgLogViewer) {
11077          if ((fgLogViewer =
11078             gROOT->GetPluginManager()->FindHandler("TProofProgressLog"))) {
11079             if (fgLogViewer->LoadPlugin() == -1) {
11080                fgLogViewer = 0;
11081                ::Error("TProof::LogViewer", "cannot load the relevant plug-in");
11082                return;
11083             }
11084          }
11085       }
11086       if (fgLogViewer) {
11087          // Execute the plug-in
11088          TString u = (url && strlen(url) <= 0) ? "lite" : url;
11089          fgLogViewer->ExecPlugin(2, u.Data(), idx);
11090       }
11091    } else {
11092       if (url && strlen(url) > 0) {
11093          ::Info("TProof::LogViewer",
11094                 "batch mode: use TProofLog *pl = TProof::Mgr(\"%s\")->GetSessionLogs(%d)", url, idx);
11095       } else if (url && strlen(url) <= 0) {
11096          ::Info("TProof::LogViewer",
11097                 "batch mode: use TProofLog *pl = TProof::Mgr(\"lite\")->GetSessionLogs(%d)", idx);
11098       } else {
11099          ::Info("TProof::LogViewer",
11100                 "batch mode: use TProofLog *pl = TProof::Mgr(\"<master>\")->GetSessionLogs(%d)", idx);
11101       }
11102    }
11103    // Done
11104    return;
11105 }
11106 
11107 //______________________________________________________________________________
11108 void TProof::SetProgressDialog(Bool_t on)
11109 {
11110    // Enable/Disable the graphic progress dialog.
11111    // By default the dialog is enabled
11112 
11113    if (on)
11114       SetBit(kUseProgressDialog);
11115    else
11116       ResetBit(kUseProgressDialog);
11117 }
11118 
11119 //______________________________________________________________________________
11120 void TProof::ShowMissingFiles(TQueryResult *qr)
11121 {
11122    // Show information about missing files during query described by 'qr' or the
11123    // last query if qr is null (default).
11124    // A short summary is printed in the end.
11125 
11126    TQueryResult *xqr = (qr) ? qr : GetQueryResult();
11127    if (!xqr) {
11128       Warning("ShowMissingFiles", "no (last) query found: do nothing");
11129       return;
11130    }
11131    
11132    // Get the list, if any
11133    TList *missing = (xqr->GetOutputList()) ? (TList *) xqr->GetOutputList()->FindObject("MissingFiles") : 0;
11134    if (!missing) {
11135       Info("ShowMissingFiles", "no files missing in query %s:%s", xqr->GetTitle(), xqr->GetName());
11136       return;
11137    }
11138 
11139    Int_t nmf = 0;
11140    Long64_t msz = 0, mszzip = 0, mev = 0;
11141    // Scan the list
11142    TFileInfo *fi = 0;
11143    TIter nxf(missing);
11144    while ((fi = (TFileInfo *) nxf())) {
11145       fi->Print();
11146       nmf++;
11147       TFileInfoMeta *im = fi->GetMetaData();
11148       if (im) {
11149          if (im->GetTotBytes() > 0) msz += im->GetTotBytes(); 
11150          if (im->GetZipBytes() > 0) mszzip += im->GetZipBytes(); 
11151          mev += im->GetEntries();
11152       }
11153    }
11154 
11155    // Final notification
11156    if (msz <= 0) msz = -1;
11157    if (mszzip <= 0) mszzip = -1;
11158    Double_t xf = (Double_t)mev / (mev + xqr->GetEntries()) ; 
11159    Printf(" +++ %d files missing, i.e. %lld events (%lld bytes, %lld zipped) --> about %.2f%%  of the total events",
11160           nmf, mev, msz, mszzip, xf * 100.);
11161 }
11162 
11163 //______________________________________________________________________________
11164 TFileCollection *TProof::GetMissingFiles(TQueryResult *qr)
11165 {
11166    // Get a TFileCollection with the files missing in the query described by 'qr'
11167    // or the last query if qr is null (default).
11168    // Return a null pointer if none were found, for whatever reason.
11169    // The caller is responsible for the returned object.
11170 
11171    TFileCollection *fc = 0;
11172 
11173    TQueryResult *xqr = (qr) ? qr : GetQueryResult();
11174    if (!xqr) {
11175       Warning("GetMissingFiles", "no (last) query found: do nothing");
11176       return fc;
11177    }
11178    
11179    // Get the list, if any
11180    TList *missing = (xqr->GetOutputList()) ? (TList *) xqr->GetOutputList()->FindObject("MissingFiles") : 0;
11181    if (!missing) {
11182       if (gDebug > 0)
11183          Info("ShowMissingFiles", "no files missing in query %s:%s", xqr->GetTitle(), xqr->GetName());
11184       return fc;
11185    }
11186 
11187    // Create collection: name is <dsname>.m<j>, where 'j' is the first giving a non existing name
11188    TString fcname("unknown");
11189    TDSet *ds = (TDSet *) xqr->GetInputObject("TDSet");
11190    if (ds) {
11191       fcname.Form("%s.m0", ds->GetName());
11192       Int_t j = 1;
11193       while (gDirectory->FindObject(fcname) && j < 1000)
11194          fcname.Form("%s.m%d", ds->GetName(), j++);
11195    }
11196    fc = new TFileCollection(fcname, "Missing Files");
11197    if (ds) fc->SetDefaultTreeName(ds->GetObjName());
11198    // Scan the list
11199    TFileInfo *fi = 0;
11200    TIter nxf(missing);
11201    while ((fi = (TFileInfo *) nxf())) {
11202       fc->Add((TFileInfo *) fi->Clone());
11203    }
11204    fc->Update();
11205    // Done
11206    return fc;
11207 }

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