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

« back to all changes in this revision

Viewing changes to storage/innodb_plugin/trx/trx0purge.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/trx0purge.c
 
21
Purge old versions
 
22
 
 
23
Created 3/26/1996 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#include "trx0purge.h"
 
27
 
 
28
#ifdef UNIV_NONINL
 
29
#include "trx0purge.ic"
 
30
#endif
 
31
 
 
32
#include "fsp0fsp.h"
 
33
#include "mach0data.h"
 
34
#include "mtr0log.h"
 
35
#include "trx0rseg.h"
 
36
#include "trx0trx.h"
 
37
#include "trx0roll.h"
 
38
#include "read0read.h"
 
39
#include "fut0fut.h"
 
40
#include "que0que.h"
 
41
#include "row0purge.h"
 
42
#include "row0upd.h"
 
43
#include "trx0rec.h"
 
44
#include "srv0que.h"
 
45
#include "os0thread.h"
 
46
 
 
47
/** The global data structure coordinating a purge */
 
48
UNIV_INTERN trx_purge_t*        purge_sys = NULL;
 
49
 
 
50
/** A dummy undo record used as a return value when we have a whole undo log
 
51
which needs no purge */
 
52
UNIV_INTERN trx_undo_rec_t      trx_purge_dummy_rec;
 
53
 
 
54
/*****************************************************************//**
 
55
Checks if trx_id is >= purge_view: then it is guaranteed that its update
 
56
undo log still exists in the system.
 
57
@return TRUE if is sure that it is preserved, also if the function
 
58
returns FALSE, it is possible that the undo log still exists in the
 
59
system */
 
60
UNIV_INTERN
 
61
ibool
 
62
trx_purge_update_undo_must_exist(
 
63
/*=============================*/
 
64
        trx_id_t        trx_id) /*!< in: transaction id */
 
65
{
 
66
#ifdef UNIV_SYNC_DEBUG
 
67
        ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
 
68
#endif /* UNIV_SYNC_DEBUG */
 
69
 
 
70
        if (!read_view_sees_trx_id(purge_sys->view, trx_id)) {
 
71
 
 
72
                return(TRUE);
 
73
        }
 
74
 
 
75
        return(FALSE);
 
76
}
 
77
 
 
78
/*=================== PURGE RECORD ARRAY =============================*/
 
79
 
 
80
/*******************************************************************//**
 
81
Stores info of an undo log record during a purge.
 
82
@return pointer to the storage cell */
 
83
static
 
84
trx_undo_inf_t*
 
85
trx_purge_arr_store_info(
 
86
/*=====================*/
 
87
        trx_id_t        trx_no, /*!< in: transaction number */
 
88
        undo_no_t       undo_no)/*!< in: undo number */
 
89
{
 
90
        trx_undo_inf_t* cell;
 
91
        trx_undo_arr_t* arr;
 
92
        ulint           i;
 
93
 
 
94
        arr = purge_sys->arr;
 
95
 
 
96
        for (i = 0;; i++) {
 
97
                cell = trx_undo_arr_get_nth_info(arr, i);
 
98
 
 
99
                if (!(cell->in_use)) {
 
100
                        /* Not in use, we may store here */
 
101
                        cell->undo_no = undo_no;
 
102
                        cell->trx_no = trx_no;
 
103
                        cell->in_use = TRUE;
 
104
 
 
105
                        arr->n_used++;
 
106
 
 
107
                        return(cell);
 
108
                }
 
109
        }
 
110
}
 
111
 
 
112
/*******************************************************************//**
 
113
Removes info of an undo log record during a purge. */
 
114
UNIV_INLINE
 
115
void
 
116
trx_purge_arr_remove_info(
 
117
/*======================*/
 
118
        trx_undo_inf_t* cell)   /*!< in: pointer to the storage cell */
 
119
{
 
120
        trx_undo_arr_t* arr;
 
121
 
 
122
        arr = purge_sys->arr;
 
123
 
 
124
        cell->in_use = FALSE;
 
125
 
 
126
        ut_ad(arr->n_used > 0);
 
127
 
 
128
        arr->n_used--;
 
129
}
 
130
 
 
131
/*******************************************************************//**
 
132
Gets the biggest pair of a trx number and an undo number in a purge array. */
 
133
static
 
134
void
 
135
trx_purge_arr_get_biggest(
 
136
/*======================*/
 
137
        trx_undo_arr_t* arr,    /*!< in: purge array */
 
138
        trx_id_t*       trx_no, /*!< out: transaction number: ut_dulint_zero
 
139
                                if array is empty */
 
140
        undo_no_t*      undo_no)/*!< out: undo number */
 
141
{
 
142
        trx_undo_inf_t* cell;
 
143
        trx_id_t        pair_trx_no;
 
144
        undo_no_t       pair_undo_no;
 
145
        int             trx_cmp;
 
146
        ulint           n_used;
 
147
        ulint           i;
 
148
        ulint           n;
 
149
 
 
150
        n = 0;
 
151
        n_used = arr->n_used;
 
152
        pair_trx_no = ut_dulint_zero;
 
153
        pair_undo_no = ut_dulint_zero;
 
154
 
 
155
        for (i = 0;; i++) {
 
156
                cell = trx_undo_arr_get_nth_info(arr, i);
 
157
 
 
158
                if (cell->in_use) {
 
159
                        n++;
 
160
                        trx_cmp = ut_dulint_cmp(cell->trx_no, pair_trx_no);
 
161
 
 
162
                        if ((trx_cmp > 0)
 
163
                            || ((trx_cmp == 0)
 
164
                                && (ut_dulint_cmp(cell->undo_no,
 
165
                                                  pair_undo_no) >= 0))) {
 
166
 
 
167
                                pair_trx_no = cell->trx_no;
 
168
                                pair_undo_no = cell->undo_no;
 
169
                        }
 
170
                }
 
171
 
 
172
                if (n == n_used) {
 
173
                        *trx_no = pair_trx_no;
 
174
                        *undo_no = pair_undo_no;
 
175
 
 
176
                        return;
 
177
                }
 
178
        }
 
179
}
 
