~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-11 17:31:45 UTC
  • Revision ID: brian@tangent.org-20081011173145-qzws50bp0npuihzp
Removed dead bootstrap variable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 2010, 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
 
#ifdef UNIV_PFS_MUTEX
55
 
/* Key to register the mutex with performance schema */
56
 
UNIV_INTERN mysql_pfs_key_t     trx_undo_mutex_key;
57
 
#endif /* UNIV_PFS_MUTEX */
58
 
 
59
 
/*************************************************************//**
60
 
Set detailed error message for the transaction. */
61
 
UNIV_INTERN
62
 
void
63
 
trx_set_detailed_error(
64
 
/*===================*/
65
 
        trx_t*          trx,    /*!< in: transaction struct */
66
 
        const char*     msg)    /*!< in: detailed error message */
67
 
{
68
 
        ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));
69
 
}
70
 
 
71
 
/*************************************************************//**
72
 
Set detailed error message for the transaction from a file. Note that the
73
 
file is rewinded before reading from it. */
74
 
UNIV_INTERN
75
 
void
76
 
trx_set_detailed_error_from_file(
77
 
/*=============================*/
78
 
        trx_t*  trx,    /*!< in: transaction struct */
79
 
        FILE*   file)   /*!< in: file to read message from */
80
 
{
81
 
        os_file_read_string(file, trx->detailed_error,
82
 
                            sizeof(trx->detailed_error));
83
 
}
84
 
 
85
 
/****************************************************************//**
86
 
Creates and initializes a transaction object.
87
 
@return own: the transaction */
88
 
UNIV_INTERN
89
 
trx_t*
90
 
trx_create(
91
 
/*=======*/
92
 
        sess_t* sess)   /*!< in: session */
93
 
{
94
 
        trx_t*  trx;
95
 
 
96
 
        ut_ad(mutex_own(&kernel_mutex));
97
 
        ut_ad(sess);
98
 
 
99
 
        trx = mem_alloc(sizeof(trx_t));
100
 
 
101
 
        trx->magic_n = TRX_MAGIC_N;
102
 
 
103
 
        trx->op_info = "";
104
 
 
105
 
        trx->is_purge = 0;
106
 
        trx->is_recovered = 0;
107
 
        trx->conc_state = TRX_NOT_STARTED;
108
 
        trx->start_time = time(NULL);
109
 
 
110
 
        trx->isolation_level = TRX_ISO_REPEATABLE_READ;
111
 
 
112
 
        trx->id = 0;
113
 
        trx->no = IB_ULONGLONG_MAX;
114
 
 
115
 
        trx->support_xa = TRUE;
116
 
 
117
 
        trx->check_foreigns = TRUE;
118
 
        trx->check_unique_secondary = TRUE;
119
 
 
120
 
        trx->flush_log_later = FALSE;
121
 
        trx->must_flush_log_later = FALSE;
122
 
 
123
 
        trx->dict_operation = TRX_DICT_OP_NONE;
124
 
        trx->table_id = 0;
125
 
 
126
 
        trx->mysql_thd = NULL;
127
 
        trx->active_trans = 0;
128
 
        trx->duplicates = 0;
129
 
 
130
 
        trx->mysql_n_tables_locked = 0;
131
 
 
132
 
        trx->mysql_log_file_name = NULL;
133
 
        trx->mysql_log_offset = 0;
134
 
 
135
 
        mutex_create(trx_undo_mutex_key, &trx->undo_mutex, SYNC_TRX_UNDO);
136
 
 
137
 
        trx->rseg = NULL;
138
 
 
139
 
        trx->undo_no = 0;
140
 
        trx->last_sql_stat_start.least_undo_no = 0;
141
 
        trx->insert_undo = NULL;
142
 
        trx->update_undo = NULL;
143
 
        trx->undo_no_arr = NULL;
144
 
 
145
 
        trx->error_state = DB_SUCCESS;
146
 
        trx->error_key_num = 0;
147
 
        trx->detailed_error[0] = '\0';
148
 
 
149
 
        trx->sess = sess;
150
 
        trx->que_state = TRX_QUE_RUNNING;
151
 
        trx->n_active_thrs = 0;
152
 
 
153
 
        trx->handling_signals = FALSE;
154
 
 
155
 
        UT_LIST_INIT(trx->signals);
156
 
        UT_LIST_INIT(trx->reply_signals);
157
 
 
158
 
        trx->graph = NULL;
159
 
 
160
 
        trx->wait_lock = NULL;
161
 
        trx->was_chosen_as_deadlock_victim = FALSE;
162
 
        UT_LIST_INIT(trx->wait_thrs);
163
 
 
164
 
        trx->lock_heap = mem_heap_create_in_buffer(256);
165
 
        UT_LIST_INIT(trx->trx_locks);
166
 
 
167
 
        UT_LIST_INIT(trx->trx_savepoints);
168
 
 
169
 
        trx->dict_operation_lock_mode = 0;
170
 
        trx->has_search_latch = FALSE;
171
 
        trx->search_latch_timeout = BTR_SEA_TIMEOUT;
172
 
 
173
 
        trx->declared_to_be_inside_innodb = FALSE;
174
 
        trx->n_tickets_to_enter_innodb = 0;
175
 
 
176
 
        trx->global_read_view_heap = mem_heap_create(256);
177
 
        trx->global_read_view = NULL;
178
 
        trx->read_view = NULL;
179
 
 
180
 
        /* Set X/Open XA transaction identification to NULL */
181
 
        memset(&trx->xid, 0, sizeof(trx->xid));
182
 
        trx->xid.formatID = -1;
183
 
 
184
 
        trx->n_autoinc_rows = 0;
185
 
 
186
 
        /* Remember to free the vector explicitly. */
187
 
        trx->autoinc_locks = ib_vector_create(
188
 
                mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
189
 
 
190
 
        return(trx);
191
 
}
192
 
 
193
 
/********************************************************************//**
194
 
Creates a transaction object for MySQL.
195
 
@return own: transaction object */
196
 
UNIV_INTERN
197
 
trx_t*
198
 
trx_allocate_for_mysql(void)
199
 
/*========================*/
200
 
{
201
 
        trx_t*  trx;
202
 
 
203
 
        mutex_enter(&kernel_mutex);
204
 
 
205
 
        trx = trx_create(trx_dummy_sess);
206
 
 
207
 
        trx_n_mysql_transactions++;
208
 
 
209
 
        UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
210
 
 
211
 
        mutex_exit(&kernel_mutex);
212
 
 
213
 
        trx->mysql_thread_id = os_thread_get_curr_id();
214
 
 
215
 
        trx->mysql_process_no = os_proc_get_number();
216
 
 
217
 
        return(trx);
218
 
}
219
 
 
220
 
/********************************************************************//**
221
 
Creates a transaction object for background operations by the master thread.
222
 
@return own: transaction object */
223
 
UNIV_INTERN
224
 
trx_t*
225
 
trx_allocate_for_background(void)
226
 
/*=============================*/
227
 
{
228
 
        trx_t*  trx;
229
 
 
230
 
        mutex_enter(&kernel_mutex);
231
 
 
232
 
        trx = trx_create(trx_dummy_sess);
233
 
 
234
 
        mutex_exit(&kernel_mutex);
235
 
 
236
 
        return(trx);
237
 
}
238
 
 
239
 
/********************************************************************//**
240
 
Releases the search latch if trx has reserved it. */
241
 
UNIV_INTERN
242
 
void
243
 
trx_search_latch_release_if_reserved(
244
 
/*=================================*/
245
 
        trx_t*     trx) /*!< in: transaction */
246
 
{
247
 
        if (trx->has_search_latch) {
248
 
                rw_lock_s_unlock(&btr_search_latch);
249
 
 
250
 
                trx->has_search_latch = FALSE;
251
 
        }
252
 
}
253
 
 
254
 
/********************************************************************//**
255
 
Frees a transaction object. */
256
 
UNIV_INTERN
257
 
void
258
 
trx_free(
259
 
/*=====*/
260
 
        trx_t*  trx)    /*!< in, own: trx object */
261
 
{
262
 
        ut_ad(mutex_own(&kernel_mutex));
263
 
 
264
 
        if (trx->declared_to_be_inside_innodb) {
265
 
                ut_print_timestamp(stderr);
266
 
                fputs("  InnoDB: Error: Freeing a trx which is declared"
267
 
                      " to be processing\n"
268
 
                      "InnoDB: inside InnoDB.\n", stderr);
269
 
                trx_print(stderr, trx, 600);
270
 
                putc('\n', stderr);
271
 
 
272
 
                /* This is an error but not a fatal error. We must keep
273
 
                the counters like srv_conc_n_threads accurate. */
274
 
                srv_conc_force_exit_innodb(trx);
275
 
        }
276
 
 
277
 
        if (trx->mysql_n_tables_locked != 0) {
278
 
 
279
 
                ut_print_timestamp(stderr);
280
 
                fprintf(stderr,
281
 
                        "  InnoDB: Error: MySQL is freeing a thd\n"
282
 
                        "InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
283
 
                        (ulong)trx->mysql_n_tables_locked);
284
 
 
285
 
                trx_print(stderr, trx, 600);
286
 
 
287
 
                ut_print_buf(stderr, trx, sizeof(trx_t));
288
 
                putc('\n', stderr);
289
 
        }
290
 
 
291
 
        ut_a(trx->magic_n == TRX_MAGIC_N);
292
 
 
293
 
        trx->magic_n = 11112222;
294
 
 
295
 
        ut_a(trx->conc_state == TRX_NOT_STARTED);
296
 
 
297
 
        mutex_free(&(trx->undo_mutex));
298
 
 
299
 
        ut_a(trx->insert_undo == NULL);
300
 
        ut_a(trx->update_undo == NULL);
301
 
 
302
 
        if (trx->undo_no_arr) {
303
 
                trx_undo_arr_free(trx->undo_no_arr);
304
 
        }
305
 
 
306
 
        ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
307
 
        ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
308
 
 
309
 
        ut_a(trx->wait_lock == NULL);
310
 
        ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
311
 
 
312
 
        ut_a(!trx->has_search_latch);
313
 
 
314
 
        ut_a(trx->dict_operation_lock_mode == 0);
315
 
 
316
 
        if (trx->lock_heap) {
317
 
                mem_heap_free(trx->lock_heap);
318
 
        }
319
 
 
320
 
        ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0);
321
 
 
322
 
        if (trx->global_read_view_heap) {
323
 
                mem_heap_free(trx->global_read_view_heap);
324
 
        }
325
 
 
326
 
        trx->global_read_view = NULL;
327
 
 
328
 
        ut_a(trx->read_view == NULL);
329
 
 
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);
333
 
 
334
 
        mem_free(trx);
