XRootD
Loading...
Searching...
No Matches
XrdCmsNode.cc
Go to the documentation of this file.
1/***********************************************************************************************/
2/* */
3/* X r d C m s N o d e . c c */
4/* */
5/* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <limits.h>
32#include <cstdio>
33#include <ctime>
34#include <netinet/in.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37
38#include "Xrd/XrdJob.hh"
39#include "Xrd/XrdLink.hh"
40
42
44#include "XrdCms/XrdCmsCache.hh"
50#include "XrdCms/XrdCmsMeter.hh"
51#include "XrdCms/XrdCmsPList.hh"
54#include "XrdCms/XrdCmsNode.hh"
56#include "XrdCms/XrdCmsState.hh"
57#include "XrdCms/XrdCmsTrace.hh"
58
59#include "XrdOss/XrdOss.hh"
60
61#include "XrdOuc/XrdOucCRC.hh"
63#include "XrdOuc/XrdOucProg.hh"
64#include "XrdOuc/XrdOucPup.hh"
65#include "XrdOuc/XrdOucUtils.hh"
66
67#include "XrdNet/XrdNetUtils.hh"
68
69#include "XrdSys/XrdSysE2T.hh"
71#include "XrdSys/XrdSysTimer.hh"
72
73using namespace XrdCms;
74
75/******************************************************************************/
76/* S t a t i c O b j e c t s */
77/******************************************************************************/
78
79XrdSysMutex XrdCmsNode::mlMutex;
80
81int XrdCmsNode::LastFree = 0;
82
83namespace
84{
87
88const char *msrcmsg = "Cluster does not support multi-source access.";
89int msrclen = strlen(msrcmsg)+1;
90const char *mtrymsg = "Cluster retry limit exceeded.";
91int mtrylen = strlen(mtrymsg)+1;
92};
93
94/******************************************************************************/
95/* C o n s t r u c t o r */
96/******************************************************************************/
97
98XrdCmsNode::XrdCmsNode(XrdLink *lnkp, const char *theIF, const char *nid,
99 int port, int lvl, int id)
100{
101 static XrdSysMutex iMutex;
102 static const SMask_t smask_1(1);
103 static int iNum = 1;
104
105 Link = lnkp;
106 NodeMask = (id < 0 ? 0 : smask_1 << id);
107 NodeID = id;
108 isOffline= (lnkp == 0);
109 logload = Config.LogPerf;
110 myNID = strdup(nid ? nid : "?");
111 if ((myCID = index(myNID, ' '))) myCID++;
112 else myCID = myNID;
113 myLevel = lvl;
114 myVersion= kYR_Version;
115
116// setName() will set the node identification information
117//
118 setName(lnkp, theIF, (nid ? port : 0));
119
120 iMutex.Lock();
121 Instance = iNum++;
122 iMutex.UnLock();
123}
124
125/******************************************************************************/
126/* D e s t r u c t o r */
127/******************************************************************************/
128
130{
131 isOffline = 1; // STMutex not needed here
132
133// Delete other appendages
134//
135 if (cidP) {cidP->RemNode(this); cidP = 0;}
136 if (Ident) free(Ident);
137 if (myNID) free(myNID);
138 if (myName)free(myName);
139}
140
141/******************************************************************************/
142/* s e t N a m e */
143/******************************************************************************/
144
145void XrdCmsNode::setName(XrdLink *lnkp, const char *theIF, int port)
146{
147 char buff[512];
148 const char *hname = lnkp->Host();
149
150// Check if this is a duplicate. Note that we check for strict equivalence.
151//
152 if (myName)
153 {if (!strcmp(myName,hname) && port == netIF.Port()
154 && netID.Same(lnkp->NetAddr())) return;
155 free(myName);
156 }
157
158// Get our address information but substitute data port for actual port
159//
160 netID = *(lnkp->NetAddr());
161
162// Set the network interface. Note that out of domain nodes are not allowed
163// to specify interface addresses as this does not make global sense.
164//
165 if (theIF && !netIF.InDomain(&netID)) theIF = 0;
166 netIF.SetIF(&netID, theIF, port);
167 hasNet = netIF.Mask();
168
169 netIF.SetPublicName(hname);
170
171// Construct our identification
172//
173 myName = strdup(hname);
174 myNlen = strlen(hname);
175
176 if (!port) strcpy(buff, lnkp->ID);
177 else sprintf(buff, "%s:%d", lnkp->ID, port);
178 if (Ident) free(Ident);
179 Ident = strdup(buff);
180}
181
182/******************************************************************************/
183/* D e l e t e */
184/******************************************************************************/
185
187{
188 EPNAME("Delete");
189 static const int warnIntvl = 60;
190 int totWait = 0, tmoWarn = 60;
191 int tmoWait (Config.DELDelay < 3 ? Config.DELDelay : 3);
192 bool doDel = true;
193
194// We need to make sure there are no references to this object. This is true
195// when the refCnt is zero but only when we hold a global write lock that has
196// been passed to us. As this node has been removed from all global tables
197// at this point, we just need to make sure than no threads are poised to
198// increase it. That can't happen if we obrtain a write lock. To start,
199// get the node lock and do some debugging. Set the isGone flag even though it
200// should be set. Note that we need to serialize with the refCnt as some
201// threads may still be holding a reference to the node.
202//
203 nodeMutex.Lock();
204 isGone = 1;
205 nodeMutex.UnLock();
206 DEBUG(Ident <<" refs=" <<refCnt);
207
208// Now wait for things to simmer down. We wait for an appropriate time because
209// we don't want to occupy this thread forever.
210//
211 gMutex.WriteLock();
212 while(refCnt)
213 {if (totWait >= Config.DELDelay) {doDel = false; break;}
214 gMutex.UnLock();
215 if (totWait >= tmoWarn)
216 {unsigned int theCnt = refCnt;
217 DeleteWarn(theCnt);
218 tmoWarn += warnIntvl;
219 }
220 XrdSysTimer::Snooze(tmoWait);
221 totWait += tmoWait;
222 gMutex.WriteLock();
223 }
224 gMutex.UnLock();
225
226// We can now safely delete this node
227//
228 if (doDel) delete this;
229 else {char eBuff[256];
230 snprintf(eBuff, sizeof(eBuff),
231 " (%p) delete timeout; node object lost!", (void*)this);
232 Say.Emsg("Delete", Ident, eBuff);
233 }
234}
235
236/******************************************************************************/
237/* Private: D e l e t e W a r n */
238/******************************************************************************/
239
240void XrdCmsNode::DeleteWarn(unsigned int lkVal)
241{
242
243// Print warning
244//
245 if (lkVal)
246 {char eBuff[256];
247 snprintf(eBuff, sizeof(eBuff), "delete sync stall; refs = %u", lkVal);
248 Say.Emsg("Delete", Ident, eBuff);
249 }
250}
251
252/******************************************************************************/
253/* D i s c */
254/******************************************************************************/
255
256void XrdCmsNode::Disc(const char *reason, int needLock)
257{
258// Indicate we are offline. If a lock is not need then we only need to set the
259// offline flag as it's already properly protected. Otherwise, set the flag
260// after we get the lock. This is indeed messy.
261//
262 if (needLock) nodeMutex.Lock();
263 isOffline = 1; // STMutex is already held if needed
264
265// If we are still connected, initiate a teardown. This may be done async as
266// we are asking for a deferred close which will be followed by a full close.
267//
268 if (isConn)
269 {Link->setEtext(reason);
270 Link->Close(1);
271 isConn = 0;
272 }
273
274// Unlock ourselves if we locked ourselves
275//
276 if (needLock) nodeMutex.UnLock();
277}
278
279/******************************************************************************/
280/* d o _ A v a i l */
281/******************************************************************************/
282
283// Node responses to space usage requests from a manager are localized to the
284// cell and need not be propopagated in any direction.
285//
287{
288 EPNAME("do_Avail")
289
290// Process: avail <fsdsk> <util>
291//
292 DiskFree = Arg.dskFree;
293 DiskUtil = static_cast<int>(Arg.dskUtil);
294
295// Do some debugging
296//
297 DEBUGR(DiskFree <<"MB free; " <<DiskUtil <<"% util");
298 return 0;
299}
300
301/******************************************************************************/
302/* d o _ C h m o d */
303/******************************************************************************/
304
305// Chmod requests are forwarded to all subscribers
306//
308{
309 EPNAME("do_Chmod")
310 mode_t mode = 0;
311 int rc;
312
313// Do some debugging
314//
315 DEBUGR("mode " <<Arg.Mode <<' ' <<Arg.Path);
316
317// We are don here if we have no data; otherwise convert the mode if we
318// haven't done so already.
319//
320 if (!Config.DiskOK) return 0;
321 if (!mode && !getMode(Arg.Mode, mode)) return "invalid mode";
322
323// Attempt to change the mode either via call-out or the oss plug-in
324//
325 if (Config.ProgCH) rc = fsExec(Config.ProgCH, Arg.Mode, Arg.Path);
326 else rc = Config.ossFS->Chmod(Arg.Path, mode);
327
328// Return appropriate result
329//
330 return (rc ? fsFail(Arg.Ident, "chmod", Arg.Path, rc) : 0);
331}
332
333/******************************************************************************/
334/* d o _ D i s c */
335/******************************************************************************/
336
337// When a manager receives a disc response from a node it sends a disc request
338// and then closes the connection.
339// When a node receives a disc request it simply closes the connection.
340
342{
343
344// Indicate we have received a disconnect
345//
346 Say.Emsg("Node", Link->Name(), "requested a disconnect");
347
348// If we must send a disc request, do so now
349//
350 if (Config.asManager()) Link->Send((char *)&Arg.Request,sizeof(Arg.Request));
351
352// Close the link and return an error
353//
354 isOffline = 1; // STMutex not needed here
355 Link->Close(1);
356 return "."; // Signal disconnect
357}
358
359/******************************************************************************/
360/* d o _ G o n e */
361/******************************************************************************/
362
363// When a manager receives a gone request it is propogated if we are subscribed
364// and we have not sent a gone request in the immediate past.
365//
367{
368 EPNAME("do_Gone")
369 static const SMask_t allNodes(~0);
370 int newgone;
371
372// Do some debugging
373//
374 TRACER(Files,Arg.Path);
375
376// Update path information and delete this from the prep queue if we are a
377// staging node. We can also be called via the admin end-point interface
378// In this case, we have no cache and simply forward up the request.
379//
380 if (Config.asManager())
382 newgone = Cache.DelFile(Sel, baseFS.isDFS() ? allNodes : NodeMask);
383 } else {
384 newgone = 1;
385 if (Config.DiskSS) PrepQ.Gone(Arg.Path);
386 }
387
388// If we have no managers and we still have the file or never had it, return
389//
390 if (!XrdCmsManager::Present() || !newgone) return 0;
391
392// Back-propogate the gone to all of our managers
393//
394 XrdCmsManager::Inform(Arg.Request, Arg.Buff, Arg.Dlen);
395
396// All done
397//
398 return 0;
399}
400
401/******************************************************************************/
402/* d o _ H a v e */
403/******************************************************************************/
404
405// When a manager receives a have request it is propogated if we are subscribed
406// and we have not sent a have request in the immediate past.
407//
409{
410 EPNAME("do_Have")
411 static const SMask_t allNodes(~0);
412 XrdCmsPInfo pinfo;
413 int isnew, Opts;
414
415// Do some debugging
416//
417 TRACER(Files, (Arg.Request.modifier&CmsHaveRequest::Pending ? "P ":"")
418 <<Arg.Path);
419
420// Find if we can handle the file in r/w mode and if staging is present
421//
422 Opts = (Cache.Paths.Find(Arg.Path, pinfo) && (pinfo.rwvec & NodeMask)
423 ? XrdCmsSelect::Write : 0);
425 Opts |= XrdCmsSelect::Pending;
426
427// Update path information. If we are exporting a shared-everything file system
428// then we need to also provide the cache the current list of nodes and how
429// they export the path in question for fast redispatch processing.
430//
431 if (!Config.asManager()) isnew = 1;
432 else {XrdCmsSelect Sel(XrdCmsSelect::Advisory|Opts,Arg.Path,Arg.PathLen-1);
433 Sel.Path.Hash = Arg.Request.streamid;
434 if (baseFS.isDFS())
435 {Sel.Vec.hf = pinfo.rovec; Sel.Vec.wf = pinfo.rwvec;
436 isnew = Cache.AddFile(Sel, allNodes);
437 } else isnew = Cache.AddFile(Sel, NodeMask);
438 }
439
440// Return if we have no managers or we already informed the managers
441//
442 if (!XrdCmsManager::Present() || !isnew) return 0;
443
444// Back-propogate the have to all of our managers
445//
446 XrdCmsManager::Inform(Arg.Request, Arg.Buff, Arg.Dlen);
447
448// All done
449//
450 return 0;
451}
452
453/******************************************************************************/
454/* d o _ L o a d */
455/******************************************************************************/
456
457// Responses to usage requests are local to the cell and never propagated.
458//
460{
461 EPNAME("do_Load")
462 uint32_t pcpu, pnet, pxeq, pmem, ppag, pdsk;
463 int temp;
464
465// Process: load <cpu> <io> <load> <mem> <pag> <util> <rsvd> <dskFree>
466// 0 1 2 3 4 5 6
467 pcpu = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::cpuLoad]);
468 pnet = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::netLoad]);
469 pxeq = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::xeqLoad]);
470 pmem = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::memLoad]);
471 ppag = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::pagLoad]);
472 pdsk = static_cast<uint32_t>(Arg.Opaque[CmsLoadRequest::dskLoad]);
473
474// Compute actual load value. Note that the update is not thread-kosher as we
475// do not obtain a write lock. However, the values below use the single writer
476// principal so other threads will eventually see a coherent picture. This is
477// good enough for what these values are used for.
478//
479 myLoad = Meter.calcLoad(pcpu, pnet, pxeq, pmem, ppag);
480 myMass = Meter.calcLoad(myLoad, pdsk);
481 DiskFree = Arg.dskFree;
482 DiskUtil = pdsk;
483
484// Do some debugging
485//
486 DEBUGR("cpu=" <<pcpu <<" net=" <<pnet <<" xeq=" <<pxeq
487 <<" mem=" <<pmem <<" pag=" <<ppag <<" dsk=" <<pdsk
488 <<"% " <<DiskFree <<"MB load=" <<myLoad <<" mass=" <<myMass);
489
490// If we are also a manager then use this load figure to come up with
491// an overall load to report when asked. If we get free space, then we
492// must report that now so that we can be selected for allocation.
493//
494 if (Config.asManager())
495 {Meter.Record(pcpu, pnet, pxeq, pmem, ppag, pdsk);
496 if (isRW && DiskFree != LastFree)
497 {mlMutex.Lock();
498 temp = LastFree; LastFree = DiskFree; Meter.setVirtUpdt();
499 if (!temp && DiskFree >= Config.DiskMin) do_Space(Arg);
500 mlMutex.UnLock();
501 }
502 }
503
504// Report new load if need be
505//
506 if (Config.LogPerf && !logload)
507 {char buff[1024];
508 long long tRefs = Cluster.Refs();
509 long long nRefs = static_cast<long long>(RefTotW + RefTotR)*100;
510 long long sRefs = static_cast<long long>(Share) * Shrin * 100;
511 int myShr = (Share ? Share : 100);
512 if (tRefs) {nRefs /= tRefs; sRefs /= tRefs;}
513 else nRefs = sRefs = 0;
514 snprintf(buff, sizeof(buff)-1,
515 "load=%d; cpu=%d net=%d inq=%d mem=%d pag=%d dsk=%d utl=%d "
516 "shr=[%d %lld %lld] ref=[%d %d]",
517 myLoad, pcpu, pnet, pxeq, pmem, ppag, Arg.dskFree, pdsk,
518 myShr, nRefs, sRefs, RefTotR+RefR, RefTotW+RefW);
519 Say.Emsg("Node", Name(), buff);
520 logload = Config.LogPerf;
521 } else logload--;
522
523// Return as if we had gotten a pong
524//
525 return do_Pong(Arg);
526}
527
528
529/******************************************************************************/
530/* d o _ L o c a t e */
531/******************************************************************************/
532
534{
535 EPNAME("do_Locate";)
536 XrdCmsRRQInfo reqInfo(Instance,RSlot,Arg.Request.streamid,Config.QryMinum);
537 XrdCmsSelect Sel(0, Arg.Path, Arg.PathLen-1);
538 XrdCmsSelected *sP = 0;
539 struct {kXR_unt32 Val;
540 char outbuff[CmsLocateRequest::RHLen*STMax];} Resp;
541 struct iovec ioV[2] = {{(char *)&Arg.Request, sizeof(Arg.Request)},
542 {(char *)&Resp, 0}};
543 const char *Why;
544 char eBuff[128], theopts[8], *toP = theopts;
546 XrdNetIF::ifType ifType;
547 int rc, bytes;
548 bool lsuniq = false, oksel = false, lsall = (*Arg.Path == '*');
549
550// Get the right interface selection options
551//
552 ifType = ifVec[(Arg.Opts & CmsLocateRequest::kYR_retipmsk)
554
555// Indicate whether we want a name or an actual address
556//
557 lsopts = (Arg.Opts & CmsLocateRequest::kYR_retname
559
560// Indicate if only a single server entry should be listed
561//
562 if (Arg.Opts & CmsLocateRequest::kYR_retuniq && baseFS.isDFS())
563 {lsuniq = true; *toP++='u';}
564
565// Indicate whether we can ignore network restrictions
566//
568 lsopts |= XrdCmsCluster::LS_ANY;
569
570// Indicate whether we ony want to list a single entry
571//
572
573// Handle private networks here
574//
576 {XrdNetIF::Privatize(ifType);
577 *toP++='P';
578 }
579
580// Encode if type into the options
581//
582 Sel.Opts = static_cast<int>(ifType) & XrdCmsSelect::ifWant;
583 lsopts = lsopts | static_cast<XrdCmsCluster::CmsLSOpts>(ifType);
584
585// Grab various options
586//
588 {Sel.Opts = XrdCmsSelect::Refresh; *toP++='s';}
590 {Sel.Opts |= XrdCmsSelect::Asap; *toP++='i'; Sel.InfoP = &reqInfo;
591 reqInfo.lsLU = static_cast<char>(lsopts);
592 }
593 else Sel.InfoP = 0;
594
595// Do some debugging
596//
597 *toP = '\0';
598 DEBUGR(theopts <<' ' <<Arg.Path);
599
600// Perform location
601//
602 if ((rc = Cluster.Locate(Sel)))
603 {if (rc > 0)
604 {Arg.Request.rrCode = kYR_wait;
605 bytes = sizeof(Resp.Val); Why = "delay ";
606 } else {
607 if (rc == XrdCmsCluster::Wait4CBk) return 0;
609 rc = kYR_ENOENT; Why = "miss ";
610 bytes = strlcpy(Resp.outbuff, "No servers have access to the file",
611 sizeof(Resp.outbuff)) + sizeof(Resp.Val) + 1;
612 }
613 } else {Why = "?"; bytes = 0;}
614
615// List the servers
616//
617 if (!rc)
618 {if (!Sel.Vec.hf || !(sP=Cluster.List(Sel.Vec.hf, lsopts, oksel)))
619 {const char *eTxt;
621 if (oksel)
622 {rc = kYR_ENETUNREACH; Why = "unreachable ";
623 sprintf(eBuff, "No servers are reachable via %s network",
624 XrdNetIF::Name(ifType));
625 eTxt = eBuff;
626 } else {
627 rc = kYR_ENOENT; Why = "none ";
628 eTxt = "No servers have the file";
629 }
630 bytes = strlcpy(Resp.outbuff, eTxt,
631 sizeof(Resp.outbuff)) + sizeof(Resp.Val) + 1;
632 } else rc = 0;
633 }
634
635// Either prepare to send an error or format the result
636//
637 if (rc)
638 {Resp.Val = htonl(rc);
639 DEBUGR(Why <<Arg.Path);
640 } else {
641 bytes = do_LocFmt(Resp.outbuff, sP, Sel.Vec.pf, Sel.Vec.wf, lsall,lsuniq)
642 + sizeof(Resp.Val) + 1;
643 Resp.Val = 0;
644 Arg.Request.rrCode = kYR_data;
645 }
646
647// Send off the response
648//
649 Arg.Request.datalen = htons(bytes);
650 ioV[1].iov_len = bytes;
651 Link->Send(ioV, 2, bytes+sizeof(Arg.Request));
652 return 0;
653}
654
655/******************************************************************************/
656/* Static d o _ L o c F m t */
657/******************************************************************************/
658
660 SMask_t pfVec, SMask_t wfVec, bool lsall, bool lsuniq)
661{
662 static const int Skip = (XrdCmsSelected::Disable | XrdCmsSelected::Offline);
663 static const int Hung = (XrdCmsSelected::Disable | XrdCmsSelected::Offline
665 XrdCmsSelected *pP;
666 char *oP = buff;
667
668// If only unique entries are wanted then we need to only let through
669// all non-servers and one server (prefereably a r/w one)
670//
671if (!lsall && lsuniq)
672 {XrdCmsSelected *xP = 0;
673 bool haverw = false;
674 pP = sP;
675 while(pP)
676 {if (!(pP->Status & (XrdCmsSelected::isMangr | Skip)))
677 {if (haverw) pP->Status |= Skip;
678 else {if (xP) xP->Status |= Skip;
679 xP = pP;
680 haverw = (pP->Mask & wfVec) != 0;
681 }
682 }
683 pP = pP->next;
684 }
685 }
686
687// format out the request as follows:
688// 01234567810123456789212345678
689// xy[::123.123.123.123]:123456
690//
691if (lsall)
692 while(sP)
693 {*oP = (sP->Status & XrdCmsSelected::isMangr ? 'M' : 'S');
694 if (sP->Status & Hung) *oP = tolower(*oP);
695 *(oP+1) = (sP->Mask & wfVec ? 'w' : 'r');
696 strcpy(oP+2, sP->Ident); oP += sP->IdentLen + 2;
697 if (sP->next) *oP++ = ' ';
698 pP = sP; sP = sP->next; delete pP;
699 }
700 else
701 while(sP)
702 {if (!(sP->Status & Skip))
703 {*oP = (sP->Status & XrdCmsSelected::isMangr ? 'M' : 'S');
704 if (sP->Mask & pfVec) *oP = tolower(*oP);
705 *(oP+1) = (sP->Mask & wfVec ? 'w' : 'r');
706 strcpy(oP+2, sP->Ident); oP += sP->IdentLen + 2;
707 if (sP->next) *oP++ = ' ';
708 }
709 pP = sP; sP = sP->next; delete pP;
710 }
711
712// Send of the result
713//
714 *oP = '\0';
715 return (oP - buff);
716}
717
718/******************************************************************************/
719/* d o _ M k d i r */
720/******************************************************************************/
721
722// Mkdir requests are forwarded to all subscribers
723//
725{
726 EPNAME("do_Mkdir")
727 mode_t mode = 0;
728 int rc;
729
730// Do some debugging
731//
732 DEBUGR("mode " <<Arg.Mode <<' ' <<Arg.Path);
733
734// We are don here if we have no data; otherwise convert the mode if we
735// haven't done so already.
736//
737 if (!Config.DiskOK) return 0;
738 if (!mode && !getMode(Arg.Mode, mode)) return "invalid mode";
739
740// Attempt to create the directory either via call-out of oss plug-in
741//
742 if (Config.ProgMD) rc = fsExec(Config.ProgMD, Arg.Mode, Arg.Path);
743 else rc = Config.ossFS->Mkdir(Arg.Path, mode);
744
745// Return appropriate result
746//
747 return (rc ? fsFail(Arg.Ident, "mkdir", Arg.Path, rc) : 0);
748}
749
750/******************************************************************************/
751/* d o _ M k p a t h */
752/******************************************************************************/
753
754// Mkpath requests are forwarded to all subscribers
755//
757{
758 EPNAME("do_Mkpath")
759 mode_t mode = 0;
760 int rc;
761
762// Do some debugging
763//
764 DEBUGR("mode " <<Arg.Mode <<' ' <<Arg.Path);
765
766// We are don here if we have no data; otherwise convert the mode if we
767// haven't done so already.
768//
769 if (!Config.DiskOK) return 0;
770 if (!mode && !getMode(Arg.Mode, mode)) return "invalid mode";
771
772// Attempt to create the directory path via call-out or oss plugin
773//
774 if (Config.ProgMP) rc = fsExec(Config.ProgMP, Arg.Mode, Arg.Path);
775 else rc = Config.ossFS->Mkdir(Arg.Path, mode, 1);
776
777// Return appropriate result
778//
779 return (rc ? fsFail(Arg.Ident, "mkpath", Arg.Path, rc) : 0);
780}
781
782/******************************************************************************/
783/* d o _ M v */
784/******************************************************************************/
785
786// Mv requests are forwarded to all subscribers
787//
789{
790 EPNAME("do_Mv")
791 static const SMask_t allNodes(~0);
792 int rc;
793
794// Do some debugging
795//
796 DEBUGR(Arg.Path <<" to " <<Arg.Path2);
797
798// If we are not a server, if must remove references to the old and new names
799// from our cache. This is independent of how the raname is handled. We need
800// not back percolate the mv since it was hanled top down in the first place.
801// Note that we will scuttle the mv if the target file exists somewhere.
802//
803 if (!Config.DiskOK)
804 {XrdCmsSelect Sel1(XrdCmsSelect::Defer, Arg.Path, strlen(Arg.Path ));
805 XrdCmsSelect Sel2(XrdCmsSelect::Defer, Arg.Path2,strlen(Arg.Path2));
806
807 // Setup select data (note that mv does not allow fast redirect)
808 //
809 Sel2.iovP = 0; Sel2.iovN = 0;
810 Sel2.InfoP = 0; // No fast redirects
811 Sel2.nmask = SMask_t(0);
812
813 // Perform selection
814 //
815 if ((rc = Cluster.Select(Sel2)))
816 {if (rc > 0) {Arg.waitVal = rc; return "!mv";}
817 else if (Sel2.Vec.hf)
818 {Say.Emsg("do_Mv",Arg.Path2,"exists; mv failed for",Arg.Path);
819 return "target file exists";
820 }
821 }
822 Cache.DelFile(Sel2, allNodes);
823 Cache.DelFile(Sel1, allNodes);
824 return 0;
825 }
826
827// Rename the file via call-out or oss plug-in (we used to do this via a requeue
828// to the local xrootd but it's no longer necessary).
829//
830 if (Config.ProgMV) rc = fsExec(Config.ProgMV, Arg.Path, Arg.Path2);
831 else rc = Config.ossFS->Rename(Arg.Path, Arg.Path2);
832
833// Return appropriate result
834//
835 return (rc ? fsFail(Arg.Ident, "mv", Arg.Path, rc) : 0);
836}
837
838/******************************************************************************/
839/* d o _ P i n g */
840/******************************************************************************/
841
842// Ping requests from a manager are local to the cell and never propagated.
843//
845{
846 static CmsPongRequest pongIt = {{0, kYR_pong, 0, 0}};
847
848// Process: ping
849// Respond: pong
850//
851 if (isBad & isDoomed) return ".redirected";
852 Link->Send((char *)&pongIt, sizeof(pongIt));
853 return 0;
854}
855
856/******************************************************************************/
857/* d o _ P o n g */
858/******************************************************************************/
859
860// Responses to a ping are local to the cell and never propagated.
861//
863{
864// Process: pong
865// Reponds: n/a
866
867 return 0;
868}
869
870/******************************************************************************/
871/* d o _ P r e p A d d */
872/******************************************************************************/
873
875{
876 EPNAME("do_PrepAdd")
877
878// Do some debugging
879//
880 DEBUGR("parms: " <<Arg.Reqid <<' ' <<Arg.Notify <<' ' <<Arg.Prty <<' '
881 <<Arg.Mode <<' ' <<Arg.Path);
882
883// Queue this request for async processing
884//
885 (new XrdCmsPrepArgs(Arg))->Queue();
886 return 0;
887}
888
889/******************************************************************************/
890/* d o _ P r e p D e l */
891/******************************************************************************/
892
894{
895 EPNAME("do_PrepDel")
896
897// Do some debugging
898//
899 DEBUGR("reqid " <<Arg.Reqid);
900
901// Cancel the request if applicable.
902//
903 if (Config.DiskOK)
904 {if (!Config.DiskSS) {DEBUGR("ignoring cancel prepare " <<Arg.Reqid);}
905 else {DEBUGR("canceling prepare " <<Arg.Reqid);
906 PrepQ.Del(Arg.Reqid);
907 }
908 }
909 return 0;
910}
911
912/******************************************************************************/
913/* d o _ R m */
914/******************************************************************************/
915
916// Rm requests are forwarded to all subscribers
917//
919{
920 EPNAME("do_Rm")
921 static const SMask_t allNodes(~0);
922 int rc;
923
924// Do some debugging
925//
926 DEBUGR(Arg.Path);
927
928// If we have no data then we should remove this file from our cache
929//
930 if (!Config.DiskOK)
931 {XrdCmsSelect Sel(0, Arg.Path, strlen(Arg.Path));
932 Cache.DelFile(Sel, allNodes);
933 return 0;
934 }
935
936// Remove the file either via call-out or the oss plugin. We used to requeue
937// the request to the local xrootd but this is no longer needed.
938//
939 if (Config.ProgRM) rc = fsExec(Config.ProgRM, Arg.Path);
940 else rc = Config.ossFS->Unlink(Arg.Path);
941
942// Return appropriate result
943//
944 return (rc ? fsFail(Arg.Ident, "rm", Arg.Path, rc) : 0);
945}
946
947/******************************************************************************/
948/* d o _ R m d i r */
949/******************************************************************************/
950
951// Rmdir requests are forwarded to all subscribers
952//
954{
955 EPNAME("do_Rmdir")
956 static const SMask_t allNodes(~0);
957 int rc;
958
959// Do some debugging
960//
961 DEBUGR(Arg.Path);
962
963// If we have no data then we should remove this directory from our cache
964//
965 if (!Config.DiskOK)
966 {XrdCmsSelect Sel(0, Arg.Path, strlen(Arg.Path));
967 Cache.DelFile(Sel, allNodes);
968 return 0;
969 }
970
971// Remove the directory either via call-out or the oss plug-in (we used to
972// do this by requeing the request to the local xrootd; no longer needed).
973//
974 if (Config.ProgRD) rc = fsExec(Config.ProgRD, Arg.Path);
975 else rc = Config.ossFS->Remdir(Arg.Path);
976
977// Return appropriate result
978//
979 return (rc ? fsFail(Arg.Ident, "rmdir", Arg.Path, rc) : 0);
980}
981
982/******************************************************************************/
983/* d o _ S e l A v o i d */
984/******************************************************************************/
985
987 char *Avoid, bool &doRedir)
988{
989 XrdNetAddr avoidAddr;
990 char *Comma;
991 int avNum = 0;
992
993// Process the avoid list
994//
995 Sel.InfoP = 0;
996 do {if ((Comma = index(Avoid,','))) *Comma = '\0';
997 if (*Avoid == '+') Sel.nmask |= Cluster.getMask(Avoid+1);
998 else if (!avoidAddr.Set(Avoid,0))
999 Sel.nmask |= Cluster.getMask(&avoidAddr);
1000 Avoid = Comma+1; avNum++;
1001 } while(Comma && *Avoid);
1002
1003// Check why we have an avoid list. For dfs style clusters, the limits on
1004// selections are handled by the basefs object.
1005//
1006 if (baseFS.isDFS())
1009 return 0;
1010 }
1011
1012// This is a standard cluster, check if client is expanding the server base
1013// and whether or not this is allowed in this cluster.
1014//
1015 if ((Arg.Opts & CmsSelectRequest::kYR_tryMSRC) && !Config.MultiSrc)
1016 {if (Config.msRdrHost)
1017 {strcpy(Sel.Resp.Data, Config.msRdrHost); // Gauranteed to fit!
1018 Sel.Resp.DLen = Config.msRdrHLen;
1019 Sel.Resp.Port = Config.msRdrPort;
1020 doRedir = true;
1021 return -1;
1022 }
1023 strncpy(Sel.Resp.Data, msrcmsg, sizeof(Sel.Resp.Data));
1024 Sel.Resp.DLen = msrclen;
1025 if (Arg.Opts & CmsSelectRequest::kYR_tryRSEL) Sel.Resp.Port = kYR_EPERM;
1026 else Sel.Resp.Port = kYR_ENOENT;
1028 }
1029
1030// Check if we exceeded the retry count
1031//
1032 if (avNum > Config.MaxRetries)
1033 {if (Config.mrRdrHost)
1034 {strcpy(Sel.Resp.Data, Config.mrRdrHost); // Gauranteed to fit!
1035 Sel.Resp.DLen = Config.mrRdrHLen;
1036 Sel.Resp.Port = Config.mrRdrPort;
1037 doRedir = true;
1038 } else {
1039 strncpy(Sel.Resp.Data, mtrymsg, sizeof(Sel.Resp.Data));
1040 Sel.Resp.DLen = mtrylen;
1041 }
1042 return -1;
1043 }
1044
1045// We succeeded, indicate selection can proceed.
1046//
1047 return 0;
1048}
1049
1050/******************************************************************************/
1051/* d o _ S e l e c t */
1052/******************************************************************************/
1053
1054// A select request comes from a redirector and is handled locally within the
1055// cell. This may cause "state" requests to be broadcast to subscribers.
1056//
1058{
1059 EPNAME("do_Select")
1060// kXR_NotFound kXR_IOError kXR_FSError kXR_ServerError
1061 static int rtEC[] = {kYR_ENOENT, kYR_EIO, kYR_FSError, kYR_SrvError};
1062 XrdCmsRRQInfo reqInfo(Instance,RSlot,Arg.Request.streamid,Config.QryMinum);
1064 struct iovec ioV[2];
1065 char theopts[16], *toP = theopts;
1066 XrdNetIF::ifType ifType;
1067 int rc, bytes;
1068
1069// Init select data (note that refresh supresses fast redirects)
1070//
1071 Sel.iovP = 0; Sel.iovN = 0; Sel.InfoP = &reqInfo;
1072
1073// Determine what interface to return to the client
1074//
1075 ifType = ifVec[(Arg.Opts & CmsSelectRequest::kYR_retipmsk)
1078 {XrdNetIF::Privatize(ifType); *toP++='P';}
1079 Sel.Opts |= static_cast<int>(ifType) & XrdCmsSelect::ifWant;
1080
1081// Complete the arguments to select
1082//
1084 {Sel.Opts |= XrdCmsSelect::Refresh; *toP++='s';}
1086 {Sel.Opts |= XrdCmsSelect::Online; *toP++='o';}
1088 {Sel.Opts |= XrdCmsSelect::noBind; *toP++='x';}
1089 else {if (Arg.Opts & CmsSelectRequest::kYR_trunc)
1090 {Sel.Opts |= XrdCmsSelect::Write | XrdCmsSelect::Trunc; *toP++='t';}
1092 {Sel.Opts |= XrdCmsSelect::Write; *toP++='w';
1093 if (Arg.Opts & CmsSelectRequest::kYR_mwfiles || !Config.DoMWChk)
1094 {Sel.Opts |= XrdCmsSelect::MWFiles; *(toP-1)='W';}
1095 }
1097 {Sel.Opts |= XrdCmsSelect::isMeta; *toP++='m';
1098 if (!(Arg.Opts & CmsSelectRequest::kYR_write))
1099 {Sel.Opts |= XrdCmsSelect::isDir; *toP++='D';}
1100 }
1104 {Sel.Opts |= XrdCmsSelect::Replica; *toP++='+';}
1105 }
1106 }
1107 *toP = '\0';
1108
1109// If the client can override selection mode, check if this has been done. Note
1110// that true packed selection turns off fast redirect.
1111//
1112 if (Config.sched_Force || !(Arg.Opts & CmsSelectRequest::kYR_aSpec))
1113 {if (Config.sched_Pack)
1114 {Sel.Opts |= XrdCmsSelect::Pack;
1115 if (Config.sched_Pack > 1) Sel.InfoP = 0;
1116 if (!Config.sched_Level) Sel.Opts |= XrdCmsSelect::UseRef;
1117 }
1118 } else {
1120 {Sel.Opts |= XrdCmsSelect::Pack;
1121 if (Arg.Opts & CmsSelectRequest::kYR_aWait) Sel.InfoP = 0;
1122 if ((Arg.Opts & CmsSelectRequest::kYR_aPack) ==
1125 }
1126 }
1127
1128// Compute alternate hash.
1129//
1130 if (Sel.Opts & XrdCmsSelect::Pack && Config.sched_AffPC
1131 && Sel.Path.Len > 3) setHash(Sel, Config.sched_AffPC);
1132
1133// Check if an avoid node present. If so, this is ineligible for fast redirect.
1134//
1135 bool doRedir = false;
1136 Sel.nmask = SMask_t(0);
1137 if (Arg.Avoid) rc = do_SelAvoid(Arg, Sel, Arg.Avoid, doRedir);
1138 else rc = 0;
1139
1140// Perform selection
1141//
1142 if (!doRedir && (rc || (rc = Cluster.Select(Sel))))
1143 {if (rc > 0)
1144 {Arg.Request.rrCode = kYR_wait;
1145 Sel.Resp.Port = rc;
1146 Sel.Resp.DLen = 0;
1147 DEBUGR("delay " <<rc <<' ' <<Arg.Path);
1148 } else {
1149 Arg.Request.rrCode = kYR_error;
1150 if (rc != XrdCmsCluster::EReplete) // if error info has not been set
1151 {if (rc == XrdCmsCluster::RetryErr)
1152 {int rtRC = (Arg.Opts & CmsSelectRequest::kYR_tryMASK)
1154 Sel.Resp.Port = rtEC[rtRC];
1155 } else {
1156 Sel.Resp.Port = kYR_ENOENT; // This should never happen!
1157 Sel.Resp.DLen = sprintf(Sel.Resp.Data,"%s","Item not found.")+1;
1158 }
1159 }
1160 DEBUGR("failed; " <<Sel.Resp.Data << ' ' <<Arg.Path);
1161 }
1162 } else if (!Sel.Resp.DLen) return 0;
1163 else {Arg.Request.rrCode = kYR_redirect;
1164 DEBUGR("Redirect -> " <<Sel.Resp.Data <<':'
1165 <<Sel.Resp.Port <<" for " <<Arg.Path);
1166 }
1167
1168// Format the response
1169//
1170 bytes = Sel.Resp.DLen+sizeof(Sel.Resp.Port);
1171 Arg.Request.datalen = htons(bytes);
1172 Sel.Resp.Port = htonl(Sel.Resp.Port);
1173
1174// Fill out the I/O vector
1175//
1176 ioV[0].iov_base = (char *)&Arg.Request;
1177 ioV[0].iov_len = sizeof(Arg.Request);
1178 ioV[1].iov_base = (char *)&Sel.Resp;
1179 ioV[1].iov_len = bytes;
1180
1181// Send back the response
1182//
1183 Link->Send(ioV, 2, bytes+sizeof(Arg.Request));
1184 return 0;
1185}
1186
1187/******************************************************************************/
1188/* d o _ S e l P r e p */
1189/******************************************************************************/
1190
1192{
1193 EPNAME("do_SelPrep")
1195 int rc;
1196
1197// Complete the arguments to select
1198//
1204 {Sel.iovP = Arg.ioV; Sel.iovN = Arg.iovNum;}
1205 else {Sel.iovP = 0; Sel.iovN = 0;
1207 }
1208
1209// Setup select data (note that prepare does not allow fast redirect)
1210//
1211 Sel.InfoP = 0; // No fast redirects
1212 Sel.nmask = SMask_t(0);
1213
1214// We do not care what interface is being used. This may conflict with a
1215// staging prepare but it's too complicated to handle at this point.
1216//
1217 Sel.Opts |= static_cast<char>(XrdNetIF::ifAny);
1218
1219// Check if co-location wanted relevant only when staging wanted
1220//
1221 if (Arg.clPath && Sel.iovP)
1222 {XrdCmsSelect Scl(XrdCmsSelect::Peers, Arg.clPath, strlen(Arg.clPath));
1223 Scl.iovP = 0; Scl.iovN = 0; Scl.InfoP = 0; Scl.nmask = SMask_t(0);
1224 DEBUGR("colocating " <<Arg.path <<" w.r.t. " <<Arg.clPath);
1225 rc = Cluster.Select(Scl);
1226 if (rc > 0) {Sched->Schedule((XrdJob *)&Arg, rc+time(0));
1227 DEBUGR("coloc to " <<Arg.clPath <<" delayed " <<rc <<" seconds");
1228 return 1;
1229 }
1230 if (rc < 0) Say.Emsg("SelPrep", Arg.path, "failed;", Sel.Resp.Data);
1231 else Sel.nmask = ~Scl.smask;
1232 }
1233
1234// Perform selection
1235//
1236 if ((rc = Cluster.Select(Sel)))
1237 {if (rc > 0)
1238 {if (!(Arg.options & CmsPrepAddRequest::kYR_stage)) return 0;
1239 Sched->Schedule((XrdJob *)&Arg, rc+time(0));
1240 DEBUGR("prep delayed " <<rc <<" seconds");
1241 return 1;
1242 }
1243 Say.Emsg("SelPrep", Arg.path, "failed;", Sel.Resp.Data);
1244 PrepQ.Inform("unavail", &Arg);
1245 }
1246
1247// All done
1248//
1249 return 0;
1250}
1251
1252/******************************************************************************/
1253/* d o _ S p a c e */
1254/******************************************************************************/
1255
1256// Manager space requests are local to the cell and never propagated.
1257//
1259{
1260 EPNAME("do_Space")
1261 struct iovec xmsg[2];
1262 CmsAvailRequest mySpace = {{0, kYR_avail, 0, 0}};
1263 char buff[sizeof(int)*2+2], *bp = buff;
1264 int blen, maxfr, tutil;
1265
1266// Process: <id> space
1267// Respond: <id> avail <numkb> <dskutil>
1268//
1269 maxfr = Meter.FreeSpace(tutil);
1270
1271// Do some debugging
1272//
1273 DEBUGR(maxfr <<"MB free; " <<tutil <<"% util");
1274
1275// Construct a message to be sent to the manager.
1276//
1277 blen = XrdOucPup::Pack(&bp, maxfr);
1278 blen += XrdOucPup::Pack(&bp, tutil);
1279 mySpace.Hdr.datalen = htons(static_cast<unsigned short>(blen));
1280
1281// Send the response
1282//
1283 if (Arg.Request.rrCode != kYR_space)
1284 XrdCmsManager::Inform(mySpace.Hdr, buff, blen);
1285 else {xmsg[0].iov_base = (char *)&mySpace;
1286 xmsg[0].iov_len = sizeof(mySpace);
1287 xmsg[1].iov_base = buff;
1288 xmsg[1].iov_len = blen;
1289 mySpace.Hdr.datalen = htons(static_cast<unsigned short>(blen));
1290 Link->Send(xmsg, 2);
1291 }
1292 return 0;
1293}
1294
1295/******************************************************************************/
1296/* d o _ S t a t e */
1297/******************************************************************************/
1298
1299// State requests from a manager are rebroadcast to all relevant subscribers.
1300//
1302{
1303 EPNAME("do_State")
1304 struct iovec xmsg[2];
1305 int rc, noResp = Arg.Request.modifier & CmsStateRequest::kYR_noresp;
1306
1307// Do some debugging
1308//
1309 TRACER(Files,Arg.Path);
1310
1311// Process: state <path>
1312// Respond: have <path>
1313//
1314 isKnown = 1;
1315
1316// If we are a manager then check for the file in the local cache. Otherwise,
1317// ask the underlying filesystem whether it has the file.
1318//
1319 if (isMan) {if(!(Arg.Request.modifier = do_StateFWD(Arg))) return 0;}
1320 else if (!Config.DiskOK && !Config.asProxy()) return 0;
1321 else if (baseFS.Limit() && Arg.Request.modifier&CmsStateRequest::kYR_metaman)
1322 {XrdCmsPInfo pinfo;
1323 pinfo.rovec = NodeMask;
1324 if ((rc = baseFS.Exists(Arg,pinfo)) > 0) Arg.Request.modifier = rc;
1325 else return 0;
1326 }
1327 else if ((rc = baseFS.Exists(Arg.Path, -(Arg.PathLen-1))) > 0)
1328 Arg.Request.modifier = rc;
1329 else return 0;
1330
1331// Respond appropriately
1332//
1333 if (Arg.Request.modifier && !noResp)
1334 {TRACER(Files,Arg.Path <<" responding have!");
1335 xmsg[0].iov_base = (char *)&Arg.Request;
1336 xmsg[0].iov_len = sizeof(Arg.Request);
1337 xmsg[1].iov_base = Arg.Buff;
1338 xmsg[1].iov_len = Arg.Dlen;
1339 Arg.Request.rrCode = kYR_have;
1340 Arg.Request.modifier |= kYR_raw;
1341 Link->Send(xmsg, 2);
1342 }
1343 return 0;
1344}
1345
1346/******************************************************************************/
1347/* d o _ S t a t e D F S */
1348/******************************************************************************/
1349
1350void XrdCmsNode::do_StateDFS(XrdCmsBaseFR *rP, int rc)
1351{
1352 EPNAME("StateDFs");
1353 static const SMask_t allNodes(~0);
1354 CmsRRHdr Request = {rP->Sid, 0, (kXR_char)(rP->Mod | kYR_raw), 0};
1355 XrdCmsSelect Sel(0, rP->Path, rP->PathLen);
1356 int isNew;
1357
1358// Do some debugging and record the hash code.
1359//
1360 DEBUG((rP->Mod & CmsStateRequest::kYR_metaman ? "met " : "man ") <<Xrd::hex1
1361 <<int(rP->Mod) <<" rc=" <<rc <<" path=" <<rP->Path);
1362 Sel.Path.Hash = rP->Sid;
1363
1364// If the return code is negative then the file does not exist. If it is zero
1365// then we should forward the request to another node. Either way we must be
1366// a manager to do so as servers only worry about existing files.
1367//
1368 if (rc <= 0)
1369 {if (Config.asManager())
1370 {Cache.AddFile(Sel, 0);
1371 if (!rc)
1372 {Request.rrCode = kYR_state;
1373 Cluster.Broadsend(rP->Route, Request, rP->Path, rP->PathLen+1);
1374 }
1375 }
1376 return;
1377 }
1378
1379// The file exists but it could be pending
1380//
1381 if (rc == CmsHaveRequest::Pending)
1382 {Sel.Opts = XrdCmsSelect::Pending;
1384 }
1385 Sel.Vec.hf = rP->Route; Sel.Vec.wf = rP->RouteW;
1386 isNew = (Config.asManager() ? Cache.AddFile(Sel, allNodes) : 1);
1387
1388// Now inform our managers only if we haven't informed them before. At some
1389// point we will only inform the manager that actually wants to know. This
1390// is encoded to the route passed to us.
1391//
1392 if (XrdCmsManager::Present() && isNew
1393 && !(rP->Mod & CmsStateRequest::kYR_noresp))
1394 {Request.rrCode = kYR_have;
1395 XrdCmsManager::Inform(Request, rP->Path, rP->PathLen+1);
1396 }
1397}
1398
1399/******************************************************************************/
1400/* d o _ S t a t e F W D */
1401/******************************************************************************/
1402
1404{
1405 EPNAME("do_StateFWD");
1406 static const SMask_t allNodes(~0);
1407 XrdCmsSelect Sel(0, Arg.Path, Arg.PathLen-1);
1408 XrdCmsPInfo pinfo;
1409 int retc;
1410
1411// Find out who could serve this file
1412//
1413 if (!Cache.Paths.Find(Arg.Path, pinfo) || pinfo.rovec == 0)
1414 {DEBUGR("Path find failed for state " <<Arg.Path);
1415 return 0;
1416 }
1417
1418// Get the primary locations for this file
1419//
1420 Sel.Vec.hf = Sel.Vec.pf = Sel.Vec.bf = 0;
1421 if (Arg.Request.modifier & CmsStateRequest::kYR_refresh) retc = 0;
1422 else retc = Cache.GetFile(Sel, pinfo.rovec);
1423
1424// If we will possibly be forwarding this request we indicate here whether this
1425// is a request from a meta-manager. Making the decision in the manager node
1426// prevents the requestor from lying about its status.
1427//
1428 if (!retc && !Config.asServer())
1430
1431// Here we process the case where we need to discover whether the file exists.
1432// For distributed file systems, we either ask the underlying file system here
1433// or forward the request to some arbitrary node in a callback via the baseFS.
1434// If cached information exists, pending status takes precedence (more below).
1435// Additionally, if a query is alrady in progress, deep-six this attempt.
1436//
1437 if (baseFS.isDFS())
1438 {if (retc < 0) return 0;
1439 if (!retc)
1440 {if (baseFS.Traverse())
1441 {Cache.AddFile(Sel, 0);
1442 Cluster.Broadsend(pinfo.rovec, Arg.Request, Arg.Buff, Arg.Dlen);
1443 return 0;
1444 }
1445 if ((retc = baseFS.Exists(Arg, pinfo)) <= 0)
1446 {if (retc < 0) Cache.AddFile(Sel, 0);
1447 return 0;
1448 }
1450 Sel.Vec.hf = pinfo.rovec; Sel.Vec.wf = pinfo.rwvec;
1451 Cache.AddFile(Sel, allNodes);
1452 return retc;
1453 }
1454 if (Sel.Vec.pf != 0) return CmsHaveRequest::Pending;
1455 if (Sel.Vec.hf != 0) return CmsHaveRequest::Online;
1456 return 0;
1457 }
1458
1459// For shared-nothing setups, first check if we need to ask any unasked nodes
1460// whether they have the file.
1461//
1462 if (!retc || Sel.Vec.bf != 0)
1463 {if (!retc) Cache.AddFile(Sel, 0);
1464 Cluster.Broadcast((retc ? Sel.Vec.bf : pinfo.rovec), Arg.Request,
1465 (void *)Arg.Buff, Arg.Dlen);
1466 }
1467
1468// Return true if anyone has the file at this point. In shared-nothing systems
1469// we are interested in some node has the file in non-pending status. This
1470// differs from shared-everything because pending status applies to all nodes.
1471//
1472 if (Sel.Vec.hf != 0) return CmsHaveRequest::Online;
1473 if (Sel.Vec.pf != 0){return CmsHaveRequest::Pending;}
1474 return 0;
1475}
1476
1477/******************************************************************************/
1478/* d o _ S t a t F S */
1479/******************************************************************************/
1480
1482{
1483 static kXR_unt32 Zero = 0;
1484 char buff[256];
1485 struct iovec ioV[3] = {{(char *)&Arg.Request, sizeof(Arg.Request)},
1486 {(char *)&Zero, sizeof(Zero)},
1487 {(char *)&buff, 0}};
1488 XrdCmsPInfo pinfo;
1489 int bytes;
1490 SpaceData theSpace;
1491
1492// Find out who serves this path and get space relative to it
1493//
1494 if (Cache.Paths.Find(Arg.Path, pinfo) && pinfo.rovec)
1495 {Cluster.Space(theSpace, pinfo.rovec);
1497 {bytes = sprintf(buff, "A %lld %lld %d",
1498 theSpace.Total, theSpace.TotFr,
1499 (theSpace.wFree < theSpace.sFree ? theSpace.sFree
1500 : theSpace.wFree)) + 1;
1501 } else {
1502 bytes = sprintf(buff, "%d %d %d %d %d %d",
1503 theSpace.wNum, theSpace.wFree, theSpace.wUtil,
1504 theSpace.sNum, theSpace.sFree, theSpace.sUtil) + 1;
1505 }
1506 } else bytes = strlcpy(buff, "-1 -1 -1 -1 -1 -1", sizeof(buff)) + 1;
1507
1508// Send the response
1509//
1510 ioV[2].iov_len = bytes;
1511 bytes += sizeof(Zero);
1512 Arg.Request.rrCode = kYR_data;
1513 Arg.Request.datalen = htons(bytes);
1514 Link->Send(ioV, 3, bytes+sizeof(Arg.Request));
1515 return 0;
1516}
1517
1518/******************************************************************************/
1519/* d o _ S t a t s */
1520/******************************************************************************/
1521
1522// We punt on stats requests as we have no way to export them anyway.
1523//
1525{
1526 static const unsigned short szLen = sizeof(kXR_unt32);
1527 static XrdSysMutex StatsData;
1528 static int statsz = 0;
1529 static int statln = 0;
1530 static char *statbuff = 0;
1531 static time_t statlast = 0;
1532 static kXR_unt32 theSize;
1533
1534 struct iovec ioV[3] = {{(char *)&Arg.Request, sizeof(Arg.Request)},
1535 {(char *)&theSize, sizeof(theSize)},
1536 {0, 0}
1537 };
1538 time_t tNow;
1539
1540// Allocate buffer if we do not have one
1541//
1542 StatsData.Lock();
1543 if (!statsz || !statbuff)
1544 {statsz = Cluster.Stats(0,0);
1545 statbuff = (char *)malloc(statsz);
1546 theSize = htonl(statsz);
1547 }
1548
1549// Check if only the size is wanted
1550//
1552 {ioV[1].iov_len = sizeof(theSize);
1553 Arg.Request.datalen = htons(szLen);
1554 Arg.Request.rrCode = kYR_data;
1555 Link->Send(ioV, 2);
1556 StatsData.UnLock();
1557 return 0;
1558 }
1559
1560// Get full statistics if enough time has passed
1561//
1562 tNow = time(0);
1563 if (statlast+9 >= tNow)
1564 {statln = Cluster.Stats(statbuff, statsz); statlast = tNow;}
1565
1566// Format result and send response
1567//
1568 ioV[2].iov_base = statbuff;
1569 ioV[2].iov_len = statln;
1570 Arg.Request.datalen = htons(static_cast<unsigned short>(szLen+statln));
1571 Arg.Request.rrCode = kYR_data;
1572 Link->Send(ioV, 3);
1573
1574// All done
1575//
1576 StatsData.UnLock();
1577 return 0;
1578}
1579
1580/******************************************************************************/
1581/* d o _ S t a t u s */
1582/******************************************************************************/
1583
1584// the reset request is propagated to all of our managers. A special reset case
1585// is sent when a subscribed supervisor adds a new node. This causes all cache
1586// lines for the supervisor to be marked suspect. Status change requests are
1587// propagated to upper-level managers only if the summary state has changed.
1588//
1590{
1591 EPNAME("do_Status")
1592 const char *srvMsg, *stgMsg;
1598 int add2Activ, add2Stage, port;
1599
1600// Do some debugging
1601//
1602 DEBUGR( (Reset ? "reset " : "")
1603 <<(Resume ? "resume " : (Suspend ? "suspend " : ""))
1604 <<(Stage ? "stage " : (noStage ? "nostage " : "")));
1605
1606// Process reset requests. These are exclsuive to any other request
1607//
1608 if (Reset)
1609 {XrdCmsManager::Reset(); // Propagate the reset to our managers
1610 Cache.Bounce(NodeMask, NodeID); // Now invalidate our cache lines
1611 }
1612
1613// Process stage/nostage
1614//
1615 if ((Stage && isNoStage) || (noStage && !isNoStage))
1616 if (noStage) {add2Stage = -1; isNoStage = 1; stgMsg="staging suspended";}
1617 else {add2Stage = 1; isNoStage = 0; stgMsg="staging resumed";}
1618 else {add2Stage = 0; stgMsg = 0;}
1619
1620// Process suspend/resume. We mmerely need a read lock to alter isBad here.
1621//
1622 if ((Resume && (isBad & isSuspend)) || (Suspend && !(isBad & isSuspend)))
1623 if (Suspend) {add2Activ = -1;
1624 Cluster.SLock(true, false);
1625 isBad |= isSuspend; // Keep coherency with black listing
1626 Cluster.SLock(false);
1627 srvMsg="service suspended";
1628 stgMsg = 0;
1629 }
1630 else {add2Activ = 1;
1631 Cluster.SLock(true, false);
1632 isBad &= ~isSuspend; // Keep coherency with black listing
1633 Cluster.SLock(false);
1634 srvMsg="service resumed";
1635 stgMsg = (isNoStage ? "(no staging)" : "(staging)");
1636 port = ntohl(Arg.Request.streamid);
1637 if (port && port != netIF.Port())
1638 {Lock(); netIF.Port(port); UnLock();
1639 DEBUGR("set data port to " <<port);
1640 }
1641 }
1642 else {add2Activ = 0; srvMsg = 0;}
1643
1644// Get the most important message out (advisory isOffline doen't need STMutex)
1645//
1646 if (isOffline) {srvMsg = "service offline"; stgMsg = 0;}
1647 else if (isBad & isDisabled) {srvMsg = "service disabled"; stgMsg = 0;}
1648 else if (isBad & isBlisted ) {srvMsg = "service blacklisted"; stgMsg = 0;}
1649
1650// Now see if we need to change anything
1651//
1652 if (add2Activ || add2Stage)
1653 {CmsState.Update(XrdCmsState::Counts, add2Activ, add2Stage);
1654 Say.Emsg("Node", Name(), srvMsg, stgMsg);
1655 }
1656
1657 return 0;
1658}
1659
1660/******************************************************************************/
1661/* d o _ T r u n c */
1662/******************************************************************************/
1663
1664// Trunc requests are forwarded to all subscribers
1665//
1667{
1668 EPNAME("do_Trunc")
1669 long long Size = -1;
1670 int rc;
1671
1672// Do some debugging
1673//
1674 DEBUGR("size " <<Arg.Mode <<' ' <<Arg.Path);
1675
1676// We are don here if we have no data; otherwise convert the mode if we
1677// haven't done so already.
1678//
1679 if (!Config.DiskOK) return 0;
1680 if (Size < 0 && !getSize(Arg.Mode, Size)) return "invalid size";
1681
1682// Attempt to change the size either via call-out or the oss plug-in
1683//
1684 if (Config.ProgTR) rc = fsExec(Config.ProgTR, Arg.Mode, Arg.Path);
1685 else rc = Config.ossFS->Truncate(Arg.Path, Size);
1686
1687// Return appropriate result
1688//
1689 return (rc ? fsFail(Arg.Ident, "trunc", Arg.Path, rc) : 0);
1690}
1691
1692/******************************************************************************/
1693/* d o _ T r y */
1694/******************************************************************************/
1695
1696// Try requests from a manager indicate that we are being displaced and should
1697// hunt for another manager. The request provides hints as to where to try.
1698// Note that this method is no longer called but handled in XrdCmsProtocol!
1699//
1701{
1702 EPNAME("do_Try")
1703
1704// Do somde debugging
1705//
1706 DEBUGR(Arg.Path);
1707
1708// Add all the alternates to our alternate list
1709//
1710 if (Manager) Manager->myMans->Add(&netID, Arg.Path, Config.PortTCP, myLevel);
1711
1712// Close the link and return an error
1713//
1714// Disc("redirected.");
1715 return ".redirected";
1716}
1717
1718/******************************************************************************/
1719/* d o _ U p d a t e */
1720/******************************************************************************/
1721
1723{
1724
1725// Process: <id> update
1726// Respond: <id> status
1727//
1728 CmsState.sendState(Link);
1729 return 0;
1730}
1731
1732/******************************************************************************/
1733/* d o _ U s a g e */
1734/******************************************************************************/
1735
1736// Usage requests from a manager are local to the cell and never propagated.
1737//
1739{
1740
1741// Process: <id> usage
1742// Respond: <id> load <cpu> <io> <load> <mem> <pag> <dskfree> <dskutil>
1743//
1744 Report_Usage(Link);
1745 return 0;
1746}
1747
1748/******************************************************************************/
1749/* R e p o r t _ U s a g e */
1750/******************************************************************************/
1751
1753{
1754 EPNAME("Report_Usage")
1755 CmsLoadRequest myLoad = {{0, kYR_load, 0, 0}};
1756 struct iovec xmsg[2];
1757 char loadbuff[CmsLoadRequest::numLoad];
1758 char respbuff[sizeof(loadbuff)+2+sizeof(int)+2], *bp = respbuff;
1759 int blen, maxfr, pcpu, pnet, pxeq, pmem, ppag, pdsk;
1760
1761// Respond: <id> load <cpu> <io> <load> <mem> <pag> <dskfree> <dskutil>
1762//
1763 maxfr = Meter.Report(pcpu, pnet, pxeq, pmem, ppag, pdsk);
1764
1765 loadbuff[CmsLoadRequest::cpuLoad] = static_cast<char>(pcpu);
1766 loadbuff[CmsLoadRequest::netLoad] = static_cast<char>(pnet);
1767 loadbuff[CmsLoadRequest::xeqLoad] = static_cast<char>(pxeq);
1768 loadbuff[CmsLoadRequest::memLoad] = static_cast<char>(pmem);
1769 loadbuff[CmsLoadRequest::pagLoad] = static_cast<char>(ppag);
1770 loadbuff[CmsLoadRequest::dskLoad] = static_cast<char>(pdsk);
1771
1772 blen = XrdOucPup::Pack(&bp, loadbuff, sizeof(loadbuff));
1773 blen += XrdOucPup::Pack(&bp, maxfr);
1774 myLoad.Hdr.datalen = htons(static_cast<unsigned short>(blen));
1775
1776 xmsg[0].iov_base = (char *)&myLoad;
1777 xmsg[0].iov_len = sizeof(myLoad);
1778 xmsg[1].iov_base = respbuff;
1779 xmsg[1].iov_len = blen;
1780 if (lp) lp->Send(xmsg, 2);
1781 else XrdCmsManager::Inform("usage", xmsg, 2);
1782
1783// Do some debugging
1784//
1785 DEBUG("cpu=" <<pcpu <<" net=" <<pnet <<" xeq=" <<pxeq
1786 <<" mem=" <<pmem <<" pag=" <<ppag <<" dsk=" <<pdsk <<' ' <<maxfr);
1787}
1788
1789/******************************************************************************/
1790/* S y n c S p a c e */
1791/******************************************************************************/
1792
1794{
1795 XrdCmsRRData Arg;
1796 int old_free = 0;
1797
1798// For newly logged in nodes, we need to sync the free space stats
1799//
1800 mlMutex.Lock();
1801 if (isRW && DiskFree > LastFree)
1802 {old_free = LastFree; LastFree = DiskFree;}
1803 mlMutex.UnLock();
1804
1805// Tell our manager if we now have more space, if need be.
1806//
1807 if (!old_free)
1808 {Arg.Request.rrCode = kYR_login;
1809 Arg.Ident = Ident;
1810 Arg.dskFree = DiskFree;
1811 Arg.dskUtil = DiskUtil;
1812 do_Space(Arg);
1813 }
1814}
1815
1816/******************************************************************************/
1817/* P r i v a t e M e t h o d s */
1818/******************************************************************************/
1819/******************************************************************************/
1820/* f s E x e c */
1821/******************************************************************************/
1822
1823int XrdCmsNode::fsExec(XrdOucProg *Prog, char *Arg1, char *Arg2)
1824{
1825 static const int PfnSZ = XrdCmsMAX_PATH_LEN+1;
1826 char Pfn1[PfnSZ], Pfn2[PfnSZ];
1827
1828// The first argument may or may not be a path. The second, if present is always
1829// a path. If we have a name mapper then we need to substitute remapped paths.
1830//
1831 if (Config.lcl_N2N)
1832 {if (*Arg1 == '/')
1833 {if (Config.lcl_N2N->lfn2pfn(Arg1,Pfn1,PfnSZ-1)) return fsL2PFail1;
1834 Arg1 = Pfn1;
1835 }
1836 if ( Arg2)
1837 {if (Config.lcl_N2N->lfn2pfn(Arg2,Pfn2,PfnSZ-1)) return fsL2PFail2;
1838 Arg2 = Pfn2;
1839 }
1840 }
1841
1842// Return results of the call-out
1843//
1844 return Prog->Run(Arg1, Arg2);
1845}
1846
1847/******************************************************************************/
1848/* f s F a i l */
1849/******************************************************************************/
1850
1851const char *XrdCmsNode::fsFail(const char *Who, const char *What,
1852 const char *Path, int rc)
1853{
1854 EPNAME("fsFail")
1855
1856// Immediately return on the two most unlikely failures; o/w issue message
1857//
1858 rc = abs(rc);
1859 if (rc == fsL2PFail1) return "lfn2pfn path1 failed";
1860 if (rc == fsL2PFail2) return "lfn2pfn path2 failed";
1861 if (rc != ENOENT) Say.Emsg("Node", rc, What, Path);
1862 else {struct {const char *Ident;} Arg = {Who};
1863 DEBUGR("rc=" <<rc <<' ' <<What <<' ' <<Path);
1864 }
1865 return rc ? XrdSysE2T(rc) : 0;
1866}
1867
1868/******************************************************************************/
1869/* g e t M o d e */
1870/******************************************************************************/
1871
1872int XrdCmsNode::getMode(const char *theMode, mode_t &Mode)
1873{
1874 char *eP;
1875
1876// Convert the mode argument
1877//
1878 if (!(Mode = strtol(theMode, &eP, 8)) || *eP || (Mode >> 9)) return 0;
1879 return 1;
1880}
1881
1882/******************************************************************************/
1883/* g e t S i z e */
1884/******************************************************************************/
1885
1886int XrdCmsNode::getSize(const char *theSize, long long &Size)
1887{
1888 char *eP;
1889
1890// Convert the size argument
1891//
1892 if (!(Size = strtoll(theSize, &eP, 10)) || *eP) return 0;
1893 return 1;
1894}
1895
1896/******************************************************************************/
1897/* s e t H a s h */
1898/******************************************************************************/
1899
1900void XrdCmsNode::setHash(XrdCmsSelect &Sel, int acount)
1901{
1902
1903// Process postive count
1904//
1905 if (acount > 0)
1906 {char *spos = (*Sel.Path.Val == '/' ? Sel.Path.Val+1 : Sel.Path.Val);
1907 char *slash = nullptr;
1908 while(acount)
1909 {if (!(slash = index(spos, '/'))) return;
1910 acount--; spos = slash+1;
1911 }
1912 *slash = 0;
1913 Sel.AltHash = XrdOucCRC::Calc32C(Sel.Path.Val, slash - Sel.Path.Val);
1914 *slash = '/';
1916 return;
1917 }
1918
1919// Process negative count
1920//
1921 if (acount < 0)
1922 {int i = Sel.Path.Len-1;
1923 if (Sel.Path.Val[i] == '/') i--;
1924
1925 for(; i > 0; i--)
1926 {if (Sel.Path.Val[i] == '/' && !(++acount)) break;}
1927
1928 if (i)
1929 {Sel.AltHash = XrdOucCRC::Calc32C(Sel.Path.Val+i, Sel.Path.Len-i);
1931 }
1932 }
1933}
unsigned int kXR_unt32
Definition XPtypes.hh:90
unsigned char kXR_char
Definition XPtypes.hh:65
#define DEBUG(x)
#define EPNAME(x)
#define DEBUGR(y)
#define TRACER(x, y)
#define STMax
unsigned long long SMask_t
#define XrdCmsMAX_PATH_LEN
int Mode
XrdOucString Path
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
if(ec< 0) ec
size_t strlcpy(char *dst, const char *src, size_t sz)
kXR_unt32 Sid
int AddFile(XrdCmsSelect &Sel, SMask_t mask)
int Broadsend(SMask_t smask, XrdCms::CmsRRHdr &Hdr, void *Data, int Dlen)
static const int EReplete
static const int RetryErr
static const int Wait4CBk
XrdOucName2Name * lcl_N2N
unsigned int Hash
Definition XrdCmsKey.hh:53
char * Val
Definition XrdCmsKey.hh:52
short Len
Definition XrdCmsKey.hh:54
static void Inform(const char *What, const char *Data, int Dlen)
static bool Present()
static void Reset()
const char * do_PrepDel(XrdCmsRRData &Arg)
int do_StateFWD(XrdCmsRRData &Arg)
const char * do_Gone(XrdCmsRRData &Arg)
const char * do_Locate(XrdCmsRRData &Arg)
const char * do_Update(XrdCmsRRData &Arg)
const char * do_Try(XrdCmsRRData &Arg)
char * Ident
Definition XrdCmsNode.hh:61
const char * do_State(XrdCmsRRData &Arg)
void Delete(XrdSysRWLock &gMutex)
static void do_StateDFS(XrdCmsBaseFR *rP, int rc)
const char * do_Space(XrdCmsRRData &Arg)
int do_SelAvoid(XrdCmsRRData &Arg, XrdCmsSelect &Sel, char *Avoid, bool &doRedir)
const char * do_Select(XrdCmsRRData &Arg)
const char * do_Mv(XrdCmsRRData &Arg)
const char * do_Trunc(XrdCmsRRData &Arg)
static void Report_Usage(XrdLink *lp)
const char * do_Usage(XrdCmsRRData &Arg)
const char * do_Chmod(XrdCmsRRData &Arg)
void SyncSpace()
void Lock()
static const char isDisabled
Definition XrdCmsNode.hh:80
const char * do_Load(XrdCmsRRData &Arg)
char * Name()
static int do_SelPrep(XrdCmsPrepArgs &Arg)
const char * do_Rm(XrdCmsRRData &Arg)
char isOffline
Definition XrdCmsNode.hh:64
const char * do_PrepAdd(XrdCmsRRData &Arg)
const char * do_Ping(XrdCmsRRData &Arg)
const char * do_Have(XrdCmsRRData &Arg)
static const char isSuspend
Definition XrdCmsNode.hh:81
const char * do_Stats(XrdCmsRRData &Arg)
const char * do_Disc(XrdCmsRRData &Arg)
const char * do_Avail(XrdCmsRRData &Arg)
char isNoStage
Definition XrdCmsNode.hh:66
static int do_LocFmt(char *buff, XrdCmsSelected *sP, SMask_t pf, SMask_t wf, bool lsall=false, bool lsuniq=false)
void Disc(const char *reason=0, int needLock=1)
const char * do_Mkpath(XrdCmsRRData &Arg)
XrdCmsNode(XrdLink *lnkp, const char *theIF=0, const char *sid=0, int port=0, int lvl=0, int id=-1)
Definition XrdCmsNode.cc:98
void UnLock()
const char * do_Pong(XrdCmsRRData &Arg)
void setName(XrdLink *lnkp, const char *theIF, int port)
const char * do_Mkdir(XrdCmsRRData &Arg)
const char * do_StatFS(XrdCmsRRData &Arg)
const char * do_Rmdir(XrdCmsRRData &Arg)
static const char isDoomed
Definition XrdCmsNode.hh:82
static const char isBlisted
Definition XrdCmsNode.hh:79
const char * do_Status(XrdCmsRRData &Arg)
SMask_t rovec
SMask_t rwvec
struct iovec ioV[iovNum]
static const int iovNum
unsigned int Opts
unsigned int dskFree
XrdCms::CmsRRHdr Request
struct iovec * iovP
struct XrdCmsSelect::@372246154012353073336061155127145056202367365025 Resp
XrdCmsRRQInfo * InfoP
XrdCmsKey Path
unsigned int AltHash
struct XrdCmsSelect::@234326324321301042052133314024110005315140201317 Vec
char Ident[IdentSize]
XrdCmsSelected * next
const char * Set(const char *hSpec, int pNum=PortInSpec)
static const char * Name(ifType ifT)
Definition XrdNetIF.hh:312
ifType
The enum that is used to index into ifData to get appropriate interface.
Definition XrdNetIF.hh:65
static void Privatize(ifType &x)
Definition XrdNetIF.hh:330
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition XrdOucCRC.cc:190
virtual int lfn2pfn(const char *lfn, char *buff, int blen)=0
int Run(XrdOucStream *Sp, const char *argV[], int argc=0, const char *envV[]=0) const
static int Pack(struct iovec **, const char *, unsigned short &buff)
Definition XrdOucPup.cc:52
static void Snooze(int seconds)
XrdCmsMeter Meter
XrdCmsCache Cache
static const unsigned char kYR_Version
Definition YProtocol.hh:80
kXR_unt16 datalen
Definition YProtocol.hh:86
@ kYR_FSError
Definition YProtocol.hh:161
@ kYR_ENETUNREACH
Definition YProtocol.hh:158
@ kYR_ENOENT
Definition YProtocol.hh:150
@ kYR_SrvError
Definition YProtocol.hh:162
@ kYR_EPERM
Definition YProtocol.hh:151
kXR_char modifier
Definition YProtocol.hh:85
XrdScheduler * Sched
XrdCmsCluster Cluster
XrdCmsBaseFS baseFS
@ kYR_redirect
Definition YProtocol.hh:143
@ kYR_error
Definition YProtocol.hh:142
XrdSysError Say
kXR_char rrCode
Definition YProtocol.hh:84
XrdCmsState CmsState
XrdCmsPrepare PrepQ
kXR_unt32 streamid
Definition YProtocol.hh:83
XrdCmsConfig Config
@ kYR_space
Definition YProtocol.hh:109
@ kYR_login
Definition YProtocol.hh:90
@ kYR_state
Definition YProtocol.hh:110
@ kYR_avail
Definition YProtocol.hh:102
static const int RHLen
Definition YProtocol.hh:264