180
 
 
181
/****************************************************************//**
 
182
Builds a purge 'query' graph. The actual purge is performed by executing
 
183
this query graph.
 
184
@return own: the query graph */
 
185
static
 
186
que_t*
 
187
trx_purge_graph_build(void)
 
188
/*=======================*/
 
189
{
 
190
        mem_heap_t*     heap;
 
191
        que_fork_t*     fork;
 
192
        que_thr_t*      thr;
 
193
        /*      que_thr_t*      thr2; */
 
194
 
 
195
        heap = mem_heap_create(512);
 
196
        fork = que_fork_create(NULL, NULL, QUE_FORK_PURGE, heap);
 
197
        fork->trx = purge_sys->trx;
 
198
 
 
199
        thr = que_thr_create(fork, heap);
 
200
 
 
201
        thr->child = row_purge_node_create(thr, heap);
 
202
 
 
203
        /*      thr2 = que_thr_create(fork, fork, heap);
 
204
 
 
205
        thr2->child = row_purge_node_create(fork, thr2, heap);   */
 
206
 
 
207
        return(fork);
 
208
}
 
209
 
 
210
/********************************************************************//**
 
211
Creates the global purge system control structure and inits the history
 
212
mutex. */
 
213
UNIV_INTERN
 
214
void
 
215
trx_purge_sys_create(void)
 
216
/*======================*/
 
217
{
 
218
        ut_ad(mutex_own(&kernel_mutex));
 
219
 
 
220
        purge_sys = mem_alloc(sizeof(trx_purge_t));
 
221
 
 
222
        purge_sys->state = TRX_STOP_PURGE;
 
223
 
 
224
        purge_sys->n_pages_handled = 0;
 
225
 
 
226
        purge_sys->purge_trx_no = ut_dulint_zero;
 
227
        purge_sys->purge_undo_no = ut_dulint_zero;
 
228
        purge_sys->next_stored = FALSE;
 
229
 
 
230
        rw_lock_create(&purge_sys->latch, SYNC_PURGE_LATCH);
 
231
 
 
232
        mutex_create(&purge_sys->mutex, SYNC_PURGE_SYS);
 
233
 
 
234
        purge_sys->heap = mem_heap_create(256);
 
235
 
 
236
        purge_sys->arr = trx_undo_arr_create();
 
237
 
 
238
        purge_sys->sess = sess_open();
 
239
 
 
240
        purge_sys->trx = purge_sys->sess->trx;
 
241
 
 
242
        purge_sys->trx->is_purge = 1;
 
243
 
 
244
        ut_a(trx_start_low(purge_sys->trx, ULINT_UNDEFINED));
 
245
 
 
246
        purge_sys->query = trx_purge_graph_build();
 
247
 
 
248
        purge_sys->view = read_view_oldest_copy_or_open_new(ut_dulint_zero,
 
249
                                                            purge_sys->heap);
 
250
}
 
251
 
 
252
/************************************************************************
 
253
Frees the global purge system control structure. */
 
254
UNIV_INTERN
 
255
void
 
256
trx_purge_sys_close(void)
 
257
/*======================*/
 
258
{
 
259
        ut_ad(!mutex_own(&kernel_mutex));
 
260
 
 
261
        que_graph_free(purge_sys->query);
 
262
 
 
263
        ut_a(purge_sys->sess->trx->is_purge);
 
264
        purge_sys->sess->trx->conc_state = TRX_NOT_STARTED;
 
265
        sess_close(purge_sys->sess);
 
266
        purge_sys->sess = NULL;
 
267
 
 
268
        if (purge_sys->view != NULL) {
 
269
                /* Because acquiring the kernel mutex is a pre-condition
 
270
                of read_view_close(). We don't really need it here. */
 
271
                mutex_enter(&kernel_mutex);
 
272
 
 
273
                read_view_close(purge_sys->view);
 
274
                purge_sys->view = NULL;
 
275
 
 
276
                mutex_exit(&kernel_mutex);
 
277
        }
 
278
 
 
279
        trx_undo_arr_free(purge_sys->arr);
 
280
 
 
281
        rw_lock_free(&purge_sys->latch);
 
282
        mutex_free(&purge_sys->mutex);
 
283
 
 
284
        mem_heap_free(purge_sys->heap);
 
285
        mem_free(purge_sys);
 
286
 
 
287
        purge_sys = NULL;
 
288
}
 
289
 
 
290
/*================ UNDO LOG HISTORY LIST =============================*/
 
291
 
 
292
/********************************************************************//**
 
293
Adds the update undo log as the first log in the history list. Removes the
 
294
update undo log segment from the rseg slot if it is too big for reuse. */
 
295
UNIV_INTERN
 
296
void
 
297
trx_purge_add_update_undo_to_history(
 
298
/*=================================*/
 
299
        trx_t*  trx,            /*!< in: transaction */
 
300
        page_t* undo_page,      /*!< in: update undo log header page,
 
301
                                x-latched */
 
302
        mtr_t*  mtr)            /*!< in: mtr */
 
303
{
 
304
        trx_undo_t*     undo;
 
305
        trx_rseg_t*     rseg;
 
306
        trx_rsegf_t*    rseg_header;
 
307
        trx_usegf_t*    seg_header;
 
308
        trx_ulogf_t*    undo_header;
 
309
        trx_upagef_t*   page_header;
 
310
        ulint           hist_size;
 
311
 
 
312
        undo = trx->update_undo;
 
313
 
 
314
        ut_ad(undo);
 
315
 
 
316
        rseg = undo->rseg;
 
317
 
 
318
        ut_ad(mutex_own(&(rseg->mutex)));
 
319
 
 
320
        rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size,
 
321
                                    rseg->page_no, mtr);
 
322
 
 
323
        undo_header = undo_page + undo->hdr_offset;
 
324
        seg_header  = undo_page + TRX_UNDO_SEG_HDR;
 
325
        page_header = undo_page + TRX_UNDO_PAGE_HDR;
 
