3431 Marko Mäkelä 2011-09-01 [merge]
Merge mysql-5.5 to mysql-trunk.
modified:
include/my_base.h
mysql-test/suite/innodb/r/innodb-index.result
mysql-test/suite/innodb/t/innodb-index.test
mysys/my_handler_errors.h
sql/handler.cc
sql/share/errmsg-utf8.txt
storage/innobase/handler/ha_innodb.cc
storage/innobase/include/db0err.h
storage/innobase/include/trx0undo.h
storage/innobase/row/row0mysql.c
storage/innobase/trx/trx0rec.c
storage/innobase/trx/trx0undo.c
storage/innobase/ut/ut0ut.c
3430 Georgi Kodinov 2011-09-01
Addendum to Bug #11766001: check if the test case can be run : make sure the plugins requred are there.
modified:
mysql-test/t/multi_plugin_load.test
=== modified file 'include/my_base.h'
--- a/include/my_base.h revid:georgi.kodinov@stripped
+++ b/include/my_base.h revid:marko.makela@stripped44-j8dj2bm329hk2avj
@@ -449,7 +449,8 @@ enum ha_base_keytype {
#define HA_ERR_NOT_IN_LOCK_PARTITIONS 178
#define HA_ERR_INDEX_COL_TOO_LONG 179 /* Index column length exceeds limit */
#define HA_ERR_INDEX_CORRUPT 180 /* InnoDB index corrupted */
-#define HA_ERR_LAST 180 /* Copy of last error nr */
+#define HA_ERR_UNDO_REC_TOO_BIG 181 /* Undo log record too big */
+#define HA_ERR_LAST 181 /* Copy of last error nr */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
=== modified file 'mysql-test/suite/innodb/r/innodb-index.result'
--- a/mysql-test/suite/innodb/r/innodb-index.result revid:georgi.kodinov@strippeddcb437733qr
+++ b/mysql-test/suite/innodb/r/innodb-index.result revid:marko.makela@strippedbm329hk2avj
@@ -978,6 +978,15 @@ INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@
UPDATE t1 SET a=1000;
DELETE FROM t1;
DROP TABLE t1;
+CREATE TABLE bug12547647(
+a INT NOT NULL, b BLOB NOT NULL, c TEXT,
+PRIMARY KEY (b(10), a), INDEX (c(767)), INDEX(b(767))
+) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
+INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7751));
+COMMIT;
+UPDATE bug12547647 SET c = REPEAT('b',16928);
+ERROR HY000: Undo log record is too big.
+DROP TABLE bug12547647;
set global innodb_file_per_table=0;
set global innodb_file_format=Antelope;
set global innodb_file_format_max=Antelope;
=== modified file 'mysql-test/suite/innodb/t/innodb-index.test'
--- a/mysql-test/suite/innodb/t/innodb-index.test revid:georgi.kodinov@stripped
+++ b/mysql-test/suite/innodb/t/innodb-index.test revid:marko.makela@stripped
@@ -478,6 +478,19 @@ DELETE FROM t1;
-- sleep 10
DROP TABLE t1;
+# Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE
+CREATE TABLE bug12547647(
+a INT NOT NULL, b BLOB NOT NULL, c TEXT,
+PRIMARY KEY (b(10), a), INDEX (c(767)), INDEX(b(767))
+) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
+
+INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7751));
+COMMIT;
+# The following used to cause infinite undo log allocation.
+--error ER_UNDO_RECORD_TOO_BIG
+UPDATE bug12547647 SET c = REPEAT('b',16928);
+DROP TABLE bug12547647;
+
eval set global innodb_file_per_table=$per_table;
eval set global innodb_file_format=$format;
eval set global innodb_file_format_max=$format;
=== modified file 'mysys/my_handler_errors.h'
--- a/mysys/my_handler_errors.h revid:georgi.kodinov@stripped0110901122610-74oe0dcb437733qr
+++ b/mysys/my_handler_errors.h revid:marko.makela@strippedm329hk2avj
@@ -83,7 +83,8 @@ static const char *handler_error_message
"Too many active concurrent transactions",
"Record not matching the given partition set",
"Index column length exceeds limit",
- "Index corrupted"
+ "Index corrupted",
+ "Undo record too big"
};
extern void my_handler_error_register(void);
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc revid:georgi.kodinov@stripped
+++ b/sql/handler.cc revid:marko.makela@strippedj8dj2bm329hk2avj
@@ -3126,6 +3126,9 @@ void handler::print_error(int error, myf
case HA_ERR_INDEX_CORRUPT:
textno= ER_INDEX_CORRUPT;
break;
+ case HA_ERR_UNDO_REC_TOO_BIG:
+ textno= ER_UNDO_RECORD_TOO_BIG;
+ break;
default:
{
/* The error was "unknown" to this function.
=== modified file 'sql/share/errmsg-utf8.txt'
--- a/sql/share/errmsg-utf8.txt revid:georgi.kodinov@stripped
+++ b/sql/share/errmsg-utf8.txt revid:marko.makela@stripped110901185944-j8dj2bm329hk2avj
@@ -6514,6 +6514,7 @@ ER_ERROR_IN_UNKNOWN_TRIGGER_BODY
ER_INDEX_CORRUPT
eng "Index %s is corrupted"
+
ER_MTS_FEATURE_IS_NOT_SUPPORTED
eng "%s is not supported in multi-threaded slave mode. %s"
ER_MTS_UPDATED_DBS_GREATER_MAX
@@ -6522,3 +6523,6 @@ ER_MTS_CANT_PARALLEL
eng "Cannot execute the current event group in the parallel mode. Encountered event %s, relay-log name %s, position %s which prevents execution of this event group in parallel mode. Reason: %s."
ER_MTS_INCONSISTENT_DATA
eng "%s"
+
+ER_UNDO_RECORD_TOO_BIG
+ eng "Undo log record is too big."
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc revid:georgi.kodinov@stripped-20110901122610-74oe0dcb437733qr
+++ b/storage/innobase/handler/ha_innodb.cc revid:marko.makela@stripped1185944-j8dj2bm329hk2avj
@@ -1243,6 +1243,8 @@ convert_error_code_to_mysql(
return(HA_ERR_UNSUPPORTED);
case DB_INDEX_CORRUPT:
return(HA_ERR_INDEX_CORRUPT);
+ case DB_UNDO_RECORD_TOO_BIG:
+ return(HA_ERR_UNDO_REC_TOO_BIG);
}
}
=== modified file 'storage/innobase/include/db0err.h'
--- a/storage/innobase/include/db0err.h revid:georgi.kodinov@stripped
+++ b/storage/innobase/include/db0err.h revid:marko.makela@stripped
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -111,6 +111,7 @@ enum db_err {
DB_TOO_BIG_INDEX_COL, /* index column size exceeds maximum
limit */
DB_INDEX_CORRUPT, /* we have corrupted index */
+ DB_UNDO_RECORD_TOO_BIG, /* the undo log record is too big */
/* The following are partial failure codes */
DB_FAIL = 1000,
=== modified file 'storage/innobase/include/trx0undo.h'
--- a/storage/innobase/include/trx0undo.h revid:georgi.kodinov@stripped
+++ b/storage/innobase/include/trx0undo.h revid:marko.makela@strippedom-20110901185944-j8dj2bm329hk2avj
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -204,17 +204,51 @@ trx_undo_add_page(
mtr_t* mtr); /*!< in: mtr which does not have a latch to any
undo log page; the caller must have reserved
the rollback segment mutex */
+/********************************************************************//**
+Frees the last undo log page.
+The caller must hold the rollback segment mutex. */
+UNIV_INTERN
+void
+trx_undo_free_last_page_func(
+/*==========================*/
+#ifdef UNIV_DEBUG
+ const trx_t* trx, /*!< in: transaction */
+#endif /* UNIV_DEBUG */
+ trx_undo_t* undo, /*!< in/out: undo log memory copy */
+ mtr_t* mtr) /*!< in/out: mini-transaction which does not
+ have a latch to any undo log page or which
+ has allocated the undo log page */
+ __attribute__((nonnull));
+#ifdef UNIV_DEBUG
+# define trx_undo_free_last_page(trx,undo,mtr) \
+ trx_undo_free_last_page_func(trx,undo,mtr)
+#else /* UNIV_DEBUG */
+# define trx_undo_free_last_page(trx,undo,mtr) \
+ trx_undo_free_last_page_func(undo,mtr)
+#endif /* UNIV_DEBUG */
+
/***********************************************************************//**
Truncates an undo log from the end. This function is used during a rollback
to free space from an undo log. */
UNIV_INTERN
void
-trx_undo_truncate_end(
-/*==================*/
- trx_t* trx, /*!< in: transaction whose undo log it is */
- trx_undo_t* undo, /*!< in: undo log */
- undo_no_t limit); /*!< in: all undo records with undo number
+trx_undo_truncate_end_func(
+/*=======================*/
+#ifdef UNIV_DEBUG
+ const trx_t* trx, /*!< in: transaction whose undo log it is */
+#endif /* UNIV_DEBUG */
+ trx_undo_t* undo, /*!< in/out: undo log */
+ undo_no_t limit) /*!< in: all undo records with undo number
>= this value should be truncated */
+ __attribute__((nonnull));
+#ifdef UNIV_DEBUG
+# define trx_undo_truncate_end(trx,undo,limit) \
+ trx_undo_truncate_end_func(trx,undo,limit)
+#else /* UNIV_DEBUG */
+# define trx_undo_truncate_end(trx,undo,limit) \
+ trx_undo_truncate_end_func(undo,limit)
+#endif /* UNIV_DEBUG */
+
/***********************************************************************//**
Truncates an undo log from the start. This function is used during a purge
operation. */
=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c revid:georgi.kodinov@stripped
+++ b/storage/innobase/row/row0mysql.c revid:marko.makela@oracle.com-20110901185944-j8dj2bm329hk2avj
@@ -586,6 +586,7 @@ handle_new_error:
case DB_DUPLICATE_KEY:
case DB_FOREIGN_DUPLICATE_KEY:
case DB_TOO_BIG_RECORD:
+ case DB_UNDO_RECORD_TOO_BIG:
case DB_ROW_IS_REFERENCED:
case DB_NO_REFERENCED_ROW:
case DB_CANNOT_ADD_CONSTRAINT:
=== modified file 'storage/innobase/trx/trx0rec.c'
--- a/storage/innobase/trx/trx0rec.c revid:georgi.kodinov@oracle.com-20110901122610-74oe0dcb437733qr
+++ b/storage/innobase/trx/trx0rec.c revid:marko.makela@stripped185944-j8dj2bm329hk2avj
@@ -671,7 +671,6 @@ trx_undo_page_report_modify(
/* Save to the undo log the old values of the columns to be updated. */
if (update) {
-
if (trx_undo_left(undo_page, ptr) < 5) {
return(0);
@@ -1121,22 +1120,29 @@ trx_undo_rec_get_partial_row(
#endif /* !UNIV_HOTBACKUP */
/***********************************************************************//**
-Erases the unused undo log page end. */
-static
-void
+Erases the unused undo log page end.
+@return TRUE if the page contained something, FALSE if it was empty */
+static __attribute__((nonnull, warn_unused_result))
+ibool
trx_undo_erase_page_end(
/*====================*/
- page_t* undo_page, /*!< in: undo page whose end to erase */
- mtr_t* mtr) /*!< in: mtr */
+ page_t* undo_page, /*!< in/out: undo page whose end to erase */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint first_free;
first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_FREE);
+ if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) {
+ /* This was an empty page to begin with.
+ Do nothing here; the caller should free the page. */
+ return(FALSE);
+ }
memset(undo_page + first_free, 0xff,
(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free);
mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr);
+ return(TRUE);
}
/***********************************************************//**
@@ -1158,7 +1164,11 @@ trx_undo_parse_erase_page_end(
return(ptr);
}
- trx_undo_erase_page_end(page, mtr);
+ if (!trx_undo_erase_page_end(page, mtr)) {
+ /* The function trx_undo_erase_page_end() should not
+ have done anything to an empty page. */
+ ut_ad(0);
+ }
return(ptr);
}
@@ -1204,6 +1214,9 @@ trx_undo_report_row_operation(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
+#ifdef UNIV_DEBUG
+ int loop_count = 0;
+#endif /* UNIV_DEBUG */
rec_offs_init(offsets_);
ut_a(dict_index_is_clust(index));
@@ -1266,7 +1279,7 @@ trx_undo_report_row_operation(
mtr_start(&mtr);
- for (;;) {
+ do {
buf_block_t* undo_block;
page_t* undo_page;
ulint offset;
@@ -1295,7 +1308,19 @@ trx_undo_report_row_operation(
version the replicate page constructed using the log
records stays identical to the original page */
- trx_undo_erase_page_end(undo_page, &mtr);
+ if (!trx_undo_erase_page_end(undo_page, &mtr)) {
+ /* The record did not fit on an empty
+ undo page. Discard the freshly allocated
+ page and return an error. */
+
+ mutex_enter(&rseg->mutex);
+ trx_undo_free_last_page(trx, undo, &mtr);
+ mutex_exit(&rseg->mutex);
+
+ err = DB_UNDO_RECORD_TOO_BIG;
+ goto err_exit;
+ }
+
mtr_commit(&mtr);
} else {
/* Success */
@@ -1315,16 +1340,15 @@ trx_undo_report_row_operation(
*roll_ptr = trx_undo_build_roll_ptr(
op_type == TRX_UNDO_INSERT_OP,
rseg->id, page_no, offset);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(DB_SUCCESS);
+ err = DB_SUCCESS;
+ goto func_exit;
}
ut_ad(page_no == undo->last_page_no);
/* We have to extend the undo log by one page */
+ ut_ad(++loop_count < 2);
mtr_start(&mtr);
/* When we add a page to an undo log, this is analogous to
@@ -1336,18 +1360,19 @@ trx_undo_report_row_operation(
page_no = trx_undo_add_page(trx, undo, &mtr);
mutex_exit(&(rseg->mutex));
+ } while (UNIV_LIKELY(page_no != FIL_NULL));
- if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
- /* Did not succeed: out of space */
+ /* Did not succeed: out of space */
+ err = DB_OUT_OF_FILE_SPACE;
- mutex_exit(&(trx->undo_mutex));
- mtr_commit(&mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(DB_OUT_OF_FILE_SPACE);
- }
+err_exit:
+ mutex_exit(&trx->undo_mutex);
+ mtr_commit(&mtr);
+func_exit:
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
}
+ return(err);
}
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
=== modified file 'storage/innobase/trx/trx0undo.c'
--- a/storage/innobase/trx/trx0undo.c revid:georgi.kodinov@oracle.com-20110901122610-74oe0dcb437733qr
+++ b/storage/innobase/trx/trx0undo.c revid:marko.makela@stripped110901185944-j8dj2bm329hk2avj
@@ -1005,29 +1005,28 @@ trx_undo_free_page(
}
/********************************************************************//**
-Frees an undo log page when there is also the memory object for the undo
-log. */
-static
+Frees the last undo log page.
+The caller must hold the rollback segment mutex. */
+UNIV_INTERN
void
-trx_undo_free_page_in_rollback(
-/*===========================*/
- trx_t* trx __attribute__((unused)), /*!< in: transaction */
- trx_undo_t* undo, /*!< in: undo log memory copy */
- ulint page_no,/*!< in: page number to free: must not be the
- header page */
- mtr_t* mtr) /*!< in: mtr which does not have a latch to any
- undo log page; the caller must have reserved
- the rollback segment mutex */
+trx_undo_free_last_page_func(
+/*==========================*/
+#ifdef UNIV_DEBUG
+ const trx_t* trx, /*!< in: transaction */
+#endif /* UNIV_DEBUG */
+ trx_undo_t* undo, /*!< in/out: undo log memory copy */
+ mtr_t* mtr) /*!< in/out: mini-transaction which does not
+ have a latch to any undo log page or which
+ has allocated the undo log page */
{
- ulint last_page_no;
-
- ut_ad(undo->hdr_page_no != page_no);
- ut_ad(mutex_own(&(trx->undo_mutex)));
-
- last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space,
- undo->hdr_page_no, page_no, mtr);
+ ut_ad(mutex_own(&trx->undo_mutex));
+ ut_ad(undo->hdr_page_no != undo->last_page_no);
+ ut_ad(undo->size > 0);
+
+ undo->last_page_no = trx_undo_free_page(
+ undo->rseg, FALSE, undo->space,
+ undo->hdr_page_no, undo->last_page_no, mtr);
- undo->last_page_no = last_page_no;
undo->size--;
}
@@ -1063,9 +1062,11 @@ Truncates an undo log from the end. This
to free space from an undo log. */
UNIV_INTERN
void
-trx_undo_truncate_end(
-/*==================*/
- trx_t* trx, /*!< in: transaction whose undo log it is */
+trx_undo_truncate_end_func(
+/*=======================*/
+#ifdef UNIV_DEBUG
+ const trx_t* trx, /*!< in: transaction whose undo log it is */
+#endif /* UNIV_DEBUG */
trx_undo_t* undo, /*!< in: undo log */
undo_no_t limit) /*!< in: all undo records with undo number
>= this value should be truncated */
@@ -1091,18 +1092,7 @@ trx_undo_truncate_end(
rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
undo->hdr_offset);
- for (;;) {
- if (rec == NULL) {
- if (last_page_no == undo->hdr_page_no) {
-
- goto function_exit;
- }
-
- trx_undo_free_page_in_rollback(
- trx, undo, last_page_no, &mtr);
- break;
- }
-
+ while (rec) {
if (trx_undo_rec_get_undo_no(rec) >= limit) {
/* Truncate at least this record off, maybe
more */
@@ -1116,6 +1106,14 @@ trx_undo_truncate_end(
undo->hdr_offset);
}
+ if (last_page_no == undo->hdr_page_no) {
+
+ goto function_exit;
+ }
+
+ ut_ad(last_page_no == undo->last_page_no);
+ trx_undo_free_last_page(trx, undo, &mtr);
+
mtr_commit(&mtr);
}
=== modified file 'storage/innobase/ut/ut0ut.c'
--- a/storage/innobase/ut/ut0ut.c revid:georgi.kodinov@stripped7733qr
+++ b/storage/innobase/ut/ut0ut.c revid:marko.makela@stripped
@@ -730,6 +730,8 @@ ut_strerr(
return("No index on referenced keys in referenced table");
case DB_INDEX_CORRUPT:
return("Index corrupted");
+ case DB_UNDO_RECORD_TOO_BIG:
+ return("Undo record too big");
case DB_END_OF_INDEX:
return("End of index");
/* do not add default: in order to produce a warning if new code
No bundle (reason: useless for push emails).| Thread |
|---|
| • bzr push into mysql-trunk branch (marko.makela:3430 to 3431) | marko.makela | 2 Sep |