1 /*
2 Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
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
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #ifndef NDB_POOL_HPP
26 #define NDB_POOL_HPP
27
28 #include <climits>
29
30 #include <ndb_global.h>
31 #include <kernel_types.h>
32
33 #define JAM_FILE_ID 315
34
35
36 /**
37 * Type bits
38 *
39 * Type id is 11 bits record type, and 5 bits resource id
40 * -> 2048 different kind of records and 32 different resource groups
41 *
42 * Resource id is used to handle configuration parameters
43 *
44 * see blocks/records_types.hpp
45 */
46 #define RG_BITS 5
47 #define RG_MASK ((1 << RG_BITS) - 1)
48 #define MAKE_TID(TID,RG) Uint32((TID << RG_BITS) | RG)
49 #define GET_RG(rt) (rt & RG_MASK)
50 #define GET_TID(rt) (rt >> RG_BITS)
51
52 /**
53 * Page bits
54 */
55 #define POOL_RECORD_BITS 13
56 #define POOL_RECORD_MASK ((1 << POOL_RECORD_BITS) - 1)
57
58 /**
59 * Record_info
60 *
61 */
62 struct Record_info
63 {
64 Uint16 m_size;
65 Uint16 m_type_id;
66 Uint16 m_offset_next_pool;
67 Uint16 m_offset_magic;
68 };
69
70 /**
71 Contains both restrictions and current state of a resource groups page memory
72 usage.
73 */
74
75 struct Resource_limit
76 {
77 static constexpr Uint32 HIGHEST_LIMIT = UINT32_MAX;
78
79 /**
80 Minimal number of pages dedicated for the resource group from shared global
81 page memory.
82
83 If set to zero it also indicates that the resource group have lower
84 priority than resource group with some dedicated pages.
85
86 The lower priority denies the resource group to use the last percentage of
87 shared global page memory.
88
89 See documentation for Resource_limits.
90 */
91 Uint32 m_min;
92
93 /**
94 Maximal number of pages that the resource group may allocate from shared
95 global page memory.
96
97 If set to zero there is no restrictions caused by this member.
98 */
99 Uint32 m_max;
100
101 /**
102 Number of pages currently in use by resource group.
103 */
104 Uint32 m_curr;
105
106 /**
107 Number of pages currently reserved as spare.
108
109 These spare pages may be used in exceptional cases, and to use them one
110 need to call special allocations functions, see alloc_spare_page in
111 Ndbd_mem_manager.
112
113 See also m_spare_pct below.
114 */
115 Uint32 m_spare;
116
117 /**
118 The number of dedicated pages that a resource do not use but made available
119 for other resources to use, using give_up_pages().
120 */
121 Uint32 m_lent;
122
123 /**
124 The number of pages this resource use from pages otherwise dedicated to
125 other resources, using take_pages().
126 */
127 Uint32 m_borrowed;
128
129 /**
130 A positive number identifying the resource group.
131 */
132 Uint32 m_resource_id;
133
134 /**
135 Control how many spare pages there should be for each page in use.
136 */
137 Uint32 m_spare_pct;
138 };
139
140 class Magic
141 {
142 public:
Magic(Uint32 type_id)143 explicit Magic(Uint32 type_id) { m_magic = make(type_id); }
check(Uint32 type_id)144 bool check(Uint32 type_id) { return match(m_magic, type_id); }
check_ptr(const T * ptr)145 template<typename T> static bool check_ptr(const T* ptr) { return match(ptr->m_magic, T::TYPE_ID); }
146 static bool match(Uint32 magic, Uint32 type_id);
147 static Uint32 make(Uint32 type_id);
148 private:
149 Uint32 m_magic;
150 };
151
make(Uint32 type_id)152 inline Uint32 Magic::make(Uint32 type_id)
153 {
154 return type_id ^ ((~type_id) << 16);
155 }
156
match(Uint32 magic,Uint32 type_id)157 inline bool Magic::match(Uint32 magic, Uint32 type_id)
158 {
159 return magic == make(type_id);
160 }
161
162 class Ndbd_mem_manager;
163 struct Pool_context
164 {
Pool_contextPool_context165 Pool_context() {}
166 class SimulatedBlock* m_block;
167
168 /**
169 * Get mem root
170 */
171 void* get_memroot() const;
172 Ndbd_mem_manager* get_mem_manager() const;
173
174 /**
175 * Alloc page.
176 *
177 * @param[out] i i value of first page
178 * @return pointer to first page (NULL if failed)
179 *
180 * Will handle resource limit
181 */
182 void* alloc_page19(Uint32 type_id, Uint32 *i);
183 void* alloc_page27(Uint32 type_id, Uint32 *i);
184 void* alloc_page30(Uint32 type_id, Uint32 *i);
185 void* alloc_page32(Uint32 type_id, Uint32 *i);
186
187 /**
188 * Release page
189 *
190 * @param[in] i i value of first page
191 */
192 void release_page(Uint32 type_id, Uint32 i);
193
194 /**
195 * Alloc consekutive pages
196 *
197 * @param[in,out] cnt no of requested pages,
198 * return no of allocated (undefined return NULL)
199 * out will never be > in
200 * @param[out] i i value of first page
201 * @param[in] min will never allocate less than min
202 * @return pointer to first page (NULL if failed)
203 *
204 * Will handle resource limit
205 */
206 void* alloc_pages(Uint32 type_id, Uint32 *i, Uint32 *cnt, Uint32 min =1);
207
208 /**
209 * Release pages
210 *
211 * @param[in] i i value of first page
212 * @param[in] cnt no of pages to release
213 */
214 void release_pages(Uint32 type_id, Uint32 i, Uint32 cnt);
215
216 void* get_valid_page(Uint32 page_num) const;
217
218 /**
219 * Abort
220 */
221 [[noreturn]] void handleAbort(int code, const char* msg) const;
222 };
223
224 template <typename T>
225 struct Ptr
226 {
227 typedef Uint32 I;
228 T * p;
229 Uint32 i;
230
getPtr231 static Ptr get(T* _p, Uint32 _i) { Ptr x; x.p = _p; x.i = _i; return x; }
232
233 /**
234 Initialize to ffff.... in debug mode. The purpose of this is to detect
235 use of uninitialized values by causing an error. To maximize performance,
236 this is done in debug mode only (when asserts are enabled).
237 */
PtrPtr238 Ptr(){assert(memset(this, 0xff, sizeof(*this)));}
PtrPtr239 Ptr(T* pVal, Uint32 iVal):p(pVal), i(iVal){}
240
241
isNullPtr242 bool isNull() const
243 {
244 assert(i <= RNIL);
245 return i == RNIL;
246 }
247
setNullPtr248 inline void setNull()
249 {
250 i = RNIL;
251 }
252 };
253
254 template <typename T>
255 struct ConstPtr
256 {
257 const T * p;
258 Uint32 i;
259
getConstPtr260 static ConstPtr get(T const* _p, Uint32 _i) { ConstPtr x; x.p = _p; x.i = _i; return x; }
261
262 /**
263 Initialize to ffff.... in debug mode. The purpose of this is to detect
264 use of uninitialized values by causing an error. To maximize performance,
265 this is done in debug mode only (when asserts are enabled).
266 */
ConstPtrConstPtr267 ConstPtr(){assert(memset(this, 0xff, sizeof(*this)));}
ConstPtrConstPtr268 ConstPtr(T* pVal, Uint32 iVal):p(pVal), i(iVal){}
269
isNullConstPtr270 bool isNull() const
271 {
272 assert(i <= RNIL);
273 return i == RNIL;
274 }
275
setNullConstPtr276 inline void setNull()
277 {
278 i = RNIL;
279 }
280 };
281
282 #ifdef XX_DOCUMENTATION_XX
283 /**
284 * Any pool should implement the following
285 */
286 struct PoolImpl
287 {
288 Pool_context m_ctx;
289 Record_info m_record_info;
290
291 void init(const Record_info& ri, const Pool_context& pc);
292 void init(const Record_info& ri, const Pool_context& pc);
293
294 bool seize(Ptr<void>&);
295 void release(Ptr<void>);
296 void * getPtr(Uint32 i) const;
297 };
298 #endif
299
300 struct ArenaHead; // forward decl.
301 class ArenaAllocator; // forward decl.
302
303 template <typename P, typename T = typename P::Type>
304 class RecordPool {
305 public:
306 typedef T Type;
307 RecordPool();
308 ~RecordPool();
309
310 void init(Uint32 type_id, const Pool_context& pc);
311 void wo_pool_init(Uint32 type_id, const Pool_context& pc);
312 void arena_pool_init(ArenaAllocator*, Uint32 type_id, const Pool_context& pc);
313
314 /**
315 * Update p value for ptr according to i value
316 */
317 void getPtr(Ptr<T> &) const;
318 void getPtr(ConstPtr<T> &) const;
319
320 /**
321 * Get pointer for i value
322 */
323 T * getPtr(Uint32 i) const;
324 const T * getConstPtr(Uint32 i) const;
325
326 /**
327 * Update p & i value for ptr according to <b>i</b> value
328 */
329 void getPtr(Ptr<T> &, Uint32 i) const;
330 void getPtr(ConstPtr<T> &, Uint32 i) const;
331
332 /**
333 * Allocate an object from pool - update Ptr
334 *
335 * Return i
336 */
337 bool seize(Ptr<T> &);
338
339 /**
340 * Allocate object from arena - update Ptr
341 */
342 bool seize(ArenaHead&, Ptr<T>&);
343
344 /**
345 * Return an object to pool
346 */
347 void release(Uint32 i);
348
349 /**
350 * Return an object to pool
351 */
352 void release(Ptr<T>);
353 private:
354 P m_pool;
355 };
356
357 template <typename P, typename T>
358 inline
RecordPool()359 RecordPool<P, T>::RecordPool()
360 {
361 }
362
363 template <typename P, typename T>
364 inline
365 void
init(Uint32 type_id,const Pool_context & pc)366 RecordPool<P, T>::init(Uint32 type_id, const Pool_context& pc)
367 {
368 T tmp;
369 const char * off_base = (char*)&tmp;
370 const char * off_next = (char*)&tmp.nextPool;
371 const char * off_magic = (char*)&tmp.m_magic;
372
373 Record_info ri;
374 ri.m_size = sizeof(T);
375 ri.m_offset_next_pool = Uint32(off_next - off_base);
376 ri.m_offset_magic = Uint32(off_magic - off_base);
377 ri.m_type_id = type_id;
378 m_pool.init(ri, pc);
379 }
380
381 template <typename P, typename T>
382 inline
383 void
wo_pool_init(Uint32 type_id,const Pool_context & pc)384 RecordPool<P, T>::wo_pool_init(Uint32 type_id, const Pool_context& pc)
385 {
386 T tmp;
387 const char * off_base = (char*)&tmp;
388 const char * off_magic = (char*)&tmp.m_magic;
389
390 Record_info ri;
391 ri.m_size = sizeof(T);
392 ri.m_offset_next_pool = 0;
393 ri.m_offset_magic = Uint32(off_magic - off_base);
394 ri.m_type_id = type_id;
395 m_pool.init(ri, pc);
396 }
397
398 template <typename P, typename T>
399 inline
400 void
arena_pool_init(ArenaAllocator * alloc,Uint32 type_id,const Pool_context & pc)401 RecordPool<P, T>::arena_pool_init(ArenaAllocator* alloc,
402 Uint32 type_id, const Pool_context& pc)
403 {
404 T tmp;
405 const char * off_base = (char*)&tmp;
406 const char * off_next = (char*)&tmp.nextPool;
407 const char * off_magic = (char*)&tmp.m_magic;
408
409 Record_info ri;
410 ri.m_size = sizeof(T);
411 ri.m_offset_next_pool = Uint32(off_next - off_base);
412 ri.m_offset_magic = Uint32(off_magic - off_base);
413 ri.m_type_id = type_id;
414 m_pool.init(alloc, ri, pc);
415 }
416
417
418 template <typename P, typename T>
419 inline
~RecordPool()420 RecordPool<P, T>::~RecordPool()
421 {
422 }
423
424
425 template <typename P, typename T>
426 inline
427 void
getPtr(Ptr<T> & ptr) const428 RecordPool<P, T>::getPtr(Ptr<T> & ptr) const
429 {
430 ptr.p = static_cast<T*>(m_pool.getPtr(ptr.i));
431 }
432
433 template <typename P, typename T>
434 inline
435 void
getPtr(ConstPtr<T> & ptr) const436 RecordPool<P, T>::getPtr(ConstPtr<T> & ptr) const
437 {
438 ptr.p = static_cast<const T*>(m_pool.getPtr(ptr.i));
439 }
440
441 template <typename P, typename T>
442 inline
443 void
getPtr(Ptr<T> & ptr,Uint32 i) const444 RecordPool<P, T>::getPtr(Ptr<T> & ptr, Uint32 i) const
445 {
446 ptr.i = i;
447 ptr.p = static_cast<T*>(m_pool.getPtr(ptr.i));
448 }
449
450 template <typename P, typename T>
451 inline
452 void
getPtr(ConstPtr<T> & ptr,Uint32 i) const453 RecordPool<P, T>::getPtr(ConstPtr<T> & ptr, Uint32 i) const
454 {
455 ptr.i = i;
456 ptr.p = static_cast<const T*>(m_pool.getPtr(ptr.i));
457 }
458
459 template <typename P, typename T>
460 inline
461 T *
getPtr(Uint32 i) const462 RecordPool<P, T>::getPtr(Uint32 i) const
463 {
464 return static_cast<T*>(m_pool.getPtr(i));
465 }
466
467 template <typename P, typename T>
468 inline
469 const T *
getConstPtr(Uint32 i) const470 RecordPool<P, T>::getConstPtr(Uint32 i) const
471 {
472 return static_cast<const T*>(m_pool.getPtr(i));
473 }
474
475 template <typename P, typename T>
476 inline
477 bool
seize(Ptr<T> & ptr)478 RecordPool<P, T>::seize(Ptr<T> & ptr)
479 {
480 Ptr<T> tmp;
481 bool ret = m_pool.seize(tmp);
482 if(likely(ret))
483 {
484 ptr.i = tmp.i;
485 ptr.p = static_cast<T*>(tmp.p);
486 }
487 return ret;
488 }
489
490 template <typename P, typename T>
491 inline
492 bool
seize(ArenaHead & ah,Ptr<T> & ptr)493 RecordPool<P, T>::seize(ArenaHead & ah, Ptr<T> & ptr)
494 {
495 Ptr<T> tmp;
496 bool ret = m_pool.seize(ah, tmp);
497 if(likely(ret))
498 {
499 ptr.i = tmp.i;
500 ptr.p = static_cast<T*>(tmp.p);
501 }
502 return ret;
503 }
504
505 template <typename P, typename T>
506 inline
507 void
release(Uint32 i)508 RecordPool<P, T>::release(Uint32 i)
509 {
510 Ptr<T> ptr;
511 ptr.i = i;
512 ptr.p = m_pool.getPtr(i);
513 m_pool.release(ptr);
514 }
515
516 template <typename P, typename T>
517 inline
518 void
release(Ptr<T> ptr)519 RecordPool<P, T>::release(Ptr<T> ptr)
520 {
521 Ptr<T> tmp;
522 tmp.i = ptr.i;
523 tmp.p = ptr.p;
524 m_pool.release(tmp);
525 }
526
527
528 #undef JAM_FILE_ID
529
530 #endif
531