1
/*****************************************************************************
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
23
Created 3/26/1996 Heikki Tuuri
24
*******************************************************/
36
#include "lock0lock.h"
39
#include "read0read.h"
45
#include "ha_prototypes.h"
47
/** Dummy session used currently in MySQL interface */
48
UNIV_INTERN sess_t* trx_dummy_sess = NULL;
50
/** Number of transactions currently allocated for MySQL: protected by
52
UNIV_INTERN ulint trx_n_mysql_transactions = 0;
54
/*************************************************************//**
55
Set detailed error message for the transaction. */
58
trx_set_detailed_error(
59
/*===================*/
60
trx_t* trx, /*!< in: transaction struct */
61
const char* msg) /*!< in: detailed error message */
63
ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));
66
/*************************************************************//**
67
Set detailed error message for the transaction from a file. Note that the
68
file is rewinded before reading from it. */
71
trx_set_detailed_error_from_file(
72
/*=============================*/
73
trx_t* trx, /*!< in: transaction struct */
74
FILE* file) /*!< in: file to read message from */
76
os_file_read_string(file, trx->detailed_error,
77
sizeof(trx->detailed_error));
80
/****************************************************************//**
81
Creates and initializes a transaction object.
82
@return own: the transaction */
87
sess_t* sess) /*!< in: session */
91
ut_ad(mutex_own(&kernel_mutex));
94
trx = mem_alloc(sizeof(trx_t));
96
trx->magic_n = TRX_MAGIC_N;
101
trx->is_recovered = 0;
102
trx->conc_state = TRX_NOT_STARTED;
103
trx->start_time = time(NULL);
105
trx->isolation_level = TRX_ISO_REPEATABLE_READ;
107
trx->id = ut_dulint_zero;
108
trx->no = ut_dulint_max;
110
trx->support_xa = TRUE;
112
trx->check_foreigns = TRUE;
113
trx->check_unique_secondary = TRUE;
115
trx->flush_log_later = FALSE;
116
trx->must_flush_log_later = FALSE;
118
trx->dict_operation = TRX_DICT_OP_NONE;
119
trx->table_id = ut_dulint_zero;
121
trx->mysql_thd = NULL;
122
trx->mysql_query_str = NULL;
125
trx->mysql_n_tables_locked = 0;
127
trx->mysql_log_file_name = NULL;
128
trx->mysql_log_offset = 0;
130
mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
134
trx->undo_no = ut_dulint_zero;
135
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
136
trx->insert_undo = NULL;
137
trx->update_undo = NULL;
138
trx->undo_no_arr = NULL;
140
trx->error_state = DB_SUCCESS;
141
trx->error_key_num = 0;
142
trx->detailed_error[0] = '\0';
145
trx->que_state = TRX_QUE_RUNNING;
146
trx->n_active_thrs = 0;
148
trx->handling_signals = FALSE;
150
UT_LIST_INIT(trx->signals);
151
UT_LIST_INIT(trx->reply_signals);
155
trx->wait_lock = NULL;
156
trx->was_chosen_as_deadlock_victim = FALSE;
157
UT_LIST_INIT(trx->wait_thrs);
159
trx->lock_heap = mem_heap_create_in_buffer(256);
160
UT_LIST_INIT(trx->trx_locks);
162
UT_LIST_INIT(trx->trx_savepoints);
164
trx->dict_operation_lock_mode = 0;
165
trx->has_search_latch = FALSE;
166
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
168
trx->declared_to_be_inside_innodb = FALSE;
169
trx->n_tickets_to_enter_innodb = 0;
171
trx->global_read_view_heap = mem_heap_create(256);
172
trx->global_read_view = NULL;
173
trx->read_view = NULL;
175
/* Set X/Open XA transaction identification to NULL */
176
memset(&trx->xid, 0, sizeof(trx->xid));
177
trx->xid.formatID = -1;
179
trx->n_autoinc_rows = 0;
181
/* Remember to free the vector explicitly. */
182
trx->autoinc_locks = ib_vector_create(
183
mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
188
/********************************************************************//**
189
Creates a transaction object for MySQL.
190
@return own: transaction object */
193
trx_allocate_for_mysql(void)
194
/*========================*/
198
mutex_enter(&kernel_mutex);
200
trx = trx_create(trx_dummy_sess);
202
trx_n_mysql_transactions++;
204
UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
206
mutex_exit(&kernel_mutex);
208
trx->mysql_thread_id = os_thread_get_curr_id();
210
trx->mysql_process_no = os_proc_get_number();
215
/********************************************************************//**
216
Creates a transaction object for background operations by the master thread.
217
@return own: transaction object */
220
trx_allocate_for_background(void)
221
/*=============================*/
225
mutex_enter(&kernel_mutex);
227
trx = trx_create(trx_dummy_sess);
229
mutex_exit(&kernel_mutex);
234
/********************************************************************//**
235
Releases the search latch if trx has reserved it. */
238
trx_search_latch_release_if_reserved(
239
/*=================================*/
240
trx_t* trx) /*!< in: transaction */
242
if (trx->has_search_latch) {
243
rw_lock_s_unlock(&btr_search_latch);
245
trx->has_search_latch = FALSE;
249
/********************************************************************//**
250
Frees a transaction object. */
255
trx_t* trx) /*!< in, own: trx object */
257
ut_ad(mutex_own(&kernel_mutex));
259
if (trx->declared_to_be_inside_innodb) {
260
ut_print_timestamp(stderr);
261
fputs(" InnoDB: Error: Freeing a trx which is declared"
262
" to be processing\n"
263
"InnoDB: inside InnoDB.\n", stderr);
264
trx_print(stderr, trx, 600);
267
/* This is an error but not a fatal error. We must keep
268
the counters like srv_conc_n_threads accurate. */
269
srv_conc_force_exit_innodb(trx);
272
if (trx->mysql_n_tables_locked != 0) {
274
ut_print_timestamp(stderr);
276
" InnoDB: Error: MySQL is freeing a thd\n"
277
"InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
278
(ulong)trx->mysql_n_tables_locked);
280
trx_print(stderr, trx, 600);
282
ut_print_buf(stderr, trx, sizeof(trx_t));
286
ut_a(trx->magic_n == TRX_MAGIC_N);
288
trx->magic_n = 11112222;
290
ut_a(trx->conc_state == TRX_NOT_STARTED);
292
mutex_free(&(trx->undo_mutex));
294
ut_a(trx->insert_undo == NULL);
295
ut_a(trx->update_undo == NULL);
297
if (trx->undo_no_arr) {
298
trx_undo_arr_free(trx->undo_no_arr);
301
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
302
ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
304
ut_a(trx->wait_lock == NULL);
305
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
307
ut_a(!trx->has_search_latch);
309
ut_a(trx->dict_operation_lock_mode == 0);
311
if (trx->lock_heap) {
312
mem_heap_free(trx->lock_heap);
315
ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0);
317
if (trx->global_read_view_heap) {
318
mem_heap_free(trx->global_read_view_heap);
321
trx->global_read_view = NULL;
323
ut_a(trx->read_view == NULL);
325
ut_a(ib_vector_is_empty(trx->autoinc_locks));
326
/* We allocated a dedicated heap for the vector. */
327
ib_vector_free(trx->autoinc_locks);
332
/********************************************************************//**
333
Frees a transaction object for MySQL. */
338
trx_t* trx) /*!< in, own: trx object */
340
mutex_enter(&kernel_mutex);
342
UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
346
ut_a(trx_n_mysql_transactions > 0);
348
trx_n_mysql_transactions--;
350
mutex_exit(&kernel_mutex);
353
/********************************************************************//**
354
Frees a transaction object of a background operation of the master thread. */
357
trx_free_for_background(
358
/*====================*/
359
trx_t* trx) /*!< in, own: trx object */
361
mutex_enter(&kernel_mutex);
365
mutex_exit(&kernel_mutex);
368
/****************************************************************//**
369
Inserts the trx handle in the trx system trx list in the right position.
370
The list is sorted on the trx id so that the biggest id is at the list
371
start. This function is used at the database startup to insert incomplete
372
transactions to the list. */
375
trx_list_insert_ordered(
376
/*====================*/
377
trx_t* trx) /*!< in: trx handle */
381
ut_ad(mutex_own(&kernel_mutex));
383
trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list);
385
while (trx2 != NULL) {
386
if (ut_dulint_cmp(trx->id, trx2->id) >= 0) {
388
ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1);
391
trx2 = UT_LIST_GET_NEXT(trx_list, trx2);
395
trx2 = UT_LIST_GET_PREV(trx_list, trx2);
398
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
400
UT_LIST_INSERT_AFTER(trx_list, trx_sys->trx_list,
404
UT_LIST_ADD_LAST(trx_list, trx_sys->trx_list, trx);
408
/****************************************************************//**
409
Creates trx objects for transactions and initializes the trx list of
410
trx_sys at database start. Rollback segment and undo log lists must
411
already exist when this function is called, because the lists of
412
transactions to be rolled back or cleaned up are built based on the
416
trx_lists_init_at_db_start(void)
417
/*============================*/
423
UT_LIST_INIT(trx_sys->trx_list);
425
/* Look from the rollback segments if there exist undo logs for
428
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
430
while (rseg != NULL) {
431
undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
433
while (undo != NULL) {
435
trx = trx_create(trx_dummy_sess);
437
trx->is_recovered = TRUE;
438
trx->id = undo->trx_id;
439
trx->xid = undo->xid;
440
trx->insert_undo = undo;
443
if (undo->state != TRX_UNDO_ACTIVE) {
445
/* Prepared transactions are left in
446
the prepared state waiting for a
447
commit or abort decision from MySQL */
449
if (undo->state == TRX_UNDO_PREPARED) {
452
"InnoDB: Transaction "
455
" XA prepared state.\n",
456
TRX_ID_PREP_PRINTF(trx->id));
458
if (srv_force_recovery == 0) {
460
trx->conc_state = TRX_PREPARED;
464
" innodb_force_recovery"
469
trx->conc_state = TRX_ACTIVE;
473
= TRX_COMMITTED_IN_MEMORY;
476
/* We give a dummy value for the trx no;
477
this should have no relevance since purge
478
is not interested in committed transaction
479
numbers, unless they are in the history
480
list, in which case it looks the number
481
from the disk based undo log structure */
485
trx->conc_state = TRX_ACTIVE;
487
/* A running transaction always has the number
488
field inited to ut_dulint_max */
490
trx->no = ut_dulint_max;
493
if (undo->dict_operation) {
494
trx_set_dict_operation(
495
trx, TRX_DICT_OP_TABLE);
496
trx->table_id = undo->table_id;
500
trx->undo_no = ut_dulint_add(undo->top_undo_no,
504
trx_list_insert_ordered(trx);
506
undo = UT_LIST_GET_NEXT(undo_list, undo);
509
undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
511
while (undo != NULL) {
512
trx = trx_get_on_id(undo->trx_id);
515
trx = trx_create(trx_dummy_sess);
517
trx->is_recovered = TRUE;
518
trx->id = undo->trx_id;
519
trx->xid = undo->xid;
521
if (undo->state != TRX_UNDO_ACTIVE) {
523
/* Prepared transactions are left in
524
the prepared state waiting for a
525
commit or abort decision from MySQL */
527
if (undo->state == TRX_UNDO_PREPARED) {
529
"InnoDB: Transaction "
530
TRX_ID_FMT " was in the"
531
" XA prepared state.\n",
535
if (srv_force_recovery == 0) {
542
" innodb_force_recovery"
552
= TRX_COMMITTED_IN_MEMORY;
555
/* We give a dummy value for the trx
560
trx->conc_state = TRX_ACTIVE;
562
/* A running transaction always has
563
the number field inited to
566
trx->no = ut_dulint_max;
570
trx_list_insert_ordered(trx);
572
if (undo->dict_operation) {
573
trx_set_dict_operation(
574
trx, TRX_DICT_OP_TABLE);
575
trx->table_id = undo->table_id;
579
trx->update_undo = undo;
582
&& (ut_dulint_cmp(undo->top_undo_no,
583
trx->undo_no) >= 0)) {
585
trx->undo_no = ut_dulint_add(undo->top_undo_no,
589
undo = UT_LIST_GET_NEXT(undo_list, undo);
592
rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
596
/******************************************************************//**
597
Assigns a rollback segment to a transaction in a round-robin fashion.
598
Skips the SYSTEM rollback segment if another is available.
599
@return assigned rollback segment id */
602
trx_assign_rseg(void)
603
/*=================*/
605
trx_rseg_t* rseg = trx_sys->latest_rseg;
607
ut_ad(mutex_own(&kernel_mutex));
609
/* Get next rseg in a round-robin fashion */
611
rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
614
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
617
/* If it is the SYSTEM rollback segment, and there exist others, skip
620
if ((rseg->id == TRX_SYS_SYSTEM_RSEG_ID)
621
&& (UT_LIST_GET_LEN(trx_sys->rseg_list) > 1)) {
625
trx_sys->latest_rseg = rseg;
630
/****************************************************************//**
631
Starts a new transaction.
637
trx_t* trx, /*!< in: transaction */
638
ulint rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
639
is passed, the system chooses the rollback segment
640
automatically in a round-robin fashion */
644
ut_ad(mutex_own(&kernel_mutex));
645
ut_ad(trx->rseg == NULL);
648
trx->id = ut_dulint_zero;
649
trx->conc_state = TRX_ACTIVE;
650
trx->start_time = time(NULL);
655
ut_ad(trx->conc_state != TRX_ACTIVE);
657
if (rseg_id == ULINT_UNDEFINED) {
659
rseg_id = trx_assign_rseg();
662
rseg = trx_sys_get_nth_rseg(trx_sys, rseg_id);
664
trx->id = trx_sys_get_new_trx_id();
666
/* The initial value for trx->no: ut_dulint_max is used in
667
read_view_open_now: */
669
trx->no = ut_dulint_max;
673
trx->conc_state = TRX_ACTIVE;
674
trx->start_time = time(NULL);
676
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
681
/****************************************************************//**
682
Starts a new transaction.
688
trx_t* trx, /*!< in: transaction */
689
ulint rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
690
is passed, the system chooses the rollback segment
691
automatically in a round-robin fashion */
695
/* Update the info whether we should skip XA steps that eat CPU time
696
For the duration of the transaction trx->support_xa is not reread
697
from thd so any changes in the value take effect in the next
698
transaction. This is to avoid a scenario where some undo
699
generated by a transaction, has XA stuff, and other undo,
700
generated by the same transaction, doesn't. */
701
trx->support_xa = thd_supports_xa(trx->mysql_thd);
703
mutex_enter(&kernel_mutex);
705
ret = trx_start_low(trx, rseg_id);
707
mutex_exit(&kernel_mutex);
712
/****************************************************************//**
713
Commits a transaction. */
716
trx_commit_off_kernel(
717
/*==================*/
718
trx_t* trx) /*!< in: transaction */
720
page_t* update_hdr_page;
726
ut_ad(mutex_own(&kernel_mutex));
728
trx->must_flush_log_later = FALSE;
732
if (trx->insert_undo != NULL || trx->update_undo != NULL) {
734
mutex_exit(&kernel_mutex);
738
/* Change the undo log segment states from TRX_UNDO_ACTIVE
739
to some other state: these modifications to the file data
740
structure define the transaction as committed in the file
741
based world, at the serialization point of the log sequence
742
number lsn obtained below. */
744
mutex_enter(&(rseg->mutex));
746
if (trx->insert_undo != NULL) {
747
trx_undo_set_state_at_finish(
748
rseg, trx, trx->insert_undo, &mtr);
751
undo = trx->update_undo;
754
mutex_enter(&kernel_mutex);
755
trx->no = trx_sys_get_new_trx_no();
757
mutex_exit(&kernel_mutex);
759
/* It is not necessary to obtain trx->undo_mutex here
760
because only a single OS thread is allowed to do the
761
transaction commit for this transaction. */
763
update_hdr_page = trx_undo_set_state_at_finish(
764
rseg, trx, undo, &mtr);
766
/* We have to do the cleanup for the update log while
767
holding the rseg mutex because update log headers
768
have to be put to the history list in the order of
771
trx_undo_update_cleanup(trx, update_hdr_page, &mtr);
774
mutex_exit(&(rseg->mutex));
776
/* Update the latest MySQL binlog name and offset info
777
in trx sys header if MySQL binlogging is on or the database
778
server is a MySQL replication slave */
780
if (trx->mysql_log_file_name
781
&& trx->mysql_log_file_name[0] != '\0') {
782
trx_sys_update_mysql_binlog_offset(
783
trx->mysql_log_file_name,
784
trx->mysql_log_offset,
785
TRX_SYS_MYSQL_LOG_INFO, &mtr);
786
trx->mysql_log_file_name = NULL;
789
/* The following call commits the mini-transaction, making the
790
whole transaction committed in the file-based world, at this
791
log sequence number. The transaction becomes 'durable' when
792
we write the log to disk, but in the logical sense the commit
793
in the file-based data structures (undo logs etc.) happens
796
NOTE that transaction numbers, which are assigned only to
797
transactions with an update undo log, do not necessarily come
798
in exactly the same order as commit lsn's, if the transactions
799
have different rollback segments. To get exactly the same
800
order we should hold the kernel mutex up to this point,
801
adding to the contention of the kernel mutex. However, if
802
a transaction T2 is able to see modifications made by
803
a transaction T1, T2 will always get a bigger transaction
804
number and a bigger commit lsn than T1. */
811
mutex_enter(&kernel_mutex);
814
ut_ad(trx->conc_state == TRX_ACTIVE
815
|| trx->conc_state == TRX_PREPARED);
816
ut_ad(mutex_own(&kernel_mutex));
818
/* The following assignment makes the transaction committed in memory
819
and makes its changes to data visible to other transactions.
820
NOTE that there is a small discrepancy from the strict formal
821
visibility rules here: a human user of the database can see
822
modifications made by another transaction T even before the necessary
823
log segment has been flushed to the disk. If the database happens to
824
crash before the flush, the user has seen modifications from T which
825
will never be a committed transaction. However, any transaction T2
826
which sees the modifications of the committing transaction T, and
827
which also itself makes modifications to the database, will get an lsn
828
larger than the committing transaction T. In the case where the log
829
flush fails, and T never gets committed, also T2 will never get
832
/*--------------------------------------*/
833
trx->conc_state = TRX_COMMITTED_IN_MEMORY;
834
/*--------------------------------------*/
836
/* If we release kernel_mutex below and we are still doing
837
recovery i.e.: back ground rollback thread is still active
838
then there is a chance that the rollback thread may see
839
this trx as COMMITTED_IN_MEMORY and goes adhead to clean it
840
up calling trx_cleanup_at_db_startup(). This can happen
841
in the case we are committing a trx here that is left in
842
PREPARED state during the crash. Note that commit of the
843
rollback of a PREPARED trx happens in the recovery thread
844
while the rollback of other transactions happen in the
845
background thread. To avoid this race we unconditionally
846
unset the is_recovered flag from the trx. */
848
trx->is_recovered = FALSE;
850
lock_release_off_kernel(trx);
852
if (trx->global_read_view) {
853
read_view_close(trx->global_read_view);
854
mem_heap_empty(trx->global_read_view_heap);
855
trx->global_read_view = NULL;
858
trx->read_view = NULL;
862
mutex_exit(&kernel_mutex);
864
if (trx->insert_undo != NULL) {
866
trx_undo_insert_cleanup(trx);
869
/* NOTE that we could possibly make a group commit more
870
efficient here: call os_thread_yield here to allow also other
871
trxs to come to commit! */
873
/*-------------------------------------*/
875
/* Depending on the my.cnf options, we may now write the log
876
buffer to the log files, making the transaction durable if
877
the OS does not crash. We may also flush the log files to
878
disk, making the transaction durable also at an OS crash or a
881
The idea in InnoDB's group commit is that a group of
882
transactions gather behind a trx doing a physical disk write
883
to log files, and when that physical write has been completed,
884
one of those transactions does a write which commits the whole
885
group. Note that this group commit will only bring benefit if
886
there are > 2 users in the database. Then at least 2 users can
887
gather behind one doing the physical log write to disk.
889
If we are calling trx_commit() under prepare_commit_mutex, we
890
will delay possible log write and flush to a separate function
891
trx_commit_complete_for_mysql(), which is only called when the
892
thread has released the mutex. This is to make the
893
group commit algorithm to work. Otherwise, the prepare_commit
894
mutex would serialize all commits and prevent a group of
895
transactions from gathering. */
897
if (trx->flush_log_later) {
899
trx->must_flush_log_later = TRUE;
900
} else if (srv_flush_log_at_trx_commit == 0) {
902
} else if (srv_flush_log_at_trx_commit == 1) {
903
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
904
/* Write the log but do not flush it to disk */
906
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
909
/* Write the log to the log files AND flush
912
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
914
} else if (srv_flush_log_at_trx_commit == 2) {
916
/* Write the log but do not flush it to disk */
918
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
923
trx->commit_lsn = lsn;
925
/*-------------------------------------*/
927
mutex_enter(&kernel_mutex);
930
/* Free all savepoints */
931
trx_roll_free_all_savepoints(trx);
933
trx->conc_state = TRX_NOT_STARTED;
935
trx->undo_no = ut_dulint_zero;
936
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
937
trx->mysql_query_str = NULL;
939
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
940
ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
942
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
945
/****************************************************************//**
946
Cleans up a transaction at database startup. The cleanup is needed if
947
the transaction already got to the middle of a commit when the database
948
crashed, and we cannot roll it back. */
951
trx_cleanup_at_db_startup(
952
/*======================*/
953
trx_t* trx) /*!< in: transaction */
955
if (trx->insert_undo != NULL) {
957
trx_undo_insert_cleanup(trx);
960
trx->conc_state = TRX_NOT_STARTED;
962
trx->undo_no = ut_dulint_zero;
963
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
965
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
968
/********************************************************************//**
969
Assigns a read view for a consistent read query. All the consistent reads
970
within the same transaction will get the same read view, which is created
971
when this function is first called for a new started transaction.
972
@return consistent read view */
975
trx_assign_read_view(
976
/*=================*/
977
trx_t* trx) /*!< in: active transaction */
979
ut_ad(trx->conc_state == TRX_ACTIVE);
981
if (trx->read_view) {
982
return(trx->read_view);
985
mutex_enter(&kernel_mutex);
987
if (!trx->read_view) {
988
trx->read_view = read_view_open_now(
989
trx->id, trx->global_read_view_heap);
990
trx->global_read_view = trx->read_view;
993
mutex_exit(&kernel_mutex);
995
return(trx->read_view);
998
/****************************************************************//**
999
Commits a transaction. NOTE that the kernel mutex is temporarily released. */
1002
trx_handle_commit_sig_off_kernel(
1003
/*=============================*/
1004
trx_t* trx, /*!< in: transaction */
1005
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1006
if the value which is passed in is
1007
a pointer to a NULL pointer, then the
1008
calling function can start running
1009
a new query thread */
1012
trx_sig_t* next_sig;
1014
ut_ad(mutex_own(&kernel_mutex));
1016
trx->que_state = TRX_QUE_COMMITTING;
1018
trx_commit_off_kernel(trx);
1020
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
1022
/* Remove all TRX_SIG_COMMIT signals from the signal queue and send
1023
reply messages to them */
1025
sig = UT_LIST_GET_FIRST(trx->signals);
1027
while (sig != NULL) {
1028
next_sig = UT_LIST_GET_NEXT(signals, sig);
1030
if (sig->type == TRX_SIG_COMMIT) {
1032
trx_sig_reply(sig, next_thr);
1033
trx_sig_remove(trx, sig);
1039
trx->que_state = TRX_QUE_RUNNING;
1042
/***********************************************************//**
1043
The transaction must be in the TRX_QUE_LOCK_WAIT state. Puts it to
1044
the TRX_QUE_RUNNING state and releases query threads which were
1045
waiting for a lock in the wait_thrs list. */
1050
trx_t* trx) /*!< in: transaction */
1054
ut_ad(mutex_own(&kernel_mutex));
1055
ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
1057
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1059
while (thr != NULL) {
1060
que_thr_end_wait_no_next_thr(thr);
1062
UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
1064
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1067
trx->que_state = TRX_QUE_RUNNING;
1070
/***********************************************************//**
1071
Moves the query threads in the lock wait list to the SUSPENDED state and puts
1072
the transaction to the TRX_QUE_RUNNING state. */
1075
trx_lock_wait_to_suspended(
1076
/*=======================*/
1077
trx_t* trx) /*!< in: transaction in the TRX_QUE_LOCK_WAIT state */
1081
ut_ad(mutex_own(&kernel_mutex));
1082
ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
1084
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1086
while (thr != NULL) {
1087
thr->state = QUE_THR_SUSPENDED;
1089
UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
1091
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1094
trx->que_state = TRX_QUE_RUNNING;
1097
/***********************************************************//**
1098
Moves the query threads in the sig reply wait list of trx to the SUSPENDED
1102
trx_sig_reply_wait_to_suspended(
1103
/*============================*/
1104
trx_t* trx) /*!< in: transaction */
1109
ut_ad(mutex_own(&kernel_mutex));
1111
sig = UT_LIST_GET_FIRST(trx->reply_signals);
1113
while (sig != NULL) {
1114
thr = sig->receiver;
1116
ut_ad(thr->state == QUE_THR_SIG_REPLY_WAIT);
1118
thr->state = QUE_THR_SUSPENDED;
1120
sig->receiver = NULL;
1122
UT_LIST_REMOVE(reply_signals, trx->reply_signals, sig);
1124
sig = UT_LIST_GET_FIRST(trx->reply_signals);
1128
/*****************************************************************//**
1129
Checks the compatibility of a new signal with the other signals in the
1131
@return TRUE if the signal can be queued */
1134
trx_sig_is_compatible(
1135
/*==================*/
1136
trx_t* trx, /*!< in: trx handle */
1137
ulint type, /*!< in: signal type */
1138
ulint sender) /*!< in: TRX_SIG_SELF or TRX_SIG_OTHER_SESS */
1142
ut_ad(mutex_own(&kernel_mutex));
1144
if (UT_LIST_GET_LEN(trx->signals) == 0) {
1149
if (sender == TRX_SIG_SELF) {
1150
if (type == TRX_SIG_ERROR_OCCURRED) {
1154
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1162
ut_ad(sender == TRX_SIG_OTHER_SESS);
1164
sig = UT_LIST_GET_FIRST(trx->signals);
1166
if (type == TRX_SIG_COMMIT) {
1167
while (sig != NULL) {
1169
if (sig->type == TRX_SIG_TOTAL_ROLLBACK) {
1174
sig = UT_LIST_GET_NEXT(signals, sig);
1179
} else if (type == TRX_SIG_TOTAL_ROLLBACK) {
1180
while (sig != NULL) {
1182
if (sig->type == TRX_SIG_COMMIT) {
1187
sig = UT_LIST_GET_NEXT(signals, sig);
1192
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1202
/****************************************************************//**
1203
Sends a signal to a trx object. */
1208
trx_t* trx, /*!< in: trx handle */
1209
ulint type, /*!< in: signal type */
1210
ulint sender, /*!< in: TRX_SIG_SELF or
1211
TRX_SIG_OTHER_SESS */
1212
que_thr_t* receiver_thr, /*!< in: query thread which wants the
1213
reply, or NULL; if type is
1214
TRX_SIG_END_WAIT, this must be NULL */
1215
trx_savept_t* savept, /*!< in: possible rollback savepoint, or
1217
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1218
if the value which is passed in is
1219
a pointer to a NULL pointer, then the
1220
calling function can start running
1221
a new query thread; if the parameter
1222
is NULL, it is ignored */
1225
trx_t* receiver_trx;
1228
ut_ad(mutex_own(&kernel_mutex));
1230
if (!trx_sig_is_compatible(trx, type, sender)) {
1231
/* The signal is not compatible with the other signals in
1237
/* Queue the signal object */
1239
if (UT_LIST_GET_LEN(trx->signals) == 0) {
1241
/* The signal list is empty: the 'sig' slot must be unused
1242
(we improve performance a bit by avoiding mem_alloc) */
1245
/* It might be that the 'sig' slot is unused also in this
1246
case, but we choose the easy way of using mem_alloc */
1248
sig = mem_alloc(sizeof(trx_sig_t));
1251
UT_LIST_ADD_LAST(signals, trx->signals, sig);
1254
sig->sender = sender;
1255
sig->receiver = receiver_thr;
1258
sig->savept = *savept;
1262
receiver_trx = thr_get_trx(receiver_thr);
1264
UT_LIST_ADD_LAST(reply_signals, receiver_trx->reply_signals,
1268
if (trx->sess->state == SESS_ERROR) {
1270
trx_sig_reply_wait_to_suspended(trx);
1273
if ((sender != TRX_SIG_SELF) || (type == TRX_SIG_BREAK_EXECUTION)) {
1277
/* If there were no other signals ahead in the queue, try to start
1278
handling of the signal */
1280
if (UT_LIST_GET_FIRST(trx->signals) == sig) {
1282
trx_sig_start_handle(trx, next_thr);
1286
/****************************************************************//**
1287
Ends signal handling. If the session is in the error state, and
1288
trx->graph_before_signal_handling != NULL, then returns control to the error
1289
handling routine of the graph (currently just returns the control to the
1290
graph root which then will send an error message to the client). */
1293
trx_end_signal_handling(
1294
/*====================*/
1295
trx_t* trx) /*!< in: trx */
1297
ut_ad(mutex_own(&kernel_mutex));
1298
ut_ad(trx->handling_signals == TRUE);
1300
trx->handling_signals = FALSE;
1302
trx->graph = trx->graph_before_signal_handling;
1304
if (trx->graph && (trx->sess->state == SESS_ERROR)) {
1306
que_fork_error_handle(trx, trx->graph);
1310
/****************************************************************//**
1311
Starts handling of a trx signal. */
1314
trx_sig_start_handle(
1315
/*=================*/
1316
trx_t* trx, /*!< in: trx handle */
1317
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1318
if the value which is passed in is
1319
a pointer to a NULL pointer, then the
1320
calling function can start running
1321
a new query thread; if the parameter
1322
is NULL, it is ignored */
1327
/* We loop in this function body as long as there are queued signals
1328
we can process immediately */
1331
ut_ad(mutex_own(&kernel_mutex));
1333
if (trx->handling_signals && (UT_LIST_GET_LEN(trx->signals) == 0)) {
1335
trx_end_signal_handling(trx);
1340
if (trx->conc_state == TRX_NOT_STARTED) {
1342
trx_start_low(trx, ULINT_UNDEFINED);
1345
/* If the trx is in a lock wait state, moves the waiting query threads
1346
to the suspended state */
1348
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
1350
trx_lock_wait_to_suspended(trx);
1353
/* If the session is in the error state and this trx has threads
1354
waiting for reply from signals, moves these threads to the suspended
1355
state, canceling wait reservations; note that if the transaction has
1356
sent a commit or rollback signal to itself, and its session is not in
1357
the error state, then nothing is done here. */
1359
if (trx->sess->state == SESS_ERROR) {
1360
trx_sig_reply_wait_to_suspended(trx);
1363
/* If there are no running query threads, we can start processing of a
1364
signal, otherwise we have to wait until all query threads of this
1365
transaction are aware of the arrival of the signal. */
1367
if (trx->n_active_thrs > 0) {
1372
if (trx->handling_signals == FALSE) {
1373
trx->graph_before_signal_handling = trx->graph;
1375
trx->handling_signals = TRUE;
1378
sig = UT_LIST_GET_FIRST(trx->signals);
1381
if (type == TRX_SIG_COMMIT) {
1383
trx_handle_commit_sig_off_kernel(trx, next_thr);
1385
} else if ((type == TRX_SIG_TOTAL_ROLLBACK)
1386
|| (type == TRX_SIG_ROLLBACK_TO_SAVEPT)) {
1388
trx_rollback(trx, sig, next_thr);
1390
/* No further signals can be handled until the rollback
1391
completes, therefore we return */
1395
} else if (type == TRX_SIG_ERROR_OCCURRED) {
1397
trx_rollback(trx, sig, next_thr);
1399
/* No further signals can be handled until the rollback
1400
completes, therefore we return */
1404
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1406
trx_sig_reply(sig, next_thr);
1407
trx_sig_remove(trx, sig);
1415
/****************************************************************//**
1416
Send the reply message when a signal in the queue of the trx has been
1422
trx_sig_t* sig, /*!< in: signal */
1423
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1424
if the value which is passed in is
1425
a pointer to a NULL pointer, then the
1426
calling function can start running
1427
a new query thread */
1429
trx_t* receiver_trx;
1432
ut_ad(mutex_own(&kernel_mutex));
1434
if (sig->receiver != NULL) {
1435
ut_ad((sig->receiver)->state == QUE_THR_SIG_REPLY_WAIT);
1437
receiver_trx = thr_get_trx(sig->receiver);
1439
UT_LIST_REMOVE(reply_signals, receiver_trx->reply_signals,
1441
ut_ad(receiver_trx->sess->state != SESS_ERROR);
1443
que_thr_end_wait(sig->receiver, next_thr);
1445
sig->receiver = NULL;
1450
/****************************************************************//**
1451
Removes a signal object from the trx signal queue. */
1456
trx_t* trx, /*!< in: trx handle */
1457
trx_sig_t* sig) /*!< in, own: signal */
1460
ut_ad(mutex_own(&kernel_mutex));
1462
ut_ad(sig->receiver == NULL);
1464
UT_LIST_REMOVE(signals, trx->signals, sig);
1465
sig->type = 0; /* reset the field to catch possible bugs */
1467
if (sig != &(trx->sig)) {
1472
/*********************************************************************//**
1473
Creates a commit command node struct.
1474
@return own: commit node struct */
1479
mem_heap_t* heap) /*!< in: mem heap where created */
1481
commit_node_t* node;
1483
node = mem_heap_alloc(heap, sizeof(commit_node_t));
1484
node->common.type = QUE_NODE_COMMIT;
1485
node->state = COMMIT_NODE_SEND;
1490
/***********************************************************//**
1491
Performs an execution step for a commit type node in a query graph.
1492
@return query thread to run next, or NULL */
1497
que_thr_t* thr) /*!< in: query thread */
1499
commit_node_t* node;
1500
que_thr_t* next_thr;
1502
node = thr->run_node;
1504
ut_ad(que_node_get_type(node) == QUE_NODE_COMMIT);
1506
if (thr->prev_node == que_node_get_parent(node)) {
1507
node->state = COMMIT_NODE_SEND;
1510
if (node->state == COMMIT_NODE_SEND) {
1511
mutex_enter(&kernel_mutex);
1513
node->state = COMMIT_NODE_WAIT;
1517
thr->state = QUE_THR_SIG_REPLY_WAIT;
1519
/* Send the commit signal to the transaction */
1521
trx_sig_send(thr_get_trx(thr), TRX_SIG_COMMIT, TRX_SIG_SELF,
1522
thr, NULL, &next_thr);
1524
mutex_exit(&kernel_mutex);
1529
ut_ad(node->state == COMMIT_NODE_WAIT);
1531
node->state = COMMIT_NODE_SEND;
1533
thr->run_node = que_node_get_parent(node);
1538
/**********************************************************************//**
1539
Does the transaction commit for MySQL.
1540
@return DB_SUCCESS or error number */
1543
trx_commit_for_mysql(
1544
/*=================*/
1545
trx_t* trx) /*!< in: trx handle */
1547
/* Because we do not do the commit by sending an Innobase
1548
sig to the transaction, we must here make sure that trx has been
1553
trx_start_if_not_started(trx);
1555
trx->op_info = "committing";
1557
mutex_enter(&kernel_mutex);
1559
trx_commit_off_kernel(trx);
1561
mutex_exit(&kernel_mutex);
1568
/**********************************************************************//**
1569
If required, flushes the log to disk if we called trx_commit_for_mysql()
1570
with trx->flush_log_later == TRUE.
1571
@return 0 or error number */
1574
trx_commit_complete_for_mysql(
1575
/*==========================*/
1576
trx_t* trx) /*!< in: trx handle */
1578
ib_uint64_t lsn = trx->commit_lsn;
1582
trx->op_info = "flushing log";
1584
if (!trx->must_flush_log_later) {
1586
} else if (srv_flush_log_at_trx_commit == 0) {
1588
} else if (srv_flush_log_at_trx_commit == 1) {
1589
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
1590
/* Write the log but do not flush it to disk */
1592
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1594
/* Write the log to the log files AND flush them to
1597
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
1599
} else if (srv_flush_log_at_trx_commit == 2) {
1601
/* Write the log but do not flush it to disk */
1603
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1608
trx->must_flush_log_later = FALSE;
1615
/**********************************************************************//**
1616
Marks the latest SQL statement ended. */
1619
trx_mark_sql_stat_end(
1620
/*==================*/
1621
trx_t* trx) /*!< in: trx handle */
1625
if (trx->conc_state == TRX_NOT_STARTED) {
1626
trx->undo_no = ut_dulint_zero;
1629
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
1632
/**********************************************************************//**
1633
Prints info about a transaction to the given file. The caller must own the
1634
kernel mutex and must have called
1635
innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL
1636
or InnoDB cannot meanwhile change the info printed here. */
1641
FILE* f, /*!< in: output stream */
1642
trx_t* trx, /*!< in: transaction */
1643
ulint max_query_len) /*!< in: max query length to print, or 0 to
1644
use the default max length */
1648
fprintf(f, "TRANSACTION " TRX_ID_FMT, TRX_ID_PREP_PRINTF(trx->id));
1650
switch (trx->conc_state) {
1651
case TRX_NOT_STARTED:
1652
fputs(", not started", f);
1655
fprintf(f, ", ACTIVE %lu sec",
1656
(ulong)difftime(time(NULL), trx->start_time));
1659
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
1660
(ulong)difftime(time(NULL), trx->start_time));
1662
case TRX_COMMITTED_IN_MEMORY:
1663
fputs(", COMMITTED IN MEMORY", f);
1666
fprintf(f, " state %lu", (ulong) trx->conc_state);
1670
fprintf(f, ", process no %lu", trx->mysql_process_no);
1672
fprintf(f, ", OS thread id %lu",
1673
(ulong) os_thread_pf(trx->mysql_thread_id));
1675
if (*trx->op_info) {
1677
fputs(trx->op_info, f);
1680
if (trx->is_recovered) {
1681
fputs(" recovered trx", f);
1684
if (trx->is_purge) {
1685
fputs(" purge trx", f);
1688
if (trx->declared_to_be_inside_innodb) {
1689
fprintf(f, ", thread declared inside InnoDB %lu",
1690
(ulong) trx->n_tickets_to_enter_innodb);
1695
if (trx->mysql_n_tables_locked > 0) {
1696
fprintf(f, "mysql tables in locked %lu\n",
1697
(ulong) trx->mysql_n_tables_locked);
1702
switch (trx->que_state) {
1703
case TRX_QUE_RUNNING:
1704
newline = FALSE; break;
1705
case TRX_QUE_LOCK_WAIT:
1706
fputs("LOCK WAIT ", f); break;
1707
case TRX_QUE_ROLLING_BACK:
1708
fputs("ROLLING BACK ", f); break;
1709
case TRX_QUE_COMMITTING:
1710
fputs("COMMITTING ", f); break;
1712
fprintf(f, "que state %lu ", (ulong) trx->que_state);
1715
if (0 < UT_LIST_GET_LEN(trx->trx_locks)
1716
|| mem_heap_get_size(trx->lock_heap) > 400) {
1719
fprintf(f, "%lu lock struct(s), heap size %lu,"
1721
(ulong) UT_LIST_GET_LEN(trx->trx_locks),
1722
(ulong) mem_heap_get_size(trx->lock_heap),
1723
(ulong) lock_number_of_rows_locked(trx));
1726
if (trx->has_search_latch) {
1728
fputs(", holds adaptive hash latch", f);
1731
if (!ut_dulint_is_zero(trx->undo_no)) {
1733
fprintf(f, ", undo log entries %lu",
1734
(ulong) ut_dulint_get_low(trx->undo_no));
1741
if (trx->mysql_thd != NULL) {
1742
innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
1746
/*******************************************************************//**
1747
Compares the "weight" (or size) of two transactions. Transactions that
1748
have edited non-transactional tables are considered heavier than ones
1750
@return <0, 0 or >0; similar to strcmp(3) */
1755
const trx_t* a, /*!< in: the first transaction to be compared */
1756
const trx_t* b) /*!< in: the second transaction to be compared */
1758
ibool a_notrans_edit;
1759
ibool b_notrans_edit;
1761
/* If mysql_thd is NULL for a transaction we assume that it has
1762
not edited non-transactional tables. */
1764
a_notrans_edit = a->mysql_thd != NULL
1765
&& thd_has_edited_nontrans_tables(a->mysql_thd);
1767
b_notrans_edit = b->mysql_thd != NULL
1768
&& thd_has_edited_nontrans_tables(b->mysql_thd);
1770
if (a_notrans_edit && !b_notrans_edit) {
1775
if (!a_notrans_edit && b_notrans_edit) {
1780
/* Either both had edited non-transactional tables or both had
1781
not, we fall back to comparing the number of altered/locked
1786
"%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n",
1788
ut_conv_dulint_to_longlong(a->undo_no),
1789
UT_LIST_GET_LEN(a->trx_locks),
1790
ut_conv_dulint_to_longlong(b->undo_no),
1791
UT_LIST_GET_LEN(b->trx_locks));
1794
return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b)));
1797
/****************************************************************//**
1798
Prepares a transaction. */
1801
trx_prepare_off_kernel(
1802
/*===================*/
1803
trx_t* trx) /*!< in: transaction */
1805
page_t* update_hdr_page;
1807
ib_uint64_t lsn = 0;
1810
ut_ad(mutex_own(&kernel_mutex));
1814
if (trx->insert_undo != NULL || trx->update_undo != NULL) {
1816
mutex_exit(&kernel_mutex);
1820
/* Change the undo log segment states from TRX_UNDO_ACTIVE
1821
to TRX_UNDO_PREPARED: these modifications to the file data
1822
structure define the transaction as prepared in the
1823
file-based world, at the serialization point of lsn. */
1825
mutex_enter(&(rseg->mutex));
1827
if (trx->insert_undo != NULL) {
1829
/* It is not necessary to obtain trx->undo_mutex here
1830
because only a single OS thread is allowed to do the
1831
transaction prepare for this transaction. */
1833
trx_undo_set_state_at_prepare(trx, trx->insert_undo,
1837
if (trx->update_undo) {
1838
update_hdr_page = trx_undo_set_state_at_prepare(
1839
trx, trx->update_undo, &mtr);
1842
mutex_exit(&(rseg->mutex));
1845
mtr_commit(&mtr); /* This mtr commit makes the
1846
transaction prepared in the file-based
1851
mutex_enter(&kernel_mutex);
1854
ut_ad(mutex_own(&kernel_mutex));
1856
/*--------------------------------------*/
1857
trx->conc_state = TRX_PREPARED;
1858
/*--------------------------------------*/
1861
/* Depending on the my.cnf options, we may now write the log
1862
buffer to the log files, making the prepared state of the
1863
transaction durable if the OS does not crash. We may also
1864
flush the log files to disk, making the prepared state of the
1865
transaction durable also at an OS crash or a power outage.
1867
The idea in InnoDB's group prepare is that a group of
1868
transactions gather behind a trx doing a physical disk write
1869
to log files, and when that physical write has been completed,
1870
one of those transactions does a write which prepares the whole
1871
group. Note that this group prepare will only bring benefit if
1872
there are > 2 users in the database. Then at least 2 users can
1873
gather behind one doing the physical log write to disk.
1875
TODO: find out if MySQL holds some mutex when calling this.
1876
That would spoil our group prepare algorithm. */
1878
mutex_exit(&kernel_mutex);
1880
if (srv_flush_log_at_trx_commit == 0) {
1882
} else if (srv_flush_log_at_trx_commit == 1) {
1883
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
1884
/* Write the log but do not flush it to disk */
1886
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
1889
/* Write the log to the log files AND flush
1892
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
1894
} else if (srv_flush_log_at_trx_commit == 2) {
1896
/* Write the log but do not flush it to disk */
1898
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1903
mutex_enter(&kernel_mutex);
1907
/**********************************************************************//**
1908
Does the transaction prepare for MySQL.
1909
@return 0 or error number */
1912
trx_prepare_for_mysql(
1913
/*==================*/
1914
trx_t* trx) /*!< in: trx handle */
1916
/* Because we do not do the prepare by sending an Innobase
1917
sig to the transaction, we must here make sure that trx has been
1922
trx->op_info = "preparing";
1924
trx_start_if_not_started(trx);
1926
mutex_enter(&kernel_mutex);
1928
trx_prepare_off_kernel(trx);
1930
mutex_exit(&kernel_mutex);
1937
/**********************************************************************//**
1938
This function is used to find number of prepared transactions and
1939
their transaction objects for a recovery.
1940
@return number of prepared transactions stored in xid_list */
1943
trx_recover_for_mysql(
1944
/*==================*/
1945
XID* xid_list, /*!< in/out: prepared transactions */
1946
ulint len) /*!< in: number of slots in xid_list */
1954
/* We should set those transactions which are in the prepared state
1957
mutex_enter(&kernel_mutex);
1959
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
1962
if (trx->conc_state == TRX_PREPARED) {
1963
xid_list[count] = trx->xid;
1966
ut_print_timestamp(stderr);
1968
" InnoDB: Starting recovery for"
1969
" XA transactions...\n");
1972
ut_print_timestamp(stderr);
1974
" InnoDB: Transaction " TRX_ID_FMT " in"
1975
" prepared state after recovery\n",
1976
TRX_ID_PREP_PRINTF(trx->id));
1978
ut_print_timestamp(stderr);
1980
" InnoDB: Transaction contains changes"
1982
(ulong) ut_conv_dulint_to_longlong(
1992
trx = UT_LIST_GET_NEXT(trx_list, trx);
1995
mutex_exit(&kernel_mutex);
1998
ut_print_timestamp(stderr);
2000
" InnoDB: %lu transactions in prepared state"
2001
" after recovery\n",
2005
return ((int) count);
2008
/*******************************************************************//**
2009
This function is used to find one X/Open XA distributed transaction
2010
which is in the prepared state
2011
@return trx or NULL */
2016
XID* xid) /*!< in: X/Open XA transaction identification */
2025
mutex_enter(&kernel_mutex);
2027
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
2030
/* Compare two X/Open XA transaction id's: their
2031
length should be the same and binary comparison
2032
of gtrid_lenght+bqual_length bytes should be
2035
if (xid->gtrid_length == trx->xid.gtrid_length
2036
&& xid->bqual_length == trx->xid.bqual_length
2037
&& memcmp(xid->data, trx->xid.data,
2038
xid->gtrid_length + xid->bqual_length) == 0) {
2042
trx = UT_LIST_GET_NEXT(trx_list, trx);
2045
mutex_exit(&kernel_mutex);
2048
if (trx->conc_state != TRX_PREPARED) {