mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
Fix for BUG#34089 "Maria crash on LOAD INDEX after FLUSH TABLES".
storage/maria/ha_maria.cc: enable LOAD INDEX for Maria storage/maria/ma_preload.c: Making index preloading work for Maria. storage/maria/maria_def.h: We don't need this #define anymore, ma_test_recovery.pl uses zerofill to do comparisons of physical files. mysql-test/r/maria-preload.result: result. The values of maria_pagecache_reads look too high, see BUG#35030 "maria_pagecache_read* status variables updated at wrong moment" mysql-test/t/maria-preload.test: Test of index preloading in Maria
This commit is contained in:
parent
b01c9528d1
commit
1bbb098104
5 changed files with 331 additions and 41 deletions
173
mysql-test/r/maria-preload.result
Normal file
173
mysql-test/r/maria-preload.result
Normal file
|
@ -0,0 +1,173 @@
|
|||
drop table if exists t1, t2;
|
||||
create table t1 (
|
||||
a int not null auto_increment,
|
||||
b char(16) not null,
|
||||
primary key (a),
|
||||
key (b)
|
||||
) engine=maria row_format=dynamic;
|
||||
create table t2(
|
||||
a int not null auto_increment,
|
||||
b char(16) not null,
|
||||
primary key (a),
|
||||
key (b)
|
||||
) engine=maria row_format=dynamic;
|
||||
insert into t1(b) values
|
||||
('test0'),
|
||||
('test1'),
|
||||
('test2'),
|
||||
('test3'),
|
||||
('test4'),
|
||||
('test5'),
|
||||
('test6'),
|
||||
('test7');
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
33448
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
20672
|
||||
flush tables;
|
||||
flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211388
|
||||
Maria_pagecache_reads 115
|
||||
select count(*) from t1 where b = 'test1';
|
||||
count(*)
|
||||
4181
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211414
|
||||
Maria_pagecache_reads 122
|
||||
select count(*) from t1 where b = 'test1';
|
||||
count(*)
|
||||
4181
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211440
|
||||
Maria_pagecache_reads 122
|
||||
flush tables;
|
||||
flush status;
|
||||
select @@preload_buffer_size;
|
||||
@@preload_buffer_size
|
||||
32768
|
||||
load index into cache t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 preload_keys status OK
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211511
|
||||
Maria_pagecache_reads 193
|
||||
select count(*) from t1 where b = 'test1';
|
||||
count(*)
|
||||
4181
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211537
|
||||
Maria_pagecache_reads 193
|
||||
flush tables;
|
||||
flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211537
|
||||
Maria_pagecache_reads 193
|
||||
set session preload_buffer_size=256*1024;
|
||||
select @@preload_buffer_size;
|
||||
@@preload_buffer_size
|
||||
262144
|
||||
load index into cache t1 ignore leaves;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 preload_keys status OK
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211608
|
||||
Maria_pagecache_reads 264
|
||||
select count(*) from t1 where b = 'test1';
|
||||
count(*)
|
||||
4181
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211634
|
||||
Maria_pagecache_reads 270
|
||||
flush tables;
|
||||
flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211634
|
||||
Maria_pagecache_reads 270
|
||||
set session preload_buffer_size=1*1024;
|
||||
select @@preload_buffer_size;
|
||||
@@preload_buffer_size
|
||||
1024
|
||||
load index into cache t1, t2 key (primary,b) ignore leaves;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 preload_keys status OK
|
||||
test.t2 preload_keys status OK
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211748
|
||||
Maria_pagecache_reads 384
|
||||
select count(*) from t1 where b = 'test1';
|
||||
count(*)
|
||||
4181
|
||||
select count(*) from t2 where b = 'test1';
|
||||
count(*)
|
||||
2584
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211788
|
||||
Maria_pagecache_reads 387
|
||||
flush tables;
|
||||
flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211788
|
||||
Maria_pagecache_reads 387
|
||||
load index into cache t3, t2 key (primary,b) ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
||||
test.t3 preload_keys error Corrupt
|
||||
test.t2 preload_keys status OK
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211831
|
||||
Maria_pagecache_reads 430
|
||||
flush tables;
|
||||
flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211831
|
||||
Maria_pagecache_reads 430
|
||||
load index into cache t3 key (b), t2 key (c) ;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
||||
test.t3 preload_keys error Corrupt
|
||||
test.t2 preload_keys Error Key 'c' doesn't exist in table 't2'
|
||||
test.t2 preload_keys status Operation failed
|
||||
show status like "maria_pagecache_read%";
|
||||
Variable_name Value
|
||||
Maria_pagecache_read_requests 211831
|
||||
Maria_pagecache_reads 430
|
||||
drop table t1, t2;
|
||||
show status like "key_read%";
|
||||
Variable_name Value
|
||||
Key_read_requests 0
|
||||
Key_reads 0
|
108
mysql-test/t/maria-preload.test
Normal file
108
mysql-test/t/maria-preload.test
Normal file
|
@ -0,0 +1,108 @@
|
|||
#
|
||||
# Testing of PRELOAD
|
||||
#
|
||||
|
||||
-- source include/have_maria.inc
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
|
||||
|
||||
# we don't use block-format because we want page cache stats
|
||||
# about indices and not data pages.
|
||||
|
||||
create table t1 (
|
||||
a int not null auto_increment,
|
||||
b char(16) not null,
|
||||
primary key (a),
|
||||
key (b)
|
||||
) engine=maria row_format=dynamic;
|
||||
|
||||
create table t2(
|
||||
a int not null auto_increment,
|
||||
b char(16) not null,
|
||||
primary key (a),
|
||||
key (b)
|
||||
) engine=maria row_format=dynamic;
|
||||
|
||||
insert into t1(b) values
|
||||
('test0'),
|
||||
('test1'),
|
||||
('test2'),
|
||||
('test3'),
|
||||
('test4'),
|
||||
('test5'),
|
||||
('test6'),
|
||||
('test7');
|
||||
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
insert into t2(b) select b from t1;
|
||||
insert into t1(b) select b from t2;
|
||||
|
||||
select count(*) from t1;
|
||||
select count(*) from t2;
|
||||
|
||||
flush tables; flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
select count(*) from t1 where b = 'test1';
|
||||
show status like "maria_pagecache_read%";
|
||||
select count(*) from t1 where b = 'test1';
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
flush tables; flush status;
|
||||
select @@preload_buffer_size;
|
||||
load index into cache t1;
|
||||
show status like "maria_pagecache_read%";
|
||||
select count(*) from t1 where b = 'test1';
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
flush tables; flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
set session preload_buffer_size=256*1024;
|
||||
select @@preload_buffer_size;
|
||||
load index into cache t1 ignore leaves;
|
||||
show status like "maria_pagecache_read%";
|
||||
select count(*) from t1 where b = 'test1';
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
flush tables; flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
set session preload_buffer_size=1*1024;
|
||||
select @@preload_buffer_size;
|
||||
load index into cache t1, t2 key (primary,b) ignore leaves;
|
||||
show status like "maria_pagecache_read%";
|
||||
select count(*) from t1 where b = 'test1';
|
||||
select count(*) from t2 where b = 'test1';
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
flush tables; flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
load index into cache t3, t2 key (primary,b) ;
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
flush tables; flush status;
|
||||
show status like "maria_pagecache_read%";
|
||||
load index into cache t3 key (b), t2 key (c) ;
|
||||
show status like "maria_pagecache_read%";
|
||||
|
||||
drop table t1, t2;
|
||||
|
||||
# check that Maria didn't use key cache
|
||||
show status like "key_read%";
|
|
@ -1494,7 +1494,6 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
|
|||
maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
|
||||
(void*) &thd->variables.preload_buff_size);
|
||||
|
||||
#ifdef NOT_YET
|
||||
int error;
|
||||
|
||||
if ((error= maria_preload(file, map, table_list->ignore_leaves)))
|
||||
|
@ -1525,7 +1524,6 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
|
|||
_ma_check_print_error(¶m, errmsg);
|
||||
DBUG_RETURN(HA_ADMIN_FAILED);
|
||||
}
|
||||
#endif
|
||||
DBUG_RETURN(HA_ADMIN_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,70 +36,81 @@
|
|||
At present pages for all indexes are preloaded.
|
||||
In future only pages for indexes specified in the key_map parameter
|
||||
of the table will be preloaded.
|
||||
We don't yet use preload_buff_size (we read page after page).
|
||||
*/
|
||||
|
||||
int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves)
|
||||
{
|
||||
ulong length, block_length= 0;
|
||||
ulong block_length= 0;
|
||||
uchar *buff= NULL;
|
||||
MARIA_SHARE* share= info->s;
|
||||
uint keys= share->state.header.keys;
|
||||
uint keynr;
|
||||
my_off_t key_file_length= share->state.state.key_file_length;
|
||||
my_off_t pos= share->base.keystart;
|
||||
pgcache_page_no_t page_no, page_no_max;
|
||||
PAGECACHE_BLOCK_LINK *page_link;
|
||||
DBUG_ENTER("maria_preload");
|
||||
|
||||
if (!keys || !maria_is_any_key_active(key_map) || key_file_length == pos)
|
||||
if (!share->state.header.keys || !maria_is_any_key_active(key_map) ||
|
||||
(key_file_length == share->base.keystart))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
block_length= share->pagecache->block_size;
|
||||
length= info->preload_buff_size/block_length * block_length;
|
||||
set_if_bigger(length, block_length);
|
||||
|
||||
if (!(buff= (uchar *) my_malloc(length, MYF(MY_WME))))
|
||||
if (!(buff= (uchar *) my_malloc(block_length, MYF(MY_WME))))
|
||||
DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
|
||||
|
||||
if (flush_pagecache_blocks(share->pagecache, &share->kfile, FLUSH_RELEASE))
|
||||
goto err;
|
||||
|
||||
do
|
||||
/*
|
||||
Currently when we come here all other open instances of the table have
|
||||
been closed, and we flushed all pages of our own instance, so there
|
||||
cannot be any page of this table in the cache. Thus my_pread() would be
|
||||
safe. But in the future, we will allow more concurrency during
|
||||
preloading, so we use pagecache_read() instead of my_pread() because we
|
||||
observed that on some Linux, concurrent pread() and pwrite() (which
|
||||
could be from a page eviction by another thread) to the same page can
|
||||
make pread() see an half-written page.
|
||||
In this future, we should find a way to read state.key_file_length
|
||||
reliably, handle concurrent shrinks (delete_all_rows()) etc.
|
||||
*/
|
||||
for ((page_no= share->base.keystart / block_length),
|
||||
(page_no_max= key_file_length / block_length);
|
||||
page_no < page_no_max; page_no++)
|
||||
{
|
||||
uchar *end;
|
||||
/* Read the next block of index file into the preload buffer */
|
||||
if ((my_off_t) length > (key_file_length-pos))
|
||||
length= (ulong) (key_file_length-pos);
|
||||
if (my_pread(share->kfile.file, (uchar*) buff, length, pos,
|
||||
MYF(MY_FAE|MY_FNABP)))
|
||||
/**
|
||||
@todo instead of reading pages one by one we could have a call
|
||||
pagecache_read_several_pages() which does a single my_pread() for many
|
||||
consecutive pages (like the my_pread() in mi_preload()).
|
||||
*/
|
||||
if (pagecache_read(share->pagecache, &share->kfile, page_no,
|
||||
DFLT_INIT_HITS, (uchar*) buff, share->page_type,
|
||||
PAGECACHE_LOCK_WRITE, &page_link) == NULL)
|
||||
goto err;
|
||||
|
||||
for (end= buff + length ; buff < end ; buff+= block_length)
|
||||
keynr= _ma_get_keynr(share, buff);
|
||||
if (((ignore_leaves && !_ma_test_if_nod(share, buff)) ||
|
||||
keynr == MARIA_DELETE_KEY_NR ||
|
||||
!(key_map & ((ulonglong) 1 << keynr))) &&
|
||||
(pagecache_pagelevel(page_link) == DFLT_INIT_HITS))
|
||||
{
|
||||
uint keynr= _ma_get_keynr(share, buff);
|
||||
if ((ignore_leaves && !_ma_test_if_nod(share, buff)) ||
|
||||
keynr == MARIA_DELETE_KEY_NR ||
|
||||
!(key_map & ((ulonglong) 1 << keynr)))
|
||||
{
|
||||
DBUG_ASSERT(share->pagecache->block_size == block_length);
|
||||
if (pagecache_write(share->pagecache,
|
||||
&share->kfile,
|
||||
(pgcache_page_no_t) (pos / block_length),
|
||||
DFLT_INIT_HITS,
|
||||
(uchar*) buff,
|
||||
PAGECACHE_PLAIN_PAGE,
|
||||
PAGECACHE_LOCK_LEFT_UNLOCKED,
|
||||
PAGECACHE_PIN_LEFT_UNPINNED,
|
||||
PAGECACHE_WRITE_DONE, 0,
|
||||
LSN_IMPOSSIBLE))
|
||||
goto err;
|
||||
}
|
||||
pos+= block_length;
|
||||
/*
|
||||
This page is not interesting, and (last condition above) we are the
|
||||
ones who put it in the cache, so nobody else is interested in it.
|
||||
*/
|
||||
if (pagecache_delete_by_link(share->pagecache, page_link,
|
||||
PAGECACHE_LOCK_LEFT_WRITELOCKED, FALSE))
|
||||
goto err;
|
||||
}
|
||||
else /* otherwise it stays in cache: */
|
||||
pagecache_unlock_by_link(share->pagecache, page_link,
|
||||
PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN,
|
||||
LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, FALSE);
|
||||
}
|
||||
while (pos != key_file_length);
|
||||
|
||||
my_free((char*) buff, MYF(0));
|
||||
my_free(buff, MYF(0));
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
my_free((char*) buff, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(buff, MYF(MY_ALLOW_ZERO_PTR));
|
||||
DBUG_RETURN(my_errno= errno);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "ma_control_file.h"
|
||||
|
||||
/* For testing recovery */
|
||||
#ifndef DBUG_OFF
|
||||
#ifdef TO_BE_REMOVED
|
||||
#define IDENTICAL_PAGES_AFTER_RECOVERY 1
|
||||
#endif
|
||||
/* Do extra sanity checking */
|
||||
|
|
Loading…
Add table
Reference in a new issue