1/******************************************************
2MariaBackup: hot backup tool for InnoDB
3(c) 2009-2013 Percona LLC and/or its affiliates.
4Originally Created 3/3/2009 Yasufumi Kinoshita
5Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
6Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; version 2 of the License.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20
21*******************************************************/
22
23/* Source file cursor implementation */
24
25#include <my_global.h>
26#include <my_base.h>
27#include <fil0fil.h>
28#include <fsp0fsp.h>
29#include <srv0start.h>
30#include <trx0sys.h>
31
32#include "fil_cur.h"
33#include "common.h"
34#include "read_filt.h"
35#include "xtrabackup.h"
36
37/* Size of read buffer in pages (640 pages = 10M for 16K sized pages) */
38#define XB_FIL_CUR_PAGES 640
39
40/***********************************************************************
41Extracts the relative path ("database/table.ibd") of a tablespace from a
42specified possibly absolute path.
43
44For user tablespaces both "./database/table.ibd" and
45"/remote/dir/database/table.ibd" result in "database/table.ibd".
46
47For system tablepsaces (i.e. When is_system is TRUE) both "/remote/dir/ibdata1"
48and "./ibdata1" yield "ibdata1" in the output. */
49const char *
50xb_get_relative_path(
51/*=================*/
52 const char* path, /*!< in: tablespace path (either
53 relative or absolute) */
54 ibool is_system) /*!< in: TRUE for system tablespaces,
55 i.e. when only the filename must be
56 returned. */
57{
58 const char *next;
59 const char *cur;
60 const char *prev;
61
62 prev = NULL;
63 cur = path;
64
65 while ((next = strchr(cur, OS_PATH_SEPARATOR)) != NULL) {
66
67 prev = cur;
68 cur = next + 1;
69 }
70
71 if (is_system) {
72
73 return(cur);
74 } else {
75
76 return((prev == NULL) ? cur : prev);
77 }
78
79}
80
81/**********************************************************************//**
82Closes a file. */
83static
84void
85xb_fil_node_close_file(
86/*===================*/
87 fil_node_t* node) /*!< in: file node */
88{
89 ibool ret;
90
91 mutex_enter(&fil_system.mutex);
92
93 ut_ad(node);
94 ut_a(node->n_pending == 0);
95 ut_a(node->n_pending_flushes == 0);
96 ut_a(!node->being_extended);
97
98 if (!node->is_open()) {
99
100 mutex_exit(&fil_system.mutex);
101
102 return;
103 }
104
105 ret = os_file_close(node->handle);
106 ut_a(ret);
107
108 node->handle = OS_FILE_CLOSED;
109
110 ut_a(fil_system.n_open > 0);
111 fil_system.n_open--;
112 fil_n_file_opened--;
113
114 if (node->space->purpose == FIL_TYPE_TABLESPACE &&
115 fil_is_user_tablespace_id(node->space->id)) {
116
117 ut_a(UT_LIST_GET_LEN(fil_system.LRU) > 0);
118
119 /* The node is in the LRU list, remove it */
120 UT_LIST_REMOVE(fil_system.LRU, node);
121 }
122
123 mutex_exit(&fil_system.mutex);
124}
125
126/************************************************************************
127Open a source file cursor and initialize the associated read filter.
128
129@return XB_FIL_CUR_SUCCESS on success, XB_FIL_CUR_SKIP if the source file must
130be skipped and XB_FIL_CUR_ERROR on error. */
131xb_fil_cur_result_t
132xb_fil_cur_open(
133/*============*/
134 xb_fil_cur_t* cursor, /*!< out: source file cursor */
135 xb_read_filt_t* read_filter, /*!< in/out: the read filter */
136 fil_node_t* node, /*!< in: source tablespace node */
137 uint thread_n) /*!< thread number for diagnostics */
138{
139 bool success;
140
141 /* Initialize these first so xb_fil_cur_close() handles them correctly
142 in case of error */
143 cursor->orig_buf = NULL;
144 cursor->node = NULL;
145
146 cursor->space_id = node->space->id;
147
148 strncpy(cursor->abs_path, node->name, sizeof(cursor->abs_path));
149
150 /* Get the relative path for the destination tablespace name, i.e. the
151 one that can be appended to the backup root directory. Non-system
152 tablespaces may have absolute paths for DATA DIRECTORY.
153 We want to make "local" copies for the backup. */
154 strncpy(cursor->rel_path,
155 xb_get_relative_path(cursor->abs_path, cursor->is_system()),
156 sizeof(cursor->rel_path));
157
158 /* In the backup mode we should already have a tablespace handle created
159 by fil_ibd_load() unless it is a system
160 tablespace. Otherwise we open the file here. */
161 if (cursor->is_system() || srv_operation == SRV_OPERATION_RESTORE_DELTA
162 || xb_close_files) {
163 node->handle = os_file_create_simple_no_error_handling(
164 0, node->name,
165 OS_FILE_OPEN,
166 OS_FILE_READ_ALLOW_DELETE, true, &success);
167 if (!success) {
168 /* The following call prints an error message */
169 os_file_get_last_error(TRUE);
170
171 msg("[%02u] mariabackup: error: cannot open "
172 "tablespace %s\n",
173 thread_n, cursor->abs_path);
174
175 return(XB_FIL_CUR_ERROR);
176 }
177 mutex_enter(&fil_system.mutex);
178
179 fil_system.n_open++;
180 fil_n_file_opened++;
181
182 if (node->space->purpose == FIL_TYPE_TABLESPACE &&
183 fil_is_user_tablespace_id(node->space->id)) {
184
185 /* Put the node to the LRU list */
186 UT_LIST_ADD_FIRST(fil_system.LRU, node);
187 }
188
189 mutex_exit(&fil_system.mutex);
190 }
191
192 ut_ad(node->is_open());
193
194 cursor->node = node;
195 cursor->file = node->handle;
196
197 if (stat(cursor->abs_path, &cursor->statinfo)) {
198 msg("[%02u] mariabackup: error: cannot stat %s\n",
199 thread_n, cursor->abs_path);
200
201 xb_fil_cur_close(cursor);
202
203 return(XB_FIL_CUR_ERROR);
204 }
205
206 if (srv_file_flush_method == SRV_O_DIRECT
207 || srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) {
208
209 os_file_set_nocache(cursor->file, node->name, "OPEN");
210 }
211
212 posix_fadvise(cursor->file, 0, 0, POSIX_FADV_SEQUENTIAL);
213
214 const page_size_t page_size(cursor->node->space->flags);
215 cursor->page_size = page_size;
216
217 /* Allocate read buffer */
218 cursor->buf_size = XB_FIL_CUR_PAGES * page_size.physical();
219 cursor->orig_buf = static_cast<byte *>
220 (malloc(cursor->buf_size + srv_page_size));
221 cursor->buf = static_cast<byte *>
222 (ut_align(cursor->orig_buf, srv_page_size));
223
224 cursor->buf_read = 0;
225 cursor->buf_npages = 0;
226 cursor->buf_offset = 0;
227 cursor->buf_page_no = 0;
228 cursor->thread_n = thread_n;
229
230 cursor->space_size = (ulint)(cursor->statinfo.st_size
231 / page_size.physical());
232
233 cursor->read_filter = read_filter;
234 cursor->read_filter->init(&cursor->read_filter_ctxt, cursor,
235 node->space->id);
236
237 return(XB_FIL_CUR_SUCCESS);
238}
239
240/************************************************************************
241Reads and verifies the next block of pages from the source
242file. Positions the cursor after the last read non-corrupted page.
243
244@return XB_FIL_CUR_SUCCESS if some have been read successfully, XB_FIL_CUR_EOF
245if there are no more pages to read and XB_FIL_CUR_ERROR on error. */
246xb_fil_cur_result_t
247xb_fil_cur_read(
248/*============*/
249 xb_fil_cur_t* cursor) /*!< in/out: source file cursor */
250{
251 ibool success;
252 byte* page;
253 ulint i;
254 ulint npages;
255 ulint retry_count;
256 xb_fil_cur_result_t ret;
257 ib_int64_t offset;
258 ib_int64_t to_read;
259 const ulint page_size = cursor->page_size.physical();
260 xb_ad(!cursor->is_system() || page_size == srv_page_size);
261
262 cursor->read_filter->get_next_batch(&cursor->read_filter_ctxt,
263 &offset, &to_read);
264
265 if (to_read == 0LL) {
266 return(XB_FIL_CUR_EOF);
267 }
268
269 if (to_read > (ib_int64_t) cursor->buf_size) {
270 to_read = (ib_int64_t) cursor->buf_size;
271 }
272
273 xb_a(to_read > 0 && to_read <= 0xFFFFFFFFLL);
274
275 if ((to_read & ~(page_size - 1))
276 && offset + to_read == cursor->statinfo.st_size) {
277
278 if (to_read < (ib_int64_t) page_size) {
279 msg("[%02u] mariabackup: Warning: junk at the end of "
280 "%s:\n", cursor->thread_n, cursor->abs_path);
281 msg("[%02u] mariabackup: Warning: offset = %llu, "
282 "to_read = %llu\n",
283 cursor->thread_n,
284 (unsigned long long) offset,
285 (unsigned long long) to_read);
286
287 return(XB_FIL_CUR_EOF);
288 }
289
290 to_read = (ib_int64_t) (((ulint) to_read) &
291 ~(page_size - 1));
292 }
293
294 xb_a((to_read & (page_size - 1)) == 0);
295
296 npages = (ulint) (to_read / cursor->page_size.physical());
297
298 retry_count = 10;
299 ret = XB_FIL_CUR_SUCCESS;
300
301read_retry:
302 xtrabackup_io_throttling();
303
304 cursor->buf_read = 0;
305 cursor->buf_npages = 0;
306 cursor->buf_offset = offset;
307 cursor->buf_page_no = (ulint)(offset / cursor->page_size.physical());
308
309 fil_space_t* space = fil_space_get(cursor->space_id);
310
311 if (!space) {
312 return(XB_FIL_CUR_ERROR);
313 }
314
315 success = os_file_read(IORequestRead,
316 cursor->file, cursor->buf, offset,
317 (ulint) to_read);
318 if (!success) {
319 return(XB_FIL_CUR_ERROR);
320 }
321
322 /* check pages for corruption and re-read if necessary. i.e. in case of
323 partially written pages */
324 for (page = cursor->buf, i = 0; i < npages;
325 page += page_size, i++) {
326 ulint page_no = cursor->buf_page_no + i;
327
328 if (cursor->space_id == TRX_SYS_SPACE &&
329 page_no >= FSP_EXTENT_SIZE &&
330 page_no < FSP_EXTENT_SIZE * 3) {
331 /* We ignore the doublewrite buffer pages */
332 } else if (!fil_space_verify_crypt_checksum(
333 page, cursor->page_size, space->id, page_no)
334 && buf_page_is_corrupted(true, page,
335 cursor->page_size,
336 space)) {
337 retry_count--;
338 if (retry_count == 0) {
339 msg("[%02u] mariabackup: "
340 "Error: failed to read page after "
341 "10 retries. File %s seems to be "
342 "corrupted.\n", cursor->thread_n,
343 cursor->abs_path);
344 ret = XB_FIL_CUR_ERROR;
345 break;
346 }
347
348 if (retry_count == 9) {
349 msg("[%02u] mariabackup: "
350 "Database page corruption detected at page "
351 ULINTPF ", retrying...\n",
352 cursor->thread_n, page_no);
353 }
354
355 os_thread_sleep(100000);
356
357 goto read_retry;
358 }
359 cursor->buf_read += page_size;
360 cursor->buf_npages++;
361 }
362
363 posix_fadvise(cursor->file, offset, to_read, POSIX_FADV_DONTNEED);
364
365 return(ret);
366}
367
368/************************************************************************
369Close the source file cursor opened with xb_fil_cur_open() and its
370associated read filter. */
371void
372xb_fil_cur_close(
373/*=============*/
374 xb_fil_cur_t *cursor) /*!< in/out: source file cursor */
375{
376 cursor->read_filter->deinit(&cursor->read_filter_ctxt);
377
378 free(cursor->orig_buf);
379
380 if (cursor->node != NULL) {
381 xb_fil_node_close_file(cursor->node);
382 cursor->file = OS_FILE_CLOSED;
383 }
384}
385