Skip to content

Commit aa719b5

Browse files
committed
MDEV-32050: Do not copy undo records in purge
Also, default to innodb_purge_batch_size=1000, replacing the old default value of processing 300 undo log pages in a batch. Axel Schwenke found this value to help reduce purge lag without having a significant impact on workload throughput. In purge, we can simply acquire a shared latch on the undo log page (to avoid a race condition like the one that was fixed in commit b102872) and retain a buffer-fix after releasing the latch. The buffer-fix will prevent the undo log page from being evicted from the buffer pool. Concurrent modification is prevented by design. Only the purge_coordinator_task (or its accomplice purge_truncation_task) may free the undo log pages, after any purge_worker_task have completed execution. Hence, we do not have to worry about any overwriting or reuse of the undo log records. trx_undo_rec_copy(): Remove. The only remaining caller would have been trx_undo_get_undo_rec_low(), which is where the logic was merged. purge_sys_t::m_initialized: Replaces heap. purge_sys_t::pages: A cache of buffer-fixed pages that have been looked up from buf_pool.page_hash. purge_sys_t::get_page(): Return a buffer-fixed undo page, using the pages cache. trx_purge_t::batch_cleanup(): Renamed from clone_end_view(). Clear the pages cache and clone the end_view at the end of a batch. purge_sys_t::n_pages_handled(): Return pages.size(). This determines if innodb_purge_batch_size was exceeded. purge_sys_t::rseg_get_next_history_log(): Replaces trx_purge_rseg_get_next_history_log(). purge_sys_t::choose_next_log(): Replaces trx_purge_choose_next_log() and trx_purge_read_undo_rec(). purge_sys_t::get_next_rec(): Replaces trx_purge_get_next_rec() and trx_undo_get_next_rec(). purge_sys_t::fetch_next_rec(): Replaces trx_purge_fetch_next_rec() and some use of trx_undo_get_first_rec(). trx_purge_attach_undo_recs(): Do not allow purge_sys.n_pages_handled() exceed the innodb_purge_batch_size or ¾ of the buffer pool, whichever is smaller. Reviewed by: Vladislav Lesin Tested by: Matthias Leich and Axel Schwenke
1 parent 8873328 commit aa719b5

File tree

12 files changed

+314
-336
lines changed

12 files changed

+314
-336
lines changed

mysql-test/suite/sys_vars/r/innodb_purge_batch_size_basic.result

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
SET @global_start_value = @@global.innodb_purge_batch_size;
22
SELECT @global_start_value;
33
@global_start_value
4-
300
4+
1000
55
'#--------------------FN_DYNVARS_046_01------------------------#'
66
SET @@global.innodb_purge_batch_size = 1;
77
SET @@global.innodb_purge_batch_size = DEFAULT;
88
SELECT @@global.innodb_purge_batch_size;
99
@@global.innodb_purge_batch_size
10-
300
10+
1000
1111
'#---------------------FN_DYNVARS_046_02-------------------------#'
1212
SET innodb_purge_batch_size = 1;
1313
ERROR HY000: Variable 'innodb_purge_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
1414
SELECT @@innodb_purge_batch_size;
1515
@@innodb_purge_batch_size
16-
300
16+
1000
1717
SELECT local.innodb_purge_batch_size;
1818
ERROR 42S02: Unknown table 'local' in field list
1919
SET global innodb_purge_batch_size = 1;
@@ -112,4 +112,4 @@ SELECT @@global.innodb_purge_batch_size;
112112
SET @@global.innodb_purge_batch_size = @global_start_value;
113113
SELECT @@global.innodb_purge_batch_size;
114114
@@global.innodb_purge_batch_size
115-
300
115+
1000

mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@
307307
NUMERIC_MAX_VALUE 65536
308308
@@ -1345,7 +1345,7 @@
309309
SESSION_VALUE NULL
310-
DEFAULT_VALUE 300
310+
DEFAULT_VALUE 1000
311311
VARIABLE_SCOPE GLOBAL
312312
-VARIABLE_TYPE BIGINT UNSIGNED
313313
+VARIABLE_TYPE INT UNSIGNED

