autovacuum.c 37.5 KB
Newer Older
1 2 3 4 5 6 7
/*-------------------------------------------------------------------------
 *
 * autovacuum.c
 *
 * PostgreSQL Integrated Autovacuum Daemon
 *
 *
8
 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
9 10 11 12
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
13
 *	  $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.32 2007/02/15 23:23:23 alvherre Exp $
14 15 16 17 18 19 20
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <signal.h>
#include <sys/types.h>
21
#include <time.h>
22 23 24 25
#include <unistd.h>

#include "access/genam.h"
#include "access/heapam.h"
26 27
#include "access/transam.h"
#include "access/xact.h"
28
#include "catalog/indexing.h"
29
#include "catalog/namespace.h"
30
#include "catalog/pg_autovacuum.h"
31
#include "catalog/pg_database.h"
32 33 34 35 36 37 38 39 40 41
#include "commands/vacuum.h"
#include "libpq/hba.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/fork_process.h"
#include "postmaster/postmaster.h"
#include "storage/fd.h"
#include "storage/ipc.h"
42
#include "storage/pmsignal.h"
43
#include "storage/proc.h"
44
#include "storage/procarray.h"
45 46 47 48
#include "storage/sinval.h"
#include "tcop/tcopprot.h"
#include "utils/flatfiles.h"
#include "utils/fmgroids.h"
49
#include "utils/lsyscache.h"
50 51
#include "utils/memutils.h"
#include "utils/ps_status.h"
52
#include "utils/syscache.h"
53 54


55 56 57
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t avlauncher_shutdown_request = false;

58 59 60 61 62 63 64 65 66
/*
 * GUC parameters
 */
bool		autovacuum_start_daemon = false;
int			autovacuum_naptime;
int			autovacuum_vac_thresh;
double		autovacuum_vac_scale;
int			autovacuum_anl_thresh;
double		autovacuum_anl_scale;
67
int			autovacuum_freeze_max_age;
68

69 70 71
int			autovacuum_vac_cost_delay;
int			autovacuum_vac_cost_limit;

72
/* Flag to tell if we are in the autovacuum daemon process */
73 74
static bool am_autovacuum_launcher = false;
static bool am_autovacuum_worker = false;
75

76 77 78 79 80 81
/* Comparison point for determining whether freeze_max_age is exceeded */
static TransactionId recentXid;

/* Default freeze_min_age to use for autovacuum (varies by database) */
static int	default_freeze_min_age;

82
/* Memory context for long-lived data */
B
Bruce Momjian 已提交
83
static MemoryContext AutovacMemCxt;
84

85 86 87
/* struct to keep list of candidate databases for vacuum */
typedef struct autovac_dbase
{
B
Bruce Momjian 已提交
88 89
	Oid			oid;
	char	   *name;
90
	TransactionId frozenxid;
91 92 93
	PgStat_StatDBEntry *entry;
} autovac_dbase;

94 95 96 97
/* struct to keep track of tables to vacuum and/or analyze */
typedef struct autovac_table
{
	Oid			relid;
98
	Oid			toastrelid;
99 100
	bool		dovacuum;
	bool		doanalyze;
101
	int			freeze_min_age;
102 103 104 105
	int			vacuum_cost_delay;
	int			vacuum_cost_limit;
} autovac_table;

106 107 108 109 110 111 112
typedef struct
{
	Oid		process_db;			/* OID of database to process */
	int		worker_pid;			/* PID of the worker process, if any */
} AutoVacuumShmemStruct;

static AutoVacuumShmemStruct *AutoVacuumShmem;
113 114

#ifdef EXEC_BACKEND
115 116
static pid_t avlauncher_forkexec(void);
static pid_t avworker_forkexec(void);
117
#endif
118 119 120
NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]);
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]);

121
static void do_autovacuum(PgStat_StatDBEntry *dbentry);
122 123
static List *autovac_get_database_list(void);
static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
B
Bruce Momjian 已提交
124 125 126 127
					 Form_pg_class classForm,
					 Form_pg_autovacuum avForm,
					 List **vacuum_tables,
					 List **toast_table_ids);
128 129 130
static void autovacuum_do_vac_analyze(Oid relid, bool dovacuum,
						  bool doanalyze, int freeze_min_age);
static void autovac_report_activity(VacuumStmt *vacstmt, Oid relid);
131 132 133
static void avl_sighup_handler(SIGNAL_ARGS);
static void avlauncher_shutdown(SIGNAL_ARGS);
static void avl_quickdie(SIGNAL_ARGS);
134 135


136 137 138 139 140 141

/********************************************************************
 *                    AUTOVACUUM LAUNCHER CODE
 ********************************************************************/

#ifdef EXEC_BACKEND
142
/*
143
 * forkexec routine for the autovacuum launcher process.
144
 *
145
 * Format up the arglist, then fork and exec.
146
 */
147 148
static pid_t
avlauncher_forkexec(void)
149
{
150 151
	char	   *av[10];
	int			ac = 0;
152

153 154 155 156
	av[ac++] = "postgres";
	av[ac++] = "--forkavlauncher";
	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
	av[ac] = NULL;
157

158
	Assert(ac < lengthof(av));
159

160 161
	return postmaster_forkexec(ac, av);
}
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
/*
 * We need this set from the outside, before InitProcess is called
 */
void
AutovacuumLauncherIAm(void)
{
	am_autovacuum_launcher = true;
}
#endif

/*
 * Main entry point for autovacuum launcher process, to be called from the
 * postmaster.
 */
int
StartAutoVacLauncher(void)
{
	pid_t		AutoVacPID;
181 182

#ifdef EXEC_BACKEND
183
	switch ((AutoVacPID = avlauncher_forkexec()))
184
#else
B
Bruce Momjian 已提交
185
	switch ((AutoVacPID = fork_process()))
186 187 188 189
#endif
	{
		case -1:
			ereport(LOG,
B
Bruce Momjian 已提交
190
					(errmsg("could not fork autovacuum process: %m")));
191 192 193 194 195 196 197 198
			return 0;

#ifndef EXEC_BACKEND
		case 0:
			/* in postmaster child ... */
			/* Close the postmaster's sockets */
			ClosePostmasterPorts(false);

199 200 201
			/* Lose the postmaster's on-exit routines */
			on_exit_reset();

202
			AutoVacLauncherMain(0, NULL);
203 204 205 206 207 208 209 210 211 212 213
			break;
#endif
		default:
			return (int) AutoVacPID;
	}

	/* shouldn't get here */
	return 0;
}

