1 /*
2 Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1301 USA */
23
24 // First include (the generated) my_config.h, to get correct platform defines.
25 #include "my_config.h"
26 #include <gtest/gtest.h>
27 #include "mysys_err.h"
28
29 #include "my_sys.h"
30
31 extern "C" void mock_error_handler_hook(uint err, const char *str, myf MyFlags);
32
33 /**
34 An alternative error_handler for non-server unit tests since it does
35 not rely on THD. It sets the global error handler function.
36 */
37 class Mock_global_error_handler
38 {
39 public:
Mock_global_error_handler(uint expected_error)40 Mock_global_error_handler(uint expected_error):
41 m_expected_error(expected_error),
42 m_handle_called(0)
43 {
44 current= this;
45 m_old_error_handler_hook= error_handler_hook;
46 error_handler_hook = mock_error_handler_hook;
47 }
48
~Mock_global_error_handler()49 virtual ~Mock_global_error_handler()
50 {
51 if (m_expected_error == 0)
52 {
53 EXPECT_EQ(0, m_handle_called);
54 }
55 else
56 {
57 EXPECT_GT(m_handle_called, 0);
58 }
59 error_handler_hook= m_old_error_handler_hook;
60 current= NULL;
61 }
62
error_handler(uint err)63 void error_handler(uint err)
64 {
65 EXPECT_EQ(m_expected_error, err);
66 ++m_handle_called;
67 }
68
handle_called() const69 int handle_called() const { return m_handle_called; }
70
71 static Mock_global_error_handler *current;
72
73 private:
74 uint m_expected_error;
75 int m_handle_called;
76
77 void (*m_old_error_handler_hook)(uint, const char *, myf);
78 };
79
80 Mock_global_error_handler *Mock_global_error_handler::current= NULL;
81
82 /*
83 Error handler function.
84 */
mock_error_handler_hook(uint err,const char * str,myf MyFlags)85 extern "C" void mock_error_handler_hook(uint err, const char *str, myf MyFlags)
86 {
87 if (Mock_global_error_handler::current)
88 Mock_global_error_handler::current->error_handler(err);
89 }
90
91 namespace my_alloc_unittest {
92
93 const size_t num_iterations= 1ULL;
94
95 class MyAllocTest : public ::testing::TestWithParam<size_t>
96 {
97 protected:
SetUp()98 virtual void SetUp()
99 {
100 init_alloc_root(PSI_NOT_INSTRUMENTED, &m_root, 1024, 0);
101 }
TearDown()102 virtual void TearDown()
103 {
104 free_root(&m_root, MYF(0));
105 }
106 size_t m_num_objects;
107 MEM_ROOT m_root;
108 };
109
110 class MyPreAllocTest : public ::testing::Test
111 {
112 protected:
SetUp()113 virtual void SetUp()
114 {
115 init_alloc_root(PSI_NOT_INSTRUMENTED, &m_prealloc_root, 1024, 2048);
116 }
TearDown()117 virtual void TearDown()
118 {
119 free_root(&m_prealloc_root, MYF(0));
120 }
121 size_t m_num_objects;
122 MEM_ROOT m_prealloc_root;
123 };
124
125
126
127 size_t test_values[]= {100, 1000, 10000, 100000 };
128
129 INSTANTIATE_TEST_CASE_P(MyAlloc, MyAllocTest,
130 ::testing::ValuesIn(test_values));
131
TEST_P(MyAllocTest,NoMemoryLimit)132 TEST_P(MyAllocTest, NoMemoryLimit)
133 {
134 m_num_objects= GetParam();
135 for (size_t ix= 0; ix < num_iterations; ++ix)
136 {
137 for (size_t objcount= 0; objcount < m_num_objects; ++objcount)
138 alloc_root(&m_root, 100);
139 }
140 }
141
TEST_P(MyAllocTest,WithMemoryLimit)142 TEST_P(MyAllocTest, WithMemoryLimit)
143 {
144 m_num_objects= GetParam();
145 set_memroot_max_capacity(&m_root, num_iterations * m_num_objects * 100);
146 for (size_t ix= 0; ix < num_iterations; ++ix)
147 {
148 for (size_t objcount= 0; objcount < m_num_objects; ++objcount)
149 alloc_root(&m_root, 100);
150 }
151 }
152
TEST_F(MyAllocTest,CheckErrorReporting)153 TEST_F(MyAllocTest, CheckErrorReporting)
154 {
155 const void *null_pointer= NULL;
156 EXPECT_TRUE(alloc_root(&m_root, 1000));
157 set_memroot_max_capacity(&m_root, 100);
158 EXPECT_EQ(null_pointer, alloc_root(&m_root, 1000));
159 set_memroot_error_reporting(&m_root, true);
160 Mock_global_error_handler error_handler(EE_CAPACITY_EXCEEDED);
161 EXPECT_TRUE(alloc_root(&m_root, 1000));
162 EXPECT_EQ(1, error_handler.handle_called());
163 }
164
TEST_F(MyPreAllocTest,PreAlloc)165 TEST_F(MyPreAllocTest, PreAlloc)
166 {
167 // PREALLOCATE_MEMORY_CHUNKS is not defined for valgrind and ASAN
168 #if !defined(HAVE_VALGRIND) && !defined(HAVE_ASAN)
169 const void *null_pointer= NULL;
170 // MEMROOT has pre-allocated 2048 bytes memory plus some overhead
171 size_t pre_allocated= m_prealloc_root.allocated_size;
172 EXPECT_LT((unsigned int)2048, pre_allocated);
173
174 // This will eat of pre-allocated memory, no more should be allocated
175 EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
176 EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
177
178 set_memroot_max_capacity(&m_prealloc_root, 100);
179 // Sufficient memory has been pre-allocated, so first alloc below will succeed
180 EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
181 EXPECT_EQ(null_pointer, alloc_root(&m_prealloc_root, 100));
182 EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
183
184 // Setting error reporting. Error is flagged but allocation succeeds
185 set_memroot_error_reporting(&m_prealloc_root, true);
186 {
187 Mock_global_error_handler error_handler(EE_CAPACITY_EXCEEDED);
188 EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
189 EXPECT_EQ(1, error_handler.handle_called());
190 EXPECT_LT(pre_allocated, m_prealloc_root.allocated_size);
191 pre_allocated= m_prealloc_root.allocated_size;
192 }
193 set_memroot_error_reporting(&m_prealloc_root, false);
194
195 //This will just mark the blocks free.
196 free_root(&m_prealloc_root, MY_MARK_BLOCKS_FREE);
197 EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
198
199 set_memroot_max_capacity(&m_prealloc_root, 2048);
200 reset_root_defaults(&m_prealloc_root, 1024, 0);
201 EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
202 reset_root_defaults(&m_prealloc_root, 1024, 1024);
203 EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
204
205 reset_root_defaults(&m_prealloc_root, 512, 1024);
206 EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
207 pre_allocated= m_prealloc_root.allocated_size;
208 // This allocation will use pre-alocated memory
209 EXPECT_TRUE(alloc_root(&m_prealloc_root, 1024));
210 EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
211 // Will allocate more memory
212 EXPECT_TRUE(alloc_root(&m_prealloc_root, 512));
213 EXPECT_LT((unsigned int)1526, m_prealloc_root.allocated_size);
214 pre_allocated= m_prealloc_root.allocated_size;
215 // This will not succeed
216 EXPECT_EQ(null_pointer, alloc_root(&m_prealloc_root, 512));
217
218 free_root(&m_prealloc_root, MY_KEEP_PREALLOC);
219 EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
220
221 // Specified pre_alloc_size is above capacity. Expect no pre-allocation
222 reset_root_defaults(&m_prealloc_root, 512, 4096);
223 EXPECT_EQ((unsigned int)0, m_prealloc_root.allocated_size);
224
225 free_root(&m_prealloc_root, 0);
226 EXPECT_EQ((unsigned int)0, m_prealloc_root.allocated_size);
227 #endif
228 }
229
230 }
231