CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
XrdFile.cc
Go to the documentation of this file.
7 #include <vector>
8 #include <sstream>
9 
10 #include "XrdClient/XrdClientConn.hh"
11 
13  : m_client (0),
14  m_offset (0),
15  m_stat(),
16  m_close (false),
17  m_name()
18 {
19  memset(&m_stat, 0, sizeof (m_stat));
20  pthread_mutex_init(&m_readv_mutex, 0);
21 }
22 
23 XrdFile::XrdFile (const char *name,
24  int flags /* = IOFlags::OpenRead */,
25  int perms /* = 066 */)
26  : m_client (0),
27  m_offset (0),
28  m_stat(),
29  m_close (false),
30  m_name()
31 {
32  memset(&m_stat, 0, sizeof (m_stat));
33  pthread_mutex_init(&m_readv_mutex, 0);
34  open (name, flags, perms);
35 }
36 
38  int flags /* = IOFlags::OpenRead */,
39  int perms /* = 066 */)
40  : m_client (0),
41  m_offset (0),
42  m_stat(),
43  m_close (false),
44  m_name()
45 {
46  memset(&m_stat, 0, sizeof (m_stat));
47  pthread_mutex_init(&m_readv_mutex, 0);
48  open (name.c_str (), flags, perms);
49 }
50 
52 {
53  if (m_close)
54  edm::LogError("XrdFileError")
55  << "Destructor called on XROOTD file '" << m_name
56  << "' but the file is still open";
57  pthread_mutex_destroy(&m_readv_mutex);
58 }
59 
61 void
62 XrdFile::create (const char *name,
63  bool exclusive /* = false */,
64  int perms /* = 066 */)
65 {
66  open (name,
68  | (exclusive ? IOFlags::OpenExclusive : 0)),
69  perms);
70 }
71 
72 void
74  bool exclusive /* = false */,
75  int perms /* = 066 */)
76 {
77  open (name.c_str (),
79  | (exclusive ? IOFlags::OpenExclusive : 0)),
80  perms);
81 }
82 
83 void
85  int flags /* = IOFlags::OpenRead */,
86  int perms /* = 066 */)
87 { open (name.c_str (), flags, perms); }
88 
89 void
90 XrdFile::open (const char *name,
91  int flags /* = IOFlags::OpenRead */,
92  int perms /* = 066 */)
93 {
94  // Actual open
95  if ((name == 0) || (*name == 0)) {
97  ex << "Cannot open a file without a name";
98  ex.addContext("Calling XrdFile::open()");
99  throw ex;
100  }
101  if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
103  ex << "Must open file '" << name << "' at least for read or write";
104  ex.addContext("Calling XrdFile::open()");
105  throw ex;
106  }
107  // If I am already open, close old file first
108  if (m_client && m_close)
109  close();
110  else
111  abort();
112 
113  // Translate our flags to system flags
114  int openflags = 0;
115 
116  if (flags & IOFlags::OpenWrite)
117  openflags |= kXR_open_updt;
118  else if (flags & IOFlags::OpenRead)
119  openflags |= kXR_open_read;
120 
121  if (flags & IOFlags::OpenAppend) {
123  ex << "Opening file '" << name << "' in append mode not supported";
124  ex.addContext("Calling XrdFile::open()");
125  throw ex;
126  }
127 
128  if (flags & IOFlags::OpenCreate)
129  {
130  if (! (flags & IOFlags::OpenExclusive))
131  openflags |= kXR_delete;
132  openflags |= kXR_new;
133  openflags |= kXR_mkpath;
134  }
135 
136  if ((flags & IOFlags::OpenTruncate) && (flags & IOFlags::OpenWrite))
137  openflags |= kXR_delete;
138 
139  m_name = name;
140  m_client = new XrdClient(name);
141  m_client->UseCache(false); // Hack from Prof. Bockelman
142 
143  if (! m_client->Open(perms, openflags)
144  || m_client->LastServerResp()->status != kXR_ok) {
146  ex << "XrdClient::Open(name='" << name
147  << "', flags=0x" << std::hex << openflags
148  << ", permissions=0" << std::oct << perms << std::dec
149  << ") => error '" << m_client->LastServerError()->errmsg
150  << "' (errno=" << m_client->LastServerError()->errnum << ")";
151  ex.addContext("Calling XrdFile::open()");
152  addConnection(ex);
153  throw ex;
154  }
155  if (! m_client->Stat(&m_stat)) {
157  ex << "XrdClient::Stat(name='" << name
158  << ") => error '" << m_client->LastServerError()->errmsg
159  << "' (errno=" << m_client->LastServerError()->errnum << ")";
160  ex.addContext("Calling XrdFile::open()");
161  addConnection(ex);
162  throw ex;
163  }
164  m_offset = 0;
165  m_close = true;
166 
167  // Send the monitoring info, if available.
168  // Note: getenv is not reentrant.
169  const char * crabJobId = edm::storage::StatisticsSenderService::getJobID();
170  if (crabJobId) {
171  kXR_unt32 dictId;
172  m_client->SendMonitoringInfo(crabJobId, &dictId);
173  edm::LogInfo("XrdFileInfo") << "Set monitoring ID to " << crabJobId << " with resulting dictId " << dictId << ".";
174  }
175 
176  edm::LogInfo("XrdFileInfo") << "Opened " << m_name;
177 
178  XrdClientConn *conn = m_client->GetClientConn();
179  edm::LogInfo("XrdFileInfo") << "Connection URL " << conn->GetCurrentUrl().GetUrl().c_str();
180 
181  std::string host = std::string(conn->GetCurrentUrl().Host.c_str());
183  if (statsService.isAvailable()) {
184  statsService->setCurrentServer(host);
185  }
186 }
187 
188 void
190 {
191  if (! m_client)
192  {
193  edm::LogError("XrdFileError")
194  << "XrdFile::close(name='" << m_name
195  << "') called but the file is not open";
196  m_close = false;
197  return;
198  }
199 
200  if (! m_client->Close())
201  edm::LogWarning("XrdFileWarning")
202  << "XrdFile::close(name='" << m_name
203  << "') failed with error '" << m_client->LastServerError()->errmsg
204  << "' (errno=" << m_client->LastServerError()->errnum << ")";
205  delete m_client;
206  m_client = 0;
207 
208  m_close = false;
209  m_offset = 0;
210  memset(&m_stat, 0, sizeof (m_stat));
211  edm::LogInfo("XrdFileInfo") << "Closed " << m_name;
212 }
213 
214 void
216 {
217  delete m_client;
218  m_client = 0;
219  m_close = false;
220  m_offset = 0;
221  memset(&m_stat, 0, sizeof (m_stat));
222 }
223 
225 IOSize
226 XrdFile::read (void *into, IOSize n)
227 {
228  if (n > 0x7fffffff) {
230  ex << "XrdFile::read(name='" << m_name << "', n=" << n
231  << ") too many bytes, limit is 0x7fffffff";
232  ex.addContext("Calling XrdFile::read()");
233  addConnection(ex);
234  throw ex;
235  }
236  int s = m_client->Read(into, m_offset, n);
237  if (s < 0) {
239  ex << "XrdClient::Read(name='" << m_name
240  << "', offset=" << m_offset << ", n=" << n
241  << ") failed with error '" << m_client->LastServerError()->errmsg
242  << "' (errno=" << m_client->LastServerError()->errnum << ")";
243  ex.addContext("Calling XrdFile::read()");
244  addConnection(ex);
245  throw ex;
246  }
247  m_offset += s;
248  return s;
249 }
250 
251 IOSize
252 XrdFile::read (void *into, IOSize n, IOOffset pos)
253 {
254  if (n > 0x7fffffff) {
256  ex << "XrdFile::read(name='" << m_name << "', n=" << n
257  << ") exceeds read size limit 0x7fffffff";
258  ex.addContext("Calling XrdFile::read()");
259  addConnection(ex);
260  throw ex;
261  }
262  int s = m_client->Read(into, pos, n);
263  if (s < 0) {
265  ex << "XrdClient::Read(name='" << m_name
266  << "', offset=" << m_offset << ", n=" << n
267  << ") failed with error '" << m_client->LastServerError()->errmsg
268  << "' (errno=" << m_client->LastServerError()->errnum << ")";
269  ex.addContext("Calling XrdFile::read()");
270  addConnection(ex);
271  throw ex;
272  }
273  return s;
274 }
275 
276 IOSize
277 XrdFile::write (const void *from, IOSize n)
278 {
279  if (n > 0x7fffffff) {
280  cms::Exception ex("FileWriteError");
281  ex << "XrdFile::write(name='" << m_name << "', n=" << n
282  << ") too many bytes, limit is 0x7fffffff";
283  ex.addContext("Calling XrdFile::write()");
284  addConnection(ex);
285  throw ex;
286  }
287  ssize_t s = m_client->Write(from, m_offset, n);
288  if (s < 0) {
289  cms::Exception ex("FileWriteError");
290  ex << "XrdFile::write(name='" << m_name << "', n=" << n
291  << ") failed with error '" << m_client->LastServerError()->errmsg
292  << "' (errno=" << m_client->LastServerError()->errnum << ")";
293  ex.addContext("Calling XrdFile::write()");
294  addConnection(ex);
295  throw ex;
296  }
297  m_offset += s;
298  if (m_offset > m_stat.size)
299  m_stat.size = m_offset;
300 
301  return s;
302 }
303 
304 IOSize
305 XrdFile::write (const void *from, IOSize n, IOOffset pos)
306 {
307  if (n > 0x7fffffff) {
308  cms::Exception ex("FileWriteError");
309  ex << "XrdFile::write(name='" << m_name << "', n=" << n
310  << ") too many bytes, limit is 0x7fffffff";
311  ex.addContext("Calling XrdFile::write()");
312  addConnection(ex);
313  throw ex;
314  }
315  ssize_t s = m_client->Write(from, pos, n);
316  if (s < 0) {
317  cms::Exception ex("FileWriteError");
318  ex << "XrdFile::write(name='" << m_name << "', n=" << n
319  << ") failed with error '" << m_client->LastServerError()->errmsg
320  << "' (errno=" << m_client->LastServerError()->errnum << ")";
321  ex.addContext("Calling XrdFile::write()");
322  addConnection(ex);
323  throw ex;
324  }
325  if (pos + s > m_stat.size)
326  m_stat.size = pos + s;
327 
328  return s;
329 }
330 
331 bool
333 {
334  // Detect a prefetch support probe, and claim we don't support it.
335  // This will make the default application-only mode, but allows us to still
336  // effectively support storage-only mode.
337  if (unlikely((n == 1) && (what[0].offset() == 0) && (what[0].size() == PREFETCH_PROBE_LENGTH))) {
338  return false;
339  }
340  std::vector<long long> offsets; offsets.resize(n);
341  std::vector<int> lens; lens.resize(n);
342  kXR_int64 total = 0;
343  for (IOSize i = 0; i < n; ++i) {
344  offsets[i] = what[i].offset();
345  lens[i] = what[i].size();
346  total += what[i].size();
347  }
348 
349  kXR_int64 r = m_client->ReadV(NULL, &offsets[0], &lens[0], n);
350  return r == total;
351 }
352 
356 IOOffset
358 {
359  if (! m_client) {
360  cms::Exception ex("FilePositionError");
361  ex << "XrdFile::position() called on a closed file";
362  ex.addContext("Calling XrdFile::position()");
363  addConnection(ex);
364  throw ex;
365  }
366  switch (whence)
367  {
368  case SET:
369  m_offset = offset;
370  break;
371 
372  case CURRENT:
373  m_offset += offset;
374  break;
375 
376  case END:
377  m_offset = m_stat.size + offset;
378  break;
379 
380  default:
381  cms::Exception ex("FilePositionError");
382  ex << "XrdFile::position() called with incorrect 'whence' parameter";
383  ex.addContext("Calling XrdFile::position()");
384  addConnection(ex);
385  throw ex;
386  }
387 
388  if (m_offset < 0)
389  m_offset = 0;
390  if (m_offset > m_stat.size)
391  m_stat.size = m_offset;
392 
393  return m_offset;
394 }
395 
396 void
398 {
399  cms::Exception ex("FileResizeError");
400  ex << "XrdFile::resize(name='" << m_name << "') not implemented";
401  ex.addContext("Calling XrdFile::resize()");
402  addConnection(ex);
403  throw ex;
404 }
405 
406 void
408 {
409  XrdClientConn *conn = m_client->GetClientConn();
410  if (conn) {
411  std::stringstream ss;
412  ss << "Current server connection: " << conn->GetCurrentUrl().GetUrl().c_str();
413  ex.addAdditionalInfo(ss.str());
414  if (conn->IsOpTimeLimitElapsed(time(NULL)))
415  {
416  ex.addAdditionalInfo("Operation timeout expired. This is possibly a temporary issue which may go away on retry.");
417  }
418  }
419  struct ServerResponseBody_Error * lastError = m_client->LastServerError();
420  if (lastError && lastError->errnum != kXR_noErrorYet)
421  {
422  std::stringstream ss;
423  // Note: I see no guarantee that the errmsg from the server is null-terminated.
424  // Hence, I'm adding the extra guarantee below.
425  char errmsg[4097]; errmsg[4096] = '\0';
426  strncpy(errmsg, lastError->errmsg, 4096);
427  ss << "Last server error (code=" << lastError->errnum << ")";
428  if (strlen(errmsg)) {ss << ": " << errmsg;}
429  ex.addAdditionalInfo(ss.str());
430  }
431 }
432 
virtual void resize(IOOffset size)
Definition: XrdFile.cc:397
int i
Definition: DBlmapReader.cc:9
#define PREFETCH_PROBE_LENGTH
Definition: Storage.h:18
virtual void close(void)
Definition: XrdFile.cc:189
XrdClientStatInfo m_stat
Definition: XrdFile.h:63
virtual void create(const char *name, bool exclusive=false, int perms=0666)
Definition: XrdFile.cc:62
std::vector< Variable::Flags > flags
Definition: MVATrainer.cc:135
#define NULL
Definition: scimark2.h:8
bool m_close
Definition: XrdFile.h:64
IOOffset m_offset
Definition: XrdFile.h:62
Relative
Definition: Storage.h:23
#define unlikely(x)
virtual bool prefetch(const IOPosBuffer *what, IOSize n)
Definition: XrdFile.cc:332
XrdFile(void)
Definition: XrdFile.cc:12
virtual IOOffset position(void) const
Definition: Storage.cc:95
void addAdditionalInfo(std::string const &info)
Definition: Exception.cc:235
int read(void)
Definition: IOInput.cc:54
unsigned int offset(bool)
XrdClient * m_client
Definition: XrdFile.h:61
IOOffset offset(void) const
Definition: IOPosBuffer.h:54
std::string m_name
Definition: XrdFile.h:65
string host
Definition: query.py:114
IOSize size(void) const
Definition: IOPosBuffer.h:64
~XrdFile(void)
Definition: XrdFile.cc:51
virtual IOOffset size(void) const
Definition: Storage.cc:102
void addContext(std::string const &context)
Definition: Exception.cc:227
int64_t IOOffset
Definition: IOTypes.h:19
pthread_mutex_t m_readv_mutex
Definition: XrdFile.h:68
size_t IOSize
Definition: IOTypes.h:14
volatile std::atomic< bool > shutdown_flag false
void addConnection(cms::Exception &)
Definition: XrdFile.cc:407
virtual void open(const char *name, int flags=IOFlags::OpenRead, int perms=0666)
Definition: XrdFile.cc:90
virtual IOSize write(const void *from, IOSize n)
Definition: XrdFile.cc:277
tuple conn
Definition: results_mgr.py:53
virtual void abort(void)
Definition: XrdFile.cc:215