Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TXNetFile.cxx
Go to the documentation of this file.
1 // @(#)root/netx:$Id$
2 // Author: Alvise Dorigo, Fabrizio Furano
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, 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 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TXNetFile //
15 // //
16 // Authors: Alvise Dorigo, Fabrizio Furano //
17 // INFN Padova, 2003 //
18 // Interfaced to the standalone client (XrdClient): G. Ganis, CERN //
19 // //
20 // TXNetFile is an extension of TNetFile able to deal with new xrootd //
21 // server. Its new features are: //
22 // - Automatic server kind recognition (xrootd load balancer, xrootd //
23 // data server, old rootd) //
24 // - Backward compatibility with old rootd server (acts as an old //
25 // TNetFile) //
26 // - Fault tolerance for read/write operations (read/write timeouts //
27 // and retry) //
28 // - Internal connection timeout (tunable indipendently from the OS //
29 // one) handled by threads //
30 // - handling of redirections from server //
31 // - Single TCP physical channel for multiple TXNetFile's instances //
32 // inside the same application //
33 // So, each TXNetFile object client must send messages containing //
34 // its ID (streamid). The server, of course, will respond with //
35 // messages containing the client's ID, in order to make the client //
36 // able to recognize its message by matching its streamid with that //
37 // one contained in the server's response. //
38 // - Tunable log verbosity level (0 = nothing, 3 = dump read/write //
39 // buffers too!) //
40 // - Many parameters configurable via TEnv facility (see SetParm() //
41 // methods) //
42 // //
43 //////////////////////////////////////////////////////////////////////////
44 
45 #include "Bytes.h"
46 
47 #include "TError.h"
48 #include "TEnv.h"
49 #include "TSocket.h"
50 #include "TXNetFile.h"
51 #include "TROOT.h"
52 #include "TVirtualMonitoring.h"
53 #include "TFileStager.h"
54 #include "TFileCacheRead.h"
55 #include "TTimeStamp.h"
56 #include "TVirtualPerfStats.h"
57 
58 #include <XrdClient/XrdClient.hh>
62 #include <XProtocol/XProtocol.hh>
63 
64 #include "XpdSysPthread.h"
65 #include "XrdSysToOuc.h"
66 
67 ClassImp(TXNetFile);
68 
69 Bool_t TXNetFile::fgInitDone = kFALSE;
70 Bool_t TXNetFile::fgRootdBC = kTRUE;
71 TFileStager *TXNetFile::fgFileStager = 0;
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 /// Create a TXNetFile object. A TXNetFile object is the same as a TNetFile
75 /// (from which the former derives) except that the protocol is extended to
76 /// support dealing with new xrootd data server or xrootd load balancer
77 /// server.
78 ///
79 /// The "url" argument must be of the form
80 ///
81 /// root://server1:port1[,server2:port2,...,serverN:portN]/pathfile,
82 ///
83 /// Note that this means that multiple servers (>= 1) can be specified in
84 /// the url. The connection will try to connect to the first server:port
85 /// and if that does not succeed, it will try the second one, and so on
86 /// until it finds a server that will respond.
87 ///
88 /// See the TNetFile documentation for the description of the other arguments.
89 ///
90 /// The creation consists of internal variable settings (most important is
91 /// the client's domain), creation of a TXUrl array containing all specified
92 /// urls (a single url is serverX:portX/pathfile), trying to connect to the
93 /// servers calling Connect() method, getting a valid access to the remote
94 /// server the client is connected to using GetAccessToSrv() method,
95 /// recognizing the remote server (if an old rootd the TNetFile's Create
96 /// method will be called).
97 ///
98 /// The options field of the URL can be used for the following purposes:
99 /// a. open a non-ROOT generic file
100 /// "root://server1:port1[,server2:port2,...]/pathfile?filetype=raw"
101 /// b. re-check the environment variables
102 /// "root://server1:port1[,server2:port2,...]/pathfile?checkenv"
103 /// c. set the cache size (in bytes)
104 /// "root://server1:port1[,server2:port2,...]/pathfile?cachesz=20000000"
105 /// d. set the read-ahead size (in bytes)
106 /// "root://server1:port1[,server2:port2,...]/pathfile?readaheadsz=100000"
107 /// e. set the cache remove policy
108 /// "root://server1:port1[,server2:port2,...]/pathfile?rmpolicy=1"
109 /// f. set the max number of redirections
110 /// "root://server1:port1[,server2:port2,...]/pathfile?mxredir=2"
111 /// (multiple options can be set concurrently)
112 
113 TXNetFile::TXNetFile(const char *url, Option_t *option, const char* ftitle,
114  Int_t compress, Int_t netopt, Bool_t parallelopen,
115  const char *logicalurl) :
116  TNetFile((logicalurl ? logicalurl : url), ftitle, compress, kFALSE)
117 {
118  TUrl urlnoanchor(url);
119  // Set debug level
120  EnvPutInt(NAME_DEBUG, gEnv->GetValue("XNet.Debug", 0));
121 
122  // Set environment, if needed
123  if (!fgInitDone || strstr(urlnoanchor.GetOptions(),"checkenv")) {
124  SetEnv();
125  fgInitDone = kTRUE;
126 
127  // Print the tag, if required (only once)
128  if (gEnv->GetValue("XNet.PrintTAG",0) == 1)
129  Info("TXNetFile","(eXtended TNetFile) %s",
130  gROOT->GetVersion());
131  }
132 
133  // Remove anchors from the URL!
134  urlnoanchor.SetAnchor("");
135 
136  // Init mutex used in the asynchronous open machinery
137  fInitMtx = (void *) new XrdSysRecMutex();
138 
139  if (gMonitoringWriter) {
140  // Init the monitoring system
141  if (!fOpenPhases) {
142  fOpenPhases = new TList;
143  fOpenPhases->SetOwner();
144  }
145  // Should not be null instead of "xrdopen" to init the thing ?
146  gMonitoringWriter->SendFileOpenProgress(this, fOpenPhases, "xrdopen", kFALSE);
147  }
148 
149  // Create an instance
150  CreateXClient(urlnoanchor.GetUrl(), option, netopt, parallelopen);
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Destructor.
155 
156 TXNetFile::~TXNetFile()
157 {
158  if (IsOpen())
159  Close(0);
160 
161  SafeDelete(fClient);
162  XrdSysRecMutex *mtx = (XrdSysRecMutex *)fInitMtx;
163  if (mtx) delete mtx;
164  fInitMtx = 0;
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// Form url for rootd socket.
169 
170 void TXNetFile::FormUrl(TUrl uu, TString &uus)
171 {
172  // Protocol
173  uus = "root://";
174 
175  // User, if any
176  if (strlen(uu.GetUser()) > 0) {
177  uus += uu.GetUser();
178  uus += "@";
179  }
180 
181  // Host, if any
182  if (strlen(uu.GetHost()) > 0) {
183  uus += uu.GetHost();
184  }
185 
186  // Port, if any
187  if (uu.GetPort() > 0) {
188  uus += ":";
189  uus += uu.GetPort();
190  }
191 
192  // End of string
193  uus += "/";
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// Parse input options for cache parameters
198 
199 Int_t TXNetFile::ParseOptions(const char *opts,
200  Int_t &cachesz, Int_t &readaheadsz,
201  Int_t &rmpolicy, Int_t &mxredir, Int_t &rastrategy, Int_t &readtrimblksz)
202 {
203  static const char *keys[6] = { "cachesz=", "readaheadsz=", "rmpolicy=",
204  "mxredir=", "readaheadstrategy=", "readtrimblksz=" };
205  Int_t fo = 0;
206  TString s(opts);
207 
208  UInt_t i = 0;
209  for (i = 0; i < (sizeof(keys)/sizeof(keys[0])); i++) {
210  Int_t j = s.Index(keys[i]);
211  if (j != kNPOS) {
212  TString val(s(j+strlen(keys[i]), s.Length()));
213  // Cut of non digits
214  Int_t k = 0;
215  while (k < val.Length())
216  if (!TString(val(k++)).IsDigit())
217  break;
218  if (k < val.Length())
219  val.Remove(--k);
220  if (val.IsDigit()) {
221  fo++;
222  if (i == 0)
223  cachesz = val.Atoi();
224  else if (i == 1)
225  readaheadsz = val.Atoi();
226  else if (i == 2)
227  rmpolicy = val.Atoi();
228  else if (i == 3)
229  mxredir = val.Atoi();
230  else if (i == 4)
231  rastrategy = val.Atoi();
232  else if (i == 5)
233  readtrimblksz = val.Atoi();
234  }
235  }
236  }
237 
238  // Notify
239  if (gDebug > 0)
240  Info("ParseCacheOptions","found: cachesz = %d, readaheadsz = %d, "
241  "rmpolicy = %d, mxredir = %d, rastrategy = %d, readtrimblksz = %d",
242  cachesz, readaheadsz, rmpolicy, mxredir, rastrategy, readtrimblksz);
243 
244  // Done
245  return fo;
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 /// The real creation work is done here.
250 
251 void TXNetFile::CreateXClient(const char *url, Option_t *option, Int_t netopt,
252  Bool_t parallelopen)
253 {
254  Int_t cachesz = -1, readaheadsz = -1, rmpolicy = -1, mxredir = -1, np = 0;
255  Int_t readaheadstrategy = -1, readtrimblksz = -1;
256 
257  fClient = 0;
258  fNetopt = netopt;
259 
260  // Set the timeout (default 999999999 secs, i.e. far, far in the future)
261  gSystem->Setenv("XRDCLIENTMAXWAIT", Form("%d",TFile::GetOpenTimeout()));
262 
263  if (GetOnlyStaged()) {
264  // Check if the file is staged before opening it
265  if (!fgFileStager || !(fgFileStager->Matches(url))) {
266  SafeDelete(fgFileStager);
267  fgFileStager = TFileStager::Open(url);
268  }
269  if (fgFileStager) {
270  if (!(fgFileStager->IsStaged(url))) {
271  ::Warning("TXNetFile","<%s> is not staged - StageOnly flag is set!",url);
272  goto zombie;
273  }
274  }
275  }
276 
277  // Init members
278  fIsRootd = kFALSE;
279 
280  // The parallel open can be forced to true in the config
281  if (gEnv->GetValue("XNet.ForceParallelOpen", 0))
282  parallelopen = kTRUE;
283  fAsyncOpenStatus = (parallelopen) ? kAOSInProgress : fAsyncOpenStatus ;
284 
285  Bool_t isRootd;
286  isRootd = kFALSE;
287  //
288  // Setup a client instance
289  fClient = new XrdClient(url);
290  if (!fClient) {
291  fAsyncOpenStatus = (parallelopen) ? kAOSFailure : fAsyncOpenStatus ;
292  Error("CreateXClient","fatal error: new object creation failed -"
293  " out of system resources.");
294  gSystem->Abort();
295  goto zombie;
296  }
297 
298  // Get client (cache, redir) parameters, if any
299  np = ParseOptions(TUrl(url).GetOptions(),
300  cachesz, readaheadsz, rmpolicy, mxredir,
301  readaheadstrategy, readtrimblksz);
302 
303  // Set max redir, if asked
304  if (mxredir > 0) {
305  if (fClient->GetClientConn()) {
306  if (gDebug > 0)
307  Info("CreateXClient", "setting maxredir = %d", mxredir);
308  fClient->GetClientConn()->SetMaxRedirCnt(mxredir);
309  }
310  np--;
311  }
312  // Set the cache parameters, if any
313  if (np > 0) {
314  if (gDebug > 0)
315  Info("CreateXClient", "setting cachesz = %d, readaheadsz = %d, "
316  "rmpolicy = %d",
317  cachesz, readaheadsz, rmpolicy);
318  fClient->SetCacheParameters(cachesz, readaheadsz, rmpolicy);
319 
320  if (readaheadstrategy >= 0) {
321  if (gDebug > 0)
322  Info("CreateXClient", "setting readaheadstrategy = %d", readaheadstrategy);
323  fClient->SetReadAheadStrategy(readaheadstrategy);
324  }
325 
326  if (readtrimblksz >= 0) {
327  if (gDebug > 0)
328  Info("CreateXClient", "setting readtrimblksz = %d", readtrimblksz);
329  fClient->SetBlockReadTrimming(readtrimblksz);
330  }
331 
332  }
333 
334  //
335  // Now try opening the file
336  if (!Open(option, parallelopen)) {
337  if (!fClient->IsOpen_wait()) {
338  if (gDebug > 1)
339  Info("CreateXClient", "remote file could not be open");
340 
341  // If the server is a rootd we need to create a TNetFile
342  isRootd = (fClient->GetClientConn()->GetServerType() == kSTRootd);
343 
344  if (isRootd) {
345  if (fgRootdBC) {
346 
347  Int_t sd = fClient->GetClientConn()->GetOpenSockFD();
348  if (sd > -1) {
349  //
350  // Create a TSocket on the open connection
351  TSocket *s = new TSocket(sd);
352 
353  s->SetOption(kNoBlock, 0);
354 
355  // Find out the remote protocol (send the client protocol first)
356  Int_t rproto = GetRootdProtocol(s);
357  if (rproto < 0) {
358  Error("CreateXClient", "getting rootd server protocol");
359  goto zombie;
360  }
361 
362  // Finalize TSocket initialization
363  s->SetRemoteProtocol(rproto);
364  TUrl uut((fClient->GetClientConn()
365  ->GetCurrentUrl()).GetUrl().c_str());
366  TString uu;
367  FormUrl(uut,uu);
368 
369  if (gDebug > 2)
370  Info("CreateXClient"," url: %s",uu.Data());
371  s->SetUrl(uu.Data());
372  s->SetService("rootd");
373  s->SetServType(TSocket::kROOTD);
374  //
375  // Set rootd flag
376  fIsRootd = kTRUE;
377  //
378  // Now we can check if we can create a TNetFile on the
379  // open connection
380  if (rproto > 13) {
381  //
382  // Remote support for reuse of open connection
383  TNetFile::Create(s, option, netopt);
384  } else {
385  //
386  // Open connection has been closed because could
387  // not be reused; TNetFile will open a new connection
388  TNetFile::Create(uu.Data(), option, netopt);
389  }
390 
391  return;
392  } else {
393  Error("CreateXClient", "rootd: underlying socket undefined");
394  goto zombie;
395  }
396  } else {
397  if (gDebug > 0)
398  Info("CreateXClient", "rootd: fall back not enabled - closing");
399  goto zombie;
400  }
401  } else {
402  Error("CreateXClient", "open attempt failed on %s", fUrl.GetUrl());
403  goto zombie;
404  }
405  }
406  }
407 
408  return;
409 
410 zombie:
411  // error in file opening occured, make this object a zombie
412  SafeDelete(fClient);
413  MakeZombie();
414  gDirectory = gROOT;
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Find out the remote rootd protocol version.
419 /// Returns -1 in case of error.
420 
421 Int_t TXNetFile::GetRootdProtocol(TSocket *s)
422 {
423  Int_t rproto = -1;
424 
425  UInt_t cproto = 0;
426  Int_t len = sizeof(cproto);
427  memcpy((char *)&cproto,
428  Form(" %d", TSocket::GetClientProtocol()),len);
429  Int_t ns = s->SendRaw(&cproto, len);
430  if (ns != len) {
431  ::Error("TXNetFile::GetRootdProtocol",
432  "sending %d bytes to rootd server [%s:%d]",
433  len, (s->GetInetAddress()).GetHostName(), s->GetPort());
434  return -1;
435  }
436 
437  // Get the remote protocol
438  Int_t ibuf[2] = {0};
439  len = sizeof(ibuf);
440  Int_t nr = s->RecvRaw(ibuf, len);
441  if (nr != len) {
442  ::Error("TXNetFile::GetRootdProtocol",
443  "reading %d bytes from rootd server [%s:%d]",
444  len, (s->GetInetAddress()).GetHostName(), s->GetPort());
445  return -1;
446  }
447  Int_t kind = net2host(ibuf[0]);
448  if (kind == kROOTD_PROTOCOL) {
449  rproto = net2host(ibuf[1]);
450  } else {
451  kind = net2host(ibuf[1]);
452  if (kind == kROOTD_PROTOCOL) {
453  len = sizeof(rproto);
454  nr = s->RecvRaw(&rproto, len);
455  if (nr != len) {
456  ::Error("TXNetFile::GetRootdProtocol",
457  "reading %d bytes from rootd server [%s:%d]",
458  len, (s->GetInetAddress()).GetHostName(), s->GetPort());
459  return -1;
460  }
461  rproto = net2host(rproto);
462  }
463  }
464  if (gDebug > 2)
465  ::Info("TXNetFile::GetRootdProtocol",
466  "remote rootd: buf1: %d, buf2: %d rproto: %d",
467  net2host(ibuf[0]),net2host(ibuf[1]),rproto);
468 
469  // We are done
470  return rproto;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// The real creation work is done here.
475 
476 Bool_t TXNetFile::Open(Option_t *option, Bool_t doitparallel)
477 {
478  //
479  // Parse options
480  kXR_unt16 openOpt = 0;
481  memset(&openOpt, 0, sizeof(openOpt));
482  TString opt = option;
483  opt.ToUpper();
484  //
485  // Check force, accepting 'f'/'F' for backward compatibility,
486  // and special read syntax
487  if (opt.BeginsWith("-") || opt.BeginsWith("F") || (opt == "+READ")) {
488  opt.Remove(0,1);
489  openOpt |= kXR_force;
490  }
491  //
492  // Read flag
493  Bool_t read = (opt == "READ");
494  //
495  // Create flag ("NEW" == "CREATE")
496  Bool_t create = (opt == "CREATE" || opt == "NEW");
497  //
498  // Recreate flag
499  Bool_t recreate = (opt == "RECREATE");
500  //
501  // Update flag
502  Bool_t update = (opt == "UPDATE");
503  //
504  // Default is Read
505  if (!create && !recreate && !update && !read) {
506  read = kTRUE;
507  opt = "READ";
508  }
509  //
510  // Save effective options
511  fOption = opt;
512  if (create || update || recreate)
513  fWritable = 1;
514  //
515  // Update requires the file existing: check that and switch to create,
516  // if the file is not found.
517  if (update) {
518  if (gSystem->AccessPathName(fUrl.GetUrl(), kFileExists)) {
519  update = kFALSE;
520  create = kTRUE;
521  }
522  if (update) {
523  if (gSystem->AccessPathName(fUrl.GetUrl(), kWritePermission)) {
524  Error("Open", "no write permission, could not open file %s",
525  fUrl.GetUrl());
526  fAsyncOpenStatus = (doitparallel) ? kAOSFailure : fAsyncOpenStatus ;
527  return kFALSE;
528  }
529  openOpt |= kXR_open_updt;
530  }
531  }
532 
533  //
534  // Create and Recreate are correlated
535  if (create)
536  openOpt |= kXR_new;
537  if (recreate) {
538  openOpt |= kXR_delete;
539  create = kTRUE;
540  }
541 
542  Bool_t mkpath = (gEnv->GetValue("XNet.Mkpath", 0) == 1) ? kTRUE : kFALSE;
543  char *p = (char*)strstr(fUrl.GetOptions(), "mkpath=");
544  if (p)
545  mkpath = (*(p + strlen("mkpath=")) == '1') ? kTRUE : kFALSE;
546  if (mkpath)
547  openOpt |= kXR_mkpath;
548 
549  if (read)
550  openOpt |= kXR_open_read;
551 
552  //
553  // Set open mode to rw-r-r
554  kXR_unt16 openMode = kXR_or | kXR_gr | kXR_ur | kXR_uw;
555 
556  //
557  // Open file (FileOpenerThread disabled for the time being)
558  if (!fClient->Open(openMode, openOpt, doitparallel)) {
559  if (gDebug > 1)
560  Info("Open", "remote file could not be open");
561  fAsyncOpenStatus = (doitparallel) ? kAOSFailure : fAsyncOpenStatus ;
562  return kFALSE;
563  } else {
564  // Initialize the file
565  // If we are using the parallel open, the init phase is
566  // performed later. In checking for the IsOpen or
567  // asynchronously in a callback func
568  if (!doitparallel) {
569  // Mutex serialization is done inside
570  Init(create);
571  // If initialization failed close everything
572  if (TFile::IsZombie()) {
573  fClient->Close();
574  // To avoid problems in final deletion of object not completely
575  // initialized
576  fWritable = 0;
577  // Notify failure
578  return kFALSE;
579  }
580  }
581  }
582 
583  // We are done
584  return kTRUE;
585 }
586 
587 ////////////////////////////////////////////////////////////////////////////////
588 /// Override TNetFile::ReadBuffer to deal with the xrootd server.
589 /// Returns kTRUE in case of errors.
590 
591 Bool_t TXNetFile::ReadBuffer(char *buffer, Int_t bufferLength)
592 {
593  if (IsZombie()) {
594  Error("ReadBuffer", "ReadBuffer is not possible because object"
595  " is in 'zombie' state");
596  return kTRUE;
597  }
598 
599  if (fIsRootd) {
600  if (gDebug > 1)
601  Info("ReadBuffer","Calling TNetFile::ReadBuffer");
602  return TNetFile::ReadBuffer(buffer, bufferLength);
603  }
604 
605  if (!IsOpen()) {
606  Error("ReadBuffer","The remote file is not open");
607  return kTRUE;
608  }
609 
610  Bool_t result = kFALSE;
611 
612  if (bufferLength==0)
613  return 0;
614 
615  // This returns:
616  // 2 if errors
617  // 1 it looks like the block has already been prefetched
618  // 0 it looks like the block has not been prefetched
619  // But we don't want it to return the buffer, to avoid recursion
620  Int_t st = 0;
621 
622  //using the new method to read
623  if (GetCacheRead() && GetCacheRead()->IsEnablePrefetching()) {
624  st = ReadBufferViaCache(buffer, bufferLength); //modify to "buffer" so that it work with the ne version!!!
625  if (st == 1){
626  fOffset -= bufferLength;
627  return kFALSE;
628  }
629  }
630  else{ //using the old method to read
631  if (GetCacheRead() && GetCacheRead()->IsAsyncReading()) {
632  st = ReadBufferViaCache(0, bufferLength);
633  if (st == 1)
634  fOffset -= bufferLength;
635  } else {
636  if (GetCacheRead()) {
637  st = ReadBufferViaCache(buffer, bufferLength);
638  if (st == 1)
639  return kFALSE;
640  }
641  }
642  }
643 
644  Double_t start = 0;
645  if (gPerfStats) start = TTimeStamp();
646 
647  // Read from the remote xrootd
648  Int_t nr = fClient->Read(buffer, fOffset, bufferLength);
649 
650  if (nr != bufferLength) {
651  Error("ReadBuffer", "error reading all requested bytes, got %d of %d",
652  nr, bufferLength);
653  return kTRUE;
654  }
655 
656  if (gDebug > 1)
657  Info("ReadBuffer", "%d bytes of data read from offset"
658  " %lld (%d requested)", nr, fOffset, bufferLength);
659 
660  fOffset += bufferLength;
661 
662  fBytesRead += nr;
663  fReadCalls++;
664 #ifdef WIN32
665  SetFileBytesRead(GetFileBytesRead() + nr);
666  SetFileReadCalls(GetFileReadCalls() + 1);
667 #else
668  fgBytesRead += nr;
669  fgReadCalls++;
670 #endif
671 
672  if (gPerfStats)
673  gPerfStats->FileReadEvent(this, bufferLength, start);
674 
675  if (gMonitoringWriter)
676  gMonitoringWriter->SendFileReadProgress(this);
677 
678  return result;
679 }
680 
681 ////////////////////////////////////////////////////////////////////////////////
682 /// Pass through to TNetFile implementation which will call back eventually
683 /// to our ReadBuffer with 2 arguments to deal with xrootd errors.
684 
685 Bool_t TXNetFile::ReadBuffer(char *buffer, Long64_t pos, Int_t bufferLength)
686 {
687  return TNetFile::ReadBuffer(buffer, pos, bufferLength);
688 }
689 
690 ////////////////////////////////////////////////////////////////////////////////
691 /// Implementation dealing with the xrootd server.
692 /// Returns kTRUE in case of errors.
693 /// This is the same as TXNetFile::ReadBuffer but using the async
694 /// call from xrootd
695 
696 Bool_t TXNetFile::ReadBufferAsync(Long64_t offs, Int_t bufferLength)
697 {
698  if (IsZombie()) {
699  Error("ReadBuffer", "ReadBuffer is not possible because object"
700  " is in 'zombie' state");
701  return kTRUE;
702  }
703 
704  if (fIsRootd) {
705  if (gDebug > 1)
706  Error("ReadBufferAsync","Not supported for rootd");
707  return kTRUE;
708  }
709 
710  if (!IsOpen()) {
711  Error("ReadBuffer","The remote file is not open");
712  return kTRUE;
713  }
714 
715  Double_t start = 0;
716  if (gPerfStats) start = TTimeStamp();
717 
718  Bool_t result = kFALSE;
719 
720  if (bufferLength==0)
721  return 0;
722 
723  SynchronizeCacheSize();
724 
725  // Read for the remote xrootd
726  // This doesnt return the number of bytes read...
727  // and even if it did we dont want to update fBytesRead
728  // because that would be updated in the real read
729  XReqErrorType nr = fClient->Read_Async(offs+fArchiveOffset, bufferLength);
730 
731  if (nr != kOK)
732  return kTRUE;
733 
734  fBytesRead += bufferLength;
735  fReadCalls++;
736 #ifdef WIN32
737  SetFileBytesRead(GetFileBytesRead() + bufferLength);
738  SetFileReadCalls(GetFileReadCalls() + 1);
739 #else
740  fgBytesRead += bufferLength;
741  fgReadCalls++;
742 #endif
743 
744  if (gPerfStats)
745  gPerfStats->FileReadEvent(this, bufferLength, start);
746 
747  if (gDebug > 1)
748  Info("ReadBufferAsync", "%d bytes of data read request from offset"
749  " %lld", bufferLength, offs);
750  return result;
751 }
752 
753 ////////////////////////////////////////////////////////////////////////////////
754 /// Read the nbuf blocks described in arrays pos and len,
755 /// where pos[i] is the seek position of block i of length len[i].
756 /// Note that for nbuf=1, this call is equivalent to TFile::ReadBuffer
757 /// This function is overloaded by TNetFile, TWebFile, etc.
758 /// Returns kTRUE in case of failure.
759 /// Note: This is the overloading made in TXNetFile. If ReadBuffers
760 /// is supported by xrootd it will try to get the whole list from one single
761 /// call avoiding the latency of multiple calls
762 
763 Bool_t TXNetFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
764 {
765  if (IsZombie()) {
766  Error("ReadBuffers", "ReadBuffers is not possible because object"
767  " is in 'zombie' state");
768  return kTRUE;
769  }
770 
771  if (fIsRootd) {
772  if (gDebug > 1)
773  Info("ReadBuffers","Calling TNetFile::ReadBuffers");
774  return TNetFile::ReadBuffers(buf, pos, len, nbuf);
775  }
776 
777  if (!IsOpen()) {
778  Error("ReadBuffers","The remote file is not open");
779  return kTRUE;
780  }
781 
782  Double_t start = 0;
783  if (gPerfStats) start = TTimeStamp();
784 
785  if (fArchiveOffset) {
786  for (Int_t i = 0; i < nbuf; i++)
787  pos[i] += fArchiveOffset;
788  }
789 
790  Long64_t expected_nr = 0;
791  for (Int_t i = 0; i < nbuf; i++) {
792  expected_nr += len[i];
793  }
794 
795  // A null buffer means that we want to use the async stuff
796  // hence we have to sync the cache size in XrdClient with the supposed
797  // size in TFile.
798  if (!buf) {
799  // Null buffer + 0 blocks means 'reset cache'
800  if (!nbuf) ResetCache();
801  SynchronizeCacheSize();
802  }
803 
804  // Read for the remote xrootd
805  Long64_t nr = fClient->ReadV(buf, pos, len, nbuf);
806 
807  if (gDebug > 1)
808  Info("ReadBuffers", "response from ReadV(%d) nr: %lld", nbuf, nr);
809 
810  if (nr == expected_nr) {
811 
812  if (gDebug > 1)
813  Info("ReadBuffers", "%lld bytes of data read from a list of %d buffers",
814  nr, nbuf);
815 
816  if (GetCacheRead() && GetCacheRead()->GetBufferSize() < nr)
817  Info("ReadBuffers", "%lld bytes of data read with a smaller (%d) TFileCacheRead buffer size?",
818  nr, GetCacheRead()->GetBufferSize());
819 
820  // Where should we leave the offset ?
821  // fOffset += bufferLength;
822  fBytesRead += nr;
823  fReadCalls++;
824 #ifdef WIN32
825  SetFileBytesRead(GetFileBytesRead() + nr);
826  SetFileReadCalls(GetFileReadCalls() + 1);
827 #else
828  fgBytesRead += nr;
829  fgReadCalls++;
830 #endif
831 
832  if (gPerfStats) {
833  fOffset = pos[0];
834  gPerfStats->FileReadEvent(this, (Int_t)nr, start);
835  }
836 
837  if (gMonitoringWriter)
838  gMonitoringWriter->SendFileReadProgress(this);
839 
840  return kFALSE;
841  }
842 
843  if (gDebug > 1)
844  Info("ReadBuffers", "XrdClient->ReadV failed, executing TFile::ReadBuffers");
845 
846  // If it wasnt able to use the specialized call
847  // then use the generic one that is a plain loop
848  // of individual requests
849  if (buf && nbuf)
850  return TFile::ReadBuffers(buf, pos, len, nbuf);
851  // If the async call was needed (buf == 0) and it got an error,
852  // just return error
853  else return kTRUE;
854 }
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// Override TNetFile::WriteBuffer to deal with the xrootd server.
858 /// Returns kTRUE in case of errors.
859 
860 Bool_t TXNetFile::WriteBuffer(const char *buffer, Int_t bufferLength)
861 {
862  if (IsZombie()) {
863  Error("WriteBuffer", "WriteBuffer is not possible because object"
864  " is in 'zombie' state");
865  return kTRUE;
866  }
867 
868  if (!fWritable) {
869  if (gDebug > 1)
870  Info("WriteBuffer","file not writable");
871  return kTRUE;
872  }
873 
874  if (fIsRootd) {
875  if (gDebug > 1)
876  Info("WriteBuffer","Calling TNetFile::WriteBuffer");
877  return TNetFile::WriteBuffer(buffer, bufferLength );
878  }
879 
880  if (!IsOpen()) {
881  Error("WriteBuffer","The remote file is not open");
882  return kTRUE;
883  }
884 
885  Int_t st;
886  if ((st = WriteBufferViaCache(buffer, bufferLength))) {
887  if (st == 2)
888  return kTRUE;
889  return kFALSE;
890  }
891 
892  // Read for the remote xrootd
893  if (!fClient->Write(buffer, fOffset, bufferLength)) {
894  if (gDebug > 0)
895  Info("WriteBuffer",
896  "error writing %d bytes of data wrote to offset %lld",
897  bufferLength , fOffset);
898  return kTRUE;
899  }
900 
901  if (gDebug > 1)
902  Info("WriteBuffer", " %d bytes of data wrote to offset"
903  " %lld", bufferLength , fOffset);
904 
905  fOffset += bufferLength;
906  fBytesWrite += bufferLength;
907 #ifdef WIN32
908  SetFileBytesWritten(GetFileBytesWritten() + bufferLength);
909 #else
910  fgBytesWrite += bufferLength;
911 #endif
912 
913  return kFALSE;
914 }
915 
916 ////////////////////////////////////////////////////////////////////////////////
917 /// Initialize the file. Makes sure that the file is really open before
918 /// calling TFile::Init. It may block.
919 
920 void TXNetFile::Init(Bool_t create)
921 {
922  if (fInitDone) {
923  // TFile::Init already called once
924  if (gDebug > 1)
925  Info("Init","TFile::Init already called once");
926  return;
927  }
928 
929  if (fIsRootd) {
930  if (gDebug > 1)
931  Info("Init","rootd: calling directly TFile::Init");
932  return TNetFile::Init(create);
933  }
934 
935  if (fClient) {
936  // A mutex serializes this very delicate section
937  XrdSysMutexHelper m((XrdSysRecMutex *)fInitMtx);
938 
939  // To safely perform the Init() we must make sure that
940  // the file is successfully open; this call may block
941  if (fClient->IsOpen_wait()) {
942 
943  // Notify the monitoring system
944  if (gMonitoringWriter)
945  gMonitoringWriter->SendFileOpenProgress(this, fOpenPhases, "rootinit", kFALSE);
946 
947  // Avoid big transfers at this level
948  bool usecachesave = fClient->UseCache(0);
949  // Note that Init will trigger recursive calls
950  TFile::Init(create);
951  // so TFile::IsOpen() returns true when in TFile::~TFile
952  fD = -2;
953  // Restore requested behaviour
954  fClient->UseCache(usecachesave);
955 
956  // Notify the monitoring system
957  if (gMonitoringWriter)
958  gMonitoringWriter->SendFileOpenProgress(this, fOpenPhases, "endopen", kTRUE);
959 
960  // Set the Endpoint Url we are now connected to. Unless there was some opaque info
961  // which cannot be re-used
962  if (fClient->GetClientConn() && fClient->GetClientConn()->fRedirOpaque.length() <= 0) {
963  fEndpointUrl = fClient->GetClientConn()->GetCurrentUrl().GetUrl().c_str();
964  // Check equivalence of initial and end-point Url to see whether we have
965  // been redirected
966  if (fEndpointUrl.GetPort() != fUrl.GetPort() ||
967  strcmp(fEndpointUrl.GetHostFQDN(), fUrl.GetHostFQDN()))
968  SetBit(TFile::kRedirected);
969  }
970  } else {
971  if (gDebug > 0)
972  Info("Init","open request failed!");
973  SafeDelete(fClient);
974  MakeZombie();
975  gDirectory = gROOT;
976  }
977  }
978 }
979 
980 ////////////////////////////////////////////////////////////////////////////////
981 /// Return kTRUE if the file is open, kFALSE otherwise.
982 
983 Bool_t TXNetFile::IsOpen() const
984 {
985  if (fIsRootd) {
986  if (gDebug > 1)
987  Info("IsOpen","Calling TNetFile::IsOpen");
988  return TNetFile::IsOpen();
989  }
990 
991  if (!fClient)
992  return kFALSE;
993 
994  // We are done
995  return ((fClient && fInitDone) ? fClient->IsOpen() : kFALSE);
996 }
997 
998 ////////////////////////////////////////////////////////////////////////////////
999 /// Return status of asynchronous request
1000 
1001 TFile::EAsyncOpenStatus TXNetFile::GetAsyncOpenStatus()
1002 {
1003  if (fAsyncOpenStatus != TFile::kAOSNotAsync) {
1004  if (fClient->IsOpen_inprogress()) {
1005  return TFile::kAOSInProgress;
1006  } else {
1007  if (fClient->IsOpen())
1008  return TFile::kAOSSuccess;
1009  else
1010  return TFile::kAOSFailure;
1011  }
1012  }
1013 
1014  // Not asynchronous
1015  return TFile::kAOSNotAsync;
1016 }
1017 
1018 ////////////////////////////////////////////////////////////////////////////////
1019 /// Re-open the file (see TNetFile::ReOpen() or TFile::ReOpen()
1020 /// for more details).
1021 
1022 Int_t TXNetFile::ReOpen(const Option_t *Mode)
1023 {
1024  if (fIsRootd) {
1025  if (gDebug > 1)
1026  Info("ReOpen","Calling TNetFile::ReOpen");
1027  return TNetFile::ReOpen(Mode);
1028  }
1029 
1030  return TFile::ReOpen(Mode);
1031 }
1032 
1033 ////////////////////////////////////////////////////////////////////////////////
1034 /// Close the file (see TNetFile::Close() or TFile::Close()
1035 /// for more details).
1036 
1037 void TXNetFile::Close(const Option_t *opt)
1038 {
1039  if (fIsRootd) {
1040  if (gDebug > 1)
1041  Info("Close","Calling TNetFile::Close");
1042  TNetFile::Close(opt);
1043  return;
1044  }
1045 
1046  if (!fClient) return;
1047 
1048  TFile::Close(opt);
1049 
1050  fIsRootd = kFALSE;
1051 
1052  if (IsOpen())
1053  fClient->Close();
1054 
1055  fD = -1; // so TFile::IsOpen() returns false when in TFile::~TFile
1056 }
1057 
1058 ////////////////////////////////////////////////////////////////////////////////
1059 /// Flushes un-written data.
1060 
1061 void TXNetFile::Flush()
1062 {
1063  if (IsZombie()) {
1064  Error("Flush", "Flush is not possible because object is"
1065  " in 'zombie' state");
1066  return;
1067  }
1068 
1069  if (!fWritable) {
1070  if (gDebug > 1)
1071  Info("Flush", "file not writable - do nothing");
1072  return;
1073  }
1074 
1075  if (fIsRootd) {
1076  if (gDebug > 1)
1077  Info("Flush","Calling TNetFile::Flush");
1078  TNetFile::Flush();
1079  return;
1080  }
1081 
1082  if (!IsOpen()) {
1083  Error("Flush","The remote file is not open");
1084  return;
1085  }
1086 
1087  FlushWriteCache();
1088 
1089  //
1090  // Flush via the remote xrootd
1091  fClient->Sync();
1092  if (gDebug > 1)
1093  Info("Flush", "XrdClient::Sync called.");
1094 }
1095 
1096 ////////////////////////////////////////////////////////////////////////////////
1097 /// Override TNetFile::SysStat (see parent's method for more details).
1098 
1099 Int_t TXNetFile::SysStat(Int_t fd, Long_t *id, Long64_t *size, Long_t *flags,
1100  Long_t *modtime)
1101 {
1102  if (IsZombie()) {
1103  Error("SysStat", "SysStat is not possible because object is"
1104  " in 'zombie' state");
1105  *size = 0;
1106  return 1;
1107  }
1108 
1109  if (fIsRootd) {
1110  if (gDebug > 1)
1111  Info("SysStat", "calling TNetFile::SysStat");
1112  return TNetFile::SysStat(fd, id, size, flags, modtime);
1113  }
1114 
1115  // Return file stat information. The interface and return value is
1116  // identical to TSystem::GetPathInfo().
1117  struct XrdClientStatInfo stinfo;
1118  if (fClient && fClient->Stat(&stinfo)) {
1119  *id = (Long_t)(stinfo.id);
1120  *size = (Long64_t)(stinfo.size);
1121  *flags = (Long_t)(stinfo.flags);
1122  *modtime = (Long_t)(stinfo.modtime);
1123  if (gDebug > 1)
1124  Info("SysStat", "got stats = %ld %lld %ld %ld",
1125  *id, *size, *flags, *modtime);
1126  } else {
1127 
1128  if (gDebug > 1) {
1129  if (!IsOpen()) Info("SysStat", "could not stat remote file. Not opened.");
1130  else
1131  Info("SysStat", "could not stat remote file");
1132  }
1133 
1134 
1135  *id = -1;
1136  return 1;
1137  }
1138 
1139  // We are done
1140  return 0;
1141 }
1142 
1143 ////////////////////////////////////////////////////////////////////////////////
1144 /// Override TNetFile::SysClose (see parent's method for more details).
1145 
1146 Int_t TXNetFile::SysClose(Int_t fd)
1147 {
1148  if (IsZombie()) {
1149  Error("SysClose", "SysClose is not possible because object is"
1150  " in 'zombie' state");
1151  return 0;
1152  }
1153 
1154  if (fIsRootd) {
1155  if (gDebug > 1)
1156  Info("SysClose","Calling TNetFile::SysClose");
1157  return TNetFile::SysClose(fd);
1158  }
1159 
1160  // Send close to remote xrootd
1161  if (IsOpen())
1162  fClient->Close();
1163 
1164  return 0;
1165 }
1166 
1167 ////////////////////////////////////////////////////////////////////////////////
1168 /// Override TNetFile::SysOpen (see parent's method for more details).
1169 
1170 Int_t TXNetFile::SysOpen(const char* pathname, Int_t flags, UInt_t mode)
1171 {
1172  if (fIsRootd) {
1173  if (gDebug > 1)
1174  Info("SysOpen", "Calling TNetFile::SysOpen");
1175  return TNetFile::SysOpen(pathname, flags, mode);
1176  }
1177 
1178  if (!fClient) {
1179 
1180  // Create an instance of XrdClient
1181  CreateXClient(fUrl.GetUrl(), fOption, fNetopt, kFALSE);
1182 
1183  } else {
1184 
1185  // url is not needed because already stored
1186  // fOption is set in TFile::ReOpen
1187  Open(fOption.Data(), kFALSE);
1188  }
1189 
1190  // If not successful, flag it
1191  if (!IsOpen())
1192  return -1;
1193 
1194  // This means ok for net files
1195  return -2; // set as fD in ReOpen
1196 }
1197 
1198 ////////////////////////////////////////////////////////////////////////////////
1199 /// Set the relevant environment variables
1200 
1201 void TXNetFile::SetEnv()
1202 {
1203  // List of domains where redirection is allowed
1204  TString allowRE = gEnv->GetValue("XNet.RedirDomainAllowRE", "");
1205  if (allowRE.Length() > 0)
1206  EnvPutString(NAME_REDIRDOMAINALLOW_RE, allowRE.Data());
1207 
1208  // List of domains where redirection is denied
1209  TString denyRE = gEnv->GetValue("XNet.RedirDomainDenyRE", "");
1210  if (denyRE.Length() > 0)
1211  EnvPutString(NAME_REDIRDOMAINDENY_RE, denyRE.Data());
1212 
1213  // List of domains where connection is allowed
1214  TString allowCO = gEnv->GetValue("XNet.ConnectDomainAllowRE", "");
1215  if (allowCO.Length() > 0)
1216  EnvPutString(NAME_CONNECTDOMAINALLOW_RE, allowCO.Data());
1217 
1218  // List of domains where connection is denied
1219  TString denyCO = gEnv->GetValue("XNet.ConnectDomainDenyRE", "");
1220  if (denyCO.Length() > 0)
1221  EnvPutString(NAME_CONNECTDOMAINDENY_RE, denyCO.Data());
1222 
1223  // Connect Timeout
1224  Int_t connTO = gEnv->GetValue("XNet.ConnectTimeout",
1225  DFLT_CONNECTTIMEOUT);
1226  EnvPutInt(NAME_CONNECTTIMEOUT, connTO);
1227 
1228  // Reconnect Timeout
1229  Int_t recoTO = gEnv->GetValue("XNet.ReconnectWait",
1230  DFLT_RECONNECTWAIT);
1231  if (recoTO == DFLT_RECONNECTWAIT) {
1232  // Check also the old variable name
1233  recoTO = gEnv->GetValue("XNet.ReconnectTimeout",
1234  DFLT_RECONNECTWAIT);
1235  }
1236  EnvPutInt(NAME_RECONNECTWAIT, recoTO);
1237 
1238  // Request Timeout
1239  Int_t requTO = gEnv->GetValue("XNet.RequestTimeout",
1240  DFLT_REQUESTTIMEOUT);
1241  EnvPutInt(NAME_REQUESTTIMEOUT, requTO);
1242 
1243  // Max number of redirections
1244  Int_t maxRedir = gEnv->GetValue("XNet.MaxRedirectCount",
1245  DFLT_MAXREDIRECTCOUNT);
1246  EnvPutInt(NAME_MAXREDIRECTCOUNT, maxRedir);
1247 
1248 
1249  // Read ahead size
1250  Int_t rAheadsiz = gEnv->GetValue("XNet.ReadAheadSize",
1251  DFLT_READAHEADSIZE);
1252  EnvPutInt(NAME_READAHEADSIZE, rAheadsiz);
1253 
1254 
1255  // Cache size (<= 0 disables cache)
1256  Int_t rCachesiz = gEnv->GetValue("XNet.ReadCacheSize",
1257  DFLT_READCACHESIZE);
1258 
1259  EnvPutInt(NAME_READCACHESIZE, rCachesiz);
1260 
1261  // Max number of retries on first connect
1262  Int_t maxRetries = gEnv->GetValue("XNet.FirstConnectMaxCnt",
1263  DFLT_FIRSTCONNECTMAXCNT);
1264  EnvPutInt(NAME_FIRSTCONNECTMAXCNT, maxRetries);
1265 
1266  // Parallel stream count
1267  Int_t parStreamsCnt = gEnv->GetValue("XNet.ParStreamsPerPhyConn",
1268  DFLT_MULTISTREAMCNT);
1269  EnvPutInt(NAME_MULTISTREAMCNT, parStreamsCnt);
1270 
1271  // Change the TCP window size (0 means 'scaling' on some platforms)
1272  Int_t tcpWindowSize = gEnv->GetValue("XNet.DfltTcpWindowSize",
1273  DFLT_DFLTTCPWINDOWSIZE);
1274  EnvPutInt(NAME_DFLTTCPWINDOWSIZE, tcpWindowSize);
1275 
1276  // Change the transaction timeout
1277  Int_t transactionTimeout = gEnv->GetValue("XNet.TransactionTimeout",
1278  DFLT_TRANSACTIONTIMEOUT);
1279  EnvPutInt(NAME_TRANSACTIONTIMEOUT, transactionTimeout);
1280 
1281  // Whether to activate automatic rootd backward-compatibility
1282  // (We override XrdClient default)
1283  fgRootdBC = gEnv->GetValue("XNet.RootdFallback", 1);
1284  EnvPutInt(NAME_KEEPSOCKOPENIFNOTXRD, fgRootdBC);
1285 
1286  // Dynamic forwarding (SOCKS4)
1287  TString socks4Host = gEnv->GetValue("XNet.SOCKS4Host","");
1288  Int_t socks4Port = gEnv->GetValue("XNet.SOCKS4Port",-1);
1289  if (socks4Port > 0) {
1290  if (socks4Host.IsNull())
1291  // Default
1292  socks4Host = "127.0.0.1";
1293  EnvPutString(NAME_SOCKS4HOST, socks4Host.Data());
1294  EnvPutInt(NAME_SOCKS4PORT, socks4Port);
1295  }
1296 
1297  const char *cenv = 0;
1298 
1299  // For password-based authentication
1300  TString autolog = gEnv->GetValue("XSec.Pwd.AutoLogin","1");
1301  if (autolog.Length() > 0 &&
1302  (!(cenv = gSystem->Getenv("XrdSecPWDAUTOLOG")) || strlen(cenv) <= 0))
1303  gSystem->Setenv("XrdSecPWDAUTOLOG",autolog.Data());
1304 
1305  // Old style netrc file
1306  TString netrc;
1307  netrc.Form("%s/.rootnetrc",gSystem->HomeDirectory());
1308  gSystem->Setenv("XrdSecNETRC", netrc.Data());
1309 
1310  TString alogfile = gEnv->GetValue("XSec.Pwd.ALogFile","");
1311  if (alogfile.Length() > 0)
1312  gSystem->Setenv("XrdSecPWDALOGFILE",alogfile.Data());
1313 
1314  TString verisrv = gEnv->GetValue("XSec.Pwd.VerifySrv","1");
1315  if (verisrv.Length() > 0 &&
1316  (!(cenv = gSystem->Getenv("XrdSecPWDVERIFYSRV")) || strlen(cenv) <= 0))
1317  gSystem->Setenv("XrdSecPWDVERIFYSRV",verisrv.Data());
1318 
1319  TString srvpuk = gEnv->GetValue("XSec.Pwd.ServerPuk","");
1320  if (srvpuk.Length() > 0)
1321  gSystem->Setenv("XrdSecPWDSRVPUK",srvpuk.Data());
1322 
1323  // For GSI authentication
1324  TString cadir = gEnv->GetValue("XSec.GSI.CAdir","");
1325  if (cadir.Length() > 0)
1326  gSystem->Setenv("XrdSecGSICADIR",cadir.Data());
1327 
1328  TString crldir = gEnv->GetValue("XSec.GSI.CRLdir","");
1329  if (crldir.Length() > 0)
1330  gSystem->Setenv("XrdSecGSICRLDIR",crldir.Data());
1331 
1332  TString crlext = gEnv->GetValue("XSec.GSI.CRLextension","");
1333  if (crlext.Length() > 0)
1334  gSystem->Setenv("XrdSecGSICRLEXT",crlext.Data());
1335 
1336  TString ucert = gEnv->GetValue("XSec.GSI.UserCert","");
1337  if (ucert.Length() > 0)
1338  gSystem->Setenv("XrdSecGSIUSERCERT",ucert.Data());
1339 
1340  TString ukey = gEnv->GetValue("XSec.GSI.UserKey","");
1341  if (ukey.Length() > 0)
1342  gSystem->Setenv("XrdSecGSIUSERKEY",ukey.Data());
1343 
1344  TString upxy = gEnv->GetValue("XSec.GSI.UserProxy","");
1345  if (upxy.Length() > 0)
1346  gSystem->Setenv("XrdSecGSIUSERPROXY",upxy.Data());
1347 
1348  TString valid = gEnv->GetValue("XSec.GSI.ProxyValid","");
1349  if (valid.Length() > 0)
1350  gSystem->Setenv("XrdSecGSIPROXYVALID",valid.Data());
1351 
1352  TString deplen = gEnv->GetValue("XSec.GSI.ProxyForward","0");
1353  if (deplen.Length() > 0 &&
1354  (!(cenv = gSystem->Getenv("XrdSecGSIPROXYDEPLEN")) || strlen(cenv) <= 0))
1355  gSystem->Setenv("XrdSecGSIPROXYDEPLEN",deplen.Data());
1356 
1357  TString pxybits = gEnv->GetValue("XSec.GSI.ProxyKeyBits","");
1358  if (pxybits.Length() > 0)
1359  gSystem->Setenv("XrdSecGSIPROXYKEYBITS",pxybits.Data());
1360 
1361  TString crlcheck = gEnv->GetValue("XSec.GSI.CheckCRL","1");
1362  if (crlcheck.Length() > 0 &&
1363  (!(cenv = gSystem->Getenv("XrdSecGSICRLCHECK")) || strlen(cenv) <= 0))
1364  gSystem->Setenv("XrdSecGSICRLCHECK",crlcheck.Data());
1365 
1366  TString delegpxy = gEnv->GetValue("XSec.GSI.DelegProxy","0");
1367  if (delegpxy.Length() > 0 &&
1368  (!(cenv = gSystem->Getenv("XrdSecGSIDELEGPROXY")) || strlen(cenv) <= 0))
1369  gSystem->Setenv("XrdSecGSIDELEGPROXY",delegpxy.Data());
1370 
1371  TString signpxy = gEnv->GetValue("XSec.GSI.SignProxy","1");
1372  if (signpxy.Length() > 0 &&
1373  (!(cenv = gSystem->Getenv("XrdSecGSISIGNPROXY")) || strlen(cenv) <= 0))
1374  gSystem->Setenv("XrdSecGSISIGNPROXY",signpxy.Data());
1375 
1376  // Using ROOT mechanism to IGNORE SIGPIPE signal
1377  gSystem->IgnoreSignal(kSigPipe);
1378 }
1379 
1380 ////////////////////////////////////////////////////////////////////////////////
1381 /// Synchronize the cache size
1382 /// Alternative purging policy
1383 
1384 void TXNetFile::SynchronizeCacheSize()
1385 {
1386  if (fClient == 0) return;
1387 
1388  fClient->UseCache(TRUE);
1389  Int_t size;
1390  Long64_t bytessubmitted, byteshit, misscount, readreqcnt;
1391  Float_t missrate, bytesusefulness;
1392  int newbsz = -1;
1393  if (fClient->GetCacheInfo(size, bytessubmitted,
1394  byteshit, misscount,
1395  missrate, readreqcnt,
1396  bytesusefulness) ) {
1397 
1398  // To allow for some space for outstanding data
1399  TFileCacheRead *cacheRead = GetCacheRead();
1400  if (cacheRead) {
1401  newbsz = GetBufferSize() / 2 * 3;
1402  newbsz = std::max(newbsz, size);
1403  } else {
1404  newbsz = size;
1405  }
1406 
1407  }
1408 
1409  if (newbsz > 0)
1410  fClient->SetCacheParameters(newbsz, 0, XrdClientReadCache::kRmBlk_FIFO);
1411 }
1412 
1413 ////////////////////////////////////////////////////////////////////////////////
1414 /// Reset the cache
1415 
1416 void TXNetFile::ResetCache()
1417 {
1418  if (fClient)
1419  fClient->RemoveAllDataFromCache();
1420 }
1421 
1422 ////////////////////////////////////////////////////////////////////////////////
1423 /// Max number of bytes to prefetch.
1424 
1425 Int_t TXNetFile::GetBytesToPrefetch() const
1426 {
1427  Int_t size;
1428  Long64_t bytessubmitted, byteshit, misscount, readreqcnt;
1429  Float_t missrate, bytesusefulness;
1430  Int_t bytes = 0;
1431  if (fClient && fClient->GetCacheInfo(size, bytessubmitted,
1432  byteshit, misscount,
1433  missrate, readreqcnt,
1434  bytesusefulness) )
1435  bytes = size;
1436  return ((bytes < 0) ? 0 : bytes);
1437 }
1438 
1439 ////////////////////////////////////////////////////////////////////////////////
1440 /// Print the local statistics.
1441 
1442 void TXNetFile::Print(Option_t *option) const
1443 {
1444  Printf("TXNetFile caching information:");
1445 
1446  Int_t size;
1447  Long64_t bytessubmitted, byteshit, misscount, readreqcnt;
1448  Float_t missrate, bytesusefulness;
1449 
1450  if (fClient && fClient->GetCacheInfo(size, bytessubmitted,
1451  byteshit, misscount,
1452  missrate, readreqcnt,
1453  bytesusefulness)) {
1454  Printf(" Max size: %d", size);
1455  Printf(" Bytes submitted: %lld", bytessubmitted);
1456  Printf(" Bytes hit (estimation): %lld", byteshit);
1457  Printf(" Miss count: %lld", misscount);
1458  Printf(" Miss rate: %f", missrate);
1459  Printf(" Read requests count: %lld", readreqcnt);
1460  Printf(" Bytes usefulness: %f\n", bytesusefulness);
1461  } else
1462  Printf(" -- No Xrd client instance allocated --\n");
1463 
1464  TFile::Print(option);
1465 }