MySQL 9.1.0
Source Code Documentation
log_sanitizer_impl.hpp
Go to the documentation of this file.
1// Copyright (c) 2022, 2024, 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 for (auto rit = list_of_files.rbegin(); rit != list_of_files.rend(); ++rit) {
46 this->m_validation_started = false;
47 if (process_one_log(reader, *rit) || rit == --list_of_files.rend()) {
48 // valid log file found or no valid position was found in relay logs
49 // remove relay logs containing no valid positions in case a valid
50 // position has been found in one of the files
51 if (rit != list_of_files.rbegin() && this->m_has_valid_pos) {
52 // keeps files between first and last; removes the rest
53 log.remove_logs_outside_range_from_index(*(list_of_files.begin()),
54 *(rit));
55 // remove logs containing partially written transaction
56 auto rem_it = rit;
57 do {
58 --rem_it;
59 std::stringstream ss;
60 ss << "Removed " << *rem_it
61 << " from index file: " << log.get_index_fname()
62 << " ; removing file from disk";
63 LogErr(INFORMATION_LEVEL, ER_LOG_SANITIZATION, ss.str().c_str());
64 my_delete_allow_opened(rem_it->c_str(), MYF(0));
65 } while (rem_it != list_of_files.rbegin());
66 }
67 return;
68 }
69 }
70}
71
72template <class Type_reader>
73void Log_sanitizer::process_logs(Type_reader &reader, MYSQL_BIN_LOG &log) {
74 auto [list_of_files, status] = log.get_filename_list();
75 if (status.is_error()) {
76 this->m_fatal_error = true;
77 this->m_is_malformed = true;
78 this->m_failure_message.assign("Could not process index file");
79 return;
80 }
81 process_logs(reader, list_of_files, log);
82}
83
84template <class Type_reader>
85void Log_sanitizer::process_logs(Type_reader &reader) {
86 if (!reader.is_open()) {
87 this->m_fatal_error = true;
88 this->m_is_malformed = true;
89 this->m_failure_message.assign("Reader is not initialized");
90 return;
91 }
92 process_one_log(reader, reader.get_file_name());
93}
94
95template <class Type_reader>
96bool Log_sanitizer::process_one_log(Type_reader &reader,
97 const std::string &filename) {
98 Scope_guard close_at_end([&reader]() { reader.close(); });
99
100 if (!reader.is_open()) {
101 if (reader.open(filename.c_str())) {
102 this->m_is_malformed = true;
103 this->m_fatal_error = true;
104 this->m_failure_message.assign("Could not open relay log file");
105 close_at_end.release();
106 return false;
107 }
108 } else {
109 close_at_end.release();
110 }
111
112 m_last_file_size = reader.ifile()->length();
115 std::shared_ptr<Log_event> ev;
116 this->m_valid_pos = reader.position();
117 this->m_valid_file = filename;
119 bool contains_finished_transaction = false;
120 this->m_in_transaction = false;
121 this->m_is_malformed = false;
122
123 while (istream >> ev) {
124 bool is_source_event = !ev->is_relay_log_event() ||
125 (ev->server_id && ::server_id != ev->server_id);
126 switch (ev->get_type_code()) {
128 this->process_query_event(dynamic_cast<Query_log_event &>(*ev));
129 break;
130 }
132 this->process_xid_event(dynamic_cast<Xid_log_event &>(*ev));
133 break;
134 }
137 dynamic_cast<XA_prepare_log_event &>(*ev));
138 break;
139 }
141 if (is_source_event) {
143 }
144 break;
145 }
146 default: {
147 break;
148 }
149 }
150
151 // Whenever the current position is at a transaction boundary, save it
152 // to m_valid_pos
153 if (!this->m_is_malformed && !this->m_in_transaction &&
154 !is_any_gtid_event(ev.get()) && !is_session_control_event(ev.get()) &&
156 this->m_valid_pos = reader.position();
157 if (ev->get_type_code() != mysql::binlog::event::STOP_EVENT &&
158 ev->get_type_code() !=
160 ev->get_type_code() != mysql::binlog::event::ROTATE_EVENT) {
161 this->m_valid_source_pos = ev->common_header->log_pos;
162 this->m_has_valid_source_pos = true;
163 }
164 if (ev->get_type_code() == mysql::binlog::event::ROTATE_EVENT &&
165 is_source_event) {
166 auto rev = dynamic_cast<mysql::binlog::event::Rotate_event *>(ev.get());
167 if (rev->new_log_ident != nullptr) {
168 this->m_valid_source_file.resize(rev->ident_len);
169 memcpy(this->m_valid_source_file.data(), rev->new_log_ident,
170 rev->ident_len);
171 this->m_has_valid_source_pos = true;
172 this->m_valid_source_pos = rev->pos;
173 }
174 }
175 this->m_has_valid_pos = true;
176 contains_finished_transaction = true;
177 }
178 if (this->m_is_malformed) break;
179 }
180 if (istream.has_error()) {
182 switch (istream.get_status()) {
183 case Status_t::out_of_memory:
184 this->m_is_malformed = true;
185 this->m_fatal_error = true;
186 this->m_failure_message.assign("Out of memory");
187 break;
188 case Status_t::exceeds_max_size:
189 this->m_is_malformed = true;
190 this->m_fatal_error = true;
191 this->m_failure_message.assign(istream.get_error_str().c_str());
192 break;
193 case Status_t::corrupted: // even if decoding failed somehow, we will
194 // trim
195 case Status_t::success:
196 case Status_t::end:
197 case Status_t::truncated:
198 break;
199 }
200 }
201
202 if ((reader.position() != this->m_valid_pos || istream.has_error()) &&
203 contains_finished_transaction && !is_fatal_error()) {
205 std::stringstream ss;
206 ss << "The following log needs truncation:" << filename;
207 ss << " ; read up to: " << reader.position();
208 LogErr(INFORMATION_LEVEL, ER_LOG_SANITIZATION, ss.str().c_str());
209 }
210 return contains_finished_transaction;
211}
212
213} // namespace binlog
214
215#endif // BINLOG_LOG_SANITIZER_IMPL_HPP
Definition: binlog.h:107
const char * get_index_fname()
Definition: binlog.h:884
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:220
bool m_has_valid_pos
Indicator on whether a valid position has been found in the log file.
Definition: log_sanitizer.h:216
bool process_one_log(Type_reader &reader, const std::string &filename)
Reads and validates one log file.
Definition: log_sanitizer_impl.hpp:96
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:85
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:96
bool m_fatal_error
Whether or not the binary log has a fatal error.
Definition: log_sanitizer.h:196
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:223
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:213
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:112
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:856
#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