1 /*
2    Copyright (c) 2008, 2021, Oracle and/or its affiliates.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <AtrtClient.hpp>
26 #include <NDBT_Output.hpp>
27 #include <NdbSleep.h>
28 #include <NdbEnv.h>
29 
AtrtClient(const char * _group_suffix)30 AtrtClient::AtrtClient(const char* _group_suffix)
31   : DbUtil("atrt", _group_suffix)
32 {
33 }
34 
35 
AtrtClient(MYSQL * mysql)36 AtrtClient::AtrtClient(MYSQL* mysql)
37   : DbUtil(mysql)
38 {
39 }
40 
41 
~AtrtClient()42 AtrtClient::~AtrtClient(){
43 }
44 
45 
46 int
writeCommand(AtrtCommandType _type,const Properties & args)47 AtrtClient::writeCommand(AtrtCommandType _type,
48                          const Properties& args){
49   if (!isConnected())
50     return false;
51 
52   BaseString sql;
53   sql.assfmt("INSERT  command ( ");
54 
55   const char* name;
56   {
57     Properties::Iterator iter(&args);
58     while((name= iter.next())){
59       sql.appfmt("%s, ", name);
60     }
61   }
62 
63   sql.appfmt(" state, cmd) VALUES (");
64 
65   {
66     Properties::Iterator iter(&args);
67     while((name= iter.next())){
68       PropertiesType t;
69       Uint32 val_i;
70       BaseString val_s;
71       args.getTypeOf(name, &t);
72       switch(t) {
73       case PropertiesType_Uint32:
74         args.get(name, &val_i);
75         sql.appfmt("%d, ", val_i);
76         break;
77       case PropertiesType_char:
78         args.get(name, val_s);
79         sql.appfmt("'%s', ", val_s.c_str());
80         break;
81       default:
82         require(false);
83         break;
84       }
85     }
86   }
87 
88   sql.appfmt("'new', %d)", _type);
89   if (!doQuery(sql)){
90     return -1;
91   }
92 
93   return (int)mysql_insert_id(m_mysql);
94 }
95 
96 
97 bool
readCommand(uint command_id,SqlResultSet & result)98 AtrtClient::readCommand(uint command_id,
99                         SqlResultSet& result){
100   Properties args;
101   args.put("0", command_id);
102   return runQuery("SELECT * FROM command WHERE id = ?",
103                   args,
104                   result);
105 }
106 
107 
108 bool
doCommand(AtrtCommandType type,const Properties & args)109 AtrtClient::doCommand(AtrtCommandType type,
110                       const Properties& args){
111 
112   int running_timeout= 10;
113   int total_timeout= 120;
114   int commandId= writeCommand(type,
115                               args);
116   if (commandId == -1){
117     g_err << "Failed to write command" << endl;
118     return false;
119   }
120 
121   while (true){
122 
123     SqlResultSet result;
124     if (!readCommand(commandId, result))
125     {
126       result.print();
127       g_err << "Failed to read command "<< commandId << endl;
128       return false;
129     }
130 
131     // Get first row
132     result.next();
133 
134     // Check if command has completed
135     BaseString state(result.column("state"));
136     if (state == "done") {
137       return true;
138     }
139 
140     if (state == "new"){
141       if (!running_timeout--){
142         g_err << "Timeout while waiting for command "
143               << commandId << " to start run" << endl;
144         return false;
145       }
146     }
147     else if (!total_timeout--){
148       g_err << "Timeout while waiting for result of command "
149             << commandId << endl;
150       return false;
151     }
152 
153 
154     NdbSleep_SecSleep(1);
155   }
156 
157   return false;
158 }
159 
160 
161 bool
changeVersion(int process_id,const char * process_args)162 AtrtClient::changeVersion(int process_id,
163                           const char* process_args){
164   Properties args;
165   args.put("process_id", process_id);
166   args.put("process_args", process_args);
167   return doCommand(ATCT_CHANGE_VERSION, args);
168 }
169 
170 
171 bool
resetProc(int process_id)172 AtrtClient::resetProc(int process_id){
173   Properties args;
174   args.put("process_id", process_id);
175   return doCommand(ATCT_RESET_PROC, args);
176 }
177 
178 
179 bool
getConnectString(int cluster_id,SqlResultSet & result)180 AtrtClient::getConnectString(int cluster_id, SqlResultSet& result){
181   Properties args;
182   args.put("0", cluster_id);
183   return doQuery("SELECT value as connectstring " \
184                  "FROM cluster c, process p, host h, options o "    \
185                  "WHERE c.id=p.cluster_id AND p.host_id=h.id AND "  \
186                  "p.id=o.process_id AND c.id=? AND "                    \
187                  "o.name='--ndb-connectstring=' AND type='ndb_mgmd'",
188                  args,
189                  result);
190 }
191 
192 
193 bool
getClusters(SqlResultSet & result)194 AtrtClient::getClusters(SqlResultSet& result){
195   Properties args;
196   return runQuery("SELECT id, name FROM cluster WHERE name != '.atrt'",
197                   args,
198                   result);
199 }
200 
201 
202 bool
getMgmds(int cluster_id,SqlResultSet & result)203 AtrtClient::getMgmds(int cluster_id, SqlResultSet& result){
204   Properties args;
205   args.put("0", cluster_id);
206   return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndb_mgmd'",
207                   args,
208                   result);
209 }
210 
211 bool
getNdbds(int cluster_id,SqlResultSet & result)212 AtrtClient::getNdbds(int cluster_id, SqlResultSet& result){
213   Properties args;
214   args.put("0", cluster_id);
215   return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndbd'",
216                   args,
217                   result);
218 }
219 
220 int
getOwnProcessId()221 AtrtClient::getOwnProcessId()
222 {
223   /**
224    * Put in env for simplicity
225    */
226   char buf[100];
227   if (NdbEnv_GetEnv("ATRT_PID", buf, sizeof(buf)))
228   {
229     return atoi(buf);
230   }
231   return -1;
232 }
233