mirror of
https://github.com/postgres/postgres.git
synced 2025-05-05 09:19:17 +03:00
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
This commit is contained in:
parent
1b9cd69c5b
commit
4ab8c81bd9
@ -93,7 +93,6 @@
|
|||||||
#include "common/pg_prng.h"
|
#include "common/pg_prng.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "port/pg_iovec.h"
|
|
||||||
#include "portability/mem.h"
|
#include "portability/mem.h"
|
||||||
#include "postmaster/startup.h"
|
#include "postmaster/startup.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
@ -3738,67 +3737,3 @@ data_sync_elevel(int elevel)
|
|||||||
{
|
{
|
||||||
return data_sync_retry ? elevel : PANIC;
|
return data_sync_retry ? elevel : PANIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* A convenience wrapper for pg_pwritev() that retries on partial write. If an
|
|
||||||
* error is returned, it is unspecified how much has been written.
|
|
||||||
*/
|
|
||||||
ssize_t
|
|
||||||
pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
|
|
||||||
{
|
|
||||||
struct iovec iov_copy[PG_IOV_MAX];
|
|
||||||
ssize_t sum = 0;
|
|
||||||
ssize_t part;
|
|
||||||
|
|
||||||
/* We'd better have space to make a copy, in case we need to retry. */
|
|
||||||
if (iovcnt > PG_IOV_MAX)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
/* Write as much as we can. */
|
|
||||||
part = pg_pwritev(fd, iov, iovcnt, offset);
|
|
||||||
if (part < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef SIMULATE_SHORT_WRITE
|
|
||||||
part = Min(part, 4096);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Count our progress. */
|
|
||||||
sum += part;
|
|
||||||
offset += part;
|
|
||||||
|
|
||||||
/* Step over iovecs that are done. */
|
|
||||||
while (iovcnt > 0 && iov->iov_len <= part)
|
|
||||||
{
|
|
||||||
part -= iov->iov_len;
|
|
||||||
++iov;
|
|
||||||
--iovcnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Are they all done? */
|
|
||||||
if (iovcnt == 0)
|
|
||||||
{
|
|
||||||
/* We don't expect the kernel to write more than requested. */
|
|
||||||
Assert(part == 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Move whatever's left to the front of our mutable copy and adjust
|
|
||||||
* the leading iovec.
|
|
||||||
*/
|
|
||||||
Assert(iovcnt > 0);
|
|
||||||
memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
|
|
||||||
Assert(iov->iov_len > part);
|
|
||||||
iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
|
|
||||||
iov_copy[0].iov_len -= part;
|
|
||||||
iov = iov_copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#ifdef FRONTEND
|
#ifdef FRONTEND
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "port/pg_iovec.h"
|
||||||
|
|
||||||
#ifdef FRONTEND
|
#ifdef FRONTEND
|
||||||
|
|
||||||
@ -460,3 +461,69 @@ get_dirent_type(const char *path,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_pwritev_with_retry
|
||||||
|
*
|
||||||
|
* Convenience wrapper for pg_pwritev() that retries on partial write. If an
|
||||||
|
* error is returned, it is unspecified how much has been written.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
|
||||||
|
{
|
||||||
|
struct iovec iov_copy[PG_IOV_MAX];
|
||||||
|
ssize_t sum = 0;
|
||||||
|
ssize_t part;
|
||||||
|
|
||||||
|
/* We'd better have space to make a copy, in case we need to retry. */
|
||||||
|
if (iovcnt > PG_IOV_MAX)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/* Write as much as we can. */
|
||||||
|
part = pg_pwritev(fd, iov, iovcnt, offset);
|
||||||
|
if (part < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef SIMULATE_SHORT_WRITE
|
||||||
|
part = Min(part, 4096);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Count our progress. */
|
||||||
|
sum += part;
|
||||||
|
offset += part;
|
||||||
|
|
||||||
|
/* Step over iovecs that are done. */
|
||||||
|
while (iovcnt > 0 && iov->iov_len <= part)
|
||||||
|
{
|
||||||
|
part -= iov->iov_len;
|
||||||
|
++iov;
|
||||||
|
--iovcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are they all done? */
|
||||||
|
if (iovcnt == 0)
|
||||||
|
{
|
||||||
|
/* We don't expect the kernel to write more than requested. */
|
||||||
|
Assert(part == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move whatever's left to the front of our mutable copy and adjust
|
||||||
|
* the leading iovec.
|
||||||
|
*/
|
||||||
|
Assert(iovcnt > 0);
|
||||||
|
memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
|
||||||
|
Assert(iov->iov_len > part);
|
||||||
|
iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
|
||||||
|
iov_copy[0].iov_len -= part;
|
||||||
|
iov = iov_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,8 @@ typedef enum PGFileType
|
|||||||
PGFILETYPE_LNK
|
PGFILETYPE_LNK
|
||||||
} PGFileType;
|
} PGFileType;
|
||||||
|
|
||||||
|
struct iovec; /* avoid including port/pg_iovec.h here */
|
||||||
|
|
||||||
#ifdef FRONTEND
|
#ifdef FRONTEND
|
||||||
extern int fsync_fname(const char *fname, bool isdir);
|
extern int fsync_fname(const char *fname, bool isdir);
|
||||||
extern void fsync_pgdata(const char *pg_data, int serverVersion);
|
extern void fsync_pgdata(const char *pg_data, int serverVersion);
|
||||||
@ -37,4 +39,9 @@ extern PGFileType get_dirent_type(const char *path,
|
|||||||
bool look_through_symlinks,
|
bool look_through_symlinks,
|
||||||
int elevel);
|
int elevel);
|
||||||
|
|
||||||
|
extern ssize_t pg_pwritev_with_retry(int fd,
|
||||||
|
const struct iovec *iov,
|
||||||
|
int iovcnt,
|
||||||
|
off_t offset);
|
||||||
|
|
||||||
#endif /* FILE_UTILS_H */
|
#endif /* FILE_UTILS_H */
|
||||||
|
@ -51,8 +51,6 @@ typedef enum RecoveryInitSyncMethod
|
|||||||
RECOVERY_INIT_SYNC_METHOD_SYNCFS
|
RECOVERY_INIT_SYNC_METHOD_SYNCFS
|
||||||
} RecoveryInitSyncMethod;
|
} RecoveryInitSyncMethod;
|
||||||
|
|
||||||
struct iovec; /* avoid including port/pg_iovec.h here */
|
|
||||||
|
|
||||||
typedef int File;
|
typedef int File;
|
||||||
|
|
||||||
|
|
||||||
@ -178,10 +176,6 @@ extern int pg_fsync_no_writethrough(int fd);
|
|||||||
extern int pg_fsync_writethrough(int fd);
|
extern int pg_fsync_writethrough(int fd);
|
||||||
extern int pg_fdatasync(int fd);
|
extern int pg_fdatasync(int fd);
|
||||||
extern void pg_flush_data(int fd, off_t offset, off_t nbytes);
|
extern void pg_flush_data(int fd, off_t offset, off_t nbytes);
|
||||||
extern ssize_t pg_pwritev_with_retry(int fd,
|
|
||||||
const struct iovec *iov,
|
|
||||||
int iovcnt,
|
|
||||||
off_t offset);
|
|
||||||
extern int pg_truncate(const char *path, off_t length);
|
extern int pg_truncate(const char *path, off_t length);
|
||||||
extern void fsync_fname(const char *fname, bool isdir);
|
extern void fsync_fname(const char *fname, bool isdir);
|
||||||
extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
|
extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user