~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/innodb_plugin/trx/trx0trx.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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->active_trans = 0;
 
124
        trx->duplicates = 0;
 
125
 
 
126
        trx->n_mysql_tables_in_use = 0;
 
127
        trx->mysql_n_tables_locked = 0;
 
128
 
 
129
        trx->mysql_log_file_name = NULL;
 
130
        trx->mysql_log_offset = 0;
 
131
 
 
132
        mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
 
133
 
 
134
        trx->rseg = NULL;
 
135
 
 
136
        trx->undo_no = ut_dulint_zero;
 
137
        trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
 
138
        trx->insert_undo = NULL;
 
139
        trx->update_undo = NULL;
 
140
        trx->undo_no_arr = NULL;
 
141
 
 
142
        trx->error_state = DB_SUCCESS;
 
143
        trx->error_key_num = 0;
 
144
        trx->detailed_error[0] = '\0';
 
145
 
 
146
        trx->sess = sess;
 
147
        trx->que_state = TRX_QUE_RUNNING;
 
148
        trx->n_active_thrs = 0;
 
149
 
 
150
        trx->handling_signals = FALSE;
 
151
 
 
152
        UT_LIST_INIT(trx->signals);
 
153
        UT_LIST_INIT(trx->reply_signals);
 
154
 
 
155
        trx->graph = NULL;
 
156
 
 
157
        trx->wait_lock = NULL;
 
158
        trx->was_chosen_as_deadlock_victim = FALSE;
 
159
        UT_LIST_INIT(trx->wait_thrs);
 
160
 
 
161
        trx->lock_heap = mem_heap_create_in_buffer(256);
 
162
        UT_LIST_INIT(trx->trx_locks);
 
163
 
 
164
        UT_LIST_INIT(trx->trx_savepoints);
 
165
 
 
166
        trx->dict_operation_lock_mode = 0;
 
167
        trx->has_search_latch = FALSE;
 
168
        trx->search_latch_timeout = BTR_SEA_TIMEOUT;
 
169
 
 
170
        trx->declared_to_be_inside_innodb = FALSE;
 
171
        trx->n_tickets_to_enter_innodb = 0;
 
172
 
 
173
        trx->global_read_view_heap = mem_heap_create(256);
 
174
        trx->global_read_view = NULL;
 
175
        trx->read_view = NULL;
 
176
 
 
177
        /* Set X/Open XA transaction identification to NULL */
 
178
        memset(&trx->xid, 0, sizeof(trx->xid));
 
179
        trx->xid.formatID = -1;
 
180
 
 
181
        trx->n_autoinc_rows = 0;
 
182
 
 
183
        /* Remember to free the vector explicitly. */
 
184
        trx->autoinc_locks = ib_vector_create(
 
185
                mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
 
186
 
 
187
        return(trx);
 
188
}
 
189
 
 
190
/********************************************************************//**
 
191
Creates a transaction object for MySQL.
 
192
@return own: transaction object */
 
193
UNIV_INTERN
 
194
trx_t*
 
195
trx_allocate_for_mysql(void)
 
196
/*========================*/
 
197
{
 
198
        trx_t*  trx;
 
199
 
 
200
        mutex_enter(&kernel_mutex);
 
201
 
 
202
        trx = trx_create(trx_dummy_sess);
 
203
 
 
204
        trx_n_mysql_transactions++;
 
205
 
 
206
        UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
 
207
 
 
208
        mutex_exit(&kernel_mutex);
 
209
 
 
210
        trx->mysql_thread_id = os_thread_get_curr_id();
 
211
 
 
212
        trx->mysql_process_no = os_proc_get_number();
 
213
 
 
214
        return(trx);
 
215
}
 
216
 
 
217
/********************************************************************//**
 
218
Creates a transaction object for background operations by the master thread.
 
219
@return own: transaction object */
 
220
UNIV_INTERN
 
221
trx_t*
 
222
trx_allocate_for_background(void)
 
223
/*=============================*/
 
224
{
 
225
        trx_t*  trx;
 
226
 
 
227
        mutex_enter(&kernel_mutex);
 
228
 
 
229
        trx = trx_create(trx_dummy_sess);
 
230
 
 
231
        mutex_exit(&kernel_mutex);
 
232
 
 
233
        return(trx);
 
234
}
 
235
 
 
236
/********************************************************************//**
 
237
Releases the search latch if trx has reserved it. */
 
238
UNIV_INTERN
 
239
void
 
240
trx_search_latch_release_if_reserved(
 
241
/*=================================*/
 
242
        trx_t*     trx) /*!< in: transaction */
 
243
{
 
244
        if (trx->has_search_latch) {
 
245
                rw_lock_s_unlock(&btr_search_latch);
 
246
 
 
247
                trx->has_search_latch = FALSE;
 
248
        }
 
249
}
 
250
 
 
251
/********************************************************************//**
 
252
Frees a transaction object. */
 
253
UNIV_INTERN
 
254
void
 
255
trx_free(
 
256
/*=====*/
 
257
        trx_t*  trx)    /*!< in, own: trx object */
 
258
{
 
259
        ut_ad(mutex_own(&kernel_mutex));
 
260
 
 
261
        if (trx->declared_to_be_inside_innodb) {
 
262
                ut_print_timestamp(stderr);
 
263
                fputs("  InnoDB: Error: Freeing a trx which is declared"
 
264
                      " to be processing\n"
 
265
                      "InnoDB: inside InnoDB.\n", stderr);
 
266
                trx_print(stderr, trx, 600);
 
267
                putc('\n', stderr);
 
268
 
 
269
                /* This is an error but not a fatal error. We must keep
 
270
                the counters like srv_conc_n_threads accurate. */
 
271
                srv_conc_force_exit_innodb(trx);
 
272
        }
 
273
 
 
274
        if (trx->n_mysql_tables_in_use != 0
 
275
            || trx->mysql_n_tables_locked != 0) {
 
276
 
 
277
                ut_print_timestamp(stderr);
 
278
                fprintf(stderr,
 
279
                        "  InnoDB: Error: MySQL is freeing a thd\n"
 
280
                        "InnoDB: though trx->n_mysql_tables_in_use is %lu\n"
 
281
                        "InnoDB: and trx->mysql_n_tables_locked is %lu.\n",
 
282
                        (ulong)trx->n_mysql_tables_in_use,
 
283
                        (ulong)trx->mysql_n_tables_locked);
 
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 (ut_dulint_cmp(trx->id, trx2->id) >= 0) {
 
392
 
 
393
                        ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1);
 
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_LIST_INIT(trx_sys->trx_list);
 
429
 
 
430
        /* Look from the rollback segments if there exist undo logs for
 
431
        transactions */
 
432
 
 
433
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
434
 
 
435
        while (rseg != NULL) {
 
436
                undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
 
437
 
 
438
                while (undo != NULL) {
 
439
 
 
440
                        trx = trx_create(trx_dummy_sess);
 
441
 
 
442
                        trx->is_recovered = TRUE;
 
443
                        trx->id = undo->trx_id;
 
444
                        trx->xid = undo->xid;
 
445
                        trx->insert_undo = undo;
 
446
                        trx->rseg = rseg;
 
447
 
 
448
                        if (undo->state != TRX_UNDO_ACTIVE) {
 
449
 
 
450
                                /* Prepared transactions are left in
 
451
                                the prepared state waiting for a
 
452
                                commit or abort decision from MySQL */
 
453
 
 
454
                                if (undo->state == TRX_UNDO_PREPARED) {
 
455
 
 
456
                                        fprintf(stderr,
 
457
                                                "InnoDB: Transaction "
 
458
                                                TRX_ID_FMT
 
459
                                                " was in the"
 
460
                                                " XA prepared state.\n",
 
461
                                                TRX_ID_PREP_PRINTF(trx->id));
 
462
 
 
463
                                        if (srv_force_recovery == 0) {
 
464
 
 
465
                                                trx->conc_state = TRX_PREPARED;
 
466
                                        } else {
 
467
                                                fprintf(stderr,
 
468
                                                        "InnoDB: Since"
 
469
                                                        " innodb_force_recovery"
 
470
                                                        " > 0, we will"
 
471
                                                        " rollback it"
 
472
                                                        " anyway.\n");
 
473
 
 
474
                                                trx->conc_state = TRX_ACTIVE;
 
475
                                        }
 
476
                                } else {
 
477
                                        trx->conc_state
 
478
                                                = TRX_COMMITTED_IN_MEMORY;
 
479
                                }
 
480
 
 
481
                                /* We give a dummy value for the trx no;
 
482
                                this should have no relevance since purge
 
483
                                is not interested in committed transaction
 
484
                                numbers, unless they are in the history
 
485
                                list, in which case it looks the number
 
486
                                from the disk based undo log structure */
 
487
 
 
488
                                trx->no = trx->id;
 
489
                        } else {
 
490
                                trx->conc_state = TRX_ACTIVE;
 
491
 
 
492
                                /* A running transaction always has the number
 
493
                                field inited to ut_dulint_max */
 
494
 
 
495
                                trx->no = ut_dulint_max;
 
496
                        }
 
497
 
 
498
                        if (undo->dict_operation) {
 
499
                                trx_set_dict_operation(
 
500
                                        trx, TRX_DICT_OP_TABLE);
 
501
                                trx->table_id = undo->table_id;
 
502
                        }
 
503
 
 
504
                        if (!undo->empty) {
 
505
                                trx->undo_no = ut_dulint_add(undo->top_undo_no,
 
506
                                                             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_PREP_PRINTF(
 
538
                                                                trx->id));
 
539
 
 
540
                                                if (srv_force_recovery == 0) {
 
541
 
 
542
                                                        trx->conc_state
 
543
                                                                = TRX_PREPARED;
 
544
                                                } else {
 
545
                                                        fprintf(stderr,
 
546
                                                                "InnoDB: Since"
 
547
                                                                " innodb_force_recovery"
 
548
                                                                " > 0, we will"
 
549
                                                                " rollback it"
 
550
                                                                " anyway.\n");
 
551
 
 
552
                                                        trx->conc_state
 
553
                                                                = TRX_ACTIVE;
 
554
                                                }
 
555
                                        } else {
 
556
                                                trx->conc_state
 
557
                                                        = TRX_COMMITTED_IN_MEMORY;
 
558
                                        }
 
559
 
 
560
                                        /* We give a dummy value for the trx
 
561
                                        number */
 
562
 
 
563
                                        trx->no = trx->id;
 
564
                                } else {
 
565
                                        trx->conc_state = TRX_ACTIVE;
 
566
 
 
567
                                        /* A running transaction always has
 
568
                                        the number field inited to
 
569
                                        ut_dulint_max */
 
570
 
 
571
                                        trx->no = ut_dulint_max;
 
572
                                }
 
573
 
 
574
                                trx->rseg = rseg;
 
575
                                trx_list_insert_ordered(trx);
 
576
 
 
577
                                if (undo->dict_operation) {
 
578
                                        trx_set_dict_operation(
 
579
                                                trx, TRX_DICT_OP_TABLE);
 
580
                                        trx->table_id = undo->table_id;
 
581
                                }
 
582
                        }
 
583
 
 
584
                        trx->update_undo = undo;
 
585
 
 
586
                        if ((!undo->empty)
 
587
                            && (ut_dulint_cmp(undo->top_undo_no,
 
588
                                              trx->undo_no) >= 0)) {
 
589
 
 
590
                                trx->undo_no = ut_dulint_add(undo->top_undo_no,
 
591
                                                             1);
 
592
                        }
 
593
 
 
594
                        undo = UT_LIST_GET_NEXT(undo_list, undo);
 
595
                }
 
596
 
 
597
                rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
598
        }
 