335
 
}
336
 
 
337
 
/********************************************************************//**
338
 
Frees a transaction object for MySQL. */
339
 
UNIV_INTERN
340
 
void
341
 
trx_free_for_mysql(
342
 
/*===============*/
343
 
        trx_t*  trx)    /*!< in, own: trx object */
344
 
{
345
 
        mutex_enter(&kernel_mutex);
346
 
 
347
 
        UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
348
 
 
349
 
        trx_free(trx);
350
 
 
351
 
        ut_a(trx_n_mysql_transactions > 0);
352
 
 
353
 
        trx_n_mysql_transactions--;
354
 
 
355
 
        mutex_exit(&kernel_mutex);
356
 
}
357
 
 
358
 
/********************************************************************//**
359
 
Frees a transaction object of a background operation of the master thread. */
360
 
UNIV_INTERN
361
 
void
362
 
trx_free_for_background(
363
 
/*====================*/
364
 
        trx_t*  trx)    /*!< in, own: trx object */
365
 
{
366
 
        mutex_enter(&kernel_mutex);
367
 
 
368
 
        trx_free(trx);
369
 
 
370
 
        mutex_exit(&kernel_mutex);
371
 
}
372
 
 
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. */
378
 
static
379
 
void
380
 
trx_list_insert_ordered(
381
 
/*====================*/
382
 
        trx_t*  trx)    /*!< in: trx handle */
383
 
{
384
 
        trx_t*  trx2;
385
 
 
386
 
        ut_ad(mutex_own(&kernel_mutex));
387
 
 
388
 
        trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list);
389
 
 
390
 
        while (trx2 != NULL) {
391
 
                if (trx->id >= trx2->id) {
392
 
 
393
 
                        ut_ad(trx->id > trx2->id);
394
 
                        break;
395
 
                }
396
 
                trx2 = UT_LIST_GET_NEXT(trx_list, trx2);
397
 
        }
