From 7ae0be25a605c04ad7b5576651f523952cce53b4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 14 Oct 2019 15:07:21 +0300 Subject: MDEV-20812 Unexpected ER_ROW_IS_REFERENCED_2 upon DELETE from versioned table with FK MDEV-16210 original case was wrongly allowed versioned DELETE from referenced table where reference is by non-primary key. InnoDB UPDATE has optimization for new rows not changing its clustered index position. In this case InnoDB doesn't update all secondary indexes and misses the one holding the referenced key. The fix was to disable this optimization for versioned DELETE. In case of versioned DELETE we forcely update all secondary indexes and therefore check them for constraints. But the above fix raised another problem with versioned DELETE on foreign table side. In case when there was no corresponding record in referenced table (illegal foreign reference can be done with "set foreign_key_checks=off") there was spurious constraint check (because versioned DELETE is actually UPDATE) and hence the operation failed with constraint error. MDEV-16210 tried to fix the above problem by checking foreign table instead of referenced table and that at least was illegal. Constraint check is done by row_ins_check_foreign_constraint() no matter what kind of table is checked, referenced or foreign (controlled by check_ref argument). Referenced table is checked by row_upd_check_references_constraints(). Foreign table is checked by row_ins_check_foreign_constraints(). Current fix rolls back the wrong fix for the above problem and disables referenced table check for DELETE on foreign side by introducing `check_foreign` argument which when set to *false* skips row_ins_check_foreign_constraints() call. --- storage/innobase/include/row0ins.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 87a72d88eb6..9b6aac9c548 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -146,9 +146,8 @@ row_ins_sec_index_entry( dict_index_t* index, /*!< in: secondary index */ dtuple_t* entry, /*!< in/out: index entry to insert */ que_thr_t* thr, /*!< in: query thread */ - bool check_ref) /*!< in: TRUE if we want to check that - the referenced table is ok, FALSE if we - want to check the foreign key table */ + bool check_foreign = true) /*!< in: true if check + foreign table is needed, false otherwise */ MY_ATTRIBUTE((warn_unused_result)); /***********************************************************//** Inserts a row to a table. This is a high-level function used in -- cgit v1.2.1 From 28098420317bc2efe082df799c917babde879242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 19 Oct 2019 15:16:47 +0300 Subject: MDEV-20864 Introduce debug option innodb_change_buffer_dump To diagnose a hang in slow shutdown (innodb_fast_shutdown=0), let us introduce a Boolean startup option in debug builds that will cause the contents of the InnoDB change buffer to be dumped to the server error log at startup. --- storage/innobase/include/dict0types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 93c2f570e54..bea08f398de 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2017, MariaDB Corporation. +Copyright (c) 2013, 2019, MariaDB Corporation. 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 @@ -96,6 +96,8 @@ typedef ib_mutex_t DictSysMutex; #define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG +/** Dump the change buffer at startup */ +extern my_bool ibuf_dump; /** Flag to control insert buffer debugging. */ extern uint ibuf_debug; #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ -- cgit v1.2.1 From a41d429765c7ddb528b9b438c68b25ff55d3bd55 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 22 Oct 2019 12:05:42 +0530 Subject: MDEV-20621 FULLTEXT INDEX activity causes InnoDB hang - fts_optimize_thread() uses dict_table_t object instead of table id. So that it doesn't acquire dict_sys->mutex. It leads to remove the hang of dict_sys->mutex between fts_optimize_thread() and other threads. - in_queue to indicate whether the table is in fts_optimize_queue. It is protected by fts_optimize_wq->mutex to avoid any race condition. - fts_optimize_init() adds the fts table to the fts_optimize_wq --- storage/innobase/include/fts0fts.h | 16 +++++----------- storage/innobase/include/fts0opt.h | 3 +++ storage/innobase/include/ut0wqueue.h | 33 +++++++++++++++++---------------- 3 files changed, 25 insertions(+), 27 deletions(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 5c50e381f91..3beddd68722 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -285,9 +285,6 @@ struct fts_t { fts_add_wq. */ ib_mutex_t bg_threads_mutex; - /* Wheter the table was added to fts_optimize_wq(); - protected by bg_threads mutex */ - unsigned in_queue:1; /* Whether the ADDED table record sync-ed after crash recovery; protected by bg_threads mutex */ unsigned added_synced:1; @@ -310,6 +307,11 @@ struct fts_t { ib_vector_t* indexes; /*!< Vector of FTS indexes, this is mainly for caching purposes. */ + + /* Whether the table was added to fts_optimize_wq(); + protected by fts_optimize_wq mutex */ + bool in_queue; + mem_heap_t* fts_heap; /*!< heap for fts_t allocation */ }; @@ -631,14 +633,6 @@ void fts_optimize_init(void); /*====================*/ -/**********************************************************************//** -Check whether the work queue is initialized. -@return TRUE if optimze queue is initialized. */ -UNIV_INTERN -ibool -fts_optimize_is_init(void); -/*======================*/ - /****************************************************************//** Drops index ancillary tables for a FTS index @return DB_SUCCESS or error code */ diff --git a/storage/innobase/include/fts0opt.h b/storage/innobase/include/fts0opt.h index e8bd4be95b7..29bb14e2f64 100644 --- a/storage/innobase/include/fts0opt.h +++ b/storage/innobase/include/fts0opt.h @@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang #ifndef INNODB_FTS0OPT_H #define INNODB_FTS0OPT_H +/** The FTS optimize thread's work queue. */ +extern ib_wqueue_t* fts_optimize_wq; + /******************************************************************** Callback function to fetch the rows in an FTS INDEX record. */ UNIV_INTERN diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h index b81b78530ca..4b0014e3091 100644 --- a/storage/innobase/include/ut0wqueue.h +++ b/storage/innobase/include/ut0wqueue.h @@ -56,16 +56,15 @@ ib_wqueue_free( /*===========*/ ib_wqueue_t* wq); /*!< in: work queue */ -/****************************************************************//** -Add a work item to the queue. */ +/** Add a work item to the queue. +@param[in,out] wq work queue +@param[in] item work item +@param[in,out] heap memory heap to use for allocating list node +@param[in] wq_locked work queue mutex locked */ UNIV_INTERN void -ib_wqueue_add( -/*==========*/ - ib_wqueue_t* wq, /*!< in: work queue */ - void* item, /*!< in: work item */ - mem_heap_t* heap); /*!< in: memory heap to use for allocating the - list node */ +ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, + bool wq_locked = false); /** Check if queue is empty. @param wq wait queue @@ -107,14 +106,16 @@ ib_wqueue_len( /*==========*/ ib_wqueue_t* wq); /* Date: Tue, 29 Oct 2019 17:11:34 +0200 Subject: MDEV-20917 InnoDB is passing NULL to nonnull function parameters mem_heap_dup(): Avoid mem_heap_alloc() and memcpy() of data=NULL, len=0. trx_undo_report_insert_virtual(), trx_undo_page_report_insert(), trx_undo_page_report_modify(): Avoid memcpy(ptr, NULL, 0). dfield_data_is_binary_equal(): Correctly handle data=NULL, len=0. This clean-up was motivated by WITH_UBSAN, and no bug related to this was observed in the wild. It should be noted that undefined behaviour such as memcpy(ptr, NULL, 0) could allow compilers to perform unsafe optimizations, like it was the case in commit fc168c3a5e58d8b364a2e87e0d876a261ec7fced (MDEV-15587). --- storage/innobase/include/data0data.h | 2 +- storage/innobase/include/data0data.ic | 2 +- storage/innobase/include/mem0mem.h | 27 ++++++++++++++++----------- 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index db321626368..33d03c8a2c9 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -168,7 +168,7 @@ dfield_data_is_binary_equal( const dfield_t* field, /*!< in: field */ ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); + MY_ATTRIBUTE((nonnull(1), warn_unused_result)); /*********************************************************************//** Gets info bits in a data tuple. diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index f6d067bcc8e..295c786a583 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -223,7 +223,7 @@ dfield_data_is_binary_equal( const byte* data) /*!< in: data */ { return(len == dfield_get_len(field) - && (len == UNIV_SQL_NULL + && (!len || len == UNIV_SQL_NULL || !memcmp(dfield_get_data(field), data, len))); } diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index 0b291e6f365..22c0a04e170 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -228,7 +228,22 @@ mem_strdupl( const char* str, /*!< in: string to be copied */ ulint len); /*!< in: length of str, in bytes */ -/** Duplicates a NUL-terminated string, allocated from a memory heap. +/** Duplicate a block of data, allocated from a memory heap. +@param[in] heap memory heap where string is allocated +@param[in] data block of data to be copied +@param[in] len length of data, in bytes +@return own: a copy of data */ +inline +void* +mem_heap_dup(mem_heap_t* heap, const void* data, size_t len) +{ + ut_ad(data || !len); + return UNIV_LIKELY(data != NULL) + ? memcpy(mem_heap_alloc(heap, len), data, len) + : NULL; +} + +/** Duplicate a NUL-terminated string, allocated from a memory heap. @param[in] heap memory heap where string is allocated @param[in] str string to be copied @return own: a copy of the string */ @@ -259,16 +274,6 @@ mem_heap_strcat( const char* s1, /*!< in: string 1 */ const char* s2); /*!< in: string 2 */ -/**********************************************************************//** -Duplicate a block of data, allocated from a memory heap. -@return own: a copy of the data */ -void* -mem_heap_dup( -/*=========*/ - mem_heap_t* heap, /*!< in: memory heap where copy is allocated */ - const void* data, /*!< in: data to be copied */ - ulint len); /*!< in: length of data, in bytes */ - /****************************************************************//** A simple sprintf replacement that dynamically allocates the space for the formatted string from the given heap. This supports a very limited set of -- cgit v1.2.1 From bef843b97f2e91859f2a08845822d619e769f89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Oct 2019 18:20:32 +0200 Subject: MDEV-20917 InnoDB is passing NULL to nonnull function parameters mem_heap_dup(): Avoid mem_heap_alloc() and memcpy() of data=NULL, len=0. trx_undo_report_insert_virtual(), trx_undo_page_report_insert(), trx_undo_page_report_modify(): Avoid memcpy(ptr, NULL, 0). dfield_data_is_binary_equal(): Correctly handle data=NULL, len=0. rec_init_offsets_temp(): Do allow def_val=NULL in the interface. This clean-up was motivated by WITH_UBSAN, and no bug related to this was observed in the wild. It should be noted that undefined behaviour such as memcpy(ptr, NULL, 0) could allow compilers to perform unsafe optimizations, like it was the case in commit fc168c3a5e58d8b364a2e87e0d876a261ec7fced (MDEV-15587). --- storage/innobase/include/data0data.h | 2 +- storage/innobase/include/data0data.ic | 2 +- storage/innobase/include/mem0mem.h | 5 ++++- storage/innobase/include/rem0rec.h | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index fbbdd3b8f2d..706d65a4469 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -168,7 +168,7 @@ dfield_data_is_binary_equal( const dfield_t* field, /*!< in: field */ ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); + MY_ATTRIBUTE((nonnull(1), warn_unused_result)); /*********************************************************************//** Gets info bits in a data tuple. diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index be0186d53fe..92be8f8c589 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -225,7 +225,7 @@ dfield_data_is_binary_equal( { ut_ad(len != UNIV_SQL_DEFAULT); return(len == dfield_get_len(field) - && (len == UNIV_SQL_NULL + && (!len || len == UNIV_SQL_NULL || !memcmp(dfield_get_data(field), data, len))); } diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index 6d0f95cba19..fa22b3d3086 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -237,7 +237,10 @@ inline void* mem_heap_dup(mem_heap_t* heap, const void* data, size_t len) { - return(memcpy(mem_heap_alloc(heap, len), data, len)); + ut_ad(data || !len); + return UNIV_LIKELY(data != NULL) + ? memcpy(mem_heap_alloc(heap, len), data, len) + : NULL; } /** Duplicate a NUL-terminated string, allocated from a memory heap. diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 54f50058140..0c49c223e10 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -983,7 +983,7 @@ rec_init_offsets_temp( ulint n_core, const dict_col_t::def_t*def_val, rec_comp_status_t status = REC_STATUS_ORDINARY) - MY_ATTRIBUTE((nonnull)); + MY_ATTRIBUTE((nonnull(1,2,3))); /** Determine the offset to each field in temporary file. @param[in] rec temporary file record @param[in] index index of that the record belongs to -- cgit v1.2.1 From 44b0c8697135be4139c4431bbf02fbf4433e058f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Oct 2019 06:42:51 +0200 Subject: Clean up ut_strlcpy(), ut_strlcpy_rev() ut_strlcpy(): Replace with the standard function strncpy(). ut_strlcpy_rev(): Define in the same compilation unit where the only caller resides. Avoid unnecessary definition in non-debug builds. --- storage/innobase/include/ut0mem.h | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'storage/innobase/include') diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 49777495cae..32d557d4f2a 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -83,29 +84,6 @@ UNIV_INLINE int ut_strcmp(const char* str1, const char* str2); -/**********************************************************************//** -Copies up to size - 1 characters from the NUL-terminated string src to -dst, NUL-terminating the result. Returns strlen(src), so truncation -occurred if the return value >= size. -@return strlen(src) */ -ulint -ut_strlcpy( -/*=======*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size); /*!< in: size of destination buffer */ - -/**********************************************************************//** -Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last -(size - 1) bytes of src, not the first. -@return strlen(src) */ -ulint -ut_strlcpy_rev( -/*===========*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size); /*!< in: size of destination buffer */ - /******************************************************************** Concatenate 3 strings.*/ char* -- cgit v1.2.1