599
}
 
600
 
 
601
/******************************************************************//**
 
602
Assigns a rollback segment to a transaction in a round-robin fashion.
 
603
Skips the SYSTEM rollback segment if another is available.
 
604
@return assigned rollback segment id */
 
605
UNIV_INLINE
 
606
ulint
 
607
trx_assign_rseg(void)
 
608
/*=================*/
 
609
{
 
610
        trx_rseg_t*     rseg    = trx_sys->latest_rseg;
 
611
 
 
612
        ut_ad(mutex_own(&kernel_mutex));
 
613
loop:
 
614
        /* Get next rseg in a round-robin fashion */
 
615
 
 
616
        rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
617
 
 
618
        if (rseg == NULL) {
 
619
                rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
620
        }
 
621
 
 
622
        /* If it is the SYSTEM rollback segment, and there exist others, skip
 
623
        it */
 
624
 
 
625
        if ((rseg->id == TRX_SYS_SYSTEM_RSEG_ID)
 
626
            && (UT_LIST_GET_LEN(trx_sys->rseg_list) > 1)) {
 
627
                goto loop;
 
628
        }
 
629
 
 
630
        trx_sys->latest_rseg = rseg;
 
631
 
 
632
        return(rseg->id);
 
633
}
 
634
 
 
635
/****************************************************************//**
 
636
Starts a new transaction.
 
637
@return TRUE */
 
638
UNIV_INTERN
 
639
ibool
 
