Merge lp:~akopytov/percona-xtrabackup/compact-backups into lp:percona-xtrabackup/2.1

Proposed by Alexey Kopytov
Status: Merged
Approved by: Stewart Smith
Approved revision: no longer in the source branch.
Merged at revision: 486
Proposed branch: lp:~akopytov/percona-xtrabackup/compact-backups
Merge into: lp:percona-xtrabackup/2.1
Diff against target: 3973 lines (+2019/-639)
25 files modified
innobackupex (+22/-2)
patches/innodb51.patch (+128/-65)
patches/innodb55.patch (+142/-63)
patches/xtradb51.patch (+125/-59)
patches/xtradb55.patch (+138/-59)
src/Makefile (+4/-3)
src/compact.c (+960/-0)
src/compact.h (+44/-0)
src/datasink.c (+1/-0)
src/ds_tmpfile.c (+1/-1)
src/fil_cur.c (+5/-3)
src/fil_cur.h (+2/-1)
src/innodb_int.c (+45/-0)
src/innodb_int.h (+22/-0)
src/write_filt.c (+1/-102)
src/write_filt.h (+1/-5)
src/xb0xb.h (+40/-0)
src/xbstream.c (+3/-2)
src/xtrabackup.c (+251/-249)
src/xtrabackup.h (+28/-0)
test/inc/incremental_sample-db/incremental_sample-schema.sql (+3/-2)
test/t/compact.sh (+5/-6)
test/t/compact_compressed.sh (+33/-9)
test/testrun.sh (+2/-1)
utils/build.sh (+13/-7)
To merge this branch: bzr merge lp:~akopytov/percona-xtrabackup/compact-backups
Reviewer Review Type Date Requested Status
Stewart Smith (community) Approve
Hrvoje Matijakovic doc Pending
Review via email: mp+139157@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :

http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.1-param/105/

compact_compressed failures in debug builds is a result of index creating taking too long with all debug options turned on (in particular, UNIV_SYNC_DEBUG).

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Included Hrvoje to make sure that documentation is updated

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

This is not review. Just revision comment for rev. 460 caught my eye.

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Another Jenkins build with recent bugfixes and merges with sporadic test suite failures: http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.1-param/148/

I also had to disable UNIV_SYNC_DEBUG and UNIV_MEM_DEBUG for debug builds, as compact_compress alone took more than 30 minutes on my not-so-slow laptop with most time spent in UNIV_SYNC_DEBUG and UNIV_MEM_DEBUG code paths when rebuilding indexes.

Revision history for this message
Stewart Smith (stewart) wrote :

