CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
XrdSource.cc
Go to the documentation of this file.
1 
2 // See http://stackoverflow.com/questions/12523122/what-is-glibcxx-use-nanosleep-all-about
3 #define _GLIBCXX_USE_NANOSLEEP
4 #include <thread>
5 #include <chrono>
6 #include <iostream>
7 #include <assert.h>
8 #include <netdb.h>
9 
10 #include "XrdCl/XrdClFile.hh"
11 
13 
14 #include "XrdSource.h"
15 #include "XrdRequest.h"
16 #include "QualityMetric.h"
17 #include "XrdStatistics.h"
18 
19 #define MAX_REQUEST 256*1024
20 #define XRD_CL_MAX_CHUNK 512*1024
21 
22 #ifdef XRD_FAKE_SLOW
23 //#define XRD_DELAY 5140
24 #define XRD_DELAY 1000
25 #define XRD_SLOW_RATE 2
26 int g_delayCount = 0;
27 #else
28 int g_delayCount = 0;
29 #endif
30 
31 using namespace XrdAdaptor;
32 
33 // File::Close() can take awhile - slow servers (which are probably
34 // inactive anyway!) can even timeout. Rather than wait around for
35 // a few minutes in the main thread, this class asynchronously closes
36 // and deletes the XrdCl::File
37 class DelayedClose : boost::noncopyable, public XrdCl::ResponseHandler
38 {
39 public:
40 
41  DelayedClose(std::shared_ptr<XrdCl::File> fh, const std::string &id, const std::string &site)
42  : m_fh(std::move(fh)),
43  m_id(id),
44  m_site(site)
45  {
46  if (m_fh && m_fh->IsOpen())
47  {
48  if (!m_fh->Close(this).IsOK())
49  {
50  delete this;
51  }
52  }
53  }
54 
55 
56  virtual ~DelayedClose() = default;
57 
58 
59  virtual void HandleResponseWithHosts(XrdCl::XRootDStatus *status, XrdCl::AnyObject *response, XrdCl::HostList *hostList) override
60  {
61  if (!status->IsOK())
62  {
63 
64  edm::LogWarning("XrdFileWarning") << "Source delayed close failed with error '" << status->ToStr()
65  << "' (errno=" << status->errNo << ", code=" << status->code << ", server=" << m_id << ", site=" << m_site << ")";
66  }
67  delete status;
68  delete hostList;
69  delete this;
70  }
71 
72 
73 private:
74  std::shared_ptr<XrdCl::File> m_fh;
77 };
78 
79 Source::Source(timespec now, std::unique_ptr<XrdCl::File> fh, const std::string &exclude)
80  : m_lastDowngrade({0, 0}),
81  m_id("(unknown)"),
82  m_exclude(exclude),
83  m_fh(std::move(fh)),
85  m_stats(nullptr)
86 #ifdef XRD_FAKE_SLOW
87  , m_slow(++g_delayCount % XRD_SLOW_RATE == 0)
88  //, m_slow(++g_delayCount >= XRD_SLOW_RATE)
89  //, m_slow(true)
90 #endif
91 {
92  if (m_fh.get())
93  {
94  if (!m_fh->GetProperty("DataServer", m_id))
95  {
96  edm::LogWarning("XrdFileWarning")
97  << "Source::Source() failed to determine data server name.'";
98  }
99  if (!m_exclude.size()) {m_exclude = m_id;}
100  }
101  m_prettyid = m_id + " (unknown site)";
103  if (getDomain(m_id, domain_id)) {m_site = domain_id;}
104  else {m_site = "Unknown (" + m_id + ")";}
105  setXrootdSite();
106  assert(m_qm.get());
107  assert(m_fh.get());
109  if (statsService)
110  {
111  m_stats = statsService->getStatisticsForSite(m_site);
112  }
113 }
114 
115 
116 bool Source::getHostname(const std::string &id, std::string &hostname)
117 {
118  size_t pos = id.find(":");
119  hostname = id;
120  if ((pos != std::string::npos) && (pos > 0)) {hostname = id.substr(0, pos);}
121 
122  bool retval = true;
123  if (hostname.size() && ((hostname[0] == '[') || isdigit(hostname[0])))
124  {
125  retval = false;
126  struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo));
127  hints.ai_family = AF_UNSPEC;
128  struct addrinfo *result;
129  if (!getaddrinfo(hostname.c_str(), NULL, &hints, &result))
130  {
131  std::vector<char> host; host.reserve(256);
132  if (!getnameinfo(result->ai_addr, result->ai_addrlen, &host[0], 255, NULL, 0, NI_NAMEREQD))
133  {
134  hostname = &host[0];
135  retval = true;
136  }
137  freeaddrinfo(result);
138  }
139  }
140  return retval;
141 }
142 
143 
145 {
146  getHostname(host, domain);
147  size_t pos = domain.find(".");
148  if (pos != std::string::npos && (pos < domain.size())) {domain = domain.substr(pos+1);}
149 
150  return domain.size();
151 }
152 
153 
154 bool
155 Source::isDCachePool(XrdCl::File &file, const XrdCl::HostList *hostList)
156 {
157  // WORKAROUND: On open-file recovery in the Xrootd client, it'll carry around the
158  // dCache opaque information to other sites, causing isDCachePool to erroneously return
159  // true. We are working with the upstream developers to solve this.
160  //
161  // For now, we see if the previous server also looks like a dCache pool - something that
162  // wouldn't happen at a real site, as the previous server should look like a dCache door.
163  std::string lastUrl;
164  file.GetProperty("LastURL", lastUrl);
165  if (lastUrl.size())
166  {
167  bool result = isDCachePool(lastUrl);
168  if (result && hostList && (hostList->size() > 1))
169  {
170  if (isDCachePool((*hostList)[hostList->size()-2].url.GetURL()))
171  {
172  return false;
173  }
174  return true;
175  }
176  return result;
177  }
178  return false;
179 }
180 
181 bool
183 {
184  XrdCl::URL url(lastUrl);
185  XrdCl::URL::ParamsMap map = url.GetParams();
186  // dCache pools always utilize this opaque identifier.
187  if (map.find("org.dcache.uuid") != map.end())
188  {
189  return true;
190  }
191  return false;
192 }
193 
194 
195 void
196 Source::determineHostExcludeString(XrdCl::File &file, const XrdCl::HostList *hostList, std::string &exclude)
197 {
198  // Detect a dCache pool and, if we are in the federation context, give a custom
199  // exclude parameter.
200  // We assume this is a federation context if there's at least a regional, dCache door,
201  // and dCache pool server (so, more than 2 servers!).
202 
203  exclude = "";
204  if (hostList && (hostList->size() > 3) && isDCachePool(file, hostList))
205  {
206  const XrdCl::HostInfo &info = (*hostList)[hostList->size()-3];
207  exclude = info.url.GetHostName();
208  std::string lastUrl; file.GetProperty("LastURL", lastUrl);
209  edm::LogVerbatim("XrdAdaptorInternal") << "Changing exclude list for URL " << lastUrl << " to " << exclude;
210  }
211 }
212 
213 
214 bool
216 {
217  std::string lastUrl;
218  fh.GetProperty("LastURL", lastUrl);
219  if (!lastUrl.size() || isDCachePool(lastUrl))
220  {
221  std::string server, id;
222  if (!fh.GetProperty("DataServer", server)) {id = "(unknown)";}
223  else {id = server;}
224  if (!lastUrl.size()) {edm::LogWarning("XrdFileWarning") << "Unable to determine the URL associated with server " << id;}
225  site = "Unknown";
226  if (server.size()) {getDomain(server, site);}
227  return false;
228  }
229  return getXrootdSiteFromURL(lastUrl, site);
230 }
231 
232 bool
234 {
235  const std::string attr = "sitename";
236  XrdCl::Buffer *response = 0;
237  XrdCl::Buffer arg( attr.size() );
238  arg.FromString( attr );
239 
240  XrdCl::FileSystem fs(url);
241  XrdCl::XRootDStatus st = fs.Query(XrdCl::QueryCode::Config, arg, response);
242  if (!st.IsOK())
243  {
244  XrdCl::URL xurl(url);
245  getDomain(xurl.GetHostName(), site);
246  delete response;
247  return false;
248  }
249  std::string rsite = response->ToString();
250  delete response;
251  if (rsite.size() && (rsite[rsite.size()-1] == '\n'))
252  {
253  rsite = rsite.substr(0, rsite.size()-1);
254  }
255  if (rsite == "sitename")
256  {
257  XrdCl::URL xurl(url);
258  getDomain(xurl.GetHostName(), site);
259  return false;
260  }
261  site = rsite;
262  return true;
263 }
264 
265 void
267 {
268  std::string site;
269  bool goodSitename = getXrootdSite(*m_fh, site);
270  if (!goodSitename)
271  {
272  edm::LogInfo("XrdAdaptorInternal")
273  << "Xrootd server at " << m_id << " did not provide a sitename. Monitoring may be incomplete.";
274  }
275  else
276  {
277  m_site = site;
278  m_prettyid = m_id + " (site " + m_site + ")";
279  }
280  edm::LogInfo("XrdAdaptorInternal") << "Reading from new server " << m_id << " at site " << m_site;
281 }
282 
284 {
285  new DelayedClose(m_fh, m_id, m_site);
286 }
287 
288 std::shared_ptr<XrdCl::File>
290 {
291  return m_fh;
292 }
293 
294 static void
295 validateList(const XrdCl::ChunkList& cl)
296 {
297  off_t last_offset = -1;
298  for (const auto & ci : cl)
299  {
300  assert(static_cast<off_t>(ci.offset) > last_offset);
301  last_offset = ci.offset;
302  assert(ci.length <= XRD_CL_MAX_CHUNK);
303  assert(ci.offset < 0x1ffffffffff);
304  assert(ci.offset > 0);
305  }
306  assert(cl.size() <= 1024);
307 }
308 
309 void
310 Source::handle(std::shared_ptr<ClientRequest> c)
311 {
312  edm::LogVerbatim("XrdAdaptorInternal") << "Reading from " << ID() << ", quality " << m_qm->get() << std::endl;
313  c->m_source = shared_from_this();
314  c->m_self_reference = c;
315  m_qm->startWatch(c->m_qmw);
316  if (m_stats)
317  {
318  std::shared_ptr<XrdReadStatistics> readStats = XrdSiteStatistics::startRead(m_stats, c);
319  c->setStatistics(readStats);
320  }
321 #ifdef XRD_FAKE_SLOW
322  if (m_slow) std::this_thread::sleep_for(std::chrono::milliseconds(XRD_DELAY));
323 #endif
324  if (c->m_into)
325  {
326  // See notes in ClientRequest definition to understand this voodoo.
327  m_fh->Read(c->m_off, c->m_size, c->m_into, c.get());
328  }
329  else
330  {
331  XrdCl::ChunkList cl;
332  cl.reserve(c->m_iolist->size());
333  for (const auto & it : *c->m_iolist)
334  {
335  cl.emplace_back(it.offset(), it.size(), it.data());
336  }
337  validateList(cl);
338  m_fh->VectorRead(cl, nullptr, c.get());
339  }
340 }
341 
std::shared_ptr< XrdCl::File > m_fh
Definition: XrdSource.cc:74
static bool getXrootdSite(XrdCl::File &file, std::string &site)
Definition: XrdSource.cc:215
std::string m_id
Definition: XrdSource.h:67
static const TGPicture * info(bool iBackgroundIsBlack)
std::shared_ptr< XrdSiteStatistics > getStatisticsForSite(std::string const &site)
static void validateList(const XrdCl::ChunkList &cl)
Definition: XrdSource.cc:295
m_qm(QualityMetricFactory::get(now, m_id))
std::string m_site
Definition: XrdSource.cc:76
assert(m_qm.get())
setXrootdSite()
static void determineHostExcludeString(XrdCl::File &file, const XrdCl::HostList *hostList, std::string &exclude)
Definition: XrdSource.cc:196
DelayedClose(std::shared_ptr< XrdCl::File > fh, const std::string &id, const std::string &site)
Definition: XrdSource.cc:41
#define NULL
Definition: scimark2.h:8
std::string m_site
Definition: XrdSource.h:69
void handle(std::shared_ptr< ClientRequest >)
Definition: XrdSource.cc:310
std::shared_ptr< XrdCl::File > m_fh
Definition: XrdSource.h:71
A arg
Definition: Factorize.h:36
std::string m_id
Definition: XrdSource.cc:75
int g_delayCount
Definition: XrdSource.cc:28
static std::unique_ptr< QualityMetricSource > get(timespec now, const std::string &id)
m_exclude(exclude)
static std::shared_ptr< XrdReadStatistics > startRead(std::shared_ptr< XrdSiteStatistics > parent, std::shared_ptr< ClientRequest > req)
static bool getDomain(const std::string &host, std::string &domain)
Definition: XrdSource.cc:144
static bool isDCachePool(XrdCl::File &file, const XrdCl::HostList *hostList=nullptr)
Definition: XrdSource.cc:155
Source(timespec now, std::unique_ptr< XrdCl::File > fileHandle, const std::string &exclude)
Definition: XrdSource.cc:79
tuple result
Definition: query.py:137
XrdSiteStatisticsInformation * statsService
Definition: XrdSource.cc:108
static XrdSiteStatisticsInformation * getInstance()
std::unique_ptr< QualityMetricSource > m_qm
Definition: XrdSource.h:73
std::string domain_id
Definition: XrdSource.cc:93
m_id("(unknown)")
string host
Definition: query.py:114
#define XRD_CL_MAX_CHUNK
Definition: XrdSource.cc:20
tuple attr
Definition: asciidump.py:432
virtual void HandleResponseWithHosts(XrdCl::XRootDStatus *status, XrdCl::AnyObject *response, XrdCl::HostList *hostList) override
Definition: XrdSource.cc:59
std::string m_prettyid
Definition: XrdSource.h:68
std::shared_ptr< XrdSiteStatistics > m_stats
Definition: XrdSource.h:74
std::shared_ptr< XrdCl::File > getFileHandle()
Definition: XrdSource.cc:289
static bool getXrootdSiteFromURL(std::string url, std::string &site)
Definition: XrdSource.cc:233
tuple Config
Definition: helper.py:9
tuple status
Definition: ntuplemaker.py:245
m_fh(std::move(fh))
static bool getHostname(const std::string &id, std::string &hostname)
Definition: XrdSource.cc:116
const std::string & ID() const
Definition: XrdSource.h:35