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