Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TProofMgr.cxx
Go to the documentation of this file.
1 // @(#)root/proof:$Id$
2 // Author: G. Ganis, Nov 2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TProofMgr
13 \ingroup proofkernel
14 
15 The PROOF manager interacts with the PROOF server coordinator to
16 create or destroy a PROOF session, attach to or detach from
17 existing one, and to monitor any client activity on the cluster.
18 At most one manager instance per server is allowed.
19 
20 */
21 
22 #include "Bytes.h"
23 #include "TError.h"
24 #include "TEnv.h"
25 #include "TFile.h"
26 #include "TFileCollection.h"
27 #include "TFileInfo.h"
28 #include "TList.h"
29 #include "TParameter.h"
30 #include "TProof.h"
31 #include "TProofMgr.h"
32 #include "TProofMgrLite.h"
33 #include "TSocket.h"
34 #include "TROOT.h"
35 #include "TMath.h"
36 
37 ClassImp(TProofMgr);
38 
39 // Sub-list of TROOT::fProofs with managers
40 TList TProofMgr::fgListOfManagers;
41 TProofMgr_t TProofMgr::fgTXProofMgrHook = 0;
42 
43 // Auxilliary structures for pinging
44 // The client request
45 typedef struct {
46  int first;
47  int second;
48  int third;
49  int fourth;
50  int fifth;
51 } clnt_HS_t;
52 // The body received after the first handshake's header
53 typedef struct {
54  int msglen;
55  int protover;
56  int msgval;
57 } srv_HS_t;
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 /// Create a PROOF manager for the standard (old) environment.
61 
62 TProofMgr::TProofMgr(const char *url, Int_t, const char *alias)
63  : TNamed("",""), fRemoteProtocol(-1), fServType(kXProofd),
64  fSessions(0), fIntHandler(0)
65 {
66  fServType = kProofd;
67 
68  // AVoid problems with empty URLs
69  fUrl = (!url || strlen(url) <= 0) ? TUrl("proof://localhost") : TUrl(url);
70 
71  // Correct URL protocol
72  if (!strcmp(fUrl.GetProtocol(), TUrl("a").GetProtocol()))
73  fUrl.SetProtocol("proof");
74 
75  // Check port
76  if (fUrl.GetPort() == TUrl("a").GetPort()) {
77  // For the time being we use 'rootd' service as default.
78  // This will be changed to 'proofd' as soon as XRD will be able to
79  // accept on multiple ports
80  Int_t port = gSystem->GetServiceByName("proofd");
81  if (port < 0) {
82  if (gDebug > 0)
83  Info("TProofMgr","service 'proofd' not found by GetServiceByName"
84  ": using default IANA assigned tcp port 1093");
85  port = 1093;
86  } else {
87  if (gDebug > 1)
88  Info("TProofMgr","port from GetServiceByName: %d", port);
89  }
90  fUrl.SetPort(port);
91  }
92 
93  // Check and save the host FQDN ...
94  if (strcmp(fUrl.GetHost(), "__lite__")) {
95  if (strcmp(fUrl.GetHost(), fUrl.GetHostFQDN()))
96  fUrl.SetHost(fUrl.GetHostFQDN());
97  }
98 
99  SetName(fUrl.GetUrl(kTRUE));
100  if (alias)
101  SetAlias(alias);
102  else
103  SetAlias(fUrl.GetHost());
104 }
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 /// Destroy a TProofMgr instance
108 
109 TProofMgr::~TProofMgr()
110 {
111  SafeDelete(fSessions);
112  SafeDelete(fIntHandler);
113 
114  fgListOfManagers.Remove(this);
115  gROOT->GetListOfProofs()->Remove(this);
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 /// Dummy version provided for completeness. Just returns a pointer to
120 /// existing session 'id' (as shown by TProof::QuerySessions) or 0 if 'id' is
121 /// not valid. The boolena 'gui' should be kTRUE when invoked from the GUI.
122 
123 TProof *TProofMgr::AttachSession(Int_t id, Bool_t gui)
124 {
125  TProofDesc *d = GetProofDesc(id);
126  if (d)
127  return AttachSession(d, gui);
128 
129  Info("AttachSession","invalid proofserv id (%d)", id);
130  return 0;
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Dummy version provided for completeness. Just returns a pointer to
135 /// existing session 'id' (as shown by TProof::QuerySessions) or 0 if 'id' is
136 /// not valid.
137 
138 TProof *TProofMgr::AttachSession(TProofDesc *d, Bool_t)
139 {
140  if (!d) {
141  Warning("AttachSession","invalid description object - do nothing");
142  return 0;
143  }
144 
145  if (d->GetProof())
146  // Nothing to do if already in contact with proofserv
147  return d->GetProof();
148 
149  Warning("AttachSession","session not available - do nothing");
150  return 0;
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Detach session with 'id' from its proofserv. The 'id' is the number
155 /// shown by QuerySessions. The correspondent TProof object is deleted.
156 /// If id == 0 all the known sessions are detached.
157 /// Option opt="S" or "s" forces session shutdown.
158 
159 void TProofMgr::DetachSession(Int_t id, Option_t *opt)
160 {
161  if (!IsValid()) {
162  Warning("DetachSession","invalid TProofMgr - do nothing");
163  return;
164  }
165 
166  if (id > 0) {
167 
168  TProofDesc *d = GetProofDesc(id);
169  if (d) {
170  if (d->GetProof())
171  d->GetProof()->Detach(opt);
172  TProof *p = d->GetProof();
173  fSessions->Remove(d);
174  SafeDelete(p);
175  delete d;
176  }
177 
178  } else if (id == 0) {
179 
180  // Requesto to destroy all sessions
181  if (fSessions) {
182  // Delete PROOF sessions
183  TIter nxd(fSessions);
184  TProofDesc *d = 0;
185  while ((d = (TProofDesc *)nxd())) {
186  if (d->GetProof())
187  d->GetProof()->Detach(opt);
188  TProof *p = d->GetProof();
189  fSessions->Remove(d);
190  SafeDelete(p);
191  }
192  fSessions->Delete();
193  }
194  }
195 
196  return;
197 }
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Detach session 'p' from its proofserv. The instance 'p' is invalidated
201 /// and should be deleted by the caller
202 
203 void TProofMgr::DetachSession(TProof *p, Option_t *opt)
204 {
205  if (!IsValid()) {
206  Warning("DetachSession","invalid TProofMgr - do nothing");
207  return;
208  }
209 
210  if (p) {
211  // Single session request
212  TProofDesc *d = GetProofDesc(p);
213  if (d) {
214  if (d->GetProof())
215  // The session is closed here
216  d->GetProof()->Detach(opt);
217  fSessions->Remove(d);
218  delete d;
219  }
220  }
221 
222  return;
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 /// Get list of sessions accessible to this manager.
227 
228 TList *TProofMgr::QuerySessions(Option_t *opt)
229 {
230  if (opt && !strncasecmp(opt,"L",1))
231  // Just return the existing list
232  return fSessions;
233 
234  // Create list if not existing
235  if (!fSessions) {
236  fSessions = new TList();
237  fSessions->SetOwner();
238  }
239 
240  // Fill-in entries from the official list
241  if (gROOT->GetListOfProofs()) {
242  // Loop over
243  TIter nxp(gROOT->GetListOfProofs());
244  TObject *o = 0;
245  TProof *p = 0;
246  Int_t ns = 0;
247  while ((o = nxp())) {
248  if (o->InheritsFrom(TProof::Class())) {
249  p = (TProof *)o;
250  // Only those belonging to this server
251  if (MatchUrl(p->GetUrl())) {
252  if (!(fSessions->FindObject(p->GetSessionTag()))) {
253  Int_t st = (p->IsIdle()) ? TProofDesc::kIdle
254  : TProofDesc::kRunning;
255  TProofDesc *d =
256  new TProofDesc(p->GetName(), p->GetTitle(), p->GetUrl(),
257  ++ns, p->GetSessionID(), st, p);
258  fSessions->Add(d);
259  }
260  }
261  }
262  }
263  }
264 
265  // Drop entries not existing any longer
266  if (fSessions->GetSize() > 0) {
267  TIter nxd(fSessions);
268  TProofDesc *d = 0;
269  while ((d = (TProofDesc *)nxd())) {
270  if (d->GetProof()) {
271  if (!(gROOT->GetListOfProofs()->FindObject(d->GetProof()))) {
272  fSessions->Remove(d);
273  SafeDelete(d);
274  } else {
275  if (opt && !strncasecmp(opt,"S",1))
276  d->Print("");
277  }
278  }
279  }
280  }
281 
282  // We are done
283  return fSessions;
284 }
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 /// Send a message to connected users. Only superusers can do this.
288 /// The first argument specifies the message or the file from where to take
289 /// the message.
290 /// The second argument specifies the user to which to send the message: if
291 /// empty or null the message is send to all the connected users.
292 /// return 0 in case of success, -1 in case of error
293 
294 Int_t TProofMgr::SendMsgToUsers(const char *, const char *)
295 {
296  Warning("SendMsgToUsers","functionality not supported");
297 
298  return -1;
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Send a cleanup request for the sessions associated with the current
303 /// user.
304 /// Not supported.
305 
306 Int_t TProofMgr::Reset(Bool_t, const char *)
307 {
308  Warning("Reset","functionality not supported");
309 
310  return -1;
311 }
312 
313 ////////////////////////////////////////////////////////////////////////////////
314 /// Show available workers
315 
316 void TProofMgr::ShowWorkers()
317 {
318  AbstractMethod("ShowWorkers");
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Get TProofDesc instance corresponding to 'id'.
323 
324 TProofDesc *TProofMgr::GetProofDesc(Int_t id)
325 {
326  TProofDesc *d = 0;
327  if (id > 0) {
328  // Retrieve an updated list
329  QuerySessions("");
330  if (fSessions) {
331  TIter nxd(fSessions);
332  while ((d = (TProofDesc *)nxd())) {
333  if (d->MatchId(id))
334  return d;
335  }
336  }
337  }
338 
339  return d;
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// Get TProofDesc instance corresponding to TProof object 'p'.
344 
345 TProofDesc *TProofMgr::GetProofDesc(TProof *p)
346 {
347  TProofDesc *d = 0;
348  if (p) {
349  // Retrieve an updated list
350  QuerySessions("");
351  if (fSessions) {
352  TIter nxd(fSessions);
353  while ((d = (TProofDesc *)nxd())) {
354  if (p == d->GetProof())
355  return d;
356  }
357  }
358  }
359 
360  return d;
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 /// Discard TProofDesc of session 'p' from the internal list
365 
366 void TProofMgr::DiscardSession(TProof *p)
367 {
368  if (p) {
369  TProofDesc *d = 0;
370  if (fSessions) {
371  TIter nxd(fSessions);
372  while ((d = (TProofDesc *)nxd())) {
373  if (p == d->GetProof()) {
374  fSessions->Remove(d);
375  delete d;
376  break;
377  }
378  }
379  }
380  }
381 }
382 
383 ////////////////////////////////////////////////////////////////////////////////
384 /// Create a new remote session (master and associated workers).
385 
386 TProof *TProofMgr::CreateSession(const char *cfg,
387  const char *cfgdir, Int_t loglevel)
388 {
389  // Create
390  if (IsProofd())
391  fUrl.SetOptions("std");
392 
393  // Create the instance
394  TProof *p = new TProof(fUrl.GetUrl(), cfg, cfgdir, loglevel, 0, this);
395 
396  if (p && p->IsValid()) {
397 
398  // Save record about this session
399  Int_t ns = 1;
400  if (fSessions) {
401  // To avoid ambiguities in case of removal of some elements
402  if (fSessions->Last())
403  ns = ((TProofDesc *)(fSessions->Last()))->GetLocalId() + 1;
404  } else {
405  // Create the list
406  fSessions = new TList;
407  }
408 
409  // Create the description class
410  Int_t st = (p->IsIdle()) ? TProofDesc::kIdle : TProofDesc::kRunning ;
411  TProofDesc *d =
412  new TProofDesc(p->GetName(), p->GetTitle(), p->GetUrl(),
413  ns, p->GetSessionID(), st, p);
414  fSessions->Add(d);
415 
416  } else {
417  // Session creation failed
418  if (gDebug > 0) Error("CreateSession", "PROOF session creation failed");
419  SafeDelete(p);
420  }
421 
422  // We are done
423  return p;
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Checks if 'url' refers to the same 'user@host:port' entity as the URL
428 /// in memory
429 
430 Bool_t TProofMgr::MatchUrl(const char *url)
431 {
432  TUrl u(url);
433 
434  // Correct URL protocol
435  if (!strcmp(u.GetProtocol(), TUrl("a").GetProtocol()))
436  u.SetProtocol("proof");
437 
438  // Correct port
439  if (u.GetPort() == TUrl("a").GetPort()) {
440  Int_t port = gSystem->GetServiceByName("proofd");
441  if (port < 0)
442  port = 1093;
443  u.SetPort(port);
444  }
445 
446  // Now we can check
447  if (!strcmp(u.GetHostFQDN(), fUrl.GetHostFQDN()))
448  if (u.GetPort() == fUrl.GetPort())
449  if (strlen(u.GetUser()) <= 0 || !strcmp(u.GetUser(),fUrl.GetUser()))
450  return kTRUE;
451 
452  // Match failed
453  return kFALSE;
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Extract pointers to PROOF managers from TROOT::fProofs.
458 
459 TList *TProofMgr::GetListOfManagers()
460 {
461  // Update the list with new entries
462  if (gROOT->GetListOfProofs()) {
463  TIter nxp(gROOT->GetListOfProofs());
464  TObject *o = 0;
465  while ((o = nxp())) {
466  if (o->InheritsFrom(TProofMgr::Class()) && !fgListOfManagers.FindObject(o))
467  fgListOfManagers.Add(o);
468  }
469  }
470 
471  // Get rid of invalid entries and notify
472  if (fgListOfManagers.GetSize() > 0) {
473  TIter nxp(&fgListOfManagers);
474  TObject *o = 0;
475  Int_t nm = 0;
476  while ((o = nxp())) {
477  if (!(gROOT->GetListOfProofs()->FindObject(o))) {
478  fgListOfManagers.Remove(o);
479  } else {
480  TProofMgr *p = (TProofMgr *)o;
481  if (gDebug > 0)
482  Printf("// #%d: \"%s\" (%s)", ++nm, p->GetName(), p->GetTitle());
483  }
484  }
485  } else {
486  if (gDebug > 0)
487  Printf("No managers found");
488  }
489 
490  // We are done
491  return &fgListOfManagers;
492 }
493 
494 ////////////////////////////////////////////////////////////////////////////////
495 /// Static method returning the appropriate TProofMgr object using
496 /// the plugin manager.
497 
498 TProofMgr *TProofMgr::Create(const char *uin, Int_t loglevel,
499  const char *alias, Bool_t xpd)
500 {
501  TProofMgr *m= 0;
502 
503  Bool_t isLite = kFALSE;
504 
505  // Resolve url; if empty the actions depend of the default
506  TUrl u(uin);
507  TString proto = u.GetProtocol();
508  if (proto.IsNull()) {
509  u.SetUrl(gEnv->GetValue("Proof.LocalDefault", "lite://"));
510  proto = u.GetProtocol();
511  }
512  TString host = u.GetHost();
513  if (proto == "lite" || host == "__lite__" ) {
514 #ifndef WIN32
515  isLite = kTRUE;
516  u.SetHost("__lite__");
517  u.SetProtocol("proof");
518  u.SetPort(1093);
519 #else
520  ::Info("TProofMgr::Create","'lite' not yet supported on Windows");
521  return m;
522 #endif
523  }
524 
525  if (!isLite) {
526  // in case user gave as url: "machine.dom.ain", replace
527  // "http" by "proof" and "80" by "1093"
528  if (!strcmp(u.GetProtocol(), TUrl("a").GetProtocol()))
529  u.SetProtocol("proof");
530  if (u.GetPort() == TUrl("a").GetPort())
531  u.SetPort(1093);
532  }
533 
534  // Avoid multiple calls to GetUrl
535  const char *url = u.GetUrl();
536 
537  // Make sure we do not have already a manager for this URL
538  TList *lm = TProofMgr::GetListOfManagers();
539  if (lm) {
540  TIter nxm(lm);
541  while ((m = (TProofMgr *)nxm())) {
542  if (m->IsValid()) {
543  if (m->MatchUrl(url)) return m;
544  } else {
545  fgListOfManagers.Remove(m);
546  SafeDelete(m);
547  break;
548  }
549  }
550  }
551 
552  if (isLite) {
553  // Init the lite version
554  return new TProofMgrLite(url, loglevel, alias);
555  }
556 
557  m = 0;
558  Bool_t trystd = kTRUE;
559 
560  // If required, we assume first that the remote server is based on XrdProofd
561  if (xpd) {
562  TProofMgr_t cm = TProofMgr::GetXProofMgrHook();
563  if (cm) {
564  m = (TProofMgr *) (*cm)(url, loglevel, alias);
565  // Update trystd flag
566  trystd = (m && !(m->IsValid()) && m->IsProofd()) ? kTRUE : kFALSE;
567  }
568  }
569 
570  // If the first attempt failed, we instantiate an old interface
571  if (trystd) {
572  SafeDelete(m);
573  m = new TProofMgr(url, loglevel, alias);
574  }
575 
576  // Record the new manager, if any
577  if (m) {
578  fgListOfManagers.Add(m);
579  if (m->IsValid() && !(m->IsProofd())) {
580  R__LOCKGUARD(gROOTMutex);
581  gROOT->GetListOfProofs()->Add(m);
582  gROOT->GetListOfSockets()->Add(m);
583  }
584  }
585 
586  // We are done
587  return m;
588 }
589 
590 ////////////////////////////////////////////////////////////////////////////////
591 /// Get the constructor hook fro TXProofMgr.
592 /// We do this without the plugin manager because it blocks the
593 /// CINT mutex breaking the parallel startup.
594 
595 TProofMgr_t TProofMgr::GetXProofMgrHook()
596 {
597  if (!fgTXProofMgrHook) {
598  // Load the appropriate library ...
599  TString prooflib = "libProofx";
600  char *p = 0;
601  if ((p = gSystem->DynamicPathName(prooflib, kTRUE))) {
602  delete[] p;
603  if (gSystem->Load(prooflib) == -1)
604  ::Error("TProofMgr::GetXProofMgrCtor",
605  "can't load %s", prooflib.Data());
606  } else
607  ::Error("TProofMgr::GetXProofMgrCtor",
608  "can't locate %s", prooflib.Data());
609  }
610 
611  // Done
612  return fgTXProofMgrHook;
613 }
614 
615 ////////////////////////////////////////////////////////////////////////////////
616 /// Set hook to TXProofMgr ctor
617 
618 void TProofMgr::SetTXProofMgrHook(TProofMgr_t pmh)
619 {
620  fgTXProofMgrHook = pmh;
621 }
622 
623 ////////////////////////////////////////////////////////////////////////////////
624 /// Non-blocking check for a PROOF (or Xrootd, if checkxrd) service at 'url'
625 /// Return
626 /// 0 if a XProofd (or Xrootd, if checkxrd) daemon is listening at 'url'
627 /// -1 if nothing is listening on the port (connection cannot be open)
628 /// 1 if something is listening but not XProofd (or not Xrootd, if checkxrd)
629 
630 Int_t TProofMgr::Ping(const char *url, Bool_t checkxrd)
631 {
632  if (!url || (url && strlen(url) <= 0)) {
633  ::Error("TProofMgr::Ping", "empty url - fail");
634  return -1;
635  }
636 
637  TUrl u(url);
638  // Check the port and set the defaults
639  if (!strcmp(u.GetProtocol(), "http") && u.GetPort() == 80) {
640  if (!checkxrd) {
641  u.SetPort(1093);
642  } else {
643  u.SetPort(1094);
644  }
645  }
646 
647  // Open the connection, disabling warnings ...
648  Int_t oldLevel = gErrorIgnoreLevel;
649  gErrorIgnoreLevel = kSysError+1;
650  TSocket s(u.GetHost(), u.GetPort());
651  if (!(s.IsValid())) {
652  if (gDebug > 0)
653  ::Info("TProofMgr::Ping", "could not open connection to %s:%d", u.GetHost(), u.GetPort());
654  gErrorIgnoreLevel = oldLevel;
655  return -1;
656  }
657  // Send the first bytes
658  int writeCount = -1;
659  clnt_HS_t initHS;
660  memset(&initHS, 0, sizeof(initHS));
661  int len = sizeof(initHS);
662  if (checkxrd) {
663  initHS.fourth = (int)host2net((int)4);
664  initHS.fifth = (int)host2net((int)2012);
665  if ((writeCount = s.SendRaw(&initHS, len)) != len) {
666  if (gDebug > 0)
667  ::Info("TProofMgr::Ping", "1st: wrong number of bytes sent: %d (expected: %d)",
668  writeCount, len);
669  gErrorIgnoreLevel = oldLevel;
670  return 1;
671  }
672  } else {
673  initHS.third = (int)host2net((int)1);
674  if ((writeCount = s.SendRaw(&initHS, len)) != len) {
675  if (gDebug > 0)
676  ::Info("TProofMgr::Ping", "1st: wrong number of bytes sent: %d (expected: %d)",
677  writeCount, len);
678  gErrorIgnoreLevel = oldLevel;
679  return 1;
680  }
681  // These 8 bytes are need by 'proofd' and discarded by XPD
682  int dum[2];
683  dum[0] = (int)host2net((int)4);
684  dum[1] = (int)host2net((int)2012);
685  if ((writeCount = s.SendRaw(&dum[0], sizeof(dum))) != sizeof(dum)) {
686  if (gDebug > 0)
687  ::Info("TProofMgr::Ping", "2nd: wrong number of bytes sent: %d (expected: %d)",
688  writeCount, (int) sizeof(dum));
689  gErrorIgnoreLevel = oldLevel;
690  return 1;
691  }
692  }
693  // Read first server response
694  int type;
695  len = sizeof(type);
696  int readCount = s.RecvRaw(&type, len); // 4(2+2) bytes
697  if (readCount != len) {
698  if (gDebug > 0)
699  ::Info("TProofMgr::Ping", "1st: wrong number of bytes read: %d (expected: %d)",
700  readCount, len);
701  gErrorIgnoreLevel = oldLevel;
702  return 1;
703  }
704  // to host byte order
705  type = net2host(type);
706  // Check if the server is the eXtended proofd
707  if (type == 0) {
708  srv_HS_t xbody;
709  len = sizeof(xbody);
710  readCount = s.RecvRaw(&xbody, len); // 12(4+4+4) bytes
711  if (readCount != len) {
712  if (gDebug > 0)
713  ::Info("TProofMgr::Ping", "2nd: wrong number of bytes read: %d (expected: %d)",
714  readCount, len);
715  gErrorIgnoreLevel = oldLevel;
716  return 1;
717  }
718  xbody.protover = net2host(xbody.protover);
719  xbody.msgval = net2host(xbody.msglen);
720  xbody.msglen = net2host(xbody.msgval);
721 
722  } else if (type == 8) {
723  // Standard proofd
724  if (gDebug > 0) ::Info("TProofMgr::Ping", "server is old %s", (checkxrd ? "ROOTD" : "PROOFD"));
725  gErrorIgnoreLevel = oldLevel;
726  return 1;
727  } else {
728  // We don't know the server type
729  if (gDebug > 0) ::Info("TProofMgr::Ping", "unknown server type: %d", type);
730  gErrorIgnoreLevel = oldLevel;
731  return 1;
732  }
733 
734  // Restore ignore level
735  gErrorIgnoreLevel = oldLevel;
736  // Done
737  return 0;
738 }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// Parse file name extracting the directory subcomponents in dirs, stored
742 /// as TObjStrings.
743 
744 void TProofMgr::ReplaceSubdirs(const char *fn, TString &fdst, TList &dirph)
745 {
746  if (!fn || (fn && strlen(fn) <= 0)) return;
747  if (dirph.GetSize() <= 0) return;
748 
749  // Parse fn
750  TList dirs;
751  TString dd(fn), d;
752  Ssiz_t from = 0;
753  while (dd.Tokenize(d, from, "/")) {
754  if (!d.IsNull()) dirs.Add(new TObjString(d));
755  }
756  if (dirs.GetSize() <= 0) return;
757  dirs.SetOwner(kTRUE);
758 
759  TIter nxph(&dirph);
760  TParameter<Int_t> *pi = 0;
761  while ((pi = (TParameter<Int_t> *) nxph())) {
762  if (pi->GetVal() < dirs.GetSize()) {
763  TObjString *os = (TObjString *) dirs.At(pi->GetVal());
764  if (os) fdst.ReplaceAll(pi->GetName(), os->GetName());
765  } else {
766  ::Warning("TProofMgr::ReplaceSubdirs",
767  "requested directory level '%s' is not available in the file path",
768  pi->GetName());
769  }
770  }
771 }
772 
773 ////////////////////////////////////////////////////////////////////////////////
774 /// Upload files provided via the list 'src' (as TFileInfo or TObjString)
775 /// to 'mss'. The path under 'mss' is determined by 'dest'; the following
776 /// place-holders can be used in 'dest':
777 /// <d0>, <d1>, <d2>, ... referring to the n-th sub-component
778 /// of the src path
779 /// <bn> basename in the source path
780 /// <bs> basename sans extension
781 /// <ex> Extension
782 /// <sn> serial number of file in the list
783 /// <s0> as <sn> but zero padded
784 /// <fn> the full file path
785 /// <us>, <gr> the local user and group names.
786 /// <pg> the users PROOF group
787 /// <pa> immediate parent directory
788 /// <gp> next-to immediate parent directory
789 /// So, for example, if the source filename for the 99-th file is
790 /// protosrc://host//d0/d1/d2/d3/d4/d5/myfile
791 /// then with dest = '/pool/user/<d3>/<d4>/<d5>/<s>/<bn>' and
792 /// mss = 'protodst://hostdst//nm/
793 /// the corresponding destination path is
794 /// protodst://hostdst//nm/pool/user/d3/d4/d5/99/myfile
795 ///
796 /// If 'dest' is empty, <fn> is used.
797 ///
798 /// Returns a TFileCollection with the destination files created; this
799 /// TFileCollection is, for example, ready to be registered as dataset.
800 
801 TFileCollection *TProofMgr::UploadFiles(TList *src,
802  const char *mss, const char *dest)
803 {
804  TFileCollection *ds = 0;
805 
806  // The inputs must be make sense
807  if (!src || (src && src->GetSize() <= 0)) {
808  ::Warning("TProofMgr::UploadFiles", "list is empty!");
809  return ds;
810  }
811  if (!mss || (mss && strlen(mss) <= 0)) {
812  ::Warning("TProofMgr::UploadFiles", "MSS is undefined!");
813  return ds;
814  }
815 
816  TList dirph;
817 
818  // If the destination is defined we need to understand if we have place-holders
819  if (dest && strlen(dest) > 0) {
820  TString dst(dest), dt;
821  Ssiz_t from = 0;
822  TRegexp re("<d+[0-9]>");
823  while (dst.Tokenize(dt, from, "/")) {
824  if (dt.Contains(re)) {
825  TParameter<Int_t> *pi = new TParameter<Int_t>(dt, -1);
826  dt.ReplaceAll("<d", "");
827  dt.ReplaceAll(">", "");
828  if (dt.IsDigit()) {
829  pi->SetVal(dt.Atoi());
830  dirph.Add(pi);
831  } else {
832  SafeDelete(pi);
833  }
834  }
835  }
836  dirph.SetOwner(kTRUE);
837  }
838  // Generate template for zero-padded serial numbers
839  TString sForm = TString::Format("%%0%dd",
840  Int_t(TMath::Log10(src->GetEntries()+1)));
841 
842  // Now we will actually copy files and create the TList object
843  ds = new TFileCollection();
844  TIter nxf(src);
845  TObject *o = 0;
846  TObjString *os = 0;
847  TFileInfo *fi = 0;
848  Int_t kn = 0;
849  while ((o = nxf())) {
850  TUrl *furl = 0;
851  if (!strcmp(o->ClassName(), "TFileInfo")) {
852  if (!(fi = dynamic_cast<TFileInfo *>(o))) {
853  ::Warning("TProofMgr::UploadFiles",
854  "object of class name '%s' does not cast to %s - ignore",
855  o->ClassName(), o->ClassName());
856  continue;
857  }
858  furl = fi->GetFirstUrl();
859  } else if (!strcmp(o->ClassName(), "TObjString")) {
860  if (!(os = dynamic_cast<TObjString *>(o))) {
861  ::Warning("TProofMgr::UploadFiles",
862  "object of class name '%s' does not cast to %s - ignore",
863  o->ClassName(), o->ClassName());
864  continue;
865  }
866  furl = new TUrl(os->GetName());
867  } else {
868  ::Warning("TProofMgr::UploadFiles",
869  "object of unsupported class '%s' found in list - ignore", o->ClassName());
870  continue;
871  }
872 
873  // The file must be accessible
874  if (gSystem->AccessPathName(furl->GetUrl()) == kFALSE) {
875 
876  // Create the destination path
877  TString fdst(mss);
878  if (dest && strlen(dest) > 0) {
879  fdst += dest;
880  } else {
881  fdst += TString::Format("/%s", furl->GetFile());
882  }
883 
884  // Replace filename and basename
885  if (fdst.Contains("<bn>")) fdst.ReplaceAll("<bn>", gSystem->BaseName(furl->GetFile()));
886  if (fdst.Contains("<fn>")) fdst.ReplaceAll("<fn>", furl->GetFile());
887  if (fdst.Contains("<bs>")) {
888  // Basename sans 'extension'
889  TString bs(gSystem->BaseName(furl->GetFile()));
890  Int_t idx = bs.Last('.');
891  if (idx != kNPOS) bs.Remove(idx);
892  fdst.ReplaceAll("<bs>", bs.Data());
893  }
894  if (fdst.Contains("<ex>")) {
895  // 'Extension' - that is the last part after the last '.'
896  TString ex(furl->GetFile());
897  Int_t idx = ex.Last('.');
898  if (idx != kNPOS) ex.Remove(0, idx+1);
899  else ex = "";
900  fdst.ReplaceAll("<ex>", ex);
901  }
902  if (fdst.Contains("<pa>")) {
903  fdst.ReplaceAll("<pa>",
904  gSystem->BaseName(gSystem
905  ->DirName(furl->GetFile())));
906 
907  }
908  if (fdst.Contains("<gp>")) {
909  fdst.ReplaceAll("<gp>",
910  gSystem->BaseName(gSystem
911  ->DirName(gSystem
912  ->DirName(furl->GetFile()))));
913 
914  }
915 
916 
917  // Replace serial number
918  if (fdst.Contains("<sn>")) {
919  TString skn = TString::Format("%d", kn);
920  fdst.ReplaceAll("<sn>", skn);
921  }
922  if (fdst.Contains("<s0>")) {
923  TString skn = TString::Format(sForm.Data(), kn);
924  fdst.ReplaceAll("<s0>", skn);
925  }
926  kn++;
927 
928  // Replace user and group name
929  UserGroup_t *pw = gSystem->GetUserInfo();
930  if (pw) {
931  if (fdst.Contains("<us>")) fdst.ReplaceAll("<us>", pw->fUser);
932  if (fdst.Contains("<gr>")) fdst.ReplaceAll("<gr>", pw->fGroup);
933  delete pw;
934  }
935  if (gProof && fdst.Contains("<pg>"))
936  fdst.ReplaceAll("<pg>", gProof->GetGroup());
937 
938  // Now replace the subdirs, if required
939  if (dirph.GetSize() > 0)
940  TProofMgr::ReplaceSubdirs(gSystem->DirName(furl->GetFile()), fdst, dirph);
941 
942  // Check double slashes in the file field (Turl sets things correctly inside)
943  TUrl u(fdst);
944  fdst = u.GetUrl();
945 
946  // Copy the file now
947  ::Info("TProofMgr::UploadFiles", "uploading '%s' to '%s'", furl->GetUrl(), fdst.Data());
948  if (TFile::Cp(furl->GetUrl(), fdst.Data())) {
949  // Build TFileCollection
950  ds->Add(new TFileInfo(fdst.Data()));
951  } else {
952  ::Error("TProofMgr::UploadFiles", "file %s was not copied", furl->GetUrl());
953  }
954  }
955  }
956 
957  // Return the TFileCollection
958  return ds;
959 }
960 
961 ////////////////////////////////////////////////////////////////////////////////
962 /// Upload to 'mss' the files listed in the text file 'srcfiles' or contained
963 /// in the directory 'srcfiles'.
964 /// In the case 'srcfiles' is a text file, the files must be specified one per
965 /// line, with line beginning by '#' ignored (i.e. considered comments).
966 /// The path under 'mss' is defined by 'dest'; the following
967 /// place-holders can be used in 'dest':
968 /// <d0>, <d1>, <d2>, ... referring to the n-th sub-component
969 /// of the src path
970 /// <bn> basename in the source path
971 /// <sn> serial number of file in the list
972 /// <fn> the full file path
973 /// <us>, <gr> the local user and group names.
974 /// So, for example, if the source filename for the 99-th file is
975 /// protosrc://host//d0/d1/d2/d3/d4/d5/myfile
976 /// then with dest = '/pool/user/<d3>/<d4>/<d5>/<s>/<bn>' and
977 /// mss = 'protodst://hostdst//nm/
978 /// the corresponding destination path is
979 /// protodst://hostdst//nm/pool/user/d3/d4/d5/99/myfile
980 ///
981 /// If 'dest' is empty, <fn> is used.
982 ///
983 /// Returns a TFileCollection with the destination files created; this
984 /// TFileCollection is, for example, ready to be registered as dataset.
985 
986 TFileCollection *TProofMgr::UploadFiles(const char *srcfiles,
987  const char *mss, const char *dest)
988 {
989  TFileCollection *ds = 0;
990 
991  // The inputs must be make sense
992  if (!srcfiles || (srcfiles && strlen(srcfiles) <= 0)) {
993  ::Error("TProofMgr::UploadFiles", "input text file or directory undefined!");
994  return ds;
995  }
996  if (!mss || (mss && strlen(mss) <= 0)) {
997  ::Error("TProofMgr::UploadFiles", "MSS is undefined!");
998  return ds;
999  }
1000 
1001  TString inpath(gSystem->ExpandPathName(srcfiles));
1002 
1003  FileStat_t fst;
1004  if (gSystem->GetPathInfo(inpath.Data(), fst)) {
1005  ::Error("TProofMgr::UploadFiles",
1006  "could not get information about the input path '%s':"
1007  " make sure that it exists and is readable", srcfiles);
1008  return ds;
1009  }
1010 
1011  // Create the list to feed UploadFile(TList *, ...)
1012  TList files;
1013  files.SetOwner();
1014 
1015  TString line;
1016  if (R_ISREG(fst.fMode)) {
1017  // Text file
1018  std::ifstream f;
1019  f.open(inpath.Data(), std::ifstream::out);
1020  if (f.is_open()) {
1021  while (f.good()) {
1022  line.ReadToDelim(f);
1023  line.Strip(TString::kTrailing, '\n');
1024  // Skip comments
1025  if (line.BeginsWith("#")) continue;
1026  if (gSystem->AccessPathName(line, kReadPermission) == kFALSE)
1027  files.Add(new TFileInfo(line));
1028  }
1029  f.close();
1030  } else {
1031  ::Error("TProofMgr::UploadFiles", "unable to open file '%s'", srcfiles);
1032  }
1033  } else if (R_ISDIR(fst.fMode)) {
1034  // Directory
1035  void *dirp = gSystem->OpenDirectory(inpath.Data());
1036  if (dirp) {
1037  const char *ent = 0;
1038  while ((ent = gSystem->GetDirEntry(dirp))) {
1039  if (!strcmp(ent, ".") || !strcmp(ent, "..")) continue;
1040  line.Form("%s/%s", inpath.Data(), ent);
1041  if (gSystem->AccessPathName(line, kReadPermission) == kFALSE)
1042  files.Add(new TFileInfo(line));
1043  }
1044  gSystem->FreeDirectory(dirp);
1045  } else {
1046  ::Error("TProofMgr::UploadFiles", "unable to open directory '%s'", inpath.Data());
1047  }
1048  } else {
1049  ::Error("TProofMgr::UploadFiles",
1050  "input path '%s' is neither a regular file nor a directory!", inpath.Data());
1051  return ds;
1052  }
1053  if (files.GetSize() <= 0) {
1054  ::Warning("TProofMgr::UploadFiles", "no files found in file or directory '%s'", inpath.Data());
1055  } else {
1056  ds = TProofMgr::UploadFiles(&files, mss, dest);
1057  }
1058  // Done
1059  return ds;
1060 }
1061 
1062 ////////////////////////////////////////////////////////////////////////////////
1063 /// Run 'rm' on 'what'. Locally it is just a call to TSystem::Unlink .
1064 
1065 Int_t TProofMgr::Rm(const char *what, const char *, const char *)
1066 {
1067  Int_t rc = -1;
1068  // Nothing to do if not in contact with proofserv
1069  if (!IsValid()) {
1070  Error("Rm", "invalid TProofMgr - do nothing");
1071  return rc;
1072  }
1073  // Nothing to do if not in contact with proofserv
1074  if (!what || (what && strlen(what) <= 0)) {
1075  Error("Rm", "path undefined!");
1076  return rc;
1077  }
1078 
1079  TUrl u(what);
1080  if (!strcmp(u.GetProtocol(), "file")) {
1081  rc = gSystem->Unlink(u.GetFile());
1082  } else {
1083  rc = gSystem->Unlink(what);
1084  }
1085  // Done
1086  return (rc == 0) ? 0 : -1;
1087 }
1088 
1089 //
1090 // TProofDesc
1091 //
1092 
1093 ClassImp(TProofDesc);
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 /// Dump the content to the screen.
1097 
1098 void TProofDesc::Print(Option_t *) const
1099 {
1100  const char *st[] = { "unknown", "idle", "processing", "shutting down"};
1101 
1102  Printf("// # %d", fLocalId);
1103  Printf("// alias: %s, url: \"%s\"", GetTitle(), GetUrl());
1104  Printf("// tag: %s", GetName());
1105  Printf("// status: %s, attached: %s (remote ID: %d)",st[fStatus+1], (fProof ? "YES" : "NO"), fRemoteId);
1106 }