1 /*
2    Copyright (c) 2018, 2019 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 COMPOSEDSLOTPOOL_HPP
26 #define COMPOSEDSLOTPOOL_HPP
27 
28 #include "blocks/record_types.hpp"
29 #include "ndb_global.h"
30 #include "ndb_limits.h"
31 #include "ndb_types.h"
32 #include "vm/Pool.hpp"
33 
34 #define JAM_FILE_ID 510
35 
36 #define COMPOSED_SLOT_POOL_NO_MAX_COUNT
37 
38 template <typename Pool1, typename Pool2>
39 class ComposedSlotPool
40 {
41  public:
42   typedef Slot Type;
43   ComposedSlotPool();
44   Uint32 getUncheckedPtrs(Uint32* from,
45                           Ptr<Slot> ptrs[],
46                           Uint32 cnt,
47                           Uint32 slot_size) const;
48   Uint32 getEntrySize() const;
49   Uint32 getNoOfFree() const;
50   Uint32 getSize() const;
51   Uint32 getUsed() const;
52   Uint32 getUsedHi() const;
53   void resetUsedHi();
54 
55   static Uint64 getMemoryNeed(Uint32 slot_size, Uint32 entry_count);
56   bool seize(Ptr<Slot>& p, Uint32 slot_size);
57   bool seize_pool2(Ptr<Slot>& p, Uint32 slot_size);
58   void release(Ptr<Slot> p, Uint32 slot_size);
59   void init(Uint32 type_id,
60             unsigned int slot_size,
61             Uint32* min_recs,
62             Uint32 max_recs,
63             const Pool_context& pool_ctx);
64 #if defined(VM_TRACE) || defined(ERROR_INSERT)
65   void resetMaxSize();
66   void setMaxSize(Uint32 max_recs);
67 #endif
68   bool startup(Uint32 slot_size);
69   bool getValidPtr(Ptr<Slot>& p, Uint32 magic, Uint32 slot_size) const;
70   bool getValidPtr_pool2(Ptr<Slot>& p, Uint32 magic, Uint32 slot_size) const;
71   bool getUncheckedPtrRO(Ptr<Slot>& p, Uint32 slot_size) const;
72   bool getUncheckedPtrRO_pool2(Ptr<Slot>& p, Uint32 slot_size) const;
73   bool getUncheckedPtrRW(Ptr<Slot>& p, Uint32 slot_size) const;
74   bool getUncheckedPtrRW_pool2(Ptr<Slot>& p, Uint32 slot_size) const;
75   bool may_shrink() const;
76   bool rearrange_free_list_and_shrink(Uint32 max_shrinks);
77 
78  private:
79   bool inPool1(Uint32 i) const;
80   Uint32 toPool2(Uint32 i) const;
81   Uint32 fromPool2(Uint32 i) const;
82 
83   Pool1 m_pool1;
84 #if !defined(COMPOSED_SLOT_POOL_NO_MAX_COUNT) || defined(VM_TRACE) || defined(ERROR_INSERT)
85   Uint32 m_max_count;
86 #endif
87   Uint32 m_use_count;
88   Uint32 m_used_high;
89   Uint32 m_shrink_level;
90   Pool2 m_pool2;
91   Uint32 m_slot_size;
92   Uint32 m_pool1_startup_count;
93 #if defined(VM_TRACE) || defined(ERROR_INSERT)
94   Uint32 m_orig_max_count;
95 #endif
96 };
97 
98 template <typename Pool1, typename Pool2>
ComposedSlotPool()99 inline ComposedSlotPool<Pool1, Pool2>::ComposedSlotPool()
100     :
101 #if !defined(COMPOSED_SLOT_POOL_NO_MAX_COUNT)
102       m_max_count(0),
103 #elif defined(VM_TRACE) || defined(ERROR_INSERT)
104       m_max_count(RNIL),
105 #endif
106       m_use_count(0),
107       m_used_high(0),
108       m_shrink_level(0),
109       m_slot_size(0),
110       m_pool1_startup_count(0)
111 #if defined(VM_TRACE) || defined(ERROR_INSERT)
112       ,
113       m_orig_max_count(m_max_count)
114 #endif
115 {
116 }
117 
118 template <typename Pool1, typename Pool2>
getUncheckedPtrs(Uint32 * from,Ptr<Slot> ptrs[],Uint32 cnt,Uint32 slot_size) const119 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getUncheckedPtrs(
120     Uint32* from, Ptr<Slot> ptrs[], Uint32 cnt, Uint32 slot_size) const
121 {
122   const Uint32 i = *from;
123   if (likely(inPool1(i)) || (i == RNIL && inPool1(0)))
124   {
125     Uint32 ptr_cnts = m_pool1.getUncheckedPtrs(from, ptrs, cnt, slot_size);
126     if (unlikely(*from == RNIL) && m_pool2.getSize() > 0)
127     {
128       *from = m_pool1.getSize();
129     }
130     return ptr_cnts;
131   }
132   Uint32 from2 = toPool2(i);
133   Uint32 ptr_cnts = m_pool2.getUncheckedPtrs(&from2, ptrs, cnt, slot_size);
134   for (Uint32 i = 0; i < ptr_cnts; i++)
135   {
136     ptrs[i].i = fromPool2(ptrs[i].i);
137   }
138   *from = fromPool2(from2);
139   return ptr_cnts;
140 }
141 
142 template <typename Pool1, typename Pool2>
getEntrySize() const143 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getEntrySize() const
144 {
145   return m_slot_size;
146 }
147 
148 template <typename Pool1, typename Pool2>
getNoOfFree() const149 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getNoOfFree() const
150 {
151   return getSize() - getUsed();
152 }
153 
154 template <typename Pool1, typename Pool2>
getSize() const155 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getSize() const
156 {
157   return m_pool1.getSize() + m_pool2.getSize();
158 }
159 
160 template <typename Pool1, typename Pool2>
getUsed() const161 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getUsed() const
162 {
163   return m_use_count;
164 }
165 
166 template <typename Pool1, typename Pool2>
getUsedHi() const167 inline Uint32 ComposedSlotPool<Pool1, Pool2>::getUsedHi() const
168 {
169   return m_used_high;
170 }
171 
172 template <typename Pool1, typename Pool2>
resetUsedHi()173 inline void ComposedSlotPool<Pool1, Pool2>::resetUsedHi()
174 {
175   m_used_high = m_use_count;
176 }
177 
178 template <typename Pool1, typename Pool2>
getMemoryNeed(Uint32 slot_size,Uint32 entry_count)179 inline Uint64 ComposedSlotPool<Pool1, Pool2>::getMemoryNeed(
180     Uint32 slot_size, Uint32 entry_count)
181 {
182   return Pool1::getMemoryNeed(slot_size, entry_count) +
183          Pool2::getMemoryNeed(slot_size, entry_count);
184 }
185 
186 template <typename Pool1, typename Pool2>
seize(Ptr<Slot> & p,Uint32 slot_size)187 inline bool ComposedSlotPool<Pool1, Pool2>::seize(Ptr<Slot>& p,
188                                                   Uint32 slot_size)
189 {
190 #if !defined(COMPOSED_SLOT_POOL_NO_MAX_COUNT) || defined(VM_TRACE) || defined(ERROR_INSERT)
191   const Uint32 max_count = m_max_count;
192 #endif
193   const Uint32 use_count = m_use_count;
194   const Uint32 new_use_count = use_count + 1;
195   const Uint32 used_high = m_used_high;
196 #if !defined(COMPOSED_SLOT_POOL_NO_MAX_COUNT)
197   if (unlikely(use_count == max_count))
198   {
199     return false;
200   }
201 #elif defined(VM_TRACE) || defined(ERROR_INSERT)
202   if (unlikely(use_count >= max_count))
203   {
204     return false;
205   }
206 #endif
207   if (unlikely(!m_pool1.seize(p, slot_size)))
208   {
209     if (!seize_pool2(p, slot_size))
210     {
211       return false;
212     }
213   }
214   m_use_count = new_use_count;
215   if (used_high < new_use_count)
216   {
217     m_used_high = new_use_count;
218   }
219   return true;
220 }
221 
222 template <typename Pool1, typename Pool2>
seize_pool2(Ptr<Slot> & p,Uint32 slot_size)223 inline bool ComposedSlotPool<Pool1, Pool2>::seize_pool2(Ptr<Slot>& p,
224                                                   Uint32 slot_size)
225 {
226   if (!m_pool2.seize(p, slot_size))
227   {
228     return false;
229   }
230   p.i = fromPool2(p.i);
231   return true;
232 }
233 
234 template <typename Pool1, typename Pool2>
release(Ptr<Slot> p,Uint32 slot_size)235 inline void ComposedSlotPool<Pool1, Pool2>::release(Ptr<Slot> p,
236                                                     Uint32 slot_size)
237 {
238   const Uint32 use_count = m_use_count;
239   const Uint32 new_use_count = use_count - 1;
240   if (likely(inPool1(p.i)))
241   {
242     m_pool1.release(p, slot_size);
243   }
244   else
245   {
246     p.i = toPool2(p.i);
247     m_pool2.release(p, slot_size);
248   }
249   m_use_count = new_use_count;
250 }
251 
252 template <typename Pool1, typename Pool2>
init(Uint32 type_id,unsigned int slot_size,Uint32 * min_recs,Uint32 max_recs,const Pool_context & pool_ctx)253 inline void ComposedSlotPool<Pool1, Pool2>::init(Uint32 type_id,
254                                                  unsigned int slot_size,
255                                                  Uint32* min_recs,
256                                                  Uint32 max_recs,
257                                                  const Pool_context& pool_ctx)
258 {
259 #if !defined(COMPOSED_SLOT_POOL_NO_MAX_COUNT)
260   m_max_count = max_recs;
261 #else
262   (void) max_recs;
263 #endif
264 #if defined(VM_TRACE) || defined(ERROR_INSERT)
265   m_orig_max_count = m_max_count;
266 #endif
267   const Uint32 req_recs = *min_recs;
268   Uint32 pool1_recs = req_recs;
269   m_pool1.init(type_id, slot_size, &pool1_recs, pool_ctx);
270   Uint32 pool2_recs = req_recs - pool1_recs;
271   m_pool2.init(type_id, slot_size, &pool2_recs, pool_ctx);
272   *min_recs = pool1_recs + pool2_recs;
273 
274   m_slot_size = slot_size;
275   m_shrink_level = (16384 / slot_size); /* slots on a half page */
276 }
277 
278 template <typename Pool1, typename Pool2>
startup(Uint32 slot_size)279 inline bool ComposedSlotPool<Pool1, Pool2>::startup(Uint32 slot_size)
280 {
281   return m_pool1.startup(&m_pool1_startup_count, slot_size);
282 }
283 
284 #if defined(VM_TRACE) || defined(ERROR_INSERT)
285 template <typename Pool1, typename Pool2>
resetMaxSize()286 inline void ComposedSlotPool<Pool1, Pool2>::resetMaxSize()
287 {
288   m_max_count = m_orig_max_count;
289 }
290 
291 template <typename Pool1, typename Pool2>
setMaxSize(Uint32 max_recs)292 inline void ComposedSlotPool<Pool1, Pool2>::setMaxSize(Uint32 max_recs)
293 {
294   m_max_count = max_recs;
295 }
296 #endif
297 
298 template <typename Pool1, typename Pool2>
getValidPtr(Ptr<Slot> & p,Uint32 magic,Uint32 slot_size) const299 inline bool ComposedSlotPool<Pool1, Pool2>::getValidPtr(
300     Ptr<Slot>& p, Uint32 magic, Uint32 slot_size) const
301 {
302   if (likely(m_pool1.getValidPtr(p, magic, slot_size)))
303   {
304     return true;
305   }
306   if (likely(inPool1(p.i)))
307   {
308     return false;
309   }
310   return getValidPtr_pool2(p,magic, slot_size);
311 }
312 
313 template<typename Pool1, typename Pool2>
getValidPtr_pool2(Ptr<Slot> & p,Uint32 magic,Uint32 slot_size) const314 inline bool ComposedSlotPool<Pool1, Pool2>::getValidPtr_pool2(
315     Ptr<Slot>& p, Uint32 magic, Uint32 slot_size) const
316 {
317   p.i = toPool2(p.i);
318   bool ok = m_pool2.getValidPtr(p, magic, slot_size);
319   p.i = fromPool2(p.i);
320   return ok;
321 }
322 
323 template <typename Pool1, typename Pool2>
getUncheckedPtrRO(Ptr<Slot> & p,Uint32 slot_size) const324 inline bool ComposedSlotPool<Pool1, Pool2>::getUncheckedPtrRO(
325     Ptr<Slot>& p, Uint32 slot_size) const
326 {
327   if (likely(m_pool1.getUncheckedPtrRO(p, slot_size)))
328   {
329     return true;
330   }
331   if (likely(inPool1(p.i)))
332   {
333     return false;
334   }
335   return getUncheckedPtrRO_pool2(p, slot_size);
336 }
337 
338 template<typename Pool1, typename Pool2>
getUncheckedPtrRO_pool2(Ptr<Slot> & p,Uint32 slot_size) const339 inline bool ComposedSlotPool<Pool1, Pool2>::getUncheckedPtrRO_pool2(
340     Ptr<Slot>& p, Uint32 slot_size) const
341 {
342   p.i = toPool2(p.i);
343   bool ok = m_pool2.getUncheckedPtrRO(p, slot_size);
344   p.i = fromPool2(p.i);
345   return ok;
346 }
347 
348 template <typename Pool1, typename Pool2>
getUncheckedPtrRW(Ptr<Slot> & p,Uint32 slot_size) const349 inline bool ComposedSlotPool<Pool1, Pool2>::getUncheckedPtrRW(
350     Ptr<Slot>& p, Uint32 slot_size) const
351 {
352   if (likely(m_pool1.getUncheckedPtrRW(p, slot_size)))
353   {
354     return true;
355   }
356   if (likely(inPool1(p.i)))
357   {
358     return false;
359   }
360   return getUncheckedPtrRW_pool2(p, slot_size);
361 }
362 
363 template<typename Pool1, typename Pool2>
getUncheckedPtrRW_pool2(Ptr<Slot> & p,Uint32 slot_size) const364 inline bool ComposedSlotPool<Pool1, Pool2>::getUncheckedPtrRW_pool2(
365     Ptr<Slot>& p, Uint32 slot_size) const
366 {
367   p.i = toPool2(p.i);
368   bool ok = m_pool2.getUncheckedPtrRW(p, slot_size);
369   p.i = fromPool2(p.i);
370   return ok;
371 }
372 
373 template <typename Pool1, typename Pool2>
may_shrink() const374 inline bool ComposedSlotPool<Pool1, Pool2>::may_shrink() const
375 {
376   return unlikely(m_pool1.may_shrink() || m_pool2.may_shrink()) &&
377          (getNoOfFree() > m_shrink_level);
378 }
379 
380 template <typename Pool1, typename Pool2>
rearrange_free_list_and_shrink(Uint32 max_shrinks)381 inline bool ComposedSlotPool<Pool1, Pool2>::rearrange_free_list_and_shrink(
382     Uint32 max_shrinks)
383 {
384   bool more = false;
385   Uint32 pool1_shrinks = max_shrinks;
386   more |= m_pool1.rearrange_free_list_and_shrink(&pool1_shrinks, m_slot_size);
387   Uint32 pool2_shrinks = max_shrinks - pool1_shrinks;
388   more |= m_pool2.rearrange_free_list_and_shrink(&pool2_shrinks, m_slot_size);
389   return more;
390 }
391 
392 template <typename Pool1, typename Pool2>
inPool1(Uint32 i) const393 inline bool ComposedSlotPool<Pool1, Pool2>::inPool1(Uint32 i) const
394 {
395   return i < m_pool1.getSize();
396 }
397 
398 template <typename Pool1, typename Pool2>
toPool2(Uint32 i) const399 inline Uint32 ComposedSlotPool<Pool1, Pool2>::toPool2(Uint32 i) const
400 {
401   if (unlikely(i == RNIL)) return RNIL;
402   require(i >= m_pool1.getSize());
403   return i - m_pool1.getSize();
404 }
405 
406 template <typename Pool1, typename Pool2>
fromPool2(Uint32 i) const407 inline Uint32 ComposedSlotPool<Pool1, Pool2>::fromPool2(Uint32 i) const
408 {
409   if (unlikely(i == RNIL)) return RNIL;
410   assert(i < RNIL - m_pool1.getSize());
411   return (i + m_pool1.getSize());
412 }
413 
414 #undef JAM_FILE_ID
415 
416 #endif
417