Drizzled Public API Documentation

btr0pcur.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
00016 
00017 *****************************************************************************/
00018 
00019 /**************************************************/
00026 #include "btr0pcur.h"
00027 
00028 #ifdef UNIV_NONINL
00029 #include "btr0pcur.ic"
00030 #endif
00031 
00032 #include "ut0byte.h"
00033 #include "rem0cmp.h"
00034 #include "trx0trx.h"
00035 
00036 /**************************************************************/
00039 UNIV_INTERN
00040 btr_pcur_t*
00041 btr_pcur_create_for_mysql(void)
00042 /*============================*/
00043 {
00044   btr_pcur_t* pcur;
00045 
00046   pcur = (btr_pcur_t *)mem_alloc(sizeof(btr_pcur_t));
00047 
00048   pcur->btr_cur.index = NULL;
00049   btr_pcur_init(pcur);
00050 
00051   return(pcur);
00052 }
00053 
00054 /**************************************************************/
00056 UNIV_INTERN
00057 void
00058 btr_pcur_free_for_mysql(
00059 /*====================*/
00060   btr_pcur_t* cursor) 
00061 {
00062   if (cursor->old_rec_buf != NULL) {
00063 
00064     mem_free(cursor->old_rec_buf);
00065 
00066     cursor->old_rec_buf = NULL;
00067   }
00068 
00069   cursor->btr_cur.page_cur.rec = NULL;
00070   cursor->old_rec = NULL;
00071   cursor->old_n_fields = 0;
00072   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00073 
00074   cursor->latch_mode = BTR_NO_LATCHES;
00075   cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
00076 
00077   mem_free(cursor);
00078 }
00079 
00080 /**************************************************************/
00087 UNIV_INTERN
00088 void
00089 btr_pcur_store_position(
00090 /*====================*/
00091   btr_pcur_t* cursor, 
00092   mtr_t*    mtr)  
00093 {
00094   page_cur_t* page_cursor;
00095   buf_block_t*  block;
00096   rec_t*    rec;
00097   dict_index_t* index;
00098   page_t*   page;
00099   ulint   offs;
00100 
00101   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00102   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00103 
00104   block = btr_pcur_get_block(cursor);
00105   index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
00106 
00107   page_cursor = btr_pcur_get_page_cur(cursor);
00108 
00109   rec = page_cur_get_rec(page_cursor);
00110   page = page_align(rec);
00111   offs = page_offset(rec);
00112 
00113   ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
00114         || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
00115   ut_a(cursor->latch_mode != BTR_NO_LATCHES);
00116 
00117   if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
00118     /* It must be an empty index tree; NOTE that in this case
00119     we do not store the modify_clock, but always do a search
00120     if we restore the cursor position */
00121 
00122     ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
00123     ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
00124 
00125     cursor->old_stored = BTR_PCUR_OLD_STORED;
00126 
00127     if (page_rec_is_supremum_low(offs)) {
00128 
00129       cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
00130     } else {
00131       cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
00132     }
00133 
00134     return;
00135   }
00136 
00137   if (page_rec_is_supremum_low(offs)) {
00138 
00139     rec = page_rec_get_prev(rec);
00140 
00141     cursor->rel_pos = BTR_PCUR_AFTER;
00142 
00143   } else if (page_rec_is_infimum_low(offs)) {
00144 
00145     rec = page_rec_get_next(rec);
00146 
00147     cursor->rel_pos = BTR_PCUR_BEFORE;
00148   } else {
00149     cursor->rel_pos = BTR_PCUR_ON;
00150   }
00151 
00152   cursor->old_stored = BTR_PCUR_OLD_STORED;
00153   cursor->old_rec = dict_index_copy_rec_order_prefix(
00154     index, rec, &cursor->old_n_fields,
00155     &cursor->old_rec_buf, &cursor->buf_size);
00156 
00157   cursor->block_when_stored = block;
00158   cursor->modify_clock = buf_block_get_modify_clock(block);
00159 }
00160 
00161 /**************************************************************/
00163 UNIV_INTERN
00164 void
00165 btr_pcur_copy_stored_position(
00166 /*==========================*/
00167   btr_pcur_t* pcur_receive, 
00169   btr_pcur_t* pcur_donate)  
00171 {
00172   if (pcur_receive->old_rec_buf) {
00173     mem_free(pcur_receive->old_rec_buf);
00174   }
00175 
00176   ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
00177 
00178   if (pcur_donate->old_rec_buf) {
00179 
00180     pcur_receive->old_rec_buf = (unsigned char *)mem_alloc(pcur_donate->buf_size);
00181 
00182     ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
00183         pcur_donate->buf_size);
00184     pcur_receive->old_rec = pcur_receive->old_rec_buf
00185       + (pcur_donate->old_rec - pcur_donate->old_rec_buf);
00186   }
00187 
00188   pcur_receive->old_n_fields = pcur_donate->old_n_fields;
00189 }
00190 
00191 /**************************************************************/
00206 UNIV_INTERN
00207 ibool
00208 btr_pcur_restore_position_func(
00209 /*===========================*/
00210   ulint   latch_mode, 
00211   btr_pcur_t* cursor,   
00212   const char* file,   
00213   ulint   line,   
00214   mtr_t*    mtr)    
00215 {
00216   dict_index_t* index;
00217   dtuple_t* tuple;
00218   ulint   mode;
00219   ulint   old_mode;
00220   mem_heap_t* heap;
00221 
00222   ut_ad(mtr);
00223   ut_ad(mtr->state == MTR_ACTIVE);
00224 
00225   index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
00226 
00227   if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
00228       || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
00229            && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
00230     ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
00231     putc('\n', stderr);
00232     if (cursor->trx_if_known) {
00233       trx_print(stderr, cursor->trx_if_known, 0);
00234     }
00235 
00236     ut_error;
00237   }
00238 
00239   if (UNIV_UNLIKELY
00240       (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
00241        || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
00242 
00243     /* In these cases we do not try an optimistic restoration,
00244     but always do a search */
00245 
00246     btr_cur_open_at_index_side(
00247       cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
00248       index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
00249 
00250     cursor->block_when_stored = btr_pcur_get_block(cursor);
00251 
00252     return(FALSE);
00253   }
00254 
00255   ut_a(cursor->old_rec);
00256   ut_a(cursor->old_n_fields);
00257 
00258   if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
00259       || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
00260     /* Try optimistic restoration */
00261 
00262     if (UNIV_LIKELY(buf_page_optimistic_get(
00263           latch_mode,
00264           cursor->block_when_stored,
00265           cursor->modify_clock,
00266           file, line, mtr))) {
00267       cursor->pos_state = BTR_PCUR_IS_POSITIONED;
00268 
00269       buf_block_dbg_add_level(btr_pcur_get_block(cursor),
00270             SYNC_TREE_NODE);
00271 
00272       if (cursor->rel_pos == BTR_PCUR_ON) {
00273 #ifdef UNIV_DEBUG
00274         const rec_t*  rec;
00275         const ulint*  offsets1;
00276         const ulint*  offsets2;
00277 #endif /* UNIV_DEBUG */
00278         cursor->latch_mode = latch_mode;
00279 #ifdef UNIV_DEBUG
00280         rec = btr_pcur_get_rec(cursor);
00281 
00282         heap = mem_heap_create(256);
00283         offsets1 = rec_get_offsets(
00284           cursor->old_rec, index, NULL,
00285           cursor->old_n_fields, &heap);
00286         offsets2 = rec_get_offsets(
00287           rec, index, NULL,
00288           cursor->old_n_fields, &heap);
00289 
00290         ut_ad(!cmp_rec_rec(cursor->old_rec,
00291                rec, offsets1, offsets2,
00292                index));
00293         mem_heap_free(heap);
00294 #endif /* UNIV_DEBUG */
00295         return(TRUE);
00296       }
00297 
00298       return(FALSE);
00299     }
00300   }
00301 
00302   /* If optimistic restoration did not succeed, open the cursor anew */
00303 
00304   heap = mem_heap_create(256);
00305 
00306   tuple = dict_index_build_data_tuple(index, cursor->old_rec,
00307               cursor->old_n_fields, heap);
00308 
00309   /* Save the old search mode of the cursor */
00310   old_mode = cursor->search_mode;
00311 
00312   if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
00313     mode = PAGE_CUR_LE;
00314   } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
00315     mode = PAGE_CUR_G;
00316   } else {
00317     ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
00318     mode = PAGE_CUR_L;
00319   }
00320 
00321   btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
00322           cursor, 0, file, line, mtr);
00323 
00324   /* Restore the old search mode */
00325   cursor->search_mode = old_mode;
00326 
00327   if (cursor->rel_pos == BTR_PCUR_ON
00328       && btr_pcur_is_on_user_rec(cursor)
00329       && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
00330            rec_get_offsets(
00331              btr_pcur_get_rec(cursor), index,
00332              NULL, ULINT_UNDEFINED, &heap))) {
00333 
00334     /* We have to store the NEW value for the modify clock, since
00335     the cursor can now be on a different page! But we can retain
00336     the value of old_rec */
00337 
00338     cursor->block_when_stored = btr_pcur_get_block(cursor);
00339     cursor->modify_clock = buf_block_get_modify_clock(
00340       cursor->block_when_stored);
00341     cursor->old_stored = BTR_PCUR_OLD_STORED;
00342 
00343     mem_heap_free(heap);
00344 
00345     return(TRUE);
00346   }
00347 
00348   mem_heap_free(heap);
00349 
00350   /* We have to store new position information, modify_clock etc.,
00351   to the cursor because it can now be on a different page, the record
00352   under it may have been removed, etc. */
00353 
00354   btr_pcur_store_position(cursor, mtr);
00355 
00356   return(FALSE);
00357 }
00358 
00359 /**************************************************************/
00365 UNIV_INTERN
00366 void
00367 btr_pcur_release_leaf(
00368 /*==================*/
00369   btr_pcur_t* cursor, 
00370   mtr_t*    mtr)  
00371 {
00372   buf_block_t*  block;
00373 
00374   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00375   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00376 
00377   block = btr_pcur_get_block(cursor);
00378 
00379   btr_leaf_page_release(block, cursor->latch_mode, mtr);
00380 
00381   cursor->latch_mode = BTR_NO_LATCHES;
00382 
00383   cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
00384 }
00385 
00386 /*********************************************************/
00391 UNIV_INTERN
00392 void
00393 btr_pcur_move_to_next_page(
00394 /*=======================*/
00395   btr_pcur_t* cursor, 
00397   mtr_t*    mtr)  
00398 {
00399   ulint   next_page_no;
00400   ulint   space;
00401   ulint   zip_size;
00402   page_t*   page;
00403   buf_block_t*  next_block;
00404   page_t*   next_page;
00405 
00406   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00407   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00408   ut_ad(btr_pcur_is_after_last_on_page(cursor));
00409 
00410   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00411 
00412   page = btr_pcur_get_page(cursor);
00413   next_page_no = btr_page_get_next(page, mtr);
00414   space = buf_block_get_space(btr_pcur_get_block(cursor));
00415   zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
00416 
00417   ut_ad(next_page_no != FIL_NULL);
00418 
00419   next_block = btr_block_get(space, zip_size, next_page_no,
00420            cursor->latch_mode, mtr);
00421   next_page = buf_block_get_frame(next_block);
00422 #ifdef UNIV_BTR_DEBUG
00423   ut_a(page_is_comp(next_page) == page_is_comp(page));
00424   ut_a(btr_page_get_prev(next_page, mtr)
00425        == buf_block_get_page_no(btr_pcur_get_block(cursor)));
00426 #endif /* UNIV_BTR_DEBUG */
00427   next_block->check_index_page_at_flush = TRUE;
00428 
00429   btr_leaf_page_release(btr_pcur_get_block(cursor),
00430             cursor->latch_mode, mtr);
00431 
00432   page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
00433 
00434   page_check_dir(next_page);
00435 }
00436 
00437 /*********************************************************/
00446 UNIV_INTERN
00447 void
00448 btr_pcur_move_backward_from_page(
00449 /*=============================*/
00450   btr_pcur_t* cursor, 
00452   mtr_t*    mtr)  
00453 {
00454   ulint   prev_page_no;
00455   page_t*   page;
00456   buf_block_t*  prev_block;
00457   ulint   latch_mode;
00458   ulint   latch_mode2;
00459 
00460   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00461   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00462   ut_ad(btr_pcur_is_before_first_on_page(cursor));
00463   ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
00464 
00465   latch_mode = cursor->latch_mode;
00466 
00467   if (latch_mode == BTR_SEARCH_LEAF) {
00468 
00469     latch_mode2 = BTR_SEARCH_PREV;
00470 
00471   } else if (latch_mode == BTR_MODIFY_LEAF) {
00472 
00473     latch_mode2 = BTR_MODIFY_PREV;
00474   } else {
00475     latch_mode2 = 0; /* To eliminate compiler warning */
00476     ut_error;
00477   }
00478 
00479   btr_pcur_store_position(cursor, mtr);
00480 
00481   mtr_commit(mtr);
00482 
00483   mtr_start(mtr);
00484 
00485   btr_pcur_restore_position(latch_mode2, cursor, mtr);
00486 
00487   page = btr_pcur_get_page(cursor);
00488 
00489   prev_page_no = btr_page_get_prev(page, mtr);
00490 
00491   if (prev_page_no == FIL_NULL) {
00492   } else if (btr_pcur_is_before_first_on_page(cursor)) {
00493 
00494     prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
00495 
00496     btr_leaf_page_release(btr_pcur_get_block(cursor),
00497               latch_mode, mtr);
00498 
00499     page_cur_set_after_last(prev_block,
00500           btr_pcur_get_page_cur(cursor));
00501   } else {
00502 
00503     /* The repositioned cursor did not end on an infimum record on
00504     a page. Cursor repositioning acquired a latch also on the
00505     previous page, but we do not need the latch: release it. */
00506 
00507     prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
00508 
00509     btr_leaf_page_release(prev_block, latch_mode, mtr);
00510   }
00511 
00512   cursor->latch_mode = latch_mode;
00513 
00514   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00515 }
00516 
00517 /*********************************************************/
00521 UNIV_INTERN
00522 ibool
00523 btr_pcur_move_to_prev(
00524 /*==================*/
00525   btr_pcur_t* cursor, 
00527   mtr_t*    mtr)  
00528 {
00529   ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00530   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00531 
00532   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00533 
00534   if (btr_pcur_is_before_first_on_page(cursor)) {
00535 
00536     if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
00537 
00538       return(FALSE);
00539     }
00540 
00541     btr_pcur_move_backward_from_page(cursor, mtr);
00542 
00543     return(TRUE);
00544   }
00545 
00546   btr_pcur_move_to_prev_on_page(cursor);
00547 
00548   return(TRUE);
00549 }
00550 
00551 /**************************************************************/
00558 UNIV_INTERN
00559 void
00560 btr_pcur_open_on_user_rec_func(
00561 /*===========================*/
00562   dict_index_t* index,    
00563   const dtuple_t* tuple,    
00564   ulint   mode,   
00565   ulint   latch_mode, 
00567   btr_pcur_t* cursor,   
00569   const char* file,   
00570   ulint   line,   
00571   mtr_t*    mtr)    
00572 {
00573   btr_pcur_open_func(index, tuple, mode, latch_mode, cursor,
00574          file, line, mtr);
00575 
00576   if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
00577 
00578     if (btr_pcur_is_after_last_on_page(cursor)) {
00579 
00580       btr_pcur_move_to_next_user_rec(cursor, mtr);
00581     }
00582   } else {
00583     ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
00584 
00585     /* Not implemented yet */
00586 
00587     ut_error;
00588   }
00589 }