1 /* Copyright (C) 2018, 2020 MariaDB Corporation 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 Foundation,
14 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16 /* Code for doing backups of Aria tables */
17
18 #include "maria_def.h"
19 #include "ma_blockrec.h" /* PAGE_SUFFIX_SIZE */
20 #include "ma_checkpoint.h"
21 #include <aria_backup.h>
22
23 /**
24 @brief Get capabilities for an Aria table
25
26 @param kfile key file (.MAI)
27 @param cap Capabilities are stored here
28
29 @return 0 ok
30 @return X errno
31 */
32
33 int aria_get_capabilities(File kfile, ARIA_TABLE_CAPABILITIES *cap)__attribute__((visibility("default"))) ;
aria_get_capabilities(File kfile,ARIA_TABLE_CAPABILITIES * cap)34 int aria_get_capabilities(File kfile, ARIA_TABLE_CAPABILITIES *cap)
35 {
36 MARIA_SHARE share;
37 int error= 0;
38 uint head_length= sizeof(share.state.header), base_pos;
39 uint aligned_bit_blocks;
40 size_t info_length;
41 uchar *disc_cache;
42 DBUG_ENTER("aria_get_capabilities");
43
44 bzero(cap, sizeof(*cap));
45 if (my_pread(kfile,share.state.header.file_version, head_length, 0,
46 MYF(MY_NABP)))
47 DBUG_RETURN(HA_ERR_NOT_A_TABLE);
48
49 if (memcmp(share.state.header.file_version, maria_file_magic, 4))
50 DBUG_RETURN(HA_ERR_NOT_A_TABLE);
51
52 share.options= mi_uint2korr(share.state.header.options);
53
54 info_length= mi_uint2korr(share.state.header.header_length);
55 base_pos= mi_uint2korr(share.state.header.base_pos);
56
57 /*
58 Allocate space for header information and for data that is too
59 big to keep on stack
60 */
61 if (!(disc_cache= my_malloc(PSI_NOT_INSTRUMENTED, info_length, MYF(MY_WME))))
62 DBUG_RETURN(ENOMEM);
63
64 if (my_pread(kfile, disc_cache, info_length, 0L, MYF(MY_NABP)))
65 {
66 error= my_errno;
67 goto err;
68 }
69 _ma_base_info_read(disc_cache + base_pos, &share.base);
70 cap->transactional= share.base.born_transactional;
71 cap->checksum= MY_TEST(share.options & HA_OPTION_PAGE_CHECKSUM);
72 cap->online_backup_safe= cap->transactional && cap->checksum;
73 cap->header_size= share.base.keystart;
74 cap->keypage_header= ((share.base.born_transactional ?
75 LSN_STORE_SIZE + TRANSID_SIZE :
76 0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
77 KEYPAGE_USED_SIZE);
78 cap->block_size= share.base.block_size;
79 cap->data_file_type= share.state.header.data_file_type;
80 cap->s3_block_size= share.base.s3_block_size;
81 cap->compression= share.base.compression_algorithm;
82 cap->encrypted= MY_TEST(share.base.extra_options &
83 MA_EXTRA_OPTIONS_ENCRYPTED);
84
85 if (share.state.header.data_file_type == BLOCK_RECORD)
86 {
87 /* Calulate how man pages the row bitmap covers. From _ma_bitmap_init() */
88 aligned_bit_blocks= (cap->block_size - PAGE_SUFFIX_SIZE) / 6;
89 /*
90 In each 6 bytes, we have 6*8/3 = 16 pages covered
91 The +1 is to add the bitmap page, as this doesn't have to be covered
92 */
93 cap->bitmap_pages_covered= aligned_bit_blocks * 16 + 1;
94 }
95
96 /* Do a check that that we got things right */
97 if (share.state.header.data_file_type != BLOCK_RECORD &&
98 cap->online_backup_safe)
99 error= HA_ERR_NOT_A_TABLE;
100
101 err:
102 my_free(disc_cache);
103 DBUG_RETURN(error);
104 } /* aria_get_capabilities */
105
106 /****************************************************************************
107 ** store MARIA_BASE_INFO
108 ****************************************************************************/
109
_ma_base_info_read(uchar * ptr,MARIA_BASE_INFO * base)110 uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base)
111 {
112 bmove(base->uuid, ptr, MY_UUID_SIZE); ptr+= MY_UUID_SIZE;
113 base->keystart= mi_sizekorr(ptr); ptr+= 8;
114 base->max_data_file_length= mi_sizekorr(ptr); ptr+= 8;
115 base->max_key_file_length= mi_sizekorr(ptr); ptr+= 8;
116 base->records= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
117 base->reloc= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
118 base->mean_row_length= mi_uint4korr(ptr); ptr+= 4;
119 base->reclength= mi_uint4korr(ptr); ptr+= 4;
120 base->pack_reclength= mi_uint4korr(ptr); ptr+= 4;
121 base->min_pack_length= mi_uint4korr(ptr); ptr+= 4;
122 base->max_pack_length= mi_uint4korr(ptr); ptr+= 4;
123 base->min_block_length= mi_uint4korr(ptr); ptr+= 4;
124 base->fields= mi_uint2korr(ptr); ptr+= 2;
125 base->fixed_not_null_fields= mi_uint2korr(ptr); ptr+= 2;
126 base->fixed_not_null_fields_length= mi_uint2korr(ptr);ptr+= 2;
127 base->max_field_lengths= mi_uint2korr(ptr); ptr+= 2;
128 base->pack_fields= mi_uint2korr(ptr); ptr+= 2;
129 base->extra_options= mi_uint2korr(ptr); ptr+= 2;
130 base->null_bytes= mi_uint2korr(ptr); ptr+= 2;
131 base->original_null_bytes= mi_uint2korr(ptr); ptr+= 2;
132 base->field_offsets= mi_uint2korr(ptr); ptr+= 2;
133 base->language= mi_uint2korr(ptr); ptr+= 2;
134 base->block_size= mi_uint2korr(ptr); ptr+= 2;
135
136 base->rec_reflength= *ptr++;
137 base->key_reflength= *ptr++;
138 base->keys= *ptr++;
139 base->auto_key= *ptr++;
140 base->born_transactional= *ptr++;
141 base->compression_algorithm= *ptr++;
142 base->pack_bytes= mi_uint2korr(ptr); ptr+= 2;
143 base->blobs= mi_uint2korr(ptr); ptr+= 2;
144 base->max_key_block_length= mi_uint2korr(ptr); ptr+= 2;
145 base->max_key_length= mi_uint2korr(ptr); ptr+= 2;
146 base->extra_alloc_bytes= mi_uint2korr(ptr); ptr+= 2;
147 base->extra_alloc_procent= *ptr++;
148 base->s3_block_size= mi_uint3korr(ptr); ptr+= 3;
149 ptr+= 13;
150 return ptr;
151 }
152
153
154 /**
155 @brief Copy an index block with re-read if checksum doesn't match
156
157 @param dfile data file (.MAD)
158 @param cap aria capabilities from aria_get_capabilities
159 @param block block number to read (0, 1, 2, 3...)
160 @param buffer read data to this buffer
161 @param bytes_read number of bytes actually read (in case of end of file)
162
163 @return 0 ok
164 @return HA_ERR_END_OF_FILE ; End of file
165 @return # error number
166 */
167
168 #define MAX_RETRY 10
169
aria_read_index(File kfile,ARIA_TABLE_CAPABILITIES * cap,ulonglong block,uchar * buffer)170 int aria_read_index(File kfile, ARIA_TABLE_CAPABILITIES *cap, ulonglong block,
171 uchar *buffer)
172 {
173 MARIA_SHARE share;
174 int retry= 0;
175 DBUG_ENTER("aria_read_index");
176
177 share.keypage_header= cap->keypage_header;
178 share.block_size= cap->block_size;
179 do
180 {
181 int error;
182 size_t length;
183 if ((length= my_pread(kfile, buffer, cap->block_size,
184 block * cap->block_size, MYF(0))) != cap->block_size)
185 {
186 if (length == 0)
187 DBUG_RETURN(HA_ERR_END_OF_FILE);
188 if (length == (size_t) -1)
189 DBUG_RETURN(my_errno ? my_errno : -1);
190 /* Assume we got a half read; Do a re-read */
191 }
192 /* If not transactional or key file header, there are no checksums */
193 if (!cap->online_backup_safe ||
194 block < cap->header_size/ cap->block_size)
195 DBUG_RETURN(length == cap->block_size ? 0 : HA_ERR_CRASHED);
196
197 if (length == cap->block_size)
198 {
199 length= _ma_get_page_used(&share, buffer);
200 if (length > cap->block_size - CRC_SIZE)
201 DBUG_RETURN(HA_ERR_CRASHED);
202 error= maria_page_crc_check(buffer, block, &share,
203 MARIA_NO_CRC_NORMAL_PAGE,
204 (int) length);
205 if (error != HA_ERR_WRONG_CRC)
206 DBUG_RETURN(error);
207 }
208 my_sleep(100000); /* Sleep 0.1 seconds */
209 } while (retry < MAX_RETRY);
210 DBUG_RETURN(HA_ERR_WRONG_CRC);
211 }
212
213
214 /**
215 @brief Copy a data block with re-read if checksum doesn't match
216
217 @param dfile data file (.MAD)
218 @param cap aria capabilities from aria_get_capabilities
219 @param block block number to read (0, 1, 2, 3...)
220 @param buffer read data to this buffer
221 @param bytes_read number of bytes actually read (in case of end of file)
222
223 @return 0 ok
224 @return HA_ERR_END_OF_FILE ; End of file
225 @return # error number
226 */
227
aria_read_data(File dfile,ARIA_TABLE_CAPABILITIES * cap,ulonglong block,uchar * buffer,size_t * bytes_read)228 int aria_read_data(File dfile, ARIA_TABLE_CAPABILITIES *cap, ulonglong block,
229 uchar *buffer, size_t *bytes_read)
230 {
231 MARIA_SHARE share;
232 int retry= 0;
233 DBUG_ENTER("aria_read_data");
234
235 share.keypage_header= cap->keypage_header;
236 share.block_size= cap->block_size;
237
238 if (!cap->online_backup_safe)
239 {
240 *bytes_read= my_pread(dfile, buffer, cap->block_size,
241 block * cap->block_size, MY_WME);
242 if (*bytes_read == 0)
243 DBUG_RETURN(HA_ERR_END_OF_FILE);
244 DBUG_RETURN(*bytes_read > 0 ? 0 : (my_errno ? my_errno : -1));
245 }
246
247 *bytes_read= cap->block_size;
248 do
249 {
250 int error;
251 size_t length;
252 if ((length= my_pread(dfile, buffer, cap->block_size,
253 block * cap->block_size, MYF(0))) != cap->block_size)
254 {
255 if (length == 0)
256 DBUG_RETURN(HA_ERR_END_OF_FILE);
257 if (length == (size_t) -1)
258 DBUG_RETURN(my_errno ? my_errno : -1);
259 }
260
261 /* If not transactional or key file header, there are no checksums */
262 if (!cap->online_backup_safe)
263 DBUG_RETURN(length == cap->block_size ? 0 : HA_ERR_CRASHED);
264
265 if (length == cap->block_size)
266 {
267 error= maria_page_crc_check(buffer, block, &share,
268 ((block % cap->bitmap_pages_covered) == 0 ?
269 MARIA_NO_CRC_BITMAP_PAGE :
270 MARIA_NO_CRC_NORMAL_PAGE),
271 share.block_size - CRC_SIZE);
272 if (error != HA_ERR_WRONG_CRC)
273 DBUG_RETURN(error);
274 }
275 my_sleep(100000); /* Sleep 0.1 seconds */
276 } while (retry < MAX_RETRY);
277 DBUG_RETURN(HA_ERR_WRONG_CRC);
278 }
279