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