mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Allow vacuum to perform analyze with shared lock. Update cvs manual.
This commit is contained in:
		
							parent
							
								
									091126fa28
								
							
						
					
					
						commit
						659f79be7a
					
				| @ -1,5 +1,5 @@ | ||||
| <!-- | ||||
| $Header: /cvsroot/pgsql/doc/src/sgml/cvs.sgml,v 1.8 2000/05/02 20:01:51 thomas Exp $ | ||||
| $Header: /cvsroot/pgsql/doc/src/sgml/cvs.sgml,v 1.9 2000/05/29 15:44:54 momjian Exp $ | ||||
| CVS code repository | ||||
| Thomas Lockhart | ||||
| --> | ||||
| @ -184,7 +184,7 @@ cvs commit | ||||
|      Do an initial login to the <productname>CVS</productname> server: | ||||
| 
 | ||||
|      <programlisting> | ||||
| $ cvs -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot login | ||||
| $ cvs -d :pserver:anoncvs@postgresql.org:/home/projects/pgsql/cvsroot login | ||||
|      </programlisting> | ||||
| 
 | ||||
|      You will be prompted for a password; enter '<literal>postgresql</literal>'. | ||||
| @ -197,7 +197,7 @@ $ cvs -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot login | ||||
|     <para> | ||||
|      Fetch the <productname>Postgres</productname> sources: | ||||
|      <programlisting> | ||||
| cvs -z3 -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot co -P pgsql | ||||
| cvs -z3 -d :pserver:anoncvs@postgresql.org:/home/projects/pgsql/cvsroot co -P pgsql | ||||
|      </programlisting> | ||||
| 
 | ||||
|      which installs the <productname>Postgres</productname> sources into a  | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.151 2000/05/29 01:55:07 momjian Exp $ | ||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.152 2000/05/29 15:44:55 momjian Exp $ | ||||
|  * | ||||
| 
 | ||||
|  *------------------------------------------------------------------------- | ||||
| @ -77,15 +77,17 @@ static void vacuum_shutdown(void); | ||||
| static void vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols); | ||||
| static VRelList getrels(NameData *VacRelP); | ||||
| static void vacuum_rel(Oid relid, bool analyze, List *va_cols); | ||||
| static void analyze_rel(Oid relid, List *va_cols); | ||||
| static void scan_heap(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages, VPageList fraged_pages); | ||||
| static void repair_frag(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages, VPageList fraged_pages, int nindices, Relation *Irel); | ||||
| static void vacuum_heap(VRelStats *vacrelstats, Relation onerel, VPageList vpl); | ||||
| static void vacuum_page(Page page, VPageDescr vpd); | ||||
| static void vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples); | ||||
| static void scan_index(Relation indrel, int num_tuples); | ||||
| static void attr_stats(Relation onerel, VRelStats *vacrelstats, HeapTuple tuple); | ||||
| static void attr_stats(Relation onerel, int attr_cnt, VacAttrStats *vacattrstats, HeapTuple tuple); | ||||
| static void bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len); | ||||
| static void update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *vacrelstats); | ||||
| static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasindex, VRelStats *vacrelstats); | ||||
| static void update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats); | ||||
| static void del_stats(Oid relid, int attcnt, int *attnums); | ||||
| static VPageDescr tid_reaped(ItemPointer itemptr, VPageList vpl); | ||||
| static void reap_page(VPageList vpl, VPageDescr vpc); | ||||
| @ -100,63 +102,7 @@ static int	vac_cmp_offno(const void *left, const void *right); | ||||
| static int	vac_cmp_vtlinks(const void *left, const void *right); | ||||
| static bool enough_space(VPageDescr vpd, Size len); | ||||
| static char *show_rusage(struct rusage * ru0); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * This routines handle a special cross-transaction portal. | ||||
|  * However it is automatically closed in case of abort. | ||||
|  */ | ||||
| void | ||||
| CommonSpecialPortalOpen(void) | ||||
| { | ||||
| 	char	   *pname; | ||||
| 
 | ||||
| 
 | ||||
| 	if (CommonSpecialPortalInUse) | ||||
| 		elog(ERROR, "CommonSpecialPortal is in use"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Create a portal for safe memory across transactions. We need to | ||||
| 	 * palloc the name space for it because our hash function expects the | ||||
| 	 * name to be on a longword boundary.  CreatePortal copies the name to | ||||
| 	 * safe storage for us. | ||||
| 	 */ | ||||
| 	pname = pstrdup(VACPNAME); | ||||
| 	vac_portal = CreatePortal(pname); | ||||
| 	pfree(pname); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set flag to indicate that vac_portal must be removed after an error. | ||||
| 	 * This global variable is checked in the transaction manager on xact | ||||
| 	 * abort, and the routine CommonSpecialPortalClose() is called if | ||||
| 	 * necessary. | ||||
| 	 */ | ||||
| 	CommonSpecialPortalInUse = true; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| CommonSpecialPortalClose(void) | ||||
| { | ||||
| 	/* Clear flag first, to avoid recursion if PortalDrop elog's */ | ||||
| 	CommonSpecialPortalInUse = false; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Release our portal for cross-transaction memory. | ||||
| 	 */ | ||||
| 	PortalDrop(&vac_portal); | ||||
| } | ||||
| 
 | ||||
| PortalVariableMemory | ||||
| CommonSpecialPortalGetMemory(void) | ||||
| { | ||||
| 	return PortalGetVariableMemory(vac_portal); | ||||
| } | ||||
| 
 | ||||
| bool | ||||
| CommonSpecialPortalIsOpen(void) | ||||
| { | ||||
| 	return CommonSpecialPortalInUse; | ||||
| } | ||||
| /* CommonSpecialPortal function at the bottom */ | ||||
| 
 | ||||
| void | ||||
| vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec) | ||||
| @ -299,6 +245,11 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols) | ||||
| 	/* vacuum each heap relation */ | ||||
| 	for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next) | ||||
| 		vacuum_rel(cur->vrl_relid, analyze, va_cols); | ||||
| 
 | ||||
