Retry short writes when flushing WAL.
authorHeikki Linnakangas
Mon, 1 Jul 2013 06:36:00 +0000 (09:36 +0300)
committerHeikki Linnakangas
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;