]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix buffile.c error handling.
authorThomas Munro <tmunro@postgresql.org>
Tue, 16 Jun 2020 01:50:56 +0000 (13:50 +1200)
committerThomas Munro <tmunro@postgresql.org>
Tue, 16 Jun 2020 05:00:53 +0000 (17:00 +1200)
Convert buffile.c error handling to use ereport.  This fixes cases where
I/O errors were indistinguishable from EOF or not reported.  Also remove
"%m" from error messages where errno would be bogus.  While we're
modifying those strings, add block numbers and short read byte counts
where appropriate.

Back-patch to all supported releases.

Reported-by: Amit Khandekar <amitdkhan.pg@gmail.com>
Reviewed-by: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Alvaro Herrera <alvherre@2ndquadrant.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Ibrar Ahmed <ibrar.ahmad@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CA%2BhUKGJE04G%3D8TLK0DLypT_27D9dR8F1RQgNp0jK6qR0tZGWOw%40mail.gmail.com

src/backend/access/gist/gistbuildbuffers.c
src/backend/executor/nodeHashjoin.c
src/backend/storage/file/buffile.c
src/backend/utils/sort/logtape.c
src/backend/utils/sort/tuplestore.c

index c917b57cd9c6eeebee2c0fa44cffa9c265bb353d..3a3726b9ffff362e64742d87abfa7d543fd83e81 100644 (file)
@@ -757,26 +757,20 @@ 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 temporary file: %m");
-       if (BufFileRead(file, ptr, BLCKSZ) != BLCKSZ)
-               elog(ERROR, "could not read temporary file: %m");
+               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);
 }
 
 static void
 WriteTempFileBlock(BufFile *file, long blknum, void *ptr)
 {
        if (BufFileSeekBlock(file, blknum) != 0)
-               elog(ERROR, "could not seek temporary file: %m");
-       if (BufFileWrite(file, ptr, BLCKSZ) != BLCKSZ)
-       {
-               /*
-                * the other errors in Read/WriteTempFileBlock shouldn't happen, but
-                * an error at write can easily happen if you run out of disk space.
-                */
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write block %ld of temporary file: %m",
-                                               blknum)));
-       }
+               elog(ERROR, "could not seek to block %ld in temporary file", blknum);
+       BufFileWrite(file, ptr, BLCKSZ);
 }
index 4125b12bf2a6f4e386ca7fd19d089ecef72902dd..0d0abbcc7ab9b21e03767574771d191ce17051be 100644 (file)
@@ -767,7 +767,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
                if (BufFileSeek(innerFile, 0, 0L, SEEK_SET))
                        ereport(ERROR,
                                        (errcode_for_file_access(),
-                                        errmsg("could not rewind hash-join temporary file: %m")));
+                                        errmsg("could not rewind hash-join temporary file")));
 
                while ((slot = ExecHashJoinGetSavedTuple(hjstate,
                                                                                                 innerFile,
@@ -797,7 +797,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
                if (BufFileSeek(hashtable->outerBatchFile[curbatch], 0, 0L, SEEK_SET))
                        ereport(ERROR,
                                        (errcode_for_file_access(),
-                                        errmsg("could not rewind hash-join temporary file: %m")));
+                                        errmsg("could not rewind hash-join temporary file")));
        }
 
        return true;
