mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-25 13:17:41 +03:00 
			
		
		
		
	Autovacuum loose end mop-up. Provide autovacuum-specific vacuum cost
delay and limit, both as global GUCs and as table-specific entries in pg_autovacuum. stats_reset_on_server_start is now OFF by default, but a reset is forced if we did WAL replay. XID-wrap vacuums do not ANALYZE, but do FREEZE if it's a template database. Alvaro Herrera
This commit is contained in:
		| @@ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.214 2005/07/30 14:15:44 momjian Exp $ | ||||
|  * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.215 2005/08/11 21:11:43 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -33,6 +33,7 @@ | ||||
| #include "catalog/catversion.h" | ||||
| #include "catalog/pg_control.h" | ||||
| #include "miscadmin.h" | ||||
| #include "pgstat.h" | ||||
| #include "postmaster/bgwriter.h" | ||||
| #include "storage/bufpage.h" | ||||
| #include "storage/fd.h" | ||||
| @@ -48,7 +49,7 @@ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  *	Becauase O_DIRECT bypasses the kernel buffers, and because we never | ||||
|  *	Because O_DIRECT bypasses the kernel buffers, and because we never | ||||
|  *	read those buffers except during crash recovery, it is a win to use | ||||
|  *	it in all cases where we sync on each write().  We could allow O_DIRECT | ||||
|  *	with fsync(), but because skipping the kernel buffer forces writes out | ||||
| @@ -4685,6 +4686,11 @@ StartupXLOG(void) | ||||
| 				RmgrTable[rmid].rm_cleanup(); | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Reset pgstat data, because it may be invalid after recovery. | ||||
| 		 */ | ||||
| 		pgstat_reset_all(); | ||||
|  | ||||
| 		/* | ||||
| 		 * Perform a new checkpoint to update our recovery activity to | ||||
| 		 * disk. | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.146 2005/07/29 19:30:04 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.147 2005/08/11 21:11:44 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -1001,13 +1001,15 @@ load_hba(void) | ||||
|  *	dboid: gets database OID | ||||
|  *	dbtablespace: gets database's default tablespace's OID | ||||
|  *	dbfrozenxid: gets database's frozen XID | ||||
|  *	dbvacuumxid: gets database's vacuum XID | ||||
|  * | ||||
|  * This is not much related to the other functions in hba.c, but we put it | ||||
|  * here because it uses the next_token() infrastructure. | ||||
|  */ | ||||
| bool | ||||
| read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, | ||||
| 					  Oid *dbtablespace, TransactionId *dbfrozenxid) | ||||
| 					  Oid *dbtablespace, TransactionId *dbfrozenxid, | ||||
| 					  TransactionId *dbvacuumxid) | ||||
| { | ||||
| 	char		buf[MAX_TOKEN]; | ||||
|  | ||||
| @@ -1030,6 +1032,10 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, | ||||
| 	if (!isdigit((unsigned char) buf[0])) | ||||
| 		elog(FATAL, "bad data in flat pg_database file"); | ||||
| 	*dbfrozenxid = atoxid(buf); | ||||
| 	next_token(fp, buf, sizeof(buf)); | ||||
| 	if (!isdigit((unsigned char) buf[0])) | ||||
| 		elog(FATAL, "bad data in flat pg_database file"); | ||||
| 	*dbvacuumxid = atoxid(buf); | ||||
| 	/* expect EOL next */ | ||||
| 	if (next_token(fp, buf, sizeof(buf))) | ||||
| 		elog(FATAL, "bad data in flat pg_database file"); | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.2 2005/07/29 19:30:04 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.3 2005/08/11 21:11:44 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -27,6 +27,7 @@ | ||||
| #include "catalog/indexing.h" | ||||
| #include "catalog/namespace.h" | ||||
| #include "catalog/pg_autovacuum.h" | ||||
| #include "catalog/pg_database.h" | ||||
| #include "commands/vacuum.h" | ||||
| #include "libpq/hba.h" | ||||
| #include "libpq/pqsignal.h" | ||||
| @@ -57,6 +58,9 @@ double		autovacuum_vac_scale; | ||||
| int			autovacuum_anl_thresh; | ||||
| double		autovacuum_anl_scale; | ||||
|  | ||||
| int			autovacuum_vac_cost_delay; | ||||
| int			autovacuum_vac_cost_limit; | ||||
|  | ||||
| /* Flag to tell if we are in the autovacuum daemon process */ | ||||
| static bool am_autovacuum = false; | ||||
|  | ||||
| @@ -64,27 +68,43 @@ static bool am_autovacuum = false; | ||||
| static time_t last_autovac_start_time = 0; | ||||
| static time_t last_autovac_stop_time = 0; | ||||
|  | ||||
| /* Memory context for long-lived data */ | ||||
| static MemoryContext	AutovacMemCxt; | ||||
|  | ||||
| /* struct to keep list of candidate databases for vacuum */ | ||||
| typedef struct autovac_dbase | ||||
| { | ||||
| 	Oid				oid; | ||||
| 	char		   *name; | ||||
| 	TransactionId	frozenxid; | ||||
| 	TransactionId	vacuumxid; | ||||
| 	PgStat_StatDBEntry *entry; | ||||
| 	int32			age; | ||||
| } autovac_dbase; | ||||
|  | ||||
| /* struct to keep track of tables to vacuum and/or analyze */ | ||||
| typedef struct autovac_table | ||||
| { | ||||
| 	Oid			relid; | ||||
| 	bool		dovacuum; | ||||
| 	bool		doanalyze; | ||||
| 	int			vacuum_cost_delay; | ||||
| 	int			vacuum_cost_limit; | ||||
| } autovac_table; | ||||
|  | ||||
|  | ||||
| #ifdef EXEC_BACKEND | ||||
| static pid_t autovac_forkexec(void); | ||||
| #endif | ||||
| NON_EXEC_STATIC void AutoVacMain(int argc, char *argv[]); | ||||
| static void do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry); | ||||
| static void process_whole_db(void); | ||||
| static void do_autovacuum(PgStat_StatDBEntry *dbentry); | ||||
| static List *autovac_get_database_list(void); | ||||
| static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
| 			 Form_pg_class classForm, Form_pg_autovacuum avForm, | ||||
| 			 List **vacuum_tables, List **analyze_tables); | ||||
| static void autovacuum_do_vac_analyze(List *relids, bool dovacuum); | ||||
| 			 List **vacuum_tables); | ||||
| static void autovacuum_do_vac_analyze(List *relids, bool dovacuum, | ||||
| 									  bool doanalyze, bool freeze); | ||||
|  | ||||
|  | ||||
| /* | ||||
| @@ -210,6 +230,12 @@ AutoVacMain(int argc, char *argv[]) | ||||
| 	/* Lose the postmaster's on-exit routines */ | ||||
| 	on_exit_reset(); | ||||
|  | ||||
| 	/* Identify myself via ps */ | ||||
| 	init_ps_display("autovacuum process", "", ""); | ||||
| 	set_ps_display(""); | ||||
|  | ||||
| 	SetProcessingMode(InitProcessing); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set up signal handlers.  We operate on databases much like a | ||||
| 	 * regular backend, so we use the same signal handling.  See | ||||
| @@ -233,12 +259,9 @@ AutoVacMain(int argc, char *argv[]) | ||||
| 	pqsignal(SIGUSR1, CatchupInterruptHandler); | ||||
| 	/* We don't listen for async notifies */ | ||||
| 	pqsignal(SIGUSR2, SIG_IGN); | ||||
| 	pqsignal(SIGFPE, FloatExceptionHandler); | ||||
| 	pqsignal(SIGCHLD, SIG_DFL); | ||||
|  | ||||
| 	/* Identify myself via ps */ | ||||
| 	init_ps_display("autovacuum process", "", ""); | ||||
| 	set_ps_display(""); | ||||
|  | ||||
| 	/* Early initialization */ | ||||
| 	BaseInit(); | ||||
|  | ||||
| @@ -302,6 +325,8 @@ AutoVacMain(int argc, char *argv[]) | ||||
| 	{ | ||||
| 		autovac_dbase  *tmp = lfirst(cell); | ||||
| 		bool			this_whole_db; | ||||
| 		int32			freeze_age, | ||||
| 						vacuum_age; | ||||
|  | ||||
| 		/* | ||||
| 		 * We look for the database that most urgently needs a database-wide | ||||
| @@ -309,9 +334,16 @@ AutoVacMain(int argc, char *argv[]) | ||||
| 		 * transactions sooner than vacuum.c's vac_truncate_clog() would | ||||
| 		 * decide to start giving warnings.  If any such db is found, we | ||||
| 		 * ignore all other dbs. | ||||
| 		 * | ||||
| 		 * Unlike vacuum.c, we also look at vacuumxid.  This is so that | ||||
| 		 * pg_clog can be kept trimmed to a reasonable size. | ||||
| 		 */ | ||||
| 		tmp->age = (int32) (nextXid - tmp->frozenxid); | ||||
| 		this_whole_db = (tmp->age > (int32) ((MaxTransactionId >> 3) * 3 - 100000)); | ||||
| 		freeze_age = (int32) (nextXid - tmp->frozenxid); | ||||
| 		vacuum_age = (int32) (nextXid - tmp->vacuumxid); | ||||
| 		tmp->age = Max(freeze_age, vacuum_age); | ||||
|  | ||||
| 		this_whole_db = (tmp->age > | ||||
| 						 (int32) ((MaxTransactionId >> 3) * 3 - 100000)); | ||||
| 		if (whole_db || this_whole_db) | ||||
| 		{ | ||||
| 			if (!this_whole_db) | ||||
| @@ -363,10 +395,21 @@ AutoVacMain(int argc, char *argv[]) | ||||
| 		set_ps_display(db->name); | ||||
| 		ereport(LOG, | ||||
| 				(errmsg("autovacuum: processing database \"%s\"", db->name))); | ||||
|  | ||||
| 		/* Create the memory context where cross-transaction state is stored */ | ||||
| 		AutovacMemCxt = AllocSetContextCreate(TopMemoryContext, | ||||
| 											  "Autovacuum context", | ||||
| 											  ALLOCSET_DEFAULT_MINSIZE, | ||||
| 											  ALLOCSET_DEFAULT_INITSIZE, | ||||
| 											  ALLOCSET_DEFAULT_MAXSIZE); | ||||
|  | ||||
| 		/* | ||||
| 		 * And do an appropriate amount of work on it | ||||
| 		 * And do an appropriate amount of work | ||||
| 		 */ | ||||
| 		do_autovacuum(whole_db, db->entry); | ||||
| 		if (whole_db) | ||||
| 			process_whole_db(); | ||||
| 		else | ||||
| 			do_autovacuum(db->entry); | ||||
| 	} | ||||
|  | ||||
| 	/* One iteration done, go away */ | ||||
| @@ -389,6 +432,7 @@ autovac_get_database_list(void) | ||||
| 	Oid		db_id; | ||||
| 	Oid		db_tablespace; | ||||
| 	TransactionId db_frozenxid; | ||||
| 	TransactionId db_vacuumxid; | ||||
|  | ||||
| 	filename = database_getflatfilename(); | ||||
| 	db_file = AllocateFile(filename, "r"); | ||||
| @@ -398,7 +442,8 @@ autovac_get_database_list(void) | ||||
| 				 errmsg("could not open file \"%s\": %m", filename))); | ||||
|  | ||||
| 	while (read_pg_database_line(db_file, thisname, &db_id, | ||||
| 								 &db_tablespace, &db_frozenxid)) | ||||
| 								 &db_tablespace, &db_frozenxid, | ||||
| 								 &db_vacuumxid)) | ||||
| 	{ | ||||
| 		autovac_dbase	*db; | ||||
|  | ||||
| @@ -407,6 +452,7 @@ autovac_get_database_list(void) | ||||
| 		db->oid = db_id; | ||||
| 		db->name = pstrdup(thisname); | ||||
| 		db->frozenxid = db_frozenxid; | ||||
| 		db->vacuumxid = db_vacuumxid; | ||||
| 		/* these get set later: */ | ||||
| 		db->entry = NULL; | ||||
| 		db->age = 0; | ||||
| @@ -421,40 +467,79 @@ autovac_get_database_list(void) | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Process a database. | ||||
|  * Process a whole database.  If it's a template database or is disallowing | ||||
|  * connection by means of datallowconn=false, then issue a VACUUM FREEZE. | ||||
|  * Else use a plain VACUUM. | ||||
|  */ | ||||
| static void | ||||
| process_whole_db(void) | ||||
| { | ||||
| 	Relation		dbRel; | ||||
| 	ScanKeyData		entry[1]; | ||||
| 	SysScanDesc		scan; | ||||
| 	HeapTuple		tup; | ||||
| 	Form_pg_database dbForm; | ||||
| 	bool			freeze; | ||||
|  | ||||
| 	/* Start a transaction so our commands have one to play into. */ | ||||
| 	StartTransactionCommand(); | ||||
|  | ||||
| 	dbRel = heap_open(DatabaseRelationId, AccessShareLock); | ||||
|  | ||||
| 	/* Must use a table scan, since there's no syscache for pg_database */ | ||||
| 	ScanKeyInit(&entry[0], | ||||
| 				ObjectIdAttributeNumber, | ||||
| 				BTEqualStrategyNumber, F_OIDEQ, | ||||
| 				ObjectIdGetDatum(MyDatabaseId)); | ||||
|  | ||||
| 	scan = systable_beginscan(dbRel, DatabaseOidIndexId, true, | ||||
| 							  SnapshotNow, 1, entry); | ||||
|  | ||||
| 	tup = systable_getnext(scan); | ||||
|  | ||||
| 	if (!HeapTupleIsValid(tup)) | ||||
| 		elog(ERROR, "could not find tuple for database %u", MyDatabaseId); | ||||
|  | ||||
| 	dbForm = (Form_pg_database) GETSTRUCT(tup); | ||||
|  | ||||
| 	if (!dbForm->datallowconn || dbForm->datistemplate) | ||||
| 		freeze = true; | ||||
| 	else | ||||
| 		freeze = false; | ||||
|  | ||||
| 	systable_endscan(scan); | ||||
|  | ||||
| 	heap_close(dbRel, AccessShareLock); | ||||
|  | ||||
| 	elog(DEBUG2, "autovacuum: VACUUM%s whole database", | ||||
| 		 (freeze) ? " FREEZE" : ""); | ||||
|  | ||||
| 	autovacuum_do_vac_analyze(NIL, true, false, freeze); | ||||
|  | ||||
| 	/* Finally close out the last transaction. */ | ||||
| 	CommitTransactionCommand(); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Process a database table-by-table | ||||
|  * | ||||
|  * If whole_db is true, the database is processed as a whole, and the | ||||
|  * dbentry parameter is ignored.  If it's false, dbentry must be a valid | ||||
|  * pointer to the database entry in the stats databases' hash table, and | ||||
|  * it will be used to determine whether vacuum or analyze is needed on a | ||||
|  * per-table basis. | ||||
|  * | ||||
|  * Note that test_rel_for_autovac generates two separate lists, one for | ||||
|  * vacuum and other for analyze.  This is to facilitate processing all | ||||
|  * analyzes first, and then all vacuums. | ||||
|  * dbentry must be a valid pointer to the database entry in the stats | ||||
|  * databases' hash table, and it will be used to determine whether vacuum or | ||||
|  * analyze is needed on a per-table basis. | ||||
|  * | ||||
|  * 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 | ||||
| do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry) | ||||
| do_autovacuum(PgStat_StatDBEntry *dbentry) | ||||
| { | ||||
| 	Relation		classRel, | ||||
| 					avRel; | ||||
| 	HeapTuple		tuple; | ||||
| 	HeapScanDesc	relScan; | ||||
| 	List		   *vacuum_tables = NIL, | ||||
| 				   *analyze_tables = NIL; | ||||
| 	MemoryContext	AutovacMemCxt; | ||||
|  | ||||
| 	Assert(whole_db || PointerIsValid(dbentry)); | ||||
|  | ||||
| 	/* Memory context where cross-transaction state is stored */ | ||||
| 	AutovacMemCxt = AllocSetContextCreate(TopMemoryContext, | ||||
| 										  "Autovacuum context", | ||||
| 										  ALLOCSET_DEFAULT_MINSIZE, | ||||
| 										  ALLOCSET_DEFAULT_INITSIZE, | ||||
| 										  ALLOCSET_DEFAULT_MAXSIZE); | ||||
| 	List		   *vacuum_tables = NIL; | ||||
| 	ListCell *cell; | ||||
| 	PgStat_StatDBEntry *shared; | ||||
|  | ||||
| 	/* Start a transaction so our commands have one to play into. */ | ||||
| 	StartTransactionCommand(); | ||||
| @@ -467,93 +552,87 @@ do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry) | ||||
| 	 */ | ||||
| 	MemoryContextSwitchTo(AutovacMemCxt); | ||||
|  | ||||
| 	if (whole_db) | ||||
| 	/* The database hash where pgstat keeps shared relations */ | ||||
| 	shared = pgstat_fetch_stat_dbentry(InvalidOid); | ||||
|  | ||||
| 	classRel = heap_open(RelationRelationId, AccessShareLock); | ||||
| 	avRel = heap_open(AutovacuumRelationId, AccessShareLock); | ||||
|  | ||||
| 	relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL); | ||||
|  | ||||
| 	/* Scan pg_class looking for tables to vacuum */ | ||||
| 	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) | ||||
| 	{ | ||||
| 		elog(DEBUG2, "autovacuum: VACUUM ANALYZE whole database"); | ||||
| 		autovacuum_do_vac_analyze(NIL, true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		/* the hash entry where pgstat stores shared relations */ | ||||
| 		PgStat_StatDBEntry *shared = pgstat_fetch_stat_dbentry(InvalidOid); | ||||
| 		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); | ||||
| 		Form_pg_autovacuum avForm = NULL; | ||||
| 		PgStat_StatTabEntry *tabentry; | ||||
| 		SysScanDesc	avScan; | ||||
| 		HeapTuple	avTup; | ||||
| 		ScanKeyData	entry[1]; | ||||
| 		Oid			relid; | ||||
|  | ||||
| 		classRel = heap_open(RelationRelationId, AccessShareLock); | ||||
| 		avRel = heap_open(AutovacuumRelationId, AccessShareLock); | ||||
|  | ||||
| 		relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL); | ||||
|  | ||||
| 		/* Scan pg_class looking for tables to vacuum */ | ||||
| 		while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL) | ||||
| 		{ | ||||
| 			Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple); | ||||
| 			Form_pg_autovacuum avForm = NULL; | ||||
| 			PgStat_StatTabEntry *tabentry; | ||||
| 			SysScanDesc	avScan; | ||||
| 			HeapTuple	avTup; | ||||
| 			ScanKeyData	entry[1]; | ||||
| 			Oid			relid; | ||||
|  | ||||
| 			/* Skip non-table entries. */ | ||||
| 			/* XXX possibly allow RELKIND_TOASTVALUE entries here too? */ | ||||
| 			if (classForm->relkind != RELKIND_RELATION) | ||||
| 				continue; | ||||
|  | ||||
| 			/* | ||||
| 			 * Skip temp tables (i.e. those in temp namespaces).  We cannot | ||||
| 			 * safely process other backends' temp tables. | ||||
| 			 */ | ||||
| 			if (isTempNamespace(classForm->relnamespace)) | ||||
| 				continue; | ||||
|  | ||||
| 			relid = HeapTupleGetOid(tuple); | ||||
|  | ||||
| 			/* See if we have a pg_autovacuum entry for this relation. */ | ||||
| 			ScanKeyInit(&entry[0], | ||||
| 						Anum_pg_autovacuum_vacrelid, | ||||
| 						BTEqualStrategyNumber, F_OIDEQ, | ||||
| 						ObjectIdGetDatum(relid)); | ||||
|  | ||||
| 			avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true, | ||||
| 										SnapshotNow, 1, entry); | ||||
|  | ||||
| 			avTup = systable_getnext(avScan); | ||||
|  | ||||
| 			if (HeapTupleIsValid(avTup)) | ||||
| 				avForm = (Form_pg_autovacuum) GETSTRUCT(avTup); | ||||
|  | ||||
| 			if (classForm->relisshared && PointerIsValid(shared)) | ||||
| 				tabentry = hash_search(shared->tables, &relid, | ||||
| 									   HASH_FIND, NULL); | ||||
| 			else | ||||
| 				tabentry = hash_search(dbentry->tables, &relid, | ||||
| 									   HASH_FIND, NULL); | ||||
|  | ||||
| 			test_rel_for_autovac(relid, tabentry, classForm, avForm, | ||||
| 								 &vacuum_tables, &analyze_tables); | ||||
|  | ||||
| 			systable_endscan(avScan); | ||||
| 		} | ||||
|  | ||||
| 		heap_endscan(relScan); | ||||
| 		heap_close(avRel, AccessShareLock); | ||||
| 		heap_close(classRel, AccessShareLock); | ||||
|  | ||||
| 		CHECK_FOR_INTERRUPTS(); | ||||
| 		/* Skip non-table entries. */ | ||||
| 		/* XXX possibly allow RELKIND_TOASTVALUE entries here too? */ | ||||
| 		if (classForm->relkind != RELKIND_RELATION) | ||||
| 			continue; | ||||
|  | ||||
| 		/* | ||||
| 		 * Perform operations on collected tables. | ||||
| 		 * Skip temp tables (i.e. those in temp namespaces).  We cannot | ||||
| 		 * safely process other backends' temp tables. | ||||
| 		 */ | ||||
| 		if (isTempNamespace(classForm->relnamespace)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (analyze_tables) | ||||
| 			autovacuum_do_vac_analyze(analyze_tables, false); | ||||
| 		relid = HeapTupleGetOid(tuple); | ||||
|  | ||||
| 		/* See if we have a pg_autovacuum entry for this relation. */ | ||||
| 		ScanKeyInit(&entry[0], | ||||
| 					Anum_pg_autovacuum_vacrelid, | ||||
| 					BTEqualStrategyNumber, F_OIDEQ, | ||||
| 					ObjectIdGetDatum(relid)); | ||||
|  | ||||
| 		avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true, | ||||
| 									SnapshotNow, 1, entry); | ||||
|  | ||||
| 		avTup = systable_getnext(avScan); | ||||
|  | ||||
| 		if (HeapTupleIsValid(avTup)) | ||||
| 			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup); | ||||
|  | ||||
| 		if (classForm->relisshared && PointerIsValid(shared)) | ||||
| 			tabentry = hash_search(shared->tables, &relid, | ||||
| 								   HASH_FIND, NULL); | ||||
| 		else | ||||
| 			tabentry = hash_search(dbentry->tables, &relid, | ||||
| 								   HASH_FIND, NULL); | ||||
|  | ||||
| 		test_rel_for_autovac(relid, tabentry, classForm, avForm, | ||||
| 							 &vacuum_tables); | ||||
|  | ||||
| 		systable_endscan(avScan); | ||||
| 	} | ||||
|  | ||||
| 	heap_endscan(relScan); | ||||
| 	heap_close(avRel, AccessShareLock); | ||||
| 	heap_close(classRel, AccessShareLock); | ||||
|  | ||||
| 	/* | ||||
| 	 * Perform operations on collected tables. | ||||
| 	 */ | ||||
| 	foreach(cell, vacuum_tables) | ||||
| 	{ | ||||
| 		autovac_table *tab = lfirst(cell); | ||||
|  | ||||
| 		CHECK_FOR_INTERRUPTS(); | ||||
|  | ||||
| 		/* get back to proper context */ | ||||
| 		MemoryContextSwitchTo(AutovacMemCxt); | ||||
| 		/* Set the vacuum cost parameters for this table */ | ||||
| 		VacuumCostDelay = tab->vacuum_cost_delay; | ||||
| 		VacuumCostLimit = tab->vacuum_cost_limit; | ||||
|  | ||||
| 		if (vacuum_tables) | ||||
| 			autovacuum_do_vac_analyze(vacuum_tables, true); | ||||
| 		autovacuum_do_vac_analyze(list_make1_oid(tab->relid), | ||||
| 								  tab->dovacuum, | ||||
| 								  tab->doanalyze, | ||||
| 								  false); | ||||
| 	} | ||||
|  | ||||
| 	/* Finally close out the last transaction. */ | ||||
| @@ -564,7 +643,7 @@ do_autovacuum(bool whole_db, PgStat_StatDBEntry *dbentry) | ||||
|  * test_rel_for_autovac | ||||
|  * | ||||
|  * Check whether a table needs to be vacuumed or analyzed.  Add it to the | ||||
|  * respective list if so. | ||||
|  * output list if so. | ||||
|  * | ||||
|  * A table needs to be vacuumed if the number of dead tuples exceeds a | ||||
|  * threshold.  This threshold is calculated as | ||||
| @@ -591,7 +670,7 @@ static void | ||||
| test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
| 					 Form_pg_class classForm, | ||||
| 					 Form_pg_autovacuum avForm, | ||||
| 					 List **vacuum_tables, List **analyze_tables) | ||||
| 					 List **vacuum_tables) | ||||
| { | ||||
| 	Relation		rel; | ||||
| 	float4			reltuples;	/* pg_class.reltuples */ | ||||
| @@ -606,6 +685,11 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
| 	/* number of vacuum (resp. analyze) tuples at this time */ | ||||
| 	float4			vactuples, | ||||
| 					anltuples; | ||||
| 	/* cost-based vacuum delay parameters */ | ||||
| 	int				vac_cost_limit; | ||||
| 	int				vac_cost_delay; | ||||
| 	bool			dovacuum; | ||||
| 	bool			doanalyze; | ||||
|  | ||||
| 	/* User disabled it in pg_autovacuum? */ | ||||
| 	if (avForm && !avForm->enabled) | ||||
| @@ -636,15 +720,25 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
| 	 */ | ||||
| 	if (avForm != NULL) | ||||
| 	{ | ||||
| 		vac_scale_factor = (avForm->vac_scale_factor < 0) ? | ||||
| 			autovacuum_vac_scale : avForm->vac_scale_factor; | ||||
| 		vac_base_thresh = (avForm->vac_base_thresh < 0) ? | ||||
| 			autovacuum_vac_thresh : avForm->vac_base_thresh; | ||||
| 		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) ? | ||||
| 			autovacuum_anl_scale : avForm->anl_scale_factor; | ||||
| 		anl_base_thresh = (avForm->anl_base_thresh < 0) ? | ||||
| 			autovacuum_anl_thresh : avForm->anl_base_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; | ||||
|  | ||||
| 		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); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -653,6 +747,12 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
|  | ||||
| 		anl_scale_factor = autovacuum_anl_scale; | ||||
| 		anl_base_thresh = autovacuum_anl_thresh; | ||||
|  | ||||
| 		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; | ||||
| 	} | ||||
|  | ||||
| 	vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples; | ||||
| @@ -668,22 +768,33 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
| 		 RelationGetRelationName(rel), | ||||
| 		 vactuples, vacthresh, anltuples, anlthresh); | ||||
|  | ||||
| 	Assert(CurrentMemoryContext == AutovacMemCxt); | ||||
|  | ||||
| 	/* Determine if this table needs vacuum or analyze. */ | ||||
| 	if (vactuples > vacthresh) | ||||
| 	dovacuum = (vactuples > vacthresh); | ||||
| 	doanalyze = (anltuples > anlthresh); | ||||
|  | ||||
| 	/* ANALYZE refuses to work with pg_statistics */ | ||||
| 	if (relid == StatisticRelationId) | ||||
| 		doanalyze = false; | ||||
|  | ||||
| 	if (dovacuum || doanalyze) | ||||
| 	{ | ||||
| 		elog(DEBUG2, "will VACUUM ANALYZE %s", | ||||
| 		autovac_table *tab; | ||||
|  | ||||
| 		elog(DEBUG2, "will%s%s %s", | ||||
| 			 (dovacuum ? " VACUUM" : ""), | ||||
| 			 (doanalyze ? " ANALYZE" : ""), | ||||
| 			 RelationGetRelationName(rel)); | ||||
| 		*vacuum_tables = lappend_oid(*vacuum_tables, relid); | ||||
| 	} | ||||
| 	else if (anltuples > anlthresh) | ||||
| 	{ | ||||
| 		/* ANALYZE refuses to work with pg_statistics */ | ||||
| 		if (relid != StatisticRelationId) | ||||
| 		{ | ||||
| 			elog(DEBUG2, "will ANALYZE %s", | ||||
| 					RelationGetRelationName(rel)); | ||||
| 			*analyze_tables = lappend_oid(*analyze_tables, relid); | ||||
| 		} | ||||
|  | ||||
| 		tab = (autovac_table *) palloc(sizeof(autovac_table)); | ||||
| 		tab->relid = relid; | ||||
| 		tab->dovacuum = dovacuum; | ||||
| 		tab->doanalyze = doanalyze; | ||||
| 		tab->vacuum_cost_limit = vac_cost_limit; | ||||
| 		tab->vacuum_cost_delay = vac_cost_delay; | ||||
|  | ||||
| 		*vacuum_tables = lappend(*vacuum_tables, tab); | ||||
| 	} | ||||
|  | ||||
| 	RelationClose(rel); | ||||
| @@ -691,14 +802,22 @@ test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, | ||||
|  | ||||
| /* | ||||
|  * autovacuum_do_vac_analyze | ||||
|  * 		Vacuum or analyze a list of tables; or all tables if relids = NIL | ||||
|  * | ||||
|  * We must be in AutovacMemCxt when this routine is called. | ||||
|  * 		Vacuum and/or analyze a list of tables; or all tables if relids = NIL | ||||
|  */ | ||||
| static void | ||||
| autovacuum_do_vac_analyze(List *relids, bool dovacuum) | ||||
| autovacuum_do_vac_analyze(List *relids, bool dovacuum, bool doanalyze, | ||||
| 						  bool freeze) | ||||
| { | ||||
| 	VacuumStmt		*vacstmt = makeNode(VacuumStmt); | ||||
| 	VacuumStmt	   *vacstmt; | ||||
| 	MemoryContext	old_cxt; | ||||
| 	 | ||||
| 	/* | ||||
| 	 * The node must survive transaction boundaries, so make sure we create it | ||||
| 	 * in a long-lived context | ||||
| 	 */ | ||||
| 	old_cxt = MemoryContextSwitchTo(AutovacMemCxt); | ||||
| 	 | ||||
| 	vacstmt = makeNode(VacuumStmt); | ||||
|  | ||||
| 	/* | ||||
| 	 * Point QueryContext to the autovac memory context to fake out the | ||||
| @@ -710,13 +829,16 @@ autovacuum_do_vac_analyze(List *relids, bool dovacuum) | ||||
| 	/* Set up command parameters */ | ||||
| 	vacstmt->vacuum = dovacuum; | ||||
| 	vacstmt->full = false; | ||||
| 	vacstmt->analyze = true; | ||||
| 	vacstmt->freeze = false; | ||||
| 	vacstmt->analyze = doanalyze; | ||||
| 	vacstmt->freeze = freeze; | ||||
| 	vacstmt->verbose = false; | ||||
| 	vacstmt->relation = NULL;	/* all tables, or not used if relids != NIL */ | ||||
| 	vacstmt->va_cols = NIL; | ||||
|  | ||||
| 	vacuum(vacstmt, relids); | ||||
|  | ||||
| 	pfree(vacstmt); | ||||
| 	MemoryContextSwitchTo(old_cxt); | ||||
| } | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  * | ||||
|  *	Copyright (c) 2001-2005, PostgreSQL Global Development Group | ||||
|  * | ||||
|  *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.104 2005/08/09 21:14:55 tgl Exp $ | ||||
|  *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.105 2005/08/11 21:11:44 tgl Exp $ | ||||
|  * ---------- | ||||
|  */ | ||||
| #include "postgres.h" | ||||
| @@ -100,7 +100,7 @@ | ||||
|  * ---------- | ||||
|  */ | ||||
| bool		pgstat_collect_startcollector = true; | ||||
| bool		pgstat_collect_resetonpmstart = true; | ||||
| bool		pgstat_collect_resetonpmstart = false; | ||||
| bool		pgstat_collect_querystring = false; | ||||
| bool		pgstat_collect_tuplelevel = false; | ||||
| bool		pgstat_collect_blocklevel = false; | ||||
| @@ -237,7 +237,7 @@ pgstat_init(void) | ||||
| 	 * statistics on postmaster start, simply remove the stats file. | ||||
| 	 */ | ||||
| 	if (!pgstat_collect_startcollector || pgstat_collect_resetonpmstart) | ||||
| 		unlink(PGSTAT_STAT_FILENAME); | ||||
| 		pgstat_reset_all(); | ||||
|  | ||||
| 	/* | ||||
| 	 * Nothing else required if collector will not get started | ||||
| @@ -456,6 +456,18 @@ startup_failed: | ||||
| 	pgstat_collect_blocklevel = false; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * pgstat_reset_all() - | ||||
|  * | ||||
|  * Remove the stats file.  This is used on server start if the  | ||||
|  * stats_reset_on_server_start feature is enabled, or if WAL | ||||
|  * recovery is needed after a crash. | ||||
|  */ | ||||
| void | ||||
| pgstat_reset_all(void) | ||||
| { | ||||
| 	unlink(PGSTAT_STAT_FILENAME); | ||||
| } | ||||
|  | ||||
| #ifdef EXEC_BACKEND | ||||
|  | ||||
| @@ -677,11 +689,19 @@ pgstat_bestart(void) | ||||
| 	if (pgStatSock < 0) | ||||
| 		return; | ||||
|  | ||||
| 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART); | ||||
| 	msg.m_databaseid = MyDatabaseId; | ||||
| 	msg.m_userid = GetSessionUserId(); | ||||
| 	memcpy(&msg.m_clientaddr, &MyProcPort->raddr, sizeof(msg.m_clientaddr)); | ||||
| 	pgstat_send(&msg, sizeof(msg)); | ||||
| 	/* | ||||
| 	 * We may not have a MyProcPort (eg, if this is the autovacuum process). | ||||
| 	 * For the moment, punt and don't send BESTART --- would be better to | ||||
| 	 * work out a clean way of handling "unknown clientaddr". | ||||
| 	 */ | ||||
| 	if (MyProcPort) | ||||
| 	{ | ||||
| 		pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART); | ||||
| 		msg.m_databaseid = MyDatabaseId; | ||||
| 		msg.m_userid = GetSessionUserId(); | ||||
| 		memcpy(&msg.m_clientaddr, &MyProcPort->raddr, sizeof(msg.m_clientaddr)); | ||||
| 		pgstat_send(&msg, sizeof(msg)); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Set up a process-exit hook to ensure we flush the last batch of | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.461 2005/07/29 19:30:04 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.462 2005/08/11 21:11:44 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  * | ||||
| @@ -342,6 +342,7 @@ typedef struct | ||||
| 	int syslogPipe[2]; | ||||
| #endif | ||||
| 	char my_exec_path[MAXPGPATH]; | ||||
| 	char pkglib_path[MAXPGPATH]; | ||||
| 	char ExtraOptions[MAXPGPATH]; | ||||
| 	char lc_collate[LOCALE_NAME_BUFLEN]; | ||||
| 	char lc_ctype[LOCALE_NAME_BUFLEN]; | ||||
| @@ -3702,6 +3703,8 @@ save_backend_variables(BackendParameters *param, Port *port, | ||||
|  | ||||
| 	StrNCpy(param->my_exec_path, my_exec_path, MAXPGPATH); | ||||
|  | ||||
| 	StrNCpy(param->pkglib_path, pkglib_path, MAXPGPATH); | ||||
|  | ||||
| 	StrNCpy(param->ExtraOptions, ExtraOptions, MAXPGPATH); | ||||
|  | ||||
| 	StrNCpy(param->lc_collate, setlocale(LC_COLLATE, NULL), LOCALE_NAME_BUFLEN); | ||||
| @@ -3903,6 +3906,8 @@ restore_backend_variables(BackendParameters *param, Port *port) | ||||
|  | ||||
| 	StrNCpy(my_exec_path, param->my_exec_path, MAXPGPATH); | ||||
|  | ||||
| 	StrNCpy(pkglib_path, param->pkglib_path, MAXPGPATH); | ||||
|  | ||||
| 	StrNCpy(ExtraOptions, param->ExtraOptions, MAXPGPATH); | ||||
|  | ||||
| 	setlocale(LC_COLLATE, param->lc_collate); | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.456 2005/08/08 03:12:12 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.457 2005/08/11 21:11:45 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  this is the "main" module of the postgres backend and | ||||
| @@ -162,7 +162,6 @@ static List *pg_rewrite_queries(List *querytree_list); | ||||
| static void start_xact_command(void); | ||||
| static void finish_xact_command(void); | ||||
| static void SigHupHandler(SIGNAL_ARGS); | ||||
| static void FloatExceptionHandler(SIGNAL_ARGS); | ||||
| static void log_disconnections(int code, Datum arg); | ||||
|  | ||||
|  | ||||
| @@ -2151,7 +2150,7 @@ StatementCancelHandler(SIGNAL_ARGS) | ||||
| } | ||||
|  | ||||
| /* signal handler for floating point exception */ | ||||
| static void | ||||
| void | ||||
| FloatExceptionHandler(SIGNAL_ARGS) | ||||
| { | ||||
| 	ereport(ERROR, | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.13 2005/07/28 22:27:02 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.14 2005/08/11 21:11:46 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -208,12 +208,14 @@ write_database_file(Relation drel) | ||||
| 		char	   *datname; | ||||
| 		Oid			datoid; | ||||
| 		Oid			dattablespace; | ||||
| 		TransactionId datfrozenxid; | ||||
| 		TransactionId datfrozenxid, | ||||
| 					  datvacuumxid; | ||||
|  | ||||
| 		datname = NameStr(dbform->datname); | ||||
| 		datoid = HeapTupleGetOid(tuple); | ||||
| 		dattablespace = dbform->dattablespace; | ||||
| 		datfrozenxid = dbform->datfrozenxid; | ||||
| 		datvacuumxid = dbform->datvacuumxid; | ||||
|  | ||||
| 		/* | ||||
| 		 * Identify the oldest datfrozenxid, ignoring databases that are not | ||||
| @@ -242,13 +244,14 @@ write_database_file(Relation drel) | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * The file format is: "dbname" oid tablespace frozenxid | ||||
| 		 * The file format is: "dbname" oid tablespace frozenxid vacuumxid | ||||
| 		 * | ||||
| 		 * The xid is not needed for backend startup, but may be of use | ||||
| 		 * for forensic purposes. | ||||
| 		 * The xids are not needed for backend startup, but are of use to | ||||
| 		 * autovacuum, and might also be helpful for forensic purposes. | ||||
| 		 */ | ||||
| 		fputs_quote(datname, fp); | ||||
| 		fprintf(fp, " %u %u %u\n", datoid, dattablespace, datfrozenxid); | ||||
| 		fprintf(fp, " %u %u %u %u\n", | ||||
| 				datoid, dattablespace, datfrozenxid, datvacuumxid); | ||||
| 	} | ||||
| 	heap_endscan(scan); | ||||
|  | ||||
| @@ -654,8 +657,10 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) | ||||
|  * base backup which may be far out of sync with the current state. | ||||
|  * | ||||
|  * In theory we could skip rebuilding the flat files if no WAL replay | ||||
|  * occurred, but it seems safest to just do it always.  We have to | ||||
|  * scan pg_database to compute the XID wrap limit anyway. | ||||
|  * occurred, but it seems best to just do it always.  We have to | ||||
|  * scan pg_database to compute the XID wrap limit anyway.  Also, this | ||||
|  * policy means we need not force initdb to change the format of the | ||||
|  * flat files. | ||||
|  * | ||||
|  * In a standalone backend we pass database_only = true to skip processing | ||||
|  * the auth file.  We won't need it, and building it could fail if there's | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.156 2005/08/08 03:12:14 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.157 2005/08/11 21:11:46 tgl Exp $ | ||||
|  * | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
| @@ -20,8 +20,10 @@ | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "access/genam.h" | ||||
| #include "access/heapam.h" | ||||
| #include "catalog/catalog.h" | ||||
| #include "catalog/indexing.h" | ||||
| #include "catalog/namespace.h" | ||||
| #include "catalog/pg_authid.h" | ||||
| #include "catalog/pg_database.h" | ||||
| @@ -79,7 +81,7 @@ FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace) | ||||
| 	char	   *filename; | ||||
| 	FILE	   *db_file; | ||||
| 	char		thisname[NAMEDATALEN]; | ||||
| 	TransactionId frozenxid; | ||||
| 	TransactionId dummyxid; | ||||
|  | ||||
| 	filename = database_getflatfilename(); | ||||
| 	db_file = AllocateFile(filename, "r"); | ||||
| @@ -89,7 +91,8 @@ FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace) | ||||
| 				 errmsg("could not open file \"%s\": %m", filename))); | ||||
|  | ||||
| 	while (read_pg_database_line(db_file, thisname, db_id, | ||||
| 								 db_tablespace, &frozenxid)) | ||||
| 								 db_tablespace, &dummyxid, | ||||
| 								 &dummyxid)) | ||||
| 	{ | ||||
| 		if (strcmp(thisname, name) == 0) | ||||
| 		{ | ||||
| @@ -131,7 +134,7 @@ static void | ||||
| ReverifyMyDatabase(const char *name) | ||||
| { | ||||
| 	Relation	pgdbrel; | ||||
| 	HeapScanDesc pgdbscan; | ||||
| 	SysScanDesc	pgdbscan; | ||||
| 	ScanKeyData key; | ||||
| 	HeapTuple	tup; | ||||
| 	Form_pg_database dbform; | ||||
| @@ -147,9 +150,10 @@ ReverifyMyDatabase(const char *name) | ||||
| 				BTEqualStrategyNumber, F_NAMEEQ, | ||||
| 				NameGetDatum(name)); | ||||
|  | ||||
| 	pgdbscan = heap_beginscan(pgdbrel, SnapshotNow, 1, &key); | ||||
| 	pgdbscan = systable_beginscan(pgdbrel, DatabaseNameIndexId, true, | ||||
| 								  SnapshotNow, 1, &key); | ||||
|  | ||||
| 	tup = heap_getnext(pgdbscan, ForwardScanDirection); | ||||
| 	tup = systable_getnext(pgdbscan); | ||||
| 	if (!HeapTupleIsValid(tup) || | ||||
| 		HeapTupleGetOid(tup) != MyDatabaseId) | ||||
| 	{ | ||||
| @@ -238,7 +242,7 @@ ReverifyMyDatabase(const char *name) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	heap_endscan(pgdbscan); | ||||
| 	systable_endscan(pgdbscan); | ||||
| 	heap_close(pgdbrel, RowShareLock); | ||||
| } | ||||
|  | ||||
| @@ -428,6 +432,18 @@ InitPostgres(const char *dbname, const char *username) | ||||
| 	/* Initialize portal manager */ | ||||
| 	EnablePortalManager(); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set up process-exit callback to do pre-shutdown cleanup.  This | ||||
| 	 * has to be after we've initialized all the low-level modules | ||||
| 	 * like the buffer manager, because during shutdown this has to | ||||
| 	 * run before the low-level modules start to close down.  On the | ||||
| 	 * other hand, we want it in place before we begin our first | ||||
| 	 * transaction --- if we fail during the initialization transaction, | ||||
| 	 * as is entirely possible, we need the AbortTransaction call to | ||||
| 	 * clean up. | ||||
| 	 */ | ||||
| 	on_shmem_exit(ShutdownPostgres, 0); | ||||
|  | ||||
| 	/* start a new transaction here before access to db */ | ||||
| 	if (!bootstrap) | ||||
| 		StartTransactionCommand(); | ||||
| @@ -465,7 +481,8 @@ InitPostgres(const char *dbname, const char *username) | ||||
| 	/* | ||||
| 	 * Unless we are bootstrapping, double-check that InitMyDatabaseInfo() | ||||
| 	 * got a correct result.  We can't do this until all the | ||||
| 	 * database-access infrastructure is up. | ||||
| 	 * database-access infrastructure is up.  (Also, it wants to know if | ||||
| 	 * the user is a superuser, so the above stuff has to happen first.) | ||||
| 	 */ | ||||
| 	if (!bootstrap) | ||||
| 		ReverifyMyDatabase(dbname); | ||||
| @@ -509,24 +526,10 @@ InitPostgres(const char *dbname, const char *username) | ||||
| 	/* initialize client encoding */ | ||||
| 	InitializeClientEncoding(); | ||||
|  | ||||
| 	/* | ||||
| 	 * Initialize statistics collection for this backend.  We do this | ||||
| 	 * here because the shutdown hook it sets up needs to be invoked | ||||
| 	 * at the corresponding phase of backend shutdown: after | ||||
| 	 * ShutdownPostgres and before we drop access to shared memory. | ||||
| 	 */ | ||||
| 	/* initialize statistics collection for this backend */ | ||||
| 	if (IsUnderPostmaster) | ||||
| 		pgstat_bestart(); | ||||
|  | ||||
| 	/* | ||||
| 	 * Set up process-exit callback to do pre-shutdown cleanup.  This | ||||
| 	 * should be last because we want shmem_exit to call this routine | ||||
| 	 * before the exit callbacks that are registered by buffer manager, | ||||
| 	 * lock manager, etc. We need to run this code before we close down | ||||
| 	 * database access! | ||||
| 	 */ | ||||
| 	on_shmem_exit(ShutdownPostgres, 0); | ||||
|  | ||||
| 	/* close the transaction we started above */ | ||||
| 	if (!bootstrap) | ||||
| 		CommitTransactionCommand(); | ||||
| @@ -538,9 +541,7 @@ InitPostgres(const char *dbname, const char *username) | ||||
| /* | ||||
|  * Backend-shutdown callback.  Do cleanup that we want to be sure happens | ||||
|  * before all the supporting modules begin to nail their doors shut via | ||||
|  * their own callbacks.  Note that because this has to be registered very | ||||
|  * late in startup, it will not get called if we suffer a failure *during* | ||||
|  * startup. | ||||
|  * their own callbacks. | ||||
|  * | ||||
|  * User-level cleanup, such as temp-relation removal and UNLISTEN, happens | ||||
|  * via separate callbacks that execute before this one.  We don't combine the | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  * Written by Peter Eisentraut <peter_e@gmx.net>. | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.280 2005/07/30 15:17:20 momjian Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.281 2005/08/11 21:11:47 tgl Exp $ | ||||
|  * | ||||
|  *-------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -672,7 +672,7 @@ static struct config_bool ConfigureNamesBool[] = | ||||
| 			NULL | ||||
| 		}, | ||||
| 		&pgstat_collect_resetonpmstart, | ||||
| 		true, NULL, NULL | ||||
| 		false, NULL, NULL | ||||
| 	}, | ||||
| 	{ | ||||
| 		{"stats_command_string", PGC_SUSET, STATS_COLLECTOR, | ||||
| @@ -1160,6 +1160,24 @@ static struct config_int ConfigureNamesInt[] = | ||||
| 		0, 0, 1000, NULL, NULL | ||||
| 	}, | ||||
|  | ||||
| 	{ | ||||
| 		{"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM, | ||||
| 			gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."), | ||||
| 			NULL | ||||
| 		}, | ||||
| 		&autovacuum_vac_cost_delay, | ||||
| 		-1, -1, 1000, NULL, NULL | ||||
| 	}, | ||||
|  | ||||
| 	{ | ||||
| 		{"autovacuum_vacuum_cost_limit", PGC_SIGHUP, AUTOVACUUM, | ||||
| 			gettext_noop("Vacuum cost amount available before napping, for autovacuum."), | ||||
| 			NULL | ||||
| 		}, | ||||
| 		&autovacuum_vac_cost_limit, | ||||
| 		-1, -1, 10000, NULL, NULL | ||||
| 	}, | ||||
|  | ||||
| 	{ | ||||
| 		{"max_files_per_process", PGC_POSTMASTER, RESOURCES_KERNEL, | ||||
| 			gettext_noop("Sets the maximum number of simultaneously open files for each server process."), | ||||
|   | ||||
| @@ -288,7 +288,7 @@ | ||||
| #stats_command_string = off | ||||
| #stats_block_level = off | ||||
| #stats_row_level = off | ||||
| #stats_reset_on_server_start = on | ||||
| #stats_reset_on_server_start = off | ||||
|  | ||||
|  | ||||
| #--------------------------------------------------------------------------- | ||||
| @@ -301,6 +301,10 @@ | ||||
| #autovacuum_analyze_threshold = 500	# min # of tuple updates before analyze | ||||
| #autovacuum_vacuum_scale_factor = 0.4	# fraction of rel size before vacuum | ||||
| #autovacuum_analyze_scale_factor = 0.2	# fraction of rel size before analyze | ||||
| #autovacuum_vacuum_cost_delay = -1  # default vacuum cost delay for autovac | ||||
|                                     # -1 means use vacuum_cost_delay | ||||
| #autovacuum_vacuum_cost_limit = -1  # default vacuum cost limit for autovac | ||||
|                                     # -1 means use vacuum_cost_limit | ||||
|  | ||||
|  | ||||
| #--------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.295 2005/08/01 20:31:14 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.296 2005/08/11 21:11:47 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -53,6 +53,6 @@ | ||||
|  */ | ||||
|  | ||||
| /*							yyyymmddN */ | ||||
| #define CATALOG_VERSION_NO	200508011 | ||||
| #define CATALOG_VERSION_NO	200508111 | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.1 2005/07/14 05:13:42 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.2 2005/08/11 21:11:47 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -34,6 +34,8 @@ CATALOG(pg_autovacuum,1248) BKI_WITHOUT_OIDS | ||||
| 	float4		vac_scale_factor;  	/* reltuples scaling factor */ | ||||
| 	int4		anl_base_thresh;	/* base threshold value */ | ||||
| 	float4		anl_scale_factor;	/* reltuples scaling factor */ | ||||
| 	int4		vac_cost_delay;		/* vacuum cost-based delay */ | ||||
| 	int4		vac_cost_limit;		/* vacuum cost limit */ | ||||
| } FormData_pg_autovacuum; | ||||
|  | ||||
| /* ---------------- | ||||
| @@ -47,13 +49,15 @@ typedef FormData_pg_autovacuum *Form_pg_autovacuum; | ||||
|  *		compiler constants for pg_autovacuum | ||||
|  * ---------------- | ||||
|  */ | ||||
| #define Natts_pg_autovacuum							6 | ||||
| #define Natts_pg_autovacuum							8 | ||||
| #define Anum_pg_autovacuum_vacrelid					1 | ||||
| #define Anum_pg_autovacuum_enabled					2 | ||||
| #define Anum_pg_autovacuum_vac_base_thresh			3 | ||||
| #define Anum_pg_autovacuum_vac_scale_factor			4 | ||||
| #define Anum_pg_autovacuum_anl_base_thresh			5 | ||||
| #define Anum_pg_autovacuum_anl_scale_factor			6 | ||||
| #define Anum_pg_autovacuum_vac_cost_delay			7 | ||||
| #define Anum_pg_autovacuum_vac_cost_limit			8 | ||||
|  | ||||
| /* There are no preloaded tuples in pg_autovacuum.h */ | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  *	  Interface to hba.c | ||||
|  * | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.39 2005/07/29 19:30:08 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.40 2005/08/11 21:11:48 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -37,6 +37,7 @@ extern void load_role(void); | ||||
| extern int	hba_getauthmethod(hbaPort *port); | ||||
| extern int	authident(hbaPort *port); | ||||
| extern bool	read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, | ||||
| 								  Oid *dbtablespace, TransactionId *dbfrozenxid); | ||||
| 								  Oid *dbtablespace, TransactionId *dbfrozenxid, | ||||
| 								  TransactionId *dbvacuumxid); | ||||
|  | ||||
| #endif /* HBA_H */ | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  * | ||||
|  *	Copyright (c) 2001-2005, PostgreSQL Global Development Group | ||||
|  * | ||||
|  *	$PostgreSQL: pgsql/src/include/pgstat.h,v 1.34 2005/07/29 19:30:09 tgl Exp $ | ||||
|  *	$PostgreSQL: pgsql/src/include/pgstat.h,v 1.35 2005/08/11 21:11:49 tgl Exp $ | ||||
|  * ---------- | ||||
|  */ | ||||
| #ifndef PGSTAT_H | ||||
| @@ -367,6 +367,7 @@ extern bool pgstat_collect_blocklevel; | ||||
| extern void pgstat_init(void); | ||||
| extern int	pgstat_start(void); | ||||
| extern void pgstat_beterm(int pid); | ||||
| extern void pgstat_reset_all(void); | ||||
|  | ||||
| #ifdef EXEC_BACKEND | ||||
| extern void PgstatBufferMain(int argc, char *argv[]); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/postmaster/autovacuum.h,v 1.1 2005/07/14 05:13:43 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/postmaster/autovacuum.h,v 1.2 2005/08/11 21:11:50 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -21,6 +21,8 @@ extern int		autovacuum_vac_thresh; | ||||
| extern double	autovacuum_vac_scale; | ||||
| extern int		autovacuum_anl_thresh; | ||||
| extern double	autovacuum_anl_scale; | ||||
| extern int		autovacuum_vac_cost_delay; | ||||
| extern int		autovacuum_vac_cost_limit; | ||||
|  | ||||
| /* Status inquiry functions */ | ||||
| extern bool AutoVacuumingActive(void); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.76 2005/07/14 05:13:44 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.77 2005/08/11 21:11:50 tgl Exp $ | ||||
|  * | ||||
|  * OLD COMMENTS | ||||
|  *	  This file was created so that other c files could get the two | ||||
| @@ -59,6 +59,7 @@ extern void die(SIGNAL_ARGS); | ||||
| extern void quickdie(SIGNAL_ARGS); | ||||
| extern void authdie(SIGNAL_ARGS); | ||||
| extern void StatementCancelHandler(SIGNAL_ARGS); | ||||
| extern void FloatExceptionHandler(SIGNAL_ARGS); | ||||
| extern void prepare_for_client_read(void); | ||||
| extern void client_read_ended(void); | ||||
| extern int	PostgresMain(int argc, char *argv[], const char *username); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user