|
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 | staticFILE*csvlogFile=NULL; |
94 | 94 | staticchar*last_file_name=NULL; |
95 | 95 | staticchar*last_csv_file_name=NULL; |
| 96 | +staticLatchsysLoggerLatch; |
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 | intcurrentLogRotationAge; |
| 172 | +pg_time_tnow; |
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 | #ifdefEXEC_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 | booltime_based_rotation= false; |
298 | 304 | intsize_rotation_for=0; |
| 305 | +longcur_timeout; |
| 306 | +intcur_flags; |
299 | 307 |
|
300 | 308 | #ifndefWIN32 |
301 | | -intbytesRead; |
302 | 309 | intrc; |
303 | | -fd_setrfds; |
304 | | -structtimevaltimeout; |
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_tnow= (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 | | -#ifndefWIN32 |
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 | | -elseif (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 | +#ifndefWIN32 |
| 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 | +intbytesRead; |
| 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 uponce a second to |
449 | | - *check for SIGHUPand rotation conditions. |
| 470 | + * detect pipe EOF. The main thread just wakes upto 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 | return0; |
@@ -1285,12 +1312,22 @@ set_next_rotation_time(void) |
1285 | 1312 | staticvoid |
1286 | 1313 | sigHupHandler(SIGNAL_ARGS) |
1287 | 1314 | { |
| 1315 | +intsave_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 | staticvoid |
1293 | 1325 | sigUsr1Handler(SIGNAL_ARGS) |
1294 | 1326 | { |
| 1327 | +intsave_errno=errno; |
| 1328 | + |
1295 | 1329 | rotation_requested= true; |
| 1330 | +SetLatch(&sysLoggerLatch); |
| 1331 | + |
| 1332 | +errno=save_errno; |
1296 | 1333 | } |