640
trx_start_low(
 
641
/*==========*/
 
642
        trx_t*  trx,    /*!< in: transaction */
 
643
        ulint   rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
 
644
                        is passed, the system chooses the rollback segment
 
645
                        automatically in a round-robin fashion */
 
646
{
 
647
        trx_rseg_t*     rseg;
 
648
 
 
649
        ut_ad(mutex_own(&kernel_mutex));
 
650
        ut_ad(trx->rseg == NULL);
 
651
 
 
652
        if (trx->is_purge) {
 
653
                trx->id = ut_dulint_zero;
 
654
                trx->conc_state = TRX_ACTIVE;
 
655
                trx->start_time = time(NULL);
 
656
 
 
657
                return(TRUE);
 
658
        }
 
659
 
 
660
        ut_ad(trx->conc_state != TRX_ACTIVE);
 
661
 
 
662
        if (rseg_id == ULINT_UNDEFINED) {
 
663
 
 
664
                rseg_id = trx_assign_rseg();
 
665
        }
 
666
 
 
667
        rseg = trx_sys_get_nth_rseg(trx_sys, rseg_id);
 
668
 
 
669
        trx->id = trx_sys_get_new_trx_id();
 
670
 
 
671
        /* The initial value for trx->no: ut_dulint_max is used in
 
672
        read_view_open_now: */
 
673
 
 
674
        trx->no = ut_dulint_max;
 
675
 
 
676
        trx->rseg = rseg;
 
677
 
 
678
        trx->conc_state = TRX_ACTIVE;
 
679
        trx->start_time = time(NULL);
 
680
 
 
681
        UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
 
682
 
 
683
        return(TRUE);
 
684
}
 
685
 
 
686
/****************************************************************//**
 
687
Starts a new transaction.
 
688
@return TRUE */
 
689
UNIV_INTERN
 
690
ibool
 
691
trx_start(
 
692
/*======*/
 
693
        trx_t*  trx,    /*!< in: transaction */
 
694
        ulint   rseg_id)/*!< in: rollback segment id; if ULINT_UNDEFINED
 
695
                        is passed, the system chooses the rollback segment
 
696
                        automatically in a round-robin fashion */
 
697
{
 
698
        ibool   ret;
 
699
 
 
700
        /* Update the info whether we should skip XA steps that eat CPU time
 
701
        For the duration of the transaction trx->support_xa is not reread
 
702
        from thd so any changes in the value take effect in the next
 
703
        transaction. This is to avoid a scenario where some undo
 
704
        generated by a transaction, has XA stuff, and other undo,
 
705
        generated by the same transaction, doesn't. */
 
706
        trx->support_xa = thd_supports_xa(trx->mysql_thd);
 
707
 
 
708
        mutex_enter(&kernel_mutex);
 
709
 
 
710
        ret = trx_start_low(trx, rseg_id);
 
711
 
 
712
        mutex_exit(&kernel_mutex);
 
713
 
 
714
        return(ret);
 
715
}
 
716
 
 
717
/****************************************************************//**
 
718
Commits a transaction. */
 
719
UNIV_INTERN
 
720
void
 
721
trx_commit_off_kernel(
 
722
/*==================*/
 
723
        trx_t*  trx)    /*!< in: transaction */
 
724
{
 
725
        page_t*         update_hdr_page;
 
726
        ib_uint64_t     lsn             = 0;
 
727
        trx_rseg_t*     rseg;
 
728
        trx_undo_t*     undo;
 
729
        mtr_t           mtr;
 
730
 
 
731
        ut_ad(mutex_own(&kernel_mutex));
 
732
 
 
733
        trx->must_flush_log_later = FALSE;
 
734
 
 
735
        rseg = trx->rseg;
 
736
 
 
737
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
 
738
 
 
739
                mutex_exit(&kernel_mutex);
 
740
 
 
741
                mtr_start(&mtr);
 
742
 
 
743
                /* Change the undo log segment states from TRX_UNDO_ACTIVE
 
744
                to some other state: these modifications to the file data
 
745
                structure define the transaction as committed in the file
 
746
                based world, at the serialization point of the log sequence
 
747
                number lsn obtained below. */
 
748
 
 
749
                mutex_enter(&(rseg->mutex));
 
750
 
 
751
                if (trx->insert_undo != NULL) {
 
752
                        trx_undo_set_state_at_finish(
 
753
                                rseg, trx, trx->insert_undo, &mtr);
 
754
                }
 
755
 
 
756
                undo = trx->update_undo;
 
757
 
 
758
                if (undo) {
 
759
                        mutex_enter(&kernel_mutex);
 
760
                        trx->no = trx_sys_get_new_trx_no();
 
761
 
 
762
                        mutex_exit(&kernel_mutex);
 
763
 
 
764
                        /* It is not necessary to obtain trx->undo_mutex here
 
765
                        because only a single OS thread is allowed to do the
 
766
                        transaction commit for this transaction. */
 
767
 
 
768
                        update_hdr_page = trx_undo_set_state_at_finish(
 
769
                                rseg, trx, undo, &mtr);
 
770
 
 
771
                        /* We have to do the cleanup for the update log while
 
772
                        holding the rseg mutex because update log headers
 
773
                        have to be put to the history list in the order of
 
774
                        the trx number. */
 
775
 
 
776
                        trx_undo_update_cleanup(trx, update_hdr_page, &mtr);
 
777
                }
 
778
 
 
779
                mutex_exit(&(rseg->mutex));
 
780
 
 
781
                /* Update the latest MySQL binlog name and offset info
 
782
                in trx sys header if MySQL binlogging is on or the database
 
783
                server is a MySQL replication slave */
 
784
 
 
785
                if (trx->mysql_log_file_name
 
786
                    && trx->mysql_log_file_name[0] != '\0') {
 
787
                        trx_sys_update_mysql_binlog_offset(
 
788
                                trx->mysql_log_file_name,
 
789
                                trx->mysql_log_offset,
 
790
                                TRX_SYS_MYSQL_LOG_INFO, &mtr);
 
791
                        trx->mysql_log_file_name = NULL;
 
792
                }
 
793
 
 
794
                /* The following call commits the mini-transaction, making the
 
795
                whole transaction committed in the file-based world, at this
 
796
                log sequence number. The transaction becomes 'durable' when
 
797
                we write the log to disk, but in the logical sense the commit
 
798
                in the file-based data structures (undo logs etc.) happens
 
799
                here.
 
800
 
 
801
                NOTE that transaction numbers, which are assigned only to
 
802
                transactions with an update undo log, do not necessarily come
 
803
                in exactly the same order as commit lsn's, if the transactions
 
804
                have different rollback segments. To get exactly the same
 
805
                order we should hold the kernel mutex up to this point,
 
806
                adding to the contention of the kernel mutex. However, if
 
807
                a transaction T2 is able to see modifications made by
 
808
                a transaction T1, T2 will always get a bigger transaction
 
809
                number and a bigger commit lsn than T1. */
 
810
 
 
811
                /*--------------*/
 
812
                mtr_commit(&mtr);
 
813
                /*--------------*/
 
814
                lsn = mtr.end_lsn;
 
815
 
 
816
                mutex_enter(&kernel_mutex);
 
817
        }
 
818
 
 
819
        ut_ad(trx->conc_state == TRX_ACTIVE
 
820
              || trx->conc_state == TRX_PREPARED);
 
821
        ut_ad(mutex_own(&kernel_mutex));
 
822
 
 
823
        /* The following assignment makes the transaction committed in memory
 
824
        and makes its changes to data visible to other transactions.
 
825
        NOTE that there is a small discrepancy from the strict formal
 
826
        visibility rules here: a human user of the database can see
 
827
        modifications made by another transaction T even before the necessary
 
828
        log segment has been flushed to the disk. If the database happens to
 
829
        crash before the flush, the user has seen modifications from T which
 
830
        will never be a committed transaction. However, any transaction T2
 
831
        which sees the modifications of the committing transaction T, and
 
832
        which also itself makes modifications to the database, will get an lsn
 
833
        larger than the committing transaction T. In the case where the log
 
834
        flush fails, and T never gets committed, also T2 will never get
 
835
        committed. */
 
836
 
 
837
        /*--------------------------------------*/
 
838
        trx->conc_state = TRX_COMMITTED_IN_MEMORY;
 
839
        /*--------------------------------------*/
 
840
 
 
841
        /* If we release kernel_mutex below and we are still doing
 
842
        recovery i.e.: back ground rollback thread is still active
 
843
        then there is a chance that the rollback thread may see
 
844
        this trx as COMMITTED_IN_MEMORY and goes adhead to clean it
 
845
        up calling trx_cleanup_at_db_startup(). This can happen 
 
846
        in the case we are committing a trx here that is left in
 
847
        PREPARED state during the crash. Note that commit of the
 
848
        rollback of a PREPARED trx happens in the recovery thread
 
849
        while the rollback of other transactions happen in the
 
850
        background thread. To avoid this race we unconditionally
 
851
        unset the is_recovered flag from the trx. */
 
852
 
 
853
        trx->is_recovered = FALSE;
 
854
 
 
855
        lock_release_off_kernel(trx);
 
856
 
 
857
        if (trx->global_read_view) {
 
858
                read_view_close(trx->global_read_view);
 
859
                mem_heap_empty(trx->global_read_view_heap);
 
860
                trx->global_read_view = NULL;
 
861
        }
 
862
 
 
863
        trx->read_view = NULL;
 
864
 
 
865
        if (lsn) {
 
866
 
 
867
                mutex_exit(&kernel_mutex);
 
868
 
 
869
                if (trx->insert_undo != NULL) {
 
870
 
 
871
                        trx_undo_insert_cleanup(trx);
 
872
                }
 
873
 
 
874
                /* NOTE that we could possibly make a group commit more
 
875
                efficient here: call os_thread_yield here to allow also other
 
876
                trxs to come to commit! */
 
877
 
 
878
                /*-------------------------------------*/
 
879
 
 
880
                /* Depending on the my.cnf options, we may now write the log
 
881
                buffer to the log files, making the transaction durable if
 
882
                the OS does not crash. We may also flush the log files to
 
883
                disk, making the transaction durable also at an OS crash or a
 
884
                power outage.
 
885
 
 
886
                The idea in InnoDB's group commit is that a group of
 
887
                transactions gather behind a trx doing a physical disk write
 
888
                to log files, and when that physical write has been completed,
 
889
                one of those transactions does a write which commits the whole
 
890
                group. Note that this group commit will only bring benefit if
 
891
                there are > 2 users in the database. Then at least 2 users can
 
892
                gather behind one doing the physical log write to disk.
 
893
 
 
894
                If we are calling trx_commit() under prepare_commit_mutex, we
 
895
                will delay possible log write and flush to a separate function
 
896
                trx_commit_complete_for_mysql(), which is only called when the
 
897
                thread has released the mutex. This is to make the
 
898
                group commit algorithm to work. Otherwise, the prepare_commit
 
899
                mutex would serialize all commits and prevent a group of
 
900
                transactions from gathering. */
 
901
 
 
902
                if (trx->flush_log_later) {
 
903
                        /* Do nothing yet */
 
904
                        trx->must_flush_log_later = TRUE;
 
905
                } else if (srv_flush_log_at_trx_commit == 0) {
 
906
                        /* Do nothing */
 
907
                } else if (srv_flush_log_at_trx_commit == 1) {
 
908
                        if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
 
909
                                /* Write the log but do not flush it to disk */
 
910
 
 
911
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
 
912
                                                FALSE);
 
913
                        } else {
 
914
                                /* Write the log to the log files AND flush
 
915
                                them to disk */
 
916
 
 
917
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
918
                        }
 
919
                } else if (srv_flush_log_at_trx_commit == 2) {
 
920
 
 
921
                        /* Write the log but do not flush it to disk */
 
922
 
 
923
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
924
                } else {
 
925
                        ut_error;
 
926
                }
 
927
 
 
928
                trx->commit_lsn = lsn;
 
929
 
 
930
                /*-------------------------------------*/
 
931
 
 
932
                mutex_enter(&kernel_mutex);
 
933
        }
 
934
 
 
935
        /* Free all savepoints */
 
936
        trx_roll_free_all_savepoints(trx);
 
937
 
 
938
        trx->conc_state = TRX_NOT_STARTED;
 
939
        trx->rseg = NULL;
 
940
        trx->undo_no = ut_dulint_zero;
 
941
        trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
 
942
        trx->mysql_query_str = NULL;
 
943
 
 
944
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
945
        ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
 
946
 
 
947
        UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
 
948
}
 
949
 
 
950
/****************************************************************//**
 
951
Cleans up a transaction at database startup. The cleanup is needed if
 
952
the transaction already got to the middle of a commit when the database
 
953
crashed, and we cannot roll it back. */
 
954
UNIV_INTERN
 
955
void
 
956
trx_cleanup_at_db_startup(
 
957
/*======================*/
 
958
        trx_t*  trx)    /*!< in: transaction */
 
