MySQL 9.3.0
Source Code Documentation
log_sanitizer_impl.hpp
Go to the documentation of this file.
1// Copyright (c) 2022, 2025, Oracle and/or its affiliates.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of MySQL hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License, version 2.0, for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23
24#ifndef BINLOG_LOG_SANITIZER_IMPL_HPP
25#define BINLOG_LOG_SANITIZER_IMPL_HPP
26
27#include "include/scope_guard.h"
29#include "mysqld_error.h"
30#include "sql/binlog.h"
31#include "sql/binlog/decompressing_event_object_istream.h" // Decompressing_event_object_istream
33#include "sql/psi_memory_key.h"
35#include "sql/raii/sentry.h" // raii::Sentry<>
36#include "sql/xa/xid_extract.h" // xa::XID_extractor
37
38namespace binlog {
39
40template <class Type_reader>
41void Log_sanitizer::process_logs(Type_reader &reader,
42 const std::list<std::string> &list_of_files,
43 MYSQL_BIN_LOG &log) {
44 // function we run for relay logs
45 this->m_skip_prepared_xids = true;
46 for (auto rit = list_of_files.rbegin(); rit != list_of_files.rend(); ++rit) {
47 this->m_validation_started = false;
48 this->m_in_transaction = false;
49 if (process_one_log(reader, *rit) || rit == --list_of_files.rend()) {
50 // valid log file found or no valid position was found in relay logs
51 // remove relay logs containing no valid positions in case a valid
52 // position has been found in one of the files
53 if (rit != list_of_files.rbegin() && this->m_has_valid_pos) {
54 // keeps files between first and last; removes the rest
55 log.remove_logs_outside_range_from_index(*(list_of_files.begin()),
56 *(rit));
57 // remove logs containing partially written transaction
58 auto rem_it = rit;
59 do {
60 --rem_it;
61 std::stringstream ss;
62 ss << "Removed " << *rem_it
63 << " from index file: " << log.get_index_fname()
64 << " ; removing file from disk";
65 LogErr(INFORMATION_LEVEL, ER_LOG_SANITIZATION, ss.str().c_str());
66 my_delete_allow_opened(rem_it->c_str(), MYF(0));
67 } while (rem_it != list_of_files.rbegin());
68 }
69 return;
70 }
71 }
72}
73
74template <class Type_reader>
75void Log_sanitizer::process_logs(Type_reader &reader, MYSQL_BIN_LOG &log) {
76 auto [list_of_files, status] = log.get_filename_list();
77 if (status.is_error()) {
78 this->m_fatal_error = true;
79 this->m_is_malformed = true;
80 this->m_failure_message.assign("Could not process index file");
81 return;
82 }
83 process_logs(reader, list_of_files, log);
84}
85
86template <class Type_reader>
87void Log_sanitizer::process_logs(Type_reader &reader) {
88 if (!reader.is_open()) {
89 this->m_fatal_error = true;
90 this->m_is_malformed = true;
91 this->m_failure_message.assign("Reader is not initialized");
92 return;
93 }
94 process_one_log(reader, reader.get_file_name());
95}
96
97template <class Type_reader>
98bool Log_sanitizer::process_one_log(Type_reader &reader,
99 const std::string &filename) {
100 Scope_guard close_at_end([&reader]() { reader.close(); });
101
102 if (!reader.is_open()) {
103 if (reader.open(filename.c_str())) {
104 this->m_is_malformed = true;
105 this->m_fatal_error = true;
106 this->m_failure_message.assign("Could not open relay log file");
107 close_at_end.release();
108 return false;
109 }
110 } else {
111 close_at_end.release();
112 }
113
114 m_last_file_size = reader.ifile()->length();
117 std::shared_ptr<Log_event> ev;
118 this->m_valid_pos = reader.position();
119 this->m_valid_file = filename;
121 bool contains_finished_transaction = false;
122 this->m_in_transaction = false;
123 this->m_is_malformed = false;
124
125 while (istream >> ev) {
126 bool is_source_event = !ev->is_relay_log_event() ||
127 (ev->server_id && ::server_id != ev->server_id);
128 switch (ev->get_type_code()) {
130 this->process_query_event(dynamic_cast<Query_log_event &>(*ev));
131 break;
132 }
134 this->process_xid_event(dynamic_cast<Xid_log_event &>(*ev));
135 break;
136 }
139 dynamic_cast<XA_prepare_log_event &>(*ev));
140 break;
141 }
143 if (is_source_event) {
145 }
146 break;
147 }
148 default: {
149 break;
150 }
151 }
152
153 // Whenever the current position is at a transaction boundary, save it
154 // to m_valid_pos
155 if (!this->m_is_malformed && !this->m_in_transaction &&
156 !is_any_gtid_event(ev.get()) && !is_session_control_event(ev.get()) &&
158 this->m_valid_pos = reader.position();
159 if (ev->get_type_code() != mysql::binlog::event::STOP_EVENT &&
160 ev->get_type_code() !=
162 ev->get_type_code() != mysql::binlog::event::ROTATE_EVENT) {
163 this->m_valid_source_pos = ev->common_header->log_pos;
164 this->m_has_valid_source_pos = true;
165 }
166 if (ev->get_type_code() == mysql::binlog::event::ROTATE_EVENT &&
167 is_source_event) {
168 auto rev = dynamic_cast<mysql::binlog::event::Rotate_event *>(ev.get());
169 if (rev->new_log_ident != nullptr) {
170 this->m_valid_source_file.resize(rev->ident_len);
171 memcpy(this->m_valid_source_file.data(), rev->new_log_ident,
172 rev->ident_len);
173 this->m_has_valid_source_pos = true;
174 this->m_valid_source_pos = rev->pos;
175 }
176 }
177 this->m_has_valid_pos = true;
178 contains_finished_transaction = true;
179 }
180 if (this->m_is_malformed) break;
181 }
182 if (istream.has_error()) {
184 switch (istream.get_status()) {
185 case Status_t::out_of_memory:
186 this->m_is_malformed = true;
187 this->m_fatal_error = true;
188 this->m_failure_message.assign("Out of memory");
189 break;
190 case Status_t::exceeds_max_size:
191 this->m_is_malformed = true;
192 this->m_fatal_error = true;
193 this->m_failure_message.assign(istream.get_error_str().c_str());
194 break;
195 case Status_t::corrupted: // even if decoding failed somehow, we will
196 // trim
197 case Status_t::success:
198 case Status_t::end:
199 case Status_t::truncated:
200 break;
201 }
202 }
203
204 if ((reader.position() != this->m_valid_pos || istream.has_error()) &&
205 contains_finished_transaction && !is_fatal_error()) {
207 std::stringstream ss;
208 ss << "The following log needs truncation:" << filename;
209 ss << " ; read up to: " << reader.position();
210 LogErr(INFORMATION_LEVEL, ER_LOG_SANITIZATION, ss.str().c_str());
211 }
212 return contains_finished_transaction;
213}
214
215} // namespace binlog
216
217#endif // BINLOG_LOG_SANITIZER_IMPL_HPP
Definition: binlog.h:107
const char * get_index_fname()
Definition: binlog.h:889
A Query event is written to the binary log whenever the database is modified on the master,...
Definition: log_event.h:1296
A Lambda to be called at scope exit.
Definition: scope_guard.h:55
Similar to Xid_log_event except that.
Definition: log_event.h:1832
This is the subclass of Xid_event defined in libbinlogevent, An XID event is generated for a commit o...
Definition: log_event.h:1781
Stream class that yields Log_event objects from a source.
Definition: decompressing_event_object_istream.h:68
mysql::binlog::event::compression::Decompress_status Status_t
Definition: decompressing_event_object_istream.h:77
bool m_has_valid_source_pos
Indicator on whether a valid source position has been found in the log file.
Definition: log_sanitizer.h:227
bool m_has_valid_pos
Indicator on whether a valid position has been found in the log file.
Definition: log_sanitizer.h:223
bool process_one_log(Type_reader &reader, const std::string &filename)
Reads and validates one log file.
Definition: log_sanitizer_impl.hpp:98
virtual PSI_memory_key & get_memory_key() const =0
Function used to obtain memory key for derived classes.
void process_logs(Type_reader &reader)
This function goes through the opened file and searches for a valid position in a binary log file.
Definition: log_sanitizer_impl.hpp:87
void process_xid_event(Xid_log_event const &ev)
Invoked when a Xid_log_event is read from the binary log file reader.
Definition: log_sanitizer.cc:95
bool m_fatal_error
Whether or not the binary log has a fatal error.
Definition: log_sanitizer.h:196
bool m_skip_prepared_xids
During binary log recovery, we check XIDs, however, during relay log sanitization we need to skip add...
Definition: log_sanitizer.h:215
bool is_fatal_error() const
Checks whether the fatal error occurred during log sanitization (OOM / decompression error which we c...
Definition: log_sanitizer.cc:55
bool m_validation_started
Indicates whether validation has started.
Definition: log_sanitizer.h:179
my_off_t m_last_file_size
Last opened file size.
Definition: log_sanitizer.h:230
std::string m_valid_source_file
Currently processed binlog file set in case source rotation event is encountered.
Definition: log_sanitizer.h:188
bool m_in_transaction
Whether or not the event being processed is within a transaction.
Definition: log_sanitizer.h:192
bool m_is_log_truncation_needed
Information on whether log needs to be truncated, i.e.
Definition: log_sanitizer.h:220
bool m_is_malformed
Whether or not the binary log is malformed/corrupted or error occurred.
Definition: log_sanitizer.h:194
my_off_t m_valid_source_pos
Position of the last binlog event that ended a transaction (source position which corresponds to m_va...
Definition: log_sanitizer.h:185
void process_xa_prepare_event(XA_prepare_log_event const &ev)
Invoked when a XA_prepare_log_event is read from the binary log file reader.
Definition: log_sanitizer.cc:114
std::string m_valid_file
Last log file containing finished transaction.
Definition: log_sanitizer.h:190
void process_query_event(Query_log_event const &ev)
Invoked when a Query_log_event is read from the binary log file reader.
Definition: log_sanitizer.cc:65
my_off_t m_valid_pos
Position of the last binlog/relay log event that ended a transaction.
Definition: log_sanitizer.h:182
std::string m_failure_message
Textual representation of the encountered failure.
Definition: log_sanitizer.h:198
When a binary log file exceeds a size limit, a ROTATE_EVENT is written at the end of the file that po...
Definition: control_events.h:117
Stream class that yields Log_event objects, including events contained in Transaction_payload_log_eve...
std::pair< std::list< std::string >, mysql::utils::Error > get_filename_list()
Definition: binlog.cc:1899
int remove_logs_outside_range_from_index(const std::string &first, const std::string &last)
Definition: binlog.cc:5282
#define BIN_LOG_HEADER_SIZE
Definition: binlog_event.h:88
#define my_delete_allow_opened(fname, flags)
Definition: my_sys.h:643
bool is_any_gtid_event(const Log_event *evt)
Definition: log_event.h:4570
bool is_session_control_event(Log_event *evt)
Check if the given event is a session control event, one of User_var_event, Intvar_event or Rand_even...
Definition: log_event.h:4584
MYSQL_PLUGIN_IMPORT ulong server_id
Definition: log_event.h:118
#define LogErr(severity, ecode,...)
Definition: log_builtins.h:872
#define MYF(v)
Definition: my_inttypes.h:97
@ INFORMATION_LEVEL
Definition: my_loglevel.h:45
Definition: pfs.cc:38
@ FORMAT_DESCRIPTION_EVENT
Definition: binlog_event.h:304
@ XID_EVENT
Definition: binlog_event.h:305
@ XA_PREPARE_LOG_EVENT
Definition: binlog_event.h:354
@ QUERY_EVENT
Definition: binlog_event.h:292
@ STOP_EVENT
Definition: binlog_event.h:293
@ ROTATE_EVENT
Definition: binlog_event.h:294
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:192
const char * filename
Definition: pfs_example_component_population.cc:67
mysql::allocators::Memory_resource psi_memory_resource(PSI_memory_key key)
Return a PSI-enabled Memory_resource using the given key.
Definition: psi_memory_resource.cc:29
required uint32 status
Definition: replication_asynchronous_connection_failover.proto:61