~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Jay Pipes
  • Date: 2008-09-11 16:03:22 UTC
  • mto: (383.5.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 386.
  • Revision ID: jay@mysql.com-20080911160322-vrl0k1djo6q6ytv1
Removed SQL_MODE variances from comment_table.test and ensured correct error thrown when a comment that is too long was input.  After moving to proto buffer definition for table, the 2048 length will go away.

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