~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/trx/trx0trx.c

  • Committer: Stewart Smith
  • Date: 2010-11-03 03:30:27 UTC
  • mto: (1902.1.1 build) (1910.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1903.
  • Revision ID: stewart@flamingspork.com-20101103033027-lskb6gxwwforfz71
fix docs warning: underline/overline too short for replace.rst

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
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.
 
8
 
 
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.
 
12
 
 
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
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file trx/trx0trx.c
 
21
The transaction
 
22
 
 
23
Created 3/26/1996 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#include "trx0trx.h"
 
27
 
 
28
#ifdef UNIV_NONINL
 
29
#include "trx0trx.ic"
 
30
#endif
 
31
 
 
32
#include "trx0undo.h"
 
33
#include "trx0rseg.h"
 
34
#include "log0log.h"
 
35
#include "que0que.h"
 
36
#include "lock0lock.h"
 
37
#include "trx0roll.h"
 
38
#include "usr0sess.h"
 
39
#include "read0read.h"
 
40
#include "srv0srv.h"
 
41
#include "thr0loc.h"
 
42
#include "btr0sea.h"
 
43
#include "os0proc.h"
 
44
#include "trx0xa.h"
 
45
#include "ha_prototypes.h"
 
46
 
 
47
/** Dummy session used currently in MySQL interface */
 
48
UNIV_INTERN sess_t*             trx_dummy_sess = NULL;
 
49
 
 
50
/** Number of transactions currently allocated for MySQL: protected by
 
51
the kernel mutex */
 
52
UNIV_INTERN ulint       trx_n_mysql_transactions = 0;
 
53
 
 
54
/*************************************************************//**
 
55
Set detailed error message for the transaction. */
 
56
UNIV_INTERN
 
57
void
 
58
trx_set_detailed_error(
 
59
/*===================*/
 
60
        trx_t*          trx,    /*!< in: transaction struct */
 
61
        const char*     msg)    /*!< in: detailed error message */
 
62
{
 
63
        ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));
 
64
}
 
65
 
 
66
/*************************************************************//**
 
67
Set detailed error message for the transaction from a file. Note that the
 
68
file is rewinded before reading from it. */
 
69
UNIV_INTERN
 
70
void
 
71
trx_set_detailed_error_from_file(
 
72
/*=============================*/
 
73
        trx_t*  trx,    /*!< in: transaction struct */
 
74
        FILE*   file)   /*!< in: file to read message from */
 
75
{
 
76
        os_file_read_string(file, trx->detailed_error,
 
77
                            sizeof(trx->detailed_error));
 
78
}
 
79
 
 
80
/****************************************************************//**
 
81
Creates and initializes a transaction object.
 
82
@return own: the transaction */
 
83
UNIV_INTERN
 
84
trx_t*
 
85
trx_create(
 
86
/*=======*/
 
87
        sess_t* sess)   /*!< in: session */
 
88
{
 
89
        trx_t*  trx;
 
90
 
 
91
        ut_ad(mutex_own(&kernel_mutex));
 
92
        ut_ad(sess);
 
93
 
 
94
        trx = mem_alloc(sizeof(trx_t));
 
95
 
 
96
        trx->magic_n = TRX_MAGIC_N;
 
97
 
 
98
        trx->op_info = "";
 
99
 
 
100
        trx->is_purge = 0;
 
101
        trx->is_recovered = 0;
 
102
        trx->conc_state = TRX_NOT_STARTED;
 
103
        trx->start_time = time(NULL);
 
104
 
 
105
        trx->isolation_level = TRX_ISO_REPEATABLE_READ;
 
106
 
 
107
        trx->id = ut_dulint_zero;
 
108
        trx->no = ut_dulint_max;
 
109
 
 
110
        trx->support_xa = TRUE;
 
111
 
 
112
        trx->check_foreigns = TRUE;
 
113
        trx->check_unique_secondary = TRUE;
 
114
 
 
115
        trx->flush_log_later = FALSE;
 
116
        trx->must_flush_log_later = FALSE;
 
117
 
 
118
        trx->dict_operation = TRX_DICT_OP_NONE;
 
119
        trx->table_id = ut_dulint_zero;
 
120
 
 
121
        trx->mysql_thd = NULL;
 
122
        trx->mysql_query_str = NULL;
 
123
        trx->duplicates = 0;
 
124
 
 
125
        trx->mysql_n_tables_locked = 0;
 
126
 
 
127
        trx->mysql_log_file_name = NULL;
 
128
        trx->mysql_log_offset = 0;
 
129
 
 
130
        mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
 
131
 
 
132
        trx->rseg = NULL;
 
133
 
 
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;
 
139
 
 
140
        trx->error_state = DB_SUCCESS;
 
141
        trx->error_key_num = 0;
 
142
        trx->detailed_error[0] = '\0';
 
143
 
 
144
        trx->sess = sess;
 
145
        trx->que_state = TRX_QUE_RUNNING;
 
146
        trx->n_active_thrs = 0;
 
147
 
 
148
        trx->handling_signals = FALSE;
 
149
 
 
150
        UT_LIST_INIT(trx->signals);
 
151
        UT_LIST_INIT(trx->reply_signals);
 
152
 
 
153
        trx->graph = NULL;
 
154
 
 
155
        trx->wait_lock = NULL;
 
156
        trx->was_chosen_as_deadlock_victim = FALSE;
 
157
        UT_LIST_INIT(trx->wait_thrs);
 
158
 
 
159
        trx->lock_heap = mem_heap_create_in_buffer(256);
 
160
        UT_LIST_INIT(trx->trx_locks);
 
161
 
 
162
        UT_LIST_INIT(trx->trx_savepoints);
 
163
 
 
164
        trx->dict_operation_lock_mode = 0;
 
165
        trx->has_search_latch = FALSE;
 
166
        trx->search_latch_timeout = BTR_SEA_TIMEOUT;
 
167
 
 
168
        trx->declared_to_be_inside_innodb = FALSE;
 
169
        trx->n_tickets_to_enter_innodb = 0;
 
170
 
 
171
        trx->global_read_view_heap = mem_heap_create(256);
 
172
        trx->global_read_view = NULL;
 
173
        trx->read_view = NULL;
 
174
 
 
175
        /* Set X/Open XA transaction identification to NULL */
 
176
        memset(&trx->xid, 0, sizeof(trx->xid));
 
177
        trx->xid.formatID = -1;
 
178
 
 
179
        trx->n_autoinc_rows = 0;
 
180
 
 
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);
 
184
 
 
185
        return(trx);
 
186
}
 
187
 
 
188
/********************************************************************//**
 
189
Creates a transaction object for MySQL.
 
190
@return own: transaction object */
 
191
UNIV_INTERN
 
192
trx_t*
 
193
trx_allocate_for_mysql(void)
 
194
/*========================*/
 
195
{
 
196
        trx_t*  trx;
 
197
 
 
198
        mutex_enter(&kernel_mutex);
 
199
 
 
200
        trx = trx_create(trx_dummy_sess);
 
201
 
 
202
        trx_n_mysql_transactions++;
 
203
 
 
204
        UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
 
205
 
 
206
        mutex_exit(&kernel_mutex);
 
207
 
 
208
        trx->mysql_thread_id = os_thread_get_curr_id();
 
209
 
 
210
        trx->mysql_process_no = os_proc_get_number();
 
211
 
 
212
        return(trx);
 
213
}
 
214
 
 
215
/********************************************************************//**
 
216
Creates a transaction object for background operations by the master thread.
 
217
@return own: transaction object */
 
218
UNIV_INTERN
 
219
trx_t*
 
220
trx_allocate_for_background(void)
 
221
/*=============================*/
 
222
{
 
223
        trx_t*  trx;
 
224
 
 
225
        mutex_enter(&kernel_mutex);
 
226
 
 
227
        trx = trx_create(trx_dummy_sess);
 
228
 
 
229
        mutex_exit(&kernel_mutex);
 
230
 
 
231
        return(trx);
 
232
}
 
233
 
 
234
/********************************************************************//**
 
235
Releases the search latch if trx has reserved it. */
 
236
UNIV_INTERN
 
237
void
 
238
trx_search_latch_release_if_reserved(
 
239
/*=================================*/
 
240
        trx_t*     trx) /*!< in: transaction */
 
241
{
 
242
        if (trx->has_search_latch) {
 
243
                rw_lock_s_unlock(&btr_search_latch);
 
244
 
 
245
                trx->has_search_latch = FALSE;
 
246
        }
 
247
}
 
248
 
 
249
/********************************************************************//**
 
250
Frees a transaction object. */
 
251
UNIV_INTERN
 
252
void
 
253
trx_free(
 
254
/*=====*/
 
255
        trx_t*  trx)    /*!< in, own: trx object */
 
256
{
 
257
        ut_ad(mutex_own(&kernel_mutex));
 
258
 
 
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);
 
265
                putc('\n', stderr);
 
266
 
 
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);
 
270
        }
 
271
 
 
272
        if (trx->mysql_n_tables_locked != 0) {
 
273
 
 
274
                ut_print_timestamp(stderr);
 
275
                fprintf(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);
 
279
 
 
280
                trx_print(stderr, trx, 600);
 
281
 
 
282
                ut_print_buf(stderr, trx, sizeof(trx_t));
 
283
                putc('\n', stderr);
 
284
        }
 
285
 
 
286
        ut_a(trx->magic_n == TRX_MAGIC_N);
 
287
 
 
288
        trx->magic_n = 11112222;
 
289
 
 
290
        ut_a(trx->conc_state == TRX_NOT_STARTED);
 
291
 
 
292
        mutex_free(&(trx->undo_mutex));
 
293
 
 
294
        ut_a(trx->insert_undo == NULL);
 
295
        ut_a(trx->update_undo == NULL);
 
296
 
 
297
        if (trx->undo_no_arr) {
 
298
                trx_undo_arr_free(trx->undo_no_arr);
 
299
        }
 
300
 
 
301
        ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
 
302
        ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
 
303
 
 
304
        ut_a(trx->wait_lock == NULL);
 
305
        ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
306
 
 
307
        ut_a(!trx->has_search_latch);
 
308
 
 
309
        ut_a(trx->dict_operation_lock_mode == 0);
 
310
 
 
311
        if (trx->lock_heap) {
 
312
                mem_heap_free(trx->lock_heap);
 
313
        }
 
314
 
 
315
        ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0);
 
316
 
 
317
        if (trx->global_read_view_heap) {
 
318
                mem_heap_free(trx->global_read_view_heap);
 
319
        }
 
320
 
 
321
        trx->global_read_view = NULL;
 
322
 
 
323
        ut_a(trx->read_view == NULL);
 
324
 
 
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);
 
328
 
 
329
        mem_free(trx);
 
330
}
 
331
 
 
332
/********************************************************************//**
 
333
Frees a transaction object for MySQL. */
 
334
UNIV_INTERN
 
335
void
 
336
trx_free_for_mysql(
 
337
/*===============*/
 
338
        trx_t*  trx)    /*!< in, own: trx object */
 
339
{
 
340
        mutex_enter(&kernel_mutex);
 
341
 
 
342
        UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
 
343
 
 
344
        trx_free(trx);
 
345
 
 
346
        ut_a(trx_n_mysql_transactions > 0);
 
347
 
 
348
        trx_n_mysql_transactions--;
 
349
 
 
350
        mutex_exit(&kernel_mutex);
 
351
}
 
352
 
 
353
/********************************************************************//**
 
354
Frees a transaction object of a background operation of the master thread. */
 
355
UNIV_INTERN
 
356
void
 
357
trx_free_for_background(
 
358
/*====================*/
 
359
        trx_t*  trx)    /*!< in, own: trx object */
 
360
{
 
361
        mutex_enter(&kernel_mutex);
 
362
 
 
363
        trx_free(trx);
 
364
 
 
365
        mutex_exit(&kernel_mutex);
 
366
}
 
367
 
 
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. */
 
373
static
 
374
void
 
375
trx_list_insert_ordered(
 
376
/*====================*/
 
377
        trx_t*  trx)    /*!< in: trx handle */
 
378
{
 
379
        trx_t*  trx2;
 
380
 
 
381
        ut_ad(mutex_own(&kernel_mutex));
 
382
 
 
383
        trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
384
 
 
385
        while (trx2 != NULL) {
 
386
                if (ut_dulint_cmp(trx->id, trx2->id) >= 0) {
 
387
 
 
388
                        ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1);
 
389
                        break;
 
390
                }
 
391
                trx2 = UT_LIST_GET_NEXT(trx_list, trx2);
 
392
        }
 
393
 
 
394
        if (trx2 != NULL) {
 
395
                trx2 = UT_LIST_GET_PREV(trx_list, trx2);
 
396
 
 
397
                if (trx2 == NULL) {
 
398
                        UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
 
399
                } else {
 
400
                        UT_LIST_INSERT_AFTER(trx_list, trx_sys->trx_list,
 
401
                                             trx2, trx);
 
402
                }
 
403
        } else {
 
404
                UT_LIST_ADD_LAST(trx_list, trx_sys->trx_list, trx);
 
405
        }
 
406
}
 
407
 
 
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
 
413
undo log lists. */
 
414
UNIV_INTERN
 
415
void
 
416
trx_lists_init_at_db_start(void)
 
417
/*============================*/
 
418
{
 
419
        trx_rseg_t*     rseg;
 
420
        trx_undo_t*     undo;
 
421
        trx_t*          trx;
 
422
 
 
423
        UT_LIST_INIT(trx_sys->trx_list);
 
424
 
 
425
        /* Look from the rollback segments if there exist undo logs for
 
426
        transactions */
 
427
 
 
428
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
429
 
 
430
        while (rseg != NULL) {
 
431
                undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
 
432
 
 
433
                while (undo != NULL) {
 
434
 
 
435
                        trx = trx_create(trx_dummy_sess);
 
436
 
 
437
                        trx->is_recovered = TRUE;
 
438
                        trx->id = undo->trx_id;
 
439
                        trx->xid = undo->xid;
 
440
                        trx->insert_undo = undo;
 
441
                        trx->rseg = rseg;
 
442
 
 
443
                        if (undo->state != TRX_UNDO_ACTIVE) {
 
444
 
 
445
                                /* Prepared transactions are left in
 
446
                                the prepared state waiting for a
 
447
                                commit or abort decision from MySQL */
 
448
 
 
449
                                if (undo->state == TRX_UNDO_PREPARED) {
 
450
 
 
451
                                        fprintf(stderr,
 
452
                                                "InnoDB: Transaction "
 
453
                                                TRX_ID_FMT
 
454
                                                " was in the"
 
455
                                                " XA prepared state.\n",
 
456
                                                TRX_ID_PREP_PRINTF(trx->id));
 
457
 
 
458
                                        if (srv_force_recovery == 0) {
 
459
 
 
460
                                                trx->conc_state = TRX_PREPARED;
 
461
                                        } else {
 
462
                                                fprintf(stderr,
 
463
                                                        "InnoDB: Since"
 
464
                                                        " innodb_force_recovery"
 
465
                                                        " > 0, we will"
 
466
                                                        " rollback it"
 
467
                                                        " anyway.\n");
 
468
 
 
469
                                                trx->conc_state = TRX_ACTIVE;
 
470
                                        }
 
471
                                } else {
 
472
                                        trx->conc_state
 
473
                                                = TRX_COMMITTED_IN_MEMORY;
 
474
                                }
 
475
 
 
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 */
 
482
 
 
483
                                trx->no = trx->id;
 
484
                        } else {
 
485
                                trx->conc_state = TRX_ACTIVE;
 
486
 
 
487
                                /* A running transaction always has the number
 
488
                                field inited to ut_dulint_max */
 
489
 
 
490
                                trx->no = ut_dulint_max;
 
491
                        }
 
492
 
 
493
                        if (undo->dict_operation) {
 
494
                                trx_set_dict_operation(
 
495
                                        trx, TRX_DICT_OP_TABLE);
 
496
                                trx->table_id = undo->table_id;
 
497
                        }
 
498
 
 
499
                        if (!undo->empty) {
 
500
                                trx->undo_no = ut_dulint_add(undo->top_undo_no,
 
501
                                                             1);
 
502
                        }
 
503
 
 
504
                        trx_list_insert_ordered(trx);
 
505
 
 
506
                        undo = UT_LIST_GET_NEXT(undo_list, undo);
 
507
                }
 
508
 
 
509
                undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
 
510
 
 
511
                while (undo != NULL) {
 
512
                        trx = trx_get_on_id(undo->trx_id);
 
513
 
 
514
                        if (NULL == trx) {
 
515
                                trx = trx_create(trx_dummy_sess);
 
516
 
 
517
                                trx->is_recovered = TRUE;
 
518
                                trx->id = undo->trx_id;
 
519
                                trx->xid = undo->xid;
 
520
 
 
521
                                if (undo->state != TRX_UNDO_ACTIVE) {
 
522
 
 
523
                                        /* Prepared transactions are left in
 
524
                                        the prepared state waiting for a
 
525
                                        commit or abort decision from MySQL */
 
526
 
 
527
                                        if (undo->state == TRX_UNDO_PREPARED) {
 
528
                                                fprintf(stderr,
 
529
                                                        "InnoDB: Transaction "
 
530
                                                        TRX_ID_FMT " was in the"
 
531
                                                        " XA prepared state.\n",
 
532
                                                        TRX_ID_PREP_PRINTF(
 
533
                                                                trx->id));
 
534
 
 
535
                                                if (srv_force_recovery == 0) {
 
536
 
 
537
                                                        trx->conc_state
 
538
                                                                = TRX_PREPARED;
 
539
                                                } else {
 
540
                                                        fprintf(stderr,
 
541
                                                                "InnoDB: Since"
 
542
                                                                " innodb_force_recovery"
 
543
                                                                " > 0, we will"
 
544
                                                                " rollback it"
 
545
                                                                " anyway.\n");
 
546
 
 
547
                                                        trx->conc_state
 
548
                                                                = TRX_ACTIVE;
 
549
                                                }
 
550
                                        } else {
 
551
                                                trx->conc_state
 
552
                                                        = TRX_COMMITTED_IN_MEMORY;
 
553
                                        }
 
554
 
 
555
                                        /* We give a dummy value for the trx
 
556
                                        number */
 
557
 
 
558
                                        trx->no = trx->id;
 
559
                                } else {
 
560
                                        trx->conc_state = TRX_ACTIVE;
 
561
 
 
562
                                        /* A running transaction always has
 
563
                                        the number field inited to
 
564
                                        ut_dulint_max */
 
565
 
 
566
                                        trx->no = ut_dulint_max;
 
567
                                }
 
568
 
 
569
                                trx->rseg = rseg;
 
570
                                trx_list_insert_ordered(trx);
 
571
 
 
572
                                if (undo->dict_operation) {
 
573
                                        trx_set_dict_operation(
 
574
                                                trx, TRX_DICT_OP_TABLE);
 
575
                                        trx->table_id = undo->table_id;
 
576
                                }
 
577
                        }
 
578
 
 
579
                        trx->update_undo = undo;
 
580
 
 
581
                        if ((!undo->empty)
 
582
                            && (ut_dulint_cmp(undo->top_undo_no,
 
583
                                              trx->undo_no) >= 0)) {
 
584
 
 
585
                                trx->undo_no = ut_dulint_add(undo->top_undo_no,
 
586
                                                             1);
 
587
                        }
 
588
 
 
589
                        undo = UT_LIST_GET_NEXT(undo_list, undo);
 
590
                }
 
591
 
 
592
                rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
593
        }
 
594
}
 
595
 
 
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 */
 
600
UNIV_INLINE
 
601
ulint
 
602
trx_assign_rseg(void)
 
603
/*=================*/
 
604
{
 
605
        trx_rseg_t*     rseg    = trx_sys->latest_rseg;
 
606
 
 
607
        ut_ad(mutex_own(&kernel_mutex));
 
608
loop:
 
609
        /* Get next rseg in a round-robin fashion */
 
610
 
 
611
        rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
612
 
 
613
        if (rseg == NULL) {
 
614
                rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
615
        }
 
616
 
 
617
        /* If it is the SYSTEM rollback segment, and there exist others, skip
 
618
        it */
 
619
 
 
620
        if ((rseg->id == TRX_SYS_SYSTEM_RSEG_ID)
 
621
            && (UT_LIST_GET_LEN(trx_sys->rseg_list) > 1)) {
 
622
                goto loop;
 
623
        }
 
624
 
 
625
        trx_sys->latest_rseg = rseg;
 
626
 
 
627
        return(rseg->id);
 
628
}
 
629
 
 
630
/****************************************************************//**
 
631
Starts a new transaction.
 
632
@return TRUE */
 
633
UNIV_INTERN
 
634
ibool
 
635
trx_start_low(
 
636
/*==========*/
 
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 */
 
641
{
 
642
        trx_rseg_t*     rseg;
 
643
 
 
644
        ut_ad(mutex_own(&kernel_mutex));
 
645
        ut_ad(trx->rseg == NULL);
 
646
 
 
647
        if (trx->is_purge) {
 
648
                trx->id = ut_dulint_zero;
 
649
                trx->conc_state = TRX_ACTIVE;
 
650
                trx->start_time = time(NULL);
 
651
 
 
652
                return(TRUE);
 
653
        }
 
654
 
 
655
        ut_ad(trx->conc_state != TRX_ACTIVE);
 
656
 
 
657
        if (rseg_id == ULINT_UNDEFINED) {
 
658
 
 
659
                rseg_id = trx_assign_rseg();
 
660
        }
 
661
 
 
662
        rseg = trx_sys_get_nth_rseg(trx_sys, rseg_id);
 
663
 
 
664
        trx->id = trx_sys_get_new_trx_id();
 
665
 
 
666
        /* The initial value for trx->no: ut_dulint_max is used in
 
667
        read_view_open_now: */
 
668
 
 
669
        trx->no = ut_dulint_max;
 
670
 
 
671
        trx->rseg = rseg;
 
672
 
 
673
        trx->conc_state = TRX_ACTIVE;
 
674
        trx->start_time = time(NULL);
 
675
 
 
676
        UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
 
677
 
 
678
        return(TRUE);
 
679
}
 
680
 
 
681
/****************************************************************//**
 
682
Starts a new transaction.
 
683
@return TRUE */
 
684
UNIV_INTERN
 
685
ibool
 
686
trx_start(
 
687
/*======*/
 
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 */
 
692
{
 
693
        ibool   ret;
 
694
 
 
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);
 
702
 
 
703
        mutex_enter(&kernel_mutex);
 
704
 
 
705
        ret = trx_start_low(trx, rseg_id);
 
706
 
 
707
        mutex_exit(&kernel_mutex);
 
708
 
 
709
        return(ret);
 
710
}
 
711
 
 
712
/****************************************************************//**
 
713
Commits a transaction. */
 
714
UNIV_INTERN
 
715
void
 
716
trx_commit_off_kernel(
 
717
/*==================*/
 
718
        trx_t*  trx)    /*!< in: transaction */
 
719
{
 
720
        page_t*         update_hdr_page;
 
721
        ib_uint64_t     lsn             = 0;
 
722
        trx_rseg_t*     rseg;
 
723
        trx_undo_t*     undo;
 
724
        mtr_t           mtr;
 
725
 
 
726
        ut_ad(mutex_own(&kernel_mutex));
 
727
 
 
728
        trx->must_flush_log_later = FALSE;
 
729
 
 
730
        rseg = trx->rseg;
 
731
 
 
732
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
 
733
 
 
734
                mutex_exit(&kernel_mutex);
 
735
 
 
736
                mtr_start(&mtr);
 
737
 
 
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. */
 
743
 
 
744
                mutex_enter(&(rseg->mutex));
 
745
 
 
746
                if (trx->insert_undo != NULL) {
 
747
                        trx_undo_set_state_at_finish(
 
748
                                rseg, trx, trx->insert_undo, &mtr);
 
749
                }
 
750
 
 
751
                undo = trx->update_undo;
 
752
 
 
753
                if (undo) {
 
754
                        mutex_enter(&kernel_mutex);
 
755
                        trx->no = trx_sys_get_new_trx_no();
 
756
 
 
757
                        mutex_exit(&kernel_mutex);
 
758
 
 
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. */
 
762
 
 
763
                        update_hdr_page = trx_undo_set_state_at_finish(
 
764
                                rseg, trx, undo, &mtr);
 
765
 
 
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
 
769
                        the trx number. */
 
770
 
 
771
                        trx_undo_update_cleanup(trx, update_hdr_page, &mtr);
 
772
                }
 
773
 
 
774
                mutex_exit(&(rseg->mutex));
 
775
 
 
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 */
 
779
 
 
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;
 
787
                }
 
788
 
 
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
 
794
                here.
 
795
 
 
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. */
 
805
 
 
806
                /*--------------*/
 
807
                mtr_commit(&mtr);
 
808
                /*--------------*/
 
809
                lsn = mtr.end_lsn;
 
810
 
 
811
                mutex_enter(&kernel_mutex);
 
812
        }
 
813
 
 
814
        ut_ad(trx->conc_state == TRX_ACTIVE
 
815
              || trx->conc_state == TRX_PREPARED);
 
816
        ut_ad(mutex_own(&kernel_mutex));
 
817
 
 
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
 
830
        committed. */
 
831
 
 
832
        /*--------------------------------------*/
 
833
        trx->conc_state = TRX_COMMITTED_IN_MEMORY;
 
834
        /*--------------------------------------*/
 
835
 
 
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. */
 
847
 
 
848
        trx->is_recovered = FALSE;
 
849
 
 
850
        lock_release_off_kernel(trx);
 
851
 
 
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;
 
856
        }
 
857
 
 
858
        trx->read_view = NULL;
 
859
 
 
860
        if (lsn) {
 
861
 
 
862
                mutex_exit(&kernel_mutex);
 
863
 
 
864
                if (trx->insert_undo != NULL) {
 
865
 
 
866
                        trx_undo_insert_cleanup(trx);
 
867
                }
 
868
 
 
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! */
 
872
 
 
873
                /*-------------------------------------*/
 
874
 
 
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
 
879
                power outage.
 
880
 
 
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.
 
888
 
 
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. */
 
896
 
 
897
                if (trx->flush_log_later) {
 
898
                        /* Do nothing yet */
 
899
                        trx->must_flush_log_later = TRUE;
 
900
                } else if (srv_flush_log_at_trx_commit == 0) {
 
901
                        /* Do nothing */
 
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 */
 
905
 
 
906
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
 
907
                                                FALSE);
 
908
                        } else {
 
909
                                /* Write the log to the log files AND flush
 
910
                                them to disk */
 
911
 
 
912
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
913
                        }
 
914
                } else if (srv_flush_log_at_trx_commit == 2) {
 
915
 
 
916
                        /* Write the log but do not flush it to disk */
 
917
 
 
918
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
919
                } else {
 
920
                        ut_error;
 
921
                }
 
922
 
 
923
                trx->commit_lsn = lsn;
 
924
 
 
925
                /*-------------------------------------*/
 
926
 
 
927
                mutex_enter(&kernel_mutex);
 
928
        }
 
929
 
 
930
        /* Free all savepoints */
 
931
        trx_roll_free_all_savepoints(trx);
 
932
 
 
933
        trx->conc_state = TRX_NOT_STARTED;
 
934
        trx->rseg = NULL;
 
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;
 
938
 
 
939
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
940
        ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
 
941
 
 
942
        UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
 
943
}
 
944
 
 
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. */
 
949
UNIV_INTERN
 
950
void
 
951
trx_cleanup_at_db_startup(
 
952
/*======================*/
 
953
        trx_t*  trx)    /*!< in: transaction */
 
954
{
 
955
        if (trx->insert_undo != NULL) {
 
956
 
 
957
                trx_undo_insert_cleanup(trx);
 
958
        }
 
959
 
 
960
        trx->conc_state = TRX_NOT_STARTED;
 
961
        trx->rseg = NULL;
 
962
        trx->undo_no = ut_dulint_zero;
 
963
        trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
 
964
 
 
965
        UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
 
966
}
 
967
 
 
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 */
 
973
UNIV_INTERN
 
974
read_view_t*
 
975
trx_assign_read_view(
 
976
/*=================*/
 
977
        trx_t*  trx)    /*!< in: active transaction */
 
978
{
 
979
        ut_ad(trx->conc_state == TRX_ACTIVE);
 
980
 
 
981
        if (trx->read_view) {
 
982
                return(trx->read_view);
 
983
        }
 
984
 
 
985
        mutex_enter(&kernel_mutex);
 
986
 
 
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;
 
991
        }
 
992
 
 
993
        mutex_exit(&kernel_mutex);
 
994
 
 
995
        return(trx->read_view);
 
996
}
 
997
 
 
998
/****************************************************************//**
 
999
Commits a transaction. NOTE that the kernel mutex is temporarily released. */
 
1000
static
 
1001
void
 
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 */
 
1010
{
 
1011
        trx_sig_t*      sig;
 
1012
        trx_sig_t*      next_sig;
 
1013
 
 
1014
        ut_ad(mutex_own(&kernel_mutex));
 
1015
 
 
1016
        trx->que_state = TRX_QUE_COMMITTING;
 
1017
 
 
1018
        trx_commit_off_kernel(trx);
 
1019
 
 
1020
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
1021
 
 
1022
        /* Remove all TRX_SIG_COMMIT signals from the signal queue and send
 
1023
        reply messages to them */
 
1024
 
 
1025
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1026
 
 
1027
        while (sig != NULL) {
 
1028
                next_sig = UT_LIST_GET_NEXT(signals, sig);
 
1029
 
 
1030
                if (sig->type == TRX_SIG_COMMIT) {
 
1031
 
 
1032
                        trx_sig_reply(sig, next_thr);
 
1033
                        trx_sig_remove(trx, sig);
 
1034
                }
 
1035
 
 
1036
                sig = next_sig;
 
1037
        }
 
1038
 
 
1039
        trx->que_state = TRX_QUE_RUNNING;
 
1040
}
 
1041
 
 
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. */
 
1046
UNIV_INTERN
 
1047
void
 
1048
trx_end_lock_wait(
 
1049
/*==============*/
 
1050
        trx_t*  trx)    /*!< in: transaction */
 
1051
{
 
1052
        que_thr_t*      thr;
 
1053
 
 
1054
        ut_ad(mutex_own(&kernel_mutex));
 
1055
        ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
 
1056
 
 
1057
        thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1058
 
 
1059
        while (thr != NULL) {
 
1060
                que_thr_end_wait_no_next_thr(thr);
 
1061
 
 
1062
                UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
 
1063
 
 
1064
                thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1065
        }
 
1066
 
 
1067
        trx->que_state = TRX_QUE_RUNNING;
 
1068
}
 
1069
 
 
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. */
 
1073
static
 
1074
void
 
1075
trx_lock_wait_to_suspended(
 
1076
/*=======================*/
 
1077
        trx_t*  trx)    /*!< in: transaction in the TRX_QUE_LOCK_WAIT state */
 
1078
{
 
1079
        que_thr_t*      thr;
 
1080
 
 
1081
        ut_ad(mutex_own(&kernel_mutex));
 
1082
        ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
 
1083
 
 
1084
        thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1085
 
 
1086
        while (thr != NULL) {
 
1087
                thr->state = QUE_THR_SUSPENDED;
 
1088
 
 
1089
                UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
 
1090
 
 
1091
                thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1092
        }
 
1093
 
 
1094
        trx->que_state = TRX_QUE_RUNNING;
 
1095
}
 
