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
This commit is contained in:
unknown 2003-10-07 17:28:59 +03:00
parent d1ab51eb94
commit d1485aad0e
85 changed files with 6568 additions and 1927 deletions

View File

@ -121,7 +121,10 @@ enum ha_extra_function {
HA_EXTRA_RESET_STATE, /* Reset positions */
HA_EXTRA_IGNORE_DUP_KEY, /* Dup keys don't rollback everything*/
HA_EXTRA_NO_IGNORE_DUP_KEY,
HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE, /* Cursor will not be used for update */
HA_EXTRA_RETRIEVE_ALL_COLS, /* Instructs InnoDB to retrieve all
columns, not just those where
field->query_id is the same as the
current query id */
HA_EXTRA_PREPARE_FOR_DELETE,
HA_EXTRA_PREPARE_FOR_UPDATE, /* Remove read cache if problems */
HA_EXTRA_PRELOAD_BUFFER_SIZE /* Set buffer size for preloading */

View File

@ -957,7 +957,7 @@ calculate_sizes_again:
/* Now, try the insert */
*rec = page_cur_insert_rec_low(page_cursor, entry, data_size,
NULL, mtr);
NULL, mtr);
if (!(*rec)) {
/* If the record did not fit, reorganize */
btr_page_reorganize(page, mtr);
@ -1048,6 +1048,7 @@ btr_cur_pessimistic_insert(
ibool dummy_inh;
ibool success;
ulint n_extents = 0;
ulint n_reserved;
ut_ad(dtuple_check_typed(entry));
@ -1067,7 +1068,7 @@ btr_cur_pessimistic_insert(
cursor->flag = BTR_CUR_BINARY;
err = btr_cur_optimistic_insert(flags, cursor, entry, rec, big_rec,
thr, mtr);
thr, mtr);
if (err != DB_FAIL) {
return(err);
@ -1090,7 +1091,7 @@ btr_cur_pessimistic_insert(
n_extents = cursor->tree_height / 16 + 3;
success = fsp_reserve_free_extents(index->space,
success = fsp_reserve_free_extents(&n_reserved, index->space,
n_extents, FSP_NORMAL, mtr);
if (!success) {
err = DB_OUT_OF_FILE_SPACE;
@ -1112,7 +1113,7 @@ btr_cur_pessimistic_insert(
if (n_extents > 0) {
fil_space_release_free_extents(index->space,
n_extents);
n_reserved);
}
return(DB_TOO_BIG_RECORD);
}
@ -1140,7 +1141,7 @@ btr_cur_pessimistic_insert(
err = DB_SUCCESS;
if (n_extents > 0) {
fil_space_release_free_extents(index->space, n_extents);
fil_space_release_free_extents(index->space, n_reserved);
}
*big_rec = big_rec_vec;
@ -1721,6 +1722,7 @@ btr_cur_pessimistic_update(
ibool was_first;
ibool success;
ulint n_extents = 0;
ulint n_reserved;
ulint* ext_vect;
ulint n_ext_vect;
ulint reserve_flag;
@ -1767,7 +1769,8 @@ btr_cur_pessimistic_update(
reserve_flag = FSP_NORMAL;
}
success = fsp_reserve_free_extents(cursor->index->space,
success = fsp_reserve_free_extents(&n_reserved,
cursor->index->space,
n_extents, reserve_flag, mtr);
if (!success) {
err = DB_OUT_OF_FILE_SPACE;
@ -1916,7 +1919,7 @@ return_after_reservations:
if (n_extents > 0) {
fil_space_release_free_extents(cursor->index->space,
n_extents);
n_reserved);
}
*big_rec = big_rec_vec;
@ -2387,6 +2390,7 @@ btr_cur_pessimistic_delete(
rec_t* rec;
dtuple_t* node_ptr;
ulint n_extents = 0;
ulint n_reserved;
ibool success;
ibool ret = FALSE;
mem_heap_t* heap;
@ -2405,7 +2409,8 @@ btr_cur_pessimistic_delete(
n_extents = cursor->tree_height / 32 + 1;
success = fsp_reserve_free_extents(cursor->index->space,
success = fsp_reserve_free_extents(&n_reserved,
cursor->index->space,
n_extents, FSP_CLEANING, mtr);
if (!success) {
*err = DB_OUT_OF_FILE_SPACE;
@ -2484,7 +2489,8 @@ return_after_reservations:
}
if (n_extents > 0) {
fil_space_release_free_extents(cursor->index->space, n_extents);
fil_space_release_free_extents(cursor->index->space,
n_reserved);
}
return(ret);
@ -3156,7 +3162,7 @@ btr_store_big_rec_extern_fields(
ut_ad(mtr_memo_contains(local_mtr, dict_tree_get_lock(index->tree),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(local_mtr, buf_block_align(rec),
MTR_MEMO_PAGE_X_FIX));
MTR_MEMO_PAGE_X_FIX));
ut_a(index->type & DICT_CLUSTERED);
space_id = buf_frame_get_space_id(rec);
@ -3322,7 +3328,7 @@ btr_free_externally_stored_field(
ut_ad(mtr_memo_contains(local_mtr, dict_tree_get_lock(index->tree),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(local_mtr, buf_block_align(data),
MTR_MEMO_PAGE_X_FIX));
MTR_MEMO_PAGE_X_FIX));
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;

View File

@ -1022,12 +1022,14 @@ btr_search_drop_page_hash_when_freed(
mtr_start(&mtr);
/* We assume that if the caller has a latch on the page,
then the caller has already dropped the hash index for the page,
and we never get here. Therefore we can acquire the s-latch to
the page without fearing a deadlock. */
/* We assume that if the caller has a latch on the page, then the
caller has already dropped the hash index for the page, and we never
get here. Therefore we can acquire the s-latch to the page without
having to fear a deadlock. */
page = buf_page_get(space, page_no, RW_S_LATCH, &mtr);
page = buf_page_get_gen(space, page_no, RW_S_LATCH, NULL,
BUF_GET_IF_IN_POOL, IB__FILE__, __LINE__,
&mtr);
buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH);

View File

@ -243,9 +243,10 @@ buf_calc_page_new_checksum(
{
ulint checksum;
/* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO
are written outside the buffer pool to the first pages of data
files, we have to skip them in the page checksum calculation.
/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
..._ARCH_LOG_NO, are written outside the buffer pool to the first
pages of data files, we have to skip them in the page checksum
calculation.
We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
checksum is stored, and also the last 8 bytes of page because
there we store the old formula checksum. */
@ -255,7 +256,7 @@ buf_calc_page_new_checksum(
+ ut_fold_binary(page + FIL_PAGE_DATA,
UNIV_PAGE_SIZE - FIL_PAGE_DATA
- FIL_PAGE_END_LSN_OLD_CHKSUM);
checksum = checksum & 0xFFFFFFFF;
checksum = checksum & 0xFFFFFFFFUL;
return(checksum);
}
@ -278,7 +279,7 @@ buf_calc_page_old_checksum(
checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
checksum = checksum & 0xFFFFFFFF;
checksum = checksum & 0xFFFFFFFFUL;
return(checksum);
}
@ -378,7 +379,7 @@ buf_page_print(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Page dump in ascii and hex (%lu bytes):\n%s",
" InnoDB: Page dump in ascii and hex (%lu bytes):\n%s",
(ulint)UNIV_PAGE_SIZE, buf);
fprintf(stderr, "InnoDB: End of page dump\n");
@ -396,11 +397,16 @@ buf_page_print(
mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM));
fprintf(stderr,
"InnoDB: Page lsn %lu %lu, low 4 bytes of lsn at page end %lu\n",
"InnoDB: Page lsn %lu %lu, low 4 bytes of lsn at page end %lu\n"
"InnoDB: Page number (if stored to page already) %lu,\n"
"InnoDB: space id (if created with >= MySQL-4.1.1 and stored already) %lu\n",
mach_read_from_4(read_buf + FIL_PAGE_LSN),
mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4));
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
mach_read_from_4(read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
== TRX_UNDO_INSERT) {
fprintf(stderr,
@ -414,10 +420,7 @@ buf_page_print(
if (fil_page_get_type(read_buf) == FIL_PAGE_INDEX) {
fprintf(stderr,
"InnoDB: Page may be an index page ");
fprintf(stderr,
"where index id is %lu %lu\n",
"InnoDB: Page may be an index page where index id is %lu %lu\n",
ut_dulint_get_high(btr_page_get_index_id(read_buf)),
ut_dulint_get_low(btr_page_get_index_id(read_buf)));
@ -435,7 +438,6 @@ buf_page_print(
index->name);
}
}
} else if (fil_page_get_type(read_buf) == FIL_PAGE_INODE) {
fprintf(stderr, "InnoDB: Page may be an 'inode' page\n");
} else if (fil_page_get_type(read_buf) == FIL_PAGE_IBUF_FREE_LIST) {
@ -581,8 +583,8 @@ buf_pool_init(
the window */
os_awe_map_physical_mem_to_window(buf_pool->frame_zero,
n_frames *
(UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE),
n_frames *
(UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE),
buf_pool->awe_info);
/*----------------------------------------*/
}
@ -1554,25 +1556,35 @@ buf_page_init(
/************************************************************************
Function which inits a page for read to the buffer buf_pool. If the page is
already in buf_pool, does nothing. Sets the io_fix flag to BUF_IO_READ and
sets a non-recursive exclusive lock on the buffer frame. The io-handler must
take care that the flag is cleared and the lock released later. This is one
of the functions which perform the state transition NOT_USED => FILE_PAGE to
a block (the other is buf_page_create). */
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
(3) if the space is deleted or being deleted,
then this function does nothing.
Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
on the buffer frame. The io-handler must take care that the flag is cleared
and the lock released later. This is one of the functions which perform the
state transition NOT_USED => FILE_PAGE to a block (the other is
buf_page_create). */
buf_block_t*
buf_page_init_for_read(
/*===================*/
/* out: pointer to the block or NULL */
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
ulint space, /* in: space id */
ulint offset) /* in: page number */
/* out: pointer to the block or NULL */
ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
ulint space, /* in: space id */
ib_longlong tablespace_version,/* in: prevents reading from a wrong
version of the tablespace in case we have done
DISCARD + IMPORT */
ulint offset) /* in: page number */
{
buf_block_t* block;
mtr_t mtr;
ut_ad(buf_pool);
*err = DB_SUCCESS;
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
/* It is a read-ahead within an ibuf routine */
@ -1596,10 +1608,17 @@ buf_page_init_for_read(
ut_ad(block);
mutex_enter(&(buf_pool->mutex));
if (NULL != buf_page_hash_get(space, offset)) {
/* The page is already in buf_pool, return */
if (fil_tablespace_deleted_or_being_deleted_in_mem(space,
tablespace_version)) {
*err = DB_TABLESPACE_DELETED;
}
if (*err == DB_TABLESPACE_DELETED
|| NULL != buf_page_hash_get(space, offset)) {
/* The page belongs to a space which has been deleted or is
being deleted, or the page is already in buf_pool, return */
mutex_exit(&(buf_pool->mutex));
buf_block_free(block);
@ -1715,7 +1734,7 @@ buf_page_create(
/* Delete possible entries for the page from the insert buffer:
such can exist if the page belonged to an index which was dropped */
ibuf_merge_or_delete_for_page(NULL, space, offset);
ibuf_merge_or_delete_for_page(NULL, space, offset, TRUE);
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
@ -1828,7 +1847,7 @@ buf_page_io_complete(
if (!recv_no_ibuf_operations) {
ibuf_merge_or_delete_for_page(block->frame,
block->space, block->offset);
block->space, block->offset, TRUE);
}
}
@ -2294,7 +2313,7 @@ buf_all_freed(void)
if (!buf_flush_ready_for_replace(block)) {
/* printf("Page %lu %lu still fixed or dirty\n",
/* printf("Page %lu %lu still fixed or dirty\n",
block->space, block->offset); */
ut_error;
}

View File

@ -361,16 +361,15 @@ buf_flush_init_for_writing(
ulint space, /* in: space id */
ulint page_no) /* in: page number */
{
UT_NOT_USED(space);
/* Write the newest modification lsn to the page header and trailer */
mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn);
mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
newest_lsn);
/* Write the page number */
/* Write the page number and the space id */
mach_write_to_4(page + FIL_PAGE_OFFSET, page_no);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space);
/* Store the new formula checksum */

View File

@ -61,6 +61,87 @@ buf_LRU_block_free_hashed_page(
buf_block_t* block); /* in: block, must contain a file page and
be in a state where it can be freed */
/**********************************************************************
Invalidates all pages belonging to a given tablespace when we are deleting
the data file(s) of that tablespace. */
void
buf_LRU_invalidate_tablespace(
/*==========================*/
ulint id) /* in: space id */
{
buf_block_t* block;
ulint page_no;
ibool all_freed;
scan_again:
mutex_enter(&(buf_pool->mutex));
all_freed = TRUE;
block = UT_LIST_GET_LAST(buf_pool->LRU);
while (block != NULL) {
if (block->space == id
&& (block->buf_fix_count > 0 || block->io_fix != 0)) {
/* We cannot remove this page during this scan yet;
maybe the system is currently reading it in, or
flushing the modifications to the file */
all_freed = FALSE;
goto next_page;
}
if (block->space == id) {
if (buf_debug_prints) {
printf(
"Dropping space %lu page %lu\n",
block->space, block->offset);
}
if (block->is_hashed) {
page_no = block->offset;
mutex_exit(&(buf_pool->mutex));
/* Note that the following call will acquire
an S-latch on the page */
btr_search_drop_page_hash_when_freed(id,
page_no);
goto scan_again;
}
if (0 != ut_dulint_cmp(block->oldest_modification,
ut_dulint_zero)) {
/* Remove from the flush list of modified
blocks */
block->oldest_modification = ut_dulint_zero;
UT_LIST_REMOVE(flush_list,
buf_pool->flush_list, block);
}
/* Remove from the LRU list */
buf_LRU_block_remove_hashed_page(block);
buf_LRU_block_free_hashed_page(block);
}
next_page:
block = UT_LIST_GET_PREV(LRU, block);
}
mutex_exit(&(buf_pool->mutex));
if (!all_freed) {
os_thread_sleep(20000);
goto scan_again;
}
}
/**********************************************************************
Gets the minimum LRU_position field for the blocks in an initial segment
(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not

View File

@ -49,19 +49,30 @@ ulint
buf_read_page_low(
/*==============*/
/* out: 1 if a read request was queued, 0 if the page
already resided in buf_pool or if the page is in
already resided in buf_pool, or if the page is in
the doublewrite buffer blocks in which case it is never
read into the pool */
read into the pool, or if the tablespace does not
exist or is being dropped */
ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
trying to read from a non-existent tablespace, or a
tablespace which is just now being dropped */
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ...,
ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
at read-ahead functions) */
ulint space, /* in: space id */
ib_longlong tablespace_version, /* in: if the space memory object has
this timestamp different from what we are giving here,
treat the tablespace as dropped; this is a timestamp we
use to stop dangling page reads from a tablespace
which we have DISCARDed + IMPORTed back */
ulint offset) /* in: page number */
{
buf_block_t* block;
ulint wake_later;
*err = DB_SUCCESS;
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
@ -72,6 +83,10 @@ buf_read_page_low(
|| (offset >= trx_doublewrite->block2
&& offset < trx_doublewrite->block2
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE))) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: trying to read doublewrite buffer page %lu\n", offset);
return(0);
}
@ -97,27 +112,36 @@ buf_read_page_low(
sync = TRUE;
}
block = buf_page_init_for_read(mode, space, offset);
/* The following call will also check if the tablespace does not exist
or is being dropped; if we succeed in initing the page in the buffer
pool for read, then DISCARD cannot proceed until the read has
completed */
if (block != NULL) {
if (buf_debug_prints) {
printf("Posting read request for page %lu, sync %lu\n",
offset, sync);
}
fil_io(OS_FILE_READ | wake_later,
sync, space, offset, 0, UNIV_PAGE_SIZE,
(void*)block->frame, (void*)block);
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
buf_page_io_complete(block);
}
block = buf_page_init_for_read(err, mode, space, tablespace_version,
offset);
if (block == NULL) {
return(1);
return(0);
}
return(0);
if (buf_debug_prints) {
printf("Posting read request for page %lu, sync %lu\n",
offset, sync);
}
*err = fil_io(OS_FILE_READ | wake_later,
sync, space,
offset, 0, UNIV_PAGE_SIZE,
(void*)block->frame, (void*)block);
ut_a(*err == DB_SUCCESS);
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
buf_page_io_complete(block);
}
return(1);
}
/************************************************************************
@ -142,12 +166,14 @@ buf_read_ahead_random(
ulint offset) /* in: page number of a page which the current thread
wants to access */
{
ib_longlong tablespace_version;
buf_block_t* block;
ulint recent_blocks = 0;
ulint count;
ulint LRU_recent_limit;
ulint ibuf_mode;
ulint low, high;
ulint err;
ulint i;
if (srv_startup_is_before_trx_rollback_phase) {
@ -164,11 +190,16 @@ buf_read_ahead_random(
return(0);
}
/* Remember the tablespace version before we ask te tablespace size
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
do not try to read outside the bounds of the tablespace! */
tablespace_version = fil_space_get_version(space);
low = (offset / BUF_READ_AHEAD_RANDOM_AREA)
* BUF_READ_AHEAD_RANDOM_AREA;
high = (offset / BUF_READ_AHEAD_RANDOM_AREA + 1)
* BUF_READ_AHEAD_RANDOM_AREA;
if (high > fil_space_get_size(space)) {
high = fil_space_get_size(space);
@ -193,7 +224,6 @@ buf_read_ahead_random(
that is, reside near the start of the LRU list. */
for (i = low; i < high; i++) {
block = buf_page_hash_get(space, i);
if ((block)
@ -227,10 +257,17 @@ buf_read_ahead_random(
mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(i)) {
count += buf_read_page_low(FALSE, ibuf_mode
count += buf_read_page_low(&err, FALSE, ibuf_mode
| OS_AIO_SIMULATED_WAKE_LATER,
space, i);
space, tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: in random readahead trying to access tablespace\n"
"InnoDB: %lu page no. %lu,\n"
"InnoDB: but the tablespace does not exist or is just being dropped.\n",
space, i);
}
}
}
@ -264,15 +301,27 @@ buf_read_page(
ulint space, /* in: space id */
ulint offset) /* in: page number */
{
ulint count;
ulint count2;
ib_longlong tablespace_version;
ulint count;
ulint count2;
ulint err;
tablespace_version = fil_space_get_version(space);
count = buf_read_ahead_random(space, offset);
/* We do the i/o in the synchronous aio mode to save thread
switches: hence TRUE */
count2 = buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space, offset);
count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
tablespace_version, offset);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: error: trying to access tablespace %lu page no. %lu,\n"
"InnoDB: but the tablespace does not exist or is just being dropped.\n",
space, offset);
}
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
@ -312,6 +361,7 @@ buf_read_ahead_linear(
ulint offset) /* in: page number of a page; NOTE: the current thread
must want access to this page (see NOTE 3 above) */
{
ib_longlong tablespace_version;
buf_block_t* block;
buf_frame_t* frame;
buf_block_t* pred_block = NULL;
@ -323,6 +373,7 @@ buf_read_ahead_linear(
ulint fail_count;
ulint ibuf_mode;
ulint low, high;
ulint err;
ulint i;
if (srv_startup_is_before_trx_rollback_phase) {
@ -350,14 +401,21 @@ buf_read_ahead_linear(
return(0);
}
/* Remember the tablespace version before we ask te tablespace size
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
do not try to read outside the bounds of the tablespace! */
tablespace_version = fil_space_get_version(space);
mutex_enter(&(buf_pool->mutex));
if (high > fil_space_get_size(space)) {
mutex_exit(&(buf_pool->mutex));
/* The area is not whole, return */
return(0);
}
mutex_enter(&(buf_pool->mutex));
if (buf_pool->n_pend_reads >
buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
mutex_exit(&(buf_pool->mutex));
@ -378,18 +436,15 @@ buf_read_ahead_linear(
fail_count = 0;
for (i = low; i < high; i++) {
block = buf_page_hash_get(space, i);
if ((block == NULL) || !block->accessed) {
/* Not accessed */
fail_count++;
} else if (pred_block && (ut_ulint_cmp(block->LRU_position,
pred_block->LRU_position)
!= asc_or_desc)) {
/* Accesses not in the right order */
fail_count++;
@ -462,7 +517,7 @@ buf_read_ahead_linear(
return(0);
}
/* If we got this far, read-ahead can be sensible: do it */
/* If we got this far, read-ahead can be sensible: do it */
if (ibuf_inside()) {
ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
@ -483,9 +538,17 @@ buf_read_ahead_linear(
aio mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(i)) {
count += buf_read_page_low(FALSE, ibuf_mode
count += buf_read_page_low(&err, FALSE, ibuf_mode
| OS_AIO_SIMULATED_WAKE_LATER,
space, i);
space, tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: in linear readahead trying to access tablespace\n"
"InnoDB: %lu page no. %lu,\n"
"InnoDB: but the tablespace does not exist or is just being dropped.\n",
space, i);
}
}
}
@ -509,7 +572,7 @@ buf_read_ahead_linear(
/************************************************************************
Issues read requests for pages which the ibuf module wants to read in, in
order to contract insert buffer trees. Technically, this function is like
order to contract the insert buffer tree. Technically, this function is like
a read-ahead function. */
void
@ -518,11 +581,17 @@ buf_read_ibuf_merge_pages(
ibool sync, /* in: TRUE if the caller wants this function
to wait for the highest address page to get
read in, before this function returns */
ulint space, /* in: space id */
ulint* space_ids, /* in: array of space ids */
ib_longlong* space_versions,/* in: the spaces must have this version
number (timestamp), otherwise we discard the
read; we use this to cancel reads if
DISCARD + IMPORT may have changed the
tablespace size */
ulint* page_nos, /* in: array of page numbers to read, with the
highest page number the last in the array */
ulint n_stored) /* in: number of page numbers in the array */
{
ulint err;
ulint i;
ut_ad(!ibuf_inside());
@ -535,12 +604,21 @@ buf_read_ibuf_merge_pages(
}
for (i = 0; i < n_stored; i++) {
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space,
page_nos[i]);
buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE,
space_ids[i], space_versions[i], page_nos[i]);
} else {
buf_read_page_low(FALSE, BUF_READ_ANY_PAGE, space,
page_nos[i]);
buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE,
space_ids[i], space_versions[i], page_nos[i]);
}
if (err == DB_TABLESPACE_DELETED) {
/* We have deleted or are deleting the single-table
tablespace: remove the entries for that page */
ibuf_merge_or_delete_for_page(NULL, space_ids[i],
page_nos[i], FALSE);
}
}
@ -548,8 +626,7 @@ buf_read_ibuf_merge_pages(
buf_flush_free_margin();
if (buf_debug_prints) {
printf("Ibuf merge read-ahead space %lu pages %lu\n",
space, n_stored);
printf("Ibuf merge read-ahead pages %lu\n", n_stored);
}
}
@ -567,8 +644,12 @@ buf_read_recv_pages(
highest page number the last in the array */
ulint n_stored) /* in: number of page numbers in the array */
{
ulint count;
ulint i;
ib_longlong tablespace_version;
ulint count;
ulint err;
ulint i;
tablespace_version = fil_space_get_version(space);
for (i = 0; i < n_stored; i++) {
@ -596,12 +677,12 @@ buf_read_recv_pages(
os_aio_print_debug = FALSE;
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(TRUE, BUF_READ_ANY_PAGE, space,
page_nos[i]);
buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
tablespace_version, page_nos[i]);
} else {
buf_read_page_low(FALSE, BUF_READ_ANY_PAGE
buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, page_nos[i]);
space, tablespace_version, page_nos[i]);
}
}

View File

@ -12,7 +12,7 @@ Created 1/16/1996 Heikki Tuuri
#include "data0type.ic"
#endif
dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0};
dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0};
dtype_t* dtype_binary = &dtype_binary_val;
/*************************************************************************

View File

@ -419,6 +419,4 @@ dict_create(void)
dict_boot();
dict_insert_initial_data();
sync_order_checks_on = TRUE;
}

View File

@ -264,6 +264,8 @@ dict_build_table_def_step(
dict_table_t* table;
dict_table_t* cluster_table;
dtuple_t* row;
ulint error;
mtr_t mtr;
UT_NOT_USED(thr);
ut_ad(mutex_own(&(dict_sys->mutex)));
@ -291,6 +293,29 @@ dict_build_table_def_step(
table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID);
}
if (srv_file_per_table) {
/* We create a new single-table tablespace for the table.
We initially let it be 4 pages:
- page 0 is the fsp header and an extent descriptor page,
- page 1 is an ibuf bitmap page,
- page 2 is the first inode page,
- page 3 will contain the root of the clustered index of the
table we create here. */
error = fil_create_new_single_table_tablespace(
&(table->space), table->name, 4);
if (error != DB_SUCCESS) {
return(error);
}
mtr_start(&mtr);
fsp_header_init(table->space, 4, &mtr);
mtr_commit(&mtr);
}
row = dict_create_sys_tables_tuple(table, node->heap);
ins_node_set_new_row(node->tab_def, row);
@ -317,7 +342,6 @@ dict_build_col_def_step(
}
#ifdef notdefined
/*************************************************************************
Creates the single index for a cluster: it contains all the columns of
the cluster definition in the order they were defined. */
@ -508,8 +532,8 @@ dict_create_sys_fields_tuple(
}
/*********************************************************************
Creates the tuple with which the index entry is searched for
writing the index tree root page number, if such a tree is created. */
Creates the tuple with which the index entry is searched for writing the index
tree root page number, if such a tree is created. */
static
dtuple_t*
dict_create_search_tuple(
@ -577,10 +601,10 @@ dict_build_index_def_step(
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
if (index->type & DICT_CLUSTERED) {
/* Inherit the space from the table */
index->space = table->space;
}
/* Inherit the space id from the table; we store all indexes of a
table in the same tablespace */
index->space = table->space;
index->page_no = FIL_NULL;
@ -664,6 +688,9 @@ dict_create_index_tree_step(
index->page_no = btr_create(index->type, index->space, index->id,
&mtr);
/* printf("Created a new index tree in space %lu root page %lu\n",
index->space, index->page_no); */
page_rec_write_index_page_no(btr_pcur_get_rec(&pcur),
DICT_SYS_INDEXES_PAGE_NO_FIELD,
index->page_no, &mtr);
@ -712,7 +739,14 @@ dict_drop_index_tree(
ut_ad(len == 4);
space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
if (!fil_tablespace_exists_in_mem(space)) {
/* It is a single table tablespace and the .ibd file is
missing: do nothing */
return;
}
/* We free all the pages but the root page first; this operation
may span several mini-transactions */
@ -722,6 +756,8 @@ dict_drop_index_tree(
we write FIL_NULL to the appropriate field in the SYS_INDEXES
record: this mini-transaction marks the B-tree totally freed */
/* printf("Dropping index tree in space %lu root page %lu\n", space,
root_page_no); */
btr_free_root(space, root_page_no, mtr);
page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
@ -746,7 +782,6 @@ dict_create_default_index(
dict_create_index(index, trx);
}
#endif
/*************************************************************************

View File

@ -139,7 +139,8 @@ dict_tree_find_index_low(
/*=====================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec); /* in: record for which to find correct index */
rec_t* rec); /* in: record for which to find correct
index */
/**************************************************************************
Removes a foreign constraint struct from the dictionet cache. */
static
@ -717,7 +718,7 @@ dict_table_get_and_increment_handle_count(
mutex_exit(&(dict_sys->mutex));
if (table != NULL) {
if (!table->stat_initialized) {
if (!table->stat_initialized && !table->ibd_file_missing) {
dict_update_statistics(table);
}
}
@ -869,6 +870,7 @@ dict_table_rename_in_cache(
ulint fold;
ulint old_size;
char* name_buf;
ibool success;
ulint i;
ut_ad(table);
@ -884,6 +886,21 @@ dict_table_rename_in_cache(
HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
(ut_strcmp(table2->name, new_name) == 0));
if (table2) {
fprintf(stderr,
"InnoDB: Error: dictionary cache already contains a table of name %s\n",
new_name);
return(FALSE);
}
}
/* If the table is stored in a single-table tablespace, rename the
.ibd file */
if (table->space != 0) {
success = fil_rename_tablespace(table->name, table->space,
new_name);
if (!success) {
return(FALSE);
}
}
@ -909,7 +926,6 @@ dict_table_rename_in_cache(
/* Add table to hash table of tables */
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
table);
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
/* Update the table_name field in indexes */
@ -999,6 +1015,31 @@ dict_table_rename_in_cache(
return(TRUE);
}
/**************************************************************************
Change the id of a table object in the dictionary cache. This is used in
DISCARD TABLESPACE. */
void
dict_table_change_id_in_cache(
/*==========================*/
dict_table_t* table, /* in: table object already in cache */
dulint new_id) /* in: new id to set */
{
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
/* Remove the table from the hash table of id's */
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
ut_fold_dulint(table->id), table);
table->id = new_id;
/* Add the table back to the hash table */
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
ut_fold_dulint(table->id), table);
}
/**************************************************************************
Removes a table object from the dictionary cache. */
@ -3295,8 +3336,8 @@ dict_tree_free(
/*===========*/
dict_tree_t* tree) /* in, own: index tree */
{
ut_ad(tree);
ut_ad(tree->magic_n == DICT_TREE_MAGIC_N);
ut_a(tree);
ut_a(tree->magic_n == DICT_TREE_MAGIC_N);
rw_lock_free(&(tree->lock));
mem_free(tree);
@ -3310,7 +3351,8 @@ dict_tree_find_index_low(
/*=====================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec) /* in: record for which to find correct index */
rec_t* rec) /* in: record for which to find correct
index */
{
dict_index_t* index;
dict_table_t* table;
@ -3348,7 +3390,8 @@ dict_tree_find_index(
/*=================*/
/* out: index */
dict_tree_t* tree, /* in: index tree */
rec_t* rec) /* in: record for which to find correct index */
rec_t* rec) /* in: record for which to find correct
index */
{
dict_index_t* index;
@ -3438,7 +3481,8 @@ dict_tree_build_node_ptr(
/*=====================*/
/* out, own: node pointer */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build node pointer */
rec_t* rec, /* in: record for which to build node
pointer */
ulint page_no,/* in: page number to put in node pointer */
mem_heap_t* heap, /* in: memory heap where pointer created */
ulint level) /* in: level of rec in tree: 0 means leaf
@ -3600,6 +3644,16 @@ dict_update_statistics_low(
ulint size;
ulint sum_of_index_sizes = 0;
if (table->ibd_file_missing) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: cannot calculate statistics for table %s\n"
"InnoDB: because the .ibd file is missing. See section 15.1 of\n"
"InnoDB: http:/www.innodb.com/ibman.html for help\n", table->name);
return;
}
/* If we have set a high innodb_force_recovery level, do not calculate
statistics, as a badly corrupted index can cause a crash in it. */

View File

@ -19,6 +19,7 @@ Created 4/24/1996 Heikki Tuuri
#include "mach0data.h"
#include "dict0dict.h"
#include "dict0boot.h"
#include "srv0start.h"
/************************************************************************
Finds the first table name in the given database. */
@ -120,8 +121,8 @@ dict_print(void)
rec_t* rec;
byte* field;
ulint len;
char table_name[10000];
mtr_t mtr;
char table_name[10000];
mutex_enter(&(dict_sys->mutex));
@ -185,6 +186,100 @@ loop:
goto loop;
}
/************************************************************************
In a crash recovery we already have all the tablespace objects created.
This function compares the space id information in the InnoDB data dictionary
to what we already read with fil_load_single_table_tablespaces().
In a normal startup we just scan the biggest space id, and store it to
fil_system. */
void
dict_check_tablespaces_or_store_max_id(
/*===================================*/
ibool in_crash_recovery) /* in: are we doing a crash recovery */
{
dict_table_t* sys_tables;
dict_index_t* sys_index;
btr_pcur_t pcur;
rec_t* rec;
byte* field;
ulint len;
ulint space_id;
ulint max_space_id = 0;
mtr_t mtr;
char name[OS_FILE_MAX_PATH];
mutex_enter(&(dict_sys->mutex));
mtr_start(&mtr);
sys_tables = dict_table_get_low((char *) "SYS_TABLES");
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
TRUE, &mtr);
loop:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
/* end of index */
btr_pcur_close(&pcur);
mtr_commit(&mtr);
/* We must make the tablespace cache aware of the biggest
known space id */
/* printf("Biggest space id in data dictionary %lu\n",
max_space_id); */
fil_set_max_space_id_if_bigger(max_space_id);
mutex_exit(&(dict_sys->mutex));
return;
}
field = rec_get_nth_field(rec, 0, &len);
if (!rec_get_deleted_flag(rec)) {
/* We found one */
ut_a(len < OS_FILE_MAX_PATH - 10);
ut_memcpy(name, field, len);
name[len] = '\0';
field = rec_get_nth_field(rec, 9, &len);
ut_a(len == 4);
space_id = mach_read_from_4(field);
btr_pcur_store_position(&pcur, &mtr);
mtr_commit(&mtr);
if (space_id != 0 && in_crash_recovery) {
/* Check that the tablespace (the .ibd file) really
exists; print a warning to the .err log if not */
fil_space_for_table_exists_in_mem(space_id, name,
TRUE, TRUE);
}
if (space_id > max_space_id) {
max_space_id = space_id;
}
mtr_start(&mtr);
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
}
goto loop;
}
/************************************************************************
Loads definitions for table columns. */
static
@ -359,13 +454,13 @@ dict_load_fields(
pos_and_prefix_len = mach_read_from_4(field);
ut_a((pos_and_prefix_len & 0xFFFF) == i
|| (pos_and_prefix_len & 0xFFFF0000) == (i << 16));
ut_a((pos_and_prefix_len & 0xFFFFUL) == i
|| (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
if ((i == 0 && pos_and_prefix_len > 0)
|| (pos_and_prefix_len & 0xFFFF0000) > 0) {
|| (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
prefix_len = pos_and_prefix_len & 0xFFFF;
prefix_len = pos_and_prefix_len & 0xFFFFUL;
} else {
prefix_len = 0;
}
@ -540,8 +635,8 @@ dict_load_indexes(
&& (0 == ut_memcmp(name_buf, (char*) "ID_IND",
name_len))))) {
/* The index was created in memory already in
booting */
/* The index was created in memory already at booting
of the database server */
} else {
index = dict_mem_index_create(table->name, name_buf,
space, type, n_fields);
@ -572,9 +667,14 @@ dictionary cache. */
dict_table_t*
dict_load_table(
/*============*/
/* out: table, NULL if does not exist */
char* name) /* in: table name */
/* out: table, NULL if does not exist; if the table is
stored in an .ibd file, but the file does not exist,
then we set the ibd_file_missing flag TRUE in the table
object we return */
char* name) /* in: table name in the databasename/tablename
format */
{
ibool ibd_file_missing = FALSE;
dict_table_t* table;
dict_table_t* sys_tables;
btr_pcur_t pcur;
@ -641,6 +741,23 @@ dict_load_table(
field = rec_get_nth_field(rec, 9, &len);
space = mach_read_from_4(field);
/* Check if the tablespace exists and has the right name */
if (space != 0) {
if (fil_space_for_table_exists_in_mem(space, name, FALSE,
FALSE)) {
/* Ok; (if we did a crash recovery then the tablespace
can already be in the memory cache) */
} else {
/* Try to open the tablespace */
if (!fil_open_single_table_tablespace(space, name)) {
/* We failed to find a sensible tablespace
file */
ibd_file_missing = TRUE;
}
}
}
ut_a(0 == ut_strcmp((char *) "N_COLS",
dict_field_get_col(
dict_index_get_nth_field(
@ -651,6 +768,8 @@ dict_load_table(
table = dict_mem_table_create(name, space, n_cols);
table->ibd_file_missing = ibd_file_missing;
ut_a(0 == ut_strcmp((char *) "ID",
dict_field_get_col(
dict_index_get_nth_field(
@ -1003,7 +1122,7 @@ dict_load_foreign(
/* We store the type to the bits 24-31 of n_fields */
foreign->type = foreign->n_fields >> 24;
foreign->n_fields = foreign->n_fields & 0xFFFFFF;
foreign->n_fields = foreign->n_fields & 0xFFFFFFUL;
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);

View File

@ -56,6 +56,8 @@ dict_mem_table_create(
table->type = DICT_TABLE_ORDINARY;
table->name = str;
table->space = space;
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
table->n_def = 0;
table->n_cols = n_cols + DATA_N_SYS_COLS;
table->mem_fix = 0;

File diff suppressed because it is too large Load Diff

View File

@ -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,
@ -827,9 +839,22 @@ fsp_init(void)
/* Does nothing at the moment */
}
/**************************************************************************
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_last_file(
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_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);
@ -2407,6 +2589,46 @@ fseg_alloc_free_page(
FALSE, mtr));
}
/**************************************************************************
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
@ -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);

View File

@ -294,10 +294,10 @@ ha_print_info(
{
hash_cell_t* cell;
/*
ha_node_t* node;
ulint len = 0;
ulint max_len = 0;
ulint nodes = 0;
ha_node_t* node;
ulint len = 0;
ulint max_len = 0;
ulint nodes = 0;
*/
ulint cells = 0;
ulint n_bufs;

File diff suppressed because it is too large Load Diff

View File

@ -189,6 +189,7 @@ btr_node_ptr_get_child_page_no(
ulint n_fields;
byte* field;
ulint len;
ulint page_no;
n_fields = rec_get_n_fields(rec);
@ -197,7 +198,16 @@ btr_node_ptr_get_child_page_no(
ut_ad(len == 4);
return(mach_read_from_4(field));
page_no = mach_read_from_4(field);
if (page_no == 0) {
fprintf(stderr,
"InnoDB: a nonsensical page number 0 in a node ptr record at offset %lu\n",
(ulint)(rec - buf_frame_align(rec)));
buf_page_print(buf_frame_align(rec));
}
return(page_no);
}
/******************************************************************

View File

@ -564,7 +564,7 @@ btr_pcur_open_at_index_side(
}
btr_cur_open_at_index_side(from_left, index, latch_mode,
btr_pcur_get_btr_cur(pcur), mtr);
btr_pcur_get_btr_cur(pcur), mtr);
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;

View File

@ -626,19 +626,27 @@ buf_pool_get_nth_block(
ulint i); /* in: index of the block */
/************************************************************************
Function which inits a page for read to the buffer buf_pool. If the page is
already in buf_pool, does nothing. Sets the io_fix flag to BUF_IO_READ and
sets a non-recursive exclusive lock on the buffer frame. The io-handler must
take care that the flag is cleared and the lock released later. This is one
of the functions which perform the state transition NOT_USED => FILE_PAGE to
a block (the other is buf_page_create). */
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
(3) if the space is deleted or being deleted,
then this function does nothing.
Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
on the buffer frame. The io-handler must take care that the flag is cleared
and the lock released later. This is one of the functions which perform the
state transition NOT_USED => FILE_PAGE to a block (the other is
buf_page_create). */
buf_block_t*
buf_page_init_for_read(
/*===================*/
/* out: pointer to the block */
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
ulint space, /* in: space id */
ulint offset);/* in: page number */
/* out: pointer to the block or NULL */
ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
ulint space, /* in: space id */
ib_longlong tablespace_version,/* in: prevents reading from a wrong
version of the tablespace in case we have done
DISCARD + IMPORT */
ulint offset);/* in: page number */
/************************************************************************
Completes an asynchronous read or write request of a file page to or from
the buffer pool. */

View File

@ -36,6 +36,16 @@ These are low-level functions
#define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA)
/**********************************************************************
Invalidates all pages belonging to a given tablespace when we are deleting
the data file(s) of that tablespace. A PROBLEM: if readahead is being started,
what guarantees that it will not try to read in pages after this operation has
completed? */
void
buf_LRU_invalidate_tablespace(
/*==========================*/
ulint id); /* in: space id */
/**********************************************************************
Gets the minimum LRU_position field for the blocks in an initial segment
(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not

View File

@ -59,7 +59,7 @@ buf_read_ahead_linear(
must want access to this page (see NOTE 3 above) */
/************************************************************************
Issues read requests for pages which the ibuf module wants to read in, in
order to contract insert buffer trees. Technically, this function is like
order to contract the insert buffer tree. Technically, this function is like
a read-ahead function. */
void
@ -68,9 +68,14 @@ buf_read_ibuf_merge_pages(
ibool sync, /* in: TRUE if the caller wants this function
to wait for the highest address page to get
read in, before this function returns */
ulint space, /* in: space id */
ulint* page_nos, /* in: array of page numbers to read, with
the highest page number last in the array */
ulint* space_ids, /* in: array of space ids */
ib_longlong* space_versions,/* in: the spaces must have this version
number (timestamp), otherwise we discard the
read; we use this to cancel reads if
DISCARD + IMPORT may have changed the
tablespace size */
ulint* page_nos, /* in: array of page numbers to read, with the
highest page number the last in the array */
ulint n_stored); /* in: number of page numbers in the array */
/************************************************************************
Issues read requests for pages which recovery wants to read in. */

View File

@ -89,6 +89,8 @@ be less than 256 */
alphabetical order for a single field and decide the storage size of an
SQL null*/
#define DATA_ORDER_NULL_TYPE_BUF_SIZE 4
/* In the >= 4.1.x storage format we need 2 bytes more for the charset */
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
/*************************************************************************
Sets a data type structure. */
@ -172,16 +174,6 @@ dtype_is_fixed_size(
/* out: TRUE if fixed size */
dtype_t* type); /* in: type */
/**************************************************************************
Stores for a type the information which determines its alphabetical ordering
and the storage size of an SQL NULL value. */
UNIV_INLINE
void
dtype_store_for_order_and_null_size(
/*================================*/
byte* buf, /* in: buffer for DATA_ORDER_NULL_TYPE_BUF_SIZE
bytes where we store the info */
dtype_t* type); /* in: type struct */
/**************************************************************************
Reads to a type the stored information which determines its alphabetical
ordering and the storage size of an SQL NULL value. */
UNIV_INLINE
@ -190,6 +182,28 @@ dtype_read_for_order_and_null_size(
/*===============================*/
dtype_t* type, /* in: type struct */
byte* buf); /* in: buffer for the stored order info */
/**************************************************************************
Stores for a type the information which determines its alphabetical ordering
and the storage size of an SQL NULL value. This is the >= 4.1.x storage
format. */
UNIV_INLINE
void
dtype_new_store_for_order_and_null_size(
/*====================================*/
byte* buf, /* in: buffer for
DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
bytes where we store the info */
dtype_t* type); /* in: type struct */
/**************************************************************************
Reads to a type the stored information which determines its alphabetical
ordering and the storage size of an SQL NULL value. This is the 4.1.x storage
format. */
UNIV_INLINE
void
dtype_new_read_for_order_and_null_size(
/*===================================*/
dtype_t* type, /* in: type struct */
byte* buf); /* in: buffer for stored type order info */
/*************************************************************************
Validates a data type structure. */
@ -211,6 +225,7 @@ dtype_print(
struct dtype_struct{
ulint mtype; /* main data type */
ulint prtype; /* precise type; MySQL data type */
ulint chrset; /* MySQL character set code */
/* remaining two fields do not affect alphabetical ordering: */

View File

@ -27,6 +27,7 @@ dtype_set(
type->prtype = prtype;
type->len = len;
type->prec = prec;
type->chrset = 0;
ut_ad(dtype_validate(type));
}
@ -127,18 +128,20 @@ dtype_get_pad_char(
/**************************************************************************
Stores for a type the information which determines its alphabetical ordering
and the storage size of an SQL NULL value. */
and the storage size of an SQL NULL value. This is the >= 4.1.x storage
format. */
UNIV_INLINE
void
dtype_store_for_order_and_null_size(
/*================================*/
byte* buf, /* in: buffer for DATA_ORDER_NULL_TYPE_BUF_SIZE
dtype_new_store_for_order_and_null_size(
/*====================================*/
byte* buf, /* in: buffer for
DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
bytes where we store the info */
dtype_t* type) /* in: type struct */
{
ut_ad(4 == DATA_ORDER_NULL_TYPE_BUF_SIZE);
ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
buf[0] = (byte)(type->mtype & 0xFF);
buf[0] = (byte)(type->mtype & 0xFFUL);
if (type->prtype & DATA_BINARY_TYPE) {
buf[0] = buf[0] | 128;
@ -148,9 +151,11 @@ dtype_store_for_order_and_null_size(
buf[0] = buf[0] | 64;
}
buf[1] = (byte)(type->prtype & 0xFF);
buf[1] = (byte)(type->prtype & 0xFFUL);
mach_write_to_2(buf + 2, type->len & 0xFFFF);
mach_write_to_2(buf + 2, type->len & 0xFFFFUL);
mach_write_to_2(buf + 4, type->chrset & 0xFFFFUL);
}
/**************************************************************************
@ -179,6 +184,35 @@ dtype_read_for_order_and_null_size(
type->len = mach_read_from_2(buf + 2);
}
/**************************************************************************
Reads to a type the stored information which determines its alphabetical
ordering and the storage size of an SQL NULL value. This is the 4.1.x storage
format. */
UNIV_INLINE
void
dtype_new_read_for_order_and_null_size(
/*===================================*/
dtype_t* type, /* in: type struct */
byte* buf) /* in: buffer for stored type order info */
{
ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
type->mtype = buf[0] & 63;
type->prtype = buf[1];
if (buf[0] & 128) {
type->prtype = type->prtype | DATA_BINARY_TYPE;
}
if (buf[0] & 64) {
type->prtype = type->prtype | DATA_NONLATIN1;
}
type->len = mach_read_from_2(buf + 2);
type->chrset = mach_read_from_2(buf + 4);
}
/***************************************************************************
Returns the size of a fixed size data type, 0 if not a fixed size type. */
UNIV_INLINE

View File

@ -48,6 +48,11 @@ Created 5/24/1996 Heikki Tuuri
from a table failed */
#define DB_NO_SAVEPOINT 42 /* no savepoint exists with the given
name */
#define DB_TABLESPACE_ALREADY_EXISTS 43 /* we cannot create a new single-table
tablespace because a file of the same
name already exists */
#define DB_TABLESPACE_DELETED 44 /* tablespace does not exist or is
being dropped right now */
/* The following are partial failure codes */
#define DB_FAIL 1000

View File

@ -93,7 +93,7 @@ dict_create(void);
indexes; ibuf tables and indexes are
assigned as the id the number
DICT_IBUF_ID_MIN plus the space id */
#define DICT_IBUF_ID_MIN ut_dulint_create(0xFFFFFFFF, 0)
#define DICT_IBUF_ID_MIN ut_dulint_create(0xFFFFFFFFUL, 0)
/* The offset of the dictionary header on the page */
#define DICT_HDR FSEG_PAGE_DATA

View File

@ -51,6 +51,16 @@ Inits the data dictionary module. */
void
dict_init(void);
/*===========*/
/************************************************************************
Gets the space id of every table of the data dictionary and makes a linear
list and a hash table of them to the data dictionary cache. This function
can be called at database startup if we did not need to do a crash recovery.
In crash recovery we must scan the space id's from the .ibd files in MySQL
database directories. */
void
dict_load_space_id_list(void);
/*=========================*/
/**************************************************************************
Returns a stored procedure object and memoryfixes it. */
UNIV_INLINE
@ -187,6 +197,15 @@ dict_table_rename_in_cache(
to preserve the original table name
in constraints which reference it */
/**************************************************************************
Change the id of a table object in the dictionary cache. This is used in
DISCARD TABLESPACE. */
void
dict_table_change_id_in_cache(
/*==========================*/
dict_table_t* table, /* in: table object already in cache */
dulint new_id);/* in: new id to set */
/**************************************************************************
Adds a foreign key constraint object to the dictionary cache. May free
the object if there already is an object with the same identifier in.
At least one of foreign table or referenced table must already be in
@ -734,7 +753,8 @@ dict_tree_build_node_ptr(
/*=====================*/
/* out, own: node pointer */
dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build node pointer */
rec_t* rec, /* in: record for which to build node
pointer */
ulint page_no,/* in: page number to put in node pointer */
mem_heap_t* heap, /* in: memory heap where pointer created */
ulint level); /* in: level of rec in tree: 0 means leaf
@ -902,7 +922,7 @@ struct dict_sys_struct{
dict_table_t* sys_columns; /* SYS_COLUMNS table */
dict_table_t* sys_indexes; /* SYS_INDEXES table */
dict_table_t* sys_fields; /* SYS_FIELDS table */
};
};
#ifndef UNIV_NONINL
#include "dict0dict.ic"

View File

@ -14,6 +14,17 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0types.h"
#include "ut0byte.h"
/************************************************************************
In a crash recovery we already have all the tablespace objects created.
This function compares the space id information in the InnoDB data dictionary
to what we already read with fil_load_single_table_tablespaces().
In a normal startup we just scan the biggest space id, and store it to
fil_system. */
void
dict_check_tablespaces_or_store_max_id(
/*===================================*/
ibool in_crash_recovery); /* in: are we doing a crash recovery */
/************************************************************************
Finds the first table name in the given database. */
@ -32,7 +43,10 @@ a foreign key references columns in this table. */
dict_table_t*
dict_load_table(
/*============*/
/* out: table, NULL if does not exist */
/* out: table, NULL if does not exist; if the table is
stored in an .ibd file, but the file does not exist,
then we set the ibd_file_missing flag TRUE in the table
object we return */
char* name); /* in: table name */
/***************************************************************************
Loads a table object based on the table id. */

View File

@ -309,6 +309,13 @@ struct dict_table_struct{
char* name; /* table name */
ulint space; /* space where the clustered index of the
table is placed */
ibool ibd_file_missing;/* TRUE if this is in a single-table
tablespace and the .ibd file is missing; then
we must return in ha_innodb.cc an error if the
user tries to query such an orphaned table */
ibool tablespace_discarded;/* this flag is set TRUE when the
user calls DISCARD TABLESPACE on this table,
and reset to FALSE in IMPORT TABLESPACE */
hash_node_t name_hash; /* hash chain node */
hash_node_t id_hash; /* hash chain node */
ulint n_def; /* number of columns defined so far */

View File

@ -7,7 +7,7 @@ Created 2/5/1996 Heikki Tuuri
*******************************************************/
#define DYN_BLOCK_MAGIC_N 375767
#define DYN_BLOCK_FULL_FLAG 0x1000000
#define DYN_BLOCK_FULL_FLAG 0x1000000UL
/****************************************************************
Adds a new block to a dyn array. */

View File

@ -60,10 +60,8 @@ extern fil_addr_t fil_addr_null;
first page in a data file: the file
has been flushed to disk at least up
to this lsn */
#define FIL_PAGE_ARCH_LOG_NO 34 /* this is only defined for the
first page in a data file: the latest
archived log file number when the
flush lsn above was written */
#define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /* starting from 4.1.x this
contains the space id of the page */
#define FIL_PAGE_DATA 38 /* start of the data on the page */
/* File page trailer */
@ -86,83 +84,15 @@ extern fil_addr_t fil_addr_null;
extern ulint fil_n_pending_log_flushes;
extern ulint fil_n_pending_tablespace_flushes;
/***********************************************************************
Reserves a right to open a single file. The right must be released with
fil_release_right_to_open. */
Returns the version number of a tablespace, -1 if not found. */
void
fil_reserve_right_to_open(void);
/*===========================*/
/***********************************************************************
Releases a right to open a single file. */
void
fil_release_right_to_open(void);
/*===========================*/
/************************************************************************
Returns TRUE if file address is undefined. */
ibool
fil_addr_is_null(
/*=============*/
/* out: TRUE if undefined */
fil_addr_t addr); /* in: address */
/********************************************************************
Initializes the file system of this module. */
void
fil_init(
/*=====*/
ulint max_n_open); /* in: max number of open files */
/********************************************************************
Initializes the ibuf indexes at a database start. This can be called
after the file space headers have been created and the dictionary system
has been initialized. */
void
fil_ibuf_init_at_db_start(void);
/*===========================*/
/***********************************************************************
Creates a space object and puts it to the file system. */
void
fil_space_create(
/*=============*/
char* name, /* in: space name */
ulint id, /* in: space id */
ulint purpose);/* in: FIL_TABLESPACE, or FIL_LOG if log */
/********************************************************************
Drops files from the start of a file space, so that its size is cut by
the amount given. */
void
fil_space_truncate_start(
/*=====================*/
ulint id, /* in: space id */
ulint trunc_len); /* in: truncate by this much; it is an error
if this does not equal to the combined size of
some initial files in the space */
/**************************************************************************
Tries to extend a data file by the number of pages given. Any fractions of a
megabyte are ignored. */
ibool
fil_extend_last_data_file(
/*======================*/
/* out: TRUE if success, also if we run
out of disk space we may return TRUE */
ulint* actual_increase,/* out: number of pages we were able to
extend, here the orginal size of the file and
the resulting size of the file are rounded
downwards to a full megabyte, and the
difference expressed in pages is returned */
ulint size_increase); /* in: try to extend this many pages */
/***********************************************************************
Frees a space object from a file system. Closes the files in the chain
but does not delete them. */
void
fil_space_free(
/*===========*/
ib_longlong
fil_space_get_version(
/*==================*/
/* out: version number, -1 if the tablespace does not
exist in the memory cache */
ulint id); /* in: space id */
/***********************************************************************
Returns the latch of a file space. */
@ -180,9 +110,118 @@ fil_space_get_type(
/*===============*/
/* out: FIL_TABLESPACE or FIL_LOG */
ulint id); /* in: space id */
/***********************************************************************
Returns the ibuf data of a file space. */
ibuf_data_t*
fil_space_get_ibuf_data(
/*====================*/
/* out: ibuf data for this space */
ulint id); /* in: space id */
/***********************************************************************
Appends a new file to the chain of files of a space. File must be closed. */
void
fil_node_create(
/*============*/
char* name, /* in: file name (file must be closed) */
ulint size, /* in: file size in database blocks, rounded downwards
to an integer */
ulint id, /* in: space id where to append */
ibool is_raw);/* in: TRUE if a raw device or a raw disk partition */
/********************************************************************
Drops files from the start of a file space, so that its size is cut by
the amount given. */
void
fil_space_truncate_start(
/*=====================*/
ulint id, /* in: space id */
ulint trunc_len); /* in: truncate by this much; it is an error
if this does not equal to the combined size of
some initial files in the space */
/***********************************************************************
Creates a space memory object and puts it to the 'fil system' hash table. If
there is an error, prints an error message to the .err log. */
ibool
fil_space_create(
/*=============*/
/* out: TRUE if success */
char* name, /* in: space name */
ulint id, /* in: space id */
ulint purpose);/* in: FIL_TABLESPACE, or FIL_LOG if log */
/***********************************************************************
Frees a space object from a the tablespace memory cache. Closes the files in
the chain but does not delete them. */
ibool
fil_space_free(
/*===========*/
/* out: TRUE if success */
ulint id); /* in: space id */
/***********************************************************************
Returns the size of the space in pages. The tablespace must be cached in the
memory cache. */
ulint
fil_space_get_size(
/*===============*/
/* out: space size, 0 if space not found */
ulint id); /* in: space id */
/***********************************************************************
Checks if the pair space, page_no refers to an existing page in a tablespace
file space. The tablespace must be cached in the memory cache. */
ibool
fil_check_adress_in_tablespace(
/*===========================*/
/* out: TRUE if the address is meaningful */
ulint id, /* in: space id */
ulint page_no);/* in: page number */
/********************************************************************
Initializes the tablespace memory cache. */
void
fil_init(
/*=====*/
ulint max_n_open); /* in: max number of open files */
/***********************************************************************
Opens all log files and system tablespace data files. They stay open until the
database server shutdown. This should be called at a server startup after the
space objects for the log and the system tablespace have been created. The
purpose of this operation is to make sure we never run out of file descriptors
if we need to read from the insert buffer or to write to the log. */
void
fil_open_log_and_system_tablespace_files(void);
/*==========================================*/
/***********************************************************************
Closes all open files. There must not be any pending i/o's or not flushed
modifications in the files. */
void
fil_close_all_files(void);
/*=====================*/
/***********************************************************************
Sets the max tablespace id counter if the given number is bigger than the
previous value. */
void
fil_set_max_space_id_if_bigger(
/*===========================*/
ulint max_id);/* in: maximum known id */
/********************************************************************
Initializes the ibuf data structure for space 0 == the system tablespace.
This can be called after the file space headers have been created and the
dictionary system has been initialized. */
void
fil_ibuf_init_at_db_start(void);
/*===========================*/
/********************************************************************
Writes the flushed lsn and the latest archived log number to the page
header of the first page of each data file. */
header of the first page of each data file in the system tablespace. */
ulint
fil_write_flushed_lsn_to_data_files(
@ -205,169 +244,186 @@ fil_read_flushed_lsn_and_arch_log_no(
dulint* max_flushed_lsn, /* in/out: */
ulint* max_arch_log_no); /* in/out: */
/***********************************************************************
Returns the ibuf data of a file space. */
ibuf_data_t*
fil_space_get_ibuf_data(
/*====================*/
/* out: ibuf data for this space */
ulint id); /* in: space id */
/***********************************************************************
Returns the size of the space in pages. */
ulint
fil_space_get_size(
/*===============*/
/* out: space size */
ulint id); /* in: space id */
/***********************************************************************
Checks if the pair space, page_no refers to an existing page in a
tablespace file space. */
Increments the count of pending insert buffer page merges, if space is not
being deleted. */
ibool
fil_check_adress_in_tablespace(
/*===========================*/
/* out: TRUE if the address is meaningful */
ulint id, /* in: space id */
ulint page_no);/* in: page number */
fil_inc_pending_ibuf_merges(
/*========================*/
/* out: TRUE if being deleted, and ibuf merges should
be skipped */
ulint id); /* in: space id */
/***********************************************************************
Appends a new file to the chain of files of a space.
File must be closed. */
Decrements the count of pending insert buffer page merges. */
void
fil_node_create(
/*============*/
char* name, /* in: file name (file must be closed) */
ulint size, /* in: file size in database blocks, rounded downwards
to an integer */
ulint id); /* in: space id where to append */
/************************************************************************
Reads or writes data. This operation is asynchronous (aio). */
fil_decr_pending_ibuf_merges(
/*========================*/
ulint id); /* in: space id */
/***********************************************************************
Deletes a single-table tablespace. The tablespace must be cached in the
memory cache. */
void
fil_io(
/*===*/
ulint type, /* in: OS_FILE_READ or OS_FILE_WRITE,
ORed to OS_FILE_LOG, if a log i/o
and ORed to OS_AIO_SIMULATED_WAKE_LATER
if simulated aio and we want to post a
batch of i/os; NOTE that a simulated batch
may introduce hidden chances of deadlocks,
because i/os are not actually handled until
all have been posted: use with great
caution! */
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
ulint len, /* in: how many bytes to read; this must
not cross a file boundary; in aio this must
be a block size multiple */
void* buf, /* in/out: buffer where to store read data
or from where to write; in aio this must be
appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/************************************************************************
Reads data from a space to a buffer. Remember that the possible incomplete
blocks at the end of a file are ignored: they are not taken into account when
calculating the byte offset within a space. */
void
fil_read(
/*=====*/
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in aio
this must be divisible by the OS block size */
ulint len, /* in: how many bytes to read; this must not
cross a file boundary; in aio this must be a
block size multiple */
void* buf, /* in/out: buffer where to store data read;
in aio this must be appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/************************************************************************
Writes data to a space from a buffer. Remember that the possible incomplete
blocks at the end of a file are ignored: they are not taken into account when
calculating the byte offset within a space. */
void
fil_write(
/*======*/
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in aio
this must be divisible by the OS block size */
ulint len, /* in: how many bytes to write; this must
not cross a file boundary; in aio this must
be a block size multiple */
void* buf, /* in: buffer from which to write; in aio
this must be appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/**************************************************************************
Waits for an aio operation to complete. This function is used to write the
handler for completed requests. The aio array of pending requests is divided
into segments (see os0file.c for more info). The thread specifies which
segment it wants to wait for. */
void
fil_aio_wait(
/*=========*/
ulint segment); /* in: the number of the segment in the aio
array to wait for */
/**************************************************************************
Flushes to disk possible writes cached by the OS. */
void
fil_flush(
/*======*/
ulint space_id); /* in: file space id (this can be a group of
log files or a tablespace of the database) */
/**************************************************************************
Flushes to disk writes in file spaces of the given type possibly cached by
the OS. */
void
fil_flush_file_spaces(
ibool
fil_delete_tablespace(
/*==================*/
ulint purpose); /* in: FIL_TABLESPACE, FIL_LOG */
/**********************************************************************
Checks the consistency of the file system. */
/* out: TRUE if success */
ulint id); /* in: space id */
/***********************************************************************
Discards a single-table tablespace. The tablespace must be cached in the
memory cache. Discarding is like deleting a tablespace, but
1) we do not drop the table from the data dictionary;
2) we remove all insert buffer entries for the tablespace immediately; in DROP
TABLE they are only removed gradually in the background;
3) when the user does IMPORT TABLESPACE, the tablespace will have the same id
as it originally had. */
ibool
fil_validate(void);
/*==============*/
/* out: TRUE if ok */
/************************************************************************
Accessor functions for a file page */
fil_discard_tablespace(
/*===================*/
/* out: TRUE if success */
ulint id); /* in: space id */
/***********************************************************************
Renames a single-table tablespace. The tablespace must be cached in the
tablespace memory cache. */
ibool
fil_rename_tablespace(
/*==================*/
/* out: TRUE if success */
char* old_name, /* in: old table name in the standard
databasename/tablename format of InnoDB */
ulint id, /* in: space id */
char* new_name); /* in: new table name in the standard
databasename/tablename format of InnoDB */
/***********************************************************************
Creates a new single-table tablespace to a database directory of MySQL.
Database directories are under the 'datadir' of MySQL. The datadir is the
directory of a running mysqld program. We can refer to it by simply the
path '.'. */
ulint
fil_page_get_prev(byte* page);
fil_create_new_single_table_tablespace(
/*===================================*/
/* out: DB_SUCCESS or error code */
ulint* space_id, /* out: space id */
char* tablename, /* in: the table name in the usual
databasename/tablename format of InnoDB */
ulint size); /* in: the initial size of the tablespace file
in pages */
/************************************************************************
Tries to open a single-table tablespace and checks the space id is right in
it. If does not succeed, prints an error message to the .err log. This
function is used to open the tablespace when we load a table definition
to the dictionarky cache. NOTE that we assume this operation is used under the
protection of the dictionary mutex, so that two users cannot race here. */
ibool
fil_open_single_table_tablespace(
/*=============================*/
/* out: TRUE if success */
ulint id, /* in: space id */
char* name); /* in: table name in the databasename/tablename
format */
/************************************************************************
At the server startup, if we need crash recovery, scans the database
directories under the MySQL datadir, looking for .ibd files. Those files are
single-table tablespaces. We need to know the space id in each of them so that
we know into which file we should look to check the contents of a page stored
in the doublewrite buffer, also to know where to apply log records where the
space id is != 0. */
ulint
fil_page_get_next(byte* page);
/*************************************************************************
Sets the file page type. */
fil_load_single_table_tablespaces(void);
/*===================================*/
/* out: DB_SUCCESS or error number */
/************************************************************************
If we need crash recovery, and we have called
fil_load_single_table_tablespaces() and dict_load_single_table_tablespaces(),
we can call this function to print an error message of orphaned .ibd files
for which there is not a data dictionary entry with a matching table name
and space id. */
void
fil_page_set_type(
/*==============*/
byte* page, /* in: file page */
ulint type); /* in: type */
/*************************************************************************
Gets the file page type. */
fil_print_orphaned_tablespaces(void);
/*================================*/
/***********************************************************************
Returns TRUE if a single-table tablespace does not exist in the memory cache,
or is being deleted there. */
ulint
fil_page_get_type(
/*==============*/
/* out: type; NOTE that if the type has not been
written to page, the return value not defined */
byte* page); /* in: file page */
ibool
fil_tablespace_deleted_or_being_deleted_in_mem(
/*===========================================*/
/* out: TRUE if does not exist or is being\
deleted */
ulint id, /* in: space id */
ib_longlong version);/* in: tablespace_version should be this; if
you pass -1 as the value of this, then this
parameter is ignored */
/***********************************************************************
Returns TRUE if a single-table tablespace exists in the memory cache. */
ibool
fil_tablespace_exists_in_mem(
/*=========================*/
/* out: TRUE if exists */
ulint id); /* in: space id */
/***********************************************************************
Returns TRUE if a matching tablespace exists in the InnoDB tablespace memory
cache. Note that if we have not done a crash recovery at the database startup,
there may be many tablespaces which are not yet in the memory cache. */
ibool
fil_space_for_table_exists_in_mem(
/*==============================*/
/* out: TRUE if a matching tablespace
exists in the memory cache */
ulint id, /* in: space id */
char* name, /* in: table name in the standard
'databasename/tablename' format */
ibool mark_space, /* in: in crash recovery, at database startup
we mark all spaces which have an associated
table in the InnoDB data dictionary, so that
we can print a warning about orphaned
tablespaces */
ibool print_error_if_does_not_exist);
/* in: print detailed error information to
the .err log if a matching tablespace is
not found from memory */
/**************************************************************************
Tries to extend a data file by the number of pages given. Fractions of 1 MB
are ignored. The tablespace must be cached in the memory cache. */
ibool
fil_extend_last_data_file(
/*======================*/
/* out: TRUE if success, also if we run
out of disk space we may return TRUE */
ulint* actual_increase,/* out: number of pages we were able to
extend, here the original size of the file and
the resulting size of the file are rounded
downwards to a full megabyte, and the
difference expressed in pages is returned */
ulint space_id, /* in: space id */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_increase); /* in: try to extend this many pages */
/**************************************************************************
Tries to extend a data file so that it would accommodate the number of pages
given. The tablespace must be cached in the memory cache. */
ibool
fil_extend_data_file_with_pages(
/*============================*/
/* out: TRUE if success */
ulint space_id, /* in: space id, must be != 0 */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_after_extend);/* in: desired size in pages after the
extension, should be less than 4 GB (this
function is primarily intended for increasing
the data file size from < 64 pages to up to
64 pages) */
/***********************************************************************
Tries to reserve free extents in a file space. */
@ -394,6 +450,152 @@ ulint
fil_space_get_n_reserved_extents(
/*=============================*/
ulint id); /* in: space id */
/************************************************************************
Reads or writes data. This operation is asynchronous (aio). */
ulint
fil_io(
/*===*/
/* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
if we are trying to do i/o on a tablespace
which does not exist */
ulint type, /* in: OS_FILE_READ or OS_FILE_WRITE,
ORed to OS_FILE_LOG, if a log i/o
and ORed to OS_AIO_SIMULATED_WAKE_LATER
if simulated aio and we want to post a
batch of i/os; NOTE that a simulated batch
may introduce hidden chances of deadlocks,
because i/os are not actually handled until
all have been posted: use with great
caution! */
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
ulint len, /* in: how many bytes to read or write; this
must not cross a file boundary; in aio this
must be a block size multiple */
void* buf, /* in/out: buffer where to store read data
or from where to write; in aio this must be
appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/************************************************************************
Reads data from a space to a buffer. Remember that the possible incomplete
blocks at the end of file are ignored: they are not taken into account when
calculating the byte offset within a space. */
ulint
fil_read(
/*=====*/
/* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
if we are trying to do i/o on a tablespace
which does not exist */
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in aio
this must be divisible by the OS block size */
ulint len, /* in: how many bytes to read; this must not
cross a file boundary; in aio this must be a
block size multiple */
void* buf, /* in/out: buffer where to store data read;
in aio this must be appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/************************************************************************
Writes data to a space from a buffer. Remember that the possible incomplete
blocks at the end of file are ignored: they are not taken into account when
calculating the byte offset within a space. */
ulint
fil_write(
/*======*/
/* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
if we are trying to do i/o on a tablespace
which does not exist */
ibool sync, /* in: TRUE if synchronous aio is desired */
ulint space_id, /* in: space id */
ulint block_offset, /* in: offset in number of blocks */
ulint byte_offset, /* in: remainder of offset in bytes; in aio
this must be divisible by the OS block size */
ulint len, /* in: how many bytes to write; this must
not cross a file boundary; in aio this must
be a block size multiple */
void* buf, /* in: buffer from which to write; in aio
this must be appropriately aligned */
void* message); /* in: message for aio handler if non-sync
aio used, else ignored */
/**************************************************************************
Waits for an aio operation to complete. This function is used to write the
handler for completed requests. The aio array of pending requests is divided
into segments (see os0file.c for more info). The thread specifies which
segment it wants to wait for. */
void
fil_aio_wait(
/*=========*/
ulint segment); /* in: the number of the segment in the aio
array to wait for */
/**************************************************************************
Flushes to disk possible writes cached by the OS. If the space does not exist
or is being dropped, does not do anything. */
void
fil_flush(
/*======*/
ulint space_id); /* in: file space id (this can be a group of
log files or a tablespace of the database) */
/**************************************************************************
Flushes to disk writes in file spaces of the given type possibly cached by
the OS. */
void
fil_flush_file_spaces(
/*==================*/
ulint purpose); /* in: FIL_TABLESPACE, FIL_LOG */
/**********************************************************************
Checks the consistency of the tablespace cache. */
ibool
fil_validate(void);
/*==============*/
/* out: TRUE if ok */
/************************************************************************
Returns TRUE if file address is undefined. */
ibool
fil_addr_is_null(
/*=============*/
/* out: TRUE if undefined */
fil_addr_t addr); /* in: address */
/************************************************************************
Accessor functions for a file page */
ulint
fil_page_get_prev(byte* page);
ulint
fil_page_get_next(byte* page);
/*************************************************************************
Sets the file page type. */
void
fil_page_set_type(
/*==============*/
byte* page, /* in: file page */
ulint type); /* in: type */
/*************************************************************************
Gets the file page type. */
ulint
fil_page_get_type(
/*==============*/
/* out: type; NOTE that if the type has not been
written to page, the return value not defined */
byte* page); /* in: file page */
typedef struct fil_space_struct fil_space_t;

View File

@ -55,7 +55,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 */
/**************************************************************************
Gets the size of the tablespace from the tablespace header. If we do not
have an auto-extending data file, this should be equal to the size of the
@ -65,9 +65,27 @@ ulint
fsp_header_get_tablespace_size(
/*===========================*/
/* out: size in pages */
ulint space); /* in: space id */
ulint space); /* in: space id, must be 0 */
/**************************************************************************
Initializes the space header of a new created space. */
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 */
/**************************************************************************
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 */
/**************************************************************************
Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0. */
void
fsp_header_init(
@ -117,12 +135,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 */
/**************************************************************************
Calculates the number of pages reserved by a segment, and how many pages are
@ -194,12 +212,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 */
@ -337,8 +364,8 @@ pages: */
#define FSP_FIRST_INODE_PAGE_NO 2
#define FSP_IBUF_HEADER_PAGE_NO 3
#define FSP_IBUF_TREE_ROOT_PAGE_NO 4
/* The ibuf tree root page number in each
tablespace; its fseg inode is on the page
/* The ibuf tree root page number in
tablespace 0; its fseg inode is on the page
number FSP_FIRST_INODE_PAGE_NO */
#define FSP_TRX_SYS_PAGE_NO 5
#define FSP_FIRST_RSEG_PAGE_NO 6

View File

@ -23,7 +23,7 @@ Created 11/28/1995 Heikki Tuuri
#define FLST_FIRST 4 /* 6-byte address of the first element
of the list; undefined if empty list */
#define FLST_LAST (4 + FIL_ADDR_SIZE) /* 6-byte address of the
first element of the list; undefined
last element of the list; undefined
if empty list */
/************************************************************************

View File

@ -40,6 +40,13 @@ void
ibuf_init_at_db_start(void);
/*=======================*/
/*************************************************************************
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);
/*===============================*/
/*************************************************************************
Initializes an ibuf bitmap page. */
void
@ -207,8 +214,8 @@ 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; note that there can exist entries if the page belonged to
an index which was dropped. */
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(
@ -216,7 +223,21 @@ 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 */
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 */
/*************************************************************************
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 */
/*************************************************************************
Contracts insert buffer trees by reading pages to the buffer pool. */
@ -266,6 +287,13 @@ ibuf_count_get(
ulint space, /* in: space id */
ulint page_no);/* in: page number */
/**********************************************************************
Looks if the insert buffer is empty. */
ibool
ibuf_is_empty(void);
/*===============*/
/* out: TRUE if empty */
/**********************************************************************
Prints info of ibuf. */
void

View File

@ -534,12 +534,12 @@ extern lock_sys_t* lock_sys;
#define LOCK_X 5 /* exclusive */
#define LOCK_AUTO_INC 6 /* locks the auto-inc counter of a table
in an exclusive mode */
#define LOCK_MODE_MASK 0xF /* mask used to extract mode from the
#define LOCK_MODE_MASK 0xFUL /* mask used to extract mode from the
type_mode field in a lock */
/* Lock types */
#define LOCK_TABLE 16 /* these type values should be so high that */
#define LOCK_REC 32 /* they can be ORed to the lock mode */
#define LOCK_TYPE_MASK 0xF0 /* mask used to extract lock type from the
#define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the
type_mode field in a lock */
/* Waiting lock flag */
#define LOCK_WAIT 256 /* this wait bit should be so high that

View File

@ -519,9 +519,9 @@ Peeks the current lsn. */
ibool
log_peek_lsn(
/*=========*/
/* out: TRUE if success, FALSE if could not get the
log system mutex */
dulint* lsn); /* out: if returns TRUE, current lsn is here */
/* out: TRUE if success, FALSE if could not get the
log system mutex */
dulint* lsn); /* out: if returns TRUE, current lsn is here */
/**************************************************************************
Refreshes the statistics used to print per-second averages. */
@ -549,7 +549,7 @@ extern log_t* log_sys;
highest bit is set to 1 if this is the
first log block in a log flush write
segment */
#define LOG_BLOCK_FLUSH_BIT_MASK 0x80000000
#define LOG_BLOCK_FLUSH_BIT_MASK 0x80000000UL
/* mask used to get the highest bit in
the preceding field */
#define LOG_BLOCK_HDR_DATA_LEN 4 /* number of bytes of log written to
@ -600,12 +600,18 @@ extern log_t* log_sys;
#define LOG_CHECKPOINT_CHECKSUM_1 LOG_CHECKPOINT_ARRAY_END
#define LOG_CHECKPOINT_CHECKSUM_2 (4 + LOG_CHECKPOINT_ARRAY_END)
#define LOG_CHECKPOINT_FSP_FREE_LIMIT (8 + LOG_CHECKPOINT_ARRAY_END)
/* current fsp free limit in the
tablespace, in units of one megabyte */
/* current fsp free limit in
tablespace 0, in units of one
megabyte; this information is only used
by ibbackup to decide if it can
truncate unused ends of
non-auto-extending data files in space
0 */
#define LOG_CHECKPOINT_FSP_MAGIC_N (12 + LOG_CHECKPOINT_ARRAY_END)
/* this magic number tells if the
checkpoint contains the above field:
the field was added to InnoDB-3.23.50 */
the field was added to
InnoDB-3.23.50 */
#define LOG_CHECKPOINT_SIZE (16 + LOG_CHECKPOINT_ARRAY_END)
#define LOG_CHECKPOINT_FSP_MAGIC_N_VAL 1441231243
@ -794,11 +800,11 @@ struct log_struct{
called */
/* Fields involved in checkpoints */
ulint log_group_capacity; /* capacity of the log group; if
the checkpoint age exceeds this, it is
a serious error because it is possible
we will then overwrite log and spoil
crash recovery */
ulint log_group_capacity; /* capacity of the log group; if
the checkpoint age exceeds this, it is
a serious error because it is possible
we will then overwrite log and spoil
crash recovery */
ulint max_modified_age_async;
/* when this recommended value for lsn
- buf_pool_get_oldest_modification()
@ -840,7 +846,8 @@ struct log_struct{
/* Fields involved in archiving */
ulint archiving_state;/* LOG_ARCH_ON, LOG_ARCH_STOPPING
LOG_ARCH_STOPPED, LOG_ARCH_OFF */
dulint archived_lsn; /* archiving has advanced to this lsn */
dulint archived_lsn; /* archiving has advanced to this
lsn */
ulint max_archived_lsn_age_async;
/* recommended maximum age of
archived_lsn, before we start

View File

@ -182,9 +182,9 @@ log_block_convert_lsn_to_no(
no = ut_dulint_get_low(lsn) / OS_FILE_LOG_BLOCK_SIZE;
no += (ut_dulint_get_high(lsn) % OS_FILE_LOG_BLOCK_SIZE)
* 2 * (0x80000000 / OS_FILE_LOG_BLOCK_SIZE);
* 2 * (0x80000000UL / OS_FILE_LOG_BLOCK_SIZE);
no = no & 0x3FFFFFFF;
no = no & 0x3FFFFFFFUL;
return(no + 1);
}
@ -206,7 +206,7 @@ log_block_calc_checksum(
sh = 0;
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
sum = sum & 0x7FFFFFFF;
sum = sum & 0x7FFFFFFFUL;
sum += (((ulint)(*(block + i))) << sh) + (ulint)(*(block + i));
sh++;
if (sh > 24) {
@ -346,7 +346,7 @@ log_reserve_and_write_fast(
#ifdef UNIV_LOG_DEBUG
log_check_log_recs(log->buf + log->old_buf_free,
log->buf_free - log->old_buf_free, log->old_lsn);
log->buf_free - log->old_buf_free, log->old_lsn);
#endif
return(lsn);
}

View File

@ -25,8 +25,8 @@ recv_read_cp_info_for_backup(
byte* hdr, /* in: buffer containing the log group header */
dulint* lsn, /* out: checkpoint lsn */
ulint* offset, /* out: checkpoint offset in the log group */
ulint* fsp_limit,/* out: fsp limit, 1000000000 if the database
is running with < version 3.23.50 of InnoDB */
ulint* fsp_limit,/* out: fsp limit of space 0, 1000000000 if the
database is running with < version 3.23.50 of InnoDB */
dulint* cp_no, /* out: checkpoint number */
dulint* first_header_lsn);
/* out: lsn of of the start of the first log file */
@ -334,7 +334,6 @@ extern ibool recv_no_ibuf_operations;
extern ibool recv_needed_recovery;
extern ibool recv_lsn_checks_on;
extern ibool recv_is_making_a_backup;
extern ulint recv_max_parsed_page_no;

View File

@ -17,7 +17,7 @@ mach_write_to_1(
ulint n) /* in: ulint integer to be stored, >= 0, < 256 */
{
ut_ad(b);
ut_ad(n <= 0xFF);
ut_ad(n <= 0xFFUL);
b[0] = (byte)n;
}
@ -46,7 +46,7 @@ mach_write_to_2(
ulint n) /* in: ulint integer to be stored */
{
ut_ad(b);
ut_ad(n <= 0xFFFF);
ut_ad(n <= 0xFFFFUL);
b[0] = (byte)(n >> 8);
b[1] = (byte)(n);
@ -79,7 +79,7 @@ mach_write_to_3(
ulint n) /* in: ulint integer to be stored */
{
ut_ad(b);
ut_ad(n <= 0xFFFFFF);
ut_ad(n <= 0xFFFFFFUL);
b[0] = (byte)(n >> 16);
b[1] = (byte)(n >> 8);
@ -222,20 +222,20 @@ mach_write_compressed(
{
ut_ad(b);
if (n < 0x80) {
if (n < 0x80UL) {
mach_write_to_1(b, n);
return(1);
} else if (n < 0x4000) {
mach_write_to_2(b, n | 0x8000);
} else if (n < 0x4000UL) {
mach_write_to_2(b, n | 0x8000UL);
return(2);
} else if (n < 0x200000) {
mach_write_to_3(b, n | 0xC00000);
} else if (n < 0x200000UL) {
mach_write_to_3(b, n | 0xC00000UL);
return(3);
} else if (n < 0x10000000) {
mach_write_to_4(b, n | 0xE0000000);
} else if (n < 0x10000000UL) {
mach_write_to_4(b, n | 0xE0000000UL);
return(4);
} else {
mach_write_to_1(b, 0xF0);
mach_write_to_1(b, 0xF0UL);
mach_write_to_4(b + 1, n);
return(5);
}
@ -250,13 +250,13 @@ mach_get_compressed_size(
/* out: compressed size in bytes */
ulint n) /* in: ulint integer (< 2^32) to be stored */
{
if (n < 0x80) {
if (n < 0x80UL) {
return(1);
} else if (n < 0x4000) {
} else if (n < 0x4000UL) {
return(2);
} else if (n < 0x200000) {
} else if (n < 0x200000UL) {
return(3);
} else if (n < 0x10000000) {
} else if (n < 0x10000000UL) {
return(4);
} else {
return(5);
@ -278,16 +278,16 @@ mach_read_compressed(
flag = mach_read_from_1(b);
if (flag < 0x80) {
if (flag < 0x80UL) {
return(flag);
} else if (flag < 0xC0) {
return(mach_read_from_2(b) & 0x7FFF);
} else if (flag < 0xE0) {
return(mach_read_from_3(b) & 0x3FFFFF);
} else if (flag < 0xF0) {
return(mach_read_from_4(b) & 0x1FFFFFFF);
} else if (flag < 0xC0UL) {
return(mach_read_from_2(b) & 0x7FFFUL);
} else if (flag < 0xE0UL) {
return(mach_read_from_3(b) & 0x3FFFFFUL);
} else if (flag < 0xF0UL) {
return(mach_read_from_4(b) & 0x1FFFFFFFUL);
} else {
ut_ad(flag == 0xF0);
ut_ad(flag == 0xF0UL);
return(mach_read_from_4(b + 1));
}
}
@ -477,7 +477,7 @@ mach_dulint_write_much_compressed(
return(mach_write_compressed(b, ut_dulint_get_low(n)));
}
*b = 0xFF;
*b = (byte)0xFF;
size = 1 + mach_write_compressed(b + 1, ut_dulint_get_high(n));
size += mach_write_compressed(b + size, ut_dulint_get_low(n));
@ -517,7 +517,7 @@ mach_dulint_read_much_compressed(
ut_ad(b);
if (*b != 0xFF) {
if (*b != (byte)0xFF) {
high = 0;
size = 0;
} else {
@ -717,11 +717,10 @@ mach_write_to_2_little_endian(
{
ut_ad(n < 256 * 256);
*dest = (byte)(n & 0xFF);
*dest = (byte)(n & 0xFFUL);
n = n >> 8;
dest++;
*dest = (byte)(n & 0xFF);
*dest = (byte)(n & 0xFFUL);
}

View File

@ -163,13 +163,6 @@ mlog_write_initial_log_record_fast(
space = buf_block_get_space(block);
offset = buf_block_get_page_no(block);
if (space != 0 || offset > 0x8FFFFFFF) {
fprintf(stderr,
"InnoDB: error: buffer page pointer %lx has nonsensical space id %lu\n"
"InnoDB: or page no %lu\n", (ulint)ptr, space, offset);
ut_a(0);
}
mach_write_to_1(log_ptr, type);
log_ptr++;
log_ptr += mach_write_compressed(log_ptr, space);

View File

@ -11,9 +11,11 @@ Created 10/21/1995 Heikki Tuuri
#include "univ.i"
#ifndef __WIN__
#include <dirent.h>
#include <sys/stat.h>
#endif
/* If the following is set to TRUE, we do not call os_file_flush in every
os_file_write */
extern ibool os_do_not_call_flush_at_each_write;
extern ibool os_has_said_disk_full;
extern ibool os_aio_print_debug;
@ -57,6 +59,7 @@ log. */
#define OS_FILE_OPEN 51
#define OS_FILE_CREATE 52
#define OS_FILE_OVERWRITE 53
#define OS_FILE_OPEN_RAW 54
#define OS_FILE_READ_ONLY 333
#define OS_FILE_READ_WRITE 444
@ -117,6 +120,36 @@ extern ulint os_n_file_reads;
extern ulint os_n_file_writes;
extern ulint os_n_fsyncs;
/* File types for directory entry data type */
enum os_file_type_enum{
OS_FILE_TYPE_UNKNOWN = 0,
OS_FILE_TYPE_FILE, /* regular file */
OS_FILE_TYPE_DIR, /* directory */
OS_FILE_TYPE_LINK /* symbolic link */
};
typedef enum os_file_type_enum os_file_type_t;
/* Maximum path string length in bytes when referring to tables with in the
'./databasename/tablename.ibd' path format; we can allocate at least 2 buffers
of this size from the thread stack; that is why this should not be made much
bigger than 4000 bytes */
#define OS_FILE_MAX_PATH 4000
/* Struct used in fetching information of a file in a directory */
typedef struct os_file_stat_struct os_file_stat_t;
struct os_file_stat_struct{
char name[OS_FILE_MAX_PATH]; /* path to a file */
os_file_type_t type; /* file type */
ib_longlong size; /* file size */
};
#ifdef __WIN___
typedef HANDLE os_file_dir_t; /* directory stream */
#else
typedef DIR* os_file_dir_t; /* directory stream */
#endif
/***************************************************************************
Gets the operating system version. Currently works only on Windows. */
@ -130,6 +163,42 @@ Creates the seek mutexes used in positioned reads and writes. */
void
os_io_init_simple(void);
/*===================*/
/***************************************************************************
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing. */
os_file_dir_t
os_file_opendir(
/*============*/
/* out: directory stream, NULL if error */
char* dirname, /* in: directory name; it must not contain
a trailing '\' or '/' */
ibool error_is_fatal);/* in: TRUE if we should treat an error as a
fatal error; if we try to open symlinks then
we do not wish a fatal error if it happens
not to be a directory */
/***************************************************************************
Closes a directory stream. */
int
os_file_closedir(
/*=============*/
/* out: 0 if success, -1 if failure */
os_file_dir_t dir); /* in: directory stream */
/***************************************************************************
This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory. */
int
os_file_readdir_next_file(
/*======================*/
/* out: 0 if ok, -1 if error, 1 if at the end
of the directory */
char* dirname,/* in: directory name or path */
os_file_dir_t dir, /* in: directory stream */
os_file_stat_t* info); /* in/out: buffer where the info is returned */
/********************************************************************
A simple function to open or create a file. */
@ -173,7 +242,9 @@ os_file_create(
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
(if does not exist, error), or OS_FILE_CREATE if a new
file is created (if exists, error), OS_FILE_OVERWRITE
if a new file is created or an old overwritten */
if a new file is created or an old overwritten;
OS_FILE_OPEN_RAW, if a raw device or disk partition
should be opened */
ulint purpose,/* in: OS_FILE_AIO, if asynchronous, non-buffered i/o
is desired, OS_FILE_NORMAL, if any normal file;
NOTE that it also depends on type, os_aio_.. and srv_..
@ -183,6 +254,25 @@ os_file_create(
ulint type, /* in: OS_DATA_FILE or OS_LOG_FILE */
ibool* success);/* out: TRUE if succeed, FALSE if error */
/***************************************************************************
Deletes a file. The file has to be closed before calling this. */
ibool
os_file_delete(
/*===========*/
/* out: TRUE if success */
char* name); /* in: file path as a null-terminated string */
/***************************************************************************
Renames a file (can also move it to another directory). It is safest that the
file is closed before calling this function. */
ibool
os_file_rename(
/*===========*/
/* out: TRUE if success */
char* oldpath, /* in: old file path as a null-terminated
string */
char* newpath); /* in: new file path */
/***************************************************************************
Closes a file handle. In case of error, error number can be retrieved with
os_file_get_last_error. */
@ -238,9 +328,12 @@ overwrite the error number). If the number is not known to this program,
the OS error number + 100 is returned. */
ulint
os_file_get_last_error(void);
/*========================*/
/* out: error number, or OS error number + 100 */
os_file_get_last_error(
/*===================*/
/* out: error number, or OS error
number + 100 */
ibool report_all_errors); /* in: TRUE if we want an error message
printed of all errors */
/***********************************************************************
Requests a synchronous read operation. */

View File

@ -596,7 +596,8 @@ byte*
page_parse_delete_rec_list(
/*=======================*/
/* out: end of log record or NULL */
byte type, /* in: MLOG_LIST_END_DELETE or MLOG_LIST_START_DELETE */
byte type, /* in: MLOG_LIST_END_DELETE or
MLOG_LIST_START_DELETE */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
page_t* page, /* in: page or NULL */

View File

@ -36,7 +36,8 @@ struct que_common_struct{
if the buffer has been allocated dynamically:
if this field is != 0, and the node is a
symbol node or a function node, then we
have to free the data field in val explicitly */
have to free the data field in val
explicitly */
};
#endif

View File

@ -21,7 +21,7 @@ Created 5/30/1994 Heikki Tuuri
/* Flag denoting the predefined minimum record: this bit is ORed in the 4
info bits of a record */
#define REC_INFO_MIN_REC_FLAG 0x10
#define REC_INFO_MIN_REC_FLAG 0x10UL
/* Number of extra bytes in a record, in addition to the data and the
offsets */
@ -406,8 +406,8 @@ rec_sprintf(
/* Maximum lengths for the data in a physical record if the offsets
are given in one byte (resp. two byte) format. */
#define REC_1BYTE_OFFS_LIMIT 0x7F
#define REC_2BYTE_OFFS_LIMIT 0x7FFF
#define REC_1BYTE_OFFS_LIMIT 0x7FUL
#define REC_2BYTE_OFFS_LIMIT 0x7FFFUL
/* The data size of record must be smaller than this because we reserve
two upmost bits in a two byte offset for special purposes */

View File

@ -29,41 +29,41 @@ significant bytes and bits are written below less significant.
and the shift needed to obtain each bit-field of the record. */
#define REC_NEXT 2
#define REC_NEXT_MASK 0xFFFF
#define REC_NEXT_MASK 0xFFFFUL
#define REC_NEXT_SHIFT 0
#define REC_SHORT 3 /* This is single byte bit-field */
#define REC_SHORT_MASK 0x1
#define REC_SHORT_MASK 0x1UL
#define REC_SHORT_SHIFT 0
#define REC_N_FIELDS 4
#define REC_N_FIELDS_MASK 0x7FE
#define REC_N_FIELDS_MASK 0x7FEUL
#define REC_N_FIELDS_SHIFT 1
#define REC_HEAP_NO 5
#define REC_HEAP_NO_MASK 0xFFF8
#define REC_HEAP_NO_MASK 0xFFF8UL
#define REC_HEAP_NO_SHIFT 3
#define REC_N_OWNED 6 /* This is single byte bit-field */
#define REC_N_OWNED_MASK 0xF
#define REC_N_OWNED_MASK 0xFUL
#define REC_N_OWNED_SHIFT 0
#define REC_INFO_BITS_MASK 0xF0
#define REC_INFO_BITS_MASK 0xF0UL
#define REC_INFO_BITS_SHIFT 0
/* The deleted flag in info bits */
#define REC_INFO_DELETED_FLAG 0x20 /* when bit is set to 1, it means the
#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the
record has been delete marked */
/* The following masks are used to filter the SQL null bit from
one-byte and two-byte offsets */
#define REC_1BYTE_SQL_NULL_MASK 0x80
#define REC_2BYTE_SQL_NULL_MASK 0x8000
#define REC_1BYTE_SQL_NULL_MASK 0x80UL
#define REC_2BYTE_SQL_NULL_MASK 0x8000UL
/* In a 2-byte offset the second most significant bit denotes
a field stored to another page: */
#define REC_2BYTE_EXTERN_MASK 0x4000
#define REC_2BYTE_EXTERN_MASK 0x4000UL
/****************************************************************
Return field length or UNIV_SQL_NULL. */
@ -133,7 +133,7 @@ rec_set_bit_field_1(
ut_ad(rec);
ut_ad(offs <= REC_N_EXTRA_BYTES);
ut_ad(mask);
ut_ad(mask <= 0xFF);
ut_ad(mask <= 0xFFUL);
ut_ad(((mask >> shift) << shift) == mask);
ut_ad(((val << shift) & mask) == (val << shift));
@ -172,8 +172,8 @@ rec_set_bit_field_2(
{
ut_ad(rec);
ut_ad(offs <= REC_N_EXTRA_BYTES);
ut_ad(mask > 0xFF);
ut_ad(mask <= 0xFFFF);
ut_ad(mask > 0xFFUL);
ut_ad(mask <= 0xFFFFUL);
ut_ad((mask >> shift) & 1);
ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1)));
ut_ad(((mask >> shift) << shift) == mask);
@ -188,8 +188,8 @@ rec_set_bit_field_2(
+ (REC_N_FIELDS_MASK << (8 * (REC_N_FIELDS - 4)))
+ (REC_HEAP_NO_MASK << (8 * (REC_HEAP_NO - 4)))
+ (REC_N_OWNED_MASK << (8 * (REC_N_OWNED - 3)))
+ (REC_INFO_BITS_MASK << (8 * (REC_INFO_BITS - 3))));
if (m != ut_dbg_zero + 0xFFFFFFFF) {
+ (REC_INFO_BITS_MASK << (8 * (REC_INFO_BITS - 3))));
if (m != ut_dbg_zero + 0xFFFFFFFFUL) {
printf("Sum of masks %lx\n", m);
ut_error;
}

View File

@ -17,6 +17,8 @@ Created 10/10/1995 Heikki Tuuri
#include "que0types.h"
#include "trx0types.h"
extern char* srv_main_thread_op_info;
/* Buffer which can be used in printing fatal error messages */
extern char srv_fatal_errbuf[];
@ -36,6 +38,8 @@ extern ibool srv_lower_case_table_names;
extern char* srv_data_home;
extern char* srv_arch_dir;
extern ibool srv_file_per_table;
extern ulint srv_n_data_files;
extern char** srv_data_file_names;
extern ulint* srv_data_file_sizes;
@ -76,6 +80,8 @@ extern char* srv_file_flush_method_str;
extern ulint srv_unix_file_flush_method;
extern ulint srv_win_file_flush_method;
extern ulint srv_max_n_open_files;
extern ulint srv_max_dirty_pages_pct;
extern ulint srv_force_recovery;

View File

@ -11,6 +11,7 @@ Created 10/10/1995 Heikki Tuuri
#define srv0start_h
#include "univ.i"
#include "ut0byte.h"
/*************************************************************************
Normalizes a directory path for Windows: converts slashes to backslashes. */
@ -79,12 +80,17 @@ innobase_shutdown_for_mysql(void);
/*=============================*/
/* out: DB_SUCCESS or error code */
extern dulint srv_shutdown_lsn;
extern dulint srv_start_lsn;
extern ulint srv_sizeof_trx_t_in_ha_innodb_cc;
extern ibool srv_is_being_started;
extern ibool srv_startup_is_before_trx_rollback_phase;
extern ibool srv_is_being_shut_down;
extern ibool srv_start_raw_disk_in_use;
/* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP
and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
@ -94,4 +100,7 @@ extern ulint srv_shutdown_state;
#define SRV_SHUTDOWN_LAST_PHASE 2
#define SRV_SHUTDOWN_EXIT_THREADS 3
/* Log 'spaces' have id's >= this */
#define SRV_LOG_SPACE_FIRST_ID 0xFFFFFFF0UL
#endif

View File

@ -381,8 +381,8 @@ or row lock! */
#define SYNC_IBUF_HEADER 914
#define SYNC_IBUF_PESS_INSERT_MUTEX 912
#define SYNC_IBUF_MUTEX 910 /* ibuf mutex is really below
SYNC_FSP_PAGE: we assign value this
high only to get the program to pass
SYNC_FSP_PAGE: we assign a value this
high only to make the program to pass
the debug checks */
/*-------------------------------*/
#define SYNC_INDEX_TREE 900
@ -401,7 +401,7 @@ or row lock! */
#define SYNC_FSP_PAGE 395
/*------------------------------------- Insert buffer headers */
/*------------------------------------- ibuf_mutex */
/*------------------------------------- Insert buffer trees */
/*------------------------------------- Insert buffer tree */
#define SYNC_IBUF_BITMAP_MUTEX 351
#define SYNC_IBUF_BITMAP 350
/*-------------------------------*/

View File

@ -37,21 +37,35 @@ extern trx_sys_t* trx_sys;
/* Doublewrite system */
extern trx_doublewrite_t* trx_doublewrite;
extern ibool trx_doublewrite_must_reset_space_ids;
extern ibool trx_sys_multiple_tablespace_format;
/********************************************************************
Creates the doublewrite buffer at a database start. The header of the
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
void
trx_sys_create_doublewrite_buf(void);
/*================================*/
/********************************************************************
At a database startup uses a possible doublewrite buffer to restore
At a database startup initializes the doublewrite buffer memory structure if
we already have a doublewrite buffer created in the data files. If we are
upgrading to an InnoDB version which supports multiple tablespaces, then this
function performs the necessary update operations. If we are in a crash
recovery, this function uses a possible doublewrite buffer to restore
half-written pages in the data files. */
void
trx_sys_doublewrite_restore_corrupt_pages(void);
/*===========================================*/
trx_sys_doublewrite_init_or_restore_pages(
/*======================================*/
ibool restore_corrupt_pages);
/********************************************************************
Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
multiple tablespace format. */
void
trx_sys_mark_upgraded_to_multiple_tablespaces(void);
/*===============================================*/
/********************************************************************
Determines if a page number is located inside the doublewrite buffer. */
@ -354,8 +368,17 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
sys header is half-written
to disk, we still may be able
to recover the information */
#define TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED (24 + FSEG_HEADER_SIZE)
/* If this is not yet set to
.._N, we must reset the
doublewrite buffer, because
starting from 4.1.x the space
id of a data page is stored to
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO */
/*-------------------------------------------------------------*/
#define TRX_SYS_DOUBLEWRITE_MAGIC_N 536853855
#define TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N 1783657386
#define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE

View File

@ -88,10 +88,9 @@ memory is read outside the allocated blocks. */
/*
#define UNIV_DEBUG
#define UNIV_SYNC_DEBUG
#define UNIV_MEM_DEBUG
#define UNIV_IBUF_DEBUG
#define UNIV_SYNC_DEBUG
#define UNIV_SEARCH_DEBUG
#define UNIV_SYNC_PERF_STAT
#define UNIV_SEARCH_PERF_STAT

View File

@ -152,7 +152,7 @@ ut_dulint_align_up(
Increments a dulint variable by 1. */
#define UT_DULINT_INC(D)\
{\
if ((D).low == 0xFFFFFFFF) {\
if ((D).low == 0xFFFFFFFFUL) {\
(D).high = (D).high + 1;\
(D).low = 0;\
} else {\

View File

@ -152,13 +152,13 @@ ut_dulint_add(
dulint a, /* in: dulint */
ulint b) /* in: ulint */
{
if (0xFFFFFFFF - b >= a.low) {
if (0xFFFFFFFFUL - b >= a.low) {
a.low += b;
return(a);
}
a.low = a.low - (0xFFFFFFFF - b) - 1;
a.low = a.low - (0xFFFFFFFFUL - b) - 1;
a.high++;
@ -183,7 +183,7 @@ ut_dulint_subtract(
b -= a.low + 1;
a.low = 0xFFFFFFFF - b;
a.low = 0xFFFFFFFFUL - b;
ut_ad(a.high > 0);
@ -214,7 +214,7 @@ ut_dulint_minus(
ut_ad(a.high == b.high + 1);
diff = (ulint)(0xFFFFFFFF - b.low);
diff = (ulint)(0xFFFFFFFFUL - b.low);
diff += 1 + a.low;
ut_ad(diff > a.low);

View File

@ -110,7 +110,7 @@ ut_2pow_remainder(
ulint n, /* in: number to be divided */
ulint m) /* in: divisor; power of 2 */
{
ut_ad(0x80000000 % m == 0);
ut_ad(0x80000000UL % m == 0);
return(n & (m - 1));
}
@ -125,7 +125,7 @@ ut_2pow_round(
ulint n, /* in: number to be rounded */
ulint m) /* in: divisor; power of 2 */
{
ut_ad(0x80000000 % m == 0);
ut_ad(0x80000000UL % m == 0);
return(n & ~(m - 1));
}

View File

@ -24,7 +24,8 @@ Created 12/9/1995 Heikki Tuuri
#include "trx0sys.h"
#include "trx0trx.h"
/* Current free limit; protected by the log sys mutex; 0 means uninitialized */
/* Current free limit of space 0; protected by the log sys mutex; 0 means
uninitialized */
ulint log_fsp_current_free_limit = 0;
/* Global log system variable */
@ -195,11 +196,10 @@ loop:
if (log->archiving_state != LOG_ARCH_OFF) {
archived_lsn_age = ut_dulint_minus(log->lsn, log->archived_lsn);
archived_lsn_age = ut_dulint_minus(log->lsn,
log->archived_lsn);
if (archived_lsn_age + len_upper_limit
> log->max_archived_lsn_age) {
/* Not enough free archived space in log groups: do a
synchronous archive write batch: */
@ -466,7 +466,8 @@ ulint
log_group_calc_lsn_offset(
/*======================*/
/* out: offset within the log group */
dulint lsn, /* in: lsn, must be within 4 GB of group->lsn */
dulint lsn, /* in: lsn, must be within 4 GB of
group->lsn */
log_group_t* group) /* in: log group */
{
dulint gr_lsn;
@ -978,7 +979,7 @@ log_io_complete(
return;
}
if ((ulint)group & 0x1) {
if ((ulint)group & 0x1UL) {
/* It was a checkpoint write */
group = (log_group_t*)((ulint)group - 1);
@ -1132,7 +1133,8 @@ loop:
if ((next_offset % group->file_size) + len > group->file_size) {
write_len = group->file_size - (next_offset % group->file_size);
write_len = group->file_size
- (next_offset % group->file_size);
} else {
write_len = len;
}
@ -1681,7 +1683,7 @@ log_group_checkpoint(
OS_FILE_LOG_BLOCK_SIZE,
buf, ((byte*)group + 1));
ut_ad(((ulint)group & 0x1) == 0);
ut_ad(((ulint)group & 0x1UL) == 0);
}
}
@ -2205,7 +2207,6 @@ loop:
log_archived_file_name_gen(name, group->id,
group->archived_file_no + n_files);
fil_reserve_right_to_open();
file_handle = os_file_create(name, open_mode, OS_FILE_AIO,
OS_DATA_FILE, &ret);
@ -2216,10 +2217,10 @@ loop:
}
if (!ret) {
fprintf(stderr,
fprintf(stderr,
"InnoDB: Cannot create or open archive log file %s.\n",
name);
fprintf(stderr, "InnoDB: Cannot continue operation.\n"
fprintf(stderr, "InnoDB: Cannot continue operation.\n"
"InnoDB: Check that the log archive directory exists,\n"
"InnoDB: you have access rights to it, and\n"
"InnoDB: there is space available.\n");
@ -2234,12 +2235,10 @@ loop:
ut_a(ret);
fil_release_right_to_open();
/* Add the archive file as a node to the space */
fil_node_create(name, group->file_size / UNIV_PAGE_SIZE,
group->archive_space_id);
group->archive_space_id, FALSE);
if (next_offset % group->file_size == 0) {
log_group_archive_file_header_write(group, n_files,
@ -3085,10 +3084,24 @@ loop:
ut_a(buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
if (ut_dulint_cmp(lsn, srv_start_lsn) < 0) {
fprintf(stderr,
"InnoDB: Error: log sequence number at shutdown %lu %lu\n"
"InnoDB: is lower than at startup %lu %lu!\n",
ut_dulint_get_high(lsn),
ut_dulint_get_low(lsn),
ut_dulint_get_high(srv_start_lsn),
ut_dulint_get_low(srv_start_lsn));
}
srv_shutdown_lsn = lsn;
fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
fil_flush_file_spaces(FIL_TABLESPACE);
fil_close_all_files();
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
ut_a(buf_all_freed());

View File

@ -17,6 +17,7 @@ Created 9/20/1997 Heikki Tuuri
#include "buf0flu.h"
#include "buf0rea.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "mtr0mtr.h"
#include "mtr0log.h"
#include "page0page.h"
@ -73,19 +74,18 @@ ulint recv_previous_parsed_rec_is_multi = 0;
ulint recv_max_parsed_page_no = 0;
/* The maximum lsn we see for a page during the recovery process. If this
is bigger than the lsn we are able to scan up to, that is an indication that
the recovery failed and the database may be corrupt. */
dulint recv_max_page_lsn;
/* This many frames must be left free in the buffer pool when we scan
the log and store the scanned log records in the buffer pool: we will
use these free frames to read in pages when we start applying the
log records to the database. */
ulint recv_n_pool_free_frames = 256;
ulint recv_n_pool_free_frames = 256;
/* The maximum lsn we see for a page during the recovery process. If this
is bigger than the lsn we are able to scan up to, that is an indication that
the recovery failed and the database may be corrupt. */
dulint recv_max_page_lsn;
/************************************************************
Creates the recovery system. */
@ -304,7 +304,8 @@ recv_copy_group(
/*============*/
log_group_t* up_to_date_group, /* in: the most up-to-date log
group */
log_group_t* group, /* in: copy to this log group */
log_group_t* group, /* in: copy to this log
group */
dulint recovered_lsn) /* in: recovery succeeded up
to this lsn */
{
@ -370,7 +371,8 @@ recv_synchronize_groups(
/* Read the last recovered log block to the recovery system buffer:
the block is always incomplete */
start_lsn = ut_dulint_align_down(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE);
start_lsn = ut_dulint_align_down(recovered_lsn,
OS_FILE_LOG_BLOCK_SIZE);
end_lsn = ut_dulint_align_up(recovered_lsn, OS_FILE_LOG_BLOCK_SIZE);
ut_a(ut_dulint_cmp(start_lsn, end_lsn) != 0);
@ -426,7 +428,7 @@ recv_check_cp_is_consistent(
fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
if ((fold & 0xFFFFFFFF) != mach_read_from_4(buf
if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf
+ LOG_CHECKPOINT_CHECKSUM_1)) {
return(FALSE);
}
@ -434,7 +436,7 @@ recv_check_cp_is_consistent(
fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
if ((fold & 0xFFFFFFFF) != mach_read_from_4(buf
if ((fold & 0xFFFFFFFFUL) != mach_read_from_4(buf
+ LOG_CHECKPOINT_CHECKSUM_2)) {
return(FALSE);
}
@ -541,8 +543,8 @@ recv_read_cp_info_for_backup(
byte* hdr, /* in: buffer containing the log group header */
dulint* lsn, /* out: checkpoint lsn */
ulint* offset, /* out: checkpoint offset in the log group */
ulint* fsp_limit,/* out: fsp limit, 1000000000 if the database
is running with < version 3.23.50 of InnoDB */
ulint* fsp_limit,/* out: fsp limit of space 0, 1000000000 if the
database is running with < version 3.23.50 of InnoDB */
dulint* cp_no, /* out: checkpoint number */
dulint* first_header_lsn)
/* out: lsn of of the start of the first log file */
@ -687,7 +689,7 @@ recv_scan_log_seg_for_backup(
< *scanned_checkpoint_no
&& *scanned_checkpoint_no
- log_block_get_checkpoint_no(log_block)
> 0x80000000) {
> 0x80000000UL) {
/* Garbage from a log buffer flush which was made
before the most recent database recovery */
@ -884,9 +886,14 @@ recv_add_to_hash_table(
recv_data_t* recv_data;
recv_data_t** prev_field;
recv_addr_t* recv_addr;
ut_a(space == 0); /* For debugging; TODO: remove this */
if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
/* The tablespace does not exist any more: do not store the
log record */
return;
}
len = rec_end - body;
recv = mem_heap_alloc(recv_sys->heap, sizeof(recv_t));
@ -909,6 +916,9 @@ recv_add_to_hash_table(
HASH_INSERT(recv_addr_t, addr_hash, recv_sys->addr_hash,
recv_fold(space, page_no), recv_addr);
recv_sys->n_addrs++;
/* printf("Inserting log rec for space %lu, page %lu\n",
space, page_no); */
}
UT_LIST_ADD_LAST(rec_list, recv_addr->rec_list, recv);
@ -1025,6 +1035,8 @@ recv_recover_page(
return;
}
/* printf("Recovering space %lu, page %lu\n", space, page_no); */
recv_addr->state = RECV_BEING_PROCESSED;
mutex_exit(&(recv_sys->mutex));
@ -1036,10 +1048,10 @@ recv_recover_page(
block = buf_block_align(page);
if (just_read_in) {
/* 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 operations to
the page to pass the debug checks. */
/* 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 operations to the page to pass the debug
checks. */
rw_lock_x_lock_move_ownership(&(block->lock));
}
@ -1433,7 +1445,7 @@ recv_apply_log_recs_for_backup(
if (recv_addr != NULL) {
success = os_file_read(data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF,
& 0xFFFFFFFFUL,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE);
if (!success) {
@ -1713,7 +1725,7 @@ recv_parse_log_rec(
if (*ptr == MLOG_DUMMY_RECORD) {
*type = *ptr;
*space = 1000; /* For debugging */
*space = ULINT_UNDEFINED - 1; /* For debugging */
return(1);
}
@ -1727,7 +1739,7 @@ recv_parse_log_rec(
/* Check that space id and page_no are sensible */
if (*space != 0 || *page_no > 0x8FFFFFFF) {
if (*page_no > 0x8FFFFFFFUL) {
recv_sys->found_corrupt_log = TRUE;
@ -2265,7 +2277,7 @@ recv_scan_log_recs(
< recv_sys->scanned_checkpoint_no)
&& (recv_sys->scanned_checkpoint_no
- log_block_get_checkpoint_no(log_block)
> 0x80000000)) {
> 0x80000000UL)) {
/* Garbage from a log buffer flush which was made
before the most recent database recovery */
@ -2298,7 +2310,8 @@ recv_scan_log_recs(
if (ut_dulint_cmp(scanned_lsn, recv_sys->scanned_lsn) > 0) {
/* We were able to find more log data: add it to the
parsing buffer if parse_start_lsn is already non-zero */
parsing buffer if parse_start_lsn is already
non-zero */
if (recv_sys->len + 4 * OS_FILE_LOG_BLOCK_SIZE
>= RECV_PARSING_BUF_SIZE) {
@ -2396,8 +2409,8 @@ recv_group_scan_log_recs(
group, start_lsn, end_lsn);
finished = recv_scan_log_recs(TRUE,
(buf_pool->n_frames
- recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
(buf_pool->n_frames
- recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
TRUE, log_sys->buf,
RECV_SCAN_SIZE, start_lsn,
contiguous_lsn, group_scanned_lsn);
@ -2447,7 +2460,6 @@ recv_recovery_from_checkpoint_start(
|| (ut_dulint_cmp(limit_lsn, ut_dulint_max) == 0));
if (type == LOG_CHECKPOINT) {
recv_sys_create();
recv_sys_init(FALSE, buf_pool_get_curr_size());
}
@ -2461,8 +2473,6 @@ recv_recovery_from_checkpoint_start(
return(DB_SUCCESS);
}
sync_order_checks_on = TRUE;
recv_recovery_on = TRUE;
recv_sys->limit_lsn = limit_lsn;
@ -2535,25 +2545,72 @@ recv_recovery_from_checkpoint_start(
recv_sys->scanned_checkpoint_no = 0;
recv_sys->recovered_lsn = checkpoint_lsn;
/* NOTE: we always do recovery at startup, but only if
srv_start_lsn = checkpoint_lsn;
/* NOTE: we always do a 'recovery' at startup, but only if
there is something wrong we will print a message to the
user about recovery: */
if (ut_dulint_cmp(checkpoint_lsn, max_flushed_lsn) != 0
|| ut_dulint_cmp(checkpoint_lsn, min_flushed_lsn) != 0) {
if (ut_dulint_cmp(checkpoint_lsn, max_flushed_lsn)
< 0) {
fprintf(stderr,
"InnoDB: ##########################################################\n"
"InnoDB: WARNING!\n"
"InnoDB: The log sequence number in ibdata files is higher\n"
"InnoDB: than the log sequence number in the ib_logfiles! Are you sure\n"
"InnoDB: you are using the right ib_logfiles to start up the database?\n"
"InnoDB: Log sequence number in ib_logfiles is %lu %lu, log\n"
"InnoDB: sequence numbers stamped to ibdata file headers are between\n"
"InnoDB: %lu %lu and %lu %lu.\n"
"InnoDB: ##########################################################\n",
ut_dulint_get_high(checkpoint_lsn),
ut_dulint_get_low(checkpoint_lsn),
ut_dulint_get_high(min_flushed_lsn),
ut_dulint_get_low(min_flushed_lsn),
ut_dulint_get_high(max_flushed_lsn),
ut_dulint_get_low(max_flushed_lsn));
}
recv_needed_recovery = TRUE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Database was not shut down normally.\n"
"InnoDB: Starting recovery from log files...\n");
" InnoDB: Database was not shut down normally!\n"
"InnoDB: Starting crash recovery.\n");
fprintf(stderr,
"InnoDB: Reading tablespace information from the .ibd files...\n");
fil_load_single_table_tablespaces();
/* If we are using the doublewrite method, we will
check if there are half-written pages in data files,
and restore them from the doublewrite buffer if
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
fprintf(stderr,
"InnoDB: Restoring possible half-written data pages from the doublewrite\n"
"InnoDB: buffer...\n");
trx_sys_doublewrite_init_or_restore_pages(
TRUE);
}
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Starting log scan based on checkpoint at\n"
"InnoDB: log sequence number %lu %lu\n",
" InnoDB: Starting log scan based on checkpoint at\n"
"InnoDB: log sequence number %lu %lu.\n",
ut_dulint_get_high(checkpoint_lsn),
ut_dulint_get_low(checkpoint_lsn));
} else {
/* Init the doublewrite buffer memory structure */
trx_sys_doublewrite_init_or_restore_pages(FALSE);
}
}
@ -2675,6 +2732,21 @@ recv_recovery_from_checkpoint_start(
log_sys->archived_lsn = archived_lsn;
recv_synchronize_groups(up_to_date_group);
if (!recv_needed_recovery) {
if (ut_dulint_cmp(checkpoint_lsn, recv_sys->recovered_lsn)
!= 0) {
fprintf(stderr,
"InnoDB: Warning: we did not need to do crash recovery, but log scan\n"
"InnoDB: progressed past the checkpoint lsn %lu %lu up to lsn %lu %lu\n",
ut_dulint_get_high(checkpoint_lsn),
ut_dulint_get_low(checkpoint_lsn),
ut_dulint_get_high(recv_sys->recovered_lsn),
ut_dulint_get_low(recv_sys->recovered_lsn));
}
} else {
srv_start_lsn = recv_sys->recovered_lsn;
}
log_sys->lsn = recv_sys->recovered_lsn;
@ -2703,8 +2775,6 @@ recv_recovery_from_checkpoint_start(
mutex_exit(&(log_sys->mutex));
sync_order_checks_on = FALSE;
recv_lsn_checks_on = TRUE;
/* The database is now ready to start almost normal processing of user
@ -2860,16 +2930,16 @@ recv_reset_log_files_for_backup(
printf(
"Setting log file size to %lu %lu\n", ut_get_high32(log_file_size),
log_file_size & 0xFFFFFFFF);
log_file_size & 0xFFFFFFFFUL);
success = os_file_set_size(name, log_file,
log_file_size & 0xFFFFFFFF,
log_file_size & 0xFFFFFFFFUL,
ut_get_high32(log_file_size));
if (!success) {
printf(
"InnoDB: Cannot set %s size to %lu %lu\n", name, ut_get_high32(log_file_size),
log_file_size & 0xFFFFFFFF);
log_file_size & 0xFFFFFFFFUL);
exit(1);
}
@ -2933,13 +3003,10 @@ try_open_again:
log_archived_file_name_gen(name, group->id, group->archived_file_no);
fil_reserve_right_to_open();
file_handle = os_file_create(name, OS_FILE_OPEN,
OS_FILE_LOG, OS_FILE_AIO, &ret);
if (ret == FALSE) {
fil_release_right_to_open();
ask_again:
fprintf(stderr,
"InnoDB: Do you want to copy additional archived log files\n"
@ -2980,12 +3047,10 @@ ask_again:
ut_a(ret);
fil_release_right_to_open();
/* Add the archive file as a node to the space */
fil_node_create(name, 1 + file_size / UNIV_PAGE_SIZE,
group->archive_space_id);
group->archive_space_id, FALSE);
ut_a(RECV_SCAN_SIZE >= LOG_FILE_HDR_SIZE);
/* Read the archive file header */
@ -3061,8 +3126,8 @@ ask_again:
read_offset % UNIV_PAGE_SIZE, len, buf, NULL);
ret = recv_scan_log_recs(TRUE,
(buf_pool->n_frames -
recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
(buf_pool->n_frames -
recv_n_pool_free_frames) * UNIV_PAGE_SIZE,
TRUE, buf, len, start_lsn,
&dummy_lsn, &scanned_lsn);
@ -3110,8 +3175,6 @@ recv_recovery_from_archive_start(
recv_sys_create();
recv_sys_init(FALSE, buf_pool_get_curr_size());
sync_order_checks_on = TRUE;
recv_recovery_on = TRUE;
recv_recovery_from_backup_on = TRUE;
@ -3198,8 +3261,6 @@ recv_recovery_from_archive_start(
mutex_exit(&(log_sys->mutex));
sync_order_checks_on = FALSE;
return(DB_SUCCESS);
}

View File

@ -36,37 +36,37 @@ mach_parse_compressed(
flag = mach_read_from_1(ptr);
if (flag < 0x80) {
if (flag < 0x80UL) {
*val = flag;
return(ptr + 1);
} else if (flag < 0xC0) {
} else if (flag < 0xC0UL) {
if (end_ptr < ptr + 2) {
return(NULL);
}
*val = mach_read_from_2(ptr) & 0x7FFF;
*val = mach_read_from_2(ptr) & 0x7FFFUL;
return(ptr + 2);
} else if (flag < 0xE0) {
} else if (flag < 0xE0UL) {
if (end_ptr < ptr + 3) {
return(NULL);
}
*val = mach_read_from_3(ptr) & 0x3FFFFF;
*val = mach_read_from_3(ptr) & 0x3FFFFFUL;
return(ptr + 3);
} else if (flag < 0xF0) {
} else if (flag < 0xF0UL) {
if (end_ptr < ptr + 4) {
return(NULL);
}
*val = mach_read_from_4(ptr) & 0x1FFFFFFF;
*val = mach_read_from_4(ptr) & 0x1FFFFFFFUL;
return(ptr + 4);
} else {
ut_ad(flag == 0xF0);
ut_ad(flag == 0xF0UL);
if (end_ptr < ptr + 5) {
return(NULL);

View File

@ -346,21 +346,22 @@ mem_hash_remove(
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
NULL, NULL);
if (error) {
printf("Inconsistency in memory heap or buffer n:o %lu created\n",
printf(
"Inconsistency in memory heap or buffer n:o %lu created\n",
node->nth_heap);
printf("in %s line %lu and tried to free in %s line %lu.\n",
printf("in %s line %lu and tried to free in %s line %lu.\n",
node->file_name, node->line, file_name, line);
printf(
"Hex dump of 400 bytes around memory heap first block start:\n");
printf(
"Hex dump of 400 bytes around memory heap first block start:\n");
ut_print_buf((byte*)(node->heap) - 200, 400);
ut_print_buf((byte*)(node->heap) - 200, 400);
printf("\nDump of the mem heap:\n");
printf("\nDump of the mem heap:\n");
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error, &size,
NULL, NULL);
ut_error;
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
&size, NULL, NULL);
ut_error;
}
/* Free the memory occupied by the node struct */
@ -441,6 +442,9 @@ mem_heap_validate_or_print(
if ((block->type == MEM_HEAP_BUFFER)
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
fprintf(stderr,
"InnoDB: Error: mem block %lx length %lu > UNIV_PAGE_SIZE\n", (ulint)block,
mem_block_get_len(block));
/* error */
return;
@ -480,6 +484,12 @@ mem_heap_validate_or_print(
mem_field_trailer_get_check(user_field)) {
/* error */
fprintf(stderr,
"InnoDB: Error: block %lx mem field %lx len %lu\n"
"InnoDB: header check field is %lx but trailer %lx\n", (ulint)block,
(ulint)field, len, check_field,
mem_field_trailer_get_check(user_field));
return;
}
@ -499,6 +509,11 @@ mem_heap_validate_or_print(
if (field != (byte*)block + mem_block_get_free(block)) {
/* error */
fprintf(stderr,
"InnoDB: Error: block %lx end of mem fields %lx\n"
"InnoDB: but block free at %lx\n", (ulint)block, (ulint)field,
(ulint)((byte*)block + mem_block_get_free(block)));
return;
}
@ -577,6 +592,10 @@ mem_heap_validate(
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
&phys_size, &n_blocks);
if (error) {
mem_heap_print(heap);
}
ut_a(!error);
return(TRUE);

View File

@ -603,8 +603,8 @@ mem_pool_validate(
}
}
ut_anp(free + pool->reserved == pool->size
- (pool->size % MEM_AREA_MIN_SIZE));
ut_anp(free + pool->reserved == pool->size);
mutex_exit(&(pool->mutex));
return(TRUE);

View File

@ -171,13 +171,13 @@ mlog_parse_nbytes(
}
if (type == MLOG_1BYTE) {
if (val > 0xFF) {
if (val > 0xFFUL) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
} else if (type == MLOG_2BYTES) {
if (val > 0xFFFF) {
if (val > 0xFFFFUL) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);

View File

@ -11,6 +11,7 @@ Created 10/21/1995 Heikki Tuuri
#include "os0thread.h"
#include "ut0mem.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "fil0fil.h"
#include "buf0buf.h"
@ -33,7 +34,7 @@ ulint os_innodb_umask = 0;
#endif
/* If the following is set to TRUE, we do not call os_file_flush in every
os_file_write. We can set this TRUE if the doublewrite buffer is used. */
os_file_write. We can set this TRUE when the doublewrite buffer is used. */
ibool os_do_not_call_flush_at_each_write = FALSE;
/* We use these mutexes to protect lseek + file i/o operation, if the
@ -154,7 +155,6 @@ os_mutex_t os_file_count_mutex;
ulint os_file_n_pending_preads = 0;
ulint os_file_n_pending_pwrites = 0;
/***************************************************************************
Gets the operating system version. Currently works only on Windows. */
@ -198,9 +198,12 @@ overwrite the error number). If the number is not known to this program,
the OS error number + 100 is returned. */
ulint
os_file_get_last_error(void)
/*========================*/
/* out: error number, or OS error number + 100 */
os_file_get_last_error(
/*===================*/
/* out: error number, or OS error
number + 100 */
ibool report_all_errors) /* in: TRUE if we want an error message
printed of all errors */
{
ulint err;
@ -208,7 +211,8 @@ os_file_get_last_error(void)
err = (ulint) GetLastError();
if (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS) {
if (report_all_errors
|| (err != ERROR_DISK_FULL && err != ERROR_FILE_EXISTS)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Operating system error number %lu in a file operation.\n"
@ -246,7 +250,8 @@ os_file_get_last_error(void)
#else
err = (ulint) errno;
if (err != ENOSPC && err != EEXIST) {
if (report_all_errors
|| (err != ENOSPC && err != EEXIST)) {
ut_print_timestamp(stderr);
fprintf(stderr,
@ -309,7 +314,7 @@ os_file_handle_error(
UT_NOT_USED(file);
err = os_file_get_last_error();
err = os_file_get_last_error(FALSE);
if (err == OS_FILE_DISK_FULL) {
/* We only print a warning about disk full once */
@ -374,6 +379,217 @@ os_io_init_simple(void)
}
}
/***************************************************************************
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
at the first entry. In both Unix and Windows we automatically skip the '.'
and '..' items at the start of the directory listing. */
os_file_dir_t
os_file_opendir(
/*============*/
/* out: directory stream, NULL if error */
char* dirname, /* in: directory name; it must not contain
a trailing '\' or '/' */
ibool error_is_fatal) /* in: TRUE if we should treat an error as a
fatal error; if we try to open symlinks then
we do not wish a fatal error if it happens
not to be a directory */
{
os_file_dir_t dir;
#ifdef __WIN__
LPWIN32_FIND_DATA lpFindFileData;
char path[OS_FILE_MAX_PATH + 3];
ut_a(strlen(dirname) < OS_FILE_MAX_PATH);
strcpy(path, dirname);
strcpy(path + strlen(path), "\*");
/* Note that in Windows opening the 'directory stream' also retrieves
the first entry in the directory. Since it is '.', that is no problem,
as we will skip over the '.' and '..' entries anyway. */
lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
dir = FindFirstFile(path, lpFindFileData);
ut_free(lpFindFileData);
if (dir == INVALID_HANDLE_VALUE) {
if (error_is_fatal) {
os_file_handle_error(NULL, dirname, "opendir");
}
return(NULL);
}
return(dir);
#else
dir = opendir(dirname);
if (dir == NULL && error_is_fatal) {
os_file_handle_error(0, dirname, "opendir");
}
return(dir);
#endif
}
/***************************************************************************
Closes a directory stream. */
int
os_file_closedir(
/*=============*/
/* out: 0 if success, -1 if failure */
os_file_dir_t dir) /* in: directory stream */
{
#ifdef __WIN__
BOOL ret;
ret = FindClose(dir);
if (!ret) {
os_file_handle_error(NULL, NULL, "closedir");
return(-1);
}
return(0);
#else
int ret;
ret = closedir(dir);
if (ret) {
os_file_handle_error(0, NULL, "closedir");
}
return(ret);
#endif
}
/***************************************************************************
This function returns information of the next file in the directory. We jump
over the '.' and '..' entries in the directory. */
int
os_file_readdir_next_file(
/*======================*/
/* out: 0 if ok, -1 if error, 1 if at the end
of the directory */
char* dirname,/* in: directory name or path */
os_file_dir_t dir, /* in: directory stream */
os_file_stat_t* info) /* in/out: buffer where the info is returned */
{
#ifdef __WIN__
LPWIN32_FIND_DATA lpFindFileData;
BOOL ret;
lpFindFileData = ut_malloc(sizeof(WIN32_FIND_DATA));
next_file:
ret = FindNextFile(dir, lpFindFileData);
if (ret) {
ut_a(strlen(lpFindFileData->cFilename) < OS_FILE_MAX_PATH);
if (strcmp(lpFindFileData->cFilename, ".") == 0
|| strcmp(lpFindFileData->cFilename, "..") == 0) {
goto next_file;
}
strcpy(info->name, lpFindFileData->cFilename);
info->size = (ib_longlong)(buf->nFileSizeLow)
+ (((ib_longlong)(buf->nFileSizeHigh)) << 32);
if (lpFindFileData->dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT) {
/* TODO: test Windows symlinks */
/* TODO: MySQL has apparently its own symlink implementation in Windows,
dbname.sym can redirect a database directory:
http://www.mysql.com/doc/en/Windows_symbolic_links.html */
info->type = OS_FILE_TYPE_LINK;
} else if (lpFindFileData->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY) {
info->type = OS_FILE_TYPE_DIR;
} else if (lpFindFileData->dwFileAttributes
& FILE_ATTRIBUTE_NORMAL) {
/* TODO: are FILE_ATTRIBUTE_NORMAL files really all normal files? */
info->type = OS_FILE_TYPE_FILE;
} else {
info->type = OS_FILE_TYPE_UNKNOWN;
}
}
ut_free(lpFindFileData);
if (ret) {
return(0);
} else if (GetLastError() == ERROR_NO_MORE_FILES) {
return(1);
} else {
os_file_handle_error(NULL, dirname, "readdir_next_file");
return(-1);
}
#else
struct dirent* ent;
char* full_path;
int ret;
struct stat statinfo;
next_file:
ent = readdir(dir);
if (ent == NULL) {
return(1);
}
ut_a(strlen(ent->d_name) < OS_FILE_MAX_PATH);
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
goto next_file;
}
strcpy(info->name, ent->d_name);
full_path = ut_malloc(strlen(dirname) + strlen(ent->d_name) + 10);
sprintf(full_path, "%s/%s", dirname, ent->d_name);
ret = stat(full_path, &statinfo);
if (ret) {
os_file_handle_error(0, full_path, "stat");
ut_free(full_path);
return(-1);
}
info->size = (ib_longlong)statinfo.st_size;
if (S_ISDIR(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_DIR;
} else if (S_ISLNK(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_LINK;
} else if (S_ISREG(statinfo.st_mode)) {
info->type = OS_FILE_TYPE_FILE;
} else {
info->type = OS_FILE_TYPE_UNKNOWN;
}
ut_free(full_path);
return(0);
#endif
}
/********************************************************************
A simple function to open or create a file. */
@ -593,7 +809,9 @@ os_file_create(
ulint create_mode, /* in: OS_FILE_OPEN if an existing file is opened
(if does not exist, error), or OS_FILE_CREATE if a new
file is created (if exists, error), OS_FILE_OVERWRITE
if a new is created or an old overwritten */
if a new is created or an old overwritten,
OS_FILE_OPEN_RAW, if a raw device or disk partition
should be opened */
ulint purpose,/* in: OS_FILE_AIO, if asynchronous, non-buffered i/o
is desired, OS_FILE_NORMAL, if any normal file;
NOTE that it also depends on type, os_aio_.. and srv_..
@ -605,6 +823,7 @@ os_file_create(
{
#ifdef __WIN__
os_file_t file;
DWORD share_mode = FILE_SHARE_READ;
DWORD create_flag;
DWORD attributes;
ibool retry;
@ -612,6 +831,9 @@ os_file_create(
try_again:
ut_a(name);
if (create_mode == OS_FILE_OPEN_RAW) {
create_flag = OPEN_EXISTING;
share_mode = FILE_SHARE_WRITE;
if (create_mode == OS_FILE_OPEN) {
create_flag = OPEN_EXISTING;
} else if (create_mode == OS_FILE_CREATE) {
@ -662,14 +884,17 @@ try_again:
file = CreateFile(name,
GENERIC_READ | GENERIC_WRITE, /* read and write
access */
FILE_SHARE_READ,/* File can be read also by other
share_mode, /* File can be read also by other
processes; we must give the read
permission because of ibbackup. We do
not give the write permission to
others because if one would succeed to
start 2 instances of mysqld on the
SAME files, that could cause severe
database corruption! */
database corruption! When opening
raw disk partitions Microsoft manuals
say that we must give also the write
permission. */
NULL, /* default security attributes */
create_flag,
attributes,
@ -679,8 +904,8 @@ try_again:
*success = FALSE;
retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
create_mode == OS_FILE_CREATE ?
"create" : "open");
if (retry) {
goto try_again;
}
@ -700,7 +925,7 @@ try_again:
try_again:
ut_a(name);
if (create_mode == OS_FILE_OPEN) {
if (create_mode == OS_FILE_OPEN || create_mode == OS_FILE_OPEN_RAW) {
mode_str = "OPEN";
create_flag = O_RDWR;
@ -767,8 +992,8 @@ try_again:
*success = FALSE;
retry = os_file_handle_error(file, name,
create_mode == OS_FILE_OPEN ?
"open" : "create");
create_mode == OS_FILE_CREATE ?
"create" : "open");
if (retry) {
goto try_again;
}
@ -780,6 +1005,85 @@ try_again:
#endif
}
/***************************************************************************
Deletes a file. The file has to be closed before calling this. */
ibool
os_file_delete(
/*===========*/
/* out: TRUE if success */
char* name) /* in: file path as a null-terminated string */
{
#ifdef __WIN__
os_file_t dummy = NULL;
BOOL ret;
ret = DeleteFile((LPCTSTR)name);
if (ret) {
return(TRUE);
}
os_file_handle_error(dummy, name, "delete");
return(FALSE);
#else
os_file_t dummy = 0;
int ret;
ret = unlink((const char*)name);
if (ret != 0) {
os_file_handle_error(dummy, name, "delete");
return(FALSE);
}
return(TRUE);
#endif
}
/***************************************************************************
Renames a file (can also move it to another directory). It is safest that the
file is closed before calling this function. */
ibool
os_file_rename(
/*===========*/
/* out: TRUE if success */
char* oldpath, /* in: old file path as a null-terminated
string */
char* newpath) /* in: new file path */
{
#ifdef __WIN__
os_file_t dummy = NULL;
BOOL ret;
ret = MoveFile((LPCTSTR)oldpath, (LPCTSTR)newpath);
if (ret) {
return(TRUE);
}
os_file_handle_error(dummy, oldpath, "delete");
return(FALSE);
#else
os_file_t dummy = 0;
int ret;
ret = rename((const char*)oldpath, (const char*)newpath);
if (ret != 0) {
os_file_handle_error(dummy, oldpath, "rename");
return(FALSE);
}
return(TRUE);
#endif
}
/***************************************************************************
Closes a file handle. In case of error, error number can be retrieved with
os_file_get_last_error. */
@ -889,7 +1193,7 @@ os_file_get_size(
}
if (sizeof(off_t) > 4) {
*size = (ulint)(offs & 0xFFFFFFFF);
*size = (ulint)(offs & 0xFFFFFFFFUL);
*size_high = (ulint)(offs >> 32);
} else {
*size = (ulint) offs;
@ -1012,6 +1316,15 @@ os_file_flush(
return(TRUE);
}
/* Since Windows returns ERROR_INVALID_FUNCTION if the 'file' is
actually a raw device, we choose to ignore that error if we are using
raw disks */
if (srv_start_raw_disk_in_use && GetLastError()
== ERROR_INVALID_FUNCTION) {
return(TRUE);
}
os_file_handle_error(file, NULL, "flush");
/* It is a fatal error if a file flush does not succeed, because then
@ -1035,9 +1348,10 @@ os_file_flush(
}
/* Since Linux returns EINVAL if the 'file' is actually a raw device,
we choose to ignore that error */
we choose to ignore that error if we are using raw disks */
if (srv_start_raw_disk_in_use && errno == EINVAL) {
if (errno == EINVAL) {
return(TRUE);
}
@ -1075,7 +1389,7 @@ os_file_pread(
off_t offs;
ssize_t n_bytes;
ut_a((offset & 0xFFFFFFFF) == offset);
ut_a((offset & 0xFFFFFFFFUL) == offset);
/* If off_t is > 4 bytes in size, then we assume we can pass a
64-bit address */
@ -1151,7 +1465,7 @@ os_file_pwrite(
ssize_t ret;
off_t offs;
ut_a((offset & 0xFFFFFFFF) == offset);
ut_a((offset & 0xFFFFFFFFUL) == offset);
/* If off_t is > 4 bytes in size, then we assume we can pass a
64-bit address */
@ -1255,7 +1569,7 @@ os_file_read(
ibool retry;
ulint i;
ut_a((offset & 0xFFFFFFFF) == offset);
ut_a((offset & 0xFFFFFFFFUL) == offset);
os_n_file_reads++;
os_bytes_read_since_printout += n;

View File

@ -321,7 +321,7 @@ os_awe_allocate_virtual_mem_window(
#elif defined(__WIN2000__)
byte* ptr;
if (size > 0x7FFFFFFFFF) {
if (size > (ulint)0x7FFFFFFFUL) {
fprintf(stderr,
"InnoDB: AWE: Cannot allocate %lu bytes of virtual memory\n", size);
@ -333,7 +333,7 @@ os_awe_allocate_virtual_mem_window(
if (ptr == NULL) {
fprintf(stderr,
"InnoDB: AWE: Cannot allocate %lu bytes of virtual memory, error %lu\n",
size, (ulint)GetLastError());
size, (ulint)GetLastError());
return(NULL);
}

View File

@ -629,7 +629,7 @@ page_cur_parse_insert_rec(
return(NULL);
}
extra_info_yes = end_seg_len & 0x1;
extra_info_yes = end_seg_len & 0x1UL;
end_seg_len = end_seg_len / 2;
if (end_seg_len >= UNIV_PAGE_SIZE) {
@ -702,7 +702,8 @@ page_cur_parse_insert_rec(
/* Build the inserted record to buf */
if (mismatch_index >= UNIV_PAGE_SIZE) {
printf("Is short %lu, info_bits %lu, offset %lu, o_offset %lu\n"
printf(
"Is short %lu, info_bits %lu, offset %lu, o_offset %lu\n"
"mismatch index %lu, end_seg_len %lu\n"
"parsed len %lu\n",
is_short, info_bits, offset, origin_offset,

View File

@ -1473,10 +1473,6 @@ loop:
mutex_exit(&kernel_mutex);
}
*/
/* TRUE below denotes that the thread is allowed to own the dictionary
mutex, though */
ut_ad(sync_thread_levels_empty_gen(TRUE));
loop_count++;
if (next_thr != thr) {

View File

@ -1739,6 +1739,7 @@ row_ins_index_entry_low(
ulint modify = 0; /* remove warning */
rec_t* insert_rec;
rec_t* rec;
rec_t* first_rec;
ulint err;
ulint n_unique;
big_rec_t* big_rec = NULL;
@ -1771,6 +1772,14 @@ row_ins_index_entry_low(
goto function_exit;
}
first_rec = page_rec_get_next(page_get_infimum_rec(
buf_frame_align(btr_cur_get_rec(&cursor))));
if (!page_rec_is_supremum(first_rec)) {
ut_a((rec_get_n_fields(first_rec))
== dtuple_get_n_fields(entry));
}
n_unique = dict_index_get_n_unique(index);
if (index->type & DICT_UNIQUE && (cursor.up_match >= n_unique

View File

@ -22,12 +22,15 @@ Created 9/17/2000 Heikki Tuuri
#include "dict0dict.h"
#include "dict0crea.h"
#include "dict0load.h"
#include "dict0boot.h"
#include "trx0roll.h"
#include "trx0purge.h"
#include "lock0lock.h"
#include "rem0cmp.h"
#include "log0log.h"
#include "btr0sea.h"
#include "fil0fil.h"
#include "ibuf0ibuf.h"
/* A dummy variable used to fool the compiler */
ibool row_mysql_identically_false = FALSE;
@ -1161,7 +1164,9 @@ row_mysql_recover_tmp_table(
trx_t* trx) /* in: transaction handle */
{
char* ptr;
char old_name[1000];
char old_name[OS_FILE_MAX_PATH];
ut_a(ut_strlen(table->name) + 10 < OS_FILE_MAX_PATH);
ut_memcpy(old_name, table->name, ut_strlen(table->name) + 1);
@ -1230,7 +1235,8 @@ row_mysql_lock_data_dictionary(
/*===========================*/
trx_t* trx) /* in: transaction */
{
ut_a(trx->dict_operation_lock_mode == 0);
ut_a(trx->dict_operation_lock_mode == 0
|| trx->dict_operation_lock_mode == RW_X_LATCH);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks or lock waits can occur then in these operations */
@ -1431,15 +1437,14 @@ row_create_table_for_mysql(
"InnoDB: Warning: cannot create table %s because tablespace full\n",
table->name);
row_drop_table_for_mysql(table->name, trx);
} else {
ut_a(err == DB_DUPLICATE_KEY);
} else if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: table %s already exists in InnoDB internal\n"
"InnoDB: data dictionary. Have you deleted the .frm file\n"
"InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n"
"InnoDB: and not used DROPT ABLE? Have you used DROP DATABASE\n"
"InnoDB: for InnoDB tables in MySQL version <= 3.23.43?\n"
"InnoDB: See the Restrictions section of the InnoDB manual.\n",
table->name);
@ -1449,9 +1454,12 @@ row_create_table_for_mysql(
"InnoDB: database and moving the .frm file to the current database.\n"
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n"
"InnoDB: You can look further help from section 15.1 of\n"
"InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n");
}
/* We may also get err == DB_ERROR if the .ibd file for the
table already exists */
trx->error_state = DB_SUCCESS;
}
@ -1490,7 +1498,7 @@ row_create_index_for_mysql(
trx->op_info = (char *) "creating index";
/* Check that the same column does not appear twice in the index.
Starting from 4.0.14 InnoDB should be able to cope with that, but
Starting from 4.0.14, InnoDB should be able to cope with that, but
safer not to allow them. */
for (i = 0; i < dict_index_get_n_fields(index); i++) {
@ -1532,6 +1540,9 @@ row_create_index_for_mysql(
trx->dict_operation = TRUE;
/* Note that the space id where we store the index is inherited from
the table in dict_build_index_def_step() in dict0crea.c. */
node = ind_create_graph_create(index, heap);
thr = pars_complete_graph_for_exec(node, trx, heap);
@ -1545,7 +1556,6 @@ row_create_index_for_mysql(
que_graph_free((que_t*) que_node_get_parent(thr));
error_handling:
if (err != DB_SUCCESS) {
/* We have special error handling here */
@ -1805,6 +1815,218 @@ row_add_table_to_background_drop_list(
mutex_exit(&kernel_mutex);
}
/*************************************************************************
Discards the tablespace of a table which stored in an .ibd file. Discarding
means that this function deletes the .ibd file and assigns a new table id for
the table. Also the flag table->ibd_file_missing is set TRUE.
How do we prevent crashes caused by ongoing operations on the table? Old
operations could try to access non-existent pages.
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
on the table before we can do DISCARD TABLESPACE. Then there are no running
queries on the table.
2) Purge and rollback: we assign a new table id for the table. Since purge and
rollback look for the table based on the table id, they see the table as
'dropped' and discard their operations.
3) Insert buffer: we remove all entries for the tablespace in the insert
buffer tree; as long as the tablespace mem object does not exist, ongoing
insert buffer page merges are discarded in buf0rea.c. If we recreate the
tablespace mem object with IMPORT TABLESPACE later, then the tablespace will
have the same id, but the tablespace_version field in the mem object is
different, and ongoing old insert buffer page merges get discarded.
4) Linear readahead and random readahead: we use the same method as in 3) to
discard ongoing operations. */
int
row_discard_tablespace_for_mysql(
/*=============================*/
/* out: error code or DB_SUCCESS */
char* name, /* in: table name */
trx_t* trx) /* in: transaction handle */
{
dulint new_id;
dict_table_t* table;
que_thr_t* thr;
que_t* graph = NULL;
ibool success;
ulint err;
char buf[2 * OS_FILE_MAX_PATH];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = (char *) "discarding tablespace";
trx_start_if_not_started(trx);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
row_mysql_lock_data_dictionary(trx);
table = dict_table_get_low(name);
if (!table) {
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
sprintf(buf,
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
"old_id CHAR;\n"
"new_id CHAR;\n"
"new_id_low INT;\n"
"new_id_high INT;\n"
"table_name CHAR;\n"
"BEGIN\n"
"table_name :='%s';\n"
"new_id_high := %lu;\n"
"new_id_low := %lu;\n"
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
"SELECT ID INTO old_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = table_name;\n"
"IF (SQL % NOTFOUND) THEN\n"
" COMMIT WORK;\n"
" RETURN;\n"
"END IF;\n"
"UPDATE SYS_TABLES SET ID = new_id\n"
"WHERE ID = old_id;\n"
"UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"COMMIT WORK;\n"
"END;\n", name, ut_dulint_get_high(new_id), ut_dulint_get_low(new_id));
ut_a(strlen(buf) < 2 * OS_FILE_MAX_PATH);
graph = pars_sql(buf);
ut_a(graph);
graph->trx = trx;
trx->graph = NULL;
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
que_run_threads(thr);
err = trx->error_state;
if (err != DB_SUCCESS) {
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS;
} else {
dict_table_change_id_in_cache(table, new_id);
success = fil_discard_tablespace(table->space);
if (!success) {
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS;
err = DB_ERROR;
} else {
/* Set the flag which tells that now it is legal to
IMPORT a tablespace for this table */
table->tablespace_discarded = TRUE;
table->ibd_file_missing = TRUE;
}
}
funct_exit:
row_mysql_unlock_data_dictionary(trx);
if (graph) {
que_graph_free(graph);
}
trx_commit_for_mysql(trx);
trx->op_info = (char *) "";
return((int) err);
}
/*********************************************************************
Imports a tablespace. The space id in the .ibd file must match the space id
of the table in the data dictionary. */
int
row_import_tablespace_for_mysql(
/*============================*/
/* out: error code or DB_SUCCESS */
char* name, /* in: table name */
trx_t* trx) /* in: transaction handle */
{
dict_table_t* table;
ibool success;
ulint err = DB_SUCCESS;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx_start_if_not_started(trx);
trx->op_info = (char*) "importing tablespace";
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
row_mysql_lock_data_dictionary(trx);
table = dict_table_get_low(name);
if (!table) {
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
if (!table->tablespace_discarded) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: you are trying to IMPORT a tablespace\n"
"InnoDB: %s, though you have not called DISCARD on it yet\n"
"InnoDB: during the lifetime of the mysqld process!\n", name);
err = DB_ERROR;
goto funct_exit;
}
/* Play safe and remove all insert buffer entries, though we should
have removed them already when DISCARD TABLESPACE was called */
ibuf_delete_for_discarded_space(table->space);
success = fil_open_single_table_tablespace(table->space, table->name);
printf(
"Remember to stop purge + undo if table->ibd_file_is_missing!!!\n");
if (success) {
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
} else {
err = DB_ERROR;
}
funct_exit:
row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx);
trx->op_info = (char *) "";
return((int) err);
}
/*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends to
characters INNODB_MONITOR, then this also stops printing of monitor
@ -1813,11 +2035,12 @@ output by the master thread. */
int
row_drop_table_for_mysql(
/*=====================*/
/* out: error code or DB_SUCCESS */
char* name, /* in: table name */
trx_t* trx) /* in: transaction handle */
/* out: error code or DB_SUCCESS */
char* name, /* in: table name */
trx_t* trx) /* in: transaction handle */
{
dict_table_t* table;
ulint space_id;
que_thr_t* thr;
que_t* graph;
ulint err;
@ -1826,8 +2049,9 @@ row_drop_table_for_mysql(
ulint len;
ulint namelen;
ulint keywordlen;
ibool success;
ibool locked_dictionary = FALSE;
char buf[10000];
char buf[OS_FILE_MAX_PATH + 2000];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(name != NULL);
@ -1968,6 +2192,8 @@ row_drop_table_for_mysql(
ut_memcpy(buf + len, str2, ut_strlen(str2) + 1);
ut_a(strlen(buf) < OS_FILE_MAX_PATH + 2000);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@ -1999,11 +2225,12 @@ row_drop_table_for_mysql(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: table %s does not exist in the InnoDB internal\n"
" InnoDB: Error: table %s\n"
"InnoDB: does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to drop it.\n"
"InnoDB: Have you copied the .frm file of the table to the\n"
"InnoDB: MySQL database directory from another database?\n"
"InnoDB: You can look further help from section 15.1 of\n"
"InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n",
name);
goto funct_exit;
@ -2063,13 +2290,32 @@ row_drop_table_for_mysql(
ut_a(0);
} else {
space_id = table->space;
dict_table_remove_from_cache(table);
if (dict_load_table(name) != NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: dropping of table %s failed!\n", name);
" InnoDB: Error: not able to remove table %s from the dictionary cache!\n",
name);
err = DB_ERROR;
}
/* Do not drop possible .ibd tablespace if something went
wrong: we do not want to delete valuable data of the user */
if (err == DB_SUCCESS && space_id != 0
&& fil_tablespace_exists_in_mem(space_id)) {
success = fil_delete_tablespace(space_id);
if (!success) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: not able to delete tablespace %lu of table %s!\n", space_id,
name);
err = DB_ERROR;
}
}
}
funct_exit:
@ -2203,9 +2449,13 @@ row_rename_table_for_mysql(
mem_heap_t* heap = NULL;
char** constraints_to_drop = NULL;
ulint n_constraints_to_drop = 0;
ibool recovering_temp_table = FALSE;
ulint namelen;
ulint keywordlen;
ulint len;
ulint i;
char buf[10000];
ibool success;
char buf[2 * OS_FILE_MAX_PATH];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(old_name != NULL);
@ -2239,16 +2489,52 @@ row_rename_table_for_mysql(
trx->op_info = (char *) "renaming table";
trx_start_if_not_started(trx);
namelen = ut_strlen(new_name);
keywordlen = ut_strlen("_recover_innodb_tmp_table");
if (namelen >= keywordlen
&& 0 == ut_memcmp(new_name + namelen - keywordlen,
(char*)"_recover_innodb_tmp_table", keywordlen)) {
recovering_temp_table = TRUE;
}
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
row_mysql_lock_data_dictionary(trx);
if (!recovering_temp_table) {
row_mysql_lock_data_dictionary(trx);
}
table = dict_table_get_low(old_name);
if (!table) {
err = DB_TABLE_NOT_FOUND;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: table %s\n"
"InnoDB: does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to rename the table.\n"
"InnoDB: Have you copied the .frm file of the table to the\n"
"InnoDB: MySQL database directory from another database?\n"
"InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n",
old_name);
goto funct_exit;
}
if (table->ibd_file_missing) {
err = DB_TABLE_NOT_FOUND;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: table %s\n"
"InnoDB: does not have an .ibd file in the database directory.\n"
"InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n",
old_name);
goto funct_exit;
}
@ -2331,6 +2617,8 @@ row_rename_table_for_mysql(
ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
ut_a(strlen(buf) < 2 * OS_FILE_MAX_PATH);
graph = pars_sql(buf);
ut_a(graph);
@ -2349,20 +2637,17 @@ row_rename_table_for_mysql(
if (err != DB_SUCCESS) {
if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: table %s exists in the InnoDB internal data\n"
"InnoDB: dictionary though MySQL is trying rename table %s to it.\n"
"InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n"
"InnoDB: You can look further help from section 15.1 of\n"
"InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n",
new_name, old_name);
fprintf(stderr,
"InnoDB: If table %s is a temporary table #sql..., then it can be that\n"
"InnoDB: there are still queries running on the table, and it will be\n"
"InnoDB: dropped automatically when the queries end.\n", new_name);
fprintf(stderr,
"InnoDB: You can drop the orphaned table inside InnoDB by\n"
"InnoDB: creating an InnoDB table with the same name in another\n"
@ -2370,13 +2655,27 @@ row_rename_table_for_mysql(
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n");
}
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS;
} else {
ut_a(dict_table_rename_in_cache(table, new_name,
!row_is_mysql_tmp_table_name(new_name)));
/* The following call will also rename the .ibd data file if
the table is stored in a single-table tablespace */
success = dict_table_rename_in_cache(table, new_name,
!row_is_mysql_tmp_table_name(new_name));
if (!success) {
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error in table rename, cannot rename %s to %s\n", old_name,
new_name);
err = DB_ERROR;
goto funct_exit;
}
if (row_is_mysql_tmp_table_name(old_name)) {
@ -2390,18 +2689,14 @@ row_rename_table_for_mysql(
err = dict_load_foreigns(new_name);
if (err != DB_SUCCESS) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: in ALTER TABLE table %s\n"
"InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n",
new_name);
ut_a(dict_table_rename_in_cache(table,
old_name, FALSE));
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE,
NULL);
@ -2410,7 +2705,9 @@ row_rename_table_for_mysql(
}
}
funct_exit:
row_mysql_unlock_data_dictionary(trx);
if (!recovering_temp_table) {
row_mysql_unlock_data_dictionary(trx);
}
if (graph) {
que_graph_free(graph);
@ -2567,7 +2864,7 @@ row_check_table_for_mysql(
ulint n_rows_in_table = ULINT_UNDEFINED;
ulint ret = DB_SUCCESS;
ulint old_isolation_level;
prebuilt->trx->op_info = (char *) "checking table";
old_isolation_level = prebuilt->trx->isolation_level;

View File

@ -1905,6 +1905,7 @@ row_sel_convert_mysql_key_to_innobase(
ulint key_len) /* in: MySQL key value length */
{
byte* original_buf = buf;
byte* original_key_ptr = key_ptr;
dict_field_t* field;
dfield_t* dfield;
ulint data_offset;
@ -2028,7 +2029,16 @@ row_sel_convert_mysql_key_to_innobase(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: using a partial-field key prefix in search\n");
" InnoDB: Warning: using a partial-field key prefix in search.\n"
"InnoDB: Table name %s, index name %s. Last data field length %lu bytes,\n"
"InnoDB: key ptr now exceeds key end by %lu bytes.\n"
"InnoDB: Key value in the MySQL format:\n", index->table_name, index->name,
data_field_len,
(ulint)(key_ptr - key_end));
fflush(stderr);
ut_print_buf(original_key_ptr, key_len);
fflush(stdout);
fprintf(stderr, "\n");
if (!is_null) {
dfield->len -= (ulint)(key_ptr - key_end);
@ -2155,9 +2165,10 @@ static
ibool
row_sel_store_mysql_rec(
/*====================*/
/* out: TRUE if success, FALSE
if could not allocate memory for a
BLOB */
/* out: TRUE if success, FALSE if
could not allocate memory for a BLOB
(though we may also assert in that
case) */
byte* mysql_rec, /* out: row in the MySQL format */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */
rec_t* rec) /* in: Innobase record in the index
@ -2169,8 +2180,9 @@ row_sel_store_mysql_rec(
byte* data;
ulint len;
byte* blob_buf;
int pad_char;
ulint i;
ut_ad(prebuilt->mysql_template);
if (prebuilt->blob_heap != NULL) {
@ -2178,9 +2190,10 @@ row_sel_store_mysql_rec(
prebuilt->blob_heap = NULL;
}
/* Mark all columns as SQL NULL */
/* MySQL assumes that all columns have the SQL NULL bit set unless it
is a nullable column with a non-NULL value */
memset(mysql_rec, 255, prebuilt->null_bitmap_len);
memset(mysql_rec, 0xFF, prebuilt->null_bitmap_len);
for (i = 0; i < prebuilt->n_template; i++) {
@ -2197,6 +2210,10 @@ row_sel_store_mysql_rec(
extern_field_heap = mem_heap_create(UNIV_PAGE_SIZE);
/* NOTE: if we are retrieving a big BLOB, we may
already run out of memory in the next call, which
causes an assert */
data = btr_rec_copy_externally_stored_field(rec,
templ->rec_field_no, &len,
extern_field_heap);
@ -2209,20 +2226,28 @@ row_sel_store_mysql_rec(
ut_a(prebuilt->templ_contains_blob);
/* A heuristic test that we can allocate
the memory for a big BLOB. We have a safety
margin of 1000000 bytes. Since the test
takes some CPU time, we do not use for small
BLOBs. */
/* A heuristic test that we can allocate the
memory for a big BLOB. We have a safety margin
of 1000000 bytes. Since the test takes some
CPU time, we do not use it for small BLOBs. */
if (len > 2000000
&& !ut_test_malloc(len + 1000000)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: could not allocate %lu + 1000000 bytes to retrieve\n"
"InnoDB: a big column. Table name %s\n", len, prebuilt->table->name);
if (extern_field_heap) {
mem_heap_free(
extern_field_heap);
}
return(FALSE);
}
/* Copy the BLOB data to the BLOB
heap of prebuilt */
/* Copy the BLOB data to the BLOB heap of
prebuilt */
if (prebuilt->blob_heap == NULL) {
prebuilt->blob_heap =
@ -2235,35 +2260,49 @@ row_sel_store_mysql_rec(
data = blob_buf;
}
row_sel_field_store_in_mysql_format(
mysql_rec + templ->mysql_col_offset,
templ->mysql_col_len, data, len,
templ->type, templ->is_unsigned);
/* Cleanup */
if (extern_field_heap) {
mem_heap_free(extern_field_heap);
mem_heap_free(extern_field_heap);
extern_field_heap = NULL;
}
}
if (templ->mysql_null_bit_mask) {
/* It is a nullable column with a non-NULL
value */
mysql_rec[templ->mysql_null_byte_offset] &=
~(byte) (templ->mysql_null_bit_mask);
}
} else {
/* MySQL seems to assume the field for an SQL NULL
value is set to zero. Not taking this into account
caused seg faults with NULL BLOB fields, and
value is set to zero or space. Not taking this into
account caused seg faults with NULL BLOB fields, and
bug number 154 in the MySQL bug database: GROUP BY
and DISTINCT could treat NULL values inequal. */
memset(mysql_rec + templ->mysql_col_offset,
((templ->type == DATA_VARCHAR ||
templ->type == DATA_VARMYSQL ||
templ->type == DATA_BINARY) ? ' ' : '\0'),
templ->mysql_col_len);
if (templ->type == DATA_VARCHAR
|| templ->type == DATA_CHAR
|| templ->type == DATA_BINARY
|| templ->type == DATA_FIXBINARY
|| templ->type == DATA_MYSQL
|| templ->type == DATA_VARMYSQL) {
/* MySQL pads all non-BLOB and non-TEXT
string types with space ' ' */
pad_char = ' ';
} else {
pad_char = '\0';
}
memset(mysql_rec + templ->mysql_col_offset, pad_char,
templ->mysql_col_len);
}
}
}
return(TRUE);
}
@ -2590,9 +2629,9 @@ row_sel_push_cache_row_for_mysql(
ut_ad(prebuilt->fetch_cache_first == 0);
row_sel_store_mysql_rec(
ut_a(row_sel_store_mysql_rec(
prebuilt->fetch_cache[prebuilt->n_fetch_cached],
prebuilt, rec);
prebuilt, rec));
prebuilt->n_fetch_cached++;
}
@ -2827,23 +2866,6 @@ row_search_for_mysql(
mode = pcur->search_mode;
}
if ((direction == ROW_SEL_NEXT || direction == ROW_SEL_PREV)
&& pcur->old_stored != BTR_PCUR_OLD_STORED) {
/* MySQL sometimes seems to do fetch next or fetch prev even
if the search condition is unique; this can, for example,
happen with the HANDLER commands; we do not always store the
pcur position in this case, so we cannot restore cursor
position, and must return immediately */
/* printf("%s record not found 1\n", index->name); */
trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
mtr_start(&mtr);
/* In a search where at most one record in the index may match, we
can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete-
marked matching record.
@ -2858,8 +2880,21 @@ row_search_for_mysql(
&& dtuple_get_n_fields(search_tuple)
== dict_index_get_n_unique(index)) {
unique_search = TRUE;
/* Even if the condition is unique, MySQL seems to try to
retrieve also a second row if a primary key contains more than
1 column. Return immediately if this is not a HANDLER
command. */
if (direction != 0 && !prebuilt->used_in_HANDLER) {
trx->op_info = (char *) "";
return(DB_RECORD_NOT_FOUND);
}
}
mtr_start(&mtr);
/*-------------------------------------------------------------*/
/* PHASE 2: Try fast adaptive hash index search if possible */
@ -2912,7 +2947,9 @@ row_search_for_mysql(
rec)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
/* We let the main loop to do the
error handling */
goto shortcut_fails_too_big_rec;
}
mtr_commit(&mtr);
@ -2960,7 +2997,7 @@ row_search_for_mysql(
return(DB_RECORD_NOT_FOUND);
}
shortcut_fails_too_big_rec:
mtr_commit(&mtr);
mtr_start(&mtr);
}

View File

@ -1532,7 +1532,8 @@ row_upd_clust_step(
then we have to free the file segments of the index tree associated
with the index */
if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
if (node->is_delete
&& ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);

View File

@ -75,6 +75,10 @@ names, where the file name itself may also contain a path */
char* srv_data_home = NULL;
char* srv_arch_dir = NULL;
ibool srv_file_per_table = FALSE; /* store to its own file each table
created by an user; data dictionary
tables are in the system tablespace
0 */
ulint srv_n_data_files = 0;
char** srv_data_file_names = NULL;
ulint* srv_data_file_sizes = NULL; /* size in database pages */
@ -162,6 +166,8 @@ char* srv_file_flush_method_str = NULL;
ulint srv_unix_file_flush_method = SRV_UNIX_FDATASYNC;
ulint srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
ulint srv_max_n_open_files = 300;
/* The InnoDB main thread tries to keep the ratio of modified pages
in the buffer pool to all database pages in the buffer pool smaller than
the following number. But it is not guaranteed that the value stays below
@ -1444,7 +1450,7 @@ srv_read_initfile(
srv_log_group_home_dirs[i] = ut_malloc(ut_strlen(str_buf) + 1);
ut_memcpy(srv_log_group_home_dirs[i], str_buf,
ut_strlen(str_buf) + 1);
ut_strlen(str_buf) + 1);
}
err = srv_read_init_val(initfile, "INNOBASE_LOG_ARCH_DIR",
@ -2325,7 +2331,7 @@ srv_sprintf_innodb_monitor(
char* buf_end = buf + len - 2000;
double time_elapsed;
time_t current_time;
ulint n_reserved;
ulint n_reserved;
mutex_enter(&srv_innodb_monitor_mutex);
@ -2436,7 +2442,8 @@ srv_sprintf_innodb_monitor(
if (mem_out_of_mem_err_msg_count > 0) {
buf += sprintf(buf,
"Mem allocation has spilled out of additional mem pool %lu times\n");
"Mem allocation has spilled out of additional mem pool %lu times\n",
mem_out_of_mem_err_msg_count);
}
if (srv_use_awe) {
@ -2453,15 +2460,15 @@ srv_sprintf_innodb_monitor(
"ROW OPERATIONS\n"
"--------------\n");
buf += sprintf(buf,
"%ld queries inside InnoDB, %lu queries in queue\n",
srv_conc_n_threads, srv_conc_n_waiting_threads);
"%ld queries inside InnoDB, %lu queries in queue\n",
srv_conc_n_threads, srv_conc_n_waiting_threads);
n_reserved = fil_space_get_n_reserved_extents(0);
if (n_reserved > 0) {
buf += sprintf(buf,
"%lu tablespace extents now reserved for B-tree split operations\n",
n_reserved);
}
n_reserved = fil_space_get_n_reserved_extents(0);
if (n_reserved > 0) {
buf += sprintf(buf,
"%lu tablespace extents now reserved for B-tree split operations\n",
n_reserved);
}
#ifdef UNIV_LINUX
buf += sprintf(buf,
@ -2701,8 +2708,13 @@ srv_error_monitor_thread(
os_thread_create */
{
ulint cnt = 0;
dulint old_lsn;
dulint new_lsn;
UT_NOT_USED(arg);
old_lsn = srv_start_lsn;
#ifdef UNIV_DEBUG_THREAD_CREATION
printf("Error monitor thread starts, id %lu\n",
os_thread_pf(os_thread_get_curr_id()));
@ -2714,6 +2726,25 @@ loop:
os_thread_sleep(2000000);
/* Try to track a strange bug reported by Harald Fuchs and others,
where the lsn seems to decrease at times */
new_lsn = log_get_lsn();
if (ut_dulint_cmp(new_lsn, old_lsn) < 0) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: old log sequence number %lu %lu was greater\n"
"InnoDB: than the new log sequence number %lu %lu!\n"
"InnoDB: Please send a bug report to mysql@lists.mysql.com\n",
ut_dulint_get_high(old_lsn),
ut_dulint_get_low(old_lsn),
ut_dulint_get_high(new_lsn),
ut_dulint_get_low(new_lsn));
}
old_lsn = new_lsn;
if (difftime(time(NULL), srv_last_monitor_time) > 60) {
/* We referesh InnoDB Monitor values so that averages are
printed from at most 60 last seconds */
@ -2903,6 +2934,9 @@ loop:
srv_main_thread_op_info = (char*)"flushing log";
log_buffer_flush_to_disk();
srv_main_thread_op_info = (char*)"making checkpoint";
log_free_check();
/* If there were less than 5 i/os during the
one second sleep, we assume that there is free
disk i/o capacity available, and it makes sense to

View File

@ -30,6 +30,7 @@ Created 2/16/1996 Heikki Tuuri
#include "page0cur.h"
#include "trx0trx.h"
#include "dict0boot.h"
#include "dict0load.h"
#include "trx0sys.h"
#include "dict0crea.h"
#include "btr0btr.h"
@ -56,6 +57,14 @@ Created 2/16/1996 Heikki Tuuri
#include "srv0start.h"
#include "que0que.h"
/* Log sequence number immediately after startup */
dulint srv_start_lsn;
/* Log sequence number at shutdown */
dulint srv_shutdown_lsn;
ibool srv_start_raw_disk_in_use = FALSE;
ibool srv_start_has_been_called = FALSE;
ulint srv_sizeof_trx_t_in_ha_innodb_cc;
@ -87,13 +96,6 @@ ibool srv_os_test_mutex_is_locked = FALSE;
#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
#define SRV_MAX_N_PENDING_SYNC_IOS 100
/* The following limit may be too big in some old operating systems:
we may get an assertion failure in os0file.c */
#define SRV_MAX_N_OPEN_FILES 500
#define SRV_LOG_SPACE_FIRST_ID 1000000000
/*************************************************************************
Reads the data files and their sizes from a character string given in
the .cnf file. */
@ -137,7 +139,8 @@ srv_parse_data_file_paths_and_sizes(
while ((*str != ':' && *str != '\0')
|| (*str == ':'
&& (*(str + 1) == '\\' || *(str + 1) == '/'))) {
&& (*(str + 1) == '\\' || *(str + 1) == '/'
|| *(str + 1) == ':'))) {
str++;
}
@ -234,11 +237,15 @@ srv_parse_data_file_paths_and_sizes(
while (*str != '\0') {
path = str;
/* Note that we must ignore the ':' in a Windows path */
/* Note that we must step over the ':' in a Windows path;
a Windows path normally looks like C:\ibdata\ibdata1:1G, but
a Windows raw partition may have a specification like
\\.\C::1Gnewraw or \\.\PHYSICALDRIVE2:1Gnewraw */
while ((*str != ':' && *str != '\0')
|| (*str == ':'
&& (*(str + 1) == '\\' || *(str + 1) == '/'))) {
&& (*(str + 1) == '\\' || *(str + 1) == '/'
|| *(str + 1) == ':'))) {
str++;
}
@ -452,7 +459,8 @@ Normalizes a directory path for Windows: converts slashes to backslashes. */
void
srv_normalize_path_for_win(
/*=======================*/
char* str __attribute__((unused))) /* in/out: null-terminated character string */
char* str __attribute__((unused))) /* in/out: null-terminated
character string */
{
#ifdef __WIN__
ulint i;
@ -510,7 +518,7 @@ srv_calc_low32(
expressed in bytes */
ulint file_size) /* in: file size in database pages */
{
return(0xFFFFFFFF & (file_size << UNIV_PAGE_SIZE_SHIFT));
return(0xFFFFFFFFUL & (file_size << UNIV_PAGE_SIZE_SHIFT));
}
/*************************************************************************
@ -563,7 +571,7 @@ open_or_create_log_file(
files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL,
OS_LOG_FILE, &ret);
if (ret == FALSE) {
if (os_file_get_last_error() != OS_FILE_ALREADY_EXISTS) {
if (os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS) {
fprintf(stderr,
"InnoDB: Error in creating or opening %s\n", name);
@ -640,7 +648,7 @@ open_or_create_log_file(
ut_a(fil_validate());
fil_node_create(name, srv_log_file_size,
2 * k + SRV_LOG_SPACE_FIRST_ID);
2 * k + SRV_LOG_SPACE_FIRST_ID, FALSE);
/* If this is the first log group, create the file space object
for archived logs */
@ -648,7 +656,8 @@ open_or_create_log_file(
if (k == 0 && i == 0) {
arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID;
fil_space_create((char*) "arch_log_space", arch_space_id, FIL_LOG);
fil_space_create((char*) "arch_log_space", arch_space_id,
FIL_LOG);
} else {
arch_space_id = ULINT_UNDEFINED;
}
@ -708,31 +717,15 @@ open_or_create_data_files(
sprintf(name, "%s%s", srv_data_home, srv_data_file_names[i]);
files[i] = os_file_create(name, OS_FILE_CREATE,
if (srv_data_file_is_raw_partition[i] == 0) {
/* First we try to create the file: if it already
exists, ret will get value FALSE */
files[i] = os_file_create(name, OS_FILE_CREATE,
OS_FILE_NORMAL, OS_DATA_FILE, &ret);
if (srv_data_file_is_raw_partition[i] == SRV_NEW_RAW) {
/* The partition is opened, not created; then it is
written over */
srv_created_new_raw = TRUE;
files[i] = os_file_create(
name, OS_FILE_OPEN, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
if (!ret) {
fprintf(stderr,
"InnoDB: Error in opening %s\n", name);
return(DB_ERROR);
}
} else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
ret = FALSE;
}
if (ret == FALSE) {
if (srv_data_file_is_raw_partition[i] != SRV_OLD_RAW
&& os_file_get_last_error() !=
if (ret == FALSE && os_file_get_last_error(FALSE) !=
OS_FILE_ALREADY_EXISTS) {
fprintf(stderr,
"InnoDB: Error in creating or opening %s\n",
@ -740,6 +733,32 @@ open_or_create_data_files(
return(DB_ERROR);
}
} else if (srv_data_file_is_raw_partition[i] == SRV_NEW_RAW) {
/* The partition is opened, not created; then it is
written over */
srv_start_raw_disk_in_use = TRUE;
srv_created_new_raw = TRUE;
files[i] = os_file_create(
name, OS_FILE_OPEN_RAW, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
if (!ret) {
fprintf(stderr,
"InnoDB: Error in opening %s\n", name);
return(DB_ERROR);
}
} else if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
srv_start_raw_disk_in_use = TRUE;
ret = FALSE;
} else {
ut_a(0);
}
if (ret == FALSE) {
/* We open the data file */
if (one_created) {
fprintf(stderr,
@ -750,71 +769,80 @@ open_or_create_data_files(
return(DB_ERROR);
}
files[i] = os_file_create(
name, OS_FILE_OPEN, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
files[i] = os_file_create(
name, OS_FILE_OPEN_RAW, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
} else {
files[i] = os_file_create(
name, OS_FILE_OPEN, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
}
if (!ret) {
fprintf(stderr,
"InnoDB: Error in opening %s\n", name);
os_file_get_last_error();
os_file_get_last_error(TRUE);
return(DB_ERROR);
}
if (srv_data_file_is_raw_partition[i] != SRV_OLD_RAW) {
ret = os_file_get_size(files[i], &size,
&size_high);
ut_a(ret);
/* Round size downward to megabytes */
if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) {
goto skip_size_check;
}
ret = os_file_get_size(files[i], &size, &size_high);
ut_a(ret);
/* Round size downward to megabytes */
rounded_size_pages = (size / (1024 * 1024)
rounded_size_pages = (size / (1024 * 1024)
+ 4096 * size_high)
<< (20 - UNIV_PAGE_SIZE_SHIFT);
if (i == srv_n_data_files - 1
if (i == srv_n_data_files - 1
&& srv_auto_extend_last_data_file) {
if (srv_data_file_sizes[i] >
if (srv_data_file_sizes[i] >
rounded_size_pages
|| (srv_last_file_size_max > 0
&& srv_last_file_size_max <
rounded_size_pages)) {
fprintf(stderr,
fprintf(stderr,
"InnoDB: Error: auto-extending data file %s is of a different size\n"
"InnoDB: %lu pages (rounded down to MB) than specified in the .cnf file:\n"
"InnoDB: initial %lu pages, max %lu (relevant if non-zero) pages!\n",
name, rounded_size_pages,
srv_data_file_sizes[i], srv_last_file_size_max);
return(DB_ERROR);
}
srv_data_file_sizes[i] =
rounded_size_pages;
return(DB_ERROR);
}
srv_data_file_sizes[i] = rounded_size_pages;
}
if (rounded_size_pages
!= srv_data_file_sizes[i]) {
if (rounded_size_pages != srv_data_file_sizes[i]) {
fprintf(stderr,
fprintf(stderr,
"InnoDB: Error: data file %s is of a different size\n"
"InnoDB: %lu pages (rounded down to MB)\n"
"InnoDB: than specified in the .cnf file %lu pages!\n", name,
rounded_size_pages,
srv_data_file_sizes[i]);
return(DB_ERROR);
}
return(DB_ERROR);
}
skip_size_check:
fil_read_flushed_lsn_and_arch_log_no(files[i],
one_opened,
min_flushed_lsn, min_arch_log_no,
max_flushed_lsn, max_arch_log_no);
one_opened = TRUE;
} else {
/* We created the data file and now write it full of
zeros */
one_created = TRUE;
if (i > 0) {
@ -862,7 +890,13 @@ open_or_create_data_files(
ut_a(fil_validate());
fil_node_create(name, srv_data_file_sizes[i], 0);
if (srv_data_file_is_raw_partition[i]) {
fil_node_create(name, srv_data_file_sizes[i], 0, TRUE);
} else {
fil_node_create(name, srv_data_file_sizes[i], 0,
FALSE);
}
}
ios = 0;
@ -972,9 +1006,11 @@ innobase_start_or_create_for_mysql(void)
ulint tablespace_size_in_header;
ulint err;
ulint i;
ulint k;
ibool srv_file_per_table_original_value = srv_file_per_table;
mtr_t mtr;
srv_file_per_table = FALSE; /* system tables are created in tablespace
0 */
#ifdef UNIV_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_DEBUG switched on !!!!!!!!!!!!!!!\n");
@ -999,7 +1035,6 @@ innobase_start_or_create_for_mysql(void)
fprintf(stderr,
"InnoDB: !!!!!!!!!!!!!! UNIV_SIMULATE_AWE switched on !!!!!!!!!!!!!!!!!\n");
#endif
if (srv_sizeof_trx_t_in_ha_innodb_cc != (ulint)sizeof(trx_t)) {
fprintf(stderr,
"InnoDB: Error: trx_t size is %lu in ha_innodb.cc but %lu in srv0start.c\n"
@ -1122,7 +1157,6 @@ innobase_start_or_create_for_mysql(void)
if (!os_aio_use_native_aio) {
/* In simulated aio we currently have use only for 4 threads */
srv_n_file_io_threads = 4;
os_aio_init(8 * SRV_N_PENDING_IOS_PER_THREAD
@ -1136,7 +1170,7 @@ innobase_start_or_create_for_mysql(void)
SRV_MAX_N_PENDING_SYNC_IOS);
}
fil_init(SRV_MAX_N_OPEN_FILES);
fil_init(srv_max_n_open_files);
if (srv_use_awe) {
fprintf(stderr,
@ -1168,7 +1202,6 @@ innobase_start_or_create_for_mysql(void)
for (i = 0; i < srv_n_file_io_threads; i++) {
n[i] = i;
os_thread_create(io_handler_thread, n + i, thread_ids + i);
}
@ -1181,7 +1214,6 @@ innobase_start_or_create_for_mysql(void)
}
if (srv_n_log_files * srv_log_file_size >= 262144) {
fprintf(stderr,
"InnoDB: Error: combined size of log files must be < 4 GB\n");
@ -1227,42 +1259,25 @@ innobase_start_or_create_for_mysql(void)
return((int) err);
}
if (!create_new_db) {
/* If we are using the doublewrite method, we will
check if there are half-written pages in data files,
and restore them from the doublewrite buffer if
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
trx_sys_doublewrite_restore_corrupt_pages();
}
}
srv_normalize_path_for_win(srv_arch_dir);
srv_arch_dir = srv_add_path_separator_if_needed(srv_arch_dir);
for (i = 0; i < srv_n_log_files; i++) {
err = open_or_create_log_file(create_new_db, &log_file_created,
log_opened, 0, i);
if (err != DB_SUCCESS) {
for (k = 0; k < srv_n_log_groups; k++) {
return((int) err);
}
for (i = 0; i < srv_n_log_files; i++) {
err = open_or_create_log_file(create_new_db,
&log_file_created,
log_opened, k, i);
if (err != DB_SUCCESS) {
return((int) err);
}
if (log_file_created) {
log_created = TRUE;
} else {
log_opened = TRUE;
}
if ((log_opened && create_new_db)
if (log_file_created) {
log_created = TRUE;
} else {
log_opened = TRUE;
}
if ((log_opened && create_new_db)
|| (log_opened && log_created)) {
fprintf(stderr,
fprintf(stderr,
"InnoDB: Error: all log files must be created at the same time.\n"
"InnoDB: All log files must be created also in database creation.\n"
"InnoDB: If you want bigger or smaller log files, shut down the\n"
@ -1270,14 +1285,16 @@ innobase_start_or_create_for_mysql(void)
"InnoDB: Then delete the existing log files. Edit the .cnf file\n"
"InnoDB: and start the database again.\n");
return(DB_ERROR);
}
return(DB_ERROR);
}
}
if (log_created && !create_new_db && !srv_archive_recovery) {
/* Open all log files and data files in the system tablespace: we
keep them open until database shutdown */
fil_open_log_and_system_tablespace_files();
if (log_created && !create_new_db && !srv_archive_recovery) {
if (ut_dulint_cmp(max_flushed_lsn, min_flushed_lsn) != 0
|| max_arch_log_no != min_arch_log_no) {
fprintf(stderr,
@ -1323,7 +1340,6 @@ innobase_start_or_create_for_mysql(void)
} else if (srv_archive_recovery) {
fprintf(stderr,
"InnoDB: Starting archive recovery from a backup...\n");
err = recv_recovery_from_archive_start(
min_flushed_lsn,
srv_archive_recovery_limit_lsn,
@ -1332,14 +1348,11 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR);
}
/* Since ibuf init is in dict_boot, and ibuf is needed
in any disk i/o, first call dict_boot */
dict_boot();
trx_sys_init_at_db_start();
srv_startup_is_before_trx_rollback_phase = FALSE;
/* Initialize the fsp free limit global variable in the log
@ -1349,7 +1362,7 @@ innobase_start_or_create_for_mysql(void)
recv_recovery_from_archive_finish();
} else {
/* We always try to do a recovery, even if the database had
been shut down normally */
been shut down normally: this is the normal startup path */
err = recv_recovery_from_checkpoint_start(LOG_CHECKPOINT,
ut_dulint_max,
@ -1413,6 +1426,14 @@ innobase_start_or_create_for_mysql(void)
}
}
if (!create_new_db && srv_force_recovery == 0) {
/* After a crash recovery we only check that the info in data
dictionary is consistent with what we already know about space
id's from the call of fil_load_single_table_tablespaces(). */
dict_check_tablespaces_or_store_max_id(recv_needed_recovery);
}
if (srv_measure_contention) {
/* os_thread_create(&test_measure_cont, NULL, thread_ids +
SRV_MAX_N_IO_THREADS); */
@ -1425,17 +1446,27 @@ innobase_start_or_create_for_mysql(void)
and prints InnoDB monitor info */
os_thread_create(&srv_lock_timeout_and_monitor_thread, NULL,
thread_ids + 2 + SRV_MAX_N_IO_THREADS);
thread_ids + 2 + SRV_MAX_N_IO_THREADS);
/* Create the thread which warns of long semaphore waits */
os_thread_create(&srv_error_monitor_thread, NULL,
thread_ids + 3 + SRV_MAX_N_IO_THREADS);
thread_ids + 3 + SRV_MAX_N_IO_THREADS);
srv_was_started = TRUE;
srv_is_being_started = FALSE;
#ifdef UNIV_DEBUG
/* Wait a while so that creates threads have time to suspend themselves
before we switch sync debugging on; otherwise a thread may execute
mutex_enter() before the checks are on, and mutex_exit() after the
checks are on. */
os_thread_sleep(2000000);
#endif
sync_order_checks_on = TRUE;
if (srv_use_doublewrite_buf && trx_doublewrite == NULL) {
if (srv_use_doublewrite_buf && trx_doublewrite == NULL) {
/* Create the doublewrite buffer to a new tablespace */
trx_sys_create_doublewrite_buf();
}
@ -1445,8 +1476,8 @@ innobase_start_or_create_for_mysql(void)
return((int)DB_ERROR);
}
/* Create the master thread which monitors the database
server, and does purge and other utility operations */
/* Create the master thread which does purge and other utility
operations */
os_thread_create(&srv_master_thread, NULL, thread_ids + 1 +
SRV_MAX_N_IO_THREADS);
@ -1478,7 +1509,7 @@ innobase_start_or_create_for_mysql(void)
tablespace_size_in_header, sum_of_data_file_sizes);
}
/* Check that os_fast_mutexes work as exptected */
/* Check that os_fast_mutexes work as expected */
os_fast_mutex_init(&srv_os_test_mutex);
if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) {
@ -1498,7 +1529,10 @@ innobase_start_or_create_for_mysql(void)
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Started\n");
fprintf(stderr,
" InnoDB: Started; log sequence number %lu %lu\n",
ut_dulint_get_high(srv_start_lsn),
ut_dulint_get_low(srv_start_lsn));
}
if (srv_force_recovery > 0) {
@ -1509,6 +1543,47 @@ innobase_start_or_create_for_mysql(void)
fflush(stderr);
if (trx_doublewrite_must_reset_space_ids) {
fprintf(stderr,
"InnoDB: You are upgrading to an InnoDB version which allows multiple\n"
"InnoDB: tablespaces. Wait that purge and insert buffer merge run to\n"
"InnoDB: completion...\n");
for (;;) {
os_thread_sleep(1000000);
if (0 == strcmp(srv_main_thread_op_info,
"waiting for server activity")) {
ut_a(ibuf_is_empty());
break;
}
}
fprintf(stderr,
"InnoDB: Full purge and insert buffer merge completed.\n");
trx_sys_mark_upgraded_to_multiple_tablespaces();
fprintf(stderr,
"InnoDB: You have now successfully upgraded to the multiple tablespaces\n"
"InnoDB: format. You should not downgrade again to an earlier version of\n"
"InnoDB: InnoDB!\n");
}
if (srv_force_recovery == 0) {
/* In the insert buffer we may have even bigger tablespace
id's, because we may have dropped those tablespaces, but
insert buffer merge has not had time to clean the records from
the ibuf tree. */
ibuf_update_max_tablespace_id();
}
srv_file_per_table = srv_file_per_table_original_value;
fprintf(stderr,
"TODO: make sure MySQL sets field->query_id right in prepare/execute\n");
return((int) DB_SUCCESS);
}
@ -1526,17 +1601,16 @@ innobase_shutdown_for_mysql(void)
if (srv_is_being_started) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: shutting down a not properly started\n");
fprintf(stderr,
" InnoDB: or created database!\n");
" InnoDB: Warning: shutting down a not properly started\n"
" InnoDB: or created database!\n");
}
return(DB_SUCCESS);
}
/* 1. Flush buffer pool to disk, write the current lsn to
/* 1. Flush the buffer pool to disk, write the current lsn to
the tablespace header(s), and copy all log data to archive.
The step 1 is the real InnoDB shutdown. The remaining steps
The step 1 is the real InnoDB shutdown. The remaining steps 2 - ...
just free data structures after the shutdown. */
logs_empty_and_mark_files_at_shutdown();
@ -1560,16 +1634,16 @@ innobase_shutdown_for_mysql(void)
/* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM
HERE OR EARLIER */
/* 1. Let the lock timeout thread exit */
/* a. Let the lock timeout thread exit */
os_event_set(srv_lock_timeout_thread_event);
/* 2. srv error monitor thread exits automatically, no need
/* b. srv error monitor thread exits automatically, no need
to do anything here */
/* 3. We wake the master thread so that it exits */
/* c. We wake the master thread so that it exits */
srv_wake_master_thread();
/* 4. Exit the i/o threads */
/* d. Exit the i/o threads */
os_aio_wake_all_threads_at_shutdown();
@ -1628,7 +1702,10 @@ innobase_shutdown_for_mysql(void)
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Shutdown completed\n");
fprintf(stderr,
" InnoDB: Shutdown completed; log sequence number %lu %lu\n",
ut_dulint_get_high(srv_shutdown_lsn),
ut_dulint_get_low(srv_shutdown_lsn));
}
return((int) DB_SUCCESS);

View File

@ -121,6 +121,11 @@ rw_lock_create_func(
lock->last_x_line = 0;
mutex_enter(&rw_lock_list_mutex);
if (UT_LIST_GET_LEN(rw_lock_list) > 0) {
ut_a(UT_LIST_GET_FIRST(rw_lock_list)->magic_n
== RW_LOCK_MAGIC_N);
}
UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
@ -137,7 +142,7 @@ rw_lock_free(
/*=========*/
rw_lock_t* lock) /* in: rw-lock */
{
ut_ad(rw_lock_validate(lock));
ut_a(rw_lock_validate(lock));
ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
ut_a(rw_lock_get_waiters(lock) == 0);
ut_a(rw_lock_get_reader_count(lock) == 0);
@ -148,6 +153,13 @@ rw_lock_free(
mutex_enter(&rw_lock_list_mutex);
if (UT_LIST_GET_PREV(list, lock)) {
ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N);
}
if (UT_LIST_GET_NEXT(list, lock)) {
ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N);
}
UT_LIST_REMOVE(list, rw_lock_list, lock);
mutex_exit(&rw_lock_list_mutex);

View File

@ -159,7 +159,7 @@ struct sync_thread_struct{
};
/* Number of slots reserved for each OS thread in the sync level array */
#define SYNC_THREAD_N_LEVELS 250
#define SYNC_THREAD_N_LEVELS 7000
struct sync_level_struct{
void* latch; /* pointer to a mutex or an rw-lock; NULL means that
@ -246,6 +246,10 @@ mutex_create_func(
mutex_enter(&mutex_list_mutex);
if (UT_LIST_GET_LEN(mutex_list) > 0) {
ut_a(UT_LIST_GET_FIRST(mutex_list)->magic_n == MUTEX_MAGIC_N);
}
UT_LIST_ADD_FIRST(list, mutex_list, mutex);
mutex_exit(&mutex_list_mutex);
@ -261,7 +265,7 @@ mutex_free(
/*=======*/
mutex_t* mutex) /* in: mutex */
{
ut_ad(mutex_validate(mutex));
ut_a(mutex_validate(mutex));
ut_a(mutex_get_lock_word(mutex) == 0);
ut_a(mutex_get_waiters(mutex) == 0);
@ -269,6 +273,15 @@ mutex_free(
mutex_enter(&mutex_list_mutex);
if (UT_LIST_GET_PREV(list, mutex)) {
ut_a(UT_LIST_GET_PREV(list, mutex)->magic_n
== MUTEX_MAGIC_N);
}
if (UT_LIST_GET_NEXT(list, mutex)) {
ut_a(UT_LIST_GET_NEXT(list, mutex)->magic_n
== MUTEX_MAGIC_N);
}
UT_LIST_REMOVE(list, mutex_list, mutex);
mutex_exit(&mutex_list_mutex);
@ -991,7 +1004,7 @@ sync_thread_add_level(
}
array = thread_slot->levels;
/* NOTE that there is a problem with _NODE and _LEAF levels: if the
B-tree height changes, then a leaf can change to an internal node
or the other way around. We do not know at present if this can cause

View File

@ -26,6 +26,17 @@ Created 3/26/1996 Heikki Tuuri
trx_sys_t* trx_sys = NULL;
trx_doublewrite_t* trx_doublewrite = NULL;
/* The following is set to TRUE when we are upgrading from the old format data
files to the new >= 4.1.x format multiple tablespaces format data files */
ibool trx_doublewrite_must_reset_space_ids = FALSE;
/* The following is TRUE when we are using the database in the new format,
i.e., we have successfully upgraded, or have created a new database
installation */
ibool trx_sys_multiple_tablespace_format = FALSE;
/* In a MySQL replication slave, in crash recovery we store the master log
file name and position here. We have successfully got the updates to InnoDB
up to this position. If .._pos is -1, it means no crash recovery was needed,
@ -75,11 +86,11 @@ trx_doublewrite_init(
{
trx_doublewrite = mem_alloc(sizeof(trx_doublewrite_t));
/* When we have the doublewrite buffer in use, we do not need to
call os_file_flush (Unix fsync) after every write. */
/* Since we now start to use the doublewrite buffer, no need to call
fsync() after every write to a data file */
os_do_not_call_flush_at_each_write = TRUE;
mutex_create(&(trx_doublewrite->mutex));
mutex_set_level(&(trx_doublewrite->mutex), SYNC_DOUBLEWRITE);
@ -105,7 +116,41 @@ trx_doublewrite_init(
}
/********************************************************************
Creates the doublewrite buffer at a database start. The header of the
Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
multiple tablespace format. */
void
trx_sys_mark_upgraded_to_multiple_tablespaces(void)
/*===============================================*/
{
page_t* page;
byte* doublewrite;
mtr_t mtr;
/* We upgraded to 4.1.x and reset the space id fields in the
doublewrite buffer. Let us mark to the trx_sys header that the upgrade
has been done. */
mtr_start(&mtr);
page = buf_page_get(TRX_SYS_SPACE, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK);
doublewrite = page + TRX_SYS_DOUBLEWRITE;
mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
MLOG_4BYTES, &mtr);
mtr_commit(&mtr);
/* Flush the modified pages to disk and make a checkpoint */
log_make_checkpoint_at(ut_dulint_max, TRUE);
trx_sys_multiple_tablespace_format = TRUE;
}
/********************************************************************
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */
void
@ -138,7 +183,6 @@ start_again:
if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
== TRX_SYS_DOUBLEWRITE_MAGIC_N) {
/* The doublewrite buffer has already been created:
just read in some numbers */
@ -244,10 +288,15 @@ start_again:
}
mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC,
TRX_SYS_DOUBLEWRITE_MAGIC_N, MLOG_4BYTES, &mtr);
TRX_SYS_DOUBLEWRITE_MAGIC_N, MLOG_4BYTES, &mtr);
mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC
+ TRX_SYS_DOUBLEWRITE_REPEAT,
TRX_SYS_DOUBLEWRITE_MAGIC_N, MLOG_4BYTES, &mtr);
TRX_SYS_DOUBLEWRITE_MAGIC_N, MLOG_4BYTES, &mtr);
mlog_write_ulint(doublewrite
+ TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED,
TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N,
MLOG_4BYTES, &mtr);
mtr_commit(&mtr);
/* Flush the modified pages to disk and make a checkpoint */
@ -255,23 +304,31 @@ start_again:
fprintf(stderr, "InnoDB: Doublewrite buffer created\n");
trx_sys_multiple_tablespace_format = TRUE;
goto start_again;
}
}
/********************************************************************
At a database startup uses a possible doublewrite buffer to restore
At a database startup initializes the doublewrite buffer memory structure if
we already have a doublewrite buffer created in the data files. If we are
upgrading to an InnoDB version which supports multiple tablespaces, then this
function performs the necessary update operations. If we are in a crash
recovery, this function uses a possible doublewrite buffer to restore
half-written pages in the data files. */
void
trx_sys_doublewrite_restore_corrupt_pages(void)
/*===========================================*/
trx_sys_doublewrite_init_or_restore_pages(
/*======================================*/
ibool restore_corrupt_pages)
{
byte* buf;
byte* read_buf;
byte* unaligned_read_buf;
ulint block1;
ulint block2;
ulint source_page_no;
byte* page;
byte* doublewrite;
ulint space_id;
@ -283,12 +340,11 @@ trx_sys_doublewrite_restore_corrupt_pages(void)
unaligned_read_buf = ut_malloc(2 * UNIV_PAGE_SIZE);
read_buf = ut_align(unaligned_read_buf, UNIV_PAGE_SIZE);
/* Read the trx sys header to check if we are using the
doublewrite buffer */
/* Read the trx sys header to check if we are using the doublewrite
buffer */
fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, TRX_SYS_PAGE_NO, 0,
UNIV_PAGE_SIZE, read_buf, NULL);
doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
@ -305,6 +361,23 @@ trx_sys_doublewrite_restore_corrupt_pages(void)
goto leave_func;
}
if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED)
!= TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) {
/* We are upgrading from a version < 4.1.x to a version where
multiple tablespaces are supported. We must reset the space id
field in the pages in the doublewrite buffer because starting
from this version the space id is stored to
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID. */
trx_doublewrite_must_reset_space_ids = TRUE;
fprintf(stderr,
"InnoDB: Resetting space id's in the doublewrite buffer\n");
} else {
trx_sys_multiple_tablespace_format = TRUE;
}
/* Read the pages from the doublewrite buffer to memory */
fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, block1, 0,
@ -322,12 +395,45 @@ trx_sys_doublewrite_restore_corrupt_pages(void)
for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
space_id = 0;
if (!fil_check_adress_in_tablespace(space_id, page_no)) {
if (trx_doublewrite_must_reset_space_ids) {
space_id = 0;
mach_write_to_4(page
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
/* We do not need to calculate new checksums for the
pages because the field .._SPACE_ID does not affect
them. Write the page back to where we read it from. */
if (i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
source_page_no = block1 + i;
} else {
source_page_no = block2
+ i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
}
fil_io(OS_FILE_WRITE, TRUE, 0, source_page_no, 0,
UNIV_PAGE_SIZE, page, NULL);
/* printf("Resetting space id in page %lu\n",
source_page_no); */
} else {
space_id = mach_read_from_4(
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
}
if (!restore_corrupt_pages) {
/* The database was shut down gracefully: no need to
restore pages */
} else if (!fil_tablespace_exists_in_mem(space_id)) {
/* Maybe we have dropped the single-table tablespace
and this page once belonged to it: do nothing */
} else if (!fil_check_adress_in_tablespace(space_id,
page_no)) {
fprintf(stderr,
"InnoDB: Warning: an inconsistent page in the doublewrite buffer\n"
"InnoDB: space id %lu page number %lu, %lu'th page in dblwr buf.\n",
"InnoDB: Warning: a page in the doublewrite buffer is not within space\n"
"InnoDB: bounds; space id %lu page number %lu, page %lu in doublewrite buf.\n",
space_id, page_no, i);
} else if (space_id == TRX_SYS_SPACE
@ -498,8 +604,8 @@ trx_sys_update_mysql_binlog_offset(
mlog_write_ulint(sys_header + field
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW,
(ulint)(offset & 0xFFFFFFFF),
MLOG_4BYTES, mtr);
(ulint)(offset & 0xFFFFFFFFUL),
MLOG_4BYTES, mtr);
}
/*********************************************************************

View File

@ -105,7 +105,7 @@ trx_create(
trx->mysql_log_file_name = NULL;
trx->mysql_log_offset = 0;
trx->mysql_master_log_file_name = "";
trx->mysql_master_log_file_name = (char*)"";
trx->mysql_master_log_pos = 0;
mutex_create(&(trx->undo_mutex));
@ -1624,14 +1624,14 @@ trx_print(
}
buf += sprintf(buf, "\n");
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
buf += sprintf(buf, "mysql tables in use %lu, locked %lu\n",
trx->n_mysql_tables_in_use,
trx->mysql_n_tables_locked);
}
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
buf += sprintf(buf, "mysql tables in use %lu, locked %lu\n",
trx->n_mysql_tables_in_use,
trx->mysql_n_tables_locked);
}
start_of_line = buf;
switch (trx->que_state) {

View File

@ -387,6 +387,7 @@ trx_undo_seg_create(
page_t* undo_page;
trx_upagef_t* page_hdr;
trx_usegf_t* seg_hdr;
ulint n_reserved;
ibool success;
ut_ad(mtr && id && rseg_hdr);
@ -411,8 +412,8 @@ trx_undo_seg_create(
space = buf_frame_get_space_id(rseg_hdr);
success = fsp_reserve_free_extents(space, 2, FSP_UNDO, mtr);
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
mtr);
if (!success) {
return(NULL);
@ -422,7 +423,7 @@ trx_undo_seg_create(
undo_page = fseg_create_general(space, 0,
TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, TRUE, mtr);
fil_space_release_free_extents(space, 2);
fil_space_release_free_extents(space, n_reserved);
if (undo_page == NULL) {
/* No space left */
@ -733,6 +734,7 @@ trx_undo_add_page(
page_t* new_page;
trx_rseg_t* rseg;
ulint page_no;
ulint n_reserved;
ibool success;
ut_ad(mutex_own(&(trx->undo_mutex)));
@ -749,8 +751,8 @@ trx_undo_add_page(
header_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
success = fsp_reserve_free_extents(undo->space, 1, FSP_UNDO, mtr);
success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
FSP_UNDO, mtr);
if (!success) {
return(FIL_NULL);
@ -761,7 +763,7 @@ trx_undo_add_page(
undo->top_page_no + 1, FSP_UP,
TRUE, mtr);
fil_space_release_free_extents(undo->space, 1);
fil_space_release_free_extents(undo->space, n_reserved);
if (page_no == FIL_NULL) {

View File

@ -18,7 +18,7 @@ Created 5/11/1994 Heikki Tuuri
dulint ut_dulint_zero = {0, 0};
/* Maximum value for a dulint */
dulint ut_dulint_max = {0xFFFFFFFF, 0xFFFFFFFF};
dulint ut_dulint_max = {0xFFFFFFFFUL, 0xFFFFFFFFUL};
/****************************************************************
Sort function for dulint arrays. */

View File

@ -200,7 +200,6 @@ ut_get_year_month_day(
*month = (ulint)cal_tm.wMonth;
*day = (ulint)cal_tm.wDay;
#else
struct tm cal_tm;
struct tm* cal_tm_ptr;
time_t tm;

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ typedef struct st_innobase_share {
uint table_name_length,use_count;
} INNOBASE_SHARE;
/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
@ -184,7 +185,7 @@ class ha_innobase: public handler
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
longlong get_auto_increment();
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
};
extern bool innodb_skip;
@ -195,16 +196,18 @@ extern char *innobase_home, *innobase_tmpdir, *innobase_logdir;
extern long innobase_lock_scan_time;
extern long innobase_mirrored_log_groups, innobase_log_files_in_group;
extern long innobase_log_file_size, innobase_log_buffer_size;
extern long innobase_buffer_pool_size, innobase_buffer_pool_awe_mem_mb,
innobase_additional_mem_pool_size;
extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size;
extern long innobase_buffer_pool_awe_mem_mb;
extern long innobase_file_io_threads, innobase_lock_wait_timeout;
extern long innobase_force_recovery, innobase_thread_concurrency;
extern long innobase_open_files;
extern char *innobase_data_home_dir, *innobase_data_file_path;
extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
extern char *innobase_unix_file_flush_method;
/* The following variables have to be my_bool for SHOW VARIABLES to work */
extern my_bool innobase_log_archive,
innobase_use_native_aio, innobase_fast_shutdown;
innobase_use_native_aio, innobase_fast_shutdown,
innobase_file_per_table;
extern "C" {
extern ulong srv_max_buf_pool_modified_pct;
}
@ -237,6 +240,6 @@ int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path);
int innodb_show_status(THD* thd);
bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
uint full_name_len);
my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
uint full_name_len);
void innobase_release_temporary_latches(void* innobase_tid);

View File

@ -3494,6 +3494,7 @@ enum options
OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
OPT_INNODB_FLUSH_METHOD,
OPT_INNODB_FAST_SHUTDOWN,
OPT_INNODB_FILE_PER_TABLE,
OPT_SAFE_SHOW_DB,
OPT_INNODB, OPT_ISAM, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
@ -3553,6 +3554,7 @@ enum options
OPT_INNODB_THREAD_CONCURRENCY,
OPT_INNODB_FORCE_RECOVERY,
OPT_INNODB_MAX_DIRTY_PAGES_PCT,
OPT_INNODB_OPEN_FILES,
OPT_BDB_CACHE_SIZE,
OPT_BDB_LOG_BUFFER_SIZE,
OPT_BDB_MAX_LOCK,
@ -3732,6 +3734,10 @@ Disable with --skip-bdb (will save memory).",
{"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT,
"Percentage of dirty pages allowed in bufferpool.", (gptr*) &srv_max_buf_pool_modified_pct,
(gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0},
{"innodb_file_per_table", OPT_INNODB_FILE_PER_TABLE,
"Stores each InnoDB table to an .ibd file in the database dir.",
(gptr*) &innobase_file_per_table,
(gptr*) &innobase_file_per_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif /* End HAVE_INNOBASE_DB */
{"help", '?', "Display this help and exit.",
(gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
@ -4188,6 +4194,10 @@ replicating a LOAD DATA INFILE command.",
"Number of file I/O threads in InnoDB.", (gptr*) &innobase_file_io_threads,
(gptr*) &innobase_file_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 4, 64, 0,
1, 0},
{"innodb_open_files", OPT_INNODB_OPEN_FILES,
"How many files at the maximum InnoDB keeps open at the same time.",
(gptr*) &innobase_open_files, (gptr*) &innobase_open_files, 0,
GET_LONG, REQUIRED_ARG, 300L, 10L, ~0L, 0, 1L, 0},
{"innodb_lock_wait_timeout", OPT_INNODB_LOCK_WAIT_TIMEOUT,
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.",
(gptr*) &innobase_lock_wait_timeout, (gptr*) &innobase_lock_wait_timeout,

View File

@ -548,10 +548,12 @@ struct show_var_st init_vars[]= {
{"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
{"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
{"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG },
{"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
{"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG },
{"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT},
{"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL},
{"innodb_file_per_table", (char*) &innobase_file_per_table, SHOW_MY_BOOL},
{"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR},
{"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG },
{"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR},

View File

@ -2564,7 +2564,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
}
/*
Check handler allowence to cache query with this tables
Check handler allowance to cache query with these tables
SYNOPSYS
Query_cache::ask_handler_allowance()
@ -2578,7 +2578,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
my_bool Query_cache::ask_handler_allowance(THD *thd,
TABLE_LIST *tables_used)
{
DBUG_ENTER("Query_cache::is_cacheable");
DBUG_ENTER("Query_cache::ask_handler_allowance");
for (; tables_used; tables_used= tables_used->next)
{

View File

@ -32,7 +32,7 @@ static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts};
const char *known_exts[]=
{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS};
{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db", ".ibd", NullS};
static TYPELIB known_extentions=
{array_elements(known_exts)-1,"known_exts", known_exts};

View File

@ -837,7 +837,7 @@ JOIN::optimize()
{
TABLE* table_h = join_tab[i_h].table;
if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
table_h->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
}
}
#endif

View File

@ -2641,6 +2641,14 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
{
/* calculating table's checksum */
ha_checksum crc= 0;
if (t->db_type == DB_TYPE_INNODB) {
/* InnoDB must be told explicitly to retrieve all columns, because
this function does not set field->query_id in the columns to the
current query id */
t->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
}
if (t->file->rnd_init(1))
protocol->store_null();
else

View File

@ -191,7 +191,7 @@ int mysql_update(THD *thd,
We can't update table directly; We must first search after all
matching rows before updating the table!
*/
table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (old_used_keys & ((key_map) 1 << used_index))
{
table->key_read=1;