XRootD
XrdClCopyProcess.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
3 // Author: Lukasz Janyst <ljanyst@cern.ch>
4 //------------------------------------------------------------------------------
5 // This file is part of the XRootD software suite.
6 //
7 // XRootD is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Lesser General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // XRootD is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19 //
20 // In applying this licence, CERN does not waive the privileges and immunities
21 // granted to it by virtue of its status as an Intergovernmental Organization
22 // or submit itself to any jurisdiction.
23 //------------------------------------------------------------------------------
24 
27 #include "XrdCl/XrdClConstants.hh"
28 #include "XrdCl/XrdClCopyJob.hh"
29 #include "XrdCl/XrdClDefaultEnv.hh"
30 #include "XrdCl/XrdClJobManager.hh"
31 #include "XrdCl/XrdClLog.hh"
32 #include "XrdCl/XrdClMonitor.hh"
35 #include "XrdCl/XrdClUtils.hh"
37 #include "XrdSys/XrdSysPthread.hh"
38 
39 #include <sys/time.h>
40 
41 namespace
42 {
43  class QueuedCopyJob: public XrdCl::Job
44  {
45  public:
46  QueuedCopyJob( XrdCl::CopyJob *job,
48  uint32_t currentJob,
49  uint32_t totalJobs,
50  XrdSysSemaphore *sem = 0 ):
51  pJob(job), pProgress(progress), pCurrentJob(currentJob),
52  pTotalJobs(totalJobs), pSem(sem),
53  pWrtRetryCnt( XrdCl::DefaultRetryWrtAtLBLimit ),
54  pRetryCnt( XrdCl::DefaultCpRetry ),
55  pRetryPolicy( XrdCl::DefaultCpRetryPolicy )
56  {
57  XrdCl::DefaultEnv::GetEnv()->GetInt( "RetryWrtAtLBLimit", pWrtRetryCnt );
58  XrdCl::DefaultEnv::GetEnv()->GetInt( "CpRetry", pRetryCnt );
59  XrdCl::DefaultEnv::GetEnv()->GetString( "CpRetryPolicy", pRetryPolicy );
60  }
61 
62  //------------------------------------------------------------------------
64  //------------------------------------------------------------------------
65  virtual void Run( void * )
66  {
68  timeval bTOD;
69 
70  //----------------------------------------------------------------------
71  // Report beginning of the copy
72  //----------------------------------------------------------------------
73  if( pProgress )
74  pProgress->BeginJob( pCurrentJob, pTotalJobs,
75  &pJob->GetSource(),
76  &pJob->GetTarget() );
77 
78  if( mon )
79  {
81  i.transfer.origin = &pJob->GetSource();
82  i.transfer.target = &pJob->GetTarget();
83  mon->Event( XrdCl::Monitor::EvCopyBeg, &i );
84  }
85 
86  gettimeofday( &bTOD, 0 );
87 
88  //----------------------------------------------------------------------
89  // Do the copy
90  //----------------------------------------------------------------------
92  while( true )
93  {
94  st = pJob->Run( pProgress );
95  //--------------------------------------------------------------------
96  // Retry due to write-recovery
97  //--------------------------------------------------------------------
98  if( !st.IsOK() && st.code == XrdCl::errRetry && pWrtRetryCnt > 0 )
99  {
100  std::string url;
101  pJob->GetResults()->Get( "LastURL", url );
102  XrdCl::URL lastURL( url );
103  XrdCl::URL::ParamsMap cgi = lastURL.GetParams();
104  auto itr = cgi.find( "tried" );
105  if( itr != cgi.end() )
106  {
107  std::string tried = itr->second;
108  if( tried[tried.size() - 1] != ',' ) tried += ',';
109  tried += lastURL.GetHostName();
110  cgi["tried"] = tried;
111  }
112  else
113  cgi["tried"] = lastURL.GetHostName();
114 
115  std::string recoveryRedir;
116  pJob->GetResults()->Get( "WrtRecoveryRedir", recoveryRedir );
117  XrdCl::URL recRedirURL( recoveryRedir );
118 
119  std::string target;
120  pJob->GetProperties()->Get( "target", target );
121  XrdCl::URL trgURL( target );
122  trgURL.SetHostName( recRedirURL.GetHostName() );
123  trgURL.SetPort( recRedirURL.GetPort() );
124  trgURL.SetProtocol( recRedirURL.GetProtocol() );
125  trgURL.SetParams( cgi );
126  pJob->GetProperties()->Set( "target", trgURL.GetURL() );
127  pJob->Init();
128 
129  // we have a new job, let's try again
130  --pWrtRetryCnt;
131  continue;
132  }
133  //--------------------------------------------------------------------
134  // Copy job retry
135  //--------------------------------------------------------------------
136  if( !st.IsOK() && pRetryCnt > 0 &&
140  {
141  if( pRetryPolicy == "continue" )
142  {
143  pJob->GetProperties()->Set( "force", false );
144  pJob->GetProperties()->Set( "continue", true );
145  }
146  else
147  {
148  pJob->GetProperties()->Set( "force", true );
149  pJob->GetProperties()->Set( "continue", false );
150  }
151  --pRetryCnt;
152  continue;
153  }
154 
155  // we only loop in case of retry error
156  break;
157  }
158 
159  pJob->GetResults()->Set( "status", st );
160 
161  //----------------------------------------------------------------------
162  // Report end of the copy
163  //----------------------------------------------------------------------
164  if( mon )
165  {
166  std::vector<std::string> sources;
167  pJob->GetResults()->Get( "sources", sources );
169  i.transfer.origin = &pJob->GetSource();
170  i.transfer.target = &pJob->GetTarget();
171  i.sources = sources.size();
172  i.bTOD = bTOD;
173  gettimeofday( &i.eTOD, 0 );
174  i.status = &st;
175  mon->Event( XrdCl::Monitor::EvCopyEnd, &i );
176  }
177 
178  if( pProgress )
179  pProgress->EndJob( pCurrentJob, pJob->GetResults() );
180 
181  if( pSem )
182  pSem->Post();
183  }
184 
185  private:
186  XrdCl::CopyJob *pJob;
187  XrdCl::CopyProgressHandler *pProgress;
188  uint32_t pCurrentJob;
189  uint32_t pTotalJobs;
190  XrdSysSemaphore *pSem;
191  int pWrtRetryCnt;
192  int pRetryCnt;
193  std::string pRetryPolicy;
194  };
195 };
196 
197 namespace XrdCl
198 {
200  {
201  std::vector<PropertyList> pJobProperties;
202  std::vector<PropertyList*> pJobResults;
203  std::vector<CopyJob*> pJobs;
204  };
205 
206  //----------------------------------------------------------------------------
207  // Destructor
208  //----------------------------------------------------------------------------
210  {
211  }
212 
213  //----------------------------------------------------------------------------
214  // Destructor
215  //----------------------------------------------------------------------------
217  {
218  CleanUpJobs();
219  delete pImpl;
220  }
221 
222  //----------------------------------------------------------------------------
223  // Add job
224  //----------------------------------------------------------------------------
226  PropertyList *results )
227  {
228  Env *env = DefaultEnv::GetEnv();
229 
230  //--------------------------------------------------------------------------
231  // Process a configuraion job
232  //--------------------------------------------------------------------------
233  if( properties.HasProperty( "jobType" ) &&
234  properties.Get<std::string>( "jobType" ) == "configuration" )
235  {
236  if( pImpl->pJobProperties.size() > 0 &&
237  pImpl->pJobProperties.rbegin()->HasProperty( "jobType" ) &&
238  pImpl->pJobProperties.rbegin()->Get<std::string>( "jobType" ) == "configuration" )
239  {
240  PropertyList &config = *pImpl->pJobProperties.rbegin();
241  PropertyList::PropertyMap::const_iterator it;
242  for( it = properties.begin(); it != properties.end(); ++it )
243  config.Set( it->first, it->second );
244  }
245  else
246  pImpl->pJobProperties.push_back( properties );
247  return XRootDStatus();
248  }
249 
250  //--------------------------------------------------------------------------
251  // Validate properties
252  //--------------------------------------------------------------------------
253  if( !properties.HasProperty( "source" ) )
254  return XRootDStatus( stError, errInvalidArgs, 0, "source not specified" );
255 
256  if( !properties.HasProperty( "target" ) )
257  return XRootDStatus( stError, errInvalidArgs, 0, "target not specified" );
258 
259  pImpl->pJobProperties.push_back( properties );
260  PropertyList &p = pImpl->pJobProperties.back();
261 
262  const char *bools[] = {"target", "force", "posc", "coerce", "makeDir",
263  "zipArchive", "xcp", "preserveXAttr", "rmOnBadCksum",
264  "continue", "zipAppend", "doServer", 0};
265  for( int i = 0; bools[i]; ++i )
266  if( !p.HasProperty( bools[i] ) )
267  p.Set( bools[i], false );
268 
269  if( !p.HasProperty( "thirdParty" ) )
270  p.Set( "thirdParty", "none" );
271 
272  if( !p.HasProperty( "thirdPartyMode" ) )
273  p.Set( "thirdPartyMode", "pull" );
274 
275  if( !p.HasProperty( "checkSumMode" ) )
276  p.Set( "checkSumMode", "none" );
277  else
278  {
279  if( !p.HasProperty( "checkSumType" ) )
280  {
281  pImpl->pJobProperties.pop_back();
282  return XRootDStatus( stError, errInvalidArgs, 0,
283  "checkSumType not specified" );
284  }
285  else
286  {
287  //----------------------------------------------------------------------
288  // Checksum type has to be case insensitive
289  //----------------------------------------------------------------------
290  std::string checkSumType;
291  p.Get( "checkSumType", checkSumType );
292  std::transform(checkSumType.begin(), checkSumType.end(),
293  checkSumType.begin(), ::tolower);
294  p.Set( "checkSumType", checkSumType );
295  }
296  }
297 
298  if( !p.HasProperty( "parallelChunks" ) )
299  {
300  int val = DefaultCPParallelChunks;
301  env->GetInt( "CPParallelChunks", val );
302  p.Set( "parallelChunks", val );
303  }
304 
305  if( !p.HasProperty( "chunkSize" ) )
306  {
307  int val = DefaultCPChunkSize;
308  env->GetInt( "CPChunkSize", val );
309  p.Set( "chunkSize", val );
310  }
311 
312  if( !p.HasProperty( "xcpBlockSize" ) )
313  {
314  int val = DefaultXCpBlockSize;
315  env->GetInt( "XCpBlockSize", val );
316  p.Set( "xcpBlockSize", val );
317  }
318 
319  if( !p.HasProperty( "initTimeout" ) )
320  {
321  int val = DefaultCPInitTimeout;
322  env->GetInt( "CPInitTimeout", val );
323  p.Set( "initTimeout", val );
324  }
325 
326  if( !p.HasProperty( "tpcTimeout" ) )
327  {
328  int val = DefaultCPTPCTimeout;
329  env->GetInt( "CPTPCTimeout", val );
330  p.Set( "tpcTimeout", val );
331  }
332 
333  if( !p.HasProperty( "cpTimeout" ) )
334  {
335  int val = DefaultCPTimeout;
336  env->GetInt( "CPTimeout", val );
337  p.Set( "cpTimeout", val );
338  }
339 
340  if( !p.HasProperty( "dynamicSource" ) )
341  p.Set( "dynamicSource", false );
342 
343  if( !p.HasProperty( "xrate" ) )
344  p.Set( "xrate", 0 );
345 
346  if( !p.HasProperty( "xrateThreshold" ) || p.Get<long long>( "xrateThreshold" ) == 0 )
347  {
348  int val = DefaultXRateThreshold;
349  env->GetInt( "XRateThreshold", val );
350  p.Set( "xrateThreshold", val );
351  }
352 
353  //--------------------------------------------------------------------------
354  // Insert the properties
355  //--------------------------------------------------------------------------
356  Log *log = DefaultEnv::GetLog();
357  Utils::LogPropertyList( log, UtilityMsg, "Adding job with properties: %s",
358  p );
359  pImpl->pJobResults.push_back( results );
360  return XRootDStatus();
361  }
362 
363  //----------------------------------------------------------------------------
364  // Prepare the copy jobs
365  //----------------------------------------------------------------------------
367  {
368  Log *log = DefaultEnv::GetLog();
369  std::vector<PropertyList>::iterator it;
370 
371  log->Debug( UtilityMsg, "CopyProcess: %zu jobs to prepare",
372  pImpl->pJobProperties.size() );
373 
374  std::map<std::string, uint32_t> targetFlags;
375  int i = 0;
376  for( it = pImpl->pJobProperties.begin(); it != pImpl->pJobProperties.end(); ++it, ++i )
377  {
378  PropertyList &props = *it;
379 
380  if( props.HasProperty( "jobType" ) &&
381  props.Get<std::string>( "jobType" ) == "configuration" )
382  continue;
383 
384  PropertyList *res = pImpl->pJobResults[i];
385  std::string tmp;
386 
387  props.Get( "source", tmp );
388  URL source = tmp;
389  if( !source.IsValid() )
390  {
391  log->Error( UtilityMsg, "Invalid copy source URL: %s", obfuscateAuth( tmp ).c_str() );
392  return XRootDStatus( stError, errInvalidArgs, 0, "invalid source" );
393  }
394 
395  //--------------------------------------------------------------------------
396  // Create a virtual redirector if it is a Metalink file
397  //--------------------------------------------------------------------------
398  if( source.IsMetalink() )
399  {
401  XRootDStatus st = registry.RegisterAndWait( source );
402  if( !st.IsOK() ) return st;
403  }
404 
405  // handle UNZIP CGI
406  const URL::ParamsMap &cgi = source.GetParams();
407  URL::ParamsMap::const_iterator itr = cgi.find( "xrdcl.unzip" );
408  if( itr != cgi.end() )
409  {
410  props.Set( "zipArchive", true );
411  props.Set( "zipSource", itr->second );
412  }
413 
414  props.Get( "target", tmp );
415  URL target = tmp;
416  if( !target.IsValid() )
417  {
418  log->Error( UtilityMsg, "Invalid copy target URL: %s", obfuscateAuth( tmp ).c_str() );
419  return XRootDStatus( stError, errInvalidArgs, 0, "invalid target" );
420  }
421 
422  if( target.GetProtocol() != "stdio" )
423  {
424  // handle directories
425  bool targetIsDir = false;
426  props.Get( "targetIsDir", targetIsDir );
427 
428  if( targetIsDir )
429  {
430  std::string path = target.GetPath() + '/';
431  std::string fn;
432 
433  bool isZip = false;
434  props.Get( "zipArchive", isZip );
435  if( isZip )
436  {
437  props.Get( "zipSource", fn );
438  }
439  else if( source.IsMetalink() )
440  {
442  VirtualRedirector *redirector = registry.Get( source );
443  fn = redirector->GetTargetName();
444  }
445  else
446  {
447  fn = source.GetPath();
448  }
449 
450  size_t pos = fn.rfind( '/' );
451  if( pos != std::string::npos )
452  fn = fn.substr( pos + 1 );
453  path += fn;
454  target.SetPath( path );
455  props.Set( "target", target.GetURL() );
456  }
457  }
458 
459  bool tpc = false;
460  props.Get( "thirdParty", tmp );
461  if( tmp != "none" )
462  tpc = true;
463 
464  //------------------------------------------------------------------------
465  // Check if we have all we need
466  //------------------------------------------------------------------------
467  if( source.GetProtocol() != "stdio" && source.GetPath().empty() )
468  {
469  log->Debug( UtilityMsg, "CopyProcess (job #%d): no source specified.",
470  i );
471  CleanUpJobs();
473  res->Set( "status", st );
474  return st;
475  }
476 
477  if( target.GetProtocol() != "stdio" && target.GetPath().empty() )
478  {
479  log->Debug( UtilityMsg, "CopyProcess (job #%d): no target specified.",
480  i );
481  CleanUpJobs();
483  res->Set( "status", st );
484  return st;
485  }
486 
487  //------------------------------------------------------------------------
488  // Check what kind of job we should do
489  //------------------------------------------------------------------------
490  CopyJob *job = 0;
491 
492  if( tpc == true )
493  {
494  MarkTPC( props );
495  job = new TPFallBackCopyJob( i+1, &props, res );
496  }
497  else
498  job = new ClassicCopyJob( i+1, &props, res );
499 
500  pImpl->pJobs.push_back( job );
501  }
502  return XRootDStatus();
503  }
504 
505  //----------------------------------------------------------------------------
506  // Run the copy jobs
507  //----------------------------------------------------------------------------
509  {
510  //--------------------------------------------------------------------------
511  // Get the configuration
512  //--------------------------------------------------------------------------
513  uint8_t parallelThreads = 1;
514  if( pImpl->pJobProperties.size() > 0 &&
515  pImpl->pJobProperties.rbegin()->HasProperty( "jobType" ) &&
516  pImpl->pJobProperties.rbegin()->Get<std::string>( "jobType" ) == "configuration" )
517  {
518  PropertyList &config = *pImpl->pJobProperties.rbegin();
519  if( config.HasProperty( "parallel" ) )
520  parallelThreads = (uint8_t)config.Get<int>( "parallel" );
521  }
522 
523  //--------------------------------------------------------------------------
524  // Run the show
525  //--------------------------------------------------------------------------
526  std::vector<CopyJob *>::iterator it;
527  uint32_t currentJob = 1;
528  uint32_t totalJobs = pImpl->pJobs.size();
529 
530  //--------------------------------------------------------------------------
531  // Single thread
532  //--------------------------------------------------------------------------
533  if( parallelThreads == 1 )
534  {
535  XRootDStatus err;
536 
537  for( it = pImpl->pJobs.begin(); it != pImpl->pJobs.end(); ++it )
538  {
539  QueuedCopyJob j( *it, progress, currentJob, totalJobs );
540  j.Run(0);
541 
542  XRootDStatus st = (*it)->GetResults()->Get<XRootDStatus>( "status" );
543  if( err.IsOK() && !st.IsOK() )
544  {
545  err = st;
546  }
547  ++currentJob;
548  }
549 
550  if( !err.IsOK() ) return err;
551  }
552  //--------------------------------------------------------------------------
553  // Multiple threads
554  //--------------------------------------------------------------------------
555  else
556  {
557  uint32_t workers = std::min( (uint32_t)parallelThreads,
558  (uint32_t)pImpl->pJobs.size() );
559  JobManager jm( workers );
560  jm.Initialize();
561  if( !jm.Start() )
562  return XRootDStatus( stError, errOSError, 0,
563  "Unable to start job manager" );
564 
565  XrdSysSemaphore *sem = new XrdSysSemaphore(0);
566  std::vector<QueuedCopyJob*> queued;
567  for( it = pImpl->pJobs.begin(); it != pImpl->pJobs.end(); ++it )
568  {
569  QueuedCopyJob *j = new QueuedCopyJob( *it, progress, currentJob,
570  totalJobs, sem );
571 
572  queued.push_back( j );
573  jm.QueueJob(j, 0);
574  ++currentJob;
575  }
576 
577  std::vector<QueuedCopyJob*>::iterator itQ;
578  for( itQ = queued.begin(); itQ != queued.end(); ++itQ )
579  sem->Wait();
580  delete sem;
581 
582  if( !jm.Stop() )
583  return XRootDStatus( stError, errOSError, 0,
584  "Unable to stop job manager" );
585  jm.Finalize();
586  for( itQ = queued.begin(); itQ != queued.end(); ++itQ )
587  delete *itQ;
588 
589  for( it = pImpl->pJobs.begin(); it != pImpl->pJobs.end(); ++it )
590  {
591  XRootDStatus st = (*it)->GetResults()->Get<XRootDStatus>( "status" );
592  if( !st.IsOK() ) return st;
593  }
594  };
595  return XRootDStatus();
596  }
597 
598  void CopyProcess::CleanUpJobs()
599  {
600  std::vector<CopyJob*>::iterator itJ;
601  for( itJ = pImpl->pJobs.begin(); itJ != pImpl->pJobs.end(); ++itJ )
602  {
603  CopyJob *job = *itJ;
604  URL src = job->GetSource();
605  if( src.IsMetalink() )
606  {
608  registry.Release( src );
609  }
610  delete job;
611  }
612  pImpl->pJobs.clear();
613  }
614 }
std::string obfuscateAuth(const std::string &input)
const URL & GetSource() const
Get source.
Definition: XrdClCopyJob.hh:94
virtual ~CopyProcess()
Destructor.
CopyProcess()
Constructor.
XRootDStatus Run(CopyProgressHandler *handler)
Run the copy jobs.
XRootDStatus Prepare()
XRootDStatus AddJob(const PropertyList &properties, PropertyList *results)
Interface for copy progress notification.
static Monitor * GetMonitor()
Get the monitor object.
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
bool GetString(const std::string &key, std::string &value)
Definition: XrdClEnv.cc:31
bool GetInt(const std::string &key, int &value)
Definition: XrdClEnv.cc:115
A synchronized queue.
bool Finalize()
Finalize the job manager, clear the queues.
bool Start()
Start the workers.
bool Initialize()
Initialize the job manager.
bool Stop()
Stop the workers.
void QueueJob(Job *job, void *arg=0)
Add a job to be run.
Interface for a job to be run by the job manager.
virtual void Run(void *arg)=0
The job logic.
Handle diagnostics.
Definition: XrdClLog.hh:101
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition: XrdClLog.cc:231
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition: XrdClLog.cc:282
An abstract class to describe the client-side monitoring plugin interface.
Definition: XrdClMonitor.hh:56
TransferInfo transfer
The transfer in question.
@ EvCopyBeg
CopyBInfo: Copy operation started.
@ EvCopyEnd
CopyEInfo: Copy operation ended.
virtual void Event(EventCode evCode, void *evData)=0
A key-value pair map storing both keys and values as strings.
void Set(const std::string &name, const Item &value)
PropertyMap::const_iterator end() const
Get the end iterator.
bool Get(const std::string &name, Item &item) const
bool HasProperty(const std::string &name) const
Check if we now about the given name.
PropertyMap::const_iterator begin() const
Get the begin iterator.
Singleton access to URL to virtual redirector mapping.
static RedirectorRegistry & Instance()
Returns reference to the single instance.
void Release(const URL &url)
Release the virtual redirector associated with the given URL.
XRootDStatus RegisterAndWait(const URL &url)
Creates a new virtual redirector and registers it (sync).
VirtualRedirector * Get(const URL &url) const
Get a virtual redirector associated with the given URL.
URL representation.
Definition: XrdClURL.hh:31
bool IsMetalink() const
Is it a URL to a metalink.
Definition: XrdClURL.cc:441
std::map< std::string, std::string > ParamsMap
Definition: XrdClURL.hh:33
const std::string & GetProtocol() const
Get the protocol.
Definition: XrdClURL.hh:118
std::string GetURL() const
Get the URL.
Definition: XrdClURL.hh:86
void SetPath(const std::string &path)
Set the path.
Definition: XrdClURL.hh:225
const ParamsMap & GetParams() const
Get the URL params.
Definition: XrdClURL.hh:244
const std::string & GetPath() const
Get the path.
Definition: XrdClURL.hh:217
bool IsValid() const
Is the url valid.
Definition: XrdClURL.cc:428
static void LogPropertyList(Log *log, uint64_t topic, const char *format, const PropertyList &list)
Log property list.
Definition: XrdClUtils.cc:617
An interface for metadata redirectors.
virtual std::string GetTargetName() const =0
Gets the file name as specified in the metalink.
const int DefaultCPInitTimeout
const int DefaultXRateThreshold
const uint16_t errOperationExpired
Definition: XrdClStatus.hh:90
const int DefaultCPChunkSize
const uint16_t stError
An error occurred that could potentially be retried.
Definition: XrdClStatus.hh:32
const int DefaultRetryWrtAtLBLimit
std::vector< PropertyList * > pJobResults
const int DefaultCPParallelChunks
const uint16_t errOSError
Definition: XrdClStatus.hh:61
const int DefaultXCpBlockSize
const uint64_t UtilityMsg
const int DefaultCPTimeout
const uint16_t errInvalidArgs
Definition: XrdClStatus.hh:58
std::vector< PropertyList > pJobProperties
const int DefaultCpRetry
const uint16_t errRetry
Try again for whatever reason.
Definition: XrdClStatus.hh:49
const uint16_t errThresholdExceeded
Definition: XrdClStatus.hh:92
const char *const DefaultCpRetryPolicy
const int DefaultCPTPCTimeout
std::vector< CopyJob * > pJobs
Describe an end of copy event.
TransferInfo transfer
The transfer in question.
int sources
Number of sources used for the copy.
timeval bTOD
Copy start time.
const XRootDStatus * status
Status of the copy.
timeval eTOD
Copy end time.
const URL * target
URL of the target.
const URL * origin
URL of the origin.
uint16_t code
Error type, or additional hints on what to do.
Definition: XrdClStatus.hh:147
bool IsOK() const
We're fine.
Definition: XrdClStatus.hh:124
static bool IsSocketError(uint16_t code)
Definition: XrdClStatus.hh:136