mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
This patch extends mysqlbinlog with logic to support the output and replay of the new Partial_rows_log_events added in the previous commit. Generally speaking, as the assembly and execution of the Rows_log_event happens in Partial_rows_log_event::do_apply_event(); there isn’t much logic required other than outputting Partial_rows_log_event in base64. With two exceptions.. In the original mysqlbinlog code, all row events fit within a single BINLOG base64 statement; such that the Table_map_log_event sets up the tables to use, the Row Events open the tables, and then after the BINLOG statement is run, the tables are closed and the rgi is destroyed. No matter how many Row Events within a transaction there are, they are all put into the same BINLOG base64 statement. However, for the new Partial_rows_log_event, each fragment is split into its own BINLOG base64 statement (to respect the server’s configured max_packet_size). The existing logic would close the tables and destroy the replay context after each BINLOG statement (i.e. each fragment). This means that 1) Partial_rows_log_events would be un-able to assemble Rows_log_events because the rgi is destroyed between events, and 2) multiple re-assembled Rows_log_events could not be executed because the context set-up by the Table_map_log_event is cleared after the first Rows_log_event executes. To fix the first problem, where we couldn’t re-assemble Rows_log_events because the rgi would disappear between Partial_rows_log_events, the server will not destroy the rgi when ingesting BINLOG statements containing Partial_rows_log_events that have not yet assembled their Rows_log_event. To fix the second problem, where the context set-up by the Table_map_log_event is cleared after the first assembled Rows_log_event executes, mysqlbinlog caches the Table_map_log_event to re-write for each fragmented Rows_log_event at the start of the last fragment’s BINLOG statement. In effect, this will re-execute the Table_map_log_event for each assembled Rows_log_event. Reviewed-by: Hemant Dangi <hemant.dangi@mariadb.com> Acked-by: Kristian Nielsen <knielsen@knielsen-hq.org> Signed-off-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
114 lines
3.2 KiB
C++
114 lines
3.2 KiB
C++
/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
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
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#ifndef TABLE_MAPPING_H
|
|
#define TABLE_MAPPING_H
|
|
|
|
/* Forward declarations */
|
|
#ifndef MYSQL_CLIENT
|
|
struct TABLE;
|
|
#else
|
|
class Table_map_log_event;
|
|
typedef Table_map_log_event TABLE;
|
|
void free_table_map_log_event(TABLE *table);
|
|
#endif
|
|
|
|
|
|
/*
|
|
CLASS table_mapping
|
|
|
|
RESPONSIBILITIES
|
|
The table mapping is used to map table id's to table pointers
|
|
|
|
COLLABORATION
|
|
RELAY_LOG For mapping table id:s to tables when receiving events.
|
|
*/
|
|
|
|
/*
|
|
Guilhem to Mats:
|
|
in the table_mapping class, the memory is allocated and never freed (until
|
|
destruction). So this is a good candidate for allocating inside a MEM_ROOT:
|
|
it gives the efficient allocation in chunks (like in expand()). So I have
|
|
introduced a MEM_ROOT.
|
|
|
|
Note that inheriting from Sql_alloc had no effect: it has effects only when
|
|
"ptr= new table_mapping" is called, and this is never called. And it would
|
|
then allocate from thd->mem_root which is a highly volatile object (reset
|
|
from example after executing each query, see dispatch_command(), it has a
|
|
free_root() at end); as the table_mapping object is supposed to live longer
|
|
than a query, it was dangerous.
|
|
A dedicated MEM_ROOT needs to be used, see below.
|
|
*/
|
|
|
|
#include "hash.h" /* HASH */
|
|
|
|
class table_mapping {
|
|
|
|
private:
|
|
MEM_ROOT m_mem_root;
|
|
|
|
public:
|
|
|
|
enum enum_error {
|
|
ERR_NO_ERROR = 0,
|
|
ERR_LIMIT_EXCEEDED,
|
|
ERR_MEMORY_ALLOCATION
|
|
};
|
|
|
|
table_mapping();
|
|
~table_mapping();
|
|
|
|
TABLE* get_table(ulonglong table_id);
|
|
|
|
int set_table(ulonglong table_id, TABLE* table);
|
|
int remove_table(ulonglong table_id);
|
|
void clear_tables();
|
|
ulong count() const { return m_table_ids.records; }
|
|
void get_table_ids(ulonglong *table_ids, size_t n_table_ids);
|
|
|
|
private:
|
|
/*
|
|
This is a POD (Plain Old Data). Keep it that way (we apply offsetof() to
|
|
it, which only works for PODs)
|
|
*/
|
|
struct entry {
|
|
ulonglong table_id;
|
|
union {
|
|
TABLE *table;
|
|
entry *next;
|
|
};
|
|
};
|
|
|
|
entry *find_entry(ulonglong table_id)
|
|
{
|
|
return (entry *) my_hash_search(&m_table_ids,
|
|
(uchar*)&table_id,
|
|
sizeof(table_id));
|
|
}
|
|
int expand();
|
|
|
|
/*
|
|
Head of the list of free entries; "free" in the sense that it's an
|
|
allocated entry free for use, NOT in the sense that it's freed
|
|
memory.
|
|
*/
|
|
entry *m_free;
|
|
|
|
/* Correspondence between an id (a number) and a TABLE object */
|
|
HASH m_table_ids;
|
|
};
|
|
|
|
#endif
|