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