mysql-test/suite/sys_vars/r/sysvars_innodb.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1293,7 +1293,7 @@ READ_ONLY NO
12931293
COMMAND_LINE_ARGUMENT OPTIONAL
12941294
VARIABLE_NAME INNODB_PURGE_BATCH_SIZE
12951295
SESSION_VALUE NULL
1296-
DEFAULT_VALUE 300
1296+
DEFAULT_VALUE 1000
12971297
VARIABLE_SCOPE GLOBAL
12981298
VARIABLE_TYPE BIGINT UNSIGNED
12991299
VARIABLE_COMMENT Number of UNDO log pages to purge in one batch from the history list.

storage/innobase/handler/ha_innodb.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18852,7 +18852,7 @@ static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size,
1885218852
PLUGIN_VAR_OPCMDARG,
1885318853
"Number of UNDO log pages to purge in one batch from the history list.",
1885418854
NULL, NULL,
18855-
300, /* Default setting */
18855+
1000, /* Default setting */
1885618856
1, /* Minimum value */
1885718857
5000, 0); /* Maximum value */
1885818858

storage/innobase/include/row0purge.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,6 @@ row_purge_step(
8080
que_thr_t* thr) /*!< in: query thread */
8181
MY_ATTRIBUTE((nonnull, warn_unused_result));
8282

