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->latch_mode = latch_mode;
00251                 cursor->pos_state = BTR_PCUR_IS_POSITIONED;
00252     cursor->block_when_stored = btr_pcur_get_block(cursor);
00253 
00254     return(FALSE);
00255   }
00256 
00257   ut_a(cursor->old_rec);
00258   ut_a(cursor->old_n_fields);
00259 
00260   if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
00261       || UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
00262     /* Try optimistic restoration */
00263 
00264     if (UNIV_LIKELY(buf_page_optimistic_get(
00265           latch_mode,
00266           cursor->block_when_stored,
00267           cursor->modify_clock,
00268           file, line, mtr))) {
00269       cursor->pos_state = BTR_PCUR_IS_POSITIONED;
00270 
00271       buf_block_dbg_add_level(btr_pcur_get_block(cursor),
00272             SYNC_TREE_NODE);
00273 
00274       if (cursor->rel_pos == BTR_PCUR_ON) {
00275 #ifdef UNIV_DEBUG
00276         const rec_t*  rec;
00277         const ulint*  offsets1;
00278         const ulint*  offsets2;
00279 #endif /* UNIV_DEBUG */
00280         cursor->latch_mode = latch_mode;
00281 #ifdef UNIV_DEBUG
00282         rec = btr_pcur_get_rec(cursor);
00283 
00284         heap = mem_heap_create(256);
00285         offsets1 = rec_get_offsets(
00286           cursor->old_rec, index, NULL,
00287           cursor->old_n_fields, &heap);
00288         offsets2 = rec_get_offsets(
00289           rec, index, NULL,
00290           cursor->old_n_fields, &heap);
00291 
00292         ut_ad(!cmp_rec_rec(cursor->old_rec,
00293                rec, offsets1, offsets2,
00294                index));
00295         mem_heap_free(heap);
00296 #endif /* UNIV_DEBUG */
00297         return(TRUE);
00298       }
00299 
00300       return(FALSE);
00301     }
00302   }
00303 
00304   /* If optimistic restoration did not succeed, open the cursor anew */
00305 
00306   heap = mem_heap_create(256);
00307 
00308   tuple = dict_index_build_data_tuple(index, cursor->old_rec,
00309               cursor->old_n_fields, heap);
00310 
00311   /* Save the old search mode of the cursor */
00312   old_mode = cursor->search_mode;
00313 
00314   if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
00315     mode = PAGE_CUR_LE;
00316   } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
00317     mode = PAGE_CUR_G;
00318   } else {
00319     ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
00320     mode = PAGE_CUR_L;
00321   }
00322 
00323   btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
00324           cursor, 0, file, line, mtr);
00325 
00326   /* Restore the old search mode */
00327   cursor->search_mode = old_mode;
00328 
00329   if (cursor->rel_pos == BTR_PCUR_ON
00330       && btr_pcur_is_on_user_rec(cursor)
00331       && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
00332            rec_get_offsets(
00333              btr_pcur_get_rec(cursor), index,
00334              NULL, ULINT_UNDEFINED, &heap))) {
00335 
00336     /* We have to store the NEW value for the modify clock, since
00337     the cursor can now be on a different page! But we can retain
00338     the value of old_rec */
00339 
00340     cursor->block_when_stored = btr_pcur_get_block(cursor);
00341     cursor->modify_clock = buf_block_get_modify_clock(
00342       cursor->block_when_stored);
00343     cursor->old_stored = BTR_PCUR_OLD_STORED;
00344 
00345     mem_heap_free(heap);
00346 
00347     return(TRUE);
00348   }
00349 
00350   mem_heap_free(heap);
00351 
00352   /* We have to store new position information, modify_clock etc.,
00353   to the cursor because it can now be on a different page, the record
00354   under it may have been removed, etc. */
00355 
00356   btr_pcur_store_position(cursor, mtr);
00357 
00358   return(FALSE);
00359 }
00360 
00361 /**************************************************************/
00367 UNIV_INTERN
00368 void
00369 btr_pcur_release_leaf(
00370 /*==================*/
00371   btr_pcur_t* cursor, 
00372   mtr_t*    mtr)  
00373 {
00374   buf_block_t*  block;
00375 
00376   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00377   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00378 
00379   block = btr_pcur_get_block(cursor);
00380 
00381   btr_leaf_page_release(block, cursor->latch_mode, mtr);
00382 
00383   cursor->latch_mode = BTR_NO_LATCHES;
00384 
00385   cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
00386 }
00387 
00388 /*********************************************************/
00393 UNIV_INTERN
00394 void
00395 btr_pcur_move_to_next_page(
00396 /*=======================*/
00397   btr_pcur_t* cursor, 
00399   mtr_t*    mtr)  
00400 {
00401   ulint   next_page_no;
00402   ulint   space;
00403   ulint   zip_size;
00404   page_t*   page;
00405   buf_block_t*  next_block;
00406   page_t*   next_page;
00407 
00408   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00409   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00410   ut_ad(btr_pcur_is_after_last_on_page(cursor));
00411 
00412   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00413 
00414   page = btr_pcur_get_page(cursor);
00415   next_page_no = btr_page_get_next(page, mtr);
00416   space = buf_block_get_space(btr_pcur_get_block(cursor));
00417   zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
00418 
00419   ut_ad(next_page_no != FIL_NULL);
00420 
00421   next_block = btr_block_get(space, zip_size, next_page_no,
00422            cursor->latch_mode, mtr);
00423   next_page = buf_block_get_frame(next_block);
00424 #ifdef UNIV_BTR_DEBUG
00425   ut_a(page_is_comp(next_page) == page_is_comp(page));
00426   ut_a(btr_page_get_prev(next_page, mtr)
00427        == buf_block_get_page_no(btr_pcur_get_block(cursor)));
00428 #endif /* UNIV_BTR_DEBUG */
00429   next_block->check_index_page_at_flush = TRUE;
00430 
00431   btr_leaf_page_release(btr_pcur_get_block(cursor),
00432             cursor->latch_mode, mtr);
00433 
00434   page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
00435 
00436   page_check_dir(next_page);
00437 }
00438 
00439 /*********************************************************/
00448 UNIV_INTERN
00449 void
00450 btr_pcur_move_backward_from_page(
00451 /*=============================*/
00452   btr_pcur_t* cursor, 
00454   mtr_t*    mtr)  
00455 {
00456   ulint   prev_page_no;
00457   page_t*   page;
00458   buf_block_t*  prev_block;
00459   ulint   latch_mode;
00460   ulint   latch_mode2;
00461 
00462   ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00463   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00464   ut_ad(btr_pcur_is_before_first_on_page(cursor));
00465   ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
00466 
00467   latch_mode = cursor->latch_mode;
00468 
00469   if (latch_mode == BTR_SEARCH_LEAF) {
00470 
00471     latch_mode2 = BTR_SEARCH_PREV;
00472 
00473   } else if (latch_mode == BTR_MODIFY_LEAF) {
00474 
00475     latch_mode2 = BTR_MODIFY_PREV;
00476   } else {
00477     latch_mode2 = 0; /* To eliminate compiler warning */
00478     ut_error;
00479   }
00480 
00481   btr_pcur_store_position(cursor, mtr);
00482 
00483   mtr_commit(mtr);
00484 
00485   mtr_start(mtr);
00486 
00487   btr_pcur_restore_position(latch_mode2, cursor, mtr);
00488 
00489   page = btr_pcur_get_page(cursor);
00490 
00491   prev_page_no = btr_page_get_prev(page, mtr);
00492 
00493   if (prev_page_no == FIL_NULL) {
00494   } else if (btr_pcur_is_before_first_on_page(cursor)) {
00495 
00496     prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
00497 
00498     btr_leaf_page_release(btr_pcur_get_block(cursor),
00499               latch_mode, mtr);
00500 
00501     page_cur_set_after_last(prev_block,
00502           btr_pcur_get_page_cur(cursor));
00503   } else {
00504 
00505     /* The repositioned cursor did not end on an infimum record on
00506     a page. Cursor repositioning acquired a latch also on the
00507     previous page, but we do not need the latch: release it. */
00508 
00509     prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
00510 
00511     btr_leaf_page_release(prev_block, latch_mode, mtr);
00512   }
00513 
00514   cursor->latch_mode = latch_mode;
00515 
00516   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00517 }
00518 
00519 /*********************************************************/
00523 UNIV_INTERN
00524 ibool
00525 btr_pcur_move_to_prev(
00526 /*==================*/
00527   btr_pcur_t* cursor, 
00529   mtr_t*    mtr)  
00530 {
00531   ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
00532   ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
00533 
00534   cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
00535 
00536   if (btr_pcur_is_before_first_on_page(cursor)) {
00537 
00538     if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
00539 
00540       return(FALSE);
00541     }
00542 
00543     btr_pcur_move_backward_from_page(cursor, mtr);
00544 
00545     return(TRUE);
00546   }
00547 
00548   btr_pcur_move_to_prev_on_page(cursor);
00549 
00550   return(TRUE);
00551 }
00552 
00553 /**************************************************************/
00560 UNIV_INTERN
00561 void
00562 btr_pcur_open_on_user_rec_func(
00563 /*===========================*/
00564   dict_index_t* index,    
00565   const dtuple_t* tuple,    
00566   ulint   mode,   
00567   ulint   latch_mode, 
00569   btr_pcur_t* cursor,   
00571   const char* file,   
00572   ulint   line,   
00573   mtr_t*    mtr)    
00574 {
00575   btr_pcur_open_func(index, tuple, mode, latch_mode, cursor,
00576          file, line, mtr);
00577 
00578   if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
00579 
00580     if (btr_pcur_is_after_last_on_page(cursor)) {
00581 
00582       btr_pcur_move_to_next_user_rec(cursor, mtr);
00583     }
00584   } else {
00585     ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
00586 
00587     /* Not implemented yet */
00588 
00589     ut_error;
00590   }
00591 }