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