326
 
 
327
        if (undo->state != TRX_UNDO_CACHED) {
 
328
                /* The undo log segment will not be reused */
 
329
 
 
330
                if (undo->id >= TRX_RSEG_N_SLOTS) {
 
331
                        fprintf(stderr,
 
332
                                "InnoDB: Error: undo->id is %lu\n",
 
333
                                (ulong) undo->id);
 
334
                        ut_error;
 
335
                }
 
336
 
 
337
                trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr);
 
338
 
 
339
                hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
 
340
                                           MLOG_4BYTES, mtr);
 
341
                ut_ad(undo->size == flst_get_len(
 
342
                              seg_header + TRX_UNDO_PAGE_LIST, mtr));
 
343
 
 
344
                mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
 
345
                                 hist_size + undo->size, MLOG_4BYTES, mtr);
 
346
        }
 
347
 
 
348
        /* Add the log as the first in the history list */
 
349
        flst_add_first(rseg_header + TRX_RSEG_HISTORY,
 
350
                       undo_header + TRX_UNDO_HISTORY_NODE, mtr);
 
351
        mutex_enter(&kernel_mutex);
 
352
        trx_sys->rseg_history_len++;
 
353
        mutex_exit(&kernel_mutex);
 
354
 
 
355
        /* Write the trx number to the undo log header */
 
356
        mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);
 
357
        /* Write information about delete markings to the undo log header */
 
358
 
 
359
        if (!undo->del_marks) {
 
360
                mlog_write_ulint(undo_header + TRX_UNDO_DEL_MARKS, FALSE,
 
361
                                 MLOG_2BYTES, mtr);
 
362
        }
 
363
 
 
364
        if (rseg->last_page_no == FIL_NULL) {
 
365
 
 
366
                rseg->last_page_no = undo->hdr_page_no;
 
367
                rseg->last_offset = undo->hdr_offset;
 
368
                rseg->last_trx_no = trx->no;
 
369
                rseg->last_del_marks = undo->del_marks;
 
370
        }
 
371
}
 
372
 
 
373
/**********************************************************************//**
 
374
Frees an undo log segment which is in the history list. Cuts the end of the
 
375
history list at the youngest undo log in this segment. */
 
376
static
 
377
void
 
378
trx_purge_free_segment(
 
379
/*===================*/
 
380
        trx_rseg_t*     rseg,           /*!< in: rollback segment */
 
381
        fil_addr_t      hdr_addr,       /*!< in: the file address of log_hdr */
 
382
        ulint           n_removed_logs) /*!< in: count of how many undo logs we
 
383
                                        will cut off from the end of the
 
384
                                        history list */
 
385
{
 
386
        page_t*         undo_page;
 
387
        trx_rsegf_t*    rseg_hdr;
 
388
        trx_ulogf_t*    log_hdr;
 
389
        trx_usegf_t*    seg_hdr;
 
390
        ibool           freed;
 
391
        ulint           seg_size;
 
392
        ulint           hist_size;
 
393
        ibool           marked          = FALSE;
 
394
        mtr_t           mtr;
 
395
 
 
396
        /*      fputs("Freeing an update undo log segment\n", stderr); */
 
397
 
 
398
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
399
loop:
 
400
        mtr_start(&mtr);
 
401
        mutex_enter(&(rseg->mutex));
 
402
 
 
403
        rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
 
404
                                 rseg->page_no, &mtr);
 
405
 
 
406
        undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
 
407
                                      hdr_addr.page, &mtr);
 
408
        seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
 
409
        log_hdr = undo_page + hdr_addr.boffset;
 
410
 
 
411
        /* Mark the last undo log totally purged, so that if the system
 
412
        crashes, the tail of the undo log will not get accessed again. The
 
413
        list of pages in the undo log tail gets inconsistent during the
 
414
        freeing of the segment, and therefore purge should not try to access
 
415
        them again. */
 
416
 
 
417
        if (!marked) {
 
418
                mlog_write_ulint(log_hdr + TRX_UNDO_DEL_MARKS, FALSE,
 
419
                                 MLOG_2BYTES, &mtr);
 
420
                marked = TRUE;
 
421
        }
 
422
 
 
423
        freed = fseg_free_step_not_header(seg_hdr + TRX_UNDO_FSEG_HEADER,
 
424
                                          &mtr);
 
425
        if (!freed) {
 
426
                mutex_exit(&(rseg->mutex));
 
427
                mtr_commit(&mtr);
 
428
 
 
429
                goto loop;
 
430
        }
 
431
 
 
432
        /* The page list may now be inconsistent, but the length field
 
433
        stored in the list base node tells us how big it was before we
 
434
        started the freeing. */
 
435
 
 
436
        seg_size = flst_get_len(seg_hdr + TRX_UNDO_PAGE_LIST, &mtr);
 
437
 
 
438
        /* We may free the undo log segment header page; it must be freed
 
439
        within the same mtr as the undo log header is removed from the
 
440
        history list: otherwise, in case of a database crash, the segment
 
441
        could become inaccessible garbage in the file space. */
 
442
 
 
443
        flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY,
 
444
                     log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr);
 
445
 
 
446
        mutex_enter(&kernel_mutex);
 
447
        ut_ad(trx_sys->rseg_history_len >= n_removed_logs);
 
448
        trx_sys->rseg_history_len -= n_removed_logs;
 
449
        mutex_exit(&kernel_mutex);
 
450
 
 
451
        freed = FALSE;
 
452
 
 
453
        while (!freed) {
 
454
                /* Here we assume that a file segment with just the header
 
455
                page can be freed in a few steps, so that the buffer pool
 
456
                is not flooded with bufferfixed pages: see the note in
 
457
                fsp0fsp.c. */
 
458
 
 
459
                freed = fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER,
 
460
                                       &mtr);
 
461
        }
 
462
 
 
463
        hist_size = mtr_read_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
 
464
                                   MLOG_4BYTES, &mtr);
 
465
        ut_ad(hist_size >= seg_size);
 
466
 
 
467
        mlog_write_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE,
 
468
                         hist_size - seg_size, MLOG_4BYTES, &mtr);
 
469
 
 
470
        ut_ad(rseg->curr_size >= seg_size);
 
