1 /* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
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 /**
24 This is unit test for the Global_THD_manager class.
25 */
26
27 #include "my_config.h"
28 #include <gtest/gtest.h>
29 #include "sql_class.h"
30 #include "thread_utils.h"
31 #include "mysqld.h"
32 #include "mysqld_thd_manager.h" // Global_THD_manager
33
34 using thread::Thread;
35 using thread::Notification;
36
37 namespace thd_manager_unittest {
38
39 class ThreadManagerTest : public ::testing::Test
40 {
41 protected:
ThreadManagerTest()42 ThreadManagerTest()
43 {
44 }
45
SetUp()46 void SetUp()
47 {
48 Global_THD_manager::create_instance();
49 thd_manager= Global_THD_manager::get_instance();
50 thd_manager->set_unit_test();
51 }
52
TearDown()53 void TearDown()
54 {
55 }
56
57 Global_THD_manager *thd_manager;
58 private:
59 GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadManagerTest);
60 };
61
62 enum TEST_TYPE
63 {
64 TEST_WAIT=0,
65 TEST_TIMED_WAIT=1
66 };
67
68 /*
69 Verify add_thd(), remove_thd() methods
70 */
TEST_F(ThreadManagerTest,AddRemoveTHDWithGuard)71 TEST_F(ThreadManagerTest, AddRemoveTHDWithGuard)
72 {
73 THD thd1(false), thd2(false);
74 thd1.server_id= 1;
75 thd1.set_new_thread_id();
76 thd2.server_id= 2;
77 thd2.set_new_thread_id();
78
79 EXPECT_EQ(0U, thd_manager->get_thd_count());
80 thd_manager->add_thd(&thd1);
81 EXPECT_EQ(1U, thd_manager->get_thd_count());
82 thd_manager->add_thd(&thd2);
83
84 thd_manager->remove_thd(&thd1);
85 EXPECT_EQ(1U, thd_manager->get_thd_count());
86 thd_manager->remove_thd(&thd2);
87 EXPECT_EQ(0U, thd_manager->get_thd_count());
88 }
89
TEST_F(ThreadManagerTest,IncDecThreadRunning)90 TEST_F(ThreadManagerTest, IncDecThreadRunning)
91 {
92 EXPECT_EQ(0, thd_manager->get_num_thread_running());
93 thd_manager->inc_thread_running();
94 EXPECT_EQ(1, thd_manager->get_num_thread_running());
95 thd_manager->dec_thread_running();
96 EXPECT_EQ(0, thd_manager->get_num_thread_running());
97 }
98
TEST_F(ThreadManagerTest,IncThreadCreated)99 TEST_F(ThreadManagerTest, IncThreadCreated)
100 {
101 EXPECT_EQ(0U, thd_manager->get_num_thread_created());
102 thd_manager->inc_thread_created();
103 EXPECT_EQ(1U, thd_manager->get_num_thread_created());
104 }
105
106 /*
107 Test function to validate do_for_all_thd, do_for_all_thd_copy.
108 It emulates counter function to count number of thds in thd list.
109 */
110 class TestFunc1 : public Do_THD_Impl
111 {
112 private:
113 int cnt;
114 public:
TestFunc1()115 TestFunc1() : cnt(0) {}
get_count()116 int get_count()
117 {
118 return cnt;
119 }
reset_count()120 void reset_count()
121 {
122 cnt= 0;
123 }
operator ()(THD * thd)124 void operator() (THD* thd)
125 {
126 cnt= cnt + 1;
127 }
128 };
129
TEST_F(ThreadManagerTest,TestTHDCopyDoFunc)130 TEST_F(ThreadManagerTest, TestTHDCopyDoFunc)
131 {
132 THD thd1(false), thd2(false);
133 thd1.server_id= 1;
134 thd1.set_new_thread_id();
135 thd2.server_id= 2;
136 thd2.set_new_thread_id();
137 // Add two THD into thd list.
138 thd_manager->add_thd(&thd1);
139 thd_manager->add_thd(&thd2);
140
141 int cnt= 0;
142 TestFunc1 testFunc1;
143 thd_manager->do_for_all_thd_copy(&testFunc1);
144 cnt= testFunc1.get_count();
145 EXPECT_EQ(2, cnt);
146
147 testFunc1.reset_count();
148 thd_manager->do_for_all_thd(&testFunc1);
149 cnt= testFunc1.get_count();
150 EXPECT_EQ(2, cnt);
151
152 // Cleanup - Remove added THD.
153 thd_manager->remove_thd(&thd1);
154 thd_manager->remove_thd(&thd2);
155 }
156
157 /*
158 Test class to verify find_thd()
159 */
160 class TestFunc2 : public Find_THD_Impl
161 {
162 public:
TestFunc2()163 TestFunc2() : search_value(0) {}
operator ()(THD * thd)164 bool operator() (THD* thd)
165 {
166 if (thd->server_id == search_value)
167 {
168 return true;
169 }
170 return false;
171 }
set_search_value(uint val)172 void set_search_value(uint val) { search_value= val; }
173 private:
174 uint search_value;
175 };
176
177 /*
178 Test class to verify do_all_for_thd() function.
179 Counts all thd whose server_id value is less than or equal to 2.
180 */
181 class TestFunc3 : public Do_THD_Impl
182 {
183 public:
TestFunc3()184 TestFunc3() : count(0) {}
operator ()(THD * thd)185 void operator() (THD* thd)
186 {
187 if (thd->server_id <= 2)
188 {
189 count++;
190 }
191 }
get_count()192 int get_count() { return count; }
193 private:
194 int count;
195 };
196
TEST_F(ThreadManagerTest,TestTHDFindFunc)197 TEST_F(ThreadManagerTest, TestTHDFindFunc)
198 {
199 THD thd1(false), thd2(false);
200 thd1.server_id= 1;
201 thd1.set_new_thread_id();
202 thd2.server_id= 2;
203 thd2.set_new_thread_id();
204 thd_manager->add_thd(&thd1);
205 thd_manager->add_thd(&thd2);
206 TestFunc2 testFunc2;
207 testFunc2.set_search_value(2);
208 THD *thd= thd_manager->find_thd(&testFunc2);
209 /* Returns the last thd which matches. */
210 EXPECT_EQ(2U, thd->server_id);
211
212 testFunc2.set_search_value(6);
213 thd= thd_manager->find_thd(&testFunc2);
214 /* Find non existing thd with server_id value 6. Expected to return NULL. */
215 const THD* null_thd= NULL;
216 EXPECT_EQ(null_thd, thd);
217
218 // Cleanup - Remove added THD.
219 thd_manager->remove_thd(&thd1);
220 thd_manager->remove_thd(&thd2);
221 }
222
223
TEST_F(ThreadManagerTest,TestTHDCountFunc)224 TEST_F(ThreadManagerTest, TestTHDCountFunc)
225 {
226 THD thd1(false), thd2(false), thd3(false);
227 thd1.server_id= 1;
228 thd1.set_new_thread_id();
229 thd2.server_id= 2;
230 thd2.set_new_thread_id();
231 thd3.server_id= 3;
232 thd3.set_new_thread_id();
233 thd_manager->add_thd(&thd1);
234 thd_manager->add_thd(&thd2);
235 thd_manager->add_thd(&thd3);
236
237 TestFunc3 testFunc3;
238 thd_manager->do_for_all_thd(&testFunc3);
239 int ret=testFunc3.get_count();
240 // testFunc3 counts for thd->server_id values, 1 and 2.
241 EXPECT_EQ(2, ret);
242
243 // Cleanup - Remove added THD.
244 thd_manager->remove_thd(&thd1);
245 thd_manager->remove_thd(&thd2);
246 thd_manager->remove_thd(&thd3);
247 }
248
249
TEST_F(ThreadManagerTest,ThreadID)250 TEST_F(ThreadManagerTest, ThreadID)
251 {
252 // Code assumes that the size of my_thread_id is 32 bit.
253 ASSERT_EQ(4U, sizeof(my_thread_id));
254
255 // Reset the thread ID counter
256 thd_manager->set_thread_id_counter(1);
257 EXPECT_EQ(1U, thd_manager->get_thread_id());
258
259 // The counter is incremented after ID is assigned.
260 EXPECT_EQ(1U, thd_manager->get_new_thread_id());
261 EXPECT_EQ(2U, thd_manager->get_thread_id());
262
263 // Two increments in a row
264 EXPECT_EQ(2U, thd_manager->get_new_thread_id());
265 EXPECT_EQ(3U, thd_manager->get_new_thread_id());
266 EXPECT_EQ(4U, thd_manager->get_thread_id());
267
268 // Force wrap of the counter
269 thd_manager->set_thread_id_counter(UINT_MAX32);
270 EXPECT_EQ(UINT_MAX32, thd_manager->get_new_thread_id());
271
272 // We should not use the value reserved for temporary THDs (0).
273 // The next available value should be 4.
274 EXPECT_EQ(4U, thd_manager->get_new_thread_id());
275 EXPECT_EQ(5U, thd_manager->get_thread_id());
276
277 // Release thread ID 3 and reset counter.
278 thd_manager->release_thread_id(3);
279 thd_manager->set_thread_id_counter(1U);
280 EXPECT_EQ(3U, thd_manager->get_new_thread_id());
281
282 // Releasing the reserved thread ID is allowed - multiple times.
283 thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id);
284 thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id);
285
286 // Cleanup
287 thd_manager->release_thread_id(1);
288 thd_manager->release_thread_id(2);
289 thd_manager->release_thread_id(3);
290 thd_manager->release_thread_id(4);
291 thd_manager->release_thread_id(UINT_MAX32);
292 }
293
294
295 #if !defined(NDEBUG)
TEST_F(ThreadManagerTest,ThreadIDDeathTest)296 TEST_F(ThreadManagerTest, ThreadIDDeathTest)
297 {
298 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
299 my_thread_id thread_id= thd_manager->get_new_thread_id();
300 thd_manager->release_thread_id(thread_id);
301 // Releasing the same ID twice should assert.
302 EXPECT_DEATH_IF_SUPPORTED(thd_manager->release_thread_id(thread_id),
303 ".*Assertion .*1 == num_erased.*");
304 }
305 #endif
306
307 } // namespace
308