XRootD
Loading...
Searching...
No Matches
XrdCmsManTree.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C m s M a n T r e 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 <cstdio>
32
34
36#include "XrdCms/XrdCmsNode.hh"
37#include "XrdCms/XrdCmsTrace.hh"
38
39using namespace XrdCms;
40
41/******************************************************************************/
42/* C o n s t r u c t o r */
43/******************************************************************************/
44
45XrdCmsManTree::XrdCmsManTree(int maxC) : maxTMI(0), numConn(0), maxConn(maxC),
46 atRoot(0), conLevel(0), conNID(-1),
47 numWaiting(0), myStatus(Active)
48{
49 snprintf(buff, sizeof(buff), "%d", maxC);
50}
51
52/******************************************************************************/
53/* A b o r t */
54/******************************************************************************/
55
57{
58 XrdSysMutexHelper Monitor(myMutex);
59
60// An abort may be issued to make sure no one is waiting to participate in
61// tree construction. It's usually issued when the manager object has been
62// permanently redirected.
63//
64 if (myStatus != Aborted && numWaiting)
65 {for (int i = 0; i < maxTMI; i++)
66 if (tmInfo[i].Status == Waiting) {tmInfo[i].Level = 0; Redrive(i);}
67 }
68
69// Indicate we have aborted
70//
71 myStatus = Aborted;
72}
73
74/******************************************************************************/
75/* C o n n e c t */
76/******************************************************************************/
77
79{
80 static CmsDiscRequest discRequest = {{0, kYR_disc, 0, 0}};
81 XrdSysMutexHelper Monitor(myMutex);
82 char mybuff[16];
83 int i;
84
85// Rule 0: If we aborted tell the client to just stop doing this
86//
87 if (myStatus == Aborted) return 0;
88
89// Rule 1: If we are already connected, thell the caller to disband the
90// connection as we must have a connection to an interior node.
91//
92 if (myStatus == Connected) return 0;
93 numConn++;
94 tmInfo[nID].nodeP = nP;
95
96// Rule 2: If we connected to a root node then consider ourselves connected
97// only if all connections are to the root.
98//
99 if (tmInfo[nID].Level == 0)
100 {if (numConn == maxConn)
101 {myStatus = Connected; conLevel = 0; atRoot = 1;
102 Say.Emsg("ManTree", "Now connected to", buff, "root node(s)");
103 }
104 tmInfo[nID].Status = Connected;
105 return 1;
106 }
107
108// Rule 3: We connected to an interior node. Disband all other existing
109// connections (these should only be to root nodes) and consider
110// ourselves connected.
111//
112 for (i = 0; i < maxTMI; i++)
113 if (i != nID && tmInfo[i].Status == Connected)
114 {tmInfo[i].nodeP->Send((char *)&discRequest, sizeof(discRequest));
115 tmInfo[i].Status = Pending;
116 }
117 myStatus = Connected;
118 conLevel = tmInfo[nID].Level;
119 conNID = nID;
120 atRoot = 0;
121
122// Document our connection configuration
123//
124 snprintf(mybuff, sizeof(mybuff), "%d", conLevel);
125 Say.Emsg("ManTree", "Now connected to supervisor at level", mybuff);
126 return 1;
127}
128
129/******************************************************************************/
130/* D i s c */
131/******************************************************************************/
132
134{
135
136// A connected caller has lost it's connection.
137//
138 myMutex.Lock();
139 if (tmInfo[nID].Status == Connected || tmInfo[nID].Status == Pending)
140 numConn--;
141 tmInfo[nID].Status = Active;
142 if (atRoot || (conLevel && conNID == nID)) myStatus = Active;
143 tmInfo[nID].nodeP = 0;
144 myMutex.UnLock();
145}
146
147/******************************************************************************/
148/* R e g i s t e r */
149/******************************************************************************/
150
152{
153 int nID;
154
155// Add this server to the tree table. Register is called only once and there
156// can be no more than MTMax connections to a manager. Hence, we dispense with
157// error checking (how optimistic :-)
158//
159 myMutex.Lock();
160 tmInfo[maxTMI].Status= Active;
161 nID = maxTMI; maxTMI++;
162 myMutex.UnLock();
163 return nID;
164}
165
166/******************************************************************************/
167/* T r y i n g */
168/******************************************************************************/
169
170// This method arranges server connections to a manager to form a minimal B-Tree
171// free of phantom arcs. The rule is simple, either all connections are to the
172// root of tree or there is only one connection to an interior node. Because
173// node discovery is non-determinstic, we must make sure that all root nodes
174// are tried so as to discover the full set of supervisor nodes we can contact.
175// This method returns True if the caller may continue at the indicated level
176// and False if the caller should restart at the root node.
177//
178int XrdCmsManTree::Trying(int nID, int lvl)
179{
180 int i;
181
182// Set the current status of the connection
183//
184 myMutex.Lock();
185 tmInfo[nID].Level = lvl;
186
187// Rule 0: If we aborted tell the client to just stop doing this
188//
189 if (myStatus == Aborted) return -1;
190
191// Rule 1: If we are already connected at level >0 then the caller must wait
192//
193 if (myStatus == Connected && conLevel > 0)
194 {Pause(nID);
195 return (lvl == tmInfo[nID].Level);
196 }
197
198// Rule 2: If the caller is trying level 0 then any waiting threads must be
199// allowed to continue but forced to level 0. This allows us to discover
200// all the supervisors connected to the root.
201//
202 if (!lvl)
203 {if (numWaiting)
204 {for (i = 0; i < maxTMI; i++)
205 if (i != nID && tmInfo[i].Status == Waiting)
206 {tmInfo[i].Level = 0; Redrive(i);}
207 }
208 myMutex.UnLock();
209 return 1;
210 }
211
212// Rule 3: If the caller is trying at a non-zero level (interior node) and
213// someone else is trying at a non-zero level, then the caller must
214// wait.
215//
216 for (i = 0; i < maxTMI; i++)
217 if (i != nID && tmInfo[i].Status == Active && tmInfo[i].Level) break;
218 if (i < maxTMI) Pause(nID);
219 else myMutex.UnLock();
220
221// The caller may continue. Indicate whether the caller must restart at the
222// root node. If the caller may continue trying to connect to an interior
223// node then it's the only thread trying to do so.
224//
225 return (lvl == tmInfo[nID].Level);
226}
int Connect(int nID, XrdCmsNode *nP)
void Disc(int nID)
XrdCmsManTree(int maxC)
int Trying(int nID, int Lvl)
XrdSysError Say