471
 
 
472
        rseg->curr_size -= seg_size;
 
473
 
 
474
        mutex_exit(&(rseg->mutex));
 
475
 
 
476
        mtr_commit(&mtr);
 
477
}
 
478
 
 
479
/********************************************************************//**
 
480
Removes unnecessary history data from a rollback segment. */
 
481
static
 
482
void
 
483
trx_purge_truncate_rseg_history(
 
484
/*============================*/
 
485
        trx_rseg_t*     rseg,           /*!< in: rollback segment */
 
486
        trx_id_t        limit_trx_no,   /*!< in: remove update undo logs whose
 
487
                                        trx number is < limit_trx_no */
 
488
        undo_no_t       limit_undo_no)  /*!< in: if transaction number is equal
 
489
                                        to limit_trx_no, truncate undo records
 
490
                                        with undo number < limit_undo_no */
 
491
{
 
492
        fil_addr_t      hdr_addr;
 
493
        fil_addr_t      prev_hdr_addr;
 
494
        trx_rsegf_t*    rseg_hdr;
 
495
        page_t*         undo_page;
 
496
        trx_ulogf_t*    log_hdr;
 
497
        trx_usegf_t*    seg_hdr;
 
498
        int             cmp;
 
499
        ulint           n_removed_logs  = 0;
 
500
        mtr_t           mtr;
 
501
 
 
502
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
503
 
 
504
        mtr_start(&mtr);
 
505
        mutex_enter(&(rseg->mutex));
 
506
 
 
507
        rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
 
508
                                 rseg->page_no, &mtr);
 
509
 
 
510
        hdr_addr = trx_purge_get_log_from_hist(
 
511
                flst_get_last(rseg_hdr + TRX_RSEG_HISTORY, &mtr));
 
512
loop:
 
513
        if (hdr_addr.page == FIL_NULL) {
 
514
 
 
515
                mutex_exit(&(rseg->mutex));
 
516
 
 
517
                mtr_commit(&mtr);
 
518
 
 
519
                return;
 
520
        }
 
521
 
 
522
        undo_page = trx_undo_page_get(rseg->space, rseg->zip_size,
 
523
                                      hdr_addr.page, &mtr);
 
524
 
 
525
        log_hdr = undo_page + hdr_addr.boffset;
 
526
 
 
527
        cmp = ut_dulint_cmp(mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO),
 
528
                            limit_trx_no);
 
529
        if (cmp == 0) {
 
530
                trx_undo_truncate_start(rseg, rseg->space, hdr_addr.page,
 
531
                                        hdr_addr.boffset, limit_undo_no);
 
532
        }
 
533
 
 
534
        if (cmp >= 0) {
 
535
                mutex_enter(&kernel_mutex);
 
536
                ut_a(trx_sys->rseg_history_len >= n_removed_logs);
 
537
                trx_sys->rseg_history_len -= n_removed_logs;
 
538
                mutex_exit(&kernel_mutex);
 
539
 
 
540
                flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
 
541
                                  log_hdr + TRX_UNDO_HISTORY_NODE,
 
542
                                  n_removed_logs, &mtr);
 
543
 
 
544
                mutex_exit(&(rseg->mutex));
 
545
                mtr_commit(&mtr);
 
546
 
 
547
                return;
 
548
        }
 
549
 
 
550
        prev_hdr_addr = trx_purge_get_log_from_hist(
 
551
                flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
 
552
        n_removed_logs++;
 
553
 
 
554
        seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
 
555
 
 
556
        if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
 
557
            && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {
 
558
 
 
559
                /* We can free the whole log segment */
 
560
 
 
561
                mutex_exit(&(rseg->mutex));
 
562
                mtr_commit(&mtr);
 
563
 
 
564
                trx_purge_free_segment(rseg, hdr_addr, n_removed_logs);
 
565
 
 
566
                n_removed_logs = 0;
 
567
        } else {
 
568
                mutex_exit(&(rseg->mutex));
 
569
                mtr_commit(&mtr);
 
570
        }
 
571
 
 
572
        mtr_start(&mtr);
 
573
        mutex_enter(&(rseg->mutex));
 
574
 
 
575
        rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size,
 
576
                                 rseg->page_no, &mtr);
 
577
 
 
578
        hdr_addr = prev_hdr_addr;
 
579
 
 
580
        goto loop;
 
581
}
 
582
 
 
583
/********************************************************************//**
 
584
Removes unnecessary history data from rollback segments. NOTE that when this
 
585
function is called, the caller must not have any latches on undo log pages! */
 
586
static
 
587
void
 
588
trx_purge_truncate_history(void)
 
589
/*============================*/
 
590
{
 
591
        trx_rseg_t*     rseg;
 
592
        trx_id_t        limit_trx_no;
 
593
        undo_no_t       limit_undo_no;
 
594
 
 
595
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
596
 
 
597
        trx_purge_arr_get_biggest(purge_sys->arr, &limit_trx_no,
 
598
                                  &limit_undo_no);
 
599
 
 
600
        if (ut_dulint_is_zero(limit_trx_no)) {
 
601
 
 
602
                limit_trx_no = purge_sys->purge_trx_no;
 
603
                limit_undo_no = purge_sys->purge_undo_no;
 
604
        }
 
605
 
 
606
        /* We play safe and set the truncate limit at most to the purge view
 
607
        low_limit number, though this is not necessary */
 
608
 
 
609
        if (ut_dulint_cmp(limit_trx_no, purge_sys->view->low_limit_no) >= 0) {
 
610
                limit_trx_no = purge_sys->view->low_limit_no;
 
611
                limit_undo_no = ut_dulint_zero;
 
612
        }
 
613
 
 
614
        ut_ad((ut_dulint_cmp(limit_trx_no,
 
615
                             purge_sys->view->low_limit_no) <= 0));
 
616
 
 
617
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
618
 
 
619
        while (rseg) {
 
620
                trx_purge_truncate_rseg_history(rseg, limit_trx_no,
 
621
                                                limit_undo_no);
 
622
                rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
623
        }
 
624
}
 
