Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+52-25
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

+5
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)