1096
 
 
1097
/***********************************************************//**
 
1098
Moves the query threads in the sig reply wait list of trx to the SUSPENDED
 
1099
state. */
 
1100
static
 
1101
void
 
1102
trx_sig_reply_wait_to_suspended(
 
1103
/*============================*/
 
1104
        trx_t*  trx)    /*!< in: transaction */
 
1105
{
 
1106
        trx_sig_t*      sig;
 
1107
        que_thr_t*      thr;
 
1108
 
 
1109
        ut_ad(mutex_own(&kernel_mutex));
 
1110
 
 
1111
        sig = UT_LIST_GET_FIRST(trx->reply_signals);
 
1112
 
 
1113
        while (sig != NULL) {
 
1114
                thr = sig->receiver;
 
1115
 
 
1116
                ut_ad(thr->state == QUE_THR_SIG_REPLY_WAIT);
 
1117
 
 
1118
                thr->state = QUE_THR_SUSPENDED;
 
1119
 
 
1120
                sig->receiver = NULL;
 
1121
 
 
1122
                UT_LIST_REMOVE(reply_signals, trx->reply_signals, sig);
 
1123
 
 
1124
                sig = UT_LIST_GET_FIRST(trx->reply_signals);
 
1125
        }
 
1126
}
 
1127
 
 
1128
/*****************************************************************//**
 
1129
Checks the compatibility of a new signal with the other signals in the
 
1130
queue.
 
1131
@return TRUE if the signal can be queued */
 
1132
static
 
1133
ibool
 
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 */
 
1139
{
 
1140
        trx_sig_t*      sig;
 
1141
 
 
1142
        ut_ad(mutex_own(&kernel_mutex));
 
1143
 
 
1144
        if (UT_LIST_GET_LEN(trx->signals) == 0) {
 
1145
 
 
1146
                return(TRUE);
 
1147
        }
 
1148
 
 
1149
        if (sender == TRX_SIG_SELF) {
 
1150
                if (type == TRX_SIG_ERROR_OCCURRED) {
 
1151
 
 
1152
                        return(TRUE);
 
1153
 
 
1154
                } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1155
 
 
1156
                        return(TRUE);
 
1157
                } else {
 
1158
                        return(FALSE);
 
1159
                }
 
1160
        }
 
1161
 
 
1162
        ut_ad(sender == TRX_SIG_OTHER_SESS);
 
1163
 
 
1164
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1165
 
 
1166
        if (type == TRX_SIG_COMMIT) {
 
1167
                while (sig != NULL) {
 
1168
 
 
1169
                        if (sig->type == TRX_SIG_TOTAL_ROLLBACK) {
 
1170
 
 
1171
                                return(FALSE);
 
1172
                        }
 
1173
 
 
1174
                        sig = UT_LIST_GET_NEXT(signals, sig);
 
1175
                }
 
1176
 
 
1177
                return(TRUE);
 
1178
 
 
1179
        } else if (type == TRX_SIG_TOTAL_ROLLBACK) {
 
1180
                while (sig != NULL) {
 
1181
 
 
1182
                        if (sig->type == TRX_SIG_COMMIT) {
 
1183
 
 
1184
                                return(FALSE);
 
1185
                        }
 
1186
 
 
1187
                        sig = UT_LIST_GET_NEXT(signals, sig);
 
1188
                }
 
1189
 
 
1190
                return(TRUE);
 
1191
 
 
1192
        } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1193
 
 
1194
                return(TRUE);
 
1195
        } else {
 
1196
                ut_error;
 
1197
 
 
1198
                return(FALSE);
 
1199
        }
 
1200
}
 
1201
 
 
1202
/****************************************************************//**
 
1203
Sends a signal to a trx object. */
 
1204
UNIV_INTERN
 
1205
void
 
1206
trx_sig_send(
 
1207
/*=========*/
 
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
 
1216
                                        NULL */
 
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 */
 
1223
{
 
1224
        trx_sig_t*      sig;
 
1225
        trx_t*          receiver_trx;
 
1226
 
 
1227
        ut_ad(trx);
 
1228
        ut_ad(mutex_own(&kernel_mutex));
 
1229
 
 
1230
        if (!trx_sig_is_compatible(trx, type, sender)) {
 
1231
                /* The signal is not compatible with the other signals in
 
1232
                the queue: die */
 
1233
 
 
1234
                ut_error;
 
1235
        }
 
1236
 
 
1237
        /* Queue the signal object */
 
1238
 
 
1239
        if (UT_LIST_GET_LEN(trx->signals) == 0) {
 
1240
 
 
1241
                /* The signal list is empty: the 'sig' slot must be unused
 
1242
                (we improve performance a bit by avoiding mem_alloc) */
 
1243
                sig = &(trx->sig);
 
1244
        } else {
 
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 */
 
1247
 
 
1248
                sig = mem_alloc(sizeof(trx_sig_t));
 
1249
        }
 
1250
 
 
1251
        UT_LIST_ADD_LAST(signals, trx->signals, sig);
 
1252
 
 
1253
        sig->type = type;
 
1254
        sig->sender = sender;
 
1255
        sig->receiver = receiver_thr;
 
1256
 
 
1257
        if (savept) {
 
1258
                sig->savept = *savept;
 
1259
        }
 
1260
 
 
1261
        if (receiver_thr) {
 
1262
                receiver_trx = thr_get_trx(receiver_thr);
 
1263
 
 
1264
                UT_LIST_ADD_LAST(reply_signals, receiver_trx->reply_signals,
 
1265
                                 sig);
 
1266
        }
 
1267
 
 
1268
        if (trx->sess->state == SESS_ERROR) {
 
1269
 
 
1270
                trx_sig_reply_wait_to_suspended(trx);
 
1271
        }
 
1272
 
 
1273
        if ((sender != TRX_SIG_SELF) || (type == TRX_SIG_BREAK_EXECUTION)) {
 
1274
                ut_error;
 
1275
        }
 
1276
 
 
1277
        /* If there were no other signals ahead in the queue, try to start
 
1278
        handling of the signal */
 
1279
 
 
1280
        if (UT_LIST_GET_FIRST(trx->signals) == sig) {
 
1281
 
 
1282
                trx_sig_start_handle(trx, next_thr);
 
1283
        }
 
1284
}
 
1285
 
 
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). */
 
1291
UNIV_INTERN
 
1292
void
 
1293
trx_end_signal_handling(
 
1294
/*====================*/
 
1295
        trx_t*  trx)    /*!< in: trx */
 
1296
{
 
1297
        ut_ad(mutex_own(&kernel_mutex));
 
1298
        ut_ad(trx->handling_signals == TRUE);
 
1299
 
 
1300
        trx->handling_signals = FALSE;
 
1301
 
 
1302
        trx->graph = trx->graph_before_signal_handling;
 
1303
 
 
1304
        if (trx->graph && (trx->sess->state == SESS_ERROR)) {
 
1305
 
 
1306
                que_fork_error_handle(trx, trx->graph);
 
1307
        }
 
1308
}
 
1309
 
 
1310
/****************************************************************//**
 
1311
Starts handling of a trx signal. */
 
1312
UNIV_INTERN
 
1313
void
 
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 */
 
