|
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 | }
|