1 /*
2 Copyright (c) 2017, 2018, 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 #include "record_types.hpp"
26 #include "IntrusiveList.hpp"
27 #include "TransientPagePool.hpp"
28 #include "TransientSlotPool.hpp"
29
30 #define JAM_FILE_ID 505
31
TransientSlotPool()32 TransientSlotPool::TransientSlotPool()
33 : m_page_pool(NULL),
34 m_type_id(0),
35 // m_slot_size(0),
36 m_use_count(0),
37 // m_use_high(0),
38 m_may_shrink(false)//,
39 // m_shrink_level(0),
40 // m_static_initialized_slots(0)
41 {
42 m_free_list.init();
43 }
44
45
init(Uint32 type_id,Uint32 slot_size,Uint32 * min_recs,const Pool_context & pool_ctx)46 void TransientSlotPool::init(Uint32 type_id,
47 Uint32 slot_size,
48 Uint32* min_recs,
49 const Pool_context& pool_ctx)
50 {
51 // const Uint32 slots_per_page = Page::DATA_WORDS_PER_PAGE / slot_size;
52
53 m_page_pool = new TransientPagePool(type_id,
54 pool_ctx.get_mem_manager());
55 m_type_id = type_id;
56 *min_recs = 0;
57 // m_slot_size = slot_size;
58 // m_shrink_level = m_static.getSize() + (slots_per_page + 1) / 2;
59 // require(expand());
60 }
61
62
~TransientSlotPool()63 TransientSlotPool::~TransientSlotPool()
64 {
65 if (m_page_pool)
66 {
67 delete m_page_pool;
68 }
69 }
70
71
expand(Uint32 slot_size)72 bool TransientSlotPool::expand(Uint32 slot_size)
73 {
74 assert(m_free_list.isEmpty());
75 Ptr<TransientPagePool::Page> lpage;
76 if (unlikely(!m_page_pool->seize(lpage)))
77 {
78 return false;
79 }
80 Ptr<Page> page;
81 page.i = lpage.i;
82 page.p = reinterpret_cast<Page*>(lpage.p);
83
84 page.p->m_use_count = 0;
85 m_may_shrink = m_page_pool->getTopPageNumber() > 0;
86
87 // Add first slot to free list
88 const Uint32 slots_per_page = Page::DATA_WORDS_PER_PAGE / slot_size;
89 LocalSlotPool<TransientSlotPool> pool(this, slot_size);
90 Ptr<Type> free_record;
91 void *pv = static_cast<void*>(&page.p->m_data[0]);
92 free_record.p = new (pv) Type;
93 free_record.i = slots_per_page * page.i;
94 Slot_list free_list(pool, m_free_list);
95 free_list.addLast(free_record);
96 page.p->m_first_in_free_array = 1;
97
98 return true;
99 }
100
getMemoryNeed(Uint32 slot_size,Uint32 entry_count)101 Uint64 TransientSlotPool::getMemoryNeed(Uint32 slot_size, Uint32 entry_count)
102 {
103 const Uint64 entries_per_page = (Page::DATA_WORDS_PER_PAGE / slot_size);
104 const Uint64 data_pages =
105 ((entry_count + entries_per_page - 1) / entries_per_page);
106 return data_pages * sizeof(Page) + TransientPagePool::getMemoryNeed(data_pages);
107 }
108
getUncheckedPtrs(Uint32 * from,Ptr<Type> ptrs[],Uint32 cnt,Uint32 slot_size) const109 Uint32 TransientSlotPool::getUncheckedPtrs(Uint32* from,
110 Ptr<Type> ptrs[],
111 Uint32 cnt,
112 Uint32 slot_size) const
113 {
114 Uint32 index = *from;
115 const Uint32 slots_per_page = Page::DATA_WORDS_PER_PAGE / slot_size;
116 Uint32 page_number = index / slots_per_page;
117 Uint32 page_index = index % slots_per_page;
118 require(index != RNIL);
119
120 Ptr<TransientPagePool::Page> lpage;
121 lpage.i = page_number;
122 if (unlikely(!m_page_pool->getUncheckedPtr(lpage)))
123 {
124 Uint32 top_page = m_page_pool->getTopPageNumber();
125 if (top_page == RNIL || page_number >= top_page)
126 {
127 index = RNIL;
128 }
129 else
130 {
131 index = index - page_index + slots_per_page;
132 }
133 *from = index;
134 return 0;
135 }
136 Page* page = reinterpret_cast<Page*>(lpage.p);
137 const Uint32 end_index = page->m_first_in_free_array;
138 Uint32 *slot_ptr = &page->m_data[page_index * slot_size];
139 Uint32 ptrs_cnt = 0;
140 for (; ptrs_cnt < cnt && page_index < end_index;
141 page_index++, index++, ptrs_cnt++, slot_ptr += slot_size)
142 {
143 ptrs[ptrs_cnt].i = index;
144 ptrs[ptrs_cnt].p = reinterpret_cast<Type*>(slot_ptr);
145 }
146 if (unlikely(page_index >= end_index))
147 {
148 Uint32 top_page = m_page_pool->getTopPageNumber();
149 require(top_page != RNIL);
150 if (page_number == top_page)
151 {
152 index = RNIL;
153 }
154 else if (page_index < slots_per_page)
155 {
156 require(page_number < top_page);
157 require(page_index == end_index);
158 index = index - page_index + slots_per_page;
159 }
160 else
161 {
162 require(page_number < top_page);
163 require(end_index == slots_per_page);
164 }
165 }
166 *from = index;
167 return ptrs_cnt;
168 }
169
rearrange_free_list_and_shrink(Uint32 * max_shrinks,Uint32 slot_size)170 bool TransientSlotPool::rearrange_free_list_and_shrink(Uint32* max_shrinks, Uint32 slot_size)
171 {
172 Uint32 free = getNoOfFree();
173 if (free > 8)
174 {
175 free = 8;
176 }
177 if (free > 0)
178 {
179 Ptr<Type> ptr[8];
180 Uint32 j = 0;
181 for (Uint32 i = 0; i < free; i++)
182 {
183 if (likely(seize(ptr[j], slot_size)))
184 {
185 j++;
186 }
187 }
188 while (j > 0)
189 {
190 j--;
191 release(ptr[j], slot_size);
192 }
193 free--;
194 }
195 for (Uint32 shrink_count = 0; shrink_count < *max_shrinks; shrink_count++)
196 {
197 if (!shrink(slot_size))
198 {
199 *max_shrinks = shrink_count;
200 return false;
201 }
202 }
203 return true;
204 }
205
shrink(Uint32 slot_size)206 bool TransientSlotPool::shrink(Uint32 slot_size)
207 {
208 if(!may_shrink())
209 {
210 return false;
211 }
212 Uint32 page_number = m_page_pool->getTopPageNumber();
213 require(m_page_pool->canRelease(page_number));
214 Ptr<TransientPagePool::Page> lpage;
215 lpage.i = page_number;
216 require(m_page_pool->getPtr(lpage));
217 Page* page = reinterpret_cast<Page*>(lpage.p);
218 require(page->m_use_count == 0);
219
220 const Uint32 slots_per_page = Page::DATA_WORDS_PER_PAGE / slot_size;
221 Uint32 base_index = slots_per_page * lpage.i;
222
223 {
224 LocalSlotPool<TransientSlotPool> pool(this, slot_size);
225 Slot_list free_list(pool, m_free_list);
226 const Uint32 end_index = page->m_first_in_free_array;
227 for (unsigned i = 0; i < end_index; i++)
228 {
229 Ptr<Type> p;
230 p.p = reinterpret_cast<Type*>(&page->m_data[i * slot_size]);
231 p.i = base_index + i;
232 free_list.remove(p);
233 }
234 }
235 require(m_page_pool->release(lpage));
236
237 lpage.i = m_page_pool->getTopPageNumber();
238 if (!m_page_pool->canRelease(lpage.i))
239 {
240 m_may_shrink = false;
241 return false;
242 }
243 require(m_page_pool->getPtr(lpage));
244
245 page = reinterpret_cast<Page*>(lpage.p);
246 if (page->m_use_count != 0)
247 {
248 m_may_shrink = false;
249 return false;
250 }
251 return true;
252 }
253
254 #if !INLINE_TRANSIENT_SLOT_POOL
255 #define inline
256 #include "TransientSlotPool.inline.hpp.inc"
257 #endif
258