]> granicus.if.org Git - postgresql/commitdiff
Retry short writes when flushing WAL.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 1 Jul 2013 06:36:00 +0000 (09:36 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 1 Jul 2013 06:36:00 +0000 (09:36 +0300)
We don't normally bother retrying when the number of bytes written by
write() is short of what was requested. It is generally assumed that a
write() to disk doesn't return short, unless you run out of disk space.
While writing the WAL, however, it seems prudent to try a bit harder,
because a failure leads to PANIC. The write() is also much larger than most
write()s in the backend (up to wal_buffers), so there's more room for
surprises.

Also retry on EINTR. All signals used in the backend are flagged SA_RESTART
nowadays, so it shouldn't happen, but better to be defensive.

src/backend/access/transam/xlog.c

index 664470336958796c04000e540085342c2af0ef9d..0ce661bf9f4432180b9812b82726f76ebe8745bc 100644 (file)
@@ -1606,6 +1606,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
                {
                        char       *from;
                        Size            nbytes;
+                       Size            nleft;
+                       int                     written;
 
                        /* Need to seek in the file? */
                        if (openLogOff != startoffset)
@@ -1622,19 +1624,25 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
                        /* OK to write the page(s) */
                        from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ;
                        nbytes = npages * (Size) XLOG_BLCKSZ;
-                       errno = 0;
-                       if (write(openLogFile, from, nbytes) != nbytes)
+                       nleft = nbytes;
+                       do
                        {
-                               /* if write didn't set errno, assume no disk space */
-                               if (errno == 0)
-                                       errno = ENOSPC;
-                               ereport(PANIC,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not write to log file %s "
-                                                               "at offset %u, length %lu: %m",
-                                                               XLogFileNameP(ThisTimeLineID, openLogSegNo),
-                                                               openLogOff, (unsigned long) nbytes)));
-                       }
+                               errno = 0;
+                               written  = write(openLogFile, from, nleft);
+                               if (written <= 0)
+                               {
+                                       if (errno == EINTR)
+                                               continue;
+                                       ereport(PANIC,
+                                                       (errcode_for_file_access(),
+                                                        errmsg("could not write to log file %s "
+                                                                       "at offset %u, length %lu: %m",
+                                                                       XLogFileNameP(ThisTimeLineID, openLogSegNo),
+                                                                       openLogOff, (unsigned long) nbytes)));
+                               }
+                               nleft -= written;
+                               from += written;
+                       } while (nleft > 0);
 
                        /* Update state for write */
                        openLogOff += nbytes;