@@ -819,7 +819,6 @@ ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
                                          BufFile **fileptr)
 {
        BufFile    *file = *fileptr;
-       size_t          written;
 
        if (file == NULL)
        {
@@ -828,17 +827,8 @@ ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
                *fileptr = file;
        }
 
-       written = BufFileWrite(file, (void *) &hashvalue, sizeof(uint32));
-       if (written != sizeof(uint32))
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to hash-join temporary file: %m")));
-
-       written = BufFileWrite(file, (void *) tuple, tuple->t_len);
-       if (written != tuple->t_len)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to hash-join temporary file: %m")));
+       BufFileWrite(file, (void *) &hashvalue, sizeof(uint32));
+       BufFileWrite(file, (void *) tuple, tuple->t_len);
 }
 
 /*
@@ -879,7 +869,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
        if (nread != sizeof(header))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not read from hash-join temporary file: %m")));
+                                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];
@@ -889,7 +880,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
        if (nread != header[1] - sizeof(uint32))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not read from hash-join temporary file: %m")));
+                                errmsg("could not read from hash-join temporary file: read only %zu of %zu bytes",
+                                               nread, header[1] - sizeof(uint32))));
        return ExecStoreMinimalTuple(tuple, tupleSlot, true);
 }
 
index 01546da7cfff4706bc5469f8ea15651e59d16ed4..b2a6ea082ff92fd2e1219af15b0baa92d28c8902 100644 (file)
@@ -94,8 +94,7 @@ static BufFile *makeBufFile(File firstfile);
 static void extendBufFile(BufFile *file);
 static void BufFileLoadBuffer(BufFile *file);
 static void BufFileDumpBuffer(BufFile *file);
-static int     BufFileFlush(BufFile *file);
-
+static void BufFileFlush(BufFile *file);
 
 /*
  * Create a BufFile given the first underlying physical file.
@@ -248,7 +247,10 @@ BufFileLoadBuffer(BufFile *file)
        if (file->curOffset != file->offsets[file->curFile])
        {
                if (FileSeek(thisfile, file->curOffset, SEEK_SET) != file->curOffset)
-                       return;                         /* seek failed, read nothing */
+                       ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not seek in file \"%s\": %m",
+                                                       FilePathName(thisfile))));
                file->offsets[file->curFile] = file->curOffset;
        }
 
@@ -260,7 +262,14 @@ BufFileLoadBuffer(BufFile *file)
                                                        sizeof(file->buffer),
                                                        WAIT_EVENT_BUFFILE_READ);
        if (file->nbytes < 0)
+       {
                file->nbytes = 0;
+               ereport(ERROR,
+                               (errcode_for_file_access(),
+                                errmsg("could not read file \"%s\": %m",
+                                               FilePathName(thisfile))));
+       }
+
        file->offsets[file->curFile] += file->nbytes;
        /* we choose not to advance curOffset here */
 
@@ -318,7 +327,10 @@ BufFileDumpBuffer(BufFile *file)
                if (file->curOffset != file->offsets[file->curFile])
                {
                        if (FileSeek(thisfile, file->curOffset, SEEK_SET) != file->curOffset)
-                               return;                 /* seek failed, give up */
+                               ereport(ERROR,
+                                               (errcode_for_file_access(),
+                                                errmsg("could not seek in file \"%s\": %m",
+                                                               FilePathName(thisfile))));
                        file->offsets[file->curFile] = file->curOffset;
                }
                bytestowrite = FileWrite(thisfile,
@@ -326,7 +338,11 @@ BufFileDumpBuffer(BufFile *file)
                                                                 bytestowrite,
                                                                 WAIT_EVENT_BUFFILE_WRITE);
                if (bytestowrite <= 0)
-                       return;                         /* failed to write */
+                       ereport(ERROR,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not write to file \"%s\" : %m",
+                                                       FilePathName(thisfile))));
+
                file->offsets[file->curFile] += bytestowrite;
                file->curOffset += bytestowrite;
                wpos += bytestowrite;
@@ -359,7 +375,8 @@ BufFileDumpBuffer(BufFile *file)
 /*
  * BufFileRead
  *
- * Like fread() except we assume 1-byte element size.
+ * Like fread() except we assume 1-byte element size and report I/O errors via
+ * ereport().
  */
 size_t
 BufFileRead(BufFile *file, void *ptr, size_t size)
@@ -367,12 +384,7 @@ BufFileRead(BufFile *file, void *ptr, size_t size)
        size_t          nread = 0;
        size_t          nthistime;
 
