00001 /******************************************************************************/ 00002 /* */ 00003 /* X r d C m s M a n T r e e . c c */ 00004 /* */ 00005 /* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University */ 00006 /* All Rights Reserved */ 00007 /* Produced by Andrew Hanushevsky for Stanford University under contract */ 00008 /* DE-AC02-76-SFO0515 with the Department of Energy */ 00009 /******************************************************************************/ 00010 00011 // $Id: XrdCmsManTree.cc 24468 2008-06-22 16:47:03Z ganis $ 00012 00013 // Original Version: 2007/07/26 15:18:24 ganis 00014 00015 const char *XrdCmsManTreeCVSID = "$Id: XrdCmsManTree.cc 24468 2008-06-22 16:47:03Z ganis $"; 00016 00017 #include <stdio.h> 00018 00019 #include "XProtocol/YProtocol.hh" 00020 00021 #include "XrdCms/XrdCmsManTree.hh" 00022 #include "XrdCms/XrdCmsNode.hh" 00023 #include "XrdCms/XrdCmsTrace.hh" 00024 00025 using namespace XrdCms; 00026 00027 /******************************************************************************/ 00028 /* G l o b a l O b j e c t s */ 00029 /******************************************************************************/ 00030 00031 XrdCmsManTree XrdCms::ManTree; 00032 00033 /******************************************************************************/ 00034 /* C o n n e c t */ 00035 /******************************************************************************/ 00036 00037 int XrdCmsManTree::Connect(int nID, XrdCmsNode *nP) 00038 { 00039 static CmsDiscRequest discRequest = {{0, kYR_disc, 0, 0}}; 00040 XrdSysMutexHelper Monitor(myMutex); 00041 char mybuff[8]; 00042 int i; 00043 00044 // Rule 1: If we are already connected, thell the caller to disband the 00045 // connection as we must have a connection to an interior node. 00046 // 00047 if (myStatus == Connected) return 0; 00048 numConn++; 00049 tmInfo[nID].nodeP = nP; 00050 00051 // Rule 2: If we connected to a root node then consider ourselves connected 00052 // only if all connections are to the root. 00053 // 00054 if (tmInfo[nID].Level == 0) 00055 {if (numConn == maxConn) 00056 {myStatus = Connected; conLevel = 0; atRoot = 1; 00057 Say.Emsg("ManTree", "Now connected to", buff, "root node(s)"); 00058 } 00059 tmInfo[nID].Status = Connected; 00060 return 1; 00061 } 00062 00063 // Rule 3: We connected to an interior node. Disband all other existing 00064 // connections (these should only be to root nodes) and consider 00065 // ourselves connected. 00066 // 00067 for (i = 0; i < maxTMI; i++) 00068 if (i != nID && tmInfo[i].Status == Connected) 00069 {tmInfo[i].nodeP->Send((char *)&discRequest, sizeof(discRequest)); 00070 tmInfo[i].Status = Pending; 00071 } 00072 myStatus = Connected; 00073 conLevel = tmInfo[nID].Level; 00074 conNID = nID; 00075 atRoot = 0; 00076 00077 // Document our connection configuration 00078 // 00079 snprintf(mybuff, sizeof(mybuff), "%d", conLevel); 00080 Say.Emsg("ManTree", "Now connected to supervisor at level", mybuff); 00081 return 1; 00082 } 00083 00084 /******************************************************************************/ 00085 /* D i s c */ 00086 /******************************************************************************/ 00087 00088 void XrdCmsManTree::Disc(int nID) 00089 { 00090 00091 // A connected caller has lost it's connection. 00092 // 00093 myMutex.Lock(); 00094 if (tmInfo[nID].Status == Connected || tmInfo[nID].Status == Pending) 00095 numConn--; 00096 tmInfo[nID].Status = Active; 00097 if (atRoot || (conLevel && conNID == nID)) myStatus = Active; 00098 tmInfo[nID].nodeP = 0; 00099 myMutex.UnLock(); 00100 } 00101 00102 /******************************************************************************/ 00103 /* R e g i s t e r */ 00104 /******************************************************************************/ 00105 00106 int XrdCmsManTree::Register() 00107 { 00108 int nID; 00109 00110 // Add this server to the tree table. Register is called only once and there 00111 // can be no more than MTMax connections to a manager. Hence, we dispense with 00112 // error checking (how optimistic :-) 00113 // 00114 myMutex.Lock(); 00115 tmInfo[maxTMI].Status= Active; 00116 nID = maxTMI; maxTMI++; 00117 myMutex.UnLock(); 00118 return nID; 00119 } 00120 00121 /******************************************************************************/ 00122 /* s e t M a x C o n */ 00123 /******************************************************************************/ 00124 00125 void XrdCmsManTree::setMaxCon(int n) 00126 { 00127 maxConn = n; 00128 snprintf(buff, sizeof(buff), "%d", n); 00129 } 00130 00131 /******************************************************************************/ 00132 /* T r y i n g */ 00133 /******************************************************************************/ 00134 00135 // This method arranges server connections to a manager to form a minimal B-Tree 00136 // free of phantom arcs. The rule is simple, either all connections are to the 00137 // root of tree or there is only one connection to an interior node. Because 00138 // node discovery is non-determinstic, we must make sure that all root nodes 00139 // are tried so as to discover the full set of supervisor nodes we can contact. 00140 // This method returns True if the caller may continue at the indicated level 00141 // and False if the caller should restart at the root node. 00142 // 00143 int XrdCmsManTree::Trying(int nID, int lvl) 00144 { 00145 int i; 00146 00147 // Set the current status of the connection 00148 // 00149 myMutex.Lock(); 00150 tmInfo[nID].Level = lvl; 00151 00152 // Rule 1: If we are already connected at level >0 then the caller must wait 00153 // 00154 if (myStatus == Connected && conLevel > 0) 00155 {Pause(nID); 00156 return (lvl == tmInfo[nID].Level); 00157 } 00158 00159 // Rule 2: If the caller is trying level 0 then any waiting threads must be 00160 // allowed to continue but forced to level 0. This allows us to discover 00161 // all the supervisors connected to the root. 00162 // 00163 if (!lvl) 00164 {if (numWaiting) 00165 for (i = 0; i < maxTMI; i++) 00166 if (i != nID && tmInfo[i].Status == Waiting) 00167 {tmInfo[i].Level = 0; Redrive(i);} 00168 myMutex.UnLock(); 00169 return 1; 00170 } 00171 00172 // Rule 3: If the caller is trying at a non-zero level (interior node) and 00173 // someone else is trying at a non-zero level, then the caller must 00174 // wait. 00175 // 00176 for (i = 0; i < maxTMI; i++) 00177 if (i != nID && tmInfo[i].Status == Active && tmInfo[i].Level) break; 00178 if (i < maxTMI) Pause(nID); 00179 else myMutex.UnLock(); 00180 00181 // The caller may continue. Indicate whether the caller must restart at the 00182 // root node. If the caller may continue trying to connect to an interior 00183 // node then it's the only thread trying to do so. 00184 // 00185 return (lvl == tmInfo[nID].Level); 00186 }