summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYasufumi Kinoshita <yasufumi.kinoshita@oracle.com>2012-11-12 22:33:40 +0900
committerYasufumi Kinoshita <yasufumi.kinoshita@oracle.com>2012-11-12 22:33:40 +0900
commitf4a0ed8dd04fe0529d0f3cf46796a65ffa141b8c (patch)
tree41c542274f9c2f950befe4a38917f272de1c2b08
parent309ee86a0d85d7029df8165928cc367b4d383774 (diff)
parentd27694144d5a0cd18559364c7805dcac4fb9eb13 (diff)
downloadmariadb-git-f4a0ed8dd04fe0529d0f3cf46796a65ffa141b8c.tar.gz
Bug #14676111 WRONG PAGE_LEVEL WRITTEN FOR UPPER THAN FATHER PAGE AT BTR_LIFT_PAGE_UP()
btr_lift_page_up() writes wrong page number (different by -1) for upper than father page. But in almost all of the cases, the father page should be root page, no upper pages. It is very rare path. In addition the leaf page should not be lifted unless the father page is root. Because the branch pages should not become the leaf pages. rb://1336 approved by Marko Makela.
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug14676111.result53
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug14676111.test128
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_limit_optimistic_insert_debug_basic.result58
-rw-r--r--mysql-test/suite/sys_vars/t/innodb_limit_optimistic_insert_debug_basic.test50
-rw-r--r--storage/innobase/btr/btr0btr.c38
-rw-r--r--storage/innobase/btr/btr0cur.c8
-rw-r--r--storage/innobase/handler/ha_innodb.cc10
-rw-r--r--storage/innobase/include/btr0cur.h5
-rw-r--r--storage/innobase/include/btr0cur.ic13
-rw-r--r--storage/innobase/include/srv0srv.h3
-rw-r--r--storage/innobase/include/trx0purge.h4
-rw-r--r--storage/innobase/srv/srv0srv.c29
-rw-r--r--storage/innobase/trx/trx0purge.c7
13 files changed, 401 insertions, 5 deletions
diff --git a/mysql-test/suite/innodb/r/innodb_bug14676111.result b/mysql-test/suite/innodb/r/innodb_bug14676111.result
new file mode 100644
index 00000000000..ebecd1d00cb
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug14676111.result
@@ -0,0 +1,53 @@
+drop table if exists t1;
+CREATE TABLE t1 (a int not null primary key) engine=InnoDB;
+set global innodb_limit_optimistic_insert_debug = 2;
+insert into t1 values (1);
+insert into t1 values (5);
+insert into t1 values (4);
+insert into t1 values (3);
+insert into t1 values (2);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+10.0000
+delete from t1 where a=4;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+8.0000
+delete from t1 where a=5;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+5.0000
+set global innodb_limit_optimistic_insert_debug = 10000;
+delete from t1 where a=2;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+3.0000
+insert into t1 values (2);
+delete from t1 where a=2;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+2.0000
+insert into t1 values (2);
+delete from t1 where a=2;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+DATA_LENGTH / 16384
+1.0000
+drop table t1;
diff --git a/mysql-test/suite/innodb/t/innodb_bug14676111.test b/mysql-test/suite/innodb/t/innodb_bug14676111.test
new file mode 100644
index 00000000000..fadd111fdc9
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug14676111.test
@@ -0,0 +1,128 @@
+# Test for bug #14676111: WRONG PAGE_LEVEL WRITTEN FOR UPPER THAN FATHER PAGE AT BTR_LIFT_PAGE_UP()
+
+-- source include/have_innodb.inc
+-- source include/have_debug.inc
+
+if (`select count(*)=0 from information_schema.global_variables where variable_name = 'INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG'`)
+{
+ --skip Test requires InnoDB built with UNIV_DEBUG definition.
+}
+
+--disable_query_log
+set @old_innodb_limit_optimistic_insert_debug = @@innodb_limit_optimistic_insert_debug;
+--enable_query_log
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+CREATE TABLE t1 (a int not null primary key) engine=InnoDB;
+
+let $wait_condition=
+ SELECT VARIABLE_VALUE < 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS
+ WHERE VARIABLE_NAME = 'INNODB_PURGE_TRX_ID_AGE';
+
+#
+# make 4 leveled straight tree
+#
+set global innodb_limit_optimistic_insert_debug = 2;
+insert into t1 values (1);
+insert into t1 values (5);
+#current tree form
+# (1, 5)
+
+insert into t1 values (4);
+#records in a page is limited to 2 artificially. root rise occurs
+#current tree form
+# (1, 5)
+#(1, 4) (5)
+
+insert into t1 values (3);
+#current tree form
+# (1, 5)
+# (1, 4) (5)
+#(1, 3) (4) (5)
+
+insert into t1 values (2);
+#current tree form
+# (1, 5)
+# (1, 4) (5)
+# (1, 3) (4) (5)
+#(1, 2) (3) (4) (5)
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+delete from t1 where a=4;
+--source include/wait_condition.inc
+#deleting 1 record of 2 records don't cause merge artificially.
+#current tree form
+# (1, 5)
+# (1) (5)
+# (1, 3) (5)
+#(1, 2) (3) (5)
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+delete from t1 where a=5;
+--source include/wait_condition.inc
+#deleting 1 record of 2 records don't cause merge artificially.
+#current tree form
+# (1)
+# (1)
+# (1, 3) <- lift up this level next, when deleting node ptr
+#(1, 2) (3) <- merged next
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+#
+# cause merge at level 0
+#
+
+#disable the artificial limitation of records in a page
+set global innodb_limit_optimistic_insert_debug = 10000;
+delete from t1 where a=2;
+--source include/wait_condition.inc
+#merge page occurs. and lift up occurs.
+#current tree form
+# (1)
+# (1)
+# (1, 3)
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+insert into t1 values (2);
+#current tree form
+# (1)
+# (1) <- lift up this level next, because it is not root
+# (1, 2, 3)
+
+delete from t1 where a=2;
+--source include/wait_condition.inc
+#current tree form
+# (1)
+# (1, 3)
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+insert into t1 values (2);
+#current tree form
+# (1)
+# (1, 2, 3) <- lift up this level next, because the father is root
+
+delete from t1 where a=2;
+--source include/wait_condition.inc
+#current tree form
+# (1, 3)
+
+analyze table t1;
+select DATA_LENGTH / 16384 from information_schema.TABLES where TABLE_SCHEMA = 'test' and TABLE_NAME = 't1';
+
+drop table t1;
+
+--disable_query_log
+set global innodb_limit_optimistic_insert_debug = @old_innodb_limit_optimistic_insert_debug;
+--enable_query_log
diff --git a/mysql-test/suite/sys_vars/r/innodb_limit_optimistic_insert_debug_basic.result b/mysql-test/suite/sys_vars/r/innodb_limit_optimistic_insert_debug_basic.result
new file mode 100644
index 00000000000..3d4f401aad1
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/innodb_limit_optimistic_insert_debug_basic.result
@@ -0,0 +1,58 @@
+SET @start_global_value = @@global.innodb_limit_optimistic_insert_debug;
+SELECT @start_global_value;
+@start_global_value
+0
+select @@global.innodb_limit_optimistic_insert_debug;
+@@global.innodb_limit_optimistic_insert_debug
+0
+select @@session.innodb_limit_optimistic_insert_debug;
+ERROR HY000: Variable 'innodb_limit_optimistic_insert_debug' is a GLOBAL variable
+show global variables like 'innodb_limit_optimistic_insert_debug';
+Variable_name Value
+innodb_limit_optimistic_insert_debug 0
+show session variables like 'innodb_limit_optimistic_insert_debug';
+Variable_name Value
+innodb_limit_optimistic_insert_debug 0
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 0
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 0
+set global innodb_limit_optimistic_insert_debug=1;
+select @@global.innodb_limit_optimistic_insert_debug;
+@@global.innodb_limit_optimistic_insert_debug
+1
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 1
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 1
+set @@global.innodb_limit_optimistic_insert_debug=0;
+select @@global.innodb_limit_optimistic_insert_debug;
+@@global.innodb_limit_optimistic_insert_debug
+0
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 0
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+VARIABLE_NAME VARIABLE_VALUE
+INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG 0
+set session innodb_limit_optimistic_insert_debug='some';
+ERROR HY000: Variable 'innodb_limit_optimistic_insert_debug' is a GLOBAL variable and should be set with SET GLOBAL
+set @@session.innodb_limit_optimistic_insert_debug='some';
+ERROR HY000: Variable 'innodb_limit_optimistic_insert_debug' is a GLOBAL variable and should be set with SET GLOBAL
+set global innodb_limit_optimistic_insert_debug=1.1;
+ERROR 42000: Incorrect argument type to variable 'innodb_limit_optimistic_insert_debug'
+set global innodb_limit_optimistic_insert_debug='foo';
+ERROR 42000: Incorrect argument type to variable 'innodb_limit_optimistic_insert_debug'
+set global innodb_limit_optimistic_insert_debug=-2;
+Warnings:
+Warning 1292 Truncated incorrect innodb_limit_optimistic_insert_d value: '-2'
+set global innodb_limit_optimistic_insert_debug=1e1;
+ERROR 42000: Incorrect argument type to variable 'innodb_limit_optimistic_insert_debug'
+SET @@global.innodb_limit_optimistic_insert_debug = @start_global_value;
+SELECT @@global.innodb_limit_optimistic_insert_debug;
+@@global.innodb_limit_optimistic_insert_debug
+0
diff --git a/mysql-test/suite/sys_vars/t/innodb_limit_optimistic_insert_debug_basic.test b/mysql-test/suite/sys_vars/t/innodb_limit_optimistic_insert_debug_basic.test
new file mode 100644
index 00000000000..7998297c69e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/innodb_limit_optimistic_insert_debug_basic.test
@@ -0,0 +1,50 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+
+SET @start_global_value = @@global.innodb_limit_optimistic_insert_debug;
+SELECT @start_global_value;
+
+#
+# exists as global only
+#
+select @@global.innodb_limit_optimistic_insert_debug;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@session.innodb_limit_optimistic_insert_debug;
+show global variables like 'innodb_limit_optimistic_insert_debug';
+show session variables like 'innodb_limit_optimistic_insert_debug';
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+
+#
+# show that it's writable
+#
+set global innodb_limit_optimistic_insert_debug=1;
+select @@global.innodb_limit_optimistic_insert_debug;
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+set @@global.innodb_limit_optimistic_insert_debug=0;
+select @@global.innodb_limit_optimistic_insert_debug;
+select * from information_schema.global_variables where variable_name='innodb_limit_optimistic_insert_debug';
+select * from information_schema.session_variables where variable_name='innodb_limit_optimistic_insert_debug';
+--error ER_GLOBAL_VARIABLE
+set session innodb_limit_optimistic_insert_debug='some';
+--error ER_GLOBAL_VARIABLE
+set @@session.innodb_limit_optimistic_insert_debug='some';
+
+#
+# incorrect types
+#
+--error ER_WRONG_TYPE_FOR_VAR
+set global innodb_limit_optimistic_insert_debug=1.1;
+--error ER_WRONG_TYPE_FOR_VAR
+set global innodb_limit_optimistic_insert_debug='foo';
+set global innodb_limit_optimistic_insert_debug=-2;
+--error ER_WRONG_TYPE_FOR_VAR
+set global innodb_limit_optimistic_insert_debug=1e1;
+
+#
+# Cleanup
+#
+
+SET @@global.innodb_limit_optimistic_insert_debug = @start_global_value;
+SELECT @@global.innodb_limit_optimistic_insert_debug;
diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c
index 1f4d8126be6..24ff78df7c0 100644
--- a/storage/innobase/btr/btr0btr.c
+++ b/storage/innobase/btr/btr0btr.c
@@ -3094,6 +3094,8 @@ btr_lift_page_up(
buf_block_t* blocks[BTR_MAX_LEVELS];
ulint n_blocks; /*!< last used index in blocks[] */
ulint i;
+ ibool lift_father_up = FALSE;
+ buf_block_t* block_orig = block;
ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
@@ -3104,11 +3106,13 @@ btr_lift_page_up(
{
btr_cur_t cursor;
- mem_heap_t* heap = mem_heap_create(100);
- ulint* offsets;
+ ulint* offsets = NULL;
+ mem_heap_t* heap = mem_heap_create(
+ sizeof(*offsets)
+ * (REC_OFFS_HEADER_SIZE + 1 + 1 + index->n_fields));
buf_block_t* b;
- offsets = btr_page_get_father_block(NULL, heap, index,
+ offsets = btr_page_get_father_block(offsets, heap, index,
block, mtr, &cursor);
father_block = btr_cur_get_block(&cursor);
father_page_zip = buf_block_get_page_zip(father_block);
@@ -3132,6 +3136,29 @@ btr_lift_page_up(
blocks[n_blocks++] = b = btr_cur_get_block(&cursor);
}
+ if (n_blocks && page_level == 0) {
+ /* The father page also should be the only on its level (not
+ root). We should lift up the father page at first.
+ Because the leaf page should be lifted up only for root page.
+ The freeing page is based on page_level (==0 or !=0)
+ to choose segment. If the page_level is changed ==0 from !=0,
+ later freeing of the page doesn't find the page allocation
+ to be freed.*/
+
+ lift_father_up = TRUE;
+ block = father_block;
+ page = buf_block_get_frame(block);
+ page_level = btr_page_get_level(page, mtr);
+
+ ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
+ ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ father_block = blocks[0];
+ father_page_zip = buf_block_get_page_zip(father_block);
+ father_page = buf_block_get_frame(father_block);
+ }
+
mem_heap_free(heap);
}
@@ -3139,6 +3166,7 @@ btr_lift_page_up(
/* Make the father empty */
btr_page_empty(father_block, father_page_zip, index, page_level, mtr);
+ page_level++;
/* Copy the records to the father page one by one. */
if (0
@@ -3171,7 +3199,7 @@ btr_lift_page_up(
lock_update_copy_and_discard(father_block, block);
/* Go upward to root page, decrementing levels by one. */
- for (i = 0; i < n_blocks; i++, page_level++) {
+ for (i = lift_father_up ? 1 : 0; i < n_blocks; i++, page_level++) {
page_t* page = buf_block_get_frame(blocks[i]);
page_zip_des_t* page_zip= buf_block_get_page_zip(blocks[i]);
@@ -3193,7 +3221,7 @@ btr_lift_page_up(
ut_ad(page_validate(father_page, index));
ut_ad(btr_check_node_ptr(index, father_block, mtr));
- return(father_block);
+ return(lift_father_up ? block_orig : father_block);
}
/*************************************************************//**
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
index 1f92de245b1..955be01f032 100644
--- a/storage/innobase/btr/btr0cur.c
+++ b/storage/innobase/btr/btr0cur.c
@@ -97,6 +97,11 @@ srv_refresh_innodb_monitor_stats(). Referenced by
srv_printf_innodb_monitor(). */
UNIV_INTERN ulint btr_cur_n_sea_old = 0;
+#ifdef UNIV_DEBUG
+/* Flag to limit optimistic insert records */
+UNIV_INTERN uint btr_cur_limit_optimistic_insert_debug = 0;
+#endif /* UNIV_DEBUG */
+
/** In the optimistic insert, if the insert does not fit, but this much space
can be released by page reorganize, then it is reorganized */
#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)
@@ -1273,6 +1278,9 @@ btr_cur_optimistic_insert(
}
}
+ LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page),
+ goto fail);
+
/* If there have been many consecutive inserts, and we are on the leaf
level, check if we have to split the page to reserve enough free space
for future updates of records. */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 12c4b5a0e40..2a14fd5c2cc 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -693,6 +693,10 @@ static SHOW_VAR innodb_status_variables[]= {
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
{"truncated_status_writes",
(char*) &export_vars.innodb_truncated_status_writes, SHOW_LONG},
+#ifdef UNIV_DEBUG
+ {"purge_trx_id_age",
+ (char*) &export_vars.innodb_purge_trx_id_age, SHOW_LONG},
+#endif /* UNIV_DEBUG */
{NullS, NullS, SHOW_LONG}
};
@@ -11680,6 +11684,11 @@ static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug,
PLUGIN_VAR_RQCMDARG,
"Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()",
NULL, NULL, 0, 0, 1024, 0);
+
+static MYSQL_SYSVAR_UINT(limit_optimistic_insert_debug,
+ btr_cur_limit_optimistic_insert_debug, PLUGIN_VAR_RQCMDARG,
+ "Artificially limit the number of records per B-tree page (0=unlimited).",
+ NULL, NULL, 0, 0, UINT_MAX32, 0);
#endif /* UNIV_DEBUG */
static struct st_mysql_sys_var* innobase_system_variables[]= {
@@ -11753,6 +11762,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(rollback_segments),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
+ MYSQL_SYSVAR(limit_optimistic_insert_debug),
#endif /* UNIV_DEBUG */
NULL
};
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 6819f2bc2c5..283a6eec852 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -805,6 +805,11 @@ srv_printf_innodb_monitor(). */
extern ulint btr_cur_n_sea_old;
#endif /* !UNIV_HOTBACKUP */
+#ifdef UNIV_DEBUG
+/* Flag to limit optimistic insert records */
+extern uint btr_cur_limit_optimistic_insert_debug;
+#endif /* UNIV_DEBUG */
+
#ifndef UNIV_NONINL
#include "btr0cur.ic"
#endif
diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic
index e31f77c77eb..5fc4651ca13 100644
--- a/storage/innobase/include/btr0cur.ic
+++ b/storage/innobase/include/btr0cur.ic
@@ -27,6 +27,16 @@ Created 10/16/1994 Heikki Tuuri
#include "btr0btr.h"
#ifdef UNIV_DEBUG
+# define LIMIT_OPTIMISTIC_INSERT_DEBUG(NREC, CODE)\
+if (btr_cur_limit_optimistic_insert_debug\
+ && (NREC) >= (ulint)btr_cur_limit_optimistic_insert_debug) {\
+ CODE;\
+}
+#else
+# define LIMIT_OPTIMISTIC_INSERT_DEBUG(NREC, CODE)
+#endif /* UNIV_DEBUG */
+
+#ifdef UNIV_DEBUG
/*********************************************************//**
Returns the page cursor component of a tree cursor.
@return pointer to page cursor component */
@@ -146,6 +156,9 @@ btr_cur_compress_recommendation(
page = btr_cur_get_page(cursor);
+ LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page) * 2,
+ return(FALSE));
+
if ((page_get_data_size(page) < BTR_CUR_PAGE_COMPRESS_LIMIT)
|| ((btr_page_get_next(page, mtr) == FIL_NULL)
&& (btr_page_get_prev(page, mtr) == FIL_NULL))) {
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 5290ef5fe11..6cbf3e795e6 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -742,6 +742,9 @@ struct export_var_struct{
ulint innodb_rows_updated; /*!< srv_n_rows_updated */
ulint innodb_rows_deleted; /*!< srv_n_rows_deleted */
ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */
+#ifdef UNIV_DEBUG
+ ulint innodb_purge_trx_id_age; /*!< max_trx_id - purged trx_id */
+#endif /* UNIV_DEBUG */
};
/** Thread slot in the thread table */
diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h
index 2bd9e64476b..1e8acd65e01 100644
--- a/storage/innobase/include/trx0purge.h
+++ b/storage/innobase/include/trx0purge.h
@@ -156,6 +156,10 @@ struct trx_purge_struct{
than this */
undo_no_t purge_undo_no; /*!< Purge has advanced past all records
whose undo number is less than this */
+#ifdef UNIV_DEBUG
+ trx_id_t done_trx_no; /* Indicate 'purge pointer' which have
+ purged already accurately. */
+#endif /* UNIV_DEBUG */
/*-----------------------------*/
ibool next_stored; /*!< TRUE if the info of the next record
to purge is stored below: if yes, then
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index df89156baae..a4e51539d81 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -2087,6 +2087,15 @@ srv_export_innodb_status(void)
export_vars.innodb_rows_deleted = srv_n_rows_deleted;
export_vars.innodb_truncated_status_writes = srv_truncated_status_writes;
+#ifdef UNIV_DEBUG
+ if (trx_sys->max_trx_id < purge_sys->done_trx_no) {
+ export_vars.innodb_purge_trx_id_age = 0;
+ } else {
+ export_vars.innodb_purge_trx_id_age =
+ trx_sys->max_trx_id - purge_sys->done_trx_no;
+ }
+#endif /* UNIV_DEBUG */
+
mutex_exit(&srv_innodb_monitor_mutex);
}
@@ -2773,6 +2782,26 @@ loop:
for (i = 0; i < 10; i++) {
ulint cur_time = ut_time_ms();
+#ifdef UNIV_DEBUG
+ if (btr_cur_limit_optimistic_insert_debug
+ && srv_n_purge_threads == 0) {
+ /* If btr_cur_limit_optimistic_insert_debug is enabled
+ and no purge_threads, purge opportunity is increased
+ by x100 (1purge/100msec), to speed up debug scripts
+ which should wait for purged. */
+ next_itr_time -= 900;
+
+ srv_main_thread_op_info = "master purging";
+
+ srv_master_do_purge();
+
+ if (srv_fast_shutdown && srv_shutdown_state > 0) {
+
+ goto background_loop;
+ }
+ }
+#endif /* UNIV_DEBUG */
+
/* ALTER TABLE in MySQL requires on Unix that the table handler
can drop tables lazily after there no longer are SELECT
queries to them. */
diff --git a/storage/innobase/trx/trx0purge.c b/storage/innobase/trx/trx0purge.c
index 96f01ea81b5..57fdd341d19 100644
--- a/storage/innobase/trx/trx0purge.c
+++ b/storage/innobase/trx/trx0purge.c
@@ -236,6 +236,7 @@ trx_purge_sys_create(
purge_sys->purge_trx_no = 0;
purge_sys->purge_undo_no = 0;
purge_sys->next_stored = FALSE;
+ ut_d(purge_sys->done_trx_no = 0);
rw_lock_create(trx_purge_latch_key,
&purge_sys->latch, SYNC_PURGE_LATCH);
@@ -656,6 +657,12 @@ trx_purge_truncate_if_arr_empty(void)
{
static ulint count;
+#ifdef UNIV_DEBUG
+ if (purge_sys->arr->n_used == 0) {
+ purge_sys->done_trx_no = purge_sys->purge_trx_no;
+ }
+#endif /* UNIV_DEBUG */
+
if (!(++count % TRX_SYS_N_RSEGS) && purge_sys->arr->n_used == 0) {
trx_purge_truncate_history();