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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 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;
123
trx->active_trans = 0;
126
trx->n_mysql_tables_in_use = 0;
127
trx->mysql_n_tables_locked = 0;
129
trx->mysql_log_file_name = NULL;
130
trx->mysql_log_offset = 0;
132
mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
136
trx->undo_no = ut_dulint_zero;
137
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
138
trx->insert_undo = NULL;
139
trx->update_undo = NULL;
140
trx->undo_no_arr = NULL;
142
trx->error_state = DB_SUCCESS;
143
trx->error_key_num = 0;
144
trx->detailed_error[0] = '\0';
147
trx->que_state = TRX_QUE_RUNNING;
148
trx->n_active_thrs = 0;
150
trx->handling_signals = FALSE;
152
UT_LIST_INIT(trx->signals);
153
UT_LIST_INIT(trx->reply_signals);
157
trx->wait_lock = NULL;
158
trx->was_chosen_as_deadlock_victim = FALSE;
159
UT_LIST_INIT(trx->wait_thrs);
161
trx->lock_heap = mem_heap_create_in_buffer(256);
162
UT_LIST_INIT(trx->trx_locks);
164
UT_LIST_INIT(trx->trx_savepoints);
166
trx->dict_operation_lock_mode = 0;
167
trx->has_search_latch = FALSE;
168
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
170
trx->declared_to_be_inside_innodb = FALSE;
171
trx->n_tickets_to_enter_innodb = 0;
173
trx->global_read_view_heap = mem_heap_create(256);
174
trx->global_read_view = NULL;
175
trx->read_view = NULL;
177
/* Set X/Open XA transaction identification to NULL */
178
memset(&trx->xid, 0, sizeof(trx->xid));
179
trx->xid.formatID = -1;
181
trx->n_autoinc_rows = 0;
183
/* Remember to free the vector explicitly. */
184
trx->autoinc_locks = ib_vector_create(
185
mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
190
/********************************************************************//**
191
Creates a transaction object for MySQL.
192
@return own: transaction object */
195
trx_allocate_for_mysql(void)
196
/*========================*/
200
mutex_enter(&kernel_mutex);
202
trx = trx_create(trx_dummy_sess);
204
trx_n_mysql_transactions++;
206
UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
208
mutex_exit(&kernel_mutex);
210
trx->mysql_thread_id = os_thread_get_curr_id();
212
trx->mysql_process_no = os_proc_get_number();
217
/********************************************************************//**
218
Creates a transaction object for background operations by the master thread.
219
@return own: transaction object */
222
trx_allocate_for_background(void)
223
/*=============================*/
227
mutex_enter(&kernel_mutex);
229
trx = trx_create(trx_dummy_sess);
231
mutex_exit(&kernel_mutex);
236
/********************************************************************//**
237
Releases the search latch if trx has reserved it. */
240
trx_search_latch_release_if_reserved(
241
/*=================================*/
242
trx_t* trx) /*!< in: transaction */
244
if (trx->has_search_latch) {
245
rw_lock_s_unlock(&btr_search_latch);
247
trx->has_search_latch = FALSE;
251
/********************************************************************//**
252
Frees a transaction object. */
257
trx_t* trx) /*!< in, own: trx object */
259
ut_ad(mutex_own(&kernel_mutex));
261
if (trx->declared_to_be_inside_innodb) {
262
ut_print_timestamp(stderr);
263
fputs(" InnoDB: Error: Freeing a trx which is declared"
264
" to be processing\n"
265
"InnoDB: inside InnoDB.\n", stderr);
266
trx_print(stderr, trx, 600);
269
/* This is an error but not a fatal error. We must keep
270
the counters like srv_conc_n_threads accurate. */
271
srv_conc_force_exit_innodb(trx);
274
if (trx->n_mysql_tables_in_use != 0
275
|| trx->mysql_n_tables_locked != 0) {
277
ut_print_timestamp(stderr);
279
" InnoDB: Error: MySQL is freeing a thd\n"
280
"InnoDB: though trx->n_mysql_tables_in_use is %lu\n"
281
"InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
282
(ulong)trx->n_mysql_tables_in_use,
283
(ulong)trx->mysql_n_tables_locked);
285
trx_print(stderr, trx, 600);
287
ut_print_buf(stderr, trx, sizeof(trx_t));
291
ut_a(trx->magic_n == TRX_MAGIC_N);
293
trx->magic_n = 11112222;
295
ut_a(trx->conc_state == TRX_NOT_STARTED);
297
mutex_free(&(trx->undo_mutex));
299
ut_a(trx->insert_undo == NULL);
300
ut_a(trx->update_undo == NULL);
302
if (trx->undo_no_arr) {
303
trx_undo_arr_free(trx->undo_no_arr);
306
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
307
ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
309
ut_a(trx->wait_lock == NULL);
310
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
312
ut_a(!trx->has_search_latch);
314
ut_a(trx->dict_operation_lock_mode == 0);
316
if (trx->lock_heap) {
317
mem_heap_free(trx->lock_heap);
320
ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0);
322
if (trx->global_read_view_heap) {
323
mem_heap_free(trx->global_read_view_heap);
326
trx->global_read_view = NULL;
328
ut_a(trx->read_view == NULL);
330
ut_a(ib_vector_is_empty(trx->autoinc_locks));
331
/* We allocated a dedicated heap for the vector. */
332
ib_vector_free(trx->autoinc_locks);
337
/********************************************************************//**
338
Frees a transaction object for MySQL. */
343
trx_t* trx) /*!< in, own: trx object */
345
mutex_enter(&kernel_mutex);
347
UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
351
ut_a(trx_n_mysql_transactions > 0);
353
trx_n_mysql_transactions--;
355
mutex_exit(&kernel_mutex);
358
/********************************************************************//**
359
Frees a transaction object of a background operation of the master thread. */
362
trx_free_for_background(
363
/*====================*/
364
trx_t* trx) /*!< in, own: trx object */
366
mutex_enter(&kernel_mutex);
370
mutex_exit(&kernel_mutex);
373
/****************************************************************//**
374
Inserts the trx handle in the trx system trx list in the right position.
375
The list is sorted on the trx id so that the biggest id is at the list
376
start. This function is used at the database startup to insert incomplete
377
transactions to the list. */
380
trx_list_insert_ordered(
381
/*====================*/
382
trx_t* trx) /*!< in: trx handle */
386
ut_ad(mutex_own(&kernel_mutex));
388
trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list);
390
while (trx2 != NULL) {
391
if (ut_dulint_cmp(trx->id, trx2->id) >= 0) {
393
ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1);
396
trx2 = UT_LIST_GET_NEXT(trx_list, trx2);
400
trx2 = UT_LIST_GET_PREV(trx_list, trx2);
403
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
405
UT_LIST_INSERT_AFTER(trx_list, trx_sys->trx_list,
409
UT_LIST_ADD_LAST(trx_list, trx_sys->trx_list, trx);
413
/****************************************************************//**
414
Creates trx objects for transactions and initializes the trx list of
415
trx_sys at database start. Rollback segment and undo log lists must
416
already exist when this function is called, because the lists of
417
transactions to be rolled back or cleaned up are built based on the
421
trx_lists_init_at_db_start(void)
422
/*============================*/
428
UT_LIST_INIT(trx_sys->trx_list);
430
/* Look from the rollback segments if there exist undo logs for
433
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
435
while (rseg != NULL) {
436
undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
438
while (undo != NULL) {
440
trx = trx_create(trx_dummy_sess);
442
trx->is_recovered = TRUE;
443
trx->id = undo->trx_id;
444
trx->xid = undo->xid;
445
trx->insert_undo = undo;
448
if (undo->state != TRX_UNDO_ACTIVE) {
450
/* Prepared transactions are left in
451
the prepared state waiting for a
452
commit or abort decision from MySQL */
454
if (undo->state == TRX_UNDO_PREPARED) {
457
"InnoDB: Transaction "
460
" XA prepared state.\n",
461
TRX_ID_PREP_PRINTF(trx->id));
463
if (srv_force_recovery == 0) {
465
trx->conc_state = TRX_PREPARED;
469
" innodb_force_recovery"
474
trx->conc_state = TRX_ACTIVE;
478
= TRX_COMMITTED_IN_MEMORY;
481
/* We give a dummy value for the trx no;
482
this should have no relevance since purge
483
is not interested in committed transaction
484
numbers, unless they are in the history
485
list, in which case it looks the number
486
from the disk based undo log structure */
490
trx->conc_state = TRX_ACTIVE;
492
/* A running transaction always has the number
493
field inited to ut_dulint_max */
495
trx->no = ut_dulint_max;
498
if (undo->dict_operation) {
499
trx_set_dict_operation(
500
trx, TRX_DICT_OP_TABLE);
501
trx->table_id = undo->table_id;
505
trx->undo_no = ut_dulint_add(undo->top_undo_no,
509
trx_list_insert_ordered(trx);
511
undo = UT_LIST_GET_NEXT(undo_list, undo);
514
undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
516
while (undo != NULL) {
517
trx = trx_get_on_id(undo->trx_id);
520
trx = trx_create(trx_dummy_sess);
522
trx->is_recovered = TRUE;
523
trx->id = undo->trx_id;
524
trx->xid = undo->xid;
526
if (undo->state != TRX_UNDO_ACTIVE) {
528
/* Prepared transactions are left in
529
the prepared state waiting for a
530
commit or abort decision from MySQL */
532
if (undo->state == TRX_UNDO_PREPARED) {
534
"InnoDB: Transaction "
535
TRX_ID_FMT " was in the"
536
" XA prepared state.\n",
540
if (srv_force_recovery == 0) {
547
" innodb_force_recovery"
557
= TRX_COMMITTED_IN_MEMORY;
560
/* We give a dummy value for the trx
565
trx->conc_state = TRX_ACTIVE;
567
/* A running transaction always has
568
the number field inited to
571
trx->no = ut_dulint_max;
575
trx_list_insert_ordered(trx);
577
if (undo->dict_operation) {
578
trx_set_dict_operation(
579
trx, TRX_DICT_OP_TABLE);
580
trx->table_id = undo->table_id;
584
trx->update_undo = undo;
587
&& (ut_dulint_cmp(undo->top_undo_no,
588
trx->undo_no) >= 0)) {
590
trx->undo_no = ut_dulint_add(undo->top_undo_no,
594
undo = UT_LIST_GET_NEXT(undo_list, undo);
597
rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
601
/******************************************************************//**
602
Assigns a rollback segment to a transaction in a round-robin fashion.
603
Skips the SYSTEM rollback segment if another is available.
604
@return assigned rollback segment id */
607
trx_assign_rseg(void)
608
/*=================*/
610
trx_rseg_t* rseg = trx_sys->latest_rseg;
612
ut_ad(mutex_own(&kernel_mutex));
614
/* Get next rseg in a round-robin fashion */
616
rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
619
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
622
/* If it is the SYSTEM rollback segment, and there exist others, skip
625
if ((rseg->id == TRX_SYS_SYSTEM_RSEG_ID)
626
&& (UT_LIST_GET_LEN(trx_sys->rseg_list) > 1)) {
630
trx_sys->latest_rseg = rseg;
635
/****************************************************************//**
636
Starts a new transaction.
642
trx_t* trx, /*!< in: transaction */
643
ulint rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
644
is passed, the system chooses the rollback segment
645
automatically in a round-robin fashion */
649
ut_ad(mutex_own(&kernel_mutex));
650
ut_ad(trx->rseg == NULL);
653
trx->id = ut_dulint_zero;
654
trx->conc_state = TRX_ACTIVE;
655
trx->start_time = time(NULL);
660
ut_ad(trx->conc_state != TRX_ACTIVE);
662
if (rseg_id == ULINT_UNDEFINED) {
664
rseg_id = trx_assign_rseg();
667
rseg = trx_sys_get_nth_rseg(trx_sys, rseg_id);
669
trx->id = trx_sys_get_new_trx_id();
671
/* The initial value for trx->no: ut_dulint_max is used in
672
read_view_open_now: */
674
trx->no = ut_dulint_max;
678
trx->conc_state = TRX_ACTIVE;
679
trx->start_time = time(NULL);
681
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
686
/****************************************************************//**
687
Starts a new transaction.
693
trx_t* trx, /*!< in: transaction */
694
ulint rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
695
is passed, the system chooses the rollback segment
696
automatically in a round-robin fashion */
700
/* Update the info whether we should skip XA steps that eat CPU time
701
For the duration of the transaction trx->support_xa is not reread
702
from thd so any changes in the value take effect in the next
703
transaction. This is to avoid a scenario where some undo
704
generated by a transaction, has XA stuff, and other undo,
705
generated by the same transaction, doesn't. */
706
trx->support_xa = thd_supports_xa(trx->mysql_thd);
708
mutex_enter(&kernel_mutex);
710
ret = trx_start_low(trx, rseg_id);
712
mutex_exit(&kernel_mutex);
717
/****************************************************************//**
718
Commits a transaction. */
721
trx_commit_off_kernel(
722
/*==================*/
723
trx_t* trx) /*!< in: transaction */
725
page_t* update_hdr_page;
731
ut_ad(mutex_own(&kernel_mutex));
733
trx->must_flush_log_later = FALSE;
737
if (trx->insert_undo != NULL || trx->update_undo != NULL) {
739
mutex_exit(&kernel_mutex);
743
/* Change the undo log segment states from TRX_UNDO_ACTIVE
744
to some other state: these modifications to the file data
745
structure define the transaction as committed in the file
746
based world, at the serialization point of the log sequence
747
number lsn obtained below. */
749
mutex_enter(&(rseg->mutex));
751
if (trx->insert_undo != NULL) {
752
trx_undo_set_state_at_finish(
753
rseg, trx, trx->insert_undo, &mtr);
756
undo = trx->update_undo;
759
mutex_enter(&kernel_mutex);
760
trx->no = trx_sys_get_new_trx_no();
762
mutex_exit(&kernel_mutex);
764
/* It is not necessary to obtain trx->undo_mutex here
765
because only a single OS thread is allowed to do the
766
transaction commit for this transaction. */
768
update_hdr_page = trx_undo_set_state_at_finish(
769
rseg, trx, undo, &mtr);
771
/* We have to do the cleanup for the update log while
772
holding the rseg mutex because update log headers
773
have to be put to the history list in the order of
776
trx_undo_update_cleanup(trx, update_hdr_page, &mtr);
779
mutex_exit(&(rseg->mutex));
781
/* Update the latest MySQL binlog name and offset info
782
in trx sys header if MySQL binlogging is on or the database
783
server is a MySQL replication slave */
785
if (trx->mysql_log_file_name
786
&& trx->mysql_log_file_name[0] != '\0') {
787
trx_sys_update_mysql_binlog_offset(
788
trx->mysql_log_file_name,
789
trx->mysql_log_offset,
790
TRX_SYS_MYSQL_LOG_INFO, &mtr);
791
trx->mysql_log_file_name = NULL;
794
/* The following call commits the mini-transaction, making the
795
whole transaction committed in the file-based world, at this
796
log sequence number. The transaction becomes 'durable' when
797
we write the log to disk, but in the logical sense the commit
798
in the file-based data structures (undo logs etc.) happens
801
NOTE that transaction numbers, which are assigned only to
802
transactions with an update undo log, do not necessarily come
803
in exactly the same order as commit lsn's, if the transactions
804
have different rollback segments. To get exactly the same
805
order we should hold the kernel mutex up to this point,
806
adding to to the contention of the kernel mutex. However, if
807
a transaction T2 is able to see modifications made by
808
a transaction T1, T2 will always get a bigger transaction
809
number and a bigger commit lsn than T1. */
816
mutex_enter(&kernel_mutex);
819
ut_ad(trx->conc_state == TRX_ACTIVE
820
|| trx->conc_state == TRX_PREPARED);
821
ut_ad(mutex_own(&kernel_mutex));
823
/* The following assignment makes the transaction committed in memory
824
and makes its changes to data visible to other transactions.
825
NOTE that there is a small discrepancy from the strict formal
826
visibility rules here: a human user of the database can see
827
modifications made by another transaction T even before the necessary
828
log segment has been flushed to the disk. If the database happens to
829
crash before the flush, the user has seen modifications from T which
830
will never be a committed transaction. However, any transaction T2
831
which sees the modifications of the committing transaction T, and
832
which also itself makes modifications to the database, will get an lsn
833
larger than the committing transaction T. In the case where the log
834
flush fails, and T never gets committed, also T2 will never get
837
/*--------------------------------------*/
838
trx->conc_state = TRX_COMMITTED_IN_MEMORY;
839
/*--------------------------------------*/
841
/* If we release kernel_mutex below and we are still doing
842
recovery i.e.: back ground rollback thread is still active
843
then there is a chance that the rollback thread may see
844
this trx as COMMITTED_IN_MEMORY and goes adhead to clean it
845
up calling trx_cleanup_at_db_startup(). This can happen
846
in the case we are committing a trx here that is left in
847
PREPARED state during the crash. Note that commit of the
848
rollback of a PREPARED trx happens in the recovery thread
849
while the rollback of other transactions happen in the
850
background thread. To avoid this race we unconditionally
851
unset the is_recovered flag from the trx. */
853
trx->is_recovered = FALSE;
855
lock_release_off_kernel(trx);
857
if (trx->global_read_view) {
858
read_view_close(trx->global_read_view);
859
mem_heap_empty(trx->global_read_view_heap);
860
trx->global_read_view = NULL;
863
trx->read_view = NULL;
867
mutex_exit(&kernel_mutex);
869
if (trx->insert_undo != NULL) {
871
trx_undo_insert_cleanup(trx);
874
/* NOTE that we could possibly make a group commit more
875
efficient here: call os_thread_yield here to allow also other
876
trxs to come to commit! */
878
/*-------------------------------------*/
880
/* Depending on the my.cnf options, we may now write the log
881
buffer to the log files, making the transaction durable if
882
the OS does not crash. We may also flush the log files to
883
disk, making the transaction durable also at an OS crash or a
886
The idea in InnoDB's group commit is that a group of
887
transactions gather behind a trx doing a physical disk write
888
to log files, and when that physical write has been completed,
889
one of those transactions does a write which commits the whole
890
group. Note that this group commit will only bring benefit if
891
there are > 2 users in the database. Then at least 2 users can
892
gather behind one doing the physical log write to disk.
894
If we are calling trx_commit() under prepare_commit_mutex, we
895
will delay possible log write and flush to a separate function
896
trx_commit_complete_for_mysql(), which is only called when the
897
thread has released the mutex. This is to make the
898
group commit algorithm to work. Otherwise, the prepare_commit
899
mutex would serialize all commits and prevent a group of
900
transactions from gathering. */
902
if (trx->flush_log_later) {
904
trx->must_flush_log_later = TRUE;
905
} else if (srv_flush_log_at_trx_commit == 0) {
907
} else if (srv_flush_log_at_trx_commit == 1) {
908
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
909
/* Write the log but do not flush it to disk */
911
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
914
/* Write the log to the log files AND flush
917
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
919
} else if (srv_flush_log_at_trx_commit == 2) {
921
/* Write the log but do not flush it to disk */
923
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
928
trx->commit_lsn = lsn;
930
/*-------------------------------------*/
932
mutex_enter(&kernel_mutex);
935
/* Free all savepoints */
936
trx_roll_free_all_savepoints(trx);
938
trx->conc_state = TRX_NOT_STARTED;
940
trx->undo_no = ut_dulint_zero;
941
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
942
trx->mysql_query_str = NULL;
944
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
945
ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
947
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
950
/****************************************************************//**
951
Cleans up a transaction at database startup. The cleanup is needed if
952
the transaction already got to the middle of a commit when the database
953
crashed, andf we cannot roll it back. */
956
trx_cleanup_at_db_startup(
957
/*======================*/
958
trx_t* trx) /*!< in: transaction */
960
if (trx->insert_undo != NULL) {
962
trx_undo_insert_cleanup(trx);
965
trx->conc_state = TRX_NOT_STARTED;
967
trx->undo_no = ut_dulint_zero;
968
trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
970
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
973
/********************************************************************//**
974
Assigns a read view for a consistent read query. All the consistent reads
975
within the same transaction will get the same read view, which is created
976
when this function is first called for a new started transaction.
977
@return consistent read view */
980
trx_assign_read_view(
981
/*=================*/
982
trx_t* trx) /*!< in: active transaction */
984
ut_ad(trx->conc_state == TRX_ACTIVE);
986
if (trx->read_view) {
987
return(trx->read_view);
990
mutex_enter(&kernel_mutex);
992
if (!trx->read_view) {
993
trx->read_view = read_view_open_now(
994
trx->id, trx->global_read_view_heap);
995
trx->global_read_view = trx->read_view;
998
mutex_exit(&kernel_mutex);
1000
return(trx->read_view);
1003
/****************************************************************//**
1004
Commits a transaction. NOTE that the kernel mutex is temporarily released. */
1007
trx_handle_commit_sig_off_kernel(
1008
/*=============================*/
1009
trx_t* trx, /*!< in: transaction */
1010
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1011
if the value which is passed in is
1012
a pointer to a NULL pointer, then the
1013
calling function can start running
1014
a new query thread */
1017
trx_sig_t* next_sig;
1019
ut_ad(mutex_own(&kernel_mutex));
1021
trx->que_state = TRX_QUE_COMMITTING;
1023
trx_commit_off_kernel(trx);
1025
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
1027
/* Remove all TRX_SIG_COMMIT signals from the signal queue and send
1028
reply messages to them */
1030
sig = UT_LIST_GET_FIRST(trx->signals);
1032
while (sig != NULL) {
1033
next_sig = UT_LIST_GET_NEXT(signals, sig);
1035
if (sig->type == TRX_SIG_COMMIT) {
1037
trx_sig_reply(sig, next_thr);
1038
trx_sig_remove(trx, sig);
1044
trx->que_state = TRX_QUE_RUNNING;
1047
/***********************************************************//**
1048
The transaction must be in the TRX_QUE_LOCK_WAIT state. Puts it to
1049
the TRX_QUE_RUNNING state and releases query threads which were
1050
waiting for a lock in the wait_thrs list. */
1055
trx_t* trx) /*!< in: transaction */
1059
ut_ad(mutex_own(&kernel_mutex));
1060
ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
1062
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1064
while (thr != NULL) {
1065
que_thr_end_wait_no_next_thr(thr);
1067
UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
1069
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1072
trx->que_state = TRX_QUE_RUNNING;
1075
/***********************************************************//**
1076
Moves the query threads in the lock wait list to the SUSPENDED state and puts
1077
the transaction to the TRX_QUE_RUNNING state. */
1080
trx_lock_wait_to_suspended(
1081
/*=======================*/
1082
trx_t* trx) /*!< in: transaction in the TRX_QUE_LOCK_WAIT state */
1086
ut_ad(mutex_own(&kernel_mutex));
1087
ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
1089
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1091
while (thr != NULL) {
1092
thr->state = QUE_THR_SUSPENDED;
1094
UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
1096
thr = UT_LIST_GET_FIRST(trx->wait_thrs);
1099
trx->que_state = TRX_QUE_RUNNING;
1102
/***********************************************************//**
1103
Moves the query threads in the sig reply wait list of trx to the SUSPENDED
1107
trx_sig_reply_wait_to_suspended(
1108
/*============================*/
1109
trx_t* trx) /*!< in: transaction */
1114
ut_ad(mutex_own(&kernel_mutex));
1116
sig = UT_LIST_GET_FIRST(trx->reply_signals);
1118
while (sig != NULL) {
1119
thr = sig->receiver;
1121
ut_ad(thr->state == QUE_THR_SIG_REPLY_WAIT);
1123
thr->state = QUE_THR_SUSPENDED;
1125
sig->receiver = NULL;
1127
UT_LIST_REMOVE(reply_signals, trx->reply_signals, sig);
1129
sig = UT_LIST_GET_FIRST(trx->reply_signals);
1133
/*****************************************************************//**
1134
Checks the compatibility of a new signal with the other signals in the
1136
@return TRUE if the signal can be queued */
1139
trx_sig_is_compatible(
1140
/*==================*/
1141
trx_t* trx, /*!< in: trx handle */
1142
ulint type, /*!< in: signal type */
1143
ulint sender) /*!< in: TRX_SIG_SELF or TRX_SIG_OTHER_SESS */
1147
ut_ad(mutex_own(&kernel_mutex));
1149
if (UT_LIST_GET_LEN(trx->signals) == 0) {
1154
if (sender == TRX_SIG_SELF) {
1155
if (type == TRX_SIG_ERROR_OCCURRED) {
1159
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1167
ut_ad(sender == TRX_SIG_OTHER_SESS);
1169
sig = UT_LIST_GET_FIRST(trx->signals);
1171
if (type == TRX_SIG_COMMIT) {
1172
while (sig != NULL) {
1174
if (sig->type == TRX_SIG_TOTAL_ROLLBACK) {
1179
sig = UT_LIST_GET_NEXT(signals, sig);
1184
} else if (type == TRX_SIG_TOTAL_ROLLBACK) {
1185
while (sig != NULL) {
1187
if (sig->type == TRX_SIG_COMMIT) {
1192
sig = UT_LIST_GET_NEXT(signals, sig);
1197
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1207
/****************************************************************//**
1208
Sends a signal to a trx object. */
1213
trx_t* trx, /*!< in: trx handle */
1214
ulint type, /*!< in: signal type */
1215
ulint sender, /*!< in: TRX_SIG_SELF or
1216
TRX_SIG_OTHER_SESS */
1217
que_thr_t* receiver_thr, /*!< in: query thread which wants the
1218
reply, or NULL; if type is
1219
TRX_SIG_END_WAIT, this must be NULL */
1220
trx_savept_t* savept, /*!< in: possible rollback savepoint, or
1222
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1223
if the value which is passed in is
1224
a pointer to a NULL pointer, then the
1225
calling function can start running
1226
a new query thread; if the parameter
1227
is NULL, it is ignored */
1230
trx_t* receiver_trx;
1233
ut_ad(mutex_own(&kernel_mutex));
1235
if (!trx_sig_is_compatible(trx, type, sender)) {
1236
/* The signal is not compatible with the other signals in
1242
/* Queue the signal object */
1244
if (UT_LIST_GET_LEN(trx->signals) == 0) {
1246
/* The signal list is empty: the 'sig' slot must be unused
1247
(we improve performance a bit by avoiding mem_alloc) */
1250
/* It might be that the 'sig' slot is unused also in this
1251
case, but we choose the easy way of using mem_alloc */
1253
sig = mem_alloc(sizeof(trx_sig_t));
1256
UT_LIST_ADD_LAST(signals, trx->signals, sig);
1259
sig->sender = sender;
1260
sig->receiver = receiver_thr;
1263
sig->savept = *savept;
1267
receiver_trx = thr_get_trx(receiver_thr);
1269
UT_LIST_ADD_LAST(reply_signals, receiver_trx->reply_signals,
1273
if (trx->sess->state == SESS_ERROR) {
1275
trx_sig_reply_wait_to_suspended(trx);
1278
if ((sender != TRX_SIG_SELF) || (type == TRX_SIG_BREAK_EXECUTION)) {
1282
/* If there were no other signals ahead in the queue, try to start
1283
handling of the signal */
1285
if (UT_LIST_GET_FIRST(trx->signals) == sig) {
1287
trx_sig_start_handle(trx, next_thr);
1291
/****************************************************************//**
1292
Ends signal handling. If the session is in the error state, and
1293
trx->graph_before_signal_handling != NULL, then returns control to the error
1294
handling routine of the graph (currently just returns the control to the
1295
graph root which then will send an error message to the client). */
1298
trx_end_signal_handling(
1299
/*====================*/
1300
trx_t* trx) /*!< in: trx */
1302
ut_ad(mutex_own(&kernel_mutex));
1303
ut_ad(trx->handling_signals == TRUE);
1305
trx->handling_signals = FALSE;
1307
trx->graph = trx->graph_before_signal_handling;
1309
if (trx->graph && (trx->sess->state == SESS_ERROR)) {
1311
que_fork_error_handle(trx, trx->graph);
1315
/****************************************************************//**
1316
Starts handling of a trx signal. */
1319
trx_sig_start_handle(
1320
/*=================*/
1321
trx_t* trx, /*!< in: trx handle */
1322
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1323
if the value which is passed in is
1324
a pointer to a NULL pointer, then the
1325
calling function can start running
1326
a new query thread; if the parameter
1327
is NULL, it is ignored */
1332
/* We loop in this function body as long as there are queued signals
1333
we can process immediately */
1336
ut_ad(mutex_own(&kernel_mutex));
1338
if (trx->handling_signals && (UT_LIST_GET_LEN(trx->signals) == 0)) {
1340
trx_end_signal_handling(trx);
1345
if (trx->conc_state == TRX_NOT_STARTED) {
1347
trx_start_low(trx, ULINT_UNDEFINED);
1350
/* If the trx is in a lock wait state, moves the waiting query threads
1351
to the suspended state */
1353
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
1355
trx_lock_wait_to_suspended(trx);
1358
/* If the session is in the error state and this trx has threads
1359
waiting for reply from signals, moves these threads to the suspended
1360
state, canceling wait reservations; note that if the transaction has
1361
sent a commit or rollback signal to itself, and its session is not in
1362
the error state, then nothing is done here. */
1364
if (trx->sess->state == SESS_ERROR) {
1365
trx_sig_reply_wait_to_suspended(trx);
1368
/* If there are no running query threads, we can start processing of a
1369
signal, otherwise we have to wait until all query threads of this
1370
transaction are aware of the arrival of the signal. */
1372
if (trx->n_active_thrs > 0) {
1377
if (trx->handling_signals == FALSE) {
1378
trx->graph_before_signal_handling = trx->graph;
1380
trx->handling_signals = TRUE;
1383
sig = UT_LIST_GET_FIRST(trx->signals);
1386
if (type == TRX_SIG_COMMIT) {
1388
trx_handle_commit_sig_off_kernel(trx, next_thr);
1390
} else if ((type == TRX_SIG_TOTAL_ROLLBACK)
1391
|| (type == TRX_SIG_ROLLBACK_TO_SAVEPT)) {
1393
trx_rollback(trx, sig, next_thr);
1395
/* No further signals can be handled until the rollback
1396
completes, therefore we return */
1400
} else if (type == TRX_SIG_ERROR_OCCURRED) {
1402
trx_rollback(trx, sig, next_thr);
1404
/* No further signals can be handled until the rollback
1405
completes, therefore we return */
1409
} else if (type == TRX_SIG_BREAK_EXECUTION) {
1411
trx_sig_reply(sig, next_thr);
1412
trx_sig_remove(trx, sig);
1420
/****************************************************************//**
1421
Send the reply message when a signal in the queue of the trx has been
1427
trx_sig_t* sig, /*!< in: signal */
1428
que_thr_t** next_thr) /*!< in/out: next query thread to run;
1429
if the value which is passed in is
1430
a pointer to a NULL pointer, then the
1431
calling function can start running
1432
a new query thread */
1434
trx_t* receiver_trx;
1437
ut_ad(mutex_own(&kernel_mutex));
1439
if (sig->receiver != NULL) {
1440
ut_ad((sig->receiver)->state == QUE_THR_SIG_REPLY_WAIT);
1442
receiver_trx = thr_get_trx(sig->receiver);
1444
UT_LIST_REMOVE(reply_signals, receiver_trx->reply_signals,
1446
ut_ad(receiver_trx->sess->state != SESS_ERROR);
1448
que_thr_end_wait(sig->receiver, next_thr);
1450
sig->receiver = NULL;
1455
/****************************************************************//**
1456
Removes a signal object from the trx signal queue. */
1461
trx_t* trx, /*!< in: trx handle */
1462
trx_sig_t* sig) /*!< in, own: signal */
1465
ut_ad(mutex_own(&kernel_mutex));
1467
ut_ad(sig->receiver == NULL);
1469
UT_LIST_REMOVE(signals, trx->signals, sig);
1470
sig->type = 0; /* reset the field to catch possible bugs */
1472
if (sig != &(trx->sig)) {
1477
/*********************************************************************//**
1478
Creates a commit command node struct.
1479
@return own: commit node struct */
1484
mem_heap_t* heap) /*!< in: mem heap where created */
1486
commit_node_t* node;
1488
node = mem_heap_alloc(heap, sizeof(commit_node_t));
1489
node->common.type = QUE_NODE_COMMIT;
1490
node->state = COMMIT_NODE_SEND;
1495
/***********************************************************//**
1496
Performs an execution step for a commit type node in a query graph.
1497
@return query thread to run next, or NULL */
1502
que_thr_t* thr) /*!< in: query thread */
1504
commit_node_t* node;
1505
que_thr_t* next_thr;
1507
node = thr->run_node;
1509
ut_ad(que_node_get_type(node) == QUE_NODE_COMMIT);
1511
if (thr->prev_node == que_node_get_parent(node)) {
1512
node->state = COMMIT_NODE_SEND;
1515
if (node->state == COMMIT_NODE_SEND) {
1516
mutex_enter(&kernel_mutex);
1518
node->state = COMMIT_NODE_WAIT;
1522
thr->state = QUE_THR_SIG_REPLY_WAIT;
1524
/* Send the commit signal to the transaction */
1526
trx_sig_send(thr_get_trx(thr), TRX_SIG_COMMIT, TRX_SIG_SELF,
1527
thr, NULL, &next_thr);
1529
mutex_exit(&kernel_mutex);
1534
ut_ad(node->state == COMMIT_NODE_WAIT);
1536
node->state = COMMIT_NODE_SEND;
1538
thr->run_node = que_node_get_parent(node);
1543
/**********************************************************************//**
1544
Does the transaction commit for MySQL.
1545
@return DB_SUCCESS or error number */
1548
trx_commit_for_mysql(
1549
/*=================*/
1550
trx_t* trx) /*!< in: trx handle */
1552
/* Because we do not do the commit by sending an Innobase
1553
sig to the transaction, we must here make sure that trx has been
1558
trx_start_if_not_started(trx);
1560
trx->op_info = "committing";
1562
mutex_enter(&kernel_mutex);
1564
trx_commit_off_kernel(trx);
1566
mutex_exit(&kernel_mutex);
1573
/**********************************************************************//**
1574
If required, flushes the log to disk if we called trx_commit_for_mysql()
1575
with trx->flush_log_later == TRUE.
1576
@return 0 or error number */
1579
trx_commit_complete_for_mysql(
1580
/*==========================*/
1581
trx_t* trx) /*!< in: trx handle */
1583
ib_uint64_t lsn = trx->commit_lsn;
1587
trx->op_info = "flushing log";
1589
if (!trx->must_flush_log_later) {
1591
} else if (srv_flush_log_at_trx_commit == 0) {
1593
} else if (srv_flush_log_at_trx_commit == 1) {
1594
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
1595
/* Write the log but do not flush it to disk */
1597
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1599
/* Write the log to the log files AND flush them to
1602
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
1604
} else if (srv_flush_log_at_trx_commit == 2) {
1606
/* Write the log but do not flush it to disk */
1608
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1613
trx->must_flush_log_later = FALSE;
1620
/**********************************************************************//**
1621
Marks the latest SQL statement ended. */
1624
trx_mark_sql_stat_end(
1625
/*==================*/
1626
trx_t* trx) /*!< in: trx handle */
1630
if (trx->conc_state == TRX_NOT_STARTED) {
1631
trx->undo_no = ut_dulint_zero;
1634
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
1637
/**********************************************************************//**
1638
Prints info about a transaction to the given file. The caller must own the
1639
kernel mutex and must have called
1640
innobase_mysql_prepare_print_arbitrary_thd(), unless he knows that MySQL
1641
or InnoDB cannot meanwhile change the info printed here. */
1646
FILE* f, /*!< in: output stream */
1647
trx_t* trx, /*!< in: transaction */
1648
ulint max_query_len) /*!< in: max query length to print, or 0 to
1649
use the default max length */
1653
fprintf(f, "TRANSACTION " TRX_ID_FMT, TRX_ID_PREP_PRINTF(trx->id));
1655
switch (trx->conc_state) {
1656
case TRX_NOT_STARTED:
1657
fputs(", not started", f);
1660
fprintf(f, ", ACTIVE %lu sec",
1661
(ulong)difftime(time(NULL), trx->start_time));
1664
fprintf(f, ", ACTIVE (PREPARED) %lu sec",
1665
(ulong)difftime(time(NULL), trx->start_time));
1667
case TRX_COMMITTED_IN_MEMORY:
1668
fputs(", COMMITTED IN MEMORY", f);
1671
fprintf(f, " state %lu", (ulong) trx->conc_state);
1675
fprintf(f, ", process no %lu", trx->mysql_process_no);
1677
fprintf(f, ", OS thread id %lu",
1678
(ulong) os_thread_pf(trx->mysql_thread_id));
1680
if (*trx->op_info) {
1682
fputs(trx->op_info, f);
1685
if (trx->is_recovered) {
1686
fputs(" recovered trx", f);
1689
if (trx->is_purge) {
1690
fputs(" purge trx", f);
1693
if (trx->declared_to_be_inside_innodb) {
1694
fprintf(f, ", thread declared inside InnoDB %lu",
1695
(ulong) trx->n_tickets_to_enter_innodb);
1700
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
1701
fprintf(f, "mysql tables in use %lu, locked %lu\n",
1702
(ulong) trx->n_mysql_tables_in_use,
1703
(ulong) trx->mysql_n_tables_locked);
1708
switch (trx->que_state) {
1709
case TRX_QUE_RUNNING:
1710
newline = FALSE; break;
1711
case TRX_QUE_LOCK_WAIT:
1712
fputs("LOCK WAIT ", f); break;
1713
case TRX_QUE_ROLLING_BACK:
1714
fputs("ROLLING BACK ", f); break;
1715
case TRX_QUE_COMMITTING:
1716
fputs("COMMITTING ", f); break;
1718
fprintf(f, "que state %lu ", (ulong) trx->que_state);
1721
if (0 < UT_LIST_GET_LEN(trx->trx_locks)
1722
|| mem_heap_get_size(trx->lock_heap) > 400) {
1725
fprintf(f, "%lu lock struct(s), heap size %lu,"
1727
(ulong) UT_LIST_GET_LEN(trx->trx_locks),
1728
(ulong) mem_heap_get_size(trx->lock_heap),
1729
(ulong) lock_number_of_rows_locked(trx));
1732
if (trx->has_search_latch) {
1734
fputs(", holds adaptive hash latch", f);
1737
if (!ut_dulint_is_zero(trx->undo_no)) {
1739
fprintf(f, ", undo log entries %lu",
1740
(ulong) ut_dulint_get_low(trx->undo_no));
1747
if (trx->mysql_thd != NULL) {
1748
innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
1752
/*******************************************************************//**
1753
Compares the "weight" (or size) of two transactions. Transactions that
1754
have edited non-transactional tables are considered heavier than ones
1756
@return <0, 0 or >0; similar to strcmp(3) */
1761
const trx_t* a, /*!< in: the first transaction to be compared */
1762
const trx_t* b) /*!< in: the second transaction to be compared */
1764
ibool a_notrans_edit;
1765
ibool b_notrans_edit;
1767
/* If mysql_thd is NULL for a transaction we assume that it has
1768
not edited non-transactional tables. */
1770
a_notrans_edit = a->mysql_thd != NULL
1771
&& thd_has_edited_nontrans_tables(a->mysql_thd);
1773
b_notrans_edit = b->mysql_thd != NULL
1774
&& thd_has_edited_nontrans_tables(b->mysql_thd);
1776
if (a_notrans_edit && !b_notrans_edit) {
1781
if (!a_notrans_edit && b_notrans_edit) {
1786
/* Either both had edited non-transactional tables or both had
1787
not, we fall back to comparing the number of altered/locked
1792
"%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n",
1794
ut_conv_dulint_to_longlong(a->undo_no),
1795
UT_LIST_GET_LEN(a->trx_locks),
1796
ut_conv_dulint_to_longlong(b->undo_no),
1797
UT_LIST_GET_LEN(b->trx_locks));
1800
return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b)));
1803
/****************************************************************//**
1804
Prepares a transaction. */
1807
trx_prepare_off_kernel(
1808
/*===================*/
1809
trx_t* trx) /*!< in: transaction */
1811
page_t* update_hdr_page;
1813
ib_uint64_t lsn = 0;
1816
ut_ad(mutex_own(&kernel_mutex));
1820
if (trx->insert_undo != NULL || trx->update_undo != NULL) {
1822
mutex_exit(&kernel_mutex);
1826
/* Change the undo log segment states from TRX_UNDO_ACTIVE
1827
to TRX_UNDO_PREPARED: these modifications to the file data
1828
structure define the transaction as prepared in the
1829
file-based world, at the serialization point of lsn. */
1831
mutex_enter(&(rseg->mutex));
1833
if (trx->insert_undo != NULL) {
1835
/* It is not necessary to obtain trx->undo_mutex here
1836
because only a single OS thread is allowed to do the
1837
transaction prepare for this transaction. */
1839
trx_undo_set_state_at_prepare(trx, trx->insert_undo,
1843
if (trx->update_undo) {
1844
update_hdr_page = trx_undo_set_state_at_prepare(
1845
trx, trx->update_undo, &mtr);
1848
mutex_exit(&(rseg->mutex));
1851
mtr_commit(&mtr); /* This mtr commit makes the
1852
transaction prepared in the file-based
1857
mutex_enter(&kernel_mutex);
1860
ut_ad(mutex_own(&kernel_mutex));
1862
/*--------------------------------------*/
1863
trx->conc_state = TRX_PREPARED;
1864
/*--------------------------------------*/
1867
/* Depending on the my.cnf options, we may now write the log
1868
buffer to the log files, making the prepared state of the
1869
transaction durable if the OS does not crash. We may also
1870
flush the log files to disk, making the prepared state of the
1871
transaction durable also at an OS crash or a power outage.
1873
The idea in InnoDB's group prepare is that a group of
1874
transactions gather behind a trx doing a physical disk write
1875
to log files, and when that physical write has been completed,
1876
one of those transactions does a write which prepares the whole
1877
group. Note that this group prepare will only bring benefit if
1878
there are > 2 users in the database. Then at least 2 users can
1879
gather behind one doing the physical log write to disk.
1881
TODO: find out if MySQL holds some mutex when calling this.
1882
That would spoil our group prepare algorithm. */
1884
mutex_exit(&kernel_mutex);
1886
if (srv_flush_log_at_trx_commit == 0) {
1888
} else if (srv_flush_log_at_trx_commit == 1) {
1889
if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
1890
/* Write the log but do not flush it to disk */
1892
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
1895
/* Write the log to the log files AND flush
1898
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
1900
} else if (srv_flush_log_at_trx_commit == 2) {
1902
/* Write the log but do not flush it to disk */
1904
log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1909
mutex_enter(&kernel_mutex);
1913
/**********************************************************************//**
1914
Does the transaction prepare for MySQL.
1915
@return 0 or error number */
1918
trx_prepare_for_mysql(
1919
/*==================*/
1920
trx_t* trx) /*!< in: trx handle */
1922
/* Because we do not do the prepare by sending an Innobase
1923
sig to the transaction, we must here make sure that trx has been
1928
trx->op_info = "preparing";
1930
trx_start_if_not_started(trx);
1932
mutex_enter(&kernel_mutex);
1934
trx_prepare_off_kernel(trx);
1936
mutex_exit(&kernel_mutex);
1943
/**********************************************************************//**
1944
This function is used to find number of prepared transactions and
1945
their transaction objects for a recovery.
1946
@return number of prepared transactions stored in xid_list */
1949
trx_recover_for_mysql(
1950
/*==================*/
1951
XID* xid_list, /*!< in/out: prepared transactions */
1952
ulint len) /*!< in: number of slots in xid_list */
1960
/* We should set those transactions which are in the prepared state
1963
mutex_enter(&kernel_mutex);
1965
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
1968
if (trx->conc_state == TRX_PREPARED) {
1969
xid_list[count] = trx->xid;
1972
ut_print_timestamp(stderr);
1974
" InnoDB: Starting recovery for"
1975
" XA transactions...\n");
1978
ut_print_timestamp(stderr);
1980
" InnoDB: Transaction " TRX_ID_FMT " in"
1981
" prepared state after recovery\n",
1982
TRX_ID_PREP_PRINTF(trx->id));
1984
ut_print_timestamp(stderr);
1986
" InnoDB: Transaction contains changes"
1988
(ulong) ut_conv_dulint_to_longlong(
1998
trx = UT_LIST_GET_NEXT(trx_list, trx);
2001
mutex_exit(&kernel_mutex);
2004
ut_print_timestamp(stderr);
2006
" InnoDB: %lu transactions in prepared state"
2007
" after recovery\n",
2011
return ((int) count);
2014
/*******************************************************************//**
2015
This function is used to find one X/Open XA distributed transaction
2016
which is in the prepared state
2017
@return trx or NULL */
2022
XID* xid) /*!< in: X/Open XA transaction identification */
2031
mutex_enter(&kernel_mutex);
2033
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
2036
/* Compare two X/Open XA transaction id's: their
2037
length should be the same and binary comparison
2038
of gtrid_lenght+bqual_length bytes should be
2041
if (xid->gtrid_length == trx->xid.gtrid_length
2042
&& xid->bqual_length == trx->xid.bqual_length
2043
&& memcmp(xid->data, trx->xid.data,
2044
xid->gtrid_length + xid->bqual_length) == 0) {
2048
trx = UT_LIST_GET_NEXT(trx_list, trx);
2051
mutex_exit(&kernel_mutex);
2054
if (trx->conc_state != TRX_PREPARED) {