1 /* Copyright (c) 2006, 2021, 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 also distributed 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 included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 22 23 #ifndef INJECTOR_H 24 #define INJECTOR_H 25 26 #include "my_global.h" 27 #include "table.h" // TABLE 28 #include "control_events.h" // enum_incidents 29 30 /* Forward declarations */ 31 class handler; 32 class MYSQL_BIN_LOG; 33 class THD; 34 typedef struct st_bitmap MY_BITMAP; 35 36 37 /* 38 Injector to inject rows into the MySQL server. 39 40 The injector class is used to notify the MySQL server of new rows that have 41 appeared outside of MySQL control. 42 43 The original purpose of this is to allow clusters---which handle replication 44 inside the cluster through other means---to insert new rows into binary log. 45 Note, however, that the injector should be used whenever rows are altered in 46 any manner that is outside of MySQL server visibility and which therefore 47 are not seen by the MySQL server. 48 */ 49 class injector 50 { 51 public: 52 53 /* 54 Get an instance of the injector. 55 56 DESCRIPTION 57 The injector is a Singleton, so this static function return the 58 available instance of the injector. 59 60 RETURN VALUE 61 A pointer to the available injector object. 62 */ 63 static injector *instance(); 64 65 /* 66 Delete the singleton instance (if allocated). Used during server shutdown. 67 */ 68 static void free_instance(); 69 70 /* 71 A transaction where rows can be added. 72 73 DESCRIPTION 74 The transaction class satisfy the **CopyConstructible** and 75 **Assignable** requirements. Note that the transaction is *not* 76 default constructible. 77 */ 78 class transaction { 79 friend class injector; 80 public: 81 /* Convenience definitions */ 82 typedef uchar* record_type; 83 typedef uint32 server_id_type; 84 85 /* 86 Table reference. 87 88 RESPONSIBILITY 89 90 The class contains constructors to handle several forms of 91 references to tables. The constructors can implicitly be used to 92 construct references from, e.g., strings containing table names. 93 94 EXAMPLE 95 96 The class is intended to be used *by value*. Please, do not try to 97 construct objects of this type using 'new'; instead construct an 98 object, possibly a temporary object. For example: 99 100 injector::transaction::table tbl(share->table, true); 101 MY_BITMAP cols; 102 bitmap_init(&cols, NULL, (i + 7) / 8, false); 103 inj->write_row(::server_id, tbl, &cols, row_data); 104 105 or 106 107 MY_BITMAP cols; 108 bitmap_init(&cols, NULL, (i + 7) / 8, false); 109 inj->write_row(::server_id, 110 injector::transaction::table(share->table, true), 111 &cols, row_data); 112 113 This will work, be more efficient, and have greater chance of 114 inlining, not run the risk of losing pointers. 115 116 COLLABORATION 117 118 injector::transaction 119 Provide a flexible interface to the representation of tables. 120 121 */ 122 class table 123 { 124 public: 125 class save_sets { 126 public: save_sets(table const & tbl,MY_BITMAP const * new_rs,MY_BITMAP const * new_ws)127 save_sets(table const &tbl, MY_BITMAP const *new_rs, MY_BITMAP const *new_ws) 128 : m_table(tbl.get_table()), 129 save_read_set(m_table->read_set), 130 save_write_set(m_table->write_set) 131 { 132 m_table->column_bitmaps_set_no_signal(const_cast<MY_BITMAP*>(new_rs), 133 const_cast<MY_BITMAP*>(new_ws)); 134 } 135 ~save_sets()136 ~save_sets() { 137 m_table->column_bitmaps_set_no_signal(save_read_set, save_write_set); 138 } 139 140 private: 141 TABLE *m_table; 142 MY_BITMAP *save_read_set; 143 MY_BITMAP *save_write_set; 144 }; 145 table(TABLE * table,bool is_transactional)146 table(TABLE *table, bool is_transactional) 147 : m_table(table), m_is_transactional(is_transactional) 148 { 149 } 150 db_name()151 char const *db_name() const { return m_table->s->db.str; } table_name()152 char const *table_name() const { return m_table->s->table_name.str; } get_table()153 TABLE *get_table() const { return m_table; } is_transactional()154 bool is_transactional() const { return m_is_transactional; } 155 156 private: 157 TABLE *m_table; 158 bool m_is_transactional; 159 }; 160 161 /* 162 Binlog position as a structure. 163 */ 164 class binlog_pos { 165 friend class transaction; 166 public: file_name()167 char const *file_name() const { return m_file_name; } file_pos()168 my_off_t file_pos() const { return m_file_pos; } 169 170 private: 171 char const *m_file_name; 172 my_off_t m_file_pos; 173 }; 174 transaction()175 transaction() : m_thd(NULL) { } 176 transaction(transaction const&); 177 ~transaction(); 178 179 /* Clear transaction, i.e., make calls to 'good()' return false. */ clear()180 void clear() { m_thd= NULL; } 181 182 /* Is the transaction in a good state? */ good()183 bool good() const { return m_thd != NULL; } 184 185 /* Default assignment operator: standard implementation */ 186 transaction& operator=(transaction t) { 187 swap(t); 188 return *this; 189 } 190 191 /* 192 193 DESCRIPTION 194 195 Register table for use within the transaction. All tables 196 that are going to be used need to be registered before being 197 used below. The member function will fail with an error if 198 use_table() is called after any *_row() function has been 199 called for the transaction. 200 201 RETURN VALUE 202 203 0 All OK 204 >0 Failure 205 206 */ 207 int use_table(server_id_type sid, table tbl); 208 209 /* 210 Add a 'write row' entry to the transaction. 211 */ 212 int write_row (server_id_type sid, table tbl, 213 MY_BITMAP const *cols, size_t colcnt, 214 record_type record, 215 const uchar* extra_row_info); 216 int write_row (server_id_type sid, table tbl, 217 MY_BITMAP const *cols, size_t colcnt, 218 record_type record); 219 220 /* 221 Add a 'delete row' entry to the transaction. 222 */ 223 int delete_row(server_id_type sid, table tbl, 224 MY_BITMAP const *cols, size_t colcnt, 225 record_type record, 226 const uchar* extra_row_info); 227 int delete_row(server_id_type sid, table tbl, 228 MY_BITMAP const *cols, size_t colcnt, 229 record_type record); 230 /* 231 Add an 'update row' entry to the transaction. 232 */ 233 int update_row(server_id_type sid, table tbl, 234 MY_BITMAP const *before_cols, 235 MY_BITMAP const *after_cols, 236 size_t colcnt, 237 record_type before, record_type after, 238 const uchar* extra_row_info); 239 int update_row(server_id_type sid, table tbl, 240 MY_BITMAP const *cols, size_t colcnt, 241 record_type before, record_type after); 242 243 /* 244 Commit a transaction. 245 246 This member function will clean up after a sequence of *_row calls by, 247 for example, releasing resource and unlocking files. 248 */ 249 int commit(); 250 251 /* 252 Rollback a transaction. 253 254 This member function will clean up after a sequence of *_row calls by, 255 for example, releasing resource and unlocking files. 256 */ 257 int rollback(); 258 259 /* 260 Get the position for the start of the transaction. 261 262 This is the current 'tail of Binlog' at the time the transaction 263 was started. The first event recorded by the transaction may 264 be at this, or some subsequent position. The first event recorded 265 by the transaction will not be before this position. 266 */ 267 binlog_pos start_pos() const; 268 269 /* 270 Get the next position after the end of the transaction 271 272 This call is only valid after a transaction has been committed. 273 It returns the next Binlog position after the committed transaction. 274 It is guaranteed that no other events will be recorded between the 275 COMMIT event of the Binlog transaction, and this position. 276 Note that this position may be in a different log file to the COMMIT 277 event. 278 279 If the commit had an error, or the transaction was empty and nothing 280 was binlogged then the next_pos will have a NULL file_name(), and 281 0 file_pos(). 282 283 */ 284 binlog_pos next_pos() const; 285 286 private: 287 /* Only the injector may construct these object */ 288 transaction(MYSQL_BIN_LOG *, THD *); 289 swap(transaction & o)290 void swap(transaction& o) { 291 /* std::swap(m_start_pos, o.m_start_pos); */ 292 { 293 binlog_pos const tmp= m_start_pos; 294 m_start_pos= o.m_start_pos; 295 o.m_start_pos= tmp; 296 } 297 298 /* std::swap(m_end_pos, o.m_end_pos); */ 299 { 300 binlog_pos const tmp= m_next_pos; 301 m_next_pos= o.m_next_pos; 302 o.m_next_pos= tmp; 303 } 304 305 /* std::swap(m_thd, o.m_thd); */ 306 { 307 THD* const tmp= m_thd; 308 m_thd= o.m_thd; 309 o.m_thd= tmp; 310 } 311 { 312 enum_state const tmp= m_state; 313 m_state= o.m_state; 314 o.m_state= tmp; 315 } 316 } 317 318 enum enum_state 319 { 320 START_STATE, /* Start state */ 321 TABLE_STATE, /* At least one table has been registered */ 322 ROW_STATE, /* At least one row has been registered */ 323 STATE_COUNT /* State count and sink state */ 324 } m_state; 325 326 /* 327 Check and update the state. 328 329 PARAMETER(S) 330 331 target_state 332 The state we are moving to: TABLE_STATE if we are 333 writing a table and ROW_STATE if we are writing a row. 334 335 DESCRIPTION 336 337 The internal state will be updated to the target state if 338 and only if it is a legal move. The only legal moves are: 339 340 START_STATE -> START_STATE 341 START_STATE -> TABLE_STATE 342 TABLE_STATE -> TABLE_STATE 343 TABLE_STATE -> ROW_STATE 344 345 That is: 346 - It is not possible to write any row before having written at 347 least one table 348 - It is not possible to write a table after at least one row 349 has been written 350 351 RETURN VALUE 352 353 0 All OK 354 -1 Incorrect call sequence 355 */ check_state(enum_state const target_state)356 int check_state(enum_state const target_state) 357 { 358 #ifndef NDEBUG 359 static char const *state_name[] = { 360 "START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT" 361 }; 362 363 assert(0 <= target_state && target_state <= STATE_COUNT); 364 DBUG_PRINT("info", ("In state %s", state_name[m_state])); 365 #endif 366 367 if (m_state <= target_state && target_state <= m_state + 1 && 368 m_state < STATE_COUNT) 369 m_state= target_state; 370 else 371 m_state= STATE_COUNT; 372 return m_state == STATE_COUNT ? 1 : 0; 373 } 374 375 376 binlog_pos m_start_pos; 377 binlog_pos m_next_pos; 378 THD *m_thd; 379 }; 380 381 /* 382 Create a new transaction. This member function will prepare for a 383 sequence of *_row calls by, for example, reserving resources and 384 locking files. The call uses placement semantics and will overwrite 385 the transaction. 386 387 injector::transaction trans2; 388 inj->new_trans(thd, &trans); 389 */ 390 void new_trans(THD *, transaction *); 391 392 int record_incident(THD*, binary_log::Incident_event::enum_incident incident, 393 LEX_STRING const message); 394 395 private: 396 explicit injector(); ~injector()397 ~injector() { } /* Nothing needs to be done */ 398 injector(injector const&); /* You're not allowed to copy injector 399 instances. 400 */ 401 }; 402 403 #endif /* INJECTOR_H */ 404