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