1 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 :
3 : This program is free software; you can redistribute it and/or modify
4 : it under the terms of the GNU General Public License as published by
5 : the Free Software Foundation; version 2 of the License.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program; if not, write to the Free Software
14 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
15 :
16 : /*
17 : Preload indexes into key cache
18 : */
19 :
20 : #include "maria_def.h"
21 :
22 :
23 : /*
24 : Preload pages of the index file for a table into the key cache
25 :
26 : SYNOPSIS
27 : maria_preload()
28 : info open table
29 : map map of indexes to preload into key cache
30 : ignore_leaves only non-leaves pages are to be preloaded
31 :
32 : RETURN VALUE
33 : 0 if a success. error code - otherwise.
34 :
35 : NOTES.
36 : At present pages for all indexes are preloaded.
37 : In future only pages for indexes specified in the key_map parameter
38 : of the table will be preloaded.
39 : We don't yet use preload_buff_size (we read page after page).
40 : */
41 :
42 : int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves)
43 0 : {
44 0 : ulong block_length= 0;
45 : uchar *buff;
46 0 : MARIA_SHARE* share= info->s;
47 : uint keynr;
48 0 : my_off_t key_file_length= share->state.state.key_file_length;
49 : pgcache_page_no_t page_no, page_no_max;
50 : PAGECACHE_BLOCK_LINK *page_link;
51 0 : DBUG_ENTER("maria_preload");
52 :
53 0 : if (!share->state.header.keys || !maria_is_any_key_active(key_map) ||
54 : (key_file_length == share->base.keystart))
55 0 : DBUG_RETURN(0);
56 :
57 0 : block_length= share->pagecache->block_size;
58 :
59 0 : if (!(buff= (uchar *) my_malloc(block_length, MYF(MY_WME))))
60 0 : DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
61 :
62 0 : if (flush_pagecache_blocks(share->pagecache, &share->kfile, FLUSH_RELEASE))
63 0 : goto err;
64 :
65 : /*
66 : Currently when we come here all other open instances of the table have
67 : been closed, and we flushed all pages of our own instance, so there
68 : cannot be any page of this table in the cache. Thus my_pread() would be
69 : safe. But in the future, we will allow more concurrency during
70 : preloading, so we use pagecache_read() instead of my_pread() because we
71 : observed that on some Linux, concurrent pread() and pwrite() (which
72 : could be from a page eviction by another thread) to the same page can
73 : make pread() see an half-written page.
74 : In this future, we should find a way to read state.key_file_length
75 : reliably, handle concurrent shrinks (delete_all_rows()) etc.
76 : */
77 : for ((page_no= share->base.keystart / block_length),
78 0 : (page_no_max= key_file_length / block_length);
79 0 : page_no < page_no_max; page_no++)
80 : {
81 : /**
82 : @todo instead of reading pages one by one we could have a call
83 : pagecache_read_several_pages() which does a single my_pread() for many
84 : consecutive pages (like the my_pread() in mi_preload()).
85 : */
86 0 : if (pagecache_read(share->pagecache, &share->kfile, page_no,
87 : DFLT_INIT_HITS, buff, share->page_type,
88 : PAGECACHE_LOCK_WRITE, &page_link) == NULL)
89 0 : goto err;
90 0 : keynr= _ma_get_keynr(share, buff);
91 0 : if (((ignore_leaves && !_ma_test_if_nod(share, buff)) ||
92 : keynr == MARIA_DELETE_KEY_NR ||
93 : !(key_map & ((ulonglong) 1 << keynr))) &&
94 : (pagecache_pagelevel(page_link) == DFLT_INIT_HITS))
95 : {
96 : /*
97 : This page is not interesting, and (last condition above) we are the
98 : ones who put it in the cache, so nobody else is interested in it.
99 : */
100 0 : if (pagecache_delete_by_link(share->pagecache, page_link,
101 : PAGECACHE_LOCK_LEFT_WRITELOCKED, FALSE))
102 : goto err;
103 : }
104 : else /* otherwise it stays in cache: */
105 0 : pagecache_unlock_by_link(share->pagecache, page_link,
106 : PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN,
107 : LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, FALSE, FALSE);
108 : }
109 :
110 0 : my_free(buff, MYF(0));
111 0 : DBUG_RETURN(0);
112 :
113 0 : err:
114 0 : my_free(buff, MYF(MY_ALLOW_ZERO_PTR));
115 0 : DBUG_RETURN(my_errno= errno);
116 : }
|