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