959
{
 
960
        if (trx->insert_undo != NULL) {
 
961
 
 
962
                trx_undo_insert_cleanup(trx);
 
963
        }
 
964
 
 
965
        trx->conc_state = TRX_NOT_STARTED;
 
966
        trx->rseg = NULL;
 
967
        trx->undo_no = ut_dulint_zero;
 
968
        trx->last_sql_stat_start.least_undo_no = ut_dulint_zero;
 
969
 
 
970
        UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
 
971
}
 
972
 
 
973
/********************************************************************//**
 
974
Assigns a read view for a consistent read query. All the consistent reads
 
975
within the same transaction will get the same read view, which is created
 
976
when this function is first called for a new started transaction.
 
977
@return consistent read view */
 
978
UNIV_INTERN
 
979
read_view_t*
 
980
trx_assign_read_view(
 
981
/*=================*/
 
982
        trx_t*  trx)    /*!< in: active transaction */
 
983
{
 
984
        ut_ad(trx->conc_state == TRX_ACTIVE);
 
985
 
 
986
        if (trx->read_view) {
 
987
                return(trx->read_view);
 
988
        }
 
989
 
 
990
        mutex_enter(&kernel_mutex);
 
991
 
 
992
        if (!trx->read_view) {
 
993
                trx->read_view = read_view_open_now(
 
994
                        trx->id, trx->global_read_view_heap);
 
995
                trx->global_read_view = trx->read_view;
 
996
        }
 
997
 
 
998
        mutex_exit(&kernel_mutex);
 
999
 
 
1000
        return(trx->read_view);
 
1001
}
 
1002
 
 
1003
/****************************************************************//**
 
1004
Commits a transaction. NOTE that the kernel mutex is temporarily released. */
 
1005
static
 
1006
void
 
1007
trx_handle_commit_sig_off_kernel(
 
1008
/*=============================*/
 
1009
        trx_t*          trx,            /*!< in: transaction */
 
1010
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
1011
                                        if the value which is passed in is
 
1012
                                        a pointer to a NULL pointer, then the
 
1013
                                        calling function can start running
 
1014
                                        a new query thread */
 
1015
{
 
1016
        trx_sig_t*      sig;
 
1017
        trx_sig_t*      next_sig;
 
1018
 
 
1019
        ut_ad(mutex_own(&kernel_mutex));
 
1020
 
 
1021
        trx->que_state = TRX_QUE_COMMITTING;
 
1022
 
 
1023
        trx_commit_off_kernel(trx);
 
1024
 
 
1025
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
1026
 
 
1027
        /* Remove all TRX_SIG_COMMIT signals from the signal queue and send
 
1028
        reply messages to them */
 
1029
 
 
1030
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1031
 
 
1032
        while (sig != NULL) {
 
1033
                next_sig = UT_LIST_GET_NEXT(signals, sig);
 
1034
 
 
1035
                if (sig->type == TRX_SIG_COMMIT) {
 
1036
 
 
1037
                        trx_sig_reply(sig, next_thr);
 
1038
                        trx_sig_remove(trx, sig);
 
1039
                }
 
1040
 
 
1041
                sig = next_sig;
 
1042
        }
 
1043
 
 
1044
        trx->que_state = TRX_QUE_RUNNING;
 
1045
}
 
1046
 
 
1047
/***********************************************************//**
 
1048
The transaction must be in the TRX_QUE_LOCK_WAIT state. Puts it to
 
1049
the TRX_QUE_RUNNING state and releases query threads which were
 
1050
waiting for a lock in the wait_thrs list. */
 
1051
UNIV_INTERN
 
1052
void
 
1053
trx_end_lock_wait(
 
1054
/*==============*/
 
1055
        trx_t*  trx)    /*!< in: transaction */
 
1056
{
 
1057
        que_thr_t*      thr;
 
1058
 
 
1059
        ut_ad(mutex_own(&kernel_mutex));
 
1060
        ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
 
1061
 
 
1062
        thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1063
 
 
1064
        while (thr != NULL) {
 
1065
                que_thr_end_wait_no_next_thr(thr);
 
1066
 
 
1067
                UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
 
1068
 
 
1069
                thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1070
        }
 
1071
 
 
1072
        trx->que_state = TRX_QUE_RUNNING;
 
1073
}
 
1074
 
 
1075
/***********************************************************//**
 
1076
Moves the query threads in the lock wait list to the SUSPENDED state and puts
 
1077
the transaction to the TRX_QUE_RUNNING state. */
 
1078
static
 
1079
void
 
1080
trx_lock_wait_to_suspended(
 
1081
/*=======================*/
 
1082
        trx_t*  trx)    /*!< in: transaction in the TRX_QUE_LOCK_WAIT state */
 
1083
{
 
1084
        que_thr_t*      thr;
 
1085
 
 
1086
        ut_ad(mutex_own(&kernel_mutex));
 
1087
        ut_ad(trx->que_state == TRX_QUE_LOCK_WAIT);
 
1088
 
 
1089
        thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1090
 
 
1091
        while (thr != NULL) {
 
1092
                thr->state = QUE_THR_SUSPENDED;
 
1093
 
 
1094
                UT_LIST_REMOVE(trx_thrs, trx->wait_thrs, thr);
 
1095
 
 
1096
                thr = UT_LIST_GET_FIRST(trx->wait_thrs);
 
1097
        }
 
1098
 
 
1099
        trx->que_state = TRX_QUE_RUNNING;
 
1100
}
 
1101
 
 
1102
/***********************************************************//**
 
1103
Moves the query threads in the sig reply wait list of trx to the SUSPENDED
 
1104
state. */
 
1105
static
 
1106
void
 
1107
trx_sig_reply_wait_to_suspended(
 
1108
/*============================*/
 
1109
        trx_t*  trx)    /*!< in: transaction */
 
1110
{
 
1111
        trx_sig_t*      sig;
 
1112
        que_thr_t*      thr;
 
1113
 
 
1114
        ut_ad(mutex_own(&kernel_mutex));
 
1115
 
 
1116
        sig = UT_LIST_GET_FIRST(trx->reply_signals);
 
1117
 
 
1118
        while (sig != NULL) {
 
1119
                thr = sig->receiver;
 
1120
 
 
1121
                ut_ad(thr->state == QUE_THR_SIG_REPLY_WAIT);
 
1122
 
 
1123
                thr->state = QUE_THR_SUSPENDED;
 
1124
 
 
1125
                sig->receiver = NULL;
 
1126
 
 
1127
                UT_LIST_REMOVE(reply_signals, trx->reply_signals, sig);
 
1128
 
 
1129
                sig = UT_LIST_GET_FIRST(trx->reply_signals);
 
1130
        }
 
1131
}
 
1132
 
 
1133
/*****************************************************************//**
 
1134
Checks the compatibility of a new signal with the other signals in the
 
1135
queue.
 
1136
@return TRUE if the signal can be queued */
 
1137
static
 
1138
ibool
 
1139
trx_sig_is_compatible(
 
1140
/*==================*/
 
1141
        trx_t*  trx,    /*!< in: trx handle */
 
1142
        ulint   type,   /*!< in: signal type */
 
1143
        ulint   sender) /*!< in: TRX_SIG_SELF or TRX_SIG_OTHER_SESS */
 
1144
{
 
1145
        trx_sig_t*      sig;
 
1146
 
 
1147
        ut_ad(mutex_own(&kernel_mutex));
 
1148
 
 
1149
        if (UT_LIST_GET_LEN(trx->signals) == 0) {
 
1150
 
 
1151
                return(TRUE);
 
1152
        }
 
1153
 
 
1154
        if (sender == TRX_SIG_SELF) {
 
1155
                if (type == TRX_SIG_ERROR_OCCURRED) {
 
1156
 
 
1157
                        return(TRUE);
 
1158
 
 
1159
                } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1160
 
 
1161
                        return(TRUE);
 
1162
                } else {
 
1163
                        return(FALSE);
 
1164
                }
 
1165
        }
 
1166
 
 
1167
        ut_ad(sender == TRX_SIG_OTHER_SESS);
 
1168
 
 
1169
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1170
 
 
1171
        if (type == TRX_SIG_COMMIT) {
 
1172
                while (sig != NULL) {
 
1173
 
 
1174
                        if (sig->type == TRX_SIG_TOTAL_ROLLBACK) {
 
1175
 
 
1176
                                return(FALSE);
 
1177
                        }
 
1178
 
 
1179
                        sig = UT_LIST_GET_NEXT(signals, sig);
 
1180
                }
 
1181
 
 
1182
                return(TRUE);
 
1183
 
 
1184
        } else if (type == TRX_SIG_TOTAL_ROLLBACK) {
 
1185
                while (sig != NULL) {
 
1186
 
 
1187
                        if (sig->type == TRX_SIG_COMMIT) {
 
1188
 
 
1189
                                return(FALSE);
 
1190
                        }
 
1191
 
 
1192
                        sig = UT_LIST_GET_NEXT(signals, sig);
 
1193
                }
 
1194
 
 
1195
                return(TRUE);
 
1196
 
 
1197
        } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1198
 
 
1199
                return(TRUE);
 
1200
        } else {
 
1201
                ut_error;
 
1202
 
 
1203
                return(FALSE);
 
1204
        }
 