625
 
 
626
/********************************************************************//**
 
627
Does a truncate if the purge array is empty. NOTE that when this function is
 
628
called, the caller must not have any latches on undo log pages!
 
629
@return TRUE if array empty */
 
630
UNIV_INLINE
 
631
ibool
 
632
trx_purge_truncate_if_arr_empty(void)
 
633
/*=================================*/
 
634
{
 
635
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
636
 
 
637
        if (purge_sys->arr->n_used == 0) {
 
638
 
 
639
                trx_purge_truncate_history();
 
640
 
 
641
                return(TRUE);
 
642
        }
 
643
 
 
644
        return(FALSE);
 
645
}
 
646
 
 
647
/***********************************************************************//**
 
648
Updates the last not yet purged history log info in rseg when we have purged
 
649
a whole undo log. Advances also purge_sys->purge_trx_no past the purged log. */
 
650
static
 
651
void
 
652
trx_purge_rseg_get_next_history_log(
 
653
/*================================*/
 
654
        trx_rseg_t*     rseg)   /*!< in: rollback segment */
 
655
{
 
656
        page_t*         undo_page;
 
657
        trx_ulogf_t*    log_hdr;
 
658
        trx_usegf_t*    seg_hdr;
 
659
        fil_addr_t      prev_log_addr;
 
660
        trx_id_t        trx_no;
 
661
        ibool           del_marks;
 
662
        mtr_t           mtr;
 
663
 
 
664
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
665
 
 
666
        mutex_enter(&(rseg->mutex));
 
667
 
 
668
        ut_a(rseg->last_page_no != FIL_NULL);
 
669
 
 
670
        purge_sys->purge_trx_no = ut_dulint_add(rseg->last_trx_no, 1);
 
671
        purge_sys->purge_undo_no = ut_dulint_zero;
 
672
        purge_sys->next_stored = FALSE;
 
673
 
 
674
        mtr_start(&mtr);
 
675
 
 
676
        undo_page = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
 
677
                                                rseg->last_page_no, &mtr);
 
678
        log_hdr = undo_page + rseg->last_offset;
 
679
        seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
 
680
 
 
681
        /* Increase the purge page count by one for every handled log */
 
682
 
 
683
        purge_sys->n_pages_handled++;
 
684
 
 
685
        prev_log_addr = trx_purge_get_log_from_hist(
 
686
                flst_get_prev_addr(log_hdr + TRX_UNDO_HISTORY_NODE, &mtr));
 
687
        if (prev_log_addr.page == FIL_NULL) {
 
688
                /* No logs left in the history list */
 
689
 
 
690
                rseg->last_page_no = FIL_NULL;
 
691
 
 
692
                mutex_exit(&(rseg->mutex));
 
693
                mtr_commit(&mtr);
 
694
 
 
695
                mutex_enter(&kernel_mutex);
 
696
 
 
697
                /* Add debug code to track history list corruption reported
 
698
                on the MySQL mailing list on Nov 9, 2004. The fut0lst.c
 
699
                file-based list was corrupt. The prev node pointer was
 
700
                FIL_NULL, even though the list length was over 8 million nodes!
 
701
                We assume that purge truncates the history list in moderate
 
702
                size pieces, and if we here reach the head of the list, the
 
703
                list cannot be longer than 20 000 undo logs now. */
 
704
 
 
705
                if (trx_sys->rseg_history_len > 20000) {
 
706
                        ut_print_timestamp(stderr);
 
707
                        fprintf(stderr,
 
708
                                "  InnoDB: Warning: purge reached the"
 
709
                                " head of the history list,\n"
 
710
                                "InnoDB: but its length is still"
 
711
                                " reported as %lu! Make a detailed bug\n"
 
712
                                "InnoDB: report, and submit it"
 
713
                                " to http://bugs.mysql.com\n",
 
714
                                (ulong) trx_sys->rseg_history_len);
 
715
                }
 
716
 
 
717
                mutex_exit(&kernel_mutex);
 
718
 
 
719
                return;
 
720
        }
 
721
 
 
722
        mutex_exit(&(rseg->mutex));
 
723
        mtr_commit(&mtr);
 
724
 
 
725
        /* Read the trx number and del marks from the previous log header */
 
726
        mtr_start(&mtr);
 
727
 
 
728
        log_hdr = trx_undo_page_get_s_latched(rseg->space, rseg->zip_size,
 
729
                                              prev_log_addr.page, &mtr)
 
730
                + prev_log_addr.boffset;
 
731
 
 
732
        trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
 
733
 
 
734
        del_marks = mach_read_from_2(log_hdr + TRX_UNDO_DEL_MARKS);
 
735
 
 
736
        mtr_commit(&mtr);
 
737
 
 
738
        mutex_enter(&(rseg->mutex));
 
739
 
 
740
        rseg->last_page_no = prev_log_addr.page;
 
741
        rseg->last_offset = prev_log_addr.boffset;
 
742
        rseg->last_trx_no = trx_no;
 
743
        rseg->last_del_marks = del_marks;
 
744
 
 
745
        mutex_exit(&(rseg->mutex));
 
746
}
 
747
 
 
748
/***********************************************************************//**
 
749
Chooses the next undo log to purge and updates the info in purge_sys. This
 
750
function is used to initialize purge_sys when the next record to purge is
 
751
not known, and also to update the purge system info on the next record when
 
752
purge has handled the whole undo log for a transaction. */
 
753
static
 
754
void
 
755
trx_purge_choose_next_log(void)
 
756
/*===========================*/
 
