]> granicus.if.org Git - postgresql/blob - src/backend/postmaster/walwriter.c
Update copyright for 2009.
[postgresql] / src / backend / postmaster / walwriter.c
1 /*-------------------------------------------------------------------------
2  *
3  * walwriter.c
4  *
5  * The WAL writer background process is new as of Postgres 8.3.  It attempts
6  * to keep regular backends from having to write out (and fsync) WAL pages.
7  * Also, it guarantees that transaction commit records that weren't synced
8  * to disk immediately upon commit (ie, were "asynchronously committed")
9  * will reach disk within a knowable time --- which, as it happens, is at
10  * most three times the wal_writer_delay cycle time.
11  *
12  * Note that as with the bgwriter for shared buffers, regular backends are
13  * still empowered to issue WAL writes and fsyncs when the walwriter doesn't
14  * keep up.
15  *
16  * Because the walwriter's cycle is directly linked to the maximum delay
17  * before async-commit transactions are guaranteed committed, it's probably
18  * unwise to load additional functionality onto it.  For instance, if you've
19  * got a yen to create xlog segments further in advance, that'd be better done
20  * in bgwriter than in walwriter.
21  *
22  * The walwriter is started by the postmaster as soon as the startup subprocess
23  * finishes.  It remains alive until the postmaster commands it to terminate.
24  * Normal termination is by SIGTERM, which instructs the walwriter to exit(0).
25  * Emergency termination is by SIGQUIT; like any backend, the walwriter will
26  * simply abort and exit on SIGQUIT.
27  *
28  * If the walwriter exits unexpectedly, the postmaster treats that the same
29  * as a backend crash: shared memory may be corrupted, so remaining backends
30  * should be killed by SIGQUIT and then a recovery cycle started.
31  *
32  *
33  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
34  *
35  *
36  * IDENTIFICATION
37  *        $PostgreSQL: pgsql/src/backend/postmaster/walwriter.c,v 1.5 2009/01/01 17:23:46 momjian Exp $
38  *
39  *-------------------------------------------------------------------------
40  */
41 #include "postgres.h"
42
43 #include <signal.h>
44 #include <sys/time.h>
45 #include <time.h>
46 #include <unistd.h>
47
48 #include "access/xlog.h"
49 #include "libpq/pqsignal.h"
50 #include "miscadmin.h"
51 #include "postmaster/walwriter.h"
52 #include "storage/bufmgr.h"
53 #include "storage/fd.h"
54 #include "storage/ipc.h"
55 #include "storage/lwlock.h"
56 #include "storage/pmsignal.h"
57 #include "storage/smgr.h"
58 #include "utils/guc.h"
59 #include "utils/hsearch.h"
60 #include "utils/memutils.h"
61 #include "utils/resowner.h"
62
63
64 /*
65  * GUC parameters
66  */
67 int                     WalWriterDelay = 200;
68
69 /*
70  * Flags set by interrupt handlers for later service in the main loop.
71  */
72 static volatile sig_atomic_t got_SIGHUP = false;
73 static volatile sig_atomic_t shutdown_requested = false;
74
75 /* Signal handlers */
76 static void wal_quickdie(SIGNAL_ARGS);
77 static void WalSigHupHandler(SIGNAL_ARGS);
78 static void WalShutdownHandler(SIGNAL_ARGS);
79
80
81 /*
82  * Main entry point for walwriter process
83  *
84  * This is invoked from BootstrapMain, which has already created the basic
85  * execution environment, but not enabled signals yet.
86  */
87 void
88 WalWriterMain(void)
89 {
90         sigjmp_buf      local_sigjmp_buf;
91         MemoryContext walwriter_context;
92
93         /*
94          * If possible, make this process a group leader, so that the postmaster
95          * can signal any child processes too.  (walwriter probably never has any
96          * child processes, but for consistency we make all postmaster child
97          * processes do this.)
98          */
99 #ifdef HAVE_SETSID
100         if (setsid() < 0)
101                 elog(FATAL, "setsid() failed: %m");
102 #endif
103
104         /*
105          * Properly accept or ignore signals the postmaster might send us
106          *
107          * We have no particular use for SIGINT at the moment, but seems
108          * reasonable to treat like SIGTERM.
109          */
110         pqsignal(SIGHUP, WalSigHupHandler); /* set flag to read config file */
111         pqsignal(SIGINT, WalShutdownHandler);           /* request shutdown */
112         pqsignal(SIGTERM, WalShutdownHandler);          /* request shutdown */
113         pqsignal(SIGQUIT, wal_quickdie);        /* hard crash time */
114         pqsignal(SIGALRM, SIG_IGN);
115         pqsignal(SIGPIPE, SIG_IGN);
116         pqsignal(SIGUSR1, SIG_IGN); /* reserve for sinval */
117         pqsignal(SIGUSR2, SIG_IGN); /* not used */
118
119         /*
120          * Reset some signals that are accepted by postmaster but not here
121          */
122         pqsignal(SIGCHLD, SIG_DFL);
123         pqsignal(SIGTTIN, SIG_DFL);
124         pqsignal(SIGTTOU, SIG_DFL);
125         pqsignal(SIGCONT, SIG_DFL);
126         pqsignal(SIGWINCH, SIG_DFL);
127
128         /* We allow SIGQUIT (quickdie) at all times */
129 #ifdef HAVE_SIGPROCMASK
130         sigdelset(&BlockSig, SIGQUIT);
131 #else
132         BlockSig &= ~(sigmask(SIGQUIT));
133 #endif
134
135         /*
136          * Create a resource owner to keep track of our resources (not clear that
137          * we need this, but may as well have one).
138          */
139         CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Writer");
140
141         /*
142          * Create a memory context that we will do all our work in.  We do this so
143          * that we can reset the context during error recovery and thereby avoid
144          * possible memory leaks.  Formerly this code just ran in
145          * TopMemoryContext, but resetting that would be a really bad idea.
146          */
147         walwriter_context = AllocSetContextCreate(TopMemoryContext,
148                                                                                           "Wal Writer",
149                                                                                           ALLOCSET_DEFAULT_MINSIZE,
150                                                                                           ALLOCSET_DEFAULT_INITSIZE,
151                                                                                           ALLOCSET_DEFAULT_MAXSIZE);
152         MemoryContextSwitchTo(walwriter_context);
153
154         /*
155          * If an exception is encountered, processing resumes here.
156          *
157          * This code is heavily based on bgwriter.c, q.v.
158          */
159         if (sigsetjmp(local_sigjmp_buf, 1) != 0)
160         {
161                 /* Since not using PG_TRY, must reset error stack by hand */
162                 error_context_stack = NULL;
163
164                 /* Prevent interrupts while cleaning up */
165                 HOLD_INTERRUPTS();
166
167                 /* Report the error to the server log */
168                 EmitErrorReport();
169
170                 /*
171                  * These operations are really just a minimal subset of
172                  * AbortTransaction().  We don't have very many resources to worry
173                  * about in walwriter, but we do have LWLocks, and perhaps buffers?
174                  */
175                 LWLockReleaseAll();
176                 AbortBufferIO();
177                 UnlockBuffers();
178                 /* buffer pins are released here: */
179                 ResourceOwnerRelease(CurrentResourceOwner,
180                                                          RESOURCE_RELEASE_BEFORE_LOCKS,
181                                                          false, true);
182                 /* we needn't bother with the other ResourceOwnerRelease phases */
183                 AtEOXact_Buffers(false);
184                 AtEOXact_Files();
185                 AtEOXact_HashTables(false);
186
187                 /*
188                  * Now return to normal top-level context and clear ErrorContext for
189                  * next time.
190                  */
191                 MemoryContextSwitchTo(walwriter_context);
192                 FlushErrorState();
193
194                 /* Flush any leaked data in the top-level context */
195                 MemoryContextResetAndDeleteChildren(walwriter_context);
196
197                 /* Now we can allow interrupts again */
198                 RESUME_INTERRUPTS();
199
200                 /*
201                  * Sleep at least 1 second after any error.  A write error is likely
202                  * to be repeated, and we don't want to be filling the error logs as
203                  * fast as we can.
204                  */
205                 pg_usleep(1000000L);
206
207                 /*
208                  * Close all open files after any error.  This is helpful on Windows,
209                  * where holding deleted files open causes various strange errors.
210                  * It's not clear we need it elsewhere, but shouldn't hurt.
211                  */
212                 smgrcloseall();
213         }
214
215         /* We can now handle ereport(ERROR) */
216         PG_exception_stack = &local_sigjmp_buf;
217
218         /*
219          * Unblock signals (they were blocked when the postmaster forked us)
220          */
221         PG_SETMASK(&UnBlockSig);
222
223         /*
224          * Loop forever
225          */
226         for (;;)
227         {
228                 long            udelay;
229
230                 /*
231                  * Emergency bailout if postmaster has died.  This is to avoid the
232                  * necessity for manual cleanup of all postmaster children.
233                  */
234                 if (!PostmasterIsAlive(true))
235                         exit(1);
236
237                 /*
238                  * Process any requests or signals received recently.
239                  */
240                 if (got_SIGHUP)
241                 {
242                         got_SIGHUP = false;
243                         ProcessConfigFile(PGC_SIGHUP);
244                 }
245                 if (shutdown_requested)
246                 {
247                         /* Normal exit from the walwriter is here */
248                         proc_exit(0);           /* done */
249                 }
250
251                 /*
252                  * Do what we're here for...
253                  */
254                 XLogBackgroundFlush();
255
256                 /*
257                  * Delay until time to do something more, but fall out of delay
258                  * reasonably quickly if signaled.
259                  */
260                 udelay = WalWriterDelay * 1000L;
261                 while (udelay > 999999L)
262                 {
263                         if (got_SIGHUP || shutdown_requested)
264                                 break;
265                         pg_usleep(1000000L);
266                         udelay -= 1000000L;
267                 }
268                 if (!(got_SIGHUP || shutdown_requested))
269                         pg_usleep(udelay);
270         }
271 }
272
273
274 /* --------------------------------
275  *              signal handler routines
276  * --------------------------------
277  */
278
279 /*
280  * wal_quickdie() occurs when signalled SIGQUIT by the postmaster.
281  *
282  * Some backend has bought the farm,
283  * so we need to stop what we're doing and exit.
284  */
285 static void
286 wal_quickdie(SIGNAL_ARGS)
287 {
288         PG_SETMASK(&BlockSig);
289
290         /*
291          * DO NOT proc_exit() -- we're here because shared memory may be
292          * corrupted, so we don't want to try to clean up our transaction. Just
293          * nail the windows shut and get out of town.
294          *
295          * Note we do exit(2) not exit(0).      This is to force the postmaster into a
296          * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
297          * backend.  This is necessary precisely because we don't clean up our
298          * shared memory state.
299          */
300         exit(2);
301 }
302
303 /* SIGHUP: set flag to re-read config file at next convenient time */
304 static void
305 WalSigHupHandler(SIGNAL_ARGS)
306 {
307         got_SIGHUP = true;
308 }
309
310 /* SIGTERM: set flag to exit normally */
311 static void
312 WalShutdownHandler(SIGNAL_ARGS)
313 {
314         shutdown_requested = true;
315 }