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