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