/*
214
 * Main loop for the autovacuum launcher process.
215
 */
216 217
NON_EXEC_STATIC void
AutoVacLauncherMain(int argc, char *argv[])
218
{
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
	sigjmp_buf	local_sigjmp_buf;
	List	   *dblist;
	bool		for_xid_wrap;
	autovac_dbase *db;
	MemoryContext	avlauncher_cxt;

	/* we are a postmaster subprocess now */
	IsUnderPostmaster = true;
	am_autovacuum_launcher = true;

	/* reset MyProcPid */
	MyProcPid = getpid();

	/* Identify myself via ps */
	init_ps_display("autovacuum launcher process", "", "", "");

	SetProcessingMode(InitProcessing);

	/*
	 * If possible, make this process a group leader, so that the postmaster
	 * can signal any child processes too.  (autovacuum probably never has
	 * any child processes, but for consistency we make all postmaster
	 * child processes do this.)
	 */
#ifdef HAVE_SETSID
	if (setsid() < 0)
		elog(FATAL, "setsid() failed: %m");
#endif

	/*
	 * Set up signal handlers.	Since this is a "dummy" process, it has
	 * particular signal requirements -- no deadlock checker or sinval
	 * catchup, for example.
	 *
	 * XXX It may be a good idea to receive signals when an avworker process
	 * finishes.
	 */
	pqsignal(SIGHUP, avl_sighup_handler);

	pqsignal(SIGINT, SIG_IGN);
	pqsignal(SIGTERM, avlauncher_shutdown);
	pqsignal(SIGQUIT, avl_quickdie);
	pqsignal(SIGALRM, SIG_IGN);

	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, SIG_IGN);
	/* We don't listen for async notifies */
	pqsignal(SIGUSR2, SIG_IGN);
	pqsignal(SIGFPE, FloatExceptionHandler);
	pqsignal(SIGCHLD, SIG_DFL);

	/* Early initialization */
	BaseInit();

	/*
	 * Create a per-backend PGPROC struct in shared memory, except in the
	 * EXEC_BACKEND case where this was done in SubPostmasterMain. We must do
	 * this before we can use LWLocks (and in the EXEC_BACKEND case we already
	 * had to do some stuff with LWLocks).
	 */
#ifndef EXEC_BACKEND
	InitDummyProcess();
#endif

	/*
	 * Create a memory context that we will do all our work in.  We do this so
	 * that we can reset the context during error recovery and thereby avoid
	 * possible memory leaks.
	 */
	avlauncher_cxt = AllocSetContextCreate(TopMemoryContext,
										   "Autovacuum Launcher",
										   ALLOCSET_DEFAULT_MINSIZE,
										   ALLOCSET_DEFAULT_INITSIZE,
										   ALLOCSET_DEFAULT_MAXSIZE);
	MemoryContextSwitchTo(avlauncher_cxt);


	/*
	 * If an exception is encountered, processing resumes here.
	 *
	 * This code is heavily based on bgwriter.c, q.v.
	 */
	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* since not using PG_TRY, must reset error stack by hand */
		error_context_stack = NULL;

		/* Prevents interrupts while cleaning up */
		HOLD_INTERRUPTS();

		/* Report the error to the server log */
		EmitErrorReport();

		/*
		 * These operations are really just a minimal subset of
		 * AbortTransaction().  We don't have very many resources to worry
		 * about, but we do have LWLocks.
		 */
		LWLockReleaseAll();
		AtEOXact_Files();

		/*
		 * Now return to normal top-level context and clear ErrorContext for
		 * next time.
		 */
		MemoryContextSwitchTo(avlauncher_cxt);
		FlushErrorState();

		/* Flush any leaked data in the top-level context */
		MemoryContextResetAndDeleteChildren(avlauncher_cxt);

		/* Make sure pgstat also considers our stat data as gone */
		pgstat_clear_snapshot();

		/* Now we can allow interrupts again */
		RESUME_INTERRUPTS();

		/*
		 * Sleep at least 1 second after any error.  We don't want to be
		 * filling the error logs as fast as we can.
		 */
		pg_usleep(1000000L);
	}

	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	ereport(LOG,
			(errmsg("autovacuum launcher started")));

	PG_SETMASK(&UnBlockSig);

	/*
	 * take a nap before executing the first iteration, unless we were
	 * requested an emergency run.
	 */
	if (autovacuum_start_daemon)
		pg_usleep(autovacuum_naptime * 1000000L); 

	for (;;)
	{
		TransactionId xidForceLimit;
		ListCell *cell;
		int		worker_pid;

		/*
		 * Emergency bailout if postmaster has died.  This is to avoid the
		 * necessity for manual cleanup of all postmaster children.
		 */
		if (!PostmasterIsAlive(true))
			exit(1);

		if (avlauncher_shutdown_request)
			break;

		if (got_SIGHUP)
		{
			got_SIGHUP = false;
			ProcessConfigFile(PGC_SIGHUP);
		}

		/*
		 * if there's a worker already running, sleep until it
		 * disappears.
		 */
		LWLockAcquire(AutovacuumLock, LW_SHARED);
		worker_pid = AutoVacuumShmem->worker_pid;
		LWLockRelease(AutovacuumLock);

		if (worker_pid != 0)
		{
			PGPROC *proc = BackendPidGetProc(worker_pid);

			if (proc != NULL && proc->isAutovacuum)
				goto sleep;
			else
			{
				/*
				 * if the worker is not really running (or it's a process
				 * that's not an autovacuum worker), remove the PID from shmem.
				 * This should not happen, because either the worker exits
				 * cleanly, in which case it'll remove the PID, or it dies, in
				 * which case postmaster will cause a system reset cycle.
				 */
				LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
				worker_pid = 0;
				LWLockRelease(AutovacuumLock);
			}
		}

		/* Get a list of databases */
		dblist = autovac_get_database_list();

		/*
		 * Determine the oldest datfrozenxid/relfrozenxid that we will allow
		 * to pass without forcing a vacuum.  (This limit can be tightened for
		 * particular tables, but not loosened.)
		 */
		recentXid = ReadNewTransactionId();
		xidForceLimit = recentXid - autovacuum_freeze_max_age;
		/* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */
		if (xidForceLimit < FirstNormalTransactionId)
			xidForceLimit -= FirstNormalTransactionId;

		/*
		 * Choose a database to connect to.  We pick the database that was least
		 * recently auto-vacuumed, or one that needs vacuuming to prevent Xid
		 * wraparound-related data loss.  If any db at risk of wraparound is
		 * found, we pick the one with oldest datfrozenxid, independently of
		 * autovacuum times.
		 *
		 * Note that a database with no stats entry is not considered, except for
		 * Xid wraparound purposes.  The theory is that if no one has ever
		 * connected to it since the stats were last initialized, it doesn't need
		 * vacuuming.
		 *
		 * XXX This could be improved if we had more info about whether it needs
		 * vacuuming before connecting to it.  Perhaps look through the pgstats
		 * data for the database's tables?  One idea is to keep track of the
		 * number of new and dead tuples per database in pgstats.  However it
		 * isn't clear how to construct a metric that measures that and not cause
		 * starvation for less busy databases.
		 */
		db = NULL;
		for_xid_wrap = false;
		foreach(cell, dblist)
		{
			autovac_dbase *tmp = lfirst(cell);

			/* Find pgstat entry if any */
			tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);

			/* Check to see if this one is at risk of wraparound */
			if (TransactionIdPrecedes(tmp->frozenxid, xidForceLimit))
			{
				if (db == NULL ||
					TransactionIdPrecedes(tmp->frozenxid, db->frozenxid))
					db = tmp;
				for_xid_wrap = true;
				continue;
			}
			else if (for_xid_wrap)
				continue;			/* ignore not-at-risk DBs */

			/*
			 * Otherwise, skip a database with no pgstat entry; it means it
			 * hasn't seen any activity.
			 */
			if (!tmp->entry)
				continue;

			/*
			 * Remember the db with oldest autovac time.  (If we are here,
			 * both tmp->entry and db->entry must be non-null.)
			 */
			if (db == NULL ||
				tmp->entry->last_autovac_time < db->entry->last_autovac_time)
				db = tmp;
		}

		/* Found a database -- process it */
		if (db != NULL)
		{
			LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
			AutoVacuumShmem->process_db = db->oid;
			LWLockRelease(AutovacuumLock);

			SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER);
		}
		
