Updated with changes from lp:percona-server/release-5.1.49-12 as of September 3, 2010

This commit is contained in:
unknown 2010-09-03 17:41:57 +02:00
commit 9ec2d5b6e5
116 changed files with 4952 additions and 1144 deletions

143
ChangeLog
View file

@ -1,3 +1,128 @@
2010-06-24 The InnoDB Team
* handler/ha_innodb.cc:
Fix Bug#54679 alter table causes compressed row_format to revert
to compact
2010-06-22 The InnoDB Team
* dict/dict0dict.c, dict/dict0mem.c, include/dict0mem.h,
include/univ.i, page/page0zip.c, row/row0merge.c:
Fix Bug#47991 InnoDB Dictionary Cache memory usage increases
indefinitely when renaming tables
2010-06-22 The InnoDB Team
* handler/ha_innodb.cc:
Fix Bug#54686: "field->col->mtype == type" assertion error at
row/row0sel.c
2010-06-22 The InnoDB Team
* handler/ha_innodb.cc, innodb_bug54044.result, innodb_bug54044.test:
Fix Bug#54044 Create temporary tables and using innodb crashes.
2010-06-21 The InnoDB Team
* dict/dict0load.c, fil/fil0fil.c:
Fix Bug#54658: InnoDB: Warning: allocated tablespace %lu,
old maximum was 0 (introduced in Bug #53578 fix)
2010-06-16 The InnoDB Team
* row/row0merge.c:
Fix Bug#54330 Broken fast index creation
2010-06-10 The InnoDB Team
* include/log0log.ic, row/row0ins.c, row/row0purge.c,
row/row0uins.c, row/row0umod.c, row/row0upd.c:
Fix Bug#39168 ERROR: the age of the last checkpoint ... exceeds
the log group capacity
2010-06-08 The InnoDB Team
* dict/dict0load.c:
Fix Bug#54009 Server crashes when data is selected from non backed
up table for InnoDB plugin
2010-06-02 The InnoDB Team
* include/db0err.h, include/lock0lock.h, include/row0mysql.h,
lock/lock0lock.c, row/row0ins.c, row/row0mysql.c, row/row0sel.c:
Fix Bug#53674 InnoDB: Error: unlock row could not find a
4 mode lock on the record
2010-06-01 The InnoDB Team
* include/sync0rw.h, sync/sync0rw.c:
Fix Bug#48197 Concurrent rw_lock_free may cause assertion failure
2010-06-01 The InnoDB Team
* row/row0umod.c:
Fix Bug#53812 assert row/row0umod.c line 660 in txn rollback
after crash recovery
2010-05-25 The InnoDB Team
* handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c:
Fix Bug#53592: crash replacing duplicates into table after fast
alter table added unique key
2010-05-24 The InnoDB Team
* dict/dict0boot.c, dict/dict0crea.c, fil/fil0fil.c,
include/dict0boot.h, include/fil0fil.h, row/row0mysql.c:
Fix Bug#53578: assert on invalid page access, in fil_io()
2010-05-14 The InnoDB Team
* mysql-test/innodb_bug48024.test, mysql-test/innodb_bug48024.result,
dict/dict0dict.c, handler/ha_innodb.cc, handler/ha_innodb.h,
include/dict0dict.h, include/ha_prototypes.h, include/row0mysql.h,
include/trx0trx.h, row/row0mysql.c, trx/trx0i_s.c, trx/trx0trx.c:
Fix Bug#48024 Innodb doesn't work with multi-statements
Fix Bug#53644 InnoDB thinks that /*/ starts and ends a comment
2010-05-12 The InnoDB Team
* handler/handler0alter.cc:
Fix Bug#53591 crash with fast alter table and text/blob prefix
primary key
2010-05-12 The InnoDB Team
* row/row0merge.c:
Fix Bug#53471 row_merge_drop_temp_indexes() refers freed memory, SEGVs
2010-05-11 The InnoDB Team
* mysql-test/innodb_bug53290.test, mysql-test/innodb_bug53290.result,
include/rem0cmp.h, rem/rem0cmp.c, row/row0merge.c:
Fix Bug#53290 wrong duplicate key error when adding a unique index
via fast alter table
2010-05-11 The InnoDB Team
* buf/buf0lru.c, include/buf0buf.ic:
Fix Bug#53307 valgrind: warnings in main.partition_innodb_plugin
2010-05-05 The InnoDB Team
* row/row0merge.c:
Fix Bug#53256 in a stress test, assert dict/dict0dict.c:815
table2 == NULL
2010-05-05 The InnoDB Team
* handler/ha_innodb.cc:
Fix Bug#53165 Setting innodb_change_buffering=DEFAULT produces
incorrect result
2010-05-04 The InnoDB Team
* fsp/fsp0fsp.c:
Fix Bug#53306 valgrind: warnings in innodb.innodb
2010-05-03 The InnoDB Team 2010-05-03 The InnoDB Team
* buf0buf.c: * buf0buf.c:
@ -48,12 +173,6 @@
Only check the record size at index creation time when Only check the record size at index creation time when
innodb_strict_mode is set or when ROW_FORMAT is DYNAMIC or COMPRESSED. innodb_strict_mode is set or when ROW_FORMAT is DYNAMIC or COMPRESSED.
2010-04-20 The InnoDB Team
* btr/btr0btr.c, include/univ.i:
Implement UNIV_BTR_AVOID_COPY, for avoiding writes when a B-tree
node is split at the first or last record.
2010-04-15 The InnoDB Team 2010-04-15 The InnoDB Team
* trx/trx0rec.c: * trx/trx0rec.c:
@ -72,6 +191,10 @@
* mysql-test/innodb_bug38231.test: * mysql-test/innodb_bug38231.test:
Remove non-determinism in the test case. Remove non-determinism in the test case.
2010-03-29 The InnoDB Team
InnoDB Plugin 1.0.7 released
2010-03-18 The InnoDB Team 2010-03-18 The InnoDB Team
* CMakeLists.txt: * CMakeLists.txt:
@ -194,6 +317,14 @@
Fix Bug#49497 Error 1467 (ER_AUTOINC_READ_FAILED) on inserting Fix Bug#49497 Error 1467 (ER_AUTOINC_READ_FAILED) on inserting
a negative value a negative value
2010-01-28 The InnoDB Team
* handler/ha_innodb.h, handler/ha_innodb.cc,
handler/handler0alter.cc,
mysql-test/innodb_bug47622.test,
mysql-test/innodb_bug47622.result:
Fix Bug#47622 the new index is added before the existing ones
in MySQL, but after one in SE
2010-01-27 The InnoDB Team 2010-01-27 The InnoDB Team
* include/row0mysql.h, log/log0recv.c, row/row0mysql.c: * include/row0mysql.h, log/log0recv.c, row/row0mysql.c:

View file

@ -573,6 +573,7 @@ yassl_dir = @yassl_dir@
yassl_h_ln_cmd = @yassl_h_ln_cmd@ yassl_h_ln_cmd = @yassl_h_ln_cmd@
yassl_libs = @yassl_libs@ yassl_libs = @yassl_libs@
yassl_taocrypt_extra_cxxflags = @yassl_taocrypt_extra_cxxflags@ yassl_taocrypt_extra_cxxflags = @yassl_taocrypt_extra_cxxflags@
yassl_thread_cxxflags = @yassl_thread_cxxflags@
zlib_dir = @zlib_dir@ zlib_dir = @zlib_dir@
MYSQLDATAdir = $(localstatedir) MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir) MYSQLSHAREdir = $(pkgdatadir)

View file

@ -2030,6 +2030,7 @@ func_start:
goto insert_empty; goto insert_empty;
} }
} else if (UNIV_UNLIKELY(insert_left)) { } else if (UNIV_UNLIKELY(insert_left)) {
ut_a(n_iterations > 0);
first_rec = page_rec_get_next(page_get_infimum_rec(page)); first_rec = page_rec_get_next(page_get_infimum_rec(page));
move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
} else { } else {
@ -2076,17 +2077,7 @@ insert_empty:
} }
/* 5. Move then the records to the new page */ /* 5. Move then the records to the new page */
if (direction == FSP_DOWN if (direction == FSP_DOWN) {
#ifdef UNIV_BTR_AVOID_COPY
&& page_rec_is_supremum(move_limit)) {
/* Instead of moving all records, make the new page
the empty page. */
left_block = block;
right_block = new_block;
} else if (direction == FSP_DOWN
#endif /* UNIV_BTR_AVOID_COPY */
) {
/* fputs("Split left\n", stderr); */ /* fputs("Split left\n", stderr); */
if (0 if (0
@ -2129,14 +2120,6 @@ insert_empty:
right_block = block; right_block = block;
lock_update_split_left(right_block, left_block); lock_update_split_left(right_block, left_block);
#ifdef UNIV_BTR_AVOID_COPY
} else if (!split_rec) {
/* Instead of moving all records, make the new page
the empty page. */
left_block = new_block;
right_block = block;
#endif /* UNIV_BTR_AVOID_COPY */
} else { } else {
/* fputs("Split right\n", stderr); */ /* fputs("Split right\n", stderr); */

View file

@ -2136,9 +2136,8 @@ any_extern:
err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
thr, mtr, &roll_ptr); thr, mtr, &roll_ptr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
err_exit:
mem_heap_free(heap); goto err_exit;
return(err);
} }
/* Ok, we may do the replacement. Store on the page infimum the /* Ok, we may do the replacement. Store on the page infimum the
@ -2184,9 +2183,10 @@ err_exit:
page_cur_move_to_next(page_cursor); page_cur_move_to_next(page_cursor);
err = DB_SUCCESS;
err_exit:
mem_heap_free(heap); mem_heap_free(heap);
return(err);
return(DB_SUCCESS);
} }
/*************************************************************//** /*************************************************************//**
@ -3412,7 +3412,7 @@ btr_estimate_n_pages_not_null(
ibool diverged_lot; ibool diverged_lot;
ulint divergence_level; ulint divergence_level;
ulint n_pages; ulint n_pages;
ulint i,j; ulint i;
mtr_t mtr; mtr_t mtr;
mem_heap_t* heap; mem_heap_t* heap;
@ -4259,6 +4259,8 @@ btr_store_big_rec_extern_fields(
field_ref += local_len; field_ref += local_len;
} }
extern_len = big_rec_vec->fields[i].len; extern_len = big_rec_vec->fields[i].len;
UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
extern_len);
ut_a(extern_len > 0); ut_a(extern_len > 0);
@ -4895,6 +4897,7 @@ btr_copy_blob_prefix(
mtr_commit(&mtr); mtr_commit(&mtr);
if (page_no == FIL_NULL || copy_len != part_len) { if (page_no == FIL_NULL || copy_len != part_len) {
UNIV_MEM_ASSERT_RW(buf, copied_len);
return(copied_len); return(copied_len);
} }
@ -5078,6 +5081,7 @@ btr_copy_externally_stored_field_prefix_low(
space_id, page_no, offset); space_id, page_no, offset);
inflateEnd(&d_stream); inflateEnd(&d_stream);
mem_heap_free(heap); mem_heap_free(heap);
UNIV_MEM_ASSERT_RW(buf, d_stream.total_out);
return(d_stream.total_out); return(d_stream.total_out);
} else { } else {
return(btr_copy_blob_prefix(buf, len, space_id, return(btr_copy_blob_prefix(buf, len, space_id,

View file

@ -182,6 +182,7 @@ void
btr_search_sys_free(void) btr_search_sys_free(void)
/*=====================*/ /*=====================*/
{ {
rw_lock_free(&btr_search_latch);
mem_free(btr_search_latch_temp); mem_free(btr_search_latch_temp);
btr_search_latch_temp = NULL; btr_search_latch_temp = NULL;
mem_heap_free(btr_search_sys->hash_index->heap); mem_heap_free(btr_search_sys->hash_index->heap);

View file

@ -490,11 +490,15 @@ buf_buddy_relocate(
pool), so there is nothing wrong about this. The pool), so there is nothing wrong about this. The
mach_read_from_4() calls here will only trigger bogus mach_read_from_4() calls here will only trigger bogus
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */ Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
bpage = buf_page_hash_get( ulint space = mach_read_from_4(
mach_read_from_4((const byte*) src (const byte*) src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID), ulint page_no = mach_read_from_4(
mach_read_from_4((const byte*) src (const byte*) src + FIL_PAGE_OFFSET);
+ FIL_PAGE_OFFSET)); /* Suppress Valgrind warnings about conditional jump
on uninitialized value. */
UNIV_MEM_VALID(&space, sizeof space);
UNIV_MEM_VALID(&page_no, sizeof page_no);
bpage = buf_page_hash_get(space, page_no);
if (!bpage || bpage->zip.data != src) { if (!bpage || bpage->zip.data != src) {
/* The block has probably been freshly /* The block has probably been freshly
@ -569,7 +573,12 @@ success:
} }
} else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) { } else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
/* This must be a buf_page_t object. */ /* This must be a buf_page_t object. */
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in
buf_page_t. On other systems, Valgrind could complain
about uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(src, size); UNIV_MEM_ASSERT_RW(src, size);
#endif
mutex_exit(&zip_free_mutex); mutex_exit(&zip_free_mutex);

View file

@ -53,6 +53,10 @@ Created 11/5/1995 Heikki Tuuri
#include "page0zip.h" #include "page0zip.h"
#include "trx0trx.h" #include "trx0trx.h"
#include "srv0start.h" #include "srv0start.h"
#include "que0que.h"
#include "read0read.h"
#include "row0row.h"
#include "ha_prototypes.h"
/* prototypes for new functions added to ha_innodb.cc */ /* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx(); trx_t* innobase_get_trx();
@ -78,9 +82,9 @@ inline void _increment_page_get_statistics(buf_block_t* block, trx_t* trx)
block_hash_byte = block_hash >> 3; block_hash_byte = block_hash >> 3;
block_hash_offset = (byte) block_hash & 0x07; block_hash_offset = (byte) block_hash & 0x07;
if (block_hash_byte < 0 || block_hash_byte >= DPAH_SIZE) if (block_hash_byte < 0 || block_hash_byte >= DPAH_SIZE)
fprintf(stderr, "!!! block_hash_byte = %lu block_hash_offset = %lu !!!\n", block_hash_byte, block_hash_offset); fprintf(stderr, "!!! block_hash_byte = %lu block_hash_offset = %d !!!\n", block_hash_byte, block_hash_offset);
if (block_hash_offset < 0 || block_hash_offset > 7) if (block_hash_offset < 0 || block_hash_offset > 7)
fprintf(stderr, "!!! block_hash_byte = %lu block_hash_offset = %lu !!!\n", block_hash_byte, block_hash_offset); fprintf(stderr, "!!! block_hash_byte = %lu block_hash_offset = %d !!!\n", block_hash_byte, block_hash_offset);
if ((trx->distinct_page_access_hash[block_hash_byte] & ((byte) 0x01 << block_hash_offset)) == 0) if ((trx->distinct_page_access_hash[block_hash_byte] & ((byte) 0x01 << block_hash_offset)) == 0)
trx->distinct_page_access++; trx->distinct_page_access++;
trx->distinct_page_access_hash[block_hash_byte] |= (byte) 0x01 << block_hash_offset; trx->distinct_page_access_hash[block_hash_byte] |= (byte) 0x01 << block_hash_offset;
@ -310,14 +314,30 @@ read-ahead or flush occurs */
UNIV_INTERN ibool buf_debug_prints = FALSE; UNIV_INTERN ibool buf_debug_prints = FALSE;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/** A chunk of buffers. The buffer pool is allocated in chunks. */ /* Buffer pool shared memory segment information */
struct buf_chunk_struct{ typedef struct buf_shm_info_struct buf_shm_info_t;
ulint mem_size; /*!< allocated size of the chunk */
ulint size; /*!< size of frames[] and blocks[] */ struct buf_shm_info_struct {
void* mem; /*!< pointer to the memory area which char head_str[8];
was allocated for the frames */ ulint binary_id;
buf_block_t* blocks; /*!< array of buffer control blocks */ ibool is_new; /* during initializing */
ibool clean; /* clean shutdowned and free */
ibool reusable; /* reusable */
ulint buf_pool_size; /* backup value */
ulint page_size; /* backup value */
ulint frame_offset; /* offset of the first frame based on chunk->mem */
ulint zip_hash_offset;
ulint zip_hash_n;
ulint checksum;
buf_pool_t buf_pool_backup;
buf_chunk_t chunk_backup;
ib_uint64_t dummy;
}; };
#define BUF_SHM_INFO_HEAD "XTRA_SHM"
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/********************************************************************//** /********************************************************************//**
@ -764,6 +784,45 @@ buf_block_init(
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
static
void
buf_block_reuse(
/*============*/
buf_block_t* block,
ptrdiff_t frame_offset)
{
/* block_init */
block->frame = ((void*)(block->frame) + frame_offset);
UNIV_MEM_DESC(block->frame, UNIV_PAGE_SIZE, block);
block->index = NULL;
#ifdef UNIV_DEBUG
/* recreate later */
block->page.in_page_hash = FALSE;
block->page.in_zip_hash = FALSE;
#endif /* UNIV_DEBUG */
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
block->n_pointers = 0;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
if (block->page.zip.data)
block->page.zip.data = ((void*)(block->page.zip.data) + frame_offset);
block->is_hashed = FALSE;
mutex_create(&block->mutex, SYNC_BUF_BLOCK);
rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
ut_ad(rw_lock_validate(&(block->lock)));
#ifdef UNIV_SYNC_DEBUG
rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
#endif /* UNIV_SYNC_DEBUG */
}
/********************************************************************//** /********************************************************************//**
Allocates a chunk of buffer frames. Allocates a chunk of buffer frames.
@return chunk, or NULL on failure */ @return chunk, or NULL on failure */
@ -776,26 +835,167 @@ buf_chunk_init(
{ {
buf_block_t* block; buf_block_t* block;
byte* frame; byte* frame;
ulint zip_hash_n = 0;
ulint zip_hash_mem_size = 0;
hash_table_t* zip_hash_tmp = NULL;
ulint i; ulint i;
buf_shm_info_t* shm_info = NULL;
/* Round down to a multiple of page size, /* Round down to a multiple of page size,
although it already should be. */ although it already should be. */
mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE); mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE);
if (srv_buffer_pool_shm_key) {
/* zip_hash size */
zip_hash_n = (mem_size / UNIV_PAGE_SIZE) * 2;
zip_hash_mem_size = ut_2pow_round(hash_create_needed(zip_hash_n)
+ (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
}
/* Reserve space for the block descriptors. */ /* Reserve space for the block descriptors. */
mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block) mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block)
+ (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE); + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
if (srv_buffer_pool_shm_key) {
mem_size += ut_2pow_round(sizeof(buf_shm_info_t)
+ (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
mem_size += zip_hash_mem_size;
}
chunk->mem_size = mem_size; chunk->mem_size = mem_size;
if (srv_buffer_pool_shm_key) {
ulint binary_id;
ibool is_new;
ut_a(buf_pool->n_chunks == 1);
fprintf(stderr,
"InnoDB: Notice: innodb_buffer_pool_shm_key option is specified.\n"
"InnoDB: This option may not be safe to keep consistency of datafiles.\n"
"InnoDB: Because InnoDB cannot lock datafiles when shutdown until reusing shared memory segment.\n"
"InnoDB: You should ensure no change of InnoDB files while using innodb_buffer_pool_shm_key.\n");
/* FIXME: This is vague id still */
binary_id = (ulint) ((void*)mtr_commit - (void*)btr_root_get)
+ (ulint) ((void*)os_get_os_version - (void*)buf_calc_page_new_checksum)
+ (ulint) ((void*)page_dir_find_owner_slot - (void*)dfield_data_is_binary_equal)
+ (ulint) ((void*)que_graph_publish - (void*)dict_casedn_str)
+ (ulint) ((void*)read_view_oldest_copy_or_open_new - (void*)fil_space_get_version)
+ (ulint) ((void*)rec_get_n_extern_new - (void*)fsp_get_size_low)
+ (ulint) ((void*)row_get_trx_id_offset - (void*)ha_create_func)
+ (ulint) ((void*)srv_set_io_thread_op_info - (void*)thd_is_replication_slave_thread)
+ (ulint) ((void*)mutex_create_func - (void*)ibuf_inside)
+ (ulint) ((void*)trx_set_detailed_error - (void*)lock_check_trx_id_sanity)
+ (ulint) ((void*)ut_time - (void*)mem_heap_strdup);
chunk->mem = os_shm_alloc(&chunk->mem_size, srv_buffer_pool_shm_key, &is_new);
if (UNIV_UNLIKELY(chunk->mem == NULL)) {
return(NULL);
}
#ifdef UNIV_SET_MEM_TO_ZERO
if (is_new) {
memset(chunk->mem, '\0', chunk->mem_size);
}
#endif
shm_info = chunk->mem;
zip_hash_tmp = (hash_table_t*)((void*)chunk->mem + chunk->mem_size - zip_hash_mem_size);
if (is_new) {
strncpy(shm_info->head_str, BUF_SHM_INFO_HEAD, 8);
shm_info->binary_id = binary_id;
shm_info->is_new = TRUE; /* changed to FALSE when the initialization is finished */
shm_info->clean = FALSE; /* changed to TRUE when free the segment. */
shm_info->reusable = FALSE; /* changed to TRUE when validation is finished. */
shm_info->buf_pool_size = srv_buf_pool_size;
shm_info->page_size = srv_page_size;
shm_info->zip_hash_offset = chunk->mem_size - zip_hash_mem_size;
shm_info->zip_hash_n = zip_hash_n;
} else {
ulint checksum;
if (strncmp(shm_info->head_str, BUF_SHM_INFO_HEAD, 8)) {
fprintf(stderr,
"InnoDB: Error: The shared memory segment seems not to be for buffer pool.\n");
return(NULL);
}
if (shm_info->binary_id != binary_id) {
fprintf(stderr,
"InnoDB: Error: The shared memory segment seems not to be for this binary.\n");
return(NULL);
}
if (shm_info->is_new) {
fprintf(stderr,
"InnoDB: Error: The shared memory was not initialized yet.\n");
return(NULL);
}
if (!shm_info->clean) {
fprintf(stderr,
"InnoDB: Error: The shared memory was not shut down cleanly.\n");
return(NULL);
}
if (!shm_info->reusable) {
fprintf(stderr,
"InnoDB: Error: The shared memory has unrecoverable contents.\n");
return(NULL);
}
if (shm_info->buf_pool_size != srv_buf_pool_size) {
fprintf(stderr,
"InnoDB: Error: srv_buf_pool_size is different (shm=%lu current=%lu).\n",
shm_info->buf_pool_size, srv_buf_pool_size);
return(NULL);
}
if (shm_info->page_size != srv_page_size) {
fprintf(stderr,
"InnoDB: Error: srv_page_size is different (shm=%lu current=%lu).\n",
shm_info->page_size, srv_page_size);
return(NULL);
}
ut_a(shm_info->zip_hash_offset == chunk->mem_size - zip_hash_mem_size);
ut_a(shm_info->zip_hash_n == zip_hash_n);
/* check checksum */
checksum = ut_fold_binary(chunk->mem + sizeof(buf_shm_info_t),
chunk->mem_size - sizeof(buf_shm_info_t));
if (shm_info->checksum != checksum) {
fprintf(stderr,
"InnoDB: Error: checksum of the shared memory is not match. "
"(stored=%lu calculated=%lu)\n",
shm_info->checksum, checksum);
return(NULL);
}
/* flag to use the segment. */
shm_info->clean = FALSE; /* changed to TRUE when free the segment. */
}
/* init zip_hash contents */
if (is_new) {
hash_create_init(zip_hash_tmp, zip_hash_n);
} else {
/* adjust offset is done later */
hash_create_reuse(zip_hash_tmp);
}
} else {
chunk->mem = os_mem_alloc_large(&chunk->mem_size); chunk->mem = os_mem_alloc_large(&chunk->mem_size);
if (UNIV_UNLIKELY(chunk->mem == NULL)) { if (UNIV_UNLIKELY(chunk->mem == NULL)) {
return(NULL); return(NULL);
} }
}
/* Allocate the block descriptors from /* Allocate the block descriptors from
the start of the memory block. */ the start of the memory block. */
if (srv_buffer_pool_shm_key) {
chunk->blocks = chunk->mem + sizeof(buf_shm_info_t);
} else {
chunk->blocks = chunk->mem; chunk->blocks = chunk->mem;
}
/* Align a pointer to the first frame. Note that when /* Align a pointer to the first frame. Note that when
os_large_page_size is smaller than UNIV_PAGE_SIZE, os_large_page_size is smaller than UNIV_PAGE_SIZE,
@ -803,8 +1003,13 @@ buf_chunk_init(
it is bigger, we may allocate more blocks than requested. */ it is bigger, we may allocate more blocks than requested. */
frame = ut_align(chunk->mem, UNIV_PAGE_SIZE); frame = ut_align(chunk->mem, UNIV_PAGE_SIZE);
if (srv_buffer_pool_shm_key) {
/* reserve zip_hash space and always -1 for reproductibity */
chunk->size = (chunk->mem_size - zip_hash_mem_size) / UNIV_PAGE_SIZE - 1;
} else {
chunk->size = chunk->mem_size / UNIV_PAGE_SIZE chunk->size = chunk->mem_size / UNIV_PAGE_SIZE
- (frame != chunk->mem); - (frame != chunk->mem);
}
/* Subtract the space needed for block descriptors. */ /* Subtract the space needed for block descriptors. */
{ {
@ -818,6 +1023,98 @@ buf_chunk_init(
chunk->size = size; chunk->size = size;
} }
if (shm_info && !(shm_info->is_new)) {
/* convert the shared memory segment for reuse */
ptrdiff_t phys_offset;
ptrdiff_t logi_offset;
ptrdiff_t blocks_offset;
void* previous_frame_address;
if (chunk->size < shm_info->chunk_backup.size) {
fprintf(stderr,
"InnoDB: Error: The buffer pool became smaller because of allocated address.\n"
"InnoDB: Retrying may avoid this situation.\n");
shm_info->clean = TRUE; /* release the flag for retrying */
return(NULL);
}
chunk->size = shm_info->chunk_backup.size;
phys_offset = (void*)frame - (void*)((void*)chunk->mem + shm_info->frame_offset);
logi_offset = (void*)frame - (void*)chunk->blocks[0].frame;
previous_frame_address = chunk->blocks[0].frame;
blocks_offset = (void*)chunk->blocks - (void*)shm_info->chunk_backup.blocks;
if (phys_offset || logi_offset || blocks_offset) {
fprintf(stderr,
"InnoDB: Buffer pool in the shared memory segment should be converted.\n"
"InnoDB: Previous frames in address : %p\n"
"InnoDB: Previous frames were located : %p\n"
"InnoDB: Current frames should be located: %p\n"
"InnoDB: Pysical offset : %ld (%#lx)\n"
"InnoDB: Logical offset (frames) : %ld (%#lx)\n"
"InnoDB: Logical offset (blocks) : %ld (%#lx)\n",
(void*)((void*)chunk->mem + shm_info->frame_offset),
(void*)chunk->blocks[0].frame, (void*)frame,
phys_offset, phys_offset, logi_offset, logi_offset,
blocks_offset, blocks_offset);
} else {
fprintf(stderr,
"InnoDB: Buffer pool in the shared memory segment can be used as it is.\n");
}
if (phys_offset) {
fprintf(stderr,
"InnoDB: Aligning physical offset...");
memmove((void*)frame, (void*)((void*)chunk->mem + shm_info->frame_offset),
chunk->size * UNIV_PAGE_SIZE);
fprintf(stderr,
" Done.\n");
}
if (logi_offset || blocks_offset) {
fprintf(stderr,
"InnoDB: Aligning logical offset...");
/* buf_block_t */
block = chunk->blocks;
for (i = chunk->size; i--; ) {
buf_block_reuse(block, logi_offset);
block++;
}
/* buf_pool_t buf_pool_backup */
UT_LIST_OFFSET(flush_list, buf_page_t, shm_info->buf_pool_backup.flush_list,
previous_frame_address, logi_offset, blocks_offset);
UT_LIST_OFFSET(free, buf_page_t, shm_info->buf_pool_backup.free,
previous_frame_address, logi_offset, blocks_offset);
UT_LIST_OFFSET(LRU, buf_page_t, shm_info->buf_pool_backup.LRU,
previous_frame_address, logi_offset, blocks_offset);
if (shm_info->buf_pool_backup.LRU_old)
shm_info->buf_pool_backup.LRU_old =
((void*)(shm_info->buf_pool_backup.LRU_old)
+ (((void*)shm_info->buf_pool_backup.LRU_old > previous_frame_address)
? logi_offset : blocks_offset));
UT_LIST_OFFSET(unzip_LRU, buf_block_t, shm_info->buf_pool_backup.unzip_LRU,
previous_frame_address, logi_offset, blocks_offset);
UT_LIST_OFFSET(zip_list, buf_page_t, shm_info->buf_pool_backup.zip_clean,
previous_frame_address, logi_offset, blocks_offset);
for (i = 0; i < BUF_BUDDY_SIZES_MAX; i++) {
UT_LIST_OFFSET(zip_list, buf_page_t, shm_info->buf_pool_backup.zip_free[i],
previous_frame_address, logi_offset, blocks_offset);
}
HASH_OFFSET(zip_hash_tmp, buf_page_t, hash,
previous_frame_address, logi_offset, blocks_offset);
fprintf(stderr,
" Done.\n");
}
} else {
/* Init block structs and assign frames for them. Then we /* Init block structs and assign frames for them. Then we
assign the frames to the first blocks (we already mapped the assign the frames to the first blocks (we already mapped the
memory above). */ memory above). */
@ -841,6 +1138,11 @@ buf_chunk_init(
block++; block++;
frame += UNIV_PAGE_SIZE; frame += UNIV_PAGE_SIZE;
} }
}
if (shm_info) {
shm_info->frame_offset = (void*)chunk->blocks[0].frame - (void*)chunk->mem;
}
return(chunk); return(chunk);
} }
@ -940,6 +1242,11 @@ buf_chunk_not_freed(
ready = buf_flush_ready_for_replace(&block->page); ready = buf_flush_ready_for_replace(&block->page);
mutex_exit(&block->mutex); mutex_exit(&block->mutex);
if (block->page.is_corrupt) {
/* corrupt page may remain, it can be skipped */
break;
}
if (!ready) { if (!ready) {
return(block); return(block);
@ -1017,6 +1324,8 @@ buf_chunk_free(
UNIV_MEM_UNDESC(block); UNIV_MEM_UNDESC(block);
} }
ut_a(!srv_buffer_pool_shm_key);
os_mem_free_large(chunk->mem, chunk->mem_size); os_mem_free_large(chunk->mem, chunk->mem_size);
} }
@ -1066,7 +1375,10 @@ buf_pool_init(void)
srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); buf_pool->page_hash = hash_create(2 * buf_pool->curr_size);
/* zip_hash is allocated to shm when srv_buffer_pool_shm_key is enabled */
if (!srv_buffer_pool_shm_key) {
buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size); buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size);
}
buf_pool->last_printout_time = time(NULL); buf_pool->last_printout_time = time(NULL);
@ -1081,6 +1393,86 @@ buf_pool_init(void)
--------------------------- */ --------------------------- */
/* All fields are initialized by mem_zalloc(). */ /* All fields are initialized by mem_zalloc(). */
if (srv_buffer_pool_shm_key) {
buf_shm_info_t* shm_info;
ut_a(chunk->blocks == chunk->mem + sizeof(buf_shm_info_t));
shm_info = chunk->mem;
buf_pool->zip_hash = (hash_table_t*)((void*)chunk->mem + shm_info->zip_hash_offset);
if(shm_info->is_new) {
shm_info->is_new = FALSE; /* initialization was finished */
} else {
buf_block_t* block = chunk->blocks;
buf_page_t* b;
/* shm_info->buf_pool_backup should be converted */
/* at buf_chunk_init(). So copy simply. */
buf_pool->flush_list = shm_info->buf_pool_backup.flush_list;
buf_pool->freed_page_clock = shm_info->buf_pool_backup.freed_page_clock;
buf_pool->free = shm_info->buf_pool_backup.free;
buf_pool->LRU = shm_info->buf_pool_backup.LRU;
buf_pool->LRU_old = shm_info->buf_pool_backup.LRU_old;
buf_pool->LRU_old_len = shm_info->buf_pool_backup.LRU_old_len;
buf_pool->unzip_LRU = shm_info->buf_pool_backup.unzip_LRU;
buf_pool->zip_clean = shm_info->buf_pool_backup.zip_clean;
for (i = 0; i < BUF_BUDDY_SIZES_MAX; i++) {
buf_pool->zip_free[i] = shm_info->buf_pool_backup.zip_free[i];
}
for (i = 0; i < chunk->size; i++, block++) {
if (buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE) {
ut_d(block->page.in_page_hash = TRUE);
HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
buf_page_address_fold(
block->page.space,
block->page.offset),
&block->page);
}
}
for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
b = UT_LIST_GET_NEXT(zip_list, b)) {
ut_ad(!b->in_flush_list);
ut_ad(b->in_LRU_list);
ut_d(b->in_page_hash = TRUE);
HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
buf_page_address_fold(b->space, b->offset), b);
}
for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
b = UT_LIST_GET_NEXT(flush_list, b)) {
ut_ad(b->in_flush_list);
ut_ad(b->in_LRU_list);
switch (buf_page_get_state(b)) {
case BUF_BLOCK_ZIP_DIRTY:
ut_d(b->in_page_hash = TRUE);
HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
buf_page_address_fold(b->space,
b->offset), b);
break;
case BUF_BLOCK_FILE_PAGE:
/* uncompressed page */
break;
case BUF_BLOCK_ZIP_FREE:
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_NOT_USED:
case BUF_BLOCK_READY_FOR_USE:
case BUF_BLOCK_MEMORY:
case BUF_BLOCK_REMOVE_HASH:
ut_error;
break;
}
}
}
}
mutex_exit(&LRU_list_mutex); mutex_exit(&LRU_list_mutex);
rw_lock_x_unlock(&page_hash_latch); rw_lock_x_unlock(&page_hash_latch);
buf_pool_mutex_exit(); buf_pool_mutex_exit();
@ -1105,6 +1497,30 @@ buf_pool_free(void)
buf_chunk_t* chunk; buf_chunk_t* chunk;
buf_chunk_t* chunks; buf_chunk_t* chunks;
if (srv_buffer_pool_shm_key) {
buf_shm_info_t* shm_info;
ut_a(buf_pool->n_chunks == 1);
chunk = buf_pool->chunks;
shm_info = chunk->mem;
ut_a(chunk->blocks == chunk->mem + sizeof(buf_shm_info_t));
/* validation the shared memory segment doesn't have unrecoverable contents. */
/* Currently, validation became not needed */
shm_info->reusable = TRUE;
memcpy(&(shm_info->buf_pool_backup), buf_pool, sizeof(buf_pool_t));
memcpy(&(shm_info->chunk_backup), chunk, sizeof(buf_chunk_t));
if (srv_fast_shutdown < 2) {
shm_info->checksum = ut_fold_binary(chunk->mem + sizeof(buf_shm_info_t),
chunk->mem_size - sizeof(buf_shm_info_t));
shm_info->clean = TRUE;
}
os_shm_free(chunk->mem, chunk->mem_size);
} else {
chunks = buf_pool->chunks; chunks = buf_pool->chunks;
chunk = chunks + buf_pool->n_chunks; chunk = chunks + buf_pool->n_chunks;
@ -1113,10 +1529,13 @@ buf_pool_free(void)
would fail at shutdown. */ would fail at shutdown. */
os_mem_free_large(chunk->mem, chunk->mem_size); os_mem_free_large(chunk->mem, chunk->mem_size);
} }
}
mem_free(buf_pool->chunks); mem_free(buf_pool->chunks);
hash_table_free(buf_pool->page_hash); hash_table_free(buf_pool->page_hash);
if (!srv_buffer_pool_shm_key) {
hash_table_free(buf_pool->zip_hash); hash_table_free(buf_pool->zip_hash);
}
mem_free(buf_pool); mem_free(buf_pool);
buf_pool = NULL; buf_pool = NULL;
} }
@ -1311,6 +1730,11 @@ try_again:
//buf_pool_mutex_enter(); //buf_pool_mutex_enter();
mutex_enter(&LRU_list_mutex); mutex_enter(&LRU_list_mutex);
if (srv_buffer_pool_shm_key) {
/* Cannot support shrink */
goto func_done;
}
shrink_again: shrink_again:
if (buf_pool->n_chunks <= 1) { if (buf_pool->n_chunks <= 1) {
@ -1554,6 +1978,11 @@ void
buf_pool_resize(void) buf_pool_resize(void)
/*=================*/ /*=================*/
{ {
if (srv_buffer_pool_shm_key) {
/* Cannot support resize */
return;
}
//buf_pool_mutex_enter(); //buf_pool_mutex_enter();
mutex_enter(&LRU_list_mutex); mutex_enter(&LRU_list_mutex);
@ -2458,7 +2887,7 @@ wait_until_unfixed:
block->page.buf_fix_count = 1; block->page.buf_fix_count = 1;
buf_block_set_io_fix(block, BUF_IO_READ); buf_block_set_io_fix(block, BUF_IO_READ);
rw_lock_x_lock(&block->lock); rw_lock_x_lock_func(&block->lock, 0, file, line);
UNIV_MEM_INVALID(bpage, sizeof *bpage); UNIV_MEM_INVALID(bpage, sizeof *bpage);
@ -2508,7 +2937,12 @@ wait_until_unfixed:
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
//mutex_enter(&block->mutex); //mutex_enter(&block->mutex);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page);
#endif
buf_block_buf_fix_inc(block, file, line); buf_block_buf_fix_inc(block, file, line);
@ -3522,7 +3956,7 @@ corrupt:
if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space) if (srv_pass_corrupt_table && !trx_sys_sys_space(bpage->space)
&& bpage->space < SRV_LOG_SPACE_FIRST_ID) { && bpage->space < SRV_LOG_SPACE_FIRST_ID) {
fprintf(stderr, fprintf(stderr,
"InnoDB: space %lu will be treated as corrupt.\n", "InnoDB: space %u will be treated as corrupt.\n",
bpage->space); bpage->space);
fil_space_set_corrupt(bpage->space); fil_space_set_corrupt(bpage->space);
if (trx && trx->dict_operation_lock_mode == 0) { if (trx && trx->dict_operation_lock_mode == 0) {

View file

@ -257,6 +257,17 @@ buf_flush_insert_into_flush_list(
ut_d(block->page.in_flush_list = TRUE); ut_d(block->page.in_flush_list = TRUE);
UT_LIST_ADD_FIRST(flush_list, buf_pool->flush_list, &block->page); UT_LIST_ADD_FIRST(flush_list, buf_pool->flush_list, &block->page);
#ifdef UNIV_DEBUG_VALGRIND
{
ulint zip_size = buf_block_get_zip_size(block);
if (UNIV_UNLIKELY(zip_size)) {
UNIV_MEM_ASSERT_RW(block->page.zip.data, zip_size);
} else {
UNIV_MEM_ASSERT_RW(block->frame, UNIV_PAGE_SIZE);
}
}
#endif /* UNIV_DEBUG_VALGRIND */
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(buf_flush_validate_low()); ut_a(buf_flush_validate_low());
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
@ -286,6 +297,18 @@ buf_flush_insert_sorted_into_flush_list(
ut_ad(!block->page.in_flush_list); ut_ad(!block->page.in_flush_list);
ut_d(block->page.in_flush_list = TRUE); ut_d(block->page.in_flush_list = TRUE);
#ifdef UNIV_DEBUG_VALGRIND
{
ulint zip_size = buf_block_get_zip_size(block);
if (UNIV_UNLIKELY(zip_size)) {
UNIV_MEM_ASSERT_RW(block->page.zip.data, zip_size);
} else {
UNIV_MEM_ASSERT_RW(block->frame, UNIV_PAGE_SIZE);
}
}
#endif /* UNIV_DEBUG_VALGRIND */
prev_b = NULL; prev_b = NULL;
/* For the most part when this function is called the flush_rbt /* For the most part when this function is called the flush_rbt
@ -830,6 +853,7 @@ try_again:
zip_size = buf_page_get_zip_size(bpage); zip_size = buf_page_get_zip_size(bpage);
if (UNIV_UNLIKELY(zip_size)) { if (UNIV_UNLIKELY(zip_size)) {
UNIV_MEM_ASSERT_RW(bpage->zip.data, zip_size);
/* Copy the compressed page and clear the rest. */ /* Copy the compressed page and clear the rest. */
memcpy(trx_doublewrite->write_buf memcpy(trx_doublewrite->write_buf
+ UNIV_PAGE_SIZE * trx_doublewrite->first_free, + UNIV_PAGE_SIZE * trx_doublewrite->first_free,
@ -839,6 +863,8 @@ try_again:
+ zip_size, 0, UNIV_PAGE_SIZE - zip_size); + zip_size, 0, UNIV_PAGE_SIZE - zip_size);
} else { } else {
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
UNIV_MEM_ASSERT_RW(((buf_block_t*) bpage)->frame,
UNIV_PAGE_SIZE);
memcpy(trx_doublewrite->write_buf memcpy(trx_doublewrite->write_buf
+ UNIV_PAGE_SIZE * trx_doublewrite->first_free, + UNIV_PAGE_SIZE * trx_doublewrite->first_free,
@ -1533,6 +1559,7 @@ retry:
} else if (!have_LRU_mutex) { } else if (!have_LRU_mutex) {
/* confirm it again with LRU_mutex for exactness */ /* confirm it again with LRU_mutex for exactness */
have_LRU_mutex = TRUE; have_LRU_mutex = TRUE;
distance = 0;
goto retry; goto retry;
} }

View file

@ -1455,7 +1455,7 @@ buf_LRU_make_block_old(
Try to free a block. If bpage is a descriptor of a compressed-only Try to free a block. If bpage is a descriptor of a compressed-only
page, the descriptor object will be freed as well. page, the descriptor object will be freed as well.
NOTE: If this function returns BUF_LRU_FREED, it will not temporarily NOTE: If this function returns BUF_LRU_FREED, it will temporarily
release buf_pool_mutex. Furthermore, the page frame will no longer be release buf_pool_mutex. Furthermore, the page frame will no longer be
accessible via bpage. accessible via bpage.
@ -1485,7 +1485,12 @@ buf_LRU_free_block(
ut_ad(buf_page_in_file(bpage)); ut_ad(buf_page_in_file(bpage));
//ut_ad(bpage->in_LRU_list); //ut_ad(bpage->in_LRU_list);
ut_ad(!bpage->in_flush_list == !bpage->oldest_modification); ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
if (!bpage->in_LRU_list || !block_mutex || !buf_page_can_relocate(bpage)) { if (!bpage->in_LRU_list || !block_mutex || !buf_page_can_relocate(bpage)) {
@ -1618,8 +1623,13 @@ not_freed:
ut_ad(prev_b->in_LRU_list); ut_ad(prev_b->in_LRU_list);
ut_ad(buf_page_in_file(prev_b)); ut_ad(buf_page_in_file(prev_b));
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no
padding in buf_page_t. On other
systems, Valgrind could complain about
uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b); UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
#endif
UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
prev_b, b); prev_b, b);
@ -1834,7 +1844,12 @@ buf_LRU_block_remove_hashed_page(
ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE); ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
ut_a(bpage->buf_fix_count == 0); ut_a(bpage->buf_fix_count == 0);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in
buf_page_t. On other systems, Valgrind could complain
about uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
buf_LRU_remove_block(bpage); buf_LRU_remove_block(bpage);

View file

@ -62,32 +62,47 @@ dict_hdr_get(
} }
/**********************************************************************//** /**********************************************************************//**
Returns a new table, index, or tree id. Returns a new table, index, or space id. */
@return the new id */
UNIV_INTERN UNIV_INTERN
dulint void
dict_hdr_get_new_id( dict_hdr_get_new_id(
/*================*/ /*================*/
ulint type) /*!< in: DICT_HDR_ROW_ID, ... */ dulint* table_id, /*!< out: table id (not assigned if NULL) */
dulint* index_id, /*!< out: index id (not assigned if NULL) */
ulint* space_id) /*!< out: space id (not assigned if NULL) */
{ {
dict_hdr_t* dict_hdr; dict_hdr_t* dict_hdr;
dulint id; dulint id;
mtr_t mtr; mtr_t mtr;
ut_ad((type == DICT_HDR_TABLE_ID) || (type == DICT_HDR_INDEX_ID));
mtr_start(&mtr); mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr); dict_hdr = dict_hdr_get(&mtr);
id = mtr_read_dulint(dict_hdr + type, &mtr); if (table_id) {
id = ut_dulint_add(id, 1); id = mtr_read_dulint(dict_hdr + DICT_HDR_TABLE_ID, &mtr);
id = ut_dulint_add(id, 1);
mlog_write_dulint(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr);
*table_id = id;
}
mlog_write_dulint(dict_hdr + type, id, &mtr); if (index_id) {
id = mtr_read_dulint(dict_hdr + DICT_HDR_INDEX_ID, &mtr);
id = ut_dulint_add(id, 1);
mlog_write_dulint(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr);
*index_id = id;
}
if (space_id) {
*space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID,
MLOG_4BYTES, &mtr);
if (fil_assign_new_space_id(space_id)) {
mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID,
*space_id, MLOG_4BYTES, &mtr);
}
}
mtr_commit(&mtr); mtr_commit(&mtr);
return(id);
} }
/**********************************************************************//** /**********************************************************************//**
@ -151,9 +166,12 @@ dict_hdr_create(
mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID,
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
/* Obsolete, but we must initialize it to 0 anyway. */ mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID,
mlog_write_dulint(dict_header + DICT_HDR_MIX_ID, 0, MLOG_4BYTES, mtr);
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
/* Obsolete, but we must initialize it anyway. */
mlog_write_ulint(dict_header + DICT_HDR_MIX_ID_LOW,
DICT_HDR_FIRST_ID, MLOG_4BYTES, mtr);
/* Create the B-tree roots for the clustered indexes of the basic /* Create the B-tree roots for the clustered indexes of the basic
system tables */ system tables */
@ -245,6 +263,29 @@ dict_boot(void)
/* Get the dictionary header */ /* Get the dictionary header */
dict_hdr = dict_hdr_get(&mtr); dict_hdr = dict_hdr_get(&mtr);
if (ut_dulint_cmp(mtr_read_dulint(dict_hdr + DICT_HDR_XTRADB_MARK, &mtr),
DICT_HDR_XTRADB_FLAG) != 0) {
/* not extended yet by XtraDB, need to be extended */
ulint root_page_no;
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_STATS_ID,
dict_ind_redundant, &mtr);
if (root_page_no == FIL_NULL) {
fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
srv_use_sys_stats_table = FALSE;
} else {
mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
MLOG_4BYTES, &mtr);
mlog_write_dulint(dict_hdr + DICT_HDR_XTRADB_MARK,
DICT_HDR_XTRADB_FLAG, &mtr);
}
mtr_commit(&mtr);
/* restart mtr */
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
}
/* Because we only write new row ids to disk-based data structure /* Because we only write new row ids to disk-based data structure
(dictionary header) when it is divisible by (dictionary header) when it is divisible by
DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
@ -406,7 +447,7 @@ dict_boot(void)
table->id = DICT_FIELDS_ID; table->id = DICT_FIELDS_ID;
dict_table_add_to_cache(table, heap); dict_table_add_to_cache(table, heap);
dict_sys->sys_fields = table; dict_sys->sys_fields = table;
mem_heap_free(heap); mem_heap_empty(heap);
index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND", index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
DICT_HDR_SPACE, DICT_HDR_SPACE,
@ -423,6 +464,41 @@ dict_boot(void)
FALSE); FALSE);
ut_a(error == DB_SUCCESS); ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0);
table->n_mysql_handles_opened = 1; /* for pin */
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
#endif
table->id = DICT_STATS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_stats = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_STATS,
MLOG_4BYTES, &mtr),
FALSE);
ut_a(error == DB_SUCCESS);
mem_heap_free(heap);
mtr_commit(&mtr); mtr_commit(&mtr);
/*-------------------------*/ /*-------------------------*/
@ -436,6 +512,7 @@ dict_boot(void)
dict_load_sys_table(dict_sys->sys_columns); dict_load_sys_table(dict_sys->sys_columns);
dict_load_sys_table(dict_sys->sys_indexes); dict_load_sys_table(dict_sys->sys_indexes);
dict_load_sys_table(dict_sys->sys_fields); dict_load_sys_table(dict_sys->sys_fields);
dict_load_sys_table(dict_sys->sys_stats);
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
} }

