1 | /* |
2 | Copyright (c) 2000, 2010, Oracle and/or its affiliates |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | /* Read and write key blocks */ |
18 | |
19 | #include "myisamdef.h" |
20 | |
21 | /* Fetch a key-page in memory */ |
22 | |
23 | uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, |
24 | my_off_t page, int level, |
25 | uchar *buff, int return_buffer) |
26 | { |
27 | uchar *tmp; |
28 | uint page_size; |
29 | DBUG_ENTER("_mi_fetch_keypage" ); |
30 | DBUG_PRINT("enter" ,("page: %ld" , (long) page)); |
31 | |
32 | tmp=(uchar*) key_cache_read(info->s->key_cache, |
33 | info->s->kfile, page, level, (uchar*) buff, |
34 | (uint) keyinfo->block_length, |
35 | (uint) keyinfo->block_length, |
36 | return_buffer); |
37 | if (tmp == info->buff) |
38 | info->buff_used=1; |
39 | else if (!tmp) |
40 | { |
41 | DBUG_PRINT("error" ,("Got errno: %d from key_cache_read" ,my_errno)); |
42 | info->last_keypage=HA_OFFSET_ERROR; |
43 | mi_print_error(info->s, HA_ERR_CRASHED); |
44 | my_errno=HA_ERR_CRASHED; |
45 | DBUG_RETURN(0); |
46 | } |
47 | info->last_keypage=page; |
48 | page_size=mi_getint(tmp); |
49 | if (page_size < 4 || page_size > keyinfo->block_length) |
50 | { |
51 | DBUG_PRINT("error" ,("page %lu had wrong page length: %u" , |
52 | (ulong) page, page_size)); |
53 | DBUG_DUMP("page" , tmp, keyinfo->block_length); |
54 | info->last_keypage = HA_OFFSET_ERROR; |
55 | mi_print_error(info->s, HA_ERR_CRASHED); |
56 | my_errno = HA_ERR_CRASHED; |
57 | tmp = 0; |
58 | } |
59 | DBUG_RETURN(tmp); |
60 | } /* _mi_fetch_keypage */ |
61 | |
62 | |
63 | /* Write a key-page on disk */ |
64 | |
65 | int _mi_write_keypage(register MI_INFO *info, register MI_KEYDEF *keyinfo, |
66 | my_off_t page, int level, uchar *buff) |
67 | { |
68 | reg3 uint length; |
69 | DBUG_ENTER("_mi_write_keypage" ); |
70 | |
71 | #ifndef FAST /* Safety check */ |
72 | if (page < info->s->base.keystart || |
73 | page+keyinfo->block_length > info->state->key_file_length || |
74 | (page & (MI_MIN_KEY_BLOCK_LENGTH-1))) |
75 | { |
76 | DBUG_PRINT("error" ,("Trying to write inside key status region: key_start: %lu length: %lu page: %lu" , |
77 | (long) info->s->base.keystart, |
78 | (long) info->state->key_file_length, |
79 | (long) page)); |
80 | my_errno=EINVAL; |
81 | DBUG_RETURN((-1)); |
82 | } |
83 | DBUG_PRINT("page" ,("write page at: %lu" ,(long) page)); |
84 | DBUG_DUMP("buff" ,(uchar*) buff,mi_getint(buff)); |
85 | #endif |
86 | |
87 | if ((length=keyinfo->block_length) > IO_SIZE*2 && |
88 | info->state->key_file_length != page+length) |
89 | length= ((mi_getint(buff)+IO_SIZE-1) & (uint) ~(IO_SIZE-1)); |
90 | DBUG_RETURN((key_cache_write(info->s->key_cache, |
91 | info->s->kfile, &info->s->dirty_part_map, |
92 | page, level, (uchar*) buff, length, |
93 | (uint) keyinfo->block_length, |
94 | (int) ((info->lock_type != F_UNLCK) || |
95 | info->s->delay_key_write)))); |
96 | } /* mi_write_keypage */ |
97 | |
98 | |
99 | /* Remove page from disk */ |
100 | |
101 | int _mi_dispose(register MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos, |
102 | int level) |
103 | { |
104 | my_off_t old_link; |
105 | uchar buff[8]; |
106 | DBUG_ENTER("_mi_dispose" ); |
107 | DBUG_PRINT("enter" ,("pos: %ld" , (long) pos)); |
108 | |
109 | old_link= info->s->state.key_del[keyinfo->block_size_index]; |
110 | info->s->state.key_del[keyinfo->block_size_index]= pos; |
111 | mi_sizestore(buff,old_link); |
112 | info->s->state.changed|= STATE_NOT_SORTED_PAGES; |
113 | DBUG_RETURN(key_cache_write(info->s->key_cache, |
114 | info->s->kfile, &info->s->dirty_part_map, |
115 | pos , level, buff, |
116 | sizeof(buff), |
117 | (uint) keyinfo->block_length, |
118 | (int) (info->lock_type != F_UNLCK))); |
119 | } /* _mi_dispose */ |
120 | |
121 | |
122 | /* Make new page on disk */ |
123 | |
124 | my_off_t _mi_new(register MI_INFO *info, MI_KEYDEF *keyinfo, int level) |
125 | { |
126 | my_off_t pos; |
127 | uchar buff[8]; |
128 | DBUG_ENTER("_mi_new" ); |
129 | |
130 | if ((pos= info->s->state.key_del[keyinfo->block_size_index]) == |
131 | HA_OFFSET_ERROR) |
132 | { |
133 | if (info->state->key_file_length >= |
134 | info->s->base.max_key_file_length - keyinfo->block_length) |
135 | { |
136 | my_errno=HA_ERR_INDEX_FILE_FULL; |
137 | DBUG_RETURN(HA_OFFSET_ERROR); |
138 | } |
139 | pos=info->state->key_file_length; |
140 | info->state->key_file_length+= keyinfo->block_length; |
141 | } |
142 | else |
143 | { |
144 | if (!key_cache_read(info->s->key_cache, |
145 | info->s->kfile, pos, level, |
146 | buff, |
147 | (uint) sizeof(buff), |
148 | (uint) keyinfo->block_length,0)) |
149 | pos= HA_OFFSET_ERROR; |
150 | else |
151 | info->s->state.key_del[keyinfo->block_size_index]= mi_sizekorr(buff); |
152 | } |
153 | info->s->state.changed|= STATE_NOT_SORTED_PAGES; |
154 | DBUG_PRINT("exit" ,("Pos: %ld" ,(long) pos)); |
155 | DBUG_RETURN(pos); |
156 | } /* _mi_new */ |
157 | |