@@ -81,6 +81,8 @@ static int compareWalFileNames(const ListCell *a, const ListCell *b);
81
81
static void throttle (size_t increment );
82
82
static void update_basebackup_progress (int64 delta );
83
83
static bool is_checksummed_file (const char * fullpath , const char * filename );
84
+ static int basebackup_read_file (int fd , char * buf , size_t nbytes , off_t offset ,
85
+ const char * filename , bool partial_read_ok );
84
86
85
87
/* Was the backup currently in-progress initiated in recovery mode? */
86
88
static bool backup_started_in_recovery = false;
@@ -98,18 +100,6 @@ static char *statrelpath = NULL;
98
100
*/
99
101
#define THROTTLING_FREQUENCY 8
100
102
101
- /*
102
- * Checks whether we encountered any error in fread(). fread() doesn't give
103
- * any clue what has happened, so we check with ferror(). Also, neither
104
- * fread() nor ferror() set errno, so we just throw a generic error.
105
- */
106
- #define CHECK_FREAD_ERROR (fp , filename ) \
107
- do { \
108
- if (ferror(fp)) \
109
- ereport(ERROR, \
110
- (errmsg("could not read from file \"%s\"", filename))); \
111
- } while (0)
112
-
113
103
/* The actual number of bytes, transfer of which may cause sleep. */
114
104
static uint64 throttling_sample ;
115
105
@@ -600,16 +590,16 @@ perform_base_backup(basebackup_options *opt)
600
590
foreach (lc , walFileList )
601
591
{
602
592
char * walFileName = (char * ) lfirst (lc );
603
- FILE * fp ;
593
+ int fd ;
604
594
char buf [TAR_SEND_SIZE ];
605
595
size_t cnt ;
606
596
pgoff_t len = 0 ;
607
597
608
598
snprintf (pathbuf , MAXPGPATH , XLOGDIR "/%s" , walFileName );
609
599
XLogFromFileName (walFileName , & tli , & segno , wal_segment_size );
610
600
611
- fp = AllocateFile (pathbuf , "rb" );
612
- if (fp == NULL )
601
+ fd = OpenTransientFile (pathbuf , O_RDONLY | PG_BINARY );
602
+ if (fd < 0 )
613
603
{
614
604
int save_errno = errno ;
615
605
@@ -626,7 +616,7 @@ perform_base_backup(basebackup_options *opt)
626
616
errmsg ("could not open file \"%s\": %m" , pathbuf )));
627
617
}
628
618
629
- if (fstat (fileno ( fp ) , & statbuf ) != 0 )
619
+ if (fstat (fd , & statbuf ) != 0 )
630
620
ereport (ERROR ,
631
621
(errcode_for_file_access (),
632
622
errmsg ("could not stat file \"%s\": %m" ,
@@ -642,9 +632,10 @@ perform_base_backup(basebackup_options *opt)
642
632
/* send the WAL file itself */
643
633
_tarWriteHeader (pathbuf , NULL , & statbuf , false);
644
634
645
- while ((cnt = fread (buf , 1 ,
646
- Min (sizeof (buf ), wal_segment_size - len ),
647
- fp )) > 0 )
635
+ while ((cnt = basebackup_read_file (fd , buf ,
636
+ Min (sizeof (buf ),
637
+ wal_segment_size - len ),
638
+ len , pathbuf , true)) > 0 )
648
639
{
649
640
CheckXLogRemoved (segno , tli );
650
641
/* Send the chunk as a CopyData message */
@@ -660,8 +651,6 @@ perform_base_backup(basebackup_options *opt)
660
651
break ;
661
652
}
662
653
663
- CHECK_FREAD_ERROR (fp , pathbuf );
664
-
665
654
if (len != wal_segment_size )
666
655
{
667
656
CheckXLogRemoved (segno , tli );
@@ -676,7 +665,7 @@ perform_base_backup(basebackup_options *opt)
676
665
*/
677
666
Assert (wal_segment_size % TAR_BLOCK_SIZE == 0 );
678
667
679
- FreeFile ( fp );
668
+ CloseTransientFile ( fd );
680
669
681
670
/*
682
671
* Mark file as archived, otherwise files can get archived again
@@ -1575,7 +1564,7 @@ sendFile(const char *readfilename, const char *tarfilename,
1575
1564
struct stat * statbuf , bool missing_ok , Oid dboid ,
1576
1565
backup_manifest_info * manifest , const char * spcoid )
1577
1566
{
1578
- FILE * fp ;
1567
+ int fd ;
1579
1568
BlockNumber blkno = 0 ;
1580
1569
bool block_retry = false;
1581
1570
char buf [TAR_SEND_SIZE ];
@@ -1594,8 +1583,8 @@ sendFile(const char *readfilename, const char *tarfilename,
1594
1583
1595
1584
pg_checksum_init (& checksum_ctx , manifest -> checksum_type );
1596
1585
1597
- fp = AllocateFile (readfilename , "rb" );
1598
- if (fp == NULL )
1586
+ fd = OpenTransientFile (readfilename , O_RDONLY | PG_BINARY );
1587
+ if (fd < 0 )
1599
1588
{
1600
1589
if (errno == ENOENT && missing_ok )
1601
1590
return false;
@@ -1637,8 +1626,27 @@ sendFile(const char *readfilename, const char *tarfilename,
1637
1626
}
1638
1627
}
1639
1628
1640
- while ((cnt = fread (buf , 1 , Min (sizeof (buf ), statbuf -> st_size - len ), fp )) > 0 )
1629
+ /*
1630
+ * Loop until we read the amount of data the caller told us to expect. The
1631
+ * file could be longer, if it was extended while we were sending it, but
1632
+ * for a base backup we can ignore such extended data. It will be restored
1633
+ * from WAL.
1634
+ */
1635
+ while (len < statbuf -> st_size )
1641
1636
{
1637
+ /* Try to read some more data. */
1638
+ cnt = basebackup_read_file (fd , buf ,
1639
+ Min (sizeof (buf ), statbuf -> st_size - len ),
1640
+ len , readfilename , true);
1641
+
1642
+ /*
1643
+ * If we hit end-of-file, a concurrent truncation must have occurred.
1644
+ * That's not an error condition, because WAL replay will fix things
1645
+ * up.
1646
+ */
1647
+ if (cnt == 0 )
1648
+ break ;
1649
+
1642
1650
/*
1643
1651
* The checksums are verified at block level, so we iterate over the
1644
1652
* buffer in chunks of BLCKSZ, after making sure that
@@ -1689,16 +1697,15 @@ sendFile(const char *readfilename, const char *tarfilename,
1689
1697
*/
1690
1698
if (block_retry == false)
1691
1699
{
1692
- /* Reread the failed block */
1693
- if (fseek (fp , - (cnt - BLCKSZ * i ), SEEK_CUR ) == -1 )
1694
- {
1695
- ereport (ERROR ,
1696
- (errcode_for_file_access (),
1697
- errmsg ("could not fseek in file \"%s\": %m" ,
1698
- readfilename )));
1699
- }
1700
+ int reread_cnt ;
1700
1701
1701
- if (fread (buf + BLCKSZ * i , 1 , BLCKSZ , fp ) != BLCKSZ )
1702
+ /* Reread the failed block */
1703
+ reread_cnt =
1704
+ basebackup_read_file (fd , buf + BLCKSZ * i ,
1705
+ BLCKSZ , len + BLCKSZ * i ,
1706
+ readfilename ,
1707
+ false);
1708
+ if (reread_cnt == 0 )
1702
1709
{
1703
1710
/*
1704
1711
* If we hit end-of-file, a concurrent
@@ -1708,24 +1715,8 @@ sendFile(const char *readfilename, const char *tarfilename,
1708
1715
* code that handles that case. (We must fix
1709
1716
* up cnt first, though.)
1710
1717
*/
1711
- if (feof (fp ))
1712
- {
1713
- cnt = BLCKSZ * i ;
1714
- break ;
1715
- }
1716
-
1717
- ereport (ERROR ,
1718
- (errcode_for_file_access (),
1719
- errmsg ("could not reread block %d of file \"%s\": %m" ,
1720
- blkno , readfilename )));
1721
- }
1722
-
1723
- if (fseek (fp , cnt - BLCKSZ * i - BLCKSZ , SEEK_CUR ) == -1 )
1724
- {
1725
- ereport (ERROR ,
1726
- (errcode_for_file_access (),
1727
- errmsg ("could not fseek in file \"%s\": %m" ,
1728
- readfilename )));
1718
+ cnt = BLCKSZ * i ;
1719
+ break ;
1729
1720
}
1730
1721
1731
1722
/* Set flag so we know a retry was attempted */
@@ -1768,20 +1759,8 @@ sendFile(const char *readfilename, const char *tarfilename,
1768
1759
1769
1760
len += cnt ;
1770
1761
throttle (cnt );
1771
-
1772
- if (feof (fp ) || len >= statbuf -> st_size )
1773
- {
1774
- /*
1775
- * Reached end of file. The file could be longer, if it was
1776
- * extended while we were sending it, but for a base backup we can
1777
- * ignore such extended data. It will be restored from WAL.
1778
- */
1779
- break ;
1780
- }
1781
1762
}
1782
1763
1783
- CHECK_FREAD_ERROR (fp , readfilename );
1784
-
1785
1764
/* If the file was truncated while we were sending it, pad it with zeros */
1786
1765
if (len < statbuf -> st_size )
1787
1766
{
@@ -1810,7 +1789,7 @@ sendFile(const char *readfilename, const char *tarfilename,
1810
1789
update_basebackup_progress (pad );
1811
1790
}
1812
1791
1813
- FreeFile ( fp );
1792
+ CloseTransientFile ( fd );
1814
1793
1815
1794
if (checksum_failures > 1 )
1816
1795
{
@@ -1996,3 +1975,35 @@ update_basebackup_progress(int64 delta)
1996
1975
1997
1976
pgstat_progress_update_multi_param (nparam , index , val );
1998
1977
}
1978
+
1979
+ /*
1980
+ * Read some data from a file, setting a wait event and reporting any error
1981
+ * encountered.
1982
+ *
1983
+ * If partial_read_ok is false, also report an error if the number of bytes
1984
+ * read is not equal to the number of bytes requested.
1985
+ *
1986
+ * Returns the number of bytes read.
1987
+ */
1988
+ static int
1989
+ basebackup_read_file (int fd , char * buf , size_t nbytes , off_t offset ,
1990
+ const char * filename , bool partial_read_ok )
1991
+ {
1992
+ int rc ;
1993
+
1994
+ pgstat_report_wait_start (WAIT_EVENT_BASEBACKUP_READ );
1995
+ rc = pg_pread (fd , buf , nbytes , offset );
1996
+ pgstat_report_wait_end ();
1997
+
1998
+ if (rc < 0 )
1999
+ ereport (ERROR ,
2000
+ (errcode_for_file_access (),
2001
+ errmsg ("could not read file \"%s\": %m" , filename )));
2002
+ if (!partial_read_ok && rc > 0 && rc != nbytes )
2003
+ ereport (ERROR ,
2004
+ (errcode_for_file_access (),
2005
+ errmsg ("could not read file \"%s\": read %d of %zu" ,
2006
+ filename , rc , nbytes )));
2007
+
2008
+ return rc ;
2009
+ }
0 commit comments