398
 
 
399
 
        if (trx2 != NULL) {
400
 
                trx2 = UT_LIST_GET_PREV(trx_list, trx2);
401
 
 
402
 
                if (trx2 == NULL) {
403
 
                        UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
404
 
                } else {
405
 
                        UT_LIST_INSERT_AFTER(trx_list, trx_sys->trx_list,
406
 
                                             trx2, trx);
407
 
                }
408
 
        } else {
409
 
                UT_LIST_ADD_LAST(trx_list, trx_sys->trx_list, trx);
410
 
        }
411
 
}
412
 
 
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
418
 
undo log lists. */
419
 
UNIV_INTERN
420
 
void
421
 
trx_lists_init_at_db_start(void)
422
 
/*============================*/
423
 
{
424
 
        trx_rseg_t*     rseg;
425
 
        trx_undo_t*     undo;
426
 
        trx_t*          trx;
427
 
 
428
 
        ut_ad(mutex_own(&kernel_mutex));
429
 
        UT_LIST_INIT(trx_sys->trx_list);
430
 
 
431
 
        /* Look from the rollback segments if there exist undo logs for
432
 
        transactions */
433
 
 
434
 
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
435
 
 
436
 
        while (rseg != NULL) {
437
 
                undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
438
 
 
439
 
                while (undo != NULL) {
440
 
 
441
 
                        trx = trx_create(trx_dummy_sess);
442
 
 
443
 
                        trx->is_recovered = TRUE;
444
 
                        trx->id = undo->trx_id;
445
 
                        trx->xid = undo->xid;
446
 
                        trx->insert_undo = undo;
447
 
                        trx->rseg = rseg;
448
 
 
449
 
                        if (undo->state != TRX_UNDO_ACTIVE) {
450
 
 
451
 
                                /* Prepared transactions are left in
452
 
                                the prepared state waiting for a
453
 
                                commit or abort decision from MySQL */
454
 
 
455
 
                                if (undo->state == TRX_UNDO_PREPARED) {
456
 
 
457
 
                                        fprintf(stderr,
458
 
                                                "InnoDB: Transaction "
459
 
                                                TRX_ID_FMT
460
 
                                                " was in the"
461
 
                                                " XA prepared state.\n",
462
 
                                                trx->id);
463
 
 
464
 
                                        if (srv_force_recovery == 0) {
465
 
 
466
 
                                                trx->conc_state = TRX_PREPARED;
467
 
                                        } else {
468
 
                                                fprintf(stderr,
469
 
                                                        "InnoDB: Since"
470
 
                                                        " innodb_force_recovery"
471
 
                                                        " > 0, we will"
472
 
                                                        " rollback it"
473
 
                                                        " anyway.\n");
474
 
 
475
 
                                                trx->conc_state = TRX_ACTIVE;
476
 
                                        }
477
 
                                } else {
478
 
                                        trx->conc_state
479
 
                                                = TRX_COMMITTED_IN_MEMORY;
480
 
                                }
481
 
 
482
 
                                /* We give a dummy value for the trx no;
483
 
                                this should have no relevance since purge
484
 
                                is not interested in committed transaction
485
 
                                numbers, unless they are in the history
486
 
                                list, in which case it looks the number
487
 
                                from the disk based undo log structure */
488
 
 
489
 
                                trx->no = trx->id;
490
 
                        } else {
491
 
                                trx->conc_state = TRX_ACTIVE;
492
 
 
493
 
                                /* A running transaction always has the number
494
 
                                field inited to IB_ULONGLONG_MAX */
495
 
 
496
 
                                trx->no = IB_ULONGLONG_MAX;
497
 
                        }
498
 
 
499
 
                        if (undo->dict_operation) {
500
 
                                trx_set_dict_operation(
501
 
                                        trx, TRX_DICT_OP_TABLE);
502
 
                                trx->table_id = undo->table_id;
503
 
                        }
504
 
 
505
 
                        if (!undo->empty) {
506
 
                                trx->undo_no = undo->top_undo_no + 1;
507
 
                        }
508
 
 
509
 
                        trx_list_insert_ordered(trx);
510
 
 
511
 
                        undo = UT_LIST_GET_NEXT(undo_list, undo);
512
 
                }
513
 
 
514
 
                undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
515
 
 
516
 
                while (undo != NULL) {
517
 
                        trx = trx_get_on_id(undo->trx_id);
518
 
 
519
 
                        if (NULL == trx) {
520
 
                                trx = trx_create(trx_dummy_sess);
521
 
 
522
 
                                trx->is_recovered = TRUE;
523
 
                                trx->id = undo->trx_id;
524
 
                                trx->xid = undo->xid;
525
 
 
526
 
                                if (undo->state != TRX_UNDO_ACTIVE) {
527
 
 
528
 
                                        /* Prepared transactions are left in
529
 
                                        the prepared state waiting for a
530
 
                                        commit or abort decision from MySQL */
531
 
 
532
 
                                        if (undo->state == TRX_UNDO_PREPARED) {
533
 
                                                fprintf(stderr,
534
 
                                                        "InnoDB: Transaction "
535
 
                                                        TRX_ID_FMT " was in the"
536
 
                                                        " XA prepared state.\n",
537
 
                                                        trx->id);
538
 
 
539
 
                                                if (srv_force_recovery == 0) {
540
 
 
541
 
                                                        trx->conc_state
542
 
                                                                = TRX_PREPARED;
543
 
                                                } else {
544
 
                                                        fprintf(stderr,
545
 
                                                                "InnoDB: Since"
546
 
                                                                " innodb_force_recovery"
547
 
                                                                " > 0, we will"
548
 
                                                                " rollback it"
549
 
                                                                " anyway.\n");
550
 
 
551
 
                                                        trx->conc_state
552
 
                                                                = TRX_ACTIVE;
553
 
                                                }
554
 
                                        } else {
555
 
                                                trx->conc_state
556
 
                                                        = TRX_COMMITTED_IN_MEMORY;
557
 
                                        }
558
 
 
559
 
                                        /* We give a dummy value for the trx
560
 
                                        number */
561
 
 
562
 
                                        trx->no = trx->id;
563
 
                                } else {
564
 
                                        trx->conc_state = TRX_ACTIVE;
565
 
 
566
 
                                        /* A running transaction always has
567
 
                                        the number field inited to
568
 
                                        IB_ULONGLONG_MAX */
569
 
 
570
 
                                        trx->no = IB_ULONGLONG_MAX;
571
 
                                }
572
 
 
573
 
                                trx->rseg = rseg;
574
 
                                trx_list_insert_ordered(trx);
575
 
 
576
 
                                if (undo->dict_operation) {
577
 
                                        trx_set_dict_operation(
578
 
                                                trx, TRX_DICT_OP_TABLE);
579
 
                                        trx->table_id = undo->table_id;
580
 
                                }
581
 
                        }
582
 
 
583
 
                        trx->update_undo = undo;
584
 
 
585
 
                        if ((!undo->empty)
586
 
                            && undo->top_undo_no >= trx->undo_no) {
587
 
 
588
 
                                trx->undo_no = undo->top_undo_no + 1;
589
 
                        }
590
 
 
591
 
                        undo = UT_LIST_GET_NEXT(undo_list, undo);
592
 
                }
593
 
 
594
 
                rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
595
 
        }
596
 
}
597
 
 
598
 
