mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Cache check_table_binlog_row_based and mark_trx_read_write
Benefits: - Speeds up insert,write and delete by avoiding 1-2 function calls per write/update/delete. - Avoiding calling write_locked_table_maps() if not needed. - The inlined code is much smaller than before - Updating of table->s->cached_row_logging_check moved to when table is opened - Moved some bool values together in handler class to get better alignment.
This commit is contained in:
115
sql/handler.cc
115
sql/handler.cc
@ -34,7 +34,6 @@
|
||||
#include "discover.h" // extension_based_table_discovery, etc
|
||||
#include "log_event.h" // *_rows_log_event
|
||||
#include "create_options.h"
|
||||
#include "rpl_filter.h"
|
||||
#include <myisampack.h>
|
||||
#include "transaction.h"
|
||||
#include "myisam.h"
|
||||
@ -3931,9 +3930,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
|
||||
if it is started.
|
||||
*/
|
||||
|
||||
inline
|
||||
void
|
||||
handler::mark_trx_read_write()
|
||||
void handler::mark_trx_read_write_internal()
|
||||
{
|
||||
Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0];
|
||||
/*
|
||||
@ -5579,30 +5576,45 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
|
||||
correct for the table.
|
||||
|
||||
A row in the given table should be replicated if:
|
||||
- It's not called by partition engine
|
||||
- Row-based replication is enabled in the current thread
|
||||
- The binlog is enabled
|
||||
- It is not a temporary table
|
||||
- The binary log is open
|
||||
- The database the table resides in shall be binlogged (binlog_*_db rules)
|
||||
- table is not mysql.event
|
||||
|
||||
RETURN VALUE
|
||||
0 No binary logging in row format
|
||||
1 Row needs to be logged
|
||||
*/
|
||||
|
||||
static bool check_table_binlog_row_based(THD *thd, TABLE *table)
|
||||
inline bool handler::check_table_binlog_row_based(bool binlog_row)
|
||||
{
|
||||
if (table->s->cached_row_logging_check == -1)
|
||||
if (unlikely((table->in_use->variables.sql_log_bin_off)))
|
||||
return 0; /* Called by partitioning engine */
|
||||
if (unlikely((!check_table_binlog_row_based_done)))
|
||||
{
|
||||
int const check(table->s->tmp_table == NO_TMP_TABLE &&
|
||||
! table->no_replicate &&
|
||||
binlog_filter->db_ok(table->s->db.str));
|
||||
table->s->cached_row_logging_check= check;
|
||||
check_table_binlog_row_based_done= 1;
|
||||
check_table_binlog_row_based_result=
|
||||
check_table_binlog_row_based_internal(binlog_row);
|
||||
}
|
||||
return check_table_binlog_row_based_result;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
|
||||
table->s->cached_row_logging_check == 1);
|
||||
bool handler::check_table_binlog_row_based_internal(bool binlog_row)
|
||||
{
|
||||
THD *thd;
|
||||
|
||||
return (thd->is_current_stmt_binlog_format_row() &&
|
||||
table->s->cached_row_logging_check &&
|
||||
#ifdef WITH_WSREP
|
||||
/* only InnoDB tables will be replicated through binlog emulation */
|
||||
if (binlog_row &&
|
||||
WSREP_EMULATE_BINLOG(thd) &&
|
||||
table->file->partition_ht()->db_type != DB_TYPE_INNODB)
|
||||
return 0;
|
||||
|
||||
thd= table->in_use;
|
||||
return (table->s->cached_row_logging_check &&
|
||||
thd->is_current_stmt_binlog_format_row() &&
|
||||
/*
|
||||
Wsrep partially enables binary logging if it have not been
|
||||
explicitly turned on. As a result we return 'true' if we are in
|
||||
@ -5617,14 +5629,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
|
||||
|
||||
Otherwise, return 'true' if binary logging is on.
|
||||
*/
|
||||
(thd->variables.sql_log_bin_off != 1) &&
|
||||
((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) ||
|
||||
((WSREP(thd) || (thd->variables.option_bits & OPTION_BIN_LOG)) &&
|
||||
mysql_bin_log.is_open())));
|
||||
#else
|
||||
IF_WSREP(((WSREP_EMULATE_BINLOG(thd) &&
|
||||
(thd->wsrep_exec_mode != REPL_RECV)) ||
|
||||
((WSREP(thd) ||
|
||||
(thd->variables.option_bits & OPTION_BIN_LOG)) &&
|
||||
mysql_bin_log.is_open())),
|
||||
(thd->variables.option_bits & OPTION_BIN_LOG) &&
|
||||
mysql_bin_log.is_open());
|
||||
#endif
|
||||
mysql_bin_log.is_open()));
|
||||
}
|
||||
|
||||
|
||||
@ -5658,8 +5669,6 @@ static int write_locked_table_maps(THD *thd)
|
||||
|
||||
DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
|
||||
|
||||
if (thd->get_binlog_table_maps() == 0)
|
||||
{
|
||||
MYSQL_LOCK *locks[2];
|
||||
locks[0]= thd->extra_lock;
|
||||
locks[1]= thd->lock;
|
||||
@ -5680,7 +5689,7 @@ static int write_locked_table_maps(THD *thd)
|
||||
TABLE *const table= *table_ptr;
|
||||
DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
|
||||
if (table->current_lock == F_WRLCK &&
|
||||
check_table_binlog_row_based(thd, table))
|
||||
table->file->check_table_binlog_row_based(0))
|
||||
{
|
||||
/*
|
||||
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
|
||||
@ -5708,14 +5717,15 @@ static int write_locked_table_maps(THD *thd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
|
||||
|
||||
static int binlog_log_row(TABLE* table,
|
||||
|
||||
|
||||
static int binlog_log_row_internal(TABLE* table,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record,
|
||||
Log_func *log_func)
|
||||
@ -5723,19 +5733,13 @@ static int binlog_log_row(TABLE* table,
|
||||
bool error= 0;
|
||||
THD *const thd= table->in_use;
|
||||
|
||||
/* only InnoDB tables will be replicated through binlog emulation */
|
||||
if (WSREP_EMULATE_BINLOG(thd) &&
|
||||
table->file->partition_ht()->db_type != DB_TYPE_INNODB)
|
||||
return 0;
|
||||
|
||||
if (check_table_binlog_row_based(thd, table))
|
||||
{
|
||||
/*
|
||||
If there are no table maps written to the binary log, this is
|
||||
the first row handled in this statement. In that case, we need
|
||||
to write table maps for all locked tables to the binary log.
|
||||
*/
|
||||
if (likely(!(error= write_locked_table_maps(thd))))
|
||||
if (likely(!(error= ((thd->get_binlog_table_maps() == 0 &&
|
||||
write_locked_table_maps(thd))))))
|
||||
{
|
||||
/*
|
||||
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
|
||||
@ -5749,10 +5753,20 @@ static int binlog_log_row(TABLE* table,
|
||||
table->file->has_transactions();
|
||||
error= (*log_func)(thd, table, has_trans, before_record, after_record);
|
||||
}
|
||||
}
|
||||
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
|
||||
}
|
||||
|
||||
static inline int binlog_log_row(TABLE* table,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record,
|
||||
Log_func *log_func)
|
||||
{
|
||||
if (!table->file->check_table_binlog_row_based(1))
|
||||
return 0;
|
||||
return binlog_log_row_internal(table, before_record, after_record, log_func);
|
||||
}
|
||||
|
||||
|
||||
int handler::ha_external_lock(THD *thd, int lock_type)
|
||||
{
|
||||
int error;
|
||||
@ -5851,6 +5865,8 @@ int handler::ha_reset()
|
||||
table->default_column_bitmaps();
|
||||
pushed_cond= NULL;
|
||||
tracker= NULL;
|
||||
mark_trx_read_write_done= check_table_binlog_row_based_done=
|
||||
check_table_binlog_row_based_result= 0;
|
||||
/* Reset information about pushed engine conditions */
|
||||
cancel_pushed_idx_cond();
|
||||
/* Reset information about pushed index conditions */
|
||||
@ -5875,14 +5891,13 @@ int handler::ha_write_row(uchar *buf)
|
||||
{ error= write_row(buf); })
|
||||
|
||||
MYSQL_INSERT_ROW_DONE(error);
|
||||
if (unlikely(error))
|
||||
DBUG_RETURN(error);
|
||||
if (likely(!error))
|
||||
{
|
||||
rows_changed++;
|
||||
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
|
||||
DBUG_RETURN(error); /* purecov: inspected */
|
||||
|
||||
error= binlog_log_row(table, 0, buf, log_func);
|
||||
}
|
||||
DEBUG_SYNC_C("ha_write_row_end");
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
@ -5908,12 +5923,12 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
|
||||
{ error= update_row(old_data, new_data);})
|
||||
|
||||
MYSQL_UPDATE_ROW_DONE(error);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
if (likely(!error))
|
||||
{
|
||||
rows_changed++;
|
||||
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
|
||||
error= binlog_log_row(table, old_data, new_data, log_func);
|
||||
}
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handler::ha_delete_row(const uchar *buf)
|
||||
@ -5935,12 +5950,12 @@ int handler::ha_delete_row(const uchar *buf)
|
||||
TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
|
||||
{ error= delete_row(buf);})
|
||||
MYSQL_DELETE_ROW_DONE(error);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
if (likely(!error))
|
||||
{
|
||||
rows_changed++;
|
||||
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
|
||||
error= binlog_log_row(table, buf, 0, log_func);
|
||||
}
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2581,11 +2581,6 @@ public:
|
||||
RANGE_SEQ_IF mrr_funcs; /* Range sequence traversal functions */
|
||||
HANDLER_BUFFER *multi_range_buffer; /* MRR buffer info */
|
||||
uint ranges_in_seq; /* Total number of ranges in the traversed sequence */
|
||||
/* TRUE <=> source MRR ranges and the output are ordered */
|
||||
bool mrr_is_output_sorted;
|
||||
|
||||
/** TRUE <=> we're currently traversing a range in mrr_cur_range. */
|
||||
bool mrr_have_range;
|
||||
/** Current range (the one we're now returning rows from) */
|
||||
KEY_MULTI_RANGE mrr_cur_range;
|
||||
|
||||
@ -2593,23 +2588,32 @@ public:
|
||||
key_range save_end_range, *end_range;
|
||||
KEY_PART_INFO *range_key_part;
|
||||
int key_compare_result_on_equal;
|
||||
|
||||
/* TRUE <=> source MRR ranges and the output are ordered */
|
||||
bool mrr_is_output_sorted;
|
||||
/** TRUE <=> we're currently traversing a range in mrr_cur_range. */
|
||||
bool mrr_have_range;
|
||||
bool eq_range;
|
||||
bool internal_tmp_table; /* If internal tmp table */
|
||||
|
||||
uint errkey; /* Last dup key */
|
||||
uint key_used_on_scan;
|
||||
uint active_index;
|
||||
bool implicit_emptied; /* Can be !=0 only if HEAP */
|
||||
bool mark_trx_read_write_done; /* mark_trx_read_write was called */
|
||||
bool check_table_binlog_row_based_done; /* check_table_binlog.. was called */
|
||||
bool check_table_binlog_row_based_result; /* cached check_table_binlog... */
|
||||
/*
|
||||
TRUE <=> the engine guarantees that returned records are within the range
|
||||
being scanned.
|
||||
*/
|
||||
bool in_range_check_pushed_down;
|
||||
|
||||
uint errkey; /* Last dup key */
|
||||
uint key_used_on_scan;
|
||||
uint active_index;
|
||||
|
||||
/** Length of ref (1-8 or the clustered key length) */
|
||||
uint ref_length;
|
||||
FT_INFO *ft_handler;
|
||||
enum {NONE=0, INDEX, RND} inited;
|
||||
bool implicit_emptied; /* Can be !=0 only if HEAP */
|
||||
|
||||
const COND *pushed_cond;
|
||||
/**
|
||||
next_insert_id is the next value which should be inserted into the
|
||||
@ -2693,11 +2697,16 @@ public:
|
||||
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
|
||||
:table_share(share_arg), table(0),
|
||||
estimation_rows_to_insert(0), ht(ht_arg),
|
||||
ref(0), end_range(NULL), key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
|
||||
ref(0), end_range(NULL),
|
||||
implicit_emptied(0),
|
||||
mark_trx_read_write_done(0),
|
||||
check_table_binlog_row_based_done(0),
|
||||
check_table_binlog_row_based_result(0),
|
||||
in_range_check_pushed_down(FALSE),
|
||||
key_used_on_scan(MAX_KEY),
|
||||
active_index(MAX_KEY),
|
||||
ref_length(sizeof(my_off_t)),
|
||||
ft_handler(0), inited(NONE),
|
||||
implicit_emptied(0),
|
||||
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
|
||||
tracker(NULL),
|
||||
pushed_idx_cond(NULL),
|
||||
@ -3875,10 +3884,22 @@ protected:
|
||||
*/
|
||||
virtual int delete_table(const char *name);
|
||||
|
||||
public:
|
||||
inline bool check_table_binlog_row_based(bool binlog_row);
|
||||
private:
|
||||
/* Cache result to avoid extra calls */
|
||||
inline void mark_trx_read_write()
|
||||
{
|
||||
if (unlikely(!mark_trx_read_write_done))
|
||||
{
|
||||
mark_trx_read_write_done= 1;
|
||||
mark_trx_read_write_internal();
|
||||
}
|
||||
}
|
||||
void mark_trx_read_write_internal();
|
||||
bool check_table_binlog_row_based_internal(bool binlog_row);
|
||||
|
||||
/* Private helpers */
|
||||
inline void mark_trx_read_write();
|
||||
private:
|
||||
inline void increment_statistics(ulong SSV::*offset) const;
|
||||
inline void decrement_statistics(ulong SSV::*offset) const;
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "discover.h"
|
||||
#include "mdl.h" // MDL_wait_for_graph_visitor
|
||||
#include "sql_view.h"
|
||||
#include "rpl_filter.h"
|
||||
|
||||
/* INFORMATION_SCHEMA name */
|
||||
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
|
||||
@ -316,7 +317,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
|
||||
share->normalized_path.length= path_length;
|
||||
share->table_category= get_table_category(& share->db, & share->table_name);
|
||||
share->open_errno= ENOENT;
|
||||
share->cached_row_logging_check= -1;
|
||||
/* The following will be fixed in open_table_from_share */
|
||||
share->cached_row_logging_check= 1;
|
||||
|
||||
init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
|
||||
|
||||
@ -381,7 +383,7 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
|
||||
share->path.length= share->normalized_path.length= strlen(path);
|
||||
share->frm_version= FRM_VER_TRUE_VARCHAR;
|
||||
|
||||
share->cached_row_logging_check= -1;
|
||||
share->cached_row_logging_check= 0; // No row logging
|
||||
|
||||
/*
|
||||
table_map_id is also used for MERGE tables to suppress repeated
|
||||
@ -2974,6 +2976,9 @@ partititon_err:
|
||||
outparam->no_replicate= FALSE;
|
||||
}
|
||||
|
||||
if (outparam->no_replicate || !binlog_filter->db_ok(outparam->s->db.str))
|
||||
outparam->s->cached_row_logging_check= 0; // No row based replication
|
||||
|
||||
/* Increment the opened_tables counter, only when open flags set. */
|
||||
if (db_stat)
|
||||
thd->status_var.opened_tables++;
|
||||
|
Reference in New Issue
Block a user