diff options
author | unknown <heikki@hundin.mysql.fi> | 2003-10-07 17:28:59 +0300 |
---|---|---|
committer | unknown <heikki@hundin.mysql.fi> | 2003-10-07 17:28:59 +0300 |
commit | d1485aad0eb79559902b1af26502b7cc53f8e95a (patch) | |
tree | d53a5cc4e9736e149276ba08d53a7dd09a14b4fd /innobase/fsp | |
parent | d1ab51eb947623f45a8314cb9c0b6ddc15f0d148 (diff) | |
download | mariadb-git-d1485aad0eb79559902b1af26502b7cc53f8e95a.tar.gz |
Many files:
Multiple tablespaces for InnoDB
sql_table.cc:
Tell explicitly that InnoDB should retrieve all columns in CHECKSUM TABLE
sql_update.cc, sql_select.cc, my_base.h:
More descriptive flag name HA_EXTRA_RETRIEVE_ALL_COLS
include/my_base.h:
More descriptive flag name HA_EXTRA_RETRIEVE_ALL_COLS
sql/sql_select.cc:
More descriptive flag name HA_EXTRA_RETRIEVE_ALL_COLS
sql/sql_update.cc:
More descriptive flag name HA_EXTRA_RETRIEVE_ALL_COLS
sql/sql_table.cc:
Tell explicitly that InnoDB should retrieve all columns in CHECKSUM TABLE
sql/sql_db.cc:
Multiple tablespaces for InnoDB
sql/ha_innodb.cc:
Multiple tablespaces for InnoDB
sql/mysqld.cc:
Multiple tablespaces for InnoDB
sql/set_var.cc:
Multiple tablespaces for InnoDB
sql/sql_cache.cc:
Multiple tablespaces for InnoDB
sql/ha_innodb.h:
Multiple tablespaces for InnoDB
innobase/include/btr0btr.ic:
Multiple tablespaces for InnoDB
innobase/include/btr0pcur.ic:
Multiple tablespaces for InnoDB
innobase/include/data0type.ic:
Multiple tablespaces for InnoDB
innobase/include/dyn0dyn.ic:
Multiple tablespaces for InnoDB
innobase/include/fut0lst.ic:
Multiple tablespaces for InnoDB
innobase/include/log0log.ic:
Multiple tablespaces for InnoDB
innobase/include/mach0data.ic:
Multiple tablespaces for InnoDB
innobase/include/mtr0log.ic:
Multiple tablespaces for InnoDB
innobase/include/rem0rec.ic:
Multiple tablespaces for InnoDB
innobase/include/ut0byte.ic:
Multiple tablespaces for InnoDB
innobase/include/ut0ut.ic:
Multiple tablespaces for InnoDB
innobase/include/buf0buf.h:
Multiple tablespaces for InnoDB
innobase/include/buf0lru.h:
Multiple tablespaces for InnoDB
innobase/include/buf0rea.h:
Multiple tablespaces for InnoDB
innobase/include/data0type.h:
Multiple tablespaces for InnoDB
innobase/include/db0err.h:
Multiple tablespaces for InnoDB
innobase/include/dict0boot.h:
Multiple tablespaces for InnoDB
innobase/include/dict0dict.h:
Multiple tablespaces for InnoDB
innobase/include/dict0load.h:
Multiple tablespaces for InnoDB
innobase/include/dict0mem.h:
Multiple tablespaces for InnoDB
innobase/include/fil0fil.h:
Multiple tablespaces for InnoDB
innobase/include/fsp0fsp.h:
Multiple tablespaces for InnoDB
innobase/include/ibuf0ibuf.h:
Multiple tablespaces for InnoDB
innobase/include/lock0lock.h:
Multiple tablespaces for InnoDB
innobase/include/log0log.h:
Multiple tablespaces for InnoDB
innobase/include/log0recv.h:
Multiple tablespaces for InnoDB
innobase/include/os0file.h:
Multiple tablespaces for InnoDB
innobase/include/page0page.h:
Multiple tablespaces for InnoDB
innobase/include/que0types.h:
Multiple tablespaces for InnoDB
innobase/include/rem0rec.h:
Multiple tablespaces for InnoDB
innobase/include/srv0srv.h:
Multiple tablespaces for InnoDB
innobase/include/srv0start.h:
Multiple tablespaces for InnoDB
innobase/include/sync0sync.h:
Multiple tablespaces for InnoDB
innobase/include/trx0sys.h:
Multiple tablespaces for InnoDB
innobase/include/ut0byte.h:
Multiple tablespaces for InnoDB
innobase/include/univ.i:
Multiple tablespaces for InnoDB
innobase/btr/btr0cur.c:
Multiple tablespaces for InnoDB
innobase/btr/btr0sea.c:
Multiple tablespaces for InnoDB
innobase/buf/buf0buf.c:
Multiple tablespaces for InnoDB
innobase/buf/buf0flu.c:
Multiple tablespaces for InnoDB
innobase/buf/buf0lru.c:
Multiple tablespaces for InnoDB
innobase/buf/buf0rea.c:
Multiple tablespaces for InnoDB
innobase/data/data0type.c:
Multiple tablespaces for InnoDB
innobase/dict/dict0boot.c:
Multiple tablespaces for InnoDB
innobase/dict/dict0crea.c:
Multiple tablespaces for InnoDB
innobase/dict/dict0dict.c:
Multiple tablespaces for InnoDB
innobase/dict/dict0load.c:
Multiple tablespaces for InnoDB
innobase/dict/dict0mem.c:
Multiple tablespaces for InnoDB
innobase/fil/fil0fil.c:
Multiple tablespaces for InnoDB
innobase/fsp/fsp0fsp.c:
Multiple tablespaces for InnoDB
innobase/ha/ha0ha.c:
Multiple tablespaces for InnoDB
innobase/ibuf/ibuf0ibuf.c:
Multiple tablespaces for InnoDB
innobase/log/log0log.c:
Multiple tablespaces for InnoDB
innobase/log/log0recv.c:
Multiple tablespaces for InnoDB
innobase/mach/mach0data.c:
Multiple tablespaces for InnoDB
innobase/mem/mem0dbg.c:
Multiple tablespaces for InnoDB
innobase/mem/mem0pool.c:
Multiple tablespaces for InnoDB
innobase/mtr/mtr0log.c:
Multiple tablespaces for InnoDB
innobase/os/os0file.c:
Multiple tablespaces for InnoDB
innobase/os/os0proc.c:
Multiple tablespaces for InnoDB
innobase/page/page0cur.c:
Multiple tablespaces for InnoDB
innobase/que/que0que.c:
Multiple tablespaces for InnoDB
innobase/row/row0ins.c:
Multiple tablespaces for InnoDB
innobase/row/row0mysql.c:
Multiple tablespaces for InnoDB
innobase/row/row0sel.c:
Multiple tablespaces for InnoDB
innobase/row/row0upd.c:
Multiple tablespaces for InnoDB
innobase/srv/srv0srv.c:
Multiple tablespaces for InnoDB
innobase/srv/srv0start.c:
Multiple tablespaces for InnoDB
innobase/sync/sync0rw.c:
Multiple tablespaces for InnoDB
innobase/sync/sync0sync.c:
Multiple tablespaces for InnoDB
innobase/trx/trx0sys.c:
Multiple tablespaces for InnoDB
innobase/trx/trx0trx.c:
Multiple tablespaces for InnoDB
innobase/trx/trx0undo.c:
Multiple tablespaces for InnoDB
innobase/ut/ut0byte.c:
Multiple tablespaces for InnoDB
innobase/ut/ut0ut.c:
Multiple tablespaces for InnoDB
Diffstat (limited to 'innobase/fsp')
-rw-r--r-- | innobase/fsp/fsp0fsp.c | 455 |
1 files changed, 333 insertions, 122 deletions
diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 8727c5156e4..7c4d691ea13 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -41,7 +41,8 @@ descriptor page, but used only in the first. */ #define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header within a file page */ /*-------------------------------------*/ -#define FSP_NOT_USED 0 /* this field contained a value up to +#define FSP_SPACE_ID 0 /* space id */ +#define FSP_NOT_USED 4 /* this field contained a value up to which we know that the modifications in the database have been flushed to the file space; not used now */ @@ -50,7 +51,13 @@ descriptor page, but used only in the first. */ #define FSP_FREE_LIMIT 12 /* Minimum page number for which the free list has not been initialized: the pages >= this limit are, by - definition, free */ + definition, free; note that in a + single-table tablespace where size + < 64 pages, this number is 64, i.e., + we have initialized the space + about the first extent, but have not + physically allocted those pages to the + file */ #define FSP_LOWEST_NO_WRITE 16 /* The lowest page offset for which the page has not been written to disk (if it has been written, we know that @@ -263,9 +270,14 @@ static void fsp_fill_free_list( /*===============*/ - ulint space, /* in: space */ - fsp_header_t* header, /* in: space header */ - mtr_t* mtr); /* in: mtr */ + ibool init_space, /* in: TRUE if this is a single-table + tablespace and we are only initing + the tablespace's first extent + descriptor page and ibuf bitmap page; + then we do not allocate more extents */ + ulint space, /* in: space */ + fsp_header_t* header, /* in: space header */ + mtr_t* mtr); /* in: mtr */ /************************************************************************** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -569,7 +581,7 @@ xdes_init( ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0); for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) { - mlog_write_ulint(descr + i, 0xFFFFFFFF, MLOG_4BYTES, mtr); + mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr); } xdes_set_state(descr, XDES_FREE, mtr); @@ -630,8 +642,8 @@ xdes_get_descriptor_with_space_hdr( page_t* descr_page; ut_ad(mtr); - ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK)); - + ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), + MTR_MEMO_X_LOCK)); /* Read free limit and space size */ limit = mtr_read_ulint(sp_header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr); size = mtr_read_ulint(sp_header + FSP_SIZE, MLOG_4BYTES, mtr); @@ -646,7 +658,7 @@ xdes_get_descriptor_with_space_hdr( /* If offset is == limit, fill free list of the space. */ if (offset == limit) { - fsp_fill_free_list(space, sp_header, mtr); + fsp_fill_free_list(FALSE, space, sp_header, mtr); } descr_page_no = xdes_calc_descriptor_page(offset); @@ -711,8 +723,8 @@ xdes_lst_get_descriptor( xdes_t* descr; ut_ad(mtr); - ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK)); - + ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), + MTR_MEMO_X_LOCK)); descr = fut_get_ptr(space, lst_node, RW_X_LATCH, mtr) - XDES_FLST_NODE; return(descr); @@ -775,7 +787,7 @@ fsp_init_file_page_low( /* printf("In log debug version: Erase the contents of the file page\n"); */ for (i = 0; i < UNIV_PAGE_SIZE; i++) { - page[i] = 0xFF; + page[i] = (byte)0xFF; } #endif mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, @@ -828,8 +840,21 @@ fsp_init(void) } /************************************************************************** +Writes the space id to a tablespace header. This function is used past the +buffer pool when we in fil0fil.c create a new single-table tablespace. */ + +void +fsp_header_write_space_id( +/*======================*/ + page_t* page, /* in: first page in the space */ + ulint space_id) /* in: space id */ +{ + mach_write_to_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID, space_id); +} + +/************************************************************************** Initializes the space header of a new created space and creates also the -insert buffer tree root. */ +insert buffer tree root if space == 0. */ void fsp_header_init( @@ -846,8 +871,7 @@ fsp_header_init( mtr_x_lock(fil_space_get_latch(space), mtr); page = buf_page_create(space, 0, mtr); - buf_page_dbg_add_level(page, SYNC_FSP_PAGE); - + buf_page_get(space, 0, RW_X_LATCH, mtr); buf_page_dbg_add_level(page, SYNC_FSP_PAGE); @@ -857,6 +881,8 @@ fsp_header_init( header = FSP_HEADER_OFFSET + page; + mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr); + mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr); mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr); mlog_write_ulint(header + FSP_LOWEST_NO_WRITE, 0, MLOG_4BYTES, mtr); @@ -870,10 +896,39 @@ fsp_header_init( mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), MLOG_8BYTES, mtr); - fsp_fill_free_list(space, header, mtr); - - btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space, + if (space == 0) { + fsp_fill_free_list(FALSE, space, header, mtr); + btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space, ut_dulint_add(DICT_IBUF_ID_MIN, space), mtr); + } else { + fsp_fill_free_list(TRUE, space, header, mtr); + } +} + +/************************************************************************** +Reads the space id from the first page of a tablespace. */ + +ulint +fsp_header_get_space_id( +/*====================*/ + /* out: space id, ULINT UNDEFINED if error */ + page_t* page) /* in: first page of a tablespace */ +{ + ulint fsp_id; + ulint id; + + fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID); + + id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + + if (id != fsp_id) { + fprintf(stderr, +"InnoDB: Error: space id in fsp header %lu, but in the page header %lu\n", + fsp_id, id); + return(ULINT_UNDEFINED); + } + + return(id); } /************************************************************************** @@ -897,7 +952,8 @@ fsp_header_inc_size( size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); - mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES, mtr); + mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES, + mtr); } /************************************************************************** @@ -910,7 +966,7 @@ ulint fsp_header_get_free_limit( /*======================*/ /* out: free limit in megabytes */ - ulint space) /* in: space id */ + ulint space) /* in: space id, must be 0 */ { fsp_header_t* header; ulint limit; @@ -944,7 +1000,7 @@ ulint fsp_header_get_tablespace_size( /*===========================*/ /* out: size in pages */ - ulint space) /* in: space id */ + ulint space) /* in: space id, must be 0 */ { fsp_header_t* header; ulint size; @@ -966,10 +1022,42 @@ fsp_header_get_tablespace_size( } /*************************************************************************** -Tries to extend the last data file file if it is defined as auto-extending. */ +Tries to extend a single-table tablespace so that a page would fit in the +data file. */ +static +ibool +fsp_try_extend_data_file_with_pages( +/*================================*/ + /* out: TRUE if success */ + ulint space, /* in: space */ + ulint page_no, /* in: page number */ + fsp_header_t* header, /* in: space header */ + mtr_t* mtr) /* in: mtr */ +{ + ulint size; + ibool success; + + ut_a(space != 0); + + size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); + + ut_a(page_no >= size); + + success = fil_extend_data_file_with_pages(space, size, page_no + 1); + + if (success) { + mlog_write_ulint(header + FSP_SIZE, page_no + 1, MLOG_4BYTES, + mtr); + } + + return(success); +} + +/*************************************************************************** +Tries to extend the last data file of a tablespace if it is auto-extending. */ static ibool -fsp_try_extend_last_file( +fsp_try_extend_data_file( /*=====================*/ /* out: FALSE if not auto-extending */ ulint* actual_increase,/* out: actual increase in pages */ @@ -981,18 +1069,16 @@ fsp_try_extend_last_file( ulint size_increase; ibool success; - ut_a(space == 0); - *actual_increase = 0; - if (!srv_auto_extend_last_data_file) { + if (space == 0 && !srv_auto_extend_last_data_file) { return(FALSE); } size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); - if (srv_last_file_size_max != 0) { + if (space == 0 && srv_last_file_size_max != 0) { if (srv_last_file_size_max < srv_data_file_sizes[srv_n_data_files - 1]) { @@ -1008,20 +1094,48 @@ fsp_try_extend_last_file( size_increase = SRV_AUTO_EXTEND_INCREMENT; } } else { - size_increase = SRV_AUTO_EXTEND_INCREMENT; + if (space == 0) { + size_increase = SRV_AUTO_EXTEND_INCREMENT; + } else { + /* We extend single-table tablespaces first one extent + at a time, but for bigger tablespaces more. It is not + enough to extend always by one extent, because some + extents are frag page extents. */ + + if (size < FSP_EXTENT_SIZE) { + /* Let us first extend the file to 64 pages */ + success = fsp_try_extend_data_file_with_pages( + space, FSP_EXTENT_SIZE - 1, + header, mtr); + + if (!success) { + return(FALSE); + } + + size = FSP_EXTENT_SIZE; + } + + if (size < 32 * FSP_EXTENT_SIZE) { + size_increase = FSP_EXTENT_SIZE; + } else { + size_increase = 8 * FSP_EXTENT_SIZE; + } + } } if (size_increase == 0) { + return(TRUE); } - /* Extend the data file. If we are not able to extend - the full requested length, the function tells us - the number of full megabytes (but the unit is pages!) - we were able to extend. */ - - success = fil_extend_last_data_file(actual_increase, size_increase); - + /* Extend the data file. If we are not able to extend the full + requested length, the function tells how many pages we were able to + extend so that the size of the tablespace would be divisible by 1 MB + (we possibly managed to extend more, but we only take into account + full megabytes). */ + + success = fil_extend_last_data_file(actual_increase, space, size, + size_increase); if (success) { mlog_write_ulint(header + FSP_SIZE, size + *actual_increase, MLOG_4BYTES, mtr); @@ -1038,9 +1152,14 @@ static void fsp_fill_free_list( /*===============*/ - ulint space, /* in: space */ - fsp_header_t* header, /* in: space header */ - mtr_t* mtr) /* in: mtr */ + ibool init_space, /* in: TRUE if this is a single-table + tablespace and we are only initing + the tablespace's first extent + descriptor page and ibuf bitmap page; + then we do not allocate more extents */ + ulint space, /* in: space */ + fsp_header_t* header, /* in: space header */ + mtr_t* mtr) /* in: mtr */ { ulint limit; ulint size; @@ -1059,27 +1178,35 @@ fsp_fill_free_list( size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr); - if (srv_auto_extend_last_data_file + if (space == 0 && srv_auto_extend_last_data_file && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) { /* Try to increase the last data file size */ - fsp_try_extend_last_file(&actual_increase, space, header, - mtr); + fsp_try_extend_data_file(&actual_increase, space, header, mtr); + size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); + } + + if (space != 0 && !init_space) { + /* Try to increase the data file size */ + fsp_try_extend_data_file(&actual_increase, space, header, mtr); size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); } i = limit; - while ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD)) { + while ((init_space && i < 1) + || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) { mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE, MLOG_4BYTES, mtr); /* Update the free limit info in the log system and make a checkpoint */ - log_fsp_current_free_limit_set_and_checkpoint( + if (space == 0) { + log_fsp_current_free_limit_set_and_checkpoint( (i + FSP_EXTENT_SIZE) / ((1024 * 1024) / UNIV_PAGE_SIZE)); + } if (0 == i % XDES_DESCRIBED_PER_PAGE) { @@ -1089,8 +1216,6 @@ fsp_fill_free_list( if (i > 0) { descr_page = buf_page_create(space, i, mtr); - buf_page_dbg_add_level(descr_page, - SYNC_FSP_PAGE); buf_page_get(space, i, RW_X_LATCH, mtr); buf_page_dbg_add_level(descr_page, SYNC_FSP_PAGE); @@ -1106,7 +1231,6 @@ fsp_fill_free_list( ibuf_page = buf_page_create(space, i + FSP_IBUF_BITMAP_OFFSET, &ibuf_mtr); - buf_page_dbg_add_level(ibuf_page, SYNC_IBUF_BITMAP); buf_page_get(space, i + FSP_IBUF_BITMAP_OFFSET, RW_X_LATCH, &ibuf_mtr); @@ -1183,7 +1307,7 @@ fsp_alloc_free_extent( first = flst_get_first(header + FSP_FREE, mtr); if (fil_addr_is_null(first)) { - fsp_fill_free_list(space, header, mtr); + fsp_fill_free_list(FALSE, space, header, mtr); first = flst_get_first(header + FSP_FREE, mtr); } @@ -1220,6 +1344,8 @@ fsp_alloc_free_page( ulint free; ulint frag_n_used; ulint page_no; + ulint space_size; + ibool success; ut_ad(mtr); @@ -1273,6 +1399,30 @@ fsp_alloc_free_page( ut_a(0); } + page_no = xdes_get_offset(descr) + free; + + space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); + + if (space_size <= page_no) { + /* It must be that we are extending a single-table tablespace + whose size is still < 64 pages */ + + ut_a(space != 0); + if (page_no >= FSP_EXTENT_SIZE) { + fprintf(stderr, +"InnoDB: Error: trying to extend a single-table tablespace %lu\n" +"InnoDB: by single page(s) though the space size %lu. Page no %lu.\n", + space, space_size, page_no); + return(FIL_NULL); + } + success = fsp_try_extend_data_file_with_pages(space, page_no, + header, mtr); + if (!success) { + /* No disk space left */ + return(FIL_NULL); + } + } + xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); /* Update the FRAG_N_USED field */ @@ -1294,8 +1444,6 @@ fsp_alloc_free_page( mtr); } - page_no = xdes_get_offset(descr) + free; - /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ @@ -1594,8 +1742,8 @@ fsp_alloc_seg_inode( inode = fsp_seg_inode_page_get_nth_inode(page, n, mtr); - if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1, mtr)) { - + if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1, + mtr)) { /* There are no other unused headers left on the page: move it to another list */ @@ -1813,12 +1961,12 @@ fseg_create_general( will belong to the created segment */ ulint byte_offset, /* in: byte offset of the created segment header on the page */ - ibool has_done_reservation, /* in: TRUE if the caller has - already done the reservation for the pages - with fsp_reserve_free_extents (at least 2 extents: - one for the inode and, then there other for the - segment) is no need to do the check for this - individual operation */ + ibool has_done_reservation, /* in: TRUE if the caller has already + done the reservation for the pages with + fsp_reserve_free_extents (at least 2 extents: one for + the inode and the other for the segment) then there is + no need to do the check for this individual + operation */ mtr_t* mtr) /* in: mtr */ { fsp_header_t* space_header; @@ -1827,6 +1975,7 @@ fseg_create_general( fseg_header_t* header = 0; /* remove warning */ rw_lock_t* latch; ibool success; + ulint n_reserved; page_t* ret = NULL; ulint i; @@ -1848,12 +1997,14 @@ fseg_create_general( /* This thread did not own the latch before this call: free excess pages from the insert buffer free list */ - ibuf_free_excess_pages(space); + if (space == 0) { + ibuf_free_excess_pages(space); + } } if (!has_done_reservation) { - success = fsp_reserve_free_extents(space, 2, FSP_NORMAL, mtr); - + success = fsp_reserve_free_extents(&n_reserved, space, 2, + FSP_NORMAL, mtr); if (!success) { return(NULL); } @@ -1916,7 +2067,7 @@ fseg_create_general( funct_exit: if (!has_done_reservation) { - fil_space_release_free_extents(space, 2); + fil_space_release_free_extents(space, n_reserved); } return(ret); @@ -2132,6 +2283,8 @@ fseg_alloc_free_page_low( FSP_UP, FSP_NO_DIR */ mtr_t* mtr) /* in: mtr handle */ { + fsp_header_t* space_header; + ulint space_size; dulint seg_id; ulint used; ulint reserved; @@ -2142,6 +2295,7 @@ fseg_alloc_free_page_low( xdes_t* ret_descr; /* the extent of the allocated page */ page_t* page; ibool frag_page_allocated = FALSE; + ibool success; ulint n; ut_ad(mtr); @@ -2154,8 +2308,10 @@ fseg_alloc_free_page_low( reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr); - descr = xdes_get_descriptor(space, hint, mtr); + space_header = fsp_get_space_header(space, mtr); + descr = xdes_get_descriptor_with_space_hdr(space_header, space, + hint, mtr); if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ @@ -2288,8 +2444,31 @@ fseg_alloc_free_page_low( return(FIL_NULL); } - if (!frag_page_allocated) { + if (space != 0) { + space_size = fil_space_get_size(space); + + if (space_size <= ret_page) { + /* It must be that we are extending a single-table + tablespace whose size is still < 64 pages */ + if (ret_page >= FSP_EXTENT_SIZE) { + fprintf(stderr, +"InnoDB: Error (2): trying to extend a single-table tablespace %lu\n" +"InnoDB: by single page(s) though the space size %lu. Page no %lu.\n", + space, space_size, ret_page); + return(FIL_NULL); + } + + success = fsp_try_extend_data_file_with_pages(space, + ret_page, space_header, mtr); + if (!success) { + /* No disk space left */ + return(FIL_NULL); + } + } + } + + if (!frag_page_allocated) { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ @@ -2348,6 +2527,7 @@ fseg_alloc_free_page_general( rw_lock_t* latch; ibool success; ulint page_no; + ulint n_reserved; space = buf_frame_get_space_id(seg_header); @@ -2362,14 +2542,16 @@ fseg_alloc_free_page_general( /* This thread did not own the latch before this call: free excess pages from the insert buffer free list */ - ibuf_free_excess_pages(space); + if (space == 0) { + ibuf_free_excess_pages(space); + } } inode = fseg_inode_get(seg_header, mtr); if (!has_done_reservation) { - success = fsp_reserve_free_extents(space, 2, FSP_NORMAL, mtr); - + success = fsp_reserve_free_extents(&n_reserved, space, 2, + FSP_NORMAL, mtr); if (!success) { return(FIL_NULL); } @@ -2378,7 +2560,7 @@ fseg_alloc_free_page_general( page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode), inode, hint, direction, mtr); if (!has_done_reservation) { - fil_space_release_free_extents(space, 2); + fil_space_release_free_extents(space, n_reserved); } return(page_no); @@ -2408,6 +2590,46 @@ fseg_alloc_free_page( } /************************************************************************** +Checks that we have at least 2 frag pages free in the first extent of a +single-table tablespace, and they are also physically initialized to the data +file. That is we have already extended the data file so that those pages are +inside the data file. If not, this function extends the tablespace with +pages. */ +static +ibool +fsp_reserve_free_pages( +/*===================*/ + /* out: TRUE if there were >= 3 free + pages, or we were able to extend */ + ulint space, /* in: space id, must be != 0 */ + fsp_header_t* space_header, /* in: header of that space, + x-latched */ + ulint size, /* in: size of the tablespace in pages, + must be < FSP_EXTENT_SIZE / 2 */ + mtr_t* mtr) /* in: mtr */ +{ + xdes_t* descr; + ulint n_used; + + ut_a(space != 0); + ut_a(size < FSP_EXTENT_SIZE / 2); + + descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0, + mtr); + n_used = xdes_get_n_used(descr, mtr); + + ut_a(n_used <= size); + + if (size >= n_used + 2) { + + return(TRUE); + } + + return(fsp_try_extend_data_file_with_pages(space, n_used + 1, + space_header, mtr)); +} + +/************************************************************************** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand and reserve enough free extents so that they certainly will be able @@ -2425,12 +2647,21 @@ two types of allocation: when space is scarce, FSP_NORMAL allocations will not succeed, but the latter two allocations will succeed, if possible. The purpose is to avoid dead end where the database is full but the user cannot free any space because these freeing operations temporarily -reserve some space. */ +reserve some space. + +Single-table tablespaces whose size is < 32 pages are a special case. In this +function we would liberally reserve several 64 page extents for every page +split or merge in a B-tree. But we do not want to waste disk space if the table +only occupies < 32 pages. That is why we apply different rules in that special +case, just ensuring that there are 3 free pages available. */ ibool fsp_reserve_free_extents( /*=====================*/ /* out: TRUE if we were able to make the reservation */ + ulint* n_reserved,/* out: number of extents actually reserved; if we + return TRUE and the tablespace size is < 64 pages, + then this can be 0, otherwise it is n_ext */ ulint space, /* in: space id */ ulint n_ext, /* in: number of extents to reserve */ ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */ @@ -2451,6 +2682,8 @@ fsp_reserve_free_extents( ut_ad(!mutex_own(&kernel_mutex) || mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK)); + *n_reserved = n_ext; + latch = fil_space_get_latch(space); mtr_x_lock(latch, mtr); @@ -2459,6 +2692,12 @@ fsp_reserve_free_extents( try_again: size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr); + if (size < FSP_EXTENT_SIZE / 2) { + /* Use different rules for small single-table tablespaces */ + *n_reserved = 0; + return(fsp_reserve_free_pages(space, space_header, size, mtr)); + } + n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr); free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT, @@ -2508,7 +2747,7 @@ try_again: return(TRUE); } try_to_extend: - success = fsp_try_extend_last_file(&n_pages_added, space, + success = fsp_try_extend_data_file(&n_pages_added, space, space_header, mtr); if (success && n_pages_added > 0) { @@ -2558,6 +2797,13 @@ fsp_get_available_space_in_free_extents( MLOG_4BYTES, &mtr); mtr_commit(&mtr); + if (size < FSP_EXTENT_SIZE) { + ut_a(space != 0); /* This must be a single-table + tablespace */ + return(0); /* TODO: count free frag pages and return + a value based on that */ + } + /* Below we play safe when counting free extents above the free limit: some of them will contain extent descriptor pages, and therefore will not be free extents */ @@ -2655,14 +2901,10 @@ fseg_free_page_low( xdes_t* descr; ulint not_full_n_used; ulint state; + dulint descr_id; + dulint seg_id; ulint i; - char errbuf[200]; - -#ifdef __WIN__ - dulint desm; - dulint segm; -#endif - + char errbuf[200]; ut_ad(seg_inode && mtr); ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == @@ -2715,26 +2957,22 @@ fseg_free_page_low( return; } + /* If we get here, the page is in some extent of the segment */ + + descr_id = mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr); + seg_id = mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr); /* fprintf(stderr, "InnoDB: InnoDB is freeing space %lu page %lu,\n" "InnoDB: which belongs to descr seg %lu %lu\n" "InnoDB: segment %lu %lu.\n", space, page, - ut_dulint_get_high( - mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_low( - mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_high( - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_low( - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))); + ut_dulint_get_high(descr_id), + ut_dulint_get_low(descr_id), + ut_dulint_get_high(seg_id), + ut_dulint_get_low(seg_id)); */ - /* If we get here, the page is in some extent of the segment */ - if (0 != ut_dulint_cmp( - mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr), - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))) { - + if (0 != ut_dulint_cmp(descr_id, seg_id)) { ut_sprintf_buf(errbuf, descr, 40); fprintf(stderr, "InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); @@ -2742,42 +2980,15 @@ fseg_free_page_low( fprintf(stderr, "InnoDB: Dump of the segment inode: %s\n", errbuf); - -#ifndef __WIN__ - - fprintf(stderr, + fprintf(stderr, "InnoDB: Serious error: InnoDB is trying to free space %lu page %lu,\n" "InnoDB: which does not belong to segment %lu %lu but belongs\n" "InnoDB: to segment %lu %lu.\n", space, page, - ut_dulint_get_high( - mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_low( - mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_high( - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr)), - ut_dulint_get_low( - mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr))); - -#else - -/* More pedantic usage to avoid VC++ 6.0 compiler errors due to inline - function expansion issues */ - - desm = mtr_read_dulint(descr + XDES_ID, MLOG_8BYTES, mtr); - segm = mtr_read_dulint(seg_inode + FSEG_ID, MLOG_8BYTES, mtr); - - fprintf(stderr, -"InnoDB: Serious error: InnoDB is trying to free space %lu page %lu,\n" -"InnoDB: which does not belong to segment %lu %lu but belongs\n" -"InnoDB: to segment %lu %lu.\n", - space, page, - ut_dulint_get_high(desm), - ut_dulint_get_low(desm), - ut_dulint_get_high(segm), - ut_dulint_get_low(segm)); - -#endif + ut_dulint_get_high(descr_id), + ut_dulint_get_low(descr_id), + ut_dulint_get_high(seg_id), + ut_dulint_get_low(seg_id)); fprintf(stderr, "InnoDB: If the InnoDB recovery crashes here, see section 6.1\n" @@ -3369,7 +3580,7 @@ fsp_validate( n_full_frag_pages = FSP_EXTENT_SIZE * flst_get_len(header + FSP_FULL_FRAG, &mtr); - ut_a(free_limit <= size); + ut_a(free_limit <= size || (space != 0 && size < FSP_EXTENT_SIZE)); flst_validate(header + FSP_FREE, &mtr); flst_validate(header + FSP_FREE_FRAG, &mtr); |