757
{
 
758
        trx_undo_rec_t* rec;
 
759
        trx_rseg_t*     rseg;
 
760
        trx_rseg_t*     min_rseg;
 
761
        trx_id_t        min_trx_no;
 
762
        ulint           space = 0;   /* remove warning (??? bug ???) */
 
763
        ulint           zip_size = 0;
 
764
        ulint           page_no = 0; /* remove warning (??? bug ???) */
 
765
        ulint           offset = 0;  /* remove warning (??? bug ???) */
 
766
        mtr_t           mtr;
 
767
 
 
768
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
769
        ut_ad(purge_sys->next_stored == FALSE);
 
770
 
 
771
        rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 
772
 
 
773
        min_trx_no = ut_dulint_max;
 
774
 
 
775
        min_rseg = NULL;
 
776
 
 
777
        while (rseg) {
 
778
                mutex_enter(&(rseg->mutex));
 
779
 
 
780
                if (rseg->last_page_no != FIL_NULL) {
 
781
 
 
782
                        if ((min_rseg == NULL)
 
783
                            || (ut_dulint_cmp(min_trx_no,
 
784
                                              rseg->last_trx_no) > 0)) {
 
785
 
 
786
                                min_rseg = rseg;
 
787
                                min_trx_no = rseg->last_trx_no;
 
788
                                space = rseg->space;
 
789
                                zip_size = rseg->zip_size;
 
790
                                ut_a(space == 0); /* We assume in purge of
 
791
                                                  externally stored fields
 
792
                                                  that space id == 0 */
 
793
                                page_no = rseg->last_page_no;
 
794
                                offset = rseg->last_offset;
 
795
                        }
 
796
                }
 
797
 
 
798
                mutex_exit(&(rseg->mutex));
 
799
 
 
800
                rseg = UT_LIST_GET_NEXT(rseg_list, rseg);
 
801
        }
 
802
 
 
803
        if (min_rseg == NULL) {
 
804
 
 
805
                return;
 
806
        }
 
807
 
 
808
        mtr_start(&mtr);
 
809
 
 
810
        if (!min_rseg->last_del_marks) {
 
811
                /* No need to purge this log */
 
812
 
 
813
                rec = &trx_purge_dummy_rec;
 
814
        } else {
 
815
                rec = trx_undo_get_first_rec(space, zip_size, page_no, offset,
 
816
                                             RW_S_LATCH, &mtr);
 
817
                if (rec == NULL) {
 
818
                        /* Undo log empty */
 
819
 
 
820
                        rec = &trx_purge_dummy_rec;
 
821
                }
 
822
        }
 
823
 
 
824
        purge_sys->next_stored = TRUE;
 
825
        purge_sys->rseg = min_rseg;
 
826
 
 
827
        purge_sys->hdr_page_no = page_no;
 
828
        purge_sys->hdr_offset = offset;
 
829
 
 
830
        purge_sys->purge_trx_no = min_trx_no;
 
831
 
 
832
        if (rec == &trx_purge_dummy_rec) {
 
833
 
 
834
                purge_sys->purge_undo_no = ut_dulint_zero;
 
835
                purge_sys->page_no = page_no;
 
836
                purge_sys->offset = 0;
 
837
        } else {
 
838
                purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec);
 
839
 
 
840
                purge_sys->page_no = page_get_page_no(page_align(rec));
 
841
                purge_sys->offset = page_offset(rec);
 
842
        }
 
843
 
 
844
        mtr_commit(&mtr);
 
845
}
 
846
 
 
847
/***********************************************************************//**
 
848
Gets the next record to purge and updates the info in the purge system.
 
849
@return copy of an undo log record or pointer to the dummy undo log record */
 
850
static
 
851
trx_undo_rec_t*
 
852
trx_purge_get_next_rec(
 
853
/*===================*/
 
854
        mem_heap_t*     heap)   /*!< in: memory heap where copied */
 
855
{
 
856
        trx_undo_rec_t* rec;
 
857
        trx_undo_rec_t* rec_copy;
 
858
        trx_undo_rec_t* rec2;
 
859
        trx_undo_rec_t* next_rec;
 
860
        page_t*         undo_page;
 
861
        page_t*         page;
 
862
        ulint           offset;
 
863
        ulint           page_no;
 
864
        ulint           space;
 
865
        ulint           zip_size;
 
866
        ulint           type;
 
867
        ulint           cmpl_info;
 
868
        mtr_t           mtr;
 
869
 
 
870
        ut_ad(mutex_own(&(purge_sys->mutex)));
 
871
        ut_ad(purge_sys->next_stored);
 
872
 
 
873
        space = purge_sys->rseg->space;
 
874
        zip_size = purge_sys->rseg->zip_size;
 
875
        page_no = purge_sys->page_no;
 
876
        offset = purge_sys->offset;
 
877
 
 
878
        if (offset == 0) {
 
879
                /* It is the dummy undo log record, which means that there is
 
880
                no need to purge this undo log */
 
881
 
 
882
                trx_purge_rseg_get_next_history_log(purge_sys->rseg);
 
883
 
 
884
                /* Look for the next undo log and record to purge */
 
885
 
 
886
                trx_purge_choose_next_log();
 
887
 
 
888
                return(&trx_purge_dummy_rec);
 
889
        }
 
890
 
 
891
        mtr_start(&mtr);
 
892
 
 
893
        undo_page = trx_undo_page_get_s_latched(space, zip_size,
 
894
                                                page_no, &mtr);
 
895
        rec = undo_page + offset;
 
896
 
 
897
        rec2 = rec;
 
898
 
 
899
        for (;;) {
 
900
                /* Try first to find the next record which requires a purge
 
901
                operation from the same page of the same undo log */
 
902
 
 
903
                next_rec = trx_undo_page_get_next_rec(rec2,
 
904
                                                      purge_sys->hdr_page_no,
 
905
                                                      purge_sys->hdr_offset);
 
906
                if (next_rec == NULL) {
 
907
                        rec2 = trx_undo_get_next_rec(
 
908
                                rec2, purge_sys->hdr_page_no,
 
909
                                purge_sys->hdr_offset, &mtr);
 
910
                        break;
 
911
                }
 
912
 
 
913
                rec2 = next_rec;
 
914
 
 
915
                type = trx_undo_rec_get_type(rec2);
 
916
 
 
917
                if (type == TRX_UNDO_DEL_MARK_REC) {
 
918
 
 
919
                        break;
 
920
                }
 
921
 
 
922
                cmpl_info = trx_undo_rec_get_cmpl_info(rec2);
 
923
 
 
924
                if (trx_undo_rec_get_extern_storage(rec2)) {
 
925
                        break;
 
926
                }
 
927
 
 
928
                if ((type == TRX_UNDO_UPD_EXIST_REC)
 
929
                    && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
 
930
                        break;
 
931
                }
 
932
        }
 
933
 
 
934
        if (rec2 == NULL) {
 
935
                mtr_commit(&mtr);
 
936
 
 
937
                trx_purge_rseg_get_next_history_log(purge_sys->rseg);
 
938
 
 
939
                /* Look for the next undo log and record to purge */
 
940
 
 
941
                trx_purge_choose_next_log();
 
942
 
 
943
                mtr_start(&mtr);
 
944
 
 
945
                undo_page = trx_undo_page_get_s_latched(space, zip_size,
 
946
                                                        page_no, &mtr);
 
947
 
 
948
                rec = undo_page + offset;
 
949
        } else {
 
950
                page = page_align(rec2);
 
951
 
 
952
                purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec2);
 
953
                purge_sys->page_no = page_get_page_no(page);
 
954
                purge_sys->offset = rec2 - page;
 
955
 
 
956
                if (undo_page != page) {
 
957
                        /* We advance to a new page of the undo log: */
 
958
                        purge_sys->n_pages_handled++;
 
959
                }
 
960
        }
 
