1/* Copyright (C) 2007-2008 MySQL 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 02111-1301 USA */
15
16#include "maria_def.h"
17
18
19/**
20 @brief calculate crc of the page avoiding special values
21
22 @param start The value to start CRC (we use page number here)
23 @param data data pointer
24 @param length length of the data
25
26 @return crc of the page without special values
27*/
28
29static uint32 maria_page_crc(uint32 start, uchar *data, uint length)
30{
31 uint32 crc= crc32(start, data, length);
32
33 /* we need this assert to get following comparison working */
34 compile_time_assert(MARIA_NO_CRC_BITMAP_PAGE ==
35 MARIA_NO_CRC_NORMAL_PAGE - 1 &&
36 MARIA_NO_CRC_NORMAL_PAGE == 0xffffffff);
37 if (crc >= MARIA_NO_CRC_BITMAP_PAGE)
38 crc= MARIA_NO_CRC_BITMAP_PAGE - 1;
39
40 return(crc);
41}
42
43/**
44 @brief Maria pages read callback (checks the page CRC)
45
46 @param page The page data to check
47 @param page_no The page number (<offset>/<page length>)
48 @param data_ptr pointer to MARIA_SHARE
49 @param no_crc_val Value which means CRC absence
50 (MARIA_NO_CRC_NORMAL_PAGE or MARIA_NO_CRC_BITMAP_PAGE)
51 @param data_length length of data to calculate CRC
52
53 @retval 0 OK
54 @retval 1 Error
55*/
56
57static my_bool maria_page_crc_check(uchar *page,
58 pgcache_page_no_t page_no,
59 MARIA_SHARE *share,
60 uint32 no_crc_val,
61 int data_length)
62{
63 uint32 crc= uint4korr(page + share->block_size - CRC_SIZE), new_crc;
64 my_bool res;
65 DBUG_ENTER("maria_page_crc_check");
66
67 DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE);
68
69 /* we need this assert to get following comparison working */
70 compile_time_assert(MARIA_NO_CRC_BITMAP_PAGE ==
71 MARIA_NO_CRC_NORMAL_PAGE - 1 &&
72 MARIA_NO_CRC_NORMAL_PAGE == 0xffffffff);
73 /*
74 If crc is no_crc_val then
75 the page has no crc, so there is nothing to check.
76 */
77 if (crc >= MARIA_NO_CRC_BITMAP_PAGE)
78 {
79 DBUG_PRINT("info", ("No crc: %lu crc: %lu page: %lu ",
80 (ulong) no_crc_val, (ulong) crc, (ulong) page_no));
81 if (crc != no_crc_val)
82 {
83 my_errno= HA_ERR_WRONG_CRC;
84 DBUG_PRINT("error", ("Wrong no CRC value"));
85 DBUG_RETURN(1);
86 }
87 DBUG_RETURN(0);
88 }
89 new_crc= maria_page_crc((uint32) page_no, page, data_length);
90 DBUG_ASSERT(new_crc != no_crc_val);
91 res= MY_TEST(new_crc != crc);
92 if (res)
93 {
94 /*
95 Bitmap pages may be totally zero filled in some cases.
96 This happens when we get a crash after the pagecache has written
97 out a page that is on a newly created bitmap page and we get
98 a crash before the bitmap page is written out.
99
100 We handle this case with the following logic:
101 When reading, approve of bitmap pages where all bytes are zero
102 (This is after all a bitmap pages where no data is reserved and
103 the CRC will be corrected at next write)
104 */
105 if (no_crc_val == MARIA_NO_CRC_BITMAP_PAGE &&
106 crc == 0 && _ma_check_if_zero(page, data_length))
107 {
108 DBUG_PRINT("warning", ("Found bitmap page that was not initialized"));
109 DBUG_RETURN(0);
110 }
111
112 DBUG_PRINT("error", ("Page: %lu crc: %lu calculated crc: %lu",
113 (ulong) page_no, (ulong) crc, (ulong) new_crc));
114 my_errno= HA_ERR_WRONG_CRC;
115 }
116 DBUG_RETURN(res);
117}
118
119
120/**
121 @brief Maria pages write callback (sets the page CRC for data and index
122 files)
123
124 @param page The page data to set
125 @param page_no The page number (<offset>/<page length>)
126 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
127
128 @retval 0 OK
129*/
130
131my_bool maria_page_crc_set_normal(PAGECACHE_IO_HOOK_ARGS *args)
132{
133 uchar *page= args->page;
134 pgcache_page_no_t page_no= args->pageno;
135 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
136 int data_length= share->block_size - CRC_SIZE;
137 uint32 crc= maria_page_crc((uint32) page_no, page, data_length);
138 DBUG_ENTER("maria_page_crc_set_normal");
139 DBUG_PRINT("info", ("Page %lu crc: %lu", (ulong) page_no, (ulong)crc));
140
141 /* crc is on the stack so it is aligned, pagecache buffer is aligned, too */
142 int4store_aligned(page + data_length, crc);
143 DBUG_RETURN(0);
144}
145
146
147/**
148 @brief Maria pages write callback (sets the page CRC for keys)
149
150 @param page The page data to set
151 @param page_no The page number (<offset>/<page length>)
152 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
153
154 @retval 0 OK
155*/
156
157my_bool maria_page_crc_set_index(PAGECACHE_IO_HOOK_ARGS *args)
158{
159 uchar *page= args->page;
160 pgcache_page_no_t page_no= args->pageno;
161 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
162 int data_length= _ma_get_page_used(share, page);
163 uint32 crc= maria_page_crc((uint32) page_no, page, data_length);
164 DBUG_ENTER("maria_page_crc_set_index");
165 DBUG_PRINT("info", ("Page %lu crc: %lu",
166 (ulong) page_no, (ulong) crc));
167 DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE);
168 /* crc is on the stack so it is aligned, pagecache buffer is aligned, too */
169 int4store_aligned(page + share->block_size - CRC_SIZE, crc);
170 DBUG_RETURN(0);
171}
172
173
174/* interface functions */
175
176
177/**
178 @brief Maria pages read callback (checks the page CRC) for index/data pages
179
180 @param page The page data to check
181 @param page_no The page number (<offset>/<page length>)
182 @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
183
184 @retval 0 OK
185 @retval 1 Error
186*/
187
188my_bool maria_page_crc_check_data(int res, PAGECACHE_IO_HOOK_ARGS *args)
189{
190 uchar *page= args->page;
191 pgcache_page_no_t page_no= args->pageno;
192 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
193 if (res)
194 {
195 return 1;
196 }
197
198 return (maria_page_crc_check(page, (uint32) page_no, share,
199 MARIA_NO_CRC_NORMAL_PAGE,
200 share->block_size - CRC_SIZE));
201}
202
203
204/**
205 @brief Maria pages read callback (checks the page CRC) for bitmap pages
206
207 @param page The page data to check
208 @param page_no The page number (<offset>/<page length>)
209 @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
210
211 @retval 0 OK
212 @retval 1 Error
213*/
214
215my_bool maria_page_crc_check_bitmap(int res, PAGECACHE_IO_HOOK_ARGS *args)
216{
217 uchar *page= args->page;
218 pgcache_page_no_t page_no= args->pageno;
219 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
220 if (res)
221 {
222 return 1;
223 }
224 return (maria_page_crc_check(page, (uint32) page_no, share,
225 MARIA_NO_CRC_BITMAP_PAGE,
226 share->block_size - CRC_SIZE));
227}
228
229
230/**
231 @brief Maria pages read callback (checks the page CRC) for index pages
232
233 @param page The page data to check
234 @param page_no The page number (<offset>/<page length>)
235 @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
236
237 @retval 0 OK
238 @retval 1 Error
239*/
240
241my_bool maria_page_crc_check_index(int res, PAGECACHE_IO_HOOK_ARGS *args)
242{
243 uchar *page= args->page;
244 pgcache_page_no_t page_no= args->pageno;
245 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
246 uint length= _ma_get_page_used(share, page);
247 if (res)
248 {
249 return 1;
250 }
251 if (length > share->block_size - CRC_SIZE)
252 {
253 DBUG_PRINT("error", ("Wrong page length: %u", length));
254 return (my_errno= HA_ERR_WRONG_CRC);
255 }
256 return maria_page_crc_check(page, (uint32) page_no, share,
257 MARIA_NO_CRC_NORMAL_PAGE,
258 length);
259}
260
261
262/**
263 @brief Maria pages dumme read callback for temporary tables
264
265 @retval 0 OK
266 @retval 1 Error
267*/
268
269my_bool maria_page_crc_check_none(int res,
270 PAGECACHE_IO_HOOK_ARGS *args
271 __attribute__((unused)))
272{
273 return res != 0;
274}
275
276
277/**
278 @brief Maria pages write callback (sets the page filler for index/data)
279
280 @param page The page data to set
281 @param page_no The page number (<offset>/<page length>)
282 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
283
284 @retval 0 OK
285*/
286
287my_bool maria_page_filler_set_normal(PAGECACHE_IO_HOOK_ARGS *args)
288{
289 uchar *page= args->page;
290#ifdef DBUG_ASSERT_EXISTS
291 pgcache_page_no_t page_no= args->pageno;
292#endif
293 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
294 DBUG_ENTER("maria_page_filler_set_normal");
295 DBUG_ASSERT(page_no != 0); /* Catches some simple bugs */
296 int4store_aligned(page + share->block_size - CRC_SIZE,
297 MARIA_NO_CRC_NORMAL_PAGE);
298 DBUG_RETURN(0);
299}
300
301
302/**
303 @brief Maria pages write callback (sets the page filler for bitmap)
304
305 @param page The page data to set
306 @param page_no The page number (<offset>/<page length>)
307 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
308
309 @retval 0 OK
310*/
311
312my_bool maria_page_filler_set_bitmap(PAGECACHE_IO_HOOK_ARGS *args)
313{
314 uchar *page= args->page;
315 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
316 DBUG_ENTER("maria_page_filler_set_bitmap");
317 int4store_aligned(page + share->block_size - CRC_SIZE,
318 MARIA_NO_CRC_BITMAP_PAGE);
319 DBUG_RETURN(0);
320}
321
322
323/**
324 @brief Maria pages dummy write callback for temporary tables
325
326 @retval 0 OK
327*/
328
329my_bool maria_page_filler_set_none(PAGECACHE_IO_HOOK_ARGS *args
330 __attribute__((unused)))
331{
332#ifdef HAVE_valgrind
333 uchar *page= args->page;
334 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
335 int4store_aligned(page + share->block_size - CRC_SIZE,
336 0);
337#endif
338 return 0;
339}
340
341
342/**
343 @brief Write failure callback (mark table as corrupted)
344
345 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
346*/
347
348void maria_page_write_failure(int error, PAGECACHE_IO_HOOK_ARGS *args)
349{
350 if (error)
351 maria_mark_crashed_share((MARIA_SHARE *)args->data);
352}
353
354
355/**
356 @brief Maria flush log log if needed
357
358 @param page The page data to set
359 @param page_no The page number (<offset>/<page length>)
360 @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
361
362 @retval 0 OK
363 @retval 1 error
364*/
365
366my_bool maria_flush_log_for_page(PAGECACHE_IO_HOOK_ARGS *args)
367{
368 LSN lsn;
369 uchar *page= args->page;
370 MARIA_SHARE *share= (MARIA_SHARE *)args->data;
371 DBUG_ENTER("maria_flush_log_for_page");
372 /* share is 0 here only in unittest */
373 DBUG_ASSERT(!share || share->page_type == PAGECACHE_LSN_PAGE);
374 lsn= lsn_korr(page);
375 if (translog_flush(lsn))
376 DBUG_RETURN(1);
377 /*
378 Now when log is written, it's safe to incremented 'open' counter for
379 the table so that we know it was not closed properly.
380 */
381 if (share && !share->global_changed)
382 _ma_mark_file_changed_now(share);
383 DBUG_RETURN(0);
384}
385
386
387my_bool maria_flush_log_for_page_none(PAGECACHE_IO_HOOK_ARGS *args
388 __attribute__((unused)))
389{
390 return 0;
391}
392
393my_bool maria_page_null_pre_read_hook(PAGECACHE_IO_HOOK_ARGS *args
394 __attribute__((unused)))
395{
396 return 0;
397}
398