用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

463 lines
16 KiB

/* Copyright (c) 2013, 2019, 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, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
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, version 2.0, 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-1301 USA */
#ifndef DEFINED_RPL_BINLOG_SENDER
#define DEFINED_RPL_BINLOG_SENDER
#include <string.h>
#include <sys/types.h>
#include <chrono>
#include "libbinlogevents/include/binlog_event.h"
#include "my_inttypes.h"
#include "my_io.h"
#include "mysql_com.h"
#include "mysqld_error.h" // ER_*
#include "sql/binlog.h" // LOG_INFO
#include "sql/binlog_reader.h"
#include "sql/rpl_gtid.h"
#include "sql/sql_error.h" // Diagnostics_area
class String;
class THD;
/**
The major logic of dump thread is implemented in this class. It sends
required binlog events to clients according to their requests.
*/
class Binlog_sender : Gtid_mode_copy {
class Event_allocator;
typedef Basic_binlog_file_reader<Binlog_ifile, Binlog_event_data_istream,
Binlog_event_object_istream, Event_allocator>
File_reader;
public:
Binlog_sender(THD *thd, const char *start_file, my_off_t start_pos,
Gtid_set *exclude_gtids, uint32 flag);
~Binlog_sender() {}
/**
It checks the dump reqest and sends events to the client until it finish
all events(for mysqlbinlog) or encounters an error.
*/
void run();
private:
THD *m_thd;
String &m_packet;
/* Requested start binlog file and position */
const char *m_start_file;
my_off_t m_start_pos;
/*
For COM_BINLOG_DUMP_GTID, It may include a GTID set. All events in the set
should not be sent to the client.
*/
Gtid_set *m_exclude_gtid;
bool m_using_gtid_protocol;
bool m_check_previous_gtid_event;
bool m_gtid_clear_fd_created_flag;
/* The binlog file it is reading */
LOG_INFO m_linfo;
binary_log::enum_binlog_checksum_alg m_event_checksum_alg;
binary_log::enum_binlog_checksum_alg m_slave_checksum_alg;
std::chrono::nanoseconds m_heartbeat_period;
std::chrono::nanoseconds m_last_event_sent_ts;
/*
For mysqlbinlog(server_id is 0), it will stop immediately without waiting
if it already reads all events.
*/
bool m_wait_new_events;
Diagnostics_area m_diag_area;
char m_errmsg_buf[MYSQL_ERRMSG_SIZE];
const char *m_errmsg;
int m_errno;
/*
The position of the event it reads most recently is stored. So it can report
the exact position after where an error happens.
m_last_file will point to m_info.log_file_name, if it is same to
m_info.log_file_name. Otherwise the file name is copied to m_last_file_buf
and m_last_file will point to it.
*/
char m_last_file_buf[FN_REFLEN];
const char *m_last_file;
my_off_t m_last_pos;
/*
Needed to be able to evaluate if buffer needs to be resized (shrunk).
*/
ushort m_half_buffer_size_req_counter;
/*
* The size of the buffer next time we shrink it.
* This variable is updated once everytime we shrink or grow the buffer.
*/
size_t m_new_shrink_size;
/*
Max size of the buffer is 4GB (UINT_MAX32). It is UINT_MAX32 since the
threshold is set to (@c Log_event::read_log_event):
max(max_allowed_packet,
binlog_row_event_max_size + MAX_LOG_EVENT_HEADER)
- binlog_row_event_max_size is defined as an unsigned long,
thence in theory row events can be bigger than UINT_MAX32.
- max_allowed_packet is set to MAX_MAX_ALLOWED_PACKET which is in
turn defined as 1GB (i.e., 1024*1024*1024). (@c Binlog_sender::init()).
Therefore, anything bigger than UINT_MAX32 is not loadable into the
packet, thus we set the limit to 4GB (which is the value for UINT_MAX32,
@c PACKET_MAXIMUM_SIZE).
*/
const static uint32 PACKET_MAX_SIZE;
/*
* After these consecutive times using less than half of the buffer
* the buffer is shrunk.
*/
const static ushort PACKET_SHRINK_COUNTER_THRESHOLD;
/**
* The minimum size of the buffer.
*/
const static uint32 PACKET_MIN_SIZE;
/**
* How much to grow the buffer each time we need to accommodate more bytes
* than it currently can hold.
*/
const static float PACKET_GROW_FACTOR;
/**
* The dual of PACKET_GROW_FACTOR. How much to shrink the buffer each time
* it is deemed to being underused.
*/
const static float PACKET_SHRINK_FACTOR;
uint32 m_flag;
/*
It is true if any plugin requires to observe the transmission for each
event. And HOOKs(reserve_header, before_send and after_send) are called when
transmitting each event. Otherwise, it is false and HOOKs are not called.
*/
bool m_observe_transmission;
/* It is true if transmit_start hook is called. If the hook is not called
* it will be false.
*/
bool m_transmit_started;
/*
It initializes the context, checks if the dump request is valid and
if binlog status is correct.
*/
void init();
void cleanup();
void init_heartbeat_period();
void init_checksum_alg();
/** Check if the requested binlog file and position are valid */
int check_start_file();
/** Transform read error numbers to error messages. */
const char *log_read_error_msg(Binlog_read_error::Error_type error);
/**
It dumps a binlog file. Events are read and sent one by one. If it need
to wait for new events, it will wait after already reading all events in
the active log file.
@param[in] reader File_reader of binlog will be sent
@param[in] start_pos Position requested by the slave's IO thread.
Only the events after the position are sent.
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int send_binlog(File_reader *reader, my_off_t start_pos);
/**
It sends some events in a binlog file to the client.
@param[in] reader File_reader of binlog will be sent
@param[in] end_pos Only the events before end_pos are sent
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int send_events(File_reader *reader, my_off_t end_pos);
/**
It gets the end position of the binlog file.
@param[in] reader File_reader of binlog will be checked
@param[out] end_pos Will be set to the end position of the reading binlog
file. If this is an inactive file, it will be set to 0.
@retval 0 Success
@retval 1 Error (the thread was killed)
*/
int get_binlog_end_pos(File_reader *reader, my_off_t *end_pos);
/**
It checks if a binlog file has Previous_gtid_log_event
@param[in] reader File_reader of binlog will be checked
@param[out] found Found Previous_gtid_log_event or not
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int has_previous_gtid_log_event(File_reader *reader, bool *found);
/**
It sends a faked rotate event which does not exist physically in any
binlog to the slave. It contains the name of the binlog we are going to
send to the slave.
Faked rotate event is required in a few cases, so slave can know which
binlog the following events are from.
- The binlog file slave requested is Empty. E.g.
"CHANGE MASTER TO MASTER_LOG_FILE='', MASTER_LOG_POS=4", etc.
- The position slave requested is exactly the end of a binlog file.
- Previous binlog file does not include a rotate event.
It happens when server is shutdown and restarted.
- The previous binary log was GTID-free (does not contain a
Previous_gtids_log_event) and the slave is connecting using
the GTID protocol.
@param[in] next_log_file The name of the binlog file will be sent after
the rotate event.
@param[in] log_pos The start position of the binlog file.
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int fake_rotate_event(const char *next_log_file, my_off_t log_pos);
/**
When starting to dump a binlog file, Format_description_log_event
is read and sent first. If the requested position is after
Format_description_log_event, log_pos field in the first
Format_description_log_event has to be set to 0. So the slave
will not increment its master's binlog position.
@param[in] reader File_reader of the binlog will be dumpped
@param[in] start_pos Position requested by the slave's IO thread.
Only the events after the position are sent.
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int send_format_description_event(File_reader *reader, my_off_t start_pos);
/**
It sends a heartbeat to the client.
@param[in] log_pos The log position that events before it are sent.
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
int send_heartbeat_event(my_off_t log_pos);
/**
It reads an event from binlog file. this function can set event_ptr either
a valid buffer pointer or nullptr. nullptr means it arrives at the end of
the binlog file if no error happens.
@param[in] reader File_reader of the binlog file.
@param[out] event_ptr The buffer used to store the event.
@param[out] event_len Length of the event.
@retval 0 Succeed
@retval 1 Fail
*/
inline int read_event(File_reader *reader, uchar **event_ptr,
uint32 *event_len);
/**
Check if it is allowed to send this event type.
The following are disallowed:
- GTID_MODE=ON and type==ANONYMOUS_GTID_LOG_EVENT
- AUTO_POSITION=1 and type==ANONYMOUS_GTID_LOG_EVENT
- GTID_MODE=OFF and type==GTID_LOG_EVENT
@param type The event type.
@param log_file The binary log file (used in error messages).
@param log_pos The binary log position (used in error messages).
@retval true The event is not allowed. In this case, this function
calls set_fatal_error().
@retval false The event is allowed.
*/
bool check_event_type(binary_log::Log_event_type type, const char *log_file,
my_off_t log_pos);
/**
It checks if the event is in m_exclude_gtid.
Clients may request to exclude some GTIDs. The events include in the GTID
groups will be skipped. We call below events sequence as a goup,
Gtid_log_event
BEGIN
...
COMMIT or ROLLBACK
or
Gtid_log_event
DDL statement
@param[in] event_ptr Buffer of the event
@param[in] in_exclude_group If it is in a execude group
@return It returns true if it should be skipped, otherwise false is turned.
*/
inline bool skip_event(const uchar *event_ptr, bool in_exclude_group);
inline void calc_event_checksum(uchar *event_ptr, size_t event_len);
inline int flush_net();
inline int send_packet();
inline int send_packet_and_flush();
inline int before_send_hook(const char *log_file, my_off_t log_pos);
inline int after_send_hook(const char *log_file, my_off_t log_pos);
/*
Reset the thread transmit packet buffer for event sending.
This function reserves the bytes for event transmission, and
should be called before storing the event data to the packet buffer.
@param[in] flags The flag used in reset_transmit hook.
@param[in] event_len If the caller already knows the event length, then
it can pass this value so that reset_transmit_packet
already reallocates the buffer if needed. Otherwise,
if event_len is 0, then the caller needs to extend
the buffer itself.
*/
inline int reset_transmit_packet(ushort flags, size_t event_len = 0);
/**
It waits until receiving an update_cond signal. It will send heartbeat
periodically if m_heartbeat_period is set.
@param[in] log_pos The end position of the last event it already sent.
It is required by heartbeat events.
@return It returns 0 if succeeds, otherwise 1 is returned.
*/
inline int wait_new_events(my_off_t log_pos);
inline int wait_with_heartbeat(my_off_t log_pos);
inline int wait_without_heartbeat();
#ifndef DBUG_OFF
/* It is used to count the events that have been sent. */
int m_event_count;
/*
It aborts dump thread with an error if m_event_count exceeds
max_binlog_dump_events.
*/
inline int check_event_count();
#endif
bool has_error() { return m_errno != 0; }
void set_error(int errorno, const char *errmsg) {
snprintf(m_errmsg_buf, sizeof(m_errmsg_buf), "%.*s", MYSQL_ERRMSG_SIZE - 1,
errmsg);
m_errmsg = m_errmsg_buf;
m_errno = errorno;
}
void set_unknown_error(const char *errmsg) {
set_error(ER_UNKNOWN_ERROR, errmsg);
}
void set_fatal_error(const char *errmsg) {
set_error(ER_MASTER_FATAL_ERROR_READING_BINLOG, errmsg);
}
bool is_fatal_error() {
return m_errno == ER_MASTER_FATAL_ERROR_READING_BINLOG;
}
bool event_checksum_on() {
return m_event_checksum_alg > binary_log::BINLOG_CHECKSUM_ALG_OFF &&
m_event_checksum_alg < binary_log::BINLOG_CHECKSUM_ALG_ENUM_END;
}
void set_last_pos(my_off_t log_pos) {
m_last_file = m_linfo.log_file_name;
m_last_pos = log_pos;
}
void set_last_file(const char *log_file) {
strcpy(m_last_file_buf, log_file);
m_last_file = m_last_file_buf;
}
/**
* This function SHALL grow the buffer of the packet if needed.
*
* If the buffer used for the packet is large enough to accommodate
* the requested extra bytes, then this function does not do anything.
*
* On the other hand, if the requested size is bigger than the available
* free bytes in the buffer, the buffer is extended by a constant factor
* (@c PACKET_GROW_FACTOR).
*
* @param extra_size The size in bytes that the caller wants to add to the
* buffer.
* @return true if an error occurred, false otherwise.
*/
inline bool grow_packet(size_t extra_size);
/**
* This function SHALL shrink the size of the buffer used.
*
* If less than half of the buffer was used in the last N
* (@c PACKET_SHRINK_COUNTER_THRESHOLD) consecutive times this function
* was called, then the buffer gets shrunk by a constant factor
* (@c PACKET_SHRINK_FACTOR).
*
* The buffer is never shrunk less than a minimum size (@c PACKET_MIN_SIZE).
*/
inline bool shrink_packet();
/**
Helper function to recalculate a new size for the growing buffer.
@param current_size The baseline (for instance, the current buffer size).
@param min_size The resulting buffer size, needs to be at least as large
as this parameter states.
@return The new buffer size, or 0 in the case of an error.
*/
inline size_t calc_grow_buffer_size(size_t current_size, size_t min_size);
/**
Helper function to recalculate the new size for the m_new_shrink_size.
@param current_size The baseline (for instance, the current buffer size).
*/
void calc_shrink_buffer_size(size_t current_size);
};
#endif // DEFINED_RPL_BINLOG_SENDER