1323
{
 
1324
        trx_sig_t*      sig;
 
1325
        ulint           type;
 
1326
loop:
 
1327
        /* We loop in this function body as long as there are queued signals
 
1328
        we can process immediately */
 
1329
 
 
1330
        ut_ad(trx);
 
1331
        ut_ad(mutex_own(&kernel_mutex));
 
1332
 
 
1333
        if (trx->handling_signals && (UT_LIST_GET_LEN(trx->signals) == 0)) {
 
1334
 
 
1335
                trx_end_signal_handling(trx);
 
1336
 
 
1337
                return;
 
1338
        }
 
1339
 
 
1340
        if (trx->conc_state == TRX_NOT_STARTED) {
 
1341
 
 
1342
                trx_start_low(trx, ULINT_UNDEFINED);
 
1343
        }
 
1344
 
 
1345
        /* If the trx is in a lock wait state, moves the waiting query threads
 
1346
        to the suspended state */
 
1347
 
 
1348
        if (trx->que_state == TRX_QUE_LOCK_WAIT) {
 
1349
 
 
1350
                trx_lock_wait_to_suspended(trx);
 
1351
        }
 
1352
 
 
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. */
 
1358
 
 
1359
        if (trx->sess->state == SESS_ERROR) {
 
1360
                trx_sig_reply_wait_to_suspended(trx);
 
1361
        }
 
1362
 
 
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. */
 
1366
 
 
1367
        if (trx->n_active_thrs > 0) {
 
1368
 
 
1369
                return;
 
1370
        }
 
1371
 
 
1372
        if (trx->handling_signals == FALSE) {
 
1373
                trx->graph_before_signal_handling = trx->graph;
 
1374
 
 
1375
                trx->handling_signals = TRUE;
 
1376
        }
 
1377
 
 
1378
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1379
        type = sig->type;
 
1380
 
 
1381
        if (type == TRX_SIG_COMMIT) {
 
1382
 
 
1383
                trx_handle_commit_sig_off_kernel(trx, next_thr);
 
1384
 
 
1385
        } else if ((type == TRX_SIG_TOTAL_ROLLBACK)
 
1386
                   || (type == TRX_SIG_ROLLBACK_TO_SAVEPT)) {
 
1387
 
 
1388
                trx_rollback(trx, sig, next_thr);
 
1389
 
 
1390
                /* No further signals can be handled until the rollback
 
1391
                completes, therefore we return */
 
1392
 
 
1393
                return;
 
1394
 
 
1395
        } else if (type == TRX_SIG_ERROR_OCCURRED) {
 
1396
 
 
1397
                trx_rollback(trx, sig, next_thr);
 
1398
 
 
1399
                /* No further signals can be handled until the rollback
 
1400
                completes, therefore we return */
 
1401
 
 
1402
                return;
 
1403
 
 
1404
        } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1405
 
 
1406
                trx_sig_reply(sig, next_thr);
 
1407
                trx_sig_remove(trx, sig);
 
1408
        } else {
 
1409
                ut_error;
 
1410
        }
 
1411
 
 
1412
        goto loop;
 
1413
}
 
1414
 
 
1415
/****************************************************************//**
 
1416
Send the reply message when a signal in the queue of the trx has been
 
1417
handled. */
 
1418
UNIV_INTERN
 
1419
void
 
1420
trx_sig_reply(
 
1421
/*==========*/
 
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 */
 
1428
{
 
1429
        trx_t*  receiver_trx;
 
1430
 
 
1431
        ut_ad(sig);
 
1432
        ut_ad(mutex_own(&kernel_mutex));
 
1433
 
 
1434
        if (sig->receiver != NULL) {
 
1435
                ut_ad((sig->receiver)->state == QUE_THR_SIG_REPLY_WAIT);
 
1436
 
 
1437
                receiver_trx = thr_get_trx(sig->receiver);
 
1438
 
 
1439
                UT_LIST_REMOVE(reply_signals, receiver_trx->reply_signals,
 
1440
                               sig);
 
1441
                ut_ad(receiver_trx->sess->state != SESS_ERROR);
 
1442
 
 
1443
                que_thr_end_wait(sig->receiver, next_thr);
 
1444
 
 
1445
                sig->receiver = NULL;
 
1446
 
 
1447
        }
 
1448
}
 
1449
 
 
1450
/****************************************************************//**
 
1451
Removes a signal object from the trx signal queue. */
 
1452
UNIV_INTERN
 
1453
void
 
1454
trx_sig_remove(
 
1455
/*===========*/
 
1456
        trx_t*          trx,    /*!< in: trx handle */
 
1457
        trx_sig_t*      sig)    /*!< in, own: signal */
 
1458
{
 
1459
        ut_ad(trx && sig);
 
1460
        ut_ad(mutex_own(&kernel_mutex));
 
1461
 
 
1462
        ut_ad(sig->receiver == NULL);
 
1463
 
 
1464
        UT_LIST_REMOVE(signals, trx->signals, sig);
 
1465
        sig->type = 0;  /* reset the field to catch possible bugs */
 
1466
 
 
1467
        if (sig != &(trx->sig)) {
 
1468
                mem_free(sig);
 
1469
        }
 
1470
}
 
1471
 
 
1472
/*********************************************************************//**
 
1473
Creates a commit command node struct.
 
1474
@return own: commit node struct */
 
1475
UNIV_INTERN
 
1476
commit_node_t*
 
1477
commit_node_create(
 
1478
/*===============*/
 
1479
        mem_heap_t*     heap)   /*!< in: mem heap where created */
 
1480
{
 
1481
        commit_node_t*  node;
 
1482
 
 
1483
        node = mem_heap_alloc(heap, sizeof(commit_node_t));
 
1484
        node->common.type  = QUE_NODE_COMMIT;
 
1485
        node->state = COMMIT_NODE_SEND;
 
1486
 
 
1487
        return(node);
 
1488
}
 
1489
 
 
1490
/***********************************************************//**
 
1491
Performs an execution step for a commit type node in a query graph.
 
1492
@return query thread to run next, or NULL */
 
1493
UNIV_INTERN
 
1494
que_thr_t*
 
1495
trx_commit_step(
 
1496
/*============*/
 
1497
        que_thr_t*      thr)    /*!< in: query thread */
 
1498
{
 
1499
        commit_node_t*  node;
 
1500
        que_thr_t*      next_thr;
 
1501
 
 
1502
        node = thr->run_node;
 
1503
 
 
1504
        ut_ad(que_node_get_type(node) == QUE_NODE_COMMIT);
 
1505
 
 
1506
        if (thr->prev_node == que_node_get_parent(node)) {
 
1507
                node->state = COMMIT_NODE_SEND;
 
1508
        }
 
1509
 
 
1510
        if (node->state == COMMIT_NODE_SEND) {
 
1511
                mutex_enter(&kernel_mutex);
 
1512
 
 
1513
                node->state = COMMIT_NODE_WAIT;
 
1514
 
 
1515
                next_thr = NULL;
 
1516
 
 
1517
                thr->state = QUE_THR_SIG_REPLY_WAIT;
 
1518
 
 
1519
                /* Send the commit signal to the transaction */
 
1520
 
 
1521
                trx_sig_send(thr_get_trx(thr), TRX_SIG_COMMIT, TRX_SIG_SELF,
 
1522
                             thr, NULL, &next_thr);
 
1523
 
 
1524
                mutex_exit(&kernel_mutex);
 
1525
 
 
1526
                return(next_thr);
 
1527
        }
 
1528
 
 
1529
        ut_ad(node->state == COMMIT_NODE_WAIT);
 
1530
 
 
1531
        node->state = COMMIT_NODE_SEND;
 
1532
 
 
1533
        thr->run_node = que_node_get_parent(node);
 
1534
 
 
1535
        return(thr);
 
1536
}
 
1537
 
 
1538
/**********************************************************************//**
 
1539
Does the transaction commit for MySQL.
 
1540
@return DB_SUCCESS or error number */
 
1541
UNIV_INTERN
 
1542
ulint
 
1543
trx_commit_for_mysql(
 
1544
/*=================*/
 
1545
        trx_t*  trx)    /*!< in: trx handle */
 
1546
{
 
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
 
1549
        started. */
 
1550
 
 
1551
        ut_a(trx);
 
1552
 
 
1553
        trx_start_if_not_started(trx);
 
1554
 
 
1555
        trx->op_info = "committing";
 
1556
 
 
1557
        mutex_enter(&kernel_mutex);
 
1558
 
 
1559
        trx_commit_off_kernel(trx);
 
1560
 
 
1561
        mutex_exit(&kernel_mutex);
 
1562
 
 
1563
        trx->op_info = "";
 
1564
 
 
1565
        return(DB_SUCCESS);
 
1566
}
 
1567
 
 
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 */
 
1572
UNIV_INTERN
 
1573
ulint
 
1574
trx_commit_complete_for_mysql(
 
1575
/*==========================*/
 
1576
        trx_t*  trx)    /*!< in: trx handle */
 
1577
{
 
1578
        ib_uint64_t     lsn     = trx->commit_lsn;
 
1579
 
 
1580
        ut_a(trx);
 
1581
 
 
1582
        trx->op_info = "flushing log";
 
1583
 
 
1584
        if (!trx->must_flush_log_later) {
 
1585
                /* Do nothing */
 
1586
        } else if (srv_flush_log_at_trx_commit == 0) {
 
1587
                /* Do nothing */
 
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 */
 
1591
 
 
1592
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1593
                } else {
 
1594
                        /* Write the log to the log files AND flush them to
 
1595
                        disk */
 
1596
 
 
1597
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
1598
                }
 
1599
        } else if (srv_flush_log_at_trx_commit == 2) {
 
1600
 
 
1601
                /* Write the log but do not flush it to disk */
 
1602
 
 
1603
                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1604
        } else {
 
1605
                ut_error;
 
1606
        }
 
1607
 
 
1608
        trx->must_flush_log_later = FALSE;
 
1609
 
 
1610
        trx->op_info = "";
 
1611
 
 
1612
        return(0);
 
1613
}
 
