Add BufFileRead variants with short read and EOF detection
Most callers of BufFileRead() want to check whether they read the full specified length. Checking this at every call site is very tedious. This patch provides additional variants BufFileReadExact() and BufFileReadMaybeEOF() that include the length checks. I considered changing BufFileRead() itself, but this function is also used in extensions, and so changing the behavior like this would create a lot of problems there. The new names are analogous to the existing LogicalTapeReadExact(). Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/f3501945-c591-8cc3-5ef0-b72a2e0eaa9c@enterprisedb.com
This commit is contained in:
parent
1561612e3b
commit
20428d344a
@ -753,14 +753,9 @@ gistRelocateBuildBuffersOnSplit(GISTBuildBuffers *gfbb, GISTSTATE *giststate,
|
||||
static void
|
||||
ReadTempFileBlock(BufFile *file, long blknum, void *ptr)
|
||||
{
|
||||
size_t nread;
|
||||
|
||||
if (BufFileSeekBlock(file, blknum) != 0)
|
||||
elog(ERROR, "could not seek to block %ld in temporary file", blknum);
|
||||
nread = BufFileRead(file, ptr, BLCKSZ);
|
||||
if (nread != BLCKSZ)
|
||||
elog(ERROR, "could not read temporary file: read only %zu of %zu bytes",
|
||||
nread, (size_t) BLCKSZ);
|
||||
BufFileReadExact(file, ptr, BLCKSZ);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -362,17 +362,10 @@ SendBackupManifest(backup_manifest_info *manifest, bbsink *sink)
|
||||
while (manifest_bytes_done < manifest->manifest_size)
|
||||
{
|
||||
size_t bytes_to_read;
|
||||
size_t rc;
|
||||
|
||||
bytes_to_read = Min(sink->bbs_buffer_length,
|
||||
manifest->manifest_size - manifest_bytes_done);
|
||||
rc = BufFileRead(manifest->buffile, sink->bbs_buffer,
|
||||
bytes_to_read);
|
||||
if (rc != bytes_to_read)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from temporary file: read only %zu of %zu bytes",
|
||||
rc, bytes_to_read)));
|
||||
BufFileReadExact(manifest->buffile, sink->bbs_buffer, bytes_to_read);
|
||||
bbsink_manifest_contents(sink, bytes_to_read);
|
||||
manifest_bytes_done += bytes_to_read;
|
||||
}
|
||||
|
@ -1260,28 +1260,18 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||
* we can read them both in one BufFileRead() call without any type
|
||||
* cheating.
|
||||
*/
|
||||
nread = BufFileRead(file, header, sizeof(header));
|
||||
nread = BufFileReadMaybeEOF(file, header, sizeof(header), true);
|
||||
if (nread == 0) /* end of file */
|
||||
{
|
||||
ExecClearTuple(tupleSlot);
|
||||
return NULL;
|
||||
}
|
||||
if (nread != sizeof(header))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from hash-join temporary file: read only %zu of %zu bytes",
|
||||
nread, sizeof(header))));
|
||||
*hashvalue = header[0];
|
||||
tuple = (MinimalTuple) palloc(header[1]);
|
||||
tuple->t_len = header[1];
|
||||
nread = BufFileRead(file,
|
||||
((char *) tuple + sizeof(uint32)),
|
||||
header[1] - sizeof(uint32));
|
||||
if (nread != header[1] - sizeof(uint32))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from hash-join temporary file: read only %zu of %zu bytes",
|
||||
nread, header[1] - sizeof(uint32))));
|
||||
BufFileReadExact(file,
|
||||
(char *) tuple + sizeof(uint32),
|
||||
header[1] - sizeof(uint32));
|
||||
ExecForceStoreMinimalTuple(tuple, tupleSlot, true);
|
||||
return tupleSlot;
|
||||
}
|
||||
|
@ -2069,19 +2069,13 @@ apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/* read length of the on-disk record */
|
||||
nbytes = BufFileRead(stream_fd, &len, sizeof(len));
|
||||
nbytes = BufFileReadMaybeEOF(stream_fd, &len, sizeof(len), true);
|
||||
|
||||
/* have we reached end of the file? */
|
||||
if (nbytes == 0)
|
||||
break;
|
||||
|
||||
/* do we have a correct length? */
|
||||
if (nbytes != sizeof(len))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from streaming transaction's changes file \"%s\": read only %zu of %zu bytes",
|
||||
path, nbytes, sizeof(len))));
|
||||
|
||||
if (len <= 0)
|
||||
elog(ERROR, "incorrect length %d in streaming transaction's changes file \"%s\"",
|
||||
len, path);
|
||||
@ -2090,12 +2084,7 @@ apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
|
||||
buffer = repalloc(buffer, len);
|
||||
|
||||
/* and finally read the data into the buffer */
|
||||
nbytes = BufFileRead(stream_fd, buffer, len);
|
||||
if (nbytes != len)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from streaming transaction's changes file \"%s\": read only %zu of %zu bytes",
|
||||
path, nbytes, (size_t) len)));
|
||||
BufFileReadExact(stream_fd, buffer, len);
|
||||
|
||||
BufFileTell(stream_fd, &fileno, &offset);
|
||||
|
||||
@ -3993,7 +3982,6 @@ static void
|
||||
subxact_info_read(Oid subid, TransactionId xid)
|
||||
{
|
||||
char path[MAXPGPATH];
|
||||
size_t nread;
|
||||
Size len;
|
||||
BufFile *fd;
|
||||
MemoryContext oldctx;
|
||||
@ -4013,12 +4001,7 @@ subxact_info_read(Oid subid, TransactionId xid)
|
||||
return;
|
||||
|
||||
/* read number of subxact items */
|
||||
nread = BufFileRead(fd, &subxact_data.nsubxacts, sizeof(subxact_data.nsubxacts));
|
||||
if (nread != sizeof(subxact_data.nsubxacts))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from streaming transaction's subxact file \"%s\": read only %zu of %zu bytes",
|
||||
path, nread, sizeof(subxact_data.nsubxacts))));
|
||||
BufFileReadExact(fd, &subxact_data.nsubxacts, sizeof(subxact_data.nsubxacts));
|
||||
|
||||
len = sizeof(SubXactInfo) * subxact_data.nsubxacts;
|
||||
|
||||
@ -4037,14 +4020,7 @@ subxact_info_read(Oid subid, TransactionId xid)
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
nread = BufFileRead(fd, subxact_data.subxacts, len);
|
||||
if (nread != len)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from streaming transaction's subxact file \"%s\": read only %zu of %zu bytes",
|
||||
path, nread, len)));
|
||||
}
|
||||
BufFileReadExact(fd, subxact_data.subxacts, len);
|
||||
|
||||
BufFileClose(fd);
|
||||
}
|
||||
|
@ -573,14 +573,19 @@ BufFileDumpBuffer(BufFile *file)
|
||||
}
|
||||
|
||||
/*
|
||||
* BufFileRead
|
||||
* BufFileRead variants
|
||||
*
|
||||
* Like fread() except we assume 1-byte element size and report I/O errors via
|
||||
* ereport().
|
||||
*
|
||||
* If 'exact' is true, then an error is also raised if the number of bytes
|
||||
* read is not exactly 'size' (no short reads). If 'exact' and 'eofOK' are
|
||||
* true, then reading zero bytes is ok.
|
||||
*/
|
||||
size_t
|
||||
BufFileRead(BufFile *file, void *ptr, size_t size)
|
||||
static size_t
|
||||
BufFileReadCommon(BufFile *file, void *ptr, size_t size, bool exact, bool eofOK)
|
||||
{
|
||||
size_t start_size = size;
|
||||
size_t nread = 0;
|
||||
size_t nthistime;
|
||||
|
||||
@ -612,9 +617,48 @@ BufFileRead(BufFile *file, void *ptr, size_t size)
|
||||
nread += nthistime;
|
||||
}
|
||||
|
||||
if (exact &&
|
||||
(nread != start_size && !(nread == 0 && eofOK)))
|
||||
ereport(ERROR,
|
||||
errcode_for_file_access(),
|
||||
file->name ?
|
||||
errmsg("could not read from file set \"%s\": read only %zu of %zu bytes",
|
||||
file->name, nread, start_size) :
|
||||
errmsg("could not read from temporary file: read only %zu of %zu bytes",
|
||||
nread, start_size));
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy interface where the caller needs to check for end of file or short
|
||||
* reads.
|
||||
*/
|
||||
size_t
|
||||
BufFileRead(BufFile *file, void *ptr, size_t size)
|
||||
{
|
||||
return BufFileReadCommon(file, ptr, size, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Require read of exactly the specified size.
|
||||
*/
|
||||
void
|
||||
BufFileReadExact(BufFile *file, void *ptr, size_t size)
|
||||
{
|
||||
BufFileReadCommon(file, ptr, size, true, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Require read of exactly the specified size, but optionally allow end of
|
||||
* file (in which case 0 is returned).
|
||||
*/
|
||||
size_t
|
||||
BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK)
|
||||
{
|
||||
return BufFileReadCommon(file, ptr, size, true, eofOK);
|
||||
}
|
||||
|
||||
/*
|
||||
* BufFileWrite
|
||||
*
|
||||
|
@ -281,19 +281,12 @@ ltsWriteBlock(LogicalTapeSet *lts, long blocknum, const void *buffer)
|
||||
static void
|
||||
ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
|
||||
{
|
||||
size_t nread;
|
||||
|
||||
if (BufFileSeekBlock(lts->pfile, blocknum) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not seek to block %ld of temporary file",
|
||||
blocknum)));
|
||||
nread = BufFileRead(lts->pfile, buffer, BLCKSZ);
|
||||
if (nread != BLCKSZ)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read block %ld of temporary file: read only %zu of %zu bytes",
|
||||
blocknum, nread, (size_t) BLCKSZ)));
|
||||
BufFileReadExact(lts->pfile, buffer, BLCKSZ);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -422,23 +422,10 @@ sts_read_tuple(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
*/
|
||||
if (accessor->sts->meta_data_size > 0)
|
||||
{
|
||||
if (BufFileRead(accessor->read_file,
|
||||
meta_data,
|
||||
accessor->sts->meta_data_size) !=
|
||||
accessor->sts->meta_data_size)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file"),
|
||||
errdetail_internal("Short read while reading meta-data.")));
|
||||
BufFileReadExact(accessor->read_file, meta_data, accessor->sts->meta_data_size);
|
||||
accessor->read_bytes += accessor->sts->meta_data_size;
|
||||
}
|
||||
if (BufFileRead(accessor->read_file,
|
||||
&size,
|
||||
sizeof(size)) != sizeof(size))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file"),
|
||||
errdetail_internal("Short read while reading size.")));
|
||||
BufFileReadExact(accessor->read_file, &size, sizeof(size));
|
||||
accessor->read_bytes += sizeof(size);
|
||||
if (size > accessor->read_buffer_size)
|
||||
{
|
||||
@ -455,13 +442,7 @@ sts_read_tuple(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
this_chunk_size = Min(remaining_size,
|
||||
BLCKSZ * STS_CHUNK_PAGES - accessor->read_bytes);
|
||||
destination = accessor->read_buffer + sizeof(uint32);
|
||||
if (BufFileRead(accessor->read_file,
|
||||
destination,
|
||||
this_chunk_size) != this_chunk_size)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file"),
|
||||
errdetail_internal("Short read while reading tuple.")));
|
||||
BufFileReadExact(accessor->read_file, destination, this_chunk_size);
|
||||
accessor->read_bytes += this_chunk_size;
|
||||
remaining_size -= this_chunk_size;
|
||||
destination += this_chunk_size;
|
||||
@ -473,12 +454,7 @@ sts_read_tuple(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
/* We are now positioned at the start of an overflow chunk. */
|
||||
SharedTuplestoreChunk chunk_header;
|
||||
|
||||
if (BufFileRead(accessor->read_file, &chunk_header, STS_CHUNK_HEADER_SIZE) !=
|
||||
STS_CHUNK_HEADER_SIZE)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file"),
|
||||
errdetail_internal("Short read while reading overflow chunk header.")));
|
||||
BufFileReadExact(accessor->read_file, &chunk_header, STS_CHUNK_HEADER_SIZE);
|
||||
accessor->read_bytes = STS_CHUNK_HEADER_SIZE;
|
||||
if (chunk_header.overflow == 0)
|
||||
ereport(ERROR,
|
||||
@ -489,13 +465,7 @@ sts_read_tuple(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
this_chunk_size = Min(remaining_size,
|
||||
BLCKSZ * STS_CHUNK_PAGES -
|
||||
STS_CHUNK_HEADER_SIZE);
|
||||
if (BufFileRead(accessor->read_file,
|
||||
destination,
|
||||
this_chunk_size) != this_chunk_size)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file"),
|
||||
errdetail_internal("Short read while reading tuple.")));
|
||||
BufFileReadExact(accessor->read_file, destination, this_chunk_size);
|
||||
accessor->read_bytes += this_chunk_size;
|
||||
remaining_size -= this_chunk_size;
|
||||
destination += this_chunk_size;
|
||||
@ -551,7 +521,6 @@ sts_parallel_scan_next(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
if (!eof)
|
||||
{
|
||||
SharedTuplestoreChunk chunk_header;
|
||||
size_t nread;
|
||||
|
||||
/* Make sure we have the file open. */
|
||||
if (accessor->read_file == NULL)
|
||||
@ -570,13 +539,7 @@ sts_parallel_scan_next(SharedTuplestoreAccessor *accessor, void *meta_data)
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not seek to block %u in shared tuplestore temporary file",
|
||||
read_page)));
|
||||
nread = BufFileRead(accessor->read_file, &chunk_header,
|
||||
STS_CHUNK_HEADER_SIZE);
|
||||
if (nread != STS_CHUNK_HEADER_SIZE)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from shared tuplestore temporary file: read only %zu of %zu bytes",
|
||||
nread, STS_CHUNK_HEADER_SIZE)));
|
||||
BufFileReadExact(accessor->read_file, &chunk_header, STS_CHUNK_HEADER_SIZE);
|
||||
|
||||
/*
|
||||
* If this is an overflow chunk, we skip it and any following
|
||||
|
@ -1468,15 +1468,11 @@ getlen(Tuplestorestate *state, bool eofOK)
|
||||
unsigned int len;
|
||||
size_t nbytes;
|
||||
|
||||
nbytes = BufFileRead(state->myfile, &len, sizeof(len));
|
||||
if (nbytes == sizeof(len))
|
||||
nbytes = BufFileReadMaybeEOF(state->myfile, &len, sizeof(len), eofOK);
|
||||
if (nbytes == 0)
|
||||
return 0;
|
||||
else
|
||||
return len;
|
||||
if (nbytes != 0 || !eofOK)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
|
||||
nbytes, sizeof(len))));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1528,25 +1524,12 @@ readtup_heap(Tuplestorestate *state, unsigned int len)
|
||||
unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
|
||||
MinimalTuple tuple = (MinimalTuple) palloc(tuplen);
|
||||
char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
|
||||
size_t nread;
|
||||
|
||||
USEMEM(state, GetMemoryChunkSpace(tuple));
|
||||
/* read in the tuple proper */
|
||||
tuple->t_len = tuplen;
|
||||
nread = BufFileRead(state->myfile, tupbody, tupbodylen);
|
||||
if (nread != (size_t) tupbodylen)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
|
||||
nread, (size_t) tupbodylen)));
|
||||
BufFileReadExact(state->myfile, tupbody, tupbodylen);
|
||||
if (state->backward) /* need trailing length word? */
|
||||
{
|
||||
nread = BufFileRead(state->myfile, &tuplen, sizeof(tuplen));
|
||||
if (nread != sizeof(tuplen))
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
|
||||
nread, sizeof(tuplen))));
|
||||
}
|
||||
BufFileReadExact(state->myfile, &tuplen, sizeof(tuplen));
|
||||
return (void *) tuple;
|
||||
}
|
||||
|
@ -38,7 +38,9 @@ typedef struct BufFile BufFile;
|
||||
|
||||
extern BufFile *BufFileCreateTemp(bool interXact);
|
||||
extern void BufFileClose(BufFile *file);
|
||||
extern size_t BufFileRead(BufFile *file, void *ptr, size_t size);
|
||||
extern pg_nodiscard size_t BufFileRead(BufFile *file, void *ptr, size_t size);
|
||||
extern void BufFileReadExact(BufFile *file, void *ptr, size_t size);
|
||||
extern size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK);
|
||||
extern void BufFileWrite(BufFile *file, const void *ptr, size_t size);
|
||||
extern int BufFileSeek(BufFile *file, int fileno, off_t offset, int whence);
|
||||
extern void BufFileTell(BufFile *file, int *fileno, off_t *offset);
|
||||
|
Loading…
x
Reference in New Issue
Block a user