| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2016, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file include/trx0trx.ic |
| 22 | The transaction |
| 23 | |
| 24 | Created 3/26/1996 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | /**********************************************************************//** |
| 28 | Determines if a transaction is in the given state. |
| 29 | The caller must hold trx_sys.mutex, or it must be the thread |
| 30 | that is serving a running transaction. |
| 31 | A running RW transaction must be in trx_sys.rw_trx_hash. |
| 32 | @return TRUE if trx->state == state */ |
| 33 | UNIV_INLINE |
| 34 | bool |
| 35 | trx_state_eq( |
| 36 | /*=========*/ |
| 37 | const trx_t* trx, /*!< in: transaction */ |
| 38 | trx_state_t state, /*!< in: state; |
| 39 | if state != TRX_STATE_NOT_STARTED |
| 40 | asserts that |
| 41 | trx->state != TRX_STATE_NOT_STARTED */ |
| 42 | bool relaxed) |
| 43 | /*!< in: whether to allow |
| 44 | trx->state == TRX_STATE_NOT_STARTED |
| 45 | after an error has been reported */ |
| 46 | { |
| 47 | #ifdef UNIV_DEBUG |
| 48 | switch (trx->state) { |
| 49 | case TRX_STATE_PREPARED: |
| 50 | |
| 51 | ut_ad(!trx_is_autocommit_non_locking(trx)); |
| 52 | return(trx->state == state); |
| 53 | |
| 54 | case TRX_STATE_ACTIVE: |
| 55 | |
| 56 | assert_trx_nonlocking_or_in_list(trx); |
| 57 | return(state == trx->state); |
| 58 | |
| 59 | case TRX_STATE_COMMITTED_IN_MEMORY: |
| 60 | |
| 61 | check_trx_state(trx); |
| 62 | return(state == trx->state); |
| 63 | |
| 64 | case TRX_STATE_NOT_STARTED: |
| 65 | /* These states are not allowed for running transactions. */ |
| 66 | ut_a(state == TRX_STATE_NOT_STARTED |
| 67 | || (relaxed |
| 68 | && thd_get_error_number(trx->mysql_thd))); |
| 69 | |
| 70 | return(true); |
| 71 | } |
| 72 | ut_error; |
| 73 | #endif /* UNIV_DEBUG */ |
| 74 | return(trx->state == state); |
| 75 | } |
| 76 | |
| 77 | /****************************************************************//** |
| 78 | Retrieves the error_info field from a trx. |
| 79 | @return the error info */ |
| 80 | UNIV_INLINE |
| 81 | const dict_index_t* |
| 82 | trx_get_error_info( |
| 83 | /*===============*/ |
| 84 | const trx_t* trx) /*!< in: trx object */ |
| 85 | { |
| 86 | return(trx->error_info); |
| 87 | } |
| 88 | |
| 89 | /*******************************************************************//** |
| 90 | Retrieves transaction's que state in a human readable string. The string |
| 91 | should not be free()'d or modified. |
| 92 | @return string in the data segment */ |
| 93 | UNIV_INLINE |
| 94 | const char* |
| 95 | trx_get_que_state_str( |
| 96 | /*==================*/ |
| 97 | const trx_t* trx) /*!< in: transaction */ |
| 98 | { |
| 99 | /* be sure to adjust TRX_QUE_STATE_STR_MAX_LEN if you change this */ |
| 100 | switch (trx->lock.que_state) { |
| 101 | case TRX_QUE_RUNNING: |
| 102 | return("RUNNING" ); |
| 103 | case TRX_QUE_LOCK_WAIT: |
| 104 | return("LOCK WAIT" ); |
| 105 | case TRX_QUE_ROLLING_BACK: |
| 106 | return("ROLLING BACK" ); |
| 107 | case TRX_QUE_COMMITTING: |
| 108 | return("COMMITTING" ); |
| 109 | default: |
| 110 | return("UNKNOWN" ); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /** Retreieves the transaction ID. |
| 115 | In a given point in time it is guaranteed that IDs of the running |
| 116 | transactions are unique. The values returned by this function for readonly |
| 117 | transactions may be reused, so a subsequent RO transaction may get the same ID |
| 118 | as a RO transaction that existed in the past. The values returned by this |
| 119 | function should be used for printing purposes only. |
| 120 | @param[in] trx transaction whose id to retrieve |
| 121 | @return transaction id */ |
| 122 | UNIV_INLINE |
| 123 | trx_id_t |
| 124 | trx_get_id_for_print( |
| 125 | const trx_t* trx) |
| 126 | { |
| 127 | /* Readonly and transactions whose intentions are unknown (whether |
| 128 | they will eventually do a WRITE) don't have trx_t::id assigned (it is |
| 129 | 0 for those transactions). Transaction IDs in |
| 130 | innodb_trx.trx_id, |
| 131 | innodb_locks.lock_id, |
| 132 | innodb_locks.lock_trx_id, |
| 133 | innodb_lock_waits.requesting_trx_id, |
| 134 | innodb_lock_waits.blocking_trx_id should match because those tables |
| 135 | could be used in an SQL JOIN on those columns. Also trx_t::id is |
| 136 | printed by SHOW ENGINE INNODB STATUS, and in logs, so we must have the |
| 137 | same value printed everywhere consistently. */ |
| 138 | |
| 139 | /* DATA_TRX_ID_LEN is the storage size in bytes. */ |
| 140 | static const trx_id_t max_trx_id |
| 141 | = (1ULL << (DATA_TRX_ID_LEN * CHAR_BIT)) - 1; |
| 142 | |
| 143 | ut_ad(trx->id <= max_trx_id); |
| 144 | |
| 145 | return(trx->id != 0 |
| 146 | ? trx->id |
| 147 | : reinterpret_cast<trx_id_t>(trx) | (max_trx_id + 1)); |
| 148 | } |
| 149 | |
| 150 | /**********************************************************************//** |
| 151 | Determine if a transaction is a dictionary operation. |
| 152 | @return dictionary operation mode */ |
| 153 | UNIV_INLINE |
| 154 | enum trx_dict_op_t |
| 155 | trx_get_dict_operation( |
| 156 | /*===================*/ |
| 157 | const trx_t* trx) /*!< in: transaction */ |
| 158 | { |
| 159 | trx_dict_op_t op = static_cast<trx_dict_op_t>(trx->dict_operation); |
| 160 | |
| 161 | #ifdef UNIV_DEBUG |
| 162 | switch (op) { |
| 163 | case TRX_DICT_OP_NONE: |
| 164 | case TRX_DICT_OP_TABLE: |
| 165 | case TRX_DICT_OP_INDEX: |
| 166 | return(op); |
| 167 | } |
| 168 | ut_error; |
| 169 | #endif /* UNIV_DEBUG */ |
| 170 | return(op); |
| 171 | } |
| 172 | /**********************************************************************//** |
| 173 | Flag a transaction a dictionary operation. */ |
| 174 | UNIV_INLINE |
| 175 | void |
| 176 | trx_set_dict_operation( |
| 177 | /*===================*/ |
| 178 | trx_t* trx, /*!< in/out: transaction */ |
| 179 | enum trx_dict_op_t op) /*!< in: operation, not |
| 180 | TRX_DICT_OP_NONE */ |
| 181 | { |
| 182 | #ifdef UNIV_DEBUG |
| 183 | enum trx_dict_op_t old_op = trx_get_dict_operation(trx); |
| 184 | |
| 185 | switch (op) { |
| 186 | case TRX_DICT_OP_NONE: |
| 187 | ut_error; |
| 188 | break; |
| 189 | case TRX_DICT_OP_TABLE: |
| 190 | switch (old_op) { |
| 191 | case TRX_DICT_OP_NONE: |
| 192 | case TRX_DICT_OP_INDEX: |
| 193 | case TRX_DICT_OP_TABLE: |
| 194 | goto ok; |
| 195 | } |
| 196 | ut_error; |
| 197 | break; |
| 198 | case TRX_DICT_OP_INDEX: |
| 199 | ut_ad(old_op == TRX_DICT_OP_NONE); |
| 200 | break; |
| 201 | } |
| 202 | ok: |
| 203 | #endif /* UNIV_DEBUG */ |
| 204 | |
| 205 | trx->ddl = true; |
| 206 | trx->dict_operation = op; |
| 207 | } |
| 208 | |