So, I have some thoughts about if we should just use sparse files instead and be done with it, and also we naturally have more QA to do, but I'm pretty happy that this is able to be merged now without adversely impacting other features.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'innobackupex'
2--- innobackupex 2013-01-14 04:46:19 +0000
3+++ innobackupex 2013-01-14 11:06:22 +0000
4@@ -118,6 +118,7 @@
5 my $option_safe_slave_backup_timeout = 300;
6
7 my $option_compact = '';
8+my $option_rebuild_indexes = '';
9
10 # name of the my.cnf configuration file
11 #my $config_file = '';
12@@ -699,6 +700,7 @@
13 '\.\.?|backup-my\.cnf|xtrabackup_logfile|' .
14 'xtrabackup_binary|xtrabackup_binlog_info|xtrabackup_checkpoints|' .
15 '.*\.qp|' .
16+ '.*\.pmap|.*\.tmp|' .
17 $iblog_files;
18 my $compressed_data_file = '.*\.ibz$';
19 my $file;
20@@ -806,6 +808,7 @@
21 sub apply_log {
22 my $rcode;
23 my $cmdline = '';
24+ my $cmdline_copy = '';
25 my $options = '';
26
27 if ($option_defaults_file) {
28@@ -839,6 +842,13 @@
29
30 # run ibbackup as a child process
31 $cmdline = "$option_ibbackup_binary $options";
32+
33+ # Only use --rebuild-indexes in the first xtrabackup call
34+ $cmdline_copy = $cmdline;
35+ if ($option_rebuild_indexes) {
36+ $cmdline = $cmdline . " --rebuild-indexes"
37+ }
38+
39 $now = current_time();
40 print STDERR "\n$now $prefix Starting ibbackup with command: $cmdline\n\n";
41 $rcode = system("$cmdline");
42@@ -850,6 +860,7 @@
43 # We should not create ib_logfile files if we prepare for following incremental applies
44 # Also we do not prepare ib_logfile if we applied incremental changes
45 if (!( ($option_redo_only) or ($option_incremental_dir))) {
46+ $cmdline = $cmdline_copy;
47 $now = current_time();
48 print STDERR "\n$now $prefix Restarting xtrabackup with command: $cmdline\nfor creating ib_logfile*\n\n";
49 $rcode = system("$cmdline");
50@@ -1036,8 +1047,12 @@
51 if ($option_stream) {
52 $options = $options . " --stream=$option_stream";
53 }
54+
55 if ($option_compact) {
56- $options = $options. " --compact";
57+ $options = $options . " --compact";
58+ }
59+ if ($option_rebuild_indexes) {
60+ $options = $options . " --rebuild-indexes";
61 }
62
63 $cmdline = "$option_ibbackup_binary $options";
64@@ -1753,7 +1768,8 @@
65 'parallel=i' => \$option_parallel,
66 'safe-slave-backup' => \$option_safe_slave_backup,
67 'safe-slave-backup-timeout=i' => \$option_safe_slave_backup_timeout,
68- 'compact' => \$option_compact
69+ 'compact' => \$option_compact,
70+ 'rebuild-indexes' => \$option_rebuild_indexes
71 );
72
73 if (!$rcode) {
74@@ -2800,6 +2816,10 @@
75
76 This option specifies the port to use when connecting to the database server with TCP/IP. The option accepts a string argument. It is passed to the mysql child process. It is passed to the mysql child process without alteration. See mysql --help for details.
77
78+=item --rebuild-indexes
79+
80+This option only has effect when used together with the --apply-log option and is passed directly to xtrabackup. When used, makes xtrabackup rebuild all secondary indexes after applying the log. This option is normally used to prepare compact backups. See the XtraBackup manual for more information.
81+
82 =item --redo-only
83
84 This option is passed directly to xtrabackup's --apply-log-only option. This forces xtrabackup to skip the "rollback" phase and do a "redo" only. This is necessary if the backup will have incremental changes applied to it later. See the xtrabackup documentation for details.
85
86=== modified file 'patches/innodb51.patch'
87--- patches/innodb51.patch 2012-11-14 04:46:11 +0000
88+++ patches/innodb51.patch 2013-01-14 11:06:22 +0000
89@@ -30,7 +30,15 @@
90 n_not_null[i]++;
91 --- a/storage/innodb_plugin/buf/buf0buf.c
92 +++ b/storage/innodb_plugin/buf/buf0buf.c
93-@@ -358,7 +358,7 @@
94+@@ -51,6 +51,7 @@
95+ #include "dict0dict.h"
96+ #include "log0recv.h"
97+ #include "page0zip.h"
98++#include "xb0xb.h"
99+
100+ /*
101+ IMPLEMENTATION OF THE BUFFER POOL
102+@@ -358,7 +359,7 @@
103 return(TRUE);
104 }
105
106@@ -39,7 +47,15 @@
107 if (recv_lsn_checks_on) {
108 ib_uint64_t current_lsn;
109
110-@@ -1690,7 +1690,9 @@
111+@@ -670,6 +671,7 @@
112+ block->page.in_flush_list = FALSE;
113+ block->page.in_free_list = FALSE;
114+ block->page.in_LRU_list = FALSE;
115++ block->page.is_compacted = FALSE;
116+ block->in_unzip_LRU_list = FALSE;
117+ #endif /* UNIV_DEBUG */
118+ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
119+@@ -1690,7 +1692,9 @@
120 ut_ad(zip_size == fil_space_get_zip_size(space));
121 ut_ad(ut_is_2pow(zip_size));
122 #ifndef UNIV_LOG_DEBUG
123@@ -50,12 +66,26 @@
124 #endif
125 buf_pool->stat.n_page_gets++;
126 loop:
127-@@ -2894,7 +2896,7 @@
128+@@ -2802,6 +2806,12 @@
129+ frame = ((buf_block_t*) bpage)->frame;
130+ }
131+
132++ /* Do not validate, recover and apply change buffer entries to
133++ bogus pages which replace skipped pages in compact backups. */
134++ if (srv_compact_backup && buf_page_is_compacted(frame)) {
135++ bpage->is_compacted = TRUE;
136++ }
137++
138+ /* If this page is not uninitialized and not in the
139+ doublewrite buffer, then the page number and space id
140+ should be the same as in block. */
141+@@ -2894,7 +2904,8 @@
142 recv_recover_page(TRUE, (buf_block_t*) bpage);
143 }
144
145 - if (uncompressed && !recv_no_ibuf_operations) {
146-+ if (uncompressed && !recv_no_ibuf_operations && !srv_fake_write) {
147++ if (uncompressed && !recv_no_ibuf_operations &&
148++ !srv_fake_write && !bpage->is_compacted) {
149 ibuf_merge_or_delete_for_page(
150 (buf_block_t*) bpage, bpage->space,
151 bpage->offset, buf_page_get_zip_size(bpage),
152@@ -783,7 +813,7 @@
153 /* In this fastest shutdown we do not flush the buffer pool:
154 --- a/storage/innodb_plugin/log/log0recv.c
155 +++ b/storage/innodb_plugin/log/log0recv.c
156-@@ -42,27 +42,27 @@
157+@@ -42,27 +42,28 @@
158 #include "trx0undo.h"
159 #include "trx0rec.h"
160 #include "fil0fil.h"
161@@ -797,6 +827,7 @@
162 # include "sync0sync.h"
163 -#else /* !UNIV_HOTBACKUP */
164 +//#else /* !UNIV_HOTBACKUP */
165++#include "xb0xb.h"
166
167 /** This is set to FALSE if the backup was originally taken with the
168 ibbackup --include regexp option: then we do not want to create tables in
169@@ -815,7 +846,7 @@
170
171 /** The recovery system */
172 UNIV_INTERN recv_sys_t* recv_sys = NULL;
173-@@ -251,7 +251,7 @@
174+@@ -251,7 +252,7 @@
175 {
176 recv_lsn_checks_on = FALSE;
177
178@@ -824,7 +855,7 @@
179
180 recv_recovery_on = FALSE;
181
182-@@ -277,7 +277,7 @@
183+@@ -277,7 +278,7 @@
184
185 recv_max_parsed_page_no = 0;
186
187@@ -833,7 +864,7 @@
188
189 recv_max_page_lsn = 0;
190 }
191-@@ -613,7 +613,7 @@
192+@@ -613,7 +614,7 @@
193 /***********************************************************************//**
194 Checks the consistency of the checkpoint info
195 @return TRUE if ok */
196@@ -842,7 +873,7 @@
197 ibool
198 recv_check_cp_is_consistent(
199 /*========================*/
200-@@ -643,7 +643,7 @@
201+@@ -643,7 +644,7 @@
202 /********************************************************//**
203 Looks for the maximum consistent checkpoint from the log groups.
204 @return error code or DB_SUCCESS */
205@@ -851,7 +882,7 @@
206 ulint
207 recv_find_max_checkpoint(
208 /*=====================*/
209-@@ -818,7 +818,7 @@
210+@@ -818,7 +819,7 @@
211 InnoDB-3.23.52 where the checksum field contains the log block number.
212 @return TRUE if ok, or if the log block may be in the format of InnoDB
213 version predating 3.23.52 */
214@@ -860,7 +891,7 @@
215 ibool
216 log_block_checksum_is_ok_or_old_format(
217 /*===================================*/
218-@@ -1486,6 +1486,7 @@
219+@@ -1486,6 +1487,7 @@
220 buf_block_get_page_no(block));
221
222 if ((recv_addr == NULL)
223@@ -868,7 +899,25 @@
224 || (recv_addr->state == RECV_BEING_PROCESSED)
225 || (recv_addr->state == RECV_PROCESSED)) {
226
227-@@ -2297,7 +2298,7 @@
228+@@ -1575,9 +1577,16 @@
229+ if (page_zip) {
230+ memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
231+ }
232++
233++ if (block->page.is_compacted) {
234++
235++ ut_ad(srv_compact_backup);
236++
237++ block->page.is_compacted = FALSE;
238++ }
239+ }
240+
241+- if (recv->start_lsn >= page_lsn) {
242++ if (!block->page.is_compacted && recv->start_lsn >= page_lsn) {
243+
244+ ib_uint64_t end_lsn;
245+
246+@@ -2297,7 +2306,7 @@
247 || type == MLOG_FILE_RENAME
248 || type == MLOG_FILE_DELETE) {
249 ut_a(space);
250@@ -877,7 +926,7 @@
251 if (recv_replay_file_ops) {
252
253 /* In ibbackup --apply-log, replay an .ibd file
254-@@ -2320,7 +2321,7 @@
255+@@ -2320,7 +2329,7 @@
256 ut_error;
257 }
258 }
259@@ -886,7 +935,7 @@
260 /* In normal mysqld crash recovery we do not try to
261 replay file operations */
262 #ifdef UNIV_LOG_LSN_DEBUG
263-@@ -2737,8 +2738,11 @@
264+@@ -2737,8 +2746,11 @@
265
266 fprintf(stderr,
267 "InnoDB: Doing recovery: scanned up to"
268@@ -900,7 +949,7 @@
269 }
270 }
271
272-@@ -2850,12 +2854,14 @@
273+@@ -2850,12 +2862,14 @@
274
275 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
276
277@@ -916,7 +965,7 @@
278 }
279 }
280
281-@@ -3005,6 +3011,7 @@
282+@@ -3005,6 +3019,7 @@
283 recv_sys->recovered_lsn = checkpoint_lsn;
284
285 srv_start_lsn = checkpoint_lsn;
286@@ -924,7 +973,7 @@
287 }
288
289 contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
290-@@ -3286,6 +3293,7 @@
291+@@ -3286,6 +3301,7 @@
292 that the data dictionary tables will be free of any locks.
293 The data dictionary latch should guarantee that there is at
294 most one data dictionary transaction active at a time. */
295@@ -1007,46 +1056,6 @@
296 #endif
297 }
298
299---- a/storage/innodb_plugin/row/row0merge.c
300-+++ b/storage/innodb_plugin/row/row0merge.c
301-@@ -453,7 +453,9 @@
302- rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext);
303- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
304-
305-- innobase_rec_to_mysql(dup->table, rec, index, offsets);
306-+ //innobase_rec_to_mysql(dup->table, rec, index, offsets);
307-+ fprintf(stderr, "InnoDB: Error: row_merge_dup_report() is called.\n");
308-+ ut_error;
309-
310- mem_heap_free(heap);
311- }
312-@@ -1457,8 +1459,12 @@
313- case 0:
314- if (UNIV_UNLIKELY
315- (dict_index_is_unique(index) && !null_eq)) {
316-- innobase_rec_to_mysql(table, mrec0,
317-- index, offsets0);
318-+ //innobase_rec_to_mysql(table, mrec0,
319-+ // index, offsets0);
320-+ (void) table;
321-+ fprintf(stderr, "InnoDB: Error: "
322-+ "row_merge_blocks() is called.\n");
323-+ ut_error;
324- mem_heap_free(heap);
325- return(DB_DUPLICATE_KEY);
326- }
327-@@ -2584,7 +2590,10 @@
328-
329- /* Reset the MySQL row buffer that is used when reporting
330- duplicate keys. */
331-- innobase_rec_reset(table);
332-+ //innobase_rec_reset(table);
333-+ fprintf(stderr, "InnoDB: Error: row_merge_build_indexes() is called."
334-+ "\n");
335-+ ut_error;
336-
337- /* Read clustered index of the table and create files for
338- secondary index entries for merge sort */
339 --- a/storage/innodb_plugin/srv/srv0srv.c
340 +++ b/storage/innodb_plugin/srv/srv0srv.c
341 @@ -374,6 +374,9 @@
342@@ -1086,7 +1095,15 @@
343 /*********************************************************************//**
344 --- a/storage/innodb_plugin/srv/srv0start.c
345 +++ b/storage/innodb_plugin/srv/srv0start.c
346-@@ -94,6 +94,8 @@
347+@@ -62,6 +62,7 @@
348+ #include "ibuf0ibuf.h"
349+ #include "srv0start.h"
350+ #include "srv0srv.h"
351++#include "xb0xb.h"
352+ #ifndef UNIV_HOTBACKUP
353+ # include "os0proc.h"
354+ # include "sync0sync.h"
355+@@ -94,6 +95,8 @@
356 /** Log sequence number at shutdown */
357 UNIV_INTERN ib_uint64_t srv_shutdown_lsn;
358
359@@ -1095,7 +1112,7 @@
360 #ifdef HAVE_DARWIN_THREADS
361 # include <sys/utsname.h>
362 /** TRUE if the F_FULLFSYNC option is available */
363-@@ -544,7 +546,7 @@
364+@@ -544,7 +547,7 @@
365 /*********************************************************************//**
366 Creates or opens the log files and closes them.
367 @return DB_SUCCESS or error code */
368@@ -1104,7 +1121,7 @@
369 ulint
370 open_or_create_log_file(
371 /*====================*/
372-@@ -702,7 +704,7 @@
373+@@ -702,7 +705,7 @@
374 /*********************************************************************//**
375 Creates or opens database data files and closes them.
376 @return DB_SUCCESS or error code */
377@@ -1113,7 +1130,7 @@
378 ulint
379 open_or_create_data_files(
380 /*======================*/
381-@@ -1359,7 +1361,7 @@
382+@@ -1359,7 +1362,7 @@
383 }
384 #endif /* UNIV_LOG_ARCHIVE */
385
386@@ -1122,7 +1139,7 @@
387 fprintf(stderr,
388 "InnoDB: Error: combined size of log files"
389 " must be < 4 GB\n");
390-@@ -1601,6 +1603,10 @@
391+@@ -1601,6 +1604,10 @@
392 are initialized in trx_sys_init_at_db_start(). */
393
394 recv_recovery_from_checkpoint_finish();
395@@ -1133,7 +1150,7 @@
396 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
397 /* The following call is necessary for the insert
398 buffer to work with multiple tablespaces. We must
399-@@ -1747,7 +1753,18 @@
400+@@ -1747,7 +1754,18 @@
401
402 if (srv_auto_extend_last_data_file
403 && sum_of_data_file_sizes < tablespace_size_in_header) {
404@@ -1152,7 +1169,7 @@
405 fprintf(stderr,
406 "InnoDB: Error: tablespace size stored in header"
407 " is %lu pages, but\n"
408-@@ -1772,6 +1789,7 @@
409+@@ -1772,6 +1790,7 @@
410
411 return(DB_ERROR);
412 }
413@@ -1160,7 +1177,18 @@
414 }
415
416 /* Check that os_fast_mutexes work as expected */
417-@@ -1867,6 +1885,7 @@
418+@@ -1793,6 +1812,10 @@
419+
420+ os_fast_mutex_free(&srv_os_test_mutex);
421+
422++ if (srv_rebuild_indexes) {
423++ xb_compact_rebuild_indexes();
424++ }
425++
426+ if (srv_print_verbose_log) {
427+ ut_print_timestamp(stderr);
428+ fprintf(stderr,
429+@@ -1867,6 +1890,7 @@
430 ibuf_update_max_tablespace_id();
431 }
432
433@@ -1251,3 +1279,38 @@
434 } else {
435 fprintf(stderr,
436 "InnoDB: Since"
437+--- a/storage/innodb_plugin/sync/sync0arr.c
438++++ b/storage/innodb_plugin/sync/sync0arr.c
439+@@ -40,6 +40,7 @@
440+ #include "os0sync.h"
441+ #include "os0file.h"
442+ #include "srv0srv.h"
443++#include "xb0xb.h"
444+
445+ /*
446+ WAIT ARRAY
447+@@ -927,6 +928,13 @@
448+ ibool fatal = FALSE;
449+ double longest_diff = 0;
450+
451++ if (srv_rebuild_indexes) {
452++
453++ /* Avoid long semaphore warnings when rebuilding indexes */
454++
455++ return(FALSE);
456++ }
457++
458+ for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
459+
460+ double diff;
461+--- a/storage/innodb_plugin/include/buf0buf.h
462++++ b/storage/innodb_plugin/include/buf0buf.h
463+@@ -1191,6 +1191,8 @@
464+ frees a page in buffer pool */
465+ # endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
466+ #endif /* !UNIV_HOTBACKUP */
467++ ibool is_compacted; /*!< TRUE if the page was skipped in
468++ compact backups */
469+ };
470+
471+ /** The buffer control block structure */
472
473=== modified file 'patches/innodb55.patch'
474--- patches/innodb55.patch 2012-02-22 16:37:18 +0000
475+++ patches/innodb55.patch 2013-01-14 11:06:22 +0000
476@@ -20,7 +20,15 @@
477 /*===================*/
478 --- a/storage/innobase/buf/buf0buf.c
479 +++ b/storage/innobase/buf/buf0buf.c
480-@@ -518,7 +518,7 @@
481+@@ -51,6 +51,7 @@
482+ #include "dict0dict.h"
483+ #include "log0recv.h"
484+ #include "page0zip.h"
485++#include "xb0xb.h"
486+
487+ /*
488+ IMPLEMENTATION OF THE BUFFER POOL
489+@@ -518,7 +519,7 @@
490 return(TRUE);
491 }
492
493@@ -29,7 +37,15 @@
494 if (recv_lsn_checks_on) {
495 ib_uint64_t current_lsn;
496
497-@@ -2299,7 +2299,8 @@
498+@@ -881,6 +882,7 @@
499+ block->page.in_flush_list = FALSE;
500+ block->page.in_free_list = FALSE;
501+ block->page.in_LRU_list = FALSE;
502++ block->page.is_compacted = FALSE;
503+ block->in_unzip_LRU_list = FALSE;
504+ #endif /* UNIV_DEBUG */
505+ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
506+@@ -2299,7 +2301,8 @@
507 ut_ad(zip_size == fil_space_get_zip_size(space));
508 ut_ad(ut_is_2pow(zip_size));
509 #ifndef UNIV_LOG_DEBUG
510@@ -39,12 +55,27 @@
511 || ibuf_page_low(space, zip_size, offset,
512 FALSE, file, line, NULL));
513 #endif
514-@@ -3668,7 +3669,7 @@
515+@@ -3567,6 +3570,13 @@
516+ frame = ((buf_block_t*) bpage)->frame;
517+ }
518+
519++ /* Do not validate, recover and apply change buffer entries to
520++ bogus pages which replace skipped pages in compact backups. */
521++ if (srv_compact_backup && buf_page_is_compacted(frame)) {
522++
523++ bpage->is_compacted = TRUE;
524++ }
525++
526+ /* If this page is not uninitialized and not in the
527+ doublewrite buffer, then the page number and space id
528+ should be the same as in block. */
529+@@ -3668,7 +3678,8 @@
530 recv_recover_page(TRUE, (buf_block_t*) bpage);
531 }
532
533 - if (uncompressed && !recv_no_ibuf_operations) {
534-+ if (uncompressed && !recv_no_ibuf_operations && !srv_fake_write) {
535++ if (uncompressed && !recv_no_ibuf_operations &&
536++ !srv_fake_write && !bpage->is_compacted) {
537 ibuf_merge_or_delete_for_page(
538 (buf_block_t*) bpage, bpage->space,
539 bpage->offset, buf_page_get_zip_size(bpage),
540@@ -695,7 +726,7 @@
541 server_busy = log_sys->n_pending_checkpoint_writes
542 --- a/storage/innobase/log/log0recv.c
543 +++ b/storage/innobase/log/log0recv.c
544-@@ -42,27 +42,27 @@
545+@@ -42,27 +42,28 @@
546 #include "trx0undo.h"
547 #include "trx0rec.h"
548 #include "fil0fil.h"
549@@ -709,6 +740,7 @@
550 # include "sync0sync.h"
551 -#else /* !UNIV_HOTBACKUP */
552 +//#else /* !UNIV_HOTBACKUP */
553++#include "xb0xb.h"
554
555 /** This is set to FALSE if the backup was originally taken with the
556 ibbackup --include regexp option: then we do not want to create tables in
557@@ -727,7 +759,7 @@
558
559 /** The recovery system */
560 UNIV_INTERN recv_sys_t* recv_sys = NULL;
561-@@ -259,7 +259,7 @@
562+@@ -259,7 +260,7 @@
563 {
564 recv_lsn_checks_on = FALSE;
565
566@@ -736,7 +768,7 @@
567
568 recv_recovery_on = FALSE;
569
570-@@ -285,7 +285,7 @@
571+@@ -285,7 +286,7 @@
572
573 recv_max_parsed_page_no = 0;
574
575@@ -745,7 +777,7 @@
576
577 recv_max_page_lsn = 0;
578 }
579-@@ -623,7 +623,7 @@
580+@@ -623,7 +624,7 @@
581 /***********************************************************************//**
582 Checks the consistency of the checkpoint info
583 @return TRUE if ok */
584@@ -754,7 +786,7 @@
585 ibool
586 recv_check_cp_is_consistent(
587 /*========================*/
588-@@ -653,7 +653,7 @@
589+@@ -653,7 +654,7 @@
590 /********************************************************//**
591 Looks for the maximum consistent checkpoint from the log groups.
592 @return error code or DB_SUCCESS */
593@@ -763,7 +795,7 @@
594 ulint
595 recv_find_max_checkpoint(
596 /*=====================*/
597-@@ -828,7 +828,7 @@
598+@@ -828,7 +829,7 @@
599 InnoDB-3.23.52 where the checksum field contains the log block number.
600 @return TRUE if ok, or if the log block may be in the format of InnoDB
601 version predating 3.23.52 */
602@@ -772,7 +804,7 @@
603 ibool
604 log_block_checksum_is_ok_or_old_format(
605 /*===================================*/
606-@@ -1496,6 +1496,7 @@
607+@@ -1496,6 +1497,7 @@
608 buf_block_get_page_no(block));
609
610 if ((recv_addr == NULL)
611@@ -780,7 +812,25 @@
612 || (recv_addr->state == RECV_BEING_PROCESSED)
613 || (recv_addr->state == RECV_PROCESSED)) {
614
615-@@ -2308,7 +2309,7 @@
616+@@ -1585,9 +1587,16 @@
617+ if (page_zip) {
618+ memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
619+ }
620++
621++ if (block->page.is_compacted) {
622++
623++ ut_ad(srv_compact_backup);
624++
625++ block->page.is_compacted = FALSE;
626++ }
627+ }
628+
629+- if (recv->start_lsn >= page_lsn) {
630++ if (!block->page.is_compacted && recv->start_lsn >= page_lsn) {
631+
632+ ib_uint64_t end_lsn;
633+
634+@@ -2308,7 +2317,7 @@
635 || type == MLOG_FILE_RENAME
636 || type == MLOG_FILE_DELETE) {
637 ut_a(space);
638@@ -789,7 +839,7 @@
639 if (recv_replay_file_ops) {
640
641 /* In ibbackup --apply-log, replay an .ibd file
642-@@ -2331,7 +2332,7 @@
643+@@ -2331,7 +2340,7 @@
644 ut_error;
645 }
646 }
647@@ -798,7 +848,7 @@
648 /* In normal mysqld crash recovery we do not try to
649 replay file operations */
650 #ifdef UNIV_LOG_LSN_DEBUG
651-@@ -2748,8 +2749,11 @@
652+@@ -2748,8 +2757,11 @@
653
654 fprintf(stderr,
655 "InnoDB: Doing recovery: scanned up to"
656@@ -812,7 +862,7 @@
657 }
658 }
659
660-@@ -2863,12 +2867,14 @@
661+@@ -2863,12 +2875,14 @@
662
663 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
664
665@@ -828,7 +878,7 @@
666 }
667 }
668
669-@@ -3018,6 +3024,7 @@
670+@@ -3018,6 +3032,7 @@
671 recv_sys->recovered_lsn = checkpoint_lsn;
672
673 srv_start_lsn = checkpoint_lsn;
674@@ -836,7 +886,7 @@
675 }
676
677 contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
678-@@ -3299,6 +3306,7 @@
679+@@ -3299,6 +3314,7 @@
680 that the data dictionary tables will be free of any locks.
681 The data dictionary latch should guarantee that there is at
682 most one data dictionary transaction active at a time. */
683@@ -918,44 +968,6 @@
684 +*/
685 #endif
686 }
687---- a/storage/innobase/row/row0merge.c
688-+++ b/storage/innobase/row/row0merge.c
689-@@ -459,7 +459,9 @@
690- rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext);
691- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
692-
693-- innobase_rec_to_mysql(dup->table, rec, index, offsets);
694-+ //innobase_rec_to_mysql(dup->table, rec, index, offsets);
695-+ fprintf(stderr, "InnoDB: Error: row_merge_dup_report() is called.\n");
696-+ ut_error;
697-
698- mem_heap_free(heap);
699- }
700-@@ -1478,8 +1480,12 @@
701- case 0:
702- if (UNIV_UNLIKELY
703- (dict_index_is_unique(index) && !null_eq)) {
704-- innobase_rec_to_mysql(table, mrec0,
705-+ /* innobase_rec_to_mysql(table, mrec0,
706- index, offsets0);
707-+ */
708-+ (void) table;
709-+ fprintf(stderr, "InnoDB: Error: row_merge_blocks() is called.\n");
710-+ ut_error;
711- mem_heap_free(heap);
712- return(DB_DUPLICATE_KEY);
713- }
714-@@ -2627,7 +2633,9 @@
715-
716- /* Reset the MySQL row buffer that is used when reporting
717- duplicate keys. */
718-- innobase_rec_reset(table);
719-+ //innobase_rec_reset(table);
720-+ fprintf(stderr, "InnoDB: Error: row_merge_build_indexes() is called.\n");
721-+ ut_error;
722-
723- /* Read clustered index of the table and create files for
724- secondary index entries for merge sort */
725 --- a/storage/innobase/srv/srv0srv.c
726 +++ b/storage/innobase/srv/srv0srv.c
727 @@ -399,6 +399,9 @@
728@@ -1004,7 +1016,15 @@
729 if (trx->was_chosen_as_deadlock_victim) {
730 --- a/storage/innobase/srv/srv0start.c
731 +++ b/storage/innobase/srv/srv0start.c
732-@@ -93,6 +93,8 @@
733+@@ -62,6 +62,7 @@
734+ #include "ibuf0ibuf.h"
735+ #include "srv0start.h"
736+ #include "srv0srv.h"
737++#include "xb0xb.h"
738+ #ifndef UNIV_HOTBACKUP
739+ # include "os0proc.h"
740+ # include "sync0sync.h"
741+@@ -93,6 +94,8 @@
742 /** Log sequence number at shutdown */
743 UNIV_INTERN ib_uint64_t srv_shutdown_lsn;
744
745@@ -1013,7 +1033,7 @@
746 #ifdef HAVE_DARWIN_THREADS
747 # include <sys/utsname.h>
748 /** TRUE if the F_FULLFSYNC option is available */
749-@@ -548,7 +550,7 @@
750+@@ -548,7 +551,7 @@
751 /*********************************************************************//**
752 Creates or opens the log files and closes them.
753 @return DB_SUCCESS or error code */
754@@ -1022,7 +1042,7 @@
755 ulint
756 open_or_create_log_file(
757 /*====================*/
758-@@ -708,7 +710,7 @@
759+@@ -708,7 +711,7 @@
760 /*********************************************************************//**
761 Creates or opens database data files and closes them.
762 @return DB_SUCCESS or error code */
763@@ -1031,7 +1051,7 @@
764 ulint
765 open_or_create_data_files(
766 /*======================*/
767-@@ -1419,7 +1421,7 @@
768+@@ -1419,7 +1422,7 @@
769 }
770 #endif /* UNIV_LOG_ARCHIVE */
771
772@@ -1040,7 +1060,7 @@
773 ut_print_timestamp(stderr);
774 fprintf(stderr,
775 " InnoDB: Error: combined size of log files"
776-@@ -1714,6 +1716,10 @@
777+@@ -1714,6 +1717,10 @@
778 are initialized in trx_sys_init_at_db_start(). */
779
780 recv_recovery_from_checkpoint_finish();
781@@ -1051,7 +1071,7 @@
782 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
783 /* The following call is necessary for the insert
784 buffer to work with multiple tablespaces. We must
785-@@ -1873,6 +1879,17 @@
786+@@ -1873,6 +1880,17 @@
787 if (!srv_auto_extend_last_data_file
788 && sum_of_data_file_sizes != tablespace_size_in_header) {
789
790@@ -1069,7 +1089,7 @@
791 ut_print_timestamp(stderr);
792 fprintf(stderr,
793 " InnoDB: Error: tablespace size"
794-@@ -1952,6 +1969,7 @@
795+@@ -1952,6 +1970,7 @@
796
797 return(DB_ERROR);
798 }
799@@ -1077,7 +1097,18 @@
800 }
801
802 /* Check that os_fast_mutexes work as expected */
803-@@ -2064,6 +2082,7 @@
804+@@ -1976,6 +1995,10 @@
805+
806+ os_fast_mutex_free(&srv_os_test_mutex);
807+
808++ if (srv_rebuild_indexes) {
809++ xb_compact_rebuild_indexes();
810++ }
811++
812+ if (srv_print_verbose_log) {
813+ ut_print_timestamp(stderr);
814+ fprintf(stderr,
815+@@ -2064,6 +2087,7 @@
816 ibuf_update_max_tablespace_id();
817 }
818
819@@ -1168,3 +1199,51 @@
820 ut_a(purge_sys->trx->n_active_thrs == 0);
821
822 rw_lock_x_lock(&purge_sys->latch);
823+--- a/configure.cmake
824++++ b/configure.cmake
825+@@ -149,7 +149,9 @@
826+ SET(CMAKE_REQUIRED_LIBRARIES
827+ ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT})
828+
829+- LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
830++ IF(CMAKE_REQUIRED_LIBRARIES)
831++ LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
832++ ENDIF()
833+ LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT})
834+
835+ OPTION(WITH_LIBWRAP "Compile with tcp wrappers support" OFF)
836+--- a/storage/innobase/sync/sync0arr.c
837++++ b/storage/innobase/sync/sync0arr.c
838+@@ -41,6 +41,7 @@
839+ #include "os0file.h"
840+ #include "srv0srv.h"
841+ #include "ha_prototypes.h"
842++#include "xb0xb.h"
843+
844+ /*
845+ WAIT ARRAY
846+@@ -928,6 +929,13 @@
847+ ibool fatal = FALSE;
848+ double longest_diff = 0;
849+
850++ if (srv_rebuild_indexes) {
851++
852++ /* Avoid long semaphore warnings when rebuilding indexes */
853++
854++ return(FALSE);
855++ }
856++
857+ #ifdef UNIV_DEBUG_VALGRIND
858+ /* Increase the timeouts if running under valgrind because it executes
859+ extremely slowly. UNIV_DEBUG_VALGRIND does not necessary mean that
860+--- a/storage/innobase/include/buf0buf.h
861++++ b/storage/innobase/include/buf0buf.h
862+@@ -1441,6 +1441,8 @@
863+ frees a page in buffer pool */
864+ # endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
865+ #endif /* !UNIV_HOTBACKUP */
866++ ibool is_compacted; /*!< TRUE if the page was skipped in
867++ compact backups */
868+ };
869+
870+ /** The buffer control block structure */
871
872=== modified file 'patches/xtradb51.patch'
873--- patches/xtradb51.patch 2012-02-22 16:37:18 +0000
874+++ patches/xtradb51.patch 2013-01-14 11:06:22 +0000
875@@ -20,7 +20,15 @@
876 /*===================*/
877 --- a/storage/innodb_plugin/buf/buf0buf.c
878 +++ b/storage/innodb_plugin/buf/buf0buf.c
879-@@ -412,7 +412,7 @@
880+@@ -53,6 +53,7 @@
881+ #include "page0zip.h"
882+ #include "trx0trx.h"
883+ #include "srv0start.h"
884++#include "xb0xb.h"
885+
886+ /* prototypes for new functions added to ha_innodb.cc */
887+ trx_t* innobase_get_trx();
888+@@ -412,7 +413,7 @@
889 return(TRUE);
890 }
891
892@@ -29,7 +37,15 @@
893 if (recv_lsn_checks_on) {
894 ib_uint64_t current_lsn;
895
896-@@ -1888,7 +1888,9 @@
897+@@ -744,6 +745,7 @@
898+ block->page.zip_list.prev = NULL;
899+ block->page.zip_list.next = NULL;
900+ block->page.in_LRU_list = FALSE;
901++ block->page.is_compacted = FALSE;
902+ block->in_unzip_LRU_list = FALSE;
903+ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
904+ block->n_pointers = 0;
905+@@ -1888,7 +1890,9 @@
906 ut_ad(zip_size == fil_space_get_zip_size(space));
907 ut_ad(ut_is_2pow(zip_size));
908 #ifndef UNIV_LOG_DEBUG
909@@ -40,12 +56,27 @@
910 #endif
911 if (innobase_get_slow_log()) {
912 trx = innobase_get_trx();
913-@@ -3302,7 +3304,7 @@
914+@@ -3190,6 +3194,13 @@
915+ frame = ((buf_block_t*) bpage)->frame;
916+ }
917+
918++ /* Do not validate, recover and apply change buffer entries to
919++ bogus pages which replace skipped pages in compact backups. */
920++ if (srv_compact_backup && buf_page_is_compacted(frame)) {
921++
922++ bpage->is_compacted = TRUE;
923++ }
924++
925+ /* If this page is not uninitialized and not in the
926+ doublewrite buffer, then the page number and space id
927+ should be the same as in block. */
928+@@ -3302,7 +3313,8 @@
929 recv_recover_page(TRUE, (buf_block_t*) bpage);
930 }
931
932 - if (uncompressed && !recv_no_ibuf_operations) {
933-+ if (uncompressed && !recv_no_ibuf_operations && !srv_fake_write) {
934++ if (uncompressed && !recv_no_ibuf_operations &&
935++ !srv_fake_write && !bpage->is_compacted) {
936 ibuf_merge_or_delete_for_page(
937 /* Delete possible entries, if bpage is_corrupt */
938 (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
939@@ -723,7 +754,7 @@
940 /* In this fastest shutdown we do not flush the buffer pool:
941 --- a/storage/innodb_plugin/log/log0recv.c
942 +++ b/storage/innodb_plugin/log/log0recv.c
943-@@ -42,27 +42,27 @@
944+@@ -42,27 +42,28 @@
945 #include "trx0undo.h"
946 #include "trx0rec.h"
947 #include "fil0fil.h"
948@@ -737,6 +768,7 @@
949 # include "sync0sync.h"
950 -#else /* !UNIV_HOTBACKUP */
951 +//#else /* !UNIV_HOTBACKUP */
952++#include "xb0xb.h"
953
954 /** This is set to FALSE if the backup was originally taken with the
955 ibbackup --include regexp option: then we do not want to create tables in
956@@ -755,7 +787,7 @@
957
958 /** The recovery system */
959 UNIV_INTERN recv_sys_t* recv_sys = NULL;
960-@@ -621,7 +621,7 @@
961+@@ -621,7 +622,7 @@
962 /***********************************************************************//**
963 Checks the consistency of the checkpoint info
964 @return TRUE if ok */
965@@ -764,7 +796,7 @@
966 ibool
967 recv_check_cp_is_consistent(
968 /*========================*/
969-@@ -651,7 +651,7 @@
970+@@ -651,7 +652,7 @@
971 /********************************************************//**
972 Looks for the maximum consistent checkpoint from the log groups.
973 @return error code or DB_SUCCESS */
974@@ -773,7 +805,7 @@
975 ulint
976 recv_find_max_checkpoint(
977 /*=====================*/
978-@@ -840,7 +840,7 @@
979+@@ -840,7 +841,7 @@
980 InnoDB-3.23.52 where the checksum field contains the log block number.
981 @return TRUE if ok, or if the log block may be in the format of InnoDB
982 version predating 3.23.52 */
983@@ -782,7 +814,25 @@
984 ibool
985 log_block_checksum_is_ok_or_old_format(
986 /*===================================*/
987-@@ -2369,7 +2369,7 @@
988+@@ -1629,9 +1630,16 @@
989+ if (page_zip) {
990+ memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
991+ }
992++
993++ if (block->page.is_compacted) {
994++
995++ ut_ad(srv_compact_backup);
996++
997++ block->page.is_compacted = FALSE;
998++ }
999+ }
1000+
1001+- if (recv->start_lsn >= page_lsn) {
1002++ if (!block->page.is_compacted && recv->start_lsn >= page_lsn) {
1003+
1004+ ib_uint64_t end_lsn;
1005+
1006+@@ -2369,7 +2377,7 @@
1007 || type == MLOG_FILE_RENAME
1008 || type == MLOG_FILE_DELETE) {
1009 ut_a(space);
1010@@ -791,7 +841,7 @@
1011 if (recv_replay_file_ops) {
1012
1013 /* In ibbackup --apply-log, replay an .ibd file
1014-@@ -2392,7 +2392,7 @@
1015+@@ -2392,7 +2400,7 @@
1016 ut_error;
1017 }
1018 }
1019@@ -800,7 +850,7 @@
1020 /* In normal mysqld crash recovery we do not try to
1021 replay file operations */
1022 #ifdef UNIV_LOG_LSN_DEBUG
1023-@@ -2809,8 +2809,11 @@
1024+@@ -2809,8 +2817,11 @@
1025
1026 fprintf(stderr,
1027 "InnoDB: Doing recovery: scanned up to"
1028@@ -814,7 +864,7 @@
1029 }
1030 }
1031
1032-@@ -2922,12 +2925,14 @@
1033+@@ -2922,12 +2933,14 @@
1034
1035 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
1036
1037@@ -830,7 +880,7 @@
1038 }
1039 }
1040
1041-@@ -3095,6 +3100,7 @@
1042+@@ -3095,6 +3108,7 @@
1043 recv_sys->recovered_lsn = checkpoint_lsn;
1044
1045 srv_start_lsn = checkpoint_lsn;
1046@@ -838,7 +888,7 @@
1047 }
1048
1049 contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
1050-@@ -3453,6 +3459,7 @@
1051+@@ -3453,6 +3467,7 @@
1052 that the data dictionary tables will be free of any locks.
1053 The data dictionary latch should guarantee that there is at
1054 most one data dictionary transaction active at a time. */
1055@@ -921,44 +971,6 @@
1056 #endif
1057 }
1058
1059---- a/storage/innodb_plugin/row/row0merge.c
1060-+++ b/storage/innodb_plugin/row/row0merge.c
1061-@@ -454,7 +454,9 @@
1062- rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext);
1063- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
1064-
1065-- innobase_rec_to_mysql(dup->table, rec, index, offsets);
1066-+ //innobase_rec_to_mysql(dup->table, rec, index, offsets);
1067-+ fprintf(stderr, "InnoDB: Error: row_merge_dup_report() is called.\n");
1068-+ ut_error;
1069-
1070- mem_heap_free(heap);
1071- }
1072-@@ -1465,8 +1467,11 @@
1073- case 0:
1074- if (UNIV_UNLIKELY
1075- (dict_index_is_unique(index) && !null_eq)) {
1076-- innobase_rec_to_mysql(table, mrec0,
1077-- index, offsets0);
1078-+ //innobase_rec_to_mysql(table, mrec0,
1079-+ // index, offsets0);
1080-+ (void) table;
1081-+ fprintf(stderr, "InnoDB: Error: row_merge_blocks() is called.\n");
1082-+ ut_error;
1083- mem_heap_free(heap);
1084- return(DB_DUPLICATE_KEY);
1085- }
1086-@@ -2594,7 +2599,9 @@
1087-
1088- /* Reset the MySQL row buffer that is used when reporting
1089- duplicate keys. */
1090-- innobase_rec_reset(table);
1091-+ //innobase_rec_reset(table);
1092-+ fprintf(stderr, "InnoDB: Error: row_merge_build_indexes() is called.\n");
1093-+ ut_error;
1094-
1095- /* Read clustered index of the table and create files for
1096- secondary index entries for merge sort */
1097 --- a/storage/innodb_plugin/srv/srv0srv.c
1098 +++ b/storage/innodb_plugin/srv/srv0srv.c
1099 @@ -86,11 +86,6 @@
1100@@ -1048,7 +1060,15 @@
1101
1102 --- a/storage/innodb_plugin/srv/srv0start.c
1103 +++ b/storage/innodb_plugin/srv/srv0start.c
1104-@@ -95,6 +95,8 @@
1105+@@ -62,6 +62,7 @@
1106+ #include "ibuf0ibuf.h"
1107+ #include "srv0start.h"
1108+ #include "srv0srv.h"
1109++#include "xb0xb.h"
1110+ #ifndef UNIV_HOTBACKUP
1111+ # include "os0proc.h"
1112+ # include "sync0sync.h"
1113+@@ -95,6 +96,8 @@
1114 /** Log sequence number at shutdown */
1115 UNIV_INTERN ib_uint64_t srv_shutdown_lsn;
1116
1117@@ -1057,7 +1077,7 @@
1118 #ifdef HAVE_DARWIN_THREADS
1119 # include <sys/utsname.h>
1120 /** TRUE if the F_FULLFSYNC option is available */
1121-@@ -545,7 +547,7 @@
1122+@@ -545,7 +548,7 @@
1123 /*********************************************************************//**
1124 Creates or opens the log files and closes them.
1125 @return DB_SUCCESS or error code */
1126@@ -1066,7 +1086,7 @@
1127 ulint
1128 open_or_create_log_file(
1129 /*====================*/
1130-@@ -703,7 +705,7 @@
1131+@@ -703,7 +706,7 @@
1132 /*********************************************************************//**
1133 Creates or opens database data files and closes them.
1134 @return DB_SUCCESS or error code */
1135@@ -1075,7 +1095,7 @@
1136 ulint
1137 open_or_create_data_files(
1138 /*======================*/
1139-@@ -1782,6 +1784,10 @@
1140+@@ -1782,6 +1785,10 @@
1141 are initialized in trx_sys_init_at_db_start(). */
1142
1143 recv_recovery_from_checkpoint_finish();
1144@@ -1086,7 +1106,7 @@
1145 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
1146 /* The following call is necessary for the insert
1147 buffer to work with multiple tablespaces. We must
1148-@@ -1962,7 +1968,18 @@
1149+@@ -1962,7 +1969,18 @@
1150
1151 if (srv_auto_extend_last_data_file
1152 && sum_of_data_file_sizes < tablespace_size_in_header) {
1153@@ -1105,7 +1125,7 @@
1154 fprintf(stderr,
1155 "InnoDB: Error: tablespace size stored in header"
1156 " is %lu pages, but\n"
1157-@@ -1987,6 +2004,7 @@
1158+@@ -1987,6 +2005,7 @@
1159
1160 return(DB_ERROR);
1161 }
1162@@ -1113,7 +1133,18 @@
1163 }
1164
1165 /* Check that os_fast_mutexes work as expected */
1166-@@ -2089,6 +2107,7 @@
1167+@@ -2008,6 +2027,10 @@
1168+
1169+ os_fast_mutex_free(&srv_os_test_mutex);
1170+
1171++ if (srv_rebuild_indexes) {
1172++ xb_compact_rebuild_indexes();
1173++ }
1174++
1175+ if (!srv_file_per_table_original_value
1176+ && srv_pass_corrupt_table) {
1177+ fprintf(stderr, "InnoDB: Warning:"
1178+@@ -2089,6 +2112,7 @@
1179 ibuf_update_max_tablespace_id();
1180 }
1181
1182@@ -1334,3 +1365,38 @@
1183
1184 /* Write the log but do not flush it to disk */
1185
1186+--- a/storage/innodb_plugin/sync/sync0arr.c
1187++++ b/storage/innodb_plugin/sync/sync0arr.c
1188+@@ -40,6 +40,7 @@
1189+ #include "os0sync.h"
1190+ #include "os0file.h"
1191+ #include "srv0srv.h"
1192++#include "xb0xb.h"
1193+
1194+ /*
1195+ WAIT ARRAY
1196+@@ -926,6 +927,13 @@
1197+ ibool fatal = FALSE;
1198+ double longest_diff = 0;
1199+
1200++ if (srv_rebuild_indexes) {
1201++
1202++ /* Avoid long semaphore warnings when rebuilding indexes */
1203++
1204++ return(FALSE);
1205++ }
1206++
1207+ for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
1208+
1209+ double diff;
1210+--- a/storage/innodb_plugin/include/buf0buf.h
1211++++ b/storage/innodb_plugin/include/buf0buf.h
1212+@@ -1211,6 +1211,8 @@
1213+ frees a page in buffer pool */
1214+ # endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1215+ #endif /* !UNIV_HOTBACKUP */
1216++ ibool is_compacted; /*!< TRUE if the page was skipped in
1217++ compact backups */
1218+ };
1219+
1220+ /** The buffer control block structure */
1221
1222=== modified file 'patches/xtradb55.patch'
1223--- patches/xtradb55.patch 2012-02-22 16:37:18 +0000
1224+++ patches/xtradb55.patch 2013-01-14 11:06:22 +0000
1225@@ -20,7 +20,15 @@
1226 /*===================*/
1227 --- a/storage/innobase/buf/buf0buf.c
1228 +++ b/storage/innobase/buf/buf0buf.c
1229-@@ -581,7 +581,7 @@
1230+@@ -53,6 +53,7 @@
1231+ #include "page0zip.h"
1232+ #include "trx0trx.h"
1233+ #include "srv0start.h"
1234++#include "xb0xb.h"
1235+
1236+ /* prototypes for new functions added to ha_innodb.cc */
1237+ trx_t* innobase_get_trx();
1238+@@ -581,7 +582,7 @@
1239 return(TRUE);
1240 }
1241
1242@@ -29,7 +37,15 @@
1243 if (recv_lsn_checks_on) {
1244 ib_uint64_t current_lsn;
1245
1246-@@ -2542,7 +2542,8 @@
1247+@@ -965,6 +966,7 @@
1248+ block->page.zip_list.prev = NULL;
1249+ block->page.zip_list.next = NULL;
1250+ block->page.in_LRU_list = FALSE;
1251++ block->page.is_compacted = FALSE;
1252+ block->in_unzip_LRU_list = FALSE;
1253+ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
1254+ block->n_pointers = 0;
1255+@@ -2542,7 +2544,8 @@
1256 ut_ad(zip_size == fil_space_get_zip_size(space));
1257 ut_ad(ut_is_2pow(zip_size));
1258 #ifndef UNIV_LOG_DEBUG
1259@@ -39,12 +55,27 @@
1260 || ibuf_page_low(space, zip_size, offset,
1261 FALSE, file, line, NULL));
1262 #endif
1263-@@ -4064,7 +4065,7 @@
1264+@@ -3952,6 +3955,13 @@
1265+ frame = ((buf_block_t*) bpage)->frame;
1266+ }
1267+
1268++ /* Do not validate, recover and apply change buffer entries to
1269++ bogus pages which replace skipped pages in compact backups. */
1270++ if (srv_compact_backup && buf_page_is_compacted(frame)) {
1271++
1272++ bpage->is_compacted = TRUE;
1273++ }
1274++
1275+ /* If this page is not uninitialized and not in the
1276+ doublewrite buffer, then the page number and space id
1277+ should be the same as in block. */
1278+@@ -4064,7 +4074,8 @@
1279 recv_recover_page(TRUE, (buf_block_t*) bpage);
1280 }
1281
1282 - if (uncompressed && !recv_no_ibuf_operations) {
1283-+ if (uncompressed && !recv_no_ibuf_operations && !srv_fake_write) {
1284++ if (uncompressed && !recv_no_ibuf_operations &&
1285++ !srv_fake_write && !bpage->is_compacted) {
1286 ibuf_merge_or_delete_for_page(
1287 /* Delete possible entries, if bpage is_corrupt */
1288 (srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
1289@@ -687,7 +718,7 @@
1290 server_busy = log_sys->n_pending_checkpoint_writes
1291 --- a/storage/innobase/log/log0recv.c
1292 +++ b/storage/innobase/log/log0recv.c
1293-@@ -42,27 +42,27 @@
1294+@@ -42,27 +42,28 @@
1295 #include "trx0undo.h"
1296 #include "trx0rec.h"
1297 #include "fil0fil.h"
1298@@ -701,6 +732,7 @@
1299 # include "sync0sync.h"
1300 -#else /* !UNIV_HOTBACKUP */
1301 +//#else /* !UNIV_HOTBACKUP */
1302++#include "xb0xb.h"
1303
1304 /** This is set to FALSE if the backup was originally taken with the
1305 ibbackup --include regexp option: then we do not want to create tables in
1306@@ -719,7 +751,7 @@
1307
1308 /** The recovery system */
1309 UNIV_INTERN recv_sys_t* recv_sys = NULL;
1310-@@ -631,7 +631,7 @@
1311+@@ -631,7 +632,7 @@
1312 /***********************************************************************//**
1313 Checks the consistency of the checkpoint info
1314 @return TRUE if ok */
1315@@ -728,7 +760,7 @@
1316 ibool
1317 recv_check_cp_is_consistent(
1318 /*========================*/
1319-@@ -661,7 +661,7 @@
1320+@@ -661,7 +662,7 @@
1321 /********************************************************//**
1322 Looks for the maximum consistent checkpoint from the log groups.
1323 @return error code or DB_SUCCESS */
1324@@ -737,7 +769,7 @@
1325 ulint
1326 recv_find_max_checkpoint(
1327 /*=====================*/
1328-@@ -850,7 +850,7 @@
1329+@@ -850,7 +851,7 @@
1330 InnoDB-3.23.52 where the checksum field contains the log block number.
1331 @return TRUE if ok, or if the log block may be in the format of InnoDB
1332 version predating 3.23.52 */
1333@@ -746,7 +778,25 @@
1334 ibool
1335 log_block_checksum_is_ok_or_old_format(
1336 /*===================================*/
1337-@@ -2380,7 +2380,7 @@
1338+@@ -1639,9 +1640,16 @@
1339+ if (page_zip) {
1340+ memset(FIL_PAGE_LSN + page_zip->data, 0, 8);
1341+ }
1342++
1343++ if (block->page.is_compacted) {
1344++
1345++ ut_ad(srv_compact_backup);
1346++
1347++ block->page.is_compacted = FALSE;
1348++ }
1349+ }
1350+
1351+- if (recv->start_lsn >= page_lsn) {
1352++ if (!block->page.is_compacted && recv->start_lsn >= page_lsn) {
1353+
1354+ ib_uint64_t end_lsn;
1355+
1356+@@ -2380,7 +2388,7 @@
1357 || type == MLOG_FILE_RENAME
1358 || type == MLOG_FILE_DELETE) {
1359 ut_a(space);
1360@@ -755,7 +805,7 @@
1361 if (recv_replay_file_ops) {
1362
1363 /* In ibbackup --apply-log, replay an .ibd file
1364-@@ -2403,7 +2403,7 @@
1365+@@ -2403,7 +2411,7 @@
1366 ut_error;
1367 }
1368 }
1369@@ -764,7 +814,7 @@
1370 /* In normal mysqld crash recovery we do not try to
1371 replay file operations */
1372 #ifdef UNIV_LOG_LSN_DEBUG
1373-@@ -2820,8 +2820,11 @@
1374+@@ -2820,8 +2828,11 @@
1375
1376 fprintf(stderr,
1377 "InnoDB: Doing recovery: scanned up to"
1378@@ -778,7 +828,7 @@
1379 }
1380 }
1381
1382-@@ -2935,12 +2938,14 @@
1383+@@ -2935,12 +2946,14 @@
1384
1385 if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
1386
1387@@ -794,7 +844,7 @@
1388 }
1389 }
1390
1391-@@ -3109,6 +3114,7 @@
1392+@@ -3109,6 +3122,7 @@
1393 recv_sys->recovered_lsn = checkpoint_lsn;
1394
1395 srv_start_lsn = checkpoint_lsn;
1396@@ -802,7 +852,7 @@
1397 }
1398
1399 contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
1400-@@ -3474,6 +3480,7 @@
1401+@@ -3474,6 +3488,7 @@
1402 that the data dictionary tables will be free of any locks.
1403 The data dictionary latch should guarantee that there is at
1404 most one data dictionary transaction active at a time. */
1405@@ -902,44 +952,6 @@
1406 +*/
1407 #endif
1408 }
1409---- a/storage/innobase/row/row0merge.c
1410-+++ b/storage/innobase/row/row0merge.c
1411-@@ -460,7 +460,9 @@
1412- rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext);
1413- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
1414-
1415-- innobase_rec_to_mysql(dup->table, rec, index, offsets);
1416-+ //innobase_rec_to_mysql(dup->table, rec, index, offsets);
1417-+ fprintf(stderr, "InnoDB: Error: row_merge_dup_report() is called.\n");
1418-+ ut_error;
1419-
1420- mem_heap_free(heap);
1421- }
1422-@@ -1486,8 +1488,11 @@
1423- case 0:
1424- if (UNIV_UNLIKELY
1425- (dict_index_is_unique(index) && !null_eq)) {
1426-- innobase_rec_to_mysql(table, mrec0,
1427-- index, offsets0);
1428-+ //innobase_rec_to_mysql(table, mrec0,
1429-+ // index, offsets0);
1430-+ (void) table;
1431-+ fprintf(stderr, "InnoDB: Error: row_merge_blocks() is called.\n");
1432-+ ut_error;
1433- mem_heap_free(heap);
1434- return(DB_DUPLICATE_KEY);
1435- }
1436-@@ -2636,7 +2641,9 @@
1437-
1438- /* Reset the MySQL row buffer that is used when reporting
1439- duplicate keys. */
1440-- innobase_rec_reset(table);
1441-+ //innobase_rec_reset(table);
1442-+ fprintf(stderr, "InnoDB: Error: row_merge_build_indexes() is called.\n");
1443-+ ut_error;
1444-
1445- /* Read clustered index of the table and create files for
1446- secondary index entries for merge sort */
1447 --- a/storage/innobase/srv/srv0srv.c
1448 +++ b/storage/innobase/srv/srv0srv.c
1449 @@ -87,11 +87,6 @@
1450@@ -1048,7 +1060,15 @@
1451
1452 --- a/storage/innobase/srv/srv0start.c
1453 +++ b/storage/innobase/srv/srv0start.c
1454-@@ -94,6 +94,8 @@
1455+@@ -62,6 +62,7 @@
1456+ #include "ibuf0ibuf.h"
1457+ #include "srv0start.h"
1458+ #include "srv0srv.h"
1459++#include "xb0xb.h"
1460+ #ifndef UNIV_HOTBACKUP
1461+ # include "os0proc.h"
1462+ # include "sync0sync.h"
1463+@@ -94,6 +95,8 @@
1464 /** Log sequence number at shutdown */
1465 UNIV_INTERN ib_uint64_t srv_shutdown_lsn;
1466
1467@@ -1057,7 +1077,7 @@
1468 #ifdef HAVE_DARWIN_THREADS
1469 # include <sys/utsname.h>
1470 /** TRUE if the F_FULLFSYNC option is available */
1471-@@ -549,7 +551,7 @@
1472+@@ -549,7 +552,7 @@
1473 /*********************************************************************//**
1474 Creates or opens the log files and closes them.
1475 @return DB_SUCCESS or error code */
1476@@ -1066,7 +1086,7 @@
1477 ulint
1478 open_or_create_log_file(
1479 /*====================*/
1480-@@ -709,7 +711,7 @@
1481+@@ -709,7 +712,7 @@
1482 /*********************************************************************//**
1483 Creates or opens database data files and closes them.
1484 @return DB_SUCCESS or error code */
1485@@ -1075,7 +1095,7 @@
1486 ulint
1487 open_or_create_data_files(
1488 /*======================*/
1489-@@ -1875,6 +1877,10 @@
1490+@@ -1875,6 +1878,10 @@
1491 are initialized in trx_sys_init_at_db_start(). */
1492
1493 recv_recovery_from_checkpoint_finish();
1494@@ -1086,7 +1106,7 @@
1495 if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
1496 /* The following call is necessary for the insert
1497 buffer to work with multiple tablespaces. We must
1498-@@ -2054,6 +2060,17 @@
1499+@@ -2054,6 +2061,17 @@
1500 if (!srv_auto_extend_last_data_file
1501 && sum_of_data_file_sizes != tablespace_size_in_header) {
1502
1503@@ -1104,7 +1124,7 @@
1504 ut_print_timestamp(stderr);
1505 fprintf(stderr,
1506 " InnoDB: Error: tablespace size"
1507-@@ -2133,6 +2150,7 @@
1508+@@ -2133,6 +2151,7 @@
1509
1510 return(DB_ERROR);
1511 }
1512@@ -1112,7 +1132,18 @@
1513 }
1514
1515 /* Check that os_fast_mutexes work as expected */
1516-@@ -2252,6 +2270,7 @@
1517+@@ -2157,6 +2176,10 @@
1518+
1519+ os_fast_mutex_free(&srv_os_test_mutex);
1520+
1521++ if (srv_rebuild_indexes) {
1522++ xb_compact_rebuild_indexes();
1523++ }
1524++
1525+ if (!srv_file_per_table_original_value
1526+ && srv_pass_corrupt_table) {
1527+ fprintf(stderr, "InnoDB: Warning:"
1528+@@ -2252,6 +2275,7 @@
1529 ibuf_update_max_tablespace_id();
1530 }
1531
1532@@ -1315,3 +1346,51 @@
1533
1534 /* Write the log but do not flush it to disk */
1535
1536+--- a/configure.cmake
1537++++ b/configure.cmake
1538+@@ -149,7 +149,9 @@
1539+ SET(CMAKE_REQUIRED_LIBRARIES
1540+ ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT})
1541+
1542+- LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
1543++ IF(CMAKE_REQUIRED_LIBRARIES)
1544++ LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
1545++ ENDIF()
1546+ LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT})
1547+
1548+ OPTION(WITH_LIBWRAP "Compile with tcp wrappers support" OFF)
1549+--- a/storage/innobase/sync/sync0arr.c
1550++++ b/storage/innobase/sync/sync0arr.c
1551+@@ -41,6 +41,7 @@
1552+ #include "os0file.h"
1553+ #include "srv0srv.h"
1554+ #include "ha_prototypes.h"
1555++#include "xb0xb.h"
1556+
1557+ /*
1558+ WAIT ARRAY
1559+@@ -926,6 +927,13 @@
1560+ ibool fatal = FALSE;
1561+ double longest_diff = 0;
1562+
1563++ if (srv_rebuild_indexes) {
1564++
1565++ /* Avoid long semaphore warnings when rebuilding indexes */
1566++
1567++ return(FALSE);
1568++ }
1569++
1570+ #ifdef UNIV_DEBUG_VALGRIND
1571+ /* Increase the timeouts if running under valgrind because it executes
1572+ extremely slowly. UNIV_DEBUG_VALGRIND does not necessary mean that
1573+--- a/storage/innobase/include/buf0buf.h
1574++++ b/storage/innobase/include/buf0buf.h
1575+@@ -1509,6 +1509,8 @@
1576+ frees a page in buffer pool */
1577+ # endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1578+ #endif /* !UNIV_HOTBACKUP */
1579++ ibool is_compacted; /*!< TRUE if the page was skipped in
1580++ compact backups */
1581+ };
1582+
1583+ /** The buffer control block structure */
1584
1585=== modified file 'src/Makefile'
1586--- src/Makefile 2013-01-07 06:19:24 +0000
1587+++ src/Makefile 2013-01-14 11:06:22 +0000
1588@@ -31,6 +31,7 @@
1589 ds_buffer.o \
1590 datasink.o \
1591 write_filt.o \
1592+ compact.o \
1593 fil_cur.o \
1594 innodb_int.o \
1595 xbstream_write.o \
1596@@ -92,7 +93,7 @@
1597
1598 # XtraBackup for MySQL 5.5
1599 5.5: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \
1600- include storage/innobase/include)
1601+ include storage/innobase/include sql)
1602 5.5: INNODBOBJS = $(MYSQL_ROOT_DIR)/storage/innobase/libinnobase.a
1603
1604 ifeq "$(wildcard $(MYSQL_ROOT_DIR)/zlib/.libs/libzlt.a)" ""
1605@@ -157,7 +158,7 @@
1606
1607 # XtraBackup for XtraDB 5.5
1608 xtradb55: INC = $(COMMON_INC) $(addprefix -isystem$(MYSQL_ROOT_DIR)/, \
1609- include storage/innobase/include)
1610+ include storage/innobase/include sql)
1611 xtradb55: INNODBOBJS = $(MYSQL_ROOT_DIR)/storage/innobase/libinnobase.a
1612 ifeq ($(shell uname -s),Linux)
1613 xtradb55: LIBS += -laio
1614@@ -189,7 +190,7 @@
1615 xbstream: $(XBSTREAMOBJS) $(MYSQLOBJS) ds_local.o ds_buffer.o datasink.o
1616 $(CC) $(CFLAGS) $^ $(INC) $(MYSQLOBJS) $(LIBS) -o $@
1617
1618-xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h
1619+xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h compact.h
1620
1621 $(TARGET): $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A)
1622 $(CC) $(CFLAGS) $(XTRABACKUPOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \
1623
1624=== added file 'src/compact.c'
1625--- src/compact.c 1970-01-01 00:00:00 +0000
1626+++ src/compact.c 2013-01-14 11:06:22 +0000
1627@@ -0,0 +1,960 @@
1628+/******************************************************
1629+XtraBackup: hot backup tool for InnoDB
1630+(c) 2009-2013 Percona Ireland Ltd.
1631+Originally Created 3/3/2009 Yasufumi Kinoshita
1632+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
1633+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
1634+
1635+This program is free software; you can redistribute it and/or modify
1636+it under the terms of the GNU General Public License as published by
1637+the Free Software Foundation; version 2 of the License.
1638+
1639+This program is distributed in the hope that it will be useful,
1640+but WITHOUT ANY WARRANTY; without even the implied warranty of
1641+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1642+GNU General Public License for more details.
1643+
1644+You should have received a copy of the GNU General Public License
1645+along with this program; if not, write to the Free Software
1646+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1647+
1648+*******************************************************/
1649+
1650+/* Compact backups implementation */
1651+
1652+#include <my_base.h>
1653+#include <page0page.h>
1654+#include <dict0dict.h>
1655+#include <dict0load.h>
1656+#include <btr0pcur.h>
1657+#include <ibuf0ibuf.h>
1658+#include <row0merge.h>
1659+#include <trx0trx.h>
1660+#include <srv0srv.h>
1661+#include "common.h"
1662+#include "write_filt.h"
1663+#include "fil_cur.h"
1664+#include "xtrabackup.h"
1665+#include "ds_buffer.h"
1666+#include "xb0xb.h"
1667+
1668+/* Number of the first primary key page in an .ibd file */
1669+#define XB_FIRST_CLUSTERED_INDEX_PAGE_NO 3
1670+
1671+/* Suffix for page map files */
1672+#define XB_PAGE_MAP_SUFFIX ".pmap"
1673+#define XB_TMPFILE_SUFFIX ".tmp"
1674+
1675+/* Page range */
1676+typedef struct {
1677+ ulint from; /*!< range start */
1678+ ulint to; /*!< range end */
1679+} page_range_t;
1680+
1681+/* Cursor in a page map file */
1682+typedef struct {
1683+ File fd; /*!< file descriptor */
1684+ IO_CACHE cache; /*!< IO_CACHE associated with fd */
1685+} page_map_cursor_t;
1686+
1687+/* Empty page use to replace skipped pages in the data files */
1688+static byte empty_page[UNIV_PAGE_SIZE_MAX];
1689+static const char compacted_page_magic[] = "COMPACTP";
1690+static const size_t compacted_page_magic_size =
1691+ sizeof(compacted_page_magic) - 1;
1692+static const ulint compacted_page_magic_offset = FIL_PAGE_DATA;
1693+
1694+/************************************************************************
1695+Compact page filter. */
1696+static my_bool wf_compact_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
1697+ xb_fil_cur_t *cursor);
1698+static my_bool wf_compact_process(xb_write_filt_ctxt_t *ctxt,
1699+ ds_file_t *dstfile);
1700+static my_bool wf_compact_finalize(xb_write_filt_ctxt_t *ctxt,
1701+ ds_file_t *dstfile);
1702+xb_write_filt_t wf_compact = {
1703+ &wf_compact_init,
1704+ &wf_compact_process,
1705+ &wf_compact_finalize,
1706+ NULL
1707+};
1708+
1709+/************************************************************************
1710+Initialize the compact page filter.
1711+
1712+@return TRUE on success, FALSE on error. */
1713+static my_bool
1714+wf_compact_init(xb_write_filt_ctxt_t *ctxt,
1715+ char *dst_name __attribute__((unused)), xb_fil_cur_t *cursor)
1716+{
1717+ xb_wf_compact_ctxt_t *cp = &(ctxt->u.wf_compact_ctxt);
1718+ char page_map_name[FN_REFLEN];
1719+ MY_STAT mystat;
1720+
1721+ ctxt->cursor = cursor;
1722+ cp->clustered_index_found = FALSE;
1723+ cp->inside_skipped_range = FALSE;
1724+ cp->free_limit = 0;
1725+
1726+ /* Don't compact the system table space */
1727+ cp->skip = cursor->is_system;
1728+ if (cp->skip) {
1729+ return(TRUE);
1730+ }
1731+
1732+ snprintf(page_map_name, sizeof(page_map_name), "%s%s", dst_name,
1733+ XB_PAGE_MAP_SUFFIX);
1734+
1735+ cp->ds_buffer = ds_create(xtrabackup_target_dir, DS_TYPE_BUFFER);
1736+ if (cp->ds_buffer == NULL) {
1737+ return(FALSE);
1738+ }
1739+
1740+ ds_set_pipe(cp->ds_buffer, ds_meta);
1741+
1742+ memset(&mystat, 0, sizeof(mystat));
1743+ mystat.st_mtime = my_time(0);
1744+ cp->buffer = ds_open(cp->ds_buffer, page_map_name, &mystat);
1745+ if (cp->buffer == NULL) {
1746+ msg("xtrabackup: Error: cannot open output stream for %s\n",
1747+ page_map_name);
1748+ return(FALSE);
1749+ }
1750+
1751+ return(TRUE);
1752+}
1753+
1754+/************************************************************************
1755+Check if the specified page should be skipped. We currently skip all
1756+non-clustered index pages for compact backups.
1757+
1758+@return TRUE if the page should be skipped. */
1759+static my_bool
1760+check_if_skip_page(xb_wf_compact_ctxt_t *cp, xb_fil_cur_t *cursor, ulint offset)
1761+{
1762+ byte *page;
1763+ ulint page_no;
1764+ ulint page_type;
1765+ INDEX_ID_T index_id;
1766+
1767+
1768+ xb_ad(cursor->is_system == FALSE);
1769+
1770+ page = cursor->buf + cursor->page_size * offset;
1771+ page_no = cursor->buf_page_no + offset;
1772+ page_type = fil_page_get_type(page);
1773+
1774+ if (UNIV_UNLIKELY(page_no == 0)) {
1775+
1776+ cp->free_limit = mach_read_from_4(page + FSP_HEADER_OFFSET +
1777+ FSP_FREE_LIMIT);
1778+ } else if (UNIV_UNLIKELY(page_no == XB_FIRST_CLUSTERED_INDEX_PAGE_NO)) {
1779+
1780+ xb_ad(cp->clustered_index_found == FALSE);
1781+
1782+ if (page_type != FIL_PAGE_INDEX) {
1783+
1784+ /* Uninitialized clustered index root page, there's
1785+ nothing we can do to compact the space.*/
1786+
1787+ msg("[%02u] Uninitialized page type value (%lu) in the "
1788+ "clustered index root page of tablespace %s. "
1789+ "Will not be compacted.\n",
1790+ cursor->thread_n,
1791+ page_type, cursor->path);
1792+
1793+ cp->skip = TRUE;
1794+
1795+ return(FALSE);
1796+ }
1797+
1798+ cp->clustered_index =
1799+ mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID);
1800+ cp->clustered_index_found = TRUE;
1801+ } else if (UNIV_UNLIKELY(page_no >= cp->free_limit)) {
1802+
1803+ /* Skip unused pages above free limit, if that value is set in
1804+ the FSP header.*/
1805+
1806+ return(cp->free_limit > 0);
1807+ } else if (cp->clustered_index_found && page_type == FIL_PAGE_INDEX) {
1808+
1809+ index_id = mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID);
1810+ if (INDEX_ID_CMP(index_id, cp->clustered_index) != 0) {
1811+ ulint fseg_hdr_space =
1812+ mach_read_from_4(page + PAGE_HEADER +
1813+ PAGE_BTR_SEG_TOP);
1814+ ulint fseg_hdr_page_no =
1815+ mach_read_from_4(page + PAGE_HEADER +
1816+ PAGE_BTR_SEG_TOP + 4);
1817+ ulint fseg_hdr_offset =
1818+ mach_read_from_2(page + PAGE_HEADER +
1819+ PAGE_BTR_SEG_TOP + 8);
1820+
1821+ /* Don't skip root index pages, i.e. the ones where the
1822+ above fields are defined. We need root index pages to be
1823+ able to correctly drop the indexes later, as they
1824+ contain fseg inode pointers. */
1825+
1826+ return(fseg_hdr_space == 0 &&
1827+ fseg_hdr_page_no == 0 &&
1828+ fseg_hdr_offset == 0);
1829+ }
1830+ }
1831+
1832+ return(FALSE);
1833+}
1834+
1835+/************************************************************************
1836+Run the next batch of pages through the compact page filter.
1837+
1838+@return TRUE on success, FALSE on error. */
1839+static my_bool
1840+wf_compact_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
1841+{
1842+ xb_fil_cur_t *cursor = ctxt->cursor;
1843+ ulint page_size = cursor->page_size;
1844+ byte *page;
1845+ byte *buf_end;
1846+ byte *write_from;
1847+ xb_wf_compact_ctxt_t *cp = &(ctxt->u.wf_compact_ctxt);
1848+ ulint i;
1849+ ulint page_no;
1850+ byte tmp[4];
1851+
1852+ if (cp->skip) {
1853+ return(!ds_write(dstfile, cursor->buf, cursor->buf_read));
1854+ }
1855+
1856+ write_from = NULL;
1857+ buf_end = cursor->buf + cursor->buf_read;
1858+ for (i = 0, page = cursor->buf; page < buf_end;
1859+ i++, page += page_size) {
1860+
1861+ page_no = cursor->buf_page_no + i;
1862+
1863+ if (!check_if_skip_page(cp, cursor, i)) {
1864+
1865+ if (write_from == NULL) {
1866+ write_from = page;
1867+ }
1868+
1869+ if (cp->inside_skipped_range) {
1870+ cp->inside_skipped_range = FALSE;
1871+
1872+ /* Write the last range endpoint to the
1873+ skipped pages map */
1874+
1875+ xb_ad(page_no > 0);
1876+ mach_write_to_4(tmp, page_no - 1);
1877+ if (ds_write(cp->buffer, tmp, sizeof(tmp))) {
1878+ return(FALSE);
1879+ }
1880+ }
1881+ continue;
1882+ }
1883+
1884+ if (write_from != NULL) {
1885+
1886+ /* The first skipped page in this block, write the
1887+ non-skipped ones to the data file */
1888+
1889+ if (ds_write(dstfile, write_from, page - write_from)) {
1890+ return(FALSE);
1891+ }
1892+
1893+ write_from = NULL;
1894+ }
1895+
1896+ if (!cp->inside_skipped_range) {
1897+
1898+ /* The first skipped page in range, write the first
1899+ range endpoint to the skipped pages map */
1900+
1901+ cp->inside_skipped_range = TRUE;
1902+
1903+ mach_write_to_4(tmp, page_no);
1904+ if (ds_write(cp->buffer, tmp, sizeof(tmp))) {
1905+ return(FALSE);
1906+ }
1907+ }
1908+ }
1909+
1910+ /* Write the remaining pages in the buffer, if any */
1911+ if (write_from != NULL &&
1912+ ds_write(dstfile, write_from, buf_end - write_from)) {
1913+ return(FALSE);
1914+ }
1915+
1916+ return(TRUE);
1917+}
1918+
1919+/************************************************************************
1920+Close the compact filter's page map stream.
1921+
1922+@return TRUE on success, FALSE on error. */
1923+static my_bool
1924+wf_compact_finalize(xb_write_filt_ctxt_t *ctxt,
1925+ ds_file_t *dstfile __attribute__((unused)))
1926+{
1927+ xb_fil_cur_t *cursor = ctxt->cursor;
1928+ xb_wf_compact_ctxt_t *cp = &(ctxt->u.wf_compact_ctxt);
1929+
1930+ /* Write the last endpoint of the current range, if the last pages of
1931+ the space have been skipped. */
1932+ if (cp->inside_skipped_range) {
1933+ byte tmp[4];
1934+
1935+ mach_write_to_4(tmp, cursor->space_size - 1);
1936+ if (ds_write(cp->buffer, tmp, sizeof(tmp))) {
1937+ return(FALSE);
1938+ }
1939+
1940+ cp->inside_skipped_range = FALSE;
1941+ }
1942+
1943+ if (cp->buffer) {
1944+ ds_close(cp->buffer);
1945+ }
1946+ if (cp->ds_buffer) {
1947+ ds_destroy(cp->ds_buffer);
1948+ }
1949+
1950+ return(TRUE);
1951+}
1952+
1953+/************************************************************************
1954+Open a page map file and return a cursor.
1955+
1956+@return page map cursor, or NULL if the file doesn't exist. */
1957+static page_map_cursor_t *
1958+page_map_file_open(const char *path)
1959+{
1960+ MY_STAT statinfo;
1961+ page_map_cursor_t *pmap_cur;
1962+ int rc;
1963+
1964+ if (my_stat(path, &statinfo, MYF(0)) == NULL) {
1965+
1966+ return(NULL);
1967+ }
1968+
1969+ /* The maximum possible page map file corresponds to a 64 TB tablespace
1970+ and the worst case when every other page was skipped. That is, 2^32/2
1971+ page ranges = 16 GB. */
1972+ xb_a(statinfo.st_size < (off_t) 16 * 1024 * 1024 * 1024);
1973+
1974+ /* Must be a series of 8-byte tuples */
1975+ xb_a(statinfo.st_size % 8 == 0);
1976+
1977+ pmap_cur = (page_map_cursor_t *) my_malloc(sizeof(page_map_cursor_t),
1978+ MYF(MY_FAE));
1979+
1980+ pmap_cur->fd = my_open(path, O_RDONLY, MYF(MY_WME));
1981+ xb_a(pmap_cur->fd != 0);
1982+
1983+ rc = init_io_cache(&pmap_cur->cache, pmap_cur->fd, 0, READ_CACHE,
1984+ 0, 0, MYF(MY_WME));
1985+ xb_a(rc == 0);
1986+
1987+ return(pmap_cur);
1988+}
1989+
1990+/************************************************************************
1991+Read the next range from a page map file and update the cursor.
1992+
1993+@return TRUE on success, FALSE on end-of-file. */
1994+static ibool
1995+page_map_file_next(page_map_cursor_t *pmap_cur, page_range_t *range)
1996+{
1997+ byte buf[8];
1998+
1999+ xb_ad(pmap_cur != NULL);
2000+
2001+ if (my_b_read(&pmap_cur->cache, buf, sizeof(buf))) {
2002+ return(FALSE);
2003+ }
2004+
2005+ range->from = mach_read_from_4(buf);
2006+ range->to = mach_read_from_4(buf + 4);
2007+
2008+ return(TRUE);
2009+}
2010+
2011+/************************************************************************
2012+Close the page map cursor.*/
2013+static void
2014+page_map_file_close(page_map_cursor_t *pmap_cur)
2015+{
2016+ int rc;
2017+
2018+ xb_ad(pmap_cur != NULL);
2019+
2020+ rc = end_io_cache(&pmap_cur->cache);
2021+ xb_a(rc == 0);
2022+
2023+ posix_fadvise(pmap_cur->fd, 0, 0, POSIX_FADV_DONTNEED);
2024+
2025+ rc = my_close(pmap_cur->fd, MY_WME);
2026+ xb_a(rc == 0);
2027+}
2028+
2029+/****************************************************************************
2030+Expand a single data file according to the skipped pages maps created by
2031+--compact.
2032+
2033+@return TRUE on success, FALSE on failure. */
2034+static my_bool
2035+xb_expand_file(fil_node_t *node)
2036+{
2037+ char pmapfile_path[FN_REFLEN];
2038+ char tmpfile_path[FN_REFLEN];
2039+ xb_fil_cur_t cursor;
2040+ xb_fil_cur_result_t res;
2041+ ds_ctxt_t *ds_local;
2042+ ds_ctxt_t *ds_buffer;
2043+ ds_file_t *tmpfile;
2044+ my_bool success = FALSE;
2045+ ulint i;
2046+ byte *page;
2047+ ulint page_expected_no;
2048+ page_map_cursor_t *pmap_cur;
2049+ ibool have_next_range;
2050+ page_range_t pmap_range;
2051+
2052+ xb_ad(trx_sys_sys_space(node->space->id) == FALSE);
2053+
2054+ snprintf(pmapfile_path, sizeof(pmapfile_path), "%s%s",
2055+ node->name, XB_PAGE_MAP_SUFFIX);
2056+
2057+ /* Skip files that don't have a corresponding page map file */
2058+
2059+ if (!(pmap_cur = page_map_file_open(pmapfile_path))) {
2060+
2061+ msg("Not expanding %s\n", node->name);
2062+
2063+ return(FALSE);
2064+ }
2065+
2066+ msg("Expanding %s\n", node->name);
2067+
2068+ ds_local = ds_create(".", DS_TYPE_LOCAL);
2069+ ds_buffer = ds_create(".", DS_TYPE_BUFFER);
2070+
2071+ xb_a(ds_local != NULL && ds_buffer != NULL);
2072+
2073+ ds_buffer_set_size(ds_buffer, FSP_EXTENT_SIZE * UNIV_PAGE_SIZE_MAX);
2074+
2075+ ds_set_pipe(ds_buffer, ds_local);
2076+
2077+ res = xb_fil_cur_open(&cursor, node, 1);
2078+ xb_a(res == XB_FIL_CUR_SUCCESS);
2079+
2080+ snprintf(tmpfile_path, sizeof(tmpfile_path), "%s%s",
2081+ node->name, XB_TMPFILE_SUFFIX);
2082+
2083+ tmpfile = ds_open(ds_buffer, tmpfile_path, &cursor.statinfo);
2084+ if (tmpfile == NULL) {
2085+
2086+ msg("Could not open temporary file '%s'\n", tmpfile_path);
2087+ goto error;
2088+ }
2089+
2090+ have_next_range = page_map_file_next(pmap_cur, &pmap_range);
2091+
2092+ page_expected_no = 0;
2093+
2094+ /* Initialize and mark the empty page which is used to replace
2095+ skipped pages. */
2096+ memset(empty_page, 0, cursor.page_size);
2097+ memcpy(empty_page + compacted_page_magic_offset,
2098+ compacted_page_magic, compacted_page_magic_size);
2099+ mach_write_to_4(empty_page + FIL_PAGE_SPACE_OR_CHKSUM,
2100+ BUF_NO_CHECKSUM_MAGIC);
2101+ mach_write_to_4(empty_page + cursor.page_size -
2102+ FIL_PAGE_END_LSN_OLD_CHKSUM,
2103+ BUF_NO_CHECKSUM_MAGIC);
2104+
2105+
2106+ /* Main copy loop */
2107+
2108+ while ((res = xb_fil_cur_read(&cursor)) == XB_FIL_CUR_SUCCESS) {
2109+
2110+ for (i = 0, page = cursor.buf; i < cursor.buf_npages;
2111+ i++, page += cursor.page_size) {
2112+
2113+ ulint page_read_no;
2114+
2115+ page_read_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
2116+ xb_a(!page_read_no || page_expected_no <= page_read_no);
2117+
2118+ if (have_next_range &&
2119+ page_expected_no == pmap_range.from) {
2120+
2121+ xb_a(pmap_range.from <= pmap_range.to);
2122+
2123+ /* Write empty pages instead of skipped ones, if
2124+ necessary. */
2125+
2126+ while (page_expected_no <= pmap_range.to) {
2127+
2128+ if (ds_write(tmpfile, empty_page,
2129+ cursor.page_size)) {
2130+
2131+ goto write_error;
2132+ }
2133+
2134+ page_expected_no++;
2135+ }
2136+
2137+ have_next_range =
2138+ page_map_file_next(pmap_cur,
2139+ &pmap_range);
2140+ }
2141+
2142+ /* Write the current page */
2143+
2144+ if (ds_write(tmpfile, page, cursor.page_size)) {
2145+
2146+ goto write_error;
2147+ }
2148+
2149+ page_expected_no++;
2150+ }
2151+ }
2152+
2153+ if (res != XB_FIL_CUR_EOF) {
2154+
2155+ goto error;
2156+ }
2157+
2158+ /* Write empty pages instead of trailing skipped ones, if any */
2159+
2160+ if (have_next_range) {
2161+
2162+ xb_a(page_expected_no == pmap_range.from);
2163+ xb_a(pmap_range.from <= pmap_range.to);
2164+
2165+ while (page_expected_no <= pmap_range.to) {
2166+
2167+ if (ds_write(tmpfile, empty_page,
2168+ cursor.page_size)) {
2169+
2170+ goto write_error;
2171+ }
2172+
2173+ page_expected_no++;
2174+ }
2175+
2176+ xb_a(!page_map_file_next(pmap_cur, &pmap_range));
2177+ }
2178+
2179+ /* Replace the original .ibd file with the expanded file */
2180+ if (my_rename(tmpfile_path, node->name, MYF(MY_WME))) {
2181+
2182+ msg("Failed to rename '%s' to '%s'\n",
2183+ tmpfile_path, node->name);
2184+ goto error;
2185+ }
2186+
2187+ my_delete(pmapfile_path, MYF(MY_WME));
2188+
2189+ ds_close(tmpfile);
2190+ tmpfile = NULL;
2191+
2192+ success = TRUE;
2193+
2194+ goto end;
2195+
2196+write_error:
2197+ msg("Write to '%s' failed\n", tmpfile_path);
2198+
2199+error:
2200+ if (tmpfile != NULL) {
2201+
2202+ ds_close(tmpfile);
2203+ my_delete(tmpfile_path, MYF(MY_WME));
2204+ }
2205+
2206+end:
2207+ ds_destroy(ds_buffer);
2208+ ds_destroy(ds_local);
2209+
2210+ page_map_file_close(pmap_cur);
2211+
2212+ return(success);
2213+}
2214+
2215+/******************************************************************************
2216+Expand the data files according to the skipped pages maps created by --compact.
2217+@return TRUE on success, FALSE on failure. */
2218+my_bool
2219+xb_expand_datafiles(void)
2220+/*=====================*/
2221+{
2222+ ulint nfiles;
2223+ datafiles_iter_t *it = NULL;
2224+ fil_node_t *node;
2225+ fil_space_t *space;
2226+
2227+ msg("Starting to expand compacted .ibd files.\n");
2228+
2229+ /* Initialize the tablespace cache */
2230+ if (xb_data_files_init() != DB_SUCCESS) {
2231+ return(FALSE);
2232+ }
2233+
2234+ nfiles = UT_LIST_GET_LEN(fil_system->space_list);
2235+ xb_a(nfiles > 0);
2236+
2237+ it = datafiles_iter_new(fil_system);
2238+ if (it == NULL) {
2239+ msg("xtrabackup: error: datafiles_iter_new() failed.\n");
2240+ goto error;
2241+ }
2242+
2243+ while ((node = datafiles_iter_next(it)) != NULL) {
2244+
2245+ space = node->space;
2246+
2247+ /* System tablespace cannot be compacted */
2248+ if (trx_sys_sys_space(space->id)) {
2249+
2250+ continue;
2251+ }
2252+
2253+ if (!xb_expand_file(node)) {
2254+
2255+ goto error;
2256+ }
2257+ }
2258+
2259+ datafiles_iter_free(it);
2260+ xb_data_files_close();
2261+
2262+ return(TRUE);
2263+
2264+error:
2265+ if (it != NULL) {
2266+ datafiles_iter_free(it);
2267+ }
2268+
2269+ xb_data_files_close();
2270+
2271+ return(FALSE);
2272+}
2273+
2274+/******************************************************************************
2275+Callback used in buf_page_io_complete() to detect compacted pages.
2276+@return TRUE if the page is marked as compacted, FALSE otherwise. */
2277+ibool
2278+buf_page_is_compacted(
2279+/*==================*/
2280+ const byte* page) /*!< in: a database page */
2281+{
2282+ return !memcmp(page + compacted_page_magic_offset,
2283+ compacted_page_magic, compacted_page_magic_size);
2284+}
2285+
2286+/********************************************************************//**
2287+Determine the flags of a table described in SYS_TABLES.
2288+@return compressed page size in kilobytes; or 0 if the tablespace is
2289+uncompressed, ULINT_UNDEFINED on error */
2290+static
2291+ulint
2292+dict_sys_tables_get_flags(
2293+/*======================*/
2294+ const rec_t* rec) /*!< in: a record of SYS_TABLES */
2295+{
2296+ const byte* field;
2297+ ulint len;
2298+ ulint n_cols;
2299+ ulint flags;
2300+
2301+ field = rec_get_nth_field_old(rec, 5, &len);
2302+ ut_a(len == 4);
2303+
2304+ flags = mach_read_from_4(field);
2305+
2306+ if (UNIV_LIKELY(flags == DICT_TABLE_ORDINARY)) {
2307+ return(0);
2308+ }
2309+
2310+ field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
2311+ n_cols = mach_read_from_4(field);
2312+
2313+ if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) {
2314+ /* New file formats require ROW_FORMAT=COMPACT. */
2315+ return(ULINT_UNDEFINED);
2316+ }
2317+
2318+ switch (flags & (DICT_TF_FORMAT_MASK | DICT_TF_COMPACT)) {
2319+ default:
2320+ case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
2321+ case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
2322+ /* flags should be DICT_TABLE_ORDINARY,
2323+ or DICT_TF_FORMAT_MASK should be nonzero. */
2324+ return(ULINT_UNDEFINED);
2325+
2326+ case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
2327+ /* We support this format. */
2328+ break;
2329+ }
2330+
2331+ if (UNIV_UNLIKELY((flags & DICT_TF_ZSSIZE_MASK)
2332+ > (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT))) {
2333+ /* Unsupported compressed page size. */
2334+ return(ULINT_UNDEFINED);
2335+ }
2336+
2337+ if (UNIV_UNLIKELY(flags & (~0 << DICT_TF_BITS))) {
2338+ /* Some unused bits are set. */
2339+ return(ULINT_UNDEFINED);
2340+ }
2341+
2342+ return(flags);
2343+}
2344+
2345+/*****************************************************************************
2346+Builds an index definition corresponding to an index object. It is roughly
2347+similar to innobase_create_index_def() / innobase_create_index_field_def() and
2348+the opposite to dict_mem_index_create() / dict_mem_index_add_field(). */
2349+static
2350+void
2351+xb_build_index_def(
2352+/*=======================*/
2353+ mem_heap_t* heap, /*!< in: heap */
2354+ const dict_index_t* index, /*!< in: index */
2355+ merge_index_def_t* index_def) /*!< out: index definition */
2356+{
2357+ merge_index_field_t* fields;
2358+ ulint n_fields;
2359+ ulint i;
2360+
2361+ ut_a(index->n_fields);
2362+ ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
2363+
2364+ /* Use n_user_defined_cols instead of n_fields, as the index will
2365+ contain a part of the primary key after n_user_defined_cols, and those
2366+ columns will be created automatically in
2367+ dict_index_build_internal_clust(). */
2368+ n_fields = index->n_user_defined_cols;
2369+
2370+ memset(index_def, 0, sizeof(*index_def));
2371+
2372+ index_def->name = mem_heap_strdup(heap, index->name);
2373+ index_def->ind_type = index->type;
2374+
2375+ fields = mem_heap_alloc(heap, n_fields * sizeof(*fields));
2376+
2377+ for (i = 0; i < n_fields; i++) {
2378+ dict_field_t* field;
2379+
2380+ field = dict_index_get_nth_field(index, i);
2381+
2382+ fields[i].field_name = mem_heap_strdup(heap, field->name);
2383+ fields[i].prefix_len = field->prefix_len;
2384+ }
2385+
2386+ index_def->fields = fields;
2387+ index_def->n_fields = n_fields;
2388+}
2389+
2390+/********************************************************************//**
2391+Rebuild secondary indexes for a given table. */
2392+static
2393+void
2394+xb_rebuild_indexes_for_table(
2395+/*=======================*/
2396+ dict_table_t* table, /*!< in: table */
2397+ trx_t* trx) /*!< in: transaction handle */
2398+{
2399+ dict_index_t* index;
2400+ dict_index_t** indexes;
2401+ ulint n_indexes;
2402+ merge_index_def_t* index_defs;
2403+ ulint i;
2404+ mem_heap_t* heap;
2405+ ulint error;
2406+
2407+ ut_ad(mutex_own(&(dict_sys->mutex)));
2408+ ut_ad(table);
2409+
2410+ ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
2411+
2412+ n_indexes = UT_LIST_GET_LEN(table->indexes) - 1;
2413+ if (!n_indexes) {
2414+ /* Only the primary key, nothing to do. */
2415+ return;
2416+ }
2417+
2418+ heap = mem_heap_create(1024);
2419+
2420+ indexes = (dict_index_t**) mem_heap_alloc(heap,
2421+ n_indexes * sizeof(*indexes));
2422+ index_defs = (merge_index_def_t*) mem_heap_alloc(heap,
2423+ n_indexes *
2424+ sizeof(*index_defs));
2425+
2426+ /* Skip the primary key. */
2427+ index = dict_table_get_first_index(table);
2428+ ut_a(dict_index_is_clust(index));
2429+
2430+ for (i = 0; (index = dict_table_get_next_index(index)); i++) {
2431+
2432+ msg(" Found index %s\n", index->name);
2433+
2434+ indexes[i] = index;
2435+
2436+ xb_build_index_def(heap, index, &index_defs[i]);
2437+ }
2438+
2439+ ut_ad(i == n_indexes);
2440+
2441+ msg(" Dropping %lu index(es).\n", n_indexes);
2442+
2443+ row_merge_drop_indexes(trx, table, indexes, n_indexes);
2444+
2445+ msg(" Rebuilding %lu index(es).\n", n_indexes);
2446+
2447+ row_merge_lock_table(trx, table, LOCK_X);
2448+
2449+ for (i = 0; i < n_indexes; i++) {
2450+ indexes[i] = row_merge_create_index(trx, table, &index_defs[i]);
2451+ }
2452+
2453+ error = row_merge_build_indexes(trx, table, table, indexes, n_indexes,
2454+ NULL);
2455+ ut_a(error == DB_SUCCESS);
2456+
2457+ mem_heap_free(heap);
2458+}
2459+
2460+/******************************************************************************
2461+Rebuild all secondary indexes in all tables in separate spaces. Called from
2462+innobase_start_or_create_for_mysql(). */
2463+void
2464+xb_compact_rebuild_indexes(void)
2465+/*=============================*/
2466+{
2467+ dict_table_t* sys_tables;
2468+ dict_index_t* sys_index;
2469+ btr_pcur_t pcur;
2470+ const rec_t* rec;
2471+ mtr_t mtr;
2472+ const byte* field;
2473+ ulint len;
2474+ ulint space_id;
2475+ ulint flags;
2476+ char* name;
2477+ dict_table_t* table;
2478+ trx_t* trx;
2479+
2480+ /* Iterate all tables that are not in the system tablespace. */
2481+
2482+ trx = trx_allocate_for_mysql();
2483+
2484+ /* Suppress foreign key checks, as we are going to drop and recreate all
2485+ secondary keys. */
2486+ trx->check_foreigns = FALSE;
2487+
2488+ row_mysql_lock_data_dictionary(trx);
2489+
2490+ /* Enlarge the fatal lock wait timeout during index rebuild
2491+ operation. */
2492+ mutex_enter(&kernel_mutex);
2493+ srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
2494+ mutex_exit(&kernel_mutex);
2495+
2496+ mtr_start(&mtr);
2497+
2498+ sys_tables = dict_table_get_low("SYS_TABLES");
2499+ sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
2500+ ut_a(!dict_table_is_comp(sys_tables));
2501+
2502+ btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
2503+ TRUE, &mtr);
2504+ for (;;) {
2505+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2506+
2507+ rec = btr_pcur_get_rec(&pcur);
2508+
2509+ if (!btr_pcur_is_on_user_rec(&pcur)) {
2510+ /* end of index */
2511+
2512+ break;
2513+ }
2514+
2515+ if (rec_get_deleted_flag(rec, 0)) {
2516+ continue;
2517+ }
2518+
2519+ field = rec_get_nth_field_old(rec, 9, &len);
2520+ ut_a(len == 4);
2521+
2522+ space_id = mach_read_from_4(field);
2523+
2524+ /* Don't touch tables in the system tablespace */
2525+ if (trx_sys_sys_space(space_id)) {
2526+
2527+ continue;
2528+ }
2529+
2530+ field = rec_get_nth_field_old(rec, 0, &len);
2531+ name = mem_strdupl((char*) field, len);
2532+
2533+ flags = dict_sys_tables_get_flags(rec);
2534+ if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
2535+
2536+ field = rec_get_nth_field_old(rec, 5, &len);
2537+ flags = mach_read_from_4(field);
2538+
2539+ ut_print_timestamp(stderr);
2540+ fputs(" InnoDB: Error: table ", stderr);
2541+ ut_print_filename(stderr, name);
2542+ fprintf(stderr, "\n"
2543+ "InnoDB: in InnoDB data dictionary"
2544+ " has unknown type %lx.\n",
2545+ (ulong) flags);
2546+
2547+ mem_free(name);
2548+
2549+ continue;
2550+ }
2551+
2552+ btr_pcur_store_position(&pcur, &mtr);
2553+
2554+ mtr_commit(&mtr);
2555+
2556+ table = dict_table_get_low(name);
2557+ ut_a(table != NULL);
2558+
2559+ /* Discard change buffer entries for this space */
2560+ ibuf_delete_for_discarded_space(space_id);
2561+
2562+ msg("Rebuilding indexes for table %s (space id: %lu)\n", name,
2563+ space_id);
2564+
2565+ xb_rebuild_indexes_for_table(table, trx);
2566+
2567+ mem_free(name);
2568+
2569+ /* Temporarily unlock the data dictionary to avoid long
2570+ semaphore waits. */
2571+ row_mysql_unlock_data_dictionary(trx);
2572+ row_mysql_lock_data_dictionary(trx);
2573+
2574+ mtr_start(&mtr);
2575+
2576+ btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
2577+ }
2578+
2579+ btr_pcur_close(&pcur);
2580+ mtr_commit(&mtr);
2581+
2582+ row_mysql_unlock_data_dictionary(trx);
2583+
2584+ trx_commit_for_mysql(trx);
2585+
2586+ trx_free_for_mysql(trx);
2587+}
2588
2589=== added file 'src/compact.h'
2590--- src/compact.h 1970-01-01 00:00:00 +0000
2591+++ src/compact.h 2013-01-14 11:06:22 +0000
2592@@ -0,0 +1,44 @@
2593+/******************************************************
2594+XtraBackup: hot backup tool for InnoDB
2595+(c) 2009-2012 Percona Ireland Ltd.
2596+Originally Created 3/3/2009 Yasufumi Kinoshita
2597+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
2598+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
2599+
2600+This program is free software; you can redistribute it and/or modify
2601+it under the terms of the GNU General Public License as published by
2602+the Free Software Foundation; version 2 of the License.
2603+
2604+This program is distributed in the hope that it will be useful,
2605+but WITHOUT ANY WARRANTY; without even the implied warranty of
2606+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2607+GNU General Public License for more details.
2608+
2609+You should have received a copy of the GNU General Public License
2610+along with this program; if not, write to the Free Software
2611+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2612+
2613+*******************************************************/
2614+
2615+#ifndef XB_COMPACT_H
2616+#define XB_COMPACT_H
2617+
2618+#include "write_filt.h"
2619+
2620+/* Compact page filter context */
2621+typedef struct {
2622+ my_bool skip;
2623+ ds_ctxt_t *ds_buffer;
2624+ ds_file_t *buffer;
2625+ INDEX_ID_T clustered_index;
2626+ my_bool clustered_index_found;
2627+ my_bool inside_skipped_range;
2628+ ulint free_limit;
2629+} xb_wf_compact_ctxt_t;
2630+
2631+/******************************************************************************
2632+Expand the data files according to the skipped pages maps created by --compact.
2633+@return TRUE on success, FALSE on failure. */
2634+my_bool xb_expand_datafiles(void);
2635+
2636+#endif
2637
2638=== modified file 'src/datasink.c'
2639--- src/datasink.c 2013-01-13 12:29:50 +0000
2640+++ src/datasink.c 2013-01-14 11:06:22 +0000
2641@@ -53,6 +53,7 @@
2642 break;
2643 default:
2644 msg("Unknown datasink type: %d\n", type);
2645+ xb_ad(0);
2646 return NULL;
2647 }
2648
2649
2650=== modified file 'src/ds_tmpfile.c'
2651--- src/ds_tmpfile.c 2013-01-11 13:00:50 +0000
2652+++ src/ds_tmpfile.c 2013-01-14 11:06:22 +0000
2653@@ -182,7 +182,7 @@
2654 xb_a(pipe_ctxt != NULL);
2655
2656 buf = my_malloc(buf_size, MYF(MY_FAE));
2657-
2658+
2659 tmpfile_ctxt = (ds_tmpfile_ctxt_t *) ctxt->ptr;
2660 list = tmpfile_ctxt->file_list;
2661
2662
2663=== modified file 'src/fil_cur.c'
2664--- src/fil_cur.c 2013-01-11 13:00:50 +0000
2665+++ src/fil_cur.c 2013-01-14 11:06:22 +0000
2666@@ -142,6 +142,8 @@
2667 cursor->buf_page_no = 0;
2668 cursor->thread_n = thread_n;
2669
2670+ cursor->space_size = cursor->statinfo.st_size / page_size;
2671+
2672 return(XB_FIL_CUR_SUCCESS);
2673 }
2674
2675@@ -216,13 +218,13 @@
2676 page_no < FSP_EXTENT_SIZE * 3) {
2677 /* skip doublewrite buffer pages */
2678 ut_a(page_size == UNIV_PAGE_SIZE);
2679- msg("[%02lu] xtrabackup: "
2680+ msg("[%02u] xtrabackup: "
2681 "Page %lu is a doublewrite buffer page, "
2682 "skipping.\n", cursor->thread_n, page_no);
2683 } else {
2684 retry_count--;
2685 if (retry_count == 0) {
2686- msg("[%02lu] xtrabackup: "
2687+ msg("[%02u] xtrabackup: "
2688 "Error: failed to read page after "
2689 "10 retries. File %s seems to be "
2690 "corrupted.\n", cursor->thread_n,
2691@@ -230,7 +232,7 @@
2692 ret = XB_FIL_CUR_ERROR;
2693 break;
2694 }
2695- msg("[%02lu] xtrabackup: "
2696+ msg("[%02u] xtrabackup: "
2697 "Database page corruption detected at page "
2698 "%lu, retrying...\n", cursor->thread_n,
2699 page_no);
2700
2701=== modified file 'src/fil_cur.h'
2702--- src/fil_cur.h 2013-01-11 13:00:50 +0000
2703+++ src/fil_cur.h 2013-01-14 11:06:22 +0000
2704@@ -52,8 +52,9 @@
2705 buffer */
2706 ulint buf_page_no; /*!< number of the first page in
2707 buffer */
2708- ulint thread_n; /*!< thread number for diagnostics */
2709+ uint thread_n; /*!< thread number for diagnostics */
2710 ulint space_id; /*!< ID of tablespace */
2711+ ulint space_size; /*!< space size in pages */
2712 } xb_fil_cur_t;
2713
2714 typedef enum {
2715
2716=== modified file 'src/innodb_int.c'
2717--- src/innodb_int.c 2013-01-11 13:00:50 +0000
2718+++ src/innodb_int.c 2013-01-14 11:06:22 +0000
2719@@ -28,8 +28,20 @@
2720 #include <srv0srv.h>
2721 #include <ha_prototypes.h>
2722 #include <trx0trx.h>
2723+#include <buf0flu.h>
2724+#ifdef INNODB_VERSION_SHORT
2725+# include <page0zip.h>
2726+#endif
2727+#if MYSQL_VERSION_ID < 50500
2728+# include <row0types.h>
2729+#endif
2730 #include "common.h"
2731
2732+/* Required by innobase_rec*() stubs */
2733+#if MYSQL_VERSION_ID >= 50500
2734+typedef struct st_table TABLE;
2735+#endif
2736+
2737 extern long innobase_lock_wait_timeout;
2738
2739 char *opt_mysql_tmpdir = NULL;
2740@@ -901,6 +913,27 @@
2741 return(fd2);
2742 }
2743
2744+/* The following is used by row0merge for error reporting. Define a stub so we
2745+can use fast index creation from XtraBackup. */
2746+void
2747+innobase_rec_reset(
2748+/*===============*/
2749+ TABLE* table __attribute__((unused)))
2750+{
2751+}
2752+
2753+/* The following is used by row0merge for error reporting. Define a stub so we
2754+can use fast index creation from XtraBackup. */
2755+void
2756+innobase_rec_to_mysql(
2757+/*==================*/
2758+ TABLE* table __attribute__((unused)),
2759+ const rec_t* rec __attribute__((unused)),
2760+ const dict_index_t* index __attribute__((unused)),
2761+ const ulint* offsets __attribute__((unused)))
2762+{
2763+}
2764+
2765 #if MYSQL_VERSION_ID >= 50507
2766 /*
2767 As of MySQL 5.5.7, InnoDB uses thd_wait plugin service.
2768@@ -923,3 +956,15 @@
2769 }
2770
2771 #endif /* MYSQL_VERSION_ID >= 50507 */
2772+
2773+#ifdef XTRADB_BASED
2774+/******************************************************************//*******
2775+Stub for an XtraDB-specific function called from row_merge_build_indexes().*/
2776+ibool
2777+thd_expand_fast_index_creation(
2778+/*================================*/
2779+ void* thd __attribute__((unused)))
2780+{
2781+ return(FALSE);
2782+}
2783+#endif /* XTRADB_BASED */
2784
2785=== modified file 'src/innodb_int.h'
2786--- src/innodb_int.h 2013-01-11 13:00:50 +0000
2787+++ src/innodb_int.h 2013-01-14 11:06:22 +0000
2788@@ -40,10 +40,16 @@
2789 # if (MYSQL_VERSION_ID < 50500)
2790 # define MACH_READ_64 mach_read_ull
2791 # define MACH_WRITE_64 mach_write_ull
2792+# define INDEX_ID_T dulint
2793+# define INDEX_ID_CMP(a,b) ((a).high != (b).high ? \
2794+ ((a).high - (b).high) : \
2795+ ((a).low - (b).low))
2796 # define OS_MUTEX_CREATE() os_mutex_create(NULL)
2797 # else
2798 # define MACH_READ_64 mach_read_from_8
2799 # define MACH_WRITE_64 mach_write_to_8
2800+# define INDEX_ID_T index_id_t
2801+# define INDEX_ID_CMP(a,b) ((a) - (b))
2802 # define OS_MUTEX_CREATE() os_mutex_create()
2803 # endif
2804 # define xb_buf_page_is_corrupted(page, zip_size) \
2805@@ -86,6 +92,22 @@
2806 HASH_SEARCH(NAME, TABLE, FOLD, xtrabackup_tables_t*, DATA, ASSERTION, \
2807 TEST)
2808
2809+/* The following constants have been copied from fsp0fsp.c */
2810+#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
2811+ within a file page */
2812+#define FSP_SIZE 8 /* Current size of the space in
2813+ pages */
2814+#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
2815+ free list has not been initialized:
2816+ the pages >= this limit are, by
2817+ definition, free; note that in a
2818+ single-table tablespace where size
2819+ < 64 pages, this number is 64, i.e.,
2820+ we have initialized the space
2821+ about the first extent, but have not
2822+ physically allocted those pages to the
2823+ file */
2824+
2825 /* ==start === definition at fil0fil.c === */
2826 // ##################################################################
2827 // NOTE: We should check the following definitions fit to the source.
2828
2829=== modified file 'src/write_filt.c'
2830--- src/write_filt.c 2013-01-11 13:00:50 +0000
2831+++ src/write_filt.c 2013-01-14 11:06:22 +0000
2832@@ -62,22 +62,6 @@
2833 };
2834
2835 /************************************************************************
2836-Compact page write filter. */
2837-static my_bool wf_compact_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
2838- xb_fil_cur_t *cursor);
2839-static my_bool wf_compact_process(xb_write_filt_ctxt_t *ctxt,
2840- ds_file_t *dstfile);
2841-static my_bool wf_compact_finalize(xb_write_filt_ctxt_t *ctxt,
2842- ds_file_t *dstfile);
2843-
2844-xb_write_filt_t wf_compact = {
2845- &wf_compact_init,
2846- &wf_compact_process,
2847- &wf_compact_finalize,
2848- NULL
2849-};
2850-
2851-/************************************************************************
2852 Initialize incremental page write filter.
2853
2854 @return TRUE on success, FALSE on error. */
2855@@ -106,7 +90,7 @@
2856 info.zip_size = cursor->zip_size;
2857 info.space_id = cursor->space_id;
2858 if (!xb_write_delta_metadata(meta_name, &info)) {
2859- msg("[%02lu] xtrabackup: Error: "
2860+ msg("[%02u] xtrabackup: Error: "
2861 "failed to write meta info for %s\n",
2862 cursor->thread_n, cursor->path);
2863 return(FALSE);
2864@@ -234,88 +218,3 @@
2865
2866 return(TRUE);
2867 }
2868-
2869-/************************************************************************
2870-Initialize the compact page write filter.
2871-
2872-@return TRUE on success, FALSE on error. */
2873-static my_bool
2874-wf_compact_init(xb_write_filt_ctxt_t *ctxt,
2875- char *dst_name __attribute__((unused)), xb_fil_cur_t *cursor)
2876-{
2877- xb_wf_compact_ctxt_t *cp = &(ctxt->u.wf_compact_ctxt);
2878-
2879- /* Don't compact the system table space */
2880- cp->skip = cursor->is_system;
2881-
2882- return(TRUE);
2883-}
2884-
2885-static my_bool
2886-check_if_skip_page(byte *page __attribute__((unused)))
2887-{
2888- return(FALSE);
2889-}
2890-
2891-/************************************************************************
2892-Run the next batch of pages through the compact page write filter.
2893-
2894-@return TRUE on success, FALSE on error. */
2895-static my_bool
2896-wf_compact_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
2897-{
2898- xb_fil_cur_t *cursor = ctxt->cursor;
2899- ulint page_size = cursor->page_size;
2900- byte *page;
2901- byte *buf_end;
2902- byte *write_from;
2903- xb_wf_compact_ctxt_t *cp = &(ctxt->u.wf_compact_ctxt);
2904-
2905- if (cp->skip) {
2906- return(!ds_write(dstfile, cursor->buf, cursor->buf_read));
2907- }
2908-
2909- write_from = NULL;
2910- buf_end = cursor->buf + cursor->buf_read;
2911- for (page = cursor->buf; page < buf_end; page += page_size) {
2912- if (!check_if_skip_page(page)) {
2913- if (write_from == NULL) {
2914- write_from = page;
2915- }
2916- continue;
2917- }
2918- }
2919-
2920- /* Write the remaining pages in the buffer, if any */
2921- if (write_from != NULL &&
2922- ds_write(dstfile, write_from, buf_end - write_from)) {
2923- return(FALSE);
2924- }
2925-
2926- return(TRUE);
2927-}
2928-
2929-/************************************************************************
2930-Close the compact write filter's page map stream.
2931-
2932-@return TRUE on success, FALSE on error. */
2933-static my_bool
2934-wf_compact_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
2935-{
2936- xb_fil_cur_t *cursor = ctxt->cursor;
2937- ulint page_size = cursor->page_size;
2938- xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
2939-
2940- if (cp->npages != page_size / 4) {
2941- mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL);
2942- }
2943-
2944- mach_write_to_4(cp->delta_buf, 0x58545241UL); /*"XTRA"*/
2945-
2946- /* flush buffer */
2947- if (ds_write(dstfile, cp->delta_buf, cp->npages * page_size)) {
2948- return(FALSE);
2949- }
2950-
2951- return(TRUE);
2952-}
2953
2954=== modified file 'src/write_filt.h'
2955--- src/write_filt.h 2013-01-11 13:00:50 +0000
2956+++ src/write_filt.h 2013-01-14 11:06:22 +0000
2957@@ -27,6 +27,7 @@
2958
2959 #include "fil_cur.h"
2960 #include "datasink.h"
2961+#include "compact.h"
2962
2963 /* Incremental page filter context */
2964 typedef struct {
2965@@ -35,11 +36,6 @@
2966 ulint npages;
2967 } xb_wf_incremental_ctxt_t;
2968
2969-/* Compact page filter context */
2970-typedef struct {
2971- my_bool skip;
2972-} xb_wf_compact_ctxt_t;
2973-
2974 /* Page filter context used as an opaque structure by callers */
2975 typedef struct {
2976 xb_fil_cur_t *cursor;
2977
2978=== added file 'src/xb0xb.h'
2979--- src/xb0xb.h 1970-01-01 00:00:00 +0000
2980+++ src/xb0xb.h 2013-01-14 11:06:22 +0000
2981@@ -0,0 +1,40 @@
2982+/******************************************************
2983+Copyright (c) 2012 Percona Ireland Ltd.
2984+
2985+Declarations of XtraBackup functions called by InnoDB code.
2986+
2987+This program is free software; you can redistribute it and/or modify
2988+it under the terms of the GNU General Public License as published by
2989+the Free Software Foundation; version 2 of the License.
2990+
2991+This program is distributed in the hope that it will be useful,
2992+but WITHOUT ANY WARRANTY; without even the implied warranty of
2993+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2994+GNU General Public License for more details.
2995+
2996+You should have received a copy of the GNU General Public License
2997+along with this program; if not, write to the Free Software
2998+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2999+
3000+*******************************************************/
3001+
3002+#ifndef xb0xb_h
3003+#define xb0xb_h
3004+
3005+extern ibool srv_compact_backup;
3006+extern ibool srv_rebuild_indexes;
3007+
3008+/******************************************************************************
3009+Callback used in buf_page_io_complete() to detect compacted pages.
3010+@return TRUE if the page is marked as compacted, FALSE otherwise. */
3011+ibool
3012+buf_page_is_compacted(
3013+/*==================*/
3014+ const byte* page); /*!< in: a database page */
3015+
3016+/******************************************************************************
3017+Rebuild all secondary indexes in all tables in separate spaces. Called from
3018+innobase_start_or_create_for_mysql(). */
3019+void
3020+xb_compact_rebuild_indexes(void);
3021+#endif
3022
3023=== modified file 'src/xbstream.c'
3024--- src/xbstream.c 2013-01-11 13:00:50 +0000
3025+++ src/xbstream.c 2013-01-14 11:06:22 +0000
3026@@ -36,11 +36,12 @@
3027 RUN_MODE_EXTRACT
3028 } run_mode_t;
3029
3030-/* Need the following definitions to avoid linking with ds_stream.o,
3031-ds_compress.o, ds_tmpfile.o and their linking dependencies */
3032+/* Need the following definitions to avoid linking with ds_*.o and their link
3033+dependencies */
3034 datasink_t datasink_stream;
3035 datasink_t datasink_compress;
3036 datasink_t datasink_tmpfile;
3037+datasink_t datasink_buffer;
3038
3039 static run_mode_t opt_mode;
3040 static char * opt_directory = NULL;
3041
3042=== modified file 'src/xtrabackup.c'
3043--- src/xtrabackup.c 2013-01-14 04:42:47 +0000
3044+++ src/xtrabackup.c 2013-01-14 11:06:22 +0000
3045@@ -199,7 +199,6 @@
3046 long innobase_lock_wait_timeout = 50;
3047 long innobase_log_buffer_size = 1024*1024L;
3048 long innobase_log_files_in_group = 2;
3049-long innobase_log_files_in_group_backup;
3050 long innobase_mirrored_log_groups = 1;
3051 long innobase_open_files = 300L;
3052
3053@@ -213,7 +212,6 @@
3054
3055 longlong innobase_buffer_pool_size = 8*1024*1024L;
3056 longlong innobase_log_file_size = 5*1024*1024L;
3057-longlong innobase_log_file_size_backup;
3058
3059 /* The default values for the following char* start-up parameters
3060 are determined in innobase_init below: */
3061@@ -222,7 +220,6 @@
3062 char* innobase_data_home_dir = NULL;
3063 char* innobase_data_file_path = NULL;
3064 char* innobase_log_group_home_dir = NULL;
3065-char* innobase_log_group_home_dir_backup = NULL;
3066 char* innobase_log_arch_dir = NULL;/* unused */
3067 /* The following has a misleading name: starting from 4.0.5, this also
3068 affects Windows: */
3069@@ -252,13 +249,20 @@
3070 #define INNOBASE_WAKE_INTERVAL 32
3071 ulong innobase_active_counter = 0;
3072
3073+ibool srv_compact_backup = FALSE;
3074+ibool srv_rebuild_indexes = FALSE;
3075+
3076 static char *xtrabackup_debug_sync = NULL;
3077
3078 static my_bool xtrabackup_compact = FALSE;
3079-
3080-/* Datasinks */
3081-static ds_ctxt_t *ds_data = NULL;
3082-static ds_ctxt_t *ds_meta = NULL;
3083+static my_bool xtrabackup_rebuild_indexes = FALSE;
3084+
3085+/* datasink chain used to store datafiles */
3086+ds_ctxt_t *ds_data = NULL;
3087+/* datasink chain used to store XtraBackup metainfo files */
3088+ds_ctxt_t *ds_meta = NULL;
3089+
3090+/* datasinks used to build the above two chains */
3091 static ds_ctxt_t *ds_local = NULL;
3092 static ds_ctxt_t *ds_compress = NULL;
3093 static ds_ctxt_t *ds_tmpfile = NULL;
3094@@ -266,15 +270,6 @@
3095 static ds_ctxt_t *ds_buffer = NULL;
3096
3097 /* ======== Datafiles iterator ======== */
3098-typedef struct {
3099- fil_system_t *system;
3100- fil_space_t *space;
3101- fil_node_t *node;
3102- ibool started;
3103- os_mutex_t mutex;
3104-} datafiles_iter_t;
3105-
3106-static
3107 datafiles_iter_t *
3108 datafiles_iter_new(fil_system_t *f_system)
3109 {
3110@@ -291,7 +286,6 @@
3111 return it;
3112 }
3113
3114-static
3115 fil_node_t *
3116 datafiles_iter_next(datafiles_iter_t *it)
3117 {
3118@@ -329,7 +323,6 @@
3119 return new_node;
3120 }
3121
3122-static
3123 void
3124 datafiles_iter_free(datafiles_iter_t *it)
3125 {
3126@@ -421,6 +414,7 @@
3127 OPT_INNODB_THREAD_SLEEP_DELAY,
3128 OPT_XTRA_DEBUG_SYNC,
3129 OPT_XTRA_COMPACT,
3130+ OPT_XTRA_REBUILD_INDEXES,
3131 OPT_DEFAULTS_GROUP
3132 };
3133
3134@@ -714,6 +708,12 @@
3135 (G_PTR*) &xtrabackup_compact, (G_PTR*) &xtrabackup_compact,
3136 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
3137
3138+ {"rebuild_indexes", OPT_XTRA_REBUILD_INDEXES,
3139+ "Rebuild secondary indexes in InnoDB tables after applying the log. "
3140+ "Only has effect with --prepare.",
3141+ (G_PTR*) &xtrabackup_rebuild_indexes, (G_PTR*) &xtrabackup_rebuild_indexes,
3142+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
3143+
3144 {"defaults_group", OPT_DEFAULTS_GROUP, "defaults group in config file (default \"mysqld\").",
3145 (G_PTR*) &defaults_group, (G_PTR*) &defaults_group,
3146 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
3147@@ -1303,8 +1303,9 @@
3148 my_bool
3149 xtrabackup_read_metadata(char *filename)
3150 {
3151- FILE *fp;
3152- my_bool r = TRUE;
3153+ FILE *fp;
3154+ my_bool r = TRUE;
3155+ int t;
3156
3157 fp = fopen(filename,"r");
3158 if(!fp) {
3159@@ -1331,7 +1332,12 @@
3160 != 1) {
3161 metadata_last_lsn = 0;
3162 }
3163-
3164+ /* Optional field */
3165+ if (fscanf(fp, "compact = %d\n", &t) == 1) {
3166+ xtrabackup_compact = (t == 1);
3167+ } else {
3168+ xtrabackup_compact = 0;
3169+ }
3170 end:
3171 fclose(fp);
3172
3173@@ -1348,11 +1354,13 @@
3174 "backup_type = %s\n"
3175 "from_lsn = %llu\n"
3176 "to_lsn = %llu\n"
3177- "last_lsn = %llu\n",
3178+ "last_lsn = %llu\n"
3179+ "compact = %d\n",
3180 metadata_type,
3181 metadata_from_lsn,
3182 metadata_to_lsn,
3183- metadata_last_lsn);
3184+ metadata_last_lsn,
3185+ xtrabackup_compact == TRUE);
3186 }
3187
3188 /***********************************************************************
3189@@ -3677,11 +3685,6 @@
3190 os_file_close(src_file);
3191 src_file = XB_FILE_UNDEFINED;
3192
3193- /* Backup log parameters */
3194- innobase_log_group_home_dir_backup = innobase_log_group_home_dir;
3195- innobase_log_file_size_backup = innobase_log_file_size;
3196- innobase_log_files_in_group_backup = innobase_log_files_in_group;
3197-
3198 /* fake InnoDB */
3199 innobase_log_group_home_dir = NULL;
3200 innobase_log_file_size = file_size;
3201@@ -4236,11 +4239,6 @@
3202 if (!xtrabackup_logfile_is_renamed)
3203 return(FALSE);
3204
3205- /* Restore log parameters */
3206- innobase_log_group_home_dir = innobase_log_group_home_dir_backup;
3207- innobase_log_file_size = innobase_log_file_size_backup;
3208- innobase_log_files_in_group = innobase_log_files_in_group_backup;
3209-
3210 /* rename 'ib_logfile0' to 'xtrabackup_logfile' */
3211 if(!xtrabackup_incremental_dir) {
3212 sprintf(dst_path, "%s/ib_logfile0", xtrabackup_target_dir);
3213@@ -4308,6 +4306,10 @@
3214 xtrabackup_prepare_func(void)
3215 {
3216 ulint err;
3217+ datafiles_iter_t *it;
3218+ fil_node_t *node;
3219+ fil_space_t *space;
3220+ char metadata_path[FN_REFLEN];
3221
3222 /* cd to target-dir */
3223
3224@@ -4325,11 +4327,10 @@
3225
3226 /* read metadata of target */
3227 {
3228- char filename[FN_REFLEN];
3229-
3230- sprintf(filename, "%s/%s", xtrabackup_target_dir, XTRABACKUP_METADATA_FILENAME);
3231-
3232- if (!xtrabackup_read_metadata(filename))
3233+ sprintf(metadata_path, "%s/%s", xtrabackup_target_dir,
3234+ XTRABACKUP_METADATA_FILENAME);
3235+
3236+ if (!xtrabackup_read_metadata(metadata_path))
3237 msg("xtrabackup: error: xtrabackup_read_metadata()\n");
3238
3239 if (!strcmp(metadata_type, "full-backuped")) {
3240@@ -4372,20 +4373,41 @@
3241 os_sync_init();
3242 sync_init();
3243 os_io_init_simple();
3244+ mem_init(srv_mem_pool_size);
3245+
3246 if(xtrabackup_init_temp_log())
3247 goto error;
3248
3249- if(innodb_init_param())
3250+ if(innodb_init_param()) {
3251 goto error;
3252+ }
3253+
3254+ /* Expand compacted datafiles */
3255+
3256+ if (xtrabackup_compact) {
3257+ srv_compact_backup = TRUE;
3258+
3259+ if (!xb_expand_datafiles()) {
3260+ goto error;
3261+ }
3262+
3263+ /* Reset the 'compact' flag in xtrabackup_checkpoints so we
3264+ don't expand on subsequent invocations. */
3265+ xtrabackup_compact = FALSE;
3266+ if (!xtrabackup_write_metadata(metadata_path)) {
3267+ msg("xtrabackup: error: xtrabackup_write_metadata() "
3268+ "failed\n");
3269+ goto error;
3270+ }
3271+ }
3272
3273 xb_normalize_init_values();
3274
3275- mem_init(srv_mem_pool_size);
3276 if (xtrabackup_incremental) {
3277 err = xb_data_files_init();
3278 if (err != DB_SUCCESS) {
3279- msg("xtrabackup: error: xb_data_files_init() failed with"
3280- "error code %lu\n", err);
3281+ msg("xtrabackup: error: xb_data_files_init() failed "
3282+ "with error code %lu\n", err);
3283 goto error;
3284 }
3285
3286@@ -4403,13 +4425,14 @@
3287 os_sync_mutex = NULL;
3288 ut_free_all_mem();
3289
3290- /* check the accessibility of target-dir */
3291- /* ############# TODO ##################### */
3292-
3293- if(innodb_init_param())
3294+ /* Reset the configuration as it might have been changed by
3295+ xb_data_files_init(). */
3296+ if(innodb_init_param()) {
3297 goto error;
3298+ }
3299
3300 srv_apply_log_only = (ibool) xtrabackup_apply_log_only;
3301+ srv_rebuild_indexes = (ibool) xtrabackup_rebuild_indexes;
3302
3303 /* increase IO threads */
3304 if(srv_n_file_io_threads < 10) {
3305@@ -4424,214 +4447,199 @@
3306 if(innodb_init())
3307 goto error;
3308
3309- /* align space sizes along with fsp header */
3310- {
3311- fil_system_t* f_system = fil_system;
3312- fil_space_t* space;
3313-
3314- mutex_enter(&(f_system->mutex));
3315- space = UT_LIST_GET_FIRST(f_system->space_list);
3316-
3317- while (space != NULL) {
3318- byte* header;
3319- ulint size;
3320- ulint actual_size;
3321- mtr_t mtr;
3322- buf_block_t* block;
3323- ulint flags;
3324-
3325- if (space->purpose == FIL_TABLESPACE) {
3326- mutex_exit(&(f_system->mutex));
3327-
3328- mtr_start(&mtr);
3329-
3330- mtr_s_lock(fil_space_get_latch(space->id, &flags), &mtr);
3331-
3332- block = buf_page_get(space->id,
3333- dict_table_flags_to_zip_size(flags),
3334- 0, RW_S_LATCH, &mtr);
3335- header = FIL_PAGE_DATA /*FSP_HEADER_OFFSET*/
3336- + buf_block_get_frame(block);
3337-
3338- size = mtr_read_ulint(header + 8 /* FSP_SIZE */, MLOG_4BYTES, &mtr);
3339-
3340- mtr_commit(&mtr);
3341-
3342- fil_extend_space_to_desired_size(&actual_size, space->id, size);
3343-
3344- mutex_enter(&(f_system->mutex));
3345+ it = datafiles_iter_new(fil_system);
3346+ if (it == NULL) {
3347+ msg("xtrabackup: Error: datafiles_iter_new() failed.\n");
3348+ exit(EXIT_FAILURE);
3349+ }
3350+
3351+ while ((node = datafiles_iter_next(it)) != NULL) {
3352+ byte *header;
3353+ ulint size;
3354+ ulint actual_size;
3355+ mtr_t mtr;
3356+ buf_block_t *block;
3357+ ulint flags;
3358+
3359+ space = node->space;
3360+
3361+ /* Align space sizes along with fsp header. We want to process
3362+ each space once, so skip all nodes except the first one in a
3363+ multi-node space. */
3364+ if (UT_LIST_GET_PREV(chain, node) != NULL) {
3365+ continue;
3366 }
3367
3368- space = UT_LIST_GET_NEXT(space_list, space);
3369- }
3370-
3371- mutex_exit(&(f_system->mutex));
3372- }
3373-
3374-
3375+ mtr_start(&mtr);
3376+
3377+ mtr_s_lock(fil_space_get_latch(space->id, &flags), &mtr);
3378+
3379+ block = buf_page_get(space->id,
3380+ dict_table_flags_to_zip_size(flags),
3381+ 0, RW_S_LATCH, &mtr);
3382+ header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
3383+
3384+ size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES,
3385+ &mtr);
3386+
3387+ mtr_commit(&mtr);
3388+
3389+ fil_extend_space_to_desired_size(&actual_size, space->id, size);
3390+ }
3391+
3392+ datafiles_iter_free(it);
3393
3394 if (xtrabackup_export) {
3395 msg("xtrabackup: export option is specified.\n");
3396- if (innobase_file_per_table) {
3397- fil_system_t* f_system = fil_system;
3398- fil_space_t* space;
3399- fil_node_t* node;
3400- os_file_t info_file = XB_FILE_UNDEFINED;
3401- char info_file_path[FN_REFLEN];
3402- ibool success;
3403- char table_name[FN_REFLEN];
3404-
3405- byte* page;
3406- byte* buf = NULL;
3407-
3408- buf = ut_malloc(UNIV_PAGE_SIZE * 2);
3409- page = ut_align(buf, UNIV_PAGE_SIZE);
3410-
3411- /* flush insert buffer at shutdwon */
3412- innobase_fast_shutdown = 0;
3413-
3414- mutex_enter(&(f_system->mutex));
3415-
3416- space = UT_LIST_GET_FIRST(f_system->space_list);
3417- while (space != NULL) {
3418- /* treat file_per_table only */
3419- if (space->purpose != FIL_TABLESPACE
3420- || trx_sys_sys_space(space->id))
3421- {
3422- space = UT_LIST_GET_NEXT(space_list, space);
3423- continue;
3424- }
3425-
3426- node = UT_LIST_GET_FIRST(space->chain);
3427- while (node != NULL) {
3428- int len;
3429- char *next, *prev, *p;
3430- dict_table_t* table;
3431- dict_index_t* index;
3432- ulint n_index;
3433-
3434- /* node exist == file exist, here */
3435- strncpy(info_file_path, node->name, FN_REFLEN);
3436- len = strlen(info_file_path);
3437- info_file_path[len - 3] = 'e';
3438- info_file_path[len - 2] = 'x';
3439- info_file_path[len - 1] = 'p';
3440-
3441- p = info_file_path;
3442- prev = NULL;
3443- while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
3444- {
3445- prev = p;
3446- p = next + 1;
3447- }
3448- info_file_path[len - 4] = 0;
3449- strncpy(table_name, prev, FN_REFLEN);
3450-
3451- info_file_path[len - 4] = '.';
3452-
3453- mutex_exit(&(f_system->mutex));
3454- mutex_enter(&(dict_sys->mutex));
3455-
3456- table = dict_table_get_low(table_name);
3457- if (!table) {
3458- msg("xtrabackup: error: "
3459- "cannot find dictionary "
3460- "record of table %s\n",
3461- table_name);
3462- goto next_node;
3463- }
3464- index = dict_table_get_first_index(table);
3465- n_index = UT_LIST_GET_LEN(table->indexes);
3466- if (n_index > 31) {
3467- msg("xtrabackup: error: "
3468- "sorry, cannot export over "
3469- "31 indexes for now.\n");
3470- goto next_node;
3471- }
3472-
3473- /* init exp file */
3474- bzero(page, UNIV_PAGE_SIZE);
3475- mach_write_to_4(page , 0x78706f72UL);
3476- mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/
3477- mach_write_to_4(page + 8, n_index);
3478- strncpy((char *) page + 12,
3479- table_name, 500);
3480-
3481- msg("xtrabackup: export metadata of "
3482- "table '%s' to file `%s` "
3483- "(%lu indexes)\n",
3484- table_name, info_file_path,
3485- n_index);
3486-
3487- n_index = 1;
3488- while (index) {
3489- mach_write_to_8(page + n_index * 512, index->id);
3490- mach_write_to_4(page + n_index * 512 + 8,
3491-#if (MYSQL_VERSION_ID < 50100)
3492- index->tree->page);
3493-#else /* MYSQL_VERSION_ID < 51000 */
3494- index->page);
3495-#endif
3496- strncpy((char *) page + n_index * 512 +
3497- 12, index->name, 500);
3498-
3499- msg("xtrabackup: name=%s, "
3500- "id.low=%lu, page=%lu\n",
3501- index->name,
3502-#if (MYSQL_VERSION_ID < 50500)
3503- index->id.low,
3504-#else
3505- (ulint)(index->id &
3506- 0xFFFFFFFFUL),
3507-#endif
3508-#if (MYSQL_VERSION_ID < 50100)
3509- index->tree->page
3510-#else /* MYSQL_VERSION_ID < 51000 */
3511- (ulint) index->page
3512+ os_file_t info_file = XB_FILE_UNDEFINED;
3513+ char info_file_path[FN_REFLEN];
3514+ ibool success;
3515+ char table_name[FN_REFLEN];
3516+
3517+ byte* page;
3518+ byte* buf = NULL;
3519+
3520+ buf = ut_malloc(UNIV_PAGE_SIZE * 2);
3521+ page = ut_align(buf, UNIV_PAGE_SIZE);
3522+
3523+ /* flush insert buffer at shutdwon */
3524+ innobase_fast_shutdown = 0;
3525+
3526+ it = datafiles_iter_new(fil_system);
3527+ if (it == NULL) {
3528+ msg("xtrabackup: Error: datafiles_iter_new() "
3529+ "failed.\n");
3530+ exit(EXIT_FAILURE);
3531+ }
3532+ while ((node = datafiles_iter_next(it)) != NULL) {
3533+ int len;
3534+ char *next, *prev, *p;
3535+ dict_table_t* table;
3536+ dict_index_t* index;
3537+ ulint n_index;
3538+
3539+ space = node->space;
3540+
3541+ /* treat file_per_table only */
3542+ if (trx_sys_sys_space(space->id)) {
3543+ continue;
3544+ }
3545+
3546+ /* node exist == file exist, here */
3547+ strncpy(info_file_path, node->name, FN_REFLEN);
3548+ len = strlen(info_file_path);
3549+ info_file_path[len - 3] = 'e';
3550+ info_file_path[len - 2] = 'x';
3551+ info_file_path[len - 1] = 'p';
3552+
3553+ p = info_file_path;
3554+ prev = NULL;
3555+ while ((next = strstr(p, SRV_PATH_SEPARATOR_STR)) != NULL)
3556+ {
3557+ prev = p;
3558+ p = next + 1;
3559+ }
3560+ info_file_path[len - 4] = 0;
3561+ strncpy(table_name, prev, FN_REFLEN);
3562+
3563+ info_file_path[len - 4] = '.';
3564+
3565+ mutex_enter(&(dict_sys->mutex));
3566+
3567+ table = dict_table_get_low(table_name);
3568+ if (!table) {
3569+ msg("xtrabackup: error: "
3570+ "cannot find dictionary "
3571+ "record of table %s\n",
3572+ table_name);
3573+ goto next_node;
3574+ }
3575+ index = dict_table_get_first_index(table);
3576+ n_index = UT_LIST_GET_LEN(table->indexes);
3577+ if (n_index > 31) {
3578+ msg("xtrabackup: error: "
3579+ "sorry, cannot export over "
3580+ "31 indexes for now.\n");
3581+ goto next_node;
3582+ }
3583+
3584+ /* init exp file */
3585+ bzero(page, UNIV_PAGE_SIZE);
3586+ mach_write_to_4(page , 0x78706f72UL);
3587+ mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/
3588+ mach_write_to_4(page + 8, n_index);
3589+ strncpy((char *) page + 12,
3590+ table_name, 500);
3591+
3592+ msg("xtrabackup: export metadata of "
3593+ "table '%s' to file `%s` "
3594+ "(%lu indexes)\n",
3595+ table_name, info_file_path,
3596+ n_index);
3597+
3598+ n_index = 1;
3599+ while (index) {
3600+ mach_write_to_8(page + n_index * 512, index->id);
3601+ mach_write_to_4(page + n_index * 512 + 8,
3602+#if (MYSQL_VERSION_ID < 50100)
3603+ index->tree->page
3604+#else /* MYSQL_VERSION_ID < 51000 */
3605+ index->page
3606 #endif
3607 );
3608- index = dict_table_get_next_index(index);
3609- n_index++;
3610- }
3611-
3612- srv_normalize_path_for_win(info_file_path);
3613- info_file = xb_file_create(
3614- info_file_path,
3615- OS_FILE_OVERWRITE,
3616- OS_FILE_NORMAL, OS_DATA_FILE,
3617- &success);
3618- if (!success) {
3619- os_file_get_last_error(TRUE);
3620- goto next_node;
3621- }
3622- success = os_file_write(info_file_path, info_file, page,
3623- 0, 0, UNIV_PAGE_SIZE);
3624- if (!success) {
3625- os_file_get_last_error(TRUE);
3626- goto next_node;
3627- }
3628- success = xb_file_flush(info_file);
3629- if (!success) {
3630- os_file_get_last_error(TRUE);
3631- goto next_node;
3632- }
3633+ strncpy((char *) page + n_index * 512 +
3634+ 12, index->name, 500);
3635+
3636+ msg("xtrabackup: name=%s, "
3637+ "id.low=%lu, page=%lu\n",
3638+ index->name,
3639+#if (MYSQL_VERSION_ID < 50500)
3640+ index->id.low,
3641+#else
3642+ (ulint)(index->id &
3643+ 0xFFFFFFFFUL),
3644+#endif
3645+#if (MYSQL_VERSION_ID < 50100)
3646+ index->tree->page
3647+#else /* MYSQL_VERSION_ID < 51000 */
3648+ (ulint) index->page
3649+#endif
3650+ );
3651+ index = dict_table_get_next_index(index);
3652+ n_index++;
3653+
3654+ srv_normalize_path_for_win(info_file_path);
3655+ info_file = xb_file_create(
3656+ info_file_path,
3657+ OS_FILE_OVERWRITE,
3658+ OS_FILE_NORMAL, OS_DATA_FILE,
3659+ &success);
3660+ if (!success) {
3661+ os_file_get_last_error(TRUE);
3662+ goto next_node;
3663+ }
3664+ success = os_file_write(info_file_path,
3665+ info_file, page,
3666+ 0, 0, UNIV_PAGE_SIZE);
3667+ if (!success) {
3668+ os_file_get_last_error(TRUE);
3669+ goto next_node;
3670+ }
3671+ success = xb_file_flush(info_file);
3672+ if (!success) {
3673+ os_file_get_last_error(TRUE);
3674+ goto next_node;
3675+ }
3676 next_node:
3677- if (info_file != XB_FILE_UNDEFINED) {
3678- os_file_close(info_file);
3679- info_file = XB_FILE_UNDEFINED;
3680- }
3681- mutex_exit(&(dict_sys->mutex));
3682- mutex_enter(&(f_system->mutex));
3683-
3684- node = UT_LIST_GET_NEXT(chain, node);
3685+ if (info_file != XB_FILE_UNDEFINED) {
3686+ os_file_close(info_file);
3687+ info_file = XB_FILE_UNDEFINED;
3688 }
3689-
3690- space = UT_LIST_GET_NEXT(space_list, space);
3691+ mutex_exit(&(dict_sys->mutex));
3692 }
3693- mutex_exit(&(f_system->mutex));
3694-
3695- ut_free(buf);
3696 }
3697+
3698+ ut_free(buf);
3699 }
3700
3701 /* print binlog position (again?) */
3702@@ -4921,12 +4929,6 @@
3703 exit(EXIT_FAILURE);
3704 }
3705
3706- if (xtrabackup_incremental && xtrabackup_compact) {
3707- msg("xtrabackup: error: --compact cannot be used with "
3708- "incremental backups.\n");
3709- exit(EXIT_FAILURE);
3710- }
3711-
3712 if (xtrabackup_incremental && xtrabackup_stream &&
3713 xtrabackup_stream_fmt == XB_STREAM_FMT_TAR) {
3714 msg("xtrabackup: error: "
3715
3716=== modified file 'src/xtrabackup.h'
3717--- src/xtrabackup.h 2013-01-11 13:00:50 +0000
3718+++ src/xtrabackup.h 2013-01-14 11:06:22 +0000
3719@@ -21,6 +21,8 @@
3720 #ifndef XB_XTRABACKUP_H
3721 #define XB_XTRABACKUP_H
3722
3723+#include "datasink.h"
3724+
3725 typedef struct {
3726 ulint page_size;
3727 ulint zip_size;
3728@@ -33,13 +35,39 @@
3729 XB_STREAM_FMT_XBSTREAM
3730 } xb_stream_fmt_t;
3731
3732+/* ======== Datafiles iterator ======== */
3733+typedef struct {
3734+ fil_system_t *system;
3735+ fil_space_t *space;
3736+ fil_node_t *node;
3737+ ibool started;
3738+ os_mutex_t mutex;
3739+} datafiles_iter_t;
3740+
3741 /* value of the --incremental option */
3742 extern LSN64 incremental_lsn;
3743
3744+extern char *xtrabackup_target_dir;
3745+extern ds_ctxt_t *ds_meta;
3746+extern ds_ctxt_t *ds_data;
3747+
3748 void xtrabackup_io_throttling(void);
3749 my_bool xb_write_delta_metadata(const char *filename,
3750 const xb_delta_info_t *info);
3751
3752+datafiles_iter_t *datafiles_iter_new(fil_system_t *f_system);
3753+fil_node_t *datafiles_iter_next(datafiles_iter_t *it);
3754+void datafiles_iter_free(datafiles_iter_t *it);
3755+
3756+/************************************************************************
3757+Initialize the tablespace memory cache and populate it by scanning for and
3758+opening data files */
3759+ulint xb_data_files_init(void);
3760+
3761+/************************************************************************
3762+Destroy the tablespace memory cache. */
3763+void xb_data_files_close(void);
3764+
3765 /***********************************************************************
3766 Reads the space flags from a given data file and returns the compressed
3767 page size, or 0 if the space is not compressed. */
3768
3769=== added file 'test/disabled/workaround_for_lp855155'
3770=== modified file 'test/inc/incremental_sample-db/incremental_sample-schema.sql'
3771--- test/inc/incremental_sample-db/incremental_sample-schema.sql 2011-07-05 04:17:41 +0000
3772+++ test/inc/incremental_sample-db/incremental_sample-schema.sql 2013-01-14 11:06:22 +0000
3773@@ -1,5 +1,6 @@
3774 DROP TABLE IF EXISTS `test`;
3775 CREATE TABLE `test` (
3776- `a` int(11) DEFAULT NULL,
3777- `number` int(11) DEFAULT NULL
3778+ `a` int(11) NOT NULL PRIMARY KEY,
3779+ `number` int(11) DEFAULT NULL,
3780+ KEY(number)
3781 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
3782
3783=== renamed file 'test/disabled/compact.sh' => 'test/t/compact.sh'
3784--- test/disabled/compact.sh 2012-02-16 18:02:07 +0000
3785+++ test/t/compact.sh 2013-01-14 11:06:22 +0000
3786@@ -4,8 +4,7 @@
3787
3788 . inc/common.sh
3789
3790-init
3791-run_mysqld --innodb_file_per_table
3792+start_server --innodb_file_per_table
3793 load_dbase_schema sakila
3794 load_dbase_data sakila
3795
3796@@ -16,20 +15,20 @@
3797
3798 record_db_state sakila
3799
3800-stop_mysqld
3801+stop_server
3802
3803 # Remove datadir
3804 rm -r $mysql_datadir
3805
3806 # Restore sakila
3807-vlog "Applying log"
3808-innobackupex --apply-log $backup_dir
3809+
3810+innobackupex --apply-log --rebuild-indexes $backup_dir
3811
3812 vlog "Restoring MySQL datadir"
3813 mkdir -p $mysql_datadir
3814 innobackupex --copy-back $backup_dir
3815
3816-run_mysqld
3817+start_server
3818
3819 verify_db_state sakila
3820
3821
3822=== renamed file 'test/disabled/compact_compressed.sh' => 'test/t/compact_compressed.sh'
3823--- test/disabled/compact_compressed.sh 2012-02-16 18:02:07 +0000
3824+++ test/t/compact_compressed.sh 2013-01-14 11:06:22 +0000
3825@@ -4,8 +4,6 @@
3826
3827 . inc/common.sh
3828
3829-init
3830-
3831 if [ -z "$INNODB_VERSION" ]; then
3832 echo "Requires InnoDB plugin or XtraDB" >$SKIPPED_REASON
3833 exit $SKIPPED_EXIT_CODE
3834@@ -17,37 +15,63 @@
3835 --innodb_file_format=Barracuda"
3836
3837 #
3838-# Test compact backup of a compressed tablespace with a specific page size
3839+# Test compact backup of a compressed tablespace with a specific page size
3840 #
3841 function test_compact_compressed()
3842 {
3843- page_size=$1
3844+ local page_size=$1
3845+ local backup_dir
3846
3847 echo "************************************************************************"
3848 echo "Testing compact backup with compressed page size=${page_size}KB "
3849 echo "************************************************************************"
3850
3851- run_mysqld ${mysqld_additional_args}
3852+ start_server ${mysqld_additional_args}
3853
3854 load_dbase_schema sakila
3855 load_dbase_data sakila
3856
3857+ backup_dir="$topdir/backup"
3858+
3859 vlog "Compressing tables"
3860
3861 table_list=`${MYSQL} ${MYSQL_ARGS} -Ns -e \
3862 "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='sakila' \
3863-AND TABLE_TYPE='BASE TABLE'"`
3864+AND TABLE_TYPE='BASE TABLE' AND ENGINE='InnoDB'"`
3865
3866 for t in $table_list; do
3867 run_cmd ${MYSQL} ${MYSQL_ARGS} -e \
3868 "ALTER TABLE $t ENGINE=InnoDB ROW_FORMAT=compressed \
3869 KEY_BLOCK_SIZE=$page_size" sakila
3870 done
3871+
3872+ innobackupex --no-timestamp --compact $backup_dir
3873+ record_db_state sakila
3874+
3875+ stop_server
3876+
3877+ rm -r $mysql_datadir
3878+
3879+ innobackupex --apply-log --rebuild-indexes $backup_dir
3880+
3881+ vlog "Restoring MySQL datadir"
3882+ mkdir -p $mysql_datadir
3883+ innobackupex --copy-back $backup_dir
3884+
3885+ start_server
3886+
3887+ verify_db_state sakila
3888+
3889+ stop_server
3890+ clean
3891 }
3892
3893-for page_size in 1 2 4 8 16; do
3894- init
3895+
3896+# Cannot test with lower page sizes, because not all tables can be compressed
3897+# with KEY_BLOCK_SIZE < 8. This can be changed, if we implement 'canned'
3898+# databases in the test suite, which will contain tables compressed with the
3899+# minimum possible page size.
3900+for page_size in 8 16; do
3901 test_compact_compressed ${page_size}
3902- clean
3903 done
3904
3905
3906=== modified file 'test/testrun.sh'
3907--- test/testrun.sh 2013-01-09 22:25:19 +0000
3908+++ test/testrun.sh 2013-01-14 11:06:22 +0000
3909@@ -86,9 +86,10 @@
3910 else
3911 LD_LIBRARY_PATH=$MYSQL_BASEDIR/lib/mysql:$LD_LIBRARY_PATH
3912 fi
3913+ DYLD_LIBRARY_PATH="$LD_LIBRARY_PATH"
3914
3915 export TEST_BASEDIR PORT_BASE TAR MYSQL_BASEDIR MYSQL MYSQLD MYSQLADMIN \
3916-MYSQL_INSTALL_DB PATH LD_LIBRARY_PATH
3917+MYSQL_INSTALL_DB PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH MYSQLDUMP
3918 }
3919
3920 function get_version_info()
3921
3922=== modified file 'utils/build.sh'
3923--- utils/build.sh 2013-01-02 04:23:18 +0000
3924+++ utils/build.sh 2013-01-14 11:06:22 +0000
3925@@ -10,26 +10,34 @@
3926 AUTO_DOWNLOAD=${AUTO_DOWNLOAD:-no}
3927 MASTER_SITE="http://s3.amazonaws.com/percona.com/downloads/community"
3928
3929+top_dir=`pwd`
3930+
3931 # Percona Server 5.5 does not build with -Werror, so ignore DEBUG for now
3932 if [ -n "$DEBUG" -a "$1" != "galera55" -a "$1" != "xtradb55" -a "$1" != "xtradb51" -a "$1" != "xtradb" ]
3933 then
3934 # InnoDB extra debug flags
3935- innodb_extra_debug="-DUNIV_DEBUG -DUNIV_SYNC_DEBUG -DUNIV_MEM_DEBUG \
3936+ innodb_extra_debug="-DUNIV_DEBUG -DUNIV_MEM_DEBUG \
3937 -DUNIV_DEBUG_THREAD_CREATION -DUNIV_DEBUG_LOCK_VALIDATE -DUNIV_DEBUG_PRINT \
3938 -DUNIV_DEBUG_FILE_ACCESS -DUNIV_SEARCH_DEBUG -DUNIV_LOG_LSN_DEBUG \
3939 -DUNIV_ZIP_DEBUG -DUNIV_AHI_DEBUG -DUNIV_SQL_DEBUG -DUNIV_AIO_DEBUG \
3940 -DUNIV_LRU_DEBUG -DUNIV_BUF_DEBUG -DUNIV_HASH_DEBUG -DUNIV_LIST_DEBUG -DUNIV_IBUF_DEBUG"
3941- export CFLAGS="$CFLAGS -g -O0 $innodb_extra_debug -DSAFE_MUTEX -DSAFEMALLOC"
3942- export CXXFLAGS="$CXXFLAGS -g -O0 $innodb_extra_debug -DSAFE_MUTEX -DSAFEMALLOC"
3943+ CFLAGS="$CFLAGS -g -O0 $innodb_extra_debug -DSAFE_MUTEX -DSAFEMALLOC"
3944+ CXXFLAGS="$CXXFLAGS -g -O0 $innodb_extra_debug -DSAFE_MUTEX -DSAFEMALLOC"
3945 extra_config_51="--with-debug=full"
3946 extra_config_55="-DWITH_DEBUG=ON"
3947 else
3948- export CFLAGS="$CFLAGS -g -O3"
3949- export CXXFLAGS="$CXXFLAGS -g -O3"
3950+ CFLAGS="$CFLAGS -g -O3"
3951+ CXXFLAGS="$CXXFLAGS -g -O3"
3952 extra_config_51=
3953 extra_config_55=
3954 fi
3955
3956+xtrabackup_include_dir="$top_dir/src"
3957+CFLAGS="$CFLAGS -I$xtrabackup_include_dir"
3958+CXXFLAGS="$CXXFLAGS -I$xtrabackup_include_dir"
3959+
3960+export CFLAGS CXXFLAGS
3961+
3962 MAKE_CMD=make
3963 if gmake --version > /dev/null 2>&1
3964 then
3965@@ -181,8 +189,6 @@
3966 fi
3967
3968 type=$1
3969-top_dir=`pwd`
3970-
3971
3972 case "$type" in
3973 "innodb51" | "plugin")

Subscribers

People subscribed via source and target branches