|
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