1 /*
2    Copyright (c) 2006, 2021, Oracle and/or its affiliates.
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 NDBD_MALLOC_IMPL_H
26 #define NDBD_MALLOC_IMPL_H
27 
28 #include <kernel_types.h>
29 #include <Bitmask.hpp>
30 #include <assert.h>
31 #include "Pool.hpp"
32 #include <Vector.hpp>
33 
34 #define JAM_FILE_ID 291
35 
36 
37 /**
38  * 13 -> 8192 words -> 32768 bytes
39  * 18 -> 262144 words -> 1M
40  */
41 #define BMW_2LOG 13
42 #define BITMAP_WORDS (1 << BMW_2LOG)
43 
44 #define BPP_2LOG (BMW_2LOG + 5)
45 #define SPACE_PER_BMP_2LOG ((2 + BMW_2LOG) + BPP_2LOG)
46 
47 //#define BITMAP_WORDS GLOBAL_PAGE_SIZE_WORDS
48 
49 struct Alloc_page
50 {
51   Uint32 m_data[BITMAP_WORDS];
52 };
53 
54 struct InitChunk
55 {
56   Uint32 m_cnt;
57   Uint32 m_start;
58   Alloc_page* m_ptr;
59 };
60 
61 struct Free_page_data
62 {
63   Uint32 m_list;
64   Uint32 m_next;
65   Uint32 m_prev;
66   Uint32 m_size;
67 };
68 
69 #define FPD_2LOG 2
70 
71 class Ndbd_mem_manager
72 {
73 public:
74   Ndbd_mem_manager();
75 
76   void set_resource_limit(const Resource_limit& rl);
77   bool get_resource_limit(Uint32 id, Resource_limit& rl) const;
78   bool get_resource_limit_nolock(Uint32 id, Resource_limit& rl) const;
79 
80   bool init(Uint32 *watchCounter, bool allow_alloc_less_than_requested = true);
81   void map(Uint32 * watchCounter, bool memlock = false, Uint32 resources[] = 0);
82   void* get_memroot() const;
83 
84   void dump() const ;
85 
86   enum AllocZone
87   {
88     NDB_ZONE_LO  = 0, // Only allocate with page_id < (1 << 13)
89     NDB_ZONE_ANY = 1  // Allocate with any page_id
90   };
91 
92   void* alloc_page(Uint32 type, Uint32* i, enum AllocZone);
93   void release_page(Uint32 type, Uint32 i);
94 
95   void alloc_pages(Uint32 type, Uint32* i, Uint32 *cnt, Uint32 min = 1);
96   void release_pages(Uint32 type, Uint32 i, Uint32 cnt);
97 
98   /**
99    * Compute 2log of size
100    * @note size = 0     -> 0
101    * @note size > 65536 -> 16
102    */
103   static Uint32 ndb_log2(Uint32 size);
104 
105 private:
106   void grow(Uint32 start, Uint32 cnt);
107 
108 #define XX_RL_COUNT 10
109   /**
110    * Return pointer to free page data on page
111    */
112   static Free_page_data* get_free_page_data(Alloc_page*, Uint32 idx);
113   Vector<Uint32> m_used_bitmap_pages;
114 
115   Uint32 m_buddy_lists[2][16];
116   Resource_limit m_resource_limit[XX_RL_COUNT]; // RG_COUNT in record_types.hpp
117   Alloc_page * m_base_page;
118 
119   void release_impl(Uint32 zone, Uint32 start, Uint32 cnt);
120   void insert_free_list(Uint32 zone, Uint32 start, Uint32 cnt);
121   Uint32 remove_free_list(Uint32 zone, Uint32 start, Uint32 list);
122 
123   void set(Uint32 first, Uint32 last);
124   void clear(Uint32 first, Uint32 last);
125   void clear_and_set(Uint32 first, Uint32 last);
126   Uint32 check(Uint32 first, Uint32 last);
127 
128   void alloc(AllocZone, Uint32* ret, Uint32 *pages, Uint32 min_requested);
129   void alloc_impl(Uint32 zone, Uint32* ret, Uint32 *pages, Uint32 min);
130   void release(Uint32 start, Uint32 cnt);
131 
132   /**
133    * This is memory that has been allocated
134    *   but not yet mapped (i.e it is not possible to get it using alloc_page(s)
135    */
136   Vector<InitChunk> m_unmapped_chunks;
137 };
138 
139 inline
140 Free_page_data*
get_free_page_data(Alloc_page * ptr,Uint32 idx)141 Ndbd_mem_manager::get_free_page_data(Alloc_page* ptr, Uint32 idx)
142 {
143   assert(idx & ((1 << BPP_2LOG) - 1));
144   assert((idx & ((1 << BPP_2LOG) - 1)) != ((1 << BPP_2LOG) - 1));
145 
146   return (Free_page_data*)
147     (ptr->m_data + ((idx & ((BITMAP_WORDS >> FPD_2LOG) - 1)) << FPD_2LOG));
148 }
149 
150 inline
151 void
set(Uint32 first,Uint32 last)152 Ndbd_mem_manager::set(Uint32 first, Uint32 last)
153 {
154   Alloc_page * ptr = m_base_page;
155 #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8)
156   Uint32 bmp = first & ~((1 << BPP_2LOG) - 1);
157   assert((first >> BPP_2LOG) == (last >> BPP_2LOG));
158   assert(bmp < m_resource_limit[0].m_resource_id);
159 
160   first -= bmp;
161   last -= bmp;
162   ptr += bmp;
163 #endif
164   BitmaskImpl::set(BITMAP_WORDS, ptr->m_data, first);
165   BitmaskImpl::set(BITMAP_WORDS, ptr->m_data, last);
166 }
167 
168 inline
169 void
clear(Uint32 first,Uint32 last)170 Ndbd_mem_manager::clear(Uint32 first, Uint32 last)
171 {
172   Alloc_page * ptr = m_base_page;
173 #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8)
174   Uint32 bmp = first & ~((1 << BPP_2LOG) - 1);
175   assert((first >> BPP_2LOG) == (last >> BPP_2LOG));
176   assert(bmp < m_resource_limit[0].m_resource_id);
177 
178   first -= bmp;
179   last -= bmp;
180   ptr += bmp;
181 #endif
182   BitmaskImpl::clear(BITMAP_WORDS, ptr->m_data, first);
183   BitmaskImpl::clear(BITMAP_WORDS, ptr->m_data, last);
184 }
185 
186 inline
187 void
clear_and_set(Uint32 first,Uint32 last)188 Ndbd_mem_manager::clear_and_set(Uint32 first, Uint32 last)
189 {
190   Alloc_page * ptr = m_base_page;
191 #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8)
192   Uint32 bmp = first & ~((1 << BPP_2LOG) - 1);
193   assert((first >> BPP_2LOG) == (last >> BPP_2LOG));
194   assert(bmp < m_resource_limit[0].m_resource_id);
195 
196   first -= bmp;
197   last -= bmp;
198   ptr += bmp;
199 #endif
200   BitmaskImpl::clear(BITMAP_WORDS, ptr->m_data, first);
201   BitmaskImpl::clear(BITMAP_WORDS, ptr->m_data, last);
202   BitmaskImpl::set(BITMAP_WORDS, ptr->m_data, last+1);
203 }
204 
205 inline
206 Uint32
check(Uint32 first,Uint32 last)207 Ndbd_mem_manager::check(Uint32 first, Uint32 last)
208 {
209   Uint32 ret = 0;
210   Alloc_page * ptr = m_base_page;
211 #if ((SPACE_PER_BMP_2LOG < 32) && (SIZEOF_CHARP == 4)) || (SIZEOF_CHARP == 8)
212   Uint32 bmp = first & ~((1 << BPP_2LOG) - 1);
213   assert((first >> BPP_2LOG) == (last >> BPP_2LOG));
214   assert(bmp < m_resource_limit[0].m_resource_id);
215 
216   first -= bmp;
217   last -= bmp;
218   ptr += bmp;
219 #endif
220   ret |= BitmaskImpl::get(BITMAP_WORDS, ptr->m_data, first) << 0;
221   ret |= BitmaskImpl::get(BITMAP_WORDS, ptr->m_data, last) << 1;
222   return ret;
223 }
224 
225 
226 
227 #undef JAM_FILE_ID
228 
229 #endif
230