Commit 0485328d authored by Monty's avatar Monty

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.
parent b436db98
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "discover.h" // extension_based_table_discovery, etc #include "discover.h" // extension_based_table_discovery, etc
#include "log_event.h" // *_rows_log_event #include "log_event.h" // *_rows_log_event
#include "create_options.h" #include "create_options.h"
#include "rpl_filter.h"
#include <myisampack.h> #include <myisampack.h>
#include "transaction.h" #include "transaction.h"
#include "myisam.h" #include "myisam.h"
...@@ -3931,9 +3930,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) ...@@ -3931,9 +3930,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
if it is started. if it is started.
*/ */
inline void handler::mark_trx_read_write_internal()
void
handler::mark_trx_read_write()
{ {
Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0]; 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) ...@@ -5579,30 +5576,45 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
correct for the table. correct for the table.
A row in the given table should be replicated if: 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 - Row-based replication is enabled in the current thread
- The binlog is enabled - The binlog is enabled
- It is not a temporary table - It is not a temporary table
- The binary log is open - The binary log is open
- The database the table resides in shall be binlogged (binlog_*_db rules) - The database the table resides in shall be binlogged (binlog_*_db rules)
- table is not mysql.event - 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 && check_table_binlog_row_based_done= 1;
! table->no_replicate && check_table_binlog_row_based_result=
binlog_filter->db_ok(table->s->db.str)); check_table_binlog_row_based_internal(binlog_row);
table->s->cached_row_logging_check= check;
} }
return check_table_binlog_row_based_result;
}
DBUG_ASSERT(table->s->cached_row_logging_check == 0 || bool handler::check_table_binlog_row_based_internal(bool binlog_row)
table->s->cached_row_logging_check == 1); {
THD *thd;
return (thd->is_current_stmt_binlog_format_row() && /* only InnoDB tables will be replicated through binlog emulation */
table->s->cached_row_logging_check && if (binlog_row &&
#ifdef WITH_WSREP 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 Wsrep partially enables binary logging if it have not been
explicitly turned on. As a result we return 'true' if we are in 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) ...@@ -5617,14 +5629,13 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
Otherwise, return 'true' if binary logging is on. Otherwise, return 'true' if binary logging is on.
*/ */
(thd->variables.sql_log_bin_off != 1) && IF_WSREP(((WSREP_EMULATE_BINLOG(thd) &&
((WSREP_EMULATE_BINLOG(thd) && (thd->wsrep_exec_mode != REPL_RECV)) || (thd->wsrep_exec_mode != REPL_RECV)) ||
((WSREP(thd) || (thd->variables.option_bits & OPTION_BIN_LOG)) && ((WSREP(thd) ||
mysql_bin_log.is_open()))); (thd->variables.option_bits & OPTION_BIN_LOG)) &&
#else mysql_bin_log.is_open())),
(thd->variables.option_bits & OPTION_BIN_LOG) && (thd->variables.option_bits & OPTION_BIN_LOG) &&
mysql_bin_log.is_open()); mysql_bin_log.is_open()));
#endif
} }
...@@ -5658,8 +5669,6 @@ static int write_locked_table_maps(THD *thd) ...@@ -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())); DBUG_PRINT("debug", ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
if (thd->get_binlog_table_maps() == 0)
{
MYSQL_LOCK *locks[2]; MYSQL_LOCK *locks[2];
locks[0]= thd->extra_lock; locks[0]= thd->extra_lock;
locks[1]= thd->lock; locks[1]= thd->lock;
...@@ -5680,7 +5689,7 @@ static int write_locked_table_maps(THD *thd) ...@@ -5680,7 +5689,7 @@ static int write_locked_table_maps(THD *thd)
TABLE *const table= *table_ptr; TABLE *const table= *table_ptr;
DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str)); DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
if (table->current_lock == F_WRLCK && 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 We need to have a transactional behavior for SQLCOM_CREATE_TABLE
...@@ -5708,14 +5717,15 @@ static int write_locked_table_maps(THD *thd) ...@@ -5708,14 +5717,15 @@ static int write_locked_table_maps(THD *thd)
} }
} }
} }
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*); 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 *before_record,
const uchar *after_record, const uchar *after_record,
Log_func *log_func) Log_func *log_func)
...@@ -5723,19 +5733,13 @@ static int binlog_log_row(TABLE* table, ...@@ -5723,19 +5733,13 @@ static int binlog_log_row(TABLE* table,
bool error= 0; bool error= 0;
THD *const thd= table->in_use; 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 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 the first row handled in this statement. In that case, we need
to write table maps for all locked tables to the binary log. 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 We need to have a transactional behavior for SQLCOM_CREATE_TABLE
...@@ -5749,10 +5753,20 @@ static int binlog_log_row(TABLE* table, ...@@ -5749,10 +5753,20 @@ static int binlog_log_row(TABLE* table,
table->file->has_transactions(); table->file->has_transactions();
error= (*log_func)(thd, table, has_trans, before_record, after_record); error= (*log_func)(thd, table, has_trans, before_record, after_record);
} }
}
return error ? HA_ERR_RBR_LOGGING_FAILED : 0; 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 handler::ha_external_lock(THD *thd, int lock_type)
{ {
int error; int error;
...@@ -5851,6 +5865,8 @@ int handler::ha_reset() ...@@ -5851,6 +5865,8 @@ int handler::ha_reset()
table->default_column_bitmaps(); table->default_column_bitmaps();
pushed_cond= NULL; pushed_cond= NULL;
tracker= 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 */ /* Reset information about pushed engine conditions */
cancel_pushed_idx_cond(); cancel_pushed_idx_cond();
/* Reset information about pushed index conditions */ /* Reset information about pushed index conditions */
...@@ -5875,14 +5891,13 @@ int handler::ha_write_row(uchar *buf) ...@@ -5875,14 +5891,13 @@ int handler::ha_write_row(uchar *buf)
{ error= write_row(buf); }) { error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error); MYSQL_INSERT_ROW_DONE(error);
if (unlikely(error)) if (likely(!error))
DBUG_RETURN(error); {
rows_changed++; rows_changed++;
if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) error= binlog_log_row(table, 0, buf, log_func);
DBUG_RETURN(error); /* purecov: inspected */ }
DEBUG_SYNC_C("ha_write_row_end"); 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) ...@@ -5908,12 +5923,12 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
{ error= update_row(old_data, new_data);}) { error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error); MYSQL_UPDATE_ROW_DONE(error);
if (unlikely(error)) if (likely(!error))
return error; {
rows_changed++; 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 error;
return 0;
} }
int handler::ha_delete_row(const uchar *buf) int handler::ha_delete_row(const uchar *buf)
...@@ -5935,12 +5950,12 @@ 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, TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, active_index, 0,
{ error= delete_row(buf);}) { error= delete_row(buf);})
MYSQL_DELETE_ROW_DONE(error); MYSQL_DELETE_ROW_DONE(error);
if (unlikely(error)) if (likely(!error))
return error; {
rows_changed++; 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 error;
return 0;
} }
......
...@@ -2581,11 +2581,6 @@ class handler :public Sql_alloc ...@@ -2581,11 +2581,6 @@ class handler :public Sql_alloc
RANGE_SEQ_IF mrr_funcs; /* Range sequence traversal functions */ RANGE_SEQ_IF mrr_funcs; /* Range sequence traversal functions */
HANDLER_BUFFER *multi_range_buffer; /* MRR buffer info */ HANDLER_BUFFER *multi_range_buffer; /* MRR buffer info */
uint ranges_in_seq; /* Total number of ranges in the traversed sequence */ 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) */ /** Current range (the one we're now returning rows from) */
KEY_MULTI_RANGE mrr_cur_range; KEY_MULTI_RANGE mrr_cur_range;
...@@ -2593,23 +2588,32 @@ class handler :public Sql_alloc ...@@ -2593,23 +2588,32 @@ class handler :public Sql_alloc
key_range save_end_range, *end_range; key_range save_end_range, *end_range;
KEY_PART_INFO *range_key_part; KEY_PART_INFO *range_key_part;
int key_compare_result_on_equal; 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 eq_range;
bool internal_tmp_table; /* If internal tmp table */ bool internal_tmp_table; /* If internal tmp table */
bool implicit_emptied; /* Can be !=0 only if HEAP */
uint errkey; /* Last dup key */ bool mark_trx_read_write_done; /* mark_trx_read_write was called */
uint key_used_on_scan; bool check_table_binlog_row_based_done; /* check_table_binlog.. was called */
uint active_index; bool check_table_binlog_row_based_result; /* cached check_table_binlog... */
/* /*
TRUE <=> the engine guarantees that returned records are within the range TRUE <=> the engine guarantees that returned records are within the range
being scanned. being scanned.
*/ */
bool in_range_check_pushed_down; 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) */ /** Length of ref (1-8 or the clustered key length) */
uint ref_length; uint ref_length;
FT_INFO *ft_handler; FT_INFO *ft_handler;
enum {NONE=0, INDEX, RND} inited; enum {NONE=0, INDEX, RND} inited;
bool implicit_emptied; /* Can be !=0 only if HEAP */
const COND *pushed_cond; const COND *pushed_cond;
/** /**
next_insert_id is the next value which should be inserted into the next_insert_id is the next value which should be inserted into the
...@@ -2693,11 +2697,16 @@ class handler :public Sql_alloc ...@@ -2693,11 +2697,16 @@ class handler :public Sql_alloc
handler(handlerton *ht_arg, TABLE_SHARE *share_arg) handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
:table_share(share_arg), table(0), :table_share(share_arg), table(0),
estimation_rows_to_insert(0), ht(ht_arg), 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), in_range_check_pushed_down(FALSE),
key_used_on_scan(MAX_KEY),
active_index(MAX_KEY),
ref_length(sizeof(my_off_t)), ref_length(sizeof(my_off_t)),
ft_handler(0), inited(NONE), ft_handler(0), inited(NONE),
implicit_emptied(0),
pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0), pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
tracker(NULL), tracker(NULL),
pushed_idx_cond(NULL), pushed_idx_cond(NULL),
...@@ -3875,10 +3884,22 @@ class handler :public Sql_alloc ...@@ -3875,10 +3884,22 @@ class handler :public Sql_alloc
*/ */
virtual int delete_table(const char *name); virtual int delete_table(const char *name);
public:
inline bool check_table_binlog_row_based(bool binlog_row);
private: 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 */ /* Private helpers */
inline void mark_trx_read_write();
private:
inline void increment_statistics(ulong SSV::*offset) const; inline void increment_statistics(ulong SSV::*offset) const;
inline void decrement_statistics(ulong SSV::*offset) const; inline void decrement_statistics(ulong SSV::*offset) const;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "discover.h" #include "discover.h"
#include "mdl.h" // MDL_wait_for_graph_visitor #include "mdl.h" // MDL_wait_for_graph_visitor
#include "sql_view.h" #include "sql_view.h"
#include "rpl_filter.h"
/* INFORMATION_SCHEMA name */ /* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; 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, ...@@ -316,7 +317,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
share->normalized_path.length= path_length; share->normalized_path.length= path_length;
share->table_category= get_table_category(& share->db, & share->table_name); share->table_category= get_table_category(& share->db, & share->table_name);
share->open_errno= ENOENT; 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)); 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, ...@@ -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->path.length= share->normalized_path.length= strlen(path);
share->frm_version= FRM_VER_TRUE_VARCHAR; 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 table_map_id is also used for MERGE tables to suppress repeated
...@@ -2974,6 +2976,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, ...@@ -2974,6 +2976,9 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
outparam->no_replicate= FALSE; 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. */ /* Increment the opened_tables counter, only when open flags set. */
if (db_stat) if (db_stat)
thd->status_var.opened_tables++; thd->status_var.opened_tables++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment