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