1205
}
 
1206
 
 
1207
/****************************************************************//**
 
1208
Sends a signal to a trx object. */
 
1209
UNIV_INTERN
 
1210
void
 
1211
trx_sig_send(
 
1212
/*=========*/
 
1213
        trx_t*          trx,            /*!< in: trx handle */
 
1214
        ulint           type,           /*!< in: signal type */
 
1215
        ulint           sender,         /*!< in: TRX_SIG_SELF or
 
1216
                                        TRX_SIG_OTHER_SESS */
 
1217
        que_thr_t*      receiver_thr,   /*!< in: query thread which wants the
 
1218
                                        reply, or NULL; if type is
 
1219
                                        TRX_SIG_END_WAIT, this must be NULL */
 
1220
        trx_savept_t*   savept,         /*!< in: possible rollback savepoint, or
 
1221
                                        NULL */
 
1222
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
1223
                                        if the value which is passed in is
 
1224
                                        a pointer to a NULL pointer, then the
 
1225
                                        calling function can start running
 
1226
                                        a new query thread; if the parameter
 
1227
                                        is NULL, it is ignored */
 
1228
{
 
1229
        trx_sig_t*      sig;
 
1230
        trx_t*          receiver_trx;
 
1231
 
 
1232
        ut_ad(trx);
 
1233
        ut_ad(mutex_own(&kernel_mutex));
 
1234
 
 
1235
        if (!trx_sig_is_compatible(trx, type, sender)) {
 
1236
                /* The signal is not compatible with the other signals in
 
1237
                the queue: die */
 
1238
 
 
1239
                ut_error;
 
1240
        }
 
1241
 
 
1242
        /* Queue the signal object */
 
1243
 
 
1244
        if (UT_LIST_GET_LEN(trx->signals) == 0) {
 
1245
 
 
1246
                /* The signal list is empty: the 'sig' slot must be unused
 
1247
                (we improve performance a bit by avoiding mem_alloc) */
 
1248
                sig = &(trx->sig);
 
1249
        } else {
 
1250
                /* It might be that the 'sig' slot is unused also in this
 
1251
                case, but we choose the easy way of using mem_alloc */
 
1252
 
 
1253
                sig = mem_alloc(sizeof(trx_sig_t));
 
1254
        }
 
1255
 
 
1256
        UT_LIST_ADD_LAST(signals, trx->signals, sig);
 
1257
 
 
1258
        sig->type = type;
 
1259
        sig->sender = sender;
 
1260
        sig->receiver = receiver_thr;
 
1261
 
 
1262
        if (savept) {
 
1263
                sig->savept = *savept;
 
1264
        }
 
1265
 
 
1266
        if (receiver_thr) {
 
1267
                receiver_trx = thr_get_trx(receiver_thr);
 
1268
 
 
1269
                UT_LIST_ADD_LAST(reply_signals, receiver_trx->reply_signals,
 
1270
                                 sig);
 
1271
        }
 
1272
 
 
1273
        if (trx->sess->state == SESS_ERROR) {
 
1274
 
 
1275
                trx_sig_reply_wait_to_suspended(trx);
 
1276
        }
 
1277
 
 
1278
        if ((sender != TRX_SIG_SELF) || (type == TRX_SIG_BREAK_EXECUTION)) {
 
1279
                ut_error;
 
1280
        }
 
1281
 
 
1282
        /* If there were no other signals ahead in the queue, try to start
 
1283
        handling of the signal */
 
1284
 
 
1285
        if (UT_LIST_GET_FIRST(trx->signals) == sig) {
 
1286
 
 
1287
                trx_sig_start_handle(trx, next_thr);
 
1288
        }
 
1289
}
 
1290
 
 
1291
/****************************************************************//**
 
1292
Ends signal handling. If the session is in the error state, and
 
1293
trx->graph_before_signal_handling != NULL, then returns control to the error
 
1294
handling routine of the graph (currently just returns the control to the
 
1295
graph root which then will send an error message to the client). */
 
1296
UNIV_INTERN
 
1297
void
 
1298
trx_end_signal_handling(
 
1299
/*====================*/
 
1300
        trx_t*  trx)    /*!< in: trx */
 
1301
{
 
1302
        ut_ad(mutex_own(&kernel_mutex));
 
1303
        ut_ad(trx->handling_signals == TRUE);
 
1304
 
 
1305
        trx->handling_signals = FALSE;
 
1306
 
 
1307
        trx->graph = trx->graph_before_signal_handling;
 
1308
 
 
1309
        if (trx->graph && (trx->sess->state == SESS_ERROR)) {
 
1310
 
 
1311
                que_fork_error_handle(trx, trx->graph);
 
1312
        }
 
1313
}
 
1314
 
 
1315
/****************************************************************//**
 
1316
Starts handling of a trx signal. */
 
1317
UNIV_INTERN
 
1318
void
 
1319
trx_sig_start_handle(
 
1320
/*=================*/
 
1321
        trx_t*          trx,            /*!< in: trx handle */
 
1322
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
1323
                                        if the value which is passed in is
 
1324
                                        a pointer to a NULL pointer, then the
 
1325
                                        calling function can start running
 
1326
                                        a new query thread; if the parameter
 
1327
                                        is NULL, it is ignored */
 
1328
{
 
1329
        trx_sig_t*      sig;
 
1330
        ulint           type;
 
1331
loop:
 
1332
        /* We loop in this function body as long as there are queued signals
 
1333
        we can process immediately */
 
1334
 
 
1335
        ut_ad(trx);
 
1336
        ut_ad(mutex_own(&kernel_mutex));
 
1337
 
 
1338
        if (trx->handling_signals && (UT_LIST_GET_LEN(trx->signals) == 0)) {
 
1339
 
 
1340
                trx_end_signal_handling(trx);
 
1341
 
 
1342
                return;
 
1343
        }
 
1344
 
 
1345
        if (trx->conc_state == TRX_NOT_STARTED) {
 
1346
 
 
1347
                trx_start_low(trx, ULINT_UNDEFINED);
 
1348
        }
 
1349
 
 
1350
        /* If the trx is in a lock wait state, moves the waiting query threads
 
1351
        to the suspended state */
 
1352
 
 
1353
        if (trx->que_state == TRX_QUE_LOCK_WAIT) {
 
1354
 
 
1355
                trx_lock_wait_to_suspended(trx);
 
1356
        }
 
1357
 
 
1358
        /* If the session is in the error state and this trx has threads
 
1359
        waiting for reply from signals, moves these threads to the suspended
 
1360
        state, canceling wait reservations; note that if the transaction has
 
1361
        sent a commit or rollback signal to itself, and its session is not in
 
1362
        the error state, then nothing is done here. */
 
1363
 
 
1364
        if (trx->sess->state == SESS_ERROR) {
 
1365
                trx_sig_reply_wait_to_suspended(trx);
 
1366
        }
 
1367
 
 
1368
        /* If there are no running query threads, we can start processing of a
 
1369
        signal, otherwise we have to wait until all query threads of this
 
1370
        transaction are aware of the arrival of the signal. */
 
1371
 
 
1372
        if (trx->n_active_thrs > 0) {
 
1373
 
 
1374
                return;
 
1375
        }
 
1376
 
 
1377
        if (trx->handling_signals == FALSE) {
 
1378
                trx->graph_before_signal_handling = trx->graph;
 
1379
 
 
1380
                trx->handling_signals = TRUE;
 
1381
        }
 
1382
 
 
1383
        sig = UT_LIST_GET_FIRST(trx->signals);
 
1384
        type = sig->type;
 
1385
 
 
1386
        if (type == TRX_SIG_COMMIT) {
 
1387
 
 
1388
                trx_handle_commit_sig_off_kernel(trx, next_thr);
 
1389
 
 
1390
        } else if ((type == TRX_SIG_TOTAL_ROLLBACK)
 
1391
                   || (type == TRX_SIG_ROLLBACK_TO_SAVEPT)) {
 
1392
 
 
1393
                trx_rollback(trx, sig, next_thr);
 
1394
 
 
1395
                /* No further signals can be handled until the rollback
 
1396
                completes, therefore we return */
 
1397
 
 
1398
                return;
 
1399
 
 
1400
        } else if (type == TRX_SIG_ERROR_OCCURRED) {
 
1401
 
 
1402
                trx_rollback(trx, sig, next_thr);
 
1403
 
 
1404
                /* No further signals can be handled until the rollback
 
1405
                completes, therefore we return */
 
1406
 
 
1407
                return;
 
1408
 
 
1409
        } else if (type == TRX_SIG_BREAK_EXECUTION) {
 
1410
 
 
1411
                trx_sig_reply(sig, next_thr);
 
1412
                trx_sig_remove(trx, sig);
 
1413
        } else {
 
1414
                ut_error;
 
1415
        }
 
1416
 
 
1417
        goto loop;
 
1418
}
 
1419
 
 
1420
/****************************************************************//**
 
1421
Send the reply message when a signal in the queue of the trx has been
 
1422
handled. */
 
1423
UNIV_INTERN
 
1424
void
 
1425
trx_sig_reply(
 
1426
/*==========*/
 
1427
        trx_sig_t*      sig,            /*!< in: signal */
 
1428
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
1429
                                        if the value which is passed in is
 
1430
                                        a pointer to a NULL pointer, then the
 
1431
                                        calling function can start running
 
1432
                                        a new query thread */
 
1433
{
 
1434
        trx_t*  receiver_trx;
 
1435
 
 
1436
        ut_ad(sig);
 
1437
        ut_ad(mutex_own(&kernel_mutex));
 
1438
 
 
1439
        if (sig->receiver != NULL) {
 
1440
                ut_ad((sig->receiver)->state == QUE_THR_SIG_REPLY_WAIT);
 
1441
 
 
1442
                receiver_trx = thr_get_trx(sig->receiver);
 
1443
 
 
1444
                UT_LIST_REMOVE(reply_signals, receiver_trx->reply_signals,
 
1445
                               sig);
 
1446
                ut_ad(receiver_trx->sess->state != SESS_ERROR);
 
1447
 
 
1448
                que_thr_end_wait(sig->receiver, next_thr);
 
1449
 
 
1450
                sig->receiver = NULL;
 
1451
 
 
1452
        }
 
1453
}
 
1454
 
 
1455
/****************************************************************//**
 
1456
Removes a signal object from the trx signal queue. */
 
1457
UNIV_INTERN
 
1458
void
 
1459
trx_sig_remove(
 
1460
/*===========*/
 
1461
        trx_t*          trx,    /*!< in: trx handle */
 
1462
        trx_sig_t*      sig)    /*!< in, own: signal */
 
1463
{
 
1464
        ut_ad(trx && sig);
 
1465
        ut_ad(mutex_own(&kernel_mutex));
 
1466
 
 
1467
        ut_ad(sig->receiver == NULL);
 
1468
 
 
1469
        UT_LIST_REMOVE(signals, trx->signals, sig);
 
1470
        sig->type = 0;  /* reset the field to catch possible bugs */
 
1471
 
 
1472
        if (sig != &(trx->sig)) {
 
1473
                mem_free(sig);
 
1474
        }
 
1475
}
 
1476
 
 
1477
/*********************************************************************//**
 
1478
Creates a commit command node struct.
 
1479
@return own: commit node struct */
 
1480
UNIV_INTERN
 
1481
commit_node_t*
 
1482
commit_node_create(
 
1483
/*===============*/
 
1484
        mem_heap_t*     heap)   /*!< in: mem heap where created */
 
1485
{
 
1486
        commit_node_t*  node;
 
1487
 
 
1488
        node = mem_heap_alloc(heap, sizeof(commit_node_t));
 
1489
        node->common.type  = QUE_NODE_COMMIT;
 
1490
        node->state = COMMIT_NODE_SEND;
 
1491
 
 
1492
        return(node);
 
1493
}
 
1494
 
 
1495
/***********************************************************//**
 
1496
Performs an execution step for a commit type node in a query graph.
 
1497
@return query thread to run next, or NULL */
 
1498
UNIV_INTERN
 
1499
que_thr_t*
 
1500
trx_commit_step(
 
1501
/*============*/
 
1502
        que_thr_t*      thr)    /*!< in: query thread */
 
1503
{
 
1504
        commit_node_t*  node;
 
1505
        que_thr_t*      next_thr;
 
1506
 
 
1507
        node = thr->run_node;
 
1508
 
 
1509
        ut_ad(que_node_get_type(node) == QUE_NODE_COMMIT);
 
1510
 
 
1511
        if (thr->prev_node == que_node_get_parent(node)) {
 
1512
                node->state = COMMIT_NODE_SEND;
 
1513
        }
 
1514
 
 
1515
        if (node->state == COMMIT_NODE_SEND) {
 
1516
                mutex_enter(&kernel_mutex);
 
1517
 
 
1518
                node->state = COMMIT_NODE_WAIT;
 
1519
 
 
1520
                next_thr = NULL;
 
1521
 
 
1522
                thr->state = QUE_THR_SIG_REPLY_WAIT;
 
1523
 
 
1524
                /* Send the commit signal to the transaction */
 
1525
 
 
1526
                trx_sig_send(thr_get_trx(thr), TRX_SIG_COMMIT, TRX_SIG_SELF,
 
1527
                             thr, NULL, &next_thr);
 
1528
 
 
1529
                mutex_exit(&kernel_mutex);
 
1530
 
 
1531
                return(next_thr);
 
1532
        }
 
1533
 
 
1534
        ut_ad(node->state == COMMIT_NODE_WAIT);
 
1535
 
 
1536
        node->state = COMMIT_NODE_SEND;
 
1537
 
 
1538
        thr->run_node = que_node_get_parent(node);
 
1539
 
 
1540
        return(thr);
 
1541
}
 
1542
 
 
1543
/**********************************************************************//**
 
1544
Does the transaction commit for MySQL.
 
1545
@return DB_SUCCESS or error number */
 
1546
UNIV_INTERN
 
1547
ulint
 
1548
trx_commit_for_mysql(
 
1549
/*=================*/
 
1550
        trx_t*  trx)    /*!< in: trx handle */
 
1551
{
 
1552
        /* Because we do not do the commit by sending an Innobase
 
1553
        sig to the transaction, we must here make sure that trx has been
 
1554
        started. */
 
1555
 
 
1556
        ut_a(trx);
 
1557
 
 
1558
        trx_start_if_not_started(trx);
 
1559
 
 
1560
        trx->op_info = "committing";
 
1561
 
 
1562
        mutex_enter(&kernel_mutex);
 
1563
 
 
1564
        trx_commit_off_kernel(trx);
 
1565
 
 
1566
        mutex_exit(&kernel_mutex);
 
1567
 
 
1568
        trx->op_info = "";
 
1569
 
 
1570
        return(DB_SUCCESS);
 
1571
}
 
1572
 
 
1573
/**********************************************************************//**
 
1574
If required, flushes the log to disk if we called trx_commit_for_mysql()
 
1575
with trx->flush_log_later == TRUE.
 
1576
@return 0 or error number */
 
1577
UNIV_INTERN
 
1578
ulint
 
1579
trx_commit_complete_for_mysql(
 
1580
/*==========================*/
 
1581
        trx_t*  trx)    /*!< in: trx handle */
 
1582
{
 
1583
        ib_uint64_t     lsn     = trx->commit_lsn;
 
1584
 
 
1585
        ut_a(trx);
 
1586
 
 
1587
        trx->op_info = "flushing log";
 
1588
 
 
1589
        if (!trx->must_flush_log_later) {
 
1590
                /* Do nothing */
 
1591
        } else if (srv_flush_log_at_trx_commit == 0) {
 
1592
                /* Do nothing */
 
1593
        } else if (srv_flush_log_at_trx_commit == 1) {
 
1594
                if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
 
1595
                        /* Write the log but do not flush it to disk */
 
1596
 
 
1597
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1598
                } else {
 
1599
                        /* Write the log to the log files AND flush them to
 
1600
                        disk */
 
1601
 
 
1602
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
1603
                }
 
1604
        } else if (srv_flush_log_at_trx_commit == 2) {
 
1605
 
 
1606
                /* Write the log but do not flush it to disk */
 
1607
 
 
1608
                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1609
        } else {
 
1610
                ut_error;
 
1611
        }
 
1612
 
 
1613
        trx->must_flush_log_later = FALSE;
 
1614
 
 
1615
        trx->op_info = "";
 
1616
 
 
1617
        return(0);
 
1618
}
 
1619
 
 
1620
/**********************************************************************//**
 
1621
Marks the latest SQL statement ended. */
 
1622
UNIV_INTERN
 
1623
void
 
1624
trx_mark_sql_stat_end(
 
1625
/*==================*/
 
1626
        trx_t*  trx)    /*!< in: trx handle */
 
1627
{
 
1628
        ut_a(trx);
 
1629
 
 
1630
        if (trx->conc_state == TRX_NOT_STARTED) {
 
1631
                trx->undo_no = ut_dulint_zero;
 
1632
        }
 
1633
 
 
1634
        trx->last_sql_stat_start.least_undo_no = trx->undo_no;
 
1635
}
 
1636
 
 
1637
/**********************************************************************//**
 
1638
Prints info about a transaction to the given file. The caller must own the
 
1639
kernel mutex. */
 
1640
UNIV_INTERN
 
1641
void
 
1642
trx_print(
 
1643
/*======*/
 
1644
        FILE*   f,              /*!< in: output stream */
 
1645
        trx_t*  trx,            /*!< in: transaction */
 
1646
        ulint   max_query_len)  /*!< in: max query length to print, or 0 to
 
1647
                                   use the default max length */
 
1648
{
 
1649
        ibool   newline;
 
1650
 
 
1651
        fprintf(f, "TRANSACTION " TRX_ID_FMT, TRX_ID_PREP_PRINTF(trx->id));
 
1652
 
 
1653
        switch (trx->conc_state) {
 
1654
        case TRX_NOT_STARTED:
 
1655
                fputs(", not started", f);
 
1656
                break;
 
1657
        case TRX_ACTIVE:
 
1658
                fprintf(f, ", ACTIVE %lu sec",
 
1659
                        (ulong)difftime(time(NULL), trx->start_time));
 
1660
                break;
 
1661
        case TRX_PREPARED:
 
1662
                fprintf(f, ", ACTIVE (PREPARED) %lu sec",
 
1663
                        (ulong)difftime(time(NULL), trx->start_time));
 
1664
                break;
 
1665
        case TRX_COMMITTED_IN_MEMORY:
 
1666
                fputs(", COMMITTED IN MEMORY", f);
 
1667
                break;
 
1668
        default:
 
1669
                fprintf(f, " state %lu", (ulong) trx->conc_state);
 
1670
        }
 
1671
 
 
1672
#ifdef UNIV_LINUX
 
1673
        fprintf(f, ", process no %lu", trx->mysql_process_no);
 
1674
#endif
 
1675
        fprintf(f, ", OS thread id %lu",
 
1676
                (ulong) os_thread_pf(trx->mysql_thread_id));
 
1677
 
 
1678
        if (*trx->op_info) {
 
1679
                putc(' ', f);
 
1680
                fputs(trx->op_info, f);
 
1681
        }
 
1682
 
 
1683
        if (trx->is_recovered) {
 
1684
                fputs(" recovered trx", f);
 
1685
        }
 
1686
 
 
1687
        if (trx->is_purge) {
 
1688
                fputs(" purge trx", f);
 
1689
        }
 
1690
 
 
1691
        if (trx->declared_to_be_inside_innodb) {
 
1692
                fprintf(f, ", thread declared inside InnoDB %lu",
 
1693
                        (ulong) trx->n_tickets_to_enter_innodb);
 
1694
        }
 
1695
 
 
1696
        putc('\n', f);
 
1697
 
 
1698
        if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
 
1699
                fprintf(f, "mysql tables in use %lu, locked %lu\n",
 
1700
                        (ulong) trx->n_mysql_tables_in_use,
 
1701
                        (ulong) trx->mysql_n_tables_locked);
 
1702
        }
 
1703
 
 
1704
        newline = TRUE;
 
1705
 
 
1706
        switch (trx->que_state) {
 
1707
        case TRX_QUE_RUNNING:
 
1708
                newline = FALSE; break;
 
1709
        case TRX_QUE_LOCK_WAIT:
 
1710
                fputs("LOCK WAIT ", f); break;
 
1711
        case TRX_QUE_ROLLING_BACK:
 
1712
                fputs("ROLLING BACK ", f); break;
 
1713
        case TRX_QUE_COMMITTING:
 
1714
                fputs("COMMITTING ", f); break;
 
1715
        default:
 
1716
                fprintf(f, "que state %lu ", (ulong) trx->que_state);
 
1717
        }
 
1718
 
 
1719
        if (0 < UT_LIST_GET_LEN(trx->trx_locks)
 
1720
            || mem_heap_get_size(trx->lock_heap) > 400) {
 
1721
                newline = TRUE;
 
1722
 
 
1723
                fprintf(f, "%lu lock struct(s), heap size %lu,"
 
1724
                        " %lu row lock(s)",
 
1725
                        (ulong) UT_LIST_GET_LEN(trx->trx_locks),
 
1726
                        (ulong) mem_heap_get_size(trx->lock_heap),
 
1727
                        (ulong) lock_number_of_rows_locked(trx));
 
1728
        }
 
1729
 
 
1730
        if (trx->has_search_latch) {
 
1731
                newline = TRUE;
 
1732
                fputs(", holds adaptive hash latch", f);
 
1733
        }
 
1734
 
 
1735
        if (!ut_dulint_is_zero(trx->undo_no)) {
 
1736
                newline = TRUE;
 
1737
                fprintf(f, ", undo log entries %lu",
 
1738
                        (ulong) ut_dulint_get_low(trx->undo_no));
 
1739
        }
 
1740
 
 
1741
        if (newline) {
 
1742
                putc('\n', f);
 
1743
        }
 
1744
 
 
1745
        if (trx->mysql_thd != NULL) {
 
1746
                innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
 
1747
        }
 
1748
}
 
1749
 
 
1750
/*******************************************************************//**
 
1751
Compares the "weight" (or size) of two transactions. Transactions that
 
1752
have edited non-transactional tables are considered heavier than ones
 
1753
that have not.
 
1754
@return <0, 0 or >0; similar to strcmp(3) */
 
1755
UNIV_INTERN
 
1756
int
 
1757
trx_weight_cmp(
 
1758
/*===========*/
 
1759
        const trx_t*    a,      /*!< in: the first transaction to be compared */
 
1760
        const trx_t*    b)      /*!< in: the second transaction to be compared */
 
1761
{
 
1762
        ibool   a_notrans_edit;
 
1763
        ibool   b_notrans_edit;
 
1764
 
 
1765
        /* If mysql_thd is NULL for a transaction we assume that it has
 
1766
        not edited non-transactional tables. */
 
1767
 
 
1768
        a_notrans_edit = a->mysql_thd != NULL
 
1769
            && thd_has_edited_nontrans_tables(a->mysql_thd);
 
1770
 
 
1771
        b_notrans_edit = b->mysql_thd != NULL
 
1772
            && thd_has_edited_nontrans_tables(b->mysql_thd);
 
1773
 
 
1774
        if (a_notrans_edit && !b_notrans_edit) {
 
1775
 
 
1776
                return(1);
 
1777
        }
 
1778
 
 
1779
        if (!a_notrans_edit && b_notrans_edit) {
 
1780
 
 
1781
                return(-1);
 
1782
        }
 
1783
 
 
1784
        /* Either both had edited non-transactional tables or both had
 
1785
        not, we fall back to comparing the number of altered/locked
 
1786
        rows. */
 
1787
 
 
1788
#if 0
 
1789
        fprintf(stderr,
 
1790
                "%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n",
 
1791
                __func__,
 
1792
                ut_conv_dulint_to_longlong(a->undo_no),
 
1793
                UT_LIST_GET_LEN(a->trx_locks),
 
1794
                ut_conv_dulint_to_longlong(b->undo_no),
 
1795
                UT_LIST_GET_LEN(b->trx_locks));
 
1796
#endif
 
1797
 
 
1798
        return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b)));
 
