1 /* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
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
22    02110-1301 USA */
23 
24 #ifndef RPL_GTID_PERSIST_H_
25 #define RPL_GTID_PERSIST_H_
26 
27 #include "my_global.h"
28 #include "rpl_table_access.h"        // System_table_access
29 #include "sql_class.h"               // Open_tables_backup
30 
31 #include <string>
32 
33 
34 class Gtid_table_access_context : public System_table_access
35 {
36 
37 public:
38   static const LEX_STRING DB_NAME;
39   static const LEX_STRING TABLE_NAME;
40 
Gtid_table_access_context()41   Gtid_table_access_context() : m_drop_thd_object(NULL) { };
~Gtid_table_access_context()42   virtual ~Gtid_table_access_context() { };
43 
44   /**
45     Initialize the gtid_executed table access context as following:
46       - Create a new THD if current_thd is NULL
47       - Disable binlog temporarily if we are going to modify the table
48       - Open and lock a table.
49 
50     @param[in/out] thd        Thread requesting to open the table
51     @param         lock_type  How to lock the table
52     @param[out]    table      We will store the open table here
53 
54     @return
55       @retval TRUE  failed
56       @retval FALSE success
57   */
58   bool init(THD **thd, TABLE **table, bool is_write);
59   /**
60     De-initialize the gtid_executed table access context as following:
61       - Close the table
62       - Reenable binlog if needed
63       - Destroy the created THD if needed.
64 
65     @param thd         Thread requesting to close the table
66     @param table       Table to be closed
67     @param error       If there was an error while updating the table
68     @param need_commit Need to commit current transaction if it is true
69 
70     @return
71       @retval true  failed
72       @retval false success
73   */
74   bool deinit(THD *thd, TABLE *table, bool error, bool need_commit);
75   /**
76     Prepares before opening table.
77     - set flags
78 
79     @param[in]  thd  Thread requesting to open the table
80   */
81   void before_open(THD* thd);
82   /**
83     Creates a new thread in the bootstrap process or in the mysqld startup,
84     a thread is created in order to be able to access a table. And reset a
85     new "statement".
86 
87     @return
88       @retval THD* Pointer to thread structure
89   */
90   THD *create_thd();
91   void drop_thd(THD* thd);
92 private:
93   /* Pointer to new created THD. */
94   THD *m_drop_thd_object;
95   /* Modify the table if it is true. */
96   bool m_is_write;
97   /* Save the lock info. */
98   Open_tables_backup m_backup;
99   /* Save binlog options. */
100   ulonglong m_tmp_disable_binlog__save_options;
101 
102   /* Prevent user from invoking default assignment function. */
103   Gtid_table_access_context &operator=(const Gtid_table_access_context &info);
104   /* Prevent user from invoking default constructor function. */
105   Gtid_table_access_context(const Gtid_table_access_context &info);
106 };
107 
108 
109 class Gtid_table_persistor
110 {
111 
112 public:
113   static const uint number_fields= 3;
114 
Gtid_table_persistor()115   Gtid_table_persistor()
116   {
117     m_count.atomic_set(0);
118   };
~Gtid_table_persistor()119   virtual ~Gtid_table_persistor() { };
120 
121   /**
122     Insert the gtid into table.
123 
124     @param thd  Thread requesting to save gtid into the table
125     @param gtid holds the sidno and the gno.
126 
127     @retval
128       0    OK
129     @retval
130       1    The table was not found.
131     @retval
132       -1   Error
133   */
134   int save(THD *thd, const Gtid *gtid);
135   /**
136     Insert the gtid set into table.
137 
138     @param gtid_set  contains a set of gtid, which holds
139                      the sidno and the gno.
140 
141     @retval
142       0    OK
143     @retval
144       -1   Error
145   */
146   int save(const Gtid_set *gtid_set);
147   /**
148     Delete all rows from the table.
149 
150     @param  thd Thread requesting to reset the table
151 
152     @retval
153       0    OK
154     @retval
155       1    The table was not found.
156     @retval
157       -1   Error
158   */
159   int reset(THD *thd);
160 
161   /**
162     Fetch gtids from gtid_executed table and store them into
163     gtid_executed set.
164 
165     @param[out]  gtid_set store gtids fetched from the gtid_executed table.
166 
167     @retval
168       0    OK
169     @retval
170       1    The table was not found.
171     @retval
172       -1   Error
173   */
174   int fetch_gtids(Gtid_set *gtid_set);
175   /**
176     Compress the gtid_executed table completely by employing one
177     or more transactions.
178 
179     @param  thd Thread requesting to compress the table
180 
181     @retval
182       0    OK
183     @retval
184       1    The table was not found.
185     @retval
186       -1   Error
187   */
188   int compress(THD *thd);
189   /**
190     Push a warning to client if user is modifying the gtid_executed
191     table explicitly by a non-XA transaction. Push an error to client
192     if user is modifying it explicitly by a XA transaction.
193 
194     @param thd Thread requesting to access the table
195     @param table The table is being accessed.
196 
197     @retval 0 No warning or error was pushed to the client.
198     @retval 1 Push a warning to client.
199     @retval 2 Push an error to client.
200   */
warn_or_err_on_explicit_modification(THD * thd,TABLE_LIST * table)201   int warn_or_err_on_explicit_modification(THD *thd, TABLE_LIST *table)
202   {
203     DBUG_ENTER("Gtid_table_persistor::warn_or_err_on_explicit_modification");
204 
205     if (!thd->is_operating_gtid_table_implicitly &&
206         table->lock_type >= TL_WRITE_ALLOW_WRITE &&
207         !strcmp(table->table_name, Gtid_table_access_context::TABLE_NAME.str))
208     {
209       if (thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_ACTIVE))
210       {
211         /*
212           Push an error to client if user is modifying the gtid_executed
213           table explicitly by a XA transaction.
214         */
215         thd->raise_error_printf(ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE,
216                                 table->table_name);
217         DBUG_RETURN(2);
218       }
219       else
220       {
221         /*
222           Push a warning to client if user is modifying the gtid_executed
223           table explicitly by a non-XA transaction.
224         */
225         thd->raise_warning_printf(ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE,
226                                   table->table_name);
227         DBUG_RETURN(1);
228       }
229     }
230 
231     DBUG_RETURN(0);
232   }
233 
234 private:
235   /* Count the append size of the table */
236   Atomic_int64 m_count;
237   /**
238     Compress the gtid_executed table, read each row by the
239     PK(sid, gno_start) in increasing order, compress the first
240     consecutive range of gtids within a single transaction.
241 
242     @param      thd          Thread requesting to compress the table
243     @param[out] is_complete  True if the gtid_executed table is
244                              compressd completely.
245 
246     @retval
247       0    OK
248     @retval
249       1    The table was not found.
250     @retval
251       -1   Error
252   */
253   int compress_in_single_transaction(THD *thd, bool &is_complete);
254   /**
255     Read each row by the PK(sid, gno_start) in increasing order,
256     compress the first consecutive range of gtids.
257     For example,
258       1 1
259       2 2
260       3 3
261       6 6
262       7 7
263       8 8
264     After the compression, the gtids in the table is compressed as following:
265       1 3
266       6 6
267       7 7
268       8 8
269 
270     @param      table        Reference to a table object.
271     @param[out] is_complete  True if the gtid_executed table
272                              is compressd completely.
273 
274     @return
275       @retval 0    OK.
276       @retval -1   Error.
277   */
278   int compress_first_consecutive_range(TABLE *table, bool &is_complete);
279   /**
280     Fill a gtid interval into fields of the gtid_executed table.
281 
282     @param  fields   Reference to table fileds.
283     @param  sid      The source id of the gtid interval.
284     @param  gno_star The first GNO of the gtid interval.
285     @param  gno_end  The last GNO of the gtid interval.
286 
287     @return
288       @retval 0    OK.
289       @retval -1   Error.
290   */
291   int fill_fields(Field **fields, const char *sid,
292                   rpl_gno gno_start, rpl_gno gno_end);
293   /**
294     Write a gtid interval into the gtid_executed table.
295 
296     @param  table    Reference to a table object.
297     @param  sid      The source id of the gtid interval.
298     @param  gno_star The first GNO of the gtid interval.
299     @param  gno_end  The last GNO of the gtid interval.
300 
301     @return
302       @retval 0    OK.
303       @retval -1   Error.
304   */
305   int write_row(TABLE *table, const char *sid,
306                 rpl_gno gno_start, rpl_gno gno_end);
307   /**
308     Update a gtid interval in the gtid_executed table.
309     - locate the gtid interval by primary key (sid, gno_start)
310       to update it with the new_gno_end.
311 
312     @param  table        Reference to a table object.
313     @param  sid          The source id of the gtid interval.
314     @param  gno_star     The first GNO of the gtid interval.
315     @param  new_gno_end  The new last GNO of the gtid interval.
316 
317     @return
318       @retval 0    OK.
319       @retval -1   Error.
320   */
321   int update_row(TABLE *table, const char *sid,
322                  rpl_gno gno_start, rpl_gno new_gno_end);
323   /**
324     Delete all rows in the gtid_executed table.
325 
326     @param  table Reference to a table object.
327 
328     @return
329       @retval 0    OK.
330       @retval -1   Error.
331   */
332   int delete_all(TABLE *table);
333   /**
334     Encode the current row fetched from the table into gtid text.
335 
336     @param  table Reference to a table object.
337     @retval Return the encoded gtid text.
338   */
339   std::string encode_gtid_text(TABLE *table);
340   /**
341     Get gtid interval from the the current row of the table.
342 
343     @param  table         Reference to a table object.
344     @param  sid[out]      The source id of the gtid interval.
345     @param  gno_star[out] The first GNO of the gtid interval.
346     @param  gno_end[out]  The last GNO of the gtid interval.
347   */
348   void get_gtid_interval(TABLE *table, std::string &sid,
349                          rpl_gno &gno_start, rpl_gno &gno_end);
350   /**
351     Insert the gtid set into table.
352 
353     @param table          The gtid_executed table.
354     @param gtid_executed  Contains a set of gtid, which holds
355                           the sidno and the gno.
356 
357     @retval
358       0    OK
359     @retval
360       -1   Error
361   */
362   int save(TABLE *table, const Gtid_set *gtid_set);
363   /* Prevent user from invoking default assignment function. */
364   Gtid_table_persistor &operator=(const Gtid_table_persistor &info);
365   /* Prevent user from invoking default constructor function. */
366   Gtid_table_persistor(const Gtid_table_persistor &info);
367 };
368 
369 extern Gtid_table_persistor *gtid_table_persistor;
370 void create_compress_gtid_table_thread();
371 void terminate_compress_gtid_table_thread();
372 
373 #endif /* RPL_GTID_PERSIST_H_ */
374