From 46ccc6a652116a20eac9511d06f8ff79d6458d42 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 6 Nov 2008 12:30:39 +0000 Subject: [PATCH] branches/innodb+: Revert r2964 and r2963. The heuristics for disabling delete buffering is not fundamentally flawed. It merely failed because of other bugs. --- ibuf/ibuf0ibuf.c | 144 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 131 insertions(+), 13 deletions(-) diff --git a/ibuf/ibuf0ibuf.c b/ibuf/ibuf0ibuf.c index 3e3aa0749e9..76477db30fe 100644 --- a/ibuf/ibuf0ibuf.c +++ b/ibuf/ibuf0ibuf.c @@ -2526,6 +2526,114 @@ ibuf_contract_after_insert( } } +/************************************************************************* +Determine if an insert buffer record has been encountered already. */ +static +ibool +ibuf_get_volume_buffered_hash( +/*==========================*/ + /* out: TRUE if a new record, + FALSE if possible duplicate */ + const rec_t* rec, /* in: ibuf record in post-4.1 format */ + byte* hash, /* in/out: hash array */ + ulint size) /* in: size of hash array, in bytes */ +{ + ulint len; + ulint fold; + const byte* types; + ulint types_len; + ulint bitmask; + + types = rec_get_nth_field_old(rec, 3, &types_len); + len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4, + FALSE); + fold = ut_fold_binary(types + types_len, len); + + hash += (fold / 8) % size; + bitmask = 1 << (fold % 8); + + if (*hash & bitmask) { + + return(FALSE); + } + + /* We have not seen this record yet. Insert it. */ + *hash |= bitmask; + + return(TRUE); +} + +/************************************************************************* +Update the estimate of the number of records on a page. */ +static +void +ibuf_get_volume_buffered_count( +/*===========================*/ + const rec_t* rec, /* in: insert buffer record */ + byte* hash, /* in/out: hash array */ + ulint size, /* in: size of hash array, in bytes */ + ulint* n_recs) /* in/out: estimated number of records + on the page that rec points to */ +{ + ulint len; + const byte* field; + ibuf_op_t ibuf_op; + + ut_ad(ibuf_inside()); + ut_ad(rec_get_n_fields_old(rec) > 2); + + field = rec_get_nth_field_old(rec, 1, &len); + + if (UNIV_UNLIKELY(len > 1)) { + /* This is a < 4.1.x format record. Ignore it in the + count, because deletes cannot be buffered if there are + old-style records for the page. */ + + return; + } + + field = rec_get_nth_field_old(rec, 3, &len); + + switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, + IBUF_REC_INFO_SIZE)) { + default: + ut_error; + case 0: + case 1: + /* This record does not include an operation counter. + Ignore it in the count, because deletes cannot be + buffered if there are old-style records for the page. */ + return; + + case IBUF_REC_INFO_SIZE: + ibuf_op = (ibuf_op_t) field[IBUF_REC_OFFSET_TYPE]; + break; + } + + switch (ibuf_op) { + case IBUF_OP_INSERT: + /* Inserts can be done by + btr_cur_set_deleted_flag_for_ibuf(). Because + delete-mark and insert operations can be pointing to + the same records, we must not count duplicates. */ + case IBUF_OP_DELETE_MARK: + /* There must be a record to delete-mark. + See if this record has been already buffered. */ + if (ibuf_get_volume_buffered_hash(rec, hash, size)) { + (*n_recs)++; + } + break; + case IBUF_OP_DELETE: + /* A record will be removed from the page. */ + if (*n_recs > 0) { + (*n_recs)--; + } + break; + default: + ut_error; + } +} + /************************************************************************* Gets an upper limit for the combined size of inserts buffered for a given page. */ @@ -2545,6 +2653,8 @@ ibuf_get_volume_buffered( or BTR_MODIFY_TREE */ ulint space, /* in: space id */ ulint page_no,/* in: page number of an index page */ + ulint* n_recs, /* out: minimum number of records on the page + after the buffered changes have been applied */ mtr_t* mtr) /* in: mtr */ { ulint volume; @@ -2554,6 +2664,7 @@ ibuf_get_volume_buffered( page_t* prev_page; ulint next_page_no; page_t* next_page; + byte hash_bitmap[128]; /* bitmap of buffered records */ ut_a(trx_sys_multiple_tablespace_format); @@ -2564,6 +2675,7 @@ ibuf_get_volume_buffered( pcur */ volume = 0; + *n_recs = 0; rec = btr_pcur_get_rec(pcur); page = page_align(rec); @@ -2640,6 +2752,8 @@ ibuf_get_volume_buffered( } count_later: + memset(hash_bitmap, 0, sizeof hash_bitmap); + rec = btr_pcur_get_rec(pcur); if (!page_rec_is_supremum(rec)) { @@ -2660,6 +2774,9 @@ count_later: volume += ibuf_rec_get_volume(rec); + ibuf_get_volume_buffered_count( + rec, hash_bitmap, sizeof hash_bitmap, n_recs); + rec = page_rec_get_next(rec); } @@ -2707,6 +2824,9 @@ count_later: volume += ibuf_rec_get_volume(rec); + ibuf_get_volume_buffered_count( + rec, hash_bitmap, sizeof hash_bitmap, n_recs); + rec = page_rec_get_next(rec); } } @@ -2989,6 +3109,7 @@ ibuf_insert_low( dtuple_t* ibuf_entry; mem_heap_t* heap; ulint buffered; + ulint min_n_recs; rec_t* ins_rec; ibool old_bit_value; page_t* bitmap_page; @@ -3093,7 +3214,16 @@ ibuf_insert_low( /* Find out the volume of already buffered inserts for the same index page */ - buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr); + buffered = ibuf_get_volume_buffered(&pcur, space, page_no, + &min_n_recs, &mtr); + + if (op == IBUF_OP_DELETE && min_n_recs == 0) { + /* The page could become empty after the record is + deleted. Refuse to buffer the operation. */ + err = DB_STRONG_FAIL; + + goto function_exit; + } #ifdef UNIV_IBUF_COUNT_DEBUG ut_a((buffered == 0) || ibuf_count_get(space, page_no)); @@ -3515,17 +3645,6 @@ ibuf_delete( offsets = rec_get_offsets( rec, index, offsets, ULINT_UNDEFINED, &heap); - if (UNIV_UNLIKELY(page_get_n_recs(page) == 1)) { - /* Refuse to delete the last record. */ - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: refusing a buffered delete" - " that would empty space %lu page %lu\n", - (ulong) buf_block_get_space(block), - (ulong) buf_block_get_page_no(block)); - rec_print_new(stderr, rec, offsets); - goto func_exit; - } - lock_update_delete(block, rec); if (!page_zip) { @@ -3547,7 +3666,6 @@ ibuf_delete( ibuf_update_free_bits_low(block, max_ins_size, mtr); } -func_exit: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); }