Fix buffile.c error handling.
authorThomas Munro <[email protected]>
Tue, 16 Jun 2020 01:50:56 +0000 (13:50 +1200)
committerThomas Munro <[email protected]>
Tue, 16 Jun 2020 05:01:22 +0000 (17:01 +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 <[email protected]>
Reviewed-by: Melanie Plageman <[email protected]>
Reviewed-by: Alvaro Herrera <[email protected]>
Reviewed-by: Robert Haas <[email protected]>
Reviewed-by: Ibrar Ahmed <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
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 3a140aa2f7877b41e81d7efba3854aa9a9208a71..7ec648050caae0610cc8c2c290d7454edc5426c1 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 8b677fbc145e832b7958f47e2c467868febb25f4..97bbf483d69e865a671c5b0db0d5624b90b01c3f 100644 (file)
@@ -820,7 +820,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,
@@ -850,7 +850,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;
@@ -872,7 +872,6 @@ ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
                      BufFile **fileptr)
 {
    BufFile    *file = *fileptr;
-   size_t      written;
 
    if (file == NULL)
    {
@@ -881,17 +880,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);
 }
 
 /*
@@ -932,7 +922,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];
@@ -942,7 +933,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 9a14addfd7a908ea27c62069c03a62197a7ce09e..1d6b8b4d5ada178291a3025b692a5bdcfb4cdd7c 100644 (file)
@@ -93,8 +93,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.
@@ -247,7 +246,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;
    }
 
@@ -256,7 +258,14 @@ BufFileLoadBuffer(BufFile *file)
     */
    file->nbytes = FileRead(thisfile, file->buffer.data, sizeof(file->buffer));
    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 */
 
@@ -314,12 +323,19 @@ 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, file->buffer.data + wpos, bytestowrite);
        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;
@@ -352,7 +368,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)
@@ -360,12 +377,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)
    {
@@ -399,7 +411,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)
@@ -413,11 +426,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? */
@@ -449,19 +458,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);
 }
 
 /*
@@ -470,6 +475,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.
@@ -527,8 +533,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 252ba2207121f732ecc0dd4b43dd1fa6cb08e1db..150127488a9cfa83538f765f533f34ad3debfb30 100644 (file)
@@ -202,12 +202,12 @@ static void ltsDumpBuffer(LogicalTapeSet *lts, LogicalTape *lt);
 static void
 ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
 {
-   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);
 }
 
 /*
@@ -219,12 +219,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 51f474d9c46d33680d9337b49e98e3a73152b535..54869822a182a7d32f3fbd51700f4b5bd552112b 100644 (file)
@@ -512,7 +512,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
            {
@@ -522,7 +522,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:
@@ -849,7 +849,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;
 
            /*
@@ -953,7 +953,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 */
 
@@ -1017,7 +1017,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;
                }
@@ -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")));
            tup = READTUP(state, tuplen);
            return tup;
 
@@ -1236,7 +1236,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");
@@ -1301,7 +1301,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
                {
@@ -1310,7 +1310,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)
@@ -1457,7 +1457,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;
 }
 
@@ -1494,22 +1495,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);
@@ -1522,20 +1511,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;
 }