301 lines
7.4 KiB
C++
301 lines
7.4 KiB
C++
/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
/**
|
|
This is unit test for the Global_THD_manager class.
|
|
*/
|
|
|
|
#include "my_config.h"
|
|
#include <gtest/gtest.h>
|
|
#include "sql_class.h"
|
|
#include "thread_utils.h"
|
|
#include "mysqld.h"
|
|
#include "mysqld_thd_manager.h" // Global_THD_manager
|
|
|
|
using thread::Thread;
|
|
using thread::Notification;
|
|
|
|
namespace thd_manager_unittest {
|
|
|
|
class ThreadManagerTest : public ::testing::Test
|
|
{
|
|
protected:
|
|
ThreadManagerTest()
|
|
{
|
|
}
|
|
|
|
void SetUp()
|
|
{
|
|
Global_THD_manager::create_instance();
|
|
thd_manager= Global_THD_manager::get_instance();
|
|
thd_manager->set_unit_test();
|
|
}
|
|
|
|
void TearDown()
|
|
{
|
|
}
|
|
|
|
Global_THD_manager *thd_manager;
|
|
private:
|
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadManagerTest);
|
|
};
|
|
|
|
enum TEST_TYPE
|
|
{
|
|
TEST_WAIT=0,
|
|
TEST_TIMED_WAIT=1
|
|
};
|
|
|
|
/*
|
|
Verify add_thd(), remove_thd() methods
|
|
*/
|
|
TEST_F(ThreadManagerTest, AddRemoveTHDWithGuard)
|
|
{
|
|
THD thd1(false), thd2(false);
|
|
thd1.server_id= 1;
|
|
thd1.set_new_thread_id();
|
|
thd2.server_id= 2;
|
|
thd2.set_new_thread_id();
|
|
|
|
EXPECT_EQ(0U, thd_manager->get_thd_count());
|
|
thd_manager->add_thd(&thd1);
|
|
EXPECT_EQ(1U, thd_manager->get_thd_count());
|
|
thd_manager->add_thd(&thd2);
|
|
|
|
thd_manager->remove_thd(&thd1);
|
|
EXPECT_EQ(1U, thd_manager->get_thd_count());
|
|
thd_manager->remove_thd(&thd2);
|
|
EXPECT_EQ(0U, thd_manager->get_thd_count());
|
|
}
|
|
|
|
TEST_F(ThreadManagerTest, IncDecThreadRunning)
|
|
{
|
|
EXPECT_EQ(0, thd_manager->get_num_thread_running());
|
|
thd_manager->inc_thread_running();
|
|
EXPECT_EQ(1, thd_manager->get_num_thread_running());
|
|
thd_manager->dec_thread_running();
|
|
EXPECT_EQ(0, thd_manager->get_num_thread_running());
|
|
}
|
|
|
|
TEST_F(ThreadManagerTest, IncThreadCreated)
|
|
{
|
|
EXPECT_EQ(0U, thd_manager->get_num_thread_created());
|
|
thd_manager->inc_thread_created();
|
|
EXPECT_EQ(1U, thd_manager->get_num_thread_created());
|
|
}
|
|
|
|
/*
|
|
Test function to validate do_for_all_thd, do_for_all_thd_copy.
|
|
It emulates counter function to count number of thds in thd list.
|
|
*/
|
|
class TestFunc1 : public Do_THD_Impl
|
|
{
|
|
private:
|
|
int cnt;
|
|
public:
|
|
TestFunc1() : cnt(0) {}
|
|
int get_count()
|
|
{
|
|
return cnt;
|
|
}
|
|
void reset_count()
|
|
{
|
|
cnt= 0;
|
|
}
|
|
void operator() (THD* thd)
|
|
{
|
|
cnt= cnt + 1;
|
|
}
|
|
};
|
|
|
|
TEST_F(ThreadManagerTest, TestTHDCopyDoFunc)
|
|
{
|
|
THD thd1(false), thd2(false);
|
|
thd1.server_id= 1;
|
|
thd1.set_new_thread_id();
|
|
thd2.server_id= 2;
|
|
thd2.set_new_thread_id();
|
|
// Add two THD into thd list.
|
|
thd_manager->add_thd(&thd1);
|
|
thd_manager->add_thd(&thd2);
|
|
|
|
int cnt= 0;
|
|
TestFunc1 testFunc1;
|
|
thd_manager->do_for_all_thd_copy(&testFunc1);
|
|
cnt= testFunc1.get_count();
|
|
EXPECT_EQ(2, cnt);
|
|
|
|
testFunc1.reset_count();
|
|
thd_manager->do_for_all_thd(&testFunc1);
|
|
cnt= testFunc1.get_count();
|
|
EXPECT_EQ(2, cnt);
|
|
|
|
// Cleanup - Remove added THD.
|
|
thd_manager->remove_thd(&thd1);
|
|
thd_manager->remove_thd(&thd2);
|
|
}
|
|
|
|
/*
|
|
Test class to verify find_thd()
|
|
*/
|
|
class TestFunc2 : public Find_THD_Impl
|
|
{
|
|
public:
|
|
TestFunc2() : search_value(0) {}
|
|
bool operator() (THD* thd)
|
|
{
|
|
if (thd->server_id == search_value)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void set_search_value(uint val) { search_value= val; }
|
|
private:
|
|
uint search_value;
|
|
};
|
|
|
|
/*
|
|
Test class to verify do_all_for_thd() function.
|
|
Counts all thd whose server_id value is less than or equal to 2.
|
|
*/
|
|
class TestFunc3 : public Do_THD_Impl
|
|
{
|
|
public:
|
|
TestFunc3() : count(0) {}
|
|
void operator() (THD* thd)
|
|
{
|
|
if (thd->server_id <= 2)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
int get_count() { return count; }
|
|
private:
|
|
int count;
|
|
};
|
|
|
|
TEST_F(ThreadManagerTest, TestTHDFindFunc)
|
|
{
|
|
THD thd1(false), thd2(false);
|
|
thd1.server_id= 1;
|
|
thd1.set_new_thread_id();
|
|
thd2.server_id= 2;
|
|
thd2.set_new_thread_id();
|
|
thd_manager->add_thd(&thd1);
|
|
thd_manager->add_thd(&thd2);
|
|
TestFunc2 testFunc2;
|
|
testFunc2.set_search_value(2);
|
|
THD *thd= thd_manager->find_thd(&testFunc2);
|
|
/* Returns the last thd which matches. */
|
|
EXPECT_EQ(2U, thd->server_id);
|
|
|
|
testFunc2.set_search_value(6);
|
|
thd= thd_manager->find_thd(&testFunc2);
|
|
/* Find non existing thd with server_id value 6. Expected to return NULL. */
|
|
const THD* null_thd= NULL;
|
|
EXPECT_EQ(null_thd, thd);
|
|
|
|
// Cleanup - Remove added THD.
|
|
thd_manager->remove_thd(&thd1);
|
|
thd_manager->remove_thd(&thd2);
|
|
}
|
|
|
|
|
|
TEST_F(ThreadManagerTest, TestTHDCountFunc)
|
|
{
|
|
THD thd1(false), thd2(false), thd3(false);
|
|
thd1.server_id= 1;
|
|
thd1.set_new_thread_id();
|
|
thd2.server_id= 2;
|
|
thd2.set_new_thread_id();
|
|
thd3.server_id= 3;
|
|
thd3.set_new_thread_id();
|
|
thd_manager->add_thd(&thd1);
|
|
thd_manager->add_thd(&thd2);
|
|
thd_manager->add_thd(&thd3);
|
|
|
|
TestFunc3 testFunc3;
|
|
thd_manager->do_for_all_thd(&testFunc3);
|
|
int ret=testFunc3.get_count();
|
|
// testFunc3 counts for thd->server_id values, 1 and 2.
|
|
EXPECT_EQ(2, ret);
|
|
|
|
// Cleanup - Remove added THD.
|
|
thd_manager->remove_thd(&thd1);
|
|
thd_manager->remove_thd(&thd2);
|
|
thd_manager->remove_thd(&thd3);
|
|
}
|
|
|
|
|
|
TEST_F(ThreadManagerTest, ThreadID)
|
|
{
|
|
// Code assumes that the size of my_thread_id is 32 bit.
|
|
ASSERT_EQ(4U, sizeof(my_thread_id));
|
|
|
|
// Reset the thread ID counter
|
|
thd_manager->set_thread_id_counter(1);
|
|
EXPECT_EQ(1U, thd_manager->get_thread_id());
|
|
|
|
// The counter is incremented after ID is assigned.
|
|
EXPECT_EQ(1U, thd_manager->get_new_thread_id());
|
|
EXPECT_EQ(2U, thd_manager->get_thread_id());
|
|
|
|
// Two increments in a row
|
|
EXPECT_EQ(2U, thd_manager->get_new_thread_id());
|
|
EXPECT_EQ(3U, thd_manager->get_new_thread_id());
|
|
EXPECT_EQ(4U, thd_manager->get_thread_id());
|
|
|
|
// Force wrap of the counter
|
|
thd_manager->set_thread_id_counter(UINT_MAX32);
|
|
EXPECT_EQ(UINT_MAX32, thd_manager->get_new_thread_id());
|
|
|
|
// We should not use the value reserved for temporary THDs (0).
|
|
// The next available value should be 4.
|
|
EXPECT_EQ(4U, thd_manager->get_new_thread_id());
|
|
EXPECT_EQ(5U, thd_manager->get_thread_id());
|
|
|
|
// Release thread ID 3 and reset counter.
|
|
thd_manager->release_thread_id(3);
|
|
thd_manager->set_thread_id_counter(1U);
|
|
EXPECT_EQ(3U, thd_manager->get_new_thread_id());
|
|
|
|
// Releasing the reserved thread ID is allowed - multiple times.
|
|
thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id);
|
|
thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id);
|
|
|
|
// Cleanup
|
|
thd_manager->release_thread_id(1);
|
|
thd_manager->release_thread_id(2);
|
|
thd_manager->release_thread_id(3);
|
|
thd_manager->release_thread_id(4);
|
|
thd_manager->release_thread_id(UINT_MAX32);
|
|
}
|
|
|
|
|
|
#if !defined(DBUG_OFF)
|
|
TEST_F(ThreadManagerTest, ThreadIDDeathTest)
|
|
{
|
|
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
|
my_thread_id thread_id= thd_manager->get_new_thread_id();
|
|
thd_manager->release_thread_id(thread_id);
|
|
// Releasing the same ID twice should assert.
|
|
EXPECT_DEATH_IF_SUPPORTED(thd_manager->release_thread_id(thread_id),
|
|
".*Assertion .*1 == num_erased.*");
|
|
}
|
|
#endif
|
|
|
|
} // namespace
|