| 	/* analyze separately so locking is minimized */ | ||||
| 	if (analyze) | ||||
| 		for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next) | ||||
| 			analyze_rel(cur->vrl_relid, va_cols); | ||||
| } | ||||
| 
 | ||||
| static VRelList | ||||
| @ -410,8 +361,7 @@ getrels(NameData *VacRelP) | ||||
| static void | ||||
| vacuum_rel(Oid relid, bool analyze, List *va_cols) | ||||
| { | ||||
| 	HeapTuple	tuple, | ||||
| 				typetuple; | ||||
| 	HeapTuple	tuple; | ||||
| 	Relation	onerel; | ||||
| 	VPageListData vacuum_pages; /* List of pages to vacuum and/or clean
 | ||||
| 								 * indices */ | ||||
| @ -474,16 +424,151 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) | ||||
| 	vacrelstats->num_pages = vacrelstats->num_tuples = 0; | ||||
| 	vacrelstats->hasindex = false; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * we can VACUUM ANALYZE any table except pg_statistic; see | ||||
| 	 * update_stats | ||||
| 	 */ | ||||
| 	if (analyze && | ||||
| 	 strcmp(RelationGetRelationName(onerel), StatisticRelationName) != 0) | ||||
| 	GetXmaxRecent(&XmaxRecent); | ||||
| 
 | ||||
| 	/* scan it */ | ||||
| 	reindex = false; | ||||
| 	vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0; | ||||
| 	scan_heap(vacrelstats, onerel, &vacuum_pages, &fraged_pages); | ||||
| 	if (IsIgnoringSystemIndexes() && IsSystemRelationName(RelationGetRelationName(onerel))) | ||||
| 		reindex = true; | ||||
| 
 | ||||
