00001 /* Copyright (C) 2004 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #define DBTUP_C 00018 #include "Dbtup.hpp" 00019 00020 static bool f_undo_done = true; 00021 00022 static 00023 NdbOut& 00024 operator<<(NdbOut& out, const Ptr<Dbtup::Page> & ptr) 00025 { 00026 out << "[ Page: ptr.i: " << ptr.i 00027 << " [ m_file_no: " << ptr.p->m_file_no 00028 << " m_page_no: " << ptr.p->m_page_no << "]" 00029 << " list_index: " << ptr.p->list_index 00030 << " free_space: " << ptr.p->free_space 00031 << " uncommitted_used_space: " << ptr.p->uncommitted_used_space 00032 << " ]"; 00033 return out; 00034 } 00035 00036 static 00037 NdbOut& 00038 operator<<(NdbOut& out, const Ptr<Dbtup::Page_request> & ptr) 00039 { 00040 out << "[ Page_request: ptr.i: " << ptr.i 00041 << " " << ptr.p->m_key 00042 << " m_estimated_free_space: " << ptr.p->m_estimated_free_space 00043 << " m_list_index: " << ptr.p->m_list_index 00044 << " m_frag_ptr_i: " << ptr.p->m_frag_ptr_i 00045 << " m_extent_info_ptr: " << ptr.p->m_extent_info_ptr 00046 << " m_ref_count: " << ptr.p->m_ref_count 00047 << " m_uncommitted_used_space: " << ptr.p->m_uncommitted_used_space 00048 << " ]"; 00049 00050 return out; 00051 } 00052 00053 static 00054 NdbOut& 00055 operator<<(NdbOut& out, const Ptr<Dbtup::Extent_info> & ptr) 00056 { 00057 out << "[ Extent_info: ptr.i " << ptr.i 00058 << " " << ptr.p->m_key 00059 << " m_first_page_no: " << ptr.p->m_first_page_no 00060 << " m_free_space: " << ptr.p->m_free_space 00061 << " m_free_matrix_pos: " << ptr.p->m_free_matrix_pos 00062 << " m_free_page_count: ["; 00063 00064 for(Uint32 i = 0; i<Dbtup::EXTENT_SEARCH_MATRIX_COLS; i++) 00065 out << " " << ptr.p->m_free_page_count[i]; 00066 out << " ] ]"; 00067 00068 return out; 00069 } 00070 00071 void 00072 Dbtup::dump_disk_alloc(Dbtup::Disk_alloc_info & alloc) 00073 { 00074 ndbout_c("dirty pages"); 00075 for(Uint32 i = 0; i<MAX_FREE_LIST; i++) 00076 { 00077 printf(" %d : ", i); 00078 Ptr<Page> ptr; 00079 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 00080 LocalDLList<Page> list(*pool, alloc.m_dirty_pages[i]); 00081 for(list.first(ptr); !ptr.isNull(); list.next(ptr)) 00082 { 00083 ndbout << ptr << " "; 00084 } 00085 ndbout_c(""); 00086 } 00087 ndbout_c("page requests"); 00088 for(Uint32 i = 0; i<MAX_FREE_LIST; i++) 00089 { 00090 printf(" %d : ", i); 00091 Ptr<Page_request> ptr; 00092 Local_page_request_list list(c_page_request_pool, 00093 alloc.m_page_requests[i]); 00094 for(list.first(ptr); !ptr.isNull(); list.next(ptr)) 00095 { 00096 ndbout << ptr << " "; 00097 } 00098 ndbout_c(""); 00099 } 00100 00101 ndbout_c("Extent matrix"); 00102 for(Uint32 i = 0; i<alloc.SZ; i++) 00103 { 00104 printf(" %d : ", i); 00105 Ptr<Extent_info> ptr; 00106 Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[i]); 00107 for(list.first(ptr); !ptr.isNull(); list.next(ptr)) 00108 { 00109 ndbout << ptr << " "; 00110 } 00111 ndbout_c(""); 00112 } 00113 00114 if (alloc.m_curr_extent_info_ptr_i != RNIL) 00115 { 00116 Ptr<Extent_info> ptr; 00117 c_extent_pool.getPtr(ptr, alloc.m_curr_extent_info_ptr_i); 00118 ndbout << "current extent: " << ptr << endl; 00119 } 00120 } 00121 00122 #if defined VM_TRACE || true 00123 #define ddassert(x) do { if(unlikely(!(x))) { dump_disk_alloc(alloc); ndbrequire(false); } } while(0) 00124 #else 00125 #define ddassert(x) 00126 #endif 00127 00128 Dbtup::Disk_alloc_info::Disk_alloc_info(const Tablerec* tabPtrP, 00129 Uint32 extent_size) 00130 { 00131 m_extent_size = extent_size; 00132 m_curr_extent_info_ptr_i = RNIL; 00133 if (tabPtrP->m_no_of_disk_attributes == 0) 00134 return; 00135 00136 Uint32 min_size= 4*tabPtrP->m_offsets[DD].m_fix_header_size; 00137 Uint32 var_size= tabPtrP->m_offsets[DD].m_max_var_offset; 00138 00139 if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0) 00140 { 00141 Uint32 recs_per_page= (4*Tup_fixsize_page::DATA_WORDS)/min_size; 00142 Uint32 pct_free= 0; 00143 m_page_free_bits_map[0] = recs_per_page; // 100% free 00144 m_page_free_bits_map[1] = 1; 00145 m_page_free_bits_map[2] = 0; 00146 m_page_free_bits_map[3] = 0; 00147 00148 Uint32 max= recs_per_page * extent_size; 00149 for(Uint32 i = 0; i<EXTENT_SEARCH_MATRIX_ROWS; i++) 00150 { 00151 m_total_extent_free_space_thresholds[i] = 00152 (EXTENT_SEARCH_MATRIX_ROWS - i - 1)*max/EXTENT_SEARCH_MATRIX_ROWS; 00153 } 00154 } 00155 else 00156 { 00157 abort(); 00158 } 00159 } 00160 00161 Uint32 00162 Dbtup::Disk_alloc_info::find_extent(Uint32 sz) const 00163 { 00169 Uint32 col = calc_page_free_bits(sz); 00170 Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1; 00171 for(Uint32 i= 0; i<EXTENT_SEARCH_MATRIX_SIZE; i++) 00172 { 00173 // Check that it can cater for request 00174 if (!m_free_extents[i].isEmpty()) 00175 { 00176 return i; 00177 } 00178 00179 if ((i & mask) >= col) 00180 { 00181 i = (i & ~mask) + mask; 00182 } 00183 } 00184 00185 return RNIL; 00186 } 00187 00188 Uint32 00189 Dbtup::Disk_alloc_info::calc_extent_pos(const Extent_info* extP) const 00190 { 00191 Uint32 free= extP->m_free_space; 00192 Uint32 mask= EXTENT_SEARCH_MATRIX_COLS - 1; 00193 00194 Uint32 col= 0, row=0; 00195 00201 { 00202 const Uint32 *arr= m_total_extent_free_space_thresholds; 00203 for(; free < * arr++; row++) 00204 assert(row < EXTENT_SEARCH_MATRIX_ROWS); 00205 } 00206 00210 { 00211 const Uint16 *arr= extP->m_free_page_count; 00212 for(; col < EXTENT_SEARCH_MATRIX_COLS && * arr++ == 0; col++); 00213 } 00214 00224 Uint32 pos= (row * (mask + 1)) + (col & mask); 00225 00226 assert(pos < EXTENT_SEARCH_MATRIX_SIZE); 00227 return pos; 00228 } 00229 00230 void 00231 Dbtup::update_extent_pos(Disk_alloc_info& alloc, 00232 Ptr<Extent_info> extentPtr) 00233 { 00234 #ifdef VM_TRACE 00235 Uint32 min_free = 0; 00236 for(Uint32 i = 0; i<MAX_FREE_LIST; i++) 00237 { 00238 Uint32 sum = alloc.calc_page_free_space(i); 00239 min_free += sum * extentPtr.p->m_free_page_count[i]; 00240 } 00241 ddassert(extentPtr.p->m_free_space >= min_free); 00242 #endif 00243 00244 Uint32 old = extentPtr.p->m_free_matrix_pos; 00245 if (old != RNIL) 00246 { 00247 Uint32 pos = alloc.calc_extent_pos(extentPtr.p); 00248 if (old != pos) 00249 { 00250 jam(); 00251 Local_extent_info_list old_list(c_extent_pool, alloc.m_free_extents[old]); 00252 Local_extent_info_list new_list(c_extent_pool, alloc.m_free_extents[pos]); 00253 old_list.remove(extentPtr); 00254 new_list.add(extentPtr); 00255 extentPtr.p->m_free_matrix_pos= pos; 00256 } 00257 } 00258 else 00259 { 00260 ddassert(alloc.m_curr_extent_info_ptr_i == extentPtr.i); 00261 } 00262 } 00263 00264 void 00265 Dbtup::restart_setup_page(Disk_alloc_info& alloc, Ptr<Page> pagePtr) 00266 { 00270 pagePtr.p->uncommitted_used_space = 0; 00271 pagePtr.p->m_restart_seq = globalData.m_restart_seq; 00272 00273 Extent_info key; 00274 key.m_key.m_file_no = pagePtr.p->m_file_no; 00275 key.m_key.m_page_idx = pagePtr.p->m_extent_no; 00276 Ptr<Extent_info> extentPtr; 00277 ndbrequire(c_extent_hash.find(extentPtr, key)); 00278 pagePtr.p->m_extent_info_ptr = extentPtr.i; 00279 00280 Uint32 idx = pagePtr.p->list_index & ~0x8000; 00281 Uint32 estimated = alloc.calc_page_free_space(idx); 00282 Uint32 real_free = pagePtr.p->free_space; 00283 00284 ddassert(real_free >= estimated); 00285 if (real_free != estimated) 00286 { 00287 extentPtr.p->m_free_space += (real_free - estimated); 00288 update_extent_pos(alloc, extentPtr); 00289 } 00290 00291 #ifdef VM_TRACE 00292 { 00293 Local_key page; 00294 page.m_file_no = pagePtr.p->m_file_no; 00295 page.m_page_no = pagePtr.p->m_page_no; 00296 00297 Tablespace_client tsman(0, c_tsman, 00298 0, 0, 0); 00299 unsigned uncommitted, committed; 00300 uncommitted = committed = ~(unsigned)0; 00301 int ret = tsman.get_page_free_bits(&page, &uncommitted, &committed); 00302 00303 idx = alloc.calc_page_free_bits(real_free); 00304 ddassert(idx == committed); 00305 } 00306 #endif 00307 } 00308 00318 #define DBG_DISK 0 00319 00320 int 00321 Dbtup::disk_page_prealloc(Signal* signal, 00322 Ptr<Fragrecord> fragPtr, 00323 Local_key* key, Uint32 sz) 00324 { 00325 int err; 00326 Uint32 i, ptrI; 00327 Ptr<Page_request> req; 00328 Fragrecord* fragPtrP = fragPtr.p; 00329 Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; 00330 Uint32 idx= alloc.calc_page_free_bits(sz); 00331 Tablespace_client tsman(signal, c_tsman, 00332 fragPtrP->fragTableId, 00333 fragPtrP->fragmentId, 00334 fragPtrP->m_tablespace_id); 00335 00336 if (DBG_DISK) 00337 ndbout << "disk_page_prealloc"; 00338 00342 for(i= 0; i <= idx; i++) 00343 { 00344 if (!alloc.m_dirty_pages[i].isEmpty()) 00345 { 00346 ptrI= alloc.m_dirty_pages[i].firstItem; 00347 Ptr<GlobalPage> page; 00348 m_global_page_pool.getPtr(page, ptrI); 00349 00350 disk_page_prealloc_dirty_page(alloc, *(PagePtr*)&page, i, sz); 00351 key->m_page_no= ((Page*)page.p)->m_page_no; 00352 key->m_file_no= ((Page*)page.p)->m_file_no; 00353 if (DBG_DISK) 00354 ndbout << " found dirty page " << *key << endl; 00355 return 0; // Page in memory 00356 } 00357 } 00358 00364 for(i= 0; i <= idx; i++) 00365 { 00366 if (!alloc.m_page_requests[i].isEmpty()) 00367 { 00368 ptrI= alloc.m_page_requests[i].firstItem; 00369 Ptr<Page_request> req; 00370 c_page_request_pool.getPtr(req, ptrI); 00371 00372 disk_page_prealloc_transit_page(alloc, req, i, sz); 00373 * key = req.p->m_key; 00374 if (DBG_DISK) 00375 ndbout << " found transit page " << *key << endl; 00376 return 0; 00377 } 00378 } 00379 00383 if (!c_page_request_pool.seize(req)) 00384 { 00385 err= 1; 00386 //XXX set error code 00387 ndbout_c("no free request"); 00388 return -err; 00389 } 00390 00391 req.p->m_ref_count= 1; 00392 req.p->m_frag_ptr_i= fragPtr.i; 00393 req.p->m_uncommitted_used_space= sz; 00394 00395 int pageBits; // received 00396 Ptr<Extent_info> ext; 00397 const Uint32 bits= alloc.calc_page_free_bits(sz); // required 00398 bool found= false; 00399 00403 if ((ext.i= alloc.m_curr_extent_info_ptr_i) != RNIL) 00404 { 00405 jam(); 00406 c_extent_pool.getPtr(ext); 00407 if ((pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits)) >= 0) 00408 { 00409 jam(); 00410 found= true; 00411 } 00412 else 00413 { 00414 jam(); 00420 alloc.m_curr_extent_info_ptr_i = RNIL; 00421 Uint32 pos= alloc.calc_extent_pos(ext.p); 00422 ext.p->m_free_matrix_pos = pos; 00423 Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[pos]); 00424 list.add(ext); 00425 } 00426 } 00427 00428 if (!found) 00429 { 00430 Uint32 pos; 00431 if ((pos= alloc.find_extent(sz)) != RNIL) 00432 { 00433 jam(); 00434 Local_extent_info_list list(c_extent_pool, alloc.m_free_extents[pos]); 00435 list.first(ext); 00436 list.remove(ext); 00437 } 00438 else 00439 { 00440 jam(); 00444 if (!c_extent_pool.seize(ext)) 00445 { 00446 //XXX 00447 err= 2; 00448 c_page_request_pool.release(req); 00449 ndbout_c("no free extent info"); 00450 return -err; 00451 } 00452 00453 if ((err= tsman.alloc_extent(&ext.p->m_key)) < 0) 00454 { 00455 c_extent_pool.release(ext); 00456 c_page_request_pool.release(req); 00457 return err; 00458 } 00459 00460 int pages= err; 00461 ndbout << "allocated " << pages << " pages: " << ext.p->m_key << endl; 00462 ext.p->m_first_page_no = ext.p->m_key.m_page_no; 00463 bzero(ext.p->m_free_page_count, sizeof(ext.p->m_free_page_count)); 00464 ext.p->m_free_space= alloc.m_page_free_bits_map[0] * pages; 00465 ext.p->m_free_page_count[0]= pages; // All pages are "free"-est 00466 c_extent_hash.add(ext); 00467 00468 Local_fragment_extent_list list1(c_extent_pool, alloc.m_extent_list); 00469 list1.add(ext); 00470 } 00471 00472 alloc.m_curr_extent_info_ptr_i= ext.i; 00473 ext.p->m_free_matrix_pos= RNIL; 00474 pageBits= tsman.alloc_page_from_extent(&ext.p->m_key, bits); 00475 ddassert(pageBits >= 0); 00476 } 00477 00481 *key= req.p->m_key= ext.p->m_key; 00482 00483 if (DBG_DISK) 00484 ndbout << " allocated page " << *key << endl; 00485 00491 Uint32 size= alloc.calc_page_free_space((Uint32)pageBits); 00492 00493 ddassert(size >= sz); 00494 Uint32 new_size = size - sz; // Subtract alloc rec 00495 req.p->m_estimated_free_space= new_size; // Store on page request 00496 00497 Uint32 newPageBits= alloc.calc_page_free_bits(new_size); 00498 if (newPageBits != (Uint32)pageBits) 00499 { 00500 ddassert(ext.p->m_free_page_count[pageBits] > 0); 00501 ext.p->m_free_page_count[pageBits]--; 00502 ext.p->m_free_page_count[newPageBits]++; 00503 } 00504 ddassert(ext.p->m_free_space >= sz); 00505 ext.p->m_free_space -= sz; 00506 00507 // And put page request in correct free list 00508 idx= alloc.calc_page_free_bits(new_size); 00509 { 00510 Local_page_request_list list(c_page_request_pool, 00511 alloc.m_page_requests[idx]); 00512 00513 list.add(req); 00514 } 00515 req.p->m_list_index= idx; 00516 req.p->m_extent_info_ptr= ext.i; 00517 00518 Page_cache_client::Request preq; 00519 preq.m_page = *key; 00520 preq.m_callback.m_callbackData= req.i; 00521 preq.m_callback.m_callbackFunction = 00522 safe_cast(&Dbtup::disk_page_prealloc_callback); 00523 00524 int flags= Page_cache_client::ALLOC_REQ; 00525 if (pageBits == 0) 00526 { 00527 //XXX empty page -> fast to map 00528 flags |= Page_cache_client::EMPTY_PAGE; 00529 preq.m_callback.m_callbackFunction = 00530 safe_cast(&Dbtup::disk_page_prealloc_initial_callback); 00531 } 00532 00533 int res= m_pgman.get_page(signal, preq, flags); 00534 switch(res) 00535 { 00536 case 0: 00537 break; 00538 case -1: 00539 ndbassert(false); 00540 break; 00541 default: 00542 execute(signal, preq.m_callback, res); // run callback 00543 } 00544 00545 return res; 00546 } 00547 00548 void 00549 Dbtup::disk_page_prealloc_dirty_page(Disk_alloc_info & alloc, 00550 Ptr<Page> pagePtr, 00551 Uint32 old_idx, Uint32 sz) 00552 { 00553 ddassert(pagePtr.p->list_index == old_idx); 00554 00555 Uint32 free= pagePtr.p->free_space; 00556 Uint32 used= pagePtr.p->uncommitted_used_space + sz; 00557 Uint32 ext= pagePtr.p->m_extent_info_ptr; 00558 00559 ddassert(free >= used); 00560 Ptr<Extent_info> extentPtr; 00561 c_extent_pool.getPtr(extentPtr, ext); 00562 00563 Uint32 new_idx= alloc.calc_page_free_bits(free - used); 00564 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 00565 00566 if (old_idx != new_idx) 00567 { 00568 LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]); 00569 LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]); 00570 old_list.remove(pagePtr); 00571 new_list.add(pagePtr); 00572 00573 ddassert(extentPtr.p->m_free_page_count[old_idx]); 00574 extentPtr.p->m_free_page_count[old_idx]--; 00575 extentPtr.p->m_free_page_count[new_idx]++; 00576 pagePtr.p->list_index= new_idx; 00577 } 00578 00579 pagePtr.p->uncommitted_used_space = used; 00580 ddassert(extentPtr.p->m_free_space >= sz); 00581 extentPtr.p->m_free_space -= sz; 00582 update_extent_pos(alloc, extentPtr); 00583 } 00584 00585 00586 void 00587 Dbtup::disk_page_prealloc_transit_page(Disk_alloc_info& alloc, 00588 Ptr<Page_request> req, 00589 Uint32 old_idx, Uint32 sz) 00590 { 00591 ddassert(req.p->m_list_index == old_idx); 00592 00593 Uint32 free= req.p->m_estimated_free_space; 00594 Uint32 used= req.p->m_uncommitted_used_space + sz; 00595 Uint32 ext= req.p->m_extent_info_ptr; 00596 00597 Ptr<Extent_info> extentPtr; 00598 c_extent_pool.getPtr(extentPtr, ext); 00599 00600 ddassert(free >= sz); 00601 Uint32 new_idx= alloc.calc_page_free_bits(free - sz); 00602 00603 if (old_idx != new_idx) 00604 { 00605 Page_request_list::Head *lists = alloc.m_page_requests; 00606 Local_page_request_list old_list(c_page_request_pool, lists[old_idx]); 00607 Local_page_request_list new_list(c_page_request_pool, lists[new_idx]); 00608 old_list.remove(req); 00609 new_list.add(req); 00610 00611 ddassert(extentPtr.p->m_free_page_count[old_idx]); 00612 extentPtr.p->m_free_page_count[old_idx]--; 00613 extentPtr.p->m_free_page_count[new_idx]++; 00614 req.p->m_list_index= new_idx; 00615 } 00616 00617 req.p->m_uncommitted_used_space = used; 00618 req.p->m_estimated_free_space = free - sz; 00619 ddassert(extentPtr.p->m_free_space >= sz); 00620 extentPtr.p->m_free_space -= sz; 00621 update_extent_pos(alloc, extentPtr); 00622 } 00623 00624 00625 void 00626 Dbtup::disk_page_prealloc_callback(Signal* signal, 00627 Uint32 page_request, Uint32 page_id) 00628 { 00629 //ndbout_c("disk_alloc_page_callback id: %d", page_id); 00630 00631 Ptr<Page_request> req; 00632 c_page_request_pool.getPtr(req, page_request); 00633 00634 Ptr<GlobalPage> gpage; 00635 m_global_page_pool.getPtr(gpage, page_id); 00636 00637 Ptr<Fragrecord> fragPtr; 00638 fragPtr.i= req.p->m_frag_ptr_i; 00639 ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); 00640 00641 Ptr<Page> pagePtr = *(Ptr<Page>*)&gpage; 00642 00643 if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq)) 00644 { 00645 restart_setup_page(fragPtr.p->m_disk_alloc_info, pagePtr); 00646 } 00647 00648 disk_page_prealloc_callback_common(signal, req, fragPtr, pagePtr); 00649 } 00650 00651 void 00652 Dbtup::disk_page_prealloc_initial_callback(Signal*signal, 00653 Uint32 page_request, 00654 Uint32 page_id) 00655 { 00656 //ndbout_c("disk_alloc_page_callback_initial id: %d", page_id); 00664 Ptr<Page_request> req; 00665 c_page_request_pool.getPtr(req, page_request); 00666 00667 Ptr<GlobalPage> gpage; 00668 m_global_page_pool.getPtr(gpage, page_id); 00669 Ptr<Page> pagePtr = *(Ptr<Page>*)&gpage; 00670 00671 Ptr<Fragrecord> fragPtr; 00672 fragPtr.i= req.p->m_frag_ptr_i; 00673 ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); 00674 00675 Ptr<Tablerec> tabPtr; 00676 tabPtr.i = fragPtr.p->fragTableId; 00677 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 00678 00679 Ptr<Extent_info> extentPtr; 00680 c_extent_pool.getPtr(extentPtr, req.p->m_extent_info_ptr); 00681 00682 pagePtr.p->m_page_no= req.p->m_key.m_page_no; 00683 pagePtr.p->m_file_no= req.p->m_key.m_file_no; 00684 pagePtr.p->m_table_id= fragPtr.p->fragTableId; 00685 pagePtr.p->m_fragment_id = fragPtr.p->fragmentId; 00686 pagePtr.p->m_extent_no = extentPtr.p->m_key.m_page_idx; // logical extent no 00687 pagePtr.p->m_extent_info_ptr= req.p->m_extent_info_ptr; 00688 pagePtr.p->m_restart_seq = globalData.m_restart_seq; 00689 pagePtr.p->list_index = 0x8000; 00690 pagePtr.p->uncommitted_used_space = 0; 00691 pagePtr.p->nextList = pagePtr.p->prevList = RNIL; 00692 00693 if (tabPtr.p->m_attributes[DD].m_no_of_varsize == 0) 00694 { 00695 convertThPage((Fix_page*)pagePtr.p, tabPtr.p, DD); 00696 } 00697 else 00698 { 00699 abort(); 00700 } 00701 disk_page_prealloc_callback_common(signal, req, fragPtr, pagePtr); 00702 } 00703 00704 void 00705 Dbtup::disk_page_prealloc_callback_common(Signal* signal, 00706 Ptr<Page_request> req, 00707 Ptr<Fragrecord> fragPtr, 00708 Ptr<Page> pagePtr) 00709 { 00716 Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; 00717 ddassert((pagePtr.p->list_index & 0x8000) == 0x8000); 00718 ddassert(pagePtr.p->m_extent_info_ptr == req.p->m_extent_info_ptr); 00719 ddassert(pagePtr.p->m_page_no == req.p->m_key.m_page_no); 00720 ddassert(pagePtr.p->m_file_no == req.p->m_key.m_file_no); 00721 00722 Uint32 old_idx = req.p->m_list_index; 00723 Uint32 free= req.p->m_estimated_free_space; 00724 Uint32 ext = req.p->m_extent_info_ptr; 00725 Uint32 used= req.p->m_uncommitted_used_space; 00726 Uint32 real_free = pagePtr.p->free_space; 00727 Uint32 real_used = used + pagePtr.p->uncommitted_used_space; 00728 00729 ddassert(real_free >= free); 00730 ddassert(real_free >= real_used); 00731 ddassert(alloc.calc_page_free_bits(free) == old_idx); 00732 Uint32 new_idx= alloc.calc_page_free_bits(real_free - real_used); 00733 00737 ArrayPool<Page> *cheat_pool= (ArrayPool<Page>*)&m_global_page_pool; 00738 LocalDLList<Page> list(* cheat_pool, alloc.m_dirty_pages[new_idx]); 00739 list.add(*(Ptr<Page>*)&pagePtr); 00740 pagePtr.p->uncommitted_used_space = real_used; 00741 pagePtr.p->list_index = new_idx; 00742 00743 if (old_idx != new_idx || free != real_free) 00744 { 00745 Ptr<Extent_info> extentPtr; 00746 c_extent_pool.getPtr(extentPtr, ext); 00747 00748 extentPtr.p->m_free_space += (real_free - free); 00749 00750 if (old_idx != new_idx) 00751 { 00752 ddassert(extentPtr.p->m_free_page_count[old_idx]); 00753 extentPtr.p->m_free_page_count[old_idx]--; 00754 extentPtr.p->m_free_page_count[new_idx]++; 00755 } 00756 00757 update_extent_pos(alloc, extentPtr); 00758 } 00759 00760 { 00761 Local_page_request_list list(c_page_request_pool, 00762 alloc.m_page_requests[old_idx]); 00763 list.release(req); 00764 } 00765 } 00766 00767 void 00768 Dbtup::disk_page_set_dirty(Ptr<Page> pagePtr) 00769 { 00770 Uint32 idx = pagePtr.p->list_index; 00771 if ((idx & 0x8000) == 0) 00772 { 00776 return ; 00777 } 00778 00779 Local_key key; 00780 key.m_page_no = pagePtr.p->m_page_no; 00781 key.m_file_no = pagePtr.p->m_file_no; 00782 00783 pagePtr.p->nextList = pagePtr.p->prevList = RNIL; 00784 00785 if (DBG_DISK) 00786 ndbout << " disk_page_set_dirty " << key << endl; 00787 00788 Uint32 tableId = pagePtr.p->m_table_id; 00789 Uint32 fragId = pagePtr.p->m_fragment_id; 00790 00791 Ptr<Tablerec> tabPtr; 00792 tabPtr.i= pagePtr.p->m_table_id; 00793 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 00794 00795 Ptr<Fragrecord> fragPtr; 00796 getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p); 00797 00798 Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; 00799 00800 Uint32 free = pagePtr.p->free_space; 00801 Uint32 used = pagePtr.p->uncommitted_used_space; 00802 if (unlikely(pagePtr.p->m_restart_seq != globalData.m_restart_seq)) 00803 { 00804 jam(); 00805 restart_setup_page(alloc, pagePtr); 00806 idx = alloc.calc_page_free_bits(free); 00807 used = 0; 00808 } 00809 else 00810 { 00811 idx &= ~0x8000; 00812 ddassert(idx == alloc.calc_page_free_bits(free - used)); 00813 } 00814 00815 ddassert(free >= used); 00816 00817 Tablespace_client tsman(0, c_tsman, 00818 fragPtr.p->fragTableId, 00819 fragPtr.p->fragmentId, 00820 fragPtr.p->m_tablespace_id); 00821 00822 pagePtr.p->list_index = idx; 00823 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 00824 LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]); 00825 list.add(pagePtr); 00826 00827 // Make sure no one will allocate it... 00828 tsman.unmap_page(&key, MAX_FREE_LIST - 1); 00829 } 00830 00831 void 00832 Dbtup::disk_page_unmap_callback(Uint32 page_id, Uint32 dirty_count) 00833 { 00834 Ptr<GlobalPage> gpage; 00835 m_global_page_pool.getPtr(gpage, page_id); 00836 PagePtr pagePtr= *(PagePtr*)&gpage; 00837 00838 Uint32 type = pagePtr.p->m_page_header.m_page_type; 00839 if (unlikely((type != File_formats::PT_Tup_fixsize_page && 00840 type != File_formats::PT_Tup_varsize_page) || 00841 f_undo_done == false)) 00842 { 00843 return ; 00844 } 00845 00846 Local_key key; 00847 key.m_page_no = pagePtr.p->m_page_no; 00848 key.m_file_no = pagePtr.p->m_file_no; 00849 Uint32 idx = pagePtr.p->list_index; 00850 00851 ndbassert((idx & 0x8000) == 0); 00852 00853 if (DBG_DISK) 00854 ndbout << "disk_page_unmap_callback " << key << endl; 00855 00856 Ptr<Tablerec> tabPtr; 00857 tabPtr.i= pagePtr.p->m_table_id; 00858 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 00859 00860 Ptr<Fragrecord> fragPtr; 00861 getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p); 00862 00863 Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; 00864 00865 if (dirty_count == 0) 00866 { 00867 Uint32 free = pagePtr.p->free_space; 00868 Uint32 used = pagePtr.p->uncommitted_used_space; 00869 ddassert(free >= used); 00870 ddassert(alloc.calc_page_free_bits(free - used) == idx); 00871 00872 Tablespace_client tsman(0, c_tsman, 00873 fragPtr.p->fragTableId, 00874 fragPtr.p->fragmentId, 00875 fragPtr.p->m_tablespace_id); 00876 00877 tsman.unmap_page(&key, idx); 00878 pagePtr.p->list_index = idx | 0x8000; 00879 } 00880 00881 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 00882 LocalDLList<Page> list(*pool, alloc.m_dirty_pages[idx]); 00883 list.remove(pagePtr); 00884 } 00885 00886 void 00887 Dbtup::disk_page_alloc(Signal* signal, 00888 Tablerec* tabPtrP, Fragrecord* fragPtrP, 00889 Local_key* key, PagePtr pagePtr, Uint32 gci) 00890 { 00891 Uint32 logfile_group_id= fragPtrP->m_logfile_group_id; 00892 Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; 00893 00894 Uint64 lsn; 00895 Uint32 old_free = pagePtr.p->free_space; 00896 Uint32 old_bits= alloc.calc_page_free_bits(old_free); 00897 if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0) 00898 { 00899 ddassert(pagePtr.p->uncommitted_used_space > 0); 00900 pagePtr.p->uncommitted_used_space--; 00901 key->m_page_idx= ((Fix_page*)pagePtr.p)->alloc_record(); 00902 lsn= disk_page_undo_alloc(pagePtr.p, key, 1, gci, logfile_group_id); 00903 } 00904 else 00905 { 00906 Uint32 sz= key->m_page_idx; 00907 ddassert(pagePtr.p->uncommitted_used_space >= sz); 00908 pagePtr.p->uncommitted_used_space -= sz; 00909 key->m_page_idx= ((Var_page*)pagePtr.p)-> 00910 alloc_record(sz, (Var_page*)ctemp_page, 0); 00911 00912 lsn= disk_page_undo_alloc(pagePtr.p, key, sz, gci, logfile_group_id); 00913 } 00914 00915 Uint32 new_free = pagePtr.p->free_space; 00916 Uint32 new_bits= alloc.calc_page_free_bits(new_free); 00917 00918 if (old_bits != new_bits) 00919 { 00920 Tablespace_client tsman(signal, c_tsman, 00921 fragPtrP->fragTableId, 00922 fragPtrP->fragmentId, 00923 fragPtrP->m_tablespace_id); 00924 00925 tsman.update_page_free_bits(key, new_bits, lsn); 00926 } 00927 } 00928 00929 void 00930 Dbtup::disk_page_free(Signal *signal, 00931 Tablerec *tabPtrP, Fragrecord * fragPtrP, 00932 Local_key* key, PagePtr pagePtr, Uint32 gci) 00933 { 00934 if (DBG_DISK) 00935 ndbout << " disk_page_free " << *key << endl; 00936 00937 Uint32 page_idx= key->m_page_idx; 00938 Uint32 logfile_group_id= fragPtrP->m_logfile_group_id; 00939 Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; 00940 Uint32 old_free= pagePtr.p->free_space; 00941 Uint32 old_bits= alloc.calc_page_free_bits(old_free); 00942 00943 Uint32 sz; 00944 Uint64 lsn; 00945 if (tabPtrP->m_attributes[DD].m_no_of_varsize == 0) 00946 { 00947 sz = 1; 00948 const Uint32 *src= ((Fix_page*)pagePtr.p)->get_ptr(page_idx, 0); 00949 ndbassert(* (src + 1) != Tup_fixsize_page::FREE_RECORD); 00950 lsn= disk_page_undo_free(pagePtr.p, key, 00951 src, tabPtrP->m_offsets[DD].m_fix_header_size, 00952 gci, logfile_group_id); 00953 00954 ((Fix_page*)pagePtr.p)->free_record(page_idx); 00955 } 00956 else 00957 { 00958 const Uint32 *src= ((Var_page*)pagePtr.p)->get_ptr(page_idx); 00959 sz= ((Var_page*)pagePtr.p)->get_entry_len(page_idx); 00960 lsn= disk_page_undo_free(pagePtr.p, key, 00961 src, sz, 00962 gci, logfile_group_id); 00963 00964 ((Var_page*)pagePtr.p)->free_record(page_idx, 0); 00965 } 00966 00967 Uint32 new_free = pagePtr.p->free_space; 00968 Uint32 new_bits = alloc.calc_page_free_bits(new_free); 00969 00970 if (old_bits != new_bits) 00971 { 00972 Tablespace_client tsman(signal, c_tsman, 00973 fragPtrP->fragTableId, 00974 fragPtrP->fragmentId, 00975 fragPtrP->m_tablespace_id); 00976 00977 tsman.update_page_free_bits(key, new_bits, lsn); 00978 } 00979 00980 Uint32 ext = pagePtr.p->m_extent_info_ptr; 00981 Uint32 used = pagePtr.p->uncommitted_used_space; 00982 Uint32 old_idx = pagePtr.p->list_index; 00983 ddassert(old_free >= used); 00984 ddassert(new_free >= used); 00985 ddassert(new_free >= old_free); 00986 ddassert((old_idx & 0x8000) == 0); 00987 00988 Uint32 new_idx = alloc.calc_page_free_bits(new_free - used); 00989 ddassert(alloc.calc_page_free_bits(old_free - used) == old_idx); 00990 00991 Ptr<Extent_info> extentPtr; 00992 c_extent_pool.getPtr(extentPtr, ext); 00993 00994 if (old_idx != new_idx) 00995 { 00996 ddassert(extentPtr.p->m_free_page_count[old_idx]); 00997 extentPtr.p->m_free_page_count[old_idx]--; 00998 extentPtr.p->m_free_page_count[new_idx]++; 00999 01000 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 01001 LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]); 01002 LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]); 01003 old_list.remove(pagePtr); 01004 new_list.add(pagePtr); 01005 pagePtr.p->list_index = new_idx; 01006 } 01007 01008 extentPtr.p->m_free_space += sz; 01009 update_extent_pos(alloc, extentPtr); 01010 } 01011 01012 void 01013 Dbtup::disk_page_abort_prealloc(Signal *signal, Fragrecord* fragPtrP, 01014 Local_key* key, Uint32 sz) 01015 { 01016 Page_cache_client::Request req; 01017 req.m_callback.m_callbackData= sz; 01018 req.m_callback.m_callbackFunction = 01019 safe_cast(&Dbtup::disk_page_abort_prealloc_callback); 01020 01021 int flags= Page_cache_client::DIRTY_REQ; 01022 memcpy(&req.m_page, key, sizeof(Local_key)); 01023 01024 int res= m_pgman.get_page(signal, req, flags); 01025 switch(res) 01026 { 01027 case 0: 01028 case -1: 01029 break; 01030 default: 01031 Ptr<GlobalPage> page; 01032 m_global_page_pool.getPtr(page, (Uint32)res); 01033 disk_page_abort_prealloc_callback_1(signal, fragPtrP, *(PagePtr*)&page, 01034 sz); 01035 } 01036 } 01037 01038 void 01039 Dbtup::disk_page_abort_prealloc_callback(Signal* signal, 01040 Uint32 sz, Uint32 page_id) 01041 { 01042 //ndbout_c("disk_alloc_page_callback id: %d", page_id); 01043 01044 Ptr<GlobalPage> gpage; 01045 m_global_page_pool.getPtr(gpage, page_id); 01046 01047 PagePtr pagePtr= *(PagePtr*)&gpage; 01048 01049 Ptr<Tablerec> tabPtr; 01050 tabPtr.i= pagePtr.p->m_table_id; 01051 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 01052 01053 Ptr<Fragrecord> fragPtr; 01054 getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p); 01055 01056 disk_page_abort_prealloc_callback_1(signal, fragPtr.p, pagePtr, sz); 01057 } 01058 01059 void 01060 Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, 01061 Fragrecord* fragPtrP, 01062 PagePtr pagePtr, 01063 Uint32 sz) 01064 { 01065 jam(); 01066 disk_page_set_dirty(pagePtr); 01067 01068 Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; 01069 Uint32 page_idx = pagePtr.p->list_index; 01070 Uint32 used = pagePtr.p->uncommitted_used_space; 01071 Uint32 free = pagePtr.p->free_space; 01072 Uint32 ext = pagePtr.p->m_extent_info_ptr; 01073 01074 Uint32 old_idx = page_idx & 0x7FFF; 01075 ddassert(free >= used); 01076 ddassert(used >= sz); 01077 ddassert(alloc.calc_page_free_bits(free - used) == old_idx); 01078 Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz); 01079 01080 Ptr<Extent_info> extentPtr; 01081 c_extent_pool.getPtr(extentPtr, ext); 01082 if (old_idx != new_idx) 01083 { 01084 ddassert(extentPtr.p->m_free_page_count[old_idx]); 01085 extentPtr.p->m_free_page_count[old_idx]--; 01086 extentPtr.p->m_free_page_count[new_idx]++; 01087 01088 if (old_idx == page_idx) 01089 { 01090 ArrayPool<Page> *pool= (ArrayPool<Page>*)&m_global_page_pool; 01091 LocalDLList<Page> old_list(*pool, alloc.m_dirty_pages[old_idx]); 01092 LocalDLList<Page> new_list(*pool, alloc.m_dirty_pages[new_idx]); 01093 old_list.remove(pagePtr); 01094 new_list.add(pagePtr); 01095 pagePtr.p->list_index = new_idx; 01096 } 01097 else 01098 { 01099 pagePtr.p->list_index = new_idx | 0x8000; 01100 } 01101 } 01102 01103 pagePtr.p->uncommitted_used_space = used - sz; 01104 01105 extentPtr.p->m_free_space += sz; 01106 update_extent_pos(alloc, extentPtr); 01107 } 01108 01109 Uint64 01110 Dbtup::disk_page_undo_alloc(Page* page, const Local_key* key, 01111 Uint32 sz, Uint32 gci, Uint32 logfile_group_id) 01112 { 01113 Logfile_client lsman(this, c_lgman, logfile_group_id); 01114 01115 Disk_undo::Alloc alloc; 01116 alloc.m_type_length= (Disk_undo::UNDO_ALLOC << 16) | (sizeof(alloc) >> 2); 01117 alloc.m_page_no = key->m_page_no; 01118 alloc.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx; 01119 01120 Logfile_client::Change c[1] = {{ &alloc, sizeof(alloc) >> 2 } }; 01121 01122 Uint64 lsn= lsman.add_entry(c, 1); 01123 m_pgman.update_lsn(* key, lsn); 01124 01125 return lsn; 01126 } 01127 01128 Uint64 01129 Dbtup::disk_page_undo_update(Page* page, const Local_key* key, 01130 const Uint32* src, Uint32 sz, 01131 Uint32 gci, Uint32 logfile_group_id) 01132 { 01133 Logfile_client lsman(this, c_lgman, logfile_group_id); 01134 01135 Disk_undo::Update update; 01136 update.m_page_no = key->m_page_no; 01137 update.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx; 01138 update.m_gci= gci; 01139 01140 update.m_type_length= 01141 (Disk_undo::UNDO_UPDATE << 16) | (sz + (sizeof(update) >> 2) - 1); 01142 01143 Logfile_client::Change c[3] = { 01144 { &update, 3 }, 01145 { src, sz }, 01146 { &update.m_type_length, 1 } 01147 }; 01148 01149 ndbassert(4*(3 + sz + 1) == (sizeof(update) + 4*sz - 4)); 01150 01151 Uint64 lsn= lsman.add_entry(c, 3); 01152 m_pgman.update_lsn(* key, lsn); 01153 01154 return lsn; 01155 } 01156 01157 Uint64 01158 Dbtup::disk_page_undo_free(Page* page, const Local_key* key, 01159 const Uint32* src, Uint32 sz, 01160 Uint32 gci, Uint32 logfile_group_id) 01161 { 01162 Logfile_client lsman(this, c_lgman, logfile_group_id); 01163 01164 Disk_undo::Free free; 01165 free.m_page_no = key->m_page_no; 01166 free.m_file_no_page_idx= key->m_file_no << 16 | key->m_page_idx; 01167 free.m_gci= gci; 01168 01169 free.m_type_length= 01170 (Disk_undo::UNDO_FREE << 16) | (sz + (sizeof(free) >> 2) - 1); 01171 01172 Logfile_client::Change c[3] = { 01173 { &free, 3 }, 01174 { src, sz }, 01175 { &free.m_type_length, 1 } 01176 }; 01177 01178 ndbassert(4*(3 + sz + 1) == (sizeof(free) + 4*sz - 4)); 01179 01180 Uint64 lsn= lsman.add_entry(c, 3); 01181 m_pgman.update_lsn(* key, lsn); 01182 01183 return lsn; 01184 } 01185 01186 #include <signaldata/LgmanContinueB.hpp> 01187 01188 static Dbtup::Apply_undo f_undo; 01189 01190 #define DBG_UNDO 0 01191 01192 void 01193 Dbtup::disk_restart_undo(Signal* signal, Uint64 lsn, 01194 Uint32 type, const Uint32 * ptr, Uint32 len) 01195 { 01196 f_undo_done = false; 01197 f_undo.m_lsn= lsn; 01198 f_undo.m_ptr= ptr; 01199 f_undo.m_len= len; 01200 f_undo.m_type = type; 01201 01202 Page_cache_client::Request preq; 01203 switch(f_undo.m_type){ 01204 case File_formats::Undofile::UNDO_LCP_FIRST: 01205 case File_formats::Undofile::UNDO_LCP: 01206 { 01207 ndbrequire(len == 3); 01208 Uint32 tableId = ptr[1] >> 16; 01209 Uint32 fragId = ptr[1] & 0xFFFF; 01210 disk_restart_undo_lcp(tableId, fragId); 01211 disk_restart_undo_next(signal); 01212 return; 01213 } 01214 case File_formats::Undofile::UNDO_TUP_ALLOC: 01215 { 01216 Disk_undo::Alloc* rec= (Disk_undo::Alloc*)ptr; 01217 preq.m_page.m_page_no = rec->m_page_no; 01218 preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; 01219 preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF; 01220 break; 01221 } 01222 case File_formats::Undofile::UNDO_TUP_UPDATE: 01223 { 01224 Disk_undo::Update* rec= (Disk_undo::Update*)ptr; 01225 preq.m_page.m_page_no = rec->m_page_no; 01226 preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; 01227 preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF; 01228 break; 01229 } 01230 case File_formats::Undofile::UNDO_TUP_FREE: 01231 { 01232 Disk_undo::Free* rec= (Disk_undo::Free*)ptr; 01233 preq.m_page.m_page_no = rec->m_page_no; 01234 preq.m_page.m_file_no = rec->m_file_no_page_idx >> 16; 01235 preq.m_page.m_page_idx = rec->m_file_no_page_idx & 0xFFFF; 01236 break; 01237 } 01238 case File_formats::Undofile::UNDO_TUP_CREATE: 01242 { 01243 Disk_undo::Create* rec= (Disk_undo::Create*)ptr; 01244 Ptr<Tablerec> tabPtr; 01245 tabPtr.i= rec->m_table; 01246 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 01247 for(Uint32 i = 0; i<MAX_FRAG_PER_NODE; i++) 01248 if (tabPtr.p->fragrec[i] != RNIL) 01249 disk_restart_undo_lcp(tabPtr.i, tabPtr.p->fragid[i]); 01250 disk_restart_undo_next(signal); 01251 return; 01252 } 01253 case File_formats::Undofile::UNDO_END: 01254 f_undo_done = true; 01255 return; 01256 default: 01257 ndbrequire(false); 01258 } 01259 01260 f_undo.m_key = preq.m_page; 01261 preq.m_callback.m_callbackFunction = 01262 safe_cast(&Dbtup::disk_restart_undo_callback); 01263 01264 int flags = 0; 01265 int res= m_pgman.get_page(signal, preq, flags); 01266 switch(res) 01267 { 01268 case 0: 01269 break; // Wait for callback 01270 case -1: 01271 ndbrequire(false); 01272 break; 01273 default: 01274 execute(signal, preq.m_callback, res); // run callback 01275 } 01276 } 01277 01278 void 01279 Dbtup::disk_restart_undo_next(Signal* signal) 01280 { 01281 signal->theData[0] = LgmanContinueB::EXECUTE_UNDO_RECORD; 01282 sendSignal(LGMAN_REF, GSN_CONTINUEB, signal, 1, JBB); 01283 } 01284 01285 void 01286 Dbtup::disk_restart_undo_lcp(Uint32 tableId, Uint32 fragId) 01287 { 01288 Ptr<Tablerec> tabPtr; 01289 tabPtr.i= tableId; 01290 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 01291 01292 if (tabPtr.p->tableStatus == DEFINED) 01293 { 01294 FragrecordPtr fragPtr; 01295 getFragmentrec(fragPtr, fragId, tabPtr.p); 01296 if (!fragPtr.isNull()) 01297 { 01298 fragPtr.p->m_undo_complete = true; 01299 } 01300 } 01301 } 01302 01303 void 01304 Dbtup::disk_restart_undo_callback(Signal* signal, 01305 Uint32 id, 01306 Uint32 page_id) 01307 { 01308 jamEntry(); 01309 Ptr<GlobalPage> gpage; 01310 m_global_page_pool.getPtr(gpage, page_id); 01311 Ptr<Page> pagePtr = *(Ptr<Page>*)&gpage; 01312 01313 Apply_undo* undo = &f_undo; 01314 01315 bool update = false; 01316 if (! (pagePtr.p->list_index & 0x8000) || 01317 pagePtr.p->nextList != RNIL || 01318 pagePtr.p->prevList != RNIL) 01319 { 01320 update = true; 01321 pagePtr.p->list_index |= 0x8000; 01322 pagePtr.p->nextList = pagePtr.p->prevList = RNIL; 01323 } 01324 01325 Uint32 tableId= pagePtr.p->m_table_id; 01326 Uint32 fragId = pagePtr.p->m_fragment_id; 01327 01328 if (tableId >= cnoOfTablerec) 01329 { 01330 disk_restart_undo_next(signal); 01331 return; 01332 } 01333 undo->m_table_ptr.i = tableId; 01334 ptrCheckGuard(undo->m_table_ptr, cnoOfTablerec, tablerec); 01335 01336 if (undo->m_table_ptr.p->tableStatus != DEFINED) 01337 { 01338 disk_restart_undo_next(signal); 01339 return; 01340 } 01341 01342 getFragmentrec(undo->m_fragment_ptr, fragId, undo->m_table_ptr.p); 01343 if(undo->m_fragment_ptr.isNull()) 01344 { 01345 disk_restart_undo_next(signal); 01346 return; 01347 } 01348 01349 if (undo->m_fragment_ptr.p->m_undo_complete) 01350 { 01351 disk_restart_undo_next(signal); 01352 return; 01353 } 01354 01355 Local_key key; 01356 key.m_page_no = pagePtr.p->m_page_no; 01357 key.m_file_no = pagePtr.p->m_file_no; 01358 01359 Uint64 lsn = 0; 01360 lsn += pagePtr.p->m_page_header.m_page_lsn_hi; lsn <<= 32; 01361 lsn += pagePtr.p->m_page_header.m_page_lsn_lo; 01362 01363 undo->m_page_ptr = pagePtr; 01364 01365 if (undo->m_lsn <= lsn) 01366 { 01367 if (DBG_UNDO) 01368 { 01369 ndbout << "apply: " << undo->m_lsn << "(" << lsn << " )" 01370 << key << " type: " << undo->m_type << endl; 01371 } 01372 01373 update = true; 01374 if (DBG_UNDO) 01375 ndbout_c("applying %lld", undo->m_lsn); 01379 switch(undo->m_type){ 01380 case File_formats::Undofile::UNDO_TUP_ALLOC: 01381 disk_restart_undo_alloc(undo); 01382 break; 01383 case File_formats::Undofile::UNDO_TUP_UPDATE: 01384 disk_restart_undo_update(undo); 01385 break; 01386 case File_formats::Undofile::UNDO_TUP_FREE: 01387 disk_restart_undo_free(undo); 01388 break; 01389 default: 01390 ndbrequire(false); 01391 } 01392 01393 if (DBG_UNDO) 01394 ndbout << "disk_restart_undo: " << undo->m_type << " " 01395 << undo->m_key << endl; 01396 01397 lsn = undo->m_lsn - 1; // make sure undo isn't run again... 01398 01399 m_pgman.update_lsn(undo->m_key, lsn); 01400 } 01401 else if (DBG_UNDO) 01402 { 01403 ndbout << "ignore: " << undo->m_lsn << "(" << lsn << " )" 01404 << key << " type: " << undo->m_type << endl; 01405 } 01406 01407 disk_restart_undo_page_bits(signal, undo); 01408 disk_restart_undo_next(signal); 01409 } 01410 01411 void 01412 Dbtup::disk_restart_undo_alloc(Apply_undo* undo) 01413 { 01414 ndbassert(undo->m_page_ptr.p->m_file_no == undo->m_key.m_file_no); 01415 ndbassert(undo->m_page_ptr.p->m_page_no == undo->m_key.m_page_no); 01416 if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0) 01417 { 01418 ((Fix_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx); 01419 } 01420 else 01421 ((Var_page*)undo->m_page_ptr.p)->free_record(undo->m_key.m_page_idx, 0); 01422 } 01423 01424 void 01425 Dbtup::disk_restart_undo_update(Apply_undo* undo) 01426 { 01427 Uint32* ptr; 01428 Uint32 len= undo->m_len - 4; 01429 if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0) 01430 { 01431 ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx, len); 01432 ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size); 01433 } 01434 else 01435 { 01436 ptr= ((Var_page*)undo->m_page_ptr.p)->get_ptr(undo->m_key.m_page_idx); 01437 abort(); 01438 } 01439 01440 const Disk_undo::Update *update = (const Disk_undo::Update*)undo->m_ptr; 01441 const Uint32* src= update->m_data; 01442 memcpy(ptr, src, 4 * len); 01443 } 01444 01445 void 01446 Dbtup::disk_restart_undo_free(Apply_undo* undo) 01447 { 01448 Uint32* ptr, idx = undo->m_key.m_page_idx; 01449 Uint32 len= undo->m_len - 4; 01450 if (undo->m_table_ptr.p->m_attributes[DD].m_no_of_varsize == 0) 01451 { 01452 ndbrequire(len == undo->m_table_ptr.p->m_offsets[DD].m_fix_header_size); 01453 idx= ((Fix_page*)undo->m_page_ptr.p)->alloc_record(idx); 01454 ptr= ((Fix_page*)undo->m_page_ptr.p)->get_ptr(idx, len); 01455 } 01456 else 01457 { 01458 abort(); 01459 } 01460 01461 ndbrequire(idx == undo->m_key.m_page_idx); 01462 const Disk_undo::Free *free = (const Disk_undo::Free*)undo->m_ptr; 01463 const Uint32* src= free->m_data; 01464 memcpy(ptr, src, 4 * len); 01465 } 01466 01467 void 01468 Dbtup::disk_restart_undo_page_bits(Signal* signal, Apply_undo* undo) 01469 { 01470 Fragrecord* fragPtrP = undo->m_fragment_ptr.p; 01471 Disk_alloc_info& alloc= fragPtrP->m_disk_alloc_info; 01472 01477 Page* pageP = undo->m_page_ptr.p; 01478 Uint32 free = pageP->free_space; 01479 Uint32 new_bits = alloc.calc_page_free_bits(free); 01480 pageP->list_index = 0x8000 | new_bits; 01481 01482 Uint64 lsn = 0; 01483 lsn += pageP->m_page_header.m_page_lsn_hi; lsn <<= 32; 01484 lsn += pageP->m_page_header.m_page_lsn_lo; 01485 01486 Tablespace_client tsman(signal, c_tsman, 01487 fragPtrP->fragTableId, 01488 fragPtrP->fragmentId, 01489 fragPtrP->m_tablespace_id); 01490 01491 tsman.restart_undo_page_free_bits(&undo->m_key, new_bits, undo->m_lsn, lsn); 01492 } 01493 01494 int 01495 Dbtup::disk_restart_alloc_extent(Uint32 tableId, Uint32 fragId, 01496 const Local_key* key, Uint32 pages) 01497 { 01498 TablerecPtr tabPtr; 01499 FragrecordPtr fragPtr; 01500 tabPtr.i = tableId; 01501 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 01502 if (tabPtr.p->tableStatus == DEFINED) 01503 { 01504 getFragmentrec(fragPtr, fragId, tabPtr.p); 01505 if (!fragPtr.isNull()) 01506 { 01507 Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; 01508 01509 Ptr<Extent_info> ext; 01510 ndbrequire(c_extent_pool.seize(ext)); 01511 01512 ndbout << "allocated " << pages << " pages: " << *key << endl; 01513 01514 ext.p->m_key = *key; 01515 ext.p->m_first_page_no = ext.p->m_key.m_page_no; 01516 ext.p->m_free_space= 0; 01517 bzero(ext.p->m_free_page_count, sizeof(ext.p->m_free_page_count)); 01518 01519 if (alloc.m_curr_extent_info_ptr_i != RNIL) 01520 { 01521 Ptr<Extent_info> old; 01522 c_extent_pool.getPtr(old, alloc.m_curr_extent_info_ptr_i); 01523 ndbassert(old.p->m_free_matrix_pos == RNIL); 01524 Uint32 pos= alloc.calc_extent_pos(old.p); 01525 Local_extent_info_list new_list(c_extent_pool, alloc.m_free_extents[pos]); 01526 new_list.add(old); 01527 old.p->m_free_matrix_pos= pos; 01528 } 01529 01530 alloc.m_curr_extent_info_ptr_i = ext.i; 01531 ext.p->m_free_matrix_pos = RNIL; 01532 c_extent_hash.add(ext); 01533 01534 Local_fragment_extent_list list1(c_extent_pool, alloc.m_extent_list); 01535 list1.add(ext); 01536 return 0; 01537 } 01538 } 01539 01540 return -1; 01541 } 01542 01543 void 01544 Dbtup::disk_restart_page_bits(Uint32 tableId, Uint32 fragId, 01545 const Local_key*, Uint32 bits) 01546 { 01547 TablerecPtr tabPtr; 01548 FragrecordPtr fragPtr; 01549 tabPtr.i = tableId; 01550 ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec); 01551 getFragmentrec(fragPtr, fragId, tabPtr.p); 01552 Disk_alloc_info& alloc= fragPtr.p->m_disk_alloc_info; 01553 01554 Ptr<Extent_info> ext; 01555 c_extent_pool.getPtr(ext, alloc.m_curr_extent_info_ptr_i); 01556 01557 Uint32 size= alloc.calc_page_free_space(bits); 01558 01559 ext.p->m_free_space += size; 01560 ext.p->m_free_page_count[bits]++; 01561 ndbassert(ext.p->m_free_matrix_pos == RNIL); 01562 }
1.4.7

