1 /*
2    Copyright (c) 2006, 2010, 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 <ndb_global.h>
29 #include <kernel_types.h>
30 
31 /**
32  * Type bits
33  *
34  * Type id is 11 bits record type, and 5 bits resource id
35  *   -> 2048 different kind of records and 32 different resource groups
36  *
37  * Resource id is used to handle configuration parameters
38  *
39  * see blocks/records_types.hpp
40  */
41 #define RG_BITS 5
42 #define RG_MASK ((1 << RG_BITS) - 1)
43 #define MAKE_TID(TID,RG) ((TID << RG_BITS) | RG)
44 
45 /**
46  * Page bits
47  */
48 #define POOL_RECORD_BITS 13
49 #define POOL_RECORD_MASK ((1 << POOL_RECORD_BITS) - 1)
50 
51 /**
52  * Record_info
53  *
54  */
55 struct Record_info
56 {
57   Uint16 m_size;
58   Uint16 m_type_id;
59   Uint16 m_offset_next_pool;
60   Uint16 m_offset_magic;
61 };
62 
63 /**
64  * Resource_limit
65  */
66 struct Resource_limit
67 {
68   Uint32 m_min;
69   Uint32 m_max;
70   Uint32 m_curr;
71   Uint32 m_resource_id;
72 };
73 
74 struct Pool_context
75 {
Pool_contextPool_context76   Pool_context() {}
77   class SimulatedBlock* m_block;
78 
79   /**
80    * Get mem root
81    */
82   void* get_memroot();
83 
84   /**
85    * Alloc consekutive pages
86    *
87    *   @param i   : out : i value of first page
88    *   @return    : pointer to first page (NULL if failed)
89    *
90    * Will handle resource limit
91    */
92   void* alloc_page(Uint32 type_id, Uint32 *i);
93 
94   /**
95    * Release pages
96    *
97    *   @param i   : in : i value of first page
98    *   @param p   : in : pointer to first page
99    */
100   void release_page(Uint32 type_id, Uint32 i);
101 
102   /**
103    * Alloc consekutive pages
104    *
105    *   @param cnt : in/out : no of requested pages,
106    *                return no of allocated (undefined return NULL)
107    *                out will never be > in
108    *   @param i   : out : i value of first page
109    *   @param min : in : will never allocate less than min
110    *   @return    : pointer to first page (NULL if failed)
111    *
112    * Will handle resource limit
113    */
114   void* alloc_pages(Uint32 type_id, Uint32 *i, Uint32 *cnt, Uint32 min =1);
115 
116   /**
117    * Release pages
118    *
119    *   @param i   : in : i value of first page
120    *   @param p   : in : pointer to first page
121    *   @param cnt : in : no of pages to release
122    */
123   void release_pages(Uint32 type_id, Uint32 i, Uint32 cnt);
124 
125   /**
126    * Abort
127    */
128   void handleAbort(int code, const char* msg) ATTRIBUTE_NORETURN;
129 };
130 
131 template <typename T>
132 struct Ptr
133 {
134   T * p;
135   Uint32 i;
isNullPtr136   inline bool isNull() const { return i == RNIL; }
setNullPtr137   inline void setNull() { i = RNIL; }
138 };
139 
140 template <typename T>
141 struct ConstPtr
142 {
143   const T * p;
144   Uint32 i;
isNullConstPtr145   inline bool isNull() const { return i == RNIL; }
setNullConstPtr146   inline void setNull() { i = RNIL; }
147 };
148 
149 #ifdef XX_DOCUMENTATION_XX
150 /**
151  * Any pool should implement the following
152  */
153 struct PoolImpl
154 {
155   Pool_context m_ctx;
156   Record_info m_record_info;
157 
158   void init(const Record_info& ri, const Pool_context& pc);
159   void init(const Record_info& ri, const Pool_context& pc);
160 
161   bool seize(Ptr<void>&);
162   void release(Ptr<void>);
163   void * getPtr(Uint32 i);
164 };
165 #endif
166 
167 struct ArenaHead; // forward decl.
168 class ArenaAllocator; // forward decl.
169 
170 template <typename T, typename P>
171 class RecordPool {
172 public:
173   RecordPool();
174   ~RecordPool();
175 
176   void init(Uint32 type_id, const Pool_context& pc);
177   void wo_pool_init(Uint32 type_id, const Pool_context& pc);
178   void arena_pool_init(ArenaAllocator*, Uint32 type_id, const Pool_context& pc);
179 
180   /**
181    * Update p value for ptr according to i value
182    */
183   void getPtr(Ptr<T> &);
184   void getPtr(ConstPtr<T> &) const;
185 
186   /**
187    * Get pointer for i value
188    */
189   T * getPtr(Uint32 i);
190   const T * getConstPtr(Uint32 i) const;
191 
192   /**
193    * Update p & i value for ptr according to <b>i</b> value
194    */
195   void getPtr(Ptr<T> &, Uint32 i);
196   void getPtr(ConstPtr<T> &, Uint32 i) const;
197 
198   /**
199    * Allocate an object from pool - update Ptr
200    *
201    * Return i
202    */
203   bool seize(Ptr<T> &);
204 
205   /**
206    * Allocate object from arena - update Ptr
207    */
208   bool seize(ArenaHead&, Ptr<T>&);
209 
210   /**
211    * Return an object to pool
212    */
213   void release(Uint32 i);
214 
215   /**
216    * Return an object to pool
217    */
218   void release(Ptr<T>);
219 private:
220   P m_pool;
221 };
222 
223 template <typename T, typename P>
224 inline
RecordPool()225 RecordPool<T, P>::RecordPool()
226 {
227 }
228 
229 template <typename T, typename P>
230 inline
231 void
init(Uint32 type_id,const Pool_context & pc)232 RecordPool<T, P>::init(Uint32 type_id, const Pool_context& pc)
233 {
234   T tmp;
235   const char * off_base = (char*)&tmp;
236   const char * off_next = (char*)&tmp.nextPool;
237   const char * off_magic = (char*)&tmp.m_magic;
238 
239   Record_info ri;
240   ri.m_size = sizeof(T);
241   ri.m_offset_next_pool = Uint32(off_next - off_base);
242   ri.m_offset_magic = Uint32(off_magic - off_base);
243   ri.m_type_id = type_id;
244   m_pool.init(ri, pc);
245 }
246 
247 template <typename T, typename P>
248 inline
249 void
wo_pool_init(Uint32 type_id,const Pool_context & pc)250 RecordPool<T, P>::wo_pool_init(Uint32 type_id, const Pool_context& pc)
251 {
252   T tmp;
253   const char * off_base = (char*)&tmp;
254   const char * off_magic = (char*)&tmp.m_magic;
255 
256   Record_info ri;
257   ri.m_size = sizeof(T);
258   ri.m_offset_next_pool = 0;
259   ri.m_offset_magic = Uint32(off_magic - off_base);
260   ri.m_type_id = type_id;
261   m_pool.init(ri, pc);
262 }
263 
264 template <typename T, typename P>
265 inline
266 void
arena_pool_init(ArenaAllocator * alloc,Uint32 type_id,const Pool_context & pc)267 RecordPool<T, P>::arena_pool_init(ArenaAllocator* alloc,
268                                   Uint32 type_id, const Pool_context& pc)
269 {
270   T tmp;
271   const char * off_base = (char*)&tmp;
272   const char * off_next = (char*)&tmp.nextPool;
273   const char * off_magic = (char*)&tmp.m_magic;
274 
275   Record_info ri;
276   ri.m_size = sizeof(T);
277   ri.m_offset_next_pool = Uint32(off_next - off_base);
278   ri.m_offset_magic = Uint32(off_magic - off_base);
279   ri.m_type_id = type_id;
280   m_pool.init(alloc, ri, pc);
281 }
282 
283 
284 template <typename T, typename P>
285 inline
~RecordPool()286 RecordPool<T, P>::~RecordPool()
287 {
288 }
289 
290 
291 template <typename T, typename P>
292 inline
293 void
getPtr(Ptr<T> & ptr)294 RecordPool<T, P>::getPtr(Ptr<T> & ptr)
295 {
296   ptr.p = static_cast<T*>(m_pool.getPtr(ptr.i));
297 }
298 
299 template <typename T, typename P>
300 inline
301 void
getPtr(ConstPtr<T> & ptr) const302 RecordPool<T, P>::getPtr(ConstPtr<T> & ptr) const
303 {
304   ptr.p = static_cast<const T*>(m_pool.getPtr(ptr.i));
305 }
306 
307 template <typename T, typename P>
308 inline
309 void
getPtr(Ptr<T> & ptr,Uint32 i)310 RecordPool<T, P>::getPtr(Ptr<T> & ptr, Uint32 i)
311 {
312   ptr.i = i;
313   ptr.p = static_cast<T*>(m_pool.getPtr(ptr.i));
314 }
315 
316 template <typename T, typename P>
317 inline
318 void
getPtr(ConstPtr<T> & ptr,Uint32 i) const319 RecordPool<T, P>::getPtr(ConstPtr<T> & ptr, Uint32 i) const
320 {
321   ptr.i = i;
322   ptr.p = static_cast<const T*>(m_pool.getPtr(ptr.i));
323 }
324 
325 template <typename T, typename P>
326 inline
327 T *
getPtr(Uint32 i)328 RecordPool<T, P>::getPtr(Uint32 i)
329 {
330   return static_cast<T*>(m_pool.getPtr(i));
331 }
332 
333 template <typename T, typename P>
334 inline
335 const T *
getConstPtr(Uint32 i) const336 RecordPool<T, P>::getConstPtr(Uint32 i) const
337 {
338   return static_cast<const T*>(m_pool.getPtr(i));
339 }
340 
341 template <typename T, typename P>
342 inline
343 bool
seize(Ptr<T> & ptr)344 RecordPool<T, P>::seize(Ptr<T> & ptr)
345 {
346   Ptr<void> tmp;
347   bool ret = m_pool.seize(tmp);
348   if(likely(ret))
349   {
350     ptr.i = tmp.i;
351     ptr.p = static_cast<T*>(tmp.p);
352   }
353   return ret;
354 }
355 
356 template <typename T, typename P>
357 inline
358 bool
seize(ArenaHead & ah,Ptr<T> & ptr)359 RecordPool<T, P>::seize(ArenaHead & ah, Ptr<T> & ptr)
360 {
361   Ptr<void> tmp;
362   bool ret = m_pool.seize(ah, tmp);
363   if(likely(ret))
364   {
365     ptr.i = tmp.i;
366     ptr.p = static_cast<T*>(tmp.p);
367   }
368   return ret;
369 }
370 
371 template <typename T, typename P>
372 inline
373 void
release(Uint32 i)374 RecordPool<T, P>::release(Uint32 i)
375 {
376   Ptr<void> ptr;
377   ptr.i = i;
378   ptr.p = m_pool.getPtr(i);
379   m_pool.release(ptr);
380 }
381 
382 template <typename T, typename P>
383 inline
384 void
release(Ptr<T> ptr)385 RecordPool<T, P>::release(Ptr<T> ptr)
386 {
387   Ptr<void> tmp;
388   tmp.i = ptr.i;
389   tmp.p = ptr.p;
390   m_pool.release(tmp);
391 }
392 
393 #endif
394