961
 
 
962
        rec_copy = trx_undo_rec_copy(rec, heap);
 
963
 
 
964
        mtr_commit(&mtr);
 
965
 
 
966
        return(rec_copy);
 
967
}
 
968
 
 
969
/********************************************************************//**
 
970
Fetches the next undo log record from the history list to purge. It must be
 
971
released with the corresponding release function.
 
972
@return copy of an undo log record or pointer to trx_purge_dummy_rec,
 
973
if the whole undo log can skipped in purge; NULL if none left */
 
974
UNIV_INTERN
 
975
trx_undo_rec_t*
 
976
trx_purge_fetch_next_rec(
 
977
/*=====================*/
 
978
        roll_ptr_t*     roll_ptr,/*!< out: roll pointer to undo record */
 
979
        trx_undo_inf_t** cell,  /*!< out: storage cell for the record in the
 
980
                                purge array */
 
981
        mem_heap_t*     heap)   /*!< in: memory heap where copied */
 
982
{
 
983
        trx_undo_rec_t* undo_rec;
 
984
 
 
985
        mutex_enter(&(purge_sys->mutex));
 
986
 
 
987
        if (purge_sys->state == TRX_STOP_PURGE) {
 
988
                trx_purge_truncate_if_arr_empty();
 
989
 
 
990
                mutex_exit(&(purge_sys->mutex));
 
991
 
 
992
                return(NULL);
 
993
        }
 
994
 
 
995
        if (!purge_sys->next_stored) {
 
996
                trx_purge_choose_next_log();
 
997
 
 
998
                if (!purge_sys->next_stored) {
 
999
                        purge_sys->state = TRX_STOP_PURGE;
 
1000
 
 
1001
                        trx_purge_truncate_if_arr_empty();
 
1002
 
 
1003
                        if (srv_print_thread_releases) {
 
1004
                                fprintf(stderr,
 
1005
                                        "Purge: No logs left in the"
 
1006
                                        " history list; pages handled %lu\n",
 
1007
                                        (ulong) purge_sys->n_pages_handled);
 
1008
                        }
 
1009
 
 
1010
                        mutex_exit(&(purge_sys->mutex));
 
1011
 
 
1012
                        return(NULL);
 
1013
                }
 
1014
        }
 
1015
 
 
1016
        if (purge_sys->n_pages_handled >= purge_sys->handle_limit) {
 
1017
 
 
1018
                purge_sys->state = TRX_STOP_PURGE;
 
1019
 
 
1020
                trx_purge_truncate_if_arr_empty();
 
1021
 
 
1022
                mutex_exit(&(purge_sys->mutex));
 
1023
 
 
1024
                return(NULL);
 
1025
        }
 
1026
 
 
1027
        if (ut_dulint_cmp(purge_sys->purge_trx_no,
 
1028
                          purge_sys->view->low_limit_no) >= 0) {
 
1029
                purge_sys->state = TRX_STOP_PURGE;
 
1030
 
 
1031
                trx_purge_truncate_if_arr_empty();
 
1032
 
 
1033
                mutex_exit(&(purge_sys->mutex));
 
1034
 
 
1035
                return(NULL);
 
1036
        }
 
1037
 
 
1038
        /*      fprintf(stderr, "Thread %lu purging trx %lu undo record %lu\n",
 
1039
        os_thread_get_curr_id(),
 
1040
        ut_dulint_get_low(purge_sys->purge_trx_no),
 
1041
        ut_dulint_get_low(purge_sys->purge_undo_no)); */
 
1042
 
 
1043
        *roll_ptr = trx_undo_build_roll_ptr(FALSE, (purge_sys->rseg)->id,
 
1044
                                            purge_sys->page_no,
 
1045
                                            purge_sys->offset);
 
1046
 
 
1047
        *cell = trx_purge_arr_store_info(purge_sys->purge_trx_no,
 
1048
                                         purge_sys->purge_undo_no);
 
1049
 
 
1050
        ut_ad(ut_dulint_cmp(purge_sys->purge_trx_no,
 
1051
                            (purge_sys->view)->low_limit_no) < 0);
 
1052
 
 
1053
        /* The following call will advance the stored values of purge_trx_no
 
1054
        and purge_undo_no, therefore we had to store them first */
 
1055
 
 
1056
        undo_rec = trx_purge_get_next_rec(heap);
 
1057
 
 
1058
        mutex_exit(&(purge_sys->mutex));
 
1059
 
 
1060
        return(undo_rec);
 
1061
}
 
1062
 
 
1063
/*******************************************************************//**
 
1064
Releases a reserved purge undo record. */
 
1065
UNIV_INTERN
 
1066
void
 
1067
trx_purge_rec_release(
 
1068
/*==================*/
 
1069
        trx_undo_inf_t* cell)   /*!< in: storage cell */
 
