1 /*
2 Copyright (C) 2003, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc.
3 All rights reserved. Use is subject to license terms.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26
27 #define DBTUP_C
28 #define DBTUP_PAGE_MAP_CPP
29 #include "Dbtup.hpp"
30 #include <RefConvert.hpp>
31 #include <ndb_limits.h>
32 #include <pc.hpp>
33 #include <signaldata/RestoreImpl.hpp>
34
35 #define DBUG_PAGE_MAP 0
36
37 //
38 // PageMap is a service used by Dbtup to map logical page id's to physical
39 // page id's. The mapping is needs the fragment and the logical page id to
40 // provide the physical id.
41 //
42 // This is a part of Dbtup which is the exclusive user of a certain set of
43 // variables on the fragment record and it is the exclusive user of the
44 // struct for page ranges.
45 //
46 //
47 // The following methods operate on the data handled by the page map class.
48 //
49 // Public methods
50 // insertPageRange(Uint32 startPageId, # In
51 // Uint32 noPages) # In
52 // Inserts a range of pages into the mapping structure.
53 //
54 // void releaseFragPages()
55 // Releases all pages and their mappings belonging to a fragment.
56 //
57 // Uint32 allocFragPages(Uint32 tafpNoAllocRequested)
58 // Allocate a set of pages to the fragment from the page manager
59 //
60 // Uint32 getEmptyPage()
61 // Get an empty page from the pool of empty pages on the fragment.
62 // It returns the physical page id of the empty page.
63 // Returns RNIL if no empty page is available.
64 //
65 // Uint32 getRealpid(Uint32 logicalPageId)
66 // Return the physical page id provided the logical page id
67 //
68 // void initializePageRange()
69 // Initialise free list of page ranges and initialise the page raneg records.
70 //
71 // void initFragRange()
72 // Initialise the fragment variables when allocating a fragment to a table.
73 //
74 // void initPageRangeSize(Uint32 size)
75 // Initialise the number of page ranges.
76 //
77 // Uint32 getNoOfPages()
78 // Get the number of pages on the fragment currently.
79 //
80 //
81 // Private methods
82 // Uint32 leafPageRangeFull(PageRangePtr currPageRangePtr)
83 //
84 // void errorHandler()
85 // Method to crash NDB kernel in case of weird data set-up
86 //
87 // void allocMoreFragPages()
88 // When no more empty pages are attached to the fragment and we need more
89 // we allocate more pages from the page manager using this method.
90 //
91 // Private data
92 // On the fragment record
93 // currentPageRange # The current page range where to insert the next range
94 // rootPageRange # The root of the page ranges owned
95 // nextStartRange # The next page id to assign when expanding the
96 // # page map
97 // noOfPages # The number of pages in the fragment
98 // emptyPrimPage # The first page of the empty pages in the fragment
99 //
100 // The full page range struct
101
getRealpid(Fragrecord * regFragPtr,Uint32 logicalPageId)102 Uint32 Dbtup::getRealpid(Fragrecord* regFragPtr, Uint32 logicalPageId)
103 {
104 DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
105 Uint32 * ptr = map.get(2 * logicalPageId);
106 if (likely(ptr != 0))
107 {
108 return * ptr;
109 }
110 ndbrequire(false);
111 return RNIL;
112 }
113
114 Uint32
getRealpidCheck(Fragrecord * regFragPtr,Uint32 logicalPageId)115 Dbtup::getRealpidCheck(Fragrecord* regFragPtr, Uint32 logicalPageId)
116 {
117 DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
118 Uint32 * ptr = map.get(2 * logicalPageId);
119 if (likely(ptr != 0))
120 {
121 Uint32 val = * ptr;
122 if ((val & FREE_PAGE_BIT) != 0)
123 return RNIL;
124 else
125 return val;
126 }
127 return RNIL;
128 }
129
getNoOfPages(Fragrecord * const regFragPtr)130 Uint32 Dbtup::getNoOfPages(Fragrecord* const regFragPtr)
131 {
132 return regFragPtr->noOfPages;
133 }//Dbtup::getNoOfPages()
134
135 void
init_page(Fragrecord * regFragPtr,PagePtr pagePtr,Uint32 pageId)136 Dbtup::init_page(Fragrecord* regFragPtr, PagePtr pagePtr, Uint32 pageId)
137 {
138 pagePtr.p->page_state = ~0;
139 pagePtr.p->frag_page_id = pageId;
140 pagePtr.p->physical_page_id = pagePtr.i;
141 pagePtr.p->nextList = RNIL;
142 pagePtr.p->prevList = RNIL;
143 }
144
145 #ifdef VM_TRACE
146 #define do_check_page_map(x) check_page_map(x)
147 #if DBUG_PAGE_MAP
148 bool
find_page_id_in_list(Fragrecord * fragPtrP,Uint32 pageId)149 Dbtup::find_page_id_in_list(Fragrecord* fragPtrP, Uint32 pageId)
150 {
151 DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
152
153 Uint32 prev = FREE_PAGE_RNIL;
154 Uint32 curr = fragPtrP->m_free_page_id_list | FREE_PAGE_BIT;
155
156 while (curr != FREE_PAGE_RNIL)
157 {
158 ndbrequire((curr & FREE_PAGE_BIT) != 0);
159 curr &= ~(Uint32)FREE_PAGE_BIT;
160 const Uint32 * prevPtr = map.get(2 * curr + 1);
161 ndbrequire(prevPtr != 0);
162 ndbrequire(prev == *prevPtr);
163
164 if (curr == pageId)
165 return true;
166
167 Uint32 * nextPtr = map.get(2 * curr);
168 ndbrequire(nextPtr != 0);
169 prev = curr | FREE_PAGE_BIT;
170 curr = (* nextPtr);
171 }
172
173 return false;
174 }
175
176 void
check_page_map(Fragrecord * fragPtrP)177 Dbtup::check_page_map(Fragrecord* fragPtrP)
178 {
179 Uint32 max = fragPtrP->m_max_page_no;
180 DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
181
182 for (Uint32 i = 0; i<max; i++)
183 {
184 const Uint32 * ptr = map.get(2*i);
185 if (ptr == 0)
186 {
187 ndbrequire(find_page_id_in_list(fragPtrP, i) == false);
188 }
189 else
190 {
191 Uint32 realpid = *ptr;
192 if (realpid == RNIL)
193 {
194 ndbrequire(find_page_id_in_list(fragPtrP, i) == false);
195 }
196 else if (realpid & FREE_PAGE_BIT)
197 {
198 ndbrequire(find_page_id_in_list(fragPtrP, i) == true);
199 }
200 else
201 {
202 PagePtr pagePtr;
203 c_page_pool.getPtr(pagePtr, realpid);
204 ndbrequire(pagePtr.p->frag_page_id == i);
205 ndbrequire(pagePtr.p->physical_page_id == realpid);
206 }
207 }
208 }
209 }
210 #else
check_page_map(Fragrecord *)211 void Dbtup::check_page_map(Fragrecord*) {}
212 #endif
213 #else
214 #define do_check_page_map(x)
215 #endif
216
217 Uint32
allocFragPage(Uint32 * err,Fragrecord * regFragPtr)218 Dbtup::allocFragPage(Uint32 * err, Fragrecord* regFragPtr)
219 {
220 PagePtr pagePtr;
221 Uint32 noOfPagesAllocated = 0;
222 Uint32 list = regFragPtr->m_free_page_id_list;
223 Uint32 max = regFragPtr->m_max_page_no;
224 Uint32 cnt = regFragPtr->noOfPages;
225
226 allocConsPages(1, noOfPagesAllocated, pagePtr.i);
227 if (noOfPagesAllocated == 0)
228 {
229 jam();
230 * err = ZMEM_NOMEM_ERROR;
231 return RNIL;
232 }//if
233
234 Uint32 pageId;
235 DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
236 if (list == FREE_PAGE_RNIL)
237 {
238 jam();
239 pageId = max;
240 Uint32 * ptr = map.set(2 * pageId);
241 if (unlikely(ptr == 0))
242 {
243 jam();
244 returnCommonArea(pagePtr.i, noOfPagesAllocated);
245 * err = ZMEM_NOMEM_ERROR;
246 return RNIL;
247 }
248 ndbrequire(* ptr == RNIL);
249 * ptr = pagePtr.i;
250 regFragPtr->m_max_page_no = max + 1;
251 }
252 else
253 {
254 jam();
255 pageId = list;
256 Uint32 * ptr = map.set(2 * pageId);
257 ndbrequire(ptr != 0);
258 Uint32 next = * ptr;
259 * ptr = pagePtr.i;
260
261 if (next != FREE_PAGE_RNIL)
262 {
263 jam();
264 ndbrequire((next & FREE_PAGE_BIT) != 0);
265 next &= ~FREE_PAGE_BIT;
266 Uint32 * nextPrevPtr = map.set(2 * next + 1);
267 ndbrequire(nextPrevPtr != 0);
268 * nextPrevPtr = FREE_PAGE_RNIL;
269 }
270 regFragPtr->m_free_page_id_list = next;
271 }
272
273 regFragPtr->noOfPages = cnt + 1;
274 c_page_pool.getPtr(pagePtr);
275 init_page(regFragPtr, pagePtr, pageId);
276
277 if (DBUG_PAGE_MAP)
278 ndbout_c("alloc -> (%u %u max: %u)", pageId, pagePtr.i,
279 regFragPtr->m_max_page_no);
280
281 do_check_page_map(regFragPtr);
282 return pagePtr.i;
283 }//Dbtup::allocFragPage()
284
285 Uint32
allocFragPage(Uint32 * err,Tablerec * tabPtrP,Fragrecord * fragPtrP,Uint32 page_no)286 Dbtup::allocFragPage(Uint32 * err,
287 Tablerec* tabPtrP, Fragrecord* fragPtrP, Uint32 page_no)
288 {
289 PagePtr pagePtr;
290 DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
291 Uint32 * ptr = map.set(2 * page_no);
292 if (unlikely(ptr == 0))
293 {
294 jam();
295 * err = ZMEM_NOMEM_ERROR;
296 return RNIL;
297 }
298 const Uint32 * prevPtr = map.set(2 * page_no + 1);
299
300 pagePtr.i = * ptr;
301 if (likely(pagePtr.i != RNIL && (pagePtr.i & FREE_PAGE_BIT) == 0))
302 {
303 jam();
304 return pagePtr.i;
305 }
306
307 LocalDLFifoList<Page> free_pages(c_page_pool, fragPtrP->thFreeFirst);
308 Uint32 cnt = fragPtrP->noOfPages;
309 Uint32 max = fragPtrP->m_max_page_no;
310 Uint32 list = fragPtrP->m_free_page_id_list;
311 Uint32 noOfPagesAllocated = 0;
312 Uint32 next = pagePtr.i;
313
314 allocConsPages(1, noOfPagesAllocated, pagePtr.i);
315 if (unlikely(noOfPagesAllocated == 0))
316 {
317 jam();
318 * err = ZMEM_NOMEM_ERROR;
319 return RNIL;
320 }
321
322 if (DBUG_PAGE_MAP)
323 ndbout_c("alloc(%u %u max: %u)", page_no, pagePtr.i, max);
324
325 * ptr = pagePtr.i;
326 if (next == RNIL)
327 {
328 jam();
329 }
330 else
331 {
332 jam();
333 ndbrequire(prevPtr != 0);
334 Uint32 prev = * prevPtr;
335
336 if (next == FREE_PAGE_RNIL)
337 {
338 jam();
339 // This should be end of list...
340 if (prev == FREE_PAGE_RNIL)
341 {
342 jam();
343 ndbrequire(list == page_no); // page_no is both head and tail...
344 fragPtrP->m_free_page_id_list = FREE_PAGE_RNIL;
345 }
346 else
347 {
348 jam();
349 Uint32 * prevNextPtr = map.set(2 * (prev & ~(Uint32)FREE_PAGE_BIT));
350 ndbrequire(prevNextPtr != 0);
351 Uint32 prevNext = * prevNextPtr;
352 ndbrequire(prevNext == (page_no | FREE_PAGE_BIT));
353 * prevNextPtr = FREE_PAGE_RNIL;
354 }
355 }
356 else
357 {
358 jam();
359 next &= ~(Uint32)FREE_PAGE_BIT;
360 Uint32 * nextPrevPtr = map.set(2 * next + 1);
361 ndbrequire(nextPrevPtr != 0);
362 ndbrequire(* nextPrevPtr == (page_no | FREE_PAGE_BIT));
363 * nextPrevPtr = prev;
364 if (prev == FREE_PAGE_RNIL)
365 {
366 jam();
367 ndbrequire(list == page_no); // page_no is head
368 fragPtrP->m_free_page_id_list = next;
369 }
370 else
371 {
372 jam();
373 Uint32 * prevNextPtr = map.get(2 * (prev & ~(Uint32)FREE_PAGE_BIT));
374 ndbrequire(prevNextPtr != 0);
375 ndbrequire(* prevNextPtr == (page_no | FREE_PAGE_BIT));
376 * prevNextPtr = next | FREE_PAGE_BIT;
377 }
378 }
379 }
380
381 fragPtrP->noOfPages = cnt + 1;
382 if (page_no + 1 > max)
383 {
384 jam();
385 fragPtrP->m_max_page_no = page_no + 1;
386 if (DBUG_PAGE_MAP)
387 ndbout_c("new max: %u", fragPtrP->m_max_page_no);
388 }
389
390 c_page_pool.getPtr(pagePtr);
391 init_page(fragPtrP, pagePtr, page_no);
392 convertThPage((Fix_page*)pagePtr.p, tabPtrP, MM);
393 pagePtr.p->page_state = ZTH_MM_FREE;
394 free_pages.addFirst(pagePtr);
395
396 do_check_page_map(fragPtrP);
397
398 return pagePtr.i;
399 }
400
401 void
releaseFragPage(Fragrecord * fragPtrP,Uint32 logicalPageId,PagePtr pagePtr)402 Dbtup::releaseFragPage(Fragrecord* fragPtrP,
403 Uint32 logicalPageId, PagePtr pagePtr)
404 {
405 Uint32 list = fragPtrP->m_free_page_id_list;
406 Uint32 cnt = fragPtrP->noOfPages;
407 DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
408 Uint32 * next = map.set(2 * logicalPageId);
409 Uint32 * prev = map.set(2 * logicalPageId + 1);
410 ndbrequire(next != 0 && prev != 0);
411
412 returnCommonArea(pagePtr.i, 1);
413
414 /**
415 * Add to head or tail of list...
416 */
417 const char * where = 0;
418 if (list == FREE_PAGE_RNIL)
419 {
420 jam();
421 * next = * prev = FREE_PAGE_RNIL;
422 fragPtrP->m_free_page_id_list = logicalPageId;
423 where = "empty";
424 }
425 else
426 {
427 jam();
428 * next = list | FREE_PAGE_BIT;
429 * prev = FREE_PAGE_RNIL;
430 fragPtrP->m_free_page_id_list = logicalPageId;
431 Uint32 * nextPrevPtr = map.set(2 * list + 1);
432 ndbrequire(nextPrevPtr != 0);
433 ndbrequire(*nextPrevPtr == FREE_PAGE_RNIL);
434 * nextPrevPtr = logicalPageId | FREE_PAGE_BIT;
435 where = "head";
436 }
437
438 fragPtrP->noOfPages = cnt - 1;
439 if (DBUG_PAGE_MAP)
440 ndbout_c("release(%u %u)@%s", logicalPageId, pagePtr.i, where);
441 do_check_page_map(fragPtrP);
442 }
443
errorHandler(Uint32 errorCode)444 void Dbtup::errorHandler(Uint32 errorCode)
445 {
446 switch (errorCode) {
447 case 0:
448 jam();
449 break;
450 case 1:
451 jam();
452 break;
453 case 2:
454 jam();
455 break;
456 default:
457 jam();
458 }
459 ndbrequire(false);
460 }//Dbtup::errorHandler()
461
462 void
rebuild_page_free_list(Signal * signal)463 Dbtup::rebuild_page_free_list(Signal* signal)
464 {
465 Ptr<Fragoperrec> fragOpPtr;
466 fragOpPtr.i = signal->theData[1];
467 Uint32 pageId = signal->theData[2];
468 Uint32 tail = signal->theData[3];
469 ptrCheckGuard(fragOpPtr, cnoOfFragoprec, fragoperrec);
470
471 Ptr<Fragrecord> fragPtr;
472 fragPtr.i= fragOpPtr.p->fragPointer;
473 ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
474
475 if (pageId == fragPtr.p->m_max_page_no)
476 {
477 RestoreLcpConf* conf = (RestoreLcpConf*)signal->getDataPtrSend();
478 conf->senderRef = reference();
479 conf->senderData = fragOpPtr.p->m_senderData;
480 sendSignal(fragOpPtr.p->m_senderRef,
481 GSN_RESTORE_LCP_CONF, signal,
482 RestoreLcpConf::SignalLength, JBB);
483
484 releaseFragoperrec(fragOpPtr);
485 return;
486 }
487
488 DynArr256 map(c_page_map_pool, fragPtr.p->m_page_map);
489 Uint32* nextPtr = map.set(2 * pageId);
490 Uint32* prevPtr = map.set(2 * pageId + 1);
491
492 // Out of memory ?? Should nto be possible here/now
493 ndbrequire(nextPtr != 0 && prevPtr != 0);
494
495 if (* nextPtr == RNIL)
496 {
497 jam();
498 /**
499 * An unallocated page id...put in free list
500 */
501 #if DBUG_PAGE_MAP
502 char * where;
503 #endif
504 if (tail == RNIL)
505 {
506 jam();
507 ndbrequire(fragPtr.p->m_free_page_id_list == FREE_PAGE_RNIL);
508 fragPtr.p->m_free_page_id_list = pageId;
509 *nextPtr = FREE_PAGE_RNIL;
510 *prevPtr = FREE_PAGE_RNIL;
511 #if DBUG_PAGE_MAP
512 where = "head";
513 #endif
514 }
515 else
516 {
517 jam();
518 ndbrequire(fragPtr.p->m_free_page_id_list != FREE_PAGE_RNIL);
519
520 *nextPtr = FREE_PAGE_RNIL;
521 *prevPtr = tail | FREE_PAGE_BIT;
522
523 Uint32 * prevNextPtr = map.set(2 * tail);
524 ndbrequire(prevNextPtr != 0);
525 ndbrequire(* prevNextPtr == FREE_PAGE_RNIL);
526 * prevNextPtr = pageId | FREE_PAGE_BIT;
527 #if DBUG_PAGE_MAP
528 where = "tail";
529 #endif
530 }
531 tail = pageId;
532 #if DBUG_PAGE_MAP
533 ndbout_c("adding page %u to free list @ %s", pageId, where);
534 #endif
535 }
536
537 signal->theData[0] = ZREBUILD_FREE_PAGE_LIST;
538 signal->theData[1] = fragOpPtr.i;
539 signal->theData[2] = pageId + 1;
540 signal->theData[3] = tail;
541 sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
542 }
543
544