diff options
Diffstat (limited to 'src/backend/postmaster/syslogger.c')
-rw-r--r-- | src/backend/postmaster/syslogger.c | 95 |
1 files changed, 66 insertions, 29 deletions
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index f5ae84157c8..35288792434 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -9,8 +9,7 @@ * in postgresql.conf. If these limits are reached or passed, the * current logfile is closed and a new one is created (rotated). * The logfiles are stored in a subdirectory (configurable in - * postgresql.conf), using an internal naming scheme that mangles - * creation time and current postmaster pid. + * postgresql.conf), using a user-selectable naming scheme. * * Author: Andreas Pflug <pgadmin@pse-consulting.de> * @@ -40,6 +39,7 @@ #include "postmaster/postmaster.h" #include "postmaster/syslogger.h" #include "storage/ipc.h" +#include "storage/latch.h" #include "storage/pg_shmem.h" #include "utils/guc.h" #include "utils/ps_status.h" @@ -93,6 +93,7 @@ static FILE *syslogFile = NULL; static FILE *csvlogFile = NULL; static char *last_file_name = NULL; static char *last_csv_file_name = NULL; +static Latch sysLoggerLatch; /* * Buffers for saving partial messages from different backends. @@ -168,12 +169,14 @@ SysLoggerMain(int argc, char *argv[]) char *currentLogDir; char *currentLogFilename; int currentLogRotationAge; + pg_time_t now; IsUnderPostmaster = true; /* we are a postmaster subprocess now */ MyProcPid = getpid(); /* reset MyProcPid */ MyStartTime = time(NULL); /* set our start time in case we call elog */ + now = MyStartTime; #ifdef EXEC_BACKEND syslogger_parseArgs(argc, argv); @@ -246,6 +249,9 @@ SysLoggerMain(int argc, char *argv[]) elog(FATAL, "setsid() failed: %m"); #endif + /* Initialize private latch for use by signal handlers */ + InitLatch(&sysLoggerLatch); + /* * Properly accept or ignore signals the postmaster might send us * @@ -296,14 +302,19 @@ SysLoggerMain(int argc, char *argv[]) { bool time_based_rotation = false; int size_rotation_for = 0; + long cur_timeout; + int cur_flags; #ifndef WIN32 - int bytesRead; int rc; - fd_set rfds; - struct timeval timeout; #endif + /* Clear any already-pending wakeups */ + ResetLatch(&sysLoggerLatch); + + /* + * Process any requests or signals received recently. + */ if (got_SIGHUP) { got_SIGHUP = false; @@ -353,11 +364,10 @@ SysLoggerMain(int argc, char *argv[]) } } - if (!rotation_requested && Log_RotationAge > 0 && !rotation_disabled) + if (Log_RotationAge > 0 && !rotation_disabled) { /* Do a logfile rotation if it's time */ - pg_time_t now = (pg_time_t) time(NULL); - + now = (pg_time_t) time(NULL); if (now >= next_rotation_time) rotation_requested = time_based_rotation = true; } @@ -389,28 +399,40 @@ SysLoggerMain(int argc, char *argv[]) logfile_rotate(time_based_rotation, size_rotation_for); } -#ifndef WIN32 - /* - * Wait for some data, timing out after 1 second + * Calculate time till next time-based rotation, so that we don't + * sleep longer than that. We assume the value of "now" obtained + * above is still close enough. Note we can't make this calculation + * until after calling logfile_rotate(), since it will advance + * next_rotation_time. */ - FD_ZERO(&rfds); - FD_SET(syslogPipe[0], &rfds); - - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout); - - if (rc < 0) + if (Log_RotationAge > 0 && !rotation_disabled) { - if (errno != EINTR) - ereport(LOG, - (errcode_for_socket_access(), - errmsg("select() failed in logger process: %m"))); + if (now < next_rotation_time) + cur_timeout = (next_rotation_time - now) * 1000L; /* msec */ + else + cur_timeout = 0; + cur_flags = WL_TIMEOUT; } - else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds)) + else { + cur_timeout = -1L; + cur_flags = 0; + } + + /* + * Sleep until there's something to do + */ +#ifndef WIN32 + rc = WaitLatchOrSocket(&sysLoggerLatch, + WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags, + syslogPipe[0], + cur_timeout); + + if (rc & WL_SOCKET_READABLE) + { + int bytesRead; + bytesRead = read(syslogPipe[0], logbuffer + bytes_in_logbuffer, sizeof(logbuffer) - bytes_in_logbuffer); @@ -445,8 +467,8 @@ SysLoggerMain(int argc, char *argv[]) /* * On Windows we leave it to a separate thread to transfer data and - * detect pipe EOF. The main thread just wakes up once a second to - * check for SIGHUP and rotation conditions. + * detect pipe EOF. The main thread just wakes up to handle SIGHUP + * and rotation conditions. * * Server code isn't generally thread-safe, so we ensure that only one * of the threads is active at a time by entering the critical section @@ -454,7 +476,9 @@ SysLoggerMain(int argc, char *argv[]) */ LeaveCriticalSection(&sysloggerSection); - pg_usleep(1000000L); + (void) WaitLatch(&sysLoggerLatch, + WL_LATCH_SET | cur_flags, + cur_timeout); EnterCriticalSection(&sysloggerSection); #endif /* WIN32 */ @@ -957,7 +981,7 @@ write_syslogger_file(const char *buffer, int count, int destination) /* * Worker thread to transfer data from the pipe to the current logfile. * - * We need this because on Windows, WaitForSingleObject does not work on + * We need this because on Windows, WaitforMultipleObjects does not work on * unnamed pipes: it always reports "signaled", so the blocking ReadFile won't * allow for SIGHUP; and select is for sockets only. */ @@ -1010,6 +1034,9 @@ pipeThread(void *arg) /* if there's any data left then force it out now */ flush_pipe_input(logbuffer, &bytes_in_logbuffer); + /* set the latch to waken the main thread, which will quit */ + SetLatch(&sysLoggerLatch); + LeaveCriticalSection(&sysloggerSection); _endthread(); return 0; @@ -1285,12 +1312,22 @@ set_next_rotation_time(void) static void sigHupHandler(SIGNAL_ARGS) { + int save_errno = errno; + got_SIGHUP = true; + SetLatch(&sysLoggerLatch); + + errno = save_errno; } /* SIGUSR1: set flag to rotate logfile */ static void sigUsr1Handler(SIGNAL_ARGS) { + int save_errno = errno; + rotation_requested = true; + SetLatch(&sysLoggerLatch); + + errno = save_errno; } |