1 /*
2    Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
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 XA_H_INCLUDED
25 #define XA_H_INCLUDED
26 
27 #include <string.h>
28 #include <sys/types.h>
29 #include <list>
30 #include <mutex>
31 
32 #include "lex_string.h"
33 #include "my_dbug.h"
34 #include "my_inttypes.h"
35 #include "my_sqlcommand.h"
36 #include "sql/malloc_allocator.h"  // Malloc_allocator
37 #include "sql/psi_memory_key.h"    // key_memory_Recovered_xa_transactions
38 #include "sql/sql_cmd.h"           // Sql_cmd
39 #include "sql/sql_list.h"          // List
40 #include "sql/sql_plugin_ref.h"    // plugin_ref
41 #include "sql/xa_aux.h"            // serialize_xid
42 
43 class Protocol;
44 class THD;
45 struct xid_t;
46 
47 typedef int64 query_id_t;
48 
49 enum xa_option_words {
50   XA_NONE,
51   XA_JOIN,
52   XA_RESUME,
53   XA_ONE_PHASE,
54   XA_SUSPEND,
55   XA_FOR_MIGRATE
56 };
57 
58 static const int TC_HEURISTIC_NOT_USED = 0;
59 static const int TC_HEURISTIC_RECOVER_COMMIT = 1;
60 static const int TC_HEURISTIC_RECOVER_ROLLBACK = 2;
61 
62 /**
63   This class represents SQL statement which starts an XA transaction
64   with the given xid value.
65 */
66 
67 class Sql_cmd_xa_start : public Sql_cmd {
68  public:
Sql_cmd_xa_start(xid_t * xid_arg,enum xa_option_words xa_option)69   Sql_cmd_xa_start(xid_t *xid_arg, enum xa_option_words xa_option)
70       : m_xid(xid_arg), m_xa_opt(xa_option) {}
71 
sql_command_code()72   virtual enum_sql_command sql_command_code() const { return SQLCOM_XA_START; }
73 
74   virtual bool execute(THD *thd);
75 
76  private:
77   bool trans_xa_start(THD *thd);
78   xid_t *m_xid;
79   enum xa_option_words m_xa_opt;
80 };
81 
82 /**
83   This class represents SQL statement which puts in the IDLE state
84   an XA transaction with the given xid value.
85 */
86 
87 class Sql_cmd_xa_end : public Sql_cmd {
88  public:
Sql_cmd_xa_end(xid_t * xid_arg,enum xa_option_words xa_option)89   Sql_cmd_xa_end(xid_t *xid_arg, enum xa_option_words xa_option)
90       : m_xid(xid_arg), m_xa_opt(xa_option) {}
91 
sql_command_code()92   virtual enum_sql_command sql_command_code() const { return SQLCOM_XA_END; }
93 
94   virtual bool execute(THD *thd);
95 
96  private:
97   bool trans_xa_end(THD *thd);
98 
99   xid_t *m_xid;
100   enum xa_option_words m_xa_opt;
101 };
102 
103 /**
104   This class represents SQL statement which puts in the PREPARED state
105   an XA transaction with the given xid value.
106 */
107 
108 class Sql_cmd_xa_prepare : public Sql_cmd {
109  public:
Sql_cmd_xa_prepare(xid_t * xid_arg)110   explicit Sql_cmd_xa_prepare(xid_t *xid_arg) : m_xid(xid_arg) {}
111 
sql_command_code()112   virtual enum_sql_command sql_command_code() const {
113     return SQLCOM_XA_PREPARE;
114   }
115 
116   virtual bool execute(THD *thd);
117 
118  private:
119   bool trans_xa_prepare(THD *thd);
120 
121   xid_t *m_xid;
122 };
123 
124 /**
125   This class represents SQL statement which returns to a client
126   a list of XID's prepared to a XA commit/rollback.
127 */
128 
129 class Sql_cmd_xa_recover : public Sql_cmd {
130  public:
Sql_cmd_xa_recover(bool print_xid_as_hex)131   explicit Sql_cmd_xa_recover(bool print_xid_as_hex)
132       : m_print_xid_as_hex(print_xid_as_hex) {}
133 
sql_command_code()134   virtual enum_sql_command sql_command_code() const {
135     return SQLCOM_XA_RECOVER;
136   }
137 
138   virtual bool execute(THD *thd);
139 
140  private:
141   bool check_xa_recover_privilege(THD *thd) const;
142   bool trans_xa_recover(THD *thd);
143 
144   bool m_print_xid_as_hex;
145 };
146 
147 class XID_STATE;
148 /**
149   This class represents SQL statement which commits
150   and terminates an XA transaction with the given xid value.
151 */
152 
153 class Sql_cmd_xa_commit : public Sql_cmd {
154  public:
Sql_cmd_xa_commit(xid_t * xid_arg,enum xa_option_words xa_option)155   Sql_cmd_xa_commit(xid_t *xid_arg, enum xa_option_words xa_option)
156       : m_xid(xid_arg), m_xa_opt(xa_option) {}
157 
sql_command_code()158   virtual enum_sql_command sql_command_code() const { return SQLCOM_XA_COMMIT; }
159 
160   virtual bool execute(THD *thd);
161 
get_xa_opt()162   enum xa_option_words get_xa_opt() const { return m_xa_opt; }
163 
164  private:
165   bool trans_xa_commit(THD *thd);
166   bool process_external_xa_commit(THD *thd, xid_t *xid, XID_STATE *xid_state);
167   bool process_internal_xa_commit(THD *thd, XID_STATE *xid_state);
168 
169   xid_t *m_xid;
170   enum xa_option_words m_xa_opt;
171 };
172 
173 /**
174   This class represents SQL statement which rollbacks and
175   terminates an XA transaction with the given xid value.
176 */
177 
178 class Sql_cmd_xa_rollback : public Sql_cmd {
179  public:
Sql_cmd_xa_rollback(xid_t * xid_arg)180   explicit Sql_cmd_xa_rollback(xid_t *xid_arg) : m_xid(xid_arg) {}
181 
sql_command_code()182   virtual enum_sql_command sql_command_code() const {
183     return SQLCOM_XA_ROLLBACK;
184   }
185 
186   virtual bool execute(THD *thd);
187 
188  private:
189   bool trans_xa_rollback(THD *thd);
190   bool process_external_xa_rollback(THD *thd, xid_t *xid, XID_STATE *xid_state);
191   bool process_internal_xa_rollback(THD *thd, XID_STATE *xid_state);
192 
193   xid_t *m_xid;
194 };
195 
196 typedef ulonglong my_xid;  // this line is the same as in log_event.h
197 #define MYSQL_XID_PREFIX "MySQLXid"
198 
199 /*
200  Same as MYSQL_XIDDATASIZE but we do not want to include plugin.h here
201  See static_assert in .cc file.
202 */
203 #define XIDDATASIZE 128
204 
205 /**
206   struct xid_t is binary compatible with the XID structure as
207   in the X/Open CAE Specification, Distributed Transaction Processing:
208   The XA Specification, X/Open Company Ltd., 1991.
209   http://www.opengroup.org/bookstore/catalog/c193.htm
210 
211   @see MYSQL_XID in mysql/plugin.h
212 */
213 typedef struct xid_t {
214  private:
215   /**
216     -1 means that the XID is null
217   */
218   long formatID;
219 
220   /**
221     value from 1 through 64
222   */
223   long gtrid_length;
224 
225   /**
226     value from 1 through 64
227   */
228   long bqual_length;
229 
230   /**
231     distributed trx identifier. not \0-terminated.
232   */
233   char data[XIDDATASIZE];
234 
235  public:
xid_txid_t236   xid_t() : formatID(-1), gtrid_length(0), bqual_length(0) {
237     memset(data, 0, XIDDATASIZE);
238   }
239 
get_format_idxid_t240   long get_format_id() const { return formatID; }
241 
set_format_idxid_t242   void set_format_id(long v) {
243     DBUG_TRACE;
244     DBUG_PRINT("debug", ("SETTING XID_STATE formatID: %ld", v));
245     formatID = v;
246     return;
247   }
248 
get_gtrid_lengthxid_t249   long get_gtrid_length() const { return gtrid_length; }
250 
set_gtrid_lengthxid_t251   void set_gtrid_length(long v) { gtrid_length = v; }
252 
get_bqual_lengthxid_t253   long get_bqual_length() const { return bqual_length; }
254 
set_bqual_lengthxid_t255   void set_bqual_length(long v) { bqual_length = v; }
256 
get_dataxid_t257   const char *get_data() const { return data; }
258 
set_dataxid_t259   void set_data(const void *v, long l) {
260     DBUG_ASSERT(l <= XIDDATASIZE);
261     memcpy(data, v, l);
262   }
263 
resetxid_t264   void reset() {
265     formatID = -1;
266     gtrid_length = 0;
267     bqual_length = 0;
268     memset(data, 0, XIDDATASIZE);
269   }
270 
setxid_t271   void set(long f, const char *g, long gl, const char *b, long bl) {
272     DBUG_TRACE;
273     DBUG_PRINT("debug", ("SETTING XID_STATE formatID: %ld", f));
274     formatID = f;
275     memcpy(data, g, gtrid_length = gl);
276     bqual_length = bl;
277     if (bl > 0) memcpy(data + gl, b, bl);
278     return;
279   }
280 
281   my_xid get_my_xid() const;
282 
keyxid_t283   uchar *key() { return reinterpret_cast<uchar *>(&gtrid_length); }
284 
keyxid_t285   const uchar *key() const {
286     return reinterpret_cast<const uchar *>(&gtrid_length);
287   }
288 
key_lengthxid_t289   uint key_length() const {
290     return sizeof(gtrid_length) + sizeof(bqual_length) + gtrid_length +
291            bqual_length;
292   }
293 
294   /*
295     The size of the string containing serialized Xid representation
296     is computed as a sum of
297       eight as the number of formatting symbols (X'',X'',)
298       plus 2 x XIDDATASIZE (2 due to hex format),
299       plus space for decimal digits of XID::formatID,
300       plus one for 0x0.
301    */
302   static const uint ser_buf_size = 8 + 2 * XIDDATASIZE + 4 * sizeof(long) + 1;
303 
304   /**
305      The method fills XID in a buffer in format of GTRID,BQUAL,FORMATID
306      where GTRID, BQUAL are represented as hex strings.
307 
308      @param  buf  a pointer to buffer
309      @return the value of the first argument
310   */
311 
serializexid_t312   char *serialize(char *buf) const {
313     return serialize_xid(buf, formatID, gtrid_length, bqual_length, data);
314   }
315 
316 #ifndef DBUG_OFF
317   /**
318      Get printable XID value.
319 
320      @param buf  pointer to the buffer where printable XID value has to be
321      stored
322 
323      @return  pointer to the buffer passed in the first argument
324   */
325   char *xid_to_str(char *buf) const;
326 #endif
327 
eqxid_t328   bool eq(const xid_t *xid) const {
329     return xid->formatID == formatID && xid->gtrid_length == gtrid_length &&
330            xid->bqual_length == bqual_length &&
331            !memcmp(xid->data, data, gtrid_length + bqual_length);
332   }
333 
is_nullxid_t334   bool is_null() const { return formatID == -1; }
335 
336  private:
setxid_t337   void set(const xid_t *xid) {
338     memcpy(this, xid, sizeof(xid->formatID) + xid->key_length());
339   }
340 
341   void set(my_xid xid);
342 
nullxid_t343   void null() { formatID = -1; }
344 
345   friend class XID_STATE;
346 } XID;
347 
348 struct st_handler_tablename;
349 
350 /**
351   Plain structure to store information about XA transaction id
352   and a list of table names involved into XA transaction with
353   specified id.
354 */
355 typedef struct st_xarecover_txn {
356   XID id;
357   List<st_handler_tablename> *mod_tables;
358 } XA_recover_txn;
359 
360 class XID_STATE {
361  public:
362   enum xa_states {
363     XA_NOTR = 0,
364     XA_ACTIVE,
365     XA_IDLE,
366     XA_PREPARED,
367     XA_ROLLBACK_ONLY
368   };
369 
370   /**
371      Transaction identifier.
372      For now, this is only used to catch duplicated external xids.
373   */
374  private:
375   static const char *xa_state_names[];
376 
377   XID m_xid;
378   /**
379     This mutex used for eliminating a possibility to run two
380     XA COMMIT/XA ROLLBACK statements concurrently against the same xid value.
381     m_xa_lock is used on handling XA COMMIT/XA ROLLBACK and acquired only for
382     external XA branches.
383   */
384   std::mutex m_xa_lock;
385 
386   /// Used by external XA only
387   xa_states xa_state;
388   bool in_recovery;
389   /// Error reported by the Resource Manager (RM) to the Transaction Manager.
390   uint rm_error;
391   /*
392     XA-prepare binary logging status. The flag serves as a facility
393     to conduct XA transaction two round binary logging.
394     It is set to @c false at XA-start.
395     It is set to @c true by binlogging routine of XA-prepare handler as well
396     as recovered to @c true at the server recovery upon restart.
397     Checked and reset at XA-commit/rollback.
398   */
399   bool m_is_binlogged;
400 
401  public:
XID_STATE()402   XID_STATE()
403       : xa_state(XA_NOTR),
404         in_recovery(false),
405         rm_error(0),
406         m_is_binlogged(false) {
407     m_xid.null();
408   }
409 
get_xa_lock()410   std::mutex &get_xa_lock() { return m_xa_lock; }
411 
set_state(xa_states state)412   void set_state(xa_states state) { xa_state = state; }
413 
get_state()414   enum xa_states get_state() { return xa_state; }
415 
has_state(xa_states state)416   bool has_state(xa_states state) const { return xa_state == state; }
417 
state_name()418   const char *state_name() const { return xa_state_names[xa_state]; }
419 
get_xid()420   const XID *get_xid() const { return &m_xid; }
421 
get_xid()422   XID *get_xid() { return &m_xid; }
423 
has_same_xid(const XID * xid)424   bool has_same_xid(const XID *xid) const { return m_xid.eq(xid); }
425 
set_query_id(query_id_t query_id)426   void set_query_id(query_id_t query_id) {
427     if (m_xid.is_null()) m_xid.set(query_id);
428   }
429 
430   void set_error(THD *thd);
431 
reset_error()432   void reset_error() { rm_error = 0; }
433 
cleanup()434   void cleanup() {
435     /*
436       If rm_error is raised, it means that this piece of a distributed
437       transaction has failed and must be rolled back. But the user must
438       rollback it explicitly, so don't start a new distributed XA until
439       then.
440     */
441     if (!rm_error) m_xid.null();
442   }
443 
reset()444   void reset() {
445     xa_state = XA_NOTR;
446     m_xid.null();
447     in_recovery = false;
448     m_is_binlogged = false;
449   }
450 
start_normal_xa(const XID * xid)451   void start_normal_xa(const XID *xid) {
452     DBUG_ASSERT(m_xid.is_null());
453     xa_state = XA_ACTIVE;
454     m_xid.set(xid);
455     in_recovery = false;
456     rm_error = 0;
457   }
458 
459   void start_recovery_xa(const XID *xid, bool binlogged_arg = false) {
460     xa_state = XA_PREPARED;
461     m_xid.set(xid);
462     in_recovery = true;
463     rm_error = 0;
464     m_is_binlogged = binlogged_arg;
465   }
466 
is_in_recovery()467   bool is_in_recovery() const { return in_recovery; }
468 
is_binlogged()469   bool is_binlogged() const { return m_is_binlogged; }
470 
set_binlogged()471   void set_binlogged() { m_is_binlogged = true; }
472 
unset_binlogged()473   void unset_binlogged() { m_is_binlogged = false; }
474 
475   void store_xid_info(Protocol *protocol, bool print_xid_as_hex) const;
476 
477   /**
478      Mark a XA transaction as rollback-only if the RM unilaterally
479      rolled back the transaction branch.
480 
481      @note If a rollback was requested by the RM, this function sets
482            the appropriate rollback error code and transits the state
483            to XA_ROLLBACK_ONLY.
484 
485      @return true if transaction was rolled back or if the transaction
486              state is XA_ROLLBACK_ONLY. false otherwise.
487   */
488 
489   bool xa_trans_rolled_back();
490 
491   /**
492     Check that XA transaction is in state IDLE or PREPARED.
493 
494     @param  report_error  true if state IDLE or PREPARED has to be interpreted
495                           as an error, else false
496 
497     @return  result of check
498       @retval  false  XA transaction is NOT in state IDLE or PREPARED
499       @retval  true   XA transaction is in state IDLE or PREPARED
500   */
501 
502   bool check_xa_idle_or_prepared(bool report_error) const;
503 
504   /**
505     Check that XA transaction has an uncommitted work. Report an error
506     to a mysql user in case when there is an uncommitted work for XA
507     transaction.
508 
509     @return  result of check
510       @retval  false  XA transaction is NOT in state IDLE, PREPARED
511                       or ROLLBACK_ONLY.
512       @retval  true   XA transaction is in state IDLE or PREPARED
513                       or ROLLBACK_ONLY.
514   */
515 
516   bool check_has_uncommitted_xa() const;
517 
518   /**
519     Check if an XA transaction has been started.
520 
521     @param  report_error  true if report an error in case when
522                           XA transaction has been stared, else false.
523 
524     @return  result of check
525       @retval  false  XA transaction hasn't been started (XA_NOTR)
526       @retval  true   XA transaction has been started (!XA_NOTR)
527   */
528 
529   bool check_in_xa(bool report_error) const;
530 };
531 
532 /**
533   This class servers as a registry for prepared XA transactions existed before
534   server was shutdown and being resurrected during the server restart.
535   The class is singleton. To collect a list of XA transaction identifiers and
536   a list of tables for that MDL locks have be acquired the method
537   add_prepared_xa_transaction() must be called. This method is invoked by
538   the function trx_recover_for_mysql() called by innobase_xa_recover during
539   running of X/Open XA distributed transaction recovery procedure. After a list
540   of XA transaction identifiers and a list of table names to be locked in MDL
541   have been collected and the function ha_recover() has returned control flow
542   the method recover_prepared_xa_transactions() must be called to resurrect
543   prepared XA transactions. Separation of collecting information about prepared
544   XA transactions from restoring XA transactions is done in order to exclude
545   possible suspending on MDL locks inside the function
546   dd::reset_tables_and_tablespaces() that is called right after the function
547   ha_recover() returns control flow.
548  */
549 
550 class Recovered_xa_transactions {
551  public:
552   /**
553     Initialize singleton.
554   */
555   static bool init();
556 
557   /**
558     Cleanup and delete singleton object
559   */
560   static void destroy();
561 
562   /**
563     Get instance of the class Recovered_xa_transactions
564   */
565   static Recovered_xa_transactions &instance();
566 
567   /**
568     Add information about prepared XA transaction into a list of
569     XA transactions to resurrect.
570 
571     @param prepared_xa_trn  information about prepared XA transaction
572 
573     @return false on success, else true
574   */
575   bool add_prepared_xa_transaction(XA_recover_txn *prepared_xa_trn);
576 
577   /**
578     Iterate along a list of prepared XA transactions, register every XA
579     transaction in a cache and acquire MDL locks for every table taking part in
580     XA transaction being resurrected.
581 
582     @return false on success, else true
583   */
584   bool recover_prepared_xa_transactions();
585 
586   /**
587     Get initialized MEM_ROOT.
588 
589     @return Pointer to a initialized MEM_ROOT.
590   */
591   MEM_ROOT *get_allocated_memroot();
592 
593  private:
594   // Disable direct instantiation. Use the method init() instead.
595   Recovered_xa_transactions();
596 
597   static Recovered_xa_transactions *m_instance;
598   std::list<XA_recover_txn *, Malloc_allocator<XA_recover_txn *>>
599       m_prepared_xa_trans;
600   bool m_mem_root_inited;
601   MEM_ROOT m_mem_root;
602 };
603 
604 class Transaction_ctx;
605 
606 /**
607   Initialize a cache to store Transaction_ctx and a mutex to protect access
608   to the cache
609 
610   @return        result of initialization
611     @retval false  success
612     @retval true   failure
613 */
614 
615 bool transaction_cache_init();
616 
617 /**
618   Transaction is marked in the cache as if it's recovered.
619   The method allows to sustain prepared transaction disconnection.
620 
621   @param transaction
622                  Pointer to Transaction object that is replaced.
623 
624   @return  operation result
625     @retval  false   success or a cache already contains XID_STATE
626                      for this XID value
627     @retval  true    failure
628 */
629 
630 bool transaction_cache_detach(Transaction_ctx *transaction);
631 
632 /**
633   Remove information about transaction from a cache.
634 
635   @param transaction     Pointer to a Transaction_ctx that has to be removed
636                          from a cache.
637 */
638 
639 void transaction_cache_delete(Transaction_ctx *transaction);
640 
641 /**
642   Release resources occupied by transaction cache.
643 */
644 
645 void transaction_cache_free();
646 
647 /**
648   This is a specific to "slave" applier collection of standard cleanup
649   actions to reset XA transaction state at the end of XA prepare rather than
650   to do it at the transaction commit, see @c ha_commit_one_phase.
651   THD of the slave applier is dissociated from a transaction object in engine
652   that continues to exist there.
653 
654   @param  thd current thread
655   @return the value of is_error()
656 */
657 
658 bool applier_reset_xa_trans(THD *thd);
659 
660 /* interface to randomly access plugin data */
661 struct st_plugin_int *plugin_find_by_type(const LEX_CSTRING &plugin, int type);
662 
663 /**
664   The function detaches existing storage engines transaction
665   context from thd. Backup area to save it is provided to low level
666   storage engine function.
667 
668   is invoked by plugin_foreach() after
669   trans_xa_start() for each storage engine.
670 
671   @param[in,out]     thd     Thread context
672   @param             plugin  Reference to handlerton
673 
674   @return    false   on success, true otherwise.
675 */
676 
677 bool detach_native_trx(THD *thd, plugin_ref plugin, void *);
678 
679 /**
680   The function reattaches existing storage engines transaction
681   context to thd. Backup area to save it is provided to low level
682   storage engine function.
683 
684   is invoked by plugin_foreach() after
685   trans_xa_prepare() for each storage engine.
686 
687   @param[in,out]     thd     Thread context
688   @param             plugin  Reference to handlerton
689 
690   @return    false   on success,
691              true    otherwise.
692 */
693 
694 bool reattach_native_trx(THD *thd, plugin_ref plugin, void *);
695 
696 /**
697   Reset some transaction state information and delete corresponding
698   Transaction_ctx object from cache.
699 
700   @param thd    Current thread
701 */
702 
703 void cleanup_trans_state(THD *thd);
704 
705 /**
706   Rollback the active XA transaction.
707 
708   @note Resets rm_error before calling ha_rollback(), so
709         the thd->transaction.xid structure gets reset
710         by ha_rollback() / THD::transaction::cleanup().
711 
712   @return true if the rollback failed, false otherwise.
713 */
714 
715 bool xa_trans_force_rollback(THD *thd);
716 #endif
717