improvement: use dynamically allocated buffers for stdio buffering

This commit is contained in:
Grigory Smolkin
2020-04-23 22:56:56 +03:00
parent 54f63319be
commit a9aab29a04
5 changed files with 177 additions and 78 deletions
+3
View File
@@ -1556,6 +1556,9 @@ get_wal_file_internal(const char *from_path, const char *to_path, FILE *out,
} }
goto cleanup; goto cleanup;
} }
/* disable stdio buffering */
setvbuf(out, NULL, _IONBF, BUFSIZ);
} }
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
else else
+122 -49
View File
@@ -566,8 +566,8 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
datapagemap_iterator_t *iter = NULL; datapagemap_iterator_t *iter = NULL;
/* stdio buffers */ /* stdio buffers */
char in_buffer[STDIO_BUFSIZE]; char *in_buf = NULL;
char out_buffer[STDIO_BUFSIZE]; char *out_buf = NULL;
/* sanity */ /* sanity */
if (file->size % BLCKSZ != 0) if (file->size % BLCKSZ != 0)
@@ -634,17 +634,12 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
from_fullpath, strerror(errno)); from_fullpath, strerror(errno));
} }
if (!fio_is_remote_file(in))
setvbuf(in, in_buffer, _IOFBF, STDIO_BUFSIZE);
/* open backup file for write */ /* open backup file for write */
out = fopen(to_fullpath, PG_BINARY_W); out = fopen(to_fullpath, PG_BINARY_W);
if (out == NULL) if (out == NULL)
elog(ERROR, "Cannot open backup file \"%s\": %s", elog(ERROR, "Cannot open backup file \"%s\": %s",
to_fullpath, strerror(errno)); to_fullpath, strerror(errno));
setvbuf(out, out_buffer, _IOFBF, STDIO_BUFSIZE);
/* update file permission */ /* update file permission */
if (chmod(to_fullpath, FILE_PERMISSION) == -1) if (chmod(to_fullpath, FILE_PERMISSION) == -1)
elog(ERROR, "Cannot change mode of \"%s\": %s", to_fullpath, elog(ERROR, "Cannot change mode of \"%s\": %s", to_fullpath,
@@ -667,6 +662,24 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
else else
use_pagemap = true; use_pagemap = true;
if (!fio_is_remote_file(in))
{
/* enable stdio buffering for local input file,
* unless the pagemap is involved, which
* imply a lot of random access.
*/
if (use_pagemap)
setvbuf(in, NULL, _IONBF, BUFSIZ);
else
{
in_buf = pgut_malloc(STDIO_BUFSIZE);
setvbuf(in, in_buf, _IOFBF, STDIO_BUFSIZE);
}
}
/* enable stdio buffering for output file */
out_buf = pgut_malloc(STDIO_BUFSIZE);
setvbuf(out, out_buf, _IOFBF, STDIO_BUFSIZE);
/* Remote mode */ /* Remote mode */
if (fio_is_remote_file(in)) if (fio_is_remote_file(in))
@@ -789,6 +802,9 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
elog(ERROR, "Cannot remove file \"%s\": %s", to_fullpath, elog(ERROR, "Cannot remove file \"%s\": %s", to_fullpath,
strerror(errno)); strerror(errno));
} }
pg_free(in_buf);
pg_free(out_buf);
} }
/* /*
@@ -837,18 +853,18 @@ backup_non_data_file(pgFile *file, pgFile *prev_file,
size_t size_t
restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char *to_fullpath) restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char *to_fullpath)
{ {
int i; int i;
size_t total_write_len = 0; size_t total_write_len = 0;
char buffer[STDIO_BUFSIZE]; char *in_buf;
for (i = parray_num(parent_chain) - 1; i >= 0; i--) for (i = parray_num(parent_chain) - 1; i >= 0; i--)
{ {
char from_root[MAXPGPATH]; char from_root[MAXPGPATH];
char from_fullpath[MAXPGPATH]; char from_fullpath[MAXPGPATH];
FILE *in = NULL; FILE *in = NULL;
pgFile **res_file = NULL; pgFile **res_file = NULL;
pgFile *tmp_file = NULL; pgFile *tmp_file = NULL;
pgBackup *backup = (pgBackup *) parray_get(parent_chain, i); pgBackup *backup = (pgBackup *) parray_get(parent_chain, i);
@@ -886,7 +902,8 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char
elog(ERROR, "Cannot open backup file \"%s\": %s", from_fullpath, elog(ERROR, "Cannot open backup file \"%s\": %s", from_fullpath,
strerror(errno)); strerror(errno));
setvbuf(in, buffer, _IOFBF, STDIO_BUFSIZE); in_buf = pgut_malloc(STDIO_BUFSIZE);
setvbuf(in, in_buf, _IOFBF, STDIO_BUFSIZE);
/* /*
* Restore the file. * Restore the file.
@@ -902,6 +919,8 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out, const char
elog(ERROR, "Cannot close file \"%s\": %s", from_fullpath, elog(ERROR, "Cannot close file \"%s\": %s", from_fullpath,
strerror(errno)); strerror(errno));
} }
pg_free(in_buf);
return total_write_len; return total_write_len;
} }
@@ -912,6 +931,21 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
BackupPageHeader header; BackupPageHeader header;
BlockNumber blknum = 0; BlockNumber blknum = 0;
size_t write_len = 0; size_t write_len = 0;
off_t cur_pos = 0;
/*
* We rely on stdio buffering of input and output.
* For buffering to be efficient, we try to minimize the
* number of lseek syscalls, because it forces buffer flush.
* For that, we track current write position in
* output file and issue fseek only when offset of block to be
* written not equal to current write position, which happens
* a lot when blocks from incremental backup are restored,
* but should never happen in case of blocks from FULL backup.
*/
if (fio_fseek(out, cur_pos) < 0)
elog(ERROR, "Cannot seek block %u of \"%s\": %s",
blknum, to_fullpath, strerror(errno));
for (;;) for (;;)
{ {
@@ -928,23 +962,24 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
/* read BackupPageHeader */ /* read BackupPageHeader */
read_len = fread(&header, 1, sizeof(header), in); read_len = fread(&header, 1, sizeof(header), in);
if (ferror(in))
elog(ERROR, "Cannot read header of block %u of \"%s\": %s",
blknum, from_fullpath, strerror(errno));
if (read_len != sizeof(header)) if (read_len != sizeof(header))
{ {
int errno_tmp = errno;
if (read_len == 0 && feof(in)) if (read_len == 0 && feof(in))
break; /* EOF found */ break; /* EOF found */
else if (read_len != 0 && feof(in))
if (read_len != 0 && feof(in))
elog(ERROR, "Odd size page found at block %u of \"%s\"", elog(ERROR, "Odd size page found at block %u of \"%s\"",
blknum, from_fullpath); blknum, from_fullpath);
else
elog(ERROR, "Cannot read header of block %u of \"%s\": %s",
blknum, from_fullpath, strerror(errno_tmp));
} }
/* Consider empty blockm. wtf empty block ? */ /* Consider empty blockm. wtf empty block ? */
if (header.block == 0 && header.compressed_size == 0) if (header.block == 0 && header.compressed_size == 0)
{ {
elog(VERBOSE, "Skip empty block of \"%s\"", from_fullpath); elog(WARNING, "Skip empty block of \"%s\"", from_fullpath);
continue; continue;
} }
@@ -1019,14 +1054,19 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
is_compressed = true; is_compressed = true;
} }
write_pos = blknum * BLCKSZ;
/* /*
* Seek and write the restored page. * Seek and write the restored page.
* When restoring file from FULL backup, pages are written sequentially,
* so there is no need to issue fseek for every page.
*/ */
if (fio_fseek(out, write_pos) < 0) write_pos = blknum * BLCKSZ;
elog(ERROR, "Cannot seek block %u of \"%s\": %s",
blknum, to_fullpath, strerror(errno)); if (cur_pos != write_pos)
{
if (fio_fseek(out, blknum * BLCKSZ) < 0)
elog(ERROR, "Cannot seek block %u of \"%s\": %s",
blknum, to_fullpath, strerror(errno));
}
/* If page is compressed and restore is in remote mode, send compressed /* If page is compressed and restore is in remote mode, send compressed
* page to the remote side. * page to the remote side.
@@ -1048,6 +1088,7 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
} }
write_len += BLCKSZ; write_len += BLCKSZ;
cur_pos = write_pos + BLCKSZ; /* update current write position */
} }
elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, write_len); elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, write_len);
@@ -1063,8 +1104,8 @@ void
restore_non_data_file_internal(FILE *in, FILE *out, pgFile *file, restore_non_data_file_internal(FILE *in, FILE *out, pgFile *file,
const char *from_fullpath, const char *to_fullpath) const char *from_fullpath, const char *to_fullpath)
{ {
ssize_t read_len = 0; size_t read_len = 0;
char buf[STDIO_BUFSIZE]; /* 64kB buffer */ char *buf = pgut_malloc(STDIO_BUFSIZE); /* 64kB buffer */
/* copy content */ /* copy content */
for (;;) for (;;)
@@ -1075,20 +1116,25 @@ restore_non_data_file_internal(FILE *in, FILE *out, pgFile *file,
if (interrupted || thread_interrupted) if (interrupted || thread_interrupted)
elog(ERROR, "Interrupted during non-data file restore"); elog(ERROR, "Interrupted during non-data file restore");
read_len = fread(buf, 1, sizeof(buf), in); read_len = fread(buf, 1, STDIO_BUFSIZE, in);
if (read_len == 0 && feof(in)) if (ferror(in))
break;
if (read_len < 0)
elog(ERROR, "Cannot read backup file \"%s\": %s", elog(ERROR, "Cannot read backup file \"%s\": %s",
from_fullpath, strerror(errno)); from_fullpath, strerror(errno));
if (fio_fwrite(out, buf, read_len) != read_len) if (read_len > 0)
elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath, {
strerror(errno)); if (fio_fwrite(out, buf, read_len) != read_len)
elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath,
strerror(errno));
}
if (feof(in))
break;
} }
pg_free(buf);
elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, file->write_size); elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, file->write_size);
} }
@@ -1103,7 +1149,6 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
pgFile *tmp_file = NULL; pgFile *tmp_file = NULL;
pgBackup *tmp_backup = NULL; pgBackup *tmp_backup = NULL;
char buffer[STDIO_BUFSIZE];
/* Check if full copy of destination file is available in destination backup */ /* Check if full copy of destination file is available in destination backup */
if (dest_file->write_size > 0) if (dest_file->write_size > 0)
@@ -1176,7 +1221,8 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
elog(ERROR, "Cannot open backup file \"%s\": %s", from_fullpath, elog(ERROR, "Cannot open backup file \"%s\": %s", from_fullpath,
strerror(errno)); strerror(errno));
setvbuf(in, buffer, _IOFBF, STDIO_BUFSIZE); /* disable stdio buffering for non-data files */
setvbuf(in, NULL, _IONBF, BUFSIZ);
/* do actual work */ /* do actual work */
restore_non_data_file_internal(in, out, tmp_file, from_fullpath, to_fullpath); restore_non_data_file_internal(in, out, tmp_file, from_fullpath, to_fullpath);
@@ -1192,6 +1238,7 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
* Copy file to backup. * Copy file to backup.
* We do not apply compression to these files, because * We do not apply compression to these files, because
* it is either small control file or already compressed cfs file. * it is either small control file or already compressed cfs file.
* TODO: optimize remote copying
*/ */
void void
backup_non_data_file_internal(const char *from_fullpath, backup_non_data_file_internal(const char *from_fullpath,
@@ -1199,10 +1246,10 @@ backup_non_data_file_internal(const char *from_fullpath,
const char *to_fullpath, pgFile *file, const char *to_fullpath, pgFile *file,
bool missing_ok) bool missing_ok)
{ {
FILE *in; FILE *in;
FILE *out; FILE *out;
ssize_t read_len = 0; ssize_t read_len = 0;
char buf[STDIO_BUFSIZE]; /* 64kB buffer */ char *buf;
pg_crc32 crc; pg_crc32 crc;
INIT_FILE_CRC32(true, crc); INIT_FILE_CRC32(true, crc);
@@ -1247,18 +1294,26 @@ backup_non_data_file_internal(const char *from_fullpath,
elog(ERROR, "Cannot change mode of \"%s\": %s", to_fullpath, elog(ERROR, "Cannot change mode of \"%s\": %s", to_fullpath,
strerror(errno)); strerror(errno));
/* disable stdio buffering for local input/output files */
if (!fio_is_remote_file(in))
setvbuf(in, NULL, _IONBF, BUFSIZ);
setvbuf(out, NULL, _IONBF, BUFSIZ);
/* allocate 64kB buffer */
buf = pgut_malloc(STDIO_BUFSIZE);
/* copy content and calc CRC */ /* copy content and calc CRC */
for (;;) for (;;)
{ {
read_len = fio_fread(in, buf, sizeof(buf)); read_len = fio_fread(in, buf, STDIO_BUFSIZE);
if (read_len == 0)
break;
if (read_len < 0) if (read_len < 0)
elog(ERROR, "Cannot read from source file \"%s\": %s", elog(ERROR, "Cannot read from source file \"%s\": %s",
from_fullpath, strerror(errno)); from_fullpath, strerror(errno));
if (read_len == 0)
break;
if (fwrite(buf, 1, read_len, out) != read_len) if (fwrite(buf, 1, read_len, out) != read_len)
elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath, elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath,
strerror(errno)); strerror(errno));
@@ -1267,6 +1322,19 @@ backup_non_data_file_internal(const char *from_fullpath,
COMP_FILE_CRC32(true, crc, buf, read_len); COMP_FILE_CRC32(true, crc, buf, read_len);
file->read_size += read_len; file->read_size += read_len;
// if (read_len < STDIO_BUFSIZE)
// {
// if (!fio_is_remote_file(in))
// {
// if (ferror(in))
// elog(ERROR, "Cannot read from source file \"%s\": %s",
// from_fullpath, strerror(errno));
//
// if (feof(in))
// break;
// }
// }
} }
file->write_size = (int64) file->read_size; file->write_size = (int64) file->read_size;
@@ -1280,6 +1348,7 @@ backup_non_data_file_internal(const char *from_fullpath,
if (fclose(out)) if (fclose(out))
elog(ERROR, "Cannot write \"%s\": %s", to_fullpath, strerror(errno)); elog(ERROR, "Cannot write \"%s\": %s", to_fullpath, strerror(errno));
fio_fclose(in); fio_fclose(in);
pg_free(buf);
} }
/* /*
@@ -1478,9 +1547,13 @@ check_file_pages(pgFile *file, XLogRecPtr stop_lsn, uint32 checksum_version,
/* read BackupPageHeader */ /* read BackupPageHeader */
read_len = fread(&header, 1, sizeof(header), in); read_len = fread(&header, 1, sizeof(header), in);
if (ferror(in))
elog(ERROR, "Cannot read header of block %u of \"%s\": %s",
blknum, file->path, strerror(errno));
if (read_len != sizeof(header)) if (read_len != sizeof(header))
{ {
int errno_tmp = errno;
if (read_len == 0 && feof(in)) if (read_len == 0 && feof(in))
break; /* EOF found */ break; /* EOF found */
else if (read_len != 0 && feof(in)) else if (read_len != 0 && feof(in))
@@ -1489,7 +1562,7 @@ check_file_pages(pgFile *file, XLogRecPtr stop_lsn, uint32 checksum_version,
blknum, file->path); blknum, file->path);
else else
elog(WARNING, "Cannot read header of block %u of \"%s\": %s", elog(WARNING, "Cannot read header of block %u of \"%s\": %s",
blknum, file->path, strerror(errno_tmp)); blknum, file->path, strerror(errno));
return false; return false;
} }
+26 -17
View File
@@ -265,7 +265,7 @@ pgFileGetCRC(const char *file_path, bool use_crc32c, bool missing_ok)
{ {
FILE *fp; FILE *fp;
pg_crc32 crc = 0; pg_crc32 crc = 0;
char buf[STDIO_BUFSIZE]; char *buf;
size_t len = 0; size_t len = 0;
INIT_FILE_CRC32(use_crc32c, crc); INIT_FILE_CRC32(use_crc32c, crc);
@@ -287,30 +287,31 @@ pgFileGetCRC(const char *file_path, bool use_crc32c, bool missing_ok)
file_path, strerror(errno)); file_path, strerror(errno));
} }
/* disable stdio buffering */
setvbuf(fp, NULL, _IONBF, BUFSIZ);
buf = pgut_malloc(STDIO_BUFSIZE);
/* calc CRC of file */ /* calc CRC of file */
for (;;) for (;;)
{ {
if (interrupted) if (interrupted)
elog(ERROR, "interrupted during CRC calculation"); elog(ERROR, "interrupted during CRC calculation");
len = fread(&buf, 1, sizeof(buf), fp); len = fread(buf, 1, STDIO_BUFSIZE, fp);
if (len == 0) if (ferror(fp))
{ elog(ERROR, "Cannot read \"%s\": %s", file_path, strerror(errno));
/* we either run into eof or error */
if (feof(fp))
break;
if (ferror(fp))
elog(ERROR, "Cannot read \"%s\": %s", file_path, strerror(errno));
}
/* update CRC */ /* update CRC */
COMP_FILE_CRC32(use_crc32c, crc, buf, len); COMP_FILE_CRC32(use_crc32c, crc, buf, len);
if (feof(fp))
break;
} }
FIN_FILE_CRC32(use_crc32c, crc); FIN_FILE_CRC32(use_crc32c, crc);
fclose(fp); fclose(fp);
pg_free(buf);
return crc; return crc;
} }
@@ -324,11 +325,11 @@ pgFileGetCRC(const char *file_path, bool use_crc32c, bool missing_ok)
pg_crc32 pg_crc32
pgFileGetCRCgz(const char *file_path, bool use_crc32c, bool missing_ok) pgFileGetCRCgz(const char *file_path, bool use_crc32c, bool missing_ok)
{ {
gzFile fp; gzFile fp;
pg_crc32 crc = 0; pg_crc32 crc = 0;
char buf[STDIO_BUFSIZE]; int len = 0;
int len = 0; int err;
int err; char *buf;
INIT_FILE_CRC32(use_crc32c, crc); INIT_FILE_CRC32(use_crc32c, crc);
@@ -349,13 +350,15 @@ pgFileGetCRCgz(const char *file_path, bool use_crc32c, bool missing_ok)
file_path, strerror(errno)); file_path, strerror(errno));
} }
buf = pgut_malloc(STDIO_BUFSIZE);
/* calc CRC of file */ /* calc CRC of file */
for (;;) for (;;)
{ {
if (interrupted) if (interrupted)
elog(ERROR, "interrupted during CRC calculation"); elog(ERROR, "interrupted during CRC calculation");
len = gzread(fp, &buf, sizeof(buf)); len = gzread(fp, buf, STDIO_BUFSIZE);
if (len <= 0) if (len <= 0)
{ {
@@ -377,6 +380,7 @@ pgFileGetCRCgz(const char *file_path, bool use_crc32c, bool missing_ok)
FIN_FILE_CRC32(use_crc32c, crc); FIN_FILE_CRC32(use_crc32c, crc);
gzclose(fp); gzclose(fp);
pg_free(buf);
return crc; return crc;
} }
@@ -1505,11 +1509,16 @@ dir_read_file_list(const char *root, const char *external_prefix,
FILE *fp; FILE *fp;
parray *files; parray *files;
char buf[MAXPGPATH * 2]; char buf[MAXPGPATH * 2];
char stdio_buf[STDIO_BUFSIZE];
fp = fio_open_stream(file_txt, location); fp = fio_open_stream(file_txt, location);
if (fp == NULL) if (fp == NULL)
elog(ERROR, "cannot open \"%s\": %s", file_txt, strerror(errno)); elog(ERROR, "cannot open \"%s\": %s", file_txt, strerror(errno));
/* enable stdio buffering for local file */
if (!fio_is_remote(location))
setvbuf(fp, stdio_buf, _IOFBF, STDIO_BUFSIZE);
files = parray_new(); files = parray_new();
while (fgets(buf, lengthof(buf), fp)) while (fgets(buf, lengthof(buf), fp))
+16 -7
View File
@@ -756,10 +756,10 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
static void * static void *
restore_files(void *arg) restore_files(void *arg)
{ {
int i; int i;
char to_fullpath[MAXPGPATH]; char to_fullpath[MAXPGPATH];
FILE *out = NULL; FILE *out = NULL;
char buffer[STDIO_BUFSIZE]; char *out_buf = pgut_malloc(STDIO_BUFSIZE);
restore_files_arg *arguments = (restore_files_arg *) arg; restore_files_arg *arguments = (restore_files_arg *) arg;
@@ -856,18 +856,25 @@ restore_files(void *arg)
if (dest_file->write_size == 0) if (dest_file->write_size == 0)
goto done; goto done;
if (!fio_is_remote_file(out))
setvbuf(out, buffer, _IOFBF, STDIO_BUFSIZE);
/* Restore destination file */ /* Restore destination file */
if (dest_file->is_datafile && !dest_file->is_cfs) if (dest_file->is_datafile && !dest_file->is_cfs)
{
/* enable stdio buffering for local destination file */
if (!fio_is_remote_file(out))
setvbuf(out, out_buf, _IOFBF, STDIO_BUFSIZE);
/* Destination file is data file */ /* Destination file is data file */
arguments->restored_bytes += restore_data_file(arguments->parent_chain, arguments->restored_bytes += restore_data_file(arguments->parent_chain,
dest_file, out, to_fullpath); dest_file, out, to_fullpath);
}
else else
{
/* disable stdio buffering for local destination file */
if (!fio_is_remote_file(out))
setvbuf(out, NULL, _IONBF, BUFSIZ);
/* Destination file is non-data file */ /* Destination file is non-data file */
arguments->restored_bytes += restore_non_data_file(arguments->parent_chain, arguments->restored_bytes += restore_non_data_file(arguments->parent_chain,
arguments->dest_backup, dest_file, out, to_fullpath); arguments->dest_backup, dest_file, out, to_fullpath);
}
done: done:
/* close file */ /* close file */
@@ -876,6 +883,8 @@ done:
strerror(errno)); strerror(errno));
} }
free(out_buf);
/* ssh connection to longer needed */ /* ssh connection to longer needed */
fio_disconnect(); fio_disconnect();
+10 -5
View File
@@ -1470,6 +1470,7 @@ int fio_send_pages(FILE* in, FILE* out, pgFile *file, XLogRecPtr horizonLsn,
return n_blocks_read; return n_blocks_read;
} }
/* TODO: read file using large buffer */
static void fio_send_pages_impl(int fd, int out, char* buf, bool with_pagemap) static void fio_send_pages_impl(int fd, int out, char* buf, bool with_pagemap)
{ {
BlockNumber blknum = 0; BlockNumber blknum = 0;
@@ -1881,7 +1882,7 @@ static void fio_send_file_impl(int out, char const* path)
FILE *fp; FILE *fp;
fio_header hdr; fio_header hdr;
char *buf = pgut_malloc(CHUNK_SIZE); char *buf = pgut_malloc(CHUNK_SIZE);
ssize_t read_len = 0; size_t read_len = 0;
char *errormsg = NULL; char *errormsg = NULL;
/* open source file for read */ /* open source file for read */
@@ -1917,13 +1918,16 @@ static void fio_send_file_impl(int out, char const* path)
goto cleanup; goto cleanup;
} }
/* disable stdio buffering */
setvbuf(fp, NULL, _IONBF, BUFSIZ);
/* copy content */ /* copy content */
for (;;) for (;;)
{ {
read_len = fread(buf, 1, CHUNK_SIZE, fp); read_len = fread(buf, 1, CHUNK_SIZE, fp);
/* report error */ /* report error */
if (read_len < 0 || (read_len == 0 && !feof(fp))) if (ferror(fp))
{ {
hdr.cop = FIO_ERROR; hdr.cop = FIO_ERROR;
errormsg = pgut_malloc(MAXPGPATH); errormsg = pgut_malloc(MAXPGPATH);
@@ -1938,9 +1942,7 @@ static void fio_send_file_impl(int out, char const* path)
goto cleanup; goto cleanup;
} }
else if (read_len == 0) if (read_len > 0)
break;
else
{ {
/* send chunk */ /* send chunk */
hdr.cop = FIO_PAGE; hdr.cop = FIO_PAGE;
@@ -1948,6 +1950,9 @@ static void fio_send_file_impl(int out, char const* path)
IO_CHECK(fio_write_all(out, &hdr, sizeof(hdr)), sizeof(hdr)); IO_CHECK(fio_write_all(out, &hdr, sizeof(hdr)), sizeof(hdr));
IO_CHECK(fio_write_all(out, buf, read_len), read_len); IO_CHECK(fio_write_all(out, buf, read_len), read_len);
} }
if (feof(fp))
break;
} }
/* we are done, send eof */ /* we are done, send eof */