Thread: Patch to reduce WAL log space usage

Patch to reduce WAL log space usage

From
Tom Lane
Date:
Per recent discussions in pghackers, I have tweaked the WAL code so that
each checkpoint truncates the log at the prior checkpoint's redo point,
not its undo point.  (There is no point in keeping the undo information
until we have UNDO support, which doesn't seem to be imminent.)  This
should reduce disk space usage very considerably in the presence of
long-running transactions.

Since I'm not sure if or how soon there will be a 7.1.3 release,
I'm posting the patch here in case people want to apply it locally.

Note: the diff also ensures that out-of-disk-space failures in WAL
logfile creation will be reported correctly.

            regards, tom lane


*** src/backend/access/transam/xlog.c~    Thu Apr  5 12:55:21 2001
--- src/backend/access/transam/xlog.c    Wed Jun  6 13:14:38 2001
***************
*** 1068,1076 ****
--- 1068,1082 ----

          /* OK to write the page */
          from = XLogCtl->pages + Write->curridx * BLCKSZ;
+         errno = 0;
          if (write(openLogFile, from, BLCKSZ) != BLCKSZ)
+         {
+             /* if write didn't set errno, assume problem is no disk space */
+             if (errno == 0)
+                 errno = ENOSPC;
              elog(STOP, "write(logfile %u seg %u off %u) failed: %m",
                   openLogId, openLogSeg, openLogOff);
+         }
          openLogOff += BLCKSZ;

          /*
***************
*** 1323,1328 ****
--- 1329,1335 ----
      MemSet(zbuffer, 0, sizeof(zbuffer));
      for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(zbuffer))
      {
+         errno = 0;
          if ((int) write(fd, zbuffer, sizeof(zbuffer)) != (int) sizeof(zbuffer))
          {
              int            save_errno = errno;
***************
*** 1332,1338 ****
               * space
               */
              unlink(tmppath);
!             errno = save_errno;

              elog(STOP, "ZeroFill(%s) failed: %m", tmppath);
          }
--- 1339,1346 ----
               * space
               */
              unlink(tmppath);
!             /* if write didn't set errno, assume problem is no disk space */
!             errno = save_errno ? save_errno : ENOSPC;

              elog(STOP, "ZeroFill(%s) failed: %m", tmppath);
          }
***************
*** 1987,1994 ****
--- 1995,2008 ----
          elog(STOP, "WriteControlFile failed to create control file (%s): %m",
               ControlFilePath);

+     errno = 0;
      if (write(fd, buffer, BLCKSZ) != BLCKSZ)
+     {
+         /* if write didn't set errno, assume problem is no disk space */
+         if (errno == 0)
+             errno = ENOSPC;
          elog(STOP, "WriteControlFile failed to write control file: %m");
+     }

      if (pg_fsync(fd) != 0)
          elog(STOP, "WriteControlFile failed to fsync control file: %m");
***************
*** 2085,2092 ****
--- 2099,2112 ----
      if (fd < 0)
          elog(STOP, "open(\"%s\") failed: %m", ControlFilePath);

+     errno = 0;
      if (write(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
+     {
+         /* if write didn't set errno, assume problem is no disk space */
+         if (errno == 0)
+             errno = ENOSPC;
          elog(STOP, "write(cntlfile) failed: %m");
+     }

      if (pg_fsync(fd) != 0)
          elog(STOP, "fsync(cntlfile) failed: %m");
***************
*** 2224,2231 ****
--- 2244,2257 ----
      use_existent = false;
      openLogFile = XLogFileInit(0, 0, &use_existent, false);

+     errno = 0;
      if (write(openLogFile, buffer, BLCKSZ) != BLCKSZ)
+     {
+         /* if write didn't set errno, assume problem is no disk space */
+         if (errno == 0)
+             errno = ENOSPC;
          elog(STOP, "BootStrapXLOG failed to write logfile: %m");
+     }

      if (pg_fsync(openLogFile) != 0)
          elog(STOP, "BootStrapXLOG failed to fsync logfile: %m");
***************
*** 2816,2830 ****
          elog(STOP, "XLog concurrent activity while data base is shutting down");

      /*
!      * Remember location of prior checkpoint's earliest info. Oldest item
!      * is redo or undo, whichever is older; but watch out for case that
!      * undo = 0.
       */
      if (ControlFile->checkPointCopy.undo.xrecoff != 0 &&
          XLByteLT(ControlFile->checkPointCopy.undo,
                   ControlFile->checkPointCopy.redo))
          XLByteToSeg(ControlFile->checkPointCopy.undo, _logId, _logSeg);
      else
          XLByteToSeg(ControlFile->checkPointCopy.redo, _logId, _logSeg);

      /*
--- 2842,2863 ----
          elog(STOP, "XLog concurrent activity while data base is shutting down");

      /*
!      * Select point at which we can truncate the log, which we base on the
!      * prior checkpoint's earliest info.
!      *
!      * With UNDO support: oldest item is redo or undo, whichever is older;
!      * but watch out for case that undo = 0.
!      *
!      * Without UNDO support: just use the redo pointer.  This allows xlog
!      * space to be freed much faster when there are long-running transactions.
       */
+ #ifdef NOT_USED
      if (ControlFile->checkPointCopy.undo.xrecoff != 0 &&
          XLByteLT(ControlFile->checkPointCopy.undo,
                   ControlFile->checkPointCopy.redo))
          XLByteToSeg(ControlFile->checkPointCopy.undo, _logId, _logSeg);
      else
+ #endif
          XLByteToSeg(ControlFile->checkPointCopy.redo, _logId, _logSeg);

      /*