Merge lp:~laurynas-biveinis/percona-xtrabackup/xb-changed-page-bitmap into lp:percona-xtrabackup/2.1

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-xtrabackup/xb-changed-page-bitmap
Merge into: lp:percona-xtrabackup/2.1
Diff against target: 3005 lines (+2092/-170)
34 files modified
doc/source/innobackupex/how_innobackupex_works.rst (+2/-2)
doc/source/xtrabackup_bin/incremental_backups.rst (+1/-1)
doc/source/xtrabackup_bin/xbk_option_reference.rst (+4/-0)
innobackupex (+113/-65)
src/Makefile (+11/-2)
src/changed_page_bitmap.cc (+1013/-0)
src/changed_page_bitmap.h (+84/-0)
src/compact.cc (+1/-1)
src/fil_cur.cc (+23/-19)
src/fil_cur.h (+10/-5)
src/innodb_int.cc (+1/-1)
src/innodb_int.h (+2/-0)
src/read_filt.cc (+206/-0)
src/read_filt.h (+63/-0)
src/xtrabackup.cc (+118/-31)
src/xtrabackup.h (+6/-0)
test/inc/common.sh (+61/-0)
test/inc/ib_incremental_common.sh (+22/-2)
test/t/bug1007446.sh (+1/-1)
test/t/ib_incremental_bitmap.sh (+25/-0)
test/t/ib_incremental_full_scan.sh (+7/-0)
test/t/xb_incremental_bitmap_misc.sh (+76/-0)
test/t/xb_incremental_compressed.inc (+59/-32)
test/t/xb_incremental_compressed_bitmap_16kb.sh (+28/-0)
test/t/xb_incremental_compressed_bitmap_1kb.sh (+28/-0)
test/t/xb_incremental_compressed_bitmap_2kb.sh (+28/-0)
test/t/xb_incremental_compressed_bitmap_4kb.sh (+28/-0)
test/t/xb_incremental_compressed_bitmap_8kb.sh (+28/-0)
test/t/xb_incremental_compressed_full_scan_16kb.sh (+8/-0)
test/t/xb_incremental_compressed_full_scan_1kb.sh (+8/-0)
test/t/xb_incremental_compressed_full_scan_2kb.sh (+8/-0)
test/t/xb_incremental_compressed_full_scan_4kb.sh (+8/-0)
test/t/xb_incremental_compressed_full_scan_8kb.sh (+8/-0)
test/t/xb_log_overwrap.sh (+3/-8)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-xtrabackup/xb-changed-page-bitmap
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Review via email: mp+157703@code.launchpad.net

This proposal supersedes a proposal from 2013-03-23.

This proposal has been superseded by a proposal from 2013-04-16.

Description of the change

2nd MP:

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

Updated to the current 2.1 trunk.

1st MP:

BT 16274

http://jenkins.percona.com/job/percona-xtrabackup-2.1-param/237/

The MP has a couple of changes to anticipate the BT 28340 5.6 merge in innodb_int.h (introduction of lsn_t and friends). But this MP and the 28340 MP will need some updating depending on their trunk merge order.

Implement bitmap-based incremental backups.
Blueprints:
https://blueprints.launchpad.net/percona-xtrabackup/+spec/changed-page-bmp-inc-backups
and
https://blueprints.launchpad.net/percona-xtrabackup/+spec/multipl-bmp-file-inc-backup
- innobackupex: split the xtrabackup_suspended to three different
  files depending on the context (1st suspend, 2nd suspend, log copy
  end). If backing up, check if server supports changed page bitmaps
  by querying for the presence of I_S.INNODB_CHANGED_PAGES plugin. If
  found, add 1st suspend to xtrabackup invocation and issue FLUSH
  CHANGED_PAGE_BITMAPS during it. Factor out waitpid/sync file
  presence loop out of wait_for_ibbackup_suspend and resume_ibbackup
  into new subroutine wait_for_ibbackup_file_create. Split the log
  copying finish logic out of resume_ibbackup into a new subroutine
  wait_for_ibbackup_log_copy_finish.

- New source files changed_page_bitmap.h and changed_page_bitmap.cc
  containing the types and functions for working with page bitmaps and
  their iterators.

- New source files read_filt.h and read_filt.cc containing the data
  file read filter abstraction. Provide two filters: rf_pass_through
  for no filtering, and rf_bitmap that uses the changed page bitmaps.

- fil_cur.h, fil_cur.cc: xb_fil_cur_t: move offset field to
  xb_read_filt_ctxt_t. Add fields for the read filter and its
  context: read_filter and read_filter_ctxt. xb_fil_cur_open(): new
  arg read_filter. Initialize the read filter context.
  xb_fil_cur_read: use the read filter to get the next read offset and
  length. xb_fil_cur_close(): deinitialize the read filter.

- innodb_int.h: include mysql_version.h to make version checks not
  depend on mysql_version.h having been included before innodb_int.h.

- innodb_int.cc: fix an unrelated warning to make it easier to ensure
  that the feature does not regress in warnings: xb_space_get_by_name:
  mark fold as unused.

- xtrabackup.h: declare checkpoint_lsn_start and changed_page_bitmap.

- xtrabackup.cc: split xtrabackup_suspended to three different files
  as in innobackupex. New functions xb_make_sync_file_name and
  xtrabackup_suspend, rename xb_create_suspend_file to
  xb_create_sync_file. Add new option --suspend-at-start to suspend
  xtrabackup after the log copying thread has started.
  xtrabackup_copy_datafile: set up a bitmap read filter if the bitmap
  has been allocated, a pass through filter otherwise and pass it to
  the file cursor.
  xtrabackup_backup_func(): in case of incremental backups attempt to
  read the changed page bitmap. Write a message if the bitmap was
  found, otherwise that a full scan is going to be used. Free the
  bitmap in the end.

- test/inc/common.sh: init_server_variables(), reset_server_variables:
  set up server error log location in SRV_MYSQLD_ERRFILE[].
  switch_server(): set up MySQL error log.
  check_full_scan_inc_backup(), check_bitmap_inc_backup(): new
  functions for grepping XtraBackup output for the incremental backup
  type used. wait_for_xb_suspend(), resume_suspended_xb(): new helper
  functions for the testcases that use xtrabackup suspend.

- Rename test test/t/ib_incremental.sh to a test include file
  test/inc/ib_incremental_common.sh. Pass additional args in
  $mysqld_extra_args to mysqld.

- Rename test test/t/xb_incremental.sh to an include file
  test/inc/xb_incremental_common.sh. Pass additional args in
  $mysqld_extra_args to mysqld. Adjust server options to have a
  minimum possible log file size (1M) and thread concurrency that can
  support such size for 5.0. Change the schema of test table T2 to
  have large rows. Insert enough rows into a database so that the
  resulting bitmap file spans at least two bitmap pages for the T2
  tablespace.

- Rename test test/t/ib_incremental.sh to an include file
  test/inc/ib_incremental_common.sh. Pass additional args in
  $mysqld_extra_args to mysqld. Tweak it to increase the testing
  coverage. ADd two new testcases ib_incremental_bitmap.sh and
  ib_incremental_full_scan.sh that use it.

- Adjust test/t/xb_incremental_compressed.inc for bitmap backups. New
  tests xb_incremental_compressed_bitmap_(1-16)kb.sh. Rename
  the previous xb_incremental_compressed_*.sh tests to
  xb_incremental_compressed_full_scan_*.sh. Remove the InnoDB version
  check from xb_incremental_compressed.inc as it's always passing with
  the currently supported versions.

- New test xb_incremental_bitmap_missing.sh to test diagnostics for
  partially-missing bitmap data.

- Temporarily disable all the bitmap tests on XtraDB Cluster
  configuration until a supporting version is released.

- Adjust test/t/bug1007446.sh for changed suspend file names.

- Adjust test/t/xb_log_overwraph.sh to use
  wait_for_xb_to_suspend/resume_suspended_xb.

- Makefile: update dependencies.

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

I have merged the 28340 MP, so this probably needs updating now according to the comments?

review: Needs Information
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

Yes, I will update it. I expect mostly mechanical changes (innodb_int.h does not need to provide lsn_t, 64-bit args instead of 32-bit pairs for I/O, etc).

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

Laurynas,

There's no time for a detailed review, but:

   - it would be nice to have an option to force the old .delta
     calculation method even if bitmaps are available; something like
     --incremental-force-scan?
   - there's no need to append ';' to the end of a query in
     mysql_query()
   - the optimization attempt to wrap multiple INSERT statements for
     incremental tests into BEGIN/COMMIT does not work, as we disconnect
     between mysql client invokations; it should be smth like the
     following:
: (echo "BEGIN;"; echo "..."; echo "COMMIT;") | $MYSQL $MYSQL_ARGS ...
   - would updating docs in the same MP be a stretch? Just trying to
     avoid the communication overhead when docs are updated by Hrvoje,
     and the required docs updates seem to be minor

Please let me know if addressing the above would take more than a day. We can then merge the current MP as is, and address the remaining stuff later.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

> - it would be nice to have an option to force the old .delta
> calculation method even if bitmaps are available; something like
> --incremental-force-scan?

Yes.

> - there's no need to append ';' to the end of a query in
> mysql_query()

Ack

> - the optimization attempt to wrap multiple INSERT statements for
> incremental tests into BEGIN/COMMIT does not work, as we disconnect
> between mysql client invokations; it should be smth like the
> following:
> : (echo "BEGIN;"; echo "..."; echo "COMMIT;") | $MYSQL $MYSQL_ARGS ...

Right, I forgot that it's all separate connections, thus separate transactions. I had some sort of persistent connection setup in progress at bug 1119451, comments #2 and #3. I think here we can just go with one statement transactions and optimize later as needed (bug 1119451 stuff is incomplete).

> - would updating docs in the same MP be a stretch? Just trying to
> avoid the communication overhead when docs are updated by Hrvoje,
> and the required docs updates seem to be minor

Will review, should be feasible.

> Please let me know if addressing the above would take more than a day. We can
> then merge the current MP as is, and address the remaining stuff later.