| 	/* Now open indices */ | ||||
| 	nindices = 0; | ||||
| 	Irel = (Relation *) NULL; | ||||
| 	get_indices(vacrelstats->relid, &nindices, &Irel); | ||||
| 	if (!Irel) | ||||
| 		reindex = false; | ||||
| 	else if (!RelationGetForm(onerel)->relhasindex) | ||||
| 		reindex = true; | ||||
| 	if (nindices > 0) | ||||
| 		vacrelstats->hasindex = true; | ||||
| 	else | ||||
| 		vacrelstats->hasindex = false; | ||||
| 	if (reindex) | ||||
| 	{ | ||||
| 		for (i = 0; i < nindices; i++) | ||||
| 			index_close(Irel[i]); | ||||
| 		Irel = (Relation *) NULL; | ||||
| 		activate_indexes_of_a_table(relid, false); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Clean/scan index relation(s) */ | ||||
| 	if (Irel != (Relation *) NULL) | ||||
| 	{ | ||||
| 		if (vacuum_pages.vpl_num_pages > 0) | ||||
| 		{ | ||||
| 			for (i = 0; i < nindices; i++) | ||||
| 				vacuum_index(&vacuum_pages, Irel[i], vacrelstats->num_tuples, 0); | ||||
| 		} | ||||
| 		else | ||||
| 		/* just scan indices to update statistic */ | ||||
| 		{ | ||||
| 			for (i = 0; i < nindices; i++) | ||||
| 				scan_index(Irel[i], vacrelstats->num_tuples); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (fraged_pages.vpl_num_pages > 0) /* Try to shrink heap */ | ||||
| 		repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages, nindices, Irel); | ||||
| 	else | ||||
| 	{ | ||||
| 		if (Irel != (Relation *) NULL) | ||||
| 			close_indices(nindices, Irel); | ||||
| 		if (vacuum_pages.vpl_num_pages > 0)		/* Clean pages from
 | ||||
| 												 * vacuum_pages list */ | ||||
| 			vacuum_heap(vacrelstats, onerel, &vacuum_pages); | ||||
| 	} | ||||
| 	if (reindex) | ||||
| 		activate_indexes_of_a_table(relid, true); | ||||
| 
 | ||||
| 	/* ok - free vacuum_pages list of reaped pages */ | ||||
| 	if (vacuum_pages.vpl_num_pages > 0) | ||||
| 	{ | ||||
| 		vpp = vacuum_pages.vpl_pagedesc; | ||||
| 		for (i = 0; i < vacuum_pages.vpl_num_pages; i++, vpp++) | ||||
| 			pfree(*vpp); | ||||
| 		pfree(vacuum_pages.vpl_pagedesc); | ||||
| 		if (fraged_pages.vpl_num_pages > 0) | ||||
| 			pfree(fraged_pages.vpl_pagedesc); | ||||
| 	} | ||||
| 
 | ||||
| 	/* all done with this class, but hold lock until commit */ | ||||
| 	heap_close(onerel, NoLock); | ||||
| 
 | ||||
| 	/* update statistics in pg_class */ | ||||
| 	update_relstats(vacrelstats->relid, vacrelstats->num_pages, | ||||
| 			vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats); | ||||
| 
 | ||||
| 	/* next command frees attribute stats */ | ||||
| 	CommitTransactionCommand(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *	analyze_rel() -- analyze relation | ||||
|  */ | ||||
| static void | ||||
| analyze_rel(Oid relid, List *va_cols) | ||||
| { | ||||
| 	HeapTuple	tuple, | ||||
| 				typetuple; | ||||
| 	Relation	onerel; | ||||
| 	int32		i; | ||||
| 	int			attr_cnt, | ||||
| 			   *attnums = NULL; | ||||
| 	Form_pg_attribute *attr; | ||||
| 	VacAttrStats *vacattrstats; | ||||
| 	HeapScanDesc scan; | ||||
| 
 | ||||
| 	StartTransactionCommand(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check for user-requested abort.	Note we want this to be inside a | ||||
| 	 * transaction, so xact.c doesn't issue useless NOTICE. | ||||
| 	 */ | ||||
| 	if (QueryCancel) | ||||
| 		CancelQuery(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Race condition -- if the pg_class tuple has gone away since the | ||||
| 	 * last time we saw it, we don't need to vacuum it. | ||||
| 	 */ | ||||
| 	tuple = SearchSysCacheTuple(RELOID, | ||||
| 								ObjectIdGetDatum(relid), | ||||
| 								0, 0, 0); | ||||
| 	/*
 | ||||
| 	 * We can VACUUM ANALYZE any table except pg_statistic. | ||||
| 	 * see update_relstats | ||||
| 	 */ | ||||
| 	if (!HeapTupleIsValid(tuple) || | ||||
| 		strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname), | ||||
| 				StatisticRelationName) == 0) | ||||
| 	{ | ||||
| 		CommitTransactionCommand(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Open the class, get an exclusive lock on it, and check permissions. | ||||
| 	 * | ||||
| 	 * Note we choose to treat permissions failure as a NOTICE and keep | ||||
| 	 * trying to vacuum the rest of the DB --- is this appropriate? | ||||
| 	 */ | ||||
| 	onerel = heap_open(relid, AccessShareLock); | ||||
| 
 | ||||
| #ifndef NO_SECURITY | ||||
| 	if (!pg_ownercheck(GetPgUserName(), RelationGetRelationName(onerel), | ||||
| 					   RELNAME)) | ||||
| 	{ | ||||
| 		/* we already did an elog during vacuum
 | ||||
| 		elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it", | ||||
| 			 RelationGetRelationName(onerel)); | ||||
| 		*/ | ||||
| 		heap_close(onerel, AccessExclusiveLock); | ||||
| 		CommitTransactionCommand(); | ||||
| 		return; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	attr_cnt = onerel->rd_att->natts; | ||||
| 	attr = onerel->rd_att->attrs; | ||||
| @ -517,7 +602,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) | ||||
| 		attr_cnt = tcnt; | ||||
| 	} | ||||
| 
 | ||||
| 		vacrelstats->vacattrstats = (VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats)); | ||||
| 	vacattrstats = (VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats)); | ||||
| 
 | ||||
| 	for (i = 0; i < attr_cnt; i++) | ||||
| 	{ | ||||
| @ -525,7 +610,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) | ||||
| 		Form_pg_operator pgopform; | ||||
| 		VacAttrStats *stats; | ||||
| 
 | ||||
| 			stats = &vacrelstats->vacattrstats[i]; | ||||
| 		stats = &vacattrstats[i]; | ||||
| 		stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE); | ||||
| 		memmove(stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE); | ||||
| 		stats->best = stats->guess1 = stats->guess2 = 0; | ||||
| @ -581,95 +666,21 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) | ||||
| 			stats->typelem = InvalidOid; | ||||
| 		} | ||||
| 	} | ||||
| 		vacrelstats->va_natts = attr_cnt; | ||||
| 	/* delete existing pg_statistic rows for relation */ | ||||
| 	del_stats(relid, ((attnums) ? attr_cnt : 0), attnums); | ||||
| 		if (attnums) | ||||
| 			pfree(attnums); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		vacrelstats->va_natts = 0; | ||||
| 		vacrelstats->vacattrstats = (VacAttrStats *) NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	GetXmaxRecent(&XmaxRecent); | ||||
| 	scan = heap_beginscan(onerel, false, SnapshotNow, 0, NULL); | ||||
| 
 | ||||
| 	/* scan it */ | ||||
| 	reindex = false; | ||||
| 	vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0; | ||||
| 	scan_heap(vacrelstats, onerel, &vacuum_pages, &fraged_pages); | ||||
| 	if (IsIgnoringSystemIndexes() && IsSystemRelationName(RelationGetRelationName(onerel))) | ||||
| 		reindex = true; | ||||
| 	while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) | ||||
| 		attr_stats(onerel, attr_cnt, vacattrstats, tuple); | ||||
| 
 | ||||
| 	/* Now open indices */ | ||||
| 	nindices = 0; | ||||
| 	Irel = (Relation *) NULL; | ||||
| 	get_indices(vacrelstats->relid, &nindices, &Irel); | ||||
| 	if (!Irel) | ||||
| 		reindex = false; | ||||
| 	else if (!RelationGetForm(onerel)->relhasindex) | ||||
| 		reindex = true; | ||||
| 	if (nindices > 0) | ||||
| 		vacrelstats->hasindex = true; | ||||
| 	else | ||||
| 		vacrelstats->hasindex = false; | ||||
| 	if (reindex) | ||||
| 	{ | ||||
| 		for (i = 0; i < nindices; i++) | ||||
| 			index_close(Irel[i]); | ||||
| 		Irel = (Relation *) NULL; | ||||
| 		activate_indexes_of_a_table(relid, false); | ||||
| 	} | ||||
| 	heap_endscan(scan); | ||||
| 
 | ||||
