|
9 | 9 | * in postgresql.conf. If these limits are reached or passed, the
|
10 | 10 | * current logfile is closed and a new one is created (rotated).
|
11 | 11 | * The logfiles are stored in a subdirectory (configurable in
|
12 |
| - * postgresql.conf), using an internal naming scheme that mangles |
13 |
| - * creation time and current postmaster pid. |
| 12 | + * postgresql.conf), using a user-selectable naming scheme. |
14 | 13 | *
|
15 | 14 | * Author: Andreas Pflug <pgadmin@pse-consulting.de>
|
16 | 15 | *
|
|
40 | 39 | #include "postmaster/postmaster.h"
|
41 | 40 | #include "postmaster/syslogger.h"
|
42 | 41 | #include "storage/ipc.h"
|
| 42 | +#include "storage/latch.h" |
43 | 43 | #include "storage/pg_shmem.h"
|
44 | 44 | #include "utils/guc.h"
|
45 | 45 | #include "utils/ps_status.h"
|
@@ -93,6 +93,7 @@ static FILE *syslogFile = NULL;
|
93 | 93 | static FILE *csvlogFile = NULL;
|
94 | 94 | static char *last_file_name = NULL;
|
95 | 95 | static char *last_csv_file_name = NULL;
|
| 96 | +static Latch sysLoggerLatch; |
96 | 97 |
|
97 | 98 | /*
|
98 | 99 | * Buffers for saving partial messages from different backends.
|
@@ -168,12 +169,14 @@ SysLoggerMain(int argc, char *argv[])
|
168 | 169 | char *currentLogDir;
|
169 | 170 | char *currentLogFilename;
|
170 | 171 | int currentLogRotationAge;
|
| 172 | + pg_time_t now; |
171 | 173 |
|
172 | 174 | IsUnderPostmaster = true; /* we are a postmaster subprocess now */
|
173 | 175 |
|
174 | 176 | MyProcPid = getpid(); /* reset MyProcPid */
|
175 | 177 |
|
176 | 178 | MyStartTime = time(NULL); /* set our start time in case we call elog */
|
| 179 | + now = MyStartTime; |
177 | 180 |
|
178 | 181 | #ifdef EXEC_BACKEND
|
179 | 182 | syslogger_parseArgs(argc, argv);
|
@@ -246,6 +249,9 @@ SysLoggerMain(int argc, char *argv[])
|
246 | 249 | elog(FATAL, "setsid() failed: %m");
|
247 | 250 | #endif
|
248 | 251 |
|
| 252 | + /* Initialize private latch for use by signal handlers */ |
| 253 | + InitLatch(&sysLoggerLatch); |
| 254 | + |
249 | 255 | /*
|
250 | 256 | * Properly accept or ignore signals the postmaster might send us
|
251 | 257 | *
|
@@ -296,14 +302,19 @@ SysLoggerMain(int argc, char *argv[])
|
296 | 302 | {
|
297 | 303 | bool time_based_rotation = false;
|
298 | 304 | int size_rotation_for = 0;
|
| 305 | + long cur_timeout; |
| 306 | + int cur_flags; |
299 | 307 |
|
300 | 308 | #ifndef WIN32
|
301 |
| - int bytesRead; |
302 | 309 | int rc;
|
303 |
| - fd_set rfds; |
304 |
| - struct timeval timeout; |
305 | 310 | #endif
|
306 | 311 |
|
| 312 | + /* Clear any already-pending wakeups */ |
| 313 | + ResetLatch(&sysLoggerLatch); |
| 314 | + |
| 315 | + /* |
| 316 | + * Process any requests or signals received recently. |
| 317 | + */ |
307 | 318 | if (got_SIGHUP)
|
308 | 319 | {
|
309 | 320 | got_SIGHUP = false;
|
@@ -353,11 +364,10 @@ SysLoggerMain(int argc, char *argv[])
|
353 | 364 | }
|
354 | 365 | }
|
355 | 366 |
|
356 |
| - if (!rotation_requested && Log_RotationAge > 0 && !rotation_disabled) |
| 367 | + if (Log_RotationAge > 0 && !rotation_disabled) |
357 | 368 | {
|
358 | 369 | /* Do a logfile rotation if it's time */
|
359 |
| - pg_time_t now = (pg_time_t) time(NULL); |
360 |
| - |
| 370 | + now = (pg_time_t) time(NULL); |
361 | 371 | if (now >= next_rotation_time)
|
362 | 372 | rotation_requested = time_based_rotation = true;
|
363 | 373 | }
|
@@ -389,28 +399,40 @@ SysLoggerMain(int argc, char *argv[])
|
389 | 399 | logfile_rotate(time_based_rotation, size_rotation_for);
|
390 | 400 | }
|
391 | 401 |
|
392 |
| -#ifndef WIN32 |
393 |
| - |
394 | 402 | /*
|
395 |
| - * Wait for some data, timing out after 1 second |
| 403 | + * Calculate time till next time-based rotation, so that we don't |
| 404 | + * sleep longer than that. We assume the value of "now" obtained |
| 405 | + * above is still close enough. Note we can't make this calculation |
| 406 | + * until after calling logfile_rotate(), since it will advance |
| 407 | + * next_rotation_time. |
396 | 408 | */
|
397 |
| - FD_ZERO(&rfds); |
398 |
| - FD_SET(syslogPipe[0], &rfds); |
399 |
| - |
400 |
| - timeout.tv_sec = 1; |
401 |
| - timeout.tv_usec = 0; |
402 |
| - |
403 |
| - rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout); |
404 |
| - |
405 |
| - if (rc < 0) |
| 409 | + if (Log_RotationAge > 0 && !rotation_disabled) |
406 | 410 | {
|
407 |
| - if (errno != EINTR) |
408 |
| - ereport(LOG, |
409 |
| - (errcode_for_socket_access(), |
410 |
| - errmsg("select() failed in logger process: %m"))); |
| 411 | + if (now < next_rotation_time) |
| 412 | + cur_timeout = (next_rotation_time - now) * 1000L; /* msec */ |
| 413 | + else |
| 414 | + cur_timeout = 0; |
| 415 | + cur_flags = WL_TIMEOUT; |
411 | 416 | }
|
412 |
| - else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds)) |
| 417 | + else |
413 | 418 | {
|
| 419 | + cur_timeout = -1L; |
| 420 | + cur_flags = 0; |
| 421 | + } |
| 422 | + |
| 423 | + /* |
| 424 | + * Sleep until there's something to do |
| 425 | + */ |
| 426 | +#ifndef WIN32 |
| 427 | + rc = WaitLatchOrSocket(&sysLoggerLatch, |
| 428 | + WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags, |
| 429 | + syslogPipe[0], |
| 430 | + cur_timeout); |
| 431 | + |
| 432 | + if (rc & WL_SOCKET_READABLE) |
| 433 | + { |
| 434 | + int bytesRead; |
| 435 | + |
414 | 436 | bytesRead = read(syslogPipe[0],
|
415 | 437 | logbuffer + bytes_in_logbuffer,
|
416 | 438 | sizeof(logbuffer) - bytes_in_logbuffer);
|
@@ -445,16 +467,18 @@ SysLoggerMain(int argc, char *argv[])
|
445 | 467 |
|
446 | 468 | /*
|
447 | 469 | * On Windows we leave it to a separate thread to transfer data and
|
448 |
| - * detect pipe EOF. The main thread just wakes up once a second to |
449 |
| - * check for SIGHUP and rotation conditions. |
| 470 | + * detect pipe EOF. The main thread just wakes up to handle SIGHUP |
| 471 | + * and rotation conditions. |
450 | 472 | *
|
451 | 473 | * Server code isn't generally thread-safe, so we ensure that only one
|
452 | 474 | * of the threads is active at a time by entering the critical section
|
453 | 475 | * whenever we're not sleeping.
|
454 | 476 | */
|
455 | 477 | LeaveCriticalSection(&sysloggerSection);
|
456 | 478 |
|
457 |
| - pg_usleep(1000000L); |
| 479 | + (void) WaitLatch(&sysLoggerLatch, |
| 480 | + WL_LATCH_SET | cur_flags, |
| 481 | + cur_timeout); |
458 | 482 |
|
459 | 483 | EnterCriticalSection(&sysloggerSection);
|
460 | 484 | #endif /* WIN32 */
|
@@ -957,7 +981,7 @@ write_syslogger_file(const char *buffer, int count, int destination)
|
957 | 981 | /*
|
958 | 982 | * Worker thread to transfer data from the pipe to the current logfile.
|
959 | 983 | *
|
960 |
| - * We need this because on Windows, WaitForSingleObject does not work on |
| 984 | + * We need this because on Windows, WaitforMultipleObjects does not work on |
961 | 985 | * unnamed pipes: it always reports "signaled", so the blocking ReadFile won't
|
962 | 986 | * allow for SIGHUP; and select is for sockets only.
|
963 | 987 | */
|
@@ -1010,6 +1034,9 @@ pipeThread(void *arg)
|
1010 | 1034 | /* if there's any data left then force it out now */
|
1011 | 1035 | flush_pipe_input(logbuffer, &bytes_in_logbuffer);
|
1012 | 1036 |
|
| 1037 | + /* set the latch to waken the main thread, which will quit */ |
| 1038 | + SetLatch(&sysLoggerLatch); |
| 1039 | + |
1013 | 1040 | LeaveCriticalSection(&sysloggerSection);
|
1014 | 1041 | _endthread();
|
1015 | 1042 | return 0;
|
@@ -1285,12 +1312,22 @@ set_next_rotation_time(void)
|
1285 | 1312 | static void
|
1286 | 1313 | sigHupHandler(SIGNAL_ARGS)
|
1287 | 1314 | {
|
| 1315 | + int save_errno = errno; |
| 1316 | + |
1288 | 1317 | got_SIGHUP = true;
|
| 1318 | + SetLatch(&sysLoggerLatch); |
| 1319 | + |
| 1320 | + errno = save_errno; |
1289 | 1321 | }
|
1290 | 1322 |
|
1291 | 1323 | /* SIGUSR1: set flag to rotate logfile */
|
1292 | 1324 | static void
|
1293 | 1325 | sigUsr1Handler(SIGNAL_ARGS)
|
1294 | 1326 | {
|
| 1327 | + int save_errno = errno; |
| 1328 | + |
1295 | 1329 | rotation_requested = true;
|
| 1330 | + SetLatch(&sysLoggerLatch); |
| 1331 | + |
| 1332 | + errno = save_errno; |
1296 | 1333 | }
|
0 commit comments