Merge lp:~laurynas-biveinis/percona-xtrabackup/xb-changed-page-bitmap into lp:percona-xtrabackup/2.1
- xb-changed-page-bitmap
- Merge into 2.1
Status: | Merged |
---|---|
Approved by: | Alexey Kopytov |
Approved revision: | 535 |
Merged at revision: | 545 |
Proposed branch: | lp:~laurynas-biveinis/percona-xtrabackup/xb-changed-page-bitmap |
Merge into: | lp:percona-xtrabackup/2.1 |
Diff against target: |
3089 lines (+2134/-172) 35 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 (+123/-66) 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 (+25/-3) test/t/bug1007446.sh (+1/-1) test/t/ib_incremental_bitmap.sh (+26/-0) test/t/ib_incremental_force_full_scan.sh (+27/-0) test/t/ib_incremental_full_scan.sh (+8/-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 |
Related bugs: | |
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexey Kopytov (community) | Approve | ||
Review via email:
|
This proposal supersedes a proposal from 2013-04-16.
Commit message
Description of the change
4th MP:
http://
- Added option --incremental-
- Added new testcase ib_incremental_
3rd MP:
http://
- Updated to the current 2.1 trunk.
- Added option --incremental-
- Fixed stray semicolons in mysql_query(). (Only in those introduced in this MP, left the existing ones untouched).
- Removed spurious BEGIN/COMMIT from the testcases.
- Updated docs. It is debatable whether it's complete and well-written, but it's a start.
2nd MP:
http://
Updated to the current 2.1 trunk.
1st MP:
BT 16274
http://
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:/
and
https:/
- innobackupex: split the xtrabackup_
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_
found, add 1st suspend to xtrabackup invocation and issue FLUSH
CHANGED_
presence loop out of wait_for_
into new subroutine wait_for_
copying finish logic out of resume_ibbackup into a new subroutine
wait_
- New source files changed_
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_
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_
mark fold as unused.
- xtrabackup.h: declare checkpoint_
- xtrabackup.cc: split xtrabackup_
as in innobackupex. New functions xb_make_
xtrabackup_
xb_create_
xtrabackup after the log copying thread has started.
xtrabackup_
has been allocated, a pass through filter otherwise and pass it to
the file cursor.
xtrabackup_
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_
set up server error log location in SRV_MYSQLD_
switch_server(): set up MySQL error log.
check_
functions for grepping XtraBackup output for the incremental backup
type used. wait_for_
functions for the testcases that use xtrabackup suspend.
- Rename test test/t/
test/
$mysqld_
- Rename test test/t/
test/
$mysqld_
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/
test/
$mysqld_
coverage. ADd two new testcases ib_incremental_
ib_incrementa
- Adjust test/t/
tests xb_incremental_
the previous xb_incremental_
xb_incrementa
check from xb_incremental_
the currently supported versions.
- New test xb_incremental_
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/
wait_
- Makefile: update dependencies.

Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |

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).

Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
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
--
- 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.

Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
> - it would be nice to have an option to force the old .delta
> calculation method even if bitmaps are available; something like
> --incremental-
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).

Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Laurynas,
I meant to say it would be nice to have --incremental-

Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
--incremental-
It's obvious, but, the work of hurry :(
Meanwhile I'll be glad to take any documentation change suggestions.

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