1799
}
 
1800
 
 
1801
/****************************************************************//**
 
1802
Prepares a transaction. */
 
1803
UNIV_INTERN
 
1804
void
 
1805
trx_prepare_off_kernel(
 
1806
/*===================*/
 
1807
        trx_t*  trx)    /*!< in: transaction */
 
1808
{
 
1809
        page_t*         update_hdr_page;
 
1810
        trx_rseg_t*     rseg;
 
1811
        ib_uint64_t     lsn             = 0;
 
1812
        mtr_t           mtr;
 
1813
 
 
1814
        ut_ad(mutex_own(&kernel_mutex));
 
1815
 
 
1816
        rseg = trx->rseg;
 
1817
 
 
1818
        if (trx->insert_undo != NULL || trx->update_undo != NULL) {
 
1819
 
 
1820
                mutex_exit(&kernel_mutex);
 
1821
 
 
1822
                mtr_start(&mtr);
 
1823
 
 
1824
                /* Change the undo log segment states from TRX_UNDO_ACTIVE
 
1825
                to TRX_UNDO_PREPARED: these modifications to the file data
 
1826
                structure define the transaction as prepared in the
 
1827
                file-based world, at the serialization point of lsn. */
 
1828
 
 
1829
                mutex_enter(&(rseg->mutex));
 
1830
 
 
1831
                if (trx->insert_undo != NULL) {
 
1832
 
 
1833
                        /* It is not necessary to obtain trx->undo_mutex here
 
1834
                        because only a single OS thread is allowed to do the
 
1835
                        transaction prepare for this transaction. */
 
1836
 
 
1837
                        trx_undo_set_state_at_prepare(trx, trx->insert_undo,
 
1838
                                                      &mtr);
 
1839
                }
 
1840
 
 
1841
                if (trx->update_undo) {
 
1842
                        update_hdr_page = trx_undo_set_state_at_prepare(
 
1843
                                trx, trx->update_undo, &mtr);
 
1844
                }
 
1845
 
 
1846
                mutex_exit(&(rseg->mutex));
 
1847
 
 
1848
                /*--------------*/
 
1849
                mtr_commit(&mtr);       /* This mtr commit makes the
 
1850
                                        transaction prepared in the file-based
 
1851
                                        world */
 
1852
                /*--------------*/
 
1853
                lsn = mtr.end_lsn;
 
1854
 
 
1855
                mutex_enter(&kernel_mutex);
 
1856
        }
 
1857
 
 
1858
        ut_ad(mutex_own(&kernel_mutex));
 
1859
 
 
1860
        /*--------------------------------------*/
 
1861
        trx->conc_state = TRX_PREPARED;
 
1862
        /*--------------------------------------*/
 
1863
 
 
1864
        if (lsn) {
 
1865
                /* Depending on the my.cnf options, we may now write the log
 
1866
                buffer to the log files, making the prepared state of the
 
1867
                transaction durable if the OS does not crash. We may also
 
1868
                flush the log files to disk, making the prepared state of the
 
1869
                transaction durable also at an OS crash or a power outage.
 
1870
 
 
1871
                The idea in InnoDB's group prepare is that a group of
 
1872
                transactions gather behind a trx doing a physical disk write
 
1873
                to log files, and when that physical write has been completed,
 
1874
                one of those transactions does a write which prepares the whole
 
1875
                group. Note that this group prepare will only bring benefit if
 
1876
                there are > 2 users in the database. Then at least 2 users can
 
1877
                gather behind one doing the physical log write to disk.
 
1878
 
 
1879
                TODO: find out if MySQL holds some mutex when calling this.
 
1880
                That would spoil our group prepare algorithm. */
 
1881
 
 
1882
                mutex_exit(&kernel_mutex);
 
1883
 
 
1884
                if (srv_flush_log_at_trx_commit == 0) {
 
1885
                        /* Do nothing */
 
1886
                } else if (srv_flush_log_at_trx_commit == 1) {
 
1887
                        if (srv_unix_file_flush_method == SRV_UNIX_NOSYNC) {
 
1888
                                /* Write the log but do not flush it to disk */
 
1889
 
 
1890
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
 
1891
                                                FALSE);
 
1892
                        } else {
 
1893
                                /* Write the log to the log files AND flush
 
1894
                                them to disk */
 
1895
 
 
1896
                                log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
 
1897
                        }
 
1898
                } else if (srv_flush_log_at_trx_commit == 2) {
 
1899
 
 
1900
                        /* Write the log but do not flush it to disk */
 
1901
 
 
1902
                        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);
 
1903
                } else {
 
1904
                        ut_error;
 
1905
                }
 
