1 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2 of the License, or
6    (at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 
17 #include "../config.h"
18 
19 #include <ctype.h>
20 #include <math.h>
21 
22 #include "die.h"
23 #include "smack.h"
24 #include "engines.h"
25 #include "parse.h"
26 
27 extern int yylineno;
28 
29 map <string, Query*, less<string> > query_pool;
30 map <string, Dictionary*, less<string> > dict_pool;
31 map <string, Client*, less<string> > client_pool;
32 map<string, Val*, less<string> > var_hash;
33 string current_client = "main";
34 vector<int> client_pids;
35 
Query_def_line(string & str)36 Query_def_line::Query_def_line(string& str):str(str)
37 {
38 }
39 
set_q_param(Query * q)40 void Query_name_def_line::set_q_param(Query* q)
41 {
42   q->name = str;
43 }
44 
set_q_param(Query * q)45 void Query_query_def_line::set_q_param(Query* q)
46 {
47   q->query = str;
48 }
49 
set_q_param(Query * q)50 void Query_type_def_line::set_q_param(Query* q)
51 {
52   q->type_name = str;
53 }
54 
set_q_param(Query * q)55 void Query_has_result_set_def_line::set_q_param(Query* q)
56 {
57   q->has_result_set = (tolower(str[0]) == 'y');
58 }
59 
set_q_param(Query * q)60 void Query_parsed_def_line::set_q_param(Query* q)
61 {
62   q->parsed = (tolower(str[0]) == 'y');
63 }
64 
make_dict()65 Dictionary* Dict_def::make_dict()
66 {
67   Dictionary* dict = NULL;
68 
69   if(dict_type == "rand")
70     {
71       dict = new Rand_dictionary;
72     }
73   else if(dict_type == "seq")
74     {
75       dict = new Seq_dictionary;
76     }
77   else if(dict_type == "unique")
78     {
79       dict = new Unique_dictionary;
80     }
81   else
82     die(0, "unknown dictionary type '%s' on line %d", dict_type.c_str(),
83         yylineno);
84 
85   if(file_size_equiv.length())
86     dict->file_size_equiv = atoi(file_size_equiv.c_str());
87   if(delim.length())
88     dict->delim = delim[0];
89 
90   if(source_type == "file")
91     {
92       dict->load_file(source.c_str());
93     }
94   else if(source_type == "list")
95     {
96       dict->load_list(source.c_str());
97     }
98   else if(source_type == "template")
99     {
100       if(!(dict_type == "unique"))
101 	die(0, "line %d: template source type is supported only for \
102 dictionaries of type 'unique'", yylineno);
103       ((Unique_dictionary*)dict)->set_template(source.c_str());
104     }
105   else
106     die(0, "unknown dictionary source type: '%s' on line %d",
107         source_type.c_str(), yylineno);
108 
109   dict->name = name;
110 
111   return dict;
112 }
113 
update_dict_def(Dict_def & d)114 void Dict_dict_type_def_line::update_dict_def(Dict_def& d)
115 {
116   d.dict_type = str;
117 }
118 
update_dict_def(Dict_def & d)119 void Dict_source_type_def_line::update_dict_def(Dict_def& d)
120 {
121   d.source_type = str;
122 }
123 
update_dict_def(Dict_def & d)124 void Dict_source_def_line::update_dict_def(Dict_def& d)
125 {
126   d.source = str;
127 }
128 
update_dict_def(Dict_def & d)129 void Dict_delim_def_line::update_dict_def(Dict_def& d)
130 {
131   d.delim = str;
132 }
133 
update_dict_def(Dict_def & d)134 void Dict_file_size_equiv_def_line::update_dict_def(Dict_def& d)
135 {
136   d.file_size_equiv = str;
137 }
138 
Table_def_line(string & str)139 Table_def_line::Table_def_line(string& str):str(str)
140 {
141 }
142 
validate_table(string & name)143 void Table_def::validate_table(string& name)
144 {
145   Client* c = client_pool[client];
146   if(!c)
147     die(0, "Missing or undefined client in the table section on line %d",
148 	yylineno);
149   Table t;
150   bool do_create = 0, do_drop = 0;
151   int min_rows_lim = atoi(min_rows.c_str());
152   c->connect();
153   t.name = name;
154   if(c->get_table_info(t))
155     {
156       do_create = 1;
157     }
158   else
159     {
160       if(t.num_rows < min_rows_lim)
161 	{
162 	  do_drop = 1;
163 	  do_create = 1;
164 	}
165     }
166 
167   if(do_drop)
168     {
169       cout << "Table '" << name <<
170 	"' does not meet condtions, will be dropped" << endl;
171       string query = "drop table ";
172       query += name;
173       c->safe_query(query.c_str());
174     }
175 
176   if(do_create)
177     {
178       char path[MAX_PATH];
179       const char* file = mk_data_path(path, data_file.c_str());
180       struct stat f;
181       cout << "Creating table '" << name << "'" << endl;
182       c->safe_query(create_st.c_str());
183       if(stat(file, &f) && populate_data_file(file, gen_data_file.c_str()))
184 	die(1, "Error generating data file");
185       cout << "Loading data from file '" << file << "' into table '" << name <<
186 	   "'" << endl;
187       c->load_table_data(name, file);
188       cout << "Table " << name << " is now ready for the test" << endl;
189     }
190 
191   c->disconnect();
192 }
193 
update_table_def(Table_def * t)194 void Table_client_def_line::update_table_def(Table_def* t)
195 {
196   t->client = str;
197 }
198 
update_table_def(Table_def * t)199 void Table_create_def_line::update_table_def(Table_def* t)
200 {
201   t->create_st = str;
202 }
203 
update_table_def(Table_def * t)204 void Table_min_rows_def_line::update_table_def(Table_def* t)
205 {
206   t->min_rows = str;
207 }
208 
update_table_def(Table_def * t)209 void Table_data_file_def_line::update_table_def(Table_def* t)
210 {
211   t->data_file = str;
212 }
213 
update_table_def(Table_def * t)214 void Table_gen_data_file_def_line::update_table_def(Table_def* t)
215 {
216   t->gen_data_file = str;
217 }
218 
219 
make_client()220 Client* Client_def::make_client()
221 {
222   Client* c;
223   c = new_client(db_type);
224   c->user = user;
225   c->pass = pass;
226   c->db = db;
227   c->host = host;
228   c->socket = this->socket;
229   c->port = port;
230 
231   if(qb)
232     c->set_query_barrel(qb);
233 
234   c->set_dictionary_pool(&dict_pool);
235 
236   return c;
237 }
238 
update_client_def(Client_def & cd)239 void Client_query_barrel_def_line::update_client_def(Client_def& cd)
240 {
241   int str_len = str.size();
242   char buf[str_len + 1];
243   int i,j = 0;
244   int last_was_space = 1;
245   int num_shots = 0;
246   enum {NUM_SHOTS, QUERY_NAME,SLEEP_TIME} parse_state = NUM_SHOTS;
247   cd.qb = new Query_barrel;
248 
249   for(i = 0; i < str_len; i++)
250     {
251      if(str[i] == ' ')
252        if(last_was_space)
253          continue;
254        else
255          {
256            last_was_space = 1;
257            buf[j] = 0;
258            j = 0;
259 
260            switch(parse_state)
261              {
262              case NUM_SHOTS:
263 	       if(buf[0] == '-')
264 		 {
265 		   float sl = atof(buf+1);
266 		   int sec,usec;
267 		   sec = (int)floor(sl);
268 		   sl -= sec;
269 		   usec = (int)floor(sl*1000000);
270 		   cd.qb->add_sleep_action(sec,usec);
271 		   break;
272 		 }
273                num_shots = atoi(buf);
274                parse_state = QUERY_NAME;
275                break;
276 
277              case QUERY_NAME:
278                {
279                  Query* q = query_pool[buf];
280                  if(!q)
281                    die(0, "query '%s' referenced on line %d has not \
282 been defined", buf, yylineno);
283                  cd.qb->add_query_charge(*q, num_shots);
284                  parse_state = NUM_SHOTS;
285                  break;
286                }
287              }
288          } // else
289      else
290        {
291          last_was_space = 0;
292          buf[j++] = str[i];
293        }
294 
295     }
296 
297   if(!last_was_space)
298     {
299       buf[j] = 0;
300       if(buf[0] == '-')
301 	{
302 	  float sl = atof(buf+1);
303 	  int sec,usec;
304 	  sec = (int)floor(sl);
305 	  sl -= sec;
306 	  usec = (int)floor(sl*1000000);
307 	  cd.qb->add_sleep_action(sec,usec);
308 	  return;
309 	}
310       Query* q = query_pool[buf];
311       if(!q)
312         die(0, "query '%s' referenced on line %d has not been defined",
313             buf, yylineno);
314        cd.qb->add_query_charge(*q, num_shots);
315     }
316 }
317 
update_client_def(Client_def & cd)318 void Client_user_def_line::update_client_def(Client_def& cd)
319 {
320   cd.user = str;
321 }
322 
update_client_def(Client_def & cd)323 void Client_pass_def_line::update_client_def(Client_def& cd)
324 {
325   cd.pass = str;
326 }
327 
update_client_def(Client_def & cd)328 void Client_host_def_line::update_client_def(Client_def& cd)
329 {
330   cd.host = str;
331 }
332 
update_client_def(Client_def & cd)333 void Client_socket_def_line::update_client_def(Client_def& cd)
334 {
335   cd.socket = str;
336 }
337 
update_client_def(Client_def & cd)338 void Client_port_def_line::update_client_def(Client_def& cd)
339 {
340   cd.port = str;
341 }
342 
343 
update_client_def(Client_def & cd)344 void Client_db_def_line::update_client_def(Client_def& cd)
345 {
346   cd.db = str;
347 }
348 
print()349 void Param_list::print()
350 {
351   if(params.size() > 0)
352     cout << params[0];
353 
354   for(int i = 1; i < params.size(); i++)
355     {
356       cout << "," << params[i];
357     }
358 }
359 
print()360 void Main_line::print()
361 {
362   cout << "main_line: client: " << client << ",method=" << method ;
363   if(param_list)
364     {
365       cout << ",param_list: " ;
366       param_list->print();
367     }
368 
369   cout << endl;
370 }
371 
execute()372 void Main_line::execute()
373 {
374   if(!(client == current_client) && !(method == "init"))
375     return;
376 
377   Client* c = client_pool[client];
378   if(!c)
379     die(0, "client '%s' referenced on line %d is not defined",
380         client.c_str(), yylineno);
381   if(method == "connect")
382     {
383       c->connect();
384     }
385   else if(method == "init")
386     {
387       if(!(current_client == "main")) return;
388       pid_t pid;
389       switch(pid = fork())
390         {
391         case 0:
392           c->init();
393           current_client = client;
394           break;
395         case -1:
396           die(1, "could not fork()");
397           break;
398 
399         default:
400           client_pids.insert(client_pids.end(), pid);
401           break;
402         }
403 
404     }
405   else if(method == "sleep")
406     {
407       if(param_list->size() != 2)
408         die(0, "line %d: sleep takes two parameters (sec,ms), you have %d",
409             yylineno, param_list->size());
410       sleep(atoi(param_list->pchar_val(0)));
411       usleep(atoi(param_list->pchar_val(1))/1000);
412     }
413   else if(method == "print")
414     {
415       if(param_list->size() != 1)
416         die(0, "line %d: print takes one parameter, you have %d",
417             yylineno, param_list->size());
418       cout << param_list->pchar_val(0) << endl;
419     }
420   else if(method == "query")
421     {
422       if(param_list->size() != 1)
423         die(0, "line %d: query takes one parameter, you have %d",
424             yylineno, param_list->size());
425       const char* q = param_list->pchar_val(0);
426       c->safe_query(q);
427     }
428   else if(method == "run_save_result")
429     {
430       if(param_list->size() != 2)
431         die(0, "line %d: run_save_result takes two parameters, you have %d",
432             yylineno, param_list->size());
433       const char* q_name = param_list->pchar_val(0);
434       const char* fname = param_list->pchar_val(1);
435       Query *q = query_pool[q_name];
436 
437       if(!q)
438         die(0, "line %d: query '%s' has not been defined", yylineno,
439             q_name);
440 
441       c->safe_query(*q);
442       if(fname[0] == '-' && !fname[1])
443 	fname = NULL;
444       if(q->has_result_set)
445         c->dump_result(fname);
446 
447     }
448   else if(method == "run_check_result")
449     {
450     }
451   else if(method == "set_num_rounds")
452     {
453       if(param_list->size() != 1)
454         die(0, "line %d: set_num_rounds takes one parameter, you have %d",
455             yylineno, param_list->size());
456       int num_rounds = param_list->int_val(0);
457       c->set_num_rounds(num_rounds);
458     }
459   else if(method == "disconnect")
460     {
461       c->disconnect();
462     }
463   else if(method == "create_threads")
464     {
465       c->start_clock();
466       if(param_list->size() != 1)
467         die(0, "line %d: create_threads takes one parameter, you have %d",
468             yylineno, param_list->size());
469       int num_threads = param_list->int_val(0);
470       c->create_threads(num_threads);
471     }
472   else if(method == "collect_threads")
473     {
474       c->thread_sync();
475       c->stop_clock();
476       cout << "Query Barrel Report for client " << client << endl;
477       c->print_connect_times();
478       c->print_barrel_report();
479     }
480   else if(method == "unload_query_barrel")
481     {
482       c->unload_query_barrel();
483     }
484   else
485     {
486       die(0, "unknown method '%s' called for client '%s' on line %d",
487           method.c_str(), client.c_str(), yylineno);
488     }
489 }
490 
491 
492 
493 
494 
495 
496