/******************************************************************//**
599
 
Assigns a rollback segment to a transaction in a round-robin fashion.
600
 
Skips the SYSTEM rollback segment if another is available.
601
 
@return assigned rollback segment id */
602
 
UNIV_INLINE
603
 
ulint
604
 
trx_assign_rseg(void)
605
 
/*=================*/
606
 
{
607
 
        trx_rseg_t*     rseg    = trx_sys->latest_rseg;
608
 
 
609
 
        ut_ad(mutex_own(&kernel_mutex));
610
 
loop:
611
 
        /* Get next rseg in a round-robin fashion */
612
 
 
613
 
        rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
614
 
 
615
 
        if (rseg == NULL) {
616
 
                rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
617
 
        }
618
 
 
619
 
        /* If it is the SYSTEM rollback segment, and there exist others, skip
620
 
        it */
621
 
 
622
 
        if ((rseg->id == TRX_SYS_SYSTEM_RSEG_ID)
623
 
            && (UT_LIST_GET_LEN(trx_sys->rseg_list) > 1)) {
624
 
                goto loop;
625
 
        }
626
 
 
627
 
        trx_sys->latest_rseg = rseg;
628
 
 
629
 
        return(rseg->id);
630
 
}
631
 
 
632
 
/****************************************************************//**
633
 
Starts a new transaction.
634
 
@return TRUE */
635
 
UNIV_INTERN
636
 
ibool
637
 
