diff options
author | Guilhem Bichot <guilhem@mysql.com> | 2009-08-04 13:25:19 +0200 |
---|---|---|
committer | Guilhem Bichot <guilhem@mysql.com> | 2009-08-04 13:25:19 +0200 |
commit | b57e4dbd88671df86e2cf39aff5178976d710b64 (patch) | |
tree | 32be2bfec3ca062c65566c60ecf59b673d1f97e9 /storage/innobase/ibuf | |
parent | 1a0c2153a036296785dcdfa7b5f4974515616e11 (diff) | |
parent | 94efc1c6b084ed531b513e70fb66e7b7a1186b56 (diff) | |
download | mariadb-git-b57e4dbd88671df86e2cf39aff5178976d710b64.tar.gz |
Creation of mysql-trunk = {summit + "Innodb plugin replacing the builtin"}:
bzr branch mysql-5.1-performance-version mysql-trunk # Summit
cd mysql-trunk
bzr merge mysql-5.1-innodb_plugin # which is 5.1 + Innodb plugin
bzr rm innobase # remove the builtin
Next step: build, test fixes.
Diffstat (limited to 'storage/innobase/ibuf')
-rw-r--r-- | storage/innobase/ibuf/ibuf0ibuf.c | 3580 |
1 files changed, 0 insertions, 3580 deletions
diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c deleted file mode 100644 index d54a3378993..00000000000 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ /dev/null @@ -1,3580 +0,0 @@ -/****************************************************** -Insert buffer - -(c) 1997 Innobase Oy - -Created 7/19/1997 Heikki Tuuri -*******************************************************/ - -#include "ibuf0ibuf.h" - -#ifdef UNIV_NONINL -#include "ibuf0ibuf.ic" -#endif - -#include "buf0buf.h" -#include "buf0rea.h" -#include "fsp0fsp.h" -#include "trx0sys.h" -#include "fil0fil.h" -#include "thr0loc.h" -#include "rem0rec.h" -#include "btr0cur.h" -#include "btr0pcur.h" -#include "btr0btr.h" -#include "sync0sync.h" -#include "dict0boot.h" -#include "fut0lst.h" -#include "lock0lock.h" -#include "log0recv.h" -#include "que0que.h" - -/* STRUCTURE OF AN INSERT BUFFER RECORD - -In versions < 4.1.x: - -1. The first field is the page number. -2. The second field is an array which stores type info for each subsequent - field. We store the information which affects the ordering of records, and - also the physical storage size of an SQL NULL value. E.g., for CHAR(10) it - is 10 bytes. -3. Next we have the fields of the actual index record. - -In versions >= 4.1.x: - -Note that contary to what we planned in the 1990's, there will only be one -insert buffer tree, and that is in the system tablespace of InnoDB. - -1. The first field is the space id. -2. The second field is a one-byte marker (0) which differentiates records from - the < 4.1.x storage format. -3. The third field is the page number. -4. The fourth field contains the type info, where we have also added 2 bytes to - store the charset. In the compressed table format of 5.0.x we must add more - information here so that we can build a dummy 'index' struct which 5.0.x - can use in the binary search on the index page in the ibuf merge phase. -5. The rest of the fields contain the fields of the actual index record. - -In versions >= 5.0.3: - -The first byte of the fourth field is an additional marker (0) if the record -is in the compact format. The presence of this marker can be detected by -looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE. - -The high-order bit of the character set field in the type info is the -"nullable" flag for the field. */ - - -/* PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM - -If an OS thread performs any operation that brings in disk pages from -non-system tablespaces into the buffer pool, or creates such a page there, -then the operation may have as a side effect an insert buffer index tree -compression. Thus, the tree latch of the insert buffer tree may be acquired -in the x-mode, and also the file space latch of the system tablespace may -be acquired in the x-mode. - -Also, an insert to an index in a non-system tablespace can have the same -effect. How do we know this cannot lead to a deadlock of OS threads? There -is a problem with the i\o-handler threads: they break the latching order -because they own x-latches to pages which are on a lower level than the -insert buffer tree latch, its page latches, and the tablespace latch an -insert buffer operation can reserve. - -The solution is the following: Let all the tree and page latches connected -with the insert buffer be later in the latching order than the fsp latch and -fsp page latches. - -Insert buffer pages must be such that the insert buffer is never invoked -when these pages are accessed as this would result in a recursion violating -the latching order. We let a special i/o-handler thread take care of i/o to -the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap -pages and the first inode page, which contains the inode of the ibuf tree: let -us call all these ibuf pages. To prevent deadlocks, we do not let a read-ahead -access both non-ibuf and ibuf pages. - -Then an i/o-handler for the insert buffer never needs to access recursively the -insert buffer tree and thus obeys the latching order. On the other hand, other -i/o-handlers for other tablespaces may require access to the insert buffer, -but because all kinds of latches they need to access there are later in the -latching order, no violation of the latching order occurs in this case, -either. - -A problem is how to grow and contract an insert buffer tree. As it is later -in the latching order than the fsp management, we have to reserve the fsp -latch first, before adding or removing pages from the insert buffer tree. -We let the insert buffer tree have its own file space management: a free -list of pages linked to the tree root. To prevent recursive using of the -insert buffer when adding pages to the tree, we must first load these pages -to memory, obtaining a latch on them, and only after that add them to the -free list of the insert buffer tree. More difficult is removing of pages -from the free list. If there is an excess of pages in the free list of the -ibuf tree, they might be needed if some thread reserves the fsp latch, -intending to allocate more file space. So we do the following: if a thread -reserves the fsp latch, we check the writer count field of the latch. If -this field has value 1, it means that the thread did not own the latch -before entering the fsp system, and the mtr of the thread contains no -modifications to the fsp pages. Now we are free to reserve the ibuf latch, -and check if there is an excess of pages in the free list. We can then, in a -separate mini-transaction, take them out of the free list and free them to -the fsp system. - -To avoid deadlocks in the ibuf system, we divide file pages into three levels: - -(1) non-ibuf pages, -(2) ibuf tree pages and the pages in the ibuf tree free list, and -(3) ibuf bitmap pages. - -No OS thread is allowed to access higher level pages if it has latches to -lower level pages; even if the thread owns a B-tree latch it must not access -the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead -is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle -exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively -level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e., -it uses synchronous aio, it can access any pages, as long as it obeys the -access order rules. */ - -/* Buffer pool size per the maximum insert buffer size */ -#define IBUF_POOL_SIZE_PER_MAX_SIZE 2 - -/* The insert buffer control structure */ -ibuf_t* ibuf = NULL; - -static ulint ibuf_rnd = 986058871; - -ulint ibuf_flush_count = 0; - -#ifdef UNIV_IBUF_DEBUG -/* Dimensions for the ibuf_count array */ -#define IBUF_COUNT_N_SPACES 500 -#define IBUF_COUNT_N_PAGES 2000 - -/* Buffered entry counts for file pages, used in debugging */ -static ulint ibuf_counts[IBUF_COUNT_N_SPACES][IBUF_COUNT_N_PAGES]; - -/********************************************************************** -Checks that the indexes to ibuf_counts[][] are within limits. */ -UNIV_INLINE -void -ibuf_count_check( -/*=============*/ - ulint space_id, /* in: space identifier */ - ulint page_no) /* in: page number */ -{ - if (space_id < IBUF_COUNT_N_SPACES && page_no < IBUF_COUNT_N_PAGES) { - return; - } - - fprintf(stderr, - "InnoDB: UNIV_IBUF_DEBUG limits space_id and page_no\n" - "InnoDB: and breaks crash recovery.\n" - "InnoDB: space_id=%lu, should be 0<=space_id<%lu\n" - "InnoDB: page_no=%lu, should be 0<=page_no<%lu\n", - (ulint) space_id, (ulint) IBUF_COUNT_N_SPACES, - (ulint) page_no, (ulint) IBUF_COUNT_N_PAGES); - ut_error; -} -#endif - -/* The start address for an insert buffer bitmap page bitmap */ -#define IBUF_BITMAP PAGE_DATA - -/* Offsets in bits for the bits describing a single page in the bitmap */ -#define IBUF_BITMAP_FREE 0 -#define IBUF_BITMAP_BUFFERED 2 -#define IBUF_BITMAP_IBUF 3 /* TRUE if page is a part of the ibuf - tree, excluding the root page, or is - in the free list of the ibuf */ - -/* Number of bits describing a single page */ -#define IBUF_BITS_PER_PAGE 4 -#if IBUF_BITS_PER_PAGE % 2 -# error "IBUF_BITS_PER_PAGE must be an even number!" -#endif - -/* The mutex used to block pessimistic inserts to ibuf trees */ -static mutex_t ibuf_pessimistic_insert_mutex; - -/* The mutex protecting the insert buffer structs */ -static mutex_t ibuf_mutex; - -/* The mutex protecting the insert buffer bitmaps */ -static mutex_t ibuf_bitmap_mutex; - -/* The area in pages from which contract looks for page numbers for merge */ -#define IBUF_MERGE_AREA 8 - -/* Inside the merge area, pages which have at most 1 per this number less -buffered entries compared to maximum volume that can buffered for a single -page are merged along with the page whose buffer became full */ -#define IBUF_MERGE_THRESHOLD 4 - -/* In ibuf_contract at most this number of pages is read to memory in one -batch, in order to merge the entries for them in the insert buffer */ -#define IBUF_MAX_N_PAGES_MERGED IBUF_MERGE_AREA - -/* If the combined size of the ibuf trees exceeds ibuf->max_size by this -many pages, we start to contract it in connection to inserts there, using -non-synchronous contract */ -#define IBUF_CONTRACT_ON_INSERT_NON_SYNC 0 - -/* Same as above, but use synchronous contract */ -#define IBUF_CONTRACT_ON_INSERT_SYNC 5 - -/* Same as above, but no insert is done, only contract is called */ -#define IBUF_CONTRACT_DO_NOT_INSERT 10 - -/* TODO: how to cope with drop table if there are records in the insert -buffer for the indexes of the table? Is there actually any problem, -because ibuf merge is done to a page when it is read in, and it is -still physically like the index page even if the index would have been -dropped! So, there seems to be no problem. */ - -/********************************************************************** -Validates the ibuf data structures when the caller owns ibuf_mutex. */ - -ibool -ibuf_validate_low(void); -/*===================*/ - /* out: TRUE if ok */ - -/********************************************************************** -Sets the flag in the current OS thread local storage denoting that it is -inside an insert buffer routine. */ -UNIV_INLINE -void -ibuf_enter(void) -/*============*/ -{ - ibool* ptr; - - ptr = thr_local_get_in_ibuf_field(); - - ut_ad(*ptr == FALSE); - - *ptr = TRUE; -} - -/********************************************************************** -Sets the flag in the current OS thread local storage denoting that it is -exiting an insert buffer routine. */ -UNIV_INLINE -void -ibuf_exit(void) -/*===========*/ -{ - ibool* ptr; - - ptr = thr_local_get_in_ibuf_field(); - - ut_ad(*ptr == TRUE); - - *ptr = FALSE; -} - -/********************************************************************** -Returns TRUE if the current OS thread is performing an insert buffer -routine. */ - -ibool -ibuf_inside(void) -/*=============*/ - /* out: TRUE if inside an insert buffer routine: for instance, - a read-ahead of non-ibuf pages is then forbidden */ -{ - return(*thr_local_get_in_ibuf_field()); -} - -/********************************************************************** -Gets the ibuf header page and x-latches it. */ -static -page_t* -ibuf_header_page_get( -/*=================*/ - /* out: insert buffer header page */ - ulint space, /* in: space id */ - mtr_t* mtr) /* in: mtr */ -{ - page_t* page; - - ut_a(space == 0); - - ut_ad(!ibuf_inside()); - - page = buf_page_get(space, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr); - -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_IBUF_HEADER); -#endif /* UNIV_SYNC_DEBUG */ - - return(page); -} - -/********************************************************************** -Gets the root page and x-latches it. */ -static -page_t* -ibuf_tree_root_get( -/*===============*/ - /* out: insert buffer tree root page */ - ibuf_data_t* data, /* in: ibuf data */ - ulint space, /* in: space id */ - mtr_t* mtr) /* in: mtr */ -{ - page_t* page; - - ut_a(space == 0); - ut_ad(ibuf_inside()); - - mtr_x_lock(dict_index_get_lock(data->index), mtr); - - page = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, - mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - - return(page); -} - -#ifdef UNIV_IBUF_DEBUG -/********************************************************************** -Gets the ibuf count for a given page. */ - -ulint -ibuf_count_get( -/*===========*/ - /* out: number of entries in the insert buffer - currently buffered for this page */ - ulint space, /* in: space id */ - ulint page_no)/* in: page number */ -{ - ibuf_count_check(space, page_no); - - return(ibuf_counts[space][page_no]); -} - -/********************************************************************** -Sets the ibuf count for a given page. */ -static -void -ibuf_count_set( -/*===========*/ - ulint space, /* in: space id */ - ulint page_no,/* in: page number */ - ulint val) /* in: value to set */ -{ - ibuf_count_check(space, page_no); - ut_a(val < UNIV_PAGE_SIZE); - - ibuf_counts[space][page_no] = val; -} -#endif - -/********************************************************************** -Creates the insert buffer data structure at a database startup and initializes -the data structures for the insert buffer. */ - -void -ibuf_init_at_db_start(void) -/*=======================*/ -{ - ibuf = mem_alloc(sizeof(ibuf_t)); - - /* Note that also a pessimistic delete can sometimes make a B-tree - grow in size, as the references on the upper levels of the tree can - change */ - - ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE - / IBUF_POOL_SIZE_PER_MAX_SIZE; - - UT_LIST_INIT(ibuf->data_list); - - ibuf->size = 0; - - mutex_create(&ibuf_pessimistic_insert_mutex, - SYNC_IBUF_PESS_INSERT_MUTEX); - - mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX); - - mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX); - - fil_ibuf_init_at_db_start(); -} - -/********************************************************************** -Updates the size information in an ibuf data, assuming the segment size has -not changed. */ -static -void -ibuf_data_sizes_update( -/*===================*/ - ibuf_data_t* data, /* in: ibuf data struct */ - page_t* root, /* in: ibuf tree root */ - mtr_t* mtr) /* in: mtr */ -{ - ulint old_size; - - ut_ad(mutex_own(&ibuf_mutex)); - - old_size = data->size; - - data->free_list_len = flst_get_len(root + PAGE_HEADER - + PAGE_BTR_IBUF_FREE_LIST, mtr); - - data->height = 1 + btr_page_get_level(root, mtr); - - data->size = data->seg_size - (1 + data->free_list_len); - /* the '1 +' is the ibuf header page */ - ut_ad(data->size < data->seg_size); - - if (page_get_n_recs(root) == 0) { - - data->empty = TRUE; - } else { - data->empty = FALSE; - } - - ut_ad(ibuf->size + data->size >= old_size); - - ibuf->size = ibuf->size + data->size - old_size; - -#if 0 - fprintf(stderr, "ibuf size %lu, space ibuf size %lu\n", - ibuf->size, data->size); -#endif -} - -/********************************************************************** -Creates the insert buffer data struct for a single tablespace. Reads the -root page of the insert buffer tree in the tablespace. This function can -be called only after the dictionary system has been initialized, as this -creates also the insert buffer table and index into this tablespace. */ - -ibuf_data_t* -ibuf_data_init_for_space( -/*=====================*/ - /* out, own: ibuf data struct, linked to the list - in ibuf control structure */ - ulint space) /* in: space id */ -{ - ibuf_data_t* data; - page_t* root; - page_t* header_page; - mtr_t mtr; - char* buf; - mem_heap_t* heap; - dict_table_t* table; - dict_index_t* index; - ulint n_used; - - ut_a(space == 0); - - data = mem_alloc(sizeof(ibuf_data_t)); - - data->space = space; - - mtr_start(&mtr); - - mutex_enter(&ibuf_mutex); - - mtr_x_lock(fil_space_get_latch(space), &mtr); - - header_page = ibuf_header_page_get(space, &mtr); - - fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, - &n_used, &mtr); - ibuf_enter(); - - ut_ad(n_used >= 2); - - data->seg_size = n_used; - - root = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, - &mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(root, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - - data->size = 0; - data->n_inserts = 0; - data->n_merges = 0; - data->n_merged_recs = 0; - - ibuf_data_sizes_update(data, root, &mtr); - /* - if (!data->empty) { - fprintf(stderr, - "InnoDB: index entries found in the insert buffer\n"); - } else { - fprintf(stderr, - "InnoDB: insert buffer empty\n"); - } - */ - mutex_exit(&ibuf_mutex); - - mtr_commit(&mtr); - - ibuf_exit(); - - heap = mem_heap_create(450); - buf = mem_heap_alloc(heap, 50); - - sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space); - /* use old-style record format for the insert buffer */ - table = dict_mem_table_create(buf, space, 2, 0); - - dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_BINARY, 0, 0); - dict_mem_table_add_col(table, heap, "TYPES", DATA_BINARY, 0, 0); - - table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space); - - dict_table_add_to_cache(table, heap); - mem_heap_free(heap); - - index = dict_mem_index_create( - buf, "CLUST_IND", space, - DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 2); - - dict_mem_index_add_field(index, "PAGE_NO", 0); - dict_mem_index_add_field(index, "TYPES", 0); - - index->id = ut_dulint_add(DICT_IBUF_ID_MIN, space); - - dict_index_add_to_cache(table, index, FSP_IBUF_TREE_ROOT_PAGE_NO); - - data->index = dict_table_get_first_index(table); - - mutex_enter(&ibuf_mutex); - - UT_LIST_ADD_LAST(data_list, ibuf->data_list, data); - - mutex_exit(&ibuf_mutex); - - return(data); -} - -/************************************************************************* -Initializes an ibuf bitmap page. */ - -void -ibuf_bitmap_page_init( -/*==================*/ - page_t* page, /* in: bitmap page */ - mtr_t* mtr) /* in: mtr */ -{ - ulint bit_offset; - ulint byte_offset; - - /* Write all zeros to the bitmap */ - - bit_offset = XDES_DESCRIBED_PER_PAGE * IBUF_BITS_PER_PAGE; - - byte_offset = bit_offset / 8 + 1; - /* better: byte_offset = UT_BITS_IN_BYTES(bit_offset); */ - - fil_page_set_type(page, FIL_PAGE_IBUF_BITMAP); - - memset(page + IBUF_BITMAP, 0, byte_offset); - - /* The remaining area (up to the page trailer) is uninitialized. */ - - mlog_write_initial_log_record(page, MLOG_IBUF_BITMAP_INIT, mtr); -} - -/************************************************************************* -Parses a redo log record of an ibuf bitmap page init. */ - -byte* -ibuf_parse_bitmap_init( -/*===================*/ - /* out: end of log record or NULL */ - byte* ptr, /* in: buffer */ - byte* end_ptr __attribute__((unused)), /* in: buffer end */ - page_t* page, /* in: page or NULL */ - mtr_t* mtr) /* in: mtr or NULL */ -{ - ut_ad(ptr && end_ptr); - - if (page) { - ibuf_bitmap_page_init(page, mtr); - } - - return(ptr); -} - -/************************************************************************ -Gets the desired bits for a given page from a bitmap page. */ -UNIV_INLINE -ulint -ibuf_bitmap_page_get_bits( -/*======================*/ - /* out: value of bits */ - page_t* page, /* in: bitmap page */ - ulint page_no,/* in: page whose bits to get */ - ulint bit, /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */ - mtr_t* mtr __attribute__((unused))) /* in: mtr containing an - x-latch to the bitmap - page */ -{ - ulint byte_offset; - ulint bit_offset; - ulint map_byte; - ulint value; - - ut_ad(bit < IBUF_BITS_PER_PAGE); -#if IBUF_BITS_PER_PAGE % 2 -# error "IBUF_BITS_PER_PAGE % 2 != 0" -#endif - ut_ad(mtr_memo_contains(mtr, buf_block_align(page), - MTR_MEMO_PAGE_X_FIX)); - - bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE - + bit; - - byte_offset = bit_offset / 8; - bit_offset = bit_offset % 8; - - ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE); - - map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset); - - value = ut_bit_get_nth(map_byte, bit_offset); - - if (bit == IBUF_BITMAP_FREE) { - ut_ad(bit_offset + 1 < 8); - - value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1); - } - - return(value); -} - -/************************************************************************ -Sets the desired bit for a given page in a bitmap page. */ -static -void -ibuf_bitmap_page_set_bits( -/*======================*/ - page_t* page, /* in: bitmap page */ - ulint page_no,/* in: page whose bits to set */ - ulint bit, /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */ - ulint val, /* in: value to set */ - mtr_t* mtr) /* in: mtr containing an x-latch to the bitmap page */ -{ - ulint byte_offset; - ulint bit_offset; - ulint map_byte; - - ut_ad(bit < IBUF_BITS_PER_PAGE); -#if IBUF_BITS_PER_PAGE % 2 -# error "IBUF_BITS_PER_PAGE % 2 != 0" -#endif - ut_ad(mtr_memo_contains(mtr, buf_block_align(page), - MTR_MEMO_PAGE_X_FIX)); -#ifdef UNIV_IBUF_DEBUG - ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE) - || (0 == ibuf_count_get(buf_frame_get_space_id(page), - page_no))); -#endif - bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE - + bit; - - byte_offset = bit_offset / 8; - bit_offset = bit_offset % 8; - - ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE); - - map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset); - - if (bit == IBUF_BITMAP_FREE) { - ut_ad(bit_offset + 1 < 8); - ut_ad(val <= 3); - - map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2); - map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2); - } else { - ut_ad(val <= 1); - map_byte = ut_bit_set_nth(map_byte, bit_offset, val); - } - - mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte, - MLOG_1BYTE, mtr); -} - -/************************************************************************ -Calculates the bitmap page number for a given page number. */ -UNIV_INLINE -ulint -ibuf_bitmap_page_no_calc( -/*=====================*/ - /* out: the bitmap page number where - the file page is mapped */ - ulint page_no) /* in: tablespace page number */ -{ - return(FSP_IBUF_BITMAP_OFFSET - + XDES_DESCRIBED_PER_PAGE - * (page_no / XDES_DESCRIBED_PER_PAGE)); -} - -/************************************************************************ -Gets the ibuf bitmap page where the bits describing a given file page are -stored. */ -static -page_t* -ibuf_bitmap_get_map_page( -/*=====================*/ - /* out: bitmap page where the file page is mapped, - that is, the bitmap page containing the descriptor - bits for the file page; the bitmap page is - x-latched */ - ulint space, /* in: space id of the file page */ - ulint page_no,/* in: page number of the file page */ - mtr_t* mtr) /* in: mtr */ -{ - page_t* page; - - page = buf_page_get(space, ibuf_bitmap_page_no_calc(page_no), - RW_X_LATCH, mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_IBUF_BITMAP); -#endif /* UNIV_SYNC_DEBUG */ - - return(page); -} - -/**************************************************************************** -Sets the free bits of the page in the ibuf bitmap. This is done in a separate -mini-transaction, hence this operation does not restrict further work to only -ibuf bitmap operations, which would result if the latch to the bitmap page -were kept. */ -UNIV_INLINE -void -ibuf_set_free_bits_low( -/*===================*/ - ulint type, /* in: index type */ - page_t* page, /* in: index page; free bit is set if the index is - non-clustered and page level is 0 */ - ulint val, /* in: value to set: < 4 */ - mtr_t* mtr) /* in: mtr */ -{ - page_t* bitmap_page; - - if (type & DICT_CLUSTERED) { - - return; - } - - if (btr_page_get_level_low(page) != 0) { - - return; - } - - bitmap_page = ibuf_bitmap_get_map_page( - buf_frame_get_space_id(page), - buf_frame_get_page_no(page), mtr); -#ifdef UNIV_IBUF_DEBUG -# if 0 - fprintf(stderr, - "Setting page no %lu free bits to %lu should be %lu\n", - buf_frame_get_page_no(page), val, - ibuf_index_page_calc_free(page)); -# endif - - ut_a(val <= ibuf_index_page_calc_free(page)); -#endif /* UNIV_IBUF_DEBUG */ - ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page), - IBUF_BITMAP_FREE, val, mtr); - -} - -/**************************************************************************** -Sets the free bit of the page in the ibuf bitmap. This is done in a separate -mini-transaction, hence this operation does not restrict further work to only -ibuf bitmap operations, which would result if the latch to the bitmap page -were kept. */ - -void -ibuf_set_free_bits( -/*===============*/ - ulint type, /* in: index type */ - page_t* page, /* in: index page; free bit is set if the index is - non-clustered and page level is 0 */ - ulint val, /* in: value to set: < 4 */ - ulint max_val)/* in: ULINT_UNDEFINED or a maximum value which - the bits must have before setting; this is for - debugging */ -{ - mtr_t mtr; - page_t* bitmap_page; - - if (type & DICT_CLUSTERED) { - - return; - } - - if (btr_page_get_level_low(page) != 0) { - - return; - } - - mtr_start(&mtr); - - bitmap_page = ibuf_bitmap_get_map_page( - buf_frame_get_space_id(page), buf_frame_get_page_no(page), - &mtr); - - if (max_val != ULINT_UNDEFINED) { -#ifdef UNIV_IBUF_DEBUG - ulint old_val; - - old_val = ibuf_bitmap_page_get_bits( - bitmap_page, buf_frame_get_page_no(page), - IBUF_BITMAP_FREE, &mtr); -# if 0 - if (old_val != max_val) { - fprintf(stderr, - "Ibuf: page %lu old val %lu max val %lu\n", - buf_frame_get_page_no(page), - old_val, max_val); - } -# endif - - ut_a(old_val <= max_val); -#endif - } -#ifdef UNIV_IBUF_DEBUG -# if 0 - fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n", - buf_frame_get_page_no(page), val, - ibuf_index_page_calc_free(page)); -# endif - - ut_a(val <= ibuf_index_page_calc_free(page)); -#endif - ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page), - IBUF_BITMAP_FREE, val, &mtr); - mtr_commit(&mtr); -} - -/**************************************************************************** -Resets the free bits of the page in the ibuf bitmap. This is done in a -separate mini-transaction, hence this operation does not restrict further -work to only ibuf bitmap operations, which would result if the latch to the -bitmap page were kept. */ - -void -ibuf_reset_free_bits_with_type( -/*===========================*/ - ulint type, /* in: index type */ - page_t* page) /* in: index page; free bits are set to 0 if the index - is non-clustered and non-unique and the page level is - 0 */ -{ - ibuf_set_free_bits(type, page, 0, ULINT_UNDEFINED); -} - -/**************************************************************************** -Resets the free bits of the page in the ibuf bitmap. This is done in a -separate mini-transaction, hence this operation does not restrict further -work to solely ibuf bitmap operations, which would result if the latch to -the bitmap page were kept. */ - -void -ibuf_reset_free_bits( -/*=================*/ - dict_index_t* index, /* in: index */ - page_t* page) /* in: index page; free bits are set to 0 if - the index is non-clustered and non-unique and - the page level is 0 */ -{ - ibuf_set_free_bits(index->type, page, 0, ULINT_UNDEFINED); -} - -/************************************************************************** -Updates the free bits for a page to reflect the present state. Does this -in the mtr given, which means that the latching order rules virtually prevent -any further operations for this OS thread until mtr is committed. */ - -void -ibuf_update_free_bits_low( -/*======================*/ - dict_index_t* index, /* in: index */ - page_t* page, /* in: index page */ - ulint max_ins_size, /* in: value of maximum insert size - with reorganize before the latest - operation performed to the page */ - mtr_t* mtr) /* in: mtr */ -{ - ulint before; - ulint after; - - before = ibuf_index_page_calc_free_bits(max_ins_size); - - after = ibuf_index_page_calc_free(page); - - if (before != after) { - ibuf_set_free_bits_low(index->type, page, after, mtr); - } -} - -/************************************************************************** -Updates the free bits for the two pages to reflect the present state. Does -this in the mtr given, which means that the latching order rules virtually -prevent any further operations until mtr is committed. */ - -void -ibuf_update_free_bits_for_two_pages_low( -/*====================================*/ - dict_index_t* index, /* in: index */ - page_t* page1, /* in: index page */ - page_t* page2, /* in: index page */ - mtr_t* mtr) /* in: mtr */ -{ - ulint state; - - /* As we have to x-latch two random bitmap pages, we have to acquire - the bitmap mutex to prevent a deadlock with a similar operation - performed by another OS thread. */ - - mutex_enter(&ibuf_bitmap_mutex); - - state = ibuf_index_page_calc_free(page1); - - ibuf_set_free_bits_low(index->type, page1, state, mtr); - - state = ibuf_index_page_calc_free(page2); - - ibuf_set_free_bits_low(index->type, page2, state, mtr); - - mutex_exit(&ibuf_bitmap_mutex); -} - -/************************************************************************** -Returns TRUE if the page is one of the fixed address ibuf pages. */ -UNIV_INLINE -ibool -ibuf_fixed_addr_page( -/*=================*/ - /* out: TRUE if a fixed address ibuf i/o page */ - ulint space, /* in: space id */ - ulint page_no)/* in: page number */ -{ - return((space == 0 && page_no == IBUF_TREE_ROOT_PAGE_NO) - || ibuf_bitmap_page(page_no)); -} - -/*************************************************************************** -Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */ - -ibool -ibuf_page( -/*======*/ - /* out: TRUE if level 2 or level 3 page */ - ulint space, /* in: space id */ - ulint page_no)/* in: page number */ -{ - page_t* bitmap_page; - mtr_t mtr; - ibool ret; - - if (recv_no_ibuf_operations) { - /* Recovery is running: no ibuf operations should be - performed */ - - return(FALSE); - } - - if (ibuf_fixed_addr_page(space, page_no)) { - - return(TRUE); - } - - if (space != 0) { - /* Currently we only have an ibuf tree in space 0 */ - - return(FALSE); - } - - ut_ad(fil_space_get_type(space) == FIL_TABLESPACE); - - mtr_start(&mtr); - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); - - ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, - &mtr); - mtr_commit(&mtr); - - return(ret); -} - -/*************************************************************************** -Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */ - -ibool -ibuf_page_low( -/*==========*/ - /* out: TRUE if level 2 or level 3 page */ - ulint space, /* in: space id */ - ulint page_no,/* in: page number */ - mtr_t* mtr) /* in: mtr which will contain an x-latch to the - bitmap page if the page is not one of the fixed - address ibuf pages */ -{ - page_t* bitmap_page; - ibool ret; - - if (ibuf_fixed_addr_page(space, page_no)) { - - return(TRUE); - } - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, mtr); - - ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, - mtr); - return(ret); -} - -/************************************************************************ -Returns the page number field of an ibuf record. */ -static -ulint -ibuf_rec_get_page_no( -/*=================*/ - /* out: page number */ - rec_t* rec) /* in: ibuf record */ -{ - byte* field; - ulint len; - - ut_ad(ibuf_inside()); - ut_ad(rec_get_n_fields_old(rec) > 2); - - field = rec_get_nth_field_old(rec, 1, &len); - - if (len == 1) { - /* This is of the >= 4.1.x record format */ - ut_a(trx_sys_multiple_tablespace_format); - - field = rec_get_nth_field_old(rec, 2, &len); - } else { - ut_a(trx_doublewrite_must_reset_space_ids); - ut_a(!trx_sys_multiple_tablespace_format); - - field = rec_get_nth_field_old(rec, 0, &len); - } - - ut_a(len == 4); - - return(mach_read_from_4(field)); -} - -/************************************************************************ -Returns the space id field of an ibuf record. For < 4.1.x format records -returns 0. */ -static -ulint -ibuf_rec_get_space( -/*===============*/ - /* out: space id */ - rec_t* rec) /* in: ibuf record */ -{ - byte* field; - ulint len; - - ut_ad(ibuf_inside()); - ut_ad(rec_get_n_fields_old(rec) > 2); - - field = rec_get_nth_field_old(rec, 1, &len); - - if (len == 1) { - /* This is of the >= 4.1.x record format */ - - ut_a(trx_sys_multiple_tablespace_format); - field = rec_get_nth_field_old(rec, 0, &len); - ut_a(len == 4); - - return(mach_read_from_4(field)); - } - - ut_a(trx_doublewrite_must_reset_space_ids); - ut_a(!trx_sys_multiple_tablespace_format); - - return(0); -} - -/************************************************************************ -Creates a dummy index for inserting a record to a non-clustered index. -*/ -static -dict_index_t* -ibuf_dummy_index_create( -/*====================*/ - /* out: dummy index */ - ulint n, /* in: number of fields */ - ibool comp) /* in: TRUE=use compact record format */ -{ - dict_table_t* table; - dict_index_t* index; - - table = dict_mem_table_create("IBUF_DUMMY", - DICT_HDR_SPACE, n, - comp ? DICT_TF_COMPACT : 0); - - index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY", - DICT_HDR_SPACE, 0, n); - - index->table = table; - - /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ - index->cached = TRUE; - - return(index); -} -/************************************************************************ -Add a column to the dummy index */ -static -void -ibuf_dummy_index_add_col( -/*=====================*/ - dict_index_t* index, /* in: dummy index */ - dtype_t* type, /* in: the data type of the column */ - ulint len) /* in: length of the column */ -{ - ulint i = index->table->n_def; - dict_mem_table_add_col(index->table, NULL, NULL, - dtype_get_mtype(type), - dtype_get_prtype(type), - dtype_get_len(type)); - dict_index_add_col(index, index->table, (dict_col_t*) - dict_table_get_nth_col(index->table, i), len); -} -/************************************************************************ -Deallocates a dummy index for inserting a record to a non-clustered index. -*/ -static -void -ibuf_dummy_index_free( -/*==================*/ - dict_index_t* index) /* in: dummy index */ -{ - dict_table_t* table = index->table; - - dict_mem_index_free(index); - dict_mem_table_free(table); -} - -/************************************************************************* -Builds the entry to insert into a non-clustered index when we have the -corresponding record in an ibuf index. */ -static -dtuple_t* -ibuf_build_entry_from_ibuf_rec( -/*===========================*/ - /* out, own: entry to insert to - a non-clustered index; NOTE that - as we copy pointers to fields in - ibuf_rec, the caller must hold a - latch to the ibuf_rec page as long - as the entry is used! */ - rec_t* ibuf_rec, /* in: record in an insert buffer */ - mem_heap_t* heap, /* in: heap where built */ - dict_index_t** pindex) /* out, own: dummy index that - describes the entry */ -{ - dtuple_t* tuple; - dfield_t* field; - ulint n_fields; - byte* types; - const byte* data; - ulint len; - ulint i; - dict_index_t* index; - - data = rec_get_nth_field_old(ibuf_rec, 1, &len); - - if (len > 1) { - /* This a < 4.1.x format record */ - - ut_a(trx_doublewrite_must_reset_space_ids); - ut_a(!trx_sys_multiple_tablespace_format); - - n_fields = rec_get_n_fields_old(ibuf_rec) - 2; - tuple = dtuple_create(heap, n_fields); - types = rec_get_nth_field_old(ibuf_rec, 1, &len); - - ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE); - - for (i = 0; i < n_fields; i++) { - field = dtuple_get_nth_field(tuple, i); - - data = rec_get_nth_field_old(ibuf_rec, i + 2, &len); - - dfield_set_data(field, data, len); - - dtype_read_for_order_and_null_size( - dfield_get_type(field), - types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE); - } - - *pindex = ibuf_dummy_index_create(n_fields, FALSE); - return(tuple); - } - - /* This a >= 4.1.x format record */ - - ut_a(trx_sys_multiple_tablespace_format); - ut_a(*data == 0); - ut_a(rec_get_n_fields_old(ibuf_rec) > 4); - - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; - - tuple = dtuple_create(heap, n_fields); - - types = rec_get_nth_field_old(ibuf_rec, 3, &len); - - ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1); - index = ibuf_dummy_index_create( - n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); - - if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { - /* compact record format */ - len--; - ut_a(*types == 0); - types++; - } - - ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); - - for (i = 0; i < n_fields; i++) { - field = dtuple_get_nth_field(tuple, i); - - data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); - - dfield_set_data(field, data, len); - - dtype_new_read_for_order_and_null_size( - dfield_get_type(field), - types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); - - ibuf_dummy_index_add_col(index, dfield_get_type(field), len); - } - - *pindex = index; - return(tuple); -} - -/************************************************************************ -Returns the space taken by a stored non-clustered index entry if converted to -an index record. */ -static -ulint -ibuf_rec_get_volume( -/*================*/ - /* out: size of index record in bytes + an upper - limit of the space taken in the page directory */ - rec_t* ibuf_rec)/* in: ibuf record */ -{ - dtype_t dtype; - ibool new_format = FALSE; - ulint data_size = 0; - ulint n_fields; - byte* types; - byte* data; - ulint len; - ulint i; - - ut_ad(ibuf_inside()); - ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); - - data = rec_get_nth_field_old(ibuf_rec, 1, &len); - - if (len > 1) { - /* < 4.1.x format record */ - - ut_a(trx_doublewrite_must_reset_space_ids); - ut_a(!trx_sys_multiple_tablespace_format); - - n_fields = rec_get_n_fields_old(ibuf_rec) - 2; - - types = rec_get_nth_field_old(ibuf_rec, 1, &len); - - ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE); - } else { - /* >= 4.1.x format record */ - - ut_a(trx_sys_multiple_tablespace_format); - ut_a(*data == 0); - - types = rec_get_nth_field_old(ibuf_rec, 3, &len); - - ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1); - if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { - /* compact record format */ - ulint volume; - dict_index_t* dummy_index; - mem_heap_t* heap = mem_heap_create(500); - dtuple_t* entry = ibuf_build_entry_from_ibuf_rec( - ibuf_rec, heap, &dummy_index); - volume = rec_get_converted_size(dummy_index, entry); - ibuf_dummy_index_free(dummy_index); - mem_heap_free(heap); - return(volume + page_dir_calc_reserved_space(1)); - } - - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; - - new_format = TRUE; - } - - for (i = 0; i < n_fields; i++) { - if (new_format) { - data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); - - dtype_new_read_for_order_and_null_size( - &dtype, types + i - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); - } else { - data = rec_get_nth_field_old(ibuf_rec, i + 2, &len); - - dtype_read_for_order_and_null_size( - &dtype, types + i - * DATA_ORDER_NULL_TYPE_BUF_SIZE); - } - - if (len == UNIV_SQL_NULL) { - data_size += dtype_get_sql_null_size(&dtype); - } else { - data_size += len; - } - } - - return(data_size + rec_get_converted_extra_size(data_size, n_fields) - + page_dir_calc_reserved_space(1)); -} - -/************************************************************************* -Builds the tuple to insert to an ibuf tree when we have an entry for a -non-clustered index. */ -static -dtuple_t* -ibuf_entry_build( -/*=============*/ - /* out, own: entry to insert into an ibuf - index tree; NOTE that the original entry - must be kept because we copy pointers to its - fields */ - dict_index_t* index, /* in: non-clustered index */ - dtuple_t* entry, /* in: entry for a non-clustered index */ - ulint space, /* in: space id */ - ulint page_no,/* in: index page number where entry should - be inserted */ - mem_heap_t* heap) /* in: heap into which to build */ -{ - dtuple_t* tuple; - dfield_t* field; - dfield_t* entry_field; - ulint n_fields; - byte* buf; - byte* buf2; - ulint i; - - /* Starting from 4.1.x, we have to build a tuple whose - (1) first field is the space id, - (2) the second field a single marker byte (0) to tell that this - is a new format record, - (3) the third contains the page number, and - (4) the fourth contains the relevent type information of each data - field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is - (a) 0 for b-trees in the old format, and - (b) 1 for b-trees in the compact format, the first byte of the field - being the marker (0); - (5) and the rest of the fields are copied from entry. All fields - in the tuple are ordered like the type binary in our insert buffer - tree. */ - - n_fields = dtuple_get_n_fields(entry); - - tuple = dtuple_create(heap, n_fields + 4); - - /* Store the space id in tuple */ - - field = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, space); - - dfield_set_data(field, buf, 4); - - /* Store the marker byte field in tuple */ - - field = dtuple_get_nth_field(tuple, 1); - - buf = mem_heap_alloc(heap, 1); - - /* We set the marker byte zero */ - - mach_write_to_1(buf, 0); - - dfield_set_data(field, buf, 1); - - /* Store the page number in tuple */ - - field = dtuple_get_nth_field(tuple, 2); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, page_no); - - dfield_set_data(field, buf, 4); - - /* Store the type info in buf2, and add the fields from entry to - tuple */ - buf2 = mem_heap_alloc(heap, n_fields - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + dict_table_is_comp(index->table)); - if (dict_table_is_comp(index->table)) { - *buf2++ = 0; /* write the compact format indicator */ - } - for (i = 0; i < n_fields; i++) { - ulint fixed_len; - const dict_field_t* ifield; - - /* We add 4 below because we have the 4 extra fields at the - start of an ibuf record */ - - field = dtuple_get_nth_field(tuple, i + 4); - entry_field = dtuple_get_nth_field(entry, i); - dfield_copy(field, entry_field); - - ifield = dict_index_get_nth_field(index, i); - /* Prefix index columns of fixed-length columns are of - fixed length. However, in the function call below, - dfield_get_type(entry_field) contains the fixed length - of the column in the clustered index. Replace it with - the fixed length of the secondary index column. */ - fixed_len = ifield->fixed_len; - -#ifdef UNIV_DEBUG - if (fixed_len) { - /* dict_index_add_col() should guarantee these */ - ut_ad(fixed_len <= (ulint) entry_field->type.len); - if (ifield->prefix_len) { - ut_ad(ifield->prefix_len == fixed_len); - } else { - ut_ad(fixed_len - == (ulint) entry_field->type.len); - } - } -#endif /* UNIV_DEBUG */ - - dtype_new_store_for_order_and_null_size( - buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, - dfield_get_type(entry_field), fixed_len); - } - - /* Store the type info in buf2 to field 3 of tuple */ - - field = dtuple_get_nth_field(tuple, 3); - - if (dict_table_is_comp(index->table)) { - buf2--; - } - - dfield_set_data(field, buf2, n_fields - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + dict_table_is_comp(index->table)); - /* Set all the types in the new tuple binary */ - - dtuple_set_types_binary(tuple, n_fields + 4); - - return(tuple); -} - -/************************************************************************* -Builds a search tuple used to search buffered inserts for an index page. -This is for < 4.1.x format records */ -static -dtuple_t* -ibuf_search_tuple_build( -/*====================*/ - /* out, own: search tuple */ - ulint space, /* in: space id */ - ulint page_no,/* in: index page number */ - mem_heap_t* heap) /* in: heap into which to build */ -{ - dtuple_t* tuple; - dfield_t* field; - byte* buf; - - ut_a(space == 0); - ut_a(trx_doublewrite_must_reset_space_ids); - ut_a(!trx_sys_multiple_tablespace_format); - - tuple = dtuple_create(heap, 1); - - /* Store the page number in tuple */ - - field = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, page_no); - - dfield_set_data(field, buf, 4); - - dtuple_set_types_binary(tuple, 1); - - return(tuple); -} - -/************************************************************************* -Builds a search tuple used to search buffered inserts for an index page. -This is for >= 4.1.x format records. */ -static -dtuple_t* -ibuf_new_search_tuple_build( -/*========================*/ - /* out, own: search tuple */ - ulint space, /* in: space id */ - ulint page_no,/* in: index page number */ - mem_heap_t* heap) /* in: heap into which to build */ -{ - dtuple_t* tuple; - dfield_t* field; - byte* buf; - - ut_a(trx_sys_multiple_tablespace_format); - - tuple = dtuple_create(heap, 3); - - /* Store the space id in tuple */ - - field = dtuple_get_nth_field(tuple, 0); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, space); - - dfield_set_data(field, buf, 4); - - /* Store the new format record marker byte */ - - field = dtuple_get_nth_field(tuple, 1); - - buf = mem_heap_alloc(heap, 1); - - mach_write_to_1(buf, 0); - - dfield_set_data(field, buf, 1); - - /* Store the page number in tuple */ - - field = dtuple_get_nth_field(tuple, 2); - - buf = mem_heap_alloc(heap, 4); - - mach_write_to_4(buf, page_no); - - dfield_set_data(field, buf, 4); - - dtuple_set_types_binary(tuple, 3); - - return(tuple); -} - -/************************************************************************* -Checks if there are enough pages in the free list of the ibuf tree that we -dare to start a pessimistic insert to the insert buffer. */ -UNIV_INLINE -ibool -ibuf_data_enough_free_for_insert( -/*=============================*/ - /* out: TRUE if enough free pages in list */ - ibuf_data_t* data) /* in: ibuf data for the space */ -{ - ut_ad(mutex_own(&ibuf_mutex)); - - /* We want a big margin of free pages, because a B-tree can sometimes - grow in size also if records are deleted from it, as the node pointers - can change, and we must make sure that we are able to delete the - inserts buffered for pages that we read to the buffer pool, without - any risk of running out of free space in the insert buffer. */ - - if (data->free_list_len >= data->size / 2 + 3 * data->height) { - - return(TRUE); - } - - return(FALSE); -} - -/************************************************************************* -Checks if there are enough pages in the free list of the ibuf tree that we -should remove them and free to the file space management. */ -UNIV_INLINE -ibool -ibuf_data_too_much_free( -/*====================*/ - /* out: TRUE if enough free pages in list */ - ibuf_data_t* data) /* in: ibuf data for the space */ -{ - ut_ad(mutex_own(&ibuf_mutex)); - - return(data->free_list_len >= 3 + data->size / 2 + 3 * data->height); -} - -/************************************************************************* -Allocates a new page from the ibuf file segment and adds it to the free -list. */ -static -ulint -ibuf_add_free_page( -/*===============*/ - /* out: DB_SUCCESS, or DB_STRONG_FAIL - if no space left */ - ulint space, /* in: space id */ - ibuf_data_t* ibuf_data) /* in: ibuf data for the space */ -{ - mtr_t mtr; - page_t* header_page; - ulint page_no; - page_t* page; - page_t* root; - page_t* bitmap_page; - - ut_a(space == 0); - - mtr_start(&mtr); - - /* Acquire the fsp latch before the ibuf header, obeying the latching - order */ - mtr_x_lock(fil_space_get_latch(space), &mtr); - - header_page = ibuf_header_page_get(space, &mtr); - - /* Allocate a new page: NOTE that if the page has been a part of a - non-clustered index which has subsequently been dropped, then the - page may have buffered inserts in the insert buffer, and these - should be deleted from there. These get deleted when the page - allocation creates the page in buffer. Thus the call below may end - up calling the insert buffer routines and, as we yet have no latches - to insert buffer tree pages, these routines can run without a risk - of a deadlock. This is the reason why we created a special ibuf - header page apart from the ibuf tree. */ - - page_no = fseg_alloc_free_page(header_page + IBUF_HEADER - + IBUF_TREE_SEG_HEADER, 0, FSP_UP, - &mtr); - if (page_no == FIL_NULL) { - mtr_commit(&mtr); - - return(DB_STRONG_FAIL); - } - - page = buf_page_get(space, page_no, RW_X_LATCH, &mtr); - -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); -#endif /* UNIV_SYNC_DEBUG */ - - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - - root = ibuf_tree_root_get(ibuf_data, space, &mtr); - - /* Add the page to the free list and update the ibuf size data */ - - flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, - page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr); - - mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_IBUF_FREE_LIST, - MLOG_2BYTES, &mtr); - - ibuf_data->seg_size++; - ibuf_data->free_list_len++; - - /* Set the bit indicating that this page is now an ibuf tree page - (level 2 page) */ - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); - - ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, - TRUE, &mtr); - mtr_commit(&mtr); - - mutex_exit(&ibuf_mutex); - - ibuf_exit(); - - return(DB_SUCCESS); -} - -/************************************************************************* -Removes a page from the free list and frees it to the fsp system. */ -static -void -ibuf_remove_free_page( -/*==================*/ - ulint space, /* in: space id */ - ibuf_data_t* ibuf_data) /* in: ibuf data for the space */ -{ - mtr_t mtr; - mtr_t mtr2; - page_t* header_page; - ulint page_no; - page_t* page; - page_t* root; - page_t* bitmap_page; - - ut_a(space == 0); - - mtr_start(&mtr); - - /* Acquire the fsp latch before the ibuf header, obeying the latching - order */ - mtr_x_lock(fil_space_get_latch(space), &mtr); - - header_page = ibuf_header_page_get(space, &mtr); - - /* Prevent pessimistic inserts to insert buffer trees for a while */ - mutex_enter(&ibuf_pessimistic_insert_mutex); - - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - - if (!ibuf_data_too_much_free(ibuf_data)) { - - mutex_exit(&ibuf_mutex); - - ibuf_exit(); - - mutex_exit(&ibuf_pessimistic_insert_mutex); - - mtr_commit(&mtr); - - return; - } - - mtr_start(&mtr2); - - root = ibuf_tree_root_get(ibuf_data, space, &mtr2); - - page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, - &mtr2) - .page; - - /* NOTE that we must release the latch on the ibuf tree root - because in fseg_free_page we access level 1 pages, and the root - is a level 2 page. */ - - mtr_commit(&mtr2); - mutex_exit(&ibuf_mutex); - - ibuf_exit(); - - /* Since pessimistic inserts were prevented, we know that the - page is still in the free list. NOTE that also deletes may take - pages from the free list, but they take them from the start, and - the free list was so long that they cannot have taken the last - page from it. */ - - fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, - space, page_no, &mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES - buf_page_reset_file_page_was_freed(space, page_no); -#endif - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - - root = ibuf_tree_root_get(ibuf_data, space, &mtr); - - ut_ad(page_no == flst_get_last(root + PAGE_HEADER - + PAGE_BTR_IBUF_FREE_LIST, &mtr) - .page); - - page = buf_page_get(space, page_no, RW_X_LATCH, &mtr); - -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - - /* Remove the page from the free list and update the ibuf size data */ - - flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, - page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr); - - ibuf_data->seg_size--; - ibuf_data->free_list_len--; - - mutex_exit(&ibuf_pessimistic_insert_mutex); - - /* Set the bit indicating that this page is no more an ibuf tree page - (level 2 page) */ - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); - - ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF, - FALSE, &mtr); -#ifdef UNIV_DEBUG_FILE_ACCESSES - buf_page_set_file_page_was_freed(space, page_no); -#endif - mtr_commit(&mtr); - - mutex_exit(&ibuf_mutex); - - ibuf_exit(); -} - -/*************************************************************************** -Frees excess pages from the ibuf free list. This function is called when an OS -thread calls fsp services to allocate a new file segment, or a new page to a -file segment, and the thread did not own the fsp latch before this call. */ - -void -ibuf_free_excess_pages( -/*===================*/ - ulint space) /* in: space id */ -{ - ibuf_data_t* ibuf_data; - ulint i; - - if (space != 0) { - fprintf(stderr, - "InnoDB: Error: calling ibuf_free_excess_pages" - " for space %lu\n", (ulong) space); - return; - } - -#ifdef UNIV_SYNC_DEBUG - ut_ad(rw_lock_own(fil_space_get_latch(space), RW_LOCK_EX)); -#endif /* UNIV_SYNC_DEBUG */ - ut_ad(rw_lock_get_x_lock_count(fil_space_get_latch(space)) == 1); - ut_ad(!ibuf_inside()); - - /* NOTE: We require that the thread did not own the latch before, - because then we know that we can obey the correct latching order - for ibuf latches */ - - ibuf_data = fil_space_get_ibuf_data(space); - - if (ibuf_data == NULL) { - /* Not yet initialized */ - -#if 0 /* defined UNIV_DEBUG */ - fprintf(stderr, - "Ibuf for space %lu not yet initialized\n", space); -#endif - - return; - } - - /* Free at most a few pages at a time, so that we do not delay the - requested service too much */ - - for (i = 0; i < 4; i++) { - - mutex_enter(&ibuf_mutex); - - if (!ibuf_data_too_much_free(ibuf_data)) { - - mutex_exit(&ibuf_mutex); - - return; - } - - mutex_exit(&ibuf_mutex); - - ibuf_remove_free_page(space, ibuf_data); - } -} - -/************************************************************************* -Reads page numbers from a leaf in an ibuf tree. */ -static -ulint -ibuf_get_merge_page_nos( -/*====================*/ - /* out: a lower limit for the combined volume - of records which will be merged */ - ibool contract,/* in: TRUE if this function is called to - contract the tree, FALSE if this is called - when a single page becomes full and we look - if it pays to read also nearby pages */ - rec_t* rec, /* in: record from which we read up and down - in the chain of records */ - ulint* space_ids,/* in/out: space id's of the pages */ - ib_longlong* space_versions,/* in/out: tablespace version - timestamps; used to prevent reading in old - pages after DISCARD + IMPORT tablespace */ - ulint* page_nos,/* in/out: buffer for at least - IBUF_MAX_N_PAGES_MERGED many page numbers; - the page numbers are in an ascending order */ - ulint* n_stored)/* out: number of page numbers stored to - page_nos in this function */ -{ - ulint prev_page_no; - ulint prev_space_id; - ulint first_page_no; - ulint first_space_id; - ulint rec_page_no; - ulint rec_space_id; - ulint sum_volumes; - ulint volume_for_page; - ulint rec_volume; - ulint limit; - ulint n_pages; - - *n_stored = 0; - - limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4); - - if (page_rec_is_supremum(rec)) { - - rec = page_rec_get_prev(rec); - } - - if (page_rec_is_infimum(rec)) { - - rec = page_rec_get_next(rec); - } - - if (page_rec_is_supremum(rec)) { - - return(0); - } - - first_page_no = ibuf_rec_get_page_no(rec); - first_space_id = ibuf_rec_get_space(rec); - n_pages = 0; - prev_page_no = 0; - prev_space_id = 0; - - /* Go backwards from the first rec until we reach the border of the - 'merge area', or the page start or the limit of storeable pages is - reached */ - - while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) { - - rec_page_no = ibuf_rec_get_page_no(rec); - rec_space_id = ibuf_rec_get_space(rec); - - if (rec_space_id != first_space_id - || rec_page_no / IBUF_MERGE_AREA - != first_page_no / IBUF_MERGE_AREA) { - - break; - } - - if (rec_page_no != prev_page_no - || rec_space_id != prev_space_id) { - n_pages++; - } - - prev_page_no = rec_page_no; - prev_space_id = rec_space_id; - - rec = page_rec_get_prev(rec); - } - - rec = page_rec_get_next(rec); - - /* At the loop start there is no prev page; we mark this with a pair - of space id, page no (0, 0) for which there can never be entries in - the insert buffer */ - - prev_page_no = 0; - prev_space_id = 0; - sum_volumes = 0; - volume_for_page = 0; - - while (*n_stored < limit) { - if (page_rec_is_supremum(rec)) { - /* When no more records available, mark this with - another 'impossible' pair of space id, page no */ - rec_page_no = 1; - rec_space_id = 0; - } else { - rec_page_no = ibuf_rec_get_page_no(rec); - rec_space_id = ibuf_rec_get_space(rec); - ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO); - } - -#ifdef UNIV_IBUF_DEBUG - ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED); -#endif - if ((rec_space_id != prev_space_id - || rec_page_no != prev_page_no) - && (prev_space_id != 0 || prev_page_no != 0)) { - - if ((prev_page_no == first_page_no - && prev_space_id == first_space_id) - || contract - || (volume_for_page - > ((IBUF_MERGE_THRESHOLD - 1) - * 4 * UNIV_PAGE_SIZE - / IBUF_PAGE_SIZE_PER_FREE_SPACE) - / IBUF_MERGE_THRESHOLD)) { - - space_ids[*n_stored] = prev_space_id; - space_versions[*n_stored] - = fil_space_get_version(prev_space_id); - page_nos[*n_stored] = prev_page_no; - - (*n_stored)++; - - sum_volumes += volume_for_page; - } - - if (rec_space_id != first_space_id - || rec_page_no / IBUF_MERGE_AREA - != first_page_no / IBUF_MERGE_AREA) { - - break; - } - - volume_for_page = 0; - } - - if (rec_page_no == 1 && rec_space_id == 0) { - /* Supremum record */ - - break; - } - - rec_volume = ibuf_rec_get_volume(rec); - - volume_for_page += rec_volume; - - prev_page_no = rec_page_no; - prev_space_id = rec_space_id; - - rec = page_rec_get_next(rec); - } - -#ifdef UNIV_IBUF_DEBUG - ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED); -#endif -#if 0 - fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n", - *n_stored, sum_volumes); -#endif - return(sum_volumes); -} - -/************************************************************************* -Contracts insert buffer trees by reading pages to the buffer pool. */ -static -ulint -ibuf_contract_ext( -/*==============*/ - /* out: a lower limit for the combined size in bytes - of entries which will be merged from ibuf trees to the - pages read, 0 if ibuf is empty */ - ulint* n_pages,/* out: number of pages to which merged */ - ibool sync) /* in: TRUE if the caller wants to wait for the - issued read with the highest tablespace address - to complete */ -{ - ulint rnd_pos; - ibuf_data_t* data; - btr_pcur_t pcur; - ulint space; - ibool all_trees_empty; - ulint page_nos[IBUF_MAX_N_PAGES_MERGED]; - ulint space_ids[IBUF_MAX_N_PAGES_MERGED]; - ib_longlong space_versions[IBUF_MAX_N_PAGES_MERGED]; - ulint n_stored; - ulint sum_sizes; - mtr_t mtr; - - *n_pages = 0; -loop: - ut_ad(!ibuf_inside()); - - mutex_enter(&ibuf_mutex); - - ut_ad(ibuf_validate_low()); - - /* Choose an ibuf tree at random (though there really is only one tree - in the current implementation) */ - ibuf_rnd += 865558671; - - rnd_pos = ibuf_rnd % ibuf->size; - - all_trees_empty = TRUE; - - data = UT_LIST_GET_FIRST(ibuf->data_list); - - for (;;) { - if (!data->empty) { - all_trees_empty = FALSE; - - if (rnd_pos < data->size) { - - break; - } - - rnd_pos -= data->size; - } - - data = UT_LIST_GET_NEXT(data_list, data); - - if (data == NULL) { - if (all_trees_empty) { - mutex_exit(&ibuf_mutex); - - return(0); - } - - data = UT_LIST_GET_FIRST(ibuf->data_list); - } - } - - ut_ad(data); - - space = data->index->space; - - ut_a(space == 0); /* We currently only have an ibuf tree in - space 0 */ - mtr_start(&mtr); - - ibuf_enter(); - - /* Open a cursor to a randomly chosen leaf of the tree, at a random - position within the leaf */ - - btr_pcur_open_at_rnd_pos(data->index, BTR_SEARCH_LEAF, &pcur, &mtr); - - if (0 == page_get_n_recs(btr_pcur_get_page(&pcur))) { - - /* This tree is empty */ - - data->empty = TRUE; - - ibuf_exit(); - - mtr_commit(&mtr); - btr_pcur_close(&pcur); - - mutex_exit(&ibuf_mutex); - - goto loop; - } - - mutex_exit(&ibuf_mutex); - - sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur), - space_ids, space_versions, - page_nos, &n_stored); -#if 0 /* defined UNIV_IBUF_DEBUG */ - fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n", - sync, n_stored, sum_sizes); -#endif - ibuf_exit(); - - mtr_commit(&mtr); - btr_pcur_close(&pcur); - - buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos, - n_stored); - *n_pages = n_stored; - - return(sum_sizes + 1); -} - -/************************************************************************* -Contracts insert buffer trees by reading pages to the buffer pool. */ - -ulint -ibuf_contract( -/*==========*/ - /* out: a lower limit for the combined size in bytes - of entries which will be merged from ibuf trees to the - pages read, 0 if ibuf is empty */ - ibool sync) /* in: TRUE if the caller wants to wait for the - issued read with the highest tablespace address - to complete */ -{ - ulint n_pages; - - return(ibuf_contract_ext(&n_pages, sync)); -} - -/************************************************************************* -Contracts insert buffer trees by reading pages to the buffer pool. */ - -ulint -ibuf_contract_for_n_pages( -/*======================*/ - /* out: a lower limit for the combined size in bytes - of entries which will be merged from ibuf trees to the - pages read, 0 if ibuf is empty */ - ibool sync, /* in: TRUE if the caller wants to wait for the - issued read with the highest tablespace address - to complete */ - ulint n_pages)/* in: try to read at least this many pages to - the buffer pool and merge the ibuf contents to - them */ -{ - ulint sum_bytes = 0; - ulint sum_pages = 0; - ulint n_bytes; - ulint n_pag2; - - while (sum_pages < n_pages) { - n_bytes = ibuf_contract_ext(&n_pag2, sync); - - if (n_bytes == 0) { - return(sum_bytes); - } - - sum_bytes += n_bytes; - sum_pages += n_pag2; - } - - return(sum_bytes); -} - -/************************************************************************* -Contract insert buffer trees after insert if they are too big. */ -UNIV_INLINE -void -ibuf_contract_after_insert( -/*=======================*/ - ulint entry_size) /* in: size of a record which was inserted - into an ibuf tree */ -{ - ibool sync; - ulint sum_sizes; - ulint size; - - mutex_enter(&ibuf_mutex); - - if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) { - mutex_exit(&ibuf_mutex); - - return; - } - - sync = FALSE; - - if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) { - - sync = TRUE; - } - - mutex_exit(&ibuf_mutex); - - /* Contract at least entry_size many bytes */ - sum_sizes = 0; - size = 1; - - while ((size > 0) && (sum_sizes < entry_size)) { - - size = ibuf_contract(sync); - sum_sizes += size; - } -} - -/************************************************************************* -Gets an upper limit for the combined size of entries buffered in the insert -buffer for a given page. */ - -ulint -ibuf_get_volume_buffered( -/*=====================*/ - /* out: upper limit for the volume of - buffered inserts for the index page, in bytes; - we may also return UNIV_PAGE_SIZE, if the - entries for the index page span on several - pages in the insert buffer */ - btr_pcur_t* pcur, /* in: pcur positioned at a place in an - insert buffer tree where we would insert an - entry for the index page whose number is - page_no, latch mode has to be BTR_MODIFY_PREV - or BTR_MODIFY_TREE */ - ulint space, /* in: space id */ - ulint page_no,/* in: page number of an index page */ - mtr_t* mtr) /* in: mtr */ -{ - ulint volume; - rec_t* rec; - page_t* page; - ulint prev_page_no; - page_t* prev_page; - ulint next_page_no; - page_t* next_page; - - ut_a(trx_sys_multiple_tablespace_format); - - ut_ad((pcur->latch_mode == BTR_MODIFY_PREV) - || (pcur->latch_mode == BTR_MODIFY_TREE)); - - /* Count the volume of records earlier in the alphabetical order than - pcur */ - - volume = 0; - - rec = btr_pcur_get_rec(pcur); - - page = buf_frame_align(rec); - - if (page_rec_is_supremum(rec)) { - rec = page_rec_get_prev(rec); - } - - for (;;) { - if (page_rec_is_infimum(rec)) { - - break; - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { - - goto count_later; - } - - volume += ibuf_rec_get_volume(rec); - - rec = page_rec_get_prev(rec); - } - - /* Look at the previous page */ - - prev_page_no = btr_page_get_prev(page, mtr); - - if (prev_page_no == FIL_NULL) { - - goto count_later; - } - - prev_page = buf_page_get(0, prev_page_no, RW_X_LATCH, mtr); -#ifdef UNIV_BTR_DEBUG - ut_a(btr_page_get_next(prev_page, mtr) - == buf_frame_get_page_no(page)); -#endif /* UNIV_BTR_DEBUG */ - -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(prev_page, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - - rec = page_get_supremum_rec(prev_page); - rec = page_rec_get_prev(rec); - - for (;;) { - if (page_rec_is_infimum(rec)) { - - /* We cannot go to yet a previous page, because we - do not have the x-latch on it, and cannot acquire one - because of the latching order: we have to give up */ - - return(UNIV_PAGE_SIZE); - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { - - goto count_later; - } - - volume += ibuf_rec_get_volume(rec); - - rec = page_rec_get_prev(rec); - } - -count_later: - rec = btr_pcur_get_rec(pcur); - - if (!page_rec_is_supremum(rec)) { - rec = page_rec_get_next(rec); - } - - for (;;) { - if (page_rec_is_supremum(rec)) { - - break; - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { - - return(volume); - } - - volume += ibuf_rec_get_volume(rec); - - rec = page_rec_get_next(rec); - } - - /* Look at the next page */ - - next_page_no = btr_page_get_next(page, mtr); - - if (next_page_no == FIL_NULL) { - - return(volume); - } - - next_page = buf_page_get(0, next_page_no, RW_X_LATCH, mtr); -#ifdef UNIV_BTR_DEBUG - ut_a(btr_page_get_prev(next_page, mtr) - == buf_frame_get_page_no(page)); -#endif /* UNIV_BTR_DEBUG */ - -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(next_page, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - - rec = page_get_infimum_rec(next_page); - rec = page_rec_get_next(rec); - - for (;;) { - if (page_rec_is_supremum(rec)) { - - /* We give up */ - - return(UNIV_PAGE_SIZE); - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { - - return(volume); - } - - volume += ibuf_rec_get_volume(rec); - - rec = page_rec_get_next(rec); - } -} - -/************************************************************************* -Reads the biggest tablespace id from the high end of the insert buffer -tree and updates the counter in fil_system. */ - -void -ibuf_update_max_tablespace_id(void) -/*===============================*/ -{ - ulint max_space_id; - rec_t* rec; - byte* field; - ulint len; - ibuf_data_t* ibuf_data; - dict_index_t* ibuf_index; - btr_pcur_t pcur; - mtr_t mtr; - - ibuf_data = fil_space_get_ibuf_data(0); - - ibuf_index = ibuf_data->index; - ut_a(!dict_table_is_comp(ibuf_index->table)); - - ibuf_enter(); - - mtr_start(&mtr); - - btr_pcur_open_at_index_side(FALSE, ibuf_index, BTR_SEARCH_LEAF, - &pcur, TRUE, &mtr); - btr_pcur_move_to_prev(&pcur, &mtr); - - if (btr_pcur_is_before_first_on_page(&pcur, &mtr)) { - /* The tree is empty */ - - max_space_id = 0; - } else { - rec = btr_pcur_get_rec(&pcur); - - field = rec_get_nth_field_old(rec, 0, &len); - - ut_a(len == 4); - - max_space_id = mach_read_from_4(field); - } - - mtr_commit(&mtr); - ibuf_exit(); - - /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */ - - fil_set_max_space_id_if_bigger(max_space_id); -} - -/************************************************************************* -Makes an index insert to the insert buffer, instead of directly to the disk -page, if this is possible. */ -static -ulint -ibuf_insert_low( -/*============*/ - /* out: DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */ - ulint mode, /* in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */ - dtuple_t* entry, /* in: index entry to insert */ - dict_index_t* index, /* in: index where to insert; must not be - unique or clustered */ - ulint space, /* in: space id where to insert */ - ulint page_no,/* in: page number where to insert */ - que_thr_t* thr) /* in: query thread */ -{ - big_rec_t* dummy_big_rec; - ulint entry_size; - btr_pcur_t pcur; - btr_cur_t* cursor; - dtuple_t* ibuf_entry; - mem_heap_t* heap; - ulint buffered; - rec_t* ins_rec; - ibool old_bit_value; - page_t* bitmap_page; - ibuf_data_t* ibuf_data; - dict_index_t* ibuf_index; - page_t* root; - ulint err; - ibool do_merge; - ulint space_ids[IBUF_MAX_N_PAGES_MERGED]; - ib_longlong space_versions[IBUF_MAX_N_PAGES_MERGED]; - ulint page_nos[IBUF_MAX_N_PAGES_MERGED]; - ulint n_stored; - ulint bits; - mtr_t mtr; - mtr_t bitmap_mtr; - - ut_a(!(index->type & DICT_CLUSTERED)); - ut_ad(dtuple_check_typed(entry)); - - ut_a(trx_sys_multiple_tablespace_format); - - do_merge = FALSE; - - /* Currently the insert buffer of space 0 takes care of inserts to all - tablespaces */ - - ibuf_data = fil_space_get_ibuf_data(0); - - ibuf_index = ibuf_data->index; - - mutex_enter(&ibuf_mutex); - - if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) { - /* Insert buffer is now too big, contract it but do not try - to insert */ - - mutex_exit(&ibuf_mutex); - -#ifdef UNIV_IBUF_DEBUG - fputs("Ibuf too big\n", stderr); -#endif - /* Use synchronous contract (== TRUE) */ - ibuf_contract(TRUE); - - return(DB_STRONG_FAIL); - } - - mutex_exit(&ibuf_mutex); - - if (mode == BTR_MODIFY_TREE) { - mutex_enter(&ibuf_pessimistic_insert_mutex); - - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - - while (!ibuf_data_enough_free_for_insert(ibuf_data)) { - - mutex_exit(&ibuf_mutex); - - ibuf_exit(); - - mutex_exit(&ibuf_pessimistic_insert_mutex); - - err = ibuf_add_free_page(0, ibuf_data); - - if (err == DB_STRONG_FAIL) { - - return(err); - } - - mutex_enter(&ibuf_pessimistic_insert_mutex); - - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - } - } else { - ibuf_enter(); - } - - entry_size = rec_get_converted_size(index, entry); - - heap = mem_heap_create(512); - - /* Build the entry which contains the space id and the page number as - the first fields and the type information for other fields, and which - will be inserted to the insert buffer. */ - - ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap); - - /* Open a cursor to the insert buffer tree to calculate if we can add - the new entry to it without exceeding the free space limit for the - page. */ - - mtr_start(&mtr); - - btr_pcur_open(ibuf_index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr); - - /* Find out the volume of already buffered inserts for the same index - page */ - buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr); - -#ifdef UNIV_IBUF_DEBUG - ut_a((buffered == 0) || ibuf_count_get(space, page_no)); -#endif - mtr_start(&bitmap_mtr); - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &bitmap_mtr); - - /* We check if the index page is suitable for buffered entries */ - - if (buf_page_peek(space, page_no) - || lock_rec_expl_exist_on_page(space, page_no)) { - err = DB_STRONG_FAIL; - - mtr_commit(&bitmap_mtr); - - goto function_exit; - } - - bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, - IBUF_BITMAP_FREE, &bitmap_mtr); - - if (buffered + entry_size + page_dir_calc_reserved_space(1) - > ibuf_index_page_calc_free_from_bits(bits)) { - mtr_commit(&bitmap_mtr); - - /* It may not fit */ - err = DB_STRONG_FAIL; - - do_merge = TRUE; - - ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur), - space_ids, space_versions, - page_nos, &n_stored); - goto function_exit; - } - - /* Set the bitmap bit denoting that the insert buffer contains - buffered entries for this index page, if the bit is not set yet */ - - old_bit_value = ibuf_bitmap_page_get_bits(bitmap_page, page_no, - IBUF_BITMAP_BUFFERED, - &bitmap_mtr); - if (!old_bit_value) { - ibuf_bitmap_page_set_bits(bitmap_page, page_no, - IBUF_BITMAP_BUFFERED, TRUE, - &bitmap_mtr); - } - - mtr_commit(&bitmap_mtr); - - cursor = btr_pcur_get_btr_cur(&pcur); - - if (mode == BTR_MODIFY_PREV) { - err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor, - ibuf_entry, &ins_rec, - &dummy_big_rec, thr, - &mtr); - if (err == DB_SUCCESS) { - /* Update the page max trx id field */ - page_update_max_trx_id(buf_frame_align(ins_rec), - thr_get_trx(thr)->id); - } - } else { - ut_ad(mode == BTR_MODIFY_TREE); - - /* We acquire an x-latch to the root page before the insert, - because a pessimistic insert releases the tree x-latch, - which would cause the x-latching of the root after that to - break the latching order. */ - - root = ibuf_tree_root_get(ibuf_data, 0, &mtr); - - err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG - | BTR_NO_UNDO_LOG_FLAG, - cursor, - ibuf_entry, &ins_rec, - &dummy_big_rec, thr, - &mtr); - if (err == DB_SUCCESS) { - /* Update the page max trx id field */ - page_update_max_trx_id(buf_frame_align(ins_rec), - thr_get_trx(thr)->id); - } - - ibuf_data_sizes_update(ibuf_data, root, &mtr); - } - -function_exit: -#ifdef UNIV_IBUF_DEBUG - if (err == DB_SUCCESS) { - fprintf(stderr, - "Incrementing ibuf count of space %lu page %lu\n" - "from %lu by 1\n", space, page_no, - ibuf_count_get(space, page_no)); - - ibuf_count_set(space, page_no, - ibuf_count_get(space, page_no) + 1); - } -#endif - if (mode == BTR_MODIFY_TREE) { - ut_ad(ibuf_validate_low()); - - mutex_exit(&ibuf_mutex); - mutex_exit(&ibuf_pessimistic_insert_mutex); - } - - mtr_commit(&mtr); - btr_pcur_close(&pcur); - ibuf_exit(); - - mem_heap_free(heap); - - mutex_enter(&ibuf_mutex); - - if (err == DB_SUCCESS) { - ibuf_data->empty = FALSE; - ibuf_data->n_inserts++; - } - - mutex_exit(&ibuf_mutex); - - if ((mode == BTR_MODIFY_TREE) && (err == DB_SUCCESS)) { - ibuf_contract_after_insert(entry_size); - } - - if (do_merge) { -#ifdef UNIV_IBUF_DEBUG - ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED); -#endif - buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions, - page_nos, n_stored); - } - - return(err); -} - -/************************************************************************* -Makes an index insert to the insert buffer, instead of directly to the disk -page, if this is possible. Does not do insert if the index is clustered -or unique. */ - -ibool -ibuf_insert( -/*========*/ - /* out: TRUE if success */ - dtuple_t* entry, /* in: index entry to insert */ - dict_index_t* index, /* in: index where to insert */ - ulint space, /* in: space id where to insert */ - ulint page_no,/* in: page number where to insert */ - que_thr_t* thr) /* in: query thread */ -{ - ulint err; - - ut_a(trx_sys_multiple_tablespace_format); - ut_ad(dtuple_check_typed(entry)); - - ut_a(!(index->type & DICT_CLUSTERED)); - - if (rec_get_converted_size(index, entry) - >= (page_get_free_space_of_empty(dict_table_is_comp(index->table)) - / 2)) { - return(FALSE); - } - - err = ibuf_insert_low(BTR_MODIFY_PREV, entry, index, space, page_no, - thr); - if (err == DB_FAIL) { - err = ibuf_insert_low(BTR_MODIFY_TREE, entry, index, space, - page_no, thr); - } - - if (err == DB_SUCCESS) { -#ifdef UNIV_IBUF_DEBUG - /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n", - page_no, index->name); */ -#endif - return(TRUE); - - } else { - ut_a(err == DB_STRONG_FAIL); - - return(FALSE); - } -} - -/************************************************************************ -During merge, inserts to an index page a secondary index entry extracted -from the insert buffer. */ -static -void -ibuf_insert_to_index_page( -/*======================*/ - dtuple_t* entry, /* in: buffered entry to insert */ - page_t* page, /* in: index page where the buffered entry - should be placed */ - dict_index_t* index, /* in: record descriptor */ - mtr_t* mtr) /* in: mtr */ -{ - page_cur_t page_cur; - ulint low_match; - rec_t* rec; - page_t* bitmap_page; - ulint old_bits; - - ut_ad(ibuf_inside()); - ut_ad(dtuple_check_typed(entry)); - - if (UNIV_UNLIKELY(dict_table_is_comp(index->table) - != (ibool)!!page_is_comp(page))) { - fputs("InnoDB: Trying to insert a record from" - " the insert buffer to an index page\n" - "InnoDB: but the 'compact' flag does not match!\n", - stderr); - goto dump; - } - - rec = page_rec_get_next(page_get_infimum_rec(page)); - - if (UNIV_UNLIKELY(rec_get_n_fields(rec, index) - != dtuple_get_n_fields(entry))) { - fputs("InnoDB: Trying to insert a record from" - " the insert buffer to an index page\n" - "InnoDB: but the number of fields does not match!\n", - stderr); -dump: - buf_page_print(page); - - dtuple_print(stderr, entry); - - fputs("InnoDB: The table where where" - " this index record belongs\n" - "InnoDB: is now probably corrupt." - " Please run CHECK TABLE on\n" - "InnoDB: your tables.\n" - "InnoDB: Submit a detailed bug report to" - " http://bugs.mysql.com!\n", stderr); - - return; - } - - low_match = page_cur_search(page, index, entry, - PAGE_CUR_LE, &page_cur); - - if (low_match == dtuple_get_n_fields(entry)) { - rec = page_cur_get_rec(&page_cur); - - btr_cur_del_unmark_for_ibuf(rec, mtr); - } else { - rec = page_cur_tuple_insert(&page_cur, entry, index, mtr); - - if (rec == NULL) { - /* If the record did not fit, reorganize */ - - btr_page_reorganize(page, index, mtr); - - page_cur_search(page, index, entry, - PAGE_CUR_LE, &page_cur); - - /* This time the record must fit */ - if (UNIV_UNLIKELY(!page_cur_tuple_insert( - &page_cur, entry, index, - mtr))) { - - ut_print_timestamp(stderr); - - fprintf(stderr, - " InnoDB: Error: Insert buffer insert" - " fails; page free %lu," - " dtuple size %lu\n", - (ulong) page_get_max_insert_size( - page, 1), - (ulong) rec_get_converted_size( - index, entry)); - fputs("InnoDB: Cannot insert index record ", - stderr); - dtuple_print(stderr, entry); - fputs("\nInnoDB: The table where" - " this index record belongs\n" - "InnoDB: is now probably corrupt." - " Please run CHECK TABLE on\n" - "InnoDB: that table.\n", stderr); - - bitmap_page = ibuf_bitmap_get_map_page( - buf_frame_get_space_id(page), - buf_frame_get_page_no(page), - mtr); - old_bits = ibuf_bitmap_page_get_bits( - bitmap_page, - buf_frame_get_page_no(page), - IBUF_BITMAP_FREE, mtr); - - fprintf(stderr, "InnoDB: Bitmap bits %lu\n", - (ulong) old_bits); - - fputs("InnoDB: Submit a detailed bug report" - " to http://bugs.mysql.com\n", stderr); - } - } - } -} - -/************************************************************************* -Deletes from ibuf the record on which pcur is positioned. If we have to -resort to a pessimistic delete, this function commits mtr and closes -the cursor. */ -static -ibool -ibuf_delete_rec( -/*============*/ - /* out: TRUE if mtr was committed and pcur - closed in this operation */ - ulint space, /* in: space id */ - ulint page_no,/* in: index page number where the record - should belong */ - btr_pcur_t* pcur, /* in: pcur positioned on the record to - delete, having latch mode BTR_MODIFY_LEAF */ - dtuple_t* search_tuple, - /* in: search tuple for entries of page_no */ - mtr_t* mtr) /* in: mtr */ -{ - ibool success; - ibuf_data_t* ibuf_data; - page_t* root; - ulint err; - - ut_ad(ibuf_inside()); - - success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); - - if (success) { -#ifdef UNIV_IBUF_DEBUG - fprintf(stderr, - "Decrementing ibuf count of space %lu page %lu\n" - "from %lu by 1\n", space, page_no, - ibuf_count_get(space, page_no)); - ibuf_count_set(space, page_no, - ibuf_count_get(space, page_no) - 1); -#endif - return(FALSE); - } - - /* We have to resort to a pessimistic delete from ibuf */ - btr_pcur_store_position(pcur, mtr); - - btr_pcur_commit_specify_mtr(pcur, mtr); - - /* Currently the insert buffer of space 0 takes care of inserts to all - tablespaces */ - - ibuf_data = fil_space_get_ibuf_data(0); - - mutex_enter(&ibuf_mutex); - - mtr_start(mtr); - - success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr); - - if (!success) { - if (fil_space_get_version(space) == -1) { - /* The tablespace has been dropped. It is possible - that another thread has deleted the insert buffer - entry. Do not complain. */ - goto commit_and_exit; - } - - fprintf(stderr, - "InnoDB: ERROR: Submit the output to" - " http://bugs.mysql.com\n" - "InnoDB: ibuf cursor restoration fails!\n" - "InnoDB: ibuf record inserted to page %lu\n", - (ulong) page_no); - fflush(stderr); - - rec_print_old(stderr, btr_pcur_get_rec(pcur)); - rec_print_old(stderr, pcur->old_rec); - dtuple_print(stderr, search_tuple); - - rec_print_old(stderr, - page_rec_get_next(btr_pcur_get_rec(pcur))); - fflush(stderr); - - btr_pcur_commit_specify_mtr(pcur, mtr); - - fputs("InnoDB: Validating insert buffer tree:\n", stderr); - if (!btr_validate_index(ibuf_data->index, NULL)) { - ut_error; - } - - fprintf(stderr, "InnoDB: ibuf tree ok\n"); - fflush(stderr); - - goto func_exit; - } - - root = ibuf_tree_root_get(ibuf_data, 0, mtr); - - btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur), - FALSE, mtr); - ut_a(err == DB_SUCCESS); - -#ifdef UNIV_IBUF_DEBUG - ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1); -#endif - ibuf_data_sizes_update(ibuf_data, root, mtr); - - ut_ad(ibuf_validate_low()); - -commit_and_exit: - btr_pcur_commit_specify_mtr(pcur, mtr); - -func_exit: - btr_pcur_close(pcur); - - mutex_exit(&ibuf_mutex); - - return(TRUE); -} - -/************************************************************************* -When an index page is read from a disk to the buffer pool, this function -inserts to the page the possible index entries buffered in the insert buffer. -The entries are deleted from the insert buffer. If the page is not read, but -created in the buffer pool, this function deletes its buffered entries from -the insert buffer; there can exist entries for such a page if the page -belonged to an index which subsequently was dropped. */ - -void -ibuf_merge_or_delete_for_page( -/*==========================*/ - page_t* page, /* in: if page has been read from disk, pointer to - the page x-latched, else NULL */ - ulint space, /* in: space id of the index page */ - ulint page_no,/* in: page number of the index page */ - ibool update_ibuf_bitmap)/* in: normally this is set to TRUE, but if - we have deleted or are deleting the tablespace, then we - naturally do not want to update a non-existent bitmap - page */ -{ - mem_heap_t* heap; - btr_pcur_t pcur; - dtuple_t* entry; - dtuple_t* search_tuple; - rec_t* ibuf_rec; - buf_block_t* block; - page_t* bitmap_page; - ibuf_data_t* ibuf_data; - ulint n_inserts; -#ifdef UNIV_IBUF_DEBUG - ulint volume; -#endif - ibool tablespace_being_deleted = FALSE; - ibool corruption_noticed = FALSE; - mtr_t mtr; - - if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - - return; - } - - if (ibuf_fixed_addr_page(space, page_no) || fsp_descr_page(page_no) - || trx_sys_hdr_page(space, page_no)) { - return; - } - - if (update_ibuf_bitmap) { - /* If the following returns FALSE, we get the counter - incremented, and must decrement it when we leave this - function. When the counter is > 0, that prevents tablespace - from being dropped. */ - - tablespace_being_deleted = fil_inc_pending_ibuf_merges(space); - - if (tablespace_being_deleted) { - /* Do not try to read the bitmap page from space; - just delete the ibuf records for the page */ - - page = NULL; - update_ibuf_bitmap = FALSE; - } - } - - if (update_ibuf_bitmap) { - mtr_start(&mtr); - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); - - if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no, - IBUF_BITMAP_BUFFERED, &mtr)) { - /* No inserts buffered for this page */ - mtr_commit(&mtr); - - if (!tablespace_being_deleted) { - fil_decr_pending_ibuf_merges(space); - } - - return; - } - mtr_commit(&mtr); - } - - /* Currently the insert buffer of space 0 takes care of inserts to all - tablespaces */ - - ibuf_data = fil_space_get_ibuf_data(0); - - ibuf_enter(); - - heap = mem_heap_create(512); - - if (!trx_sys_multiple_tablespace_format) { - ut_a(trx_doublewrite_must_reset_space_ids); - search_tuple = ibuf_search_tuple_build(space, page_no, heap); - } else { - search_tuple = ibuf_new_search_tuple_build(space, page_no, - heap); - } - - if (page) { - /* Move the ownership of the x-latch on the page to this OS - thread, so that we can acquire a second x-latch on it. This - is needed for the insert operations to the index page to pass - the debug checks. */ - - block = buf_block_align(page); - rw_lock_x_lock_move_ownership(&(block->lock)); - - if (fil_page_get_type(page) != FIL_PAGE_INDEX) { - - corruption_noticed = TRUE; - - ut_print_timestamp(stderr); - - mtr_start(&mtr); - - fputs(" InnoDB: Dump of the ibuf bitmap page:\n", - stderr); - - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, - &mtr); - buf_page_print(bitmap_page); - - mtr_commit(&mtr); - - fputs("\nInnoDB: Dump of the page:\n", stderr); - - buf_page_print(page); - - fprintf(stderr, - "InnoDB: Error: corruption in the tablespace." - " Bitmap shows insert\n" - "InnoDB: buffer records to page n:o %lu" - " though the page\n" - "InnoDB: type is %lu, which is" - " not an index page!\n" - "InnoDB: We try to resolve the problem" - " by skipping the insert buffer\n" - "InnoDB: merge for this page." - " Please run CHECK TABLE on your tables\n" - "InnoDB: to determine if they are corrupt" - " after this.\n\n" - "InnoDB: Please submit a detailed bug report" - " to http://bugs.mysql.com\n\n", - (ulong) page_no, - (ulong) fil_page_get_type(page)); - } - } - - n_inserts = 0; -#ifdef UNIV_IBUF_DEBUG - volume = 0; -#endif -loop: - mtr_start(&mtr); - - if (page) { - ibool success = buf_page_get_known_nowait(RW_X_LATCH, page, - BUF_KEEP_OLD, - __FILE__, __LINE__, - &mtr); - ut_a(success); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE); -#endif /* UNIV_SYNC_DEBUG */ - } - - /* Position pcur in the insert buffer at the first entry for this - index page */ - btr_pcur_open_on_user_rec(ibuf_data->index, search_tuple, PAGE_CUR_GE, - BTR_MODIFY_LEAF, &pcur, &mtr); - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); - - goto reset_bit; - } - - for (;;) { - ut_ad(btr_pcur_is_on_user_rec(&pcur, &mtr)); - - ibuf_rec = btr_pcur_get_rec(&pcur); - - /* Check if the entry is for this index page */ - if (ibuf_rec_get_page_no(ibuf_rec) != page_no - || ibuf_rec_get_space(ibuf_rec) != space) { - if (page) { - page_header_reset_last_insert(page, &mtr); - } - goto reset_bit; - } - - if (corruption_noticed) { - fputs("InnoDB: Discarding record\n ", stderr); - rec_print_old(stderr, ibuf_rec); - fputs("\n from the insert buffer!\n\n", stderr); - } else if (page) { - /* Now we have at pcur a record which should be - inserted to the index page; NOTE that the call below - copies pointers to fields in ibuf_rec, and we must - keep the latch to the ibuf_rec page until the - insertion is finished! */ - dict_index_t* dummy_index; - dulint max_trx_id = page_get_max_trx_id( - buf_frame_align(ibuf_rec)); - page_update_max_trx_id(page, max_trx_id); - - entry = ibuf_build_entry_from_ibuf_rec( - ibuf_rec, heap, &dummy_index); -#ifdef UNIV_IBUF_DEBUG - volume += rec_get_converted_size(dummy_index, entry) - + page_dir_calc_reserved_space(1); - ut_a(volume <= 4 * UNIV_PAGE_SIZE - / IBUF_PAGE_SIZE_PER_FREE_SPACE); -#endif - ibuf_insert_to_index_page(entry, page, - dummy_index, &mtr); - ibuf_dummy_index_free(dummy_index); - } - - n_inserts++; - - /* Delete the record from ibuf */ - if (ibuf_delete_rec(space, page_no, &pcur, search_tuple, - &mtr)) { - /* Deletion was pessimistic and mtr was committed: - we start from the beginning again */ - - goto loop; - } - - if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) { - mtr_commit(&mtr); - btr_pcur_close(&pcur); - - goto loop; - } - } - -reset_bit: -#ifdef UNIV_IBUF_DEBUG - if (ibuf_count_get(space, page_no) > 0) { - /* btr_print_tree(ibuf_data->index->tree, 100); - ibuf_print(); */ - } -#endif - if (update_ibuf_bitmap) { - bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr); - ibuf_bitmap_page_set_bits(bitmap_page, page_no, - IBUF_BITMAP_BUFFERED, FALSE, &mtr); - if (page) { - ulint old_bits = ibuf_bitmap_page_get_bits( - bitmap_page, page_no, IBUF_BITMAP_FREE, &mtr); - ulint new_bits = ibuf_index_page_calc_free(page); -#if 0 /* defined UNIV_IBUF_DEBUG */ - fprintf(stderr, "Old bits %lu new bits %lu" - " max size %lu\n", - old_bits, new_bits, - page_get_max_insert_size_after_reorganize( - page, 1)); -#endif - if (old_bits != new_bits) { - ibuf_bitmap_page_set_bits(bitmap_page, page_no, - IBUF_BITMAP_FREE, - new_bits, &mtr); - } - } - } -#if 0 /* defined UNIV_IBUF_DEBUG */ - fprintf(stderr, - "Ibuf merge %lu records volume %lu to page no %lu\n", - n_inserts, volume, page_no); -#endif - mtr_commit(&mtr); - btr_pcur_close(&pcur); - mem_heap_free(heap); - - /* Protect our statistics keeping from race conditions */ - mutex_enter(&ibuf_mutex); - - ibuf_data->n_merges++; - ibuf_data->n_merged_recs += n_inserts; - - mutex_exit(&ibuf_mutex); - - if (update_ibuf_bitmap && !tablespace_being_deleted) { - - fil_decr_pending_ibuf_merges(space); - } - - ibuf_exit(); -#ifdef UNIV_IBUF_DEBUG - ut_a(ibuf_count_get(space, page_no) == 0); -#endif -} - -/************************************************************************* -Deletes all entries in the insert buffer for a given space id. This is used -in DISCARD TABLESPACE and IMPORT TABLESPACE. -NOTE: this does not update the page free bitmaps in the space. The space will -become CORRUPT when you call this function! */ - -void -ibuf_delete_for_discarded_space( -/*============================*/ - ulint space) /* in: space id */ -{ - mem_heap_t* heap; - btr_pcur_t pcur; - dtuple_t* search_tuple; - rec_t* ibuf_rec; - ulint page_no; - ibool closed; - ibuf_data_t* ibuf_data; - ulint n_inserts; - mtr_t mtr; - - /* Currently the insert buffer of space 0 takes care of inserts to all - tablespaces */ - - ibuf_data = fil_space_get_ibuf_data(0); - - heap = mem_heap_create(512); - - /* Use page number 0 to build the search tuple so that we get the - cursor positioned at the first entry for this space id */ - - search_tuple = ibuf_new_search_tuple_build(space, 0, heap); - - n_inserts = 0; -loop: - ibuf_enter(); - - mtr_start(&mtr); - - /* Position pcur in the insert buffer at the first entry for the - space */ - btr_pcur_open_on_user_rec(ibuf_data->index, search_tuple, PAGE_CUR_GE, - BTR_MODIFY_LEAF, &pcur, &mtr); - if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { - ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr)); - - goto leave_loop; - } - - for (;;) { - ut_ad(btr_pcur_is_on_user_rec(&pcur, &mtr)); - - ibuf_rec = btr_pcur_get_rec(&pcur); - - /* Check if the entry is for this space */ - if (ibuf_rec_get_space(ibuf_rec) != space) { - - goto leave_loop; - } - - page_no = ibuf_rec_get_page_no(ibuf_rec); - - n_inserts++; - - /* Delete the record from ibuf */ - closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple, - &mtr); - if (closed) { - /* Deletion was pessimistic and mtr was committed: - we start from the beginning again */ - - ibuf_exit(); - - goto loop; - } - - if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) { - mtr_commit(&mtr); - btr_pcur_close(&pcur); - - ibuf_exit(); - - goto loop; - } - } - -leave_loop: - mtr_commit(&mtr); - btr_pcur_close(&pcur); - - /* Protect our statistics keeping from race conditions */ - mutex_enter(&ibuf_mutex); - - ibuf_data->n_merges++; - ibuf_data->n_merged_recs += n_inserts; - - mutex_exit(&ibuf_mutex); - /* - fprintf(stderr, - "InnoDB: Discarded %lu ibuf entries for space %lu\n", - (ulong) n_inserts, (ulong) space); - */ - ibuf_exit(); - - mem_heap_free(heap); -} - - -/********************************************************************** -Validates the ibuf data structures when the caller owns ibuf_mutex. */ - -ibool -ibuf_validate_low(void) -/*===================*/ - /* out: TRUE if ok */ -{ - ibuf_data_t* data; - ulint sum_sizes; - - ut_ad(mutex_own(&ibuf_mutex)); - - sum_sizes = 0; - - data = UT_LIST_GET_FIRST(ibuf->data_list); - - while (data) { - sum_sizes += data->size; - - data = UT_LIST_GET_NEXT(data_list, data); - } - - ut_a(sum_sizes == ibuf->size); - - return(TRUE); -} - -/********************************************************************** -Looks if the insert buffer is empty. */ - -ibool -ibuf_is_empty(void) -/*===============*/ - /* out: TRUE if empty */ -{ - ibuf_data_t* data; - ibool is_empty; - page_t* root; - mtr_t mtr; - - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - - data = UT_LIST_GET_FIRST(ibuf->data_list); - - mtr_start(&mtr); - - root = ibuf_tree_root_get(data, 0, &mtr); - - if (page_get_n_recs(root) == 0) { - - is_empty = TRUE; - - if (data->empty == FALSE) { - fprintf(stderr, - "InnoDB: Warning: insert buffer tree is empty" - " but the data struct does not\n" - "InnoDB: know it. This condition is legal" - " if the master thread has not yet\n" - "InnoDB: run to completion.\n"); - } - } else { - ut_a(data->empty == FALSE); - - is_empty = FALSE; - } - - mtr_commit(&mtr); - - ut_a(data->space == 0); - - mutex_exit(&ibuf_mutex); - - ibuf_exit(); - - return(is_empty); -} - -/********************************************************************** -Prints info of ibuf. */ - -void -ibuf_print( -/*=======*/ - FILE* file) /* in: file where to print */ -{ - ibuf_data_t* data; -#ifdef UNIV_IBUF_DEBUG - ulint i; -#endif - - mutex_enter(&ibuf_mutex); - - data = UT_LIST_GET_FIRST(ibuf->data_list); - - while (data) { - fprintf(file, - "Ibuf: size %lu, free list len %lu, seg size %lu,\n" - "%lu inserts, %lu merged recs, %lu merges\n", - (ulong) data->size, - (ulong) data->free_list_len, - (ulong) data->seg_size, - (ulong) data->n_inserts, - (ulong) data->n_merged_recs, - (ulong) data->n_merges); -#ifdef UNIV_IBUF_DEBUG - for (i = 0; i < IBUF_COUNT_N_PAGES; i++) { - if (ibuf_count_get(data->space, i) > 0) { - - fprintf(stderr, - "Ibuf count for page %lu is %lu\n", - (ulong) i, - (ulong) - ibuf_count_get(data->space, i)); - } - } -#endif - data = UT_LIST_GET_NEXT(data_list, data); - } - - mutex_exit(&ibuf_mutex); -} |