Skip to content

Commit fe5a5fb

Browse files
committed
refactoring to read block via SQL for ptrack backups
1 parent 114a575 commit fe5a5fb

File tree

2 files changed

+131
-138
lines changed

2 files changed

+131
-138
lines changed

src/data.c

Lines changed: 128 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -101,26 +101,118 @@ typedef struct BackupPageHeader
101101

102102
/* Verify page's header */
103103
static bool
104-
parse_page(const DataPage *page, XLogRecPtr *lsn)
104+
parse_page(Page page, XLogRecPtr *lsn)
105105
{
106-
const PageHeaderData *page_data = &page->page_data;
106+
PageHeader phdr = (PageHeader) page;
107107

108108
/* Get lsn from page header */
109-
*lsn = PageXLogRecPtrGet(page_data->pd_lsn);
110-
111-
if (PageGetPageSize(page_data) == BLCKSZ &&
112-
PageGetPageLayoutVersion(page_data) == PG_PAGE_LAYOUT_VERSION &&
113-
(page_data->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
114-
page_data->pd_lower >= SizeOfPageHeaderData &&
115-
page_data->pd_lower <= page_data->pd_upper &&
116-
page_data->pd_upper <= page_data->pd_special &&
117-
page_data->pd_special <= BLCKSZ &&
118-
page_data->pd_special == MAXALIGN(page_data->pd_special))
109+
*lsn = PageXLogRecPtrGet(phdr->pd_lsn);
110+
111+
if (PageGetPageSize(phdr) == BLCKSZ &&
112+
PageGetPageLayoutVersion(phdr) == PG_PAGE_LAYOUT_VERSION &&
113+
(phdr->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
114+
phdr->pd_lower >= SizeOfPageHeaderData &&
115+
phdr->pd_lower <= phdr->pd_upper &&
116+
phdr->pd_upper <= phdr->pd_special &&
117+
phdr->pd_special <= BLCKSZ &&
118+
phdr->pd_special == MAXALIGN(phdr->pd_special))
119119
return true;
120120

121121
return false;
122122
}
123123

124+
/* Read one page from file directly accessing disk
125+
* return value:
126+
* 0 - if the page is not found
127+
* 1 - if the page is found and valid
128+
* -1 - if the page is found but invalid
129+
*/
130+
static int
131+
read_page_from_file(pgFile *file, BlockNumber blknum,
132+
FILE *in, FILE *out, Page page)
133+
{
134+
off_t offset = blknum*BLCKSZ;
135+
size_t read_len = 0;
136+
XLogRecPtr page_lsn;
137+
138+
/* read the block */
139+
if (fseek(in, offset, SEEK_SET) != 0)
140+
elog(ERROR, "File: %s, could not seek to block %u: %s",
141+
file->path, blknum, strerror(errno));
142+
143+
read_len = fread(page, 1, BLCKSZ, in);
144+
145+
if (read_len != BLCKSZ)
146+
{
147+
/* The block could have been truncated. It is fine. */
148+
if (read_len == 0)
149+
{
150+
elog(LOG, "File %s, block %u, file was truncated",
151+
file->path, blknum);
152+
return 0;
153+
}
154+
else
155+
elog(WARNING, "File: %s, block %u, expected block size %lu,"
156+
"but read %d, try again",
157+
file->path, blknum, read_len, BLCKSZ);
158+
}
159+
160+
/*
161+
* If we found page with invalid header, at first check if it is zeroed,
162+
* which is a valid state for page. If it is not, read it and check header
163+
* again, because it's possible that we've read a partly flushed page.
164+
* If after several attempts page header is still invalid, throw an error.
165+
* The same idea is applied to checksum verification.
166+
*/
167+
if (!parse_page(page, &page_lsn))
168+
{
169+
int i;
170+
/* Check if the page is zeroed. */
171+
for(i = 0; i < BLCKSZ && page[i] == 0; i++);
172+
173+
/* Page is zeroed. No need to check header and checksum. */
174+
if (i == BLCKSZ)
175+
{
176+
elog(LOG, "File: %s blknum %u, empty page", file->path, blknum);
177+
return 1;
178+
}
179+
180+
/*
181+
* If page is not completely empty and we couldn't parse it,
182+
* try again several times. If it didn't help, throw error
183+
*/
184+
elog(LOG, "File: %s blknum %u have wrong page header, try again",
185+
file->path, blknum);
186+
return -1;
187+
}
188+
189+
/* Verify checksum */
190+
if(current.checksum_version)
191+
{
192+
/*
193+
* If checksum is wrong, sleep a bit and then try again
194+
* several times. If it didn't help, throw error
195+
*/
196+
if (pg_checksum_page(page, file->segno * RELSEG_SIZE + blknum)
197+
!= ((PageHeader) page)->pd_checksum)
198+
{
199+
elog(WARNING, "File: %s blknum %u have wrong checksum, try again",
200+
file->path, blknum);
201+
return -1;
202+
}
203+
else
204+
{
205+
/* page header and checksum are correct */
206+
return 1;
207+
}
208+
}
209+
else
210+
{
211+
/* page header is correct and checksum check is disabled */
212+
return 1;
213+
}
214+
}
215+
124216
/*
125217
* Backup the specified block from a file of a relation.
126218
* Verify page header and checksum of the page and write it
@@ -134,147 +226,44 @@ backup_data_page(pgFile *file, XLogRecPtr prev_backup_start_lsn,
134226
BackupMode backup_mode)
135227
{
136228
BackupPageHeader header;
137-
off_t offset;
138-
DataPage page; /* used as read buffer */
139-
DataPage *page_ptr = &page; /* used as read buffer */
140-
DataPage compressed_page; /* used as read buffer */
229+
Page page = malloc(BLCKSZ);
230+
Page compressed_page = malloc(BLCKSZ);
141231
size_t write_buffer_size;
142-
/* maximum size of write buffer */
143232
char write_buffer[BLCKSZ+sizeof(header)];
144-
size_t read_len = 0;
145-
XLogRecPtr page_lsn;
146-
int try_checksum = 100;
147-
bool page_is_invalid = true;
148-
header.block = blknum;
149-
offset = blknum * BLCKSZ;
150233

234+
int try_again = 100;
235+
bool page_is_valid = false;
236+
151237
/*
152238
* Read the page and verify its header and checksum.
153239
* Under high write load it's possible that we've read partly
154240
* flushed page, so try several times before throwing an error.
155241
*/
156-
while(try_checksum--)
242+
if (backup_mode != BACKUP_MODE_DIFF_PTRACK)
157243
{
158-
if (fseek(in, offset, SEEK_SET) != 0)
159-
elog(ERROR, "File: %s, could not seek to block %u: %s",
160-
file->path, blknum, strerror(errno));
161-
162-
read_len = fread(&page, 1, BLCKSZ, in);
163-
164-
if (read_len != BLCKSZ)
165-
{
166-
if (read_len == 0)
167-
{
168-
elog(LOG, "File %s, block %u, file was truncated",
169-
file->path, blknum);
170-
page_is_invalid = false;
171-
return;
172-
}
173-
else if (try_checksum)
174-
{
175-
elog(LOG, "File: %s, block %u, expected block size %lu, but read %d, try again",
176-
file->path, blknum, read_len, BLCKSZ);
177-
usleep(100);
178-
continue;
179-
}
180-
181-
elog(ERROR, "File: %s, invalid block size of block %u : %lu",
182-
file->path, blknum, read_len);
183-
}
184-
185-
/*
186-
* If we found page with invalid header, at first check if it is zeroed,
187-
* which is valid state for page. If it is not, read it and check header
188-
* again, because it's possible that we've read a partly flushed page.
189-
* If after several attempts page header is still invalid, throw an error.
190-
* The same idea is applied to checksum verification.
191-
*/
192-
if (!parse_page(&page, &page_lsn))
193-
{
194-
int i;
195-
/* Check if the page is zeroed. */
196-
for(i = 0; i < BLCKSZ && page.data[i] == 0; i++);
197-
198-
/* Page is zeroed. No need to check header and checksum. */
199-
if (i == BLCKSZ)
200-
{
201-
elog(LOG, "File: %s blknum %u, empty page", file->path, blknum);
202-
page_is_invalid = false;
203-
break;
204-
}
205-
206-
/*
207-
* If page is not completely empty and we couldn't parse it,
208-
* try again several times. If it didn't help, throw error
209-
*/
210-
211-
/* Try to read and verify this page again several times. */
212-
if (try_checksum)
213-
{
214-
elog(WARNING, "File: %s blknum %u have wrong page header, try again",
215-
file->path, blknum);
216-
usleep(100);
217-
continue;
218-
}
219-
else
220-
elog(ERROR, "File: %s blknum %u have wrong page header.", file->path, blknum);
221-
}
222-
223-
// /* If the page hasn't changed since previous backup, don't backup it. */
224-
// if (!XLogRecPtrIsInvalid(prev_backup_start_lsn)
225-
// && !XLogRecPtrIsInvalid(page_lsn)
226-
// && page_lsn < prev_backup_start_lsn)
227-
// {
228-
// *n_skipped += 1;
229-
// return;
230-
// }
231-
232-
/* Verify checksum */
233-
if(current.checksum_version)
234-
{
235-
/*
236-
* If checksum is wrong, sleep a bit and then try again
237-
* several times. If it didn't help, throw error
238-
*/
239-
if (pg_checksum_page(page.data, file->segno * RELSEG_SIZE + blknum)
240-
!= ((PageHeader) page.data)->pd_checksum)
241-
{
242-
if (try_checksum)
243-
{
244-
elog(WARNING, "File: %s blknum %u have wrong checksum, try again",
245-
file->path, blknum);
246-
usleep(100);
247-
continue;
248-
}
249-
else
250-
elog(ERROR, "File: %s blknum %u have wrong checksum.",
251-
file->path, blknum);
252-
}
253-
else
254-
{
255-
page_is_invalid = false;
256-
break; /* page header and checksum are correct */
257-
}
258-
}
259-
else
244+
while(!page_is_valid && try_again)
260245
{
261-
page_is_invalid = false;
262-
break; /* page header is correct and checksum check is disabled */
246+
try_again--;
247+
page_is_valid = read_page_from_file(file, blknum,
248+
in, out, page);
263249
}
264250
}
265251

266-
267-
if (page_is_invalid ||
252+
if (!page_is_valid ||
268253
(backup_mode == BACKUP_MODE_DIFF_PTRACK))
269254
{
270255
size_t page_size = 0;
271-
page_ptr = pg_ptrack_get_block(file->relOid, blknum, &page_size);
256+
free(page);
257+
page = (Page) pg_ptrack_get_block(file->relOid, blknum, &page_size);
272258
}
273259

274-
file->read_size += read_len;
275260

276-
header.compressed_size = do_compress(compressed_page.data, sizeof(compressed_page.data),
277-
page.data, sizeof(page.data), compress_alg);
261+
262+
file->read_size += BLCKSZ;
263+
264+
header.block = blknum;
265+
header.compressed_size = do_compress(compressed_page, BLCKSZ,
266+
page, BLCKSZ, compress_alg);
278267

279268
file->compress_alg = compress_alg;
280269

@@ -285,15 +274,15 @@ backup_data_page(pgFile *file, XLogRecPtr prev_backup_start_lsn,
285274
if (header.compressed_size > 0)
286275
{
287276
memcpy(write_buffer, &header, sizeof(header));
288-
memcpy(write_buffer + sizeof(header), compressed_page.data, header.compressed_size);
277+
memcpy(write_buffer + sizeof(header), compressed_page, header.compressed_size);
289278
write_buffer_size += MAXALIGN(header.compressed_size);
290279
}
291280
/* The page compression failed. Write it as is. */
292281
else
293282
{
294283
header.compressed_size = BLCKSZ;
295284
memcpy(write_buffer, &header, sizeof(header));
296-
memcpy(write_buffer + sizeof(header), page.data, BLCKSZ);
285+
memcpy(write_buffer + sizeof(header), page, BLCKSZ);
297286
write_buffer_size += header.compressed_size;
298287
}
299288

@@ -311,6 +300,9 @@ backup_data_page(pgFile *file, XLogRecPtr prev_backup_start_lsn,
311300
}
312301

313302
file->write_size += write_buffer_size;
303+
304+
free(page);
305+
free(compressed_page);
314306
}
315307

316308
/*

src/pg_probackup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,11 @@ typedef struct pgRecoveryTarget
237237
/* Union to ease operations on relation pages */
238238
typedef union DataPage
239239
{
240-
PageHeaderData page_data;
241-
char data[BLCKSZ];
240+
PageHeaderData page_data;
241+
char data[BLCKSZ];
242242
} DataPage;
243243

244+
244245
/*
245246
* return pointer that exceeds the length of prefix from character string.
246247
* ex. str="/xxx/yyy/zzz", prefix="/xxx/yyy", return="zzz".

0 commit comments

Comments
 (0)