XRootD
Loading...
Searching...
No Matches
XrdMapCluster.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d M a p C l u s t e r . c c */
4/* */
5/* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Department of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30/* This utility maps the connections in a cluster starting at some node. It
31 can also, optionally, check for file existence at each point. Syntax:
32
33 xrdmapc <host>:<port> [<path>]
34
35*/
36
37/******************************************************************************/
38/* i n c l u d e f i l e s */
39/******************************************************************************/
40
41#include <cerrno>
42#include <getopt.h>
43#include <cstdlib>
44#include <cstdio>
45#include <cstring>
46#include <strings.h>
47#include <unistd.h>
48#include <sys/param.h>
49#include <sys/types.h>
50
52#include "XrdCl/XrdClEnv.hh"
55#include "XrdNet/XrdNetAddr.hh"
56#include "XrdOuc/XrdOucHash.hh"
58
59/******************************************************************************/
60/* L o c a l D e f i n i t i o n s */
61/******************************************************************************/
62
63#define EMSG(x) std::cerr <<"xrdmapc: " <<x <<std::endl
64
65// Bypass stupid issue with stupid solaris for missdefining 'struct opt'.
66//
67#ifdef __solaris__
68#define OPT_TYPE (char *)
69#else
70#define OPT_TYPE
71#endif
72
73namespace
74{
75struct clMap
76{ clMap *nextMan;
77 clMap *nextSrv;
78 clMap *nextLvl;
79 const char *state;
80 char *key;
81 char name[284];
82 char hasfile;
83 char verfile;
84 char valid;
85 char isMan;
86
87 clMap(const char *addr) : nextMan(0), nextSrv(0), nextLvl(0),
88 state(""), hasfile(' '), verfile(' '),
89 valid(1), isMan(0)
90 {if (addr)
91 {XrdNetAddr epAddr;
92 epAddr.Set(addr); epAddr.Name();
93 epAddr.Format(name, sizeof(name));
94 key = strdup(addr);
95 } else {
96 *name = 0;
97 key = strdup("");
98 }
99 }
100 ~clMap() {}
101};
102};
103
104/******************************************************************************/
105/* G l o b a l O b j e c t s */
106/******************************************************************************/
107
108extern int optind, optopt;
109
110namespace
111{
112bool listMan = true, listSrv = true, doVerify = false, doHush = false;
113
114clMap *clLost = 0;
115
116char *Path = 0;
117
118uint16_t theTO = 30;
119
120XrdOucHash<clMap> clHash;
121};
122
123/******************************************************************************/
124/* M a k e U R L */
125/******************************************************************************/
126
127namespace
128{
129const char *MakeURL(const char *name, char *buff, int blen)
130{
131 snprintf(buff, blen, "xroot://%s//", name);
132 return buff;
133}
134};
135
136/******************************************************************************/
137/* M a p C o d e */
138/******************************************************************************/
139
140namespace
141{
142void MapCode(XrdCl::XRootDStatus &Status, clMap *node, bool nspl=false)
143{
144 char buff[128];
145
146 node->verfile = '?';
147
148 if (Status.code == XrdCl::errErrorResponse)
149 {switch(Status.errNo)
150 {case kXR_FSError: node->state = " [fs error]"; break;
151 case kXR_IOError: node->state = " [io error]"; break;
152 case kXR_NoMemory: node->state = " [no memory]"; break;
153 case kXR_NotAuthorized: node->state = " [not authorized]";break;
154 case kXR_NotFound: if (nspl)
155 node->state = " [no subscribers]";
156 else {node->state = "";
157 node->verfile = '-';
158 }
159 break;
160 case kXR_NotFile: node->state = " [not a file]"; break;
161 default: sprintf(buff, " [xrootd error %d]", Status.errNo);
162 node->state = strdup(buff);
163 break;
164 }
165 return;
166 }
167
168 switch(Status.code)
169 {case XrdCl::errInvalidAddr: node->state = " [invalid addr]";
170 break;
171 case XrdCl::errSocketError: node->state = " [socket error]";
172 break;
173 case XrdCl::errSocketTimeout: node->state = " [timeout]";
174 break;
175 case XrdCl::errSocketDisconnected: node->state = " [disconnect]";
176 break;
177 case XrdCl::errStreamDisconnect: node->state = " [disconnect]";
178 break;
179 case XrdCl::errConnectionError: node->state = " [connect error]";
180 break;
181 case XrdCl::errHandShakeFailed: node->state = " [handshake failed]";
182 break;
183 case XrdCl::errLoginFailed: node->state = " [login failed]";
184 break;
185 case XrdCl::errAuthFailed: node->state = " [auth failed]";
186 break;
187 case XrdCl::errOperationExpired: node->state = " [op expired]";
188 break;
189 case XrdCl::errRedirectLimit: node->state = " [redirect loop]";
190 break;
191 default: if (!(*Status.ToStr().c_str()))
192 sprintf(buff, " [client error %d]", Status.code);
193 else snprintf(buff, sizeof(buff), " [%s]",
194 Status.ToStr().c_str());
195 node->state = strdup(buff);
196 break;
197 }
198}
199};
200
201/******************************************************************************/
202/* M a p C l u s t e r */
203/******************************************************************************/
204
205namespace
206{
207void MapCluster(clMap *node, clMap *origin)
208{
210 char buff[2048];
211 XrdCl::URL theURL((const std::string)MakeURL(node->name,buff,sizeof(buff)));
212 XrdCl::FileSystem xrdFS(theURL);
213 XrdCl::XRootDStatus Status;
214 XrdCl::LocationInfo *info = 0;
217 clMap *clmP, *branch;
218
219// Issue a locate
220//
221 Status = xrdFS.Locate((const std::string)"*", flags, info, theTO);
222
223// Make sure all went well
224//
225 if (!Status.IsOK())
226 {if (Status.errNo != kXR_NotFound && !doHush)
227 EMSG("Unable to get " <<node->name <<" subscribers; "
228 <<Status.ToStr().c_str());
229 MapCode(Status, origin, true);
230 node->valid = 0;
231 return;
232 }
233
234// Grab all of the information
235//
236 for( it = info->Begin(); it != info->End(); ++it )
237 {clmP = new clMap(it->GetAddress().c_str());
238 locType = it->GetType();
241 {clmP->nextSrv = node->nextSrv;
242 node->nextSrv = clmP;
243 } else {
244 clmP->nextMan = node->nextMan;
245 node->nextMan = clmP;
246 clmP->isMan = 1;
247 }
248 clHash.Add(clmP->key, clmP, 0, Hash_keep);
249 }
250
251// Now map all managers
252//
253 clmP = node->nextMan;
254 while(clmP)
255 {branch = new clMap(clmP->name);
256 MapCluster(branch, clmP);
257// if (branch->nextSrv || branch->nextMan || node->valid)
258 clmP->nextLvl = branch;
259// else delete branch;
260 clmP = clmP->nextMan;
261 }
262
263// All done
264//
265 delete info;
266}
267};
268
269/******************************************************************************/
270/* M a p P a t h */
271/******************************************************************************/
272
273namespace
274{
275void MapPath(clMap *node, const char *Path, bool doRefresh=false)
276{
278 char buff[2048];
279 XrdCl::URL theURL((const std::string)MakeURL(node->name,buff,sizeof(buff)));
280 XrdCl::FileSystem xrdFS(theURL);
281 XrdCl::XRootDStatus Status;
282 XrdCl::LocationInfo *info = 0;
284 clMap *clmP;
285
286// Insert refresh is so wanted
287//
288 if (doRefresh) flags = XrdCl::OpenFlags::Refresh;
289
290// Issue a locate
291//
292 Status = xrdFS.Locate((const std::string)Path, flags, info, theTO);
293
294// Make sure all went well
295//
296 if (!Status.IsOK())
297 {if (Status.errNo != kXR_NotFound && !doHush)
298 EMSG("Unable to query " <<node->name <<" about path; "
299 <<Status.ToStr().c_str());
300 MapCode(Status, node);
301 return;
302 }
303
304// Recursively mark each node as having the file
305//
306 for( it = info->Begin(); it != info->End(); ++it )
307 {const char *clAddr = it->GetAddress().c_str();
308 if ((clmP = clHash.Find(clAddr)))
309 {clmP->hasfile = '>';
310 if (clmP->isMan) MapPath(clmP, Path);
311 } else {
312 clmP = new clMap(clAddr);
313 clmP->nextSrv = clLost;
314 clLost = clmP;
315 }
316 }
317
318// All done here
319//
320 delete info;
321}
322};
323
324/******************************************************************************/
325/* O p N a m e */
326/******************************************************************************/
327
328namespace
329{
330const char *OpName(char *Argv[])
331{
332 static char oName[4] = {'-', 0, 0, 0};
333
334 if (!optopt || optopt == '-' || *(Argv[optind-1]+1) == '-')
335 return Argv[optind-1];
336 oName[1] = optopt;
337 return oName;
338}
339};
340
341/******************************************************************************/
342/* P a t h C h k */
343/******************************************************************************/
344
345namespace
346{
347void PathChk(clMap *node)
348{
349 char buff[2048];
350 XrdCl::URL theURL((const std::string)MakeURL(node->name,buff,sizeof(buff)));
351 XrdCl::FileSystem xrdFS(theURL);
352 XrdCl::XRootDStatus Status;
353 XrdCl::StatInfo *info = 0;
354
355// Issue a stat for the file
356//
357 Status = xrdFS.Stat((const std::string)Path, info);
358
359// Make sure all went well
360//
361 if (!Status.IsOK()) MapCode(Status, node);
362 else node->verfile = '+';
363
364// All done here
365//
366 delete info;
367}
368};
369
370/******************************************************************************/
371/* P r i n t M a p */
372/******************************************************************************/
373
374namespace
375{
376void PrintMap(clMap *clmP, int lvl)
377{
378 clMap *clnow;
379 const char *pfx = "";
380 char *pfxbuff = 0;
381 int n;
382
383// Compute index spacing
384//
385 if ((n = lvl*5))
386 {pfxbuff = (char *)malloc(n+1);
387 memset(pfxbuff, ' ', n); pfxbuff[n] = 0;
388 pfx = pfxbuff;
389 }
390
391// Print all of the servers first
392//
393 if (listSrv)
394 {clnow = clmP->nextSrv;
395 while(clnow)
396 {if (doVerify) PathChk(clnow);
397 if (lvl)
398 {pfxbuff[1] = clnow->hasfile;
399 pfxbuff[2] = clnow->verfile;
400 }
401 std::cout <<' ' <<pfx <<"Srv " <<clnow->name <<clnow->state <<std::endl;
402 clnow = clnow->nextSrv;
403 }
404 }
405
406// Now recursively print the managers
407//
408 if (listMan)
409 {clnow = clmP->nextMan;
410 if (lvl) pfxbuff[2] = ' ';
411 while(clnow)
412 {if (lvl) pfxbuff[1] = clnow->hasfile;
413 std::cout <<lvl <<pfx <<"Man " <<clnow->name <<clnow->state <<std::endl;
414 if (clnow->valid && clnow->nextLvl) PrintMap(clnow->nextLvl,lvl+1);
415 clnow = clnow->nextMan;
416 }
417 }
418
419// All done
420//
421 if (lvl) free(pfxbuff);
422}
423};
424
425/******************************************************************************/
426/* S e t E n v */
427/******************************************************************************/
428
429namespace
430{
431int cwValue = 10;
432int crValue = 0;
433int trValue = 5;
434
435void SetEnv()
436{
438
439 env->PutInt("ConnectionWindow", cwValue);
440 env->PutInt("ConnectionRetry", crValue);
441 env->PutInt("TimeoutResolution",trValue);
442}
443};
444
445/******************************************************************************/
446/* U s a g e */
447/******************************************************************************/
448
449namespace
450{
451void Usage(const char *emsg)
452{
453 if (emsg) EMSG(emsg);
454 std::cerr <<"Usage: xrdmapc [<opt>] <host>:<port> [<path>]\n"
455 <<"<opt>: [--help] [--list {all|m|s}] [--quiet] [--refresh] [--verify]" <<std::endl;
456 if (!emsg)
457 {std::cerr <<
458"--list | -l 'all' lists managers and servers (default), 'm' lists only\n"
459" managers and 's' lists only servers.\n"
460"--quiet | -q does not print error messages to std::cerr; errors appear inline.\n"
461"--refresh | -r does not use cached information but will refresh the cache.\n"
462"--verify | -v verifies <path> existence status at each server.\n"
463"<path> when specified, uses <host>:<port> to determine the locations\n"
464" of path and does optional verification."
465 <<std::endl;
466 }
467 exit((emsg ? 1 : 0));
468}
469};
470
471/******************************************************************************/
472/* m a i n */
473/******************************************************************************/
474
475int main(int argc, char *argv[])
476{
477 const char *opLetters = ":hl:rv";
478 struct option opVec[] = // For getopt_long()
479 {
480 {OPT_TYPE "help", 0, 0, (int)'h'},
481 {OPT_TYPE "list", 1, 0, (int)'l'},
482 {OPT_TYPE "quiet", 0, 0, (int)'q'},
483 {OPT_TYPE "refresh", 0, 0, (int)'r'},
484 {OPT_TYPE "verify", 0, 0, (int)'v'},
485 {0, 0, 0, 0}
486 };
487 extern int optind, opterr;
488 extern char *optarg;
489 XrdNetAddr sPoint;
490 clMap *baseNode, *clNow;
491 const char *eMsg;
492 char opC;
493 int i;
494 bool doRefresh = false;
495
496// Process options
497//
498 opterr = 0;
499 optind = 1;
500 while((opC = getopt_long(argc, argv, opLetters, opVec, &i)) != (char)-1)
501 switch(opC)
502 {case 'h': Usage(0);
503 break;
504 case 'l': if (!strcmp("all",optarg))
505 {listMan = true; listSrv = true;}
506 else if (!strcmp("m", optarg))
507 {listMan = true; listSrv = false;}
508 else if (!strcmp("s", optarg))
509 {listMan = false; listSrv = true;}
510 else Usage("Invalid list argument.");
511 break;
512 case 'q': doHush = true;
513 break;
514 case 'r': doRefresh = true;
515 break;
516 case 'v': doVerify = true;
517 break;
518 case ':': EMSG("'" <<OpName(argv) <<"' argument missing.");
519 exit(2); break;
520 case '?': EMSG("Invalid option, '" <<OpName(argv) <<"'.");
521 exit(2); break;
522 default: EMSG("Internal error processing '" <<OpName(argv) <<"'.");
523 exit(2); break;
524 }
525
526// Make sure we have a starting point
527//
528 if (optind >= argc) Usage("Initial node not specified.");
529
530// Establish starting point
531//
532 if ((eMsg = sPoint.Set(argv[optind])))
533 {EMSG("Unable to validate initial node; " <<eMsg);
534 exit(2);
535 }
536
537// Make sure it's resolvable
538//
539 if (!sPoint.Name(0, &eMsg))
540 {EMSG("Unable to resolve " <<argv[optind] <<"; " <<eMsg);
541 exit(2);
542 }
543
544// Establish the base node
545//
546 baseNode = new clMap(argv[optind]);
547
548// Check if we will be checking a path
549//
550 if (optind+1 < argc) Path = argv[optind+1];
551 else doVerify = false;
552
553// Set default client values
554//
555 SetEnv();
556
557// Map the cluster
558//
559 MapCluster(baseNode, baseNode);
560
561// Check if we need to do a locate on a file and possibly verify results
562//
563 if (Path)
564 {MapPath(baseNode, Path, doRefresh);
565 eMsg = (doVerify ? "0*rv* " : "0*r** ");
566 } else eMsg = "0**** ";
567
568// Print the first line
569//
570 std::cout <<eMsg <<baseNode->name <<baseNode->state <<std::endl;
571 PrintMap(baseNode, 1);
572
573// Check if we have any phantom nodes
574//
575 if (Path && clLost)
576 {std::cerr <<"Warning! " <<baseNode->name
577 <<" referred to the following unconnected node:" <<std::endl;
578 clNow = clLost;
579 while(clNow)
580 {std::cerr <<"????? " <<clNow->name <<std::endl;
581 clNow = clNow->nextSrv;
582 }
583 }
584
585// All done
586//
587 exit(0);
588}
@ kXR_NotAuthorized
Definition XProtocol.hh:998
@ kXR_NotFound
Definition XProtocol.hh:999
@ kXR_NotFile
@ kXR_IOError
Definition XProtocol.hh:995
@ kXR_FSError
Definition XProtocol.hh:993
@ kXR_NoMemory
Definition XProtocol.hh:996
void Usage(const char *msg)
int main(int argc, char *argv[])
int optopt
#define OPT_TYPE
int optind
#define EMSG(x)
@ Hash_keep
Definition XrdOucHash.hh:55
XrdOucString Path
#define eMsg(x)
int emsg(int rc, char *msg)
static Env * GetEnv()
Get default client environment.
bool PutInt(const std::string &key, int value)
Definition XrdClEnv.cc:110
Send file/filesystem queries to an XRootD cluster.
Path location info.
Iterator Begin()
Get the location begin iterator.
LocationType
Describes the node type and file status for a given location.
@ ServerPending
server node where the file is pending to be online
@ ServerOnline
server node where the file is online
LocationList::iterator Iterator
Iterator over locations.
Iterator End()
Get the location end iterator.
Object stat info.
URL representation.
Definition XrdClURL.hh:31
std::string ToStr() const
Convert to string.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
const uint16_t errInvalidAddr
const uint16_t errStreamDisconnect
const uint16_t errRedirectLimit
const uint16_t errErrorResponse
const uint16_t errOperationExpired
const uint16_t errLoginFailed
const uint16_t errSocketTimeout
const uint16_t errHandShakeFailed
const uint16_t errConnectionError
const uint16_t errSocketError
const uint16_t errSocketDisconnected
const uint16_t errAuthFailed
Flags
Open flags, may be or'd when appropriate.
uint16_t code
Error type, or additional hints on what to do.
bool IsOK() const
We're fine.
uint32_t errNo
Errno, if any.