sleep:
		/*
		 * in emergency mode, exit immediately so that the postmaster can
		 * request another run right away if needed.
		 *
		 * XXX -- maybe it would be better to handle this inside the launcher
		 * itself.
		 */
		if (!autovacuum_start_daemon)
			break;

		/* have pgstat read the file again next time */
		pgstat_clear_snapshot();

		/* now sleep until the next autovac iteration */
		pg_usleep(autovacuum_naptime * 1000000L); 
	}

	/* Normal exit from the autovac launcher is here */
	ereport(LOG,
			(errmsg("autovacuum launcher shutting down")));

	proc_exit(0);		/* done */
}

/* SIGHUP: set flag to re-read config file at next convenient time */
static void
avl_sighup_handler(SIGNAL_ARGS)
{
	got_SIGHUP = true;
519 520
}

521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
static void
avlauncher_shutdown(SIGNAL_ARGS)
{
	avlauncher_shutdown_request = true;
}

/*
 * avl_quickdie occurs when signalled SIGQUIT from postmaster.
 *
 * Some backend has bought the farm, so we need to stop what we're doing
 * and exit.
 */
static void
avl_quickdie(SIGNAL_ARGS)
{
	PG_SETMASK(&BlockSig);

	/*
	 * DO NOT proc_exit() -- we're here because shared memory may be
	 * corrupted, so we don't want to try to clean up our transaction. Just
	 * nail the windows shut and get out of town.
	 *
	 * Note we do exit(2) not exit(0).	This is to force the postmaster into a
	 * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
	 * backend.  This is necessary precisely because we don't clean up our
	 * shared memory state.
	 */
	exit(2);
}


/********************************************************************
 *                    AUTOVACUUM WORKER CODE
 ********************************************************************/

556 557
#ifdef EXEC_BACKEND
/*
558
 * forkexec routines for the autovacuum worker.
559
 *
560
 * Format up the arglist, then fork and exec.
561 562
 */
static pid_t
563
avworker_forkexec(void)
564 565 566 567 568
{
	char	   *av[10];
	int			ac = 0;

	av[ac++] = "postgres";
569
	av[ac++] = "--forkavworker";
B
Bruce Momjian 已提交
570
	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
571 572 573 574 575 576
	av[ac] = NULL;

	Assert(ac < lengthof(av));

	return postmaster_forkexec(ac, av);
}
577 578 579 580 581

/*
 * We need this set from the outside, before InitProcess is called
 */
void
582 583 584 585 586 587 588 589 590 591 592 593 594
AutovacuumWorkerIAm(void)
{
	am_autovacuum_worker = true;
}
#endif

/*
 * Main entry point for autovacuum worker process.
 *
 * This code is heavily based on pgarch.c, q.v.
 */
int
StartAutoVacWorker(void)
595
{
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
	pid_t		worker_pid;

#ifdef EXEC_BACKEND
	switch ((worker_pid = avworker_forkexec()))
#else
	switch ((worker_pid = fork_process()))
#endif
	{
		case -1:
			ereport(LOG,
					(errmsg("could not fork autovacuum process: %m")));
			return 0;

#ifndef EXEC_BACKEND
		case 0:
			/* in postmaster child ... */
			/* Close the postmaster's sockets */
			ClosePostmasterPorts(false);

			/* Lose the postmaster's on-exit routines */
			on_exit_reset();

			AutoVacWorkerMain(0, NULL);
			break;
#endif
		default:
			return (int) worker_pid;
	}

	/* shouldn't get here */
	return 0;
627
}
628 629

