2010-07-14 14:27:13 +02:00
|
|
|
#ifndef MY_COMPILER_INCLUDED
|
|
|
|
#define MY_COMPILER_INCLUDED
|
|
|
|
|
2011-06-30 17:46:53 +02:00
|
|
|
/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
MDEV-15250 UPSERT during ALTER TABLE results in 'Duplicate entry' error for alter
- InnoDB DDL results in `Duplicate entry' if concurrent DML throws
duplicate key error. The following scenario explains the problem
connection con1:
ALTER TABLE t1 FORCE;
connection con2:
INSERT INTO t1(pk, uk) VALUES (2, 2), (3, 2);
In connection con2, InnoDB throws the 'DUPLICATE KEY' error because
of unique index. Alter operation will throw the error when applying
the concurrent DML log.
- Inserting the duplicate key for unique index logs the insert
operation for online ALTER TABLE. When insertion fails,
transaction does rollback and it leads to logging of
delete operation for online ALTER TABLE.
While applying the insert log entries, alter operation
encounters 'DUPLICATE KEY' error.
- To avoid the above fake duplicate scenario, InnoDB should
not write any log for online ALTER TABLE before DML transaction
commit.
- User thread which does DML can apply the online log if
InnoDB ran out of online log and index is marked as completed.
Set online log error if apply phase encountered any error.
It can also clear all other indexes log, marks the newly
added indexes as corrupted.
- Removed the old online code which was a part of DML operations
commit_inplace_alter_table() : Does apply the online log
for the last batch of secondary index log and does frees
the log for the completed index.
trx_t::apply_online_log: Set to true while writing the undo
log if the modified table has active DDL
trx_t::apply_log(): Apply the DML changes to online DDL tables
dict_table_t::is_active_ddl(): Returns true if the table
has an active DDL
dict_index_t::online_log_make_dummy(): Assign dummy value
for clustered index online log to indicate the secondary
indexes are being rebuild.
dict_index_t::online_log_is_dummy(): Check whether the online
log has dummy value
ha_innobase_inplace_ctx::log_failure(): Handle the apply log
failure for online DDL transaction
row_log_mark_other_online_index_abort(): Clear out all other
online index log after encountering the error during
row_log_apply()
row_log_get_error(): Get the error happened during row_log_apply()
row_log_online_op(): Does apply the online log if index is
completed and ran out of memory. Returns false if apply log fails
UndorecApplier: Introduced a class to maintain the undo log
record, latched undo buffer page, parse the undo log record,
maintain the undo record type, info bits and update vector
UndorecApplier::get_old_rec(): Get the correct version of the
clustered index record that was modified by the current undo
log record
UndorecApplier::clear_undo_rec(): Clear the undo log related
information after applying the undo log record
UndorecApplier::log_update(): Handle the update, delete undo
log and apply it on online indexes
UndorecApplier::log_insert(): Handle the insert undo log
and apply it on online indexes
UndorecApplier::is_same(): Check whether the given roll pointer
is generated by the current undo log record information
trx_t::rollback_low(): Set apply_online_log for the transaction
after partially rollbacked transaction has any active DDL
prepare_inplace_alter_table_dict(): After allocating the online
log, InnoDB does create fulltext common tables. Fulltext index
doesn't allow the index to be online. So removed the dead
code of online log removal
Thanks to Marko Mäkelä for providing the initial prototype and
Matthias Leich for testing the issue patiently.
2022-04-25 10:06:56 +02:00
|
|
|
Copyright (c) 2017, 2022, MariaDB Corporation.
|
2010-07-14 14:27:13 +02:00
|
|
|
|
|
|
|
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 Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2019-05-11 20:29:06 +02:00
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
2010-07-14 14:27:13 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Header for compiler-dependent features.
|
|
|
|
|
|
|
|
Intended to contain a set of reusable wrappers for preprocessor
|
|
|
|
macros, attributes, pragmas, and any other features that are
|
|
|
|
specific to a target compiler.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
Compiler-dependent internal convenience macros.
|
|
|
|
*/
|
|
|
|
|
2020-02-28 18:59:01 +01:00
|
|
|
/* C vs C++ */
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#define CONSTEXPR constexpr
|
|
|
|
#else
|
|
|
|
#define CONSTEXPR
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
2010-07-14 14:27:13 +02:00
|
|
|
/* GNU C/C++ */
|
|
|
|
#if defined __GNUC__
|
|
|
|
# define MY_ALIGN_EXT
|
2023-07-11 19:24:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
__builtin_unreachable() removes the "statement may fall through" warning-as-
|
|
|
|
error when MY_ASSERT_UNREACHABLE() is used in "case xxx:" in switch (...)
|
|
|
|
statements.
|
|
|
|
abort() is there to prevent the execution from reaching the
|
|
|
|
__builtin_unreachable() as this may cause misleading stack traces.
|
|
|
|
*/
|
|
|
|
# define MY_ASSERT_UNREACHABLE() { abort(); __builtin_unreachable(); }
|
2010-07-14 14:27:13 +02:00
|
|
|
|
|
|
|
/* Microsoft Visual C++ */
|
|
|
|
#elif defined _MSC_VER
|
|
|
|
# define MY_ALIGNOF(type) __alignof(type)
|
|
|
|
# define MY_ALIGNED(n) __declspec(align(n))
|
|
|
|
|
|
|
|
/* Oracle Solaris Studio */
|
|
|
|
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
2010-07-14 21:39:40 +02:00
|
|
|
# if __SUNPRO_C >= 0x590
|
2010-07-14 14:27:13 +02:00
|
|
|
# define MY_ALIGN_EXT
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/* IBM XL C/C++ */
|
|
|
|
#elif defined __xlC__
|
|
|
|
# if __xlC__ >= 0x0600
|
|
|
|
# define MY_ALIGN_EXT
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/* HP aCC */
|
|
|
|
#elif defined(__HP_aCC) || defined(__HP_cc)
|
|
|
|
# if (__HP_aCC >= 60000) || (__HP_cc >= 60000)
|
|
|
|
# define MY_ALIGN_EXT
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MY_ALIGN_EXT
|
|
|
|
/** Specifies the minimum alignment of a type. */
|
|
|
|
# define MY_ALIGNOF(type) __alignof__(type)
|
|
|
|
/** Determine the alignment requirement of a type. */
|
|
|
|
# define MY_ALIGNED(n) __attribute__((__aligned__((n))))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
2010-10-20 20:21:40 +02:00
|
|
|
Generic (compiler-independent) features.
|
2010-07-14 14:27:13 +02:00
|
|
|
*/
|
2010-11-10 22:14:47 +01:00
|
|
|
|
2010-07-14 14:27:13 +02:00
|
|
|
#ifndef MY_ALIGNOF
|
|
|
|
# ifdef __cplusplus
|
|
|
|
template<typename type> struct my_alignof_helper { char m1; type m2; };
|
|
|
|
/* Invalid for non-POD types, but most compilers give the right answer. */
|
|
|
|
# define MY_ALIGNOF(type) offsetof(my_alignof_helper<type>, m2)
|
|
|
|
# else
|
|
|
|
# define MY_ALIGNOF(type) offsetof(struct { char m1; type m2; }, m2)
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2010-10-20 20:21:40 +02:00
|
|
|
#ifndef MY_ASSERT_UNREACHABLE
|
2023-07-11 19:24:28 +02:00
|
|
|
# define MY_ASSERT_UNREACHABLE() do { abort(); } while (0)
|
2010-10-20 20:21:40 +02:00
|
|
|
#endif
|
|
|
|
|
2010-07-14 14:27:13 +02:00
|
|
|
/**
|
|
|
|
C++ Type Traits
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
|
|
|
/**
|
|
|
|
Opaque storage with a particular alignment.
|
|
|
|
*/
|
|
|
|
# if defined(MY_ALIGNED)
|
|
|
|
/* Partial specialization used due to MSVC++. */
|
|
|
|
template<size_t alignment> struct my_alignment_imp;
|
|
|
|
template<> struct MY_ALIGNED(1) my_alignment_imp<1> {};
|
|
|
|
template<> struct MY_ALIGNED(2) my_alignment_imp<2> {};
|
|
|
|
template<> struct MY_ALIGNED(4) my_alignment_imp<4> {};
|
|
|
|
template<> struct MY_ALIGNED(8) my_alignment_imp<8> {};
|
|
|
|
template<> struct MY_ALIGNED(16) my_alignment_imp<16> {};
|
|
|
|
/* ... expand as necessary. */
|
|
|
|
# else
|
|
|
|
template<size_t alignment>
|
|
|
|
struct my_alignment_imp { double m1; };
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
A POD type with a given size and alignment.
|
|
|
|
|
|
|
|
@remark If the compiler does not support a alignment attribute
|
|
|
|
(MY_ALIGN macro), the default alignment of a double is
|
|
|
|
used instead.
|
|
|
|
|
|
|
|
@tparam size The minimum size.
|
|
|
|
@tparam alignment The desired alignment: 1, 2, 4, 8 or 16.
|
|
|
|
*/
|
|
|
|
template <size_t size, size_t alignment>
|
|
|
|
struct my_aligned_storage
|
|
|
|
{
|
|
|
|
union
|
|
|
|
{
|
|
|
|
char data[size];
|
|
|
|
my_alignment_imp<alignment> align;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
2011-05-04 10:45:51 +02:00
|
|
|
# ifndef MY_ALIGNED
|
2011-05-04 10:42:48 +02:00
|
|
|
/*
|
|
|
|
Make sure MY_ALIGNED can be used also on platforms where we don't
|
|
|
|
have a way of aligning data structures.
|
|
|
|
*/
|
|
|
|
#define MY_ALIGNED(size)
|
|
|
|
#endif
|
|
|
|
|
2017-08-31 07:20:29 +02:00
|
|
|
#ifdef __GNUC__
|
|
|
|
# define ATTRIBUTE_NORETURN __attribute__((noreturn))
|
2020-06-04 09:24:10 +02:00
|
|
|
# define ATTRIBUTE_NOINLINE __attribute__((noinline))
|
2017-08-31 07:20:29 +02:00
|
|
|
/** Starting with GCC 4.3, the "cold" attribute is used to inform the
|
|
|
|
compiler that a function is unlikely executed. The function is
|
|
|
|
optimized for size rather than speed and on many targets it is placed
|
|
|
|
into special subsection of the text section so all cold functions
|
|
|
|
appears close together improving code locality of non-cold parts of
|
|
|
|
program. The paths leading to call of cold functions within code are
|
|
|
|
marked as unlikely by the branch prediction mechanism. optimize a
|
|
|
|
rarely invoked function for size instead for speed. */
|
MDEV-15250 UPSERT during ALTER TABLE results in 'Duplicate entry' error for alter
- InnoDB DDL results in `Duplicate entry' if concurrent DML throws
duplicate key error. The following scenario explains the problem
connection con1:
ALTER TABLE t1 FORCE;
connection con2:
INSERT INTO t1(pk, uk) VALUES (2, 2), (3, 2);
In connection con2, InnoDB throws the 'DUPLICATE KEY' error because
of unique index. Alter operation will throw the error when applying
the concurrent DML log.
- Inserting the duplicate key for unique index logs the insert
operation for online ALTER TABLE. When insertion fails,
transaction does rollback and it leads to logging of
delete operation for online ALTER TABLE.
While applying the insert log entries, alter operation
encounters 'DUPLICATE KEY' error.
- To avoid the above fake duplicate scenario, InnoDB should
not write any log for online ALTER TABLE before DML transaction
commit.
- User thread which does DML can apply the online log if
InnoDB ran out of online log and index is marked as completed.
Set online log error if apply phase encountered any error.
It can also clear all other indexes log, marks the newly
added indexes as corrupted.
- Removed the old online code which was a part of DML operations
commit_inplace_alter_table() : Does apply the online log
for the last batch of secondary index log and does frees
the log for the completed index.
trx_t::apply_online_log: Set to true while writing the undo
log if the modified table has active DDL
trx_t::apply_log(): Apply the DML changes to online DDL tables
dict_table_t::is_active_ddl(): Returns true if the table
has an active DDL
dict_index_t::online_log_make_dummy(): Assign dummy value
for clustered index online log to indicate the secondary
indexes are being rebuild.
dict_index_t::online_log_is_dummy(): Check whether the online
log has dummy value
ha_innobase_inplace_ctx::log_failure(): Handle the apply log
failure for online DDL transaction
row_log_mark_other_online_index_abort(): Clear out all other
online index log after encountering the error during
row_log_apply()
row_log_get_error(): Get the error happened during row_log_apply()
row_log_online_op(): Does apply the online log if index is
completed and ran out of memory. Returns false if apply log fails
UndorecApplier: Introduced a class to maintain the undo log
record, latched undo buffer page, parse the undo log record,
maintain the undo record type, info bits and update vector
UndorecApplier::get_old_rec(): Get the correct version of the
clustered index record that was modified by the current undo
log record
UndorecApplier::clear_undo_rec(): Clear the undo log related
information after applying the undo log record
UndorecApplier::log_update(): Handle the update, delete undo
log and apply it on online indexes
UndorecApplier::log_insert(): Handle the insert undo log
and apply it on online indexes
UndorecApplier::is_same(): Check whether the given roll pointer
is generated by the current undo log record information
trx_t::rollback_low(): Set apply_online_log for the transaction
after partially rollbacked transaction has any active DDL
prepare_inplace_alter_table_dict(): After allocating the online
log, InnoDB does create fulltext common tables. Fulltext index
doesn't allow the index to be online. So removed the dead
code of online log removal
Thanks to Marko Mäkelä for providing the initial prototype and
Matthias Leich for testing the issue patiently.
2022-04-25 10:06:56 +02:00
|
|
|
# define ATTRIBUTE_COLD __attribute__((cold))
|
2023-04-27 12:37:18 +02:00
|
|
|
# define ATTRIBUTE_MALLOC __attribute__((malloc))
|
2017-09-29 20:15:20 +02:00
|
|
|
#elif defined _MSC_VER
|
2017-08-31 07:20:29 +02:00
|
|
|
# define ATTRIBUTE_NORETURN __declspec(noreturn)
|
2020-06-04 09:24:10 +02:00
|
|
|
# define ATTRIBUTE_NOINLINE __declspec(noinline)
|
2017-08-31 07:20:29 +02:00
|
|
|
#else
|
|
|
|
# define ATTRIBUTE_NORETURN /* empty */
|
2020-06-04 09:24:10 +02:00
|
|
|
# define ATTRIBUTE_NOINLINE /* empty */
|
2017-08-31 07:20:29 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef ATTRIBUTE_COLD
|
|
|
|
# define ATTRIBUTE_COLD /* empty */
|
|
|
|
#endif
|
|
|
|
|
2023-04-27 12:37:18 +02:00
|
|
|
#ifndef ATTRIBUTE_MALLOC
|
|
|
|
# define ATTRIBUTE_MALLOC
|
|
|
|
#endif
|
|
|
|
|
2010-07-14 21:39:40 +02:00
|
|
|
#include <my_attribute.h>
|
|
|
|
|
2024-06-07 16:20:10 +02:00
|
|
|
/*
|
|
|
|
C++11 thread_local incurs a performance penalty on some platforms
|
|
|
|
accessing "extern thread_local" variable (not static).
|
|
|
|
To workaround, we use the platform specific thread local
|
|
|
|
storage mechanism, which also available in plain C.
|
|
|
|
*/
|
|
|
|
#if defined (_MSC_VER)
|
|
|
|
# define MY_THREAD_LOCAL __declspec(thread)
|
|
|
|
#else
|
|
|
|
# define MY_THREAD_LOCAL __thread
|
|
|
|
#endif
|
|
|
|
|
2010-07-14 14:27:13 +02:00
|
|
|
#endif /* MY_COMPILER_INCLUDED */
|