Skip to content

Commit 0c6be59

Browse files
committed
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
1 parent baf7c93 commit 0c6be59

File tree

2 files changed

+57
-25
lines changed

2 files changed

+57
-25
lines changed

src/common/file_utils.c

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,52 @@ get_dirent_type(const char *path,
581581
return result;
582582
}
583583

584+
/*
585+
* Compute what remains to be done after a possibly partial vectored read or
586+
* write. The part of 'source' beginning after 'transferred' bytes is copied
587+
* to 'destination', and its length is returned. 'source' and 'destination'
588+
* may point to the same array, for in-place adjustment. A return value of
589+
* zero indicates completion (for callers without a cheaper way to know that).
590+
*/
591+
int
592+
compute_remaining_iovec(struct iovec *destination,
593+
const struct iovec *source,
594+
int iovcnt,
595+
size_t transferred)
596+
{
597+
Assert(iovcnt > 0);
598+
599+
/* Skip wholly transferred iovecs. */
600+
while (source->iov_len <= transferred)
601+
{
602+
transferred -= source->iov_len;
603+
source++;
604+
iovcnt--;
605+
606+
/* All iovecs transferred? */
607+
if (iovcnt == 0)
608+
{
609+
/*
610+
* We don't expect the kernel to transfer more than we asked it
611+
* to, or something is out of sync.
612+
*/
613+
Assert(transferred == 0);
614+
return 0;
615+
}
616+
}
617+
618+
/* Copy the remaining iovecs to the front of the array. */
619+
if (source != destination)
620+
memmove(destination, source, sizeof(*source) * iovcnt);
621+
622+
/* Adjust leading iovec, which may have been partially transferred. */
623+
Assert(destination->iov_len > transferred);
624+
destination->iov_base = (char *) destination->iov_base + transferred;
625+
destination->iov_len -= transferred;
626+
627+
return iovcnt;
628+
}
629+
584630
/*
585631
* pg_pwritev_with_retry
586632
*
@@ -601,7 +647,7 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
601647
return -1;
602648
}
603649

604-
for (;;)
650+
do
605651
{
606652
/* Write as much as we can. */
607653
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)
616662
sum += part;
617663
offset += part;
618664

619-
/* Step over iovecs that are done. */
620-
while (iovcnt > 0 && iov->iov_len <= part)
621-
{
622-
part -= iov->iov_len;
623-
++iov;
624-
--iovcnt;
625-
}
626-
627-
/* Are they all done? */
628-
if (iovcnt == 0)
629-
{
630-
/* We don't expect the kernel to write more than requested. */
631-
Assert(part == 0);
632-
break;
633-
}
634-
635665
/*
636-
* Move whatever's left to the front of our mutable copy and adjust
637-
* the leading iovec.
666+
* See what is left. On the first loop we used the caller's array,
667+
* but in later loops we'll use our local copy that we are allowed to
668+
* mutate.
638669
*/
639-
Assert(iovcnt > 0);
640-
memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
641-
Assert(iov->iov_len > part);
642-
iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
643-
iov_copy[0].iov_len -= part;
670+
iovcnt = compute_remaining_iovec(iov_copy, iov, iovcnt, part);
644671
iov = iov_copy;
645-
}
672+
} while (iovcnt > 0);
646673

647674
return sum;
648675
}

src/include/common/file_utils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ extern PGFileType get_dirent_type(const char *path,
4646
bool look_through_symlinks,
4747
int elevel);
4848

49+
extern int compute_remaining_iovec(struct iovec *destination,
50+
const struct iovec *source,
51+
int iovcnt,
52+
size_t transferred);
53+
4954
extern ssize_t pg_pwritev_with_retry(int fd,
5055
const struct iovec *iov,
5156
int iovcnt,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy