Skip to content

Commit 4ab8c81

Browse files
committed
Move pg_pwritev_with_retry() to src/common/file_utils.c
This commit moves pg_pwritev_with_retry(), a convenience wrapper of pg_writev() able to handle partial writes, to common/file_utils.c so that the frontend code is able to use it. A first use-case targetted for this routine is pg_basebackup and pg_receivewal, for the zero-padding of a newly-initialized WAL segment. This is used currently in the backend when the GUC wal_init_zero is enabled (default). Author: Bharath Rupireddy Reviewed-by: Nathan Bossart, Thomas Munro Discussion: https://postgr.es/m/CALj2ACUq7nAb7=bJNbK3yYmp-SZhJcXFR_pLk8un6XgDzDF3OA@mail.gmail.com
1 parent 1b9cd69 commit 4ab8c81

File tree

4 files changed

+74
-71
lines changed

4 files changed

+74
-71
lines changed

src/backend/storage/file/fd.c

-65
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
#include "common/pg_prng.h"
9494
#include "miscadmin.h"
9595
#include "pgstat.h"
96-
#include "port/pg_iovec.h"
9796
#include "portability/mem.h"
9897
#include "postmaster/startup.h"
9998
#include "storage/fd.h"
@@ -3738,67 +3737,3 @@ data_sync_elevel(int elevel)
37383737
{
37393738
return data_sync_retry ? elevel : PANIC;
37403739
}
3741-
3742-
/*
3743-
* A convenience wrapper for pg_pwritev() that retries on partial write. If an
3744-
* error is returned, it is unspecified how much has been written.
3745-
*/
3746-
ssize_t
3747-
pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
3748-
{
3749-
struct iovec iov_copy[PG_IOV_MAX];
3750-
ssize_t sum = 0;
3751-
ssize_t part;
3752-
3753-
/* We'd better have space to make a copy, in case we need to retry. */
3754-
if (iovcnt > PG_IOV_MAX)
3755-
{
3756-
errno = EINVAL;
3757-
return -1;
3758-
}
3759-
3760-
for (;;)
3761-
{
3762-
/* Write as much as we can. */
3763-
part = pg_pwritev(fd, iov, iovcnt, offset);
3764-
if (part < 0)
3765-
return -1;
3766-
3767-
#ifdef SIMULATE_SHORT_WRITE
3768-
part = Min(part, 4096);
3769-
#endif
3770-
3771-
/* Count our progress. */
3772-
sum += part;
3773-
offset += part;
3774-
3775-
/* Step over iovecs that are done. */
3776-
while (iovcnt > 0 && iov->iov_len <= part)
3777-
{
3778-
part -= iov->iov_len;
3779-
++iov;
3780-
--iovcnt;
3781-
}
3782-
3783-
/* Are they all done? */
3784-
if (iovcnt == 0)
3785-
{
3786-
/* We don't expect the kernel to write more than requested. */
3787-
Assert(part == 0);
3788-
break;
3789-
}
3790-
3791-
/*
3792-
* Move whatever's left to the front of our mutable copy and adjust
3793-
* the leading iovec.
3794-
*/
3795-
Assert(iovcnt > 0);
3796-
memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
3797-
Assert(iov->iov_len > part);
3798-
iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
3799-
iov_copy[0].iov_len -= part;
3800-
iov = iov_copy;
3801-
}
3802-
3803-
return sum;
3804-
}

src/common/file_utils.c

+67
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#ifdef FRONTEND
2929
#include "common/logging.h"
3030
#endif
31+
#include "port/pg_iovec.h"
3132

3233
#ifdef FRONTEND
3334

@@ -460,3 +461,69 @@ get_dirent_type(const char *path,
460461

461462
return result;
462463
}
464+
465+
/*
466+
* pg_pwritev_with_retry
467+
*
468+
* Convenience wrapper for pg_pwritev() that retries on partial write. If an
469+
* error is returned, it is unspecified how much has been written.
470+
*/
471+
ssize_t
472+
pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
473+
{
474+
struct iovec iov_copy[PG_IOV_MAX];
475+
ssize_t sum = 0;
476+
ssize_t part;
477+
478+
/* We'd better have space to make a copy, in case we need to retry. */
479+
if (iovcnt > PG_IOV_MAX)
480+
{
481+
errno = EINVAL;
482+
return -1;
483+
}
484+
485+
for (;;)
486+
{
487+
/* Write as much as we can. */
488+
part = pg_pwritev(fd, iov, iovcnt, offset);
489+
if (part < 0)
490+
return -1;
491+
492+
#ifdef SIMULATE_SHORT_WRITE
493+
part = Min(part, 4096);
494+
#endif
495+
496+
/* Count our progress. */
497+
sum += part;
498+
offset += part;
499+
500+
/* Step over iovecs that are done. */
501+
while (iovcnt > 0 && iov->iov_len <= part)
502+
{
503+
part -= iov->iov_len;
504+
++iov;
505+
--iovcnt;
506+
}
507+
508+
/* Are they all done? */
509+
if (iovcnt == 0)
510+
{
511+
/* We don't expect the kernel to write more than requested. */
512+
Assert(part == 0);
513+
break;
514+
}
515+
516+
/*
517+
* Move whatever's left to the front of our mutable copy and adjust
518+
* the leading iovec.
519+
*/
520+
Assert(iovcnt > 0);
521+
memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
522+
Assert(iov->iov_len > part);
523+
iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
524+
iov_copy[0].iov_len -= part;
525+
iov = iov_copy;
526+
}
527+
528+
return sum;
529+
}

src/include/common/file_utils.h

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ typedef enum PGFileType
2424
PGFILETYPE_LNK
2525
} PGFileType;
2626

27+
struct iovec; /* avoid including port/pg_iovec.h here */
28+
2729
#ifdef FRONTEND
2830
extern int fsync_fname(const char *fname, bool isdir);
2931
extern void fsync_pgdata(const char *pg_data, int serverVersion);
@@ -37,4 +39,9 @@ extern PGFileType get_dirent_type(const char *path,
3739
bool look_through_symlinks,
3840
int elevel);
3941

42+
extern ssize_t pg_pwritev_with_retry(int fd,
43+
const struct iovec *iov,
44+
int iovcnt,
45+
off_t offset);
46+
4047
#endif /* FILE_UTILS_H */

src/include/storage/fd.h

-6
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ typedef enum RecoveryInitSyncMethod
5151
RECOVERY_INIT_SYNC_METHOD_SYNCFS
5252
} RecoveryInitSyncMethod;
5353

54-
struct iovec; /* avoid including port/pg_iovec.h here */
55-
5654
typedef int File;
5755

5856

@@ -178,10 +176,6 @@ extern int pg_fsync_no_writethrough(int fd);
178176
extern int pg_fsync_writethrough(int fd);
179177
extern int pg_fdatasync(int fd);
180178
extern void pg_flush_data(int fd, off_t offset, off_t nbytes);
181-
extern ssize_t pg_pwritev_with_retry(int fd,
182-
const struct iovec *iov,
183-
int iovcnt,
184-
off_t offset);
185179
extern int pg_truncate(const char *path, off_t length);
186180
extern void fsync_fname(const char *fname, bool isdir);
187181
extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);

0 commit comments

Comments
 (0)