1 | /****************************************************** |
2 | XtraBackup: hot backup tool for InnoDB |
3 | (c) 2009-2012 Percona Inc. |
4 | Originally Created 3/3/2009 Yasufumi Kinoshita |
5 | Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko, |
6 | Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz. |
7 | |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; version 2 of the License. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
20 | |
21 | *******************************************************/ |
22 | |
23 | /* Data file read filter implementation */ |
24 | |
25 | #include "read_filt.h" |
26 | #include "common.h" |
27 | #include "fil_cur.h" |
28 | #include "xtrabackup.h" |
29 | |
30 | /****************************************************************//** |
31 | Perform read filter context initialization that is common to all read |
32 | filters. */ |
33 | static |
34 | void |
35 | common_init( |
36 | /*========*/ |
37 | xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */ |
38 | const xb_fil_cur_t* cursor) /*!<in: file cursor */ |
39 | { |
40 | ctxt->offset = 0; |
41 | ctxt->data_file_size = cursor->statinfo.st_size; |
42 | ctxt->buffer_capacity = cursor->buf_size; |
43 | ctxt->page_size = cursor->page_size; |
44 | } |
45 | |
46 | /****************************************************************//** |
47 | Initialize the pass-through read filter. */ |
48 | static |
49 | void |
50 | rf_pass_through_init( |
51 | /*=================*/ |
52 | xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter context */ |
53 | const xb_fil_cur_t* cursor, /*!<in: file cursor */ |
54 | ulint space_id __attribute__((unused))) |
55 | /*!<in: space id we are reading */ |
56 | { |
57 | common_init(ctxt, cursor); |
58 | } |
59 | |
60 | /****************************************************************//** |
61 | Get the next batch of pages for the pass-through read filter. */ |
62 | static |
63 | void |
64 | rf_pass_through_get_next_batch( |
65 | /*===========================*/ |
66 | xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter |
67 | context */ |
68 | ib_int64_t* read_batch_start, /*!<out: starting read |
69 | offset in bytes for the |
70 | next batch of pages */ |
71 | ib_int64_t* read_batch_len) /*!<out: length in |
72 | bytes of the next batch |
73 | of pages */ |
74 | { |
75 | *read_batch_start = ctxt->offset; |
76 | *read_batch_len = ctxt->data_file_size - ctxt->offset; |
77 | |
78 | if (*read_batch_len > (ib_int64_t)ctxt->buffer_capacity) { |
79 | *read_batch_len = ctxt->buffer_capacity; |
80 | } |
81 | |
82 | ctxt->offset += *read_batch_len; |
83 | } |
84 | |
85 | /****************************************************************//** |
86 | Deinitialize the pass-through read filter. */ |
87 | static |
88 | void |
89 | rf_pass_through_deinit( |
90 | /*===================*/ |
91 | xb_read_filt_ctxt_t* ctxt __attribute__((unused))) |
92 | /*!<in: read filter context */ |
93 | { |
94 | } |
95 | |
96 | /****************************************************************//** |
97 | Initialize the changed page bitmap-based read filter. Assumes that |
98 | the bitmap is already set up in changed_page_bitmap. */ |
99 | static |
100 | void |
101 | rf_bitmap_init( |
102 | /*===========*/ |
103 | xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter |
104 | context */ |
105 | const xb_fil_cur_t* cursor, /*!<in: read cursor */ |
106 | ulint space_id) /*!<in: space id */ |
107 | { |
108 | common_init(ctxt, cursor); |
109 | ctxt->bitmap_range = xb_page_bitmap_range_init(changed_page_bitmap, |
110 | space_id); |
111 | ctxt->filter_batch_end = 0; |
112 | } |
113 | |
114 | /****************************************************************//** |
115 | Get the next batch of pages for the bitmap read filter. */ |
116 | static |
117 | void |
118 | rf_bitmap_get_next_batch( |
119 | /*=====================*/ |
120 | xb_read_filt_ctxt_t* ctxt, /*!<in/out: read filter |
121 | context */ |
122 | ib_int64_t* read_batch_start, /*!<out: starting read |
123 | offset in bytes for the |
124 | next batch of pages */ |
125 | ib_int64_t* read_batch_len) /*!<out: length in |
126 | bytes of the next batch |
127 | of pages */ |
128 | { |
129 | ulint start_page_id; |
130 | const ulint page_size = ctxt->page_size.physical(); |
131 | |
132 | start_page_id = (ulint)(ctxt->offset / page_size); |
133 | |
134 | xb_a (ctxt->offset % page_size == 0); |
135 | |
136 | if (start_page_id == ctxt->filter_batch_end) { |
137 | |
138 | /* Used up all the previous bitmap range, get some more */ |
139 | ulint next_page_id; |
140 | |
141 | /* Find the next changed page using the bitmap */ |
142 | next_page_id = xb_page_bitmap_range_get_next_bit |
143 | (ctxt->bitmap_range, TRUE); |
144 | |
145 | if (next_page_id == ULINT_UNDEFINED) { |
146 | *read_batch_len = 0; |
147 | return; |
148 | } |
149 | |
150 | ctxt->offset = next_page_id * page_size; |
151 | |
152 | /* Find the end of the current changed page block by searching |
153 | for the next cleared bitmap bit */ |
154 | ctxt->filter_batch_end |
155 | = xb_page_bitmap_range_get_next_bit(ctxt->bitmap_range, |
156 | FALSE); |
157 | xb_a(next_page_id < ctxt->filter_batch_end); |
158 | } |
159 | |
160 | *read_batch_start = ctxt->offset; |
161 | if (ctxt->filter_batch_end == ULINT_UNDEFINED) { |
162 | /* No more cleared bits in the bitmap, need to copy all the |
163 | remaining pages. */ |
164 | *read_batch_len = ctxt->data_file_size - ctxt->offset; |
165 | } else { |
166 | *read_batch_len = ctxt->filter_batch_end * page_size |
167 | - ctxt->offset; |
168 | } |
169 | |
170 | /* If the page block is larger than the buffer capacity, limit it to |
171 | buffer capacity. The subsequent invocations will continue returning |
172 | the current block in buffer-sized pieces until ctxt->filter_batch_end |
173 | is reached, trigerring the next bitmap query. */ |
174 | if (*read_batch_len > (ib_int64_t)ctxt->buffer_capacity) { |
175 | *read_batch_len = ctxt->buffer_capacity; |
176 | } |
177 | |
178 | ctxt->offset += *read_batch_len; |
179 | xb_a (ctxt->offset % page_size == 0); |
180 | xb_a (*read_batch_start % page_size == 0); |
181 | xb_a (*read_batch_len % page_size == 0); |
182 | } |
183 | |
184 | /****************************************************************//** |
185 | Deinitialize the changed page bitmap-based read filter. */ |
186 | static |
187 | void |
188 | rf_bitmap_deinit( |
189 | /*=============*/ |
190 | xb_read_filt_ctxt_t* ctxt) /*!<in/out: read filter context */ |
191 | { |
192 | xb_page_bitmap_range_deinit(ctxt->bitmap_range); |
193 | } |
194 | |
195 | /* The pass-through read filter */ |
196 | xb_read_filt_t rf_pass_through = { |
197 | &rf_pass_through_init, |
198 | &rf_pass_through_get_next_batch, |
199 | &rf_pass_through_deinit |
200 | }; |
201 | |
202 | /* The changed page bitmap-based read filter */ |
203 | xb_read_filt_t rf_bitmap = { |
204 | &rf_bitmap_init, |
205 | &rf_bitmap_get_next_batch, |
206 | &rf_bitmap_deinit |
207 | }; |
208 | |