1 /******************************************************
2 MariaBackup: hot backup tool for InnoDB
3 (c) 2009-2013 Percona LLC and/or its affiliates.
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-1335 USA
20
21 *******************************************************/
22
23 /* Page write filters implementation */
24
25 #include <my_global.h>
26 #include <my_base.h>
27 #include "common.h"
28 #include "write_filt.h"
29 #include "fil_cur.h"
30 #include <os0proc.h>
31
32 /************************************************************************
33 Write-through page write filter. */
34 static my_bool wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
35 xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages);
36 static my_bool wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile);
37
38 xb_write_filt_t wf_write_through = {
39 &wf_wt_init,
40 &wf_wt_process,
41 NULL,
42 NULL
43 };
44
45 /************************************************************************
46 Incremental page write filter. */
47 static my_bool wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
48 xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages);
49 static my_bool wf_incremental_process(xb_write_filt_ctxt_t *ctxt,
50 ds_file_t *dstfile);
51 static my_bool wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt,
52 ds_file_t *dstfile);
53 static void wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt);
54
55 xb_write_filt_t wf_incremental = {
56 &wf_incremental_init,
57 &wf_incremental_process,
58 &wf_incremental_finalize,
59 &wf_incremental_deinit
60 };
61
62 /************************************************************************
63 Initialize incremental page write filter.
64
65 @return TRUE on success, FALSE on error. */
66 static my_bool
wf_incremental_init(xb_write_filt_ctxt_t * ctxt,char * dst_name,xb_fil_cur_t * cursor,CorruptedPages * corrupted_pages)67 wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
68 xb_fil_cur_t *cursor, CorruptedPages *corrupted_pages)
69 {
70 char meta_name[FN_REFLEN];
71 xb_wf_incremental_ctxt_t *cp =
72 &(ctxt->wf_incremental_ctxt);
73
74 ctxt->cursor = cursor;
75
76 /* allocate buffer for incremental backup (4096 pages) */
77 cp->delta_buf_size = (cursor->page_size.physical() / 4)
78 * cursor->page_size.physical();
79 cp->delta_buf = (unsigned char *)os_mem_alloc_large(&cp->delta_buf_size);
80
81 if (!cp->delta_buf) {
82 msg(cursor->thread_n,"Can't allocate %zu bytes",
83 (size_t) cp->delta_buf_size);
84 return (FALSE);
85 }
86
87 /* write delta meta info */
88 snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name,
89 XB_DELTA_INFO_SUFFIX);
90 const xb_delta_info_t info(cursor->page_size, cursor->space_id);
91 if (!xb_write_delta_metadata(meta_name, &info)) {
92 msg(cursor->thread_n,"Error: "
93 "failed to write meta info for %s",
94 cursor->rel_path);
95 return(FALSE);
96 }
97
98 /* change the target file name, since we are only going to write
99 delta pages */
100 strcat(dst_name, ".delta");
101
102 mach_write_to_4(cp->delta_buf, 0x78747261UL); /*"xtra"*/
103
104 cp->npages = 1;
105 cp->corrupted_pages = corrupted_pages;
106
107 return(TRUE);
108 }
109
110 /************************************************************************
111 Run the next batch of pages through incremental page write filter.
112
113 @return TRUE on success, FALSE on error. */
114 static my_bool
wf_incremental_process(xb_write_filt_ctxt_t * ctxt,ds_file_t * dstfile)115 wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
116 {
117 ulint i;
118 xb_fil_cur_t *cursor = ctxt->cursor;
119 byte *page;
120 const ulint page_size
121 = cursor->page_size.physical();
122 xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
123
124 for (i = 0, page = cursor->buf; i < cursor->buf_npages;
125 i++, page += page_size) {
126
127 if ((!cp->corrupted_pages ||
128 !cp->corrupted_pages->contains(cursor->node->space->id,
129 cursor->buf_page_no + i)) &&
130 incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN))
131 continue;
132
133 /* updated page */
134 if (cp->npages == page_size / 4) {
135 /* flush buffer */
136 if (ds_write(dstfile, cp->delta_buf,
137 cp->npages * page_size)) {
138 return(FALSE);
139 }
140
141 /* clear buffer */
142 memset(cp->delta_buf, 0, page_size / 4 * page_size);
143 /*"xtra"*/
144 mach_write_to_4(cp->delta_buf, 0x78747261UL);
145 cp->npages = 1;
146 }
147
148 mach_write_to_4(cp->delta_buf + cp->npages * 4,
149 cursor->buf_page_no + i);
150 memcpy(cp->delta_buf + cp->npages * page_size, page,
151 page_size);
152
153 cp->npages++;
154 }
155
156 return(TRUE);
157 }
158
159 /************************************************************************
160 Flush the incremental page write filter's buffer.
161
162 @return TRUE on success, FALSE on error. */
163 static my_bool
wf_incremental_finalize(xb_write_filt_ctxt_t * ctxt,ds_file_t * dstfile)164 wf_incremental_finalize(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
165 {
166 xb_fil_cur_t *cursor = ctxt->cursor;
167 const ulint page_size
168 = cursor->page_size.physical();
169 xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
170
171 if (cp->npages != page_size / 4) {
172 mach_write_to_4(cp->delta_buf + cp->npages * 4, 0xFFFFFFFFUL);
173 }
174
175 /* Mark the final block */
176 mach_write_to_4(cp->delta_buf, 0x58545241UL); /*"XTRA"*/
177
178 /* flush buffer */
179 if (ds_write(dstfile, cp->delta_buf, cp->npages * page_size)) {
180 return(FALSE);
181 }
182
183 return(TRUE);
184 }
185
186 /************************************************************************
187 Free the incremental page write filter's buffer. */
188 static void
wf_incremental_deinit(xb_write_filt_ctxt_t * ctxt)189 wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt)
190 {
191 xb_wf_incremental_ctxt_t *cp = &(ctxt->wf_incremental_ctxt);
192 os_mem_free_large(cp->delta_buf, cp->delta_buf_size);
193 }
194
195 /************************************************************************
196 Initialize the write-through page write filter.
197
198 @return TRUE on success, FALSE on error. */
199 static my_bool
wf_wt_init(xb_write_filt_ctxt_t * ctxt,char * dst_name,xb_fil_cur_t * cursor,CorruptedPages *)200 wf_wt_init(xb_write_filt_ctxt_t *ctxt, char *dst_name __attribute__((unused)),
201 xb_fil_cur_t *cursor, CorruptedPages *)
202 {
203 ctxt->cursor = cursor;
204
205 return(TRUE);
206 }
207
208 /************************************************************************
209 Write the next batch of pages to the destination datasink.
210
211 @return TRUE on success, FALSE on error. */
212 static my_bool
wf_wt_process(xb_write_filt_ctxt_t * ctxt,ds_file_t * dstfile)213 wf_wt_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
214 {
215 xb_fil_cur_t *cursor = ctxt->cursor;
216
217 if (ds_write(dstfile, cursor->buf, cursor->buf_read)) {
218 return(FALSE);
219 }
220
221 return(TRUE);
222 }
223