MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbMgmd.hpp
1 /* Copyright (C) 2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
2  All rights reserved. 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 #ifndef NDB_MGMD_HPP
18 #define NDB_MGMD_HPP
19 
20 #include <mgmapi.h>
21 #include <mgmapi_internal.h>
22 
23 #include <BaseString.hpp>
24 #include <Properties.hpp>
25 
26 #include <OutputStream.hpp>
27 #include <SocketInputStream2.hpp>
28 
29 #include "../../src/mgmsrv/Config.hpp"
30 
31 class NdbMgmd {
32  BaseString m_connect_str;
33  NdbMgmHandle m_handle;
34  Uint32 m_nodeid;
35  bool m_verbose;
36  unsigned int m_timeout;
37  void error(const char* msg, ...) ATTRIBUTE_FORMAT(printf, 2, 3)
38  {
39  if (!m_verbose)
40  return;
41 
42  va_list args;
43  printf("NdbMgmd::");
44  va_start(args, msg);
45  vprintf(msg, args);
46  va_end(args);
47  printf("\n");
48 
49  if (m_handle){
50  ndbout_c(" error: %d, line: %d, desc: %s",
51  ndb_mgm_get_latest_error(m_handle),
54  }
55  }
56 public:
57  NdbMgmd() :
58  m_handle(NULL), m_nodeid(0), m_verbose(true), m_timeout(0)
59  {
60  const char* connect_string= getenv("NDB_CONNECTSTRING");
61  if (connect_string)
62  m_connect_str.assign(connect_string);
63  }
64 
65  ~NdbMgmd()
66  {
67  close();
68  }
69 
70  void close(void)
71  {
72  if (m_handle)
73  {
74  ndb_mgm_disconnect_quiet(m_handle);
75  ndb_mgm_destroy_handle(&m_handle);
76  m_handle = NULL;
77  }
78  }
79 
80  NdbMgmHandle handle(void) const {
81  return m_handle;
82  }
83 
84  NDB_SOCKET_TYPE socket(void) const {
85  return _ndb_mgm_get_socket(m_handle);
86  }
87 
88  NodeId nodeid(void) const {
89  return m_nodeid;
90  }
91 
92  const char* getConnectString() const {
93  return m_connect_str.c_str();
94  }
95 
96  void setConnectString(const char* connect_str) {
97  m_connect_str.assign(connect_str);
98  }
99 
100  bool set_timeout(unsigned int timeout) {
101  m_timeout = timeout;
102  if (m_handle &&
103  ndb_mgm_set_timeout(m_handle, timeout) != 0)
104  {
105  error("set_timeout: failed to set timeout on handle");
106  return false;
107  }
108  return true;
109  }
110 
111  void verbose(bool yes = true){
112  m_verbose= yes;
113  }
114 
115  int last_error(void) const {
116  return ndb_mgm_get_latest_error(m_handle);
117  }
118 
119  const char* last_error_message(void) const {
120  return ndb_mgm_get_latest_error_desc(m_handle);
121  }
122 
123  bool connect(const char* connect_string = NULL,
124  int num_retries = 0, int retry_delay_in_seconds = 0) {
125  assert(m_handle == NULL);
126  m_handle= ndb_mgm_create_handle();
127  if (!m_handle){
128  error("connect: ndb_mgm_create_handle failed");
129  return false;
130  }
131 
132  if (ndb_mgm_set_connectstring(m_handle,
133  connect_string ?
134  connect_string : getConnectString()) != 0){
135  error("connect: ndb_mgm_set_connectstring failed");
136  return false;
137  }
138 
139  if (m_timeout > 0 &&
140  ndb_mgm_set_timeout(m_handle, m_timeout) != 0){
141  error("connect: ndb_mgm_set_timeout failed");
142  return false;
143  }
144 
145  if (ndb_mgm_connect(m_handle,num_retries,retry_delay_in_seconds,0) != 0){
146  error("connect: ndb_mgm_connect failed");
147  return false;
148  }
149 
150  // Handshake with the server to make sure it's really there
151  int major, minor, build;
152  char buf[16];
153  if (ndb_mgm_get_version(m_handle, &major, &minor, &build,
154  sizeof(buf), buf) != 1)
155  {
156  error("connect: ndb_get_version failed");
157  return false;
158  }
159  //printf("connected to ndb_mgmd version %d.%d.%d\n",
160  // major, minor, build);
161 
162  if ((m_nodeid = ndb_mgm_get_mgmd_nodeid(m_handle)) == 0){
163  error("connect: could not get nodeid of connected mgmd");
164  return false;
165  }
166 
167  return true;
168  }
169 
170  bool is_connected(void) {
171  if (!m_handle){
172  error("is_connected: no handle");
173  return false;
174  }
175  if (!ndb_mgm_is_connected(m_handle)){
176  error("is_connected: not connected");
177  return false;
178  }
179  return true;
180  }
181 
182  bool disconnect(void) {
183  if (ndb_mgm_disconnect(m_handle) != 0){
184  error("disconnect: ndb_mgm_disconnect failed");
185  return false;
186  }
187 
188  ndb_mgm_destroy_handle(&m_handle);
189  m_handle = NULL;
190 
191  return true;
192  }
193 
194  bool restart(bool abort = false) {
195  if (!is_connected()){
196  error("restart: not connected");
197  return false;
198  }
199 
200  int disconnect= 0;
201  int node_list= m_nodeid;
202  int restarted= ndb_mgm_restart3(m_handle,
203  1,
204  &node_list,
205  false, /* initial */
206  false, /* nostart */
207  abort,
208  &disconnect);
209 
210  if (restarted != 1){
211  error("restart: failed to restart node %d, restarted: %d",
212  m_nodeid, restarted);
213  return false;
214  }
215  return true;
216  }
217 
218  bool call(const char* cmd, const Properties& args,
219  const char* cmd_reply, Properties& reply,
220  const char* bulk = NULL,
221  bool name_value_pairs = true){
222 
223  if (!is_connected()){
224  error("call: not connected");
225  return false;
226  }
227 
228  SocketOutputStream out(socket());
229 
230  if (out.println(cmd)){
231  error("call: println failed at line %d", __LINE__);
232  return false;
233  }
234 
235  Properties::Iterator iter(&args);
236  const char *name;
237  while((name = iter.next()) != NULL) {
238  PropertiesType t;
239  Uint32 val_i;
240  Uint64 val_64;
241  BaseString val_s;
242 
243  args.getTypeOf(name, &t);
244  switch(t) {
245  case PropertiesType_Uint32:
246  args.get(name, &val_i);
247  if (out.println("%s: %d", name, val_i)){
248  error("call: println failed at line %d", __LINE__);
249  return false;
250  }
251  break;
252  case PropertiesType_Uint64:
253  args.get(name, &val_64);
254  if (out.println("%s: %Ld", name, val_64)){
255  error("call: println failed at line %d", __LINE__);
256  return false;
257  }
258  break;
259  case PropertiesType_char:
260  args.get(name, val_s);
261  if (out.println("%s: %s", name, val_s.c_str())){
262  error("call: println failed at line %d", __LINE__);
263  return false;
264  }
265  break;
266  default:
267  case PropertiesType_Properties:
268  /* Illegal */
269  abort();
270  break;
271  }
272  }
273 
274  // Emtpy line terminates argument list
275  if (out.print("\n")){
276  error("call: print('\n') failed at line %d", __LINE__);
277  return false;
278  }
279 
280  // Send any bulk data
281  if (bulk && out.println(bulk)){
282  error("call: print('<bulk>') failed at line %d", __LINE__);
283  return false;
284  }
285 
286  BaseString buf;
287  SocketInputStream2 in(socket());
288  if (cmd_reply)
289  {
290  // Read the reply header and compare against "cmd_reply"
291  if (!in.gets(buf)){
292  error("call: could not read reply command");
293  return false;
294  }
295 
296  // 1. Check correct reply header
297  if (buf != cmd_reply){
298  error("call: unexpected reply command, expected: '%s', got '%s'",
299  cmd_reply, buf.c_str());
300  return false;
301  }
302  }
303 
304  // 2. Read lines until empty line
305  int line = 1;
306  while(in.gets(buf)){
307 
308  // empty line -> end of reply
309  if (buf == "")
310  return true;
311 
312  if (name_value_pairs)
313  {
314  // 3a. Read colon separated name value pair, split
315  // the name value pair on first ':'
316  Vector<BaseString> name_value_pair;
317  if (buf.split(name_value_pair, ":", 2) != 2){
318  error("call: illegal name value pair '%s' received", buf.c_str());
319  return false;
320  }
321 
322  reply.put(name_value_pair[0].trim(" ").c_str(),
323  name_value_pair[1].trim(" ").c_str());
324  }
325  else
326  {
327  // 3b. Not name value pair, save the line into "reply"
328  // using unique key
329  reply.put("line", line++, buf.c_str());
330  }
331  }
332 
333  error("call: should never come here");
334  reply.print();
335  abort();
336  return false;
337  }
338 
339 
340  bool get_config(Config& config){
341 
342  if (!is_connected()){
343  error("get_config: not connected");
344  return false;
345  }
346 
347  struct ndb_mgm_configuration* conf =
348  ndb_mgm_get_configuration(m_handle,0);
349  if (!conf) {
350  error("get_config: ndb_mgm_get_configuration failed");
351  return false;
352  }
353 
354  config.m_configValues= conf;
355  return true;
356  }
357 
358  bool set_config(Config& config){
359 
360  if (!is_connected()){
361  error("set_config: not connected");
362  return false;
363  }
364 
365  if (ndb_mgm_set_configuration(m_handle,
366  config.values()) != 0)
367  {
368  error("set_config: ndb_mgm_set_configuration failed");
369  return false;
370  }
371  return true;
372  }
373 
374  bool end_session(void){
375  if (!is_connected()){
376  error("end_session: not connected");
377  return false;
378  }
379 
380  if (ndb_mgm_end_session(m_handle) != 0){
381  error("end_session: ndb_mgm_end_session failed");
382  return false;
383  }
384  return true;
385  }
386 
387  // Pretty printer for 'ndb_mgm_node_type'
388  class NodeType {
389  BaseString m_str;
390  public:
391  NodeType(Uint32 node_type) {
392  const char* str= NULL;
393  const char* alias=
395  m_str.assfmt("%s(%s)", alias, str);
396  }
397 
398  const char* c_str() { return m_str.c_str(); }
399  };
400 };
401 
402 #endif