/*
630
 * AutoVacWorkerMain
631 632
 */
NON_EXEC_STATIC void
633
AutoVacWorkerMain(int argc, char *argv[])
634
{
B
Bruce Momjian 已提交
635
	sigjmp_buf	local_sigjmp_buf;
636
	Oid			dbid;
637 638 639

	/* we are a postmaster subprocess now */
	IsUnderPostmaster = true;
640
	am_autovacuum_worker = true;
641 642 643 644

	/* reset MyProcPid */
	MyProcPid = getpid();

645
	/* Identify myself via ps */
646
	init_ps_display("autovacuum worker process", "", "", "");
647 648 649

	SetProcessingMode(InitProcessing);

650 651 652 653 654 655 656 657 658 659 660
	/*
	 * If possible, make this process a group leader, so that the postmaster
	 * can signal any child processes too.  (autovacuum probably never has
	 * any child processes, but for consistency we make all postmaster
	 * child processes do this.)
	 */
#ifdef HAVE_SETSID
	if (setsid() < 0)
		elog(FATAL, "setsid() failed: %m");
#endif

661
	/*
B
Bruce Momjian 已提交
662 663 664
	 * Set up signal handlers.	We operate on databases much like a regular
	 * backend, so we use the same signal handling.  See equivalent code in
	 * tcop/postgres.c.
665
	 *
666 667
	 * Currently, we don't pay attention to postgresql.conf changes that
	 * happen during a single daemon iteration, so we can ignore SIGHUP.
668 669
	 */
	pqsignal(SIGHUP, SIG_IGN);
B
Bruce Momjian 已提交
670

671
	/*
B
Bruce Momjian 已提交
672 673
	 * Presently, SIGINT will lead to autovacuum shutdown, because that's how
	 * we handle ereport(ERROR).  It could be improved however.
674 675 676 677 678 679 680 681 682 683
	 */
	pqsignal(SIGINT, StatementCancelHandler);
	pqsignal(SIGTERM, die);
	pqsignal(SIGQUIT, quickdie);
	pqsignal(SIGALRM, handle_sig_alarm);

	pqsignal(SIGPIPE, SIG_IGN);
	pqsignal(SIGUSR1, CatchupInterruptHandler);
	/* We don't listen for async notifies */
	pqsignal(SIGUSR2, SIG_IGN);
684
	pqsignal(SIGFPE, FloatExceptionHandler);
685 686 687 688 689
	pqsignal(SIGCHLD, SIG_DFL);

	/* Early initialization */
	BaseInit();

690
	/*
B
Bruce Momjian 已提交
691 692 693 694
	 * Create a per-backend PGPROC struct in shared memory, except in the
	 * EXEC_BACKEND case where this was done in SubPostmasterMain. We must do
	 * this before we can use LWLocks (and in the EXEC_BACKEND case we already
	 * had to do some stuff with LWLocks).
695 696 697 698 699
	 */
#ifndef EXEC_BACKEND
	InitProcess();
#endif

700 701 702 703 704 705 706 707 708 709 710 711 712 713
	/*
	 * If an exception is encountered, processing resumes here.
	 *
	 * See notes in postgres.c about the design of this coding.
	 */
	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
	{
		/* Prevents interrupts while cleaning up */
		HOLD_INTERRUPTS();

		/* Report the error to the server log */
		EmitErrorReport();

		/*
714 715
		 * We can now go away.	Note that because we called InitProcess, a
		 * callback was registered to do ProcKill, which will clean up
B
Bruce Momjian 已提交
716
		 * necessary state.
717 718 719 720 721 722 723 724 725
		 */
		proc_exit(0);
	}

	/* We can now handle ereport(ERROR) */
	PG_exception_stack = &local_sigjmp_buf;

	PG_SETMASK(&UnBlockSig);

726
	/*
B
Bruce Momjian 已提交
727 728 729
	 * Force zero_damaged_pages OFF in the autovac process, even if it is set
	 * in postgresql.conf.	We don't really want such a dangerous option being
	 * applied non-interactively.
730 731 732
	 */
	SetConfigOption("zero_damaged_pages", "false", PGC_SUSET, PGC_S_OVERRIDE);

733
	/*
734 735 736
	 * Get the database Id we're going to work on, and announce our PID
	 * in the shared memory area.  We remove the database OID immediately
	 * from the shared memory area.
737
	 */
738
	LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
739

740 741 742
	dbid = AutoVacuumShmem->process_db;
	AutoVacuumShmem->process_db = InvalidOid;
	AutoVacuumShmem->worker_pid = MyProcPid;
743

744
	LWLockRelease(AutovacuumLock);
745

746
	if (OidIsValid(dbid))
747
	{
748 749 750
		char	*dbname;
		PgStat_StatDBEntry *dbentry;

751
		/*
B
Bruce Momjian 已提交
752 753 754 755 756 757
		 * Report autovac startup to the stats collector.  We deliberately do
		 * this before InitPostgres, so that the last_autovac_time will get
		 * updated even if the connection attempt fails.  This is to prevent
		 * autovac from getting "stuck" repeatedly selecting an unopenable
		 * database, rather than making any progress on stuff it can connect
		 * to.
758
		 */
759
		pgstat_report_autovac(dbid);
760

761 762
		/*
		 * Connect to the selected database
763 764 765
		 *
		 * Note: if we have selected a just-deleted database (due to using
		 * stale stats info), we'll fail and exit here.
766
		 */
767
		InitPostgres(NULL, dbid, NULL, &dbname);
768
		SetProcessingMode(NormalProcessing);
769
		set_ps_display(dbname, false);
770
		ereport(DEBUG1,
771
				(errmsg("autovacuum: processing database \"%s\"", dbname)));
772 773 774 775 776 777 778 779

		/* Create the memory context where cross-transaction state is stored */
		AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
											  "Autovacuum context",
											  ALLOCSET_DEFAULT_MINSIZE,
											  ALLOCSET_DEFAULT_INITSIZE,
											  ALLOCSET_DEFAULT_MAXSIZE);

780 781 782 783
		/* And do an appropriate amount of work */
		recentXid = ReadNewTransactionId();
		dbentry = pgstat_fetch_stat_dbentry(dbid);
		do_autovacuum(dbentry);
784 785
	}