trx_start_low(
638
 
/*==========*/
639
 
        trx_t*  trx,    /*!< in: transaction */
640
 
        ulint   rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
641
 
                        is passed, the system chooses the rollback segment
642
 
                        automatically in a round-robin fashion */
643
 
{
644
 
        trx_rseg_t*     rseg;
645
 
 
646
 
        ut_ad(mutex_own(&kernel_mutex));
647
 
        ut_ad(trx->rseg == NULL);
648
 
 
649
 
        if (trx->is_purge) {
650
 
                trx->id = 0;
651
 
                trx->conc_state = TRX_ACTIVE;
652
 
                trx->start_time = time(NULL);
653
 
 
654
 
                return(TRUE);
655
 
        }
656
 
 
657
 
        ut_ad(trx->conc_state != TRX_ACTIVE);
658
 
 
659
 
        if (rseg_id == ULINT_UNDEFINED) {
660
 
 
661
 
                rseg_id = trx_assign_rseg();
662
 
        }
663
 
 
664
 
        rseg = trx_sys_get_nth_rseg(trx_sys, rseg_id);
665
 
 
666
 
        trx->id = trx_sys_get_new_trx_id();
667
 
 
668
 
        /* The initial value for trx->no: IB_ULONGLONG_MAX is used in
669
 
        read_view_open_now: */
670
 
 
671
 
        trx->no = IB_ULONGLONG_MAX;
672
 
 
673
 
        trx->rseg = rseg;
674
 
 
675
 
        trx->conc_state = TRX_ACTIVE;
676
 
        trx->start_time = time(NULL);
677
 
 
678
 
        UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
679
 
 
680
 
        return(TRUE);
681
 
}
682
 
 
683
 
/****************************************************************//**
684
 
Starts a new transaction.
685
 
@return TRUE */
686
 
UNIV_INTERN
687
 
ibool
688
 
trx_start(
689
 
/*======*/
690
 
        trx_t*  trx,    /*!< in: transaction */
691
 
        ulint   rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
692
 
                        is passed, the system chooses the rollback segment
693
 
                        automatically in a round-robin fashion */
694
 
{
695
 
        ibool   ret;
696
 
 
697
 
        /* Update the info whether we should skip XA steps that eat CPU time
698
 
        For the duration of the transaction trx->support_xa is not reread
699
 
        from thd so any changes in the value take effect in the next
700
 
        transaction. This is to avoid a scenario where some undo
701
 
        generated by a transaction, has XA stuff, and other undo,
702
 
        generated by the same transaction, doesn't. */
703
 
        trx->support_xa = thd_supports_xa(trx->mysql_thd);
704
 
 
705
 
        mutex_enter(&kernel_mutex);
706
 
 
707
 
        ret = trx_start_low(trx, rseg_id);
708
 
 
709
 
        mutex_exit(&kernel_mutex);
710
 
 
711
 
        return(ret);
712
 
}
713
 
 
714
 
/****************************************************************//**
715
 
Commits a transaction. */
716
 
UNIV_INTERN
717
 
void
718
 
trx_commit_off_kernel(
719
 
/*==================*/
720
 
        trx_t*  trx)    /*!< in: transaction */
721
 
{
722
 
        page_t*         update_hdr_page;
723
 
        ib_uint64_t     lsn             = 0;
724
 
        trx_rseg_t*     rseg;
725
 
        trx_undo_t*     undo;
726
 
        mtr_t           mtr;
727
 
 
728
 
        ut_ad(mutex_own(&kernel_mutex));
729
 
 
730
 
        trx->must_flush_log_later = FALSE;
731
 
 
732
 
        rseg = trx->rseg;
733
 
 
734
 
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
735
 
 
736
 
                mutex_exit(&kernel_mutex);
737
 
 
738
 
                mtr_start(&mtr);
739
 
 
740
 
                /* Change the undo log segment states from TRX_UNDO_ACTIVE
741
 
                to some other state: these modifications to the file data
742
 
                structure define the transaction as committed in the file
743
 
                based world, at the serialization point of the log sequence
744
 
                number lsn obtained below. */
745
 
 
746
 
                mutex_enter(&(rseg->mutex));
747
 
 
748
 
                if (trx->insert_undo != NULL) {
749
 
                        trx_undo_set_state_at_finish(
750
 
                                rseg, trx, trx->insert_undo, &mtr);
751
 
                }
752
 
 
753
 
                undo = trx->update_undo;
754
 
 
755
 
                if (undo) {
756
 
                        mutex_enter(&kernel_mutex);
757
 
                        trx->no = trx_sys_get_new_trx_no();
758
 
                        mutex_exit(&kernel_mutex);
759
 
 
760
 
                        /* It is not necessary to obtain trx->undo_mutex here
761
 
                        because only a single OS thread is allowed to do the
762
 
                        transaction commit for this transaction. */
763
 
 
764
 
                        update_hdr_page = trx_undo_set_state_at_finish(
765
 
                                rseg, trx, undo, &mtr);
766
 
 
767
 
                        /* We have to do the cleanup for the update log while
768
 
                        holding the rseg mutex because update log headers
769
 
                        have to be put to the history list in the order of
770
 
                        the trx number. */
771
 
 
772
 
                        trx_undo_update_cleanup(trx, update_hdr_page, &mtr);
773
 
                }
774
 
 
775
 
                mutex_exit(&(rseg->mutex));
776
 
 
777
 
                /* Update the latest MySQL binlog name and offset info
778
 
                in trx sys header if MySQL binlogging is on or the database
779
 
                server is a MySQL replication slave */
780
 
 
781
 
                if (trx->mysql_log_file_name
782
 
                    && trx->mysql_log_file_name[0] != '\0') {
783
 
                        trx_sys_update_mysql_binlog_offset(
784
 
                                trx->mysql_log_file_name,
785
 
                                trx->mysql_log_offset,
786
 
                                TRX_SYS_MYSQL_LOG_INFO, &mtr);
787
 
                        trx->mysql_log_file_name = NULL;
788
 
                }
789
 
 
790
 
                /* The following call commits the mini-transaction, making the
791
 
                whole transaction committed in the file-based world, at this
792
 
                log sequence number. The transaction becomes 'durable' when
793
 
                we write the log to disk, but in the logical sense the commit
794
 
                in the file-based data structures (undo logs etc.) happens
795
 
                here.
796
 
 
797
 
                NOTE that transaction numbers, which are assigned only to
798
 
                transactions with an update undo log, do not necessarily come
799
 
                in exactly the same order as commit lsn's, if the transactions
800
 
                have different rollback segments. To get exactly the same
801
 
                order we should hold the kernel mutex up to this point,
802
 
                adding to the contention of the kernel mutex. However, if
803
 
                a transaction T2 is able to see modifications made by
804
 
                a transaction T1, T2 will always get a bigger transaction
805
 
                number and a bigger commit lsn than T1. */
806
 
 
807
 
                /*--------------*/
808
 
                mtr_commit(&mtr);
809
 
                /*--------------*/
810
 
                lsn = mtr.end_lsn;
811
 
 
812
 
                mutex_enter(&kernel_mutex);
813
 
        }
814
 
 
815
 
        ut_ad(trx->conc_state == TRX_ACTIVE
816
 
              || trx->conc_state == TRX_PREPARED);
817
 
        ut_ad(mutex_own(&kernel_mutex));
818
 
 
819
 
        /* The following assignment makes the transaction committed in memory
820
 
        and makes its changes to data visible to other transactions.
821
 
        NOTE that there is a small discrepancy from the strict formal
822
 
        visibility rules here: a human user of the database can see
823
 
        modifications made by another transaction T even before the necessary
824
 
        log segment has been flushed to the disk. If the database happens to
825
 
        crash before the flush, the user has seen modifications from T which
826
 
        will never be a committed transaction. However, any transaction T2
827
 
        which sees the modifications of the committing transaction T, and
828
 
        which also itself makes modifications to the database, will get an lsn
829
 
        larger than the committing transaction T. In the case where the log
830
 
        flush fails, and T never gets committed, also T2 will never get
831
 
        committed. */
832
 
 
833
 
        /*--------------------------------------*/
834
 
        trx->conc_state = TRX_COMMITTED_IN_MEMORY;
835
 
        /*--------------------------------------*/
836
 
 
837
 
        /* If we release kernel_mutex below and we are still doing
838
 
        recovery i.e.: back ground rollback thread is still active
839
 
        then there is a chance that the rollback thread may see
840
 
        this trx as COMMITTED_IN_MEMORY and goes adhead to clean it
841
 
        up calling trx_cleanup_at_db_startup(). This can happen
842
 
        in the case we are committing a trx here that is left in
843
 
        PREPARED state during the crash. Note that commit of the
844
 
        rollback of a PREPARED trx happens in the recovery thread
845
 
        while the rollback of other transactions happen in the
846
 
        background thread. To avoid this race we unconditionally
847
 
        unset the is_recovered flag from the trx. */
848
 
 
849
 
        trx->is_recovered = FALSE;
850
 
 
851
 
        lock_release_off_kernel(trx);
852
 
 
853
 
        if (trx->global_read_view) {
854
 
                read_view_close(trx->global_read_view);
855
 
                mem_heap_empty(trx->global_read_view_heap);
856
 
                trx->global_read_view = NULL;
857
 
        }
858
 
 
859
 
        trx->read_view = NULL;
860
 
 
861
 
        if (lsn) {
862
 
 
863
 
                mutex_exit(&kernel_mutex);
864
 
 
865
 
                if (trx->insert_undo != NULL) {
866
 
 
867
 
                        trx_undo_insert_cleanup(trx);
868
 
                }
869
 
 
870
 
                /* NOTE that we could possibly make a group commit more
871
 
                efficient here: call os_thread_yield here to allow also other
872
 
                trxs to come to commit! */
873
 
 
874
 
                /*-------------------------------------*/
875
 
 
876
 
                /* Depending on the my.cnf options, we may now write the log
877
 
                buffer to the log files, making the transaction durable if
878
 
                the OS does not crash. We may also flush the log files to
879
 
                disk, making the transaction durable also at an OS crash or a
880
 
                power outage.
881
 
 
882
 
                The idea in InnoDB's group commit is that a group of
883
 
                transactions gather behind a trx doing a physical disk write
884
 
                to log files, and when that physical write has been completed,
885
 
                one of those transactions does a write which commits the whole
886
 
                group. Note that this group commit will only bring benefit if
887
 
                there are > 2 users in the database. Then at least 2 users can
888
 
                gather behind one doing the physical log write to disk.
889
 
 
890
 
                If we are calling trx_commit() under prepare_commit_mutex, we
891
 
                will delay possible log write and flush to a separate function
892
 
                trx_commit_complete_for_mysql(), which is only called when the
893
 
                thread has released the mutex. This is to make the
894
 
                group commit algorithm to work. Otherwise, the prepare_commit
895
 
                mutex would serialize all commits and prevent a group of
896
 
                transactions from gathering. */
897
 
 
898
 
                if (trx->flush_log_later) {
899
 
                        /* Do nothing yet */
900
 
                        trx->must_flush_log_later = TRUE;
901
 
                } else if (srv_flush_log_at_trx_commit == 0) {
902
 
                        /* Do nothing */
903
 
                } else if (srv_flush_log_at_trx_commit == 1) {
904
 
                        if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
905
 
                                /* Write the log but do not flush it to disk */
906
 
 
907
 
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
908
 
                                                FALSE);
909
 
                        } else {
910
 
                                /* Write the log to the log files AND flush
911
 
                                them to disk */
912
 
 
913
 
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
914
 
                        }
915
 
                } else if (srv_flush_log_at_trx_commit == 2) {
916
 
 
917
 
                        /* Write the log but do not flush it to disk */
918
 
 
919
 
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
920
 
                } else {
921
 
                        ut_error;
922
 
                }
923
 
 
924
 
                trx->commit_lsn = lsn;
925
 
 
926
 
                /*-------------------------------------*/
927
 
 
928
 
                mutex_enter(&kernel_mutex);
929
 
        }
930
 
 
931
 
        /* Free all savepoints */
932
 
        trx_roll_free_all_savepoints(trx);
933
 
 
934
 
        trx->conc_state = TRX_NOT_STARTED;
935
 
        trx->rseg = NULL;
936
 
        trx->undo_no = 0;
937
 
        trx->last_sql_stat_start.least_undo_no = 0;
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 = 0;
963
 
        trx->last_sql_stat_start.least_undo_no = 0;
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 = 0;
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. */
1635
 
UNIV_INTERN
1636
 
void
1637
 
trx_print(
1638
 
/*======*/
1639
 
        FILE*   f,              /*!< in: output stream */
1640
 
        trx_t*  trx,            /*!< in: transaction */
1641
 
        ulint   max_query_len)  /*!< in: max query length to print, or 0 to
1642
 
                                   use the default max length */
1643
 
{
1644
 
        ibool   newline;
1645
 
 
1646
 
        fprintf(f, "TRANSACTION " TRX_ID_FMT, trx->id);
1647
 
 
1648
 
        switch (trx->conc_state) {
1649
 
        case TRX_NOT_STARTED:
1650
 
                fputs(", not started", f);
1651
 
                break;
1652
 
        case TRX_ACTIVE:
1653
 
                fprintf(f, ", ACTIVE %lu sec",
1654
 
                        (ulong)difftime(time(NULL), trx->start_time));
1655
 
                break;
1656
 
        case TRX_PREPARED:
1657
 
                fprintf(f, ", ACTIVE (PREPARED) %lu sec",
1658
 
                        (ulong)difftime(time(NULL), trx->start_time));
1659
 
                break;
1660
 
        case TRX_COMMITTED_IN_MEMORY:
1661
 
                fputs(", COMMITTED IN MEMORY", f);
1662
 
                break;
1663
 
        default:
1664
 
                fprintf(f, " state %lu", (ulong) trx->conc_state);
1665
 
        }
1666
 
 
1667
 
#ifdef UNIV_LINUX
1668
 
        fprintf(f, ", process no %lu", trx->mysql_process_no);
1669
 
#endif
1670
 
        fprintf(f, ", OS thread id %lu",
1671
 
                (ulong) os_thread_pf(trx->mysql_thread_id));
1672
 
 
1673
 
        if (*trx->op_info) {
1674
 
                putc(' ', f);
1675
 
                fputs(trx->op_info, f);
1676
 
        }
1677
 
 
1678
 
        if (trx->is_recovered) {
1679
 
                fputs(" recovered trx", f);
1680
 
        }
1681
 
 
1682
 
        if (trx->is_purge) {
1683
 
                fputs(" purge trx", f);
1684
 
        }
1685
 
 
1686
 
        if (trx->declared_to_be_inside_innodb) {
1687
 
                fprintf(f, ", thread declared inside InnoDB %lu",
1688
 
                        (ulong) trx->n_tickets_to_enter_innodb);
1689
 
        }
1690
 
 
1691
 
        putc('\n', f);
1692
 
 
1693
 
        if (trx->mysql_n_tables_locked > 0) {
1694
 
                fprintf(f, "mysql tables in locked %lu\n",
1695
 
                        (ulong) trx->mysql_n_tables_locked);
1696
 
        }
1697
 
 
1698
 
        newline = TRUE;
1699
 
 
1700
 
        switch (trx->que_state) {
1701
 
        case TRX_QUE_RUNNING:
1702
 
                newline = FALSE; break;
1703
 
        case TRX_QUE_LOCK_WAIT:
1704
 
                fputs("LOCK WAIT ", f); break;
1705
 
        case TRX_QUE_ROLLING_BACK:
1706
 
                fputs("ROLLING BACK ", f); break;
1707
 
        case TRX_QUE_COMMITTING:
1708
 
                fputs("COMMITTING ", f); break;
1709
 
        default:
1710
 
                fprintf(f, "que state %lu ", (ulong) trx->que_state);
1711
 
        }
1712
 
 
1713
 
        if (0 < UT_LIST_GET_LEN(trx->trx_locks)
1714
 
            || mem_heap_get_size(trx->lock_heap) > 400) {
1715
 
                newline = TRUE;
1716
 
 
1717
 
                fprintf(f, "%lu lock struct(s), heap size %lu,"
1718
 
                        " %lu row lock(s)",
1719
 
                        (ulong) UT_LIST_GET_LEN(trx->trx_locks),
1720
 
                        (ulong) mem_heap_get_size(trx->lock_heap),
1721
 
                        (ulong) lock_number_of_rows_locked(trx));
1722
 
        }
1723
 
 
1724
 
        if (trx->has_search_latch) {
1725
 
                newline = TRUE;
1726
 
                fputs(", holds adaptive hash latch", f);
1727
 
        }
1728
 
 
1729
 
        if (trx->undo_no != 0) {
1730
 
                newline = TRUE;
1731
 
                fprintf(f, ", undo log entries %llu",
1732
 
                        (ullint) trx->undo_no);
1733
 
        }
1734
 
 
1735
 
        if (newline) {
1736
 
                putc('\n', f);
1737
 
        }
1738
 
 
1739
 
        if (trx->mysql_thd != NULL) {
1740
 
                innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
1741
 
        }
1742
 
}
1743
 
 
1744
 