View file

@ -239,16 +239,34 @@ dict_build_table_def_step(
const char* path_or_name; const char* path_or_name;
ibool is_path; ibool is_path;
mtr_t mtr; mtr_t mtr;
ulint space = 0;
ibool file_per_table;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
table = node->table; table = node->table;
table->id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); /* Cache the global variable "srv_file_per_table" to
a local variable before using it. Please note
"srv_file_per_table" is not under dict_sys mutex
protection, and could be changed while executing
this function. So better to cache the current value
to a local variable, and all future reference to
"srv_file_per_table" should use this local variable. */
file_per_table = srv_file_per_table;
dict_hdr_get_new_id(&table->id, NULL, NULL);
thr_get_trx(thr)->table_id = table->id; thr_get_trx(thr)->table_id = table->id;
if (srv_file_per_table) { if (file_per_table) {
/* Get a new space id if srv_file_per_table is set */
dict_hdr_get_new_id(NULL, NULL, &space);
if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) {
return(DB_ERROR);
}
/* We create a new single-table tablespace for the table. /* We create a new single-table tablespace for the table.
We initially let it be 4 pages: We initially let it be 4 pages:
- page 0 is the fsp header and an extent descriptor page, - page 0 is the fsp header and an extent descriptor page,
@ -257,8 +275,6 @@ dict_build_table_def_step(
- page 3 will contain the root of the clustered index of the - page 3 will contain the root of the clustered index of the
table we create here. */ table we create here. */
ulint space = 0; /* reset to zero for the call below */
if (table->dir_path_of_temp_table) { if (table->dir_path_of_temp_table) {
/* We place tables created with CREATE TEMPORARY /* We place tables created with CREATE TEMPORARY
TABLE in the tmp dir of mysqld server */ TABLE in the tmp dir of mysqld server */
@ -276,7 +292,7 @@ dict_build_table_def_step(
flags = table->flags & ~(~0 << DICT_TF_BITS); flags = table->flags & ~(~0 << DICT_TF_BITS);
error = fil_create_new_single_table_tablespace( error = fil_create_new_single_table_tablespace(
&space, path_or_name, is_path, space, path_or_name, is_path,
flags == DICT_TF_COMPACT ? 0 : flags, flags == DICT_TF_COMPACT ? 0 : flags,
FIL_IBD_FILE_INITIAL_SIZE); FIL_IBD_FILE_INITIAL_SIZE);
table->space = (unsigned int) space; table->space = (unsigned int) space;
@ -491,6 +507,51 @@ dict_create_sys_fields_tuple(
return(entry); return(entry);
} }
/*****************************************************************//**
Based on an index object, this function builds the entry to be inserted
in the SYS_STATS system table.
@return the tuple which should be inserted */
static
dtuple_t*
dict_create_sys_stats_tuple(
/*========================*/
const dict_index_t* index,
ulint i,
mem_heap_t* heap)
{
dict_table_t* sys_stats;
dtuple_t* entry;
dfield_t* dfield;
byte* ptr;
ut_ad(index);
ut_ad(heap);
sys_stats = dict_sys->sys_stats;
entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
dict_table_copy_types(entry, sys_stats);
/* 0: INDEX_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
ptr = mem_heap_alloc(heap, 8);
mach_write_to_8(ptr, index->id);
dfield_set_data(dfield, ptr, 8);
/* 1: KEY_COLS -----------------------*/
dfield = dtuple_get_nth_field(entry, 1/*KEY_COLS*/);
ptr = mem_heap_alloc(heap, 4);
mach_write_to_4(ptr, i);
dfield_set_data(dfield, ptr, 4);
/* 4: DIFF_VALS ----------------------*/
dfield = dtuple_get_nth_field(entry, 2/*DIFF_VALS*/);
ptr = mem_heap_alloc(heap, 8);
mach_write_to_8(ptr, ut_dulint_zero); /* initial value is 0 */
dfield_set_data(dfield, ptr, 8);
return(entry);
}
/*****************************************************************//** /*****************************************************************//**
Creates the tuple with which the index entry is searched for writing the index Creates the tuple with which the index entry is searched for writing the index
tree root page number, if such a tree is created. tree root page number, if such a tree is created.
@ -561,7 +622,7 @@ dict_build_index_def_step(
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0) ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
|| dict_index_is_clust(index)); || dict_index_is_clust(index));
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID); dict_hdr_get_new_id(NULL, &index->id, NULL);
/* Inherit the space id from the table; we store all indexes of a /* Inherit the space id from the table; we store all indexes of a
table in the same tablespace */ table in the same tablespace */
@ -600,6 +661,27 @@ dict_build_field_def_step(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/***************************************************************//**
Builds a row for storing stats to insert.
@return DB_SUCCESS */
static
ulint
dict_build_stats_def_step(
/*======================*/
ind_node_t* node)
{
dict_index_t* index;
dtuple_t* row;
index = node->index;
row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap);
ins_node_set_new_row(node->stats_def, row);
return(DB_SUCCESS);
}
/***************************************************************//** /***************************************************************//**
Creates an index tree for the index if it is not a member of a cluster. Creates an index tree for the index if it is not a member of a cluster.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
@ -924,6 +1006,49 @@ ind_create_graph_create(
dict_sys->sys_fields, heap); dict_sys->sys_fields, heap);
node->field_def->common.parent = node; node->field_def->common.parent = node;
if (srv_use_sys_stats_table) {
node->stats_def = ins_node_create(INS_DIRECT,
dict_sys->sys_stats, heap);
node->stats_def->common.parent = node;
} else {
node->stats_def = NULL;
}
node->commit_node = commit_node_create(heap);
node->commit_node->common.parent = node;
return(node);
}
/*********************************************************************//**
*/
UNIV_INTERN
ind_node_t*
ind_insert_stats_graph_create(
/*==========================*/
dict_index_t* index,
mem_heap_t* heap)
{
ind_node_t* node;
node = mem_heap_alloc(heap, sizeof(ind_node_t));
node->common.type = QUE_NODE_INSERT_STATS;
node->index = index;
node->state = INDEX_BUILD_STATS_COLS;
node->page_no = FIL_NULL;
node->heap = mem_heap_create(256);
node->ind_def = NULL;
node->field_def = NULL;
node->stats_def = ins_node_create(INS_DIRECT,
dict_sys->sys_stats, heap);
node->stats_def->common.parent = node;
node->stats_no = 0;
node->commit_node = commit_node_create(heap); node->commit_node = commit_node_create(heap);
node->commit_node->common.parent = node; node->commit_node->common.parent = node;
@ -1074,6 +1199,7 @@ dict_create_index_step(
node->state = INDEX_BUILD_FIELD_DEF; node->state = INDEX_BUILD_FIELD_DEF;
node->field_no = 0; node->field_no = 0;
node->stats_no = 0;
thr->run_node = node->ind_def; thr->run_node = node->ind_def;
@ -1119,7 +1245,31 @@ dict_create_index_step(
goto function_exit; goto function_exit;
} }
node->state = INDEX_CREATE_INDEX_TREE; if (srv_use_sys_stats_table) {
node->state = INDEX_BUILD_STATS_COLS;
} else {
node->state = INDEX_CREATE_INDEX_TREE;
}
}
if (node->state == INDEX_BUILD_STATS_COLS) {
if (node->stats_no <= dict_index_get_n_unique(node->index)) {
err = dict_build_stats_def_step(node);
if (err != DB_SUCCESS) {
goto function_exit;
}
node->stats_no++;
thr->run_node = node->stats_def;
return(thr);
} else {
node->state = INDEX_CREATE_INDEX_TREE;
}
} }
if (node->state == INDEX_CREATE_INDEX_TREE) { if (node->state == INDEX_CREATE_INDEX_TREE) {
@ -1170,6 +1320,66 @@ function_exit:
return(thr); return(thr);
} }
/****************************************************************//**
*/
UNIV_INTERN
que_thr_t*
dict_insert_stats_step(
/*===================*/
que_thr_t* thr) /*!< in: query thread */
{
ind_node_t* node;
ulint err = DB_ERROR;
trx_t* trx;
ut_ad(thr);
trx = thr_get_trx(thr);
node = thr->run_node;
if (thr->prev_node == que_node_get_parent(node)) {
node->state = INDEX_BUILD_STATS_COLS;
}
if (node->state == INDEX_BUILD_STATS_COLS) {
if (node->stats_no <= dict_index_get_n_unique(node->index)) {
err = dict_build_stats_def_step(node);
if (err != DB_SUCCESS) {
goto function_exit;
}
node->stats_no++;
thr->run_node = node->stats_def;
return(thr);
} else {
node->state = INDEX_COMMIT_WORK;
}
}
if (node->state == INDEX_COMMIT_WORK) {
/* do not commit transaction here for now */
}
function_exit:
trx->error_state = err;
if (err == DB_SUCCESS) {
} else {
return(NULL);
}
thr->run_node = que_node_get_parent(node);
return(thr);
}
/****************************************************************//** /****************************************************************//**
Creates the foreign key constraints system tables inside InnoDB Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are at database creation or database start if they are not found or are

View file

@ -83,7 +83,7 @@ static char dict_ibfk[] = "_ibfk_";
/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */ /** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
#define DICT_INDEX_STAT_MUTEX_SIZE 32 #define DICT_INDEX_STAT_MUTEX_SIZE 32
mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE]; static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
/*******************************************************************//** /*******************************************************************//**
Tries to find column names for the index and sets the col field of the Tries to find column names for the index and sets the col field of the
@ -571,13 +571,11 @@ dict_table_get_on_id(
if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0 if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
|| trx->dict_operation_lock_mode == RW_X_LATCH) { || trx->dict_operation_lock_mode == RW_X_LATCH) {
/* It is a system table which will always exist in the table
cache: we avoid acquiring the dictionary mutex, because
if we are doing a rollback to handle an error in TABLE
CREATE, for example, we already have the mutex! */
ut_ad(mutex_own(&(dict_sys->mutex)) /* Note: An X latch implies that the transaction
|| trx->dict_operation_lock_mode == RW_X_LATCH); already owns the dictionary mutex. */
ut_ad(mutex_own(&dict_sys->mutex));
return(dict_table_get_on_id_low(table_id)); return(dict_table_get_on_id_low(table_id));
} }
@ -712,7 +710,7 @@ dict_table_get(
/* If table->ibd_file_missing == TRUE, this will /* If table->ibd_file_missing == TRUE, this will
print an error message and return without doing print an error message and return without doing
anything. */ anything. */
dict_update_statistics(table); dict_update_statistics(table, FALSE);
} }
} }
@ -855,7 +853,8 @@ dict_table_add_to_cache(
/* Add table to LRU list of tables */ /* Add table to LRU list of tables */
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
dict_sys->size += mem_heap_get_size(table->heap); dict_sys->size += mem_heap_get_size(table->heap)
+ strlen(table->name) + 1;
} }
/**********************************************************************//** /**********************************************************************//**
@ -909,14 +908,21 @@ dict_table_rename_in_cache(
dict_foreign_t* foreign; dict_foreign_t* foreign;
dict_index_t* index; dict_index_t* index;
ulint fold; ulint fold;
ulint old_size; char old_name[MAX_TABLE_NAME_LEN + 1];
const char* old_name;
ut_ad(table); ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
old_size = mem_heap_get_size(table->heap); /* store the old/current name to an automatic variable */
old_name = table->name; if (strlen(table->name) + 1 <= sizeof(old_name)) {
memcpy(old_name, table->name, strlen(table->name) + 1);
} else {
ut_print_timestamp(stderr);
fprintf(stderr, "InnoDB: too long table name: '%s', "
"max length is %d\n", table->name,
MAX_TABLE_NAME_LEN);
ut_error;
}
fold = ut_fold_string(new_name); fold = ut_fold_string(new_name);
@ -962,12 +968,22 @@ dict_table_rename_in_cache(
/* Remove table from the hash tables of tables */ /* Remove table from the hash tables of tables */
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
ut_fold_string(old_name), table); ut_fold_string(old_name), table);
table->name = mem_heap_strdup(table->heap, new_name);
if (strlen(new_name) > strlen(table->name)) {
/* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
memory fragmentation, we assume a repeated calls of
ut_realloc() with the same size do not cause fragmentation */
ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1);
}
memcpy(table->name, new_name, strlen(new_name) + 1);
/* Add table to hash table of tables */ /* Add table to hash table of tables */
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
table); table);
dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
dict_sys->size += strlen(new_name) - strlen(old_name);
ut_a(dict_sys->size > 0);
/* Update the table_name field in indexes */ /* Update the table_name field in indexes */
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
@ -1192,7 +1208,7 @@ dict_table_remove_from_cache(
/* Remove table from LRU list of tables */ /* Remove table from LRU list of tables */
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
size = mem_heap_get_size(table->heap); size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
ut_ad(dict_sys->size >= size); ut_ad(dict_sys->size >= size);
@ -3076,25 +3092,28 @@ static
char* char*
dict_strip_comments( dict_strip_comments(
/*================*/ /*================*/
const char* sql_string) /*!< in: SQL string */ const char* sql_string, /*!< in: SQL string */
size_t sql_length) /*!< in: length of sql_string */
{ {
char* str; char* str;
const char* sptr; const char* sptr;
const char* eptr = sql_string + sql_length;
char* ptr; char* ptr;
/* unclosed quote character (0 if none) */ /* unclosed quote character (0 if none) */
char quote = 0; char quote = 0;
str = mem_alloc(strlen(sql_string) + 1); str = mem_alloc(sql_length + 1);
sptr = sql_string; sptr = sql_string;
ptr = str; ptr = str;
for (;;) { for (;;) {
scan_more: scan_more:
if (*sptr == '\0') { if (sptr >= eptr || *sptr == '\0') {
end_of_string:
*ptr = '\0'; *ptr = '\0';
ut_a(ptr <= str + strlen(sql_string)); ut_a(ptr <= str + sql_length);
return(str); return(str);
} }
@ -3113,30 +3132,35 @@ scan_more:
|| (sptr[0] == '-' && sptr[1] == '-' || (sptr[0] == '-' && sptr[1] == '-'
&& sptr[2] == ' ')) { && sptr[2] == ' ')) {
for (;;) { for (;;) {
if (++sptr >= eptr) {
goto end_of_string;
}
/* In Unix a newline is 0x0A while in Windows /* In Unix a newline is 0x0A while in Windows
it is 0x0D followed by 0x0A */ it is 0x0D followed by 0x0A */
if (*sptr == (char)0x0A switch (*sptr) {
|| *sptr == (char)0x0D case (char) 0X0A:
|| *sptr == '\0') { case (char) 0x0D:
case '\0':
goto scan_more; goto scan_more;
} }
sptr++;
} }
} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') { } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
sptr += 2;
for (;;) { for (;;) {
if (*sptr == '*' && *(sptr + 1) == '/') { if (sptr >= eptr) {
goto end_of_string;
sptr += 2;
goto scan_more;
} }
if (*sptr == '\0') { switch (*sptr) {
case '\0':
goto scan_more; goto scan_more;
case '*':
if (sptr[1] == '/') {
sptr += 2;
goto scan_more;
}
} }
sptr++; sptr++;
@ -3817,6 +3841,7 @@ dict_create_foreign_constraints(
name before it: test.table2; the name before it: test.table2; the
default database id the database of default database id the database of
parameter name */ parameter name */
size_t sql_length, /*!< in: length of sql_string */
const char* name, /*!< in: table full name in the const char* name, /*!< in: table full name in the
normalized form normalized form
database_name/table_name */ database_name/table_name */
@ -3831,7 +3856,7 @@ dict_create_foreign_constraints(
ut_a(trx); ut_a(trx);
ut_a(trx->mysql_thd); ut_a(trx->mysql_thd);
str = dict_strip_comments(sql_string); str = dict_strip_comments(sql_string, sql_length);
heap = mem_heap_create(10000); heap = mem_heap_create(10000);
err = dict_create_foreign_constraints_low( err = dict_create_foreign_constraints_low(
@ -3864,6 +3889,7 @@ dict_foreign_parse_drop_constraints(
dict_foreign_t* foreign; dict_foreign_t* foreign;
ibool success; ibool success;
char* str; char* str;
size_t len;
const char* ptr; const char* ptr;
const char* id; const char* id;
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
@ -3878,7 +3904,10 @@ dict_foreign_parse_drop_constraints(
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*)); *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
str = dict_strip_comments(*(trx->mysql_query_str)); ptr = innobase_get_stmt(trx->mysql_thd, &len);
str = dict_strip_comments(ptr, len);
ptr = str; ptr = str;
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
@ -4218,6 +4247,259 @@ dict_index_calc_min_rec_len(
return(sum); return(sum);
} }
/*********************************************************************//**
functions to use SYS_STATS system table. */
static
ibool
dict_reload_statistics(
/*===================*/
dict_table_t* table,
ulint* sum_of_index_sizes)
{
dict_index_t* index;
ulint size;
mem_heap_t* heap;
index = dict_table_get_first_index(table);
if (index == NULL) {
/* Table definition is corrupt */
return(FALSE);
}
heap = mem_heap_create(1000);
while (index) {
if (table->is_corrupt) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return(FALSE);
}
size = btr_get_size(index, BTR_TOTAL_SIZE);
index->stat_index_size = size;
*sum_of_index_sizes += size;
size = btr_get_size(index, BTR_N_LEAF_PAGES);
if (size == 0) {
/* The root node of the tree is a leaf */
size = 1;
}
index->stat_n_leaf_pages = size;
/*===========================================*/
{
dict_table_t* sys_stats;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
ulint key_cols;
ulint n_cols;
const rec_t* rec;
const byte* field;
ulint len;
ib_int64_t* stat_n_diff_key_vals_tmp;
byte* buf;
ulint i;
mtr_t mtr;
n_cols = dict_index_get_n_unique(index);
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
sys_stats = dict_sys->sys_stats;
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
ut_a(!dict_table_is_comp(sys_stats));
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
mtr_start(&mtr);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i <= n_cols; i++) {
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur)
|| ut_dulint_cmp(mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)),
index->id)) {
/* not found: even 1 if not found should not be alowed */
fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
" not fonund in SYS_STATS\n",
index->table_name, index->name, i, n_cols);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
mem_heap_free(heap);
return(FALSE);
}
if (rec_get_deleted_flag(rec, 0)) {
goto next_rec;
}
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
key_cols = mach_read_from_4(field);
ut_a(i == key_cols);
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
ut_a(len == 8);
stat_n_diff_key_vals_tmp[i] = ut_conv_dulint_to_longlong(mach_read_from_8(field));
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
dict_index_stat_mutex_enter(index);
for (i = 0; i <= n_cols; i++) {
index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
}
dict_index_stat_mutex_exit(index);
}
/*===========================================*/
index = dict_table_get_next_index(index);
}
mem_heap_free(heap);
return(TRUE);
}
static
void
dict_store_statistics(
/*==================*/
dict_table_t* table)
{
dict_index_t* index;
mem_heap_t* heap;
index = dict_table_get_first_index(table);
ut_a(index);
heap = mem_heap_create(1000);
while (index) {
if (table->is_corrupt) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return;
}
/*===========================================*/
{
dict_table_t* sys_stats;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
ulint key_cols;
ulint n_cols;
ulint rests;
const rec_t* rec;
const byte* field;
ulint len;
ib_int64_t* stat_n_diff_key_vals_tmp;
byte* buf;
ulint i;
mtr_t mtr;
n_cols = dict_index_get_n_unique(index);
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
dict_index_stat_mutex_enter(index);
for (i = 0; i <= n_cols; i++) {
stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
}
dict_index_stat_mutex_exit(index);
sys_stats = dict_sys->sys_stats;
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
ut_a(!dict_table_is_comp(sys_stats));
tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
buf = mem_heap_alloc(heap, 8);
mach_write_to_8(buf, index->id);
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);
mtr_start(&mtr);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF, &pcur, &mtr);
rests = n_cols + 1;
for (i = 0; i <= n_cols; i++) {
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur)
|| ut_dulint_cmp(mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)),
index->id)) {
/* not found */
btr_pcur_close(&pcur);
mtr_commit(&mtr);
break;
}
if (rec_get_deleted_flag(rec, 0)) {
goto next_rec;
}
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
key_cols = mach_read_from_4(field);
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
ut_a(len == 8);
mlog_write_dulint((byte*)field,
ut_dulint_create((ulint) (stat_n_diff_key_vals_tmp[key_cols] >> 32),
(ulint) stat_n_diff_key_vals_tmp[key_cols] & 0xFFFFFFFF),
&mtr);
rests--;
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
if (rests) {
fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries"
" of %s/%s to SYS_STATS system table.\n",
rests, index->table_name, index->name);
}
}
/*===========================================*/
index = dict_table_get_next_index(index);
}
mem_heap_free(heap);
}
/*********************************************************************//** /*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
@ -4226,9 +4508,10 @@ void
dict_update_statistics_low( dict_update_statistics_low(
/*=======================*/ /*=======================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool has_dict_mutex __attribute__((unused))) ibool has_dict_mutex __attribute__((unused)),
/*!< in: TRUE if the caller has the /*!< in: TRUE if the caller has the
dictionary mutex */ dictionary mutex */
ibool sync) /*!< in: TRUE if must update SYS_STATS */
{ {
dict_index_t* index; dict_index_t* index;
ulint size; ulint size;
@ -4254,6 +4537,23 @@ dict_update_statistics_low(
return; return;
} }
if (srv_use_sys_stats_table && !sync) {
/* reload statistics from SYS_STATS table */
if (dict_reload_statistics(table, &sum_of_index_sizes)) {
/* success */
#ifdef UNIV_DEBUG
fprintf(stderr, "InnoDB: DEBUG: reload_statistics is scceeded for %s.\n",
table->name);
#endif
goto end;
}
}
#ifdef UNIV_DEBUG
fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
table->name);
#endif
sum_of_index_sizes = 0;
/* Find out the sizes of the indexes and how many different values /* Find out the sizes of the indexes and how many different values
for the key they approximately have */ for the key they approximately have */
@ -4291,6 +4591,11 @@ dict_update_statistics_low(
index = dict_table_get_next_index(index); index = dict_table_get_next_index(index);
} }
if (srv_use_sys_stats_table) {
/* store statistics to SYS_STATS table */
dict_store_statistics(table);
}
end:
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
dict_index_stat_mutex_enter(index); dict_index_stat_mutex_enter(index);
@ -4317,9 +4622,10 @@ UNIV_INTERN
void void
dict_update_statistics( dict_update_statistics(
/*===================*/ /*===================*/
dict_table_t* table) /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool sync)
{ {
dict_update_statistics_low(table, FALSE); dict_update_statistics_low(table, FALSE, sync);
} }
/**********************************************************************//** /**********************************************************************//**
@ -4400,7 +4706,7 @@ dict_table_print_low(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
if (srv_stats_auto_update) if (srv_stats_auto_update)
dict_update_statistics_low(table, TRUE); dict_update_statistics_low(table, TRUE, FALSE);
fprintf(stderr, fprintf(stderr,
"--------------------------------------\n" "--------------------------------------\n"

View file

@ -222,7 +222,7 @@ loop:
is no index */ is no index */
if (srv_stats_auto_update && dict_table_get_first_index(table)) { if (srv_stats_auto_update && dict_table_get_first_index(table)) {
dict_update_statistics_low(table, TRUE); dict_update_statistics_low(table, TRUE, FALSE);
} }
dict_table_print_low(table); dict_table_print_low(table);
@ -316,7 +316,7 @@ dict_check_tablespaces_and_store_max_id(
dict_index_t* sys_index; dict_index_t* sys_index;
btr_pcur_t pcur; btr_pcur_t pcur;
const rec_t* rec; const rec_t* rec;
ulint max_space_id = 0; ulint max_space_id;
mtr_t mtr; mtr_t mtr;
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
@ -327,6 +327,11 @@ dict_check_tablespaces_and_store_max_id(
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
ut_a(!dict_table_is_comp(sys_tables)); ut_a(!dict_table_is_comp(sys_tables));
max_space_id = mtr_read_ulint(dict_hdr_get(&mtr)
+ DICT_HDR_MAX_SPACE_ID,
MLOG_4BYTES, &mtr);
fil_set_max_space_id_if_bigger(max_space_id);
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
TRUE, &mtr); TRUE, &mtr);
loop: loop:
@ -973,6 +978,7 @@ err_exit:
/* Try to open the tablespace */ /* Try to open the tablespace */
if (!fil_open_single_table_tablespace( if (!fil_open_single_table_tablespace(
TRUE, space, TRUE, space,
flags == DICT_TF_COMPACT ? 0 :
flags & ~(~0 << DICT_TF_BITS), name)) { flags & ~(~0 << DICT_TF_BITS), name)) {
/* We failed to find a sensible /* We failed to find a sensible
tablespace file */ tablespace file */

View file

@ -68,7 +68,8 @@ dict_mem_table_create(
table->heap = heap; table->heap = heap;
table->flags = (unsigned int) flags; table->flags = (unsigned int) flags;
table->name = mem_heap_strdup(heap, name); table->name = ut_malloc(strlen(name) + 1);
memcpy(table->name, name, strlen(name) + 1);
table->space = (unsigned int) space; table->space = (unsigned int) space;
table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS); table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS);
@ -108,6 +109,7 @@ dict_mem_table_free(
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex)); mutex_free(&(table->autoinc_mutex));
#endif /* UNIV_HOTBACKUP */ #endif /* UNIV_HOTBACKUP */
ut_free(table->name);
mem_heap_free(table->heap); mem_heap_free(table->heap);
} }

View file

@ -44,6 +44,8 @@ Created 10/25/1995 Heikki Tuuri
#include "trx0sys.h" #include "trx0sys.h"
#include "pars0pars.h" #include "pars0pars.h"
#include "row0mysql.h" #include "row0mysql.h"
#include "row0row.h"
#include "que0que.h"
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
# include "buf0lru.h" # include "buf0lru.h"
# include "ibuf0ibuf.h" # include "ibuf0ibuf.h"
@ -284,6 +286,10 @@ struct fil_system_struct {
request */ request */
UT_LIST_BASE_NODE_T(fil_space_t) space_list; UT_LIST_BASE_NODE_T(fil_space_t) space_list;
/*!< list of all file spaces */ /*!< list of all file spaces */
ibool space_id_reuse_warned;
/* !< TRUE if fil_space_create()
has issued a warning about
potential space_id reuse */
}; };
/** The tablespace memory cache. This variable is NULL before the module is /** The tablespace memory cache. This variable is NULL before the module is
@ -1198,7 +1204,19 @@ try_again:
space->tablespace_version = fil_system->tablespace_version; space->tablespace_version = fil_system->tablespace_version;
space->mark = FALSE; space->mark = FALSE;
if (purpose == FIL_TABLESPACE && id > fil_system->max_assigned_id) { if (UNIV_LIKELY(purpose == FIL_TABLESPACE && !recv_recovery_on)
&& UNIV_UNLIKELY(id > fil_system->max_assigned_id)) {
if (!fil_system->space_id_reuse_warned) {
fil_system->space_id_reuse_warned = TRUE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: allocated tablespace %lu,"
" old maximum was %lu\n",
(ulong) id,
(ulong) fil_system->max_assigned_id);
}
fil_system->max_assigned_id = id; fil_system->max_assigned_id = id;
} }
@ -1238,19 +1256,25 @@ try_again:
Assigns a new space id for a new single-table tablespace. This works simply by Assigns a new space id for a new single-table tablespace. This works simply by
incrementing the global counter. If 4 billion id's is not enough, we may need incrementing the global counter. If 4 billion id's is not enough, we may need
to recycle id's. to recycle id's.
@return new tablespace id; ULINT_UNDEFINED if could not assign an id */ @return TRUE if assigned, FALSE if not */
static UNIV_INTERN
ulint ibool
fil_assign_new_space_id(void) fil_assign_new_space_id(
/*=========================*/ /*====================*/
ulint* space_id) /*!< in/out: space id */
{ {
ulint id; ulint id;
ibool success;
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
fil_system->max_assigned_id++; id = *space_id;
id = fil_system->max_assigned_id; if (id < fil_system->max_assigned_id) {
id = fil_system->max_assigned_id;
}
id++;
if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) { if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
@ -1266,7 +1290,11 @@ fil_assign_new_space_id(void)
(ulong) SRV_LOG_SPACE_FIRST_ID); (ulong) SRV_LOG_SPACE_FIRST_ID);
} }
if (id >= SRV_LOG_SPACE_FIRST_ID) { success = (id < SRV_LOG_SPACE_FIRST_ID);
if (success) {
*space_id = fil_system->max_assigned_id = id;
} else {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: You have run out of single-table" "InnoDB: You have run out of single-table"
@ -1276,14 +1304,12 @@ fil_assign_new_space_id(void)
" have to dump all your tables and\n" " have to dump all your tables and\n"
"InnoDB: recreate the whole InnoDB installation.\n", "InnoDB: recreate the whole InnoDB installation.\n",
(ulong) id); (ulong) id);
fil_system->max_assigned_id--; *space_id = ULINT_UNDEFINED;
id = ULINT_UNDEFINED;
} }
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
return(id); return(success);
} }
/*******************************************************************//** /*******************************************************************//**
@ -1519,7 +1545,7 @@ fil_init(
ut_a(hash_size > 0); ut_a(hash_size > 0);
ut_a(max_n_open > 0); ut_a(max_n_open > 0);
fil_system = mem_alloc(sizeof(fil_system_t)); fil_system = mem_zalloc(sizeof(fil_system_t));
mutex_create(&fil_system->mutex, SYNC_ANY_LATCH); mutex_create(&fil_system->mutex, SYNC_ANY_LATCH);
@ -1528,16 +1554,9 @@ fil_init(
UT_LIST_INIT(fil_system->LRU); UT_LIST_INIT(fil_system->LRU);
fil_system->n_open = 0;
fil_system->max_n_open = max_n_open; fil_system->max_n_open = max_n_open;
fil_system->modification_counter = 0;
fil_system->max_assigned_id = TRX_SYS_SPACE_MAX; fil_system->max_assigned_id = TRX_SYS_SPACE_MAX;
fil_system->tablespace_version = 0;
UT_LIST_INIT(fil_system->unflushed_spaces);
UT_LIST_INIT(fil_system->space_list);
} }
/*******************************************************************//** /*******************************************************************//**
@ -2122,7 +2141,7 @@ fil_op_log_parse_or_replay(
fil_create_directory_for_tablename(name); fil_create_directory_for_tablename(name);
if (fil_create_new_single_table_tablespace( if (fil_create_new_single_table_tablespace(
&space_id, name, FALSE, flags, space_id, name, FALSE, flags,
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
ut_error; ut_error;
} }
@ -2569,9 +2588,7 @@ UNIV_INTERN
ulint ulint
fil_create_new_single_table_tablespace( fil_create_new_single_table_tablespace(
/*===================================*/ /*===================================*/
ulint* space_id, /*!< in/out: space id; if this is != 0, ulint space_id, /*!< in: space id */
then this is an input parameter,
otherwise output */
const char* tablename, /*!< in: the table name in the usual const char* tablename, /*!< in: the table name in the usual
databasename/tablename format databasename/tablename format
of InnoDB, or a dir path to a temp of InnoDB, or a dir path to a temp
@ -2591,6 +2608,8 @@ fil_create_new_single_table_tablespace(
ibool success; ibool success;
char* path; char* path;
ut_a(space_id > 0);
ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
ROW_FORMAT=COMPACT ROW_FORMAT=COMPACT
@ -2647,38 +2666,21 @@ fil_create_new_single_table_tablespace(
return(DB_ERROR); return(DB_ERROR);
} }
buf2 = ut_malloc(3 * UNIV_PAGE_SIZE);
/* Align the memory for file i/o if we might have O_DIRECT set */
page = ut_align(buf2, UNIV_PAGE_SIZE);
ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0); ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0);
if (!ret) { if (!ret) {
ut_free(buf2); err = DB_OUT_OF_FILE_SPACE;
os_file_close(file);
os_file_delete(path);
mem_free(path);
return(DB_OUT_OF_FILE_SPACE);
}
if (*space_id == 0) {
*space_id = fil_assign_new_space_id();
}
/* printf("Creating tablespace %s id %lu\n", path, *space_id); */
if (*space_id == ULINT_UNDEFINED) {
ut_free(buf2);
error_exit: error_exit:
os_file_close(file); os_file_close(file);
error_exit2: error_exit2:
os_file_delete(path); os_file_delete(path);
mem_free(path); mem_free(path);
return(DB_ERROR); return(err);
} }
/* printf("Creating tablespace %s id %lu\n", path, space_id); */
/* We have to write the space id to the file immediately and flush the /* We have to write the space id to the file immediately and flush the
file to disk. This is because in crash recovery we must be aware what file to disk. This is because in crash recovery we must be aware what
tablespaces exist and what are their space id's, so that we can apply tablespaces exist and what are their space id's, so that we can apply
@ -2688,10 +2690,14 @@ error_exit2:
with zeros from the call of os_file_set_size(), until a buffer pool with zeros from the call of os_file_set_size(), until a buffer pool
flush would write to it. */ flush would write to it. */
buf2 = ut_malloc(3 * UNIV_PAGE_SIZE);
/* Align the memory for file i/o if we might have O_DIRECT set */
page = ut_align(buf2, UNIV_PAGE_SIZE);
memset(page, '\0', UNIV_PAGE_SIZE); memset(page, '\0', UNIV_PAGE_SIZE);
fsp_header_init_fields(page, *space_id, flags); fsp_header_init_fields(page, space_id, flags);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, *space_id); mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
if (!(flags & DICT_TF_ZSSIZE_MASK)) { if (!(flags & DICT_TF_ZSSIZE_MASK)) {
buf_flush_init_for_writing(page, NULL, 0); buf_flush_init_for_writing(page, NULL, 0);
@ -2722,6 +2728,7 @@ error_exit2:
" to tablespace ", stderr); " to tablespace ", stderr);
ut_print_filename(stderr, path); ut_print_filename(stderr, path);
putc('\n', stderr); putc('\n', stderr);
err = DB_ERROR;
goto error_exit; goto error_exit;
} }
@ -2731,22 +2738,20 @@ error_exit2:
fputs("InnoDB: Error: file flush of tablespace ", stderr); fputs("InnoDB: Error: file flush of tablespace ", stderr);
ut_print_filename(stderr, path); ut_print_filename(stderr, path);
fputs(" failed\n", stderr); fputs(" failed\n", stderr);
err = DB_ERROR;
goto error_exit; goto error_exit;
} }
os_file_close(file); os_file_close(file);
if (*space_id == ULINT_UNDEFINED) { success = fil_space_create(path, space_id, flags, FIL_TABLESPACE);
goto error_exit2;
}
success = fil_space_create(path, *space_id, flags, FIL_TABLESPACE);
if (!success) { if (!success) {
err = DB_ERROR;
goto error_exit2; goto error_exit2;
} }
fil_node_create(path, size, *space_id, FALSE); fil_node_create(path, size, space_id, FALSE);
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
{ {
@ -2757,7 +2762,7 @@ error_exit2:
fil_op_write_log(flags fil_op_write_log(flags
? MLOG_FILE_CREATE2 ? MLOG_FILE_CREATE2
: MLOG_FILE_CREATE, : MLOG_FILE_CREATE,
*space_id, space_id,
is_temp ? MLOG_FILE_FLAG_TEMP : 0, is_temp ? MLOG_FILE_FLAG_TEMP : 0,
flags, flags,
tablename, NULL, &mtr); tablename, NULL, &mtr);
@ -3122,7 +3127,7 @@ fil_open_single_table_tablespace(
for (i = 0; i < n_index; i++) { for (i = 0; i < n_index; i++) {
new_id[i] = new_id[i] =
dict_table_get_index_on_name(table, dict_table_get_index_on_name(table,
(page + (i + 1) * 512 + 12))->id; (char*)(page + (i + 1) * 512 + 12))->id;
old_id[i] = mach_read_from_8(page + (i + 1) * 512); old_id[i] = mach_read_from_8(page + (i + 1) * 512);
root_page[i] = mach_read_from_4(page + (i + 1) * 512 + 8); root_page[i] = mach_read_from_4(page + (i + 1) * 512 + 8);
} }
@ -3146,7 +3151,7 @@ skip_info:
/* over write space id of all pages */ /* over write space id of all pages */
rec_offs_init(offsets_); rec_offs_init(offsets_);
fprintf(stderr, "InnoDB: Progress in %:"); fprintf(stderr, "InnoDB: Progress in %%:");
for (offset = 0; offset < size_bytes; offset += UNIV_PAGE_SIZE) { for (offset = 0; offset < size_bytes; offset += UNIV_PAGE_SIZE) {
ulint checksum_field; ulint checksum_field;
@ -3888,39 +3893,6 @@ next_datadir_item:
return(err); return(err);
} }
/********************************************************************//**
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. */
UNIV_INTERN
void
fil_print_orphaned_tablespaces(void)
/*================================*/
{
fil_space_t* space;
mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space) {
if (space->purpose == FIL_TABLESPACE && !trx_sys_sys_space(space->id)
&& !space->mark) {
fputs("InnoDB: Warning: tablespace ", stderr);
ut_print_filename(stderr, space->name);
fprintf(stderr, " of id %lu has no matching table in\n"
"InnoDB: the InnoDB data dictionary.\n",
(ulong) space->id);
}
space = UT_LIST_GET_NEXT(space_list, space);
}
mutex_exit(&fil_system->mutex);
}
/*******************************************************************//** /*******************************************************************//**
Returns TRUE if a single-table tablespace does not exist in the memory cache, Returns TRUE if a single-table tablespace does not exist in the memory cache,
or is being deleted there. or is being deleted there.

View file

@ -658,7 +658,7 @@ xdes_calc_descriptor_page(
ulint offset) /*!< in: page offset */ ulint offset) /*!< in: page offset */
{ {
#ifndef DOXYGEN /* Doxygen gets confused of these */ #ifndef DOXYGEN /* Doxygen gets confused of these */
//# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \ //# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET
// + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE // + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
//# error //# error
//# endif //# endif
@ -882,12 +882,10 @@ fsp_init_file_page_low(
return; return;
} }
UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE); memset(page, 0, UNIV_PAGE_SIZE);
mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block)); mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
memset(page + FIL_PAGE_LSN, 0, 8);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
buf_block_get_space(block)); buf_block_get_space(block));
memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8);
} }
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP

View file

@ -127,6 +127,70 @@ hash_create(
return(table); return(table);
} }
/*************************************************************//**
*/
UNIV_INTERN
ulint
hash_create_needed(
/*===============*/
ulint n)
{
ulint prime;
ulint offset;
prime = ut_find_prime(n);
offset = (sizeof(hash_table_t) + 7) / 8;
offset *= 8;
return(offset + sizeof(hash_cell_t) * prime);
}
UNIV_INTERN
void
hash_create_init(
/*=============*/
hash_table_t* table,
ulint n)
{
ulint prime;
ulint offset;
prime = ut_find_prime(n);
offset = (sizeof(hash_table_t) + 7) / 8;
offset *= 8;
table->array = (hash_cell_t*)(((void*)table) + offset);
table->n_cells = prime;
# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
table->adaptive = FALSE;
# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
table->n_mutexes = 0;
table->mutexes = NULL;
table->heaps = NULL;
table->heap = NULL;
ut_d(table->magic_n = HASH_TABLE_MAGIC_N);
/* Initialize the cell array */
hash_table_clear(table);
}
UNIV_INTERN
void
hash_create_reuse(
/*==============*/
hash_table_t* table)
{
ulint offset;
offset = (sizeof(hash_table_t) + 7) / 8;
offset *= 8;
table->array = (hash_cell_t*)(((void*)table) + offset);
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
}
/*************************************************************//** /*************************************************************//**
Frees a hash table. */ Frees a hash table. */
UNIV_INTERN UNIV_INTERN

View file

@ -196,6 +196,7 @@ static my_bool innobase_overwrite_relay_log_info = FALSE;
static my_bool innobase_rollback_on_timeout = FALSE; static my_bool innobase_rollback_on_timeout = FALSE;
static my_bool innobase_create_status_file = FALSE; static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE; static my_bool innobase_stats_on_metadata = TRUE;
static my_bool innobase_use_sys_stats_table = FALSE;
static char* internal_innobase_data_file_path = NULL; static char* internal_innobase_data_file_path = NULL;
@ -340,6 +341,12 @@ static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.", "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0); NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
static MYSQL_THDVAR_ULONG(flush_log_at_trx_commit_session, PLUGIN_VAR_RQCMDARG,
"Control innodb_flush_log_at_trx_commit for each sessions. "
"The value 0~2 are same meanings to innodb_flush_log_at_trx_commit. "
"The value 3 regards innodb_flush_log_at_trx_commit (default).",
NULL, NULL, 3, 0, 3, 0);
static handler *innobase_create_handler(handlerton *hton, static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table, TABLE_SHARE *table,
@ -720,6 +727,17 @@ thd_lock_wait_timeout(
return(THDVAR((THD*) thd, lock_wait_timeout)); return(THDVAR((THD*) thd, lock_wait_timeout));
} }
/******************************************************************//**
*/
extern "C" UNIV_INTERN
ulong
thd_flush_log_at_trx_commit_session(
/*================================*/
void* thd)
{
return(THDVAR((THD*) thd, flush_log_at_trx_commit_session));
}
/********************************************************************//** /********************************************************************//**
Obtain the InnoDB transaction of a MySQL thread. Obtain the InnoDB transaction of a MySQL thread.
@return reference to transaction pointer */ @return reference to transaction pointer */
@ -1035,6 +1053,29 @@ innobase_get_charset(
return(thd_charset((THD*) mysql_thd)); return(thd_charset((THD*) mysql_thd));
} }
/**********************************************************************//**
Determines the current SQL statement.
@return SQL statement string */
extern "C" UNIV_INTERN
const char*
innobase_get_stmt(
/*==============*/
void* mysql_thd, /*!< in: MySQL thread handle */
size_t* length) /*!< out: length of the SQL statement */
{
#if MYSQL_VERSION_ID >= 50142
LEX_STRING* stmt;
stmt = thd_query_string((THD*) mysql_thd);
*length = stmt->length;
return(stmt->str);
#else
const char* stmt_str = thd_query((THD*) mysql_thd);
*length = strlen(stmt_str);
return(stmt_str);
#endif
}
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) #if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
/*******************************************************************//** /*******************************************************************//**
@ -1355,7 +1396,6 @@ innobase_trx_allocate(
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
trx->mysql_thd = thd; trx->mysql_thd = thd;
trx->mysql_query_str = thd_query(thd);
innobase_trx_init(thd, trx); innobase_trx_init(thd, trx);
@ -2039,12 +2079,12 @@ innobase_init(
srv_page_size_shift = 0; srv_page_size_shift = 0;
if (innobase_page_size != (1 << 14)) { if (innobase_page_size != (1 << 14)) {
int n_shift; uint n_shift;
fprintf(stderr, fprintf(stderr,
"InnoDB: Warning: innodb_page_size has been changed from default value 16384. (###EXPERIMENTAL### operation)\n"); "InnoDB: Warning: innodb_page_size has been changed from default value 16384. (###EXPERIMENTAL### operation)\n");
for (n_shift = 12; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) { for (n_shift = 12; n_shift <= UNIV_PAGE_SIZE_SHIFT_MAX; n_shift++) {
if (innobase_page_size == (1 << n_shift)) { if (innobase_page_size == ((ulong)1 << n_shift)) {
srv_page_size_shift = n_shift; srv_page_size_shift = n_shift;
srv_page_size = (1 << srv_page_size_shift); srv_page_size = (1 << srv_page_size_shift);
fprintf(stderr, fprintf(stderr,
@ -2235,6 +2275,8 @@ mem_free_and_error:
srv_extra_undoslots = (ibool) innobase_extra_undoslots; srv_extra_undoslots = (ibool) innobase_extra_undoslots;
srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
/* -------------- Log files ---------------------------*/ /* -------------- Log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */ /* The default dir for log files is the datadir of MySQL */
@ -4230,6 +4272,11 @@ get_innobase_type_from_mysql_type(
case MYSQL_TYPE_BLOB: case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_LONG_BLOB:
return(DATA_BLOB); return(DATA_BLOB);
case MYSQL_TYPE_NULL:
/* MySQL currently accepts "NULL" datatype, but will
reject such datatype in the next release. We will cope
with it and not trigger assertion failure in 5.1 */
break;
default: default:
ut_error; ut_error;
} }
@ -5699,6 +5746,9 @@ ha_innobase::index_read(
prebuilt->index_usable = FALSE; prebuilt->index_usable = FALSE;
DBUG_RETURN(HA_ERR_CRASHED); DBUG_RETURN(HA_ERR_CRASHED);
} }
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED);
}
/* Note that if the index for which the search template is built is not /* Note that if the index for which the search template is built is not
necessarily prebuilt->index, but can also be the clustered index */ necessarily prebuilt->index, but can also be the clustered index */
@ -6338,7 +6388,22 @@ create_table_def(
field = form->field[i]; field = form->field[i];
col_type = get_innobase_type_from_mysql_type(&unsigned_type, col_type = get_innobase_type_from_mysql_type(&unsigned_type,
field); field);
if (!col_type) {
push_warning_printf(
(THD*) trx->mysql_thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CANT_CREATE_TABLE,
"Error creating table '%s' with "
"column '%s'. Please check its "
"column type and try to re-create "
"the table with an appropriate "
"column type.",
table->name, (char*) field->field_name);
goto err_col;
}
if (field->null_ptr) { if (field->null_ptr) {
nulls_allowed = 0; nulls_allowed = 0;
} else { } else {
@ -6396,7 +6461,7 @@ create_table_def(
if (dict_col_name_is_reserved(field->field_name)){ if (dict_col_name_is_reserved(field->field_name)){
my_error(ER_WRONG_COLUMN_NAME, MYF(0), my_error(ER_WRONG_COLUMN_NAME, MYF(0),
field->field_name); field->field_name);
err_col:
dict_mem_table_free(table); dict_mem_table_free(table);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
@ -6796,6 +6861,9 @@ ha_innobase::create(
/* Cache the value of innodb_file_format, in case it is /* Cache the value of innodb_file_format, in case it is
modified by another thread while the table is being created. */ modified by another thread while the table is being created. */
const ulint file_format = srv_file_format; const ulint file_format = srv_file_format;
const char* stmt;
size_t stmt_len;
enum row_type row_type;
DBUG_ENTER("ha_innobase::create"); DBUG_ENTER("ha_innobase::create");
@ -6916,94 +6984,94 @@ ha_innobase::create(
} }
} }
if (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT) { row_type = form->s->row_type;
if (flags) {
/* KEY_BLOCK_SIZE was specified. */ if (flags) {
if (form->s->row_type != ROW_TYPE_COMPRESSED) { /* KEY_BLOCK_SIZE was specified. */
/* ROW_FORMAT other than COMPRESSED if (!(create_info->used_fields & HA_CREATE_USED_ROW_FORMAT)) {
ignores KEY_BLOCK_SIZE. It does not /* ROW_FORMAT was not specified;
make sense to reject conflicting default to ROW_FORMAT=COMPRESSED */
KEY_BLOCK_SIZE and ROW_FORMAT, because row_type = ROW_TYPE_COMPRESSED;
such combinations can be obtained } else if (row_type != ROW_TYPE_COMPRESSED) {
with ALTER TABLE anyway. */ /* ROW_FORMAT other than COMPRESSED
push_warning_printf( ignores KEY_BLOCK_SIZE. It does not
thd, make sense to reject conflicting
MYSQL_ERROR::WARN_LEVEL_WARN, KEY_BLOCK_SIZE and ROW_FORMAT, because
ER_ILLEGAL_HA_CREATE_OPTION, such combinations can be obtained
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu" with ALTER TABLE anyway. */
" unless ROW_FORMAT=COMPRESSED.", push_warning_printf(
create_info->key_block_size); thd,
flags = 0; MYSQL_ERROR::WARN_LEVEL_WARN,
} ER_ILLEGAL_HA_CREATE_OPTION,
} else { "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
/* No KEY_BLOCK_SIZE */ " unless ROW_FORMAT=COMPRESSED.",
if (form->s->row_type == ROW_TYPE_COMPRESSED) { create_info->key_block_size);
/* ROW_FORMAT=COMPRESSED without flags = 0;
KEY_BLOCK_SIZE implies half the }
maximum KEY_BLOCK_SIZE. */ } else {
flags = (DICT_TF_ZSSIZE_MAX - 1) /* No KEY_BLOCK_SIZE */
<< DICT_TF_ZSSIZE_SHIFT if (row_type == ROW_TYPE_COMPRESSED) {
| DICT_TF_COMPACT /* ROW_FORMAT=COMPRESSED without
| DICT_TF_FORMAT_ZIP KEY_BLOCK_SIZE implies half the
<< DICT_TF_FORMAT_SHIFT; maximum KEY_BLOCK_SIZE. */
flags = (DICT_TF_ZSSIZE_MAX - 1)
<< DICT_TF_ZSSIZE_SHIFT
| DICT_TF_COMPACT
| DICT_TF_FORMAT_ZIP
<< DICT_TF_FORMAT_SHIFT;
//#if DICT_TF_ZSSIZE_MAX < 1 //#if DICT_TF_ZSSIZE_MAX < 1
//# error "DICT_TF_ZSSIZE_MAX < 1" //# error "DICT_TF_ZSSIZE_MAX < 1"
//#endif //#endif
}
} }
}
switch (form->s->row_type) { switch (row_type) {
const char* row_format_name; const char* row_format_name;
case ROW_TYPE_REDUNDANT: case ROW_TYPE_REDUNDANT:
break; break;
case ROW_TYPE_COMPRESSED: case ROW_TYPE_COMPRESSED:
case ROW_TYPE_DYNAMIC: case ROW_TYPE_DYNAMIC:
row_format_name row_format_name
= form->s->row_type == ROW_TYPE_COMPRESSED = row_type == ROW_TYPE_COMPRESSED
? "COMPRESSED" ? "COMPRESSED"
: "DYNAMIC"; : "DYNAMIC";
if (!srv_file_per_table) { if (!srv_file_per_table) {
push_warning_printf( push_warning_printf(
thd, thd,
MYSQL_ERROR::WARN_LEVEL_WARN, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION, ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s" "InnoDB: ROW_FORMAT=%s"
" requires innodb_file_per_table.", " requires innodb_file_per_table.",
row_format_name); row_format_name);
} else if (file_format < DICT_TF_FORMAT_ZIP) { } else if (file_format < DICT_TF_FORMAT_ZIP) {
push_warning_printf( push_warning_printf(
thd, thd,
MYSQL_ERROR::WARN_LEVEL_WARN, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION, ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s" "InnoDB: ROW_FORMAT=%s"
" requires innodb_file_format >" " requires innodb_file_format >"
" Antelope.", " Antelope.",
row_format_name); row_format_name);
} else { } else {
flags |= DICT_TF_COMPACT flags |= DICT_TF_COMPACT
| (DICT_TF_FORMAT_ZIP | (DICT_TF_FORMAT_ZIP
<< DICT_TF_FORMAT_SHIFT); << DICT_TF_FORMAT_SHIFT);
break;
}
/* fall through */
case ROW_TYPE_NOT_USED:
case ROW_TYPE_FIXED:
default:
push_warning(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: assuming ROW_FORMAT=COMPACT.");
case ROW_TYPE_DEFAULT:
case ROW_TYPE_COMPACT:
flags = DICT_TF_COMPACT;
break; break;
} }
} else if (!flags) {
/* No KEY_BLOCK_SIZE or ROW_FORMAT specified: /* fall through */
use ROW_FORMAT=COMPACT by default. */ case ROW_TYPE_NOT_USED:
case ROW_TYPE_FIXED:
default:
push_warning(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: assuming ROW_FORMAT=COMPACT.");
case ROW_TYPE_DEFAULT:
case ROW_TYPE_COMPACT:
flags = DICT_TF_COMPACT; flags = DICT_TF_COMPACT;
break;
} }
/* Look for a primary key */ /* Look for a primary key */
@ -7012,7 +7080,7 @@ ha_innobase::create(
(int) form->s->primary_key : (int) form->s->primary_key :
-1); -1);
/* Our function row_get_mysql_key_number_for_index assumes /* Our function innobase_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */ the primary key is always number 0, if it exists */
ut_a(primary_key_no == -1 || primary_key_no == 0); ut_a(primary_key_no == -1 || primary_key_no == 0);
@ -7072,9 +7140,11 @@ ha_innobase::create(
} }
} }
if (*trx->mysql_query_str) { stmt = innobase_get_stmt(thd, &stmt_len);
error = row_table_add_foreign_constraints(trx,
*trx->mysql_query_str, norm_name, if (stmt) {
error = row_table_add_foreign_constraints(
trx, stmt, stmt_len, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE); create_info->options & HA_LEX_CREATE_TMP_TABLE);
error = convert_error_code_to_mysql(error, flags, NULL); error = convert_error_code_to_mysql(error, flags, NULL);
@ -7367,7 +7437,6 @@ innobase_drop_database(
/* In the Windows plugin, thd = current_thd is always NULL */ /* In the Windows plugin, thd = current_thd is always NULL */
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
trx->mysql_thd = NULL; trx->mysql_thd = NULL;
trx->mysql_query_str = NULL;
#else #else
trx = innobase_trx_allocate(thd); trx = innobase_trx_allocate(thd);
#endif #endif
@ -7567,6 +7636,10 @@ ha_innobase::records_in_range(
n_rows = HA_POS_ERROR; n_rows = HA_POS_ERROR;
goto func_exit; goto func_exit;
} }
if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) {
n_rows = HA_ERR_TABLE_DEF_CHANGED;
goto func_exit;
}
heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t) heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
+ sizeof(dtuple_t))); + sizeof(dtuple_t)));
@ -7745,6 +7818,86 @@ ha_innobase::is_corrupt() const
return (FALSE); return (FALSE);
} }
/*********************************************************************//**
Calculates the key number used inside MySQL for an Innobase index. We will
first check the "index translation table" for a match of the index to get
the index number. If there does not exist an "index translation table",
or not able to find the index in the translation table, then we will fall back
to the traditional way of looping through dict_index_t list to find a
match. In this case, we have to take into account if we generated a
default clustered index for the table
@return the key number used inside MySQL */
static
unsigned int
innobase_get_mysql_key_number_for_index(
/*====================================*/
INNOBASE_SHARE* share, /*!< in: share structure for index
translation table. */
const TABLE* table, /*!< in: table in MySQL data
dictionary */
dict_table_t* ib_table,/*!< in: table in Innodb data
dictionary */
const dict_index_t* index) /*!< in: index */
{
const dict_index_t* ind;
unsigned int i;
ut_ad(index);
ut_ad(ib_table);
ut_ad(table);
ut_ad(share);
/* If index does not belong to the table of share structure. Search
index->table instead */
if (index->table != ib_table) {
i = 0;
ind = dict_table_get_first_index(index->table);
while (index != ind) {
ind = dict_table_get_next_index(ind);
i++;
}
if (row_table_got_default_clust_index(index->table)) {
ut_a(i > 0);
i--;
}
return(i);
}
/* If index translation table exists, we will first check
the index through index translation table for a match. */
if (share->idx_trans_tbl.index_mapping) {
for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
if (share->idx_trans_tbl.index_mapping[i] == index) {
return(i);
}
}
/* Print an error message if we cannot find the index
** in the "index translation table". */
sql_print_error("Cannot find index %s in InnoDB index "
"translation table.", index->name);
}
/* If we do not have an "index translation table", or not able
to find the index in the translation table, we'll directly find
matching index in the dict_index_t list */
for (i = 0; i < table->s->keys; i++) {
ind = dict_table_get_index_on_name(
ib_table, table->key_info[i].name);
if (index == ind) {
return(i);
}
}
sql_print_error("Cannot find matching index number for index %s "
"in InnoDB index list.", index->name);
return(0);
}
/*********************************************************************//** /*********************************************************************//**
Returns statistics information of the table to the MySQL interpreter, Returns statistics information of the table to the MySQL interpreter,
in various fields of the handle object. */ in various fields of the handle object. */
@ -7802,9 +7955,30 @@ ha_innobase::info(
/* In sql_show we call with this flag: update /* In sql_show we call with this flag: update
then statistics so that they are up-to-date */ then statistics so that they are up-to-date */
if (srv_use_sys_stats_table
&& thd_sql_command(user_thd) == SQLCOM_ANALYZE) {
/* If the indexes on the table don't have enough rows in SYS_STATS system table, */
/* they need to be created. */
dict_index_t* index;
prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
for (index = dict_table_get_first_index(ib_table);
index != NULL;
index = dict_table_get_next_index(index)) {
row_insert_stats_for_mysql(index, prebuilt->trx);
innobase_commit_low(prebuilt->trx);
}
ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
}
prebuilt->trx->op_info = "updating table statistics"; prebuilt->trx->op_info = "updating table statistics";
dict_update_statistics(ib_table); dict_update_statistics(ib_table,
(thd_sql_command(user_thd) == SQLCOM_ANALYZE)?TRUE:FALSE);
prebuilt->trx->op_info = "returning various info to MySQL"; prebuilt->trx->op_info = "returning various info to MySQL";
} }
@ -8016,8 +8190,8 @@ ha_innobase::info(
err_index = trx_get_error_info(prebuilt->trx); err_index = trx_get_error_info(prebuilt->trx);
if (err_index) { if (err_index) {
errkey = (unsigned int) errkey = innobase_get_mysql_key_number_for_index(
row_get_mysql_key_number_for_index(err_index); share, table, ib_table, err_index);
} else { } else {
errkey = (unsigned int) prebuilt->trx->error_key_num; errkey = (unsigned int) prebuilt->trx->error_key_num;
} }
@ -10766,7 +10940,35 @@ innodb_old_blocks_pct_update(
} }
/*************************************************************//** /*************************************************************//**
Check if it is a valid value of innodb_change_buffering. This function is Find the corresponding ibuf_use_t value that indexes into
innobase_change_buffering_values[] array for the input
change buffering option name.
@return corresponding IBUF_USE_* value for the input variable
name, or IBUF_USE_COUNT if not able to find a match */
static
ibuf_use_t
innodb_find_change_buffering_value(
/*===============================*/
const char* input_name) /*!< in: input change buffering
option name */
{
ulint use;
for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
use++) {
/* found a match */
if (!innobase_strcasecmp(
input_name, innobase_change_buffering_values[use])) {
return((ibuf_use_t)use);
}
}
/* Did not find any match */
return(IBUF_USE_COUNT);
}
/*************************************************************//**
Check if it is a valid value of innodb_change_buffering. This function is
registered as a callback with MySQL. registered as a callback with MySQL.
@return 0 for valid innodb_change_buffering */ @return 0 for valid innodb_change_buffering */
static static
@ -10790,19 +10992,22 @@ innodb_change_buffering_validate(
change_buffering_input = value->val_str(value, buff, &len); change_buffering_input = value->val_str(value, buff, &len);
if (change_buffering_input != NULL) { if (change_buffering_input != NULL) {
ulint use; ibuf_use_t use;
for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values); use = innodb_find_change_buffering_value(
use++) { change_buffering_input);
if (!innobase_strcasecmp(
change_buffering_input, if (use != IBUF_USE_COUNT) {
innobase_change_buffering_values[use])) { /* Find a matching change_buffering option value. */
*(ibuf_use_t*) save = (ibuf_use_t) use; *static_cast<const char**>(save) =
return(0); innobase_change_buffering_values[use];
}
return(0);
} }
} }
/* No corresponding change buffering option for user supplied
"change_buffering_input" */
return(1); return(1);
} }
@ -10813,21 +11018,27 @@ static
void void
innodb_change_buffering_update( innodb_change_buffering_update(
/*===========================*/ /*===========================*/
THD* thd, /*!< in: thread handle */ THD* thd, /*!< in: thread handle */
struct st_mysql_sys_var* var, /*!< in: pointer to struct st_mysql_sys_var* var, /*!< in: pointer to
system variable */ system variable */
void* var_ptr, /*!< out: where the void* var_ptr,/*!< out: where the
formal string goes */ formal string goes */
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
ibuf_use_t use;
ut_a(var_ptr != NULL); ut_a(var_ptr != NULL);
ut_a(save != NULL); ut_a(save != NULL);
ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
ibuf_use = *(const ibuf_use_t*) save; use = innodb_find_change_buffering_value(
*static_cast<const char*const*>(save));
*(const char**) var_ptr = innobase_change_buffering_values[ibuf_use]; ut_a(use < IBUF_USE_COUNT);
ibuf_use = use;
*static_cast<const char**>(var_ptr) =
*static_cast<const char*const*>(save);
} }
static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff)
@ -11093,6 +11304,14 @@ static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock,
"e.g. Data_free.", "e.g. Data_free.",
NULL, NULL, 1, 0, 1, 0); NULL, NULL, 1, 0, 1, 0);
static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"Enable to use SYS_STATS system table to store statistics statically, "
"And avoids to calculate statistics at every first open of the tables. "
"This option may make the opportunities of update statistics less. "
"So you should use ANALYZE TABLE command intentionally.",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled, static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
PLUGIN_VAR_OPCMDARG, PLUGIN_VAR_OPCMDARG,
"Enable InnoDB adaptive hash index (enabled by default). " "Enable InnoDB adaptive hash index (enabled by default). "
@ -11118,7 +11337,12 @@ static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment,
static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L); NULL, NULL, 128*1024*1024L, 32*1024*1024L, LONGLONG_MAX, 1024*1024L);
static MYSQL_SYSVAR_UINT(buffer_pool_shm_key, srv_buffer_pool_shm_key,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"[experimental] The key value of shared memory segment for the buffer pool. 0 means disable the feature (default).",
NULL, NULL, 0, 0, INT_MAX32, 0);
static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
@ -11249,7 +11473,7 @@ static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering,
"Buffer changes to reduce random access: " "Buffer changes to reduce random access: "
"OFF, ON, none, inserts.", "OFF, ON, none, inserts.",
innodb_change_buffering_validate, innodb_change_buffering_validate,
innodb_change_buffering_update, NULL); innodb_change_buffering_update, "inserts");
static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold, static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
@ -11379,6 +11603,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(autoextend_increment),
MYSQL_SYSVAR(buffer_pool_size), MYSQL_SYSVAR(buffer_pool_size),
MYSQL_SYSVAR(buffer_pool_shm_key),
MYSQL_SYSVAR(checksums), MYSQL_SYSVAR(checksums),
MYSQL_SYSVAR(fast_checksum), MYSQL_SYSVAR(fast_checksum),
MYSQL_SYSVAR(commit_concurrency), MYSQL_SYSVAR(commit_concurrency),
@ -11423,6 +11648,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_method), MYSQL_SYSVAR(stats_method),
MYSQL_SYSVAR(stats_auto_update), MYSQL_SYSVAR(stats_auto_update),
MYSQL_SYSVAR(stats_update_need_lock), MYSQL_SYSVAR(stats_update_need_lock),
MYSQL_SYSVAR(use_sys_stats_table),
MYSQL_SYSVAR(stats_sample_pages), MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index), MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(replication_delay), MYSQL_SYSVAR(replication_delay),
@ -11446,6 +11672,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(flush_neighbor_pages), MYSQL_SYSVAR(flush_neighbor_pages),
MYSQL_SYSVAR(read_ahead), MYSQL_SYSVAR(read_ahead),
MYSQL_SYSVAR(adaptive_checkpoint), MYSQL_SYSVAR(adaptive_checkpoint),
MYSQL_SYSVAR(flush_log_at_trx_commit_session),
MYSQL_SYSVAR(enable_unsafe_group_commit), MYSQL_SYSVAR(enable_unsafe_group_commit),
MYSQL_SYSVAR(expand_import), MYSQL_SYSVAR(expand_import),
MYSQL_SYSVAR(extra_rsegments), MYSQL_SYSVAR(extra_rsegments),
@ -11465,7 +11692,7 @@ mysql_declare_plugin(innodb_plugin)
&innobase_storage_engine, &innobase_storage_engine,
innobase_hton_name, innobase_hton_name,
"Innobase Oy", "Innobase Oy",
"Supports transactions, row-level locking, and foreign keys", "Percona-XtraDB, Supports transactions, row-level locking, and foreign keys",
PLUGIN_LICENSE_GPL, PLUGIN_LICENSE_GPL,
innobase_init, /* Plugin Init */ innobase_init, /* Plugin Init */
NULL, /* Plugin Deinit */ NULL, /* Plugin Deinit */
@ -11490,6 +11717,7 @@ i_s_innodb_index_stats,
i_s_innodb_admin_command, i_s_innodb_admin_command,
i_s_innodb_sys_tables, i_s_innodb_sys_tables,
i_s_innodb_sys_indexes, i_s_innodb_sys_indexes,
i_s_innodb_sys_stats,
i_s_innodb_patches i_s_innodb_patches
mysql_declare_plugin_end; mysql_declare_plugin_end;

View file

@ -233,7 +233,11 @@ the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
extern "C" { extern "C" {
struct charset_info_st *thd_charset(MYSQL_THD thd); struct charset_info_st *thd_charset(MYSQL_THD thd);
#if MYSQL_VERSION_ID >= 50142
LEX_STRING *thd_query_string(MYSQL_THD thd);
#else
char **thd_query(MYSQL_THD thd); char **thd_query(MYSQL_THD thd);
#endif
/** Get the file name of the MySQL binlog. /** Get the file name of the MySQL binlog.
* @return the name of the binlog file * @return the name of the binlog file

View file

@ -894,6 +894,8 @@ error:
prebuilt->trx->error_info = NULL; prebuilt->trx->error_info = NULL;
/* fall through */ /* fall through */
default: default:
trx->error_state = DB_SUCCESS;
if (new_primary) { if (new_primary) {
if (indexed_table != innodb_table) { if (indexed_table != innodb_table) {
row_merge_drop_table(trx, indexed_table); row_merge_drop_table(trx, indexed_table);

View file

@ -43,20 +43,11 @@ extern "C" {
#include "ha_prototypes.h" /* for innobase_convert_name() */ #include "ha_prototypes.h" /* for innobase_convert_name() */
#include "srv0start.h" /* for srv_was_started */ #include "srv0start.h" /* for srv_was_started */
#include "btr0btr.h" /* for btr_page_get_index_id */ #include "btr0btr.h" /* for btr_page_get_index_id */
#include "dict0dict.h" /* for dict_index_get_if_in_cache */
#include "trx0rseg.h" /* for trx_rseg_struct */ #include "trx0rseg.h" /* for trx_rseg_struct */
#include "trx0sys.h" /* for trx_sys */ #include "trx0sys.h" /* for trx_sys */
#include "dict0dict.h" /* for dict_sys */ #include "dict0dict.h" /* for dict_sys */
#include "btr0pcur.h" #include "btr0pcur.h"
#include "buf0lru.h" /* for XTRA_LRU_[DUMP/RESTORE] */ #include "buf0lru.h" /* for XTRA_LRU_[DUMP/RESTORE] */
/* from buf0buf.c */
struct buf_chunk_struct{
ulint mem_size; /* allocated size of the chunk */
ulint size; /* size of frames[] and blocks[] */
void* mem; /* pointer to the memory area which
was allocated for the frames */
buf_block_t* blocks; /* array of buffer control blocks */
};
} }
static const char plugin_author[] = "Innobase Oy"; static const char plugin_author[] = "Innobase Oy";
@ -450,27 +441,11 @@ static ST_FIELD_INFO i_s_innodb_buffer_pool_pages_fields_info[] =
static ST_FIELD_INFO i_s_innodb_buffer_pool_pages_index_fields_info[] = static ST_FIELD_INFO i_s_innodb_buffer_pool_pages_index_fields_info[] =
{ {
{STRUCT_FLD(field_name, "schema_name"), {STRUCT_FLD(field_name, "index_id"),
STRUCT_FLD(field_length, 64), STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING), STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0), STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "table_name"),
STRUCT_FLD(field_length, 64),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "index_name"),
STRUCT_FLD(field_length, 64),
STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, 0),
STRUCT_FLD(old_name, ""), STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
@ -671,7 +646,6 @@ i_s_innodb_buffer_pool_pages_fill(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
buf_pool_mutex_enter(); buf_pool_mutex_enter();
mutex_enter(&(dict_sys->mutex));
chunk = buf_pool->chunks; chunk = buf_pool->chunks;
@ -743,7 +717,6 @@ i_s_innodb_buffer_pool_pages_fill(
} }
} }
mutex_exit(&(dict_sys->mutex));
buf_pool_mutex_exit(); buf_pool_mutex_exit();
DBUG_RETURN(status); DBUG_RETURN(status);
@ -764,13 +737,8 @@ i_s_innodb_buffer_pool_pages_index_fill(
int status = 0; int status = 0;
ulint n_chunks, n_blocks; ulint n_chunks, n_blocks;
dict_index_t* index;
dulint index_id; dulint index_id;
const char *p;
char db_name_raw[NAME_LEN*5+1], db_name[NAME_LEN+1];
char table_name_raw[NAME_LEN*5+1], table_name[NAME_LEN+1];
buf_chunk_t* chunk; buf_chunk_t* chunk;
DBUG_ENTER("i_s_innodb_buffer_pool_pages_index_fill"); DBUG_ENTER("i_s_innodb_buffer_pool_pages_index_fill");
@ -784,7 +752,6 @@ i_s_innodb_buffer_pool_pages_index_fill(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
buf_pool_mutex_enter(); buf_pool_mutex_enter();
mutex_enter(&(dict_sys->mutex));
chunk = buf_pool->chunks; chunk = buf_pool->chunks;
@ -796,48 +763,28 @@ i_s_innodb_buffer_pool_pages_index_fill(
if (fil_page_get_type(frame) == FIL_PAGE_INDEX) { if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
index_id = btr_page_get_index_id(frame); index_id = btr_page_get_index_id(frame);
index = dict_index_get_if_in_cache_low(index_id); table->field[0]->store(ut_conv_dulint_to_longlong(index_id));
if(index) table->field[1]->store(block->page.space);
{ table->field[2]->store(block->page.offset);
if((p = strchr(index->table_name, '/'))) table->field[3]->store(page_get_n_recs(frame));
{ table->field[4]->store(page_get_data_size(frame));
strncpy(db_name_raw, index->table_name, p-index->table_name); table->field[5]->store(block->is_hashed);
db_name_raw[p-index->table_name] = 0; table->field[6]->store(block->page.access_time);
filename_to_tablename(db_name_raw, db_name, sizeof(db_name)); table->field[7]->store(block->page.newest_modification != 0);
field_store_string(table->field[0], db_name); table->field[8]->store(block->page.oldest_modification != 0);
p++; table->field[9]->store(block->page.old);
} else { table->field[10]->store(0);
field_store_string(table->field[0], NULL); table->field[11]->store(block->page.buf_fix_count);
p = index->table_name; table->field[12]->store(block->page.flush_type);
}
strcpy(table_name_raw, (const char*)p);
filename_to_tablename(table_name_raw, table_name, sizeof(table_name));
field_store_string(table->field[1], table_name);
field_store_string(table->field[2], index->name);
table->field[3]->store(block->page.space); if (schema_table_store_record(thd, table)) {
table->field[4]->store(block->page.offset); status = 1;
table->field[5]->store(page_get_n_recs(frame)); break;
table->field[6]->store(page_get_data_size(frame));
table->field[7]->store(block->is_hashed);
table->field[8]->store(block->page.access_time);
table->field[9]->store(block->page.newest_modification != 0);
table->field[10]->store(block->page.oldest_modification != 0);
table->field[11]->store(block->page.old);
table->field[12]->store(0);
table->field[13]->store(block->page.buf_fix_count);
table->field[14]->store(block->page.flush_type);
if (schema_table_store_record(thd, table)) {
status = 1;
break;
}
} }
} }
} }
} }
mutex_exit(&(dict_sys->mutex));
buf_pool_mutex_exit(); buf_pool_mutex_exit();
DBUG_RETURN(status); DBUG_RETURN(status);
@ -875,7 +822,6 @@ i_s_innodb_buffer_pool_pages_blob_fill(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
buf_pool_mutex_enter(); buf_pool_mutex_enter();
mutex_enter(&(dict_sys->mutex));
chunk = buf_pool->chunks; chunk = buf_pool->chunks;
@ -931,7 +877,6 @@ i_s_innodb_buffer_pool_pages_blob_fill(
} }
} }
mutex_exit(&(dict_sys->mutex));
buf_pool_mutex_exit(); buf_pool_mutex_exit();
DBUG_RETURN(status); DBUG_RETURN(status);
@ -3037,11 +2982,10 @@ i_s_innodb_admin_command_fill(
COND* cond) COND* cond)
{ {
TABLE* i_s_table = (TABLE *) tables->table; TABLE* i_s_table = (TABLE *) tables->table;
CHARSET_INFO *cs= system_charset_info;
char** query_str; char** query_str;
char* ptr; char* ptr;
char quote = '\0'; char quote = '\0';
char* command_head = "XTRA_"; const char* command_head = "XTRA_";
DBUG_ENTER("i_s_innodb_admin_command_fill"); DBUG_ENTER("i_s_innodb_admin_command_fill");
@ -3310,6 +3254,35 @@ static ST_FIELD_INFO i_s_innodb_sys_indexes_info[] =
END_OF_ST_FIELD_INFO END_OF_ST_FIELD_INFO
}; };
static ST_FIELD_INFO i_s_innodb_sys_stats_info[] =
{
{STRUCT_FLD(field_name, "INDEX_ID"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "KEY_COLS"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
{STRUCT_FLD(field_name, "DIFF_VALS"),
STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS),
STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG),
STRUCT_FLD(value, 0),
STRUCT_FLD(field_flags, MY_I_S_UNSIGNED),
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
END_OF_ST_FIELD_INFO
};
static static
int int
copy_string_field( copy_string_field(
@ -3564,6 +3537,40 @@ copy_sys_indexes_rec(
return 0; return 0;
} }
static
int
copy_sys_stats_rec(
/*===============*/
TABLE* table,
const dict_index_t* index,
const rec_t* rec
)
{
int status;
int field;
/* INDEX_ID */
field = dict_index_get_nth_col_pos(index, 0);
status = copy_id_field(table, 0, rec, field);
if (status) {
return status;
}
/* KEY_COLS */
field = dict_index_get_nth_col_pos(index, 1);
status = copy_int_field(table, 1, rec, field);
if (status) {
return status;
}
/* DIFF_VALS */
field = dict_index_get_nth_col_pos(index, 2);
status = copy_id_field(table, 2, rec, field);
if (status) {
return status;
}
return 0;
}
static static
int int
i_s_innodb_schema_table_fill( i_s_innodb_schema_table_fill(
@ -3593,6 +3600,8 @@ i_s_innodb_schema_table_fill(
id = 0; id = 0;
} else if (innobase_strcasecmp(table_name, "innodb_sys_indexes") == 0) { } else if (innobase_strcasecmp(table_name, "innodb_sys_indexes") == 0) {
id = 1; id = 1;
} else if (innobase_strcasecmp(table_name, "innodb_sys_stats") == 0) {
id = 2;
} else { } else {
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -3606,8 +3615,10 @@ i_s_innodb_schema_table_fill(
if (id == 0) { if (id == 0) {
innodb_table = dict_table_get_low("SYS_TABLES"); innodb_table = dict_table_get_low("SYS_TABLES");
} else { } else if (id == 1) {
innodb_table = dict_table_get_low("SYS_INDEXES"); innodb_table = dict_table_get_low("SYS_INDEXES");
} else {
innodb_table = dict_table_get_low("SYS_STATS");
} }
index = UT_LIST_GET_FIRST(innodb_table->indexes); index = UT_LIST_GET_FIRST(innodb_table->indexes);
@ -3632,8 +3643,10 @@ i_s_innodb_schema_table_fill(
if (id == 0) { if (id == 0) {
status = copy_sys_tables_rec(table, index, rec); status = copy_sys_tables_rec(table, index, rec);
} else { } else if (id == 1) {
status = copy_sys_indexes_rec(table, index, rec); status = copy_sys_indexes_rec(table, index, rec);
} else {
status = copy_sys_stats_rec(table, index, rec);
} }
if (status) { if (status) {
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
@ -3698,6 +3711,21 @@ i_s_innodb_sys_indexes_init(
DBUG_RETURN(0); DBUG_RETURN(0);
} }
static
int
i_s_innodb_sys_stats_init(
/*======================*/
void* p)
{
DBUG_ENTER("i_s_innodb_sys_stats_init");
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = i_s_innodb_sys_stats_info;
schema->fill_table = i_s_innodb_schema_table_fill;
DBUG_RETURN(0);
}
UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables = UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables =
{ {
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
@ -3729,3 +3757,19 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_indexes =
STRUCT_FLD(system_vars, NULL), STRUCT_FLD(system_vars, NULL),
STRUCT_FLD(__reserved1, NULL) STRUCT_FLD(__reserved1, NULL)
}; };
UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats =
{
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
STRUCT_FLD(info, &i_s_info),
STRUCT_FLD(name, "INNODB_SYS_STATS"),
STRUCT_FLD(author, plugin_author),
STRUCT_FLD(descr, "InnoDB SYS_STATS table"),
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
STRUCT_FLD(init, i_s_innodb_sys_stats_init),
STRUCT_FLD(deinit, i_s_common_deinit),
STRUCT_FLD(version, 0x0100 /* 1.0 */),
STRUCT_FLD(status_vars, NULL),
STRUCT_FLD(system_vars, NULL),
STRUCT_FLD(__reserved1, NULL)
};

View file

@ -43,5 +43,6 @@ extern struct st_mysql_plugin i_s_innodb_index_stats;
extern struct st_mysql_plugin i_s_innodb_admin_command; extern struct st_mysql_plugin i_s_innodb_admin_command;
extern struct st_mysql_plugin i_s_innodb_sys_tables; extern struct st_mysql_plugin i_s_innodb_sys_tables;
extern struct st_mysql_plugin i_s_innodb_sys_indexes; extern struct st_mysql_plugin i_s_innodb_sys_indexes;
extern struct st_mysql_plugin i_s_innodb_sys_stats;
#endif /* i_s_h */ #endif /* i_s_h */

View file

@ -47,5 +47,6 @@ struct innodb_enhancement {
{"innodb_fast_checksum","Using the checksum on 32bit-unit calculation","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_fast_checksum","Using the checksum on 32bit-unit calculation","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_files_extend","allow >4GB transaction log files, and can vary universal page size of datafiles","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_files_extend","allow >4GB transaction log files, and can vary universal page size of datafiles","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_sys_tables_sys_indexes","Expose InnoDB SYS_TABLES and SYS_INDEXES schema tables","","http://www.percona.com/docs/wiki/percona-xtradb"}, {"innodb_sys_tables_sys_indexes","Expose InnoDB SYS_TABLES and SYS_INDEXES schema tables","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_buffer_pool_shm","Put buffer pool contents to shared memory segment and reuse it at clean restart [experimental]","","http://www.percona.com/docs/wiki/percona-xtradb"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -36,6 +36,7 @@ Created 11/5/1995 Heikki Tuuri
#include "ut0rbt.h" #include "ut0rbt.h"
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
#include "os0proc.h" #include "os0proc.h"
#include "srv0srv.h"
/** @name Modes for buf_page_get_gen */ /** @name Modes for buf_page_get_gen */
/* @{ */ /* @{ */
@ -1301,11 +1302,23 @@ struct buf_block_struct{
/**********************************************************************//** /**********************************************************************//**
Compute the hash fold value for blocks in buf_pool->zip_hash. */ Compute the hash fold value for blocks in buf_pool->zip_hash. */
/* @{ */ /* @{ */
#define BUF_POOL_ZIP_FOLD_PTR(ptr) ((ulint) (ptr) / UNIV_PAGE_SIZE) /* the fold should be relative when srv_buffer_pool_shm_key is enabled */
#define BUF_POOL_ZIP_FOLD_PTR(ptr) (!srv_buffer_pool_shm_key\
?((ulint) (ptr) / UNIV_PAGE_SIZE)\
:((ulint) ((void*)ptr - (void*)(buf_pool->chunks->blocks->frame)) / UNIV_PAGE_SIZE))
#define BUF_POOL_ZIP_FOLD(b) BUF_POOL_ZIP_FOLD_PTR((b)->frame) #define BUF_POOL_ZIP_FOLD(b) BUF_POOL_ZIP_FOLD_PTR((b)->frame)
#define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b)) #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b))
/* @} */ /* @} */
/** A chunk of buffers. The buffer pool is allocated in chunks. */
struct buf_chunk_struct{
ulint mem_size; /*!< allocated size of the chunk */
ulint size; /*!< size of frames[] and blocks[] */
void* mem; /*!< pointer to the memory area which
was allocated for the frames */
buf_block_t* blocks; /*!< array of buffer control blocks */
};
/** @brief The buffer pool statistics structure. */ /** @brief The buffer pool statistics structure. */
struct buf_pool_stat_struct{ struct buf_pool_stat_struct{
ulint n_page_gets; /*!< number of page gets performed; ulint n_page_gets; /*!< number of page gets performed;

View file

@ -973,7 +973,12 @@ buf_page_hash_get(
ut_a(buf_page_in_file(bpage)); ut_a(buf_page_in_file(bpage));
ut_ad(bpage->in_page_hash); ut_ad(bpage->in_page_hash);
ut_ad(!bpage->in_zip_hash); ut_ad(!bpage->in_zip_hash);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in
buf_page_t. On other systems, Valgrind could complain
about uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
} }
return(bpage); return(bpage);

View file

@ -96,7 +96,7 @@ buf_LRU_insert_zip_clean(
Try to free a block. If bpage is a descriptor of a compressed-only Try to free a block. If bpage is a descriptor of a compressed-only
page, the descriptor object will be freed as well. page, the descriptor object will be freed as well.
NOTE: If this function returns BUF_LRU_FREED, it will not temporarily NOTE: If this function returns BUF_LRU_FREED, it will temporarily
release buf_pool_mutex. Furthermore, the page frame will no longer be release buf_pool_mutex. Furthermore, the page frame will no longer be
accessible via bpage. accessible via bpage.

View file

@ -158,8 +158,7 @@ buf_read_recv_pages(
/** The size in pages of the area which the read-ahead algorithms read if /** The size in pages of the area which the read-ahead algorithms read if
invoked */ invoked */
#define BUF_READ_AHEAD_AREA \ #define BUF_READ_AHEAD_AREA 64
ut_min(64, ut_2_power_up(buf_pool->curr_size / 32))
/** @name Modes used in read-ahead @{ */ /** @name Modes used in read-ahead @{ */
/** read only pages belonging to the insert buffer tree */ /** read only pages belonging to the insert buffer tree */

View file

@ -28,6 +28,8 @@ Created 5/24/1996 Heikki Tuuri
enum db_err { enum db_err {
DB_SUCCESS_LOCKED_REC = 9, /*!< like DB_SUCCESS, but a new
explicit record lock was created */
DB_SUCCESS = 10, DB_SUCCESS = 10,
/* The following are error codes */ /* The following are error codes */

View file

@ -46,13 +46,14 @@ dict_hdr_get(
/*=========*/ /*=========*/
mtr_t* mtr); /*!< in: mtr */ mtr_t* mtr); /*!< in: mtr */
/**********************************************************************//** /**********************************************************************//**
Returns a new row, table, index, or tree id. Returns a new table, index, or space id. */
@return the new id */
UNIV_INTERN UNIV_INTERN
dulint void
dict_hdr_get_new_id( dict_hdr_get_new_id(
/*================*/ /*================*/
ulint type); /*!< in: DICT_HDR_ROW_ID, ... */ dulint* table_id, /*!< out: table id (not assigned if NULL) */
dulint* index_id, /*!< out: index id (not assigned if NULL) */
ulint* space_id); /*!< out: space id (not assigned if NULL) */
/**********************************************************************//** /**********************************************************************//**
Returns a new row id. Returns a new row id.
@return the new id */ @return the new id */
@ -100,6 +101,7 @@ dict_create(void);
#define DICT_COLUMNS_ID ut_dulint_create(0, 2) #define DICT_COLUMNS_ID ut_dulint_create(0, 2)
#define DICT_INDEXES_ID ut_dulint_create(0, 3) #define DICT_INDEXES_ID ut_dulint_create(0, 3)
#define DICT_FIELDS_ID ut_dulint_create(0, 4) #define DICT_FIELDS_ID ut_dulint_create(0, 4)
#define DICT_STATS_ID ut_dulint_create(0, 6)
/* The following is a secondary index on SYS_TABLES */ /* The following is a secondary index on SYS_TABLES */
#define DICT_TABLE_IDS_ID ut_dulint_create(0, 5) #define DICT_TABLE_IDS_ID ut_dulint_create(0, 5)
@ -119,17 +121,21 @@ dict_create(void);
#define DICT_HDR_ROW_ID 0 /* The latest assigned row id */ #define DICT_HDR_ROW_ID 0 /* The latest assigned row id */
#define DICT_HDR_TABLE_ID 8 /* The latest assigned table id */ #define DICT_HDR_TABLE_ID 8 /* The latest assigned table id */
#define DICT_HDR_INDEX_ID 16 /* The latest assigned index id */ #define DICT_HDR_INDEX_ID 16 /* The latest assigned index id */
#define DICT_HDR_MIX_ID 24 /* Obsolete, always 0. */ #define DICT_HDR_MAX_SPACE_ID 24 /* The latest assigned space id, or 0*/
#define DICT_HDR_MIX_ID_LOW 28 /* Obsolete,always DICT_HDR_FIRST_ID */
#define DICT_HDR_TABLES 32 /* Root of the table index tree */ #define DICT_HDR_TABLES 32 /* Root of the table index tree */
#define DICT_HDR_TABLE_IDS 36 /* Root of the table index tree */ #define DICT_HDR_TABLE_IDS 36 /* Root of the table index tree */
#define DICT_HDR_COLUMNS 40 /* Root of the column index tree */ #define DICT_HDR_COLUMNS 40 /* Root of the column index tree */
#define DICT_HDR_INDEXES 44 /* Root of the index index tree */ #define DICT_HDR_INDEXES 44 /* Root of the index index tree */
#define DICT_HDR_FIELDS 48 /* Root of the index field #define DICT_HDR_FIELDS 48 /* Root of the index field
index tree */ index tree */
#define DICT_HDR_STATS 52 /* Root of the stats tree */
#define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace
segment into which the dictionary segment into which the dictionary
header is created */ header is created */
#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */
/*-------------------------------------------------------------*/ /*-------------------------------------------------------------*/
/* The field number of the page number field in the sys_indexes table /* The field number of the page number field in the sys_indexes table
@ -139,11 +145,15 @@ clustered index */
#define DICT_SYS_INDEXES_TYPE_FIELD 6 #define DICT_SYS_INDEXES_TYPE_FIELD 6
#define DICT_SYS_INDEXES_NAME_FIELD 4 #define DICT_SYS_INDEXES_NAME_FIELD 4
#define DICT_SYS_STATS_DIFF_VALS_FIELD 4
/* When a row id which is zero modulo this number (which must be a power of /* When a row id which is zero modulo this number (which must be a power of
two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
updated */ updated */
#define DICT_HDR_ROW_ID_WRITE_MARGIN 256 #define DICT_HDR_ROW_ID_WRITE_MARGIN 256
#define DICT_HDR_XTRADB_FLAG ut_dulint_create(0x58545241UL,0x44425F31UL) /* "XTRADB_1" */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "dict0boot.ic" #include "dict0boot.ic"
#endif #endif

View file

@ -53,6 +53,14 @@ ind_create_graph_create(
dict_index_t* index, /*!< in: index to create, built as a memory data dict_index_t* index, /*!< in: index to create, built as a memory data
structure */ structure */
mem_heap_t* heap); /*!< in: heap where created */ mem_heap_t* heap); /*!< in: heap where created */
/*********************************************************************//**
*/
UNIV_INTERN
ind_node_t*
ind_insert_stats_graph_create(
/*==========================*/
dict_index_t* index,
mem_heap_t* heap);
/***********************************************************//** /***********************************************************//**
Creates a table. This is a high-level function used in SQL execution graphs. Creates a table. This is a high-level function used in SQL execution graphs.
@return query thread to run next or NULL */ @return query thread to run next or NULL */
@ -62,6 +70,13 @@ dict_create_table_step(
/*===================*/ /*===================*/
que_thr_t* thr); /*!< in: query thread */ que_thr_t* thr); /*!< in: query thread */
/***********************************************************//** /***********************************************************//**
*/
UNIV_INTERN
que_thr_t*
dict_insert_stats_step(
/*===================*/
que_thr_t* thr);
/***********************************************************//**
Creates an index. This is a high-level function used in SQL execution Creates an index. This is a high-level function used in SQL execution
graphs. graphs.
@return query thread to run next or NULL */ @return query thread to run next or NULL */
@ -170,6 +185,7 @@ struct ind_node_struct{
ins_node_t* field_def; /* child node which does the inserts of ins_node_t* field_def; /* child node which does the inserts of
the field definitions; the row to be inserted the field definitions; the row to be inserted
is built by the parent node */ is built by the parent node */
ins_node_t* stats_def;
commit_node_t* commit_node; commit_node_t* commit_node;
/* child node which performs a commit after /* child node which performs a commit after
a successful index creation */ a successful index creation */
@ -180,6 +196,7 @@ struct ind_node_struct{
dict_table_t* table; /*!< table which owns the index */ dict_table_t* table; /*!< table which owns the index */
dtuple_t* ind_row;/* index definition row built */ dtuple_t* ind_row;/* index definition row built */
ulint field_no;/* next field definition to insert */ ulint field_no;/* next field definition to insert */
ulint stats_no;
mem_heap_t* heap; /*!< memory heap used as auxiliary storage */ mem_heap_t* heap; /*!< memory heap used as auxiliary storage */
}; };
@ -189,6 +206,7 @@ struct ind_node_struct{
#define INDEX_CREATE_INDEX_TREE 3 #define INDEX_CREATE_INDEX_TREE 3
#define INDEX_COMMIT_WORK 4 #define INDEX_COMMIT_WORK 4
#define INDEX_ADD_TO_CACHE 5 #define INDEX_ADD_TO_CACHE 5
#define INDEX_BUILD_STATS_COLS 6
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "dict0crea.ic" #include "dict0crea.ic"

View file

@ -352,6 +352,7 @@ dict_create_foreign_constraints(
name before it: test.table2; the name before it: test.table2; the
default database id the database of default database id the database of
parameter name */ parameter name */
size_t sql_length, /*!< in: length of sql_string */
const char* name, /*!< in: table full name in the const char* name, /*!< in: table full name in the
normalized form normalized form
database_name/table_name */ database_name/table_name */
@ -1039,8 +1040,9 @@ void
dict_update_statistics_low( dict_update_statistics_low(
/*=======================*/ /*=======================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool has_dict_mutex);/*!< in: TRUE if the caller has the ibool has_dict_mutex, /*!< in: TRUE if the caller has the
dictionary mutex */ dictionary mutex */
ibool sync);
/*********************************************************************//** /*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
@ -1048,7 +1050,8 @@ UNIV_INTERN
void void
dict_update_statistics( dict_update_statistics(
/*===================*/ /*===================*/
dict_table_t* table); /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool sync);
/********************************************************************//** /********************************************************************//**
Reserves the dictionary system mutex for MySQL. */ Reserves the dictionary system mutex for MySQL. */
UNIV_INTERN UNIV_INTERN
@ -1159,6 +1162,7 @@ struct dict_sys_struct{
dict_table_t* sys_columns; /*!< SYS_COLUMNS table */ dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
dict_table_t* sys_fields; /*!< SYS_FIELDS table */ dict_table_t* sys_fields; /*!< SYS_FIELDS table */
dict_table_t* sys_stats; /*!< SYS_STATS table */
}; };
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */

View file

@ -382,7 +382,7 @@ initialized to 0, NULL or FALSE in dict_mem_table_create(). */
struct dict_table_struct{ struct dict_table_struct{
dulint id; /*!< id of the table */ dulint id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */ mem_heap_t* heap; /*!< memory heap */
const char* name; /*!< table name */ char* name; /*!< table name */
const char* dir_path_of_temp_table;/*!< NULL or the directory path const char* dir_path_of_temp_table;/*!< NULL or the directory path
where a TEMPORARY table that was explicitly where a TEMPORARY table that was explicitly
created by a user should be placed if created by a user should be placed if

View file

@ -226,6 +226,16 @@ fil_space_create(
0 for uncompressed tablespaces */ 0 for uncompressed tablespaces */
ulint purpose);/*!< in: FIL_TABLESPACE, or FIL_LOG if log */ ulint purpose);/*!< in: FIL_TABLESPACE, or FIL_LOG if log */
/*******************************************************************//** /*******************************************************************//**
Assigns a new space id for a new single-table tablespace. This works simply by
incrementing the global counter. If 4 billion id's is not enough, we may need
to recycle id's.
@return TRUE if assigned, FALSE if not */
UNIV_INTERN
ibool
fil_assign_new_space_id(
/*====================*/
ulint* space_id); /*!< in/out: space id */
/*******************************************************************//**
Returns the size of the space in pages. The tablespace must be cached in the Returns the size of the space in pages. The tablespace must be cached in the
memory cache. memory cache.
@return space size, 0 if space not found */ @return space size, 0 if space not found */
@ -428,9 +438,7 @@ UNIV_INTERN
ulint ulint
fil_create_new_single_table_tablespace( fil_create_new_single_table_tablespace(
/*===================================*/ /*===================================*/
ulint* space_id, /*!< in/out: space id; if this is != 0, ulint space_id, /*!< in: space id */
then this is an input parameter,
otherwise output */
const char* tablename, /*!< in: the table name in the usual const char* tablename, /*!< in: the table name in the usual
databasename/tablename format databasename/tablename format
of InnoDB, or a dir path to a temp of InnoDB, or a dir path to a temp
@ -499,16 +507,6 @@ UNIV_INTERN
ulint ulint
fil_load_single_table_tablespaces(void); fil_load_single_table_tablespaces(void);
/*===================================*/ /*===================================*/
/********************************************************************//**
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. */
UNIV_INTERN
void
fil_print_orphaned_tablespaces(void);
/*================================*/
/*******************************************************************//** /*******************************************************************//**
Returns TRUE if a single-table tablespace does not exist in the memory cache, Returns TRUE if a single-table tablespace does not exist in the memory cache,
or is being deleted there. or is being deleted there.

View file

@ -215,11 +215,21 @@ innobase_casedn_str(
/**********************************************************************//** /**********************************************************************//**
Determines the connection character set. Determines the connection character set.
@return connection character set */ @return connection character set */
UNIV_INTERN
struct charset_info_st* struct charset_info_st*
innobase_get_charset( innobase_get_charset(
/*=================*/ /*=================*/
void* mysql_thd); /*!< in: MySQL thread handle */ void* mysql_thd); /*!< in: MySQL thread handle */
/**********************************************************************//**
Determines the current SQL statement.
@return SQL statement string */
UNIV_INTERN
const char*
innobase_get_stmt(
/*==============*/
void* mysql_thd, /*!< in: MySQL thread handle */
size_t* length) /*!< out: length of the SQL statement */
__attribute__((nonnull));
/******************************************************************//** /******************************************************************//**
This function is used to find the storage length in bytes of the first n This function is used to find the storage length in bytes of the first n
characters for prefix indexes using a multibyte character set. The function characters for prefix indexes using a multibyte character set. The function
@ -258,4 +268,12 @@ thd_lock_wait_timeout(
void* thd); /*!< in: thread handle (THD*), or NULL to query void* thd); /*!< in: thread handle (THD*), or NULL to query
the global innodb_lock_wait_timeout */ the global innodb_lock_wait_timeout */
/******************************************************************//**
*/
ulong
thd_flush_log_at_trx_commit_session(
/*================================*/
void* thd);
#endif #endif

View file

@ -49,6 +49,28 @@ hash_table_t*
hash_create( hash_create(
/*========*/ /*========*/
ulint n); /*!< in: number of array cells */ ulint n); /*!< in: number of array cells */
/*************************************************************//**
*/
UNIV_INTERN
ulint
hash_create_needed(
/*===============*/
ulint n);
UNIV_INTERN
void
hash_create_init(
/*=============*/
hash_table_t* table,
ulint n);
UNIV_INTERN
void
hash_create_reuse(
/*==============*/
hash_table_t* table);
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/*************************************************************//** /*************************************************************//**
Creates a mutex array to protect a hash table. */ Creates a mutex array to protect a hash table. */
@ -328,6 +350,33 @@ do {\
}\ }\
} while (0) } while (0)
/********************************************************************//**
Align nodes with moving location.*/
#define HASH_OFFSET(TABLE, NODE_TYPE, PTR_NAME, FADDR, FOFFSET, BOFFSET) \
do {\
ulint i2222;\
ulint cell_count2222;\
\
cell_count2222 = hash_get_n_cells(TABLE);\
\
for (i2222 = 0; i2222 < cell_count2222; i2222++) {\
NODE_TYPE* node2222;\
\
if ((TABLE)->array[i2222].node) \
(TABLE)->array[i2222].node \
+= (((TABLE)->array[i2222].node > (void*)FADDR)?FOFFSET:BOFFSET);\
node2222 = HASH_GET_FIRST((TABLE), i2222);\
\
while (node2222) {\
if (node2222->PTR_NAME) \
node2222->PTR_NAME = ((void*)node2222->PTR_NAME) \
+ ((((void*)node2222->PTR_NAME) > (void*)FADDR)?FOFFSET:BOFFSET);\
\
node2222 = node2222->PTR_NAME;\
}\
}\
} while (0)
/************************************************************//** /************************************************************//**
Gets the mutex index for a fold value in a hash table. Gets the mutex index for a fold value in a hash table.
@return mutex number */ @return mutex number */

View file

@ -341,11 +341,12 @@ lock_sec_rec_modify_check_and_lock(
que_thr_t* thr, /*!< in: query thread */ que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr); /*!< in/out: mini-transaction */ mtr_t* mtr); /*!< in/out: mini-transaction */
/*********************************************************************//** /*********************************************************************//**
Like the counterpart for a clustered index below, but now we read a Like lock_clust_rec_read_check_and_lock(), but reads a
secondary index record. secondary index record.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
UNIV_INTERN UNIV_INTERN
ulint enum db_err
lock_sec_rec_read_check_and_lock( lock_sec_rec_read_check_and_lock(
/*=============================*/ /*=============================*/
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG
@ -372,9 +373,10 @@ if the query thread should anyway be suspended for some reason; if not, then
puts the transaction and the query thread to the lock wait state and inserts a puts the transaction and the query thread to the lock wait state and inserts a
waiting request for a record lock to the lock queue. Sets the requested mode waiting request for a record lock to the lock queue. Sets the requested mode
lock on the record. lock on the record.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
UNIV_INTERN UNIV_INTERN
ulint enum db_err
lock_clust_rec_read_check_and_lock( lock_clust_rec_read_check_and_lock(
/*===============================*/ /*===============================*/
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG

View file

@ -433,7 +433,10 @@ void
log_free_check(void) log_free_check(void)
/*================*/ /*================*/
{ {
/* ut_ad(sync_thread_levels_empty()); */
#ifdef UNIV_SYNC_DEBUG
ut_ad(sync_thread_levels_empty_gen(TRUE));
#endif /* UNIV_SYNC_DEBUG */
if (log_sys->check_flush_or_checkpoint) { if (log_sys->check_flush_or_checkpoint) {

View file

@ -36,7 +36,7 @@ mach_write_to_1(
ulint n) /*!< in: ulint integer to be stored, >= 0, < 256 */ ulint n) /*!< in: ulint integer to be stored, >= 0, < 256 */
{ {
ut_ad(b); ut_ad(b);
ut_ad(n <= 0xFFUL); ut_ad((n | 0xFFUL) <= 0xFFUL);
b[0] = (byte)n; b[0] = (byte)n;
} }
@ -65,7 +65,7 @@ mach_write_to_2(
ulint n) /*!< in: ulint integer to be stored */ ulint n) /*!< in: ulint integer to be stored */
{ {
ut_ad(b); ut_ad(b);
ut_ad(n <= 0xFFFFUL); ut_ad((n | 0xFFFFUL) <= 0xFFFFUL);
b[0] = (byte)(n >> 8); b[0] = (byte)(n >> 8);
b[1] = (byte)(n); b[1] = (byte)(n);
@ -81,10 +81,7 @@ mach_read_from_2(
/*=============*/ /*=============*/
const byte* b) /*!< in: pointer to 2 bytes */ const byte* b) /*!< in: pointer to 2 bytes */
{ {
ut_ad(b); return(((ulint)(b[0]) << 8) | (ulint)(b[1]));
return( ((ulint)(b[0]) << 8)
+ (ulint)(b[1])
);
} }
/********************************************************//** /********************************************************//**
@ -129,7 +126,7 @@ mach_write_to_3(
ulint n) /*!< in: ulint integer to be stored */ ulint n) /*!< in: ulint integer to be stored */
{ {
ut_ad(b); ut_ad(b);
ut_ad(n <= 0xFFFFFFUL); ut_ad((n | 0xFFFFFFUL) <= 0xFFFFFFUL);
b[0] = (byte)(n >> 16); b[0] = (byte)(n >> 16);
b[1] = (byte)(n >> 8); b[1] = (byte)(n >> 8);
@ -148,8 +145,8 @@ mach_read_from_3(
{ {
ut_ad(b); ut_ad(b);
return( ((ulint)(b[0]) << 16) return( ((ulint)(b[0]) << 16)
+ ((ulint)(b[1]) << 8) | ((ulint)(b[1]) << 8)
+ (ulint)(b[2]) | (ulint)(b[2])
); );
} }
@ -183,9 +180,9 @@ mach_read_from_4(
{ {
ut_ad(b); ut_ad(b);
return( ((ulint)(b[0]) << 24) return( ((ulint)(b[0]) << 24)
+ ((ulint)(b[1]) << 16) | ((ulint)(b[1]) << 16)
+ ((ulint)(b[2]) << 8) | ((ulint)(b[2]) << 8)
+ (ulint)(b[3]) | (ulint)(b[3])
); );
} }
@ -721,7 +718,7 @@ mach_read_from_2_little_endian(
/*===========================*/ /*===========================*/
const byte* buf) /*!< in: from where to read */ const byte* buf) /*!< in: from where to read */
{ {
return((ulint)(*buf) + ((ulint)(*(buf + 1))) * 256); return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8));
} }
/*********************************************************//** /*********************************************************//**

View file

@ -203,7 +203,7 @@ mlog_write_initial_log_record_fast(
system tablespace */ system tablespace */
if ((space == TRX_SYS_SPACE if ((space == TRX_SYS_SPACE
|| (srv_doublewrite_file && space == TRX_DOUBLEWRITE_SPACE)) || (srv_doublewrite_file && space == TRX_DOUBLEWRITE_SPACE))
&& offset >= FSP_EXTENT_SIZE && offset < 3 * FSP_EXTENT_SIZE) { && offset >= (ulint)FSP_EXTENT_SIZE && offset < 3 * (ulint)FSP_EXTENT_SIZE) {
if (trx_doublewrite_buf_is_being_created) { if (trx_doublewrite_buf_is_being_created) {
/* Do nothing: we only come to this branch in an /* Do nothing: we only come to this branch in an
InnoDB database creation. We do not redo log InnoDB database creation. We do not redo log

View file

@ -32,6 +32,11 @@ Created 9/30/1995 Heikki Tuuri
#ifdef UNIV_LINUX #ifdef UNIV_LINUX
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/shm.h> #include <sys/shm.h>
#else
# if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H
#include <sys/ipc.h>
#include <sys/shm.h>
# endif
#endif #endif
typedef void* os_process_t; typedef void* os_process_t;
@ -70,6 +75,29 @@ os_mem_free_large(
ulint size); /*!< in: size returned by ulint size); /*!< in: size returned by
os_mem_alloc_large() */ os_mem_alloc_large() */
/****************************************************************//**
Allocates or attaches and reuses shared memory segment.
The content is not cleared automatically.
@return allocated memory */
UNIV_INTERN
void*
os_shm_alloc(
/*=========*/
ulint* n, /*!< in/out: number of bytes */
uint key,
ibool* is_new);
/****************************************************************//**
Detach shared memory segment. */
UNIV_INTERN
void
os_shm_free(
/*========*/
void *ptr, /*!< in: pointer returned by
os_shm_alloc() */
ulint size); /*!< in: size returned by
os_shm_alloc() */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "os0proc.ic" #include "os0proc.ic"
#endif #endif

View file

@ -500,7 +500,7 @@ ibool
page_is_leaf( page_is_leaf(
/*=========*/ /*=========*/
const page_t* page) /*!< in: page */ const page_t* page) /*!< in: page */
__attribute__((nonnull, pure)); __attribute__((pure));
/************************************************************//** /************************************************************//**
Gets the pointer to the next record on the page. Gets the pointer to the next record on the page.
@return pointer to next record */ @return pointer to next record */

View file

@ -275,6 +275,9 @@ page_is_leaf(
/*=========*/ /*=========*/
const page_t* page) /*!< in: page */ const page_t* page) /*!< in: page */
{ {
if (!page) {
return(FALSE);
}
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL))); return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
} }

View file

@ -114,7 +114,7 @@ page_zip_compress(
const page_t* page, /*!< in: uncompressed page */ const page_t* page, /*!< in: uncompressed page */
dict_index_t* index, /*!< in: index of the B-tree node */ dict_index_t* index, /*!< in: index of the B-tree node */
mtr_t* mtr) /*!< in: mini-transaction, or NULL */ mtr_t* mtr) /*!< in: mini-transaction, or NULL */
__attribute__((nonnull(1,2,3))); __attribute__((nonnull(1,3)));
/**********************************************************************//** /**********************************************************************//**
Decompress a page. This function should tolerate errors on the compressed Decompress a page. This function should tolerate errors on the compressed

View file

@ -492,6 +492,8 @@ struct que_fork_struct{
#define QUE_NODE_CALL 31 #define QUE_NODE_CALL 31
#define QUE_NODE_EXIT 32 #define QUE_NODE_EXIT 32
#define QUE_NODE_INSERT_STATS 34
/* Query thread states */ /* Query thread states */
#define QUE_THR_RUNNING 1 #define QUE_THR_RUNNING 1
#define QUE_THR_PROCEDURE_WAIT 2 #define QUE_THR_PROCEDURE_WAIT 2

View file

@ -148,7 +148,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */ const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */
const dict_index_t* index); /*!< in: data dictionary index */ const dict_index_t* index, /*!< in: data dictionary index */
ibool* null_eq);/*!< out: set to TRUE if
found matching null values */
/*************************************************************//** /*************************************************************//**
This function is used to compare two physical records. Only the common This function is used to compare two physical records. Only the common
first fields are compared, and if an externally stored field is first fields are compared, and if an externally stored field is

View file

@ -253,15 +253,6 @@ row_table_got_default_clust_index(
/*==============================*/ /*==============================*/
const dict_table_t* table); /*!< in: table */ const dict_table_t* table); /*!< in: table */
/*********************************************************************//** /*********************************************************************//**
Calculates the key number used inside MySQL for an Innobase index. We have
to take into account if we generated a default clustered index for the table
@return the key number used inside MySQL */
UNIV_INTERN
ulint
row_get_mysql_key_number_for_index(
/*===============================*/
const dict_index_t* index); /*!< in: index */
/*********************************************************************//**
Does an update or delete of a row for MySQL. Does an update or delete of a row for MySQL.
@return error code or DB_SUCCESS */ @return error code or DB_SUCCESS */
UNIV_INTERN UNIV_INTERN
@ -273,27 +264,26 @@ row_update_for_mysql(
row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL
handle */ handle */
/*********************************************************************//** /*********************************************************************//**
This can only be used when srv_locks_unsafe_for_binlog is TRUE or This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
session is using a READ COMMITTED isolation level. Before session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
calling this function we must use trx_reset_new_rec_lock_info() and Before calling this function row_search_for_mysql() must have
trx_register_new_rec_lock() to store the information which new record locks initialized prebuilt->new_rec_locks to store the information which new
really were set. This function removes a newly set lock under prebuilt->pcur, record locks really were set. This function removes a newly set
and also under prebuilt->clust_pcur. Currently, this is only used and tested clustered index record lock under prebuilt->pcur or
in the case of an UPDATE or a DELETE statement, where the row lock is of the prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that
LOCK_X type. releases the latest clustered index record lock we set.
Thus, this implements a 'mini-rollback' that releases the latest record @return error code or DB_SUCCESS */
locks we set.
@return error code or DB_SUCCESS */
UNIV_INTERN UNIV_INTERN
int int
row_unlock_for_mysql( row_unlock_for_mysql(
/*=================*/ /*=================*/
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL
handle */ handle */
ibool has_latches_on_recs);/*!< TRUE if called so that we have ibool has_latches_on_recs);/*!< in: TRUE if called
the latches on the records under pcur so that we have the latches on
and clust_pcur, and we do not need to the records under pcur and
reposition the cursors. */ clust_pcur, and we do not need
to reposition the cursors. */
/*********************************************************************//** /*********************************************************************//**
Creates an query graph node of 'update' type to be used in the MySQL Creates an query graph node of 'update' type to be used in the MySQL
interface. interface.
@ -386,6 +376,14 @@ row_create_index_for_mysql(
then checked for not being too then checked for not being too
large. */ large. */
/*********************************************************************//** /*********************************************************************//**
*/
UNIV_INTERN
int
row_insert_stats_for_mysql(
/*=======================*/
dict_index_t* index,
trx_t* trx);
/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created. should be called after the indexes for a table have been created.
@ -403,6 +401,7 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d), FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the table2 can be written also with the
database name before it: test.table2 */ database name before it: test.table2 */
size_t sql_length, /*!< in: length of sql_string */
const char* name, /*!< in: table full name in the const char* name, /*!< in: table full name in the
normalized form normalized form
database_name/table_name */ database_name/table_name */
@ -710,18 +709,17 @@ struct row_prebuilt_struct {
ulint new_rec_locks; /*!< normally 0; if ulint new_rec_locks; /*!< normally 0; if
srv_locks_unsafe_for_binlog is srv_locks_unsafe_for_binlog is
TRUE or session is using READ TRUE or session is using READ
COMMITTED isolation level, in a COMMITTED or READ UNCOMMITTED
cursor search, if we set a new isolation level, set in
record lock on an index, this is row_search_for_mysql() if we set a new
incremented; this is used in record lock on the secondary
releasing the locks under the or clustered index; this is
cursors if we are performing an used in row_unlock_for_mysql()
UPDATE and we determine after when releasing the lock under
retrieving the row that it does the cursor if we determine
not need to be locked; thus, after retrieving the row that
these can be used to implement a it does not need to be locked
'mini-rollback' that releases ('mini-rollback') */
the latest record locks */
ulint mysql_prefix_len;/*!< byte offset of the end of ulint mysql_prefix_len;/*!< byte offset of the end of
the last requested column */ the last requested column */
ulint mysql_row_len; /*!< length in bytes of a row in the ulint mysql_row_len; /*!< length in bytes of a row in the

View file

@ -156,6 +156,8 @@ extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */
extern ulint srv_mem_pool_size; extern ulint srv_mem_pool_size;
extern ulint srv_lock_table_size; extern ulint srv_lock_table_size;
extern uint srv_buffer_pool_shm_key;
extern ibool srv_thread_concurrency_timer_based; extern ibool srv_thread_concurrency_timer_based;
extern ulint srv_n_file_io_threads; extern ulint srv_n_file_io_threads;
@ -207,6 +209,7 @@ extern ulint srv_stats_method;
#define SRV_STATS_METHOD_IGNORE_NULLS 2 #define SRV_STATS_METHOD_IGNORE_NULLS 2
extern ulint srv_stats_auto_update; extern ulint srv_stats_auto_update;
extern ulint srv_stats_update_need_lock; extern ulint srv_stats_update_need_lock;
extern ibool srv_use_sys_stats_table;
extern ibool srv_use_doublewrite_buf; extern ibool srv_use_doublewrite_buf;
extern ibool srv_use_checksums; extern ibool srv_use_checksums;
@ -367,8 +370,9 @@ enum {
when writing data files, but do flush when writing data files, but do flush
after writing to log files */ after writing to log files */
SRV_UNIX_NOSYNC, /*!< do not flush after writing */ SRV_UNIX_NOSYNC, /*!< do not flush after writing */
SRV_UNIX_O_DIRECT /*!< invoke os_file_set_nocache() on SRV_UNIX_O_DIRECT, /*!< invoke os_file_set_nocache() on
data files */ data files */
SRV_UNIX_ALL_O_DIRECT /* new method for examination: logfile also open O_DIRECT */
}; };
/** Alternatives for file i/o in Windows */ /** Alternatives for file i/o in Windows */

View file

@ -556,11 +556,12 @@ struct rw_lock_struct {
//unsigned cline:14; /*!< Line where created */ //unsigned cline:14; /*!< Line where created */
unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_s_line:14; /*!< Line number where last time s-locked */
unsigned last_x_line:14; /*!< Line number where last time x-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */
#ifdef UNIV_DEBUG
ulint magic_n; /*!< RW_LOCK_MAGIC_N */ ulint magic_n; /*!< RW_LOCK_MAGIC_N */
};
/** Value of rw_lock_struct::magic_n */ /** Value of rw_lock_struct::magic_n */
#define RW_LOCK_MAGIC_N 22643 #define RW_LOCK_MAGIC_N 22643
#endif /* UNIV_DEBUG */
};
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/** The structure for storing debug info of an rw-lock */ /** The structure for storing debug info of an rw-lock */

View file

@ -438,7 +438,7 @@ or row lock! */
#define SYNC_FILE_FORMAT_TAG 1200 /* Used to serialize access to the #define SYNC_FILE_FORMAT_TAG 1200 /* Used to serialize access to the
file format tag */ file format tag */
#define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve #define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve
this in X-mode, implicit or backround this in X-mode; implicit or backround
operations purge, rollback, foreign operations purge, rollback, foreign
key checks reserve this in S-mode */ key checks reserve this in S-mode */
#define SYNC_DICT 1000 #define SYNC_DICT 1000

View file

@ -326,6 +326,7 @@ UNIV_INTERN
void void
trx_sys_update_mysql_binlog_offset( trx_sys_update_mysql_binlog_offset(
/*===============================*/ /*===============================*/
trx_sysf_t* sys_header,
const char* file_name_in,/*!< in: MySQL log file name */ const char* file_name_in,/*!< in: MySQL log file name */
ib_int64_t offset, /*!< in: position in that log file */ ib_int64_t offset, /*!< in: position in that log file */
ulint field, /*!< in: offset of the MySQL log info field in ulint field, /*!< in: offset of the MySQL log info field in

View file

@ -497,6 +497,7 @@ struct trx_struct{
FALSE, one can save CPU time and about FALSE, one can save CPU time and about
150 bytes in the undo log size as then 150 bytes in the undo log size as then
we skip XA steps */ we skip XA steps */
ulint flush_log_at_trx_commit_session;
ulint flush_log_later;/* In 2PC, we hold the ulint flush_log_later;/* In 2PC, we hold the
prepare_commit mutex across prepare_commit mutex across
both phases. In that case, we both phases. In that case, we
@ -560,9 +561,6 @@ struct trx_struct{
/*------------------------------*/ /*------------------------------*/
void* mysql_thd; /*!< MySQL thread handle corresponding void* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */ to this trx, or NULL */
char** mysql_query_str;/* pointer to the field in mysqld_thd
which contains the pointer to the
current SQL query string */
const char* mysql_log_file_name; const char* mysql_log_file_name;
/* if MySQL binlog is used, this field /* if MySQL binlog is used, this field
contains a pointer to the latest file contains a pointer to the latest file

View file

@ -46,10 +46,10 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0 #define INNODB_VERSION_MINOR 0
#define INNODB_VERSION_BUGFIX 8 #define INNODB_VERSION_BUGFIX 10
#ifndef PERCONA_INNODB_VERSION #ifndef PERCONA_INNODB_VERSION
#define PERCONA_INNODB_VERSION 11.2 #define PERCONA_INNODB_VERSION 12.0
#endif #endif
@ -172,9 +172,9 @@ command. Not tested on Windows. */
#define UNIV_COMPILE_TEST_FUNCS #define UNIV_COMPILE_TEST_FUNCS
*/ */
#ifdef HAVE_purify #if defined HAVE_VALGRIND
# define UNIV_DEBUG_VALGRIND # define UNIV_DEBUG_VALGRIND
#endif /* HAVE_purify */ #endif /* HAVE_VALGRIND */
#if 0 #if 0
#define UNIV_DEBUG_VALGRIND /* Enable extra #define UNIV_DEBUG_VALGRIND /* Enable extra
Valgrind instrumentation */ Valgrind instrumentation */
@ -212,10 +212,6 @@ operations (very slow); also UNIV_DEBUG must be defined */
adaptive hash index */ adaptive hash index */
#define UNIV_SRV_PRINT_LATCH_WAITS /* enable diagnostic output #define UNIV_SRV_PRINT_LATCH_WAITS /* enable diagnostic output
in sync0sync.c */ in sync0sync.c */
#define UNIV_BTR_AVOID_COPY /* when splitting B-tree nodes,
do not move any records when
all the records would
be moved */
#define UNIV_BTR_PRINT /* enable functions for #define UNIV_BTR_PRINT /* enable functions for
printing B-trees */ printing B-trees */
#define UNIV_ZIP_DEBUG /* extensive consistency checks #define UNIV_ZIP_DEBUG /* extensive consistency checks
@ -305,6 +301,12 @@ management to ensure correct alignment for doubles etc. */
/* Maximum number of parallel threads in a parallelized operation */ /* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32 #define UNIV_MAX_PARALLELISM 32
/* The maximum length of a table name. This is the MySQL limit and is
defined in mysql_com.h like NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN, the
number does not include a terminating '\0'. InnoDB probably can handle
longer names internally */
#define MAX_TABLE_NAME_LEN 192
/* /*
UNIVERSAL TYPE DEFINITIONS UNIVERSAL TYPE DEFINITIONS
========================== ==========================

View file

@ -257,5 +257,48 @@ do { \
ut_a(ut_list_node_313 == NULL); \ ut_a(ut_list_node_313 == NULL); \
} while (0) } while (0)
/********************************************************************//**
Align nodes with moving location.
@param NAME the name of the list
@param TYPE node type
@param BASE base node (not a pointer to it)
@param OFFSET offset moved */
#define UT_LIST_OFFSET(NAME, TYPE, BASE, FADDR, FOFFSET, BOFFSET) \
do { \
ulint ut_list_i_313; \
TYPE* ut_list_node_313; \
\
if ((BASE).start) \
(BASE).start = ((void*)((BASE).start) \
+ (((void*)((BASE).start) > (void*)FADDR)?FOFFSET:BOFFSET));\
if ((BASE).end) \
(BASE).end = ((void*)((BASE).end) \
+ (((void*)((BASE).end) > (void*)FADDR)?FOFFSET:BOFFSET));\
\
ut_list_node_313 = (BASE).start; \
\
for (ut_list_i_313 = (BASE).count; ut_list_i_313--; ) { \
ut_a(ut_list_node_313); \
if ((ut_list_node_313->NAME).prev) \
(ut_list_node_313->NAME).prev = ((void*)((ut_list_node_313->NAME).prev)\
+ (((void*)((ut_list_node_313->NAME).prev) > (void*)FADDR)?FOFFSET:BOFFSET));\
if ((ut_list_node_313->NAME).next) \
(ut_list_node_313->NAME).next = ((void*)((ut_list_node_313->NAME).next)\
+ (((void*)((ut_list_node_313->NAME).next)> (void*)FADDR)?FOFFSET:BOFFSET));\
ut_list_node_313 = (ut_list_node_313->NAME).next; \
} \
\
ut_a(ut_list_node_313 == NULL); \
\
ut_list_node_313 = (BASE).end; \
\
for (ut_list_i_313 = (BASE).count; ut_list_i_313--; ) { \
ut_a(ut_list_node_313); \
ut_list_node_313 = (ut_list_node_313->NAME).prev; \
} \
\
ut_a(ut_list_node_313 == NULL); \
} while (0)
#endif #endif

View file

@ -1733,11 +1733,11 @@ lock_rec_create(
Enqueues a waiting request for a lock which cannot be granted immediately. Enqueues a waiting request for a lock which cannot be granted immediately.
Checks for deadlocks. Checks for deadlocks.
@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or @return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or
DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that
transaction was chosen as a victim, and we got the lock immediately: there was a deadlock, but another transaction was chosen as a victim,
no need to wait then */ and we got the lock immediately: no need to wait then */
static static
ulint enum db_err
lock_rec_enqueue_waiting( lock_rec_enqueue_waiting(
/*=====================*/ /*=====================*/
ulint type_mode,/*!< in: lock mode this ulint type_mode,/*!< in: lock mode this
@ -1811,7 +1811,7 @@ lock_rec_enqueue_waiting(
if (trx->wait_lock == NULL) { if (trx->wait_lock == NULL) {
return(DB_SUCCESS); return(DB_SUCCESS_LOCKED_REC);
} }
trx->que_state = TRX_QUE_LOCK_WAIT; trx->que_state = TRX_QUE_LOCK_WAIT;
@ -1931,6 +1931,16 @@ somebody_waits:
return(lock_rec_create(type_mode, block, heap_no, index, trx)); return(lock_rec_create(type_mode, block, heap_no, index, trx));
} }
/** Record locking request status */
enum lock_rec_req_status {
/** Failed to acquire a lock */
LOCK_REC_FAIL,
/** Succeeded in acquiring a lock (implicit or already acquired) */
LOCK_REC_SUCCESS,
/** Explicitly created a new lock */
LOCK_REC_SUCCESS_CREATED
};
/*********************************************************************//** /*********************************************************************//**
This is a fast routine for locking a record in the most common cases: This is a fast routine for locking a record in the most common cases:
there are no explicit locks on the page, or there is just one lock, owned there are no explicit locks on the page, or there is just one lock, owned
@ -1938,9 +1948,9 @@ by this transaction, and of the right type_mode. This is a low-level function
which does NOT look at implicit locks! Checks lock compatibility within which does NOT look at implicit locks! Checks lock compatibility within
explicit locks. This function sets a normal next-key lock, or in the case of explicit locks. This function sets a normal next-key lock, or in the case of
a page supremum record, a gap type lock. a page supremum record, a gap type lock.
@return TRUE if locking succeeded */ @return whether the locking succeeded */
UNIV_INLINE UNIV_INLINE
ibool enum lock_rec_req_status
lock_rec_lock_fast( lock_rec_lock_fast(
/*===============*/ /*===============*/
ibool impl, /*!< in: if TRUE, no lock is set ibool impl, /*!< in: if TRUE, no lock is set
@ -1979,19 +1989,19 @@ lock_rec_lock_fast(
lock_rec_create(mode, block, heap_no, index, trx); lock_rec_create(mode, block, heap_no, index, trx);
} }
return(TRUE); return(LOCK_REC_SUCCESS_CREATED);
} }
if (lock_rec_get_next_on_page(lock)) { if (lock_rec_get_next_on_page(lock)) {
return(FALSE); return(LOCK_REC_FAIL);
} }
if (lock->trx != trx if (lock->trx != trx
|| lock->type_mode != (mode | LOCK_REC) || lock->type_mode != (mode | LOCK_REC)
|| lock_rec_get_n_bits(lock) <= heap_no) { || lock_rec_get_n_bits(lock) <= heap_no) {
return(FALSE); return(LOCK_REC_FAIL);
} }
if (!impl) { if (!impl) {
@ -2000,10 +2010,11 @@ lock_rec_lock_fast(
if (!lock_rec_get_nth_bit(lock, heap_no)) { if (!lock_rec_get_nth_bit(lock, heap_no)) {
lock_rec_set_nth_bit(lock, heap_no); lock_rec_set_nth_bit(lock, heap_no);
return(LOCK_REC_SUCCESS_CREATED);
} }
} }
return(TRUE); return(LOCK_REC_SUCCESS);
} }
/*********************************************************************//** /*********************************************************************//**
@ -2011,9 +2022,10 @@ This is the general, and slower, routine for locking a record. This is a
low-level function which does NOT look at implicit locks! Checks lock low-level function which does NOT look at implicit locks! Checks lock
compatibility within explicit locks. This function sets a normal next-key compatibility within explicit locks. This function sets a normal next-key
lock, or in the case of a page supremum record, a gap type lock. lock, or in the case of a page supremum record, a gap type lock.
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
static static
ulint enum db_err
lock_rec_lock_slow( lock_rec_lock_slow(
/*===============*/ /*===============*/
ibool impl, /*!< in: if TRUE, no lock is set ibool impl, /*!< in: if TRUE, no lock is set
@ -2030,7 +2042,6 @@ lock_rec_lock_slow(
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
trx_t* trx; trx_t* trx;
ulint err;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_ad((LOCK_MODE_MASK & mode) != LOCK_S ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
@ -2049,27 +2060,23 @@ lock_rec_lock_slow(
/* The trx already has a strong enough lock on rec: do /* The trx already has a strong enough lock on rec: do
nothing */ nothing */
err = DB_SUCCESS;
} else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) { } else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
/* If another transaction has a non-gap conflicting request in /* If another transaction has a non-gap conflicting request in
the queue, as this transaction does not have a lock strong the queue, as this transaction does not have a lock strong
enough already granted on the record, we have to wait. */ enough already granted on the record, we have to wait. */
err = lock_rec_enqueue_waiting(mode, block, heap_no, return(lock_rec_enqueue_waiting(mode, block, heap_no,
index, thr); index, thr));
} else { } else if (!impl) {
if (!impl) { /* Set the requested lock on the record */
/* Set the requested lock on the record */
lock_rec_add_to_queue(LOCK_REC | mode, block, lock_rec_add_to_queue(LOCK_REC | mode, block,
heap_no, index, trx); heap_no, index, trx);
} return(DB_SUCCESS_LOCKED_REC);
err = DB_SUCCESS;
} }
return(err); return(DB_SUCCESS);
} }
/*********************************************************************//** /*********************************************************************//**
@ -2078,9 +2085,10 @@ possible, enqueues a waiting lock request. This is a low-level function
which does NOT look at implicit locks! Checks lock compatibility within which does NOT look at implicit locks! Checks lock compatibility within
explicit locks. This function sets a normal next-key lock, or in the case explicit locks. This function sets a normal next-key lock, or in the case
of a page supremum record, a gap type lock. of a page supremum record, a gap type lock.
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
static static
ulint enum db_err
lock_rec_lock( lock_rec_lock(
/*==========*/ /*==========*/
ibool impl, /*!< in: if TRUE, no lock is set ibool impl, /*!< in: if TRUE, no lock is set
@ -2096,8 +2104,6 @@ lock_rec_lock(
dict_index_t* index, /*!< in: index of record */ dict_index_t* index, /*!< in: index of record */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_ad((LOCK_MODE_MASK & mode) != LOCK_S ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
|| lock_table_has(thr_get_trx(thr), index->table, LOCK_IS)); || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
@ -2109,18 +2115,20 @@ lock_rec_lock(
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0); || mode - (LOCK_MODE_MASK & mode) == 0);
if (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) { /* We try a simplified and faster subroutine for the most
common cases */
/* We try a simplified and faster subroutine for the most switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
common cases */ case LOCK_REC_SUCCESS:
return(DB_SUCCESS);
err = DB_SUCCESS; case LOCK_REC_SUCCESS_CREATED:
} else { return(DB_SUCCESS_LOCKED_REC);
err = lock_rec_lock_slow(impl, mode, block, case LOCK_REC_FAIL:
heap_no, index, thr); return(lock_rec_lock_slow(impl, mode, block,
heap_no, index, thr));
} }
return(err); ut_error;
return(DB_ERROR);
} }
/*********************************************************************//** /*********************************************************************//**
@ -3948,8 +3956,8 @@ lock_rec_unlock(
const rec_t* rec, /*!< in: record */ const rec_t* rec, /*!< in: record */
enum lock_mode lock_mode)/*!< in: LOCK_S or LOCK_X */ enum lock_mode lock_mode)/*!< in: LOCK_S or LOCK_X */
{ {
lock_t* first_lock;
lock_t* lock; lock_t* lock;
lock_t* release_lock = NULL;
ulint heap_no; ulint heap_no;
ut_ad(trx && rec); ut_ad(trx && rec);
@ -3959,48 +3967,40 @@ lock_rec_unlock(
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
lock = lock_rec_get_first(block, heap_no); first_lock = lock_rec_get_first(block, heap_no);
/* Find the last lock with the same lock_mode and transaction /* Find the last lock with the same lock_mode and transaction
from the record. */ from the record. */
while (lock != NULL) { for (lock = first_lock; lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
if (lock->trx == trx && lock_get_mode(lock) == lock_mode) { if (lock->trx == trx && lock_get_mode(lock) == lock_mode) {
release_lock = lock;
ut_a(!lock_get_wait(lock)); ut_a(!lock_get_wait(lock));
lock_rec_reset_nth_bit(lock, heap_no);
goto released;
} }
lock = lock_rec_get_next(heap_no, lock);
} }
/* If a record lock is found, release the record lock */ mutex_exit(&kernel_mutex);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: unlock row could not"
" find a %lu mode lock on the record\n",
(ulong) lock_mode);
if (UNIV_LIKELY(release_lock != NULL)) { return;
lock_rec_reset_nth_bit(release_lock, heap_no);
} else {
mutex_exit(&kernel_mutex);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: unlock row could not"
" find a %lu mode lock on the record\n",
(ulong) lock_mode);
return;
}
released:
/* Check if we can now grant waiting lock requests */ /* Check if we can now grant waiting lock requests */
lock = lock_rec_get_first(block, heap_no); for (lock = first_lock; lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
while (lock != NULL) {
if (lock_get_wait(lock) if (lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) { && !lock_rec_has_to_wait_in_queue(lock)) {
/* Grant the lock */ /* Grant the lock */
lock_grant(lock); lock_grant(lock);
} }
lock = lock_rec_get_next(heap_no, lock);
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
@ -5095,7 +5095,14 @@ lock_rec_insert_check_and_lock(
lock_mutex_exit_kernel(); lock_mutex_exit_kernel();
if ((err == DB_SUCCESS) && !dict_index_is_clust(index)) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
/* fall through */
case DB_SUCCESS:
if (dict_index_is_clust(index)) {
break;
}
/* Update the page max trx id field */ /* Update the page max trx id field */
page_update_max_trx_id(block, page_update_max_trx_id(block,
buf_block_get_page_zip(block), buf_block_get_page_zip(block),
@ -5218,6 +5225,10 @@ lock_clust_rec_modify_check_and_lock(
ut_ad(lock_rec_queue_validate(block, rec, index, offsets)); ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) {
err = DB_SUCCESS;
}
return(err); return(err);
} }
@ -5284,22 +5295,27 @@ lock_sec_rec_modify_check_and_lock(
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
if (err == DB_SUCCESS) { if (err == DB_SUCCESS || err == DB_SUCCESS_LOCKED_REC) {
/* Update the page max trx id field */ /* Update the page max trx id field */
/* It might not be necessary to do this if
err == DB_SUCCESS (no new lock created),
but it should not cost too much performance. */
page_update_max_trx_id(block, page_update_max_trx_id(block,
buf_block_get_page_zip(block), buf_block_get_page_zip(block),
thr_get_trx(thr)->id, mtr); thr_get_trx(thr)->id, mtr);
err = DB_SUCCESS;
} }
return(err); return(err);
} }
/*********************************************************************//** /*********************************************************************//**
Like the counterpart for a clustered index below, but now we read a Like lock_clust_rec_read_check_and_lock(), but reads a
secondary index record. secondary index record.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
UNIV_INTERN UNIV_INTERN
ulint enum db_err
lock_sec_rec_read_check_and_lock( lock_sec_rec_read_check_and_lock(
/*=============================*/ /*=============================*/
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG
@ -5320,8 +5336,8 @@ lock_sec_rec_read_check_and_lock(
LOCK_REC_NOT_GAP */ LOCK_REC_NOT_GAP */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err; enum db_err err;
ulint heap_no; ulint heap_no;
ut_ad(!dict_index_is_clust(index)); ut_ad(!dict_index_is_clust(index));
ut_ad(block->frame == page_align(rec)); ut_ad(block->frame == page_align(rec));
@ -5372,9 +5388,10 @@ if the query thread should anyway be suspended for some reason; if not, then
puts the transaction and the query thread to the lock wait state and inserts a puts the transaction and the query thread to the lock wait state and inserts a
waiting request for a record lock to the lock queue. Sets the requested mode waiting request for a record lock to the lock queue. Sets the requested mode
lock on the record. lock on the record.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
or DB_QUE_THR_SUSPENDED */
UNIV_INTERN UNIV_INTERN
ulint enum db_err
lock_clust_rec_read_check_and_lock( lock_clust_rec_read_check_and_lock(
/*===============================*/ /*===============================*/
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG
@ -5395,8 +5412,8 @@ lock_clust_rec_read_check_and_lock(
LOCK_REC_NOT_GAP */ LOCK_REC_NOT_GAP */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err; enum db_err err;
ulint heap_no; ulint heap_no;
ut_ad(dict_index_is_clust(index)); ut_ad(dict_index_is_clust(index));
ut_ad(block->frame == page_align(rec)); ut_ad(block->frame == page_align(rec));
@ -5467,17 +5484,22 @@ lock_clust_rec_read_check_and_lock_alt(
mem_heap_t* tmp_heap = NULL; mem_heap_t* tmp_heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_; ulint* offsets = offsets_;
ulint ret; ulint err;
rec_offs_init(offsets_); rec_offs_init(offsets_);
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &tmp_heap); ULINT_UNDEFINED, &tmp_heap);
ret = lock_clust_rec_read_check_and_lock(flags, block, rec, index, err = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
offsets, mode, gap_mode, thr); offsets, mode, gap_mode, thr);
if (tmp_heap) { if (tmp_heap) {
mem_heap_free(tmp_heap); mem_heap_free(tmp_heap);
} }
return(ret);
if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) {
err = DB_SUCCESS;
}
return(err);
} }
/*******************************************************************//** /*******************************************************************//**

View file

@ -1111,6 +1111,7 @@ log_io_complete(
group = (log_group_t*)((ulint)group - 1); group = (log_group_t*)((ulint)group - 1);
if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
&& srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
fil_flush(group->space_id); fil_flush(group->space_id);
@ -1132,6 +1133,7 @@ log_io_complete(
logs and cannot end up here! */ logs and cannot end up here! */
if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
&& srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
&& srv_flush_log_at_trx_commit != 2) { && srv_flush_log_at_trx_commit != 2) {
@ -1512,7 +1514,8 @@ loop:
mutex_exit(&(log_sys->mutex)); mutex_exit(&(log_sys->mutex));
if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC
|| srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
/* O_DSYNC means the OS did not buffer the log file at all: /* O_DSYNC means the OS did not buffer the log file at all:
so we have also flushed to disk what we have written */ so we have also flushed to disk what we have written */

View file

@ -2965,9 +2965,12 @@ recv_recovery_from_checkpoint_start_func(
ib_uint64_t contiguous_lsn; ib_uint64_t contiguous_lsn;
ib_uint64_t archived_lsn; ib_uint64_t archived_lsn;
byte* buf; byte* buf;
byte log_hdr_buf[LOG_FILE_HDR_SIZE]; byte* log_hdr_buf;
byte log_hdr_buf_base[LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE];
ulint err; ulint err;
log_hdr_buf = ut_align(log_hdr_buf_base, OS_FILE_LOG_BLOCK_SIZE);
#ifdef UNIV_LOG_ARCHIVE #ifdef UNIV_LOG_ARCHIVE
ut_ad(type != LOG_CHECKPOINT || limit_lsn == IB_ULONGLONG_MAX); ut_ad(type != LOG_CHECKPOINT || limit_lsn == IB_ULONGLONG_MAX);
/** TRUE when recovering from a checkpoint */ /** TRUE when recovering from a checkpoint */
@ -3325,7 +3328,6 @@ recv_recovery_from_checkpoint_finish(void)
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
if (recv_needed_recovery && srv_recovery_stats) { if (recv_needed_recovery && srv_recovery_stats) {
FILE* file = stderr;
ulint i; ulint i;
fprintf(stderr, fprintf(stderr,

View file

@ -214,7 +214,7 @@ static os_aio_array_t* os_aio_sync_array = NULL; /*!< Synchronous I/O */
/* Per thread buffer used for merged IO requests. Used by /* Per thread buffer used for merged IO requests. Used by
os_aio_simulated_handle so that a buffer doesn't have to be allocated os_aio_simulated_handle so that a buffer doesn't have to be allocated
for each request. */ for each request. */
static char* os_aio_thread_buffer[SRV_MAX_N_IO_THREADS]; static byte* os_aio_thread_buffer[SRV_MAX_N_IO_THREADS];
static ulint os_aio_thread_buffer_size[SRV_MAX_N_IO_THREADS]; static ulint os_aio_thread_buffer_size[SRV_MAX_N_IO_THREADS];
/** Number of asynchronous I/O segments. Set by os_aio_init(). */ /** Number of asynchronous I/O segments. Set by os_aio_init(). */
@ -1379,7 +1379,11 @@ try_again:
/* When srv_file_per_table is on, file creation failure may not /* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in be critical to the whole instance. Do not crash the server in
case of unknown errors. */ case of unknown errors.
Please note "srv_file_per_table" is a global variable with
no explicit synchronization protection. It could be
changed during this execution path. It might not have the
same value as the one when building the table definition */
if (srv_file_per_table) { if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name, retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ? create_mode == OS_FILE_CREATE ?
@ -1466,7 +1470,11 @@ try_again:
/* When srv_file_per_table is on, file creation failure may not /* When srv_file_per_table is on, file creation failure may not
be critical to the whole instance. Do not crash the server in be critical to the whole instance. Do not crash the server in
case of unknown errors. */ case of unknown errors.
Please note "srv_file_per_table" is a global variable with
no explicit synchronization protection. It could be
changed during this execution path. It might not have the
same value as the one when building the table definition */
if (srv_file_per_table) { if (srv_file_per_table) {
retry = os_file_handle_error_no_exit(name, retry = os_file_handle_error_no_exit(name,
create_mode == OS_FILE_CREATE ? create_mode == OS_FILE_CREATE ?
@ -1494,6 +1502,11 @@ try_again:
os_file_set_nocache(file, name, mode_str); os_file_set_nocache(file, name, mode_str);
} }
/* ALL_O_DIRECT: O_DIRECT also for transaction log file */
if (srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
os_file_set_nocache(file, name, mode_str);
}
#ifdef USE_FILE_LOCK #ifdef USE_FILE_LOCK
if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) { if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) {

View file

@ -229,3 +229,173 @@ os_mem_free_large(
} }
#endif #endif
} }
/****************************************************************//**
Allocates or attaches and reuses shared memory segment.
The content is not cleared automatically.
@return allocated memory */
UNIV_INTERN
void*
os_shm_alloc(
/*=========*/
ulint* n, /*!< in/out: number of bytes */
uint key,
ibool* is_new)
{
void* ptr;
ulint size;
int shmid;
*is_new = FALSE;
#if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H
fprintf(stderr,
"InnoDB: The shared memory key %#x (%d) is specified.\n",
key, key);
# if defined HAVE_LARGE_PAGES && defined UNIV_LINUX
if (!os_use_large_pages || !os_large_page_size) {
goto skip;
}
/* Align block size to os_large_page_size */
ut_ad(ut_is_2pow(os_large_page_size));
size = ut_2pow_round(*n + (os_large_page_size - 1),
os_large_page_size);
shmid = shmget((key_t)key, (size_t)size,
IPC_CREAT | IPC_EXCL | SHM_HUGETLB | SHM_R | SHM_W);
if (shmid < 0) {
if (errno == EEXIST) {
fprintf(stderr,
"InnoDB: HugeTLB: The shared memory segment seems to exist already.\n");
shmid = shmget((key_t)key, (size_t)size,
SHM_HUGETLB | SHM_R | SHM_W);
if (shmid < 0) {
fprintf(stderr,
"InnoDB: HugeTLB: Warning: Failed to allocate %lu bytes.(reuse) errno %d\n",
size, errno);
goto skip;
} else {
fprintf(stderr,
"InnoDB: HugeTLB: The existent shared memory segment is used.\n");
}
} else {
fprintf(stderr,
"InnoDB: HugeTLB: Warning: Failed to allocate %lu bytes.(new) errno %d\n",
size, errno);
goto skip;
}
} else {
*is_new = TRUE;
fprintf(stderr,
"InnoDB: HugeTLB: The new shared memory segment is created.\n");
}
ptr = shmat(shmid, NULL, 0);
if (ptr == (void *)-1) {
fprintf(stderr,
"InnoDB: HugeTLB: Warning: Failed to attach shared memory segment, errno %d\n",
errno);
ptr = NULL;
}
if (ptr) {
*n = size;
os_fast_mutex_lock(&ut_list_mutex);
ut_total_allocated_memory += size;
os_fast_mutex_unlock(&ut_list_mutex);
UNIV_MEM_ALLOC(ptr, size);
return(ptr);
}
skip:
*is_new = FALSE;
# endif /* HAVE_LARGE_PAGES && defined UNIV_LINUX */
# ifdef HAVE_GETPAGESIZE
size = getpagesize();
# else
size = UNIV_PAGE_SIZE;
# endif
/* Align block size to system page size */
ut_ad(ut_is_2pow(size));
size = *n = ut_2pow_round(*n + (size - 1), size);
shmid = shmget((key_t)key, (size_t)size,
IPC_CREAT | IPC_EXCL | SHM_R | SHM_W);
if (shmid < 0) {
if (errno == EEXIST) {
fprintf(stderr,
"InnoDB: The shared memory segment seems to exist already.\n");
shmid = shmget((key_t)key, (size_t)size,
SHM_R | SHM_W);
if (shmid < 0) {
fprintf(stderr,
"InnoDB: Warning: Failed to allocate %lu bytes.(reuse) errno %d\n",
size, errno);
ptr = NULL;
goto end;
} else {
fprintf(stderr,
"InnoDB: The existent shared memory segment is used.\n");
}
} else {
fprintf(stderr,
"InnoDB: Warning: Failed to allocate %lu bytes.(new) errno %d\n",
size, errno);
ptr = NULL;
goto end;
}
} else {
*is_new = TRUE;
fprintf(stderr,
"InnoDB: The new shared memory segment is created.\n");
}
ptr = shmat(shmid, NULL, 0);
if (ptr == (void *)-1) {
fprintf(stderr,
"InnoDB: Warning: Failed to attach shared memory segment, errno %d\n",
errno);
ptr = NULL;
}
if (ptr) {
*n = size;
os_fast_mutex_lock(&ut_list_mutex);
ut_total_allocated_memory += size;
os_fast_mutex_unlock(&ut_list_mutex);
UNIV_MEM_ALLOC(ptr, size);
}
end:
#else /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */
fprintf(stderr, "InnoDB: shared memory segment is not supported.\n");
ptr = NULL;
#endif /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */
return(ptr);
}
/****************************************************************//**
Detach shared memory segment. */
UNIV_INTERN
void
os_shm_free(
/*========*/
void *ptr, /*!< in: pointer returned by
os_shm_alloc() */
ulint size) /*!< in: size returned by
os_shm_alloc() */
{
os_fast_mutex_lock(&ut_list_mutex);
ut_a(ut_total_allocated_memory >= size);
os_fast_mutex_unlock(&ut_list_mutex);
#if defined HAVE_SYS_IPC_H && HAVE_SYS_SHM_H
if (!shmdt(ptr)) {
os_fast_mutex_lock(&ut_list_mutex);
ut_a(ut_total_allocated_memory >= size);
ut_total_allocated_memory -= size;
os_fast_mutex_unlock(&ut_list_mutex);
UNIV_MEM_FREE(ptr, size);
}
#else /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */
fprintf(stderr, "InnoDB: shared memory segment is not supported.\n");
#endif /* HAVE_SYS_IPC_H && HAVE_SYS_SHM_H */
}

View file

@ -571,7 +571,7 @@ page_zip_dir_encode(
/* Traverse the list of stored records in the collation order, /* Traverse the list of stored records in the collation order,
starting from the first user record. */ starting from the first user record. */
rec = page + PAGE_NEW_INFIMUM, TRUE; rec = page + PAGE_NEW_INFIMUM;
i = 0; i = 0;
@ -1153,6 +1153,10 @@ page_zip_compress(
FILE* logfile = NULL; FILE* logfile = NULL;
#endif #endif
if (!page) {
return(FALSE);
}
ut_a(page_is_comp(page)); ut_a(page_is_comp(page));
ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(page_simple_validate_new((page_t*) page)); ut_ad(page_simple_validate_new((page_t*) page));
@ -1464,6 +1468,7 @@ page_zip_fields_free(
dict_table_t* table = index->table; dict_table_t* table = index->table;
mem_heap_free(index->heap); mem_heap_free(index->heap);
mutex_free(&(table->autoinc_mutex)); mutex_free(&(table->autoinc_mutex));
ut_free(table->name);
mem_heap_free(table->heap); mem_heap_free(table->heap);
} }
} }
@ -3117,8 +3122,13 @@ page_zip_validate_low(
temp_page_zip in a debugger when running valgrind --db-attach. */ temp_page_zip in a debugger when running valgrind --db-attach. */
VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE); VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE);
UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE); UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
# if UNIV_WORD_SIZE == 4
VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip); VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip);
/* On 32-bit systems, there is no padding in page_zip_des_t.
On other systems, Valgrind could complain about uninitialized
pad bytes. */
UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip); UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip);
# endif
VALGRIND_GET_VBITS(page_zip->data, temp_page, VALGRIND_GET_VBITS(page_zip->data, temp_page,
page_zip_get_size(page_zip)); page_zip_get_size(page_zip));
UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));

View file

@ -0,0 +1 @@
--innodb_buffer_pool_shm_key=123456

View file

@ -0,0 +1,6 @@
show variables like 'innodb_buffer_pool_shm%';
Variable_name Value
innodb_buffer_pool_shm_key 123456
show variables like 'innodb_buffer_pool_shm%';
Variable_name Value
innodb_buffer_pool_shm_key 123456

View file

@ -0,0 +1,18 @@
--source include/have_innodb.inc
show variables like 'innodb_buffer_pool_shm%';
#clean shutdown (restart_mysqld.inc is not clean if over 10 sec...)
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
wait
EOF
shutdown_server 120;
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
restart
EOF
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect
show variables like 'innodb_buffer_pool_shm%';
--sleep 1
--system ipcrm -M 123456

View file

@ -0,0 +1 @@
--innodb_use_sys_stats_table

View file

@ -0,0 +1,3 @@
show variables like 'innodb_use_sys_stats%';
Variable_name Value
innodb_use_sys_stats_table ON

View file

@ -0,0 +1,2 @@
--source include/have_innodb.inc
show variables like 'innodb_use_sys_stats%';

View file

@ -0,0 +1 @@
--log-error

View file

@ -0,0 +1,15 @@
SET @old_max_connections = @@max_connections;
SET @old_log_warnings = @@log_warnings;
SET GLOBAL max_connections=2;
SET GLOBAL LOG_WARNINGS = 0;
connect(localhost,root,,test,port,socket);
ERROR HY000: Too many connections
SET GLOBAL LOG_WARNINGS = 1;
connect(localhost,root,,test,port,socket);
ERROR HY000: Too many connections
SET GLOBAL LOG_WARNINGS = 0;
connect(localhost,root,,test,port,socket);
ERROR HY000: Too many connections
SET GLOBAL max_connections = @old_max_connections;
SET GLOBAL log_warnings = @old_log_warnings;
1

View file

@ -0,0 +1,52 @@
--source include/not_embedded.inc
connect (main,localhost,root,,);
connection main;
SET @old_max_connections = @@max_connections;
SET @old_log_warnings = @@log_warnings;
SET GLOBAL max_connections=2;
let $port=`SELECT Variable_value FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name LIKE 'port'`;
let $socket=`SELECT Variable_value FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name LIKE 'socket'`;
SET GLOBAL LOG_WARNINGS = 0;
--connect (conn0,localhost,root,,)
connection conn0;
replace_result $port port $socket socket;
--error 1040
--connect(conn1,localhost,root,,)
disconnect conn0;
SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right
connection main;
SET GLOBAL LOG_WARNINGS = 1;
--connect (conn1,localhost,root,,)
replace_result $port port $socket socket;
--error 1040
--connect (conn0,localhost,root,,)
disconnect conn1;
SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right
connection main;
SET GLOBAL LOG_WARNINGS = 0;
--connect (conn0,localhost,root,,)
replace_result $port port $socket socket;
--error 1040
--connect(conn1,localhost,root,,)
disconnect conn0;
SLEEP 0.1; # tsarev: hack, but i don't know (and didn't find) how right
connection main;
SET GLOBAL max_connections = @old_max_connections;
SET GLOBAL log_warnings = @old_log_warnings;
let $log_error_= `SELECT @@GLOBAL.log_error`;
if(!`select LENGTH('$log_error_')`)
{
# MySQL Server on windows is started with --console and thus
# does not know the location of its .err log, use default location
let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err;
}
# Assign env variable LOG_ERROR
let LOG_ERROR=$log_error_;
let cmd=cat $log_error | grep "Too many connections" | wc -l;
exec $cmd;

View file

@ -0,0 +1,60 @@
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
DROP TABLE IF EXISTS t;
CREATE TABLE t(id INT);
SELECT * from t;
id
SELECT * from t;
id
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
Warnings:
Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 10
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=ON;
INSERT INTO t VALUES(0);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
0
INSERT INTO t VALUES(1);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
0
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
2
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
3
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
FLUSH QUERY_RESPONSE_TIME;
INSERT INTO t VALUES(0);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
0
INSERT INTO t VALUES(1);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
0
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
2
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count)
3
DROP TABLE IF EXISTS t;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=OFF;

View file

@ -0,0 +1,52 @@
--source include/master-slave.inc
connection master;
-- disable_warnings
DROP TABLE IF EXISTS t;
-- enable_warnings
CREATE TABLE t(id INT);
SELECT * from t;
sync_slave_with_master;
connection slave;
SELECT * from t;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=ON;
connection master;
INSERT INTO t VALUES(0);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
INSERT INTO t VALUES(1);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
sync_slave_with_master;
connection slave;
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
connection master;
INSERT INTO t VALUES(0);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
INSERT INTO t VALUES(1);
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
sync_slave_with_master;
connection slave;
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SELECT SUM(INFORMATION_SCHEMA.QUERY_RESPONSE_TIME.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
connection master;
DROP TABLE IF EXISTS t;
sync_slave_with_master;
connection slave;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=OFF;

View file

@ -0,0 +1,310 @@
CREATE FUNCTION test_f()
RETURNS CHAR(30) DETERMINISTIC
BEGIN
DECLARE first VARCHAR(5);
DECLARE second VARCHAR(5);
DECLARE result VARCHAR(20);
SELECT SLEEP(1.11) INTO first;
SET first= 'Hello';
SET second=', ';
SET result= CONCAT(first,second);
SET result= CONCAT(result,'world!');
RETURN result;
END/
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
Warnings:
Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
FLUSH QUERY_RESPONSE_TIME;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
44
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000003
0.000007
0.000015
0.000030
0.000061
0.000122
0.000244
0.000488
0.000976
0.001953
0.003906
0.007812
0.015625
0.031250
0.062500
0.125000
0.250000
0.500000
1.000000
2.000000
4.000000
8.000000
16.000000
32.000000
64.000000
128.000000
256.000000
512.000000
1024.000000
2048.000000
4096.000000
8192.000000
16384.000000
32768.000000
65536.000000
131072.000000
262144.000000
524288.000000
1048576.00000
2097152.00000
4194304.00000
8388608.00000
TOO LONG QUERY
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
test_f()
Hello, world!
SELECT test_f();
test_f()
Hello, world!
SELECT test_f();
test_f()
Hello, world!
SELECT test_f();
test_f()
Hello, world!
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 5 2 44
4 5 2 44
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
44
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000003
0.000007
0.000015
0.000030
0.000061
0.000122
0.000244
0.000488
0.000976
0.001953
0.003906
0.007812
0.015625
0.031250
0.062500
0.125000
0.250000
0.500000
1.000000
2.000000
4.000000
8.000000
16.000000
32.000000
64.000000
128.000000
256.000000
512.000000
1024.000000
2048.000000
4096.000000
8192.000000
16384.000000
32768.000000
65536.000000
131072.000000
262144.000000
524288.000000
1048576.00000
2097152.00000
4194304.00000
8388608.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 10
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
test_f()
Hello, world!
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 2 2 14
1 2 2 14
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
14
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000010
0.000100
0.001000
0.010000
0.100000
1.000000
10.000000
100.000000
1000.000000
10000.000000
100000.000000
1000000.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 10
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 7
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
test_f()
Hello, world!
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 2 2 17
1 2 2 17
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
17
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000008
0.000059
0.000416
0.002915
0.020408
0.142857
1.000000
7.000000
49.000000
343.000000
2401.000000
16807.000000
117649.000000
823543.000000
5764801.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 7
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 156
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
test_f()
Hello, world!
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 2 2 7
1 2 2 7
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
7
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000041
0.006410
1.000000
156.000000
24336.000000
3796416.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 156
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
test_f()
Hello, world!
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 2 2 6
1 2 2 6
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
6
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.001000
1.000000
1000.000000
1000000.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001;
Warnings:
Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10;
DROP FUNCTION test_f;

View file

@ -0,0 +1,87 @@
source include/have_innodb.inc;
delimiter /;
CREATE FUNCTION test_f()
RETURNS CHAR(30) DETERMINISTIC
BEGIN
DECLARE first VARCHAR(5);
DECLARE second VARCHAR(5);
DECLARE result VARCHAR(20);
SELECT SLEEP(1.11) INTO first;
SET first= 'Hello';
SET second=', ';
SET result= CONCAT(first,second);
SET result= CONCAT(result,'world!');
RETURN result;
END/
delimiter ;/
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
source include/percona_query_response_time_show.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
SELECT test_f();
SELECT test_f();
SELECT test_f();
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT test_f();
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10;
DROP FUNCTION test_f;

View file

@ -0,0 +1,564 @@
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
Warnings:
Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
FLUSH QUERY_RESPONSE_TIME;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
44
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000003
0.000007
0.000015
0.000030
0.000061
0.000122
0.000244
0.000488
0.000976
0.001953
0.003906
0.007812
0.015625
0.031250
0.062500
0.125000
0.250000
0.500000
1.000000
2.000000
4.000000
8.000000
16.000000
32.000000
64.000000
128.000000
256.000000
512.000000
1024.000000
2048.000000
4096.000000
8192.000000
16384.000000
32768.000000
65536.000000
131072.000000
262144.000000
524288.000000
1048576.00000
2097152.00000
4194304.00000
8388608.00000
TOO LONG QUERY
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT SLEEP(0.31);
SLEEP(0.31)
0
SELECT SLEEP(0.32);
SLEEP(0.32)
0
SELECT SLEEP(0.33);
SLEEP(0.33)
0
SELECT SLEEP(0.34);
SLEEP(0.34)
0
SELECT SLEEP(0.35);
SLEEP(0.35)
0
SELECT SLEEP(0.36);
SLEEP(0.36)
0
SELECT SLEEP(0.37);
SLEEP(0.37)
0
SELECT SLEEP(0.38);
SLEEP(0.38)
0
SELECT SLEEP(0.39);
SLEEP(0.39)
0
SELECT SLEEP(0.40);
SLEEP(0.40)
0
SELECT SLEEP(1.1);
SLEEP(1.1)
0
SELECT SLEEP(1.2);
SLEEP(1.2)
0
SELECT SLEEP(1.3);
SLEEP(1.3)
0
SELECT SLEEP(1.5);
SLEEP(1.5)
0
SELECT SLEEP(1.4);
SLEEP(1.4)
0
SELECT SLEEP(0.5);
SLEEP(0.5)
0
SELECT SLEEP(2.1);
SLEEP(2.1)
0
SELECT SLEEP(2.3);
SLEEP(2.3)
0
SELECT SLEEP(2.5);
SLEEP(2.5)
0
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 20 5 44
10 20 5 44
1 20 5 44
5 20 5 44
3 20 5 44
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
44
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000003
0.000007
0.000015
0.000030
0.000061
0.000122
0.000244
0.000488
0.000976
0.001953
0.003906
0.007812
0.015625
0.031250
0.062500
0.125000
0.250000
0.500000
1.000000
2.000000
4.000000
8.000000
16.000000
32.000000
64.000000
128.000000
256.000000
512.000000
1024.000000
2048.000000
4096.000000
8192.000000
16384.000000
32768.000000
65536.000000
131072.000000
262144.000000
524288.000000
1048576.00000
2097152.00000
4194304.00000
8388608.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 2
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 10
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT SLEEP(0.31);
SLEEP(0.31)
0
SELECT SLEEP(0.32);
SLEEP(0.32)
0
SELECT SLEEP(0.33);
SLEEP(0.33)
0
SELECT SLEEP(0.34);
SLEEP(0.34)
0
SELECT SLEEP(0.35);
SLEEP(0.35)
0
SELECT SLEEP(0.36);
SLEEP(0.36)
0
SELECT SLEEP(0.37);
SLEEP(0.37)
0
SELECT SLEEP(0.38);
SLEEP(0.38)
0
SELECT SLEEP(0.39);
SLEEP(0.39)
0
SELECT SLEEP(0.40);
SLEEP(0.40)
0
SELECT SLEEP(1.1);
SLEEP(1.1)
0
SELECT SLEEP(1.2);
SLEEP(1.2)
0
SELECT SLEEP(1.3);
SLEEP(1.3)
0
SELECT SLEEP(1.5);
SLEEP(1.5)
0
SELECT SLEEP(1.4);
SLEEP(1.4)
0
SELECT SLEEP(0.5);
SLEEP(0.5)
0
SELECT SLEEP(2.1);
SLEEP(2.1)
0
SELECT SLEEP(2.3);
SLEEP(2.3)
0
SELECT SLEEP(2.5);
SLEEP(2.5)
0
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 20 3 14
11 20 3 14
8 20 3 14
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
14
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000010
0.000100
0.001000
0.010000
0.100000
1.000000
10.000000
100.000000
1000.000000
10000.000000
100000.000000
1000000.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 10
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 7
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT SLEEP(0.31);
SLEEP(0.31)
0
SELECT SLEEP(0.32);
SLEEP(0.32)
0
SELECT SLEEP(0.33);
SLEEP(0.33)
0
SELECT SLEEP(0.34);
SLEEP(0.34)
0
SELECT SLEEP(0.35);
SLEEP(0.35)
0
SELECT SLEEP(0.36);
SLEEP(0.36)
0
SELECT SLEEP(0.37);
SLEEP(0.37)
0
SELECT SLEEP(0.38);
SLEEP(0.38)
0
SELECT SLEEP(0.39);
SLEEP(0.39)
0
SELECT SLEEP(0.40);
SLEEP(0.40)
0
SELECT SLEEP(1.1);
SLEEP(1.1)
0
SELECT SLEEP(1.2);
SLEEP(1.2)
0
SELECT SLEEP(1.3);
SLEEP(1.3)
0
SELECT SLEEP(1.5);
SLEEP(1.5)
0
SELECT SLEEP(1.4);
SLEEP(1.4)
0
SELECT SLEEP(0.5);
SLEEP(0.5)
0
SELECT SLEEP(2.1);
SLEEP(2.1)
0
SELECT SLEEP(2.3);
SLEEP(2.3)
0
SELECT SLEEP(2.5);
SLEEP(2.5)
0
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 20 3 17
11 20 3 17
8 20 3 17
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
17
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.000008
0.000059
0.000416
0.002915
0.020408
0.142857
1.000000
7.000000
49.000000
343.000000
2401.000000
16807.000000
117649.000000
823543.000000
5764801.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 7
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 156
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT SLEEP(0.31);
SLEEP(0.31)
0
SELECT SLEEP(0.32);
SLEEP(0.32)
0
SELECT SLEEP(0.33);
SLEEP(0.33)
0
SELECT SLEEP(0.34);
SLEEP(0.34)
0
SELECT SLEEP(0.35);
SLEEP(0.35)
0
SELECT SLEEP(0.36);
SLEEP(0.36)
0
SELECT SLEEP(0.37);
SLEEP(0.37)
0
SELECT SLEEP(0.38);
SLEEP(0.38)
0
SELECT SLEEP(0.39);
SLEEP(0.39)
0
SELECT SLEEP(0.40);
SLEEP(0.40)
0
SELECT SLEEP(1.1);
SLEEP(1.1)
0
SELECT SLEEP(1.2);
SLEEP(1.2)
0
SELECT SLEEP(1.3);
SLEEP(1.3)
0
SELECT SLEEP(1.5);
SLEEP(1.5)
0
SELECT SLEEP(1.4);
SLEEP(1.4)
0
SELECT SLEEP(0.5);
SLEEP(0.5)
0
SELECT SLEEP(2.1);
SLEEP(2.1)
0
SELECT SLEEP(2.3);
SLEEP(2.3)
0
SELECT SLEEP(2.5);
SLEEP(2.5)
0
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 20 3 7
11 20 3 7
8 20 3 7
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
7
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000041
0.006410
1.000000
156.000000
24336.000000
3796416.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 156
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
FLUSH QUERY_RESPONSE_TIME;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
SELECT SLEEP(0.31);
SLEEP(0.31)
0
SELECT SLEEP(0.32);
SLEEP(0.32)
0
SELECT SLEEP(0.33);
SLEEP(0.33)
0
SELECT SLEEP(0.34);
SLEEP(0.34)
0
SELECT SLEEP(0.35);
SLEEP(0.35)
0
SELECT SLEEP(0.36);
SLEEP(0.36)
0
SELECT SLEEP(0.37);
SLEEP(0.37)
0
SELECT SLEEP(0.38);
SLEEP(0.38)
0
SELECT SLEEP(0.39);
SLEEP(0.39)
0
SELECT SLEEP(0.40);
SLEEP(0.40)
0
SELECT SLEEP(1.1);
SLEEP(1.1)
0
SELECT SLEEP(1.2);
SLEEP(1.2)
0
SELECT SLEEP(1.3);
SLEEP(1.3)
0
SELECT SLEEP(1.5);
SLEEP(1.5)
0
SELECT SLEEP(1.4);
SLEEP(1.4)
0
SELECT SLEEP(0.5);
SLEEP(0.5)
0
SELECT SLEEP(2.1);
SLEEP(2.1)
0
SELECT SLEEP(2.3);
SLEEP(2.3)
0
SELECT SLEEP(2.5);
SLEEP(2.5)
0
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
count query_count not_zero_region_count region_count
1 20 3 6
11 20 3 6
8 20 3 6
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
region_count
6
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
time
0.000001
0.001000
1.000000
1000.000000
1000000.00000
TOO LONG QUERY
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001;
Warnings:
Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
Variable_name Value
query_response_time_range_base 1000
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10;

View file

@ -0,0 +1,65 @@
source include/have_innodb.inc;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 2;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
source include/percona_query_response_time_show.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
source include/percona_query_response_time_sleep.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 10;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
source include/percona_query_response_time_sleep.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 7;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
source include/percona_query_response_time_sleep.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 156;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
source include/percona_query_response_time_sleep.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1000;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
source include/percona_query_response_time_flush.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=1;
source include/percona_query_response_time_sleep.inc;
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
source include/percona_query_response_time_show.inc;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE = 1001;
SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
SET GLOBAL ENABLE_QUERY_RESPONSE_TIME_STATS=0;
SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE =10;

View file

@ -0,0 +1 @@
FLUSH QUERY_RESPONSE_TIME;

View file

@ -0,0 +1,7 @@
SELECT c.count,
(SELECT SUM(a.count) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as a WHERE a.count != 0) as query_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as b WHERE b.count != 0) as not_zero_region_count,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME) as region_count
FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME as c WHERE c.count > 0;
SELECT COUNT(*) as region_count FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
SELECT time FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;

View file

@ -0,0 +1,19 @@
SELECT SLEEP(0.31);
SELECT SLEEP(0.32);
SELECT SLEEP(0.33);
SELECT SLEEP(0.34);
SELECT SLEEP(0.35);
SELECT SLEEP(0.36);
SELECT SLEEP(0.37);
SELECT SLEEP(0.38);
SELECT SLEEP(0.39);
SELECT SLEEP(0.40);
SELECT SLEEP(1.1);
SELECT SLEEP(1.2);
SELECT SLEEP(1.3);
SELECT SLEEP(1.5);
SELECT SLEEP(1.4);
SELECT SLEEP(0.5);
SELECT SLEEP(2.1);
SELECT SLEEP(2.3);
SELECT SLEEP(2.5);

View file

@ -0,0 +1,340 @@
show variables;
Variable_name Value
auto_increment_increment Value
auto_increment_offset Value
autocommit Value
automatic_sp_privileges Value
back_log Value
basedir Value
big_tables Value
binlog_cache_size Value
binlog_direct_non_transactional_updates Value
binlog_format Value
bulk_insert_buffer_size Value
character_set_client Value
character_set_connection Value
character_set_database Value
character_set_filesystem Value
character_set_results Value
character_set_server Value
character_set_system Value
character_sets_dir Value
collation_connection Value
collation_database Value
collation_server Value
completion_type Value
concurrent_insert Value
connect_timeout Value
datadir Value
date_format Value
datetime_format Value
debug Value
debug_sync Value
default_week_format Value
delay_key_write Value
delayed_insert_limit Value
delayed_insert_timeout Value
delayed_queue_size Value
div_precision_increment Value
enable_query_response_time_stats Value
engine_condition_pushdown Value
error_count Value
event_scheduler Value
expire_logs_days Value
fast_index_creation Value
flush Value
flush_time Value
foreign_key_checks Value
ft_boolean_syntax Value
ft_max_word_len Value
ft_min_word_len Value
ft_query_expansion_limit Value
ft_stopword_file Value
general_log Value
general_log_file Value
group_concat_max_len Value
have_community_features Value
have_compress Value
have_crypt Value
have_csv Value
have_dynamic_loading Value
have_geometry Value
have_innodb Value
have_ndbcluster Value
have_openssl Value
have_partitioning Value
have_query_cache Value
have_rtree_keys Value
have_ssl Value
have_symlink Value
hostname Value
identity Value
ignore_builtin_innodb Value
init_connect Value
init_file Value
init_slave Value
innodb_adaptive_checkpoint Value
innodb_adaptive_flushing Value
innodb_adaptive_hash_index Value
innodb_additional_mem_pool_size Value
innodb_autoextend_increment Value
innodb_autoinc_lock_mode Value
innodb_buffer_pool_shm_key Value
innodb_buffer_pool_size Value
innodb_change_buffering Value
innodb_checkpoint_age_target Value
innodb_checksums Value
innodb_commit_concurrency Value
innodb_concurrency_tickets Value
innodb_data_file_path Value
innodb_data_home_dir Value
innodb_dict_size_limit Value
innodb_doublewrite Value
innodb_doublewrite_file Value
innodb_enable_unsafe_group_commit Value
innodb_expand_import Value
innodb_extra_rsegments Value
innodb_extra_undoslots Value
innodb_fast_checksum Value
innodb_fast_recovery Value
innodb_fast_shutdown Value
innodb_file_format Value
innodb_file_format_check Value
innodb_file_per_table Value
innodb_flush_log_at_trx_commit Value
innodb_flush_log_at_trx_commit_session Value
innodb_flush_method Value
innodb_flush_neighbor_pages Value
innodb_force_recovery Value
innodb_ibuf_accel_rate Value
innodb_ibuf_active_contract Value
innodb_ibuf_max_size Value
innodb_io_capacity Value
innodb_lock_wait_timeout Value
innodb_locks_unsafe_for_binlog Value
innodb_log_buffer_size Value
innodb_log_file_size Value
innodb_log_files_in_group Value
innodb_log_group_home_dir Value
innodb_max_dirty_pages_pct Value
innodb_max_purge_lag Value
innodb_mirrored_log_groups Value
innodb_old_blocks_pct Value
innodb_old_blocks_time Value
innodb_open_files Value
innodb_overwrite_relay_log_info Value
innodb_page_size Value
innodb_pass_corrupt_table Value
innodb_read_ahead Value
innodb_read_ahead_threshold Value
innodb_read_io_threads Value
innodb_recovery_stats Value
innodb_replication_delay Value
innodb_rollback_on_timeout Value
innodb_show_locks_held Value
innodb_show_verbose_locks Value
innodb_spin_wait_delay Value
innodb_stats_auto_update Value
innodb_stats_method Value
innodb_stats_on_metadata Value
innodb_stats_sample_pages Value
innodb_stats_update_need_lock Value
innodb_strict_mode Value
innodb_support_xa Value
innodb_sync_spin_loops Value
innodb_table_locks Value
innodb_thread_concurrency Value
innodb_thread_concurrency_timer_based Value
innodb_thread_sleep_delay Value
innodb_use_purge_thread Value
innodb_use_sys_malloc Value
innodb_use_sys_stats_table Value
innodb_version Value
innodb_write_io_threads Value
insert_id Value
interactive_timeout Value
join_buffer_size Value
keep_files_on_create Value
key_buffer_size Value
key_cache_age_threshold Value
key_cache_block_size Value
key_cache_division_limit Value
language Value
large_files_support Value
large_page_size Value
large_pages Value
last_insert_id Value
lc_time_names Value
license Value
local_infile Value
locked_in_memory Value
log Value
log_bin Value
log_bin_trust_function_creators Value
log_bin_trust_routine_creators Value
log_error Value
log_output Value
log_queries_not_using_indexes Value
log_slave_updates Value
log_slow_filter Value
log_slow_queries Value
log_slow_rate_limit Value
log_slow_slave_statements Value
log_slow_sp_statements Value
log_slow_timestamp_every Value
log_slow_verbosity Value
log_warnings Value
long_query_time Value
low_priority_updates Value
lower_case_file_system Value
lower_case_table_names Value
max_allowed_packet Value
max_binlog_cache_size Value
max_binlog_size Value
max_connect_errors Value
max_connections Value
max_delayed_threads Value
max_error_count Value
max_heap_table_size Value
max_insert_delayed_threads Value
max_join_size Value
max_length_for_sort_data Value
max_prepared_stmt_count Value
max_relay_log_size Value
max_seeks_for_key Value
max_sort_length Value
max_sp_recursion_depth Value
max_tmp_tables Value
max_user_connections Value
max_write_lock_count Value
min_examined_row_limit Value
multi_range_count Value
myisam_data_pointer_size Value
myisam_max_sort_file_size Value
myisam_mmap_size Value
myisam_recover_options Value
myisam_repair_threads Value
myisam_sort_buffer_size Value
myisam_stats_method Value
myisam_use_mmap Value
net_buffer_length Value
net_read_timeout Value
net_retry_count Value
net_write_timeout Value
new Value
old Value
old_alter_table Value
old_passwords Value
open_files_limit Value
optimizer_fix Value
optimizer_prune_level Value
optimizer_search_depth Value
optimizer_switch Value
pid_file Value
plugin_dir Value
port Value
preload_buffer_size Value
profiling Value
profiling_history_size Value
profiling_server Value
profiling_use_getrusage Value
protocol_version Value
pseudo_thread_id Value
query_alloc_block_size Value
query_cache_limit Value
query_cache_min_res_unit Value
query_cache_size Value
query_cache_strip_comments Value
query_cache_type Value
query_cache_wlock_invalidate Value
query_prealloc_size Value
query_response_time_range_base Value
rand_seed1 Value
rand_seed2 Value
range_alloc_block_size Value
read_buffer_size Value
read_only Value
read_rnd_buffer_size Value
relay_log Value
relay_log_index Value
relay_log_info_file Value
relay_log_purge Value
relay_log_space_limit Value
report_host Value
report_password Value
report_port Value
report_user Value
rpl_recovery_rank Value
secure_auth Value
secure_file_priv Value
server_id Value
skip_external_locking Value
skip_name_resolve Value
skip_networking Value
skip_show_database Value
slave_compressed_protocol Value
slave_exec_mode Value
slave_load_tmpdir Value
slave_net_timeout Value
slave_skip_errors Value
slave_transaction_retries Value
slow_launch_time Value
slow_query_log Value
slow_query_log_file Value
slow_query_log_microseconds_timestamp Value
socket Value
sort_buffer_size Value
sql_auto_is_null Value
sql_big_selects Value
sql_big_tables Value
sql_buffer_result Value
sql_log_bin Value
sql_log_off Value
sql_log_update Value
sql_low_priority_updates Value
sql_max_join_size Value
sql_mode Value
sql_notes Value
sql_quote_show_create Value
sql_safe_updates Value
sql_select_limit Value
sql_slave_skip_counter Value
sql_warnings Value
ssl_ca Value
ssl_capath Value
ssl_cert Value
ssl_cipher Value
ssl_key Value
storage_engine Value
suppress_log_warning_1592 Value
sync_binlog Value
sync_frm Value
system_time_zone Value
table_definition_cache Value
table_lock_wait_timeout Value
table_open_cache Value
table_type Value
thread_cache_size Value
thread_handling Value
thread_stack Value
thread_statistics Value
time_format Value
time_zone Value
timed_mutexes Value
timestamp Value
tmp_table_size Value
tmpdir Value
transaction_alloc_block_size Value
transaction_prealloc_size Value
tx_isolation Value
unique_checks Value
updatable_views_with_limit Value
use_global_log_slow_control Value
use_global_long_query_time Value
userstat_running Value
version Value
version_comment Value
version_compile_machine Value
version_compile_os Value
wait_timeout Value
warning_count Value

View file

@ -0,0 +1,7 @@
--source include/have_innodb.inc
--source include/have_debug.inc
#check the list of variable names
--replace_column 2 Value
show variables;

View file

@ -0,0 +1 @@
--long_query_time=0 --log_slow_verbosity=innodb --log_slow_slave_statements

View file

@ -0,0 +1 @@
--long_query_time=0 --log_slow_verbosity=innodb --log_slow_slave_statements

View file

@ -0,0 +1,21 @@
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
DROP TABLE IF EXISTS t;
CREATE TABLE t(id INT,data CHAR(30)) ENGINE=InnoDB;
INSERT INTO t VALUES
(1,"aaaaabbbbbcccccdddddeeeeefffff"),
(2,"aaaaabbbbbcccccdddddeeeeefffff"),
(3,"aaaaabbbbbcccccdddddeeeeefffff"),
(4,"aaaaabbbbbcccccdddddeeeeefffff"),
(5,"aaaaabbbbbcccccdddddeeeeefffff");
INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2;
INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2;
STOP SLAVE;
START SLAVE;
INSERT INTO t SELECT t.id,t.data from t;
DROP TABLE IF EXISTS t;
4

View file

@ -0,0 +1,43 @@
source include/have_innodb.inc;
source include/master-slave.inc;
connection master;
-- disable_warnings
DROP TABLE IF EXISTS t;
-- enable_warnings
CREATE TABLE t(id INT,data CHAR(30)) ENGINE=InnoDB;
INSERT INTO t VALUES
(1,"aaaaabbbbbcccccdddddeeeeefffff"),
(2,"aaaaabbbbbcccccdddddeeeeefffff"),
(3,"aaaaabbbbbcccccdddddeeeeefffff"),
(4,"aaaaabbbbbcccccdddddeeeeefffff"),
(5,"aaaaabbbbbcccccdddddeeeeefffff");
INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2;
INSERT INTO t SELECT t2.id,t2.data from t as t1, t as t2;
sync_slave_with_master;
connection slave;
STOP SLAVE;
-- source include/wait_for_slave_to_stop.inc
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
wait
EOF
--shutdown_server 10
--source include/wait_until_disconnected.inc
--append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
restart
EOF
--enable_reconnect
--source include/wait_until_connected_again.inc
START SLAVE;
-- source include/wait_for_slave_to_start.inc
connection master;
INSERT INTO t SELECT t.id,t.data from t;
sync_slave_with_master;
connection master;
DROP TABLE IF EXISTS t;
sync_slave_with_master;
exec cat var/mysqld.2/mysqld-slow.log | grep InnoDB_IO_r_ops | wc -l;

View file

@ -22,3 +22,38 @@ set global long_query_time=2;
set global use_global_long_query_time=0; set global use_global_long_query_time=0;
cat var/mysqld.1/data/percona_slow_query_log-use_global_long_query_time.log | grep Query_time | wc -l cat var/mysqld.1/data/percona_slow_query_log-use_global_long_query_time.log | grep Query_time | wc -l
3 3
show global variables like 'use_global_log_slow_control';
Variable_name Value
use_global_log_slow_control none
show global variables like 'use_global_long_query_time';
Variable_name Value
use_global_long_query_time OFF
set global use_global_log_slow_control = long_query_time;
show global variables like 'use_global_log_slow_control';
Variable_name Value
use_global_log_slow_control long_query_time
show global variables like 'use_global_long_query_time';
Variable_name Value
use_global_long_query_time ON
set global use_global_log_slow_control = log_slow_filter;
show global variables like 'use_global_log_slow_control';
Variable_name Value
use_global_log_slow_control log_slow_filter
show global variables like 'use_global_long_query_time';
Variable_name Value
use_global_long_query_time OFF
set global use_global_long_query_time = ON;
show global variables like 'use_global_log_slow_control';
Variable_name Value
use_global_log_slow_control log_slow_filter,long_query_time
show global variables like 'use_global_long_query_time';
Variable_name Value
use_global_long_query_time ON
set global use_global_long_query_time = OFF;
show global variables like 'use_global_log_slow_control';
Variable_name Value
use_global_log_slow_control log_slow_filter
show global variables like 'use_global_long_query_time';
Variable_name Value
use_global_long_query_time OFF
set global use_global_log_slow_control = none;

View file

@ -17,3 +17,24 @@ set global use_global_long_query_time=0;
let $cmd = cat var/mysqld.1/data/percona_slow_query_log-use_global_long_query_time.log | grep Query_time | wc -l; let $cmd = cat var/mysqld.1/data/percona_slow_query_log-use_global_long_query_time.log | grep Query_time | wc -l;
echo $cmd; echo $cmd;
exec $cmd; exec $cmd;
show global variables like 'use_global_log_slow_control';
show global variables like 'use_global_long_query_time';
set global use_global_log_slow_control = long_query_time;
show global variables like 'use_global_log_slow_control';
show global variables like 'use_global_long_query_time';
set global use_global_log_slow_control = log_slow_filter;
show global variables like 'use_global_log_slow_control';
show global variables like 'use_global_long_query_time';
set global use_global_long_query_time = ON;
show global variables like 'use_global_log_slow_control';
show global variables like 'use_global_long_query_time';
set global use_global_long_query_time = OFF;
show global variables like 'use_global_log_slow_control';
show global variables like 'use_global_long_query_time';
set global use_global_log_slow_control = none;

View file

@ -0,0 +1,12 @@
drop table if exists t1;
create table t (a int not null);
insert into t values (1),(2),(3);
SELECT SQL_NO_FCACHE SLEEP(0);
SLEEP(0)
0
SELECT /*!40001 SQL_NO_CACHE */ /*!50084 SQL_NO_FCACHE */ * FROM t;
a
1
2
3
DROP TABLE t;

View file

@ -0,0 +1,11 @@
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t (a int not null);
insert into t values (1),(2),(3);
SELECT SQL_NO_FCACHE SLEEP(0);
SELECT /*!40001 SQL_NO_CACHE */ /*!50084 SQL_NO_FCACHE */ * FROM t;
DROP TABLE t;

View file

@ -0,0 +1,27 @@
set GLOBAL query_cache_size=1355776;
flush query cache;
flush query cache;
reset query cache;
flush status;
DROP TABLE IF EXISTS t;
CREATE TABLE t(id INT, number INT);
INSERT INTO t VALUES (0,1);
INSERT INTO t VALUES (1,2);
INSERT INTO t VALUES (2,3);
SELECT number from t where id > 0;
number
2
3
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
SELECT number from t where id > 0;
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
SELECT number from t where id > 0;
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
SHOW PROCESSLIST;
Id User Host db Command Time State Info
Id root localhost test Sleep Time NULL
Id root localhost test Query Time Waiting on query cache mutex SELECT number from t where id > 0
Id root localhost test Query Time Waiting on query cache mutex SELECT number from t where id > 0
Id root localhost test Query Time NULL SHOW PROCESSLIST
DROP TABLE t;
set GLOBAL query_cache_size=0;

View file

@ -0,0 +1,37 @@
--source include/have_query_cache.inc
--source include/have_debug.inc
set GLOBAL query_cache_size=1355776;
--source include/percona_query_cache_with_comments_clear.inc
-- disable_warnings
DROP TABLE IF EXISTS t;
-- enable_warnings
CREATE TABLE t(id INT, number INT);
INSERT INTO t VALUES (0,1);
INSERT INTO t VALUES (1,2);
INSERT INTO t VALUES (2,3);
SELECT number from t where id > 0;
--connect (conn0,localhost,root,,)
--connect (conn1,localhost,root,,)
--connect (conn2,localhost,root,,)
--connection conn0
--error 0, ER_UNKNOWN_SYSTEM_VARIABLE
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
SEND SELECT number from t where id > 0;
SLEEP 1.0;
--connection conn1
--error 0, ER_UNKNOWN_SYSTEM_VARIABLE
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
SEND SELECT number from t where id > 0;
SLEEP 1.0;
--connection conn2
--error 0, ER_UNKNOWN_SYSTEM_VARIABLE
SET SESSION debug="+d,status_wait_query_cache_mutex_sleep";
--replace_column 1 Id 6 Time
SHOW PROCESSLIST;
DROP TABLE t;
set GLOBAL query_cache_size=0;

View file

@ -21,15 +21,18 @@ CREATE PROCEDURE insert_many(p1 int)
BEGIN BEGIN
SET @x = 0; SET @x = 0;
SET @y = 0; SET @y = 0;
start transaction;
REPEAT REPEAT
insert into test1 set b=1; insert into test1 set b=1;
SET @x = @x + 1; SET @x = @x + 1;
SET @y = @y + 1; SET @y = @y + 1;
IF @y >= 100 THEN IF @y >= 1000 THEN
commit; commit;
start transaction;
SET @y = 0; SET @y = 0;
END IF; END IF;
UNTIL @x >= p1 END REPEAT; UNTIL @x >= p1 END REPEAT;
commit;
END| END|
delimiter ;| delimiter ;|
call insert_many(100000); call insert_many(100000);

View file

@ -622,10 +622,20 @@ que_graph_free_recursive(
que_graph_free_recursive(cre_ind->ind_def); que_graph_free_recursive(cre_ind->ind_def);
que_graph_free_recursive(cre_ind->field_def); que_graph_free_recursive(cre_ind->field_def);
if (srv_use_sys_stats_table)
que_graph_free_recursive(cre_ind->stats_def);
que_graph_free_recursive(cre_ind->commit_node); que_graph_free_recursive(cre_ind->commit_node);
mem_heap_free(cre_ind->heap); mem_heap_free(cre_ind->heap);
break;
case QUE_NODE_INSERT_STATS:
cre_ind = node;
que_graph_free_recursive(cre_ind->stats_def);
que_graph_free_recursive(cre_ind->commit_node);
mem_heap_free(cre_ind->heap);
break; break;
case QUE_NODE_PROC: case QUE_NODE_PROC:
que_graph_free_stat_list(((proc_node_t*)node)->stat_list); que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
@ -1139,6 +1149,8 @@ que_node_print_info(
str = "CREATE TABLE"; str = "CREATE TABLE";
} else if (type == QUE_NODE_CREATE_INDEX) { } else if (type == QUE_NODE_CREATE_INDEX) {
str = "CREATE INDEX"; str = "CREATE INDEX";
} else if (type == QUE_NODE_INSERT_STATS) {
str = "INSERT TO SYS_STATS";
} else if (type == QUE_NODE_FOR) { } else if (type == QUE_NODE_FOR) {
str = "FOR LOOP"; str = "FOR LOOP";
} else if (type == QUE_NODE_RETURN) { } else if (type == QUE_NODE_RETURN) {
@ -1256,6 +1268,8 @@ que_thr_step(
thr = dict_create_table_step(thr); thr = dict_create_table_step(thr);
} else if (type == QUE_NODE_CREATE_INDEX) { } else if (type == QUE_NODE_CREATE_INDEX) {
thr = dict_create_index_step(thr); thr = dict_create_index_step(thr);
} else if (type == QUE_NODE_INSERT_STATS) {
thr = dict_insert_stats_step(thr);
} else if (type == QUE_NODE_ROW_PRINTF) { } else if (type == QUE_NODE_ROW_PRINTF) {
thr = row_printf_step(thr); thr = row_printf_step(thr);
} else { } else {

View file

@ -706,7 +706,9 @@ cmp_rec_rec_simple(
const rec_t* rec2, /*!< in: physical record */ const rec_t* rec2, /*!< in: physical record */
const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */
const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */
const dict_index_t* index) /*!< in: data dictionary index */ const dict_index_t* index, /*!< in: data dictionary index */
ibool* null_eq)/*!< out: set to TRUE if
found matching null values */
{ {
ulint rec1_f_len; /*!< length of current field in rec1 */ ulint rec1_f_len; /*!< length of current field in rec1 */
const byte* rec1_b_ptr; /*!< pointer to the current byte const byte* rec1_b_ptr; /*!< pointer to the current byte
@ -753,6 +755,9 @@ cmp_rec_rec_simple(
|| rec2_f_len == UNIV_SQL_NULL) { || rec2_f_len == UNIV_SQL_NULL) {
if (rec1_f_len == rec2_f_len) { if (rec1_f_len == rec2_f_len) {
if (null_eq) {
*null_eq = TRUE;
}
goto next_field; goto next_field;

View file

@ -51,6 +51,15 @@ Created 4/20/1996 Heikki Tuuri
#define ROW_INS_PREV 1 #define ROW_INS_PREV 1
#define ROW_INS_NEXT 2 #define ROW_INS_NEXT 2
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
is enough space in the redo log before for that operation. This is
done by calling log_free_check(). The reason for checking the
availability of the redo log space before the start of the operation is
that we MUST not hold any synchonization objects when performing the
check.
If you make a change in this module make sure that no codepath is
introduced where a call to log_free_check() is bypassed. */
/*********************************************************************//** /*********************************************************************//**
Creates an insert node struct. Creates an insert node struct.
@ -1121,9 +1130,9 @@ nonstandard_exit_func:
/*********************************************************************//** /*********************************************************************//**
Sets a shared lock on a record. Used in locking possible duplicate key Sets a shared lock on a record. Used in locking possible duplicate key
records and also in checking foreign key constraints. records and also in checking foreign key constraints.
@return DB_SUCCESS or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
static static
ulint enum db_err
row_ins_set_shared_rec_lock( row_ins_set_shared_rec_lock(
/*========================*/ /*========================*/
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
@ -1134,7 +1143,7 @@ row_ins_set_shared_rec_lock(
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err; enum db_err err;
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
@ -1152,9 +1161,9 @@ row_ins_set_shared_rec_lock(
/*********************************************************************//** /*********************************************************************//**
Sets a exclusive lock on a record. Used in locking possible duplicate key Sets a exclusive lock on a record. Used in locking possible duplicate key
records records
@return DB_SUCCESS or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
static static
ulint enum db_err
row_ins_set_exclusive_rec_lock( row_ins_set_exclusive_rec_lock(
/*===========================*/ /*===========================*/
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
@ -1165,7 +1174,7 @@ row_ins_set_exclusive_rec_lock(
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err; enum db_err err;
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
@ -1205,7 +1214,6 @@ row_ins_check_foreign_constraint(
dict_index_t* check_index; dict_index_t* check_index;
ulint n_fields_cmp; ulint n_fields_cmp;
btr_pcur_t pcur; btr_pcur_t pcur;
ibool moved;
int cmp; int cmp;
ulint err; ulint err;
ulint i; ulint i;
@ -1336,7 +1344,7 @@ run_again:
/* Scan index records and check if there is a matching record */ /* Scan index records and check if there is a matching record */
for (;;) { do {
const rec_t* rec = btr_pcur_get_rec(&pcur); const rec_t* rec = btr_pcur_get_rec(&pcur);
const buf_block_t* block = btr_pcur_get_block(&pcur); const buf_block_t* block = btr_pcur_get_block(&pcur);
@ -1348,7 +1356,7 @@ run_again:
if (page_rec_is_infimum(rec)) { if (page_rec_is_infimum(rec)) {
goto next_rec; continue;
} }
offsets = rec_get_offsets(rec, check_index, offsets = rec_get_offsets(rec, check_index,
@ -1359,12 +1367,13 @@ run_again:
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block, err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
rec, check_index, rec, check_index,
offsets, thr); offsets, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
break; case DB_SUCCESS:
continue;
default:
goto end_scan;
} }
goto next_rec;
} }
cmp = cmp_dtuple_rec(entry, rec, offsets); cmp = cmp_dtuple_rec(entry, rec, offsets);
@ -1375,9 +1384,12 @@ run_again:
err = row_ins_set_shared_rec_lock( err = row_ins_set_shared_rec_lock(
LOCK_ORDINARY, block, LOCK_ORDINARY, block,
rec, check_index, offsets, thr); rec, check_index, offsets, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break; break;
default:
goto end_scan;
} }
} else { } else {
/* Found a matching record. Lock only /* Found a matching record. Lock only
@ -1388,15 +1400,18 @@ run_again:
LOCK_REC_NOT_GAP, block, LOCK_REC_NOT_GAP, block,
rec, check_index, offsets, thr); rec, check_index, offsets, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break; break;
default:
goto end_scan;
} }
if (check_ref) { if (check_ref) {
err = DB_SUCCESS; err = DB_SUCCESS;
break; goto end_scan;
} else if (foreign->type != 0) { } else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE /* There is an ON UPDATE or ON DELETE
condition: check them in a separate condition: check them in a separate
@ -1422,7 +1437,7 @@ run_again:
err = DB_FOREIGN_DUPLICATE_KEY; err = DB_FOREIGN_DUPLICATE_KEY;
} }
break; goto end_scan;
} }
/* row_ins_foreign_check_on_constraint /* row_ins_foreign_check_on_constraint
@ -1435,49 +1450,41 @@ run_again:
thr, foreign, rec, entry); thr, foreign, rec, entry);
err = DB_ROW_IS_REFERENCED; err = DB_ROW_IS_REFERENCED;
break; goto end_scan;
} }
} }
} } else {
ut_a(cmp < 0);
if (cmp < 0) {
err = row_ins_set_shared_rec_lock( err = row_ins_set_shared_rec_lock(
LOCK_GAP, block, LOCK_GAP, block,
rec, check_index, offsets, thr); rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
break; switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
} }
if (check_ref) { goto end_scan;
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
break;
} }
} while (btr_pcur_move_to_next(&pcur, &mtr));
ut_a(cmp == 0); if (check_ref) {
next_rec: row_ins_foreign_report_add_err(
moved = btr_pcur_move_to_next(&pcur, &mtr); trx, foreign, btr_pcur_get_rec(&pcur), entry);
err = DB_NO_REFERENCED_ROW;
if (!moved) { } else {
if (check_ref) { err = DB_SUCCESS;
rec = btr_pcur_get_rec(&pcur);
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
err = DB_NO_REFERENCED_ROW;
} else {
err = DB_SUCCESS;
}
break;
}
} }
end_scan:
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
@ -1725,9 +1732,13 @@ row_ins_scan_sec_index_for_duplicate(
rec, index, offsets, thr); rec, index, offsets, thr);
} }
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break; break;
default:
goto end_scan;
} }
if (page_rec_is_supremum(rec)) { if (page_rec_is_supremum(rec)) {
@ -1744,17 +1755,15 @@ row_ins_scan_sec_index_for_duplicate(
thr_get_trx(thr)->error_info = index; thr_get_trx(thr)->error_info = index;
break; goto end_scan;
} }
} else {
ut_a(cmp < 0);
goto end_scan;
} }
if (cmp < 0) {
break;
}
ut_a(cmp == 0);
} while (btr_pcur_move_to_next(&pcur, &mtr)); } while (btr_pcur_move_to_next(&pcur, &mtr));
end_scan:
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
@ -1843,7 +1852,11 @@ row_ins_duplicate_error_in_clust(
cursor->index, offsets, thr); cursor->index, offsets, thr);
} }
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto func_exit; goto func_exit;
} }
@ -1883,7 +1896,11 @@ row_ins_duplicate_error_in_clust(
rec, cursor->index, offsets, thr); rec, cursor->index, offsets, thr);
} }
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto func_exit; goto func_exit;
} }

View file

@ -717,14 +717,16 @@ row_merge_read(
} }
/********************************************************************//** /********************************************************************//**
Read a merge block from the file system. Write a merge block to the file system.
@return TRUE if request was successful, FALSE if fail */ @return TRUE if request was successful, FALSE if fail */
static static
ibool ibool
row_merge_write( row_merge_write(
/*============*/ /*============*/
int fd, /*!< in: file descriptor */ int fd, /*!< in: file descriptor */
ulint offset, /*!< in: offset where to write */ ulint offset, /*!< in: offset where to read
in number of row_merge_block_t
elements */
const void* buf) /*!< in: data */ const void* buf) /*!< in: data */
{ {
ib_uint64_t ofs = ((ib_uint64_t) offset) ib_uint64_t ofs = ((ib_uint64_t) offset)
@ -1075,11 +1077,14 @@ row_merge_cmp(
record to be compared */ record to be compared */
const ulint* offsets1, /*!< in: first record offsets */ const ulint* offsets1, /*!< in: first record offsets */
const ulint* offsets2, /*!< in: second record offsets */ const ulint* offsets2, /*!< in: second record offsets */
const dict_index_t* index) /*!< in: index */ const dict_index_t* index, /*!< in: index */
ibool* null_eq) /*!< out: set to TRUE if
found matching null values */
{ {
int cmp; int cmp;
cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index); cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index,
null_eq);
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
if (row_merge_print_cmp) { if (row_merge_print_cmp) {
@ -1452,11 +1457,13 @@ corrupt:
} }
while (mrec0 && mrec1) { while (mrec0 && mrec1) {
ibool null_eq = FALSE;
switch (row_merge_cmp(mrec0, mrec1, switch (row_merge_cmp(mrec0, mrec1,
offsets0, offsets1, index)) { offsets0, offsets1, index,
&null_eq)) {
case 0: case 0:
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(dict_index_is_unique(index))) { (dict_index_is_unique(index) && !null_eq)) {
innobase_rec_to_mysql(table, mrec0, innobase_rec_to_mysql(table, mrec0,
index, offsets0); index, offsets0);
mem_heap_free(heap); mem_heap_free(heap);
@ -1578,22 +1585,28 @@ row_merge(
const dict_index_t* index, /*!< in: index being created */ const dict_index_t* index, /*!< in: index being created */
merge_file_t* file, /*!< in/out: file containing merge_file_t* file, /*!< in/out: file containing
index entries */ index entries */
ulint* half, /*!< in/out: half the file */
row_merge_block_t* block, /*!< in/out: 3 buffers */ row_merge_block_t* block, /*!< in/out: 3 buffers */
int* tmpfd, /*!< in/out: temporary file handle */ int* tmpfd, /*!< in/out: temporary file handle */
TABLE* table) /*!< in/out: MySQL table, for TABLE* table, /*!< in/out: MySQL table, for
reporting erroneous key value reporting erroneous key value
if applicable */ if applicable */
ulint* num_run,/*!< in/out: Number of runs remain
to be merged */
ulint* run_offset) /*!< in/out: Array contains the
first offset number for each merge
run */
{ {
ulint foffs0; /*!< first input offset */ ulint foffs0; /*!< first input offset */
ulint foffs1; /*!< second input offset */ ulint foffs1; /*!< second input offset */
ulint error; /*!< error code */ ulint error; /*!< error code */
merge_file_t of; /*!< output file */ merge_file_t of; /*!< output file */
const ulint ihalf = *half; const ulint ihalf = run_offset[*num_run / 2];
/*!< half the input file */ /*!< half the input file */
ulint ohalf; /*!< half the output file */ ulint n_run = 0;
/*!< num of runs generated from this merge */
UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
ut_ad(ihalf < file->offset); ut_ad(ihalf < file->offset);
of.fd = *tmpfd; of.fd = *tmpfd;
@ -1601,17 +1614,20 @@ row_merge(
of.n_rec = 0; of.n_rec = 0;
/* Merge blocks to the output file. */ /* Merge blocks to the output file. */
ohalf = 0;
foffs0 = 0; foffs0 = 0;
foffs1 = ihalf; foffs1 = ihalf;
UNIV_MEM_INVALID(run_offset, *num_run * sizeof *run_offset);
for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
ulint ahalf; /*!< arithmetic half the input file */
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) { if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
return(DB_INTERRUPTED); return(DB_INTERRUPTED);
} }
/* Remember the offset number for this run */
run_offset[n_run++] = of.offset;
error = row_merge_blocks(index, file, block, error = row_merge_blocks(index, file, block,
&foffs0, &foffs1, &of, table); &foffs0, &foffs1, &of, table);
@ -1619,21 +1635,6 @@ row_merge(
return(error); return(error);
} }
/* Record the offset of the output file when
approximately half the output has been generated. In
this way, the next invocation of row_merge() will
spend most of the time in this loop. The initial
estimate is ohalf==0. */
ahalf = file->offset / 2;
ut_ad(ohalf <= of.offset);
/* Improve the estimate until reaching half the input
file size, or we can not get any closer to it. All
comparands should be non-negative when !(ohalf < ahalf)
because ohalf <= of.offset. */
if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) {
ohalf = of.offset;
}
} }
/* Copy the last blocks, if there are any. */ /* Copy the last blocks, if there are any. */
@ -1643,6 +1644,9 @@ row_merge(
return(DB_INTERRUPTED); return(DB_INTERRUPTED);
} }
/* Remember the offset number for this run */
run_offset[n_run++] = of.offset;
if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) {
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
@ -1655,6 +1659,9 @@ row_merge(
return(DB_INTERRUPTED); return(DB_INTERRUPTED);
} }
/* Remember the offset number for this run */
run_offset[n_run++] = of.offset;
if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
@ -1666,10 +1673,23 @@ row_merge(
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
ut_ad(n_run <= *num_run);
*num_run = n_run;
/* Each run can contain one or more offsets. As merge goes on,
the number of runs (to merge) will reduce until we have one
single run. So the number of runs will always be smaller than
the number of offsets in file */
ut_ad((*num_run) <= file->offset);
/* The number of offsets in output file is always equal or
smaller than input file */
ut_ad(of.offset <= file->offset);
/* Swap file descriptors for the next pass. */ /* Swap file descriptors for the next pass. */
*tmpfd = file->fd; *tmpfd = file->fd;
*file = of; *file = of;
*half = ohalf;
UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]); UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
@ -1694,27 +1714,44 @@ row_merge_sort(
if applicable */ if applicable */
{ {
ulint half = file->offset / 2; ulint half = file->offset / 2;
ulint num_runs;
ulint* run_offset;
ulint error = DB_SUCCESS;
/* Record the number of merge runs we need to perform */
num_runs = file->offset;
/* If num_runs are less than 1, nothing to merge */
if (num_runs <= 1) {
return(error);
}
/* "run_offset" records each run's first offset number */
run_offset = (ulint*) mem_alloc(file->offset * sizeof(ulint));
/* This tells row_merge() where to start for the first round
of merge. */
run_offset[half] = half;
/* The file should always contain at least one byte (the end /* The file should always contain at least one byte (the end
of file marker). Thus, it must be at least one block. */ of file marker). Thus, it must be at least one block. */
ut_ad(file->offset > 0); ut_ad(file->offset > 0);
/* Merge the runs until we have one big run */
do { do {
ulint error; error = row_merge(trx, index, file, block, tmpfd,
table, &num_runs, run_offset);
error = row_merge(trx, index, file, &half, UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset);
block, tmpfd, table);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
return(error); break;
} }
} while (num_runs > 1);
/* half > 0 should hold except when the file consists mem_free(run_offset);
of one block. No need to merge further then. */
ut_ad(half > 0 || file->offset == 1);
} while (half < file->offset && half > 0);
return(DB_SUCCESS); return(error);
} }
/*************************************************************//** /*************************************************************//**
@ -1986,6 +2023,8 @@ row_merge_drop_index(
"UPDATE SYS_INDEXES SET NAME=CONCAT('" "UPDATE SYS_INDEXES SET NAME=CONCAT('"
TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n" TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
"COMMIT WORK;\n" "COMMIT WORK;\n"
/* Drop the statistics of the index. */
"DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
/* Drop the field definitions of the index. */ /* Drop the field definitions of the index. */
"DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
/* Drop the index definition and the B-tree. */ /* Drop the index definition and the B-tree. */
@ -2094,13 +2133,16 @@ row_merge_drop_temp_indexes(void)
btr_pcur_store_position(&pcur, &mtr); btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr); btr_pcur_commit_specify_mtr(&pcur, &mtr);
table = dict_load_table_on_id(table_id); table = dict_table_get_on_id_low(table_id);
if (table) { if (table) {
dict_index_t* index; dict_index_t* index;
dict_index_t* next_index;
for (index = dict_table_get_first_index(table); for (index = dict_table_get_first_index(table);
index; index = dict_table_get_next_index(index)) { index; index = next_index) {
next_index = dict_table_get_next_index(index);
if (*index->name == TEMP_INDEX_PREFIX) { if (*index->name == TEMP_INDEX_PREFIX) {
row_merge_drop_index(index, table, trx); row_merge_drop_index(index, table, trx);
@ -2303,7 +2345,7 @@ row_merge_rename_tables(
{ {
ulint err = DB_ERROR; ulint err = DB_ERROR;
pars_info_t* info; pars_info_t* info;
const char* old_name= old_table->name; char old_name[MAX_TABLE_NAME_LEN + 1];
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(old_table != new_table); ut_ad(old_table != new_table);
@ -2311,6 +2353,17 @@ row_merge_rename_tables(
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
/* store the old/current name to an automatic variable */
if (strlen(old_table->name) + 1 <= sizeof(old_name)) {
memcpy(old_name, old_table->name, strlen(old_table->name) + 1);
} else {
ut_print_timestamp(stderr);
fprintf(stderr, "InnoDB: too long table name: '%s', "
"max length is %d\n", old_table->name,
MAX_TABLE_NAME_LEN);
ut_error;
}
trx->op_info = "renaming tables"; trx->op_info = "renaming tables";
/* We use the private SQL parser of Innobase to generate the query /* We use the private SQL parser of Innobase to generate the query

View file

@ -522,6 +522,7 @@ handle_new_error:
case DB_CANNOT_ADD_CONSTRAINT: case DB_CANNOT_ADD_CONSTRAINT:
case DB_TOO_MANY_CONCURRENT_TRXS: case DB_TOO_MANY_CONCURRENT_TRXS:
case DB_OUT_OF_FILE_SPACE: case DB_OUT_OF_FILE_SPACE:
case DB_INTERRUPTED:
if (savept) { if (savept) {
/* Roll back the latest, possibly incomplete /* Roll back the latest, possibly incomplete
insertion or update */ insertion or update */
@ -624,6 +625,8 @@ row_create_prebuilt(
prebuilt->select_lock_type = LOCK_NONE; prebuilt->select_lock_type = LOCK_NONE;
prebuilt->stored_select_lock_type = 99999999; prebuilt->stored_select_lock_type = 99999999;
UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
sizeof prebuilt->stored_select_lock_type);
prebuilt->search_tuple = dtuple_create( prebuilt->search_tuple = dtuple_create(
heap, 2 * dict_table_get_n_cols(table)); heap, 2 * dict_table_get_n_cols(table));
@ -864,7 +867,7 @@ row_update_statistics_if_needed(
if (counter > 2000000000 if (counter > 2000000000
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) { || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
dict_update_statistics(table); dict_update_statistics(table, TRUE);
} }
} }
@ -1124,6 +1127,13 @@ row_insert_for_mysql(
thr = que_fork_get_first_thr(prebuilt->ins_graph); thr = que_fork_get_first_thr(prebuilt->ins_graph);
if (!prebuilt->mysql_has_locked) {
fprintf(stderr, "InnoDB: Error: row_insert_for_mysql is called without ha_innobase::external_lock()\n");
if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(stderr, trx->mysql_thd, 600);
}
}
if (prebuilt->sql_stat_start) { if (prebuilt->sql_stat_start) {
node->state = INS_NODE_SET_IX_LOCK; node->state = INS_NODE_SET_IX_LOCK;
prebuilt->sql_stat_start = FALSE; prebuilt->sql_stat_start = FALSE;
@ -1430,27 +1440,26 @@ run_again:
} }
/*********************************************************************//** /*********************************************************************//**
This can only be used when srv_locks_unsafe_for_binlog is TRUE or This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
this session is using a READ COMMITTED isolation level. Before session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
calling this function we must use trx_reset_new_rec_lock_info() and Before calling this function row_search_for_mysql() must have
trx_register_new_rec_lock() to store the information which new record locks initialized prebuilt->new_rec_locks to store the information which new
really were set. This function removes a newly set lock under prebuilt->pcur, record locks really were set. This function removes a newly set
and also under prebuilt->clust_pcur. Currently, this is only used and tested clustered index record lock under prebuilt->pcur or
in the case of an UPDATE or a DELETE statement, where the row lock is of the prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that
LOCK_X type. releases the latest clustered index record lock we set.
Thus, this implements a 'mini-rollback' that releases the latest record @return error code or DB_SUCCESS */
locks we set.
@return error code or DB_SUCCESS */
UNIV_INTERN UNIV_INTERN
int int
row_unlock_for_mysql( row_unlock_for_mysql(
/*=================*/ /*=================*/
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL
handle */ handle */
ibool has_latches_on_recs)/*!< TRUE if called so that we have ibool has_latches_on_recs)/*!< in: TRUE if called so
the latches on the records under pcur that we have the latches on
and clust_pcur, and we do not need to the records under pcur and
reposition the cursors. */ clust_pcur, and we do not need
to reposition the cursors. */
{ {
btr_pcur_t* pcur = prebuilt->pcur; btr_pcur_t* pcur = prebuilt->pcur;
btr_pcur_t* clust_pcur = prebuilt->clust_pcur; btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
@ -1647,37 +1656,6 @@ row_table_got_default_clust_index(
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS); return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
} }
/*********************************************************************//**
Calculates the key number used inside MySQL for an Innobase index. We have
to take into account if we generated a default clustered index for the table
@return the key number used inside MySQL */
UNIV_INTERN
ulint
row_get_mysql_key_number_for_index(
/*===============================*/
const dict_index_t* index) /*!< in: index */
{
const dict_index_t* ind;
ulint i;
ut_a(index);
i = 0;
ind = dict_table_get_first_index(index->table);
while (index != ind) {
ind = dict_table_get_next_index(ind);
i++;
}
if (row_table_got_default_clust_index(index->table)) {
ut_a(i > 0);
i--;
}
return(i);
}
/*********************************************************************//** /*********************************************************************//**
Locks the data dictionary in shared mode from modifications, for performing Locks the data dictionary in shared mode from modifications, for performing
foreign key check, rollback, or other operation invisible to MySQL. */ foreign key check, rollback, or other operation invisible to MySQL. */
@ -2043,6 +2021,45 @@ error_handling:
return((int) err); return((int) err);
} }
/*********************************************************************//**
*/
UNIV_INTERN
int
row_insert_stats_for_mysql(
/*=======================*/
dict_index_t* index,
trx_t* trx)
{
ind_node_t* node;
mem_heap_t* heap;
que_thr_t* thr;
ulint err;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "try to insert rows to SYS_STATS";
trx_start_if_not_started(trx);
trx->error_state = DB_SUCCESS;
heap = mem_heap_create(512);
node = ind_insert_stats_graph_create(index, heap);
thr = pars_complete_graph_for_exec(node, trx, heap);
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
que_run_threads(thr);
err = trx->error_state;
que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = "";
return((int) err);
}
/*********************************************************************//** /*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
@ -2062,6 +2079,7 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d), FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the table2 can be written also with the
database name before it: test.table2 */ database name before it: test.table2 */
size_t sql_length, /*!< in: length of sql_string */
const char* name, /*!< in: table full name in the const char* name, /*!< in: table full name in the
normalized form normalized form
database_name/table_name */ database_name/table_name */
@ -2083,8 +2101,8 @@ row_table_add_foreign_constraints(
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
err = dict_create_foreign_constraints(trx, sql_string, name, err = dict_create_foreign_constraints(trx, sql_string, sql_length,
reject_fks); name, reject_fks);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
/* Check that also referencing constraints are ok */ /* Check that also referencing constraints are ok */
err = dict_load_foreigns(name, TRUE); err = dict_load_foreigns(name, TRUE);
@ -2428,7 +2446,7 @@ row_discard_tablespace_for_mysql(
goto funct_exit; goto funct_exit;
} }
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); dict_hdr_get_new_id(&new_id, NULL, NULL);
/* Remove all locks except the table-level S and X locks. */ /* Remove all locks except the table-level S and X locks. */
lock_remove_all_on_table(table, FALSE); lock_remove_all_on_table(table, FALSE);
@ -2790,10 +2808,11 @@ row_truncate_table_for_mysql(
dict_index_t* index; dict_index_t* index;
space = 0; dict_hdr_get_new_id(NULL, NULL, &space);
if (fil_create_new_single_table_tablespace( if (space == ULINT_UNDEFINED
&space, table->name, FALSE, flags, || fil_create_new_single_table_tablespace(
space, table->name, FALSE, flags,
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
@ -2898,7 +2917,7 @@ next_rec:
mem_heap_free(heap); mem_heap_free(heap);
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); dict_hdr_get_new_id(&new_id, NULL, NULL);
info = pars_info_create(); info = pars_info_create();
@ -2942,7 +2961,7 @@ next_rec:
dict_table_autoinc_lock(table); dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, 1); dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table); dict_table_autoinc_unlock(table);
dict_update_statistics(table); dict_update_statistics(table, TRUE);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
@ -3244,6 +3263,8 @@ check_next_foreign:
" IF (SQL % NOTFOUND) THEN\n" " IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n" " found := 0;\n"
" ELSE\n" " ELSE\n"
" DELETE FROM SYS_STATS\n"
" WHERE INDEX_ID = index_id;\n"
" DELETE FROM SYS_FIELDS\n" " DELETE FROM SYS_FIELDS\n"
" WHERE INDEX_ID = index_id;\n" " WHERE INDEX_ID = index_id;\n"
" DELETE FROM SYS_INDEXES\n" " DELETE FROM SYS_INDEXES\n"

View file

@ -44,6 +44,16 @@ Created 3/14/1997 Heikki Tuuri
#include "row0mysql.h" #include "row0mysql.h"
#include "log0log.h" #include "log0log.h"
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
is enough space in the redo log before for that operation. This is
done by calling log_free_check(). The reason for checking the
availability of the redo log space before the start of the operation is
that we MUST not hold any synchonization objects when performing the
check.
If you make a change in this module make sure that no codepath is
introduced where a call to log_free_check() is bypassed. */
/********************************************************************//** /********************************************************************//**
Creates a purge node to a query graph. Creates a purge node to a query graph.
@return own: purge node */ @return own: purge node */
@ -126,6 +136,7 @@ row_purge_remove_clust_if_poss_low(
pcur = &(node->pcur); pcur = &(node->pcur);
btr_cur = btr_pcur_get_btr_cur(pcur); btr_cur = btr_pcur_get_btr_cur(pcur);
log_free_check();
mtr_start(&mtr); mtr_start(&mtr);
success = row_purge_reposition_pcur(mode, node, &mtr); success = row_purge_reposition_pcur(mode, node, &mtr);

View file

@ -863,8 +863,14 @@ row_sel_get_clust_rec(
clust_rec, index, offsets, clust_rec, index, offsets,
node->row_lock_mode, lock_type, thr); node->row_lock_mode, lock_type, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS:
case DB_SUCCESS_LOCKED_REC:
/* Declare the variable uninitialized in Valgrind.
It should be set to DB_SUCCESS at func_exit. */
UNIV_MEM_INVALID(&err, sizeof err);
break;
default:
goto err_exit; goto err_exit;
} }
} else { } else {
@ -934,9 +940,9 @@ err_exit:
/*********************************************************************//** /*********************************************************************//**
Sets a lock on a record. Sets a lock on a record.
@return DB_SUCCESS or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
UNIV_INLINE UNIV_INLINE
ulint enum db_err
sel_set_rec_lock( sel_set_rec_lock(
/*=============*/ /*=============*/
const buf_block_t* block, /*!< in: buffer block of rec */ const buf_block_t* block, /*!< in: buffer block of rec */
@ -948,8 +954,8 @@ sel_set_rec_lock(
LOC_REC_NOT_GAP */ LOC_REC_NOT_GAP */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
trx_t* trx; trx_t* trx;
ulint err; enum db_err err;
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
@ -1482,11 +1488,15 @@ rec_loop:
node->row_lock_mode, node->row_lock_mode,
lock_type, thr); lock_type, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break;
default:
/* Note that in this case we will store in pcur /* Note that in this case we will store in pcur
the PREDECESSOR of the record we are waiting the PREDECESSOR of the record we are waiting
the lock for */ the lock for */
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -1538,8 +1548,12 @@ skip_lock:
rec, index, offsets, rec, index, offsets,
node->row_lock_mode, lock_type, thr); node->row_lock_mode, lock_type, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -2498,6 +2512,7 @@ row_sel_field_store_in_mysql_format(
byte* pad_ptr; byte* pad_ptr;
ut_ad(len != UNIV_SQL_NULL); ut_ad(len != UNIV_SQL_NULL);
UNIV_MEM_ASSERT_RW(data, len);
switch (templ->type) { switch (templ->type) {
case DATA_INT: case DATA_INT:
@ -2663,6 +2678,12 @@ row_sel_store_mysql_rec(
prebuilt->blob_heap = NULL; prebuilt->blob_heap = NULL;
} }
/* init null bytes with default values as they might be
left uninitialized in some cases and these uninited bytes
might be copied into mysql record buffer that leads to
valgrind warnings */
memcpy(mysql_rec, prebuilt->default_rec, prebuilt->null_bitmap_len);
for (i = 0; i < prebuilt->n_template; i++) { for (i = 0; i < prebuilt->n_template; i++) {
templ = prebuilt->mysql_template + i; templ = prebuilt->mysql_template + i;
@ -2746,6 +2767,9 @@ row_sel_store_mysql_rec(
/* MySQL assumes that the field for an SQL /* MySQL assumes that the field for an SQL
NULL value is set to the default value. */ NULL value is set to the default value. */
UNIV_MEM_ASSERT_RW(prebuilt->default_rec
+ templ->mysql_col_offset,
templ->mysql_col_len);
mysql_rec[templ->mysql_null_byte_offset] mysql_rec[templ->mysql_null_byte_offset]
|= (byte) templ->mysql_null_bit_mask; |= (byte) templ->mysql_null_bit_mask;
memcpy(mysql_rec + templ->mysql_col_offset, memcpy(mysql_rec + templ->mysql_col_offset,
@ -2797,9 +2821,9 @@ row_sel_build_prev_vers_for_mysql(
Retrieves the clustered index record corresponding to a record in a Retrieves the clustered index record corresponding to a record in a
non-clustered index. Does the necessary locking. Used in the MySQL non-clustered index. Does the necessary locking. Used in the MySQL
interface. interface.
@return DB_SUCCESS or error code */ @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
static static
ulint enum db_err
row_sel_get_clust_rec_for_mysql( row_sel_get_clust_rec_for_mysql(
/*============================*/ /*============================*/
row_prebuilt_t* prebuilt,/*!< in: prebuilt struct in the handle */ row_prebuilt_t* prebuilt,/*!< in: prebuilt struct in the handle */
@ -2826,7 +2850,7 @@ row_sel_get_clust_rec_for_mysql(
dict_index_t* clust_index; dict_index_t* clust_index;
const rec_t* clust_rec; const rec_t* clust_rec;
rec_t* old_vers; rec_t* old_vers;
ulint err; enum db_err err;
trx_t* trx; trx_t* trx;
*out_rec = NULL; *out_rec = NULL;
@ -2885,6 +2909,7 @@ row_sel_get_clust_rec_for_mysql(
clust_rec = NULL; clust_rec = NULL;
err = DB_SUCCESS;
goto func_exit; goto func_exit;
} }
@ -2900,8 +2925,11 @@ row_sel_get_clust_rec_for_mysql(
0, btr_pcur_get_block(prebuilt->clust_pcur), 0, btr_pcur_get_block(prebuilt->clust_pcur),
clust_rec, clust_index, *offsets, clust_rec, clust_index, *offsets,
prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS:
case DB_SUCCESS_LOCKED_REC:
break;
default:
goto err_exit; goto err_exit;
} }
} else { } else {
@ -2961,6 +2989,8 @@ row_sel_get_clust_rec_for_mysql(
rec, sec_index, clust_rec, clust_index)); rec, sec_index, clust_rec, clust_index));
#endif #endif
} }
err = DB_SUCCESS;
} }
func_exit: func_exit:
@ -2973,7 +3003,6 @@ func_exit:
btr_pcur_store_position(prebuilt->clust_pcur, mtr); btr_pcur_store_position(prebuilt->clust_pcur, mtr);
} }
err = DB_SUCCESS;
err_exit: err_exit:
return(err); return(err);
} }
@ -3070,6 +3099,11 @@ row_sel_pop_cached_row_for_mysql(
for (i = 0; i < prebuilt->n_template; i++) { for (i = 0; i < prebuilt->n_template; i++) {
templ = prebuilt->mysql_template + i; templ = prebuilt->mysql_template + i;
#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
UNIV_MEM_ASSERT_RW(cached_rec
+ templ->mysql_col_offset,
templ->mysql_col_len);
#endif
ut_memcpy(buf + templ->mysql_col_offset, ut_memcpy(buf + templ->mysql_col_offset,
cached_rec + templ->mysql_col_offset, cached_rec + templ->mysql_col_offset,
templ->mysql_col_len); templ->mysql_col_len);
@ -3084,6 +3118,11 @@ row_sel_pop_cached_row_for_mysql(
} }
} }
else { else {
#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
UNIV_MEM_ASSERT_RW(prebuilt->fetch_cache
[prebuilt->fetch_cache_first],
prebuilt->mysql_prefix_len);
#endif
ut_memcpy(buf, ut_memcpy(buf,
prebuilt->fetch_cache[prebuilt->fetch_cache_first], prebuilt->fetch_cache[prebuilt->fetch_cache_first],
prebuilt->mysql_prefix_len); prebuilt->mysql_prefix_len);
@ -3134,6 +3173,8 @@ row_sel_push_cache_row_for_mysql(
} }
ut_ad(prebuilt->fetch_cache_first == 0); ut_ad(prebuilt->fetch_cache_first == 0);
UNIV_MEM_INVALID(prebuilt->fetch_cache[prebuilt->n_fetch_cached],
prebuilt->mysql_row_len);
if (UNIV_UNLIKELY(!row_sel_store_mysql_rec( if (UNIV_UNLIKELY(!row_sel_store_mysql_rec(
prebuilt->fetch_cache[ prebuilt->fetch_cache[
@ -3280,6 +3321,7 @@ row_search_for_mysql(
mem_heap_t* heap = NULL; mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_; ulint* offsets = offsets_;
ibool problematic_use = FALSE;
rec_offs_init(offsets_); rec_offs_init(offsets_);
@ -3595,6 +3637,13 @@ shortcut_fails_too_big_rec:
trx->has_search_latch = FALSE; trx->has_search_latch = FALSE;
} }
ut_ad(prebuilt->sql_stat_start || trx->conc_state == TRX_ACTIVE);
ut_ad(trx->conc_state == TRX_NOT_STARTED
|| trx->conc_state == TRX_ACTIVE);
ut_ad(prebuilt->sql_stat_start
|| prebuilt->select_lock_type != LOCK_NONE
|| trx->read_view);
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
@ -3679,8 +3728,12 @@ shortcut_fails_too_big_rec:
prebuilt->select_lock_type, prebuilt->select_lock_type,
LOCK_GAP, thr); LOCK_GAP, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -3696,6 +3749,15 @@ shortcut_fails_too_big_rec:
} }
} }
if (!prebuilt->mysql_has_locked) {
fprintf(stderr, "InnoDB: Error: row_search_for_mysql() is called without ha_innobase::external_lock()\n");
if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(stderr, trx->mysql_thd, 600);
}
problematic_use = TRUE;
}
retry_check:
if (!prebuilt->sql_stat_start) { if (!prebuilt->sql_stat_start) {
/* No need to set an intention lock or assign a read view */ /* No need to set an intention lock or assign a read view */
@ -3706,6 +3768,14 @@ shortcut_fails_too_big_rec:
" perform a consistent read\n" " perform a consistent read\n"
"InnoDB: but the read view is not assigned!\n", "InnoDB: but the read view is not assigned!\n",
stderr); stderr);
if (problematic_use) {
fprintf(stderr, "InnoDB: It may be caused by calling "
"without ha_innobase::external_lock()\n"
"InnoDB: For the first-aid, avoiding the crash. "
"But it should be fixed ASAP.\n");
prebuilt->sql_stat_start = TRUE;
goto retry_check;
}
trx_print(stderr, trx, 600); trx_print(stderr, trx, 600);
fputc('\n', stderr); fputc('\n', stderr);
ut_a(0); ut_a(0);
@ -3785,8 +3855,12 @@ rec_loop:
prebuilt->select_lock_type, prebuilt->select_lock_type,
LOCK_ORDINARY, thr); LOCK_ORDINARY, thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -3916,8 +3990,11 @@ wrong_offs:
prebuilt->select_lock_type, LOCK_GAP, prebuilt->select_lock_type, LOCK_GAP,
thr); thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -3952,8 +4029,11 @@ wrong_offs:
prebuilt->select_lock_type, LOCK_GAP, prebuilt->select_lock_type, LOCK_GAP,
thr); thr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} }
@ -4023,15 +4103,21 @@ no_gap_lock:
switch (err) { switch (err) {
const rec_t* old_vers; const rec_t* old_vers;
case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC:
if (srv_locks_unsafe_for_binlog if (srv_locks_unsafe_for_binlog
|| trx->isolation_level <= TRX_ISO_READ_COMMITTED) { || trx->isolation_level
<= TRX_ISO_READ_COMMITTED) {
/* Note that a record of /* Note that a record of
prebuilt->index was locked. */ prebuilt->index was locked. */
prebuilt->new_rec_locks = 1; prebuilt->new_rec_locks = 1;
} }
err = DB_SUCCESS;
case DB_SUCCESS:
break; break;
case DB_LOCK_WAIT: case DB_LOCK_WAIT:
/* Never unlock rows that were part of a conflict. */
prebuilt->new_rec_locks = 0;
if (UNIV_LIKELY(prebuilt->row_read_type if (UNIV_LIKELY(prebuilt->row_read_type
!= ROW_READ_TRY_SEMI_CONSISTENT) != ROW_READ_TRY_SEMI_CONSISTENT)
|| unique_search || unique_search
@ -4061,7 +4147,6 @@ no_gap_lock:
if (UNIV_LIKELY(trx->wait_lock != NULL)) { if (UNIV_LIKELY(trx->wait_lock != NULL)) {
lock_cancel_waiting_and_release( lock_cancel_waiting_and_release(
trx->wait_lock); trx->wait_lock);
prebuilt->new_rec_locks = 0;
} else { } else {
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
@ -4073,9 +4158,6 @@ no_gap_lock:
ULINT_UNDEFINED, ULINT_UNDEFINED,
&heap); &heap);
err = DB_SUCCESS; err = DB_SUCCESS;
/* Note that a record of
prebuilt->index was locked. */
prebuilt->new_rec_locks = 1;
break; break;
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
@ -4212,27 +4294,30 @@ requires_clust_rec:
err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec, err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec,
thr, &clust_rec, thr, &clust_rec,
&offsets, &heap, &mtr); &offsets, &heap, &mtr);
if (err != DB_SUCCESS) { switch (err) {
case DB_SUCCESS:
if (clust_rec == NULL) {
/* The record did not exist in the read view */
ut_ad(prebuilt->select_lock_type == LOCK_NONE);
goto next_rec;
}
break;
case DB_SUCCESS_LOCKED_REC:
ut_a(clust_rec != NULL);
if (srv_locks_unsafe_for_binlog
|| trx->isolation_level
<= TRX_ISO_READ_COMMITTED) {
/* Note that the clustered index record
was locked. */
prebuilt->new_rec_locks = 2;
}
err = DB_SUCCESS;
break;
default:
goto lock_wait_or_error; goto lock_wait_or_error;
} }
if (clust_rec == NULL) {
/* The record did not exist in the read view */
ut_ad(prebuilt->select_lock_type == LOCK_NONE);
goto next_rec;
}
if ((srv_locks_unsafe_for_binlog
|| trx->isolation_level <= TRX_ISO_READ_COMMITTED)
&& prebuilt->select_lock_type != LOCK_NONE) {
/* Note that both the secondary index record
and the clustered index record were locked. */
ut_ad(prebuilt->new_rec_locks == 1);
prebuilt->new_rec_locks = 2;
}
if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) { if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) {
/* The record is delete marked: we can skip it */ /* The record is delete marked: we can skip it */

View file

@ -46,6 +46,16 @@ Created 2/25/1997 Heikki Tuuri
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "log0log.h" #include "log0log.h"
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
is enough space in the redo log before for that operation. This is
done by calling log_free_check(). The reason for checking the
availability of the redo log space before the start of the operation is
that we MUST not hold any synchonization objects when performing the
check.
If you make a change in this module make sure that no codepath is
introduced where a call to log_free_check() is bypassed. */
/***************************************************************//** /***************************************************************//**
Removes a clustered index record. The pcur in node was positioned on the Removes a clustered index record. The pcur in node was positioned on the
record, now it is detached. record, now it is detached.
@ -152,7 +162,6 @@ row_undo_ins_remove_sec_low(
ulint err; ulint err;
mtr_t mtr; mtr_t mtr;
log_free_check();
mtr_start(&mtr); mtr_start(&mtr);
found = row_search_index_entry(index, entry, mode, &pcur, &mtr); found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
@ -335,6 +344,7 @@ row_undo_ins(
transactions. */ transactions. */
ut_a(trx_is_recv(node->trx)); ut_a(trx_is_recv(node->trx));
} else { } else {
log_free_check();
err = row_undo_ins_remove_sec(node->index, entry); err = row_undo_ins_remove_sec(node->index, entry);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
@ -346,5 +356,6 @@ row_undo_ins(
node->index = dict_table_get_next_index(node->index); node->index = dict_table_get_next_index(node->index);
} }
log_free_check();
return(row_undo_ins_remove_clust_rec(node)); return(row_undo_ins_remove_clust_rec(node));
} }

View file

@ -58,12 +58,22 @@ delete marked clustered index record was delete unmarked and possibly also
some of its fields were changed. Now, it is possible that the delete marked some of its fields were changed. Now, it is possible that the delete marked
version has become obsolete at the time the undo is started. */ version has become obsolete at the time the undo is started. */
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
is enough space in the redo log before for that operation. This is
done by calling log_free_check(). The reason for checking the
availability of the redo log space before the start of the operation is
that we MUST not hold any synchonization objects when performing the
check.
If you make a change in this module make sure that no codepath is
introduced where a call to log_free_check() is bypassed. */
/***********************************************************//** /***********************************************************//**
Checks if also the previous version of the clustered index record was Checks if also the previous version of the clustered index record was
modified or inserted by the same transaction, and its undo number is such modified or inserted by the same transaction, and its undo number is such
that it should be undone in the same rollback. that it should be undone in the same rollback.
@return TRUE if also previous modify or insert of this row should be undone */ @return TRUE if also previous modify or insert of this row should be undone */
UNIV_INLINE static
ibool ibool
row_undo_mod_undo_also_prev_vers( row_undo_mod_undo_also_prev_vers(
/*=============================*/ /*=============================*/
@ -231,6 +241,8 @@ row_undo_mod_clust(
ut_ad(node && thr); ut_ad(node && thr);
log_free_check();
/* Check if also the previous version of the clustered index record /* Check if also the previous version of the clustered index record
should be undone in this same rollback operation */ should be undone in this same rollback operation */
@ -657,24 +669,55 @@ row_undo_mod_upd_exist_sec(
/* Build the newest version of the index entry */ /* Build the newest version of the index entry */
entry = row_build_index_entry(node->row, node->ext, entry = row_build_index_entry(node->row, node->ext,
index, heap); index, heap);
ut_a(entry); if (UNIV_UNLIKELY(!entry)) {
/* NOTE that if we updated the fields of a /* The server must have crashed in
delete-marked secondary index record so that row_upd_clust_rec_by_insert(), in
alphabetically they stayed the same, e.g., row_ins_index_entry_low() before
'abc' -> 'aBc', we cannot return to the original btr_store_big_rec_extern_fields()
values because we do not know them. But this should has written the externally stored columns
not cause problems because in row0sel.c, in queries (BLOBs) of the new clustered index entry. */
we always retrieve the clustered index record or an
earlier version of it, if the secondary index record
through which we do the search is delete-marked. */
err = row_undo_mod_del_mark_or_remove_sec(node, thr, /* The table must be in DYNAMIC or COMPRESSED
index, format. REDUNDANT and COMPACT formats
entry); store a local 768-byte prefix of each
if (err != DB_SUCCESS) { externally stored column. */
mem_heap_free(heap); ut_a(dict_table_get_format(index->table)
>= DICT_TF_FORMAT_ZIP);
return(err); /* This is only legitimate when
rolling back an incomplete transaction
after crash recovery. */
ut_a(thr_get_trx(thr)->is_recovered);
/* The server must have crashed before
completing the insert of the new
clustered index entry and before
inserting to the secondary indexes.
Because node->row was not yet written
to this index, we can ignore it. But
we must restore node->undo_row. */
} else {
/* NOTE that if we updated the fields of a
delete-marked secondary index record so that
alphabetically they stayed the same, e.g.,
'abc' -> 'aBc', we cannot return to the
original values because we do not know them.
But this should not cause problems because
in row0sel.c, in queries we always retrieve
the clustered index record or an earlier
version of it, if the secondary index record
through which we do the search is
delete-marked. */
err = row_undo_mod_del_mark_or_remove_sec(
node, thr, index, entry);
if (err != DB_SUCCESS) {
mem_heap_free(heap);
return(err);
}
mem_heap_empty(heap);
} }
/* We may have to update the delete mark in the /* We may have to update the delete mark in the
@ -683,7 +726,6 @@ row_undo_mod_upd_exist_sec(
the secondary index record if we updated its fields the secondary index record if we updated its fields
but alphabetically they stayed the same, e.g., but alphabetically they stayed the same, e.g.,
'abc' -> 'aBc'. */ 'abc' -> 'aBc'. */
mem_heap_empty(heap);
entry = row_build_index_entry(node->undo_row, entry = row_build_index_entry(node->undo_row,
node->undo_ext, node->undo_ext,
index, heap); index, heap);

View file

@ -297,7 +297,7 @@ row_undo(
if (locked_data_dict) { if (locked_data_dict) {
row_mysql_lock_data_dictionary(trx); row_mysql_freeze_data_dictionary(trx);
} }
if (node->state == UNDO_NODE_INSERT) { if (node->state == UNDO_NODE_INSERT) {
@ -312,7 +312,7 @@ row_undo(
if (locked_data_dict) { if (locked_data_dict) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unfreeze_data_dictionary(trx);
} }
/* Do some cleanup */ /* Do some cleanup */

Some files were not shown because too many files have changed in this diff Show more