Skip to content

Commit ef2f3d2

Browse files
committed
MDEV-16168: Performance regression after MDEV-12288
The function row_purge_reset_trx_id() that had been introduced in commit 3c09f14 (MDEV-12288) introduces some extra buffer pool and redo log activity that will cause a significant performance regression under some workloads. This is currently the most significant performance issue, after commit acd071f (MDEV-21923) fixed the InnoDB LSN allocation and MDEV-19749 the MDL bottleneck in 12.1. The purpose of row_purge_reset_trx_id() was to ensure that we can easily identify records for which no history exists. If DB_TRX_ID is 0, we could avoid looking up the transaction to see if the history is accessible or the record is implicitly locked. To avoid trx_sys_t::find() for stale DB_TRX_ID values, we can refer to trx_t::max_inactive_id, which was introduced in commit 4105017 (MDEV-30357). Instead of comparing DB_TRX_ID to 0, we may compare it to this cached value. The cache would be updated by trx_sys_t::find_same_or_older(), which is invoked for some operations on secondary indexes. row_purge_reset_trx_id(): Remove. We will no longer reset the DB_TRX_ID to 0 after an INSERT. We will retain a single undo log for all operations, though. Before MDEV-12288, there had been separate insert_undo and update_undo logs. row_check_index(): No longer warn "InnoDB: Clustered index record with stale history in table". lock_rec_queue_validate(), lock_rec_convert_impl_to_expl(), row_vers_impl_x_locked_low(): Instead of comparing the DB_TRX_ID to 0, compare it to trx_t::max_inactive_id. In dict0load.cc we will not spend any effort to avoid extra trx_sys.find() calls for stale DB_TRX_ID in dictionary tables. This code does not currently use trx_t objects, and therefore we cannot easily access trx_t::max_inactive_id. Loading table definitions into the InnoDB data dictionary cache (dict_sys) should be a very rare operation. Reviewed by: Vladislav Lesin
1 parent a304282 commit ef2f3d2

File tree

10 files changed

+33
-244
lines changed

10 files changed

+33
-244
lines changed

mysql-test/suite/innodb/r/dml_purge.result

Lines changed: 0 additions & 51 deletions
This file was deleted.