1906
 
 
1907
                mutex_enter(&kernel_mutex);
 
1908
        }
 
1909
}
 
1910
 
 
1911
/**********************************************************************//**
 
1912
Does the transaction prepare for MySQL.
 
1913
@return 0 or error number */
 
1914
UNIV_INTERN
 
1915
ulint
 
1916
trx_prepare_for_mysql(
 
1917
/*==================*/
 
1918
        trx_t*  trx)    /*!< in: trx handle */
 
1919
{
 
1920
        /* Because we do not do the prepare by sending an Innobase
 
1921
        sig to the transaction, we must here make sure that trx has been
 
1922
        started. */
 
1923
 
 
1924
        ut_a(trx);
 
1925
 
 
1926
        trx->op_info = "preparing";
 
1927
 
 
1928
        trx_start_if_not_started(trx);
 
1929
 
 
1930
        mutex_enter(&kernel_mutex);
 
1931
 
 
1932
        trx_prepare_off_kernel(trx);
 
1933
 
 
1934
        mutex_exit(&kernel_mutex);
 
1935
 
 
1936
        trx->op_info = "";
 
1937
 
 
1938
        return(0);
 
1939
}
 
1940
 
 
1941
/**********************************************************************//**
 
1942
This function is used to find number of prepared transactions and
 
1943
their transaction objects for a recovery.
 
1944
@return number of prepared transactions stored in xid_list */
 
