mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
[MDEV-6877] Add binlog writing according to columns
The logging function now writes to the binlog according to the bitmap columns implied by the binlog_row_image variable.
This commit is contained in:
@ -5658,8 +5658,7 @@ static int write_locked_table_maps(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef bool Log_func(THD*, TABLE*, bool, MY_BITMAP*,
|
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
|
||||||
uint, const uchar*, const uchar*);
|
|
||||||
|
|
||||||
static int binlog_log_row(TABLE* table,
|
static int binlog_log_row(TABLE* table,
|
||||||
const uchar *before_record,
|
const uchar *before_record,
|
||||||
@ -5705,8 +5704,7 @@ static int binlog_log_row(TABLE* table,
|
|||||||
*/
|
*/
|
||||||
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
|
bool const has_trans= thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
|
||||||
table->file->has_transactions();
|
table->file->has_transactions();
|
||||||
error= (*log_func)(thd, table, has_trans, &cols, table->s->fields,
|
error= (*log_func)(thd, table, has_trans, before_record, after_record);
|
||||||
before_record, after_record);
|
|
||||||
}
|
}
|
||||||
if (!use_bitbuf)
|
if (!use_bitbuf)
|
||||||
my_bitmap_free(&cols);
|
my_bitmap_free(&cols);
|
||||||
|
@ -4528,14 +4528,11 @@ public:
|
|||||||
#if defined(MYSQL_SERVER)
|
#if defined(MYSQL_SERVER)
|
||||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||||
bool is_transactional,
|
bool is_transactional,
|
||||||
MY_BITMAP *cols,
|
|
||||||
uint fields,
|
|
||||||
const uchar *before_record
|
const uchar *before_record
|
||||||
__attribute__((unused)),
|
__attribute__((unused)),
|
||||||
const uchar *after_record)
|
const uchar *after_record)
|
||||||
{
|
{
|
||||||
return thd->binlog_write_row(table, is_transactional,
|
return thd->binlog_write_row(table, is_transactional, after_record);
|
||||||
cols, fields, after_record);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -4596,13 +4593,11 @@ public:
|
|||||||
#ifdef MYSQL_SERVER
|
#ifdef MYSQL_SERVER
|
||||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||||
bool is_transactional,
|
bool is_transactional,
|
||||||
MY_BITMAP *cols,
|
|
||||||
uint fields,
|
|
||||||
const uchar *before_record,
|
const uchar *before_record,
|
||||||
const uchar *after_record)
|
const uchar *after_record)
|
||||||
{
|
{
|
||||||
return thd->binlog_update_row(table, is_transactional,
|
return thd->binlog_update_row(table, is_transactional,
|
||||||
cols, fields, before_record, after_record);
|
before_record, after_record);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -4668,14 +4663,12 @@ public:
|
|||||||
#ifdef MYSQL_SERVER
|
#ifdef MYSQL_SERVER
|
||||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||||
bool is_transactional,
|
bool is_transactional,
|
||||||
MY_BITMAP *cols,
|
|
||||||
uint fields,
|
|
||||||
const uchar *before_record,
|
const uchar *before_record,
|
||||||
const uchar *after_record
|
const uchar *after_record
|
||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
return thd->binlog_delete_row(table, is_transactional,
|
return thd->binlog_delete_row(table, is_transactional,
|
||||||
cols, fields, before_record);
|
before_record);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -369,14 +369,11 @@ public:
|
|||||||
#if !defined(MYSQL_CLIENT)
|
#if !defined(MYSQL_CLIENT)
|
||||||
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
static bool binlog_row_logging_function(THD *thd, TABLE *table,
|
||||||
bool is_transactional,
|
bool is_transactional,
|
||||||
MY_BITMAP *cols,
|
|
||||||
uint fields,
|
|
||||||
const uchar *before_record
|
const uchar *before_record
|
||||||
__attribute__((unused)),
|
__attribute__((unused)),
|
||||||
const uchar *after_record)
|
const uchar *after_record)
|
||||||
{
|
{
|
||||||
return thd->binlog_write_row(table, is_transactional,
|
return thd->binlog_write_row(table, is_transactional, after_record);
|
||||||
cols, fields, after_record);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -452,7 +449,7 @@ public:
|
|||||||
const uchar *after_record)
|
const uchar *after_record)
|
||||||
{
|
{
|
||||||
return thd->binlog_update_row(table, is_transactional,
|
return thd->binlog_update_row(table, is_transactional,
|
||||||
cols, fields, before_record, after_record);
|
before_record, after_record);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -526,8 +523,7 @@ public:
|
|||||||
const uchar *after_record
|
const uchar *after_record
|
||||||
__attribute__((unused)))
|
__attribute__((unused)))
|
||||||
{
|
{
|
||||||
return thd->binlog_delete_row(table, is_transactional,
|
return thd->binlog_delete_row(table, is_transactional, before_record);
|
||||||
cols, fields, before_record);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
123
sql/sql_class.cc
123
sql/sql_class.cc
@ -6112,9 +6112,8 @@ CPP_UNNAMED_NS_START
|
|||||||
|
|
||||||
CPP_UNNAMED_NS_END
|
CPP_UNNAMED_NS_END
|
||||||
|
|
||||||
int THD::binlog_write_row(TABLE* table, bool is_trans,
|
int THD::binlog_write_row(TABLE* table, bool is_trans,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
uchar const *record)
|
||||||
uchar const *record)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
||||||
@ -6129,7 +6128,7 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
|
|||||||
|
|
||||||
uchar *row_data= memory.slot(0);
|
uchar *row_data= memory.slot(0);
|
||||||
|
|
||||||
size_t const len= pack_row(table, cols, row_data, record);
|
size_t const len= pack_row(table, table->write_set, row_data, record);
|
||||||
|
|
||||||
/* Ensure that all events in a GTID group are in the same cache */
|
/* Ensure that all events in a GTID group are in the same cache */
|
||||||
if (variables.option_bits & OPTION_GTID_BEGIN)
|
if (variables.option_bits & OPTION_GTID_BEGIN)
|
||||||
@ -6147,13 +6146,19 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int THD::binlog_update_row(TABLE* table, bool is_trans,
|
int THD::binlog_update_row(TABLE* table, bool is_trans,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
|
||||||
const uchar *before_record,
|
const uchar *before_record,
|
||||||
const uchar *after_record)
|
const uchar *after_record)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
||||||
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
|
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
|
||||||
|
|
||||||
|
/**
|
||||||
|
Save a reference to the original read and write set bitmaps.
|
||||||
|
We will need this to restore the bitmaps at the end.
|
||||||
|
*/
|
||||||
|
MY_BITMAP *old_read_set= table->read_set;
|
||||||
|
MY_BITMAP *old_write_set= table->write_set;
|
||||||
|
|
||||||
size_t const before_maxlen = max_row_length(table, before_record);
|
size_t const before_maxlen = max_row_length(table, before_record);
|
||||||
size_t const after_maxlen = max_row_length(table, after_record);
|
size_t const after_maxlen = max_row_length(table, after_record);
|
||||||
|
|
||||||
@ -6164,9 +6169,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
|
|||||||
uchar *before_row= row_data.slot(0);
|
uchar *before_row= row_data.slot(0);
|
||||||
uchar *after_row= row_data.slot(1);
|
uchar *after_row= row_data.slot(1);
|
||||||
|
|
||||||
size_t const before_size= pack_row(table, cols, before_row,
|
size_t const before_size= pack_row(table, table->read_set, before_row,
|
||||||
before_record);
|
before_record);
|
||||||
size_t const after_size= pack_row(table, cols, after_row,
|
size_t const after_size= pack_row(table, table->write_set, after_row,
|
||||||
after_record);
|
after_record);
|
||||||
|
|
||||||
/* Ensure that all events in a GTID group are in the same cache */
|
/* Ensure that all events in a GTID group are in the same cache */
|
||||||
@ -6192,19 +6197,37 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
|
|||||||
if (unlikely(ev == 0))
|
if (unlikely(ev == 0))
|
||||||
return HA_ERR_OUT_OF_MEM;
|
return HA_ERR_OUT_OF_MEM;
|
||||||
|
|
||||||
return
|
int error= ev->add_row_data(before_row, before_size) ||
|
||||||
ev->add_row_data(before_row, before_size) ||
|
ev->add_row_data(after_row, after_size);
|
||||||
ev->add_row_data(after_row, after_size);
|
|
||||||
|
/* restore read/write set for the rest of execution */
|
||||||
|
table->column_bitmaps_set_no_signal(old_read_set,
|
||||||
|
old_write_set);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int THD::binlog_delete_row(TABLE* table, bool is_trans,
|
int THD::binlog_delete_row(TABLE* table, bool is_trans,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
|
||||||
uchar const *record)
|
uchar const *record)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
|
||||||
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
|
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
|
||||||
|
/**
|
||||||
|
Save a reference to the original read and write set bitmaps.
|
||||||
|
We will need this to restore the bitmaps at the end.
|
||||||
|
*/
|
||||||
|
MY_BITMAP *old_read_set= table->read_set;
|
||||||
|
MY_BITMAP *old_write_set= table->write_set;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
This will remove spurious fields required during execution but
|
||||||
|
not needed for binlogging. This is done according to the:
|
||||||
|
binlog-row-image option.
|
||||||
|
*/
|
||||||
|
binlog_prepare_row_images(table);
|
||||||
|
|
||||||
|
/*
|
||||||
Pack records into format for transfer. We are allocating more
|
Pack records into format for transfer. We are allocating more
|
||||||
memory than needed, but that doesn't matter.
|
memory than needed, but that doesn't matter.
|
||||||
*/
|
*/
|
||||||
@ -6214,7 +6237,8 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
|
|||||||
|
|
||||||
uchar *row_data= memory.slot(0);
|
uchar *row_data= memory.slot(0);
|
||||||
|
|
||||||
size_t const len= pack_row(table, cols, row_data, record);
|
DBUG_DUMP("table->read_set", (uchar*) table->read_set->bitmap, (table->s->fields + 7) / 8);
|
||||||
|
size_t const len= pack_row(table, table->read_set, row_data, record);
|
||||||
|
|
||||||
/* Ensure that all events in a GTID group are in the same cache */
|
/* Ensure that all events in a GTID group are in the same cache */
|
||||||
if (variables.option_bits & OPTION_GTID_BEGIN)
|
if (variables.option_bits & OPTION_GTID_BEGIN)
|
||||||
@ -6228,10 +6252,81 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
|
|||||||
if (unlikely(ev == 0))
|
if (unlikely(ev == 0))
|
||||||
return HA_ERR_OUT_OF_MEM;
|
return HA_ERR_OUT_OF_MEM;
|
||||||
|
|
||||||
return ev->add_row_data(row_data, len);
|
|
||||||
|
int error= ev->add_row_data(row_data, len);
|
||||||
|
|
||||||
|
/* restore read/write set for the rest of execution */
|
||||||
|
table->column_bitmaps_set_no_signal(old_read_set,
|
||||||
|
old_write_set);
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void THD::binlog_prepare_row_images(TABLE *table)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("THD::binlog_prepare_row_images");
|
||||||
|
/**
|
||||||
|
Remove from read_set spurious columns. The write_set has been
|
||||||
|
handled before in table->mark_columns_needed_for_update.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s", table->read_set);
|
||||||
|
THD *thd= table->in_use;
|
||||||
|
|
||||||
|
/**
|
||||||
|
if there is a primary key in the table (ie, user declared PK or a
|
||||||
|
non-null unique index) and we dont want to ship the entire image,
|
||||||
|
and the handler involved supports this.
|
||||||
|
*/
|
||||||
|
if (table->s->primary_key < MAX_KEY &&
|
||||||
|
(thd->variables.binlog_row_image < BINLOG_ROW_IMAGE_FULL) &&
|
||||||
|
!ha_check_storage_engine_flag(table->s->db_type(), HTON_NO_BINLOG_ROW_OPT))
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
Just to be sure that tmp_set is currently not in use as
|
||||||
|
the read_set already.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(table->read_set != &table->tmp_set);
|
||||||
|
|
||||||
|
bitmap_clear_all(&table->tmp_set);
|
||||||
|
|
||||||
|
switch(thd->variables.binlog_row_image)
|
||||||
|
{
|
||||||
|
case BINLOG_ROW_IMAGE_MINIMAL:
|
||||||
|
/* MINIMAL: Mark only PK */
|
||||||
|
table->mark_columns_used_by_index_no_reset(table->s->primary_key,
|
||||||
|
&table->tmp_set);
|
||||||
|
break;
|
||||||
|
case BINLOG_ROW_IMAGE_NOBLOB:
|
||||||
|
/**
|
||||||
|
NOBLOB: Remove unnecessary BLOB fields from read_set
|
||||||
|
(the ones that are not part of PK).
|
||||||
|
*/
|
||||||
|
bitmap_union(&table->tmp_set, table->read_set);
|
||||||
|
for (Field **ptr=table->field ; *ptr ; ptr++)
|
||||||
|
{
|
||||||
|
Field *field= (*ptr);
|
||||||
|
if ((field->type() == MYSQL_TYPE_BLOB) &&
|
||||||
|
!(field->flags & PRI_KEY_FLAG))
|
||||||
|
bitmap_clear_bit(&table->tmp_set, field->field_index);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBUG_ASSERT(0); // impossible.
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the temporary read_set */
|
||||||
|
table->column_bitmaps_set_no_signal(&table->tmp_set,
|
||||||
|
table->write_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s", table->read_set);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int THD::binlog_remove_pending_rows_event(bool clear_maps,
|
int THD::binlog_remove_pending_rows_event(bool clear_maps,
|
||||||
bool is_transactional)
|
bool is_transactional)
|
||||||
{
|
{
|
||||||
|
@ -2127,14 +2127,12 @@ public:
|
|||||||
int binlog_write_table_map(TABLE *table, bool is_transactional,
|
int binlog_write_table_map(TABLE *table, bool is_transactional,
|
||||||
my_bool *with_annotate= 0);
|
my_bool *with_annotate= 0);
|
||||||
int binlog_write_row(TABLE* table, bool is_transactional,
|
int binlog_write_row(TABLE* table, bool is_transactional,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
|
||||||
const uchar *buf);
|
const uchar *buf);
|
||||||
int binlog_delete_row(TABLE* table, bool is_transactional,
|
int binlog_delete_row(TABLE* table, bool is_transactional,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
|
||||||
const uchar *buf);
|
const uchar *buf);
|
||||||
int binlog_update_row(TABLE* table, bool is_transactional,
|
int binlog_update_row(TABLE* table, bool is_transactional,
|
||||||
MY_BITMAP const* cols, size_t colcnt,
|
|
||||||
const uchar *old_data, const uchar *new_data);
|
const uchar *old_data, const uchar *new_data);
|
||||||
|
void binlog_prepare_row_images(TABLE* table);
|
||||||
|
|
||||||
void set_server_id(uint32 sid) { variables.server_id = sid; }
|
void set_server_id(uint32 sid) { variables.server_id = sid; }
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user