786 787 788 789 790 791 792 793 794
	/*
	 * Now remove our PID from shared memory, so that the launcher can start
	 * another worker as soon as appropriate.
	 */
	LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE);
	AutoVacuumShmem->worker_pid = 0;
	LWLockRelease(AutovacuumLock);

	/* All done, go away */
795 796 797 798 799 800
	proc_exit(0);
}

/*
 * autovac_get_database_list
 *
B
Bruce Momjian 已提交
801
 *		Return a list of all databases.  Note we cannot use pg_database,
802
 *		because we aren't connected; we use the flat database file.
803 804 805 806
 */
static List *
autovac_get_database_list(void)
{
B
Bruce Momjian 已提交
807 808 809 810 811 812
	char	   *filename;
	List	   *dblist = NIL;
	char		thisname[NAMEDATALEN];
	FILE	   *db_file;
	Oid			db_id;
	Oid			db_tablespace;
813
	TransactionId db_frozenxid;
814 815 816 817 818 819 820 821

	filename = database_getflatfilename();
	db_file = AllocateFile(filename, "r");
	if (db_file == NULL)
		ereport(FATAL,
				(errcode_for_file_access(),
				 errmsg("could not open file \"%s\": %m", filename)));

822
	while (read_pg_database_line(db_file, thisname, &db_id,
823
								 &db_tablespace, &db_frozenxid))
824
	{
B
Bruce Momjian 已提交
825
		autovac_dbase *db;
826 827 828 829 830

		db = (autovac_dbase *) palloc(sizeof(autovac_dbase));

		db->oid = db_id;
		db->name = pstrdup(thisname);
831 832
		db->frozenxid = db_frozenxid;
		/* this gets set later: */
833 834 835 836 837 838 839 840 841 842 843
		db->entry = NULL;

		dblist = lappend(dblist, db);
	}

	FreeFile(db_file);
	pfree(filename);

	return dblist;
}

844 845
/*
 * Process a database table-by-table
846
 *
847 848 849
 * dbentry is either a pointer to the database entry in the stats databases
 * hash table, or NULL if we couldn't find any entry (the latter case occurs
 * only if we are forcing a vacuum for anti-wrap purposes).
850 851 852 853 854
 *
 * Note that CHECK_FOR_INTERRUPTS is supposed to be used in certain spots in
 * order not to ignore shutdown commands for too long.
 */
static void
855
do_autovacuum(PgStat_StatDBEntry *dbentry)
856
{
B
Bruce Momjian 已提交
857 858 859 860
	Relation	classRel,
				avRel;
	HeapTuple	tuple;
	HeapScanDesc relScan;
861
	Form_pg_database dbForm;
B
Bruce Momjian 已提交
862 863 864
	List	   *vacuum_tables = NIL;
	List	   *toast_table_ids = NIL;
	ListCell   *cell;
865
	PgStat_StatDBEntry *shared;
866 867 868 869

	/* Start a transaction so our commands have one to play into. */
	StartTransactionCommand();

B
Bruce Momjian 已提交
870
	/* functions in indexes may want a snapshot set */
871 872
	ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());

873
	/*
B
Bruce Momjian 已提交
874 875 876
	 * Clean up any dead statistics collector entries for this DB. We always
	 * want to do this exactly once per DB-processing cycle, even if we find
	 * nothing worth vacuuming in the database.
877 878 879
	 */
	pgstat_vacuum_tabstat();

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
	/*
	 * Find the pg_database entry and select the default freeze_min_age.
	 * We use zero in template and nonconnectable databases,
	 * else the system-wide default.
	 */
	tuple = SearchSysCache(DATABASEOID,
						   ObjectIdGetDatum(MyDatabaseId),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
	dbForm = (Form_pg_database) GETSTRUCT(tuple);

	if (dbForm->datistemplate || !dbForm->datallowconn)
		default_freeze_min_age = 0;
	else
		default_freeze_min_age = vacuum_freeze_min_age;

	ReleaseSysCache(tuple);

899
	/*
B
Bruce Momjian 已提交
900 901 902
	 * StartTransactionCommand and CommitTransactionCommand will automatically
	 * switch to other contexts.  We need this one to keep the list of
	 * relations to vacuum/analyze across transactions.
903 904 905
	 */
	MemoryContextSwitchTo(AutovacMemCxt);

906 907
	/* The database hash where pgstat keeps shared relations */
	shared = pgstat_fetch_stat_dbentry(InvalidOid);
908

909 910
	classRel = heap_open(RelationRelationId, AccessShareLock);
	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
911

912 913 914
	/*
	 * Scan pg_class and determine which tables to vacuum.
	 *
915 916 917 918
	 * The stats subsystem collects stats for toast tables independently of
	 * the stats for their parent tables.  We need to check those stats since
	 * in cases with short, wide tables there might be proportionally much
	 * more activity in the toast table than in its parent.
919 920 921
	 *
	 * Since we can only issue VACUUM against the parent table, we need to
	 * transpose a decision to vacuum a toast table into a decision to vacuum
B
Bruce Momjian 已提交
922 923
	 * its parent.	There's no point in considering ANALYZE on a toast table,
	 * either.	To support this, we keep a list of OIDs of toast tables that
924 925
	 * need vacuuming alongside the list of regular tables.  Regular tables
	 * will be entered into the table list even if they appear not to need
B
Bruce Momjian 已提交
926 927
	 * vacuuming; we go back and re-mark them after finding all the vacuumable
	 * toast tables.
928
	 */
929
	relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
930

931 932 933 934 935
	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
	{
		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
		Form_pg_autovacuum avForm = NULL;
		PgStat_StatTabEntry *tabentry;
B
Bruce Momjian 已提交
936
		SysScanDesc avScan;
937
		HeapTuple	avTup;
B
Bruce Momjian 已提交
938
		ScanKeyData entry[1];
939 940
		Oid			relid;

941 942 943
		/* Consider only regular and toast tables. */
		if (classForm->relkind != RELKIND_RELATION &&
			classForm->relkind != RELKIND_TOASTVALUE)
944
			continue;
945

946
		/*
B
Bruce Momjian 已提交
947 948
		 * Skip temp tables (i.e. those in temp namespaces).  We cannot safely
		 * process other backends' temp tables.
949
		 */
950
		if (isAnyTempNamespace(classForm->relnamespace))
951
			continue;
952

953
		relid = HeapTupleGetOid(tuple);
954

955 956 957 958 959
		/* See if we have a pg_autovacuum entry for this relation. */
		ScanKeyInit(&entry[0],
					Anum_pg_autovacuum_vacrelid,
					BTEqualStrategyNumber, F_OIDEQ,
					ObjectIdGetDatum(relid));
960

961 962
		avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
									SnapshotNow, 1, entry);
963

964
		avTup = systable_getnext(avScan);
965

966 967
		if (HeapTupleIsValid(avTup))
			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
968

969 970 971
		if (classForm->relisshared && PointerIsValid(shared))
			tabentry = hash_search(shared->tables, &relid,
								   HASH_FIND, NULL);
972
		else if (PointerIsValid(dbentry))
973 974
			tabentry = hash_search(dbentry->tables, &relid,
								   HASH_FIND, NULL);
975 976
		else
			tabentry = NULL;
977

978
		test_rel_for_autovac(relid, tabentry, classForm, avForm,
979
							 &vacuum_tables, &toast_table_ids);
980

981 982
		systable_endscan(avScan);
	}