| 	/* Clean/scan index relation(s) */ | ||||
| 	if (Irel != (Relation *) NULL) | ||||
| 	{ | ||||
| 		if (vacuum_pages.vpl_num_pages > 0) | ||||
| 		{ | ||||
| 			for (i = 0; i < nindices; i++) | ||||
| 				vacuum_index(&vacuum_pages, Irel[i], vacrelstats->num_tuples, 0); | ||||
| 		} | ||||
| 		else | ||||
| /* just scan indices to update statistic */ | ||||
| 		{ | ||||
| 			for (i = 0; i < nindices; i++) | ||||
| 				scan_index(Irel[i], vacrelstats->num_tuples); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (fraged_pages.vpl_num_pages > 0) /* Try to shrink heap */ | ||||
| 		repair_frag(vacrelstats, onerel, &vacuum_pages, &fraged_pages, nindices, Irel); | ||||
| 	else | ||||
| 	{ | ||||
| 		if (Irel != (Relation *) NULL) | ||||
| 			close_indices(nindices, Irel); | ||||
| 		if (vacuum_pages.vpl_num_pages > 0)		/* Clean pages from
 | ||||
| 												 * vacuum_pages list */ | ||||
| 			vacuum_heap(vacrelstats, onerel, &vacuum_pages); | ||||
| 	} | ||||
| 	if (reindex) | ||||
| 		activate_indexes_of_a_table(relid, true); | ||||
| 
 | ||||
| 	/* ok - free vacuum_pages list of reaped pages */ | ||||
| 	if (vacuum_pages.vpl_num_pages > 0) | ||||
| 	{ | ||||
| 		vpp = vacuum_pages.vpl_pagedesc; | ||||
| 		for (i = 0; i < vacuum_pages.vpl_num_pages; i++, vpp++) | ||||
| 			pfree(*vpp); | ||||
| 		pfree(vacuum_pages.vpl_pagedesc); | ||||
| 		if (fraged_pages.vpl_num_pages > 0) | ||||
| 			pfree(fraged_pages.vpl_pagedesc); | ||||
| 	} | ||||
| 	heap_close(onerel, AccessShareLock); | ||||
| 
 | ||||
| 	/* update statistics in pg_class */ | ||||
| 	update_stats(vacrelstats->relid, vacrelstats->num_pages, | ||||
| 			vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats); | ||||
| 	update_attstats(relid, attr_cnt, vacattrstats); | ||||
| 
 | ||||
| 	/* all done with this class, but hold lock until commit */ | ||||
| 	heap_close(onerel, NoLock); | ||||
| 
 | ||||
| 	/* next command frees attribute stats */ | ||||
| 	CommitTransactionCommand(); | ||||
| } | ||||
| 
 | ||||
| @ -979,7 +990,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, | ||||
| 					min_tlen = tuple.t_len; | ||||
| 				if (tuple.t_len > max_tlen) | ||||
| 					max_tlen = tuple.t_len; | ||||
| 				attr_stats(onerel, vacrelstats, &tuple); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| @ -2106,7 +2116,7 @@ scan_index(Relation indrel, int num_tuples) | ||||
| 
 | ||||
| 	/* now update statistics in pg_class */ | ||||
| 	nipages = RelationGetNumberOfBlocks(indrel); | ||||
| 	update_stats(RelationGetRelid(indrel), nipages, nitups, false, NULL); | ||||
| 	update_relstats(RelationGetRelid(indrel), nipages, nitups, false, NULL); | ||||
| 
 | ||||
| 	elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u. %s", | ||||
| 		 RelationGetRelationName(indrel), nipages, nitups, | ||||
| @ -2183,7 +2193,7 @@ vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples) | ||||
| 
 | ||||
