1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 
26 #define DBTUP_C
27 #define DBTUP_PAGE_MAP_CPP
28 #include "Dbtup.hpp"
29 #include <RefConvert.hpp>
30 #include <ndb_limits.h>
31 #include <pc.hpp>
32 #include <signaldata/RestoreImpl.hpp>
33 
34 #define JAM_FILE_ID 415
35 
36 
37 #define DBUG_PAGE_MAP 0
38 
39 //
40 // PageMap is a service used by Dbtup to map logical page id's to physical
41 // page id's. The mapping is needs the fragment and the logical page id to
42 // provide the physical id.
43 //
44 // This is a part of Dbtup which is the exclusive user of a certain set of
45 // variables on the fragment record and it is the exclusive user of the
46 // struct for page ranges.
47 //
48 //
49 // The following methods operate on the data handled by the page map class.
50 //
51 // Public methods
52 // insertPageRange(Uint32 startPageId,     # In
53 //                 Uint32 noPages)         # In
54 // Inserts a range of pages into the mapping structure.
55 //
56 // void releaseFragPages()
57 // Releases all pages and their mappings belonging to a fragment.
58 //
59 // Uint32 allocFragPages(Uint32 tafpNoAllocRequested)
60 // Allocate a set of pages to the fragment from the page manager
61 //
62 // Uint32 getEmptyPage()
63 // Get an empty page from the pool of empty pages on the fragment.
64 // It returns the physical page id of the empty page.
65 // Returns RNIL if no empty page is available.
66 //
67 // Uint32 getRealpid(Uint32 logicalPageId)
68 // Return the physical page id provided the logical page id
69 //
70 // void initializePageRange()
71 // Initialise free list of page ranges and initialise the page raneg records.
72 //
73 // void initFragRange()
74 // Initialise the fragment variables when allocating a fragment to a table.
75 //
76 // void initPageRangeSize(Uint32 size)
77 // Initialise the number of page ranges.
78 //
79 // Uint32 getNoOfPages()
80 // Get the number of pages on the fragment currently.
81 //
82 //
83 // Private methods
84 // Uint32 leafPageRangeFull(PageRangePtr currPageRangePtr)
85 //
86 // void errorHandler()
87 // Method to crash NDB kernel in case of weird data set-up
88 //
89 // void allocMoreFragPages()
90 // When no more empty pages are attached to the fragment and we need more
91 // we allocate more pages from the page manager using this method.
92 //
93 // Private data
94 // On the fragment record
95 // currentPageRange    # The current page range where to insert the next range
96 // rootPageRange       # The root of the page ranges owned
97 // nextStartRange      # The next page id to assign when expanding the
98 //                     # page map
99 // noOfPages           # The number of pages in the fragment
100 // emptyPrimPage       # The first page of the empty pages in the fragment
101 //
102 // The full page range struct
103 
getRealpid(Fragrecord * regFragPtr,Uint32 logicalPageId)104 Uint32 Dbtup::getRealpid(Fragrecord* regFragPtr, Uint32 logicalPageId)
105 {
106   DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
107   Uint32 * ptr = map.get(2 * logicalPageId);
108   if (likely(ptr != 0))
109   {
110     return * ptr;
111   }
112   ndbrequire(false);
113   return RNIL;
114 }
115 
116 Uint32
getRealpidCheck(Fragrecord * regFragPtr,Uint32 logicalPageId)117 Dbtup::getRealpidCheck(Fragrecord* regFragPtr, Uint32 logicalPageId)
118 {
119   DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
120   // logicalPageId might not be mapped yet,
121   // get_dirty returns NULL also in debug in this case.
122   Uint32 * ptr = map.get_dirty(2 * logicalPageId);
123   if (likely(ptr != 0))
124   {
125     Uint32 val = * ptr;
126     if ((val & FREE_PAGE_BIT) != 0)
127       return RNIL;
128     else
129       return val;
130   }
131   return RNIL;
132 }
133 
getNoOfPages(Fragrecord * const regFragPtr)134 Uint32 Dbtup::getNoOfPages(Fragrecord* const regFragPtr)
135 {
136   return regFragPtr->noOfPages;
137 }//Dbtup::getNoOfPages()
138 
139 void
init_page(Fragrecord * regFragPtr,PagePtr pagePtr,Uint32 pageId)140 Dbtup::init_page(Fragrecord* regFragPtr, PagePtr pagePtr, Uint32 pageId)
141 {
142   pagePtr.p->page_state = ~0;
143   pagePtr.p->frag_page_id = pageId;
144   pagePtr.p->physical_page_id = pagePtr.i;
145   pagePtr.p->nextList = RNIL;
146   pagePtr.p->prevList = RNIL;
147   pagePtr.p->m_flags = 0;
148 }
149 
150 #ifdef VM_TRACE
151 #define do_check_page_map(x) check_page_map(x)
152 #if DBUG_PAGE_MAP
153 bool
find_page_id_in_list(Fragrecord * fragPtrP,Uint32 pageId)154 Dbtup::find_page_id_in_list(Fragrecord* fragPtrP, Uint32 pageId)
155 {
156   DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
157 
158   Uint32 prev = FREE_PAGE_RNIL;
159   Uint32 curr = fragPtrP->m_free_page_id_list | FREE_PAGE_BIT;
160 
161   while (curr != FREE_PAGE_RNIL)
162   {
163     ndbrequire((curr & FREE_PAGE_BIT) != 0);
164     curr &= ~(Uint32)FREE_PAGE_BIT;
165     const Uint32 * prevPtr = map.get(2 * curr + 1);
166     ndbrequire(prevPtr != 0);
167     ndbrequire(prev == *prevPtr);
168 
169     if (curr == pageId)
170       return true;
171 
172     Uint32 * nextPtr = map.get(2 * curr);
173     ndbrequire(nextPtr != 0);
174     prev = curr | FREE_PAGE_BIT;
175     curr = (* nextPtr);
176   }
177 
178   return false;
179 }
180 
181 void
check_page_map(Fragrecord * fragPtrP)182 Dbtup::check_page_map(Fragrecord* fragPtrP)
183 {
184   Uint32 max = fragPtrP->m_max_page_cnt;
185   DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
186 
187   for (Uint32 i = 0; i<max; i++)
188   {
189     const Uint32 * ptr = map.get(2*i);
190     if (ptr == 0)
191     {
192       ndbrequire(find_page_id_in_list(fragPtrP, i) == false);
193     }
194     else
195     {
196       Uint32 realpid = *ptr;
197       if (realpid == RNIL)
198       {
199         ndbrequire(find_page_id_in_list(fragPtrP, i) == false);
200       }
201       else if (realpid & FREE_PAGE_BIT)
202       {
203         ndbrequire(find_page_id_in_list(fragPtrP, i) == true);
204       }
205       else
206       {
207         PagePtr pagePtr;
208         c_page_pool.getPtr(pagePtr, realpid);
209         ndbrequire(pagePtr.p->frag_page_id == i);
210         ndbrequire(pagePtr.p->physical_page_id == realpid);
211       }
212     }
213   }
214 }
215 #else
check_page_map(Fragrecord *)216 void Dbtup::check_page_map(Fragrecord*) {}
217 #endif
218 #else
219 #define do_check_page_map(x)
220 #endif
221 
222 Uint32
allocFragPage(EmulatedJamBuffer * jamBuf,Uint32 * err,Fragrecord * regFragPtr)223 Dbtup::allocFragPage(EmulatedJamBuffer* jamBuf,
224                      Uint32 * err,
225                      Fragrecord* regFragPtr)
226 {
227   PagePtr pagePtr;
228   Uint32 noOfPagesAllocated = 0;
229   Uint32 list = regFragPtr->m_free_page_id_list;
230   Uint32 max = regFragPtr->m_max_page_cnt;
231   Uint32 cnt = regFragPtr->noOfPages;
232 
233   allocConsPages(jamBuf, 1, noOfPagesAllocated, pagePtr.i);
234   if (noOfPagesAllocated == 0)
235   {
236     thrjam(jamBuf);
237     * err = ZMEM_NOMEM_ERROR;
238     return RNIL;
239   }//if
240 
241   Uint32 pageId;
242   DynArr256 map(c_page_map_pool, regFragPtr->m_page_map);
243   if (list == FREE_PAGE_RNIL)
244   {
245     thrjam(jamBuf);
246     pageId = max;
247     if (!Local_key::isShort(pageId))
248     {
249       /**
250        * TODO: remove when ACC supports 48 bit references
251        */
252       thrjam(jamBuf);
253       * err = 889;
254       return RNIL;
255     }
256     Uint32 * ptr = map.set(2 * pageId);
257     if (unlikely(ptr == 0))
258     {
259       thrjam(jamBuf);
260       returnCommonArea(pagePtr.i, noOfPagesAllocated);
261       * err = ZMEM_NOMEM_ERROR;
262       return RNIL;
263     }
264     ndbrequire(* ptr == RNIL);
265     * ptr = pagePtr.i;
266     regFragPtr->m_max_page_cnt = max + 1;
267   }
268   else
269   {
270     thrjam(jamBuf);
271     pageId = list;
272     Uint32 * ptr = map.set(2 * pageId);
273     ndbrequire(ptr != 0);
274     Uint32 next = * ptr;
275     * ptr = pagePtr.i;
276 
277     if (next != FREE_PAGE_RNIL)
278     {
279       thrjam(jamBuf);
280       ndbrequire((next & FREE_PAGE_BIT) != 0);
281       next &= ~FREE_PAGE_BIT;
282       Uint32 * nextPrevPtr = map.set(2 * next + 1);
283       ndbrequire(nextPrevPtr != 0);
284       * nextPrevPtr = FREE_PAGE_RNIL;
285     }
286     regFragPtr->m_free_page_id_list = next;
287   }
288 
289   regFragPtr->noOfPages = cnt + 1;
290   c_page_pool.getPtr(pagePtr);
291   init_page(regFragPtr, pagePtr, pageId);
292 
293   if (DBUG_PAGE_MAP)
294     ndbout_c("alloc -> (%u %u max: %u)", pageId, pagePtr.i,
295              regFragPtr->m_max_page_cnt);
296 
297   do_check_page_map(regFragPtr);
298   return pagePtr.i;
299 }//Dbtup::allocFragPage()
300 
301 Uint32
allocFragPage(Uint32 * err,Tablerec * tabPtrP,Fragrecord * fragPtrP,Uint32 page_no)302 Dbtup::allocFragPage(Uint32 * err,
303                      Tablerec* tabPtrP, Fragrecord* fragPtrP, Uint32 page_no)
304 {
305   PagePtr pagePtr;
306   DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
307   Uint32 * ptr = map.set(2 * page_no);
308   if (unlikely(ptr == 0))
309   {
310     jam();
311     * err = ZMEM_NOMEM_ERROR;
312     return RNIL;
313   }
314   const Uint32 * prevPtr = map.set(2 * page_no + 1);
315 
316   pagePtr.i = * ptr;
317   if (likely(pagePtr.i != RNIL && (pagePtr.i & FREE_PAGE_BIT) == 0))
318   {
319     jam();
320     return pagePtr.i;
321   }
322 
323   LocalDLFifoList<Page> free_pages(c_page_pool, fragPtrP->thFreeFirst);
324   Uint32 cnt = fragPtrP->noOfPages;
325   Uint32 max = fragPtrP->m_max_page_cnt;
326   Uint32 list = fragPtrP->m_free_page_id_list;
327   Uint32 noOfPagesAllocated = 0;
328   Uint32 next = pagePtr.i;
329 
330   allocConsPages(jamBuffer(), 1, noOfPagesAllocated, pagePtr.i);
331   if (unlikely(noOfPagesAllocated == 0))
332   {
333     jam();
334     * err = ZMEM_NOMEM_ERROR;
335     return RNIL;
336   }
337 
338   if (DBUG_PAGE_MAP)
339     ndbout_c("alloc(%u %u max: %u)", page_no, pagePtr.i, max);
340 
341   * ptr = pagePtr.i;
342   if (next == RNIL)
343   {
344     jam();
345   }
346   else
347   {
348     jam();
349     ndbrequire(prevPtr != 0);
350     Uint32 prev = * prevPtr;
351 
352     if (next == FREE_PAGE_RNIL)
353     {
354       jam();
355       // This should be end of list...
356       if (prev == FREE_PAGE_RNIL)
357       {
358         jam();
359         ndbrequire(list == page_no); // page_no is both head and tail...
360         fragPtrP->m_free_page_id_list = FREE_PAGE_RNIL;
361       }
362       else
363       {
364         jam();
365         Uint32 * prevNextPtr = map.set(2 * (prev & ~(Uint32)FREE_PAGE_BIT));
366         ndbrequire(prevNextPtr != 0);
367         Uint32 prevNext = * prevNextPtr;
368         ndbrequire(prevNext == (page_no | FREE_PAGE_BIT));
369         * prevNextPtr = FREE_PAGE_RNIL;
370       }
371     }
372     else
373     {
374       jam();
375       next &= ~(Uint32)FREE_PAGE_BIT;
376       Uint32 * nextPrevPtr = map.set(2 * next + 1);
377       ndbrequire(nextPrevPtr != 0);
378       ndbrequire(* nextPrevPtr == (page_no | FREE_PAGE_BIT));
379       * nextPrevPtr = prev;
380       if (prev == FREE_PAGE_RNIL)
381       {
382         jam();
383         ndbrequire(list == page_no); // page_no is head
384         fragPtrP->m_free_page_id_list = next;
385       }
386       else
387       {
388         jam();
389         Uint32 * prevNextPtr = map.get(2 * (prev & ~(Uint32)FREE_PAGE_BIT));
390         ndbrequire(prevNextPtr != 0);
391         ndbrequire(* prevNextPtr == (page_no | FREE_PAGE_BIT));
392         * prevNextPtr = next | FREE_PAGE_BIT;
393       }
394     }
395   }
396 
397   fragPtrP->noOfPages = cnt + 1;
398   if (page_no + 1 > max)
399   {
400     jam();
401     fragPtrP->m_max_page_cnt = page_no + 1;
402     if (DBUG_PAGE_MAP)
403       ndbout_c("new max: %u", fragPtrP->m_max_page_cnt);
404   }
405 
406   Uint32 lcp_scan_ptr_i = fragPtrP->m_lcp_scan_op;
407   c_page_pool.getPtr(pagePtr);
408   init_page(fragPtrP, pagePtr, page_no);
409   if (lcp_scan_ptr_i != RNIL)
410   {
411     jam();
412     ScanOpPtr scanOp;
413     c_scanOpPool.getPtr(scanOp, lcp_scan_ptr_i);
414     if (page_no < scanOp.p->m_endPage)
415     {
416       Local_key lcp_key = scanOp.p->m_scanPos.m_key;
417       if (page_no > lcp_key.m_page_no)
418       {
419         jam();
420         /**
421          * We allocated a page during an LCP, it was within the pages that
422          * will be checked during the LCP scan. The page has also not yet
423          * been scanned by the LCP. Given that we know that the page will
424          * only contain rows that would set the LCP_SKIP bit we will
425          * set the LCP skip on the page level instead to speed up LCP
426          * processing.
427          */
428         pagePtr.p->set_page_to_skip_lcp();
429       }
430     }
431   }
432   convertThPage((Fix_page*)pagePtr.p, tabPtrP, MM);
433   pagePtr.p->page_state = ZTH_MM_FREE;
434   free_pages.addFirst(pagePtr);
435 
436   do_check_page_map(fragPtrP);
437 
438   return pagePtr.i;
439 }
440 
441 void
releaseFragPage(Fragrecord * fragPtrP,Uint32 logicalPageId,PagePtr pagePtr)442 Dbtup::releaseFragPage(Fragrecord* fragPtrP,
443                        Uint32 logicalPageId, PagePtr pagePtr)
444 {
445   Uint32 list = fragPtrP->m_free_page_id_list;
446   Uint32 cnt = fragPtrP->noOfPages;
447   DynArr256 map(c_page_map_pool, fragPtrP->m_page_map);
448   Uint32 * next = map.set(2 * logicalPageId);
449   Uint32 * prev = map.set(2 * logicalPageId + 1);
450   ndbrequire(next != 0 && prev != 0);
451 
452   returnCommonArea(pagePtr.i, 1);
453 
454   /**
455    * Add to head or tail of list...
456    */
457   const char * where = 0;
458   if (list == FREE_PAGE_RNIL)
459   {
460     jam();
461     * next = * prev = FREE_PAGE_RNIL;
462     fragPtrP->m_free_page_id_list = logicalPageId;
463     where = "empty";
464   }
465   else
466   {
467     jam();
468     * next = list | FREE_PAGE_BIT;
469     * prev = FREE_PAGE_RNIL;
470     fragPtrP->m_free_page_id_list = logicalPageId;
471     Uint32 * nextPrevPtr = map.set(2 * list + 1);
472     ndbrequire(nextPrevPtr != 0);
473     ndbrequire(*nextPrevPtr == FREE_PAGE_RNIL);
474     * nextPrevPtr = logicalPageId | FREE_PAGE_BIT;
475     where = "head";
476   }
477 
478   fragPtrP->noOfPages = cnt - 1;
479   if (DBUG_PAGE_MAP)
480     ndbout_c("release(%u %u)@%s", logicalPageId, pagePtr.i, where);
481   do_check_page_map(fragPtrP);
482 }
483 
errorHandler(Uint32 errorCode)484 void Dbtup::errorHandler(Uint32 errorCode)
485 {
486   switch (errorCode) {
487   case 0:
488     jam();
489     break;
490   case 1:
491     jam();
492     break;
493   case 2:
494     jam();
495     break;
496   default:
497     jam();
498   }
499   ndbrequire(false);
500 }//Dbtup::errorHandler()
501 
502 void
rebuild_page_free_list(Signal * signal)503 Dbtup::rebuild_page_free_list(Signal* signal)
504 {
505   Ptr<Fragoperrec> fragOpPtr;
506   fragOpPtr.i = signal->theData[1];
507   Uint32 pageId = signal->theData[2];
508   Uint32 tail = signal->theData[3];
509   ptrCheckGuard(fragOpPtr, cnoOfFragoprec, fragoperrec);
510 
511   Ptr<Fragrecord> fragPtr;
512   fragPtr.i= fragOpPtr.p->fragPointer;
513   ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord);
514 
515   if (pageId == fragPtr.p->m_max_page_cnt)
516   {
517     RestoreLcpConf* conf = (RestoreLcpConf*)signal->getDataPtrSend();
518     conf->senderRef = reference();
519     conf->senderData = fragOpPtr.p->m_senderData;
520     sendSignal(fragOpPtr.p->m_senderRef,
521 	       GSN_RESTORE_LCP_CONF, signal,
522 	       RestoreLcpConf::SignalLength, JBB);
523 
524     releaseFragoperrec(fragOpPtr);
525     return;
526   }
527 
528   DynArr256 map(c_page_map_pool, fragPtr.p->m_page_map);
529   Uint32* nextPtr = map.set(2 * pageId);
530   Uint32* prevPtr = map.set(2 * pageId + 1);
531 
532   // Out of memory ?? Should nto be possible here/now
533   ndbrequire(nextPtr != 0 && prevPtr != 0);
534 
535   if (* nextPtr == RNIL)
536   {
537     jam();
538     /**
539      * An unallocated page id...put in free list
540      */
541 #if DBUG_PAGE_MAP
542     char * where;
543 #endif
544     if (tail == RNIL)
545     {
546       jam();
547       ndbrequire(fragPtr.p->m_free_page_id_list == FREE_PAGE_RNIL);
548       fragPtr.p->m_free_page_id_list = pageId;
549       *nextPtr = FREE_PAGE_RNIL;
550       *prevPtr = FREE_PAGE_RNIL;
551 #if DBUG_PAGE_MAP
552       where = "head";
553 #endif
554     }
555     else
556     {
557       jam();
558       ndbrequire(fragPtr.p->m_free_page_id_list != FREE_PAGE_RNIL);
559 
560       *nextPtr = FREE_PAGE_RNIL;
561       *prevPtr = tail | FREE_PAGE_BIT;
562 
563       Uint32 * prevNextPtr = map.set(2 * tail);
564       ndbrequire(prevNextPtr != 0);
565       ndbrequire(* prevNextPtr == FREE_PAGE_RNIL);
566       * prevNextPtr = pageId | FREE_PAGE_BIT;
567 #if DBUG_PAGE_MAP
568       where = "tail";
569 #endif
570     }
571     tail = pageId;
572 #if DBUG_PAGE_MAP
573     ndbout_c("adding page %u to free list @ %s", pageId, where);
574 #endif
575   }
576 
577   signal->theData[0] = ZREBUILD_FREE_PAGE_LIST;
578   signal->theData[1] = fragOpPtr.i;
579   signal->theData[2] = pageId + 1;
580   signal->theData[3] = tail;
581   sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB);
582 }
583 
584