1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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; version 2 of the License.
6 
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11 
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
15 
16 #include <my_global.h>
17 
18 #include <my_sys.h>
19 #include <my_pthread.h>
20 #include "mysql.h"
21 #include <my_getopt.h>
22 
23 static my_bool version, verbose, tty_password= 0;
24 static uint thread_count,number_of_tests=1000,number_of_threads=2;
25 static pthread_cond_t COND_thread_count;
26 static pthread_mutex_t LOCK_thread_count;
27 
28 static char *database,*host,*user,*password,*unix_socket,*query;
29 uint tcp_port;
30 
31 #ifndef __WIN__
32 void *test_thread(void *arg __attribute__((unused)))
33 #else
34 unsigned __stdcall test_thread(void *arg __attribute__((unused)))
35 #endif
36 {
37   MYSQL *mysql;
38   uint count;
39 
40   mysql=mysql_init(NULL);
41   if (!mysql_real_connect(mysql,host,user,password,database,tcp_port,
42 			  unix_socket,0))
43   {
44     fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(mysql));
45     perror("");
46     goto end;
47   }
48   mysql.reconnect= 1;
49   if (verbose) { putchar('*'); fflush(stdout); }
50   for (count=0 ; count < number_of_tests ; count++)
51   {
52     MYSQL_RES *res;
53     if (mysql_query(mysql,query))
54     {
55       fprintf(stderr,"Query failed (%s)\n",mysql_error(mysql));
56       goto end;
57     }
58     if (!(res=mysql_store_result(mysql)))
59     {
60       fprintf(stderr,"Couldn't get result from %s\n", mysql_error(mysql));
61       goto end;
62     }
63     mysql_free_result(res);
64     if (verbose) { putchar('.'); fflush(stdout); }
65   }
66 end:
67   if (verbose) { putchar('#'); fflush(stdout); }
68   mysql_close(mysql);
69   pthread_mutex_lock(&LOCK_thread_count);
70   thread_count--;
71   pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
72   pthread_mutex_unlock(&LOCK_thread_count);
73   pthread_exit(0);
74   return 0;
75 }
76 
77 
78 static struct my_option my_long_options[] =
79 {
80   {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
81    0, 0, 0, 0, 0},
82   {"database", 'D', "Database to use", &database, &database,
83    0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
84   {"host", 'h', "Connect to host", &host, &host, 0, GET_STR,
85    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86   {"password", 'p',
87    "Password to use when connecting to server. If password is not given it's asked from the tty.",
88    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
89   {"user", 'u', "User for login if not current user", &user,
90    &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
91   {"version", 'V', "Output version information and exit",
92    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
93   {"verbose", 'v', "Write some progress indicators", &verbose,
94    &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
95   {"query", 'Q', "Query to execute in each threads", &query,
96    &query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
97   {"port", 'P', "Port number to use for connection or 0 for default to, in "
98    "order of preference, my.cnf, $MYSQL_TCP_PORT, "
99 #if MYSQL_PORT_DEFAULT == 0
100    "/etc/services, "
101 #endif
102    "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
103    &tcp_port,
104    &tcp_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0},
105   {"socket", 'S', "Socket file to use for connection", &unix_socket,
106    &unix_socket, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
107   {"test-count", 'c', "Run test count times (default %d)",
108    &number_of_tests, &number_of_tests, 0, GET_UINT,
109    REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
110   {"thread-count", 't', "Number of threads to start",
111    &number_of_threads, &number_of_threads, 0, GET_UINT,
112    REQUIRED_ARG, 2, 0, 0, 0, 0, 0},
113   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
114 };
115 
116 
117 static const char *load_default_groups[]=
118 { "client", "client-server", "client-mariadb", 0 };
119 
120 static void usage()
121 {
122   printf("Connection to a mysql server with multiple threads\n");
123   if (version)
124     return;
125   puts("This software comes with ABSOLUTELY NO WARRANTY.\n");
126   printf("Usage: %s [OPTIONS] [database]\n", my_progname);
127 
128   my_print_help(my_long_options);
129   print_defaults("my",load_default_groups);
130   my_print_variables(my_long_options);
131   printf("\nExample usage:\n\n\
132 %s -Q 'select * from mysql.user' -c %d -t %d\n",
133 	 my_progname, number_of_tests, number_of_threads);
134 }
135 
136 
137 static my_bool
138 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
139 	       char *argument)
140 {
141   switch (optid) {
142   case 'p':
143     if (argument)
144     {
145       my_free(password);
146       password= my_strdup(argument, MYF(MY_FAE));
147       while (*argument) *argument++= 'x';		/* Destroy argument */
148     }
149     else
150       tty_password= 1;
151     break;
152   case 'V':
153     version= 1;
154     usage();
155     exit(0);
156     break;
157   case '?':
158   case 'I':					/* Info */
159     usage();
160     exit(1);
161     break;
162   }
163   return 0;
164 }
165 
166 
167 static void get_options(int argc, char **argv)
168 {
169   int ho_error;
170 
171   load_defaults_or_exit("my", load_default_groups, &argc, &argv);
172   if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option)))
173     exit(ho_error);
174 
175   free_defaults(argv);
176   if (tty_password)
177     password=get_tty_password(NullS);
178   return;
179 }
180 
181 
182 int main(int argc, char **argv)
183 {
184   pthread_t tid;
185   pthread_attr_t thr_attr;
186   uint i;
187   int error;
188   MY_INIT(argv[0]);
189   get_options(argc,argv);
190 
191   if ((error=pthread_cond_init(&COND_thread_count,NULL)))
192   {
193     fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
194 	    error,errno);
195     exit(1);
196   }
197   pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
198 
199   if ((error=pthread_attr_init(&thr_attr)))
200   {
201     fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
202 	    error,errno);
203     exit(1);
204   }
205   if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
206   {
207     fprintf(stderr,
208 	    "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
209 	    error,errno);
210     exit(1);
211   }
212 
213   printf("Init ok. Creating %d threads\n",number_of_threads);
214   for (i=1 ; i <= number_of_threads ; i++)
215   {
216     int *param= &i;
217 
218     if (verbose) { putchar('+'); fflush(stdout); }
219     pthread_mutex_lock(&LOCK_thread_count);
220     if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
221     {
222       fprintf(stderr,"\nGot error: %d from pthread_create (errno: %d) when creating thread: %i\n",
223 	      error,errno,i);
224       pthread_mutex_unlock(&LOCK_thread_count);
225       exit(1);
226     }
227     thread_count++;
228     pthread_mutex_unlock(&LOCK_thread_count);
229   }
230 
231   printf("Waiting for threads to finnish\n");
232   error=pthread_mutex_lock(&LOCK_thread_count);
233   while (thread_count)
234   {
235     if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
236       fprintf(stderr,"\nGot error: %d from pthread_cond_wait\n",error);
237   }
238   pthread_mutex_unlock(&LOCK_thread_count);
239   pthread_attr_destroy(&thr_attr);
240   printf("\nend\n");
241 
242   my_end(0);
243   return 0;
244 
245   exit(0);
246   return 0;					/* Keep some compilers happy */
247 }
248 
249