1 /* Copyright (c) 2003-2006 MySQL AB
2    Use is subject to license terms
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include <ndb_global.h>
18 #include <ndb_opt_defaults.h>
19 #include <IPCConfig.hpp>
20 #include <NdbOut.hpp>
21 #include <NdbHost.h>
22 
23 #include <TransporterDefinitions.hpp>
24 #include <TransporterRegistry.hpp>
25 #include <Properties.hpp>
26 
27 #include <mgmapi_configuration.hpp>
28 #include <mgmapi_config_parameters.h>
29 
30 #if defined DEBUG_TRANSPORTER
31 #define DEBUG(t) ndbout << __FILE__ << ":" << __LINE__ << ":" << t << endl;
32 #else
33 #define DEBUG(t)
34 #endif
35 
IPCConfig(Properties * p)36 IPCConfig::IPCConfig(Properties * p)
37 {
38   theNoOfRemoteNodes = 0;
39   the_ownId = 0;
40   if(p != 0)
41     props = new Properties(* p);
42   else
43     props = 0;
44 }
45 
46 
~IPCConfig()47 IPCConfig::~IPCConfig()
48 {
49   if(props != 0){
50     delete props;
51   }
52 }
53 
54 int
init()55 IPCConfig::init(){
56   Uint32 nodeId;
57 
58   if(props == 0) return -1;
59   if(!props->get("LocalNodeId", &nodeId)) {
60     DEBUG( "Did not find local node id." );
61     return -1;
62   }
63   the_ownId = nodeId;
64 
65   Uint32 noOfConnections;
66   if(!props->get("NoOfConnections", &noOfConnections)) {
67     DEBUG( "Did not find noOfConnections." );
68     return -1;
69   }
70 
71   for(Uint32 i = 0; i<noOfConnections; i++){
72     const Properties * tmp;
73     Uint32 node1, node2;
74 
75     if(!props->get("Connection", i, &tmp)) {
76       DEBUG( "Did not find Connection." );
77       return -1;
78     }
79     if(!tmp->get("NodeId1", &node1)) {
80       DEBUG( "Did not find NodeId1." );
81       return -1;
82     }
83     if(!tmp->get("NodeId2", &node2)) {
84       DEBUG( "Did not find NodeId2." );
85       return -1;
86     }
87 
88     if(node1 == the_ownId && node2 != the_ownId)
89       if(!addRemoteNodeId(node2)) {
90 	DEBUG( "addRemoteNodeId(node2) failed." );
91 	return -1;
92       }
93 
94     if(node1 != the_ownId && node2 == the_ownId)
95       if(!addRemoteNodeId(node1)) {
96 	DEBUG( "addRemoteNodeId(node2) failed." );
97 	return -1;
98       }
99   }
100   return 0;
101 }
102 
103 bool
addRemoteNodeId(NodeId nodeId)104 IPCConfig::addRemoteNodeId(NodeId nodeId){
105   for(int i = 0; i<theNoOfRemoteNodes; i++)
106     if(theRemoteNodeIds[i] == nodeId)
107       return false;
108   theRemoteNodeIds[theNoOfRemoteNodes] = nodeId;
109   theNoOfRemoteNodes++;
110   return true;
111 }
112 
113 /**
114  * Supply a nodeId,
115  *  and get next higher node id
116  * Returns false if none found
117  */
118 bool
getNextRemoteNodeId(NodeId & nodeId) const119 IPCConfig::getNextRemoteNodeId(NodeId & nodeId) const {
120   NodeId returnNode = MAX_NODES + 1;
121   for(int i = 0; i<theNoOfRemoteNodes; i++)
122     if(theRemoteNodeIds[i] > nodeId){
123       if(theRemoteNodeIds[i] < returnNode){
124 	returnNode = theRemoteNodeIds[i];
125       }
126     }
127   if(returnNode == (MAX_NODES + 1))
128     return false;
129   nodeId = returnNode;
130   return true;
131 }
132 
133 
134 Uint32
getREPHBFrequency(NodeId id) const135 IPCConfig::getREPHBFrequency(NodeId id) const {
136   const Properties * tmp;
137   Uint32 out;
138 
139   /**
140    *  Todo: Fix correct heartbeat
141    */
142   if (!props->get("Node", id, &tmp) ||
143       !tmp->get("HeartbeatIntervalRepRep", &out)) {
144     DEBUG("Illegal Node or HeartbeatIntervalRepRep in config.");
145     out = 10000;
146   }
147 
148   return out;
149 }
150 
151 const char*
getNodeType(NodeId id) const152 IPCConfig::getNodeType(NodeId id) const {
153   const char * out;
154   const Properties * tmp;
155 
156   if (!props->get("Node", id, &tmp) || !tmp->get("Type", &out)) {
157     DEBUG("Illegal Node or NodeType in config.");
158     out = "Unknown";
159   }
160 
161   return out;
162 }
163 
164 #include <mgmapi.h>
165 Uint32
configureTransporters(Uint32 nodeId,const class ndb_mgm_configuration & config,class TransporterRegistry & tr)166 IPCConfig::configureTransporters(Uint32 nodeId,
167 				 const class ndb_mgm_configuration & config,
168 				 class TransporterRegistry & tr){
169   TransporterConfiguration conf;
170 
171   DBUG_ENTER("IPCConfig::configureTransporters");
172 
173   /**
174    * Iterate over all MGM's an construct a connectstring
175    * create mgm_handle and give it to the Transporter Registry
176    */
177   {
178     const char *separator= "";
179     BaseString connect_string;
180     ndb_mgm_configuration_iterator iter(config, CFG_SECTION_NODE);
181     for(iter.first(); iter.valid(); iter.next())
182     {
183       Uint32 type;
184       if(iter.get(CFG_TYPE_OF_SECTION, &type)) continue;
185       if(type != NODE_TYPE_MGM) continue;
186       const char* hostname;
187       Uint32 port;
188       if(iter.get(CFG_NODE_HOST, &hostname)) continue;
189       if( strlen(hostname) == 0 ) continue;
190       if(iter.get(CFG_MGM_PORT, &port)) continue;
191       connect_string.appfmt("%s%s:%u",separator,hostname,port);
192       separator= ",";
193     }
194     NdbMgmHandle h= ndb_mgm_create_handle();
195     if ( h && connect_string.length() > 0 )
196     {
197       ndb_mgm_set_connectstring(h,connect_string.c_str());
198       tr.set_mgm_handle(h);
199     }
200   }
201 
202   Uint32 noOfTransportersCreated= 0;
203   ndb_mgm_configuration_iterator iter(config, CFG_SECTION_CONNECTION);
204 
205   for(iter.first(); iter.valid(); iter.next()){
206 
207     Uint32 nodeId1, nodeId2, remoteNodeId;
208     const char * remoteHostName= 0, * localHostName= 0;
209     if(iter.get(CFG_CONNECTION_NODE_1, &nodeId1)) continue;
210     if(iter.get(CFG_CONNECTION_NODE_2, &nodeId2)) continue;
211 
212     if(nodeId1 != nodeId && nodeId2 != nodeId) continue;
213     remoteNodeId = (nodeId == nodeId1 ? nodeId2 : nodeId1);
214 
215     {
216       const char * host1= 0, * host2= 0;
217       iter.get(CFG_CONNECTION_HOSTNAME_1, &host1);
218       iter.get(CFG_CONNECTION_HOSTNAME_2, &host2);
219       localHostName  = (nodeId == nodeId1 ? host1 : host2);
220       remoteHostName = (nodeId == nodeId1 ? host2 : host1);
221     }
222 
223     Uint32 sendSignalId = 1;
224     Uint32 checksum = 1;
225     if(iter.get(CFG_CONNECTION_SEND_SIGNAL_ID, &sendSignalId)) continue;
226     if(iter.get(CFG_CONNECTION_CHECKSUM, &checksum)) continue;
227 
228     Uint32 type = ~0;
229     if(iter.get(CFG_TYPE_OF_SECTION, &type)) continue;
230 
231     Uint32 server_port= 0;
232     if(iter.get(CFG_CONNECTION_SERVER_PORT, &server_port)) break;
233 
234     Uint32 nodeIdServer= 0;
235     if(iter.get(CFG_CONNECTION_NODE_ID_SERVER, &nodeIdServer)) break;
236 
237     /*
238       We check the node type.
239     */
240     Uint32 node1type, node2type;
241     ndb_mgm_configuration_iterator node1iter(config, CFG_SECTION_NODE);
242     ndb_mgm_configuration_iterator node2iter(config, CFG_SECTION_NODE);
243     node1iter.find(CFG_NODE_ID,nodeId1);
244     node2iter.find(CFG_NODE_ID,nodeId2);
245     node1iter.get(CFG_TYPE_OF_SECTION,&node1type);
246     node2iter.get(CFG_TYPE_OF_SECTION,&node2type);
247 
248     if(node1type==NODE_TYPE_MGM || node2type==NODE_TYPE_MGM)
249       conf.isMgmConnection= true;
250     else
251       conf.isMgmConnection= false;
252 
253     if (nodeId == nodeIdServer && !conf.isMgmConnection) {
254       tr.add_transporter_interface(remoteNodeId, localHostName, server_port);
255     }
256 
257     DBUG_PRINT("info", ("Transporter between this node %d and node %d using port %d, signalId %d, checksum %d",
258                nodeId, remoteNodeId, server_port, sendSignalId, checksum));
259     /*
260       This may be a dynamic port. It depends on when we're getting
261       our configuration. If we've been restarted, we'll be getting
262       a configuration with our old dynamic port in it, hence the number
263       here is negative (and we try the old port number first).
264 
265       On a first-run, server_port will be zero (with dynamic ports)
266 
267       If we're not using dynamic ports, we don't do anything.
268     */
269 
270     conf.localNodeId    = nodeId;
271     conf.remoteNodeId   = remoteNodeId;
272     conf.checksum       = checksum;
273     conf.signalId       = sendSignalId;
274     conf.s_port         = server_port;
275     conf.localHostName  = localHostName;
276     conf.remoteHostName = remoteHostName;
277     conf.serverNodeId   = nodeIdServer;
278 
279     switch(type){
280     case CONNECTION_TYPE_SHM:
281       if(iter.get(CFG_SHM_KEY, &conf.shm.shmKey)) break;
282       if(iter.get(CFG_SHM_BUFFER_MEM, &conf.shm.shmSize)) break;
283 
284       Uint32 tmp;
285       if(iter.get(CFG_SHM_SIGNUM, &tmp)) break;
286       conf.shm.signum= tmp;
287 
288       if(!tr.createSHMTransporter(&conf)){
289         DBUG_PRINT("error", ("Failed to create SHM Transporter from %d to %d",
290 	           conf.localNodeId, conf.remoteNodeId));
291 	ndbout << "Failed to create SHM Transporter from: "
292 	       << conf.localNodeId << " to: " << conf.remoteNodeId << endl;
293       } else {
294 	noOfTransportersCreated++;
295       }
296       DBUG_PRINT("info", ("Created SHM Transporter using shmkey %d, "
297 			  "buf size = %d", conf.shm.shmKey, conf.shm.shmSize));
298 
299       break;
300 
301     case CONNECTION_TYPE_SCI:
302       if(iter.get(CFG_SCI_SEND_LIMIT, &conf.sci.sendLimit)) break;
303       if(iter.get(CFG_SCI_BUFFER_MEM, &conf.sci.bufferSize)) break;
304       if (nodeId == nodeId1) {
305         if(iter.get(CFG_SCI_HOST2_ID_0, &conf.sci.remoteSciNodeId0)) break;
306         if(iter.get(CFG_SCI_HOST2_ID_1, &conf.sci.remoteSciNodeId1)) break;
307       } else {
308         if(iter.get(CFG_SCI_HOST1_ID_0, &conf.sci.remoteSciNodeId0)) break;
309         if(iter.get(CFG_SCI_HOST1_ID_1, &conf.sci.remoteSciNodeId1)) break;
310       }
311       if (conf.sci.remoteSciNodeId1 == 0) {
312         conf.sci.nLocalAdapters = 1;
313       } else {
314         conf.sci.nLocalAdapters = 2;
315       }
316      if(!tr.createSCITransporter(&conf)){
317         DBUG_PRINT("error", ("Failed to create SCI Transporter from %d to %d",
318 	           conf.localNodeId, conf.remoteNodeId));
319 	ndbout << "Failed to create SCI Transporter from: "
320 	       << conf.localNodeId << " to: " << conf.remoteNodeId << endl;
321       } else {
322         DBUG_PRINT("info", ("Created SCI Transporter: Adapters = %d, "
323 			    "remote SCI node id %d",
324                    conf.sci.nLocalAdapters, conf.sci.remoteSciNodeId0));
325         DBUG_PRINT("info", ("Host 1 = %s, Host 2 = %s, sendLimit = %d, "
326 			    "buf size = %d", conf.localHostName,
327 			    conf.remoteHostName, conf.sci.sendLimit,
328 			    conf.sci.bufferSize));
329         if (conf.sci.nLocalAdapters > 1) {
330           DBUG_PRINT("info", ("Fault-tolerant with 2 Remote Adapters, "
331 			      "second remote SCI node id = %d",
332 			      conf.sci.remoteSciNodeId1));
333         }
334 	noOfTransportersCreated++;
335 	continue;
336       }
337      break;
338 
339     case CONNECTION_TYPE_TCP:
340       if(iter.get(CFG_TCP_SEND_BUFFER_SIZE, &conf.tcp.sendBufferSize)) break;
341       if(iter.get(CFG_TCP_RECEIVE_BUFFER_SIZE, &conf.tcp.maxReceiveSize)) break;
342 
343       const char * proxy;
344       if (!iter.get(CFG_TCP_PROXY, &proxy)) {
345 	if (strlen(proxy) > 0 && nodeId2 == nodeId) {
346 	  // TODO handle host:port
347 	  conf.s_port = atoi(proxy);
348 	}
349       }
350 
351       if(!tr.createTCPTransporter(&conf)){
352 	ndbout << "Failed to create TCP Transporter from: "
353 	       << nodeId << " to: " << remoteNodeId << endl;
354       } else {
355 	noOfTransportersCreated++;
356       }
357       DBUG_PRINT("info", ("Created TCP Transporter: sendBufferSize = %d, "
358 			  "maxReceiveSize = %d", conf.tcp.sendBufferSize,
359 			  conf.tcp.maxReceiveSize));
360       break;
361     default:
362       ndbout << "Unknown transporter type from: " << nodeId <<
363 	" to: " << remoteNodeId << endl;
364       break;
365     } // switch
366   } // for
367 
368   DBUG_RETURN(noOfTransportersCreated);
369 }
370 
371