1614
 
 
1615
/**********************************************************************//**
 
1616
Marks the latest SQL statement ended. */
 
1617
UNIV_INTERN
 
1618
void
 
1619
trx_mark_sql_stat_end(
 
1620
/*==================*/
 
1621
        trx_t*  trx)    /*!< in: trx handle */
 
1622
{
 
1623
        ut_a(trx);
 
1624
 
 
1625
        if (trx->conc_state == TRX_NOT_STARTED) {
 
1626
                trx->undo_no = ut_dulint_zero;
 
1627
        }
 
1628
 
 
1629
        trx->last_sql_stat_start.least_undo_no = trx->undo_no;
 
1630
}
 
1631
 
 
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. */
 
1637
UNIV_INTERN
 
1638
void
 
1639
trx_print(
 
1640
/*======*/
 
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 */
 
1645
{
 
1646
        ibool   newline;
 
1647
 
 
1648
        fprintf(f, "TRANSACTION " TRX_ID_FMT, TRX_ID_PREP_PRINTF(trx->id));
 
1649
 
 
1650
        switch (trx->conc_state) {
 
1651
        case TRX_NOT_STARTED:
 
1652
                fputs(", not started", f);
 
1653
                break;
 
1654
        case TRX_ACTIVE:
 
1655
                fprintf(f, ", ACTIVE %lu sec",
 
1656
                        (ulong)difftime(time(NULL), trx->start_time));
 
1657
                break;
 
1658
        case TRX_PREPARED:
 
1659
                fprintf(f, ", ACTIVE (PREPARED) %lu sec",
 
1660
                        (ulong)difftime(time(NULL), trx->start_time));
 
1661
                break;
 
1662
        case TRX_COMMITTED_IN_MEMORY:
 
1663
                fputs(", COMMITTED IN MEMORY", f);
 
1664
                break;
 
1665
        default:
 
1666
                fprintf(f, " state %lu", (ulong) trx->conc_state);
 
1667
        }
 
1668
 
 
1669
#ifdef UNIV_LINUX
 
1670
        fprintf(f, ", process no %lu", trx->mysql_process_no);
 
1671
#endif
 
1672
        fprintf(f, ", OS thread id %lu",
 
1673
                (ulong) os_thread_pf(trx->mysql_thread_id));
 
1674
 
 
1675
        if (*trx->op_info) {
 
1676
                putc(' ', f);
 
1677
                fputs(trx->op_info, f);
 
1678
        }
 
1679
 
 
1680
        if (trx->is_recovered) {
 
1681
                fputs(" recovered trx", f);
 
1682
        }
 
1683
 
 
1684
        if (trx->is_purge) {
 
1685
                fputs(" purge trx", f);
 
1686
        }
 
1687
 
 
1688
        if (trx->declared_to_be_inside_innodb) {
 
1689
                fprintf(f, ", thread declared inside InnoDB %lu",
 
1690
                        (ulong) trx->n_tickets_to_enter_innodb);
 
1691
        }
 
1692
 
 
1693
        putc('\n', f);
 
1694
 
 
1695
        if (trx->mysql_n_tables_locked > 0) {
 
1696
                fprintf(f, "mysql tables in locked %lu\n",
 
1697
                        (ulong) trx->mysql_n_tables_locked);
 
1698
        }
 
1699
 
 
1700
        newline = TRUE;
 
1701
 
 
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;
 
1711
        default:
 
1712
                fprintf(f, "que state %lu ", (ulong) trx->que_state);
 
1713
        }
 
1714
 
 
1715
        if (0 < UT_LIST_GET_LEN(trx->trx_locks)
 
1716
            || mem_heap_get_size(trx->lock_heap) > 400) {
 
1717
                newline = TRUE;
 
1718
 
 
1719
                fprintf(f, "%lu lock struct(s), heap size %lu,"
 
1720
                        " %lu row lock(s)",
 
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));
 
1724
        }
 
1725
 
 
1726
        if (trx->has_search_latch) {
 
1727
                newline = TRUE;
 
1728
                fputs(", holds adaptive hash latch", f);
 
1729
        }
 
1730
 
 
1731
        if (!ut_dulint_is_zero(trx->undo_no)) {
 
1732
                newline = TRUE;
 
1733
                fprintf(f, ", undo log entries %lu",
 
1734
                        (ulong) ut_dulint_get_low(trx->undo_no));
 
1735
        }
 
1736
 
 
1737
        if (newline) {
 
1738
                putc('\n', f);
 
1739
        }
 
1740
 
 
1741
        if (trx->mysql_thd != NULL) {
 
1742
                innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
 
1743
        }
 
1744
}
 
1745
 
 
1746
/*******************************************************************//**
 
1747
Compares the "weight" (or size) of two transactions. Transactions that
 
1748
have edited non-transactional tables are considered heavier than ones
 
1749
that have not.
 
1750
@return <0, 0 or >0; similar to strcmp(3) */
 
1751
UNIV_INTERN
 
1752
int
 
1753
trx_weight_cmp(
 
1754
/*===========*/
 
1755
        const trx_t*    a,      /*!< in: the first transaction to be compared */
 
1756
        const trx_t*    b)      /*!< in: the second transaction to be compared */
 
1757
{
 
1758
        ibool   a_notrans_edit;
 
1759
        ibool   b_notrans_edit;
 
1760
 
 
1761
        /* If mysql_thd is NULL for a transaction we assume that it has
 
1762
        not edited non-transactional tables. */
 
1763
 
 
1764
        a_notrans_edit = a->mysql_thd != NULL
 
1765
            && thd_has_edited_nontrans_tables(a->mysql_thd);
 
1766
 
 
1767
        b_notrans_edit = b->mysql_thd != NULL
 
1768
            && thd_has_edited_nontrans_tables(b->mysql_thd);
 
1769
 
 
1770
        if (a_notrans_edit && !b_notrans_edit) {
 
1771
 
 
1772
                return(1);
 
1773
        }
 
1774
 
 
1775
        if (!a_notrans_edit && b_notrans_edit) {
 
1776
 
 
1777
                return(-1);
 
1778
        }
 
1779
 
 
1780
        /* Either both had edited non-transactional tables or both had
 
1781
        not, we fall back to comparing the number of altered/locked
 
1782
        rows. */
 
1783
 
 
1784
#if 0
 
1785
        fprintf(stderr,
 
1786
                "%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n",
 
1787
                __func__,
 
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));
 