-       if (file->dirty)
-       {
-               if (BufFileFlush(file) != 0)
-                       return 0;                       /* could not flush... */
-               Assert(!file->dirty);
-       }
+       BufFileFlush(file);
 
        while (size > 0)
        {
@@ -406,7 +418,8 @@ BufFileRead(BufFile *file, void *ptr, size_t size)
 /*
  * BufFileWrite
  *
- * Like fwrite() except we assume 1-byte element size.
+ * Like fwrite() except we assume 1-byte element size and report errors via
+ * ereport().
  */
 size_t
 BufFileWrite(BufFile *file, void *ptr, size_t size)
@@ -420,11 +433,7 @@ BufFileWrite(BufFile *file, void *ptr, size_t size)
                {
                        /* Buffer full, dump it out */
                        if (file->dirty)
-                       {
                                BufFileDumpBuffer(file);
-                               if (file->dirty)
-                                       break;          /* I/O error */
-                       }
                        else
                        {
                                /* Hmm, went directly from reading to writing? */
@@ -456,19 +465,15 @@ BufFileWrite(BufFile *file, void *ptr, size_t size)
 /*
  * BufFileFlush
  *
- * Like fflush()
+ * Like fflush(), except that I/O errors are reported with ereport().
  */
-static int
+static void
 BufFileFlush(BufFile *file)
 {
        if (file->dirty)
-       {
                BufFileDumpBuffer(file);
-               if (file->dirty)
-                       return EOF;
-       }
 
-       return 0;
+       Assert(!file->dirty);
 }
 
 /*
@@ -477,6 +482,7 @@ BufFileFlush(BufFile *file)
  * Like fseek(), except that target position needs two values in order to
  * work when logical filesize exceeds maximum value representable by long.
  * We do not support relative seeks across more than LONG_MAX, however.
+ * I/O errors are reported by ereport().
  *
  * Result is 0 if OK, EOF if not.  Logical position is not moved if an
  * impossible seek is attempted.
@@ -534,8 +540,7 @@ BufFileSeek(BufFile *file, int fileno, off_t offset, int whence)
                return 0;
        }
        /* Otherwise, must reposition buffer, so flush any dirty data */
-       if (BufFileFlush(file) != 0)
-               return EOF;
+       BufFileFlush(file);
 
        /*
         * At this point and no sooner, check for seek past last segment. The
index 4b946e1b496b00ac734545e03a82642e58399c00..e80943ea687bc8a63e1f28db533b785554cf2b38 100644 (file)
@@ -223,12 +223,12 @@ ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
        }
 
        /* Write the requested block */
-       if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
-               BufFileWrite(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
+       if (BufFileSeekBlock(lts->pfile, blocknum) != 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not write block %ld of temporary file: %m",
+                                errmsg("could not seek to block %ld of temporary file",
                                                blocknum)));
+       BufFileWrite(lts->pfile, buffer, BLCKSZ);
 
        /* Update nBlocksWritten, if we extended the file */
        if (blocknum == lts->nBlocksWritten)
@@ -244,12 +244,19 @@ ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
 static void
 ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
 {
-       if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
-               BufFileRead(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
+       size_t          nread;
+
+       if (BufFileSeekBlock(lts->pfile, blocknum) != 0)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not read block %ld of temporary file: %m",
+                                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)));
 }
 
 /*
index 98c006b663e3d2f6c7db00bf20c71ab5fbf24c39..110b083c64d46a86a79c2bc6f010f79778d02c6b 100644 (file)
@@ -515,7 +515,7 @@ tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
                                                                SEEK_SET) != 0)
                                        ereport(ERROR,
                                                        (errcode_for_file_access(),
-                                                        errmsg("could not seek in tuplestore temporary file: %m")));
+                                                        errmsg("could not seek in tuplestore temporary file")));
                        }
                        else
                        {
@@ -525,7 +525,7 @@ tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
                                                                SEEK_SET) != 0)
                                        ereport(ERROR,
                                                        (errcode_for_file_access(),
-                                                        errmsg("could not seek in tuplestore temporary file: %m")));
+                                                        errmsg("could not seek in tuplestore temporary file")));
                        }
                        break;
                default:
@@ -866,7 +866,7 @@ tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
                                                        SEEK_SET) != 0)
                                ereport(ERROR,
                                                (errcode_for_file_access(),
-                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                errmsg("could not seek in tuplestore temporary file")));
                        state->status = TSS_WRITEFILE;
 
                        /*
@@ -970,7 +970,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
                                                                SEEK_SET) != 0)
                                        ereport(ERROR,
                                                        (errcode_for_file_access(),
-                                                        errmsg("could not seek in tuplestore temporary file: %m")));
+                                                        errmsg("could not seek in tuplestore temporary file")));
                        state->status = TSS_READFILE;
                        /* FALL THRU into READFILE case */
 
@@ -1034,7 +1034,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
                                                                        SEEK_CUR) != 0)
                                                ereport(ERROR,
                                                                (errcode_for_file_access(),
-                                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                                errmsg("could not seek in tuplestore temporary file")));
                                        Assert(!state->truncated);
                                        return NULL;
                                }
