Skip to content
Permalink
Browse files

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.
  • Loading branch information
montywi committed Feb 16, 2016
1 parent b436db9 commit 0485328d030f4b742dac7b667e8ed099beb9e9f2
Showing with 171 additions and 130 deletions.
  1. +128 −113 sql/handler.cc
  2. +36 −15 sql/handler.h
  3. +7 −2 sql/table.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
(thd->variables.option_bits & OPTION_BIN_LOG) &&
mysql_bin_log.is_open());
#endif
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()));
}


@@ -5658,54 +5669,51 @@ 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;
my_bool with_annotate= thd->variables.binlog_annotate_row_events &&
thd->query() && thd->query_length();

for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
{
MYSQL_LOCK *locks[2];
locks[0]= thd->extra_lock;
locks[1]= thd->lock;
my_bool with_annotate= thd->variables.binlog_annotate_row_events &&
thd->query() && thd->query_length();
MYSQL_LOCK const *const lock= locks[i];
if (lock == NULL)
continue;

for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
TABLE **const end_ptr= lock->table + lock->table_count;
for (TABLE **table_ptr= lock->table ;
table_ptr != end_ptr ;
++table_ptr)
{
MYSQL_LOCK const *const lock= locks[i];
if (lock == NULL)
continue;

TABLE **const end_ptr= lock->table + lock->table_count;
for (TABLE **table_ptr= lock->table ;
table_ptr != end_ptr ;
++table_ptr)
TABLE *const table= *table_ptr;
DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
if (table->current_lock == F_WRLCK &&
table->file->check_table_binlog_row_based(0))
{
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))
{
/*
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
(e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
compatible behavior with the STMT based replication even when
the table is not transactional. In other words, if the operation
fails while executing the insert phase nothing is written to the
binlog.
Note that at this point, we check the type of a set of tables to
create the table map events. In the function binlog_log_row(),
which calls the current function, we check the type of the table
of the current row.
*/
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans,
&with_annotate);
/*
If an error occurs, it is the responsibility of the caller to
roll back the transaction.
*/
if (unlikely(error))
DBUG_RETURN(1);
}
/*
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
(e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
compatible behavior with the STMT based replication even when
the table is not transactional. In other words, if the operation
fails while executing the insert phase nothing is written to the
binlog.
Note that at this point, we check the type of a set of tables to
create the table map events. In the function binlog_log_row(),
which calls the current function, we check the type of the table
of the current row.
*/
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans,
&with_annotate);
/*
If an error occurs, it is the responsibility of the caller to
roll back the transaction.
*/
if (unlikely(error))
DBUG_RETURN(1);
}
}
}
@@ -5715,44 +5723,50 @@ static int write_locked_table_maps(THD *thd)

typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);

static int binlog_log_row(TABLE* table,
const uchar *before_record,
const uchar *after_record,
Log_func *log_func)


static int binlog_log_row_internal(TABLE* table,
const uchar *before_record,
const uchar *after_record,
Log_func *log_func)
{
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= ((thd->get_binlog_table_maps() == 0 &&
write_locked_table_maps(thd))))))
{
/*
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.
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
(i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
compatible behavior with the STMT based replication even when
the table is not transactional. In other words, if the operation
fails while executing the insert phase nothing is written to the
binlog.
*/
if (likely(!(error= write_locked_table_maps(thd))))
{
/*
We need to have a transactional behavior for SQLCOM_CREATE_TABLE
(i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
compatible behavior with the STMT based replication even when
the table is not transactional. In other words, if the operation
fails while executing the insert phase nothing is written to the
binlog.
*/
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
table->file->has_transactions();
error= (*log_func)(thd, table, has_trans, before_record, after_record);
}
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_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);
rows_changed++;
if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
DBUG_RETURN(error); /* purecov: inspected */

if (likely(!error))
{
rows_changed++;
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;
rows_changed++;
if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
return error;
return 0;
if (likely(!error))
{
rows_changed++;
error= binlog_log_row(table, old_data, new_data, log_func);
}
return error;
}

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;
rows_changed++;
if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
return error;
return 0;
if (likely(!error))
{
rows_changed++;
error= binlog_log_row(table, buf, 0, log_func);
}
return error;
}


0 comments on commit 0485328

Please sign in to comment.
You can’t perform that action at this time.