/*******************************************************************//**
1745
 
Compares the "weight" (or size) of two transactions. Transactions that
1746
 
have edited non-transactional tables are considered heavier than ones
1747
 
that have not.
1748
 
@return TRUE if weight(a) >= weight(b) */
1749
 
UNIV_INTERN
1750
 
ibool
1751
 
trx_weight_ge(
1752
 
/*==========*/
1753
 
        const trx_t*    a,      /*!< in: the first transaction to be compared */
1754
 
        const trx_t*    b)      /*!< in: the second transaction to be compared */
1755
 
{
1756
 
        ibool   a_notrans_edit;
1757
 
        ibool   b_notrans_edit;
1758
 
 
1759
 
        /* If mysql_thd is NULL for a transaction we assume that it has
1760
 
        not edited non-transactional tables. */
1761
 
 
1762
 
        a_notrans_edit = a->mysql_thd != NULL
1763
 
                && thd_has_edited_nontrans_tables(a->mysql_thd);
1764
 
 
1765
 
        b_notrans_edit = b->mysql_thd != NULL
1766
 
                && thd_has_edited_nontrans_tables(b->mysql_thd);
1767
 
 
1768
 
        if (a_notrans_edit != b_notrans_edit) {
1769
 
 
1770
 
                return(a_notrans_edit);
1771
 
        }
1772
 
 
1773
 
        /* Either both had edited non-transactional tables or both had
1774
 
        not, we fall back to comparing the number of altered/locked
1775
 
        rows. */
1776
 
 
1777
 
#if 0
1778
 
        fprintf(stderr,
1779
 
                "%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n",
1780
 
                __func__,
1781
 
                a->undo_no, UT_LIST_GET_LEN(a->trx_locks),
1782
 
                b->undo_no, UT_LIST_GET_LEN(b->trx_locks));
1783
 
#endif
1784
 
 
1785
 
        return(TRX_WEIGHT(a) >= TRX_WEIGHT(b));
1786
 
}
1787
 
 
1788
 
/****************************************************************//**
1789
 
Prepares a transaction. */
1790
 
UNIV_INLINE
1791
 
void
1792
 
trx_prepare_off_kernel(
1793
 
/*===================*/
1794
 
        trx_t*  trx)    /*!< in: transaction */
1795
 
{
1796
 
        trx_rseg_t*     rseg;
1797
 
        ib_uint64_t     lsn             = 0;
1798
 
        mtr_t           mtr;
1799
 
 
1800
 
        ut_ad(mutex_own(&kernel_mutex));
1801
 
 
1802
 
        rseg = trx->rseg;
1803
 
 
1804
 
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
1805
 
 
1806
 
                mutex_exit(&kernel_mutex);
1807
 
 
1808
 
                mtr_start(&mtr);
1809
 
 
1810
 
                /* Change the undo log segment states from TRX_UNDO_ACTIVE
1811
 
                to TRX_UNDO_PREPARED: these modifications to the file data
1812
 
                structure define the transaction as prepared in the
1813
 
                file-based world, at the serialization point of lsn. */
1814
 
 
1815
 
                mutex_enter(&(rseg->mutex));
1816
 
 
1817
 
                if (trx->insert_undo != NULL) {
1818
 
 
1819
 
                        /* It is not necessary to obtain trx->undo_mutex here
1820
 
                        because only a single OS thread is allowed to do the
1821
 
                        transaction prepare for this transaction. */
1822
 
 
1823
 
                        trx_undo_set_state_at_prepare(trx, trx->insert_undo,
1824
 
                                                      &mtr);
1825
 
                }
1826
 
 
1827
 
                if (trx->update_undo) {
1828
 
                        trx_undo_set_state_at_prepare(
1829
 
                                trx, trx->update_undo, &mtr);
1830
 
                }
1831
 
 
1832
 
                mutex_exit(&(rseg->mutex));
1833
 
 
1834
 
                /*--------------*/
1835
 
                mtr_commit(&mtr);       /* This mtr commit makes the
1836
 
                                        transaction prepared in the file-based
1837
 
                                        world */
1838
 
                /*--------------*/
1839
 
                lsn = mtr.end_lsn;
1840
 
 
1841
 
                mutex_enter(&kernel_mutex);
1842
 
        }
1843
 
 
1844
 
        ut_ad(mutex_own(&kernel_mutex));
1845
 
 
1846
 
        /*--------------------------------------*/
1847
 
        trx->conc_state = TRX_PREPARED;
1848
 
        /*--------------------------------------*/
1849
 
 
1850
 
        if (lsn) {
1851
 
                /* Depending on the my.cnf options, we may now write the log
1852
 
                buffer to the log files, making the prepared state of the
1853
 
                transaction durable if the OS does not crash. We may also
1854
 
                flush the log files to disk, making the prepared state of the
1855
 
                transaction durable also at an OS crash or a power outage.
1856
 
 
1857
 
                The idea in InnoDB's group prepare is that a group of
1858
 
                transactions gather behind a trx doing a physical disk write
1859
 
                to log files, and when that physical write has been completed,
1860
 
                one of those transactions does a write which prepares the whole
1861
 
                group. Note that this group prepare will only bring benefit if
1862
 
                there are > 2 users in the database. Then at least 2 users can
1863
 
                gather behind one doing the physical log write to disk.
1864
 
 
1865
 
                TODO: find out if MySQL holds some mutex when calling this.
1866
 
                That would spoil our group prepare algorithm. */
1867
 
 
1868
 
                mutex_exit(&kernel_mutex);
1869
 
 
1870
 
                if (srv_flush_log_at_trx_commit == 0) {
1871
 
                        /* Do nothing */
1872
 
                } else if (srv_flush_log_at_trx_commit == 1) {
1873
 
                        if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
1874
 
                                /* Write the log but do not flush it to disk */
1875
 
 
1876
 
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
1877
 
                                                FALSE);
1878
 
                        } else {
1879
 
                                /* Write the log to the log files AND flush
1880
 
                                them to disk */
1881
 
 
1882
 
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
1883
 
                        }