@@ -1051,7 +1051,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
                                                        SEEK_CUR) != 0)
                                ereport(ERROR,
                                                (errcode_for_file_access(),
-                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                errmsg("could not seek in tuplestore temporary file")));
                        tup = READTUP(state, tuplen);
                        return tup;
 
@@ -1253,7 +1253,7 @@ tuplestore_rescan(Tuplestorestate *state)
                        if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)
                                ereport(ERROR,
                                                (errcode_for_file_access(),
-                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                errmsg("could not seek in tuplestore temporary file")));
                        break;
                default:
                        elog(ERROR, "invalid tuplestore state");
@@ -1318,7 +1318,7 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
                                                                        SEEK_SET) != 0)
                                                ereport(ERROR,
                                                                (errcode_for_file_access(),
-                                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                                errmsg("could not seek in tuplestore temporary file")));
                                }
                                else
                                {
@@ -1327,7 +1327,7 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
                                                                        SEEK_SET) != 0)
                                                ereport(ERROR,
                                                                (errcode_for_file_access(),
-                                                                errmsg("could not seek in tuplestore temporary file: %m")));
+                                                                errmsg("could not seek in tuplestore temporary file")));
                                }
                        }
                        else if (srcptr == state->activeptr)
@@ -1474,7 +1474,8 @@ getlen(Tuplestorestate *state, bool eofOK)
        if (nbytes != 0 || !eofOK)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not read from tuplestore temporary file: %m")));
+                                errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
+                                               nbytes, sizeof(len))));
        return 0;
 }
 
@@ -1511,22 +1512,10 @@ writetup_heap(Tuplestorestate *state, void *tup)
        /* total on-disk footprint: */
        unsigned int tuplen = tupbodylen + sizeof(int);
 
-       if (BufFileWrite(state->myfile, (void *) &tuplen,
-                                        sizeof(tuplen)) != sizeof(tuplen))
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to tuplestore temporary file: %m")));
-       if (BufFileWrite(state->myfile, (void *) tupbody,
-                                        tupbodylen) != (size_t) tupbodylen)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not write to tuplestore temporary file: %m")));
+       BufFileWrite(state->myfile, (void *) &tuplen, sizeof(tuplen));
+       BufFileWrite(state->myfile, (void *) tupbody, tupbodylen);
        if (state->backward)            /* need trailing length word? */
-               if (BufFileWrite(state->myfile, (void *) &tuplen,
-                                                sizeof(tuplen)) != sizeof(tuplen))
-                       ereport(ERROR,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not write to tuplestore temporary file: %m")));
+               BufFileWrite(state->myfile, (void *) &tuplen, sizeof(tuplen));
 
        FREEMEM(state, GetMemoryChunkSpace(tuple));
        heap_free_minimal_tuple(tuple);
@@ -1539,20 +1528,25 @@ 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;
-       if (BufFileRead(state->myfile, (void *) tupbody,
-                                       tupbodylen) != (size_t) tupbodylen)
+       nread = BufFileRead(state->myfile, (void *) tupbody, tupbodylen);
+       if (nread != (size_t) tupbodylen)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not read from tuplestore temporary file: %m")));
+                                errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
+                                               nread, (size_t) tupbodylen)));
        if (state->backward)            /* need trailing length word? */
-               if (BufFileRead(state->myfile, (void *) &tuplen,
-                                               sizeof(tuplen)) != sizeof(tuplen))
+       {
+               nread = BufFileRead(state->myfile, (void *) &tuplen, sizeof(tuplen));
+               if (nread != sizeof(tuplen))
                        ereport(ERROR,
                                        (errcode_for_file_access(),
-                                        errmsg("could not read from tuplestore temporary file: %m")));
+                                        errmsg("could not read from tuplestore temporary file: read only %zu of %zu bytes",
+                                                       nread, sizeof(tuplen))));
+       }
        return (void *) tuple;
 }