983

984 985 986
	heap_endscan(relScan);
	heap_close(avRel, AccessShareLock);
	heap_close(classRel, AccessShareLock);
987

988 989 990 991 992 993
	/*
	 * Perform operations on collected tables.
	 */
	foreach(cell, vacuum_tables)
	{
		autovac_table *tab = lfirst(cell);
994

995
		CHECK_FOR_INTERRUPTS();
996

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
		/*
		 * Check to see if we need to force vacuuming of this table because
		 * its toast table needs it.
		 */
		if (OidIsValid(tab->toastrelid) && !tab->dovacuum &&
			list_member_oid(toast_table_ids, tab->toastrelid))
		{
			tab->dovacuum = true;
			elog(DEBUG2, "autovac: VACUUM %u because of TOAST table",
				 tab->relid);
		}

		/* Otherwise, ignore table if it needs no work */
		if (!tab->dovacuum && !tab->doanalyze)
			continue;

1013 1014 1015
		/* Set the vacuum cost parameters for this table */
		VacuumCostDelay = tab->vacuum_cost_delay;
		VacuumCostLimit = tab->vacuum_cost_limit;
1016

1017
		autovacuum_do_vac_analyze(tab->relid,
1018 1019
								  tab->dovacuum,
								  tab->doanalyze,
1020
								  tab->freeze_min_age);
1021
	}
1022

1023 1024 1025 1026 1027 1028
	/*
	 * Update pg_database.datfrozenxid, and truncate pg_clog if possible.
	 * We only need to do this once, not after each table.
	 */
	vac_update_datfrozenxid();

1029 1030 1031 1032 1033 1034 1035
	/* Finally close out the last transaction. */
	CommitTransactionCommand();
}

/*
 * test_rel_for_autovac
 *
B
Bruce Momjian 已提交
1036
 * Check whether a table needs to be vacuumed or analyzed.	Add it to the
1037
 * appropriate output list if so.
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
 *
 * A table needs to be vacuumed if the number of dead tuples exceeds a
 * threshold.  This threshold is calculated as
 *
 * threshold = vac_base_thresh + vac_scale_factor * reltuples
 *
 * For analyze, the analysis done is that the number of tuples inserted,
 * deleted and updated since the last analyze exceeds a threshold calculated
 * in the same fashion as above.  Note that the collector actually stores
 * the number of tuples (both live and dead) that there were as of the last
 * analyze.  This is asymmetric to the VACUUM case.
 *
1050 1051 1052
 * We also force vacuum if the table's relfrozenxid is more than freeze_max_age
 * transactions back.
 *
1053
 * A table whose pg_autovacuum.enabled value is false, is automatically
1054 1055 1056
 * skipped (unless we have to vacuum it due to freeze_max_age).  Thus
 * autovacuum can be disabled for specific tables.  Also, when the stats
 * collector does not have data about a table, it will be skipped.
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
 *
 * A table whose vac_base_thresh value is <0 takes the base value from the
 * autovacuum_vacuum_threshold GUC variable.  Similarly, a vac_scale_factor
 * value <0 is substituted with the value of
 * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
 */
static void
test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
					 Form_pg_class classForm,
					 Form_pg_autovacuum avForm,
1067 1068
					 List **vacuum_tables,
					 List **toast_table_ids)
