1 /* Copyright (C) 2018, 2021, MariaDB corporation.
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 /******************************************************************************
19 Testing ma_backup interface
20 Table creation code is taken from ma_test1
21 ******************************************************************************/
22
23 #define ROWS_IN_TEST 100000
24
25 #include "maria_def.h"
26 #include "ma_blockrec.h" /* PAGE_SUFFIX_SIZE */
27 #include "ma_checkpoint.h"
28 #include <aria_backup.h>
29
30 static int silent;
31 static int create_test_table(const char *table_name, int stage);
32 static int copy_table(const char *table_name, int stage);
33 static void create_record(uchar *record,uint rownr);
34
main(int argc,char * argv[])35 int main(int argc __attribute__((unused)), char *argv[])
36 {
37 int error= 1;
38 int i;
39 char buff[FN_REFLEN];
40 #ifdef SAFE_MUTEX
41 safe_mutex_deadlock_detector= 1;
42 #endif
43 MY_INIT(argv[0]);
44 maria_data_root= ".";
45
46 /* Maria requires that we always have a page cache */
47 if (maria_init() ||
48 (init_pagecache(maria_pagecache, maria_block_size * 2000, 0, 0,
49 maria_block_size, 0, MY_WME) == 0) ||
50 ma_control_file_open(TRUE, TRUE, TRUE) ||
51 (init_pagecache(maria_log_pagecache,
52 TRANSLOG_PAGECACHE_SIZE, 0, 0,
53 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0) ||
54 translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
55 0, 0, maria_log_pagecache,
56 TRANSLOG_DEFAULT_FLAGS, 0) ||
57 (trnman_init(0) || ma_checkpoint_init(0)))
58 {
59 fprintf(stderr, "Error in initialization\n");
60 exit(1);
61 }
62 init_thr_lock();
63
64 fn_format(buff, "test_copy", maria_data_root, "", MYF(0));
65
66 for (i= 0; i < 5 ; i++)
67 {
68 printf("Stage: %d\n", i);
69 fflush(stdout);
70 if (create_test_table(buff, i))
71 goto err;
72 if (copy_table(buff, i))
73 goto err;
74 }
75 error= 0;
76 printf("test ok\n");
77 err:
78 if (error)
79 fprintf(stderr, "Test %i failed\n", i);
80 maria_end();
81 my_uuid_end();
82 my_end(MY_CHECK_ERROR);
83 exit(error);
84 }
85
86
87 /**
88 Example of how to read an Aria table
89 */
90
copy_table(const char * table_name,int stage)91 static int copy_table(const char *table_name, int stage)
92 {
93 char old_name[FN_REFLEN];
94 uchar *copy_buffer= 0;
95 ARIA_TABLE_CAPABILITIES cap;
96 ulonglong block;
97 File org_file= -1;
98 int error= 1;
99
100 strxmov(old_name, table_name, ".MAI", NullS);
101
102 if ((org_file= my_open(old_name,
103 O_RDONLY | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
104 MYF(MY_WME))) < 0)
105 goto err;
106 if ((error= aria_get_capabilities(org_file, &cap)))
107 {
108 fprintf(stderr, "aria_get_capabilities failed: %d\n", error);
109 goto err;
110 }
111
112 printf("- Capabilities read. oneline_backup_safe: %d\n",
113 cap.online_backup_safe);
114 printf("- Copying index file\n");
115
116 copy_buffer= my_malloc(PSI_NOT_INSTRUMENTED, cap.block_size, MYF(0));
117 for (block= 0 ; ; block++)
118 {
119 if ((error= aria_read_index(org_file, &cap, block, copy_buffer) ==
120 HA_ERR_END_OF_FILE))
121 break;
122 if (error)
123 {
124 fprintf(stderr, "aria_read_index failed: %d\n", error);
125 goto err;
126 }
127 }
128 my_close(org_file, MYF(MY_WME));
129
130
131 printf("- Copying data file\n");
132 strxmov(old_name, table_name, ".MAD", NullS);
133 if ((org_file= my_open(old_name, O_RDONLY | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
134 MYF(MY_WME))) < 0)
135 goto err;
136
137 for (block= 0 ; ; block++)
138 {
139 size_t length;
140 if ((error= aria_read_data(org_file, &cap, block, copy_buffer,
141 &length) == HA_ERR_END_OF_FILE))
142 break;
143 if (error)
144 {
145 fprintf(stderr, "aria_read_index failed: %d\n", error);
146 goto err;
147 }
148 }
149 error= 0;
150
151 err:
152 my_free(copy_buffer);
153 if (org_file >= 0)
154 my_close(org_file, MYF(MY_WME));
155 if (error)
156 fprintf(stderr, "Failed in copy_table stage: %d\n", stage);
157 return error;
158 }
159
160
161 /* Code extracted from ma_test1.c */
162 #define MAX_REC_LENGTH 1024
163
164 static MARIA_COLUMNDEF recinfo[4];
165 static MARIA_KEYDEF keyinfo[10];
166 static HA_KEYSEG keyseg[10];
167 static HA_KEYSEG uniqueseg[10];
168
169
170 /**
171 Create a test table and fill it with some data
172 */
173
create_test_table(const char * table_name,int type_of_table)174 static int create_test_table(const char *table_name, int type_of_table)
175 {
176 MARIA_HA *file;
177 int i,error,uniques=0;
178 int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE;
179 int key_type=HA_KEYTYPE_NUM;
180 int create_flag=0;
181 uint pack_seg=0, pack_keys= 0;
182 uint key_length;
183 uchar record[MAX_REC_LENGTH];
184 MARIA_UNIQUEDEF uniquedef;
185 MARIA_CREATE_INFO create_info;
186 enum data_file_type record_type= DYNAMIC_RECORD;
187 my_bool null_fields= 0, unique_key= 0;
188 my_bool opt_unique= 0;
189 my_bool transactional= 0;
190
191 key_length= 12;
192 switch (type_of_table) {
193 case 0:
194 break;
195 case 1:
196 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
197 break;
198 case 2: /* transactional */
199 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
200 record_type= BLOCK_RECORD;
201 transactional= 1;
202 break;
203 case 3: /* transactional */
204 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
205 record_type= BLOCK_RECORD;
206 transactional= 1;
207 key_field=FIELD_VARCHAR; /* varchar keys */
208 extra_field= FIELD_VARCHAR;
209 key_type= HA_KEYTYPE_VARTEXT1;
210 pack_seg|= HA_VAR_LENGTH_PART;
211 null_fields= 1;
212 break;
213 case 4: /* transactional */
214 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
215 record_type= BLOCK_RECORD;
216 transactional= 1;
217 key_field=FIELD_BLOB; /* blob key */
218 extra_field= FIELD_BLOB;
219 pack_seg|= HA_BLOB_PART;
220 key_type= HA_KEYTYPE_VARTEXT1;
221 break;
222 }
223
224
225 bzero((char*) recinfo,sizeof(recinfo));
226 bzero((char*) &create_info,sizeof(create_info));
227
228 /* First define 2 columns */
229 create_info.null_bytes= 1;
230 recinfo[0].type= key_field;
231 recinfo[0].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr :
232 key_length);
233 if (key_field == FIELD_VARCHAR)
234 recinfo[0].length+= HA_VARCHAR_PACKLENGTH(key_length);
235 recinfo[1].type=extra_field;
236 recinfo[1].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : 24);
237 if (extra_field == FIELD_VARCHAR)
238 recinfo[1].length+= HA_VARCHAR_PACKLENGTH(recinfo[1].length);
239 recinfo[1].null_bit= null_fields ? 2 : 0;
240
241 if (opt_unique)
242 {
243 recinfo[2].type=FIELD_CHECK;
244 recinfo[2].length=MARIA_UNIQUE_HASH_LENGTH;
245 }
246
247 if (key_type == HA_KEYTYPE_VARTEXT1 &&
248 key_length > 255)
249 key_type= HA_KEYTYPE_VARTEXT2;
250
251 /* Define a key over the first column */
252 keyinfo[0].seg=keyseg;
253 keyinfo[0].keysegs=1;
254 keyinfo[0].block_length= 0; /* Default block length */
255 keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
256 keyinfo[0].seg[0].type= key_type;
257 keyinfo[0].seg[0].flag= pack_seg;
258 keyinfo[0].seg[0].start=1;
259 keyinfo[0].seg[0].length=key_length;
260 keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
261 keyinfo[0].seg[0].null_pos=0;
262 keyinfo[0].seg[0].language= default_charset_info->number;
263 if (pack_seg & HA_BLOB_PART)
264 {
265 keyinfo[0].seg[0].bit_start=4; /* Length of blob length */
266 }
267 keyinfo[0].flag = (uint8) (pack_keys | unique_key);
268
269 if (opt_unique)
270 {
271 uint start;
272 uniques=1;
273 bzero((char*) &uniquedef,sizeof(uniquedef));
274 bzero((char*) uniqueseg,sizeof(uniqueseg));
275 uniquedef.seg=uniqueseg;
276 uniquedef.keysegs=2;
277
278 /* Make a unique over all columns (except first NULL fields) */
279 for (i=0, start=1 ; i < 2 ; i++)
280 {
281 uniqueseg[i].start=start;
282 start+=recinfo[i].length;
283 uniqueseg[i].length=recinfo[i].length;
284 uniqueseg[i].language= default_charset_info->number;
285 }
286 uniqueseg[0].type= key_type;
287 uniqueseg[0].null_bit= null_fields ? 2 : 0;
288 uniqueseg[1].type= HA_KEYTYPE_TEXT;
289 if (extra_field == FIELD_BLOB)
290 {
291 uniqueseg[1].length=0; /* The whole blob */
292 uniqueseg[1].bit_start=4; /* long blob */
293 uniqueseg[1].flag|= HA_BLOB_PART;
294 }
295 else if (extra_field == FIELD_VARCHAR)
296 {
297 uniqueseg[1].flag|= HA_VAR_LENGTH_PART;
298 uniqueseg[1].type= (HA_VARCHAR_PACKLENGTH(recinfo[1].length-1) == 1 ?
299 HA_KEYTYPE_VARTEXT1 : HA_KEYTYPE_VARTEXT2);
300 }
301 }
302 else
303 uniques=0;
304
305 if (!silent)
306 printf("- Creating Aria file\n");
307 create_info.max_rows= 0;
308 create_info.transactional= transactional;
309 if (maria_create(table_name, record_type, 1, keyinfo,2+opt_unique,recinfo,
310 uniques, &uniquedef, &create_info,
311 create_flag))
312 goto err;
313 if (!(file=maria_open(table_name,2,HA_OPEN_ABORT_IF_LOCKED, 0)))
314 goto err;
315 if (!silent)
316 printf("- Writing key:s\n");
317
318 if (maria_begin(file))
319 goto err;
320 my_errno=0;
321 for (i= 0 ; i < ROWS_IN_TEST ; i++)
322 {
323 create_record(record,i);
324 if ((error=maria_write(file,record)))
325 goto err;
326 }
327
328 if (maria_commit(file) | maria_close(file))
329 goto err;
330 printf("- Data copied\n");
331 return 0;
332
333 err:
334 printf("got error: %3d when using maria-database\n",my_errno);
335 return 1; /* skip warning */
336 }
337
338
create_key_part(uchar * key,uint rownr)339 static void create_key_part(uchar *key,uint rownr)
340 {
341 if (keyinfo[0].seg[0].type == HA_KEYTYPE_NUM)
342 {
343 sprintf((char*) key,"%*d",keyinfo[0].seg[0].length,rownr);
344 }
345 else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 ||
346 keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2)
347 { /* Alpha record */
348 /* Create a key that may be easily packed */
349 bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
350 sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr % 100);
351 if ((rownr & 7) == 0)
352 {
353 /* Change the key to force a unpack of the next key */
354 bfill(key+3,keyinfo[0].seg[0].length-5,rownr < 10 ? 'a' : 'b');
355 }
356 }
357 else
358 { /* Alpha record */
359 if (keyinfo[0].seg[0].flag & HA_SPACE_PACK)
360 sprintf((char*) key,"%-*d",keyinfo[0].seg[0].length,rownr);
361 else
362 {
363 /* Create a key that may be easily packed */
364 bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
365 sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr % 100);
366 if ((rownr & 7) == 0)
367 {
368 /* Change the key to force a unpack of the next key */
369 key[1]= (rownr < 10 ? 'a' : 'b');
370 }
371 }
372 }
373 }
374
375
376 static uchar blob_key[MAX_REC_LENGTH];
377 static uchar blob_record[MAX_REC_LENGTH+20*20];
378
379
create_record(uchar * record,uint rownr)380 static void create_record(uchar *record,uint rownr)
381 {
382 uchar *pos;
383 bzero((char*) record,MAX_REC_LENGTH);
384 record[0]=1; /* delete marker */
385 if (rownr == 0 && keyinfo[0].seg[0].null_bit)
386 record[0]|=keyinfo[0].seg[0].null_bit; /* Null key */
387
388 pos=record+1;
389 if (recinfo[0].type == FIELD_BLOB)
390 {
391 size_t tmp;
392 uchar *ptr;
393 create_key_part(blob_key,rownr);
394 tmp=strlen((char*) blob_key);
395 int4store(pos,tmp);
396 ptr=blob_key;
397 memcpy(pos+4,&ptr,sizeof(char*));
398 pos+=recinfo[0].length;
399 }
400 else if (recinfo[0].type == FIELD_VARCHAR)
401 {
402 size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[0].length-1);
403 create_key_part(pos+pack_length,rownr);
404 tmp= strlen((char*) pos+pack_length);
405 if (pack_length == 1)
406 *(uchar*) pos= (uchar) tmp;
407 else
408 int2store(pos,tmp);
409 pos+= recinfo[0].length;
410 }
411 else
412 {
413 create_key_part(pos,rownr);
414 pos+=recinfo[0].length;
415 }
416 if (recinfo[1].type == FIELD_BLOB)
417 {
418 size_t tmp;
419 uchar *ptr;;
420 sprintf((char*) blob_record,"... row: %d", rownr);
421 strappend((char*) blob_record, rownr % MAX_REC_LENGTH,'x');
422 tmp=strlen((char*) blob_record);
423 int4store(pos,tmp);
424 ptr=blob_record;
425 memcpy(pos+4,&ptr,sizeof(char*));
426 }
427 else if (recinfo[1].type == FIELD_VARCHAR)
428 {
429 size_t tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
430 sprintf((char*) pos+pack_length, "... row: %d", rownr);
431 tmp= strlen((char*) pos+pack_length);
432 if (pack_length == 1)
433 *pos= (uchar) tmp;
434 else
435 int2store(pos,tmp);
436 }
437 else
438 {
439 sprintf((char*) pos,"... row: %d", rownr);
440 strappend((char*) pos,recinfo[1].length,' ');
441 }
442 }
443
444 #include "ma_check_standalone.h"
445