1945
UNIV_INTERN
 
1946
int
 
1947
trx_recover_for_mysql(
 
1948
/*==================*/
 
1949
        XID*    xid_list,       /*!< in/out: prepared transactions */
 
1950
        ulint   len)            /*!< in: number of slots in xid_list */
 
1951
{
 
1952
        trx_t*  trx;
 
1953
        ulint   count = 0;
 
1954
 
 
1955
        ut_ad(xid_list);
 
1956
        ut_ad(len);
 
1957
 
 
1958
        /* We should set those transactions which are in the prepared state
 
1959
        to the xid_list */
 
1960
 
 
1961
        mutex_enter(&kernel_mutex);
 
1962
 
 
1963
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
1964
 
 
1965
        while (trx) {
 
1966
                if (trx->conc_state == TRX_PREPARED) {
 
1967
                        xid_list[count] = trx->xid;
 
1968
 
 
1969
                        if (count == 0) {
 
1970
                                ut_print_timestamp(stderr);
 
1971
                                fprintf(stderr,
 
1972
                                        "  InnoDB: Starting recovery for"
 
1973
                                        " XA transactions...\n");
 
1974
                        }
 
1975
 
 
1976
                        ut_print_timestamp(stderr);
 
1977
                        fprintf(stderr,
 
1978
                                "  InnoDB: Transaction " TRX_ID_FMT " in"
 
1979
                                " prepared state after recovery\n",
 
1980
                                TRX_ID_PREP_PRINTF(trx->id));
 
1981
 
 
1982
                        ut_print_timestamp(stderr);
 
1983
                        fprintf(stderr,
 
1984
                                "  InnoDB: Transaction contains changes"
 
1985
                                " to %lu rows\n",
 
1986
                                (ulong) ut_conv_dulint_to_longlong(
 
1987
                                        trx->undo_no));
 
1988
 
 
1989
                        count++;
 
1990
 
 
1991
                        if (count == len) {
 
1992
                                break;
 
1993
                        }
 
1994
                }
 
1995
 
 
1996
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
1997
        }
 
1998
 
 
1999
        mutex_exit(&kernel_mutex);
 
2000
 
 
2001
        if (count > 0){
 
2002
                ut_print_timestamp(stderr);
 
2003
                fprintf(stderr,
 
2004
                        "  InnoDB: %lu transactions in prepared state"
 
2005
                        " after recovery\n",
 
2006
                        (ulong) count);
 
2007
        }
 
2008
 
 
2009
        return ((int) count);
 
2010
}
 
2011
 
 
2012
/*******************************************************************//**
 
2013
This function is used to find one X/Open XA distributed transaction
 
2014
which is in the prepared state
 
2015
@return trx or NULL */
 
2016
UNIV_INTERN
 
2017
trx_t*
 
2018
trx_get_trx_by_xid(
 
2019
/*===============*/
 
2020
        XID*    xid)    /*!< in: X/Open XA transaction identification */
 
2021
{
 
2022
        trx_t*  trx;
 
2023
 
 
2024
        if (xid == NULL) {
 
2025
 
 
2026
                return (NULL);
 
2027
        }
 
2028
 
 
2029
        mutex_enter(&kernel_mutex);
 
2030
 
 
2031
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
2032
 
 
2033
        while (trx) {
 
2034
                /* Compare two X/Open XA transaction id's: their
 
2035
                length should be the same and binary comparison
 
2036
                of gtrid_lenght+bqual_length bytes should be
 
2037
                the same */
 
2038
 
 
2039
                if (xid->gtrid_length == trx->xid.gtrid_length
 
2040
                    && xid->bqual_length == trx->xid.bqual_length
 
2041
                    && memcmp(xid->data, trx->xid.data,
 
2042
                              xid->gtrid_length + xid->bqual_length) == 0) {
 
2043
                        break;
 
2044
                }
 
2045
 
 
2046
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
2047
        }
 
2048
 
 
2049
        mutex_exit(&kernel_mutex);
 
2050
 
 
2051
        if (trx) {
 
2052
                if (trx->conc_state != TRX_PREPARED) {
 
2053
 
 
2054
                        return(NULL);
 
2055
                }
 
2056
 
 
2057
                return(trx);
 
2058
        } else {
 
2059
                return(NULL);
 
2060
        }
 
2061
}