1069
{
1070 1071 1072
	bool		force_vacuum;
	bool		dovacuum;
	bool		doanalyze;
B
Bruce Momjian 已提交
1073
	float4		reltuples;		/* pg_class.reltuples */
1074
	/* constants from pg_autovacuum or GUC variables */
B
Bruce Momjian 已提交
1075 1076 1077 1078
	int			vac_base_thresh,
				anl_base_thresh;
	float4		vac_scale_factor,
				anl_scale_factor;
1079
	/* thresholds calculated from above constants */
B
Bruce Momjian 已提交
1080 1081
	float4		vacthresh,
				anlthresh;
1082
	/* number of vacuum (resp. analyze) tuples at this time */
B
Bruce Momjian 已提交
1083 1084
	float4		vactuples,
				anltuples;
1085 1086 1087 1088
	/* freeze parameters */
	int			freeze_min_age;
	int			freeze_max_age;
	TransactionId xidForceLimit;
1089
	/* cost-based vacuum delay parameters */
B
Bruce Momjian 已提交
1090 1091
	int			vac_cost_limit;
	int			vac_cost_delay;
1092 1093 1094 1095 1096 1097 1098 1099

	/*
	 * If there is a tuple in pg_autovacuum, use it; else, use the GUC
	 * defaults.  Note that the fields may contain "-1" (or indeed any
	 * negative value), which means use the GUC defaults for each setting.
	 */
	if (avForm != NULL)
	{
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		vac_scale_factor = (avForm->vac_scale_factor >= 0) ?
			avForm->vac_scale_factor : autovacuum_vac_scale;
		vac_base_thresh = (avForm->vac_base_thresh >= 0) ?
			avForm->vac_base_thresh : autovacuum_vac_thresh;

		anl_scale_factor = (avForm->anl_scale_factor >= 0) ?
			avForm->anl_scale_factor : autovacuum_anl_scale;
		anl_base_thresh = (avForm->anl_base_thresh >= 0) ?
			avForm->anl_base_thresh : autovacuum_anl_thresh;

1110 1111 1112 1113 1114 1115
		freeze_min_age = (avForm->freeze_min_age >= 0) ?
			avForm->freeze_min_age : default_freeze_min_age;
		freeze_max_age = (avForm->freeze_max_age >= 0) ?
			Min(avForm->freeze_max_age, autovacuum_freeze_max_age) :
			autovacuum_freeze_max_age;

1116 1117 1118 1119 1120 1121 1122 1123 1124
		vac_cost_limit = (avForm->vac_cost_limit >= 0) ?
			avForm->vac_cost_limit :
			((autovacuum_vac_cost_limit >= 0) ?
			 autovacuum_vac_cost_limit : VacuumCostLimit);

		vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
			avForm->vac_cost_delay :
			((autovacuum_vac_cost_delay >= 0) ?
			 autovacuum_vac_cost_delay : VacuumCostDelay);
1125 1126 1127 1128 1129 1130 1131 1132
	}
	else
	{
		vac_scale_factor = autovacuum_vac_scale;
		vac_base_thresh = autovacuum_vac_thresh;

		anl_scale_factor = autovacuum_anl_scale;
		anl_base_thresh = autovacuum_anl_thresh;
1133

1134 1135 1136
		freeze_min_age = default_freeze_min_age;
		freeze_max_age = autovacuum_freeze_max_age;

1137 1138 1139 1140 1141
		vac_cost_limit = (autovacuum_vac_cost_limit >= 0) ?
			autovacuum_vac_cost_limit : VacuumCostLimit;

		vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
			autovacuum_vac_cost_delay : VacuumCostDelay;
1142 1143
	}

1144 1145 1146 1147 1148 1149 1150
	/* Force vacuum if table is at risk of wraparound */
	xidForceLimit = recentXid - freeze_max_age;
	if (xidForceLimit < FirstNormalTransactionId)
		xidForceLimit -= FirstNormalTransactionId;
	force_vacuum = (TransactionIdIsNormal(classForm->relfrozenxid) &&
					TransactionIdPrecedes(classForm->relfrozenxid,
										  xidForceLimit));
1151

1152 1153 1154
	/* User disabled it in pg_autovacuum?  (But ignore if at risk) */
	if (avForm && !avForm->enabled && !force_vacuum)
		return;
1155

1156 1157 1158 1159 1160 1161
	if (PointerIsValid(tabentry))
	{
		reltuples = classForm->reltuples;
		vactuples = tabentry->n_dead_tuples;
		anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
			tabentry->last_anl_tuples;
1162

1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
		vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
		anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;

		/*
		 * Note that we don't need to take special consideration for stat
		 * reset, because if that happens, the last vacuum and analyze counts
		 * will be reset too.
		 */
		elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
			 NameStr(classForm->relname),
			 vactuples, vacthresh, anltuples, anlthresh);

		/* Determine if this table needs vacuum or analyze. */
		dovacuum = force_vacuum || (vactuples > vacthresh);
		doanalyze = (anltuples > anlthresh);
	}
	else
	{
		/*
		 * Skip a table not found in stat hash, unless we have to force
		 * vacuum for anti-wrap purposes.  If it's not acted upon, there's
		 * no need to vacuum it.
		 */
		dovacuum = force_vacuum;
		doanalyze = false;
	}
1189 1190 1191 1192 1193

	/* ANALYZE refuses to work with pg_statistics */
	if (relid == StatisticRelationId)
		doanalyze = false;

1194 1195 1196
	Assert(CurrentMemoryContext == AutovacMemCxt);

	if (classForm->relkind == RELKIND_RELATION)
1197
	{
1198 1199 1200 1201
		if (dovacuum || doanalyze)
			elog(DEBUG2, "autovac: will%s%s %s",
				 (dovacuum ? " VACUUM" : ""),
				 (doanalyze ? " ANALYZE" : ""),
1202
				 NameStr(classForm->relname));
1203

1204 1205 1206 1207 1208 1209 1210
		/*
		 * we must record tables that have a toast table, even if we currently
		 * don't think they need vacuuming.
		 */
		if (dovacuum || doanalyze || OidIsValid(classForm->reltoastrelid))
		{
			autovac_table *tab;
1211

1212 1213 1214 1215 1216
			tab = (autovac_table *) palloc(sizeof(autovac_table));
			tab->relid = relid;
			tab->toastrelid = classForm->reltoastrelid;
			tab->dovacuum = dovacuum;
			tab->doanalyze = doanalyze;
1217
			tab->freeze_min_age = freeze_min_age;
1218 1219
			tab->vacuum_cost_limit = vac_cost_limit;
			tab->vacuum_cost_delay = vac_cost_delay;
1220

1221 1222 1223 1224 1225 1226 1227 1228
			*vacuum_tables = lappend(*vacuum_tables, tab);
		}
	}
	else
	{
		Assert(classForm->relkind == RELKIND_TOASTVALUE);
		if (dovacuum)
			*toast_table_ids = lappend_oid(*toast_table_ids, relid);
1229 1230 1231 1232 1233
	}
}

/*
 * autovacuum_do_vac_analyze
1234
 *		Vacuum and/or analyze the specified table
1235 1236
 */