It should take less than a day, and I will work on this today (maybe tomorrow morning will be needed to wait for Jenkins run etc).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/source/innobackupex/how_innobackupex_works.rst'
2--- doc/source/innobackupex/how_innobackupex_works.rst 2012-09-07 13:20:26 +0000
3+++ doc/source/innobackupex/how_innobackupex_works.rst 2013-04-15 15:08:38 +0000
4@@ -15,7 +15,7 @@
5
6 If no mode is specified, |innobackupex| will assume the backup mode.
7
8-By default, it starts :program:`xtrabackup` with the :option:`--suspend-at-end` option, and lets it copy the InnoDB data files. When :program:`xtrabackup` finishes that, :program:`innobackupex` sees it create the :file:`xtrabackup_suspended` file and executes ``FLUSH TABLES WITH READ LOCK``. Then it begins copying the rest of the files.
9+By default, it starts :program:`xtrabackup` with the :option:`--suspend-at-end` option, and lets it copy the InnoDB data files. When :program:`xtrabackup` finishes that, :program:`innobackupex` sees it create the :file:`xtrabackup_suspended_2` file and executes ``FLUSH TABLES WITH READ LOCK``. Then it begins copying the rest of the files.
10
11 If the :option:`--ibbackup` is not supplied, |innobackupex| will try to detect it: if the :file:`xtrabackup_binary` file exists on the backup directory, it reads from it which binary of |xtrabackup| will be used. Otherwise, it will try to connect to the database server in order to determine it. If the connection can't be established, |xtrabackup| will fail and you must specify it (see :ref:`ibk-right-binary`).
12
13@@ -25,7 +25,7 @@
14
15 Once this is done, the backup of the files will begin. It will backup :term:`.frm`, :term:`.MRG`, :term:`.MYD`, :term:`.MYI`, :term:`.TRG`, :term:`.TRN`, :term:`.ARM`, :term:`.ARZ`, :term:`.CSM`, :term:`.CSV` and :term:`.opt` files.
16
17-When all the files are backed up, it resumes :program:`ibbackup` and wait until it finishes copying the transactions done while the backup was done. Then, the tables are unlocked, the slave is started (if the option :option:`--safe-slave-backup` was used) and the connection with the server is closed. Then, it removes the :file:`xtrabackup_suspended` file and permits :program:`xtrabackup` to exit.
18+When all the files are backed up, it resumes :program:`ibbackup` and wait until it finishes copying the transactions done while the backup was done. Then, the tables are unlocked, the slave is started (if the option :option:`--safe-slave-backup` was used) and the connection with the server is closed. Then, it removes the :file:`xtrabackup_suspended_2` file and permits :program:`xtrabackup` to exit.
19
20 It will also create the following files in the directory of the backup:
21
22
23=== modified file 'doc/source/xtrabackup_bin/incremental_backups.rst'
24--- doc/source/xtrabackup_bin/incremental_backups.rst 2013-01-17 15:08:37 +0000
25+++ doc/source/xtrabackup_bin/incremental_backups.rst 2013-04-15 15:08:38 +0000
26@@ -4,7 +4,7 @@
27
28 Both |xtrabackup| and |innobackupex| tools supports incremental backups, which means that it can copy only the data that has changed since the last full backup. You can perform many incremental backups between each full backup, so you can set up a backup process such as a full backup once a week and an incremental backup every day, or full backups every day and incremental backups every hour.
29
30-Incremental backups work because each InnoDB page (usually 16kb in size) contains a log sequence number, or :term:`LSN`. The :term:`LSN` is the system version number for the entire database. Each page's :term:`LSN` shows how recently it was changed. An incremental backup copies each page whose :term:`LSN` is newer than the previous incremental or full backup's :term:`LSN`.
31+Incremental backups work because each InnoDB page (usually 16kb in size) contains a log sequence number, or :term:`LSN`. The :term:`LSN` is the system version number for the entire database. Each page's :term:`LSN` shows how recently it was changed. An incremental backup copies each page whose :term:`LSN` is newer than the previous incremental or full backup's :term:`LSN`. There are two algorithms in use to find the set of such pages to be copied. The first one, available with all the server types and versions, is to check the page :term:`LSN` directly by reading all the data pages. The second one, available with |Percona Server|, is to enable the changed page tracking feature on the server, which will note the pages as they are being changed. This information will be then written out in a compact separate so-called bitmap file. The |xtrabackup| binary will use that file to read only the data pages it needs for the incremental backup, potentially saving many read requests. The latter algorithm is enabled by default if the |xtrabackup| binary finds the bitmap file. It is possible to specify :option:`--incremental-force-scan` to read all the pages even if the bitmap data is available.
32
33 Incremental backups do not actually compare the data files to the previous backup's data files. In fact, you can use :option:`--incremental-lsn` to perform an incremental backup without even having the previous backup, if you know its :term:`LSN`. Incremental backups simply read the pages and compare their :term:`LSN` to the last backup's :term:`LSN`. You still need a full backup to recover the incremental changes, however; without a full backup to act as a base, the incremental backups are useless.
34
35
36=== modified file 'doc/source/xtrabackup_bin/xbk_option_reference.rst'
37--- doc/source/xtrabackup_bin/xbk_option_reference.rst 2012-05-18 11:19:17 +0000
38+++ doc/source/xtrabackup_bin/xbk_option_reference.rst 2013-04-15 15:08:38 +0000
39@@ -65,6 +65,10 @@
40
41 When preparing an incremental backup, this is the directory where the incremental backup is combined with the full backup to make a new full backup.
42
43+.. option:: --incremental-force-scan
44+
45+ When creating an incremental backup, force a full scan of the data pages in the instance being backuped even if the complete changed page bitmap data is available.
46+
47 .. option:: --incremental-lsn=name
48
49 When creating an incremental backup, you can specify the log sequence number (:term:`LSN`) instead of specifying :option:`--incremental-basedir`. For databases created by *MySQL* and *Percona Server* 5.0-series versions, specify the :term:`LSN` as two 32-bit integers in high:low format. For databases created in 5.1 and later, specify the :term:`LSN` as a single 64-bit integer. ##ATTENTION##: If a wrong LSN value is specified, it is impossible to diagnose this, causing the backup to be unusable. Be careful!
50
51=== modified file 'innobackupex'
52--- innobackupex 2013-04-09 10:58:46 +0000
53+++ innobackupex 2013-04-15 15:08:38 +0000
54@@ -71,6 +71,10 @@
55 # end of modifiable parameters
56 ######################################################################
57
58+#######################
59+# Server capabilities #
60+#######################
61+my $have_changed_page_bitmaps = 0;
62
63 # command line options
64 my $option_help = '';
65@@ -144,8 +148,8 @@
66 # backup directory pathname
67 my $backup_dir = '';
68
69-# name of the ibbackup suspend-at-end file
70-my $suspend_file = '';
71+# directory where innobackupex aux files are cretead
72+my $work_dir;
73
74 # home directory of innoDB log files
75 my $innodb_log_group_home_dir = '';
76@@ -221,6 +225,12 @@
77 my $xtrabackup_pid_file = 'xtrabackup_pid';
78 my %rsync_files_hash;
79
80+my $xb_fn_suspended_at_start = "/xtrabackup_suspended_1";
81+my $xb_fn_suspended_at_end = "/xtrabackup_suspended_2";
82+my $xb_fn_log_copied = "/xtrabackup_log_copied";
83+my @xb_suspend_files = ($xb_fn_suspended_at_start, $xb_fn_suspended_at_end,
84+ $xb_fn_log_copied);
85+
86 my $copy_dir_src;
87 my $copy_dir_dst;
88 my $copy_dir_exclude_regexp;
89@@ -379,12 +389,25 @@
90 #
91 sub backup {
92 my $orig_datadir = get_option(\%config, $option_defaults_group, 'datadir');
93+ my $suspend_file;
94+
95+ if ($option_incremental) {
96+ detect_mysql_capabilities_for_backup(\%mysql);
97+ }
98
99 # start ibbackup as a child process
100 start_ibbackup();
101
102+ if ($option_incremental && $have_changed_page_bitmaps) {
103+ $suspend_file = $work_dir . $xb_fn_suspended_at_start;
104+ wait_for_ibbackup_suspend($suspend_file);
105+ mysql_query(\%mysql, 'FLUSH NO_WRITE_TO_BINLOG CHANGED_PAGE_BITMAPS');
106+ resume_ibbackup($suspend_file);
107+ }
108+
109 # wait for ibbackup to suspend itself
110- wait_for_ibbackup_suspend();
111+ $suspend_file = $work_dir . $xb_fn_suspended_at_end;
112+ wait_for_ibbackup_suspend($suspend_file);
113
114 if ($option_safe_slave_backup) {
115 wait_for_safe_slave(\%mysql);
116@@ -408,8 +431,10 @@
117 # (or finalize the backup by syncing changes if using rsync)
118 backup_files(0);
119
120- # resume ibbackup and wait till log copying is finished
121- resume_ibbackup();
122+ # resume XtraBackup and wait till it has finished
123+ resume_ibbackup($suspend_file);
124+ $suspend_file = $work_dir . $xb_fn_log_copied;
125+ wait_for_ibbackup_log_copy_finish($suspend_file);
126
127 # release read locks on all tables
128 mysql_unlockall(\%mysql) if !$option_no_lock;
129@@ -887,24 +912,50 @@
130
131 }
132
133-
134-#
135-# wait_for_ibbackup_suspend subroutine waits until ibbackup has suspended
136+#
137+# Loops until the specified file is created or the ibbackup process dies.
138+#
139+#
140+# If this function detects that the xtrabackup process has terminated, it also
141+# sets ibbackup_exit_code and resets ibbackup_pid to avoid trying to reap a
142+# non-existing process later
143+#
144+sub wait_for_ibbackup_file_create {
145+
146+ my $suspend_file = shift;
147+ my $pid = -1;
148+
149+ for (;;) {
150+ # check if the xtrabackup process is still alive _before_ checking if
151+ # the file exists to avoid a race condition when the file is created
152+ # and the process terminates right after we do the file check
153+ $pid = waitpid($ibbackup_pid, &WNOHANG);
154+
155+ last if -e $suspend_file;
156+
157+ if ($ibbackup_pid == $pid) {
158+ # The file doesn't exist, but the process has terminated
159+ Die "ibbackup child process has died";
160+ }
161+
162+ sleep 1;
163+ }
164+
165+ if ($pid == $ibbackup_pid) {
166+ $ibbackup_exit_code = $CHILD_ERROR >> 8;
167+ $ibbackup_pid = '';
168+ }
169+}
170+
171+#
172+# wait_for_ibbackup_suspend subroutine waits until ibbackup has suspended
173 # itself.
174 #
175 sub wait_for_ibbackup_suspend {
176+ my $suspend_file = shift;
177 print STDERR "$prefix Waiting for ibbackup (pid=$ibbackup_pid) to suspend\n";
178 print STDERR "$prefix Suspend file '$suspend_file'\n\n";
179- for (;;) {
180- usleep(100000);
181- last if -e $suspend_file;
182-
183- # check that ibbackup child process is still alive
184- if ($ibbackup_pid == waitpid($ibbackup_pid, &WNOHANG)) {
185- $ibbackup_pid = '';
186- Die "ibbackup child process has died";
187- }
188- }
189+ wait_for_ibbackup_file_create($suspend_file);
190 $now = current_time();
191 open XTRABACKUP_PID, "> $option_tmpdir/$xtrabackup_pid_file";
192 print XTRABACKUP_PID $ibbackup_pid;
193@@ -912,43 +963,27 @@
194 print STDERR "\n$now $prefix Continuing after ibbackup has suspended\n";
195 }
196
197-
198 #
199 # resume_ibbackup subroutine signals ibbackup to finish log copying by deleting
200-# the 'xtrabackup_suspended' file and waits until log copying is stopped,
201-# i.e. until 'xtrabackup_suspended' is created again.
202-#
203-# If this functions detects that the xtrabackup process has terminated, it also
204-# sets ibbackup_exit_code and resets ibbackup_pid to avoid trying to reap a
205-# non-existing process later
206+# $suspend_file.
207 #
208 sub resume_ibbackup {
209- my $pid = -1;
210+ my $suspend_file = shift;
211+ unlink $suspend_file || Die "Failed to delete '$suspend_file': $!";
212+}
213
214- $now = current_time();
215+#
216+# Wait until xtrabackup finishes copying log or dies. The log copying is
217+# signaled by a sync file creation. If this function detects that the
218+# xtrabackup process has terminated, it also sets ibbackup_exit_code and resets
219+# ibbackup_pid to avoid trying to reap a non-existing process later.
220+#
221+sub wait_for_ibbackup_log_copy_finish {
222+ my $suspend_file = shift;
223+ my $now = current_time();
224 print STDERR "$now $prefix Waiting for log copying to finish\n\n";
225- unlink $suspend_file || Die "Failed to delete '$suspend_file': $!";
226-
227- for (;;) {
228- # check if the xtrabackup process is still alive _before_ checking if
229- # the file exists to avoid a race condition when the file is created and
230- # the process terminates right after we do the file check
231- $pid = waitpid($ibbackup_pid, &WNOHANG);
232-
233- last if -e $suspend_file;
234-
235- if ($ibbackup_pid == $pid) {
236- # The file doesn't exist, but the process has terminated
237- Die "ibbackup child process has died";
238- }
239-
240- sleep 1;
241- }
242-
243- if ($pid == $ibbackup_pid) {
244- $ibbackup_exit_code = $CHILD_ERROR >> 8;
245- $ibbackup_pid = '';
246- }
247+
248+ wait_for_ibbackup_file_create($suspend_file);
249
250 unlink $suspend_file || Die "Failed to delete '$suspend_file': $!";
251 }
252@@ -972,7 +1007,6 @@
253 $ibbackup_pid = '';
254 return $CHILD_ERROR >> 8;
255 }
256-
257
258 #
259 # start_ibbackup subroutine spawns a child process running ibbackup
260@@ -1051,6 +1085,9 @@
261 } else {
262 $options = $options . " --incremental-basedir='$incremental_basedir'";
263 }
264+ if ($have_changed_page_bitmaps) {
265+ $options = $options . " --suspend-at-start";
266+ }
267 }
268
269 if ($option_tables_file) {
270@@ -1638,28 +1675,31 @@
271 $backup_dir = File::Spec->rel2abs(make_backup_dir());
272 print STDERR "$prefix Created backup directory $backup_dir\n";
273 if (!$option_stream) {
274- $backup_config_file = $backup_dir . '/backup-my.cnf';
275- $suspend_file = $backup_dir . '/xtrabackup_suspended';
276- $binlog_info = $backup_dir . '/xtrabackup_binlog_info';
277- $galera_info = $backup_dir . '/xtrabackup_galera_info';
278- $slave_info = $backup_dir . '/xtrabackup_slave_info';
279+ $work_dir = $backup_dir;
280 } else {
281- $suspend_file = $option_tmpdir . '/xtrabackup_suspended';
282- $backup_config_file = $option_tmpdir . '/backup-my.cnf';
283- $binlog_info = $option_tmpdir . '/xtrabackup_binlog_info';
284- $galera_info = $option_tmpdir . '/xtrabackup_galera_info';
285- $slave_info = $option_tmpdir . '/xtrabackup_slave_info';
286+ $work_dir = $option_tmpdir;
287 }
288+ $backup_config_file = $work_dir . '/backup-my.cnf';
289+ $binlog_info = $work_dir . '/xtrabackup_binlog_info';
290+ $galera_info = $work_dir . '/xtrabackup_galera_info';
291+ $slave_info = $work_dir . '/xtrabackup_slave_info';
292 write_backup_config_file($backup_config_file);
293+
294+ foreach (@xb_suspend_files) {
295+ my $suspend_file = $work_dir . "$_";
296+ if ( -e "$suspend_file" ) {
297+ print STDERR
298+ "WARNING : A left over instance of " .
299+ "suspend file '$suspend_file' was found.\n";
300+ unlink "$suspend_file"
301+ || Die "Failed to delete '$suspend_file': $!";
302+ }
303+ }
304+
305 } elsif ($option_copy_back || $option_move_back) {
306 #$backup_config_file = $backup_dir . '/backup-my.cnf';
307 #read_config_file($backup_config_file, \%backup_config);
308 }
309-
310- if ( -e "$suspend_file" ) {
311- print STDERR "WARNING : A left over instance of suspend file '$suspend_file' was found.\n";
312- unlink $suspend_file || Die "Failed to delete '$suspend_file': $!";
313- }
314 }
315
316
317@@ -2730,6 +2770,14 @@
318 return $rcode;
319 }
320
321+#
322+# Query the server to find out what backup capabilities it supports.
323+#
324+sub detect_mysql_capabilities_for_backup {
325+ $have_changed_page_bitmaps =
326+ mysql_query($_[0], 'SELECT COUNT(*) FROM INFORMATION_SCHEMA.PLUGINS '.
327+ 'WHERE PLUGIN_NAME LIKE "INNODB_CHANGED_PAGES"')
328+}
329
330 =pod
331
332
333=== modified file 'src/Makefile'
334--- src/Makefile 2013-04-09 07:24:21 +0000
335+++ src/Makefile 2013-04-15 15:08:38 +0000
336@@ -41,7 +41,9 @@
337 datasink.o \
338 xbstream_write.o \
339 quicklz/quicklz.o
340-XTRABACKUPCCOBJS = xtrabackup.o innodb_int.o compact.o fil_cur.o write_filt.o
341+XTRABACKUPCCOBJS = xtrabackup.o innodb_int.o compact.o fil_cur.o write_filt.o \
342+ changed_page_bitmap.o \
343+ read_filt.o
344
345 XBSTREAMOBJS = xbstream.o xbstream_write.o xbstream_read.o
346
347@@ -231,7 +233,14 @@
348 xbcrypt: $(XBCRYPTOBJS) $(MYSQLOBJS)
349 $(CXX) $(CXXFLAGS) $^ $(INC) $(MYSQLOBJS) $(LIBS) -o $@
350
351-xtrabackup.o: xtrabackup.cc xb_regex.h write_filt.h fil_cur.h xtrabackup.h compact.h
352+changed_page_bitmap.o: changed_page_bitmap.cc changed_page_bitmap.h innodb_int.h \
353+ common.h xtrabackup.h
354+
355+read_filt.o: read_filt.cc read_filt.h fil_cur.h xtrabackup.h innodb_int.h \
356+ common.h changed_page_bitmap.h
357+
358+xtrabackup.o: xtrabackup.cc xb_regex.h write_filt.h fil_cur.h xtrabackup.h compact.h \
359+ common.h changed_page_bitmap.h read_filt.h innodb_int.h
360
361 $(TARGET): $(XTRABACKUPCCOBJS) $(XTRABACKUPCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBARCHIVE_A)
362 $(CXX) $(CFXXLAGS) $(XTRABACKUPCCOBJS) $(XTRABACKUPCOBJS) $(INNODBOBJS) $(MYSQLOBJS) $(LIBS) \
363
364=== added file 'src/changed_page_bitmap.cc'
365--- src/changed_page_bitmap.cc 1970-01-01 00:00:00 +0000
366+++ src/changed_page_bitmap.cc 2013-04-15 15:08:38 +0000
367@@ -0,0 +1,1013 @@
368+/******************************************************
369+XtraBackup: hot backup tool for InnoDB
370+(c) 2009-2012 Percona Inc.
371+Originally Created 3/3/2009 Yasufumi Kinoshita
372+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
373+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
374+
375+This program is free software; you can redistribute it and/or modify
376+it under the terms of the GNU General Public License as published by
377+the Free Software Foundation; version 2 of the License.
378+
379+This program is distributed in the hope that it will be useful,
380+but WITHOUT ANY WARRANTY; without even the implied warranty of
381+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
382+GNU General Public License for more details.
383+
384+You should have received a copy of the GNU General Public License
385+along with this program; if not, write to the Free Software
386+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
387+
388+*******************************************************/
389+
390+/* Changed page bitmap implementation */
391+
392+#include "changed_page_bitmap.h"
393+
394+#include "common.h"
395+#include "innodb_int.h"
396+#include "xtrabackup.h"
397+
398+/* TODO: copy-pasted shared definitions from the XtraDB bitmap write code.
399+Remove these on the first opportunity, i.e. single-binary XtraBackup. */
400+
401+/* log0online.h */
402+
403+/** Single bitmap file information */
404+struct log_online_bitmap_file_t {
405+ char name[FN_REFLEN]; /*!< Name with full path */
406+ os_file_t file; /*!< Handle to opened file */
407+ ib_uint64_t size; /*!< Size of the file */
408+ ib_uint64_t offset; /*!< Offset of the next read,
409+ or count of already-read bytes
410+ */
411+};
412+
413+/** A set of bitmap files containing some LSN range */
414+struct log_online_bitmap_file_range_t {
415+ size_t count; /*!< Number of files */
416+ /*!< Dynamically-allocated array of info about individual files */
417+ struct files_t {
418+ char name[FN_REFLEN];/*!< Name of a file */
419+ lsn_t start_lsn; /*!< Starting LSN of data in this
420+ file */
421+ ulong seq_num; /*!< Sequence number of this file */
422+ } *files;
423+};
424+
425+/* log0online.c */
426+
427+/** File name stem for bitmap files. */
428+static const char* bmp_file_name_stem = "ib_modified_log_";
429+
430+/** The bitmap file block size in bytes. All writes will be multiples of this.
431+ */
432+enum {
433+ MODIFIED_PAGE_BLOCK_SIZE = 4096
434+};
435+
436+/** Offsets in a file bitmap block */
437+enum {
438+ MODIFIED_PAGE_IS_LAST_BLOCK = 0,/* 1 if last block in the current
439+ write, 0 otherwise. */
440+ MODIFIED_PAGE_START_LSN = 4, /* The starting tracked LSN of this and
441+ other blocks in the same write */
442+ MODIFIED_PAGE_END_LSN = 12, /* The ending tracked LSN of this and
443+ other blocks in the same write */
444+ MODIFIED_PAGE_SPACE_ID = 20, /* The space ID of tracked pages in
445+ this block */
446+ MODIFIED_PAGE_1ST_PAGE_ID = 24, /* The page ID of the first tracked
447+ page in this block */
448+ MODIFIED_PAGE_BLOCK_UNUSED_1 = 28,/* Unused in order to align the start
449+ of bitmap at 8 byte boundary */
450+ MODIFIED_PAGE_BLOCK_BITMAP = 32,/* Start of the bitmap itself */
451+ MODIFIED_PAGE_BLOCK_UNUSED_2 = MODIFIED_PAGE_BLOCK_SIZE - 8,
452+ /* Unused in order to align the end of
453+ bitmap at 8 byte boundary */
454+ MODIFIED_PAGE_BLOCK_CHECKSUM = MODIFIED_PAGE_BLOCK_SIZE - 4
455+ /* The checksum of the current block */
456+};
457+
458+/** Length of the bitmap data in a block */
459+enum { MODIFIED_PAGE_BLOCK_BITMAP_LEN
460+ = MODIFIED_PAGE_BLOCK_UNUSED_2 - MODIFIED_PAGE_BLOCK_BITMAP };
461+
462+/** Length of the bitmap data in a block in page ids */
463+enum { MODIFIED_PAGE_BLOCK_ID_COUNT = MODIFIED_PAGE_BLOCK_BITMAP_LEN * 8 };
464+
465+typedef ib_uint64_t bitmap_word_t;
466+
467+/****************************************************************//**
468+Calculate a bitmap block checksum. Algorithm borrowed from
469+log_block_calc_checksum.
470+@return checksum */
471+UNIV_INLINE
472+ulint
473+log_online_calc_checksum(
474+/*=====================*/
475+ const byte* block); /*!<in: bitmap block */
476+
477+/****************************************************************//**
478+Provide a comparisson function for the RB-tree tree (space,
479+block_start_page) pairs. Actual implementation does not matter as
480+long as the ordering is full.
481+@return -1 if p1 < p2, 0 if p1 == p2, 1 if p1 > p2
482+*/
483+static
484+int
485+log_online_compare_bmp_keys(
486+/*========================*/
487+ const void* p1, /*!<in: 1st key to compare */
488+ const void* p2) /*!<in: 2nd key to compare */
489+{
490+ const byte *k1 = (const byte *)p1;
491+ const byte *k2 = (const byte *)p2;
492+
493+ ulint k1_space = mach_read_from_4(k1 + MODIFIED_PAGE_SPACE_ID);
494+ ulint k2_space = mach_read_from_4(k2 + MODIFIED_PAGE_SPACE_ID);
495+ if (k1_space == k2_space) {
496+
497+ ulint k1_start_page
498+ = mach_read_from_4(k1 + MODIFIED_PAGE_1ST_PAGE_ID);
499+ ulint k2_start_page
500+ = mach_read_from_4(k2 + MODIFIED_PAGE_1ST_PAGE_ID);
501+ return k1_start_page < k2_start_page
502+ ? -1 : k1_start_page > k2_start_page ? 1 : 0;
503+ }
504+ return k1_space < k2_space ? -1 : 1;
505+}
506+
507+/****************************************************************//**
508+Calculate a bitmap block checksum. Algorithm borrowed from
509+log_block_calc_checksum.
510+@return checksum */
511+UNIV_INLINE
512+ulint
513+log_online_calc_checksum(
514+/*=====================*/
515+ const byte* block) /*!<in: bitmap block */
516+{
517+ ulint sum;
518+ ulint sh;
519+ ulint i;
520+
521+ sum = 1;
522+ sh = 0;
523+
524+ for (i = 0; i < MODIFIED_PAGE_BLOCK_CHECKSUM; i++) {
525+
526+ ulint b = block[i];
527+ sum &= 0x7FFFFFFFUL;
528+ sum += b;
529+ sum += b << sh;
530+ sh++;
531+ if (sh > 24) {
532+
533+ sh = 0;
534+ }
535+ }
536+
537+ return sum;
538+}
539+
540+/****************************************************************//**
541+Read one bitmap data page and check it for corruption.
542+
543+@return TRUE if page read OK, FALSE if I/O error */
544+static
545+ibool
546+log_online_read_bitmap_page(
547+/*========================*/
548+ log_online_bitmap_file_t *bitmap_file, /*!<in/out: bitmap
549+ file */
550+ byte *page, /*!<out: read page. Must be at
551+ least MODIFIED_PAGE_BLOCK_SIZE
552+ bytes long */
553+ ibool *checksum_ok) /*!<out: TRUE if page
554+ checksum OK */
555+{
556+ ulint checksum;
557+ ulint actual_checksum;
558+ ibool success;
559+
560+ ut_a(bitmap_file->size >= MODIFIED_PAGE_BLOCK_SIZE);
561+ ut_a(bitmap_file->offset
562+ <= bitmap_file->size - MODIFIED_PAGE_BLOCK_SIZE);
563+ ut_a(bitmap_file->offset % MODIFIED_PAGE_BLOCK_SIZE == 0);
564+
565+ success = xb_os_file_read(bitmap_file->file, page, bitmap_file->offset,
566+ MODIFIED_PAGE_BLOCK_SIZE);
567+
568+ if (UNIV_UNLIKELY(!success)) {
569+
570+ /* The following call prints an error message */
571+ os_file_get_last_error(TRUE);
572+ msg("InnoDB: Warning: failed reading changed page bitmap "
573+ "file \'%s\'\n", bitmap_file->name);
574+ return FALSE;
575+ }
576+
577+ bitmap_file->offset += MODIFIED_PAGE_BLOCK_SIZE;
578+ ut_ad(bitmap_file->offset <= bitmap_file->size);
579+
580+ checksum = mach_read_from_4(page + MODIFIED_PAGE_BLOCK_CHECKSUM);
581+ actual_checksum = log_online_calc_checksum(page);
582+ *checksum_ok = (checksum == actual_checksum);
583+
584+ return TRUE;
585+}
586+
587+/*********************************************************************//**
588+Check the name of a given file if it's a changed page bitmap file and
589+return file sequence and start LSN name components if it is. If is not,
590+the values of output parameters are undefined.
591+
592+@return TRUE if a given file is a changed page bitmap file. */
593+static
594+ibool
595+log_online_is_bitmap_file(
596+/*======================*/
597+ const os_file_stat_t* file_info, /*!<in: file to
598+ check */
599+ ulong* bitmap_file_seq_num, /*!<out: bitmap file
600+ sequence number */
601+ lsn_t* bitmap_file_start_lsn) /*!<out: bitmap file
602+ start LSN */
603+{
604+ char stem[FN_REFLEN];
605+
606+ ut_ad (strlen(file_info->name) < OS_FILE_MAX_PATH);
607+
608+ return ((file_info->type == OS_FILE_TYPE_FILE
609+ || file_info->type == OS_FILE_TYPE_LINK)
610+ && (sscanf(file_info->name, "%[a-z_]%lu_" LSN_PF ".xdb", stem,
611+ bitmap_file_seq_num, bitmap_file_start_lsn) == 3)
612+ && (!strcmp(stem, bmp_file_name_stem)));
613+}
614+
615+/*********************************************************************//**
616+List the bitmap files in srv_data_home and setup their range that contains the
617+specified LSN interval. This range, if non-empty, will start with a file that
618+has the greatest LSN equal to or less than the start LSN and will include all
619+the files up to the one with the greatest LSN less than the end LSN. Caller
620+must free bitmap_files->files when done if bitmap_files set to non-NULL and
621+this function returned TRUE. Field bitmap_files->count might be set to a
622+larger value than the actual count of the files, and space for the unused array
623+slots will be allocated but cleared to zeroes.
624+
625+@return TRUE if succeeded
626+*/
627+static
628+ibool
629+log_online_setup_bitmap_file_range(
630+/*===============================*/
631+ log_online_bitmap_file_range_t *bitmap_files, /*!<in/out: bitmap file
632+ range */
633+ lsn_t range_start, /*!<in: start LSN */
634+ lsn_t range_end) /*!<in: end LSN */
635+{
636+ os_file_dir_t bitmap_dir;
637+ os_file_stat_t bitmap_dir_file_info;
638+ ulong first_file_seq_num = ULONG_MAX;
639+ ulong last_file_seq_num = 0;
640+ lsn_t first_file_start_lsn = 0;
641+
642+ xb_ad(range_end >= range_start);
643+
644+ bitmap_files->count = 0;
645+ bitmap_files->files = NULL;
646+
647+ /* 1st pass: size the info array */
648+
649+ bitmap_dir = os_file_opendir(srv_data_home, FALSE);
650+ if (UNIV_UNLIKELY(!bitmap_dir)) {
651+
652+ msg("InnoDB: Error: failed to open bitmap directory \'%s\'\n",
653+ srv_data_home);
654+ return FALSE;
655+ }
656+
657+ while (!os_file_readdir_next_file(srv_data_home, bitmap_dir,
658+ &bitmap_dir_file_info)) {
659+
660+ ulong file_seq_num;
661+ lsn_t file_start_lsn;
662+
663+ if (!log_online_is_bitmap_file(&bitmap_dir_file_info,
664+ &file_seq_num,
665+ &file_start_lsn)
666+ || file_start_lsn >= range_end) {
667+
668+ continue;
669+ }
670+
671+ if (file_seq_num > last_file_seq_num) {
672+
673+ last_file_seq_num = file_seq_num;
674+ }
675+
676+ if (file_start_lsn >= range_start
677+ || file_start_lsn == first_file_start_lsn
678+ || first_file_start_lsn > range_start) {
679+
680+ /* A file that falls into the range */
681+
682+ if (file_start_lsn < first_file_start_lsn) {
683+
684+ first_file_start_lsn = file_start_lsn;
685+ }
686+ if (file_seq_num < first_file_seq_num) {
687+
688+ first_file_seq_num = file_seq_num;
689+ }
690+ } else if (file_start_lsn > first_file_start_lsn) {
691+
692+ /* A file that has LSN closer to the range start
693+ but smaller than it, replacing another such file */
694+ first_file_start_lsn = file_start_lsn;
695+ first_file_seq_num = file_seq_num;
696+ }
697+ }
698+
699+ if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) {
700+
701+ os_file_get_last_error(TRUE);
702+ msg("InnoDB: Error: cannot close \'%s\'\n",srv_data_home);
703+ return FALSE;
704+ }
705+
706+ if (first_file_seq_num == ULONG_MAX && last_file_seq_num == 0) {
707+
708+ bitmap_files->count = 0;
709+ return TRUE;
710+ }
711+
712+ bitmap_files->count = last_file_seq_num - first_file_seq_num + 1;
713+
714+ /* 2nd pass: get the file names in the file_seq_num order */
715+
716+ bitmap_dir = os_file_opendir(srv_data_home, FALSE);
717+ if (UNIV_UNLIKELY(!bitmap_dir)) {
718+
719+ msg("InnoDB: Error: failed to open bitmap directory \'%s\'\n",
720+ srv_data_home);
721+ return FALSE;
722+ }
723+
724+ bitmap_files->files =
725+ static_cast<log_online_bitmap_file_range_t::files_t *>
726+ (ut_malloc(bitmap_files->count
727+ * sizeof(bitmap_files->files[0])));
728+ memset(bitmap_files->files, 0,
729+ bitmap_files->count * sizeof(bitmap_files->files[0]));
730+
731+ while (!os_file_readdir_next_file(srv_data_home, bitmap_dir,
732+ &bitmap_dir_file_info)) {
733+
734+ ulong file_seq_num;
735+ lsn_t file_start_lsn;
736+ size_t array_pos;
737+
738+ if (!log_online_is_bitmap_file(&bitmap_dir_file_info,
739+ &file_seq_num,
740+ &file_start_lsn)
741+ || file_start_lsn >= range_end
742+ || file_start_lsn < first_file_start_lsn) {
743+
744+ continue;
745+ }
746+
747+ array_pos = file_seq_num - first_file_seq_num;
748+ xb_a(array_pos < bitmap_files->count);
749+ if (file_seq_num > bitmap_files->files[array_pos].seq_num) {
750+
751+ bitmap_files->files[array_pos].seq_num = file_seq_num;
752+ strncpy(bitmap_files->files[array_pos].name,
753+ bitmap_dir_file_info.name, FN_REFLEN);
754+ bitmap_files->files[array_pos].name[FN_REFLEN - 1]
755+ = '\0';
756+ bitmap_files->files[array_pos].start_lsn
757+ = file_start_lsn;
758+ }
759+ }
760+
761+ if (UNIV_UNLIKELY(os_file_closedir(bitmap_dir))) {
762+
763+ os_file_get_last_error(TRUE);
764+ msg("InnoDB: Error: cannot close \'%s\'\n", srv_data_home);
765+ free(bitmap_files->files);
766+ return FALSE;
767+ }
768+
769+#ifdef UNIV_DEBUG
770+ ut_ad(bitmap_files->files[0].seq_num == first_file_seq_num);
771+ ut_ad(bitmap_files->files[0].start_lsn == first_file_start_lsn);
772+
773+ for (size_t i = 1; i < bitmap_files->count; i++) {
774+ if (!bitmap_files->files[i].seq_num) {
775+
776+ break;
777+ }
778+ ut_ad(bitmap_files->files[i].seq_num
779+ > bitmap_files->files[i - 1].seq_num);
780+ ut_ad(bitmap_files->files[i].start_lsn
781+ >= bitmap_files->files[i - 1].start_lsn);
782+ }
783+#endif
784+
785+ return TRUE;
786+}
787+
788+/****************************************************************//**
789+Open a bitmap file for reading.
790+
791+@return TRUE if opened successfully */
792+static
793+ibool
794+log_online_open_bitmap_file_read_only(
795+/*==================================*/
796+ const char* name, /*!<in: bitmap file
797+ name without directory,
798+ which is assumed to be
799+ srv_data_home */
800+ log_online_bitmap_file_t* bitmap_file) /*!<out: opened bitmap
801+ file */
802+{
803+ ibool success = FALSE;
804+
805+ xb_ad(name[0] != '\0');
806+
807+ ut_snprintf(bitmap_file->name, FN_REFLEN, "%s%s", srv_data_home, name);
808+ bitmap_file->file
809+ = xb_file_create_no_error_handling(bitmap_file->name,
810+ OS_FILE_OPEN,
811+ OS_FILE_READ_ONLY,
812+ &success);
813+ if (UNIV_UNLIKELY(!success)) {
814+
815+ /* Here and below assume that bitmap file names do not
816+ contain apostrophes, thus no need for ut_print_filename(). */
817+ msg("InnoDB: Warning: error opening the changed page "
818+ "bitmap \'%s\'\n", bitmap_file->name);
819+ return FALSE;
820+ }
821+
822+ bitmap_file->size = os_file_get_size(bitmap_file->file);
823+ bitmap_file->offset = 0;
824+
825+#ifdef UNIV_LINUX
826+ posix_fadvise(bitmap_file->file, 0, 0, POSIX_FADV_SEQUENTIAL);
827+ posix_fadvise(bitmap_file->file, 0, 0, POSIX_FADV_NOREUSE);
828+#endif
829+
830+ return TRUE;
831+}
832+
833+/****************************************************************//**
834+Diagnose one or both of the following situations if we read close to
835+the end of bitmap file:
836+1) Warn if the remainder of the file is less than one page.
837+2) Error if we cannot read any more full pages but the last read page
838+did not have the last-in-run flag set.
839+
840+@return FALSE for the error */
841+static
842+ibool
843+log_online_diagnose_bitmap_eof(
844+/*===========================*/
845+ const log_online_bitmap_file_t* bitmap_file, /*!< in: bitmap file */
846+ ibool last_page_in_run)/*!< in: "last page in
847+ run" flag value in the
848+ last read page */
849+{
850+ /* Check if we are too close to EOF to read a full page */
851+ if ((bitmap_file->size < MODIFIED_PAGE_BLOCK_SIZE)
852+ || (bitmap_file->offset
853+ > bitmap_file->size - MODIFIED_PAGE_BLOCK_SIZE)) {
854+
855+ if (UNIV_UNLIKELY(bitmap_file->offset != bitmap_file->size)) {
856+
857+ /* If we are not at EOF and we have less than one page
858+ to read, it's junk. This error is not fatal in
859+ itself. */
860+
861+ msg("InnoDB: Warning: junk at the end of changed "
862+ "page bitmap file \'%s\'.\n", bitmap_file->name);
863+ }
864+
865+ if (UNIV_UNLIKELY(!last_page_in_run)) {
866+
867+ /* We are at EOF but the last read page did not finish
868+ a run */
869+ /* It's a "Warning" here because it's not a fatal error
870+ for the whole server */
871+ msg("InnoDB: Warning: changed page bitmap "
872+ "file \'%s\' does not contain a complete run "
873+ "at the end.\n", bitmap_file->name);
874+ return FALSE;
875+ }
876+ }
877+ return TRUE;
878+}
879+
880+/* End of copy-pasted definitions */
881+
882+/** Iterator structure over changed page bitmap */
883+struct xb_page_bitmap_range_struct {
884+ const xb_page_bitmap *bitmap; /* Bitmap with data */
885+ ulint space_id; /* Space id for this
886+ iterator */
887+ ulint bit_i; /* Bit index of the iterator
888+ position in the current page */
889+ const ib_rbt_node_t *bitmap_node; /* Current bitmap tree node */
890+ const byte *bitmap_page; /* Current bitmap page */
891+ ulint current_page_id;/* Current page id */
892+};
893+
894+/****************************************************************//**
895+Print a diagnostic message on missing bitmap data for an LSN range. */
896+static __attribute__((cold))
897+void
898+xb_msg_missing_lsn_data(
899+/*====================*/
900+ lsn_t missing_interval_start, /*!<in: interval start */
901+ lsn_t missing_interval_end) /*!<in: interval end */
902+{
903+ msg("xtrabackup: warning: changed page data missing for LSNs between "
904+ LSN_PF " and " LSN_PF "\n", missing_interval_start,
905+ missing_interval_end);
906+}
907+
908+/****************************************************************//**
909+Scan a bitmap file until data for a desired LSN or EOF is found and check that
910+the page before the starting one is not corrupted to ensure that the found page
911+indeed contains the very start of the desired LSN data. The caller must check
912+the page LSN values to determine if the bitmap file was scanned until the data
913+was found or until EOF. Page must be at least MODIFIED_PAGE_BLOCK_SIZE big.
914+
915+@return TRUE if the scan successful without corruption detected
916+*/
917+static
918+ibool
919+xb_find_lsn_in_bitmap_file(
920+/*=======================*/
921+ log_online_bitmap_file_t *bitmap_file, /*!<in/out: bitmap
922+ file */
923+ byte *page, /*!<in/out: last read
924+ bitmap page */
925+ lsn_t *page_end_lsn, /*!<out: end LSN of the
926+ last read page */
927+ lsn_t lsn) /*!<in: LSN to find */
928+{
929+ ibool last_page_ok = TRUE;
930+ ibool next_to_last_page_ok = TRUE;
931+
932+ xb_ad (bitmap_file->size >= MODIFIED_PAGE_BLOCK_SIZE);
933+
934+ *page_end_lsn = 0;
935+
936+ while ((*page_end_lsn <= lsn)
937+ && (bitmap_file->offset
938+ <= bitmap_file->size - MODIFIED_PAGE_BLOCK_SIZE)) {
939+
940+ next_to_last_page_ok = last_page_ok;
941+ if (!log_online_read_bitmap_page(bitmap_file, page,
942+ &last_page_ok)) {
943+
944+ return FALSE;
945+ }
946+
947+ *page_end_lsn = MACH_READ_64(page + MODIFIED_PAGE_END_LSN);
948+ }
949+
950+ /* We check two pages here because the last read page already contains
951+ the required LSN data. If the next to the last one page is corrupted,
952+ then we have no way of telling if that page contained the required LSN
953+ range data too */
954+ return last_page_ok && next_to_last_page_ok;
955+}
956+
957+/****************************************************************//**
958+Read the disk bitmap and build the changed page bitmap tree for the
959+LSN interval incremental_lsn to checkpoint_lsn_start.
960+
961+@return the built bitmap tree or NULL if unable to read the full interval for
962+any reason. */
963+xb_page_bitmap*
964+xb_page_bitmap_init(void)
965+/*=====================*/
966+{
967+ log_online_bitmap_file_t bitmap_file;
968+ lsn_t bmp_start_lsn = incremental_lsn;
969+ lsn_t bmp_end_lsn = checkpoint_lsn_start;
970+ byte page[MODIFIED_PAGE_BLOCK_SIZE];
971+ lsn_t current_page_end_lsn;
972+ xb_page_bitmap *result;
973+ ibool last_page_in_run= FALSE;
974+ log_online_bitmap_file_range_t bitmap_files;
975+ size_t bmp_i;
976+ ibool last_page_ok = TRUE;
977+
978+ if (UNIV_UNLIKELY(bmp_start_lsn > bmp_end_lsn)) {
979+
980+ msg("xtrabackup: incremental backup LSN " LSN_PF
981+ " is larger than than the last checkpoint LSN " LSN_PF
982+ "\n", bmp_start_lsn, bmp_end_lsn);
983+ return NULL;
984+ }
985+
986+ if (!log_online_setup_bitmap_file_range(&bitmap_files, bmp_start_lsn,
987+ bmp_end_lsn)) {
988+
989+ return NULL;
990+ }
991+
992+ /* Only accept no bitmap files returned if start LSN == end LSN */
993+ if (bitmap_files.count == 0 && bmp_end_lsn != bmp_start_lsn) {
994+
995+ return NULL;
996+ }
997+
998+ result = rbt_create(MODIFIED_PAGE_BLOCK_SIZE,
999+ log_online_compare_bmp_keys);
1000+
1001+ if (bmp_start_lsn == bmp_end_lsn) {
1002+
1003+ /* Empty range - empty bitmap */
1004+ return result;
1005+ }
1006+
1007+ bmp_i = 0;
1008+
1009+ if (UNIV_UNLIKELY(bitmap_files.files[bmp_i].start_lsn
1010+ > bmp_start_lsn)) {
1011+
1012+ /* The 1st file does not have the starting LSN data */
1013+ xb_msg_missing_lsn_data(bmp_start_lsn,
1014+ bitmap_files.files[bmp_i].start_lsn);
1015+ rbt_free(result);
1016+ free(bitmap_files.files);
1017+ return NULL;
1018+ }
1019+
1020+ /* Skip any zero-sized files at the start */
1021+ while ((bmp_i < bitmap_files.count - 1)
1022+ && (bitmap_files.files[bmp_i].start_lsn
1023+ == bitmap_files.files[bmp_i + 1].start_lsn)) {
1024+
1025+ bmp_i++;
1026+ }
1027+
1028+ /* Is the 1st bitmap file missing? */
1029+ if (UNIV_UNLIKELY(bitmap_files.files[bmp_i].name[0] == '\0')) {
1030+
1031+ /* TODO: this is not the exact missing range */
1032+ xb_msg_missing_lsn_data(bmp_start_lsn, bmp_end_lsn);
1033+ rbt_free(result);
1034+ free(bitmap_files.files);
1035+ return NULL;
1036+ }
1037+
1038+ /* Open the 1st bitmap file */
1039+ if (UNIV_UNLIKELY(!log_online_open_bitmap_file_read_only(
1040+ bitmap_files.files[bmp_i].name,
1041+ &bitmap_file))) {
1042+
1043+ rbt_free(result);
1044+ free(bitmap_files.files);
1045+ return NULL;
1046+ }
1047+
1048+ /* If the 1st file is truncated, no data. Not merged with the case
1049+ below because zero-length file indicates not a corruption but missing
1050+ subsequent files instead. */
1051+ if (UNIV_UNLIKELY(bitmap_file.size < MODIFIED_PAGE_BLOCK_SIZE)) {
1052+
1053+ xb_msg_missing_lsn_data(bmp_start_lsn, bmp_end_lsn);
1054+ rbt_free(result);
1055+ free(bitmap_files.files);
1056+ os_file_close(bitmap_file.file);
1057+ return NULL;
1058+ }
1059+
1060+ /* Find the start of the required LSN range in the file */
1061+ if (UNIV_UNLIKELY(!xb_find_lsn_in_bitmap_file(&bitmap_file, page,
1062+ &current_page_end_lsn,
1063+ bmp_start_lsn))) {
1064+
1065+ msg("xtrabackup: Warning: changed page bitmap file "
1066+ "\'%s\' corrupted\n", bitmap_file.name);
1067+ rbt_free(result);
1068+ free(bitmap_files.files);
1069+ os_file_close(bitmap_file.file);
1070+ return NULL;
1071+ }
1072+
1073+ last_page_in_run
1074+ = mach_read_from_4(page + MODIFIED_PAGE_IS_LAST_BLOCK);
1075+
1076+ if (UNIV_UNLIKELY(!log_online_diagnose_bitmap_eof(&bitmap_file,
1077+ last_page_in_run))) {
1078+
1079+ rbt_free(result);
1080+ free(bitmap_files.files);
1081+ os_file_close(bitmap_file.file);
1082+ return NULL;
1083+ }
1084+
1085+ if (UNIV_UNLIKELY(current_page_end_lsn < bmp_start_lsn)) {
1086+
1087+ xb_msg_missing_lsn_data(current_page_end_lsn, bmp_start_lsn);
1088+ rbt_free(result);
1089+ free(bitmap_files.files);
1090+ os_file_close(bitmap_file.file);
1091+ return NULL;
1092+ }
1093+
1094+ /* 1st bitmap page found, add it to the tree. */
1095+ rbt_insert(result, page, page);
1096+
1097+ /* Read next pages/files until all required data is read */
1098+ while (last_page_ok
1099+ && (current_page_end_lsn < bmp_end_lsn
1100+ || (current_page_end_lsn == bmp_end_lsn
1101+ && !last_page_in_run))) {
1102+
1103+ ib_rbt_bound_t tree_search_pos;
1104+
1105+ /* If EOF, advance the file skipping over any empty files */
1106+ while (bitmap_file.size < MODIFIED_PAGE_BLOCK_SIZE
1107+ || (bitmap_file.offset
1108+ > bitmap_file.size - MODIFIED_PAGE_BLOCK_SIZE)) {
1109+
1110+ os_file_close(bitmap_file.file);
1111+
1112+ if (UNIV_UNLIKELY(
1113+ !log_online_diagnose_bitmap_eof(
1114+ &bitmap_file, last_page_in_run))) {
1115+
1116+ rbt_free(result);
1117+ free(bitmap_files.files);
1118+ return NULL;
1119+ }
1120+
1121+ bmp_i++;
1122+
1123+ if (UNIV_UNLIKELY(bmp_i == bitmap_files.count
1124+ || (bitmap_files.files[bmp_i].seq_num
1125+ == 0))) {
1126+
1127+ xb_msg_missing_lsn_data(current_page_end_lsn,
1128+ bmp_end_lsn);
1129+ rbt_free(result);
1130+ free(bitmap_files.files);
1131+ return NULL;
1132+ }
1133+
1134+ /* Is the next file missing? */
1135+ if (UNIV_UNLIKELY(bitmap_files.files[bmp_i].name[0]
1136+ == '\0')) {
1137+
1138+ /* TODO: this is not the exact missing range */
1139+ xb_msg_missing_lsn_data(bitmap_files.files
1140+ [bmp_i - 1].start_lsn,
1141+ bmp_end_lsn);
1142+ rbt_free(result);
1143+ free(bitmap_files.files);
1144+ return NULL;
1145+ }
1146+
1147+ if (UNIV_UNLIKELY(
1148+ !log_online_open_bitmap_file_read_only(
1149+ bitmap_files.files[bmp_i].name,
1150+ &bitmap_file))) {
1151+
1152+ rbt_free(result);
1153+ free(bitmap_files.files);
1154+ return NULL;
1155+ }
1156+ }
1157+
1158+ if (UNIV_UNLIKELY(
1159+ !log_online_read_bitmap_page(&bitmap_file, page,
1160+ &last_page_ok))) {
1161+
1162+ rbt_free(result);
1163+ free(bitmap_files.files);
1164+ os_file_close(bitmap_file.file);
1165+ return NULL;
1166+ }
1167+
1168+ if (UNIV_UNLIKELY(!last_page_ok)) {
1169+
1170+ msg("xtrabackup: warning: changed page bitmap file "
1171+ "\'%s\' corrupted.\n", bitmap_file.name);
1172+ rbt_free(result);
1173+ free(bitmap_files.files);
1174+ os_file_close(bitmap_file.file);
1175+ return NULL;
1176+ }
1177+
1178+ /* Merge the current page with an existing page or insert a new
1179+ page into the tree */
1180+
1181+ if (!rbt_search(result, &tree_search_pos, page)) {
1182+
1183+ /* Merge the bitmap pages */
1184+ byte *existing_page
1185+ = rbt_value(byte, tree_search_pos.last);
1186+ bitmap_word_t *bmp_word_1 = (bitmap_word_t *)
1187+ (existing_page + MODIFIED_PAGE_BLOCK_BITMAP);
1188+ bitmap_word_t *bmp_end = (bitmap_word_t *)
1189+ (existing_page + MODIFIED_PAGE_BLOCK_UNUSED_2);
1190+ bitmap_word_t *bmp_word_2 = (bitmap_word_t *)
1191+ (page + MODIFIED_PAGE_BLOCK_BITMAP);
1192+ while (bmp_word_1 < bmp_end) {
1193+
1194+ *bmp_word_1++ |= *bmp_word_2++;
1195+ }
1196+ xb_a (bmp_word_1 == bmp_end);
1197+ } else {
1198+
1199+ /* Add a new page */
1200+ rbt_add_node(result, &tree_search_pos, page);
1201+ }
1202+
1203+ current_page_end_lsn
1204+ = MACH_READ_64(page + MODIFIED_PAGE_END_LSN);
1205+ last_page_in_run
1206+ = mach_read_from_4(page + MODIFIED_PAGE_IS_LAST_BLOCK);
1207+ }
1208+
1209+ xb_a (current_page_end_lsn >= bmp_end_lsn);
1210+
1211+ free(bitmap_files.files);
1212+ os_file_close(bitmap_file.file);
1213+
1214+ return result;
1215+}
1216+
1217+/****************************************************************//**
1218+Free the bitmap tree. */
1219+void
1220+xb_page_bitmap_deinit(
1221+/*==================*/
1222+ xb_page_bitmap* bitmap) /*!<in/out: bitmap tree */
1223+{
1224+ if (bitmap) {
1225+
1226+ rbt_free(bitmap);
1227+ }
1228+}
1229+
1230+/****************************************************************//**
1231+Advance to the next bitmap page or setup the first bitmap page for the
1232+given bitmap range. Assumes that bitmap_range->bitmap_page has been
1233+already found/bumped by rbt_search()/rbt_next().
1234+
1235+@return FALSE if no more bitmap data for the range space ID */
1236+static
1237+ibool
1238+xb_page_bitmap_setup_next_page(
1239+/*===========================*/
1240+ xb_page_bitmap_range* bitmap_range) /*!<in/out: the bitmap range */
1241+{
1242+ ulint new_space_id;
1243+ ulint new_1st_page_id;
1244+
1245+ if (bitmap_range->bitmap_node == NULL) {
1246+
1247+ bitmap_range->current_page_id = ULINT_UNDEFINED;
1248+ return FALSE;
1249+ }
1250+
1251+ bitmap_range->bitmap_page = rbt_value(byte, bitmap_range->bitmap_node);
1252+
1253+ new_space_id = mach_read_from_4(bitmap_range->bitmap_page
1254+ + MODIFIED_PAGE_SPACE_ID);
1255+ if (new_space_id != bitmap_range->space_id) {
1256+
1257+ /* No more data for the current page id. */
1258+ xb_a(new_space_id > bitmap_range->space_id);
1259+ bitmap_range->current_page_id = ULINT_UNDEFINED;
1260+ return FALSE;
1261+ }
1262+
1263+ new_1st_page_id = mach_read_from_4(bitmap_range->bitmap_page +
1264+ MODIFIED_PAGE_1ST_PAGE_ID);
1265+ xb_a (new_1st_page_id >= bitmap_range->current_page_id
1266+ || bitmap_range->current_page_id == ULINT_UNDEFINED);
1267+
1268+ bitmap_range->current_page_id = new_1st_page_id;
1269+ bitmap_range->bit_i = 0;
1270+
1271+ return TRUE;
1272+}
1273+
1274+/****************************************************************//**
1275+Set up a new bitmap range iterator over a given space id changed
1276+pages in a given bitmap.
1277+
1278+@return bitmap range iterator */
1279+xb_page_bitmap_range*
1280+xb_page_bitmap_range_init(
1281+/*======================*/
1282+ xb_page_bitmap* bitmap, /*!< in: bitmap to iterate over */
1283+ ulint space_id) /*!< in: space id */
1284+{
1285+ byte search_page[MODIFIED_PAGE_BLOCK_SIZE];
1286+ xb_page_bitmap_range *result
1287+ = static_cast<xb_page_bitmap_range *>
1288+ (ut_malloc(sizeof(*result)));
1289+
1290+ memset(result, 0, sizeof(*result));
1291+ result->bitmap = bitmap;
1292+ result->space_id = space_id;
1293+ result->current_page_id = ULINT_UNDEFINED;
1294+
1295+ /* Search for the 1st page for the given space id */
1296+ /* This also sets MODIFIED_PAGE_1ST_PAGE_ID to 0, which is what we
1297+ want. */
1298+ memset(search_page, 0, MODIFIED_PAGE_BLOCK_SIZE);
1299+ mach_write_to_4(search_page + MODIFIED_PAGE_SPACE_ID, space_id);
1300+
1301+ result->bitmap_node = rbt_lower_bound(result->bitmap, search_page);
1302+
1303+ xb_page_bitmap_setup_next_page(result);
1304+
1305+ return result;
1306+}
1307+
1308+/****************************************************************//**
1309+Get the value of the bitmap->range->bit_i bitmap bit
1310+
1311+@return the current bit value */
1312+static inline
1313+ibool
1314+is_bit_set(
1315+/*=======*/
1316+ const xb_page_bitmap_range* bitmap_range) /*!< in: bitmap
1317+ range */
1318+{
1319+ return ((*(((bitmap_word_t *)(bitmap_range->bitmap_page
1320+ + MODIFIED_PAGE_BLOCK_BITMAP))
1321+ + (bitmap_range->bit_i >> 6)))
1322+ & (1ULL << (bitmap_range->bit_i & 0x3F))) ? TRUE : FALSE;
1323+}
1324+
1325+/****************************************************************//**
1326+Get the next page id that has its bit set or cleared, i.e. equal to
1327+bit_value.
1328+
1329+@return page id */
1330+ulint
1331+xb_page_bitmap_range_get_next_bit(
1332+/*==============================*/
1333+ xb_page_bitmap_range* bitmap_range, /*!< in/out: bitmap range */
1334+ ibool bit_value) /*!< in: bit value */
1335+{
1336+ if (UNIV_UNLIKELY(bitmap_range->current_page_id
1337+ == ULINT_UNDEFINED)) {
1338+
1339+ return ULINT_UNDEFINED;
1340+ }
1341+
1342+ do {
1343+ while (bitmap_range->bit_i < MODIFIED_PAGE_BLOCK_ID_COUNT) {
1344+
1345+ while (is_bit_set(bitmap_range) != bit_value
1346+ && (bitmap_range->bit_i
1347+ < MODIFIED_PAGE_BLOCK_ID_COUNT)) {
1348+
1349+ bitmap_range->current_page_id++;
1350+ bitmap_range->bit_i++;
1351+ }
1352+
1353+ if (bitmap_range->bit_i
1354+ < MODIFIED_PAGE_BLOCK_ID_COUNT) {
1355+
1356+ ulint result = bitmap_range->current_page_id;
1357+ bitmap_range->current_page_id++;
1358+ bitmap_range->bit_i++;
1359+ return result;
1360+ }
1361+ }
1362+
1363+ bitmap_range->bitmap_node
1364+ = rbt_next(bitmap_range->bitmap,
1365+ bitmap_range->bitmap_node);
1366+
1367+ } while (xb_page_bitmap_setup_next_page(bitmap_range));
1368+
1369+ return ULINT_UNDEFINED;
1370+}
1371+
1372+/****************************************************************//**
1373+Free the bitmap range iterator. */
1374+void
1375+xb_page_bitmap_range_deinit(
1376+/*========================*/
1377+ xb_page_bitmap_range* bitmap_range) /*! in/out: bitmap range */
1378+{
1379+ ut_free(bitmap_range);
1380+}
1381
1382=== added file 'src/changed_page_bitmap.h'
1383--- src/changed_page_bitmap.h 1970-01-01 00:00:00 +0000
1384+++ src/changed_page_bitmap.h 2013-04-15 15:08:38 +0000
1385@@ -0,0 +1,84 @@
1386+/******************************************************
1387+XtraBackup: hot backup tool for InnoDB
1388+(c) 2009-2012 Percona Inc.
1389+Originally Created 3/3/2009 Yasufumi Kinoshita
1390+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
1391+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
1392+
1393+This program is free software; you can redistribute it and/or modify
1394+it under the terms of the GNU General Public License as published by
1395+the Free Software Foundation; version 2 of the License.
1396+
1397+This program is distributed in the hope that it will be useful,
1398+but WITHOUT ANY WARRANTY; without even the implied warranty of
1399+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1400+GNU General Public License for more details.
1401+
1402+You should have received a copy of the GNU General Public License
1403+along with this program; if not, write to the Free Software
1404+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1405+
1406+*******************************************************/
1407+
1408+/* Changed page bitmap interface */
1409+
1410+#ifndef XB_CHANGED_PAGE_BITMAP_H
1411+#define XB_CHANGED_PAGE_BITMAP_H
1412+
1413+#include "innodb_int.h"
1414+
1415+/* The changed page bitmap structure */
1416+typedef ib_rbt_t xb_page_bitmap;
1417+
1418+struct xb_page_bitmap_range_struct;
1419+
1420+/* The bitmap range iterator over one space id */
1421+typedef struct xb_page_bitmap_range_struct xb_page_bitmap_range;
1422+
1423+/****************************************************************//**
1424+Read the disk bitmap and build the changed page bitmap tree for the
1425+LSN interval incremental_lsn to checkpoint_lsn_start.
1426+
1427+@return the built bitmap tree */
1428+xb_page_bitmap*
1429+xb_page_bitmap_init(void);
1430+/*=====================*/
1431+
1432+/****************************************************************//**
1433+Free the bitmap tree. */
1434+void
1435+xb_page_bitmap_deinit(
1436+/*==================*/
1437+ xb_page_bitmap* bitmap); /*!<in/out: bitmap tree */
1438+
1439+
1440+/****************************************************************//**
1441+Set up a new bitmap range iterator over a given space id changed
1442+pages in a given bitmap.
1443+
1444+@return bitmap range iterator */
1445+xb_page_bitmap_range*
1446+xb_page_bitmap_range_init(
1447+/*======================*/
1448+ xb_page_bitmap* bitmap, /*!< in: bitmap to iterate over */
1449+ ulint space_id); /*!< in: space id */
1450+
1451+/****************************************************************//**
1452+Get the next page id that has its bit set or cleared, i.e. equal to
1453+bit_value.
1454+
1455+@return page id */
1456+ulint
1457+xb_page_bitmap_range_get_next_bit(
1458+/*==============================*/
1459+ xb_page_bitmap_range* bitmap_range, /*!< in/out: bitmap range */
1460+ ibool bit_value); /*!< in: bit value */
1461+
1462+/****************************************************************//**
1463+Free the bitmap range iterator. */
1464+void
1465+xb_page_bitmap_range_deinit(
1466+/*========================*/
1467+ xb_page_bitmap_range* bitmap_range); /*! in/out: bitmap range */
1468+
1469+#endif
1470
1471=== modified file 'src/compact.cc'
1472--- src/compact.cc 2013-03-22 09:14:31 +0000
1473+++ src/compact.cc 2013-04-15 15:08:38 +0000
1474@@ -443,7 +443,7 @@
1475
1476 ds_set_pipe(ds_buffer, ds_local);
1477
1478- res = xb_fil_cur_open(&cursor, node, 1);
1479+ res = xb_fil_cur_open(&cursor, &rf_pass_through, node, 1);
1480 xb_a(res == XB_FIL_CUR_SUCCESS);
1481
1482 snprintf(tmpfile_path, sizeof(tmpfile_path), "%s%s",
1483
1484=== modified file 'src/fil_cur.cc'
1485--- src/fil_cur.cc 2013-03-22 09:14:31 +0000
1486+++ src/fil_cur.cc 2013-04-15 15:08:38 +0000
1487@@ -26,13 +26,14 @@
1488 #include "innodb_int.h"
1489 #include "fil_cur.h"
1490 #include "common.h"
1491+#include "read_filt.h"
1492 #include "xtrabackup.h"
1493
1494 /* Size of read buffer in pages */
1495 #define XB_FIL_CUR_PAGES 64
1496
1497 /************************************************************************
1498-Open a source file cursor.
1499+Open a source file cursor and initialize the associated read filter.
1500
1501 @return XB_FIL_CUR_SUCCESS on success, XB_FIL_CUR_SKIP if the source file must
1502 be skipped and XB_FIL_CUR_ERROR on error. */
1503@@ -40,6 +41,7 @@
1504 xb_fil_cur_open(
1505 /*============*/
1506 xb_fil_cur_t* cursor, /*!< out: source file cursor */
1507+ xb_read_filt_t* read_filter, /*!< in/out: the read filter */
1508 fil_node_t* node, /*!< in: source tablespace node */
1509 uint thread_n) /*!< thread number for diagnostics */
1510 {
1511@@ -131,7 +133,6 @@
1512 cursor->buf = static_cast<byte *>
1513 (ut_align(cursor->orig_buf, UNIV_PAGE_SIZE));
1514
1515- cursor->offset = 0;
1516 cursor->buf_read = 0;
1517 cursor->buf_npages = 0;
1518 cursor->buf_offset = 0;
1519@@ -140,6 +141,10 @@
1520
1521 cursor->space_size = cursor->statinfo.st_size / page_size;
1522
1523+ cursor->read_filter = read_filter;
1524+ cursor->read_filter->init(&cursor->read_filter_ctxt, cursor,
1525+ node->space->id);
1526+
1527 return(XB_FIL_CUR_SUCCESS);
1528 }
1529
1530@@ -155,17 +160,16 @@
1531 xb_fil_cur_t* cursor) /*!< in/out: source file cursor */
1532 {
1533 ibool success;
1534- ulint page_size;
1535 byte* page;
1536 ulint i;
1537 ulint npages;
1538 ulint retry_count;
1539 xb_fil_cur_result_t ret;
1540+ ib_int64_t offset;
1541 ib_int64_t to_read;
1542
1543- page_size = cursor->page_size;
1544-
1545- to_read = (ib_int64_t) cursor->statinfo.st_size - cursor->offset;
1546+ cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt,
1547+ &offset, &to_read);
1548
1549 if (to_read == 0LL) {
1550 return(XB_FIL_CUR_EOF);
1551@@ -174,8 +178,8 @@
1552 if (to_read > (ib_int64_t) cursor->buf_size) {
1553 to_read = (ib_int64_t) cursor->buf_size;
1554 }
1555- ut_a(to_read > 0 && to_read <= 0xFFFFFFFFLL);
1556- ut_a(to_read % page_size == 0);
1557+ xb_a(to_read > 0 && to_read <= 0xFFFFFFFFLL);
1558+ xb_a(to_read % cursor->page_size == 0);
1559
1560 npages = (ulint) (to_read >> cursor->page_size_shift);
1561
1562@@ -187,19 +191,18 @@
1563
1564 cursor->buf_read = 0;
1565 cursor->buf_npages = 0;
1566- cursor->buf_offset = cursor->offset;
1567- cursor->buf_page_no = (ulint) (cursor->offset >>
1568- cursor->page_size_shift);
1569+ cursor->buf_offset = offset;
1570+ cursor->buf_page_no = (ulint) (offset >> cursor->page_size_shift);
1571
1572- success = xb_os_file_read(cursor->file, cursor->buf, cursor->offset,
1573- to_read);
1574+ success = xb_os_file_read(cursor->file, cursor->buf, offset, to_read);
1575 if (!success) {
1576 return(XB_FIL_CUR_ERROR);
1577 }
1578
1579 /* check pages for corruption and re-read if necessary. i.e. in case of
1580 partially written pages */
1581- for (page = cursor->buf, i = 0; i < npages; page += page_size, i++) {
1582+ for (page = cursor->buf, i = 0; i < npages;
1583+ page += cursor->page_size, i++) {
1584 if (xb_buf_page_is_corrupted(page, cursor->zip_size))
1585 {
1586 ulint page_no = cursor->buf_page_no + i;
1587@@ -208,7 +211,7 @@
1588 page_no >= FSP_EXTENT_SIZE &&
1589 page_no < FSP_EXTENT_SIZE * 3) {
1590 /* skip doublewrite buffer pages */
1591- ut_a(page_size == UNIV_PAGE_SIZE);
1592+ xb_a(cursor->page_size == UNIV_PAGE_SIZE);
1593 msg("[%02u] xtrabackup: "
1594 "Page %lu is a doublewrite buffer page, "
1595 "skipping.\n", cursor->thread_n, page_no);
1596@@ -233,24 +236,25 @@
1597 goto read_retry;
1598 }
1599 }
1600- cursor->buf_read += page_size;
1601+ cursor->buf_read += cursor->page_size;
1602 cursor->buf_npages++;
1603 }
1604
1605 posix_fadvise(cursor->file, 0, 0, POSIX_FADV_DONTNEED);
1606
1607- cursor->offset += page_size * i;
1608-
1609 return(ret);
1610 }
1611
1612 /************************************************************************
1613-Close the source file cursor opened with xb_fil_cur_open(). */
1614+Close the source file cursor opened with xb_fil_cur_open() and its
1615+associated read filter. */
1616 void
1617 xb_fil_cur_close(
1618 /*=============*/
1619 xb_fil_cur_t *cursor) /*!< in/out: source file cursor */
1620 {
1621+ cursor->read_filter->deinit(&cursor->read_filter_ctxt);
1622+
1623 if (cursor->orig_buf != NULL) {
1624 ut_free(cursor->orig_buf);
1625 }
1626
1627=== modified file 'src/fil_cur.h'
1628--- src/fil_cur.h 2013-03-22 09:14:31 +0000
1629+++ src/fil_cur.h 2013-04-15 15:08:38 +0000
1630@@ -27,8 +27,9 @@
1631
1632 #include <my_dir.h>
1633 #include "innodb_int.h"
1634+#include "read_filt.h"
1635
1636-typedef struct {
1637+struct xb_fil_cur_t {
1638 os_file_t file; /*!< source file handle */
1639 char path[FN_REFLEN];/*!< normalized file path */
1640 MY_STAT statinfo; /*!< information about the file */
1641@@ -38,9 +39,11 @@
1642 UNIV_PAGE_SIZE for uncompressed ones */
1643 ulint page_size_shift;/*!< bit shift corresponding to
1644 page_size */
1645- ib_int64_t offset; /*!< current file offset in bytes */
1646 my_bool is_system; /*!< TRUE for system tablespace, FALSE
1647 otherwise */
1648+ xb_read_filt_t* read_filter; /*!< read filter */
1649+ xb_read_filt_ctxt_t read_filter_ctxt;
1650+ /*!< read filter context */
1651 byte* orig_buf; /*!< read buffer */
1652 byte* buf; /*!< aligned pointer for orig_buf */
1653 ulint buf_size; /*!< buffer size in bytes */
1654@@ -55,7 +58,7 @@
1655 uint thread_n; /*!< thread number for diagnostics */
1656 ulint space_id; /*!< ID of tablespace */
1657 ulint space_size; /*!< space size in pages */
1658-} xb_fil_cur_t;
1659+};
1660
1661 typedef enum {
1662 XB_FIL_CUR_SUCCESS,
1663@@ -65,7 +68,7 @@
1664 } xb_fil_cur_result_t;
1665
1666 /************************************************************************
1667-Open a source file cursor.
1668+Open a source file cursor and initialize the associated read filter.
1669
1670 @return XB_FIL_CUR_SUCCESS on success, XB_FIL_CUR_SKIP if the source file must
1671 be skipped and XB_FIL_CUR_ERROR on error. */
1672@@ -73,6 +76,7 @@
1673 xb_fil_cur_open(
1674 /*============*/
1675 xb_fil_cur_t* cursor, /*!< out: source file cursor */
1676+ xb_read_filt_t* read_filter, /*!< in/out: the read filter */
1677 fil_node_t* node, /*!< in: source tablespace node */
1678 uint thread_n); /*!< thread number for diagnostics */
1679
1680@@ -88,7 +92,8 @@
1681 xb_fil_cur_t* cursor); /*!< in/out: source file cursor */
1682
1683 /************************************************************************
1684-Close the source file cursor opened with xb_fil_cur_open(). */
1685+Close the source file cursor opened with xb_fil_cur_open() and its
1686+associated read filter. */
1687 void
1688 xb_fil_cur_close(
1689 /*=============*/
1690
1691=== modified file 'src/innodb_int.cc'
1692--- src/innodb_int.cc 2013-03-22 09:14:31 +0000
1693+++ src/innodb_int.cc 2013-04-15 15:08:38 +0000
1694@@ -199,7 +199,7 @@
1695 const char* name) /*!< in: space name */
1696 {
1697 fil_space_t* space;
1698- ulint fold;
1699+ ulint fold __attribute__((unused));
1700
1701 ut_ad(mutex_own(&fil_system->mutex));
1702
1703
1704=== modified file 'src/innodb_int.h'
1705--- src/innodb_int.h 2013-03-22 09:14:31 +0000
1706+++ src/innodb_int.h 2013-04-15 15:08:38 +0000
1707@@ -85,6 +85,7 @@
1708 #include <ut0crc32.h>
1709 #endif
1710 #include <ut0mem.h>
1711+#include <ut0rbt.h>
1712
1713 #if MYSQL_VERSION_ID < 50600
1714 }
1715@@ -166,6 +167,7 @@
1716 typedef ib_uint64_t lsn_t;
1717 typedef merge_index_def_t index_def_t;
1718 typedef merge_index_field_t index_field_t;
1719+ typedef struct ib_rbt_struct ib_rbt_t;
1720 # define xb_btr_pcur_open_at_index_side(from_left, index, latch_mode, pcur, \
1721 init_pcur, level, mtr) \
1722 btr_pcur_open_at_index_side(from_left, index, latch_mode, pcur, \
1723
1724=== added file 'src/read_filt.cc'
1725--- src/read_filt.cc 1970-01-01 00:00:00 +0000
1726+++ src/read_filt.cc 2013-04-15 15:08:38 +0000
1727@@ -0,0 +1,206 @@
1728+/******************************************************
1729+XtraBackup: hot backup tool for InnoDB
1730+(c) 2009-2012 Percona Inc.
1731+Originally Created 3/3/2009 Yasufumi Kinoshita
1732+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
1733+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
1734+
1735+This program is free software; you can redistribute it and/or modify
1736+it under the terms of the GNU General Public License as published by
1737+the Free Software Foundation; version 2 of the License.
1738+
1739+This program is distributed in the hope that it will be useful,
1740+but WITHOUT ANY WARRANTY; without even the implied warranty of
1741+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1742+GNU General Public License for more details.
1743+
1744+You should have received a copy of the GNU General Public License
1745+along with this program; if not, write to the Free Software
1746+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1747+
1748+*******************************************************/
1749+
1750+/* Data file read filter implementation */
1751+
1752+#include "read_filt.h"
1753+#include "common.h"
1754+#include "fil_cur.h"
1755+#include "xtrabackup.h"
1756+
1757+/****************************************************************//**
1758+Perform read filter context initialization that is common to all read
1759+filters. */
1760+static
1761+void
1762+common_init(
1763+/*========*/
1764+ xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */
1765+ const xb_fil_cur_t* cursor) /*!<in: file cursor */
1766+{
1767+ ctxt->offset = 0;
1768+ ctxt->data_file_size = cursor->statinfo.st_size;
1769+ ctxt->buffer_capacity = cursor->buf_size;
1770+ ctxt->page_size = cursor->page_size;
1771+}
1772+
1773+/****************************************************************//**
1774+Initialize the pass-through read filter. */
1775+static
1776+void
1777+rf_pass_through_init(
1778+/*=================*/
1779+ xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */
1780+ const xb_fil_cur_t* cursor, /*!<in: file cursor */
1781+ ulint space_id __attribute__((unused)))
1782+ /*!<in: space id we are reading */
1783+{
1784+ common_init(ctxt, cursor);
1785+}
1786+
1787+/****************************************************************//**
1788+Get the next batch of pages for the pass-through read filter. */
1789+static
1790+void
1791+rf_pass_through_get_next_batch(
1792+/*===========================*/
1793+ xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
1794+ context */
1795+ ib_int64_t* read_batch_start, /*!<out: starting read
1796+ offset in bytes for the
1797+ next batch of pages */
1798+ ib_int64_t* read_batch_len) /*!<out: length in
1799+ bytes of the next batch
1800+ of pages */
1801+{
1802+ *read_batch_start = ctxt->offset;
1803+ *read_batch_len = ctxt->data_file_size - ctxt->offset;
1804+
1805+ if (*read_batch_len > ctxt->buffer_capacity) {
1806+ *read_batch_len = ctxt->buffer_capacity;
1807+ }
1808+
1809+ ctxt->offset += *read_batch_len;
1810+}
1811+
1812+/****************************************************************//**
1813+Deinitialize the pass-through read filter. */
1814+static
1815+void
1816+rf_pass_through_deinit(
1817+/*===================*/
1818+ xb_read_filt_ctxt_t* ctxt __attribute__((unused)))
1819+ /*!<in: read filter context */
1820+{
1821+}
1822+
1823+/****************************************************************//**
1824+Initialize the changed page bitmap-based read filter. Assumes that
1825+the bitmap is already set up in changed_page_bitmap. */
1826+static
1827+void
1828+rf_bitmap_init(
1829+/*===========*/
1830+ xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
1831+ context */
1832+ const xb_fil_cur_t* cursor, /*!<in: read cursor */
1833+ ulint space_id) /*!<in: space id */
1834+{
1835+ common_init(ctxt, cursor);
1836+ ctxt->bitmap_range = xb_page_bitmap_range_init(changed_page_bitmap,
1837+ space_id);
1838+ ctxt->filter_batch_end = 0;
1839+}
1840+
1841+/****************************************************************//**
1842+Get the next batch of pages for the bitmap read filter. */
1843+static
1844+void
1845+rf_bitmap_get_next_batch(
1846+/*=====================*/
1847+ xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter
1848+ context */
1849+ ib_int64_t* read_batch_start, /*!<out: starting read
1850+ offset in bytes for the
1851+ next batch of pages */
1852+ ib_int64_t* read_batch_len) /*!<out: length in
1853+ bytes of the next batch
1854+ of pages */
1855+{
1856+ ulint start_page_id;
1857+
1858+ start_page_id = ctxt->offset / ctxt->page_size;
1859+
1860+ xb_a (ctxt->offset % ctxt->page_size == 0);
1861+
1862+ if (start_page_id == ctxt->filter_batch_end) {
1863+
1864+ /* Used up all the previous bitmap range, get some more */
1865+ ulint next_page_id;
1866+
1867+ /* Find the next changed page using the bitmap */
1868+ next_page_id = xb_page_bitmap_range_get_next_bit
1869+ (ctxt->bitmap_range, TRUE);
1870+
1871+ if (next_page_id == ULINT_UNDEFINED) {
1872+ *read_batch_len = 0;
1873+ return;
1874+ }
1875+
1876+ ctxt->offset = next_page_id * ctxt->page_size;
1877+
1878+ /* Find the end of the current changed page block by searching
1879+ for the next cleared bitmap bit */
1880+ ctxt->filter_batch_end
1881+ = xb_page_bitmap_range_get_next_bit(ctxt->bitmap_range,
1882+ FALSE);
1883+ xb_a(next_page_id < ctxt->filter_batch_end);
1884+ }
1885+
1886+ *read_batch_start = ctxt->offset;
1887+ if (ctxt->filter_batch_end == ULINT_UNDEFINED) {
1888+ /* No more cleared bits in the bitmap, need to copy all the
1889+ remaining pages. */
1890+ *read_batch_len = ctxt->data_file_size - ctxt->offset;
1891+ } else {
1892+ *read_batch_len = ctxt->filter_batch_end * ctxt->page_size
1893+ - ctxt->offset;
1894+ }
1895+
1896+ /* If the page block is larger than the buffer capacity, limit it to
1897+ buffer capacity. The subsequent invocations will continue returning
1898+ the current block in buffer-sized pieces until ctxt->filter_batch_end
1899+ is reached, trigerring the next bitmap query. */
1900+ if (*read_batch_len > ctxt->buffer_capacity) {
1901+ *read_batch_len = ctxt->buffer_capacity;
1902+ }
1903+
1904+ ctxt->offset += *read_batch_len;
1905+ xb_a (ctxt->offset % ctxt->page_size == 0);
1906+ xb_a (*read_batch_start % ctxt->page_size == 0);
1907+ xb_a (*read_batch_len % ctxt->page_size == 0);
1908+}
1909+
1910+/****************************************************************//**
1911+Deinitialize the changed page bitmap-based read filter. */
1912+static
1913+void
1914+rf_bitmap_deinit(
1915+/*=============*/
1916+ xb_read_filt_ctxt_t* ctxt) /*!<in/out: read filter context */
1917+{
1918+ xb_page_bitmap_range_deinit(ctxt->bitmap_range);
1919+}
1920+
1921+/* The pass-through read filter */
1922+xb_read_filt_t rf_pass_through = {
1923+ &rf_pass_through_init,
1924+ &rf_pass_through_get_next_batch,
1925+ &rf_pass_through_deinit
1926+};
1927+
1928+/* The changed page bitmap-based read filter */
1929+xb_read_filt_t rf_bitmap = {
1930+ &rf_bitmap_init,
1931+ &rf_bitmap_get_next_batch,
1932+ &rf_bitmap_deinit
1933+};
1934
1935=== added file 'src/read_filt.h'
1936--- src/read_filt.h 1970-01-01 00:00:00 +0000
1937+++ src/read_filt.h 2013-04-15 15:08:38 +0000
1938@@ -0,0 +1,63 @@
1939+/******************************************************
1940+XtraBackup: hot backup tool for InnoDB
1941+(c) 2009-2012 Percona Inc.
1942+Originally Created 3/3/2009 Yasufumi Kinoshita
1943+Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
1944+Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
1945+
1946+This program is free software; you can redistribute it and/or modify
1947+it under the terms of the GNU General Public License as published by
1948+the Free Software Foundation; version 2 of the License.
1949+
1950+This program is distributed in the hope that it will be useful,
1951+but WITHOUT ANY WARRANTY; without even the implied warranty of
1952+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1953+GNU General Public License for more details.
1954+
1955+You should have received a copy of the GNU General Public License
1956+along with this program; if not, write to the Free Software
1957+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1958+
1959+*******************************************************/
1960+
1961+/* Data file read filter interface */
1962+
1963+#ifndef XB_READ_FILT_H
1964+#define XB_READ_FILT_H
1965+
1966+#include "innodb_int.h"
1967+#include "changed_page_bitmap.h"
1968+
1969+struct xb_fil_cur_t;
1970+
1971+/* The read filter context */
1972+struct xb_read_filt_ctxt_t {
1973+ ib_int64_t offset; /*!< current file offset */
1974+ ib_int64_t data_file_size; /*!< data file size */
1975+ ib_int64_t buffer_capacity;/*!< read buffer capacity */
1976+ ulint space_id; /*!< space id */
1977+ /* The following fields used only in bitmap filter */
1978+ /* Move these to union if any other filters are added in future */
1979+ xb_page_bitmap_range *bitmap_range; /*!< changed page bitmap range
1980+ iterator for space_id */
1981+ ulint page_size; /*!< page size */
1982+ ulint filter_batch_end;/*!< the ending page id of the
1983+ current changed page block in
1984+ the bitmap */
1985+};
1986+
1987+/* The read filter */
1988+struct xb_read_filt_t {
1989+ void (*init)(xb_read_filt_ctxt_t* ctxt,
1990+ const xb_fil_cur_t* cursor,
1991+ ulint space_id);
1992+ void (*get_next_batch)(xb_read_filt_ctxt_t* ctxt,
1993+ ib_int64_t* read_batch_start,
1994+ ib_int64_t* read_batch_len);
1995+ void (*deinit)(xb_read_filt_ctxt_t* ctxt);
1996+};
1997+
1998+extern xb_read_filt_t rf_pass_through;
1999+extern xb_read_filt_t rf_bitmap;
2000+
2001+#endif
2002
2003=== modified file 'src/xtrabackup.cc'
2004--- src/xtrabackup.cc 2013-04-09 07:24:21 +0000
2005+++ src/xtrabackup.cc 2013-04-15 15:08:38 +0000
2006@@ -72,6 +72,13 @@
2007 #include "ds_buffer.h"
2008 #include "ds_tmpfile.h"
2009 #include "xbstream.h"
2010+#include "changed_page_bitmap.h"
2011+#include "read_filt.h"
2012+
2013+/* === File name constants === */
2014+#define XB_FN_SUSPENDED_AT_START "xtrabackup_suspended_1"
2015+#define XB_FN_SUSPENDED_AT_END "xtrabackup_suspended_2"
2016+#define XB_FN_LOG_COPIED "xtrabackup_log_copied"
2017
2018 my_bool innodb_inited= 0;
2019
2020@@ -87,6 +94,7 @@
2021 my_bool xtrabackup_export = FALSE;
2022 my_bool xtrabackup_apply_log_only = FALSE;
2023
2024+static my_bool xtrabackup_suspend_at_start = FALSE;
2025 my_bool xtrabackup_suspend_at_end = FALSE;
2026 longlong xtrabackup_use_memory = 100*1024*1024L;
2027 my_bool xtrabackup_create_ib_logfile = FALSE;
2028@@ -99,6 +107,7 @@
2029 lsn_t incremental_lsn;
2030 lsn_t incremental_to_lsn;
2031 lsn_t incremental_last_lsn;
2032+xb_page_bitmap *changed_page_bitmap = NULL;
2033
2034 char *xtrabackup_incremental_basedir = NULL; /* for --backup */
2035 char *xtrabackup_extra_lsndir = NULL; /* for --backup with --extra-lsndir */
2036@@ -256,6 +265,8 @@
2037 static my_bool xtrabackup_compact = FALSE;
2038 static my_bool xtrabackup_rebuild_indexes = FALSE;
2039
2040+static my_bool xtrabackup_incremental_force_scan = FALSE;
2041+
2042 /* Datasinks */
2043 ds_ctxt_t *ds_data = NULL;
2044 ds_ctxt_t *ds_meta = NULL;
2045@@ -356,6 +367,7 @@
2046 OPT_XTRA_EXPORT,
2047 OPT_XTRA_APPLY_LOG_ONLY,
2048 OPT_XTRA_PRINT_PARAM,
2049+ OPT_XTRA_SUSPEND_AT_START,
2050 OPT_XTRA_SUSPEND_AT_END,
2051 OPT_XTRA_USE_MEMORY,
2052 OPT_XTRA_THROTTLE,
2053@@ -430,6 +442,7 @@
2054 OPT_INNODB_CHECKSUM_ALGORITHM,
2055 OPT_UNDO_TABLESPACES,
2056 #endif
2057+ OPT_XTRA_INCREMENTAL_FORCE_SCAN,
2058 OPT_DEFAULTS_GROUP
2059 };
2060
2061@@ -485,9 +498,21 @@
2062 (G_PTR*) &xtrabackup_use_memory, (G_PTR*) &xtrabackup_use_memory,
2063 0, GET_LL, REQUIRED_ARG, 100*1024*1024L, 1024*1024L, LONGLONG_MAX, 0,
2064 1024*1024L, 0},
2065- {"suspend-at-end", OPT_XTRA_SUSPEND_AT_END, "creates a file 'xtrabackup_suspended' and waits until the user deletes that file at the end of '--backup'",
2066+
2067+ {"suspend-at-start", OPT_XTRA_SUSPEND_AT_START,
2068+ "creates a file '" XB_FN_SUSPENDED_AT_START "' and waits until the user "
2069+ "deletes that file after the background log copying thread is started "
2070+ "during backup",
2071+ (G_PTR*) &xtrabackup_suspend_at_start,
2072+ (G_PTR*) &xtrabackup_suspend_at_start, 0, GET_BOOL, NO_ARG,
2073+ 0, 0, 0, 0, 0, 0},
2074+
2075+ {"suspend-at-end", OPT_XTRA_SUSPEND_AT_END, "creates a file '"
2076+ XB_FN_SUSPENDED_AT_END "' and waits until the user deletes that file at "
2077+ "the end of '--backup'",
2078 (G_PTR*) &xtrabackup_suspend_at_end, (G_PTR*) &xtrabackup_suspend_at_end,
2079 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
2080+
2081 {"throttle", OPT_XTRA_THROTTLE, "limit count of IO operations (pairs of read&write) per second to IOS values (for '--backup')",
2082 (G_PTR*) &xtrabackup_throttle, (G_PTR*) &xtrabackup_throttle,
2083 0, GET_LONG, REQUIRED_ARG, 0, 0, LONG_MAX, 0, 1, 0},
2084@@ -792,6 +817,13 @@
2085 0, GET_ULONG, REQUIRED_ARG, 0, 0, 126, 0, 1, 0},
2086 #endif
2087
2088+ {"incremental-force-scan", OPT_XTRA_INCREMENTAL_FORCE_SCAN,
2089+ "Perform a full-scan incremental backup even in the presence of changed "
2090+ "page bitmap data",
2091+ (G_PTR*)&xtrabackup_incremental_force_scan,
2092+ (G_PTR*)&xtrabackup_incremental_force_scan, 0, GET_BOOL, NO_ARG,
2093+ 0, 0, 0, 0, 0, 0},
2094+
2095 {"defaults_group", OPT_DEFAULTS_GROUP, "defaults group in config file (default \"mysqld\").",
2096 (G_PTR*) &defaults_group, (G_PTR*) &defaults_group,
2097 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
2098@@ -1747,6 +1779,7 @@
2099 xb_write_filt_t *write_filter = NULL;
2100 xb_write_filt_ctxt_t write_filt_ctxt;
2101 const char *action;
2102+ xb_read_filt_t *read_filter;
2103
2104 if (!trx_sys_sys_space(node->space->id) && /* don't skip system space */
2105 check_if_skip_table(node->name, "ibd")) {
2106@@ -1754,7 +1787,13 @@
2107 return(FALSE);
2108 }
2109
2110- res = xb_fil_cur_open(&cursor, node, thread_n);
2111+ if (!changed_page_bitmap) {
2112+ read_filter = &rf_pass_through;
2113+ }
2114+ else {
2115+ read_filter = &rf_bitmap;
2116+ }
2117+ res = xb_fil_cur_open(&cursor, read_filter, node, thread_n);
2118 if (res == XB_FIL_CUR_SKIP) {
2119 goto skip;
2120 } else if (res == XB_FIL_CUR_ERROR) {
2121@@ -2302,7 +2341,9 @@
2122 ds_data = ds;
2123
2124 if (xtrabackup_stream_fmt != XB_STREAM_FMT_XBSTREAM ||
2125- xtrabackup_suspend_at_end) {
2126+ xtrabackup_suspend_at_end ||
2127+ xtrabackup_suspend_at_start) {
2128+
2129 /* 'xbstream' allow parallel streams, but we
2130 still can't stream directly to stdout when
2131 xtrabackup is invoked from innobackupex
2132@@ -2481,20 +2522,34 @@
2133 }
2134
2135 /***********************************************************************
2136+Prepare a sync file path. */
2137+static void
2138+xb_make_sync_file_name(
2139+/*===================*/
2140+ const char* name, /*!<in: sync file name */
2141+ char* path) /*!<in/out: path to the sync file */
2142+{
2143+ snprintf(path, FN_REFLEN, "%s/%s", xtrabackup_target_dir, name);
2144+ srv_normalize_path_for_win(path);
2145+}
2146+
2147+/***********************************************************************
2148 Create an empty file with a given path and close it.
2149 @return TRUE on succees, FALSE on error. */
2150 static ibool
2151-xb_create_suspend_file(const char *path)
2152+xb_create_sync_file(
2153+/*================*/
2154+ const char* path) /*!<in: path to the sync file */
2155 {
2156- ibool success;
2157- os_file_t suspend_file = XB_FILE_UNDEFINED;
2158+ ibool success;
2159+ os_file_t suspend_file = XB_FILE_UNDEFINED;
2160
2161 /* xb_file_create reads srv_unix_file_flush_method */
2162 suspend_file = xb_file_create(path, OS_FILE_CREATE,
2163 OS_FILE_NORMAL, OS_DATA_FILE,
2164 &success);
2165
2166- if (success && suspend_file != XB_FILE_UNDEFINED) {
2167+ if (UNIV_LIKELY(success && suspend_file != XB_FILE_UNDEFINED)) {
2168
2169 os_file_close(suspend_file);
2170
2171@@ -2641,6 +2696,33 @@
2172 }
2173 }
2174
2175+/***********************************************************************
2176+Create a specified sync file and wait until it's removed. */
2177+static void
2178+xtrabackup_suspend(
2179+/*===============*/
2180+ const char* sync_fn) /*!<in: sync file name */
2181+{
2182+ char suspend_path[FN_REFLEN];
2183+ ibool success = TRUE;
2184+ ibool exists = TRUE;
2185+ os_file_type_t type;
2186+
2187+ xb_make_sync_file_name(sync_fn, suspend_path);
2188+
2189+ if (!xb_create_sync_file(suspend_path)) {
2190+ return;
2191+ }
2192+
2193+ while (exists && success) {
2194+ os_thread_sleep(200000); /*0.2 sec*/
2195+ success = os_file_status(suspend_path, &exists, &type);
2196+ /* success == FALSE if file exists, but stat() failed.
2197+ os_file_status() prints an error message in this case */
2198+ ut_a(success);
2199+ }
2200+}
2201+
2202 static void
2203 xtrabackup_backup_func(void)
2204 {
2205@@ -2650,8 +2732,6 @@
2206 uint count;
2207 os_ib_mutex_t count_mutex;
2208 data_thread_ctxt_t *data_threads;
2209- char suspend_path[FN_REFLEN];
2210- ibool success;
2211
2212 #ifdef USE_POSIX_FADVISE
2213 msg("xtrabackup: uses posix_fadvise().\n");
2214@@ -2939,6 +3019,25 @@
2215
2216 os_thread_create(log_copying_thread, NULL, &log_copying_thread_id);
2217
2218+ /* Suspend at start, for the FLUSH CHANGED_PAGE_BITMAPS call */
2219+ if (xtrabackup_suspend_at_start) {
2220+ xtrabackup_suspend(XB_FN_SUSPENDED_AT_START);
2221+ }
2222+
2223+ if (xtrabackup_incremental) {
2224+ if (!xtrabackup_incremental_force_scan) {
2225+ changed_page_bitmap = xb_page_bitmap_init();
2226+ }
2227+ if (!changed_page_bitmap) {
2228+ msg("xtrabackup: using the full scan for incremental "
2229+ "backup\n");
2230+ } else if (incremental_lsn != checkpoint_lsn_start) {
2231+ /* Do not print that bitmaps are used when dummy bitmap
2232+ is build for an empty LSN range. */
2233+ msg("xtrabackup: using the changed page bitmap\n");
2234+ }
2235+ }
2236+
2237 ut_a(xtrabackup_parallel > 0);
2238
2239 if (xtrabackup_parallel > 1) {
2240@@ -2982,29 +3081,14 @@
2241 ut_free(data_threads);
2242 datafiles_iter_free(it);
2243
2244+ if (changed_page_bitmap) {
2245+ xb_page_bitmap_deinit(changed_page_bitmap);
2246+ }
2247 }
2248
2249 /* suspend-at-end */
2250 if (xtrabackup_suspend_at_end) {
2251- ibool exists;
2252- os_file_type_t type;
2253-
2254- sprintf(suspend_path, "%s%s", xtrabackup_target_dir,
2255- "/xtrabackup_suspended");
2256- srv_normalize_path_for_win(suspend_path);
2257-
2258- if (!xb_create_suspend_file(suspend_path)) {
2259- exit(EXIT_FAILURE);
2260- }
2261-
2262- exists = TRUE;
2263- while (exists) {
2264- os_thread_sleep(200000); /*0.2 sec*/
2265- success = os_file_status(suspend_path, &exists, &type);
2266- /* success == FALSE if file exists, but stat() failed.
2267- os_file_status() prints an error message in this case */
2268- ut_a(success);
2269- }
2270+ xtrabackup_suspend(XB_FN_SUSPENDED_AT_END);
2271 }
2272
2273 /* read the latest checkpoint lsn */
2274@@ -3051,9 +3135,12 @@
2275 /* Signal innobackupex that log copying has stopped and it may now
2276 unlock tables, so we can possibly stream xtrabackup_logfile later
2277 without holding the lock. */
2278- if (xtrabackup_suspend_at_end &&
2279- !xb_create_suspend_file(suspend_path)) {
2280- exit(EXIT_FAILURE);
2281+ if (xtrabackup_suspend_at_end) {
2282+ char log_copied_sync_file[FN_REFLEN];
2283+ xb_make_sync_file_name(XB_FN_LOG_COPIED, log_copied_sync_file);
2284+ if (!xb_create_sync_file(log_copied_sync_file)) {
2285+ exit(EXIT_FAILURE);
2286+ }
2287 }
2288
2289 if(!xtrabackup_incremental) {
2290
2291=== modified file 'src/xtrabackup.h'
2292--- src/xtrabackup.h 2013-03-22 09:14:31 +0000
2293+++ src/xtrabackup.h 2013-04-15 15:08:38 +0000
2294@@ -23,6 +23,7 @@
2295
2296 #include "datasink.h"
2297 #include "innodb_int.h"
2298+#include "changed_page_bitmap.h"
2299
2300 typedef struct {
2301 ulint page_size;
2302@@ -46,6 +47,11 @@
2303 extern ds_ctxt_t *ds_meta;
2304 extern ds_ctxt_t *ds_data;
2305
2306+/* The last checkpoint LSN at the backup startup time */
2307+extern lsn_t checkpoint_lsn_start;
2308+
2309+extern xb_page_bitmap *changed_page_bitmap;
2310+
2311 void xtrabackup_io_throttling(void);
2312 my_bool xb_write_delta_metadata(const char *filename,
2313 const xb_delta_info_t *info);
2314
2315=== modified file 'test/inc/common.sh'
2316--- test/inc/common.sh 2013-03-22 09:14:31 +0000
2317+++ test/inc/common.sh 2013-04-15 15:08:38 +0000
2318@@ -189,6 +189,7 @@
2319 SRV_MYSQLD_DATADIR[$id]="$vardir/data"
2320 SRV_MYSQLD_TMPDIR[$id]="$vardir/tmp"
2321 SRV_MYSQLD_PIDFILE[$id]="${TEST_BASEDIR}/mysqld${id}.pid"
2322+ SRV_MYSQLD_ERRFILE[$id]="$vardir/data/mysqld${id}.err"
2323 SRV_MYSQLD_PORT[$id]=`get_free_port $id`
2324 SRV_MYSQLD_SOCKET[$id]=`mktemp -t xtrabackup.mysql.sock.XXXXXX`
2325 }
2326@@ -211,6 +212,7 @@
2327 SRV_MYSQLD_DATADIR[$id]=
2328 SRV_MYSQLD_TMPDIR[$id]=
2329 SRV_MYSQLD_PIDFILE[$id]=
2330+ SRV_MYSQLD_ERRFILE[$id]=
2331 SRV_MYSQLD_PORT[$id]=
2332 SRV_MYSQLD_SOCKET[$id]=
2333 }
2334@@ -227,11 +229,13 @@
2335 MYSQLD_DATADIR="${SRV_MYSQLD_DATADIR[$id]}"
2336 MYSQLD_TMPDIR="${SRV_MYSQLD_TMPDIR[$id]}"
2337 MYSQLD_PIDFILE="${SRV_MYSQLD_PIDFILE[$id]}"
2338+ MYSQLD_ERRFILE="${SRV_MYSQLD_ERRFILE[$id]}"
2339 MYSQLD_PORT="${SRV_MYSQLD_PORT[$id]}"
2340 MYSQLD_SOCKET="${SRV_MYSQLD_SOCKET[$id]}"
2341
2342 MYSQL_ARGS="--no-defaults --socket=${MYSQLD_SOCKET} --user=root"
2343 MYSQLD_ARGS="--no-defaults --basedir=${MYSQL_BASEDIR} \
2344+--log-error=${MYSQLD_ERRFILE}
2345 --socket=${MYSQLD_SOCKET} --port=${MYSQLD_PORT} --server-id=$id \
2346 --datadir=${MYSQLD_DATADIR} --tmpdir=${MYSQLD_TMPDIR} --log-bin=mysql-bin \
2347 --relay-log=mysql-relay-bin --pid-file=${MYSQLD_PIDFILE} ${MYSQLD_EXTRA_ARGS}"
2348@@ -455,5 +459,62 @@
2349 return ${PIPESTATUS[0]}
2350 }
2351
2352+readonly xb_performed_bmp_inc_backup="xtrabackup: using the full scan for incremental backup"
2353+readonly xb_performed_full_scan_inc_backup="xtrabackup: using the changed page bitmap"
2354+
2355+####################################################
2356+# Helper functions for testing incremental backups #
2357+####################################################
2358+function check_full_scan_inc_backup()
2359+{
2360+ if ! grep -q "$xb_performed_bmp_inc_backup" $OUTFILE ;
2361+ then
2362+ vlog "xtrabackup did not perform a full scan for the incremental backup."
2363+ exit -1
2364+ fi
2365+ if grep -q "$xb_performed_full_scan_inc_backup" $OUTFILE ;
2366+ then
2367+ vlog "xtrabackup appeared to use bitmaps instead of full scan for the incremental backup."
2368+ exit -1
2369+ fi
2370+}
2371+
2372+function check_bitmap_inc_backup()
2373+{
2374+ if ! grep -q "$xb_performed_full_scan_inc_backup" $OUTFILE ;
2375+ then
2376+ vlog "xtrabackup did not use bitmaps for the incremental backup."
2377+ exit -1
2378+ fi
2379+ if grep -q "$xb_performed_bmp_inc_backup" $OUTFILE ;
2380+ then
2381+ vlog "xtrabackup used a full scan instead of bitmaps for the incremental backup."
2382+ exit -1
2383+ fi
2384+}
2385+
2386+##############################################################
2387+# Helper functions for xtrabackup process suspend and resume #
2388+##############################################################
2389+function wait_for_xb_to_suspend()
2390+{
2391+ local file=$1
2392+ local i=0
2393+ echo "Waiting for $file to be created"
2394+ while [ ! -r $file ]
2395+ do
2396+ sleep 1
2397+ i=$((i+1))
2398+ echo "Waited $i seconds for xtrabackup_suspended to be created"
2399+ done
2400+}
2401+
2402+function resume_suspended_xb()
2403+{
2404+ local file=$1
2405+ echo "Removing $file"
2406+ rm -f $file
2407+}
2408+
2409 # To avoid unbound variable error when no server have been started
2410 SRV_MYSQLD_IDS=
2411
2412=== renamed file 'test/t/ib_incremental.sh' => 'test/inc/ib_incremental_common.sh'
2413--- test/t/ib_incremental.sh 2012-10-15 16:14:59 +0000
2414+++ test/inc/ib_incremental_common.sh 2013-04-15 15:08:38 +0000
2415@@ -1,6 +1,14 @@
2416+# Expects the following variable to be set before including:
2417+# mysqld_extra_args: an extra arg to be passed for all mysqld invocations.
2418+# Use this to set special options that influence
2419+# incremental backups, e.g. turns on log archiving or
2420+# changed page bitmap output.
2421+
2422 . inc/common.sh
2423
2424-start_server --innodb_file_per_table
2425+mysqld_extra_args="$mysqld_extra_args --innodb_file_per_table"
2426+
2427+start_server $mysqld_extra_args
2428 load_dbase_schema incremental_sample
2429
2430 # Adding initial rows
2431@@ -35,6 +43,18 @@
2432 ${MYSQL} ${MYSQL_ARGS} -e "insert into t2 values ($count, $numrow);" incremental_sample
2433 let "count=count+1"
2434 done
2435+
2436+# Rotate bitmap file here and force checkpoint at the same time
2437+shutdown_server
2438+start_server $mysqld_extra_args
2439+
2440+i=1001
2441+while [ "$i" -lt "7500" ]
2442+do
2443+ ${MYSQL} ${MYSQL_ARGS} -e "insert into t2 values ($i, repeat(\"ab\", 32500));" incremental_sample
2444+ let "i=i+1"
2445+done
2446+
2447 vlog "Changes done"
2448
2449 # Saving the checksum of original table
2450@@ -87,7 +107,7 @@
2451 innobackupex --copy-back $full_backup_dir
2452 vlog "Data restored"
2453
2454-start_server --innodb_file_per_table
2455+start_server $mysqld_extra_args
2456
2457 vlog "Checking checksums"
2458 checksum_test_b=`checksum_table incremental_sample test`
2459
2460=== modified file 'test/t/bug1007446.sh'
2461--- test/t/bug1007446.sh 2012-12-26 23:48:57 +0000
2462+++ test/t/bug1007446.sh 2013-04-15 15:08:38 +0000
2463@@ -6,7 +6,7 @@
2464
2465 start_server
2466
2467-echo "" > $MYSQLD_TMPDIR/xtrabackup_suspended
2468+echo "" > $MYSQLD_TMPDIR/xtrabackup_suspended_1
2469
2470 mkdir -p $topdir/backup
2471 innobackupex --stream=tar $topdir/backup > /dev/null
2472
2473=== added file 'test/t/ib_incremental_bitmap.sh'
2474--- test/t/ib_incremental_bitmap.sh 1970-01-01 00:00:00 +0000
2475+++ test/t/ib_incremental_bitmap.sh 2013-04-15 15:08:38 +0000
2476@@ -0,0 +1,25 @@
2477+# Test for incremental backups that use changed page bitmaps
2478+
2479+if [ -z "$XTRADB_VERSION" ]; then
2480+ echo "Requires XtraDB" > $SKIPPED_REASON
2481+ exit $SKIPPED_EXIT_CODE
2482+fi
2483+
2484+# The test is disabled for Percona XtraDB Cluster until a version
2485+# with bitmap user requests is released (containing PS 5.5.29-30.0
2486+# or later)
2487+set +e
2488+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2489+probe_result=$?
2490+if [[ "$probe_result" == "0" ]]
2491+ then
2492+ vlog "Incompatible test" > $SKIPPED_REASON
2493+ exit $SKIPPED_EXIT_CODE
2494+fi
2495+set -e
2496+
2497+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2498+
2499+. inc/ib_incremental_common.sh
2500+
2501+check_bitmap_inc_backup
2502
2503=== added file 'test/t/ib_incremental_full_scan.sh'
2504--- test/t/ib_incremental_full_scan.sh 1970-01-01 00:00:00 +0000
2505+++ test/t/ib_incremental_full_scan.sh 2013-04-15 15:08:38 +0000
2506@@ -0,0 +1,7 @@
2507+# Test incremental backups that do full data file scans
2508+
2509+mysqld_extra_args=
2510+
2511+. inc/ib_incremental_common.sh
2512+
2513+check_full_scan_inc_backup
2514
2515=== added file 'test/t/xb_incremental_bitmap_misc.sh'
2516--- test/t/xb_incremental_bitmap_misc.sh 1970-01-01 00:00:00 +0000
2517+++ test/t/xb_incremental_bitmap_misc.sh 2013-04-15 15:08:38 +0000
2518@@ -0,0 +1,76 @@
2519+# Test diagnostics for missing bitmap data and --incremental-force-scan option
2520+
2521+if [ -z "$XTRADB_VERSION" ]; then
2522+ echo "Requires XtraDB" > $SKIPPED_REASON
2523+ exit $SKIPPED_EXIT_CODE
2524+fi
2525+
2526+# The test is disabled for Percona XtraDB Cluster until a version
2527+# with bitmap user requests is released (containing PS 5.5.29-30.0
2528+# or later)
2529+set +e
2530+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2531+probe_result=$?
2532+if [[ "$probe_result" == "0" ]]
2533+ then
2534+ vlog "Incompatible test" > $SKIPPED_REASON
2535+ exit $SKIPPED_EXIT_CODE
2536+fi
2537+set -e
2538+
2539+. inc/common.sh
2540+
2541+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2542+
2543+start_server $mysqld_extra_args
2544+${MYSQL} ${MYSQL_ARGS} -e "CREATE TABLE t1 (a INT) ENGINE=INNODB" test
2545+${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO t1 VALUES (1)" test
2546+
2547+# Force checkpoint
2548+shutdown_server
2549+start_server $mysqld_extra_args
2550+
2551+# Full backup
2552+# mkdir $topdir/data/full
2553+# xtrabackup --datadir=$mysql_datadir --backup --target-dir=$topdir/data/inc1 --
2554+
2555+${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO t1 VALUES (2)" test
2556+# Force checkpoint
2557+shutdown_server
2558+start_server $mysqld_extra_args
2559+${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO t1 VALUES (3)" test
2560+# Force checkpoint
2561+shutdown_server
2562+start_server $mysqld_extra_args
2563+${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO t1 VALUES (4)" test
2564+# Force checkpoint
2565+shutdown_server
2566+start_server $mysqld_extra_args
2567+
2568+ls -l $mysql_datadir/*.xdb
2569+
2570+vlog "Test --incremental-force-scan option"
2571+xtrabackup --datadir=$mysql_datadir --backup \
2572+ --target-dir=$topdir/data/inc0 --incremental_lsn=9000 \
2573+ --incremental-force-scan
2574+
2575+vlog "Test nonsensical LSN range (start LSN > end LSN)"
2576+xtrabackup --datadir=$mysql_datadir --backup \
2577+ --target-dir=$topdir/data/inc1 --incremental-lsn=500000000000
2578+
2579+vlog "Test missing bitmap data diagnostics: middle of range"
2580+run_cmd rm $mysql_datadir/ib_modified_log_2*.xdb
2581+xtrabackup --datadir=$mysql_datadir --backup \
2582+ --target-dir=$topdir/data/inc2 --incremental-lsn=9000
2583+
2584+vlog "Test missing bitmap data diagnostics: end of range too"
2585+run_cmd rm $mysql_datadir/ib_modified_log_3*.xdb
2586+xtrabackup --datadir=$mysql_datadir --backup \
2587+ --target-dir=$topdir/data/inc3 --incremental-lsn=9000
2588+
2589+vlog "Test missing bitmap data diagnostics: start of range too"
2590+run_cmd rm $mysql_datadir/ib_modified_log_1*.xdb
2591+xtrabackup --datadir=$mysql_datadir --backup \
2592+ --target-dir=$topdir/data/inc4 --incremental-lsn=9000
2593+
2594+check_full_scan_inc_backup
2595
2596=== modified file 'test/t/xb_incremental_compressed.inc'
2597--- test/t/xb_incremental_compressed.inc 2012-11-08 03:44:14 +0000
2598+++ test/t/xb_incremental_compressed.inc 2013-04-15 15:08:38 +0000
2599@@ -1,13 +1,33 @@
2600 ################################################################################
2601 # Test incremental backup with InnoDB compression
2602 ################################################################################
2603+# Expects the following variable to be set before including:
2604+# mysqld_extra_args: an extra arg to be passed for all mysqld invocations.
2605+# Use this to set special options that influence
2606+# incremental backups, e.g. turns on log archiving or
2607+# changed page bitmap output.
2608+# first_inc_suspend_command: if non-empty string, passes --suspend-at-start
2609+# to incremental XB invocation and executes the
2610+# given command while it's suspended
2611
2612 . inc/common.sh
2613
2614-if [ -z "$INNODB_VERSION" ]; then
2615- echo "Requires InnoDB plugin or XtraDB" >$SKIPPED_REASON
2616- exit $SKIPPED_EXIT_CODE
2617-fi
2618+function add_rows()
2619+{
2620+ local table=$1
2621+ local start=$2
2622+ local limit=$3
2623+
2624+ while [ "$limit" -gt "$start" ]; do
2625+ sql="INSERT INTO $table VALUES ($start, $limit)"
2626+ let "start=start+1"
2627+ for ((i=0; $i<99; i++)); do
2628+ sql="${sql},($start, $limit)"
2629+ let "start=start+1"
2630+ done
2631+ ${MYSQL} ${MYSQL_ARGS} -e "$sql" incremental_sample
2632+ done
2633+}
2634
2635 #
2636 # Test incremental backup of a compressed tablespace with a specific page size
2637@@ -22,9 +42,9 @@
2638
2639 # Use innodb_strict_mode so that failure to use compression results in an
2640 # error rather than a warning
2641- mysqld_additional_args="--innodb_strict_mode --innodb_file_per_table \
2642- --innodb_file_format=Barracuda --innodb_max_dirty_pages_pct=0 \
2643- --innodb_log_file_size=1M"
2644+ mysqld_additional_args="$mysqld_extra_args --innodb_strict_mode \
2645+ --innodb_file_per_table --innodb_file_format=Barracuda \
2646+ --innodb_max_dirty_pages_pct=0 --innodb_log_file_size=1M"
2647
2648 start_server ${mysqld_additional_args}
2649
2650@@ -40,17 +60,7 @@
2651
2652 vlog "Adding initial rows to database..."
2653
2654- numrow=10000
2655- count=0
2656- while [ "$numrow" -gt "$count" ]; do
2657- sql="INSERT INTO test VALUES ($count, $numrow)"
2658- let "count=count+1"
2659- for ((i=0; $i<99; i++)); do
2660- sql="${sql},($count, $numrow)"
2661- let "count=count+1"
2662- done
2663- ${MYSQL} ${MYSQL_ARGS} -e "$sql" incremental_sample
2664- done
2665+ add_rows test 0 10000
2666
2667 rows=`${MYSQL} ${MYSQL_ARGS} -Ns -e "SELECT COUNT(*) FROM test" \
2668 incremental_sample`
2669@@ -84,18 +94,15 @@
2670 number INT(11) DEFAULT NULL) ENGINE=INNODB \
2671 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=$page_size" incremental_sample
2672
2673- let "count=numrow+1"
2674- let "numrow=15000"
2675- while [ "$numrow" -gt "$count" ]; do
2676- sql="VALUES ($count, $numrow)"
2677- let "count=count+1"
2678- for ((i=0; $i<99; i++)); do
2679- sql="${sql},($count, $numrow)"
2680- let "count=count+1"
2681- done
2682- ${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO test $sql" incremental_sample
2683- ${MYSQL} ${MYSQL_ARGS} -e "INSERT INTO t2 $sql" incremental_sample
2684- done
2685+ add_rows test 10001 12500
2686+ add_rows t2 10001 12500
2687+
2688+ # Rotate bitmap file here and force checkpoint at the same time
2689+ shutdown_server
2690+ start_server ${mysqld_additional_args}
2691+
2692+ add_rows test 12501 15000
2693+ add_rows t2 12501 15000
2694
2695 rows=`${MYSQL} ${MYSQL_ARGS} -Ns -e "SELECT COUNT(*) FROM test" \
2696 incremental_sample`
2697@@ -122,10 +129,29 @@
2698
2699 vlog "Making incremental backup"
2700
2701+ if [ -n "$first_inc_suspend_command" ]
2702+ then
2703+ suspend_arg="--suspend_at_start";
2704+ else
2705+ suspend_arg="";
2706+ fi
2707+
2708 # Incremental backup
2709 xtrabackup --datadir=$mysql_datadir --backup \
2710 --target-dir=$topdir/data/delta --incremental-basedir=$topdir/data/full \
2711- ${mysqld_additional_args}
2712+ ${mysqld_additional_args} $suspend_arg &
2713+
2714+ xb_pid=$!
2715+
2716+ if [ -n "$first_inc_suspend_command" ]
2717+ then
2718+ wait_for_xb_to_suspend $topdir/data/delta/xtrabackup_suspended_1
2719+ ${MYSQL} ${MYSQL_ARGS} -e "$first_inc_suspend_command"
2720+
2721+ resume_suspended_xb $topdir/data/delta/xtrabackup_suspended_1
2722+ fi
2723+
2724+ wait $xb_pid
2725
2726 vlog "Incremental backup done"
2727 vlog "Preparing backup"
2728@@ -149,7 +175,8 @@
2729
2730 # Restore backup
2731
2732- stop_server
2733+ shutdown_server
2734+ rm -f $mysql_datadir/ib_modified_log*
2735
2736 vlog "Copying files"
2737
2738
2739=== added file 'test/t/xb_incremental_compressed_bitmap_16kb.sh'
2740--- test/t/xb_incremental_compressed_bitmap_16kb.sh 1970-01-01 00:00:00 +0000
2741+++ test/t/xb_incremental_compressed_bitmap_16kb.sh 2013-04-15 15:08:38 +0000
2742@@ -0,0 +1,28 @@
2743+# Test incremental backups that use bitmaps with 16KB compressed pages
2744+
2745+if [ -z "$XTRADB_VERSION" ]; then
2746+ echo "Requires XtraDB" > $SKIPPED_REASON
2747+ exit $SKIPPED_EXIT_CODE
2748+fi
2749+
2750+# The test is disabled for Percona XtraDB Cluster until a version
2751+# with bitmap user requests is released (containing PS 5.5.29-30.0
2752+# or later)
2753+set +e
2754+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2755+probe_result=$?
2756+if [[ "$probe_result" == "0" ]]
2757+ then
2758+ vlog "Incompatible test" > $SKIPPED_REASON
2759+ exit $SKIPPED_EXIT_CODE
2760+fi
2761+set -e
2762+
2763+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2764+first_inc_suspend_command="FLUSH CHANGED_PAGE_BITMAPS;"
2765+
2766+source t/xb_incremental_compressed.inc
2767+
2768+test_incremental_compressed 16
2769+
2770+check_bitmap_inc_backup
2771
2772=== added file 'test/t/xb_incremental_compressed_bitmap_1kb.sh'
2773--- test/t/xb_incremental_compressed_bitmap_1kb.sh 1970-01-01 00:00:00 +0000
2774+++ test/t/xb_incremental_compressed_bitmap_1kb.sh 2013-04-15 15:08:38 +0000
2775@@ -0,0 +1,28 @@
2776+# Test incremental backups that use bitmaps with 1KB compressed pages
2777+
2778+if [ -z "$XTRADB_VERSION" ]; then
2779+ echo "Requires XtraDB" > $SKIPPED_REASON
2780+ exit $SKIPPED_EXIT_CODE
2781+fi
2782+
2783+# The test is disabled for Percona XtraDB Cluster until a version
2784+# with bitmap user requests is released (containing PS 5.5.29-30.0
2785+# or later)
2786+set +e
2787+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2788+probe_result=$?
2789+if [[ "$probe_result" == "0" ]]
2790+ then
2791+ vlog "Incompatible test" > $SKIPPED_REASON
2792+ exit $SKIPPED_EXIT_CODE
2793+fi
2794+set -e
2795+
2796+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2797+first_inc_suspend_command="FLUSH CHANGED_PAGE_BITMAPS;"
2798+
2799+source t/xb_incremental_compressed.inc
2800+
2801+test_incremental_compressed 1
2802+
2803+check_bitmap_inc_backup
2804
2805=== added file 'test/t/xb_incremental_compressed_bitmap_2kb.sh'
2806--- test/t/xb_incremental_compressed_bitmap_2kb.sh 1970-01-01 00:00:00 +0000
2807+++ test/t/xb_incremental_compressed_bitmap_2kb.sh 2013-04-15 15:08:38 +0000
2808@@ -0,0 +1,28 @@
2809+# Test incremental backups that use bitmaps with 2KB compressed pages
2810+
2811+if [ -z "$XTRADB_VERSION" ]; then
2812+ echo "Requires XtraDB" > $SKIPPED_REASON
2813+ exit $SKIPPED_EXIT_CODE
2814+fi
2815+
2816+# The test is disabled for Percona XtraDB Cluster until a version
2817+# with bitmap user requests is released (containing PS 5.5.29-30.0
2818+# or later)
2819+set +e
2820+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2821+probe_result=$?
2822+if [[ "$probe_result" == "0" ]]
2823+ then
2824+ vlog "Incompatible test" > $SKIPPED_REASON
2825+ exit $SKIPPED_EXIT_CODE
2826+fi
2827+set -e
2828+
2829+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2830+first_inc_suspend_command="FLUSH CHANGED_PAGE_BITMAPS;"
2831+
2832+source t/xb_incremental_compressed.inc
2833+
2834+test_incremental_compressed 2
2835+
2836+check_bitmap_inc_backup
2837
2838=== added file 'test/t/xb_incremental_compressed_bitmap_4kb.sh'
2839--- test/t/xb_incremental_compressed_bitmap_4kb.sh 1970-01-01 00:00:00 +0000
2840+++ test/t/xb_incremental_compressed_bitmap_4kb.sh 2013-04-15 15:08:38 +0000
2841@@ -0,0 +1,28 @@
2842+# Test incremental backups that use bitmaps with 4KB compressed pages
2843+
2844+if [ -z "$XTRADB_VERSION" ]; then
2845+ echo "Requires XtraDB" > $SKIPPED_REASON
2846+ exit $SKIPPED_EXIT_CODE
2847+fi
2848+
2849+# The test is disabled for Percona XtraDB Cluster until a version
2850+# with bitmap user requests is released (containing PS 5.5.29-30.0
2851+# or later)
2852+set +e
2853+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2854+probe_result=$?
2855+if [[ "$probe_result" == "0" ]]
2856+ then
2857+ vlog "Incompatible test" > $SKIPPED_REASON
2858+ exit $SKIPPED_EXIT_CODE
2859+fi
2860+set -e
2861+
2862+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2863+first_inc_suspend_command="FLUSH CHANGED_PAGE_BITMAPS;"
2864+
2865+source t/xb_incremental_compressed.inc
2866+
2867+test_incremental_compressed 4
2868+
2869+check_bitmap_inc_backup
2870
2871=== added file 'test/t/xb_incremental_compressed_bitmap_8kb.sh'
2872--- test/t/xb_incremental_compressed_bitmap_8kb.sh 1970-01-01 00:00:00 +0000
2873+++ test/t/xb_incremental_compressed_bitmap_8kb.sh 2013-04-15 15:08:38 +0000
2874@@ -0,0 +1,28 @@
2875+# Test incremental backups that use bitmaps with 8KB compressed pages
2876+
2877+if [ -z "$XTRADB_VERSION" ]; then
2878+ echo "Requires XtraDB" > $SKIPPED_REASON
2879+ exit $SKIPPED_EXIT_CODE
2880+fi
2881+
2882+# The test is disabled for Percona XtraDB Cluster until a version
2883+# with bitmap user requests is released (containing PS 5.5.29-30.0
2884+# or later)
2885+set +e
2886+${MYSQLD} --basedir=$MYSQL_BASEDIR --user=$USER --help --verbose --wsrep-sst-method=rsync| grep -q wsrep
2887+probe_result=$?
2888+if [[ "$probe_result" == "0" ]]
2889+ then
2890+ vlog "Incompatible test" > $SKIPPED_REASON
2891+ exit $SKIPPED_EXIT_CODE
2892+fi
2893+set -e
2894+
2895+mysqld_extra_args=--innodb-track-changed-pages=TRUE
2896+first_inc_suspend_command="FLUSH CHANGED_PAGE_BITMAPS;"
2897+
2898+source t/xb_incremental_compressed.inc
2899+
2900+test_incremental_compressed 8
2901+
2902+check_bitmap_inc_backup
2903
2904=== renamed file 'test/t/xb_incremental_compressed_16kb.sh' => 'test/t/xb_incremental_compressed_full_scan_16kb.sh'
2905--- test/t/xb_incremental_compressed_16kb.sh 2012-11-08 03:44:14 +0000
2906+++ test/t/xb_incremental_compressed_full_scan_16kb.sh 2013-04-15 15:08:38 +0000
2907@@ -1,2 +1,10 @@
2908+# Test incremental backups that do full data scans with 16KB compressed pages
2909+
2910+mysqld_extra_args=
2911+first_inc_suspend_command=
2912+
2913 source t/xb_incremental_compressed.inc
2914+
2915 test_incremental_compressed 16
2916+
2917+check_full_scan_inc_backup
2918
2919=== renamed file 'test/t/xb_incremental_compressed_1kb.sh' => 'test/t/xb_incremental_compressed_full_scan_1kb.sh'
2920--- test/t/xb_incremental_compressed_1kb.sh 2012-11-08 03:44:14 +0000
2921+++ test/t/xb_incremental_compressed_full_scan_1kb.sh 2013-04-15 15:08:38 +0000
2922@@ -1,2 +1,10 @@
2923+# Test incremental backups that do full data scans with 1KB compressed pages
2924+
2925+mysqld_extra_args=
2926+first_inc_suspend_command=
2927+
2928 source t/xb_incremental_compressed.inc
2929+
2930 test_incremental_compressed 1
2931+
2932+check_full_scan_inc_backup
2933
2934=== renamed file 'test/t/xb_incremental_compressed_2kb.sh' => 'test/t/xb_incremental_compressed_full_scan_2kb.sh'
2935--- test/t/xb_incremental_compressed_2kb.sh 2012-11-08 03:44:14 +0000
2936+++ test/t/xb_incremental_compressed_full_scan_2kb.sh 2013-04-15 15:08:38 +0000
2937@@ -1,2 +1,10 @@
2938+# Test incremental backups that do full data scans with 2KB compressed pages
2939+
2940+mysqld_extra_args=
2941+first_inc_suspend_command=
2942+
2943 source t/xb_incremental_compressed.inc
2944+
2945 test_incremental_compressed 2
2946+
2947+check_full_scan_inc_backup
2948
2949=== renamed file 'test/t/xb_incremental_compressed_4kb.sh' => 'test/t/xb_incremental_compressed_full_scan_4kb.sh'
2950--- test/t/xb_incremental_compressed_4kb.sh 2012-11-08 03:44:14 +0000
2951+++ test/t/xb_incremental_compressed_full_scan_4kb.sh 2013-04-15 15:08:38 +0000
2952@@ -1,2 +1,10 @@
2953+# Test incremental backups that do full data scans with 4KB compressed pages
2954+
2955+mysqld_extra_args=
2956+first_inc_suspend_command=
2957+
2958 source t/xb_incremental_compressed.inc
2959+
2960 test_incremental_compressed 4
2961+
2962+check_full_scan_inc_backup
2963
2964=== renamed file 'test/t/xb_incremental_compressed_8kb.sh' => 'test/t/xb_incremental_compressed_full_scan_8kb.sh'
2965--- test/t/xb_incremental_compressed_8kb.sh 2012-11-08 03:44:14 +0000
2966+++ test/t/xb_incremental_compressed_full_scan_8kb.sh 2013-04-15 15:08:38 +0000
2967@@ -1,2 +1,10 @@
2968+# Test incremental backups that do full data scans with 8KB compressed pages
2969+
2970+mysqld_extra_args=
2971+first_inc_suspend_command=
2972+
2973 source t/xb_incremental_compressed.inc
2974+
2975 test_incremental_compressed 8
2976+
2977+check_full_scan_inc_backup
2978
2979=== modified file 'test/t/xb_log_overwrap.sh'
2980--- test/t/xb_log_overwrap.sh 2013-01-08 10:14:53 +0000
2981+++ test/t/xb_log_overwrap.sh 2013-04-15 15:08:38 +0000
2982@@ -20,14 +20,7 @@
2983
2984 pid_file=$topdir/backup/xtrabackup_debug_sync
2985
2986-# Wait for xtrabackup to suspend
2987-i=0
2988-while [ ! -r "$pid_file" ]
2989-do
2990- sleep 1
2991- i=$((i+1))
2992- echo "Waited $i seconds for $pid_file to be created"
2993-done
2994+wait_for_xb_to_suspend $pid_file
2995
2996 xb_pid=`cat $pid_file`
2997
2998@@ -41,5 +34,7 @@
2999 vlog "Resuming xtrabackup"
3000 kill -SIGCONT $xb_pid
3001
3002+resume_suspended_xb $topdir/backup/xtrabackup_suspended_2
3003+
3004 # wait's return code will be the code returned by the background process
3005 run_cmd wait $job_pid

Subscribers

People subscribed via source and target branches