| 	/* now update statistics in pg_class */ | ||||
| 	num_pages = RelationGetNumberOfBlocks(indrel); | ||||
| 	update_stats(RelationGetRelid(indrel), num_pages, num_index_tuples, false, NULL); | ||||
| 	update_relstats(RelationGetRelid(indrel), num_pages, num_index_tuples, false, NULL); | ||||
| 
 | ||||
| 	elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u: Deleted %u. %s", | ||||
| 		 RelationGetRelationName(indrel), num_pages, | ||||
| @ -2263,11 +2273,9 @@ tid_reaped(ItemPointer itemptr, VPageList vpl) | ||||
|  * | ||||
|  */ | ||||
| static void | ||||
| attr_stats(Relation onerel, VRelStats *vacrelstats, HeapTuple tuple) | ||||
| attr_stats(Relation onerel, int attr_cnt, VacAttrStats *vacattrstats, HeapTuple tuple) | ||||
| { | ||||
| 	int			i, | ||||
| 				attr_cnt = vacrelstats->va_natts; | ||||
| 	VacAttrStats *vacattrstats = vacrelstats->vacattrstats; | ||||
| 	int			i; | ||||
| 	TupleDesc	tupDesc = onerel->rd_att; | ||||
| 	Datum		value; | ||||
| 	bool		isnull; | ||||
| @ -2387,7 +2395,7 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len) | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *	update_stats() -- update statistics for one relation | ||||
|  *	update_relstats() -- update statistics for one relation | ||||
|  * | ||||
|  *		Statistics are stored in several places: the pg_class row for the | ||||
|  *		relation has stats about the whole relation, the pg_attribute rows | ||||
| @ -2408,29 +2416,15 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len) | ||||
|  *		Updating pg_class's own statistics would be especially tricky. | ||||
|  *		Of course, this only works for fixed-size never-null columns, but | ||||
|  *		these are. | ||||
|  * | ||||
|  *		Updates of pg_attribute statistics are handled in the same way | ||||
|  *		for the same reasons. | ||||
|  * | ||||
|  *		To keep things simple, we punt for pg_statistic, and don't try | ||||
|  *		to compute or store rows for pg_statistic itself in pg_statistic. | ||||
|  *		This could possibly be made to work, but it's not worth the trouble. | ||||
|  */ | ||||
| static void | ||||
| update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, | ||||
| update_relstats(Oid relid, int num_pages, int num_tuples, bool hasindex, | ||||
| 			VRelStats *vacrelstats) | ||||
| { | ||||
| 	Relation	rd, | ||||
| 				ad, | ||||
| 				sd; | ||||
| 	HeapScanDesc scan; | ||||
| 	Relation	rd; | ||||
| 	HeapTupleData rtup; | ||||
| 	HeapTuple	ctup, | ||||
| 				atup, | ||||
| 				stup; | ||||
| 	HeapTuple	ctup; | ||||
| 	Form_pg_class pgcform; | ||||
| 	ScanKeyData askey; | ||||
| 	Form_pg_attribute attp; | ||||
| 	Buffer		buffer; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -2461,11 +2455,28 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, | ||||
| 	WriteBuffer(buffer); | ||||
| 
 | ||||
| 	heap_close(rd, RowExclusiveLock); | ||||
| } | ||||
| 
 | ||||
