1 /* Copyright (c) 2015, 2016, 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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include <my_global.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <mysql_version.h>
27 #include <mysql/plugin.h>
28 #include <my_dir.h>
29 #include "my_sys.h" // my_write, my_malloc
30 #include "m_string.h" // strlen
31 #include "sql_plugin.h" // st_plugin_int
32
33 static const char *log_filename= "test_session_in_thd";
34
35 #define MAX_SESSIONS 500
36
37 #define STRING_BUFFER_SIZE 512
38
39 #define WRITE_STR(format) my_snprintf(buffer,sizeof(buffer),format); \
40 my_write(outfile,(uchar*)buffer,strlen(buffer),MYF(0))
41 #define WRITE_VAL(format,value) my_snprintf(buffer,sizeof(buffer),format,value); \
42 my_write(outfile,(uchar*)buffer,strlen(buffer),MYF(0))
43 static const char *sep = "============================================================================================\n";
44
45 #define WRITE_SEP() my_write(outfile, (uchar*)sep, strlen(sep), MYF(0))
46
47 static File outfile;
48
49 struct test_services_context
50 {
51 my_thread_handle test_services_thread;
52 };
53
54 /* SQL (system) variable to control number of sessions */
55 /* Only effective at start of mysqld by setting it as option --loose-... */
56 int nb_sessions;
57 static MYSQL_SYSVAR_INT (nb_sessions, nb_sessions, PLUGIN_VAR_RQCMDARG,
58 "number of sessions", NULL, NULL, 1, 1, 500, 0);
59
60 static struct st_mysql_sys_var *test_services_sysvars[]= {
61 MYSQL_SYSVAR(nb_sessions),
62 NULL
63 };
64
test_session(void * p)65 static void test_session(void *p)
66 {
67 char buffer[STRING_BUFFER_SIZE];
68 DBUG_ENTER("test_session");
69
70 MYSQL_SESSION sessions[MAX_SESSIONS];
71 bool session_ret= false;
72 void *plugin_ctx= p;
73
74 /* Open session 1: Must pass */
75 for (int i= 0; i < nb_sessions; i++)
76 {
77 WRITE_VAL("sql open session %d.\n", i);
78 sessions[i]= srv_session_open(NULL, plugin_ctx);
79 if (!sessions[i])
80 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_open_%d failed.", i);
81 }
82
83 /* close session 1: Must pass i*/
84 WRITE_VAL("close following nb of sessions: %d\n",nb_sessions);
85 for (int i= 0; i < nb_sessions; i++)
86 {
87 WRITE_VAL("sql session close session %d.\n", nb_sessions-1-i);
88 session_ret= srv_session_close(sessions[nb_sessions-1-i]);
89 if (session_ret)
90 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_close_%d failed.", nb_sessions-1-i);
91 }
92
93 /* Open session 1: Must pass */
94 for (int i= 0; i < nb_sessions; i++)
95 {
96 WRITE_VAL("sql open session %d.\n", i);
97 sessions[i]= srv_session_open(NULL, plugin_ctx);
98 if (!sessions[i])
99 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_open_%d failed.", i);
100 }
101
102 /* close session 1: Must pass */
103 WRITE_VAL("close following nb of sessions: %d\n",nb_sessions);
104 for (int i= 0; i < nb_sessions; i++)
105 {
106 WRITE_VAL("sql session close session %d.\n", i);
107 session_ret= srv_session_close(sessions[i]);
108 if (session_ret)
109 my_plugin_log_message(&p, MY_ERROR_LEVEL, "srv_session_close_%d failed.", i);
110 }
111
112 DBUG_VOID_RETURN;
113 }
114
115
116 struct test_thread_context
117 {
118 my_thread_handle thread;
119 void *p;
120 bool thread_finished;
121 void (*test_function)(void *);
122 };
123
124
test_sql_threaded_wrapper(void * param)125 static void* test_sql_threaded_wrapper(void *param)
126 {
127 char buffer[STRING_BUFFER_SIZE];
128 struct test_thread_context *context= (struct test_thread_context*) param;
129
130 WRITE_SEP();
131 WRITE_STR("init thread\n");
132 if (srv_session_init_thread(context->p))
133 my_plugin_log_message(&context->p, MY_ERROR_LEVEL, "srv_session_init_thread failed.");
134
135 context->test_function(context->p);
136
137 WRITE_STR("deinit thread\n");
138 srv_session_deinit_thread();
139
140 context->thread_finished= true;
141 return NULL;
142 }
143
144
create_log_file(const char * log_name)145 static void create_log_file(const char * log_name)
146 {
147 char filename[FN_REFLEN];
148
149 fn_format(filename, log_name, "", ".log",
150 MY_REPLACE_EXT | MY_UNPACK_FILENAME);
151 unlink(filename);
152 outfile= my_open(filename, O_CREAT|O_RDWR, MYF(0));
153 }
154
155
test_in_spawned_thread(void * p,void (* test_function)(void *))156 static void test_in_spawned_thread(void *p, void (*test_function)(void *))
157 {
158 my_thread_attr_t attr; /* Thread attributes */
159 my_thread_attr_init(&attr);
160 (void) my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
161
162 struct test_thread_context context;
163
164 context.p= p;
165 context.thread_finished= false;
166 context.test_function= test_function;
167
168 /* now create the thread and call test_session within the thread. */
169 if (my_thread_create(&(context.thread), &attr, test_sql_threaded_wrapper, &context) != 0)
170 my_plugin_log_message(&p, MY_ERROR_LEVEL, "Could not create test session thread");
171 else
172 my_thread_join(&context.thread, NULL);
173 }
174
test_sql_service_plugin_init(void * p)175 static int test_sql_service_plugin_init(void *p)
176 {
177 char buffer[STRING_BUFFER_SIZE];
178 DBUG_ENTER("test_sql_service_plugin_init");
179 my_plugin_log_message(&p, MY_INFORMATION_LEVEL, "Installation.");
180
181 create_log_file(log_filename);
182
183 WRITE_STR("Follows threaded run\n");
184 test_in_spawned_thread(p, test_session);
185
186 my_close(outfile, MYF(0));
187
188 DBUG_RETURN(0);
189 }
190
191
test_sql_service_plugin_deinit(void * p)192 static int test_sql_service_plugin_deinit(void *p)
193 {
194 DBUG_ENTER("test_sql_service_plugin_deinit");
195 DBUG_RETURN(0);
196 }
197
198
199 struct st_mysql_daemon test_session_service_plugin=
200 { MYSQL_DAEMON_INTERFACE_VERSION };
201
202
203 /*
204 Plugin library descriptor
205 */
206
mysql_declare_plugin(test_daemon)207 mysql_declare_plugin(test_daemon)
208 {
209 MYSQL_DAEMON_PLUGIN,
210 &test_session_service_plugin,
211 "test_session_in_thd",
212 "Horst Hunger, Andrey Hristov",
213 "Test sessions in thread",
214 PLUGIN_LICENSE_GPL,
215 test_sql_service_plugin_init, /* Plugin Init */
216 test_sql_service_plugin_deinit, /* Plugin Deinit */
217 0x0100, /* 1.0 */
218 NULL, /* status variables */
219 test_services_sysvars, /* system variables */
220 NULL, /* config options */
221 0, /* flags */
222 }
223 mysql_declare_plugin_end;
224