MySQL 8.0.31
Source Code Documentation
ut0pool.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2013, 2022, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25*****************************************************************************/
26
27/** @file include/ut0pool.h
28 Object pool.
29
30 Created 2012-Feb-26 Sunny Bains
31 ***********************************************************************/
32
33#ifndef ut0pool_h
34#define ut0pool_h
35
36#include <functional>
37#include <queue>
38#include <vector>
39
40#include "ut0new.h"
41
42/** Allocate the memory for the object in blocks. We keep the objects sorted
43on pointer so that they are closer together in case they have to be iterated
44over in a list. */
45template <typename Type, typename Factory, typename LockStrategy>
46struct Pool {
48
49 // FIXME: Add an assertion to check alignment and offset is
50 // as we expect it. Also, sizeof(void*) can be 8, can we improve on this.
51 struct Element {
54 };
55
56 /** Constructor
57 @param size size of the memory block */
58 Pool(size_t size) : m_end(), m_start(), m_size(size), m_last() {
59 ut_a(size >= sizeof(Element));
60
61 m_lock_strategy.create();
62
63 ut_a(m_start == nullptr);
64
65 m_start = reinterpret_cast<Element *>(
67
69
70 m_end = &m_start[m_size / sizeof(*m_start)];
71
72 /* Note: Initialise only a small subset, even though we have
73 allocated all the memory. This is required only because PFS
74 (MTR) results change if we instantiate too many mutexes up
75 front. */
76
77 init(std::min(size_t(16), size_t(m_end - m_start)));
78
79 ut_ad(m_pqueue.size() <= size_t(m_last - m_start));
80 }
81
82 /** Destructor */
84 m_lock_strategy.destroy();
85
86 for (Element *elem = m_start; elem != m_last; ++elem) {
87 ut_ad(elem->m_pool == this);
88 Factory::destroy(&elem->m_type);
89 }
90
92 m_end = m_last = m_start = nullptr;
93 m_size = 0;
94 }
95
96 /** Get an object from the pool.
97 @return a free instance or NULL if exhausted. */
98 Type *get() {
99 Element *elem;
100
101 m_lock_strategy.enter();
102
103 if (!m_pqueue.empty()) {
104 elem = m_pqueue.top();
105 m_pqueue.pop();
106
107 } else if (m_last < m_end) {
108 /* Initialise the remaining elements. */
109 init(m_end - m_last);
110
111 ut_ad(!m_pqueue.empty());
112
113 elem = m_pqueue.top();
114 m_pqueue.pop();
115 } else {
116 elem = nullptr;
117 }
118
119 m_lock_strategy.exit();
120
121 return (elem != nullptr ? &elem->m_type : nullptr);
122 }
123
124 /** Add the object to the pool.
125 @param ptr object to free */
126 static void mem_free(value_type *ptr) {
127 Element *elem;
128 byte *p = reinterpret_cast<byte *>(ptr + 1);
129
130 elem = reinterpret_cast<Element *>(p - sizeof(*elem));
131
132 elem->m_pool->put(elem);
133 }
134
135 protected:
136 // Disable copying
137 Pool(const Pool &);
138 Pool &operator=(const Pool &);
139
140 private:
141 /* We only need to compare on pointer address. */
142 typedef std::priority_queue<Element *,
143 std::vector<Element *, ut::allocator<Element *>>,
144 std::greater<Element *>>
146
147 /** Release the object to the free pool
148 @param elem element to free */
149 void put(Element *elem) {
150 m_lock_strategy.enter();
151
152 ut_ad(elem >= m_start && elem < m_last);
153
154 ut_ad(Factory::debug(&elem->m_type));
155
156 m_pqueue.push(elem);
157
158 m_lock_strategy.exit();
159 }
160
161 /** Initialise the elements.
162 @param n_elems Number of elements to initialise */
163 void init(size_t n_elems) {
164 ut_ad(size_t(m_end - m_last) >= n_elems);
165
166 for (size_t i = 0; i < n_elems; ++i, ++m_last) {
167 m_last->m_pool = this;
169 m_pqueue.push(m_last);
170 }
171
172 ut_ad(m_last <= m_end);
173 }
174
175 private:
176 /** Pointer to the last element */
178
179 /** Pointer to the first element */
181
182 /** Size of the block in bytes */
183 size_t m_size;
184
185 /** Upper limit of used space */
187
188 /** Priority queue ordered on the pointer addresses. */
190
191 /** Lock strategy to use */
192 LockStrategy m_lock_strategy;
193};
194
195template <typename Pool, typename LockStrategy>
197 typedef Pool PoolType;
199
200 PoolManager(size_t size) : m_size(size) { create(); }
201
203 destroy();
204
205 ut_a(m_pools.empty());
206 }
207
208 /** Get an element from one of the pools.
209 @return instance or NULL if pool is empty. */
211 size_t index = 0;
212 size_t delay = 1;
213 value_type *ptr = nullptr;
214
215 do {
216 m_lock_strategy.enter();
217
218 ut_ad(!m_pools.empty());
219
220 size_t n_pools = m_pools.size();
221
222 PoolType *pool = m_pools[index % n_pools];
223
224 m_lock_strategy.exit();
225
226 ptr = pool->get();
227
228 if (ptr == nullptr && (index / n_pools) > 2) {
229 if (!add_pool(n_pools)) {
230 ib::error(ER_IB_MSG_FAILED_TO_ALLOCATE_WAIT, m_size, delay);
231
232 /* There is nothing much we can do
233 except crash and burn, however lets
234 be a little optimistic and wait for
235 a resource to be freed. */
236 std::this_thread::sleep_for(std::chrono::seconds(delay));
237
238 if (delay < 32) {
239 delay <<= 1;
240 }
241
242 } else {
243 delay = 1;
244 }
245 }
246
247 ++index;
248
249 } while (ptr == nullptr);
250
251 return (ptr);
252 }
253
254 static void mem_free(value_type *ptr) { PoolType::mem_free(ptr); }
255
256 private:
257 /** Add a new pool
258 @param n_pools Number of pools that existed when the add pool was
259 called.
260 @return true on success */
261 bool add_pool(size_t n_pools) {
262 bool added = false;
263
264 m_lock_strategy.enter();
265
266 if (n_pools < m_pools.size()) {
267 /* Some other thread already added a pool. */
268 added = true;
269 } else {
270 PoolType *pool;
271
272 ut_ad(n_pools == m_pools.size());
273
274 pool = ut::new_withkey<PoolType>(UT_NEW_THIS_FILE_PSI_KEY, m_size);
275
276 if (pool != nullptr) {
277 ut_ad(n_pools <= m_pools.size());
278
279 m_pools.push_back(pool);
280
281 added = true;
282 }
283 }
284
285 ut_ad(n_pools < m_pools.size() || !added);
286
287 m_lock_strategy.exit();
288
289 return (added);
290 }
291
292 /** Create the pool manager. */
293 void create() {
294 ut_a(m_size > sizeof(value_type));
295 m_lock_strategy.create();
296
297 add_pool(0);
298 }
299
300 /** Release the resources. */
301 void destroy() {
302 typename Pools::iterator it;
303 typename Pools::iterator end = m_pools.end();
304
305 for (it = m_pools.begin(); it != end; ++it) {
306 PoolType *pool = *it;
307
308 ut::delete_(pool);
309 }
310
311 m_pools.clear();
312
313 m_lock_strategy.destroy();
314 }
315
316 private:
317 // Disable copying
320
321 typedef std::vector<PoolType *, ut::allocator<PoolType *>> Pools;
322
323 /** Size of each block */
324 size_t m_size;
325
326 /** Pools managed this manager */
328
329 /** Lock strategy to use */
330 LockStrategy m_lock_strategy;
331};
332
333#endif /* ut0pool_h */
static mysql_service_status_t init()
Component initialization.
Definition: audit_api_message_emit.cc:570
The class error is used to emit error messages.
Definition: ut0log.h:229
const char * p
Definition: ctype-mb.cc:1236
static mysql_service_status_t destroy(reference_caching_channel channel) noexcept
Definition: component.cc:49
Type
Definition: resource_group_basic_types.h:32
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:191
void * zalloc_withkey(PSI_memory_key_t key, std::size_t size) noexcept
Dynamically allocates zero-initialized storage of given size.
Definition: ut0new.h:630
void delete_(T *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::new*() variants.
Definition: ut0new.h:807
void free(void *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::malloc*(),...
Definition: ut0new.h:715
Definition: ut0pool.h:196
size_t m_size
Size of each block.
Definition: ut0pool.h:324
bool add_pool(size_t n_pools)
Add a new pool.
Definition: ut0pool.h:261
value_type * get()
Get an element from one of the pools.
Definition: ut0pool.h:210
LockStrategy m_lock_strategy
Lock strategy to use.
Definition: ut0pool.h:330
void create()
Create the pool manager.
Definition: ut0pool.h:293
PoolManager(const PoolManager &)
PoolManager(size_t size)
Definition: ut0pool.h:200
PoolManager & operator=(const PoolManager &)
Pools m_pools
Pools managed this manager.
Definition: ut0pool.h:327
~PoolManager()
Definition: ut0pool.h:202
PoolType::value_type value_type
Definition: ut0pool.h:198
std::vector< PoolType *, ut::allocator< PoolType * > > Pools
Definition: ut0pool.h:321
Pool PoolType
Definition: ut0pool.h:197
static void mem_free(value_type *ptr)
Definition: ut0pool.h:254
void destroy()
Release the resources.
Definition: ut0pool.h:301
Definition: ut0pool.h:51
Pool * m_pool
Definition: ut0pool.h:52
value_type m_type
Definition: ut0pool.h:53
Allocate the memory for the object in blocks.
Definition: ut0pool.h:46
LockStrategy m_lock_strategy
Lock strategy to use.
Definition: ut0pool.h:192
Pool(const Pool &)
~Pool()
Destructor.
Definition: ut0pool.h:83
std::priority_queue< Element *, std::vector< Element *, ut::allocator< Element * > >, std::greater< Element * > > pqueue_t
Definition: ut0pool.h:145
Pool(size_t size)
Constructor.
Definition: ut0pool.h:58
void init(size_t n_elems)
Initialise the elements.
Definition: ut0pool.h:163
pqueue_t m_pqueue
Priority queue ordered on the pointer addresses.
Definition: ut0pool.h:189
Type value_type
Definition: ut0pool.h:47
Element * m_last
Upper limit of used space.
Definition: ut0pool.h:186
size_t m_size
Size of the block in bytes.
Definition: ut0pool.h:183
Element * m_end
Pointer to the last element.
Definition: ut0pool.h:177
static void mem_free(value_type *ptr)
Add the object to the pool.
Definition: ut0pool.h:126
Pool & operator=(const Pool &)
void put(Element *elem)
Release the object to the free pool.
Definition: ut0pool.h:149
Type * get()
Get an object from the pool.
Definition: ut0pool.h:98
Element * m_start
Pointer to the first element.
Definition: ut0pool.h:180
double seconds()
Definition: task.cc:309
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:68
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:56
Dynamic memory allocation routines and custom allocators specifically crafted to support memory instr...
#define UT_NEW_THIS_FILE_PSI_KEY
Definition: ut0new.h:562
static int added
Definition: xcom_statistics.cc:99