Commit 659f79be authored by Bruce Momjian's avatar Bruce Momjian

Allow vacuum to perform analyze with shared lock. Update cvs manual.

parent 091126fa
<!-- <!--
$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 CVS code repository
Thomas Lockhart Thomas Lockhart
--> -->
...@@ -184,7 +184,7 @@ cvs commit ...@@ -184,7 +184,7 @@ cvs commit
Do an initial login to the <productname>CVS</productname> server: Do an initial login to the <productname>CVS</productname> server:
<programlisting> <programlisting>
$ cvs -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot login $ cvs -d :pserver:anoncvs@postgresql.org:/home/projects/pgsql/cvsroot login
</programlisting> </programlisting>
You will be prompted for a password; enter '<literal>postgresql</literal>'. 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 ...@@ -197,7 +197,7 @@ $ cvs -d :pserver:anoncvs@postgresql.org:/usr/local/cvsroot login
<para> <para>
Fetch the <productname>Postgres</productname> sources: Fetch the <productname>Postgres</productname> sources:
<programlisting> <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> </programlisting>
which installs the <productname>Postgres</productname> sources into a which installs the <productname>Postgres</productname> sources into a
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -77,15 +77,17 @@ static void vacuum_shutdown(void);
static void vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols); static void vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols);
static VRelList getrels(NameData *VacRelP); static VRelList getrels(NameData *VacRelP);
static void vacuum_rel(Oid relid, bool analyze, List *va_cols); 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 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 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_heap(VRelStats *vacrelstats, Relation onerel, VPageList vpl);
static void vacuum_page(Page page, VPageDescr vpd); static void vacuum_page(Page page, VPageDescr vpd);
static void vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples); 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 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 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 void del_stats(Oid relid, int attcnt, int *attnums);
static VPageDescr tid_reaped(ItemPointer itemptr, VPageList vpl); static VPageDescr tid_reaped(ItemPointer itemptr, VPageList vpl);
static void reap_page(VPageList vpl, VPageDescr vpc); static void reap_page(VPageList vpl, VPageDescr vpc);
...@@ -100,63 +102,7 @@ static int vac_cmp_offno(const void *left, const void *right); ...@@ -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 int vac_cmp_vtlinks(const void *left, const void *right);
static bool enough_space(VPageDescr vpd, Size len); static bool enough_space(VPageDescr vpd, Size len);
static char *show_rusage(struct rusage * ru0); static char *show_rusage(struct rusage * ru0);
/* CommonSpecialPortal function at the bottom */
/*
* 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;
}
void void
vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec) vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec)
...@@ -299,6 +245,11 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols) ...@@ -299,6 +245,11 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
/* vacuum each heap relation */ /* vacuum each heap relation */
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next) for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
vacuum_rel(cur->vrl_relid, analyze, va_cols); 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 static VRelList
...@@ -410,8 +361,7 @@ getrels(NameData *VacRelP) ...@@ -410,8 +361,7 @@ getrels(NameData *VacRelP)
static void static void
vacuum_rel(Oid relid, bool analyze, List *va_cols) vacuum_rel(Oid relid, bool analyze, List *va_cols)
{ {
HeapTuple tuple, HeapTuple tuple;
typetuple;
Relation onerel; Relation onerel;
VPageListData vacuum_pages; /* List of pages to vacuum and/or clean VPageListData vacuum_pages; /* List of pages to vacuum and/or clean
* indices */ * indices */
...@@ -474,16 +424,151 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) ...@@ -474,16 +424,151 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
vacrelstats->num_pages = vacrelstats->num_tuples = 0; vacrelstats->num_pages = vacrelstats->num_tuples = 0;
vacrelstats->hasindex = false; vacrelstats->hasindex = false;
/* GetXmaxRecent(&XmaxRecent);
* we can VACUUM ANALYZE any table except pg_statistic; see
* update_stats /* scan it */
*/ reindex = false;
if (analyze && vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0;
strcmp(RelationGetRelationName(onerel), StatisticRelationName) != 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, int attr_cnt,
*attnums = NULL; *attnums = NULL;
Form_pg_attribute *attr; 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_cnt = onerel->rd_att->natts;
attr = onerel->rd_att->attrs; attr = onerel->rd_att->attrs;
...@@ -517,7 +602,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) ...@@ -517,7 +602,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
attr_cnt = tcnt; 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++) for (i = 0; i < attr_cnt; i++)
{ {
...@@ -525,7 +610,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) ...@@ -525,7 +610,7 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
Form_pg_operator pgopform; Form_pg_operator pgopform;
VacAttrStats *stats; VacAttrStats *stats;
stats = &vacrelstats->vacattrstats[i]; stats = &vacattrstats[i];
stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE); stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
memmove(stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE); memmove(stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
stats->best = stats->guess1 = stats->guess2 = 0; stats->best = stats->guess1 = stats->guess2 = 0;
...@@ -581,95 +666,21 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols) ...@@ -581,95 +666,21 @@ vacuum_rel(Oid relid, bool analyze, List *va_cols)
stats->typelem = InvalidOid; stats->typelem = InvalidOid;
} }
} }
vacrelstats->va_natts = attr_cnt;
/* delete existing pg_statistic rows for relation */ /* delete existing pg_statistic rows for relation */
del_stats(relid, ((attnums) ? attr_cnt : 0), attnums); 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 */ while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
reindex = false; attr_stats(onerel, attr_cnt, vacattrstats, tuple);
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 */ heap_endscan(scan);
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 */ heap_close(onerel, AccessShareLock);
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);
}
/* update statistics in pg_class */ /* update statistics in pg_class */
update_stats(vacrelstats->relid, vacrelstats->num_pages, update_attstats(relid, attr_cnt, vacattrstats);
vacrelstats->num_tuples, vacrelstats->hasindex, vacrelstats);
/* all done with this class, but hold lock until commit */
heap_close(onerel, NoLock);
/* next command frees attribute stats */
CommitTransactionCommand(); CommitTransactionCommand();
} }
...@@ -979,7 +990,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, ...@@ -979,7 +990,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
min_tlen = tuple.t_len; min_tlen = tuple.t_len;
if (tuple.t_len > max_tlen) if (tuple.t_len > max_tlen)
max_tlen = tuple.t_len; max_tlen = tuple.t_len;
attr_stats(onerel, vacrelstats, &tuple);
} }
} }
...@@ -2106,7 +2116,7 @@ scan_index(Relation indrel, int num_tuples) ...@@ -2106,7 +2116,7 @@ scan_index(Relation indrel, int num_tuples)
/* now update statistics in pg_class */ /* now update statistics in pg_class */
nipages = RelationGetNumberOfBlocks(indrel); 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", elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u. %s",
RelationGetRelationName(indrel), nipages, nitups, RelationGetRelationName(indrel), nipages, nitups,
...@@ -2183,7 +2193,7 @@ vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples) ...@@ -2183,7 +2193,7 @@ vacuum_index(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
/* now update statistics in pg_class */ /* now update statistics in pg_class */
num_pages = RelationGetNumberOfBlocks(indrel); 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", elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u: Deleted %u. %s",
RelationGetRelationName(indrel), num_pages, RelationGetRelationName(indrel), num_pages,
...@@ -2263,11 +2273,9 @@ tid_reaped(ItemPointer itemptr, VPageList vpl) ...@@ -2263,11 +2273,9 @@ tid_reaped(ItemPointer itemptr, VPageList vpl)
* *
*/ */
static void static void
attr_stats(Relation onerel, VRelStats *vacrelstats, HeapTuple tuple) attr_stats(Relation onerel, int attr_cnt, VacAttrStats *vacattrstats, HeapTuple tuple)
{ {
int i, int i;
attr_cnt = vacrelstats->va_natts;
VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
TupleDesc tupDesc = onerel->rd_att; TupleDesc tupDesc = onerel->rd_att;
Datum value; Datum value;
bool isnull; bool isnull;
...@@ -2387,7 +2395,7 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len) ...@@ -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 * Statistics are stored in several places: the pg_class row for the
* relation has stats about the whole relation, the pg_attribute rows * 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) ...@@ -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. * Updating pg_class's own statistics would be especially tricky.
* Of course, this only works for fixed-size never-null columns, but * Of course, this only works for fixed-size never-null columns, but
* these are. * 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 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) VRelStats *vacrelstats)
{ {
Relation rd, Relation rd;
ad,
sd;
HeapScanDesc scan;
HeapTupleData rtup; HeapTupleData rtup;
HeapTuple ctup, HeapTuple ctup;
atup,
stup;
Form_pg_class pgcform; Form_pg_class pgcform;
ScanKeyData askey;
Form_pg_attribute attp;
Buffer buffer; Buffer buffer;
/* /*
...@@ -2461,11 +2455,28 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, ...@@ -2461,11 +2455,28 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex,
WriteBuffer(buffer); WriteBuffer(buffer);
heap_close(rd, RowExclusiveLock); heap_close(rd, RowExclusiveLock);
}
if (vacrelstats != NULL && vacrelstats->va_natts > 0) /*
{ * update_attstats() -- update attribute statistics for one relation
VacAttrStats *vacattrstats = vacrelstats->vacattrstats; *
int natts = vacrelstats->va_natts; * 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); ad = heap_openr(AttributeRelationName, RowExclusiveLock);
sd = heap_openr(StatisticRelationName, RowExclusiveLock); sd = heap_openr(StatisticRelationName, RowExclusiveLock);
...@@ -2511,7 +2522,6 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, ...@@ -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) else if (stats->null_cnt <= 1 && stats->best_cnt == 1)
{ {
/* /*
* looks like we have a unique-key attribute --- flag * looks like we have a unique-key attribute --- flag
* this with special -1.0 flag value. * this with special -1.0 flag value.
...@@ -2656,7 +2666,6 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex, ...@@ -2656,7 +2666,6 @@ update_stats(Oid relid, int num_pages, int num_tuples, bool hasindex,
/* close rels, but hold locks till upcoming commit */ /* close rels, but hold locks till upcoming commit */
heap_close(ad, NoLock); heap_close(ad, NoLock);
heap_close(sd, NoLock); heap_close(sd, NoLock);
}
} }
/* /*
...@@ -2867,6 +2876,62 @@ vac_cmp_vtlinks(const void *left, const void *right) ...@@ -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 static void
get_indices(Oid relid, int *nindices, Relation **Irel) get_indices(Oid relid, int *nindices, Relation **Irel)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -125,8 +125,6 @@ typedef struct VRelStats
Size min_tlen; Size min_tlen;
Size max_tlen; Size max_tlen;
bool hasindex; bool hasindex;
int va_natts; /* number of attrs being analyzed */
VacAttrStats *vacattrstats;
int num_vtlinks; int num_vtlinks;
VTupleLink vtlinks; VTupleLink vtlinks;
} VRelStats; } VRelStats;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment