diff options
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/btr/btr0sea.c | 74 | ||||
-rw-r--r-- | innobase/buf/buf0buf.c | 25 | ||||
-rw-r--r-- | innobase/buf/buf0flu.c | 7 | ||||
-rw-r--r-- | innobase/buf/buf0lru.c | 2 | ||||
-rw-r--r-- | innobase/buf/buf0rea.c | 7 | ||||
-rw-r--r-- | innobase/fil/fil0fil.c | 10 | ||||
-rw-r--r-- | innobase/ha/ha0ha.c | 125 | ||||
-rw-r--r-- | innobase/include/buf0buf.h | 16 | ||||
-rw-r--r-- | innobase/include/buf0flu.ic | 2 | ||||
-rw-r--r-- | innobase/include/fil0fil.h | 2 | ||||
-rw-r--r-- | innobase/include/ha0ha.h | 18 | ||||
-rw-r--r-- | innobase/include/hash0hash.h | 18 | ||||
-rw-r--r-- | innobase/include/os0file.h | 3 | ||||
-rw-r--r-- | innobase/include/row0mysql.h | 15 | ||||
-rw-r--r-- | innobase/include/srv0srv.h | 104 | ||||
-rw-r--r-- | innobase/include/trx0trx.h | 2 | ||||
-rw-r--r-- | innobase/lock/lock0lock.c | 30 | ||||
-rw-r--r-- | innobase/log/log0log.c | 17 | ||||
-rw-r--r-- | innobase/os/os0file.c | 28 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 51 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 31 | ||||
-rw-r--r-- | innobase/srv/srv0srv.c | 106 |
22 files changed, 574 insertions, 119 deletions
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index 9384168df88..ad74f9704da 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -435,8 +435,8 @@ btr_search_update_hash_ref( ha_insert_for_fold(btr_search_sys->hash_index, fold, rec); } -} - +} + /************************************************************************* Updates the search info. */ @@ -915,17 +915,6 @@ btr_search_drop_page_hash_index( { hash_table_t* table; buf_block_t* block; - ulint n_fields; - ulint n_bytes; - rec_t* rec; - rec_t* sup; - ulint fold; - ulint prev_fold; - dulint tree_id; - ulint n_cached; - ulint n_recs; - ulint* folds; - ulint i; #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); @@ -951,72 +940,17 @@ btr_search_drop_page_hash_index( || (block->buf_fix_count == 0)); #endif /* UNIV_SYNC_DEBUG */ - n_fields = block->curr_n_fields; - n_bytes = block->curr_n_bytes; - - ut_a(n_fields + n_bytes > 0); + ut_a(block->curr_n_fields + block->curr_n_bytes > 0); rw_lock_s_unlock(&btr_search_latch); - n_recs = page_get_n_recs(page); - - /* Calculate and cache fold values into an array for fast deletion - from the hash index */ - - folds = mem_alloc(n_recs * sizeof(ulint)); - - n_cached = 0; - - sup = page_get_supremum_rec(page); - - rec = page_get_infimum_rec(page); - rec = page_rec_get_next(rec); - - if (rec != sup) { - ut_a(n_fields <= rec_get_n_fields(rec)); - - if (n_bytes > 0) { - ut_a(n_fields < rec_get_n_fields(rec)); - } - } - - tree_id = btr_page_get_index_id(page); - - prev_fold = 0; - - while (rec != sup) { - /* FIXME: in a mixed tree, not all records may have enough - ordering fields: */ - - fold = rec_fold(rec, n_fields, n_bytes, tree_id); - - if (fold == prev_fold && prev_fold != 0) { - - goto next_rec; - } - - /* Remove all hash nodes pointing to this page from the - hash chain */ - - folds[n_cached] = fold; - n_cached++; -next_rec: - rec = page_rec_get_next(rec); - prev_fold = fold; - } - rw_lock_x_lock(&btr_search_latch); - for (i = 0; i < n_cached; i++) { - - ha_remove_all_nodes_to_page(table, folds[i], page); - } + ha_remove_all_nodes_to_page(table, page); block->is_hashed = FALSE; rw_lock_x_unlock(&btr_search_latch); - - mem_free(folds); } /************************************************************************ diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index adb69f3c3a7..376deedabec 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -465,6 +465,7 @@ buf_block_init( block->in_LRU_list = FALSE; block->n_pointers = 0; + block->hash_nodes = NULL; rw_lock_create(&(block->lock)); ut_ad(rw_lock_validate(&(block->lock))); @@ -2136,6 +2137,30 @@ buf_print(void) } /************************************************************************* +Returns the number of latched pages in the buffer pool. */ + +ulint +buf_get_latched_pages_number(void) +{ + buf_block_t* block; + ulint i; + ulint fixed_pages_number = 0; + + mutex_enter(&(buf_pool->mutex)); + + for (i = 0; i < buf_pool->curr_size; i++) { + + block = buf_pool_get_nth_block(buf_pool, i); + + if ((block->buf_fix_count != 0) || (block->io_fix != 0)) + fixed_pages_number++; + } + + mutex_exit(&(buf_pool->mutex)); + return fixed_pages_number; +} + +/************************************************************************* Returns the number of pending buf pool ios. */ ulint diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 964c396dd08..aff4fe92a71 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -273,6 +273,10 @@ buf_flush_buffered_writes(void) } } + /* increment the doublewrite flushed pages counter */ + srv_dblwr_pages_written+= trx_doublewrite->first_free; + srv_dblwr_writes++; + if (trx_doublewrite->first_free > TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) { len = TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE; } else { @@ -901,6 +905,9 @@ buf_flush_batch( (ulong) page_count); } + if (page_count != ULINT_UNDEFINED) + srv_buf_pool_flushed+= page_count; + return(page_count); } diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 796311f0157..42e3b363ced 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -432,6 +432,7 @@ loop: /* No free block was found: try to flush the LRU list */ buf_flush_free_margin(); + ++srv_buf_pool_wait_free; os_aio_simulated_wake_handler_threads(); @@ -789,6 +790,7 @@ buf_LRU_block_free_non_file_page( || (block->state == BUF_BLOCK_READY_FOR_USE)); ut_a(block->n_pointers == 0); + ut_a(block->hash_nodes == NULL); ut_a(!block->in_free_list); block->state = BUF_BLOCK_NOT_USED; diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c index 11107d777c8..f34920549fe 100644 --- a/innobase/buf/buf0rea.c +++ b/innobase/buf/buf0rea.c @@ -20,6 +20,10 @@ Created 11/5/1995 Heikki Tuuri #include "os0file.h" #include "srv0start.h" +extern ulint srv_read_ahead_rnd; +extern ulint srv_read_ahead_seq; +extern ulint srv_buf_pool_reads; + /* The size in blocks of the area where the random read-ahead algorithm counts the accessed pages when deciding whether to read-ahead */ #define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA @@ -291,6 +295,7 @@ buf_read_ahead_random( (ulong) count); } + ++srv_read_ahead_rnd; return(count); } @@ -323,6 +328,7 @@ buf_read_page( count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, tablespace_version, offset); + srv_buf_pool_reads+= count2; if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, @@ -575,6 +581,7 @@ buf_read_ahead_linear( (ulong) space, (ulong) offset, (ulong) count); } + ++srv_read_ahead_seq; return(count); } diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index de528355182..6d3ffcd63f3 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -88,6 +88,9 @@ but in the MySQL Embedded Server Library and ibbackup it is not the default directory, and we must set the base file path explicitly */ const char* fil_path_to_mysql_datadir = "."; +/* The number of fsyncs done to the log */ +ulint fil_n_log_flushes = 0; + ulint fil_n_pending_log_flushes = 0; ulint fil_n_pending_tablespace_flushes = 0; @@ -3684,6 +3687,12 @@ fil_io( mode = OS_AIO_NORMAL; } + if (type == OS_FILE_READ) { + srv_data_read+= len; + } else if (type == OS_FILE_WRITE) { + srv_data_written+= len; + } + /* Reserve the fil_system mutex and make sure that we can open at least one file while holding it, if the file is not already open */ @@ -3969,6 +3978,7 @@ fil_flush( fil_n_pending_tablespace_flushes++; } else { fil_n_pending_log_flushes++; + fil_n_log_flushes++; } #ifdef __WIN__ if (node->is_raw_disk) { diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index ad1391ff83e..49b59882626 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -66,9 +66,52 @@ ha_create( } /***************************************************************** +Removes an adaptive hash index node from the doubly linked list of hash nodes +for the buffer block. */ +UNIV_INLINE +void +ha_remove_buf_block_node( +/*=====================*/ + buf_block_t* block, /* in: buffer block */ + ha_node_t* node) /* in: an adaptive hash index node */ +{ + if (node == block->hash_nodes) { + block->hash_nodes = node->next_for_block; + } + + if (node->prev_for_block != NULL) { + (node->prev_for_block)->next_for_block = node->next_for_block; + } + + if (node->next_for_block != NULL) { + (node->next_for_block)->prev_for_block = node->prev_for_block; + } +} + +/***************************************************************** +Adds an adaptive hash index node to the start of the doubly linked list of +hash nodes for the buffer block. */ +UNIV_INLINE +void +ha_add_buf_block_node( +/*==================*/ + buf_block_t* block, /* in: buffer block */ + ha_node_t* node) /* in: an adaptive hash index node */ +{ + node->next_for_block = block->hash_nodes; + node->prev_for_block = NULL; + + block->hash_nodes = node; + + if (node->next_for_block != NULL) { + (node->next_for_block)->prev_for_block = node; + } +} + +/***************************************************************** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node -is inserted. */ +is inserted. This function is only used in the adaptive hash index. */ ibool ha_insert_for_fold( @@ -84,6 +127,7 @@ ha_insert_for_fold( { hash_cell_t* cell; ha_node_t* node; + buf_block_t* block; ha_node_t* prev_node; buf_block_t* prev_block; ulint hash; @@ -92,6 +136,9 @@ ha_insert_for_fold( #ifdef UNIV_SYNC_DEBUG ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold))); #endif /* UNIV_SYNC_DEBUG */ + + block = buf_block_align(data); + hash = hash_calc_hash(fold, table); cell = hash_get_nth_cell(table, hash); @@ -104,7 +151,15 @@ ha_insert_for_fold( prev_block = buf_block_align(prev_node->data); ut_a(prev_block->n_pointers > 0); prev_block->n_pointers--; - buf_block_align(data)->n_pointers++; + + block->n_pointers++; + + if (prev_block != block) { + ha_remove_buf_block_node(prev_block, + prev_node); + ha_add_buf_block_node(block, + prev_node); + } } prev_node->data = data; @@ -131,7 +186,9 @@ ha_insert_for_fold( ha_node_set_data(node, data); if (table->adaptive) { - buf_block_align(data)->n_pointers++; + block->n_pointers++; + + ha_add_buf_block_node(block, node); } node->fold = fold; @@ -166,9 +223,15 @@ ha_delete_hash_node( hash_table_t* table, /* in: hash table */ ha_node_t* del_node) /* in: node to be deleted */ { + buf_block_t* block; + if (table->adaptive) { - ut_a(buf_block_align(del_node->data)->n_pointers > 0); - buf_block_align(del_node->data)->n_pointers--; + block = buf_block_align(del_node->data); + + ut_a(block->n_pointers > 0); + + block->n_pointers--; + ha_remove_buf_block_node(block, del_node); } HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node); @@ -209,6 +272,8 @@ ha_search_and_update_if_found( void* data, /* in: pointer to the data */ void* new_data)/* in: new pointer to the data */ { + buf_block_t* old_block; + buf_block_t* block; ha_node_t* node; #ifdef UNIV_SYNC_DEBUG @@ -220,8 +285,15 @@ ha_search_and_update_if_found( if (node) { if (table->adaptive) { ut_a(buf_block_align(node->data)->n_pointers > 0); - buf_block_align(node->data)->n_pointers--; - buf_block_align(new_data)->n_pointers++; + + old_block = buf_block_align(node->data); + ut_a(old_block->n_pointers > 0); + old_block->n_pointers--; + ha_remove_buf_block_node(old_block, node); + + block = buf_block_align(new_data); + block->n_pointers++; + ha_add_buf_block_node(block, node); } node->data = new_data; @@ -236,43 +308,25 @@ void ha_remove_all_nodes_to_page( /*========================*/ hash_table_t* table, /* in: hash table */ - ulint fold, /* in: fold value */ page_t* page) /* in: buffer page */ { + buf_block_t* block; ha_node_t* node; -#ifdef UNIV_SYNC_DEBUG - ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold))); -#endif /* UNIV_SYNC_DEBUG */ - node = ha_chain_get_first(table, fold); - - while (node) { - if (buf_frame_align(ha_node_get_data(node)) == page) { + block = buf_block_align(page); - /* Remove the hash node */ + node = block->hash_nodes; - ha_delete_hash_node(table, node); + while (node) { + /* Remove the hash node */ - /* Start again from the first node in the chain - because the deletion may compact the heap of - nodes and move other nodes! */ + ha_delete_hash_node(table, node); - node = ha_chain_get_first(table, fold); - } else { - node = ha_chain_get_next(node); - } + node = block->hash_nodes; } -#ifdef UNIV_DEBUG - /* Check that all nodes really got deleted */ - node = ha_chain_get_first(table, fold); - - while (node) { - ut_a(buf_frame_align(ha_node_get_data(node)) != page); - - node = ha_chain_get_next(node); - } -#endif + ut_a(block->n_pointers == 0); + ut_a(block->hash_nodes == NULL); } /***************************************************************** @@ -352,6 +406,7 @@ ha_print_info( n_bufs++; } - fprintf(file, ", node heap has %lu buffer(s)\n", (ulong) n_bufs); + fprintf(file, ", node heap has %lu buffer(s)\n", + (ulong) n_bufs); } } diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 53599d03c73..b46b8ce40be 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -29,6 +29,7 @@ Created 11/5/1995 Heikki Tuuri #include "buf0types.h" #include "sync0rw.h" #include "hash0hash.h" +#include "ha0ha.h" #include "ut0byte.h" #include "os0proc.h" @@ -57,6 +58,8 @@ extern buf_pool_t* buf_pool; /* The buffer pool of the database */ extern ibool buf_debug_prints;/* If this is set TRUE, the program prints info whenever read or flush occurs */ +extern ulint srv_buf_pool_write_requests; /* variable to count write request + issued */ /************************************************************************ Creates the buffer pool. */ @@ -496,6 +499,12 @@ void buf_print(void); /*============*/ /************************************************************************* +Returns the number of latched pages in the buffer pool. */ + +ulint +buf_get_latched_pages_number(void); +/*==============================*/ +/************************************************************************* Returns the number of pending buf pool ios. */ ulint @@ -817,7 +826,7 @@ struct buf_block_struct{ records with the same prefix should be indexed in the hash index */ - /* The following 4 fields are protected by btr_search_latch: */ + /* The following 6 fields are protected by btr_search_latch: */ ibool is_hashed; /* TRUE if hash index has already been built on this page; note that it does @@ -834,6 +843,11 @@ struct buf_block_struct{ ulint curr_side; /* BTR_SEARCH_LEFT_SIDE or BTR_SEARCH_RIGHT_SIDE in hash indexing */ + ha_node_t* hash_nodes; /* a doubly linked list of hash nodes + for this buffer block; this points to + the first node in the list if any; + note that we do not use UT_LST_ macros + to manipulate this list */ /* 6. Debug fields */ #ifdef UNIV_SYNC_DEBUG rw_lock_t debug_latch; /* in the debug version, each thread diff --git a/innobase/include/buf0flu.ic b/innobase/include/buf0flu.ic index d6dbdcc0865..9a8a021e029 100644 --- a/innobase/include/buf0flu.ic +++ b/innobase/include/buf0flu.ic @@ -61,6 +61,8 @@ buf_flush_note_modification( ut_ad(ut_dulint_cmp(block->oldest_modification, mtr->start_lsn) <= 0); } + + ++srv_buf_pool_write_requests; } /************************************************************************ diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 43327aab9d2..75b32937e0b 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -89,6 +89,8 @@ extern fil_addr_t fil_addr_null; #define FIL_TABLESPACE 501 #define FIL_LOG 502 +extern ulint fil_n_log_flushes; + extern ulint fil_n_pending_log_flushes; extern ulint fil_n_pending_tablespace_flushes; diff --git a/innobase/include/ha0ha.h b/innobase/include/ha0ha.h index bdaecfcc57a..5e3af9c1869 100644 --- a/innobase/include/ha0ha.h +++ b/innobase/include/ha0ha.h @@ -54,7 +54,7 @@ ha_create( /***************************************************************** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node -is inserted. */ +is inserted. This function is only used in the adaptive hash index. */ ibool ha_insert_for_fold( @@ -111,7 +111,6 @@ void ha_remove_all_nodes_to_page( /*========================*/ hash_table_t* table, /* in: hash table */ - ulint fold, /* in: fold value */ page_t* page); /* in: buffer page */ /***************************************************************** Validates a hash table. */ @@ -134,9 +133,18 @@ ha_print_info( typedef struct ha_node_struct ha_node_t; struct ha_node_struct { - ha_node_t* next; /* next chain node or NULL if none */ - void* data; /* pointer to the data */ - ulint fold; /* fold value for the data */ + ha_node_t* next; /* next chain node; NULL if none */ + void* data; /* pointer to the data */ + ulint fold; /* fold value for the data */ + ha_node_t* next_for_block;/* in an adaptive hash index + (btr0sea.c), a doubly linked list of hash + nodes for the buffer block; these nodes + contain pointers to index records on the + page; in the last node this field is NULL; + note that we do not use UT_LST_ macros + to manipulate this list */ + ha_node_t* prev_for_block;/* pointer to the previous node; in the + first node NULL */ }; #ifndef UNIV_NONINL diff --git a/innobase/include/hash0hash.h b/innobase/include/hash0hash.h index 51315e40875..befe8a8d757 100644 --- a/innobase/include/hash0hash.h +++ b/innobase/include/hash0hash.h @@ -166,7 +166,7 @@ hash_get_n_cells( /*********************************************************************** Deletes a struct which is stored in the heap of the hash table, and compacts the heap. The fold value must be stored in the struct NODE in a field named -'fold'. */ +'fold'. This macro is only used for the adaptive hash index. */ #define HASH_DELETE_AND_COMPACT(TYPE, NAME, TABLE, NODE)\ do {\ @@ -192,11 +192,23 @@ do {\ \ *(NODE) = *top_node111;\ \ + /* Update the adaptive hash list of the buffer block that\ + corresponds to the top node */\ + if (top_node111->next_for_block != NULL) {\ + (top_node111->next_for_block)->prev_for_block = NODE;\ + }\ +\ + if (top_node111->prev_for_block != NULL) {\ + (top_node111->prev_for_block)->next_for_block = NODE;\ + } else {\ + buf_block_align(top_node111->data)->hash_nodes = NODE;\ + }\ +\ + /* Look for the hash pointer to the top node, to update it */\ +\ cell111 = hash_get_nth_cell(TABLE,\ hash_calc_hash(top_node111->fold, TABLE));\ \ - /* Look for the pointer to the top node, to update it */\ -\ if (cell111->node == top_node111) {\ /* The top node is the first in the chain */\ \ diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index d1439faf29f..599e78bab48 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -24,6 +24,9 @@ extern ibool os_aio_print_debug; extern ulint os_file_n_pending_preads; extern ulint os_file_n_pending_pwrites; +extern ulint os_n_pending_reads; +extern ulint os_n_pending_writes; + #ifdef __WIN__ /* We define always WIN_ASYNC_IO, and check at run-time whether diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 73f41dea0da..d4634482752 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -237,6 +237,17 @@ row_update_for_mysql( the MySQL format */ row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ + +/************************************************************************* +Does an unlock of a row for MySQL. */ + +int +row_unlock_for_mysql( +/*=================*/ + /* out: error code or DB_SUCCESS */ + row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL + handle */ + /************************************************************************* Creates an query graph node of 'update' type to be used in the MySQL interface. */ @@ -583,6 +594,10 @@ struct row_prebuilt_struct { allocated mem buf start, because there is a 4 byte magic number at the start and at the end */ + ibool keep_other_fields_on_keyread; /* when using fetch + cache with HA_EXTRA_KEYREAD, don't + overwrite other fields in mysql row + row buffer.*/ ulint fetch_cache_first;/* position of the first not yet fetched row in fetch_cache */ ulint n_fetch_cached; /* number of not yet fetched rows diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 6cfe9cef927..b9963d93265 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -184,6 +184,63 @@ i/o handler thread */ extern const char* srv_io_thread_op_info[]; extern const char* srv_io_thread_function[]; +/* the number of the log write requests done */ +extern ulint srv_log_write_requests; + +/* the number of physical writes to the log performed */ +extern ulint srv_log_writes; + +/* amount of data written to the log files in bytes */ +extern ulint srv_os_log_written; + +/* amount of writes being done to the log files */ +extern ulint srv_os_log_pending_writes; + +/* we increase this counter, when there we don't have enough space in the +log buffer and have to flush it */ +extern ulint srv_log_waits; + +/* variable that counts amount of data read in total (in bytes) */ +extern ulint srv_data_read; + +/* here we count the amount of data written in total (in bytes) */ +extern ulint srv_data_written; + +/* this variable counts the amount of times, when the doublewrite buffer +was flushed */ +extern ulint srv_dblwr_writes; + +/* here we store the number of pages that have been flushed to the +doublewrite buffer */ +extern ulint srv_dblwr_pages_written; + +/* in this variable we store the number of write requests issued */ +extern ulint srv_buf_pool_write_requests; + +/* here we store the number of times when we had to wait for a free page +in the buffer pool. It happens when the buffer pool is full and we need +to make a flush, in order to be able to read or create a page. */ +extern ulint srv_buf_pool_wait_free; + +/* variable to count the number of pages that were written from the +buffer pool to disk */ +extern ulint srv_buf_pool_flushed; + +/* variable to count the number of buffer pool reads that led to the +reading of a disk page */ +extern ulint srv_buf_pool_reads; + +/* variable to count the number of sequential read-aheads were done */ +extern ulint srv_read_ahead_seq; + +/* variable to count the number of random read-aheads were done */ +extern ulint srv_read_ahead_rnd; + +/* In this structure we store status variables to be passed to MySQL */ +typedef struct export_var_struct export_struc; + +extern export_struc export_vars; + typedef struct srv_sys_struct srv_sys_t; /* The server system */ @@ -400,7 +457,12 @@ void srv_printf_innodb_monitor( /*======================*/ FILE* file); /* in: output stream */ +/************************************************************************ +Function to pass InnoDB status variables to MySQL */ +void +srv_export_innodb_status(void); +/*=====================*/ /* Types for the threads existing in the system. Threads of types 4 - 9 are called utility threads. Note that utility threads are mainly disk @@ -426,6 +488,48 @@ typedef struct srv_slot_struct srv_slot_t; /* Thread table is an array of slots */ typedef srv_slot_t srv_table_t; +/* In this structure we store status variables to be passed to MySQL */ +struct export_var_struct{ + ulint innodb_data_pending_reads; + ulint innodb_data_pending_writes; + ulint innodb_data_pending_fsyncs; + ulint innodb_data_fsyncs; + ulint innodb_data_read; + ulint innodb_data_writes; + ulint innodb_data_written; + ulint innodb_data_reads; + ulint innodb_buffer_pool_pages_total; + ulint innodb_buffer_pool_pages_data; + ulint innodb_buffer_pool_pages_dirty; + ulint innodb_buffer_pool_pages_misc; + ulint innodb_buffer_pool_pages_free; + ulint innodb_buffer_pool_pages_latched; + ulint innodb_buffer_pool_read_requests; + ulint innodb_buffer_pool_reads; + ulint innodb_buffer_pool_wait_free; + ulint innodb_buffer_pool_pages_flushed; + ulint innodb_buffer_pool_write_requests; + ulint innodb_buffer_pool_read_ahead_seq; + ulint innodb_buffer_pool_read_ahead_rnd; + ulint innodb_dblwr_pages_written; + ulint innodb_dblwr_writes; + ulint innodb_log_waits; + ulint innodb_log_write_requests; + ulint innodb_log_writes; + ulint innodb_os_log_written; + ulint innodb_os_log_fsyncs; + ulint innodb_os_log_pending_writes; + ulint innodb_os_log_pending_fsyncs; + ulint innodb_page_size; + ulint innodb_pages_created; + ulint innodb_pages_read; + ulint innodb_pages_written; + ulint innodb_rows_read; + ulint innodb_rows_inserted; + ulint innodb_rows_updated; + ulint innodb_rows_deleted; +}; + /* The server system struct */ struct srv_sys_struct{ os_event_t operational; /* created threads must wait for the diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 7eb91048684..602291f946a 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -423,6 +423,8 @@ struct trx_struct{ lock_t* auto_inc_lock; /* possible auto-inc lock reserved by the transaction; note that it is also in the lock list trx_locks */ + ibool trx_create_lock;/* this is TRUE if we have created a + new lock for a record accessed */ ulint n_lock_table_exp;/* number of explicit table locks (LOCK TABLES) reserved by the transaction, stored in trx_locks */ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 6f2d58b72c3..98def88fa31 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -1630,6 +1630,9 @@ lock_rec_create( HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock); + /* Note that we have create a new lock */ + trx->trx_create_lock = TRUE; + if (type_mode & LOCK_WAIT) { lock_set_lock_and_trx_wait(lock, trx); @@ -1804,6 +1807,15 @@ lock_rec_add_to_queue( if (similar_lock && !somebody_waits && !(type_mode & LOCK_WAIT)) { + /* If the nth bit of a record lock is already set then we + do not set a new lock bit, otherwice we set */ + + if (lock_rec_get_nth_bit(similar_lock, heap_no)) { + trx->trx_create_lock = FALSE; + } else { + trx->trx_create_lock = TRUE; + } + lock_rec_set_nth_bit(similar_lock, heap_no); return(similar_lock); @@ -1835,6 +1847,7 @@ lock_rec_lock_fast( { lock_t* lock; ulint heap_no; + trx_t* trx; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); @@ -1853,9 +1866,12 @@ lock_rec_lock_fast( lock = lock_rec_get_first_on_page(rec); + trx = thr_get_trx(thr); + trx->trx_create_lock = FALSE; + if (lock == NULL) { if (!impl) { - lock_rec_create(mode, rec, index, thr_get_trx(thr)); + lock_rec_create(mode, rec, index, trx); } return(TRUE); @@ -1866,13 +1882,23 @@ lock_rec_lock_fast( return(FALSE); } - if (lock->trx != thr_get_trx(thr) + if (lock->trx != trx || lock->type_mode != (mode | LOCK_REC) || lock_rec_get_n_bits(lock) <= heap_no) { return(FALSE); } if (!impl) { + + /* If the nth bit of a record lock is already set then we + do not set a new lock bit, otherwice we set */ + + if (lock_rec_get_nth_bit(lock, heap_no)) { + trx->trx_create_lock = FALSE; + } else { + trx->trx_create_lock = TRUE; + } + lock_rec_set_nth_bit(lock, heap_no); } diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index e08adb013b5..1ab91b71e8f 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -190,6 +190,8 @@ loop: log_buffer_flush_to_disk(); + srv_log_waits++; + ut_ad(++count < 50); goto loop; @@ -292,6 +294,8 @@ part_loop: if (str_len > 0) { goto part_loop; } + + srv_log_write_requests++; } /**************************************************************** @@ -1112,11 +1116,15 @@ log_group_file_header_flush( if (log_do_write) { log_sys->n_log_ios++; + srv_os_log_pending_writes++; + fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, dest_offset / UNIV_PAGE_SIZE, dest_offset % UNIV_PAGE_SIZE, OS_FILE_LOG_BLOCK_SIZE, buf, group); + + srv_os_log_pending_writes--; } } @@ -1181,6 +1189,8 @@ loop: log_group_file_header_flush(group, next_offset / group->file_size, start_lsn); + srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE; + srv_log_writes++; } if ((next_offset % group->file_size) + len > group->file_size) { @@ -1225,9 +1235,16 @@ loop: if (log_do_write) { log_sys->n_log_ios++; + srv_os_log_pending_writes++; + fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, next_offset / UNIV_PAGE_SIZE, next_offset % UNIV_PAGE_SIZE, write_len, buf, group); + + srv_os_log_pending_writes--; + + srv_os_log_written+= write_len; + srv_log_writes++; } if (write_len < len) { diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 5c140e4b798..7aed4a4ab0e 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -155,6 +155,10 @@ os_mutex_t os_file_count_mutex; ulint os_file_n_pending_preads = 0; ulint os_file_n_pending_pwrites = 0; +/* These are not protected by any mutex */ +ulint os_n_pending_writes = 0; +ulint os_n_pending_reads = 0; + /*************************************************************************** Gets the operating system version. Currently works only on Windows. */ @@ -1987,8 +1991,12 @@ try_again: goto error_handling; } + os_n_pending_reads++; + ret = ReadFile(file, buf, n, &len, NULL); + os_n_pending_reads--; + os_mutex_exit(os_file_seek_mutexes[i]); if (ret && len == n) { @@ -2001,8 +2009,12 @@ try_again: os_bytes_read_since_printout += n; try_again: + os_n_pending_reads++; + ret = os_file_pread(file, buf, n, offset, offset_high); + os_n_pending_reads--; + if ((ulint)ret == n) { return(TRUE); @@ -2090,8 +2102,12 @@ try_again: goto error_handling; } + os_n_pending_reads++; + ret = ReadFile(file, buf, n, &len, NULL); + os_n_pending_reads--; + os_mutex_exit(os_file_seek_mutexes[i]); if (ret && len == n) { @@ -2104,8 +2120,12 @@ try_again: os_bytes_read_since_printout += n; try_again: + os_n_pending_reads++; + ret = os_file_pread(file, buf, n, offset, offset_high); + os_n_pending_reads--; + if ((ulint)ret == n) { return(TRUE); @@ -2187,7 +2207,11 @@ retry: return(FALSE); } + os_n_pending_writes++; + ret = WriteFile(file, buf, n, &len, NULL); + + os_n_pending_writes--; /* Always do fsync to reduce the probability that when the OS crashes, a database page is only partially physically written to disk. */ @@ -2248,8 +2272,12 @@ retry: #else ssize_t ret; + os_n_pending_writes++; + ret = os_file_pwrite(file, buf, n, offset, offset_high); + os_n_pending_writes--; + if ((ulint)ret == n) { return(TRUE); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 17747ae2a8e..6ac8c943dc6 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1194,6 +1194,57 @@ run_again: return((int) err); } +/************************************************************************* +Does an unlock of a row for MySQL. */ + +int +row_unlock_for_mysql( +/*=================*/ + /* out: error code or DB_SUCCESS */ + row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL + handle */ +{ + rec_t* rec; + btr_pcur_t* cur = prebuilt->pcur; + trx_t* trx = prebuilt->trx; + mtr_t mtr; + + ut_ad(prebuilt && trx); + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); + + trx->op_info = "unlock_row"; + + if (srv_locks_unsafe_for_binlog) { + if (trx->trx_create_lock == TRUE) { + + mtr_start(&mtr); + + /* Restore a cursor position and find a record */ + btr_pcur_restore_position(BTR_SEARCH_LEAF, cur, &mtr); + rec = btr_pcur_get_rec(cur); + + if (rec) { + + lock_rec_reset_and_release_wait(rec); + } else { + fputs("InnoDB: Error: " + "Record for the lock not found\n", + stderr); + mem_analyze_corruption((byte*) trx); + ut_error; + } + + trx->trx_create_lock = FALSE; + mtr_commit(&mtr); + } + + } + + trx->op_info = ""; + + return(DB_SUCCESS); +} + /************************************************************************** Does a cascaded delete or set null in a foreign key operation. */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 740241fa210..71163bc35b6 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2632,10 +2632,35 @@ row_sel_pop_cached_row_for_mysql( row */ row_prebuilt_t* prebuilt) /* in: prebuilt struct */ { - ut_ad(prebuilt->n_fetch_cached > 0); + ulint i; + mysql_row_templ_t* templ; + byte* cached_rec; + ut_ad(prebuilt->n_fetch_cached > 0); + + if (prebuilt->keep_other_fields_on_keyread) + { + /* Copy cache record field by field, don't touch fields that + are not covered by current key */ + cached_rec = + prebuilt->fetch_cache[prebuilt->fetch_cache_first]; + + for (i = 0; i < prebuilt->n_template; i++) { + templ = prebuilt->mysql_template + i; + ut_memcpy( + buf + templ->mysql_col_offset, + cached_rec + templ->mysql_col_offset, + templ->mysql_col_len); - ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first], - prebuilt->mysql_row_len); + if (templ->mysql_null_bit_mask) + buf[templ->mysql_null_byte_offset] &= + cached_rec[templ->mysql_null_byte_offset]; + } + } + else + { + ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first], + prebuilt->mysql_row_len); + } prebuilt->n_fetch_cached--; prebuilt->fetch_cache_first++; diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index b8d03cfab5f..80aea50be2e 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -186,6 +186,61 @@ that during a time of heavy update/insert activity. */ ulint srv_max_buf_pool_modified_pct = 90; +/* variable counts amount of data read in total (in bytes) */ +ulint srv_data_read = 0; + +/* here we count the amount of data written in total (in bytes) */ +ulint srv_data_written = 0; + +/* the number of the log write requests done */ +ulint srv_log_write_requests = 0; + +/* the number of physical writes to the log performed */ +ulint srv_log_writes = 0; + +/* amount of data written to the log files in bytes */ +ulint srv_os_log_written = 0; + +/* amount of writes being done to the log files */ +ulint srv_os_log_pending_writes = 0; + +/* we increase this counter, when there we don't have enough space in the +log buffer and have to flush it */ +ulint srv_log_waits = 0; + +/* this variable counts the amount of times, when the doublewrite buffer +was flushed */ +ulint srv_dblwr_writes = 0; + +/* here we store the number of pages that have been flushed to the +doublewrite buffer */ +ulint srv_dblwr_pages_written = 0; + +/* in this variable we store the number of write requests issued */ +ulint srv_buf_pool_write_requests = 0; + +/* here we store the number of times when we had to wait for a free page +in the buffer pool. It happens when the buffer pool is full and we need +to make a flush, in order to be able to read or create a page. */ +ulint srv_buf_pool_wait_free = 0; + +/* variable to count the number of pages that were written from buffer +pool to the disk */ +ulint srv_buf_pool_flushed = 0; + +/* variable to count the number of buffer pool reads that led to the +reading of a disk page */ +ulint srv_buf_pool_reads = 0; + +/* variable to count the number of sequential read-aheads */ +ulint srv_read_ahead_seq = 0; + +/* variable to count the number of random read-aheads */ +ulint srv_read_ahead_rnd = 0; + +/* structure to pass status variables to MySQL */ +export_struc export_vars; + /* If the following is != 0 we do not allow inserts etc. This protects the user from forgetting the innodb_force_recovery keyword to my.cnf */ @@ -1619,6 +1674,57 @@ srv_printf_innodb_monitor( fflush(file); } +/********************************************************************** +Function to pass InnoDB status variables to MySQL */ + +void +srv_export_innodb_status(void) +{ + + mutex_enter(&srv_innodb_monitor_mutex); + export_vars.innodb_data_pending_reads= os_n_pending_reads; + export_vars.innodb_data_pending_writes= os_n_pending_writes; + export_vars.innodb_data_pending_fsyncs= + fil_n_pending_log_flushes + fil_n_pending_tablespace_flushes; + export_vars.innodb_data_fsyncs= os_n_fsyncs; + export_vars.innodb_data_read= srv_data_read; + export_vars.innodb_data_reads= os_n_file_reads; + export_vars.innodb_data_writes= os_n_file_writes; + export_vars.innodb_data_written= srv_data_written; + export_vars.innodb_buffer_pool_read_requests= buf_pool->n_page_gets; + export_vars.innodb_buffer_pool_write_requests= srv_buf_pool_write_requests; + export_vars.innodb_buffer_pool_wait_free= srv_buf_pool_wait_free; + export_vars.innodb_buffer_pool_pages_flushed= srv_buf_pool_flushed; + export_vars.innodb_buffer_pool_reads= srv_buf_pool_reads; + export_vars.innodb_buffer_pool_read_ahead_rnd= srv_read_ahead_rnd; + export_vars.innodb_buffer_pool_read_ahead_seq= srv_read_ahead_seq; + export_vars.innodb_buffer_pool_pages_data= UT_LIST_GET_LEN(buf_pool->LRU); + export_vars.innodb_buffer_pool_pages_dirty= UT_LIST_GET_LEN(buf_pool->flush_list); + export_vars.innodb_buffer_pool_pages_free= UT_LIST_GET_LEN(buf_pool->free); + export_vars.innodb_buffer_pool_pages_latched= buf_get_latched_pages_number(); + export_vars.innodb_buffer_pool_pages_total= buf_pool->curr_size; + export_vars.innodb_buffer_pool_pages_misc= buf_pool->max_size - + UT_LIST_GET_LEN(buf_pool->LRU) - UT_LIST_GET_LEN(buf_pool->free); + export_vars.innodb_page_size= UNIV_PAGE_SIZE; + export_vars.innodb_log_waits= srv_log_waits; + export_vars.innodb_os_log_written= srv_os_log_written; + export_vars.innodb_os_log_fsyncs= fil_n_log_flushes; + export_vars.innodb_os_log_pending_fsyncs= fil_n_pending_log_flushes; + export_vars.innodb_os_log_pending_writes= srv_os_log_pending_writes; + export_vars.innodb_log_write_requests= srv_log_write_requests; + export_vars.innodb_log_writes= srv_log_writes; + export_vars.innodb_dblwr_pages_written= srv_dblwr_pages_written; + export_vars.innodb_dblwr_writes= srv_dblwr_writes; + export_vars.innodb_pages_created= buf_pool->n_pages_created; + export_vars.innodb_pages_read= buf_pool->n_pages_read; + export_vars.innodb_pages_written= buf_pool->n_pages_written; + export_vars.innodb_rows_read= srv_n_rows_read; + export_vars.innodb_rows_inserted= srv_n_rows_inserted; + export_vars.innodb_rows_updated= srv_n_rows_updated; + export_vars.innodb_rows_deleted= srv_n_rows_deleted; + mutex_exit(&srv_innodb_monitor_mutex); +} + /************************************************************************* A thread which wakes up threads whose lock wait may have lasted too long. This also prints the info output by various InnoDB monitors. */ |