~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-04-25 20:45:19 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 1003.
  • Revision ID: mordred@inaugust.com-20090425204519-lgrl7mz2r66v0jby
Blackhole.

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., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 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 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, andf 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
 
}