mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-01 09:01:17 +02:00
Provide helper for retrying partial vectored I/O.
compute_remaining_iovec() is a re-usable routine for retrying after pg_readv() or pg_writev() reports a short transfer. This will gain new users in a later commit, but can already replace the open-coded equivalent code in the existing pg_pwritev_with_retry() function. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://postgr.es/m/CA+hUKGJkOiOCa+mag4BF+zHo7qo=o9CFheB8=g6uT5TUm2gkvA@mail.gmail.com
This commit is contained in:
parent
baf7c93ed5
commit
0c6be59f5e
@ -581,6 +581,52 @@ get_dirent_type(const char *path,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute what remains to be done after a possibly partial vectored read or
|
||||||
|
* write. The part of 'source' beginning after 'transferred' bytes is copied
|
||||||
|
* to 'destination', and its length is returned. 'source' and 'destination'
|
||||||
|
* may point to the same array, for in-place adjustment. A return value of
|
||||||
|
* zero indicates completion (for callers without a cheaper way to know that).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
compute_remaining_iovec(struct iovec *destination,
|
||||||
|
const struct iovec *source,
|
||||||
|
int iovcnt,
|
||||||
|
size_t transferred)
|
||||||
|
{
|
||||||
|
Assert(iovcnt > 0);
|
||||||
|
|
||||||
|
/* Skip wholly transferred iovecs. */
|
||||||
|
while (source->iov_len <= transferred)
|
||||||
|
{
|
||||||
|
transferred -= source->iov_len;
|
||||||
|
source++;
|
||||||
|
iovcnt--;
|
||||||
|
|
||||||
|
/* All iovecs transferred? */
|
||||||
|
if (iovcnt == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We don't expect the kernel to transfer more than we asked it
|
||||||
|
* to, or something is out of sync.
|
||||||
|
*/
|
||||||
|
Assert(transferred == 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the remaining iovecs to the front of the array. */
|
||||||
|
if (source != destination)
|
||||||
|
memmove(destination, source, sizeof(*source) * iovcnt);
|
||||||
|
|
||||||
|
/* Adjust leading iovec, which may have been partially transferred. */
|
||||||
|
Assert(destination->iov_len > transferred);
|
||||||
|
destination->iov_base = (char *) destination->iov_base + transferred;
|
||||||
|
destination->iov_len -= transferred;
|
||||||
|
|
||||||
|
return iovcnt;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pg_pwritev_with_retry
|
* pg_pwritev_with_retry
|
||||||
*
|
*
|
||||||
@ -601,7 +647,7 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
do
|
||||||
{
|
{
|
||||||
/* Write as much as we can. */
|
/* Write as much as we can. */
|
||||||
part = pg_pwritev(fd, iov, iovcnt, offset);
|
part = pg_pwritev(fd, iov, iovcnt, offset);
|
||||||
@ -616,33 +662,14 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
|
|||||||
sum += part;
|
sum += part;
|
||||||
offset += 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
|
* See what is left. On the first loop we used the caller's array,
|
||||||
* the leading iovec.
|
* but in later loops we'll use our local copy that we are allowed to
|
||||||
|
* mutate.
|
||||||
*/
|
*/
|
||||||
Assert(iovcnt > 0);
|
iovcnt = compute_remaining_iovec(iov_copy, iov, iovcnt, part);
|
||||||
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;
|
iov = iov_copy;
|
||||||
}
|
} while (iovcnt > 0);
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,11 @@ extern PGFileType get_dirent_type(const char *path,
|
|||||||
bool look_through_symlinks,
|
bool look_through_symlinks,
|
||||||
int elevel);
|
int elevel);
|
||||||
|
|
||||||
|
extern int compute_remaining_iovec(struct iovec *destination,
|
||||||
|
const struct iovec *source,
|
||||||
|
int iovcnt,
|
||||||
|
size_t transferred);
|
||||||
|
|
||||||
extern ssize_t pg_pwritev_with_retry(int fd,
|
extern ssize_t pg_pwritev_with_retry(int fd,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
int iovcnt,
|
int iovcnt,
|
||||||
|
Loading…
Reference in New Issue
Block a user