1 /*
2 Copyright (c) 2006, 2014, 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 "RWPool.hpp"
26 #include <ndbd_exit_codes.h>
27 #include <NdbOut.hpp>
28
29 #define JAM_FILE_ID 278
30
31
32 #define REC_NIL GLOBAL_PAGE_SIZE_WORDS
33
RWPool()34 RWPool::RWPool()
35 {
36 memset(this, 0, sizeof(* this));
37 m_current_pos = RWPage::RWPAGE_WORDS;
38 m_current_first_free = REC_NIL;
39 m_first_free_page = RNIL;
40 }
41
42 void
init(const Record_info & ri,const Pool_context & pc)43 RWPool::init(const Record_info& ri, const Pool_context& pc)
44 {
45 m_ctx = pc;
46 m_record_info = ri;
47 m_record_info.m_size = ((ri.m_size + 3) >> 2); // Align to word boundary
48 m_record_info.m_offset_magic = ((ri.m_offset_magic + 3) >> 2);
49 m_record_info.m_offset_next_pool = ((ri.m_offset_next_pool + 3) >> 2);
50 m_memroot = (RWPage*)m_ctx.get_memroot();
51 #ifdef VM_TRACE
52 ndbout_c("RWPool::init(%x, %d)",ri.m_type_id, m_record_info.m_size);
53 #endif
54 }
55
56 bool
seize(Ptr<void> & ptr)57 RWPool::seize(Ptr<void>& ptr)
58 {
59 Uint32 pos = m_current_pos;
60 Uint32 size = m_record_info.m_size;
61 Uint32 off = m_record_info.m_offset_magic;
62 RWPage *pageP = m_current_page;
63 if (likely(m_current_first_free != REC_NIL))
64 {
65 seize_free:
66 pos = m_current_first_free;
67 ptr.i = (m_current_page_no << POOL_RECORD_BITS) + pos;
68 ptr.p = pageP->m_data + pos;
69 pageP->m_data[pos+off] = ~(Uint32)m_record_info.m_type_id;
70 m_current_ref_count++;
71 m_current_first_free = pageP->m_data[pos+m_record_info.m_offset_next_pool];
72 return true;
73 }
74 else if (pos + size < RWPage::RWPAGE_WORDS)
75 {
76 seize_first:
77 ptr.i = (m_current_page_no << POOL_RECORD_BITS) + pos;
78 ptr.p = (pageP->m_data + pos);
79 pageP->m_data[pos+off] = ~(Uint32)m_record_info.m_type_id;
80 m_current_ref_count++;
81 m_current_pos = pos + size;
82 return true;
83 }
84
85 if (m_current_page)
86 {
87 m_current_page->m_first_free = REC_NIL;
88 m_current_page->m_next_page = RNIL;
89 m_current_page->m_prev_page = RNIL;
90 m_current_page->m_type_id = m_record_info.m_type_id;
91 m_current_page->m_ref_count = m_current_ref_count;
92 }
93
94 if (m_first_free_page != RNIL)
95 {
96 pageP = m_current_page = m_memroot + m_first_free_page;
97 m_current_page_no = m_first_free_page;
98 m_current_pos = RWPage::RWPAGE_WORDS;
99 m_current_first_free = m_current_page->m_first_free;
100 m_first_free_page = m_current_page->m_next_page;
101 m_current_ref_count = m_current_page->m_ref_count;
102 if (m_first_free_page != RNIL)
103 {
104 (m_memroot + m_first_free_page)->m_prev_page = RNIL;
105 }
106 goto seize_free;
107 }
108
109 m_current_ref_count = 0;
110
111 RWPage* page;
112 Uint32 page_no = RNIL;
113 if ((page = (RWPage*)m_ctx.alloc_page(m_record_info.m_type_id, &page_no)))
114 {
115 pos = 0;
116 m_current_page_no = page_no;
117 pageP = m_current_page = page;
118 m_current_first_free = REC_NIL;
119 page->m_type_id = m_record_info.m_type_id;
120 goto seize_first;
121 }
122
123 m_current_page = 0;
124 m_current_page_no = RNIL;
125 m_current_pos = RWPage::RWPAGE_WORDS;
126 m_current_first_free = REC_NIL;
127
128 return false;
129 }
130
131 void
release(Ptr<void> ptr)132 RWPool::release(Ptr<void> ptr)
133 {
134 Uint32 cur_page = m_current_page_no;
135 Uint32 ptr_page = ptr.i >> POOL_RECORD_BITS;
136 Uint32 *record_ptr = (Uint32*)ptr.p;
137 Uint32 magic_val = * (record_ptr + m_record_info.m_offset_magic);
138
139 if (likely(magic_val == ~(Uint32)m_record_info.m_type_id))
140 {
141 * (record_ptr + m_record_info.m_offset_magic) = 0;
142 if (cur_page == ptr_page)
143 {
144 * (record_ptr + m_record_info.m_offset_next_pool) = m_current_first_free;
145 assert(m_current_ref_count);
146 m_current_ref_count--;
147 m_current_first_free = ptr.i & POOL_RECORD_MASK;
148 return;
149 }
150
151 // Cache miss on page...
152 RWPage* page = m_memroot + ptr_page;
153 Uint32 ref_cnt = page->m_ref_count;
154 Uint32 ff = page->m_first_free;
155
156 * (record_ptr + m_record_info.m_offset_next_pool) = ff;
157 page->m_first_free = ptr.i & POOL_RECORD_MASK;
158 page->m_ref_count = ref_cnt - 1;
159
160 if (ff == REC_NIL)
161 {
162 /**
163 * It was full...add to free page list
164 */
165 Uint32 ffp = m_first_free_page;
166 if (ffp != RNIL)
167 {
168 RWPage* next = (m_memroot + ffp);
169 assert(next->m_prev_page == RNIL);
170 next->m_prev_page = ptr_page;
171 }
172 page->m_next_page = ffp;
173 page->m_prev_page = RNIL;
174 m_first_free_page = ptr_page;
175 return;
176 }
177 else if(ref_cnt == 1)
178 {
179 /**
180 * It's now empty...release it
181 */
182 Uint32 prev = page->m_prev_page;
183 Uint32 next = page->m_next_page;
184 if (prev != RNIL)
185 {
186 (m_memroot + prev)->m_next_page = next;
187 }
188 else
189 {
190 assert(m_first_free_page == ptr_page);
191 m_first_free_page = next;
192 }
193
194 if (next != RNIL)
195 {
196 (m_memroot + next)->m_prev_page = prev;
197 }
198 m_ctx.release_page(m_record_info.m_type_id, ptr_page);
199 return;
200 }
201 return;
202 }
203 handle_invalid_release(ptr);
204 }
205
206 void
handle_invalid_release(Ptr<void> ptr)207 RWPool::handle_invalid_release(Ptr<void> ptr)
208 {
209 char buf[255];
210
211 Uint32 pos = ptr.i & POOL_RECORD_MASK;
212 Uint32 pageI = ptr.i >> POOL_RECORD_BITS;
213 Uint32 * record_ptr_p = (Uint32*)ptr.p;
214 Uint32 * record_ptr_i = (m_memroot+pageI)->m_data + pos;
215
216 Uint32 magic = * (record_ptr_p + m_record_info.m_offset_magic);
217 BaseString::snprintf(buf, sizeof(buf),
218 "Invalid memory release: ptr (%x %p %p) magic: (%.8x %.8x) memroot: %p page: %x",
219 ptr.i, ptr.p, record_ptr_i, magic, m_record_info.m_type_id,
220 m_memroot,
221 (m_memroot+pageI)->m_type_id);
222
223 m_ctx.handleAbort(NDBD_EXIT_PRGERR, buf);
224 }
225
226 void
handle_invalid_get_ptr(Uint32 ptrI)227 RWPool::handle_invalid_get_ptr(Uint32 ptrI)
228 {
229 char buf[255];
230
231 Uint32 pos = ptrI & POOL_RECORD_MASK;
232 Uint32 pageI = ptrI >> POOL_RECORD_BITS;
233 Uint32 * record_ptr_i = (m_memroot+pageI)->m_data + pos;
234
235 Uint32 magic = * (record_ptr_i + m_record_info.m_offset_magic);
236 BaseString::snprintf(buf, sizeof(buf),
237 "Invalid memory access: ptr (%x %p) magic: (%.8x %.8x) memroot: %p page: %x",
238 ptrI, record_ptr_i, magic, m_record_info.m_type_id,
239 m_memroot,
240 (m_memroot+pageI)->m_type_id);
241
242 m_ctx.handleAbort(NDBD_EXIT_PRGERR, buf);
243 }
244