static void
1237 1238
autovacuum_do_vac_analyze(Oid relid, bool dovacuum, bool doanalyze,
						  int freeze_min_age)
1239
{
B
Bruce Momjian 已提交
1240 1241 1242
	VacuumStmt *vacstmt;
	MemoryContext old_cxt;

1243 1244 1245 1246 1247
	/*
	 * The node must survive transaction boundaries, so make sure we create it
	 * in a long-lived context
	 */
	old_cxt = MemoryContextSwitchTo(AutovacMemCxt);
B
Bruce Momjian 已提交
1248

1249
	vacstmt = makeNode(VacuumStmt);
1250 1251 1252

	/*
	 * Point QueryContext to the autovac memory context to fake out the
B
Bruce Momjian 已提交
1253 1254
	 * PreventTransactionChain check inside vacuum().  Note that this is also
	 * why we palloc vacstmt instead of just using a local variable.
1255 1256 1257 1258 1259 1260
	 */
	QueryContext = CurrentMemoryContext;

	/* Set up command parameters */
	vacstmt->vacuum = dovacuum;
	vacstmt->full = false;
1261
	vacstmt->analyze = doanalyze;
1262
	vacstmt->freeze_min_age = freeze_min_age;
1263
	vacstmt->verbose = false;
1264
	vacstmt->relation = NULL;	/* not used since we pass a relids list */
1265 1266
	vacstmt->va_cols = NIL;

1267
	/* Let pgstat know what we're doing */
1268
	autovac_report_activity(vacstmt, relid);
1269

1270
	vacuum(vacstmt, list_make1_oid(relid));
1271 1272 1273

	pfree(vacstmt);
	MemoryContextSwitchTo(old_cxt);
1274 1275
}

1276 1277
/*
 * autovac_report_activity
B
Bruce Momjian 已提交
1278
 *		Report to pgstat what autovacuum is doing
1279 1280 1281 1282 1283 1284 1285 1286 1287
 *
 * We send a SQL string corresponding to what the user would see if the
 * equivalent command was to be issued manually.
 *
 * Note we assume that we are going to report the next command as soon as we're
 * done with the current one, and exiting right after the last one, so we don't
 * bother to report "<IDLE>" or some such.
 */
static void
1288
autovac_report_activity(VacuumStmt *vacstmt, Oid relid)
1289
{
1290 1291
	char	   *relname = get_rel_name(relid);
	char	   *nspname = get_namespace_name(get_rel_namespace(relid));
1292
#define MAX_AUTOVAC_ACTIV_LEN (NAMEDATALEN * 2 + 32)
1293 1294 1295 1296 1297
	char		activity[MAX_AUTOVAC_ACTIV_LEN];

	/* Report the command and possible options */
	if (vacstmt->vacuum)
		snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
1298
				 "VACUUM%s",
1299
				 vacstmt->analyze ? " ANALYZE" : "");
1300
	else
1301
		snprintf(activity, MAX_AUTOVAC_ACTIV_LEN,
1302
				 "ANALYZE");
1303

1304 1305 1306 1307 1308 1309 1310 1311
	/*
	 * Report the qualified name of the relation.
	 *
	 * Paranoia is appropriate here in case relation was recently dropped
	 * --- the lsyscache routines we just invoked will return NULL rather
	 * than failing.
	 */
	if (relname && nspname)
1312
	{
1313
		int			len = strlen(activity);
1314

1315 1316
		snprintf(activity + len, MAX_AUTOVAC_ACTIV_LEN - len,
				 " %s.%s", nspname, relname);
1317 1318 1319 1320 1321
	}

	pgstat_report_activity(activity);
}

1322 1323
/*
 * AutoVacuumingActive
B
Bruce Momjian 已提交
1324 1325
 *		Check GUC vars and report whether the autovacuum process should be
 *		running.
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
 */
bool
AutoVacuumingActive(void)
{
	if (!autovacuum_start_daemon || !pgstat_collect_startcollector ||
		!pgstat_collect_tuplelevel)
		return false;
	return true;
}

/*
 * autovac_init
B
Bruce Momjian 已提交
1338
 *		This is called at postmaster initialization.
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
 *
 * Annoy the user if he got it wrong.
 */
void
autovac_init(void)
{
	if (!autovacuum_start_daemon)
		return;

	if (!pgstat_collect_startcollector || !pgstat_collect_tuplelevel)
	{
		ereport(WARNING,
				(errmsg("autovacuum not started because of misconfiguration"),
				 errhint("Enable options \"stats_start_collector\" and \"stats_row_level\".")));
B
Bruce Momjian 已提交
1353

1354 1355 1356 1357 1358 1359 1360 1361 1362
		/*
		 * Set the GUC var so we don't fork autovacuum uselessly, and also to
		 * help debugging.
		 */
		autovacuum_start_daemon = false;
	}
}

/*
1363 1364 1365
 * IsAutoVacuum functions
 *		Return whether this is either a launcher autovacuum process or a worker
 *		process.
1366 1367
 */
bool
1368 1369 1370 1371 1372 1373 1374
IsAutoVacuumLauncherProcess(void)
{
	return am_autovacuum_launcher;
}

bool
IsAutoVacuumWorkerProcess(void)
1375
{
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
	return am_autovacuum_worker;
}


/*
 * AutoVacuumShmemSize
 * 		Compute space needed for autovacuum-related shared memory
 */
Size
AutoVacuumShmemSize(void)
{
	return sizeof(AutoVacuumShmemStruct);
}

/*
 * AutoVacuumShmemInit
 *		Allocate and initialize autovacuum-related shared memory
 */
void
AutoVacuumShmemInit(void)
{
	bool        found;

	AutoVacuumShmem = (AutoVacuumShmemStruct *)
		ShmemInitStruct("AutoVacuum Data",
						AutoVacuumShmemSize(),
						&found);
	if (AutoVacuumShmem == NULL)
		ereport(FATAL,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("not enough shared memory for autovacuum")));
	if (found)
		return;                 /* already initialized */

	MemSet(AutoVacuumShmem, 0, sizeof(AutoVacuumShmemStruct));
1411
}