~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Vijay Samuel
  • Date: 2010-09-10 21:03:37 UTC
  • mto: (1757.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1758.
  • Revision ID: vijay@vijay-20100910210337-rf7c2ymawtqj6tkv
Merge added utf 8 tamil test case suite and test case for creating a database in tamil.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file trx/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
 
}