83-
/** Info required to purge a record */
84-
struct trx_purge_rec_t
85-
{
86-
/** Record to purge */
87-
const trx_undo_rec_t *undo_rec;
88-
/** File pointer to undo record */
89-
roll_ptr_t roll_ptr;
90-
};
91-
9283
/** Purge worker context */
9384
struct purge_node_t
9485
{

storage/innobase/include/trx0purge.h

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Created 3/26/1996 Heikki Tuuri
3131
#include "srw_lock.h"
3232

3333
#include <queue>
34+
#include <unordered_map>
3435

3536
/** Prepend the history list with an undo log.
3637
Remove the undo log segment from the rseg slot if it is too big for reuse.
@@ -127,13 +128,16 @@ struct TrxUndoRsegsIterator {
127128
/** The control structure used in the purge operation */
128129
class purge_sys_t
129130
{
131+
friend TrxUndoRsegsIterator;
130132
public:
131133
/** latch protecting view, m_enabled */
132134
alignas(CPU_LEVEL1_DCACHE_LINESIZE) mutable srw_spin_lock latch;
133135
private:
134136
/** Read view at the start of a purge batch. Any encountered index records
135137
that are older than view will be removed. */
136138
ReadViewBase view;
139+
/** whether the subsystem has been initialized */
140+
bool m_initialized{false};
137141
/** whether purge is enabled; protected by latch and std::atomic */
138142
std::atomic<bool> m_enabled{false};
139143
public:
@@ -152,7 +156,34 @@ class purge_sys_t
152156
/** Read view at the end of a purge batch (copied from view). Any undo pages
153157
containing records older than end_view may be freed. */
154158
ReadViewBase end_view;
159+
160+
struct hasher
161+
{
162+
size_t operator()(const page_id_t &id) const { return size_t(id.raw()); }
163+
};
164+
165+
using unordered_map =
166+
std::unordered_map<const page_id_t, buf_block_t*, hasher,
167+
#if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ >= 8
168+
std::equal_to<page_id_t>
169+
/* GCC 4.8.5 would fail to find a matching allocator */
170+
#else
171+
std::equal_to<page_id_t>,
172+
ut_allocator<std::pair<const page_id_t, buf_block_t*>>
173+
#endif
174+
>;
175+
/** map of buffer-fixed undo log pages processed during a purge batch */
176+
unordered_map pages;
155177
public:
178+
/** @return the number of processed undo pages */
179+
size_t n_pages_handled() const { return pages.size(); }
180+
181+
/** Look up an undo log page.
182+
@param id undo page identifier
183+
@return undo page
184+
@retval nullptr in case the page is corrupted */
185+
buf_block_t *get_page(page_id_t id);
186+
156187
que_t* query; /*!< The query graph which will do the
157188
parallelized purge operation */
158189

@@ -188,6 +219,7 @@ class purge_sys_t
188219
to purge */
189220
trx_rseg_t* rseg; /*!< Rollback segment for the next undo
190221
record to purge */
222+
private:
191223
uint32_t page_no; /*!< Page number for the next undo
192224
record to purge, page number of the
193225
log header, if dummy record */
@@ -202,7 +234,7 @@ class purge_sys_t
202234
TrxUndoRsegsIterator
203235
rseg_iter; /*!< Iterator to get the next rseg
204236
to process */
205-
237+
public:
206238
purge_pq_t purge_queue; /*!< Binary min-heap, ordered on
207239
TrxUndoRsegs::trx_no. It is protected
208240
by the pq_mutex */
@@ -217,17 +249,6 @@ class purge_sys_t
217249
fil_space_t* last;
218250
} truncate;
219251

220-
/** Heap for reading the undo log records */
221-
mem_heap_t* heap;
222-
/**
223-
Constructor.
224-
225-
Some members may require late initialisation, thus we just mark object as
226-
uninitialised. Real initialisation happens in create().
227-
*/
228-
229-
purge_sys_t(): m_enabled(false), heap(nullptr) {}
230-
231252
/** Create the instance */
232253
void create();
233254

@@ -281,6 +302,32 @@ class purge_sys_t
281302
/** @return whether stop_SYS() is in effect */
282303
bool must_wait_FTS() const { return m_FTS_paused; }
283304

305+
private:
306+
/**
307+
Get the next record to purge and update the info in the purge system.
308+
@param roll_ptr undo log pointer to the record
309+
@return buffer-fixed reference to undo log record
310+
@retval {nullptr,1} if the whole undo log can skipped in purge
311+
@retval {nullptr,0} if nothing is left, or on corruption */
312+
inline trx_purge_rec_t get_next_rec(roll_ptr_t roll_ptr);
313+
314+
/** Choose the next undo log to purge.
315+
@return whether anything is to be purged */
316+
bool choose_next_log();
317+
318+
/** Update the last not yet purged history log info in rseg when
319+
we have purged a whole undo log. Advances also purge_trx_no
320+
past the purged log. */
321+
void rseg_get_next_history_log();
322+
323+
public:
324+
/**
325+
Fetch the next undo log record from the history list to purge.
326+
@return buffer-fixed reference to undo log record
327+
@retval {nullptr,1} if the whole undo log can skipped in purge
328+
@retval {nullptr,0} if nothing is left, or on corruption */
329+
inline trx_purge_rec_t fetch_next_rec();
330+
284331
/** Determine if the history of a transaction is purgeable.
285332
@param trx_id transaction identifier
286333
@return whether the history is purgeable */
@@ -327,9 +374,10 @@ class purge_sys_t
327374
/** Wake up the purge threads if there is work to do. */
328375
void wake_if_not_active();
329376

330-
/** Update end_view at the end of a purge batch.
331-
@param head the new head of the purge queue */
332-
inline void clone_end_view(const iterator &head);
377+
/** Release undo pages and update end_view at the end of a purge batch.
378+
@retval false when nothing is to be purged
379+
@retval true when purge_sys.rseg->latch was locked */
380+
inline void batch_cleanup(const iterator &head);
333381

334382
struct view_guard
335383
{

storage/innobase/include/trx0rec.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,9 @@ Created 3/26/1996 Heikki Tuuri
2828

2929
#include "trx0types.h"
3030
#include "row0types.h"
31-
#include "mtr0mtr.h"
32-
#include "rem0types.h"
3331
#include "page0types.h"
34-
#include "row0log.h"
3532
#include "que0types.h"
3633

37-
/***********************************************************************//**
38-
Copies the undo record to the heap.
39-
@param undo_rec record in an undo log page
40-
@param heap memory heap
41-
@return copy of undo_rec
42-
@retval nullptr if the undo log record is corrupted */
43-
inline trx_undo_rec_t* trx_undo_rec_copy(const trx_undo_rec_t *undo_rec,
44-
mem_heap_t *heap)
45-
{
46-
const size_t offset= ut_align_offset(undo_rec, srv_page_size);
47-
const size_t end= mach_read_from_2(undo_rec);
48-
if (end <= offset || end >= srv_page_size - FIL_PAGE_DATA_END)
49-
return nullptr;
50-
const size_t len= end - offset;
51-
trx_undo_rec_t *rec= static_cast<trx_undo_rec_t*>
52-
(mem_heap_dup(heap, undo_rec, len));
53-
mach_write_to_2(rec, len);
54-
return rec;
55-
}
56-
5734
/**********************************************************************//**
5835
Reads the undo log record number.
5936
@return undo no */

storage/innobase/include/trx0types.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ typedef byte trx_undo_rec_t;
107107

108108
/* @} */
109109

110+
/** Info required to purge a record */
111+
struct trx_purge_rec_t
112+
{
113+
/** Undo log record, or nullptr (roll_ptr!=0 if the log can be skipped) */
114+
const trx_undo_rec_t *undo_rec;
115+
/** File pointer to undo_rec */
116+
roll_ptr_t roll_ptr;
117+
};
118+
110119
typedef std::vector<trx_id_t, ut_allocator<trx_id_t> > trx_ids_t;
111120

112121
/** Number of std::unordered_map hash buckets expected to be needed

storage/innobase/include/trx0undo.h

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,31 +116,16 @@ trx_undo_page_get_next_rec(const buf_block_t *undo_page, uint16_t rec,
116116
trx_undo_rec_t*
117117
trx_undo_get_prev_rec(buf_block_t *&block, uint16_t rec, uint32_t page_no,
118118
uint16_t offset, bool shared, mtr_t *mtr);
119-
/** Get the next record in an undo log.
120-
@param[in,out] block undo log page
121-
@param[in] rec undo record offset in the page
122-
@param[in] page_no undo log header page number
123-
@param[in] offset undo log header offset on page
124-
@param[in,out] mtr mini-transaction
125-
@return undo log record, the page latched, NULL if none */
126-
trx_undo_rec_t*
127-
trx_undo_get_next_rec(const buf_block_t *&block, uint16_t rec,
128-
uint32_t page_no, uint16_t offset, mtr_t *mtr);
129119

130-
/** Get the first record in an undo log.
131-
@param[in] space undo log header space
132-
@param[in] page_no undo log header page number
133-
@param[in] offset undo log header offset on page
134-
@param[in] mode latching mode: RW_S_LATCH or RW_X_LATCH
135-
@param[out] block undo log page
136-
@param[in,out] mtr mini-transaction
137-
@param[out] err error code
138-
@return undo log record, the page latched
139-
@retval nullptr if none */
120+
/** Get the first undo log record on a page.
121+
@param[in] block undo log page
122+
@param[in] page_no undo log header page number
123+
@param[in] offset undo log header page offset
124+
@return pointer to first record
125+
@retval nullptr if none exists */
140126
trx_undo_rec_t*
141-
trx_undo_get_first_rec(const fil_space_t &space, uint32_t page_no,
142-
uint16_t offset, ulint mode, const buf_block_t*& block,
143-
mtr_t *mtr, dberr_t *err);
127+
trx_undo_page_get_first_rec(const buf_block_t *block, uint32_t page_no,
128+
uint16_t offset);
144129

145130
/** Initialize an undo log page.
146131
NOTE: This corresponds to a redo log record and must not be changed!

0 commit comments

Comments
 (0)