@@ -101,26 +101,118 @@ typedef struct BackupPageHeader
101101
102102/* Verify page's header */
103103static 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/*
0 commit comments