mysql-test/suite/innodb/r/table_flags.result

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ SYS_TABLES clustered index root page (8):
1313
N_RECS=8; LEVEL=0; INDEX_ID=0x0000000000000001
1414
header=0x01000003008d (NAME=0x696e66696d756d00)
1515
header=0x0000101500d5 (NAME='SYS_FOREIGN',
16-
DB_TRX_ID=0x000000000000,
17-
DB_ROLL_PTR=0x80000000000000,
16+
DB_TRX_ID=0xXXXXXXXXXXXX,
17+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
1818
ID=0x000000000000000b,
1919
N_COLS=0x00000004,
2020
TYPE=0x00000001,
@@ -23,8 +23,8 @@ header=0x0000101500d5 (NAME='SYS_FOREIGN',
2323
CLUSTER_NAME=NULL(0 bytes),
2424
SPACE=0x00000000)
2525
header=0x000018150122 (NAME='SYS_FOREIGN_COLS',
26-
DB_TRX_ID=0x000000000000,
27-
DB_ROLL_PTR=0x80000000000000,
26+
DB_TRX_ID=0xXXXXXXXXXXXX,
27+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
2828
ID=0x000000000000000c,
2929
N_COLS=0x00000004,
3030
TYPE=0x00000001,
@@ -33,8 +33,8 @@ header=0x000018150122 (NAME='SYS_FOREIGN_COLS',
3333
CLUSTER_NAME=NULL(0 bytes),
3434
SPACE=0x00000000)
3535
header=0x0000201501ae (NAME='SYS_VIRTUAL',
36-
DB_TRX_ID=0x000000000000,
37-
DB_ROLL_PTR=0x80000000000000,
36+
DB_TRX_ID=0xXXXXXXXXXXXX,
37+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
3838
ID=0x000000000000000d,
3939
N_COLS=0x00000003,
4040
TYPE=0x00000001,
@@ -43,8 +43,8 @@ header=0x0000201501ae (NAME='SYS_VIRTUAL',
4343
CLUSTER_NAME=NULL(0 bytes),
4444
SPACE=0x00000000)
4545
header=0x0400301501f2 (NAME='test/tc',
46-
DB_TRX_ID=0x000000000000,
47-
DB_ROLL_PTR=0x80000000000000,
46+
DB_TRX_ID=0xXXXXXXXXXXXX,
47+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
4848
ID=0x000000000000000f,
4949
N_COLS=0x80000001,
5050
TYPE=0x00000001,
@@ -53,8 +53,8 @@ header=0x0400301501f2 (NAME='test/tc',
5353
CLUSTER_NAME=NULL(0 bytes),
5454
SPACE=0x00000002)
5555
header=0x00003815027a (NAME='test/td',
56-
DB_TRX_ID=0x000000000000,
57-
DB_ROLL_PTR=0x80000000000000,
56+
DB_TRX_ID=0xXXXXXXXXXXXX,
57+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
5858
ID=0x0000000000000010,
5959
N_COLS=0x80000001,
6060
TYPE=0x00000021,
@@ -63,8 +63,8 @@ header=0x00003815027a (NAME='test/td',
6363
CLUSTER_NAME=NULL(0 bytes),
6464
SPACE=0x00000003)
6565
header=0x00004815016a (NAME='test/tp',
66-
DB_TRX_ID=0x000000000000,
67-
DB_ROLL_PTR=0x80000000000000,
66+
DB_TRX_ID=0xXXXXXXXXXXXX,
67+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
6868
ID=0x0000000000000012,
6969
N_COLS=0x80000001,
7070
TYPE=0x000009a1,
@@ -73,8 +73,8 @@ header=0x00004815016a (NAME='test/tp',
7373
CLUSTER_NAME=NULL(0 bytes),
7474
SPACE=0x00000005)
7575
header=0x000028150236 (NAME='test/tr',
76-
DB_TRX_ID=0x000000000000,
77-
DB_ROLL_PTR=0x80000000000000,
76+
DB_TRX_ID=0xXXXXXXXXXXXX,
77+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
7878
ID=0x000000000000000e,
7979
N_COLS=0x00000001,
8080
TYPE=0x00000001,
@@ -83,8 +83,8 @@ header=0x000028150236 (NAME='test/tr',
8383
CLUSTER_NAME=NULL(0 bytes),
8484
SPACE=0x00000001)
8585
header=0x000040150074 (NAME='test/tz',
86-
DB_TRX_ID=0x000000000000,
87-
DB_ROLL_PTR=0x80000000000000,
86+
DB_TRX_ID=0xXXXXXXXXXXXX,
87+
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
8888
ID=0x0000000000000011,
8989
N_COLS=0x80000001,
9090
TYPE=0x00000023,
@@ -156,6 +156,7 @@ BEGIN;
156156
INSERT INTO tr VALUES(1);
157157
INSERT INTO tc VALUES(1);
158158
INSERT INTO td VALUES(1);
159+
INSERT INTO tz VALUES(1);
159160
INSERT INTO tp VALUES(1);
160161
ROLLBACK;
161162
SELECT * FROM tr;

mysql-test/suite/innodb/t/dml_purge.test

Lines changed: 0 additions & 83 deletions
This file was deleted.

mysql-test/suite/innodb/t/table_flags.test

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ for (my $offset= 0x65; $offset;
9090
my $end= unpack("C", substr($page, $offset-7-$i, 1));
9191
print ",\n " if $i;
9292
print "$fields[$i]=";
93-
if ($end & 0x80) {
93+
if ($i == 1 || $i == 2) {
94+
print "0x", "XX" x ($end-$start);
95+
} elsif ($end & 0x80) {
9496
print "NULL(", ($end & 0x7f) - $start, " bytes)"
9597
} elsif ($n_fields > 1 && $i == 0) {
9698
$name= substr($page,$offset+$start,$end-$start);
@@ -211,10 +213,7 @@ BEGIN;
211213
INSERT INTO tr VALUES(1);
212214
INSERT INTO tc VALUES(1);
213215
INSERT INTO td VALUES(1);
214-
# We cannot access tz, because due to our fiddling of the NO_ROLLBACK flag,
215-
# it now has a record with DB_TRX_ID=0, which is invalid for
216-
# transactional tables until MDEV-12288 is implemented.
217-
# INSERT INTO tz VALUES(1);
216+
INSERT INTO tz VALUES(1);
218217
INSERT INTO tp VALUES(1);
219218
ROLLBACK;
220219

storage/innobase/include/trx0trx.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,8 @@ struct trx_t : ilist_node<>
638638
{
639639
/** The largest encountered transaction identifier for which no
640640
transaction was observed to be active. This is a cache to speed up
641-
trx_sys_t::find_same_or_older().
641+
trx_sys_t::find_same_or_older() as well as to elide some calls to
642+
trx_sys_t::find().
642643
643644
This will be zero-initialized in Pool::Pool() and not initialized
644645
when a transaction object in the pool is freed and reused. The

storage/innobase/lock/lock0lock.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5409,8 +5409,10 @@ lock_rec_queue_validate(
54095409
? lock_clust_rec_some_has_impl(rec, index, offsets)
54105410
: 0;
54115411

5412-
if (trx_t *impl_trx = impl_trx_id
5413-
? trx_sys.find(current_trx(), impl_trx_id, false)
5412+
trx_t *trx= current_trx();
5413+
5414+
if (trx_t *impl_trx = impl_trx_id > (trx ? trx->max_inactive_id : 0)
5415+
? trx_sys.find(trx, impl_trx_id, false)
54145416
: 0) {
54155417
/* impl_trx could have been committed before we
54165418
acquire its mutex, but not thereafter. */
@@ -5990,7 +5992,7 @@ lock_rec_convert_impl_to_expl(
59905992

59915993
trx_id = lock_clust_rec_some_has_impl(rec, index, offsets);
59925994

5993-
if (trx_id == 0) {
5995+
if (trx_id <= caller_trx->max_inactive_id) {
59945996
return nullptr;
59955997
}
59965998
if (UNIV_UNLIKELY(trx_id == caller_trx->id)) {

storage/innobase/row/row0merge.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,8 +2411,7 @@ row_merge_read_clustered_index(
24112411
} else if (rec_trx_id < trx->id) {
24122412
/* Reset the DB_TRX_ID,DB_ROLL_PTR of old rows
24132413
for which history is not going to be
2414-
available after the rebuild operation.
2415-
This essentially mimics row_purge_reset_trx_id(). */
2414+
available after the rebuild operation. */
24162415
row->fields[new_trx_id_col].data
24172416
= const_cast<byte*>(reset_trx_id);
24182417
row->fields[new_trx_id_col + 1].data

storage/innobase/row/row0purge.cc

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,78 +1080,6 @@ row_purge_del_mark(
10801080
return result;
10811081
}
10821082

1083-
/** Reset DB_TRX_ID, DB_ROLL_PTR of a clustered index record
1084-
whose old history can no longer be observed.
1085-
@param[in,out] node purge node
1086-
@param[in,out] mtr mini-transaction (will be started and committed) */
1087-
static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
1088-
{
1089-
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
1090-
mtr->start();
1091-
1092-
if (row_purge_reposition_pcur(BTR_MODIFY_LEAF, node, mtr)) {
1093-
dict_index_t* index = dict_table_get_first_index(
1094-
node->table);
1095-
ulint trx_id_pos = index->n_uniq ? index->n_uniq : 1;
1096-
rec_t* rec = btr_pcur_get_rec(&node->pcur);
1097-
mem_heap_t* heap = NULL;
1098-
/* Reserve enough offsets for the PRIMARY KEY and 2 columns
1099-
so that we can access DB_TRX_ID, DB_ROLL_PTR. */
1100-
rec_offs offsets_[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS + 3];
1101-
rec_offs_init(offsets_);
1102-
rec_offs* offsets = rec_get_offsets(
1103-
rec, index, offsets_, index->n_core_fields,
1104-
trx_id_pos + 2, &heap);
1105-
ut_ad(heap == NULL);
1106-
1107-
ut_ad(dict_index_get_nth_field(index, trx_id_pos)
1108-
->col->mtype == DATA_SYS);
1109-
ut_ad(dict_index_get_nth_field(index, trx_id_pos)
1110-
->col->prtype == (DATA_TRX_ID | DATA_NOT_NULL));
1111-
ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
1112-
->col->mtype == DATA_SYS);
1113-
ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
1114-
->col->prtype == (DATA_ROLL_PTR | DATA_NOT_NULL));
1115-
1116-
/* Only update the record if DB_ROLL_PTR matches (the
1117-
record has not been modified after this transaction
1118-
became purgeable) */
1119-
if (node->roll_ptr
1120-
== row_get_rec_roll_ptr(rec, index, offsets)) {
1121-
ut_ad(!rec_get_deleted_flag(
1122-
rec, rec_offs_comp(offsets))
1123-
|| rec_is_alter_metadata(rec, *index));
1124-
DBUG_LOG("purge", "reset DB_TRX_ID="
1125-
<< ib::hex(row_get_rec_trx_id(
1126-
rec, index, offsets)));
1127-
1128-
index->set_modified(*mtr);
1129-
buf_block_t* block = btr_pcur_get_block(&node->pcur);
1130-
if (UNIV_LIKELY_NULL(block->page.zip.data)) {
1131-
page_zip_write_trx_id_and_roll_ptr(
1132-
block, rec, offsets, trx_id_pos,
1133-
0, 1ULL << ROLL_PTR_INSERT_FLAG_POS,
1134-
mtr);
1135-
} else {
1136-
ulint len;
1137-
byte* ptr = rec_get_nth_field(
1138-
rec, offsets, trx_id_pos, &len);
1139-
ut_ad(len == DATA_TRX_ID_LEN);
1140-
size_t offs = ptr - block->page.frame;
1141-
mtr->memset(block, offs, DATA_TRX_ID_LEN, 0);
1142-
offs += DATA_TRX_ID_LEN;
1143-
mtr->write<1,mtr_t::MAYBE_NOP>(
1144-
*block, block->page.frame + offs,
1145-
0x80U);
1146-
mtr->memset(block, offs + 1,
1147-
DATA_ROLL_PTR_LEN - 1, 0);
1148-
}
1149-
}
1150-
}
1151-
1152-
mtr->commit();
1153-
}
1154-
11551083
/***********************************************************//**
11561084
Purges an update of an existing record. Also purges an update of a delete
11571085
marked record if that record contained an externally stored field. */
@@ -1281,8 +1209,6 @@ row_purge_upd_exist_or_extern_func(
12811209
mtr.commit();
12821210
}
12831211
}
1284-
1285-
row_purge_reset_trx_id(node, &mtr);
12861212
}
12871213

12881214
#ifdef UNIV_DEBUG
@@ -1578,8 +1504,6 @@ row_purge_record_func(
15781504
/* fall through */
15791505
default:
15801506
if (!updated_extern) {
1581-
mtr_t mtr;
1582-
row_purge_reset_trx_id(node, &mtr);
15831507
break;
15841508
}
15851509
/* fall through */

0 commit comments

Comments
 (0)