1884
 
                } else if (srv_flush_log_at_trx_commit == 2) {
1885
 
 
1886
 
                        /* Write the log but do not flush it to disk */
1887
 
 
1888
 
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
1889
 
                } else {
1890
 
                        ut_error;
1891
 
                }
1892
 
 
1893
 
                mutex_enter(&kernel_mutex);
1894
 
        }
1895
 
}
1896
 
 
1897
 
/**********************************************************************//**
1898
 
Does the transaction prepare for MySQL.
1899
 
@return 0 or error number */
1900
 
UNIV_INTERN
1901
 
ulint
1902
 
trx_prepare_for_mysql(
1903
 
/*==================*/
1904
 
        trx_t*  trx)    /*!< in: trx handle */
1905
 
{
1906
 
        /* Because we do not do the prepare by sending an Innobase
1907
 
        sig to the transaction, we must here make sure that trx has been
1908
 
        started. */
1909
 
 
1910
 
        ut_a(trx);
1911
 
 
1912
 
        trx->op_info = "preparing";
1913
 
 
1914
 
        trx_start_if_not_started(trx);
1915
 
 
1916
 
        mutex_enter(&kernel_mutex);
1917
 
 
1918
 
        trx_prepare_off_kernel(trx);
1919
 
 
1920
 
        mutex_exit(&kernel_mutex);
1921
 
 
1922
 
        trx->op_info = "";
1923
 
 
1924
 
        return(0);
1925
 
}
1926
 
 
1927
 
/**********************************************************************//**
1928
 
This function is used to find number of prepared transactions and
1929
 
their transaction objects for a recovery.
1930
 
@return number of prepared transactions stored in xid_list */
1931
 
UNIV_INTERN
1932
 
int
1933
 
trx_recover_for_mysql(
1934
 
/*==================*/
1935
 
        XID*    xid_list,       /*!< in/out: prepared transactions */
1936
 
        ulint   len)            /*!< in: number of slots in xid_list */
1937
 
{
1938
 
        trx_t*  trx;
1939
 
        ulint   count = 0;
1940
 
 
1941
 
        ut_ad(xid_list);
1942
 
        ut_ad(len);
1943
 
 
1944
 
        /* We should set those transactions which are in the prepared state
1945
 
        to the xid_list */
1946
 
 
1947
 
        mutex_enter(&kernel_mutex);
1948
 
 
1949
 
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
1950
 
 
1951
 
        while (trx) {
1952
 
                if (trx->conc_state == TRX_PREPARED) {
1953
 
                        xid_list[count] = trx->xid;
1954
 
 
1955
 
                        if (count == 0) {
1956
 
                                ut_print_timestamp(stderr);
1957
 
                                fprintf(stderr,
1958
 
                                        "  InnoDB: Starting recovery for"
1959
 
                                        " XA transactions...\n");
1960
 
                        }
1961
 
 
1962
 
                        ut_print_timestamp(stderr);
1963
 
                        fprintf(stderr,
1964
 
                                "  InnoDB: Transaction " TRX_ID_FMT " in"
1965
 
                                " prepared state after recovery\n",
1966
 
                                trx->id);
1967
 
 
1968
 
                        ut_print_timestamp(stderr);
1969
 
                        fprintf(stderr,
1970
 
                                "  InnoDB: Transaction contains changes"
1971
 
                                " to %llu rows\n",
1972
 
                                (ullint) trx->undo_no);
1973
 
 
1974
 
                        count++;
1975
 
 
1976
 
                        if (count == len) {
1977
 
                                break;
1978
 
                        }
1979
 
                }
1980
 
 
1981
 
                trx = UT_LIST_GET_NEXT(trx_list, trx);
1982
 
        }
1983
 
 
1984
 
        mutex_exit(&kernel_mutex);
1985
 
 
1986
 
        if (count > 0){
1987
 
                ut_print_timestamp(stderr);
1988
 
                fprintf(stderr,
1989
 
                        "  InnoDB: %lu transactions in prepared state"
1990
 
                        " after recovery\n",
1991
 
                        (ulong) count);
1992
 
        }
1993
 
 
1994
 
        return ((int) count);
1995
 
}
1996
 
 
1997
 
/*******************************************************************//**
1998
 
This function is used to find one X/Open XA distributed transaction
1999
 
which is in the prepared state
2000
 
@return trx or NULL */
2001
 
UNIV_INTERN
2002
 
trx_t*
2003
 
trx_get_trx_by_xid(
2004
 
/*===============*/
2005
 
        XID*    xid)    /*!< in: X/Open XA transaction identification */
2006
 
{
2007
 
        trx_t*  trx;
2008
 
 
2009
 
        if (xid == NULL) {
2010
 
 
2011
 
                return (NULL);
2012
 
        }
2013
 
 
2014
 
        mutex_enter(&kernel_mutex);
2015
 
 
2016
 
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
2017
 
 
2018
 
        while (trx) {
2019
 
                /* Compare two X/Open XA transaction id's: their
2020
 
                length should be the same and binary comparison
2021
 
                of gtrid_length+bqual_length bytes should be
2022
 
                the same */
2023
 
 
2024
 
                if (xid->gtrid_length == trx->xid.gtrid_length
2025
 
                    && xid->bqual_length == trx->xid.bqual_length
2026
 
                    && memcmp(xid->data, trx->xid.data,
2027
 
                              xid->gtrid_length + xid->bqual_length) == 0) {
2028
 
                        break;
2029
 
                }
2030
 
 
2031
 
                trx = UT_LIST_GET_NEXT(trx_list, trx);
2032
 
        }
2033
 
 
2034
 
        mutex_exit(&kernel_mutex);
2035
 
 
2036
 
        if (trx) {
2037
 
                if (trx->conc_state != TRX_PREPARED) {
2038
 
 
2039
 
                        return(NULL);
2040
 
                }
2041
 
 
2042
 
                return(trx);
2043
 
        } else {
2044
 
                return(NULL);
2045
 
        }
2046
 
}