35
35
* worker and dealt with just by having the worker exit normally. The launcher
36
36
* will launch a new worker again later, per schedule.
37
37
*
38
- * When the worker is done vacuuming it sends SIGUSR1 to the launcher. The
38
+ * When the worker is done vacuuming it sends SIGUSR2 to the launcher. The
39
39
* launcher then wakes up and is able to launch another worker, if the schedule
40
40
* is so tight that a new worker is needed immediately. At this time the
41
41
* launcher can also balance the settings for the various remaining workers'
55
55
*
56
56
*
57
57
* IDENTIFICATION
58
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.103 2009/08/27 17:18:44 alvherre Exp $
58
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.104 2009/08/31 19:40:59 tgl Exp $
59
59
*
60
60
*-------------------------------------------------------------------------
61
61
*/
67
67
#include <time.h>
68
68
#include <unistd.h>
69
69
70
- #include "access/genam.h"
71
70
#include "access/heapam.h"
72
71
#include "access/reloptions.h"
73
72
#include "access/transam.h"
74
73
#include "access/xact.h"
75
74
#include "catalog/dependency.h"
76
- #include "catalog/indexing.h"
77
75
#include "catalog/namespace.h"
78
76
#include "catalog/pg_database.h"
79
77
#include "commands/dbcommands.h"
80
78
#include "commands/vacuum.h"
81
- #include "libpq/hba.h"
82
79
#include "libpq/pqsignal.h"
83
80
#include "miscadmin.h"
84
81
#include "pgstat.h"
85
82
#include "postmaster/autovacuum.h"
86
83
#include "postmaster/fork_process.h"
87
84
#include "postmaster/postmaster.h"
88
85
#include "storage/bufmgr.h"
89
- #include "storage/fd.h"
90
86
#include "storage/ipc.h"
91
87
#include "storage/pmsignal.h"
92
88
#include "storage/proc.h"
93
- #include "storage/procarray.h"
94
89
#include "storage/procsignal.h"
95
90
#include "storage/sinvaladt.h"
96
91
#include "tcop/tcopprot.h"
97
- #include "utils/dynahash.h"
98
- #include "utils/flatfiles.h"
99
92
#include "utils/fmgroids.h"
100
93
#include "utils/lsyscache.h"
101
94
#include "utils/memutils.h"
102
95
#include "utils/ps_status.h"
96
+ #include "utils/snapmgr.h"
103
97
#include "utils/syscache.h"
104
98
#include "utils/tqual.h"
105
99
@@ -133,7 +127,7 @@ static bool am_autovacuum_worker = false;
133
127
134
128
/* Flags set by signal handlers */
135
129
static volatile sig_atomic_t got_SIGHUP = false;
136
- static volatile sig_atomic_t got_SIGUSR1 = false;
130
+ static volatile sig_atomic_t got_SIGUSR2 = false;
137
131
static volatile sig_atomic_t got_SIGTERM = false;
138
132
139
133
/* Comparison point for determining whether freeze_max_age is exceeded */
@@ -303,9 +297,8 @@ static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
303
297
PgStat_StatDBEntry * dbentry );
304
298
static void autovac_report_activity (autovac_table * tab );
305
299
static void avl_sighup_handler (SIGNAL_ARGS );
306
- static void avl_sigusr1_handler (SIGNAL_ARGS );
300
+ static void avl_sigusr2_handler (SIGNAL_ARGS );
307
301
static void avl_sigterm_handler (SIGNAL_ARGS );
308
- static void avl_quickdie (SIGNAL_ARGS );
309
302
static void autovac_refresh_stats (void );
310
303
311
304
@@ -407,6 +400,9 @@ AutoVacLauncherMain(int argc, char *argv[])
407
400
/* Identify myself via ps */
408
401
init_ps_display ("autovacuum launcher process" , "" , "" , "" );
409
402
403
+ ereport (LOG ,
404
+ (errmsg ("autovacuum launcher started" )));
405
+
410
406
if (PostAuthDelay )
411
407
pg_usleep (PostAuthDelay * 1000000L );
412
408
@@ -424,20 +420,20 @@ AutoVacLauncherMain(int argc, char *argv[])
424
420
#endif
425
421
426
422
/*
427
- * Set up signal handlers. Since this is an auxiliary process, it has
428
- * particular signal requirements -- no deadlock checker or sinval
429
- * catchup, for example .
423
+ * Set up signal handlers. We operate on databases much like a regular
424
+ * backend, so we use the same signal handling. See equivalent code in
425
+ * tcop/postgres.c .
430
426
*/
431
427
pqsignal (SIGHUP , avl_sighup_handler );
432
-
433
- pqsignal (SIGINT , SIG_IGN );
428
+ pqsignal (SIGINT , StatementCancelHandler );
434
429
pqsignal (SIGTERM , avl_sigterm_handler );
435
- pqsignal (SIGQUIT , avl_quickdie );
436
- pqsignal (SIGALRM , SIG_IGN );
430
+
431
+ pqsignal (SIGQUIT , quickdie );
432
+ pqsignal (SIGALRM , handle_sig_alarm );
437
433
438
434
pqsignal (SIGPIPE , SIG_IGN );
439
- pqsignal (SIGUSR1 , avl_sigusr1_handler );
440
- pqsignal (SIGUSR2 , SIG_IGN );
435
+ pqsignal (SIGUSR1 , procsignal_sigusr1_handler );
436
+ pqsignal (SIGUSR2 , avl_sigusr2_handler );
441
437
pqsignal (SIGFPE , FloatExceptionHandler );
442
438
pqsignal (SIGCHLD , SIG_DFL );
443
439
@@ -451,9 +447,13 @@ AutoVacLauncherMain(int argc, char *argv[])
451
447
* had to do some stuff with LWLocks).
452
448
*/
453
449
#ifndef EXEC_BACKEND
454
- InitAuxiliaryProcess ();
450
+ InitProcess ();
455
451
#endif
456
452
453
+ InitPostgres (NULL , InvalidOid , NULL , NULL );
454
+
455
+ SetProcessingMode (NormalProcessing );
456
+
457
457
/*
458
458
* Create a memory context that we will do all our work in. We do this so
459
459
* that we can reset the context during error recovery and thereby avoid
@@ -466,11 +466,10 @@ AutoVacLauncherMain(int argc, char *argv[])
466
466
ALLOCSET_DEFAULT_MAXSIZE );
467
467
MemoryContextSwitchTo (AutovacMemCxt );
468
468
469
-
470
469
/*
471
470
* If an exception is encountered, processing resumes here.
472
471
*
473
- * This code is heavily based on bgwriter.c, q.v .
472
+ * This code is a stripped down version of PostgresMain error recovery .
474
473
*/
475
474
if (sigsetjmp (local_sigjmp_buf , 1 ) != 0 )
476
475
{
@@ -480,17 +479,16 @@ AutoVacLauncherMain(int argc, char *argv[])
480
479
/* Prevents interrupts while cleaning up */
481
480
HOLD_INTERRUPTS ();
482
481
482
+ /* Forget any pending QueryCancel request */
483
+ QueryCancelPending = false;
484
+ disable_sig_alarm (true);
485
+ QueryCancelPending = false; /* again in case timeout occurred */
486
+
483
487
/* Report the error to the server log */
484
488
EmitErrorReport ();
485
489
486
- /*
487
- * These operations are really just a minimal subset of
488
- * AbortTransaction(). We don't have very many resources to worry
489
- * about, but we do have LWLocks.
490
- */
491
- LWLockReleaseAll ();
492
- AtEOXact_Files ();
493
- AtEOXact_HashTables (false);
490
+ /* Abort the current transaction in order to recover */
491
+ AbortCurrentTransaction ();
494
492
495
493
/*
496
494
* Now return to normal top-level context and clear ErrorContext for
@@ -525,9 +523,6 @@ AutoVacLauncherMain(int argc, char *argv[])
525
523
/* We can now handle ereport(ERROR) */
526
524
PG_exception_stack = & local_sigjmp_buf ;
527
525
528
- ereport (LOG ,
529
- (errmsg ("autovacuum launcher started" )));
530
-
531
526
/* must unblock signals before calling rebuild_database_list */
532
527
PG_SETMASK (& UnBlockSig );
533
528
@@ -561,11 +556,14 @@ AutoVacLauncherMain(int argc, char *argv[])
561
556
* necessity for manual cleanup of all postmaster children.
562
557
*/
563
558
if (!PostmasterIsAlive (true))
564
- exit (1 );
559
+ proc_exit (1 );
565
560
566
561
launcher_determine_sleep ((AutoVacuumShmem -> av_freeWorkers != NULL ),
567
562
false, & nap );
568
563
564
+ /* Allow sinval catchup interrupts while sleeping */
565
+ EnableCatchupInterrupt ();
566
+
569
567
/*
570
568
* Sleep for a while according to schedule.
571
569
*
@@ -595,12 +593,14 @@ AutoVacLauncherMain(int argc, char *argv[])
595
593
* necessity for manual cleanup of all postmaster children.
596
594
*/
597
595
if (!PostmasterIsAlive (true))
598
- exit (1 );
596
+ proc_exit (1 );
599
597
600
- if (got_SIGTERM || got_SIGHUP || got_SIGUSR1 )
598
+ if (got_SIGTERM || got_SIGHUP || got_SIGUSR2 )
601
599
break ;
602
600
}
603
601
602
+ DisableCatchupInterrupt ();
603
+
604
604
/* the normal shutdown case */
605
605
if (got_SIGTERM )
606
606
break ;
@@ -610,7 +610,7 @@ AutoVacLauncherMain(int argc, char *argv[])
610
610
got_SIGHUP = false;
611
611
ProcessConfigFile (PGC_SIGHUP );
612
612
613
- /* shutdown requested in config file */
613
+ /* shutdown requested in config file? */
614
614
if (!AutoVacuumingActive ())
615
615
break ;
616
616
@@ -627,9 +627,9 @@ AutoVacLauncherMain(int argc, char *argv[])
627
627
* a worker finished, or postmaster signalled failure to start a
628
628
* worker
629
629
*/
630
- if (got_SIGUSR1 )
630
+ if (got_SIGUSR2 )
631
631
{
632
- got_SIGUSR1 = false;
632
+ got_SIGUSR2 = false;
633
633
634
634
/* rebalance cost limits, if needed */
635
635
if (AutoVacuumShmem -> av_signal [AutoVacRebalance ])
@@ -1306,7 +1306,7 @@ launch_worker(TimestampTz now)
1306
1306
1307
1307
/*
1308
1308
* Called from postmaster to signal a failure to fork a process to become
1309
- * worker. The postmaster should kill(SIGUSR1 ) the launcher shortly
1309
+ * worker. The postmaster should kill(SIGUSR2 ) the launcher shortly
1310
1310
* after calling this function.
1311
1311
*/
1312
1312
void
@@ -1322,11 +1322,11 @@ avl_sighup_handler(SIGNAL_ARGS)
1322
1322
got_SIGHUP = true;
1323
1323
}
1324
1324
1325
- /* SIGUSR1 : a worker is up and running, or just finished, or failed to fork */
1325
+ /* SIGUSR2 : a worker is up and running, or just finished, or failed to fork */
1326
1326
static void
1327
- avl_sigusr1_handler (SIGNAL_ARGS )
1327
+ avl_sigusr2_handler (SIGNAL_ARGS )
1328
1328
{
1329
- got_SIGUSR1 = true;
1329
+ got_SIGUSR2 = true;
1330
1330
}
1331
1331
1332
1332
/* SIGTERM: time to die */
@@ -1336,38 +1336,6 @@ avl_sigterm_handler(SIGNAL_ARGS)
1336
1336
got_SIGTERM = true;
1337
1337
}
1338
1338
1339
- /*
1340
- * avl_quickdie occurs when signalled SIGQUIT from postmaster.
1341
- *
1342
- * Some backend has bought the farm, so we need to stop what we're doing
1343
- * and exit.
1344
- */
1345
- static void
1346
- avl_quickdie (SIGNAL_ARGS )
1347
- {
1348
- PG_SETMASK (& BlockSig );
1349
-
1350
- /*
1351
- * We DO NOT want to run proc_exit() callbacks -- we're here because
1352
- * shared memory may be corrupted, so we don't want to try to clean up our
1353
- * transaction. Just nail the windows shut and get out of town. Now that
1354
- * there's an atexit callback to prevent third-party code from breaking
1355
- * things by calling exit() directly, we have to reset the callbacks
1356
- * explicitly to make this work as intended.
1357
- */
1358
- on_exit_reset ();
1359
-
1360
- /*
1361
- * Note we do exit(2) not exit(0). This is to force the postmaster into a
1362
- * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
1363
- * backend. This is necessary precisely because we don't clean up our
1364
- * shared memory state. (The "dead man switch" mechanism in pmsignal.c
1365
- * should ensure the postmaster sees this as a crash, too, but no harm in
1366
- * being doubly sure.)
1367
- */
1368
- exit (2 );
1369
- }
1370
-
1371
1339
1372
1340
/********************************************************************
1373
1341
* AUTOVACUUM WORKER CODE
@@ -1590,7 +1558,7 @@ AutoVacWorkerMain(int argc, char *argv[])
1590
1558
1591
1559
/* wake up the launcher */
1592
1560
if (AutoVacuumShmem -> av_launcherpid != 0 )
1593
- kill (AutoVacuumShmem -> av_launcherpid , SIGUSR1 );
1561
+ kill (AutoVacuumShmem -> av_launcherpid , SIGUSR2 );
1594
1562
}
1595
1563
else
1596
1564
{
@@ -1784,46 +1752,57 @@ autovac_balance_cost(void)
1784
1752
1785
1753
/*
1786
1754
* get_database_list
1755
+ * Return a list of all databases found in pg_database.
1787
1756
*
1788
- * Return a list of all databases. Note we cannot use pg_database,
1789
- * because we aren't connected; we use the flat database file.
1757
+ * Note: this is the only function in which the autovacuum launcher uses a
1758
+ * transaction. Although we aren't attached to any particular database and
1759
+ * therefore can't access most catalogs, we do have enough infrastructure
1760
+ * to do a seqscan on pg_database.
1790
1761
*/
1791
1762
static List *
1792
1763
get_database_list (void )
1793
1764
{
1794
- char * filename ;
1795
1765
List * dblist = NIL ;
1796
- char thisname [NAMEDATALEN ];
1797
- FILE * db_file ;
1798
- Oid db_id ;
1799
- Oid db_tablespace ;
1800
- TransactionId db_frozenxid ;
1801
-
1802
- filename = database_getflatfilename ();
1803
- db_file = AllocateFile (filename , "r" );
1804
- if (db_file == NULL )
1805
- ereport (FATAL ,
1806
- (errcode_for_file_access (),
1807
- errmsg ("could not open file \"%s\": %m" , filename )));
1766
+ Relation rel ;
1767
+ HeapScanDesc scan ;
1768
+ HeapTuple tup ;
1769
+
1770
+ /*
1771
+ * Start a transaction so we can access pg_database, and get a snapshot.
1772
+ * We don't have a use for the snapshot itself, but we're interested in
1773
+ * the secondary effect that it sets RecentGlobalXmin. (This is critical
1774
+ * for anything that reads heap pages, because HOT may decide to prune
1775
+ * them even if the process doesn't attempt to modify any tuples.)
1776
+ */
1777
+ StartTransactionCommand ();
1778
+ (void ) GetTransactionSnapshot ();
1779
+
1780
+ /* Allocate our results in AutovacMemCxt, not transaction context */
1781
+ MemoryContextSwitchTo (AutovacMemCxt );
1808
1782
1809
- while (read_pg_database_line (db_file , thisname , & db_id ,
1810
- & db_tablespace , & db_frozenxid ))
1783
+ rel = heap_open (DatabaseRelationId , AccessShareLock );
1784
+ scan = heap_beginscan (rel , SnapshotNow , 0 , NULL );
1785
+
1786
+ while (HeapTupleIsValid (tup = heap_getnext (scan , ForwardScanDirection )))
1811
1787
{
1812
- avw_dbase * avdb ;
1788
+ Form_pg_database pgdatabase = (Form_pg_database ) GETSTRUCT (tup );
1789
+ avw_dbase * avdb ;
1813
1790
1814
1791
avdb = (avw_dbase * ) palloc (sizeof (avw_dbase ));
1815
1792
1816
- avdb -> adw_datid = db_id ;
1817
- avdb -> adw_name = pstrdup (thisname );
1818
- avdb -> adw_frozenxid = db_frozenxid ;
1793
+ avdb -> adw_datid = HeapTupleGetOid ( tup ) ;
1794
+ avdb -> adw_name = pstrdup (NameStr ( pgdatabase -> datname ) );
1795
+ avdb -> adw_frozenxid = pgdatabase -> datfrozenxid ;
1819
1796
/* this gets set later: */
1820
1797
avdb -> adw_entry = NULL ;
1821
1798
1822
1799
dblist = lappend (dblist , avdb );
1823
1800
}
1824
1801
1825
- FreeFile (db_file );
1826
- pfree (filename );
1802
+ heap_endscan (scan );
1803
+ heap_close (rel , AccessShareLock );
1804
+
1805
+ CommitTransactionCommand ();
1827
1806
1828
1807
return dblist ;
1829
1808
}
0 commit comments