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