1070
{
 
1071
        trx_undo_arr_t* arr;
 
1072
 
 
1073
        mutex_enter(&(purge_sys->mutex));
 
1074
 
 
1075
        arr = purge_sys->arr;
 
1076
 
 
1077
        trx_purge_arr_remove_info(cell);
 
1078
 
 
1079
        mutex_exit(&(purge_sys->mutex));
 
1080
}
 
1081
 
 
1082
/*******************************************************************//**
 
1083
This function runs a purge batch.
 
1084
@return number of undo log pages handled in the batch */
 
1085
UNIV_INTERN
 
1086
ulint
 
1087
trx_purge(void)
 
1088
/*===========*/
 
1089
{
 
1090
        que_thr_t*      thr;
 
1091
        /*      que_thr_t*      thr2; */
 
1092
        ulint           old_pages_handled;
 
1093
 
 
1094
        mutex_enter(&(purge_sys->mutex));
 
1095
 
 
1096
        if (purge_sys->trx->n_active_thrs > 0) {
 
1097
 
 
1098
                mutex_exit(&(purge_sys->mutex));
 
1099
 
 
1100
                /* Should not happen */
 
1101
 
 
1102
                ut_error;
 
1103
 
 
1104
                return(0);
 
1105
        }
 
1106
 
 
1107
        rw_lock_x_lock(&(purge_sys->latch));
 
1108
 
 
1109
        mutex_enter(&kernel_mutex);
 
1110
 
 
1111
        /* Close and free the old purge view */
 
1112
 
 
1113
        read_view_close(purge_sys->view);
 
1114
        purge_sys->view = NULL;
 
1115
        mem_heap_empty(purge_sys->heap);
 
1116
 
 
1117
        /* Determine how much data manipulation language (DML) statements
 
1118
        need to be delayed in order to reduce the lagging of the purge
 
1119
        thread. */
 
1120
        srv_dml_needed_delay = 0; /* in microseconds; default: no delay */
 
1121
 
 
1122
        /* If we cannot advance the 'purge view' because of an old
 
1123
        'consistent read view', then the DML statements cannot be delayed.
 
1124
        Also, srv_max_purge_lag <= 0 means 'infinity'. */
 
1125
        if (srv_max_purge_lag > 0
 
1126
            && !UT_LIST_GET_LAST(trx_sys->view_list)) {
 
1127
                float   ratio = (float) trx_sys->rseg_history_len
 
1128
                        / srv_max_purge_lag;
 
1129
                if (ratio > ULINT_MAX / 10000) {
 
1130
                        /* Avoid overflow: maximum delay is 4295 seconds */
 
1131
                        srv_dml_needed_delay = ULINT_MAX;
 
1132
                } else if (ratio > 1) {
 
1133
                        /* If the history list length exceeds the
 
1134
                        innodb_max_purge_lag, the
 
1135
                        data manipulation statements are delayed
 
1136
                        by at least 5000 microseconds. */
 
1137
                        srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
 
1138
                }
 
1139
        }
 
1140
 
 
1141
        purge_sys->view = read_view_oldest_copy_or_open_new(ut_dulint_zero,
 
1142
                                                            purge_sys->heap);
 
1143
        mutex_exit(&kernel_mutex);
 
1144
 
 
1145
        rw_lock_x_unlock(&(purge_sys->latch));
 
1146
 
 
1147
        purge_sys->state = TRX_PURGE_ON;
 
1148
 
 
1149
        /* Handle at most 20 undo log pages in one purge batch */
 
1150
 
 
1151
        purge_sys->handle_limit = purge_sys->n_pages_handled + 20;
 
1152
 
 
1153
        old_pages_handled = purge_sys->n_pages_handled;
 
1154
 
 
1155
        mutex_exit(&(purge_sys->mutex));
 
1156
 
 
1157
        mutex_enter(&kernel_mutex);
 
1158
 
 
1159
        thr = que_fork_start_command(purge_sys->query);
 
1160
 
 
1161
        ut_ad(thr);
 
1162
 
 
1163
        /*      thr2 = que_fork_start_command(purge_sys->query);
 
1164
 
 
1165
        ut_ad(thr2); */
 
1166
 
 
1167
 
 
1168
        mutex_exit(&kernel_mutex);
 
1169
 
 
1170
        /*      srv_que_task_enqueue(thr2); */
 
1171
 
 
1172
        if (srv_print_thread_releases) {
 
1173
 
 
1174
                fputs("Starting purge\n", stderr);
 
1175
        }
 
1176
 
 
1177
        que_run_threads(thr);
 
1178
 
 
1179
        if (srv_print_thread_releases) {
 
1180
 
 
1181
                fprintf(stderr,
 
1182
                        "Purge ends; pages handled %lu\n",
 
1183
                        (ulong) purge_sys->n_pages_handled);
 
1184
        }
 
1185
 
 
1186
        return(purge_sys->n_pages_handled - old_pages_handled);
 
1187
}
 
1188
 
 
1189
/******************************************************************//**
 
1190
Prints information of the purge system to stderr. */
 
1191
UNIV_INTERN
 
1192
void
 
1193
trx_purge_sys_print(void)
 
1194
/*=====================*/
 
1195
{
 
1196
        fprintf(stderr, "InnoDB: Purge system view:\n");
 
1197
        read_view_print(purge_sys->view);
 
1198
 
 
1199
        fprintf(stderr, "InnoDB: Purge trx n:o " TRX_ID_FMT
 
1200
                ", undo n:o " TRX_ID_FMT "\n",
 
1201
                TRX_ID_PREP_PRINTF(purge_sys->purge_trx_no),
 
1202
                TRX_ID_PREP_PRINTF(purge_sys->purge_undo_no));
 
1203
        fprintf(stderr,
 
1204
                "InnoDB: Purge next stored %lu, page_no %lu, offset %lu,\n"
 
1205
                "InnoDB: Purge hdr_page_no %lu, hdr_offset %lu\n",
 
1206
                (ulong) purge_sys->next_stored,
 
1207
                (ulong) purge_sys->page_no,
 
1208
                (ulong) purge_sys->offset,
 
1209
                (ulong) purge_sys->hdr_page_no,
 
1210
                (ulong) purge_sys->hdr_offset);
 
1211
}