Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

walwriter.c

/*-------------------------------------------------------------------------
 *
 * walwriter.c
 *
 * The WAL writer background process is new as of Postgres 8.3.  It attempts
 * to keep regular backends from having to write out (and fsync) WAL pages.
 * Also, it guarantees that transaction commit records that weren't synced
 * to disk immediately upon commit (ie, were "asynchronously committed")
 * will reach disk within a knowable time --- which, as it happens, is at
 * most three times the wal_writer_delay cycle time.
 *
 * Note that as with the bgwriter for shared buffers, regular backends are
 * still empowered to issue WAL writes and fsyncs when the walwriter doesn't
 * keep up.
 *
 * Because the walwriter's cycle is directly linked to the maximum delay
 * before async-commit transactions are guaranteed committed, it's probably
 * unwise to load additional functionality onto it.  For instance, if you've
 * got a yen to create xlog segments further in advance, that'd be better done
 * in bgwriter than in walwriter.
 *
 * The walwriter is started by the postmaster as soon as the startup subprocess
 * finishes.  It remains alive until the postmaster commands it to terminate.
 * Normal termination is by SIGTERM, which instructs the walwriter to exit(0).
 * Emergency termination is by SIGQUIT; like any backend, the walwriter will
 * simply abort and exit on SIGQUIT.
 *
 * If the walwriter exits unexpectedly, the postmaster treats that the same
 * as a backend crash: shared memory may be corrupted, so remaining backends
 * should be killed by SIGQUIT and then a recovery cycle started.
 *
 *
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/src/backend/postmaster/walwriter.c,v 1.7 2009/06/11 14:49:01 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

#include "access/xlog.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "postmaster/walwriter.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/pmsignal.h"
#include "storage/smgr.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/resowner.h"


/*
 * GUC parameters
 */
int               WalWriterDelay = 200;

/*
 * Flags set by interrupt handlers for later service in the main loop.
 */
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;

/* Signal handlers */
static void wal_quickdie(SIGNAL_ARGS);
static void WalSigHupHandler(SIGNAL_ARGS);
static void WalShutdownHandler(SIGNAL_ARGS);


/*
 * Main entry point for walwriter process
 *
 * This is invoked from BootstrapMain, which has already created the basic
 * execution environment, but not enabled signals yet.
 */