| 	if (vacrelstats != NULL && vacrelstats->va_natts > 0) | ||||
| 	{ | ||||
| 		VacAttrStats *vacattrstats = vacrelstats->vacattrstats; | ||||
| 		int			natts = vacrelstats->va_natts; | ||||
| /*
 | ||||
|  *	update_attstats() -- update attribute statistics for one relation | ||||
|  * | ||||
|  *		Updates of pg_attribute statistics are handled by over-write. | ||||
|  *		for reasons described above. | ||||
|  * | ||||
|  *		To keep things simple, we punt for pg_statistic, and don't try | ||||
|  *		to compute or store rows for pg_statistic itself in pg_statistic. | ||||
|  *		This could possibly be made to work, but it's not worth the trouble. | ||||
|  */ | ||||
| static void | ||||
| update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats) | ||||
| { | ||||
| 	Relation	ad, | ||||
| 				sd; | ||||
| 	HeapScanDesc scan; | ||||
| 	HeapTuple	atup, | ||||
| 				stup; | ||||
| 	ScanKeyData askey; | ||||
| 	Form_pg_attribute attp; | ||||
| 
 | ||||
| 	ad = heap_openr(AttributeRelationName, RowExclusiveLock); | ||||
| 	sd = heap_openr(StatisticRelationName, RowExclusiveLock); | ||||
| @ -2511,7 +2522,6 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, | ||||
| 			} | ||||
| 			else if (stats->null_cnt <= 1 && stats->best_cnt == 1) | ||||
| 			{ | ||||
| 
 | ||||
| 				/*
 | ||||
| 				 * looks like we have a unique-key attribute --- flag | ||||
| 				 * this with special -1.0 flag value. | ||||
| @ -2656,7 +2666,6 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, | ||||
| 	/* close rels, but hold locks till upcoming commit */ | ||||
| 	heap_close(ad, NoLock); | ||||
| 	heap_close(sd, NoLock); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -2867,6 +2876,62 @@ vac_cmp_vtlinks(const void *left, const void *right) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This routines handle a special cross-transaction portal. | ||||
|  * However it is automatically closed in case of abort. | ||||
|  */ | ||||
| void | ||||
| CommonSpecialPortalOpen(void) | ||||
| { | ||||
| 	char	   *pname; | ||||
| 
 | ||||
| 
 | ||||
| 	if (CommonSpecialPortalInUse) | ||||
| 		elog(ERROR, "CommonSpecialPortal is in use"); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Create a portal for safe memory across transactions. We need to | ||||
| 	 * palloc the name space for it because our hash function expects the | ||||
| 	 * name to be on a longword boundary.  CreatePortal copies the name to | ||||
| 	 * safe storage for us. | ||||
| 	 */ | ||||
| 	pname = pstrdup(VACPNAME); | ||||
| 	vac_portal = CreatePortal(pname); | ||||
| 	pfree(pname); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set flag to indicate that vac_portal must be removed after an error. | ||||
| 	 * This global variable is checked in the transaction manager on xact | ||||
| 	 * abort, and the routine CommonSpecialPortalClose() is called if | ||||
| 	 * necessary. | ||||
| 	 */ | ||||
| 	CommonSpecialPortalInUse = true; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| CommonSpecialPortalClose(void) | ||||
| { | ||||
| 	/* Clear flag first, to avoid recursion if PortalDrop elog's */ | ||||
| 	CommonSpecialPortalInUse = false; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Release our portal for cross-transaction memory. | ||||
| 	 */ | ||||
| 	PortalDrop(&vac_portal); | ||||
| } | ||||
| 
 | ||||
| PortalVariableMemory | ||||
| CommonSpecialPortalGetMemory(void) | ||||
| { | ||||
| 	return PortalGetVariableMemory(vac_portal); | ||||
| } | ||||
| 
 | ||||
| bool | ||||
| CommonSpecialPortalIsOpen(void) | ||||
| { | ||||
| 	return CommonSpecialPortalInUse; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| get_indices(Oid relid, int *nindices, Relation **Irel) | ||||
| { | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $Id: vacuum.h,v 1.27 2000/04/12 17:16:32 momjian Exp $ | ||||
|  * $Id: vacuum.h,v 1.28 2000/05/29 15:44:55 momjian Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -125,8 +125,6 @@ typedef struct VRelStats | ||||
| 	Size		min_tlen; | ||||
| 	Size		max_tlen; | ||||
| 	bool		hasindex; | ||||
| 	int			va_natts;		/* number of attrs being analyzed */ | ||||
| 	VacAttrStats *vacattrstats; | ||||
| 	int			num_vtlinks; | ||||
| 	VTupleLink	vtlinks; | ||||
| } VRelStats; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user