diff options
author | Karen Langford <karen.langford@oracle.com> | 2011-11-17 00:26:16 +0100 |
---|---|---|
committer | Karen Langford <karen.langford@oracle.com> | 2011-11-17 00:26:16 +0100 |
commit | e1df69f75ac478b0456bc768b61dfd412fa510e9 (patch) | |
tree | 59efaebcf87a955329cd085b04e55e05558d41ee /storage/innobase | |
parent | 8c886b3bc0002ce5c14f9ffc9c0df4d2664b032d (diff) | |
parent | aac03193362f8e68ccbc46743a52e830ce94f44f (diff) | |
download | mariadb-git-e1df69f75ac478b0456bc768b61dfd412fa510e9.tar.gz |
Merge from mysql-5.1.60-release
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/btr/btr0btr.c | 251 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.c | 124 | ||||
-rw-r--r-- | storage/innobase/fsp/fsp0fsp.c | 159 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 10 | ||||
-rw-r--r-- | storage/innobase/include/btr0btr.h | 43 | ||||
-rw-r--r-- | storage/innobase/include/btr0cur.h | 35 | ||||
-rw-r--r-- | storage/innobase/include/buf0buf.h | 19 | ||||
-rw-r--r-- | storage/innobase/include/fsp0fsp.h | 6 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 7 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.ic | 4 | ||||
-rw-r--r-- | storage/innobase/include/page0page.h | 20 | ||||
-rw-r--r-- | storage/innobase/include/page0page.ic | 16 | ||||
-rw-r--r-- | storage/innobase/mtr/mtr0mtr.c | 10 | ||||
-rw-r--r-- | storage/innobase/page/page0page.c | 31 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.c | 71 | ||||
-rw-r--r-- | storage/innobase/row/row0row.c | 38 | ||||
-rw-r--r-- | storage/innobase/row/row0umod.c | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.c | 39 | ||||
-rw-r--r-- | storage/innobase/trx/trx0undo.c | 2 |
19 files changed, 225 insertions, 662 deletions
diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index ad99913cf3b..5079757272a 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -300,30 +300,29 @@ btr_page_alloc_for_ibuf( /****************************************************************** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! */ -static -ulint -btr_page_alloc_low( -/*===============*/ - /* out: allocated page number, - FIL_NULL if out of space */ + +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated page, x-latched; + NULL if out of space */ dict_index_t* index, /* in: index */ ulint hint_page_no, /* in: hint of a good page */ byte file_direction, /* in: direction where a possible page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /* in/out: mini-transaction - in which the page should be - initialized (may be the same - as mtr), or NULL if it should - not be initialized (the page - at hint was previously freed - in mtr) */ + mtr_t* mtr) /* in: mtr */ { fseg_header_t* seg_header; page_t* root; + page_t* new_page; + ulint new_page_no; + + if (index->type & DICT_IBUF) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } root = btr_root_get(index, mtr); @@ -337,61 +336,19 @@ btr_page_alloc_low( reservation for free extents, and thus we know that a page can be allocated: */ - return(fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, - mtr, init_mtr)); -} - -/**************************************************************//** -Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! */ - -page_t* -btr_page_alloc( -/*===========*/ - /* out: new allocated block, x-latched; - NULL if out of space */ - dict_index_t* index, /* in: index */ - ulint hint_page_no, /* in: hint of a good page */ - byte file_direction, /* in: direction where a possible - page split is made */ - ulint level, /* in: level where the page is placed - in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr) /* in/out: mini-transaction - for x-latching and initializing - the page */ -{ - page_t* new_page; - ulint new_page_no; - - if (index->type & DICT_IBUF) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } - - new_page_no = btr_page_alloc_low( - index, hint_page_no, file_direction, level, mtr, init_mtr); - + new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, mtr); if (new_page_no == FIL_NULL) { return(NULL); } new_page = buf_page_get(dict_index_get_space(index), new_page_no, - RW_X_LATCH, init_mtr); + RW_X_LATCH, mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ - if (mtr->freed_clust_leaf) { - mtr_memo_release(mtr, new_page, MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(!mtr_memo_contains(mtr, buf_block_align(new_page), - MTR_MEMO_FREE_CLUST_LEAF)); - } - - ut_ad(btr_freed_leaves_validate(mtr)); return(new_page); } @@ -538,138 +495,8 @@ btr_page_free( level = btr_page_get_level(page, mtr); btr_page_free_low(index, page, level, mtr); - - /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ - ut_ad(mtr_memo_contains(mtr, buf_block_align(page), - MTR_MEMO_PAGE_X_FIX)); - - if (level == 0 && (index->type & DICT_CLUSTERED)) { - /* We may have to call btr_mark_freed_leaves() to - temporarily mark the block nonfree for invoking - btr_store_big_rec_extern_fields() after an - update. Remember that the block was freed. */ - mtr->freed_clust_leaf = TRUE; - mtr_memo_push(mtr, buf_block_align(page), - MTR_MEMO_FREE_CLUST_LEAF); - } - - ut_ad(btr_freed_leaves_validate(mtr)); } -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ - -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /* in/out: clustered index */ - mtr_t* mtr, /* in/out: mini-transaction */ - ibool nonfree)/* in: TRUE=mark nonfree, FALSE=mark freed */ -{ - /* This is loosely based on mtr_memo_release(). */ - - ulint offset; - - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - if (!mtr->freed_clust_leaf) { - return; - } - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(buf_block_get_space(block) - == dict_index_get_space(index)); - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); - - if (nonfree) { - /* Allocate the same page again. */ - ulint page_no; - page_no = btr_page_alloc_low( - index, buf_block_get_page_no(block), - FSP_NO_DIR, 0, mtr, NULL); - ut_a(page_no == buf_block_get_page_no(block)); - } else { - /* Assert that the page is allocated and free it. */ - btr_page_free_low(index, buf_block_get_frame(block), - 0, mtr); - } - } - - ut_ad(btr_freed_leaves_validate(mtr)); -} - -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -See btr_mark_freed_leaves(). */ - -ibool -btr_freed_leaves_validate( -/*======================*/ - /* out: TRUE if valid */ - mtr_t* mtr) /* in: mini-transaction */ -{ - ulint offset; - - ut_ad(mtr->magic_n == MTR_MAGIC_N); - ut_ad(mtr->state == MTR_ACTIVE); - - offset = dyn_array_get_data_size(&mtr->memo); - - while (offset > 0) { - mtr_memo_slot_t* slot; - buf_block_t* block; - - offset -= sizeof *slot; - - slot = dyn_array_get_element(&mtr->memo, offset); - - if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { - continue; - } - - ut_a(mtr->freed_clust_leaf); - /* Because btr_page_alloc() does invoke - mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all - blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the - memo must still be clustered index leaf tree pages. */ - block = slot->object; - ut_a(fil_page_get_type(buf_block_get_frame(block)) - == FIL_PAGE_INDEX); - ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); - } - - return(TRUE); -} -#endif /* UNIV_DEBUG */ - /****************************************************************** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1199,7 +1026,7 @@ btr_root_raise_and_insert( a node pointer to the new page, and then splitting the new page. */ new_page = btr_page_alloc(index, 0, FSP_NO_DIR, - btr_page_get_level(root, mtr), mtr, mtr); + btr_page_get_level(root, mtr), mtr); btr_page_create(new_page, index, mtr); @@ -1820,7 +1647,7 @@ func_start: /* 2. Allocate a new page to the index */ new_page = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr, mtr); + btr_page_get_level(page, mtr), mtr); btr_page_create(new_page, cursor->index, mtr); /* 3. Calculate the first record on the upper half-page, and the @@ -2121,7 +1948,7 @@ btr_node_ptr_delete( ut_a(err == DB_SUCCESS); if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); + btr_cur_compress_if_useful(&cursor, mtr); } } @@ -2129,10 +1956,9 @@ btr_node_ptr_delete( If page is the only on its level, this function moves its records to the father page, thus reducing the tree height. */ static -page_t* +void btr_lift_page_up( /*=============*/ - /* out: father page */ dict_index_t* index, /* in: index tree */ page_t* page, /* in: page which is the only on its level; must not be empty: use @@ -2208,8 +2034,6 @@ btr_lift_page_up( ibuf_reset_free_bits(index, father_page); ut_ad(page_validate(father_page, index)); ut_ad(btr_check_node_ptr(index, father_page, mtr)); - - return(father_page); } /***************************************************************** @@ -2226,13 +2050,11 @@ enough free extents so that the compression will always succeed if done! */ void btr_compress( /*=========*/ - btr_cur_t* cursor, /* in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr) /* in: mtr */ { dict_index_t* index; ulint space; @@ -2247,7 +2069,6 @@ btr_compress( rec_t* node_ptr; ulint data_size; ulint n_recs; - ulint nth_rec = 0; /* remove bogus warning */ ulint max_ins_size; ulint max_ins_size_reorg; ulint comp; @@ -2255,7 +2076,6 @@ btr_compress( page = btr_cur_get_page(cursor); index = btr_cur_get_index(cursor); comp = page_is_comp(page); - ut_a((ibool)!!comp == dict_table_is_comp(index->table)); ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), @@ -2277,10 +2097,6 @@ btr_compress( father_page = buf_frame_align(node_ptr); ut_a(comp == page_is_comp(father_page)); - if (adjust) { - nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); - } - /* Decide the page to which we try to merge and which will inherit the locks */ @@ -2305,8 +2121,9 @@ btr_compress( } else { /* The page is the only one on the level, lift the records to the father */ - merge_page = btr_lift_page_up(index, page, mtr); - goto func_exit; + btr_lift_page_up(index, page, mtr); + + return; } n_recs = page_get_n_recs(page); @@ -2382,10 +2199,6 @@ btr_compress( index, mtr); lock_update_merge_left(merge_page, orig_pred, page); - - if (adjust) { - nth_rec += page_rec_get_n_recs_before(orig_pred); - } } else { orig_succ = page_rec_get_next( page_get_infimum_rec(merge_page)); @@ -2406,12 +2219,6 @@ btr_compress( btr_page_free(index, page, mtr); ut_ad(btr_check_node_ptr(index, merge_page, mtr)); - -func_exit: - if (adjust) { - btr_cur_position(index, page_rec_get_nth(merge_page, nth_rec), - cursor); - } } /***************************************************************** diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 37bb3188785..3c12e28feb6 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1790,9 +1790,7 @@ btr_cur_pessimistic_update( /* out: DB_SUCCESS or error code */ ulint flags, /* in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /* in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /* in: cursor on the record to update */ big_rec_t** big_rec,/* out: big rec vector whose fields have to be stored externally by the caller, or NULL */ upd_t* update, /* in: update vector; this is allowed also @@ -1927,10 +1925,6 @@ btr_cur_pessimistic_update( err = DB_TOO_BIG_RECORD; goto return_after_reservations; } - - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(btr_page_get_level(page, mtr) == 0); - ut_ad(flags & BTR_KEEP_POS_FLAG); } page_cursor = btr_cur_get_page_cur(cursor); @@ -1957,8 +1951,6 @@ btr_cur_pessimistic_update( ut_a(rec || optim_err != DB_UNDERFLOW); if (rec) { - page_cursor->rec = rec; - lock_rec_restore_from_page_infimum(rec, page); rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); @@ -1972,30 +1964,12 @@ btr_cur_pessimistic_update( btr_cur_unmark_extern_fields(rec, mtr, offsets); } - btr_cur_compress_if_useful( - cursor, - big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG), - mtr); + btr_cur_compress_if_useful(cursor, mtr); err = DB_SUCCESS; goto return_after_reservations; } - if (big_rec_vec) { - ut_ad(index->type & DICT_CLUSTERED); - ut_ad(btr_page_get_level(page, mtr) == 0); - ut_ad(flags & BTR_KEEP_POS_FLAG); - - /* btr_page_split_and_insert() in - btr_cur_pessimistic_insert() invokes - mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK). - We must keep the index->lock when we created a - big_rec, so that row_upd_clust_rec() can store the - big_rec in the same mini-transaction. */ - - mtr_x_lock(dict_index_get_lock(index), mtr); - } - if (page_cur_is_before_first(page_cursor)) { /* The record to be updated was positioned as the first user record on its page */ @@ -2016,7 +1990,6 @@ btr_cur_pessimistic_update( ut_a(rec); ut_a(err == DB_SUCCESS); ut_a(dummy_big_rec == NULL); - page_cursor->rec = rec; rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); @@ -2419,6 +2392,30 @@ btr_cur_del_unmark_for_ibuf( /*==================== B-TREE RECORD REMOVE =========================*/ /***************************************************************** +Tries to compress a page of the tree on the leaf level. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +void +btr_cur_compress( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(mtr_memo_contains(mtr, + dict_index_get_lock(btr_cur_get_index(cursor)), + MTR_MEMO_X_LOCK)); + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), + MTR_MEMO_PAGE_X_FIX)); + ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0); + + btr_compress(cursor, mtr); +} + +/***************************************************************** Tries to compress a page of the tree if it seems useful. It is assumed that mtr holds an x-latch on the tree and on the cursor page. To avoid deadlocks, mtr must also own x-latches to brothers of page, if those @@ -2429,12 +2426,10 @@ ibool btr_cur_compress_if_useful( /*=======================*/ /* out: TRUE if compression occurred */ - btr_cur_t* cursor, /* in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr) /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr) /* in: mtr */ { ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(btr_cur_get_index(cursor)), @@ -2444,7 +2439,7 @@ btr_cur_compress_if_useful( if (btr_cur_compress_recommendation(cursor, mtr)) { - btr_compress(cursor, adjust, mtr); + btr_compress(cursor, mtr); return(TRUE); } @@ -2657,7 +2652,7 @@ return_after_reservations: mem_heap_free(heap); if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); + ret = btr_cur_compress_if_useful(cursor, mtr); } if (n_extents > 0) { @@ -3449,11 +3444,6 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ - mtr_t* alloc_mtr, /* in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr containing the latch to rec and to the tree */ @@ -3474,8 +3464,6 @@ btr_store_big_rec_extern_fields( ulint i; mtr_t mtr; - ut_ad(local_mtr); - ut_ad(!alloc_mtr || alloc_mtr == local_mtr); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); @@ -3485,25 +3473,6 @@ btr_store_big_rec_extern_fields( space_id = buf_frame_get_space_id(rec); - if (alloc_mtr) { - /* Because alloc_mtr will be committed after - mtr, it is possible that the tablespace has been - extended when the B-tree record was updated or - inserted, or it will be extended while allocating - pages for big_rec. - - TODO: In mtr (not alloc_mtr), write a redo log record - about extending the tablespace to its current size, - and remember the current size. Whenever the tablespace - grows as pages are allocated, write further redo log - records to mtr. (Currently tablespace extension is not - covered by the redo log. If it were, the record would - only be written to alloc_mtr, which is committed after - mtr.) */ - } else { - alloc_mtr = &mtr; - } - /* We have to create a file segment to the tablespace for each field and put the pointer to the field in rec */ @@ -3530,7 +3499,7 @@ btr_store_big_rec_extern_fields( } page = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, alloc_mtr, &mtr); + FSP_NO_DIR, 0, &mtr); if (page == NULL) { mtr_commit(&mtr); @@ -3584,42 +3553,37 @@ btr_store_big_rec_extern_fields( extern_len -= store_len; - if (alloc_mtr == &mtr) { #ifdef UNIV_SYNC_DEBUG - rec_page = + rec_page = #endif /* UNIV_SYNC_DEBUG */ - buf_page_get( - space_id, - buf_frame_get_page_no(data), - RW_X_LATCH, &mtr); + buf_page_get(space_id, + buf_frame_get_page_no(data), + RW_X_LATCH, &mtr); #ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level( - rec_page, SYNC_NO_ORDER_CHECK); + buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ - } - mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); if (prev_page_no == FIL_NULL) { mlog_write_ulint(data + local_len + BTR_EXTERN_SPACE_ID, space_id, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO, page_no, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, alloc_mtr); + MLOG_4BYTES, &mtr); /* Set the bit denoting that this field in rec is stored externally */ @@ -3627,7 +3591,7 @@ btr_store_big_rec_extern_fields( rec_set_nth_field_extern_bit( rec, index, big_rec_vec->fields[i].field_no, - TRUE, alloc_mtr); + TRUE, &mtr); } prev_page_no = page_no; diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index d5be8fca38f..90e6ad34a9a 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -300,12 +300,8 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr);/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr); /* in/out: mini-transaction */ + /************************************************************************** Reads the file space size stored in the header page. */ @@ -1375,43 +1371,6 @@ fsp_alloc_free_extent( return(descr); } -/**********************************************************************//** -Allocates a single free page from a space. */ -static __attribute__((nonnull)) -void -fsp_alloc_from_free_frag( -/*=====================*/ - fsp_header_t* header, /* in/out: tablespace header */ - xdes_t* descr, /* in/out: extent descriptor */ - ulint bit, /* in: slot to allocate in the extent */ - mtr_t* mtr) /* in/out: mini-transaction */ -{ - ulint frag_n_used; - - ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); - xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } -} - /************************************************************************** Allocates a single free page from a space. The page is marked as used. */ static @@ -1422,22 +1381,19 @@ fsp_alloc_free_page( be allocated */ ulint space, /* in: space id */ ulint hint, /* in: hint of which page would be desirable */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr)/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr) */ + mtr_t* mtr) /* in/out: mini-transaction */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; page_t* page; ulint free; + ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); - ut_ad(init_mtr); header = fsp_get_space_header(space, mtr); @@ -1517,21 +1473,40 @@ fsp_alloc_free_page( } } - fsp_alloc_from_free_frag(header, descr, free, mtr); + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, init_mtr); + buf_page_create(space, page_no, mtr); - page = buf_page_get(space, page_no, RW_X_LATCH, init_mtr); + page = buf_page_get(space, page_no, RW_X_LATCH, mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ /* Prior contents of the page should be ignored */ - fsp_init_file_page(page, init_mtr); + fsp_init_file_page(page, mtr); return(page_no); } @@ -1750,7 +1725,7 @@ fsp_alloc_seg_inode_page( space = buf_frame_get_space_id(space_header); - page_no = fsp_alloc_free_page(space, 0, mtr, mtr); + page_no = fsp_alloc_free_page(space, 0, mtr); if (page_no == FIL_NULL) { @@ -2120,8 +2095,7 @@ fseg_create_general( } if (page == 0) { - page = fseg_alloc_free_page_low(space, - inode, 0, FSP_UP, mtr, mtr); + page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr); if (page == FIL_NULL) { @@ -2365,12 +2339,7 @@ fseg_alloc_free_page_low( inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr)/* in/out: mini-transaction in which the - page should be initialized - (may be the same as mtr), or NULL if it - should not be initialized (the page at hint - was previously freed in mtr) */ + mtr_t* mtr) /* in/out: mini-transaction */ { fsp_header_t* space_header; ulint space_size; @@ -2382,6 +2351,7 @@ fseg_alloc_free_page_low( if could not be allocated */ xdes_t* ret_descr; /* the extent of the allocated page */ page_t* page; + ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2402,8 +2372,6 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ - ut_a(init_mtr); - /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, hint, mtr); } @@ -2415,20 +2383,15 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { -take_hinted_page: + /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; - /* Skip the check for extending the tablespace. If the - page hint were not within the size of the tablespace, - we would have got (descr == NULL) above and reset the hint. */ - goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if (xdes_get_state(descr, mtr) == XDES_FREE - && (!init_mtr - || ((reserved - used < reserved / FSEG_FILLFACTOR) - && used >= FSEG_FRAG_LIMIT))) { + } else if ((xdes_get_state(descr, mtr) == XDES_FREE) + && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && (used >= FSEG_FRAG_LIMIT)) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2446,20 +2409,8 @@ take_hinted_page: /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, hint + FSP_EXTENT_SIZE, mtr); - goto take_hinted_page; - /*-----------------------------------------------------------*/ - } else if (!init_mtr) { - ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); - fsp_alloc_from_free_frag(space_header, descr, - hint % FSP_EXTENT_SIZE, mtr); ret_page = hint; - ret_descr = NULL; - - /* Put the page in the fragment page array of the segment */ - n = fseg_find_free_frag_page_slot(seg_inode, mtr); - ut_a(n != FIL_NULL); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); - goto got_hinted_page; + /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2517,9 +2468,11 @@ take_hinted_page: } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, hint, mtr, init_mtr); + ret_page = fsp_alloc_free_page(space, hint, mtr); ret_descr = NULL; + frag_page_allocated = TRUE; + if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2529,10 +2482,6 @@ take_hinted_page: fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } - - /* fsp_alloc_free_page() invoked fsp_init_file_page() - already. */ - return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2579,31 +2528,22 @@ take_hinted_page: } } -got_hinted_page: - { + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ - mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - page = buf_page_create(space, ret_page, block_mtr); + page = buf_page_create(space, ret_page, mtr); - ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, - block_mtr)); + ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr)); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ - if (init_mtr) { - /* The prior contents of the page should be ignored */ - fsp_init_file_page(page, init_mtr); - } - } + /* The prior contents of the page should be ignored */ + fsp_init_file_page(page, mtr); - /* ret_descr == NULL if the block was allocated from free_frag - (XDES_FREE_FRAG) */ - if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2640,11 +2580,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /* in/out: mini-transaction handle */ - mtr_t* init_mtr)/* in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr) /* in/out: mini-transaction */ { fseg_inode_t* inode; ulint space; @@ -2682,8 +2618,7 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode), - inode, hint, direction, - mtr, init_mtr); + inode, hint, direction, mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2711,7 +2646,7 @@ fseg_alloc_free_page( mtr_t* mtr) /* in: mtr handle */ { return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr, mtr)); + FALSE, mtr)); } /************************************************************************** diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7f82959dffd..6709f790994 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4263,14 +4263,16 @@ calc_row_difference( /* The field has changed */ ufield = uvect->fields + n_changed; + UNIV_MEM_INVALID(ufield, sizeof *ufield); /* Let us use a dummy dfield to make the conversion from the MySQL column format to the InnoDB format */ - dict_col_copy_type_noninline(prebuilt->table->cols + i, - &dfield.type); - if (n_len != UNIV_SQL_NULL) { + dict_col_copy_type_noninline( + prebuilt->table->cols + i, + &dfield.type); + buf = row_mysql_store_col_in_innobase_format( &dfield, (byte*)buf, @@ -4281,11 +4283,13 @@ calc_row_difference( prebuilt->table)); ufield->new_val.data = dfield.data; ufield->new_val.len = dfield.len; + ufield->new_val.type = dfield.type; } else { ufield->new_val.data = NULL; ufield->new_val.len = UNIV_SQL_NULL; } + ufield->extern_storage = FALSE; ufield->exp = NULL; ufield->field_no = dict_col_get_clust_pos_noninline( &prebuilt->table->cols[i], clust_index); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 3988019589d..1573de7e818 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -312,13 +312,11 @@ enough free extents so that the compression will always succeed if done! */ void btr_compress( /*=========*/ - btr_cur_t* cursor, /* in/out: cursor on the page to merge - or lift; the page must not be empty: - when deleting records, use btr_discard_page() - if the page would become empty */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr); /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + the page must not be empty: in record delete + use btr_discard_page if the page would become + empty */ + mtr_t* mtr); /* in: mtr */ /***************************************************************** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot @@ -379,11 +377,7 @@ btr_page_alloc( page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr, /* in/out: mini-transaction - for the allocation */ - mtr_t* init_mtr); /* in/out: mini-transaction - for x-latching and initializing - the page */ + mtr_t* mtr); /* in: mtr */ /****************************************************************** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -406,31 +400,6 @@ btr_page_free_low( page_t* page, /* in: page to be freed, x-latched */ ulint level, /* in: page level */ mtr_t* mtr); /* in: mtr */ -/**************************************************************//** -Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. -For invoking btr_store_big_rec_extern_fields() after an update, -we must temporarily mark freed clustered index pages allocated, so -that off-page columns will not be allocated from them. Between the -btr_store_big_rec_extern_fields() and mtr_commit() we have to -mark the pages free again, so that no pages will be leaked. */ - -void -btr_mark_freed_leaves( -/*==================*/ - dict_index_t* index, /* in/out: clustered index */ - mtr_t* mtr, /* in/out: mini-transaction */ - ibool nonfree);/* in: TRUE=mark nonfree, FALSE=mark freed */ -#ifdef UNIV_DEBUG -/**************************************************************//** -Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. -See btr_mark_freed_leaves(). */ - -ibool -btr_freed_leaves_validate( -/*======================*/ - /* out: TRUE if valid */ - mtr_t* mtr); /* in: mini-transaction */ -#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /***************************************************************** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index c2bf84ef9cb..20235c55f22 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -23,9 +23,6 @@ Created 10/16/1994 Heikki Tuuri #define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */ #define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the update vector or inserted entry */ -#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update() - must keep cursor position when - moving columns to big_rec */ #define BTR_CUR_ADAPT #define BTR_CUR_HASH_ADAPT @@ -240,9 +237,7 @@ btr_cur_pessimistic_update( /* out: DB_SUCCESS or error code */ ulint flags, /* in: undo logging, locking, and rollback flags */ - btr_cur_t* cursor, /* in/out: cursor on the record to update; - cursor may become invalid if *big_rec == NULL - || !(flags & BTR_KEEP_POS_FLAG) */ + btr_cur_t* cursor, /* in: cursor on the record to update */ big_rec_t** big_rec,/* out: big rec vector whose fields have to be stored externally by the caller, or NULL */ upd_t* update, /* in: update vector; this is allowed also @@ -291,6 +286,19 @@ btr_cur_del_unmark_for_ibuf( rec_t* rec, /* in: record to delete unmark */ mtr_t* mtr); /* in: mtr */ /***************************************************************** +Tries to compress a page of the tree on the leaf level. It is assumed +that mtr holds an x-latch on the tree and on the cursor page. To avoid +deadlocks, mtr must also own x-latches to brothers of page, if those +brothers exist. NOTE: it is assumed that the caller has reserved enough +free extents so that the compression will always succeed if done! */ + +void +btr_cur_compress( +/*=============*/ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid */ + mtr_t* mtr); /* in: mtr */ +/***************************************************************** Tries to compress a page of the tree if it seems useful. It is assumed that mtr holds an x-latch on the tree and on the cursor page. To avoid deadlocks, mtr must also own x-latches to brothers of page, if those @@ -301,12 +309,10 @@ ibool btr_cur_compress_if_useful( /*=======================*/ /* out: TRUE if compression occurred */ - btr_cur_t* cursor, /* in/out: cursor on the page to compress; - cursor does not stay valid if !adjust and - compression occurs */ - ibool adjust, /* in: TRUE if should adjust the - cursor position even if compression occurs */ - mtr_t* mtr); /* in/out: mini-transaction */ + btr_cur_t* cursor, /* in: cursor on the page to compress; + cursor does not stay valid if compression + occurs */ + mtr_t* mtr); /* in: mtr */ /*********************************************************** Removes the record on which the tree cursor is positioned. It is assumed that the mtr has an x-latch on the page where the cursor is positioned, @@ -462,11 +468,6 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ - mtr_t* alloc_mtr, /* in/out: in an insert, NULL; - in an update, local_mtr for - allocating BLOB pages and - updating BLOB pointers; alloc_mtr - must not have freed any leaf pages */ mtr_t* local_mtr); /* in: mtr containing the latch to rec and to the tree */ /*********************************************************************** diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 50e0aa9376c..0f7553a7043 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -654,25 +654,6 @@ buf_page_address_fold( /* out: the folded value */ ulint space, /* in: space id */ ulint offset);/* in: offset of the page within space */ -#ifdef UNIV_SYNC_DEBUG -/*********************************************************************** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc_debug( -/*========================*/ - buf_block_t* block, /* in: block to bufferfix */ - const char* file __attribute__ ((unused)), /* in: file name */ - ulint line __attribute__ ((unused))); /* in: line */ -#else /* UNIV_SYNC_DEBUG */ -/*********************************************************************** -Increments the bufferfix count. */ -UNIV_INLINE -void -buf_block_buf_fix_inc( -/*==================*/ - buf_block_t* block); /* in: block to bufferfix */ -#endif /* UNIV_SYNC_DEBUG */ /********************************************************************** Returns the control block of a file page, NULL if not found. */ UNIV_INLINE diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 4c58d6075e6..b7322944189 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -179,11 +179,7 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr, /* in/out: mini-transaction */ - mtr_t* init_mtr);/* in/out: mtr or another mini-transaction - in which the page should be initialized, - or NULL if this is a "fake allocation" of - a page that was previously freed in mtr */ + mtr_t* mtr); /* in/out: mini-transaction */ /************************************************************************** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 58983063361..2b41fa0059a 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -36,8 +36,6 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 -/* The mini-transaction freed a clustered index leaf page. */ -#define MTR_MEMO_FREE_CLUST_LEAF 57 /* Log item types: we have made them to be of the type 'byte' for the compiler to warn if val and type parameters are switched @@ -317,12 +315,9 @@ struct mtr_struct{ ulint state; /* MTR_ACTIVE, MTR_COMMITTING, MTR_COMMITTED */ dyn_array_t memo; /* memo stack for locks etc. */ dyn_array_t log; /* mini-transaction log */ - unsigned modifications:1; + ibool modifications; /* TRUE if the mtr made modifications to buffer pool pages */ - unsigned freed_clust_leaf:1; - /* TRUE if MTR_MEMO_FREE_CLUST_LEAF - was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 6b4cacf0766..81eec3bfc92 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -26,7 +26,6 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; - mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; #ifdef UNIV_DEBUG @@ -51,8 +50,7 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); - ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); + ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 24698557e77..273007c2778 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -234,22 +234,11 @@ page_get_supremum_rec( /*==================*/ /* out: the last record in record list */ page_t* page); /* in: page which must have record(s) */ -/************************************************************//** -Returns the nth record of the record list. -This is the inverse function of page_rec_get_n_recs_before(). */ +/**************************************************************** +Returns the middle record of record list. If there are an even number +of records in the list, returns the first record of upper half-list. */ rec_t* -page_rec_get_nth( -/*=============*/ - /* out: nth record */ - page_t* page, /* in: page */ - ulint nth); /* in: nth record */ -/***************************************************************** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. */ -UNIV_INLINE -rec_t* page_get_middle_rec( /*================*/ /* out: middle record */ @@ -291,8 +280,7 @@ page_get_n_recs( page_t* page); /* in: index page */ /******************************************************************* Returns the number of records before the given record in chain. -The number includes infimum and supremum records. -This is the inverse function of page_rec_get_nth(). */ +The number includes infimum and supremum records. */ ulint page_rec_get_n_recs_before( diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index a019aa28515..d9e67f3eeeb 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -341,22 +341,6 @@ page_rec_is_infimum( } /***************************************************************** -Returns the middle record of the records on the page. If there is an -even number of records in the list, returns the first record of the -upper half-list. */ -UNIV_INLINE -rec_t* -page_get_middle_rec( -/*================*/ - /* out: middle record */ - page_t* page) /* in: page */ -{ - ulint middle = (page_get_n_recs(page) + 2) / 2; - - return(page_rec_get_nth(page, middle)); -} - -/***************************************************************** Compares a data tuple to a physical record. Differs from the function cmp_dtuple_rec_with_match in the way that the record must reside on an index page, and also page infimum and supremum records can be given in diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 33b71f0766c..728c37ce564 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -53,13 +53,17 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); - } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY - || type == MTR_MEMO_FREE_CLUST_LEAF); +#ifdef UNIV_DEBUG + } else if (type == MTR_MEMO_X_LOCK) { + rw_lock_x_unlock((rw_lock_t*)object); + } else { + ut_ad(type == MTR_MEMO_MODIFY); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); +#else } else { rw_lock_x_unlock((rw_lock_t*)object); +#endif } } diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 6a89df7de22..543cf9e34eb 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -1194,42 +1194,49 @@ page_dir_balance_slot( } /**************************************************************** -Returns the nth record of the record list. */ +Returns the middle record of the record list. If there are an even number +of records in the list, returns the first record of the upper half-list. */ rec_t* -page_rec_get_nth( -/*=============*/ - /* out: nth record */ - page_t* page, /* in: page */ - ulint nth) /* in: nth record */ +page_get_middle_rec( +/*================*/ + /* out: middle record */ + page_t* page) /* in: page */ { page_dir_slot_t* slot; + ulint middle; ulint i; ulint n_owned; + ulint count; rec_t* rec; - ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1)); + /* This many records we must leave behind */ + middle = (page_get_n_recs(page) + 2) / 2; + + count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); - if (n_owned > nth) { + if (count + n_owned > middle) { break; } else { - nth -= n_owned; + count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); rec = page_dir_slot_get_rec(slot); + rec = page_rec_get_next(rec); + + /* There are now count records behind rec */ - do { + for (i = 0; i < middle - count; i++) { rec = page_rec_get_next(rec); - ut_ad(rec); - } while (nth--); + } return(rec); } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index c18b6995066..db134ca7a41 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -259,7 +259,6 @@ row_ins_sec_index_entry_by_modify( err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &dummy_big_rec, update, 0, thr, mtr); - ut_a(!dummy_big_rec); } func_exit: mem_heap_free(heap); @@ -330,9 +329,8 @@ row_ins_clust_index_entry_by_modify( goto func_exit; } - err = btr_cur_pessimistic_update( - BTR_KEEP_POS_FLAG, cursor, big_rec, update, - 0, thr, mtr); + err = btr_cur_pessimistic_update(0, cursor, big_rec, update, + 0, thr, mtr); } func_exit: mem_heap_free(heap); @@ -425,11 +423,9 @@ row_ins_cascade_calc_update_vec( dict_table_t* table = foreign->foreign_table; dict_index_t* index = foreign->foreign_index; upd_t* update; - upd_field_t* ufield; dict_table_t* parent_table; dict_index_t* parent_index; upd_t* parent_update; - upd_field_t* parent_ufield; ulint n_fields_updated; ulint parent_field_no; ulint i; @@ -465,12 +461,14 @@ row_ins_cascade_calc_update_vec( dict_index_get_nth_col_no(parent_index, i)); for (j = 0; j < parent_update->n_fields; j++) { - parent_ufield = parent_update->fields + j; + const upd_field_t* parent_ufield + = &parent_update->fields[j]; if (parent_ufield->field_no == parent_field_no) { ulint min_size; const dict_col_t* col; + upd_field_t* ufield; col = dict_index_get_nth_col(index, i); @@ -975,10 +973,9 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } - if ((node->is_delete - && (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)) - || (!node->is_delete - && (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) { + if (node->is_delete + ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) + : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { /* Build the appropriate update vector which sets foreign->n_fields first fields in rec to SQL NULL */ @@ -987,6 +984,8 @@ row_ins_foreign_check_on_constraint( update->info_bits = 0; update->n_fields = foreign->n_fields; + UNIV_MEM_INVALID(update->fields, + update->n_fields * sizeof *update->fields); for (i = 0; i < foreign->n_fields; i++) { (update->fields + i)->field_no @@ -2085,50 +2084,6 @@ row_ins_index_entry_low( err = row_ins_clust_index_entry_by_modify( mode, &cursor, &big_rec, entry, ext_vec, n_ext_vec, thr, &mtr); - - if (big_rec) { - ut_a(err == DB_SUCCESS); - /* Write out the externally stored - columns, but allocate the pages and - write the pointers using the - mini-transaction of the record update. - If any pages were freed in the update, - temporarily mark them allocated so - that off-page columns will not - overwrite them. We must do this, - because we will write the redo log for - the BLOB writes before writing the - redo log for the record update. Thus, - redo log application at crash recovery - will see BLOBs being written to free pages. */ - - btr_mark_freed_leaves(index, &mtr, TRUE); - - rec = btr_cur_get_rec(&cursor); - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, - &heap); - - err = btr_store_big_rec_extern_fields( - index, rec, offsets, big_rec, - &mtr, &mtr); - /* If writing big_rec fails (for - example, because of DB_OUT_OF_FILE_SPACE), - the record will be corrupted. Even if - we did not update any externally - stored columns, our update could cause - the record to grow so that a - non-updated column was selected for - external storage. This non-update - would not have been written to the - undo log, and thus the record cannot - be rolled back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again - in order to avoid a leak. */ - btr_mark_freed_leaves(index, &mtr, FALSE); - goto stored_big_rec; - } } else { err = row_ins_sec_index_entry_by_modify( mode, &cursor, entry, thr, &mtr); @@ -2165,6 +2120,7 @@ function_exit: mtr_commit(&mtr); if (big_rec) { + rec_t* rec; mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2174,9 +2130,8 @@ function_exit: ULINT_UNDEFINED, &heap); err = btr_store_big_rec_extern_fields(index, rec, - offsets, big_rec, - NULL, &mtr); -stored_big_rec: + offsets, big_rec, &mtr); + if (modify) { dtuple_big_rec_free(big_rec); } else { diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index ccb3c1f7781..171039e34ac 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -212,27 +212,23 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - if (rec_offs_any_null_extern(rec, offsets)) { - /* This condition can occur during crash recovery - before trx_rollback_or_clean_all_without_sess() has - completed execution. - - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. - - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it is active. (In this version of InnoDB, we - cannot assert that it was recovered, because there is no - trx->is_recovered field.) */ - - ut_a(trx_assert_active( - row_get_rec_trx_id(rec, index, offsets))); - ut_a(trx_undo_roll_ptr_is_insert( - row_get_rec_roll_ptr(rec, index, offsets))); - } + /* This condition can occur during crash recovery before + trx_rollback_or_clean_all_without_sess() has completed + execution. + + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. + + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it is active. (In this version of InnoDB, we + cannot assert that it was recovered, because there is no + trx->is_recovered field.) */ + + ut_a(!rec_offs_any_null_extern(rec, offsets) + || trx_assert_active(row_get_rec_trx_id(rec, index, offsets))); #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 0b00aa2411a..a3333fcc536 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -119,7 +119,6 @@ row_undo_mod_clust_low( | BTR_KEEP_SYS_FLAG, btr_cur, &dummy_big_rec, node->update, node->cmpl_info, thr, mtr); - ut_ad(!dummy_big_rec); } return(err); @@ -472,7 +471,6 @@ row_undo_mod_del_unmark_sec_and_undo_update( BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG, btr_cur, &dummy_big_rec, update, 0, thr, &mtr); - ut_ad(!dummy_big_rec); } mem_heap_free(heap); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 58739edfd98..0790cfe02e2 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1580,51 +1580,32 @@ row_upd_clust_rec( ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); - err = btr_cur_pessimistic_update( - BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, - &big_rec, node->update, node->cmpl_info, thr, mtr); + err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur, + &big_rec, node->update, + node->cmpl_info, thr, mtr); + mtr_commit(mtr); - if (big_rec) { + if (err == DB_SUCCESS && big_rec) { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; *offsets_ = (sizeof offsets_) / sizeof *offsets_; - ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns, but - allocate the pages and write the pointers using the - mini-transaction of the record update. If any pages - were freed in the update, temporarily mark them - allocated so that off-page columns will not overwrite - them. We must do this, because we write the redo log - for the BLOB writes before writing the redo log for - the record update. */ - - btr_mark_freed_leaves(index, mtr, TRUE); + mtr_start(mtr); + + ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr, mtr); + big_rec, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - /* If writing big_rec fails (for example, because of - DB_OUT_OF_FILE_SPACE), the record will be corrupted. - Even if we did not update any externally stored - columns, our update could cause the record to grow so - that a non-updated column was selected for external - storage. This non-update would not have been written - to the undo log, and thus the record cannot be rolled - back. */ - ut_a(err == DB_SUCCESS); - /* Free the pages again in order to avoid a leak. */ - btr_mark_freed_leaves(index, mtr, FALSE); + mtr_commit(mtr); } - mtr_commit(mtr); - if (big_rec) { dtuple_big_rec_free(big_rec); } diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index ce09862f317..329565943c8 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -864,7 +864,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr, mtr); + TRUE, mtr); fil_space_release_free_extents(undo->space, n_reserved); |