1792
#endif
 
1793
 
 
1794
        return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b)));
 
1795
}
 
1796
 
 
1797
/****************************************************************//**
 
1798
Prepares a transaction. */
 
1799
UNIV_INLINE
 
1800
void
 
1801
trx_prepare_off_kernel(
 
1802
/*===================*/
 
1803
        trx_t*  trx)    /*!< in: transaction */
 
1804
{
 
1805
        page_t*         update_hdr_page;
 
1806
        trx_rseg_t*     rseg;
 
1807
        ib_uint64_t     lsn             = 0;
 
1808
        mtr_t           mtr;
 
1809
 
 
1810
        ut_ad(mutex_own(&kernel_mutex));
 
1811
 
 
1812
        rseg = trx->rseg;
 
1813
 
 
1814
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
 
1815
 
 
1816
                mutex_exit(&kernel_mutex);
 
1817
 
 
1818
                mtr_start(&mtr);
 
1819
 
 
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. */
 
1824
 
 
1825
                mutex_enter(&(rseg->mutex));
 
1826
 
 
1827
                if (trx->insert_undo != NULL) {
 
1828
 
 
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. */
 
1832
 
 
1833
                        trx_undo_set_state_at_prepare(trx, trx->insert_undo,
 
1834
                                                      &mtr);
 
1835
                }
 
1836
 
 
1837
                if (trx->update_undo) {
 
1838
                        update_hdr_page = trx_undo_set_state_at_prepare(
 
1839
                                trx, trx->update_undo, &mtr);
 
1840
                }
 
1841
 
 
1842
                mutex_exit(&(rseg->mutex));
 
1843
 
 
1844
                /*--------------*/
 
1845
                mtr_commit(&mtr);       /* This mtr commit makes the
 
1846
                                        transaction prepared in the file-based
 
1847
                                        world */
 
1848
                /*--------------*/
 
1849
                lsn = mtr.end_lsn;
 
1850
 
 
1851
                mutex_enter(&kernel_mutex);
 
1852
        }
 
1853
 
 
1854
        ut_ad(mutex_own(&kernel_mutex));
 
1855
 
 
1856
        /*--------------------------------------*/
 
1857
        trx->conc_state = TRX_PREPARED;
 
1858
        /*--------------------------------------*/
 
1859
 
 
1860
        if (lsn) {
 
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.
 
1866
 
 
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.
 
1874
 
 
1875
                TODO: find out if MySQL holds some mutex when calling this.
 
1876
                That would spoil our group prepare algorithm. */
 
1877
 
 
1878
                mutex_exit(&kernel_mutex);
 
1879
 
 
1880
                if (srv_flush_log_at_trx_commit == 0) {
 
1881
                        /* Do nothing */
 
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 */
 
1885
 
 
1886
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
 
1887
                                                FALSE);
 
1888
                        } else {
 
1889
                                /* Write the log to the log files AND flush
 
1890
                                them to disk */
 
1891
 
 
1892
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
1893
                        }
 
1894
                } else if (srv_flush_log_at_trx_commit == 2) {
 
1895
 
 
1896
                        /* Write the log but do not flush it to disk */
 
1897
 
 
1898
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1899
                } else {
 
1900
                        ut_error;
 
1901
                }
 
1902
 
 
1903
                mutex_enter(&kernel_mutex);
 
1904
        }
 
1905
}
 
1906
 
 
1907
/**********************************************************************//**
 
1908
Does the transaction prepare for MySQL.
 
1909
@return 0 or error number */
 
1910
UNIV_INTERN
 
1911
ulint
 
1912
trx_prepare_for_mysql(
 
1913
/*==================*/
 
1914
        trx_t*  trx)    /*!< in: trx handle */
 
1915
{
 
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
 
1918
        started. */
 
1919
 
 
1920
        ut_a(trx);
 
1921
 
 
1922
        trx->op_info = "preparing";
 
1923
 
 
1924
        trx_start_if_not_started(trx);
 
1925
 
 
1926
        mutex_enter(&kernel_mutex);
 
1927
 
 
1928
        trx_prepare_off_kernel(trx);
 
1929
 
 
1930
        mutex_exit(&kernel_mutex);
 
1931
 
 
1932
        trx->op_info = "";
 
1933
 
 
1934
        return(0);
 
1935
}
 
1936
 
 
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 */
 
1941
UNIV_INTERN
 
1942
int
 
1943
trx_recover_for_mysql(
 
1944
/*==================*/
 
1945
        XID*    xid_list,       /*!< in/out: prepared transactions */
 
1946
        ulint   len)            /*!< in: number of slots in xid_list */
 
1947
{
 
1948
        trx_t*  trx;
 
1949
        ulint   count = 0;
 
1950
 
 
1951
        ut_ad(xid_list);
 
1952
        ut_ad(len);
 
1953
 
 
1954
        /* We should set those transactions which are in the prepared state
 
1955
        to the xid_list */
 
1956
 
 
1957
        mutex_enter(&kernel_mutex);
 
1958
 
 
1959
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
1960
 
 
1961
        while (trx) {
 
1962
                if (trx->conc_state == TRX_PREPARED) {
 
1963
                        xid_list[count] = trx->xid;
 
1964
 
 
1965
                        if (count == 0) {
 
1966
                                ut_print_timestamp(stderr);
 
1967
                                fprintf(stderr,
 
1968
                                        "  InnoDB: Starting recovery for"
 
1969
                                        " XA transactions...\n");
 
1970
                        }
 
1971
 
 
1972
                        ut_print_timestamp(stderr);
 
1973
                        fprintf(stderr,
 
1974
                                "  InnoDB: Transaction " TRX_ID_FMT " in"
 
1975
                                " prepared state after recovery\n",
 
1976
                                TRX_ID_PREP_PRINTF(trx->id));
 
1977
 
 
1978
                        ut_print_timestamp(stderr);
 
1979
                        fprintf(stderr,
 
1980
                                "  InnoDB: Transaction contains changes"
 
1981
                                " to %lu rows\n",
 
1982
                                (ulong) ut_conv_dulint_to_longlong(
 
1983
                                        trx->undo_no));
 
1984
 
 
1985
                        count++;
 
1986
 
 
1987
                        if (count == len) {
 
1988
                                break;
 
1989
                        }
 
1990
                }
 
1991
 
 
1992
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
1993
        }
 
1994
 
 
1995
        mutex_exit(&kernel_mutex);
 
1996
 
 
1997
        if (count > 0){
 
1998
                ut_print_timestamp(stderr);
 
1999
                fprintf(stderr,
 
2000
                        "  InnoDB: %lu transactions in prepared state"
 
2001
                        " after recovery\n",
 
2002
                        (ulong) count);
 
2003
        }
 
2004
 
 
2005
        return ((int) count);
 
2006
}
 
2007
 
 
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 */
 
2012
UNIV_INTERN
 
2013
trx_t*
 
2014
trx_get_trx_by_xid(
 
2015
/*===============*/
 
2016
        XID*    xid)    /*!< in: X/Open XA transaction identification */
 
2017
{
 
2018
        trx_t*  trx;
 
2019
 
 
2020
        if (xid == NULL) {
 
2021
 
 
2022
                return (NULL);
 
2023
        }
 
2024
 
 
2025
        mutex_enter(&kernel_mutex);
 
2026
 
 
2027
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
2028
 
 
2029
        while (trx) {
 
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
 
2033
                the same */
 
2034
 
 
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) {
 
2039
                        break;
 
2040
                }
 
2041
 
 
2042
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
2043
        }
 
2044
 
 
2045
        mutex_exit(&kernel_mutex);
 
2046
 
 
2047
        if (trx) {
 
2048
                if (trx->conc_state != TRX_PREPARED) {
 
2049
 
 
2050
                        return(NULL);
 
2051
                }
 
2052
 
 
2053
                return(trx);
 
2054
        } else {
 
2055
                return(NULL);
 
2056
        }
 
2057
}