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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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 
maria_preload(MARIA_HA * info,ulonglong key_map,my_bool ignore_leaves)42 int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves)
43 {
44   ulong block_length= 0;
45   uchar *buff;
46   MARIA_SHARE* share= info->s;
47   uint keynr;
48   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   DBUG_ENTER("maria_preload");
52 
53   if (!share->state.header.keys || !maria_is_any_key_active(key_map) ||
54       (key_file_length == share->base.keystart))
55     DBUG_RETURN(0);
56 
57   block_length= share->pagecache->block_size;
58 
59   if (!(buff= (uchar *) my_malloc(PSI_INSTRUMENT_ME, block_length, MYF(MY_WME))))
60     DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
61 
62   if (flush_pagecache_blocks(share->pagecache, &share->kfile, FLUSH_RELEASE))
63     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          (page_no_max= key_file_length / block_length);
79        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     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       goto err;
90     keynr= _ma_get_keynr(share, buff);
91     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       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       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   my_free(buff);
111   DBUG_RETURN(0);
112 
113 err:
114   my_free(buff);
115   DBUG_RETURN(my_errno= errno);
116 }
117