void
WalWriterMain(void)
{
      sigjmp_buf  local_sigjmp_buf;
      MemoryContext walwriter_context;

      /*
       * If possible, make this process a group leader, so that the postmaster
       * can signal any child processes too.    (walwriter probably never has any
       * child processes, but for consistency we make all postmaster child
       * processes do this.)
       */
#ifdef HAVE_SETSID
      if (setsid() < 0)
            elog(FATAL, "setsid() failed: %m");
#endif

      /*
       * Properly accept or ignore signals the postmaster might send us
       *
       * We have no particular use for SIGINT at the moment, but seems
       * reasonable to treat like SIGTERM.
       */
      pqsignal(SIGHUP, WalSigHupHandler); /* set flag to read config file */
      pqsignal(SIGINT, WalShutdownHandler);           /* request shutdown */
      pqsignal(SIGTERM, WalShutdownHandler);          /* request shutdown */
      pqsignal(SIGQUIT, wal_quickdie);    /* hard crash time */
      pqsignal(SIGALRM, SIG_IGN);
      pqsignal(SIGPIPE, SIG_IGN);
      pqsignal(SIGUSR1, SIG_IGN); /* reserve for sinval */
      pqsignal(SIGUSR2, SIG_IGN); /* not used */

      /*
       * Reset some signals that are accepted by postmaster but not here
       */
      pqsignal(SIGCHLD, SIG_DFL);
      pqsignal(SIGTTIN, SIG_DFL);
      pqsignal(SIGTTOU, SIG_DFL);
      pqsignal(SIGCONT, SIG_DFL);
      pqsignal(SIGWINCH, SIG_DFL);

      /* We allow SIGQUIT (quickdie) at all times */
#ifdef HAVE_SIGPROCMASK
      sigdelset(&BlockSig, SIGQUIT);
#else
      BlockSig &= ~(sigmask(SIGQUIT));
#endif

      /*
       * Create a resource owner to keep track of our resources (not clear that
       * we need this, but may as well have one).
       */
      CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Writer");

      /*
       * Create a memory context that we will do all our work in.  We do this so
       * that we can reset the context during error recovery and thereby avoid
       * possible memory leaks.  Formerly this code just ran in
       * TopMemoryContext, but resetting that would be a really bad idea.
       */
      walwriter_context = AllocSetContextCreate(TopMemoryContext,
                                                                    "Wal Writer",
                                                                    ALLOCSET_DEFAULT_MINSIZE,
                                                                    ALLOCSET_DEFAULT_INITSIZE,
                                                                    ALLOCSET_DEFAULT_MAXSIZE);
      MemoryContextSwitchTo(walwriter_context);

      /*
       * If an exception is encountered, processing resumes here.
       *
       * This code is heavily based on bgwriter.c, q.v.
       */
      if (sigsetjmp(local_sigjmp_buf, 1) != 0)
      {
            /* Since not using PG_TRY, must reset error stack by hand */
            error_context_stack = NULL;

            /* Prevent interrupts while cleaning up */
            HOLD_INTERRUPTS();

            /* Report the error to the server log */
            EmitErrorReport();

            /*
             * These operations are really just a minimal subset of
             * AbortTransaction().  We don't have very many resources to worry
             * about in walwriter, but we do have LWLocks, and perhaps buffers?
             */
            LWLockReleaseAll();
            AbortBufferIO();
            UnlockBuffers();
            /* buffer pins are released here: */
            ResourceOwnerRelease(CurrentResourceOwner,
                                           RESOURCE_RELEASE_BEFORE_LOCKS,
                                           false, true);
            /* we needn't bother with the other ResourceOwnerRelease phases */
            AtEOXact_Buffers(false);
            AtEOXact_Files();
            AtEOXact_HashTables(false);

            /*
             * Now return to normal top-level context and clear ErrorContext for
             * next time.
             */
            MemoryContextSwitchTo(walwriter_context);
            FlushErrorState();

            /* Flush any leaked data in the top-level context */
            MemoryContextResetAndDeleteChildren(walwriter_context);

            /* Now we can allow interrupts again */
            RESUME_INTERRUPTS();

            /*
             * Sleep at least 1 second after any error.  A write error is likely
             * to be repeated, and we don't want to be filling the error logs as
             * fast as we can.
             */
            pg_usleep(1000000L);

            /*
             * Close all open files after any error.  This is helpful on Windows,
             * where holding deleted files open causes various strange errors.
             * It's not clear we need it elsewhere, but shouldn't hurt.
             */
            smgrcloseall();
      }

      /* We can now handle ereport(ERROR) */
      PG_exception_stack = &local_sigjmp_buf;

      /*
       * Unblock signals (they were blocked when the postmaster forked us)
       */
      PG_SETMASK(&UnBlockSig);

      /*
       * Loop forever
       */
      for (;;)
      {
            long        udelay;

            /*
             * Emergency bailout if postmaster has died.  This is to avoid the
             * necessity for manual cleanup of all postmaster children.
             */
            if (!PostmasterIsAlive(true))
                  exit(1);

            /*
             * Process any requests or signals received recently.
             */
            if (got_SIGHUP)
            {
                  got_SIGHUP = false;
                  ProcessConfigFile(PGC_SIGHUP);
            }
            if (shutdown_requested)
            {
                  /* Normal exit from the walwriter is here */
                  proc_exit(0);           /* done */
            }

            /*
             * Do what we're here for...
             */
            XLogBackgroundFlush();

            /*
             * Delay until time to do something more, but fall out of delay
             * reasonably quickly if signaled.
             */
            udelay = WalWriterDelay * 1000L;
            while (udelay > 999999L)
            {
                  if (got_SIGHUP || shutdown_requested)
                        break;
                  pg_usleep(1000000L);
                  udelay -= 1000000L;
            }
            if (!(got_SIGHUP || shutdown_requested))
                  pg_usleep(udelay);
      }
}


/* --------------------------------
 *          signal handler routines
 * --------------------------------
 */

/*
 * wal_quickdie() occurs when signalled SIGQUIT by the postmaster.
 *
 * Some backend has bought the farm,
 * so we need to stop what we're doing and exit.
 */
static void
wal_quickdie(SIGNAL_ARGS)
{
      PG_SETMASK(&BlockSig);

      /*
       * We DO NOT want to run proc_exit() callbacks -- we're here because
       * shared memory may be corrupted, so we don't want to try to clean up our
       * transaction.  Just nail the windows shut and get out of town.  Now that
       * there's an atexit callback to prevent third-party code from breaking
       * things by calling exit() directly, we have to reset the callbacks
       * explicitly to make this work as intended.
       */
      on_exit_reset();

      /*
       * Note we do exit(2) not exit(0).  This is to force the postmaster into a
       * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
       * backend.  This is necessary precisely because we don't clean up our
       * shared memory state.  (The "dead man switch" mechanism in pmsignal.c
       * should ensure the postmaster sees this as a crash, too, but no harm in
       * being doubly sure.)
       */
      exit(2);
}

/* SIGHUP: set flag to re-read config file at next convenient time */
static void
WalSigHupHandler(SIGNAL_ARGS)
{
      got_SIGHUP = true;
}

/* SIGTERM: set flag to exit normally */
static void
WalShutdownHandler(SIGNAL_ARGS)
{
      shutdown_requested = true;
}

Generated by  Doxygen 1.6.0   Back to index