Commit 2300ac0d authored by Bruce Momjian's avatar Bruce Momjian

Add attribute optimization statistics.

parent 4c0faba0
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.18 1997/01/29 02:59:03 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.19 1997/02/07 16:22:34 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <postgres.h> #include <postgres.h>
#include <fmgr.h>
#include <utils/portal.h> #include <utils/portal.h>
#include <access/genam.h> #include <access/genam.h>
#include <access/heapam.h> #include <access/heapam.h>
...@@ -32,12 +33,17 @@ ...@@ -32,12 +33,17 @@
#include <catalog/catalog.h> #include <catalog/catalog.h>
#include <catalog/pg_class.h> #include <catalog/pg_class.h>
#include <catalog/pg_proc.h> #include <catalog/pg_proc.h>
#include <catalog/pg_statistic.h>
#include <catalog/pg_type.h>
#include <catalog/pg_operator.h>
#include <storage/smgr.h> #include <storage/smgr.h>
#include <storage/lmgr.h> #include <storage/lmgr.h>
#include <utils/inval.h> #include <utils/inval.h>
#include <utils/mcxt.h> #include <utils/mcxt.h>
#include <utils/inval.h>
#include <utils/syscache.h> #include <utils/syscache.h>
#include <commands/vacuum.h> #include <commands/vacuum.h>
#include <parser/catalog_utils.h>
#include <storage/bufpage.h> #include <storage/bufpage.h>
#include "storage/shmem.h" #include "storage/shmem.h"
#ifndef HAVE_GETRUSAGE #ifndef HAVE_GETRUSAGE
...@@ -48,44 +54,48 @@ ...@@ -48,44 +54,48 @@
#endif #endif
bool VacuumRunning = false; bool VacuumRunning = false;
static int MESSLEV; /* message level */ static int MESSAGE_LEVEL; /* message level */
typedef struct { #define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
FuncIndexInfo finfo; #define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
FuncIndexInfo *finfoP; #define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
IndexTupleForm tform; #define VacAttrStatsEqValid(stats) ( RegProcedureIsValid(stats->cmpeq))
int natts; #define VacAttrStatsLtGtValid(stats) ( RegProcedureIsValid(stats->cmplt) && \
} IndDesc; RegProcedureIsValid(stats->cmpgt) && \
RegProcedureIsValid(stats->outfunc) )
/* non-export function prototypes */ /* non-export function prototypes */
static void _vc_init(void); static void vc_init(void);
static void _vc_shutdown(void); static void vc_shutdown(void);
static void _vc_vacuum(NameData *VacRelP); static void vc_vacuum(NameData *VacRelP);
static VRelList _vc_getrels(Portal p, NameData *VacRelP); static VRelList vc_getrels(Portal p, NameData *VacRelP);
static void _vc_vacone (VRelList curvrl); static void vc_vacone (Oid relid);
static void _vc_scanheap (VRelList curvrl, Relation onerel, VPageList Vvpl, VPageList Fvpl); static void vc_scanheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
static void _vc_rpfheap (VRelList curvrl, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel); static void vc_rpfheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel);
static void _vc_vacheap (VRelList curvrl, Relation onerel, VPageList vpl); static void vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList vpl);
static void _vc_vacpage (Page page, VPageDescr vpd, Relation archrel); static void vc_vacpage (Page page, VPageDescr vpd, Relation archrel);
static void _vc_vaconeind (VPageList vpl, Relation indrel, int nhtups); static void vc_vaconeind (VPageList vpl, Relation indrel, int nhtups);
static void _vc_scanoneind (Relation indrel, int nhtups); static void vc_scanoneind (Relation indrel, int nhtups);
static void _vc_updstats(Oid relid, int npages, int ntuples, bool hasindex); static void vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup);
static void _vc_setpagelock(Relation rel, BlockNumber blkno); static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len);
static VPageDescr _vc_tidreapped (ItemPointer itemptr, VPageList curvrl); static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacattrstats);
static void _vc_reappage (VPageList vpl, VPageDescr vpc); static void vc_delhilowstats(Oid relid);
static void _vc_vpinsert (VPageList vpl, VPageDescr vpnew); static void vc_setpagelock(Relation rel, BlockNumber blkno);
static void _vc_free(Portal p, VRelList vrl); static VPageDescr vc_tidreapped (ItemPointer itemptr, VPageList vpl);
static void _vc_getindices (Oid relid, int *nindices, Relation **Irel); static void vc_reappage (VPageList vpl, VPageDescr vpc);
static void _vc_clsindices (int nindices, Relation *Irel); static void vc_vpinsert (VPageList vpl, VPageDescr vpnew);
static Relation _vc_getarchrel(Relation heaprel); static void vc_free(Portal p, VRelList vrl);
static void _vc_archive(Relation archrel, HeapTuple htup); static void vc_getindices (Oid relid, int *nindices, Relation **Irel);
static bool _vc_isarchrel(char *rname); static void vc_clsindices (int nindices, Relation *Irel);
static void _vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc); static Relation vc_getarchrel(Relation heaprel);
static char * _vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *)); static void vc_archive(Relation archrel, HeapTuple htup);
static int _vc_cmp_blk (char *left, char *right); static bool vc_isarchrel(char *rname);
static int _vc_cmp_offno (char *left, char *right); static void vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
static bool _vc_enough_space (VPageDescr vpd, Size len); static char * vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *));
static int vc_cmp_blk (char *left, char *right);
static int vc_cmp_offno (char *left, char *right);
static bool vc_enough_space (VPageDescr vpd, Size len);
void void
vacuum(char *vacrel, bool verbose) vacuum(char *vacrel, bool verbose)
...@@ -93,30 +103,30 @@ vacuum(char *vacrel, bool verbose) ...@@ -93,30 +103,30 @@ vacuum(char *vacrel, bool verbose)
NameData VacRel; NameData VacRel;
if (verbose) if (verbose)
MESSLEV = NOTICE; MESSAGE_LEVEL = NOTICE;
else else
MESSLEV = DEBUG; MESSAGE_LEVEL = DEBUG;
/* vacrel gets de-allocated on transaction commit */ /* vacrel gets de-allocated on transaction commit */
/* initialize vacuum cleaner */ /* initialize vacuum cleaner */
_vc_init(); vc_init();
/* vacuum the database */ /* vacuum the database */
if (vacrel) if (vacrel)
{ {
strcpy(VacRel.data,vacrel); strcpy(VacRel.data,vacrel);
_vc_vacuum(&VacRel); vc_vacuum(&VacRel);
} }
else else
_vc_vacuum(NULL); vc_vacuum(NULL);
/* clean up */ /* clean up */
_vc_shutdown(); vc_shutdown();
} }
/* /*
* _vc_init(), _vc_shutdown() -- start up and shut down the vacuum cleaner. * vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
* *
* We run exactly one vacuum cleaner at a time. We use the file system * We run exactly one vacuum cleaner at a time. We use the file system
* to guarantee an exclusive lock on vacuuming, since a single vacuum * to guarantee an exclusive lock on vacuuming, since a single vacuum
...@@ -128,12 +138,12 @@ vacuum(char *vacrel, bool verbose) ...@@ -128,12 +138,12 @@ vacuum(char *vacrel, bool verbose)
* is invoked via a sql command, and so is already executing inside * is invoked via a sql command, and so is already executing inside
* a transaction. We need to leave ourselves in a predictable state * a transaction. We need to leave ourselves in a predictable state
* on entry and exit to the vacuum cleaner. We commit the transaction * on entry and exit to the vacuum cleaner. We commit the transaction
* started in PostgresMain() inside _vc_init(), and start one in * started in PostgresMain() inside vc_init(), and start one in
* _vc_shutdown() to match the commit waiting for us back in * vc_shutdown() to match the commit waiting for us back in
* PostgresMain(). * PostgresMain().
*/ */
static void static void
_vc_init() vc_init()
{ {
int fd; int fd;
...@@ -156,7 +166,7 @@ _vc_init() ...@@ -156,7 +166,7 @@ _vc_init()
} }
static void static void
_vc_shutdown() vc_shutdown()
{ {
/* on entry, not in a transaction */ /* on entry, not in a transaction */
if (unlink("pg_vlock") < 0) if (unlink("pg_vlock") < 0)
...@@ -167,6 +177,7 @@ _vc_shutdown() ...@@ -167,6 +177,7 @@ _vc_shutdown()
/* matches the CommitTransaction in PostgresMain() */ /* matches the CommitTransaction in PostgresMain() */
StartTransactionCommand(); StartTransactionCommand();
} }
void void
...@@ -179,7 +190,7 @@ vc_abort() ...@@ -179,7 +190,7 @@ vc_abort()
} }
/* /*
* _vc_vacuum() -- vacuum the database. * vc_vacuum() -- vacuum the database.
* *
* This routine builds a list of relations to vacuum, and then calls * This routine builds a list of relations to vacuum, and then calls
* code that vacuums them one at a time. We are careful to vacuum each * code that vacuums them one at a time. We are careful to vacuum each
...@@ -187,7 +198,7 @@ vc_abort() ...@@ -187,7 +198,7 @@ vc_abort()
* locks at one time. * locks at one time.
*/ */
static void static void
_vc_vacuum(NameData *VacRelP) vc_vacuum(NameData *VacRelP)
{ {
VRelList vrl, cur; VRelList vrl, cur;
char *pname; char *pname;
...@@ -206,19 +217,24 @@ _vc_vacuum(NameData *VacRelP) ...@@ -206,19 +217,24 @@ _vc_vacuum(NameData *VacRelP)
pfree(pname); pfree(pname);
/* get list of relations */ /* get list of relations */
vrl = _vc_getrels(p, VacRelP); vrl = vc_getrels(p, VacRelP);
if (VacRelP != NULL)
vc_delhilowstats(vrl->vrl_relid);
else
vc_delhilowstats(InvalidOid);
/* 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)
_vc_vacone (cur); vc_vacone (cur->vrl_relid);
_vc_free(p, vrl); vc_free(p, vrl);
PortalDestroy(&p); PortalDestroy(&p);
} }
static VRelList static VRelList
_vc_getrels(Portal p, NameData *VacRelP) vc_getrels(Portal p, NameData *VacRelP)
{ {
Relation pgclass; Relation pgclass;
TupleDesc pgcdesc; TupleDesc pgcdesc;
...@@ -246,7 +262,7 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -246,7 +262,7 @@ _vc_getrels(Portal p, NameData *VacRelP)
ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind, ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind,
CharacterEqualRegProcedure, CharGetDatum('r')); CharacterEqualRegProcedure, CharGetDatum('r'));
} }
portalmem = PortalGetVariableMemory(p); portalmem = PortalGetVariableMemory(p);
vrl = cur = (VRelList) NULL; vrl = cur = (VRelList) NULL;
...@@ -271,7 +287,7 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -271,7 +287,7 @@ _vc_getrels(Portal p, NameData *VacRelP)
rname = (char*)d; rname = (char*)d;
/* skip archive relations */ /* skip archive relations */
if (_vc_isarchrel(rname)) { if (vc_isarchrel(rname)) {
ReleaseBuffer(buf); ReleaseBuffer(buf);
continue; continue;
} }
...@@ -320,9 +336,6 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -320,9 +336,6 @@ _vc_getrels(Portal p, NameData *VacRelP)
(void) MemoryContextSwitchTo(old); (void) MemoryContextSwitchTo(old);
cur->vrl_relid = pgctup->t_oid; cur->vrl_relid = pgctup->t_oid;
cur->vrl_attlist = (VAttList) NULL;
cur->vrl_npages = cur->vrl_ntups = 0;
cur->vrl_hasindex = false;
cur->vrl_next = (VRelList) NULL; cur->vrl_next = (VRelList) NULL;
/* wei hates it if you forget to do this */ /* wei hates it if you forget to do this */
...@@ -332,8 +345,8 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -332,8 +345,8 @@ _vc_getrels(Portal p, NameData *VacRelP)
elog(NOTICE, "Vacuum: table not found" ); elog(NOTICE, "Vacuum: table not found" );
heap_close(pgclass);
heap_endscan(pgcscan); heap_endscan(pgcscan);
heap_close(pgclass);
CommitTransactionCommand(); CommitTransactionCommand();
...@@ -341,10 +354,10 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -341,10 +354,10 @@ _vc_getrels(Portal p, NameData *VacRelP)
} }
/* /*
* _vc_vacone() -- vacuum one heap relation * vc_vacone() -- vacuum one heap relation
* *
* This routine vacuums a single heap, cleans out its indices, and * This routine vacuums a single heap, cleans out its indices, and
* updates its statistics npages and ntuples statistics. * updates its statistics npages and ntups statistics.
* *
* Doing one heap at a time incurs extra overhead, since we need to * Doing one heap at a time incurs extra overhead, since we need to
* check that the heap exists again just before we vacuum it. The * check that the heap exists again just before we vacuum it. The
...@@ -353,11 +366,11 @@ _vc_getrels(Portal p, NameData *VacRelP) ...@@ -353,11 +366,11 @@ _vc_getrels(Portal p, NameData *VacRelP)
* us to lock the entire database during one pass of the vacuum cleaner. * us to lock the entire database during one pass of the vacuum cleaner.
*/ */
static void static void
_vc_vacone (VRelList curvrl) vc_vacone (Oid relid)
{ {
Relation pgclass; Relation pgclass;
TupleDesc pgcdesc; TupleDesc pgcdesc;
HeapTuple pgctup; HeapTuple pgctup, pgttup;
Buffer pgcbuf; Buffer pgcbuf;
HeapScanDesc pgcscan; HeapScanDesc pgcscan;
Relation onerel; Relation onerel;
...@@ -366,14 +379,15 @@ _vc_vacone (VRelList curvrl) ...@@ -366,14 +379,15 @@ _vc_vacone (VRelList curvrl)
VPageListData Fvpl; /* List of pages with space enough for re-using */ VPageListData Fvpl; /* List of pages with space enough for re-using */
VPageDescr *vpp; VPageDescr *vpp;
Relation *Irel; Relation *Irel;
int nindices; int32 nindices, i, attr_cnt;
int i; AttributeTupleForm *attr;
VRelStats *vacrelstats;
StartTransactionCommand(); StartTransactionCommand();
ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber, ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber,
ObjectIdEqualRegProcedure, ObjectIdEqualRegProcedure,
ObjectIdGetDatum(curvrl->vrl_relid)); ObjectIdGetDatum(relid));
pgclass = heap_openr(RelationRelationName); pgclass = heap_openr(RelationRelationName);
pgcdesc = RelationGetTupleDescriptor(pgclass); pgcdesc = RelationGetTupleDescriptor(pgclass);
...@@ -392,23 +406,80 @@ _vc_vacone (VRelList curvrl) ...@@ -392,23 +406,80 @@ _vc_vacone (VRelList curvrl)
} }
/* now open the class and vacuum it */ /* now open the class and vacuum it */
onerel = heap_open(curvrl->vrl_relid); onerel = heap_open(relid);
attr_cnt = onerel->rd_att->natts;
attr = onerel->rd_att->attrs;
vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
vacrelstats->relid = relid;
vacrelstats->npages = vacrelstats->ntups = 0;
vacrelstats->hasindex = false;
vacrelstats->vacattrstats =
(VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats));
for (i = 0; i < attr_cnt; i++) {
Operator func_operator;
OperatorTupleForm pgopform;
VacAttrStats *stats = &vacrelstats->vacattrstats[i];
stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
memmove(stats->attr,attr[i],ATTRIBUTE_TUPLE_SIZE);
stats->best = stats->guess1 = stats->guess2 = 0;
stats->max = stats->min = 0;
stats->best_len = stats->guess1_len = stats->guess2_len = 0;
stats->max_len = stats->min_len = 0;
stats->initialized = false;
stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
func_operator = oper("=",stats->attr->atttypid,stats->attr->atttypid,true);
if (func_operator != NULL) {
pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
stats->cmpeq = pgopform->oprcode;
}
else stats->cmpeq = InvalidOid;
func_operator = oper("<",stats->attr->atttypid,stats->attr->atttypid,true);
if (func_operator != NULL) {
pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
stats->cmplt = pgopform->oprcode;
}
else stats->cmplt = InvalidOid;
func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
if (func_operator != NULL) {
pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
stats->cmpgt = pgopform->oprcode;
}
else stats->cmpgt = InvalidOid;
func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
if (func_operator != NULL) {
pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
stats->cmpgt = pgopform->oprcode;
}
else stats->cmpgt = InvalidOid;
pgttup = SearchSysCacheTuple(TYPOID,
ObjectIdGetDatum(stats->attr->atttypid),
0,0,0);
if (HeapTupleIsValid(pgttup))
stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
else stats->outfunc = InvalidOid;
}
/* we require the relation to be locked until the indices are cleaned */ /* we require the relation to be locked until the indices are cleaned */
RelationSetLockForWrite(onerel); RelationSetLockForWrite(onerel);
/* scan it */ /* scan it */
Vvpl.vpl_npages = Fvpl.vpl_npages = 0; Vvpl.vpl_npages = Fvpl.vpl_npages = 0;
_vc_scanheap(curvrl, onerel, &Vvpl, &Fvpl); vc_scanheap(vacrelstats, onerel, &Vvpl, &Fvpl);
/* Now open indices */ /* Now open indices */
Irel = (Relation *) NULL; Irel = (Relation *) NULL;
_vc_getindices(curvrl->vrl_relid, &nindices, &Irel); vc_getindices(vacrelstats->relid, &nindices, &Irel);
if ( nindices > 0 ) if ( nindices > 0 )
curvrl->vrl_hasindex = true; vacrelstats->hasindex = true;
else else
curvrl->vrl_hasindex = false; vacrelstats->hasindex = false;
/* Clean/scan index relation(s) */ /* Clean/scan index relation(s) */
if ( Irel != (Relation*) NULL ) if ( Irel != (Relation*) NULL )
...@@ -416,23 +487,23 @@ _vc_vacone (VRelList curvrl) ...@@ -416,23 +487,23 @@ _vc_vacone (VRelList curvrl)
if ( Vvpl.vpl_npages > 0 ) if ( Vvpl.vpl_npages > 0 )
{ {
for (i = 0; i < nindices; i++) for (i = 0; i < nindices; i++)
_vc_vaconeind (&Vvpl, Irel[i], curvrl->vrl_ntups); vc_vaconeind (&Vvpl, Irel[i], vacrelstats->ntups);
} }
else /* just scan indices to update statistic */ else /* just scan indices to update statistic */
{ {
for (i = 0; i < nindices; i++) for (i = 0; i < nindices; i++)
_vc_scanoneind (Irel[i], curvrl->vrl_ntups); vc_scanoneind (Irel[i], vacrelstats->ntups);
} }
} }
if ( Fvpl.vpl_npages > 0 ) /* Try to shrink heap */ if ( Fvpl.vpl_npages > 0 ) /* Try to shrink heap */
_vc_rpfheap (curvrl, onerel, &Vvpl, &Fvpl, nindices, Irel); vc_rpfheap (vacrelstats, onerel, &Vvpl, &Fvpl, nindices, Irel);
else else
{ {
if ( Irel != (Relation*) NULL ) if ( Irel != (Relation*) NULL )
_vc_clsindices (nindices, Irel); vc_clsindices (nindices, Irel);
if ( Vvpl.vpl_npages > 0 ) /* Clean pages from Vvpl list */ if ( Vvpl.vpl_npages > 0 ) /* Clean pages from Vvpl list */
_vc_vacheap (curvrl, onerel, &Vvpl); vc_vacheap (vacrelstats, onerel, &Vvpl);
} }
/* ok - free Vvpl list of reapped pages */ /* ok - free Vvpl list of reapped pages */
...@@ -452,14 +523,18 @@ _vc_vacone (VRelList curvrl) ...@@ -452,14 +523,18 @@ _vc_vacone (VRelList curvrl)
heap_close(pgclass); heap_close(pgclass);
/* update statistics in pg_class */ /* update statistics in pg_class */
_vc_updstats(curvrl->vrl_relid, curvrl->vrl_npages, curvrl->vrl_ntups, vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
curvrl->vrl_hasindex); vacrelstats->hasindex, vacrelstats->vacattrstats);
/* next command frees everything anyway */
if (vacrelstats->vacattrstats != NULL)
pfree(vacrelstats);
CommitTransactionCommand(); CommitTransactionCommand();
} }
/* /*
* _vc_scanheap() -- scan an open heap relation * vc_scanheap() -- scan an open heap relation
* *
* This routine sets commit times, constructs Vvpl list of * This routine sets commit times, constructs Vvpl list of
* empty/uninitialized pages and pages with dead tuples and * empty/uninitialized pages and pages with dead tuples and
...@@ -468,7 +543,7 @@ _vc_vacone (VRelList curvrl) ...@@ -468,7 +543,7 @@ _vc_vacone (VRelList curvrl)
* on the number of live tuples in a heap. * on the number of live tuples in a heap.
*/ */
static void static void
_vc_scanheap (VRelList curvrl, Relation onerel, vc_scanheap (VRelStats *vacrelstats, Relation onerel,
VPageList Vvpl, VPageList Fvpl) VPageList Vvpl, VPageList Fvpl)
{ {
int nblocks, blkno; int nblocks, blkno;
...@@ -487,14 +562,14 @@ _vc_scanheap (VRelList curvrl, Relation onerel, ...@@ -487,14 +562,14 @@ _vc_scanheap (VRelList curvrl, Relation onerel,
Size frsize, frsusf; Size frsize, frsusf;
Size min_tlen = MAXTUPLEN; Size min_tlen = MAXTUPLEN;
Size max_tlen = 0; Size max_tlen = 0;
int i; int32 i/*, attr_cnt*/;
struct rusage ru0, ru1; struct rusage ru0, ru1;
getrusage(RUSAGE_SELF, &ru0); getrusage(RUSAGE_SELF, &ru0);
nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0; nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0;
frsize = frsusf = 0; frsize = frsusf = 0;
relname = (RelationGetRelationName(onerel))->data; relname = (RelationGetRelationName(onerel))->data;
nblocks = RelationGetNumberOfBlocks(onerel); nblocks = RelationGetNumberOfBlocks(onerel);
...@@ -532,7 +607,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel, ...@@ -532,7 +607,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel,
frsize += (vpc->vpd_free - sizeof (ItemIdData)); frsize += (vpc->vpd_free - sizeof (ItemIdData));
nnepg++; nnepg++;
nemend++; nemend++;
_vc_reappage (Vvpl, vpc); vc_reappage (Vvpl, vpc);
WriteBuffer(buf); WriteBuffer(buf);
continue; continue;
} }
...@@ -542,7 +617,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel, ...@@ -542,7 +617,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel,
frsize += (vpc->vpd_free - sizeof (ItemIdData)); frsize += (vpc->vpd_free - sizeof (ItemIdData));
nempg++; nempg++;
nemend++; nemend++;
_vc_reappage (Vvpl, vpc); vc_reappage (Vvpl, vpc);
ReleaseBuffer(buf); ReleaseBuffer(buf);
continue; continue;
} }
...@@ -585,7 +660,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel, ...@@ -585,7 +660,7 @@ _vc_scanheap (VRelList curvrl, Relation onerel,
tupgone = true; tupgone = true;
} }
else { else {
elog (MESSLEV, "Rel %.*s: InsertTransactionInProgress %u for TID %u/%u", elog (MESSAGE_LEVEL, "Rel %.*s: InsertTransactionInProgress %u for TID %u/%u",
NAMEDATALEN, relname, htup->t_xmin, blkno, offnum); NAMEDATALEN, relname, htup->t_xmin, blkno, offnum);
} }
} }
...@@ -677,6 +752,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -677,6 +752,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
min_tlen = htup->t_len; min_tlen = htup->t_len;
if ( htup->t_len > max_tlen ) if ( htup->t_len > max_tlen )
max_tlen = htup->t_len; max_tlen = htup->t_len;
vc_attrstats(onerel, vacrelstats->vacattrstats, htup);
} }
} }
...@@ -692,7 +768,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -692,7 +768,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
PageRepairFragmentation(tempPage); PageRepairFragmentation(tempPage);
vpc->vpd_free = ((PageHeader)tempPage)->pd_upper - ((PageHeader)tempPage)->pd_lower; vpc->vpd_free = ((PageHeader)tempPage)->pd_upper - ((PageHeader)tempPage)->pd_lower;
frsize += vpc->vpd_free; frsize += vpc->vpd_free;
_vc_reappage (Vvpl, vpc); vc_reappage (Vvpl, vpc);
pfree (tempPage); pfree (tempPage);
tempPage = (Page) NULL; tempPage = (Page) NULL;
} }
...@@ -700,7 +776,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -700,7 +776,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
{ /* there are only ~LP_USED line pointers */ { /* there are only ~LP_USED line pointers */
vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower; vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
frsize += vpc->vpd_free; frsize += vpc->vpd_free;
_vc_reappage (Vvpl, vpc); vc_reappage (Vvpl, vpc);
} }
if ( dobufrel ) if ( dobufrel )
ReleaseBuffer(buf); ReleaseBuffer(buf);
...@@ -713,12 +789,13 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -713,12 +789,13 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
pfree (vpc); pfree (vpc);
/* save stats in the rel list for use later */ /* save stats in the rel list for use later */
curvrl->vrl_ntups = ntups; vacrelstats->ntups = ntups;
curvrl->vrl_npages = nblocks; vacrelstats->npages = nblocks;
/* vacrelstats->natts = attr_cnt;*/
if ( ntups == 0 ) if ( ntups == 0 )
min_tlen = max_tlen = 0; min_tlen = max_tlen = 0;
curvrl->vrl_min_tlen = min_tlen; vacrelstats->min_tlen = min_tlen;
curvrl->vrl_max_tlen = max_tlen; vacrelstats->max_tlen = max_tlen;
Vvpl->vpl_nemend = nemend; Vvpl->vpl_nemend = nemend;
Fvpl->vpl_nemend = nemend; Fvpl->vpl_nemend = nemend;
...@@ -738,9 +815,9 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -738,9 +815,9 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
for (i = 0; i < nusf; i++) for (i = 0; i < nusf; i++)
{ {
vp = Vvpl->vpl_pgdesc[i]; vp = Vvpl->vpl_pgdesc[i];
if ( _vc_enough_space (vp, min_tlen) ) if ( vc_enough_space (vp, min_tlen) )
{ {
_vc_vpinsert (Fvpl, vp); vc_vpinsert (Fvpl, vp);
frsusf += vp->vpd_free; frsusf += vp->vpd_free;
} }
} }
...@@ -748,7 +825,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.", ...@@ -748,7 +825,7 @@ DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
getrusage(RUSAGE_SELF, &ru1); getrusage(RUSAGE_SELF, &ru1);
elog (MESSLEV, "Rel %.*s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \ elog (MESSAGE_LEVEL, "Rel %.*s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. Elapsed %u/%u sec.", Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. Elapsed %u/%u sec.",
NAMEDATALEN, relname, NAMEDATALEN, relname,
nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg, nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg,
...@@ -757,11 +834,11 @@ Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. ...@@ -757,11 +834,11 @@ Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail.
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec, ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec); ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
} /* _vc_scanheap */ } /* vc_scanheap */
/* /*
* _vc_rpfheap() -- try to repaire relation' fragmentation * vc_rpfheap() -- try to repaire relation' fragmentation
* *
* This routine marks dead tuples as unused and tries re-use dead space * This routine marks dead tuples as unused and tries re-use dead space
* by moving tuples (and inserting indices if needed). It constructs * by moving tuples (and inserting indices if needed). It constructs
...@@ -771,7 +848,7 @@ Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. ...@@ -771,7 +848,7 @@ Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail.
* if some end-blocks are gone away. * if some end-blocks are gone away.
*/ */
static void static void
_vc_rpfheap (VRelList curvrl, Relation onerel, vc_rpfheap (VRelStats *vacrelstats, Relation onerel,
VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel) VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel)
{ {
TransactionId myXID; TransactionId myXID;
...@@ -806,7 +883,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -806,7 +883,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
if ( Irel != (Relation*) NULL ) /* preparation for index' inserts */ if ( Irel != (Relation*) NULL ) /* preparation for index' inserts */
{ {
_vc_mkindesc (onerel, nindices, Irel, &Idesc); vc_mkindesc (onerel, nindices, Irel, &Idesc);
tupdesc = RelationGetTupleDescriptor(onerel); tupdesc = RelationGetTupleDescriptor(onerel);
idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof (*idatum)); idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof (*idatum));
inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof (*inulls)); inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof (*inulls));
...@@ -815,7 +892,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -815,7 +892,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
/* if the relation has an archive, open it */ /* if the relation has an archive, open it */
if (onerel->rd_rel->relarch != 'n') if (onerel->rd_rel->relarch != 'n')
{ {
archrel = _vc_getarchrel(onerel); archrel = vc_getarchrel(onerel);
/* Archive tuples from "empty" end-pages */ /* Archive tuples from "empty" end-pages */
for ( vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1, for ( vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1,
i = Vvpl->vpl_nemend; i > 0; i--, vpp-- ) i = Vvpl->vpl_nemend; i > 0; i--, vpp-- )
...@@ -825,7 +902,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -825,7 +902,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
buf = ReadBuffer(onerel, (*vpp)->vpd_blkno); buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
page = BufferGetPage(buf); page = BufferGetPage(buf);
Assert ( !PageIsEmpty(page) ); Assert ( !PageIsEmpty(page) );
_vc_vacpage (page, *vpp, archrel); vc_vacpage (page, *vpp, archrel);
WriteBuffer (buf); WriteBuffer (buf);
} }
} }
...@@ -848,7 +925,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -848,7 +925,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber)); vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber));
vpc->vpd_nusd = vpc->vpd_noff = 0; vpc->vpd_nusd = vpc->vpd_noff = 0;
nblocks = curvrl->vrl_npages; nblocks = vacrelstats->npages;
for (blkno = nblocks - Vvpl->vpl_nemend - 1; ; blkno--) for (blkno = nblocks - Vvpl->vpl_nemend - 1; ; blkno--)
{ {
/* if it's reapped page and it was used by me - quit */ /* if it's reapped page and it was used by me - quit */
...@@ -868,7 +945,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -868,7 +945,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
if ( Vvplast->vpd_noff > 0 ) /* there are dead tuples */ if ( Vvplast->vpd_noff > 0 ) /* there are dead tuples */
{ /* on this page - clean */ { /* on this page - clean */
Assert ( ! isempty ); Assert ( ! isempty );
_vc_vacpage (page, Vvplast, archrel); vc_vacpage (page, Vvplast, archrel);
dowrite = true; dowrite = true;
} }
else else
...@@ -913,7 +990,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -913,7 +990,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
/* try to find new page for this tuple */ /* try to find new page for this tuple */
if ( ToBuf == InvalidBuffer || if ( ToBuf == InvalidBuffer ||
! _vc_enough_space (ToVpd, tlen) ) ! vc_enough_space (ToVpd, tlen) )
{ {
if ( ToBuf != InvalidBuffer ) if ( ToBuf != InvalidBuffer )
{ {
...@@ -923,7 +1000,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -923,7 +1000,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
* If no one tuple can't be added to this page - * If no one tuple can't be added to this page -
* remove page from Fvpl. - vadim 11/27/96 * remove page from Fvpl. - vadim 11/27/96
*/ */
if ( !_vc_enough_space (ToVpd, curvrl->vrl_min_tlen) ) if ( !vc_enough_space (ToVpd, vacrelstats->min_tlen) )
{ {
if ( ToVpd != Fvplast ) if ( ToVpd != Fvplast )
{ {
...@@ -943,7 +1020,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -943,7 +1020,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
} }
for (i=0; i < Fnpages; i++) for (i=0; i < Fnpages; i++)
{ {
if ( _vc_enough_space (Fvpl->vpl_pgdesc[i], tlen) ) if ( vc_enough_space (Fvpl->vpl_pgdesc[i], tlen) )
break; break;
} }
if ( i == Fnpages ) if ( i == Fnpages )
...@@ -954,7 +1031,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel, ...@@ -954,7 +1031,7 @@ _vc_rpfheap (VRelList curvrl, Relation onerel,
ToPage = BufferGetPage(ToBuf); ToPage = BufferGetPage(ToBuf);
/* if this page was not used before - clean it */ /* if this page was not used before - clean it */
if ( ! PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0 ) if ( ! PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0 )
_vc_vacpage (ToPage, ToVpd, archrel); vc_vacpage (ToPage, ToVpd, archrel);
} }
/* copy tuple */ /* copy tuple */
...@@ -1022,7 +1099,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", ...@@ -1022,7 +1099,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if ( vpc->vpd_noff > 0 ) /* some tuples were moved */ if ( vpc->vpd_noff > 0 ) /* some tuples were moved */
{ {
_vc_reappage (&Nvpl, vpc); vc_reappage (&Nvpl, vpc);
WriteBuffer(buf); WriteBuffer(buf);
} }
else if ( dowrite ) else if ( dowrite )
...@@ -1071,7 +1148,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", ...@@ -1071,7 +1148,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
{ {
/* noff == 0 in empty pages only - such pages should be re-used */ /* noff == 0 in empty pages only - such pages should be re-used */
Assert ( (*vpp)->vpd_noff > 0 ); Assert ( (*vpp)->vpd_noff > 0 );
_vc_vacpage (page, *vpp, archrel); vc_vacpage (page, *vpp, archrel);
} }
else /* this page was used */ else /* this page was used */
{ {
...@@ -1100,7 +1177,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", ...@@ -1100,7 +1177,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
getrusage(RUSAGE_SELF, &ru1); getrusage(RUSAGE_SELF, &ru1);
elog (MESSLEV, "Rel %.*s: Pages: %u --> %u; Tuple(s) moved: %u. \ elog (MESSAGE_LEVEL, "Rel %.*s: Pages: %u --> %u; Tuple(s) moved: %u. \
Elapsed %u/%u sec.", Elapsed %u/%u sec.",
NAMEDATALEN, (RelationGetRelationName(onerel))->data, NAMEDATALEN, (RelationGetRelationName(onerel))->data,
nblocks, blkno, nmoved, nblocks, blkno, nmoved,
...@@ -1122,7 +1199,7 @@ Elapsed %u/%u sec.", ...@@ -1122,7 +1199,7 @@ Elapsed %u/%u sec.",
vpsave = *vpleft; *vpleft = *vpright; *vpright = vpsave; vpsave = *vpleft; *vpleft = *vpright; *vpright = vpsave;
} }
for (i = 0; i < nindices; i++) for (i = 0; i < nindices; i++)
_vc_vaconeind (&Nvpl, Irel[i], curvrl->vrl_ntups); vc_vaconeind (&Nvpl, Irel[i], vacrelstats->ntups);
} }
/* /*
...@@ -1165,7 +1242,7 @@ Elapsed %u/%u sec.", ...@@ -1165,7 +1242,7 @@ Elapsed %u/%u sec.",
{ {
blkno = smgrtruncate (onerel->rd_rel->relsmgr, onerel, blkno); blkno = smgrtruncate (onerel->rd_rel->relsmgr, onerel, blkno);
Assert ( blkno >= 0 ); Assert ( blkno >= 0 );
curvrl->vrl_npages = blkno; /* set new number of blocks */ vacrelstats->npages = blkno; /* set new number of blocks */
} }
if ( archrel != (Relation) NULL ) if ( archrel != (Relation) NULL )
...@@ -1176,21 +1253,21 @@ Elapsed %u/%u sec.", ...@@ -1176,21 +1253,21 @@ Elapsed %u/%u sec.",
pfree (Idesc); pfree (Idesc);
pfree (idatum); pfree (idatum);
pfree (inulls); pfree (inulls);
_vc_clsindices (nindices, Irel); vc_clsindices (nindices, Irel);
} }
pfree (vpc); pfree (vpc);
} /* _vc_rpfheap */ } /* vc_rpfheap */
/* /*
* _vc_vacheap() -- free dead tuples * vc_vacheap() -- free dead tuples
* *
* This routine marks dead tuples as unused and truncates relation * This routine marks dead tuples as unused and truncates relation
* if there are "empty" end-blocks. * if there are "empty" end-blocks.
*/ */
static void static void
_vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl) vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl)
{ {
Buffer buf; Buffer buf;
Page page; Page page;
...@@ -1202,7 +1279,7 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl) ...@@ -1202,7 +1279,7 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl)
nblocks = Vvpl->vpl_npages; nblocks = Vvpl->vpl_npages;
/* if the relation has an archive, open it */ /* if the relation has an archive, open it */
if (onerel->rd_rel->relarch != 'n') if (onerel->rd_rel->relarch != 'n')
archrel = _vc_getarchrel(onerel); archrel = vc_getarchrel(onerel);
else else
{ {
archrel = (Relation) NULL; archrel = (Relation) NULL;
...@@ -1215,7 +1292,7 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl) ...@@ -1215,7 +1292,7 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl)
{ {
buf = ReadBuffer(onerel, (*vpp)->vpd_blkno); buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
page = BufferGetPage (buf); page = BufferGetPage (buf);
_vc_vacpage (page, *vpp, archrel); vc_vacpage (page, *vpp, archrel);
WriteBuffer (buf); WriteBuffer (buf);
} }
} }
...@@ -1223,11 +1300,11 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl) ...@@ -1223,11 +1300,11 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl)
/* truncate relation if there are some empty end-pages */ /* truncate relation if there are some empty end-pages */
if ( Vvpl->vpl_nemend > 0 ) if ( Vvpl->vpl_nemend > 0 )
{ {
Assert ( curvrl->vrl_npages >= Vvpl->vpl_nemend ); Assert ( vacrelstats->npages >= Vvpl->vpl_nemend );
nblocks = curvrl->vrl_npages - Vvpl->vpl_nemend; nblocks = vacrelstats->npages - Vvpl->vpl_nemend;
elog (MESSLEV, "Rel %.*s: Pages: %u --> %u.", elog (MESSAGE_LEVEL, "Rel %.*s: Pages: %u --> %u.",
NAMEDATALEN, (RelationGetRelationName(onerel))->data, NAMEDATALEN, (RelationGetRelationName(onerel))->data,
curvrl->vrl_npages, nblocks); vacrelstats->npages, nblocks);
/* /*
* we have to flush "empty" end-pages (if changed, but who knows it) * we have to flush "empty" end-pages (if changed, but who knows it)
...@@ -1237,20 +1314,20 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl) ...@@ -1237,20 +1314,20 @@ _vc_vacheap (VRelList curvrl, Relation onerel, VPageList Vvpl)
nblocks = smgrtruncate (onerel->rd_rel->relsmgr, onerel, nblocks); nblocks = smgrtruncate (onerel->rd_rel->relsmgr, onerel, nblocks);
Assert ( nblocks >= 0 ); Assert ( nblocks >= 0 );
curvrl->vrl_npages = nblocks; /* set new number of blocks */ vacrelstats->npages = nblocks; /* set new number of blocks */
} }
if ( archrel != (Relation) NULL ) if ( archrel != (Relation) NULL )
heap_close(archrel); heap_close(archrel);
} /* _vc_vacheap */ } /* vc_vacheap */
/* /*
* _vc_vacpage() -- free (and archive if needed) dead tuples on a page * vc_vacpage() -- free (and archive if needed) dead tuples on a page
* and repaire its fragmentation. * and repaire its fragmentation.
*/ */
static void static void
_vc_vacpage (Page page, VPageDescr vpd, Relation archrel) vc_vacpage (Page page, VPageDescr vpd, Relation archrel)
{ {
ItemId itemid; ItemId itemid;
HeapTuple htup; HeapTuple htup;
...@@ -1263,20 +1340,20 @@ _vc_vacpage (Page page, VPageDescr vpd, Relation archrel) ...@@ -1263,20 +1340,20 @@ _vc_vacpage (Page page, VPageDescr vpd, Relation archrel)
if ( archrel != (Relation) NULL && ItemIdIsUsed(itemid) ) if ( archrel != (Relation) NULL && ItemIdIsUsed(itemid) )
{ {
htup = (HeapTuple) PageGetItem (page, itemid); htup = (HeapTuple) PageGetItem (page, itemid);
_vc_archive (archrel, htup); vc_archive (archrel, htup);
} }
itemid->lp_flags &= ~LP_USED; itemid->lp_flags &= ~LP_USED;
} }
PageRepairFragmentation(page); PageRepairFragmentation(page);
} /* _vc_vacpage */ } /* vc_vacpage */
/* /*
* _vc_scanoneind() -- scan one index relation to update statistic. * _vc_scanoneind() -- scan one index relation to update statistic.
* *
*/ */
static void static void
_vc_scanoneind (Relation indrel, int nhtups) vc_scanoneind (Relation indrel, int nhtups)
{ {
RetrieveIndexResult res; RetrieveIndexResult res;
IndexScanDesc iscan; IndexScanDesc iscan;
...@@ -1301,11 +1378,11 @@ _vc_scanoneind (Relation indrel, int nhtups) ...@@ -1301,11 +1378,11 @@ _vc_scanoneind (Relation indrel, int nhtups)
/* now update statistics in pg_class */ /* now update statistics in pg_class */
nipages = RelationGetNumberOfBlocks(indrel); nipages = RelationGetNumberOfBlocks(indrel);
_vc_updstats(indrel->rd_id, nipages, nitups, false); vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
getrusage(RUSAGE_SELF, &ru1); getrusage(RUSAGE_SELF, &ru1);
elog (MESSLEV, "Ind %.*s: Pages %u; Tuples %u. Elapsed %u/%u sec.", elog (MESSAGE_LEVEL, "Ind %.*s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
NAMEDATALEN, indrel->rd_rel->relname.data, nipages, nitups, NAMEDATALEN, indrel->rd_rel->relname.data, nipages, nitups,
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec, ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec); ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
...@@ -1314,10 +1391,10 @@ _vc_scanoneind (Relation indrel, int nhtups) ...@@ -1314,10 +1391,10 @@ _vc_scanoneind (Relation indrel, int nhtups)
elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)", elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
nitups, nhtups); nitups, nhtups);
} /* _vc_scanoneind */ } /* vc_scanoneind */
/* /*
* _vc_vaconeind() -- vacuum one index relation. * vc_vaconeind() -- vacuum one index relation.
* *
* Vpl is the VPageList of the heap we're currently vacuuming. * Vpl is the VPageList of the heap we're currently vacuuming.
* It's locked. Indrel is an index relation on the vacuumed heap. * It's locked. Indrel is an index relation on the vacuumed heap.
...@@ -1329,7 +1406,7 @@ _vc_scanoneind (Relation indrel, int nhtups) ...@@ -1329,7 +1406,7 @@ _vc_scanoneind (Relation indrel, int nhtups)
* pg_class. * pg_class.
*/ */
static void static void
_vc_vaconeind(VPageList vpl, Relation indrel, int nhtups) vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
{ {
RetrieveIndexResult res; RetrieveIndexResult res;
IndexScanDesc iscan; IndexScanDesc iscan;
...@@ -1351,7 +1428,7 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups) ...@@ -1351,7 +1428,7 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
!= (RetrieveIndexResult) NULL) { != (RetrieveIndexResult) NULL) {
heapptr = &res->heap_iptr; heapptr = &res->heap_iptr;
if ( (vp = _vc_tidreapped (heapptr, vpl)) != (VPageDescr) NULL) if ( (vp = vc_tidreapped (heapptr, vpl)) != (VPageDescr) NULL)
{ {
#if 0 #if 0
elog(DEBUG, "<%x,%x> -> <%x,%x>", elog(DEBUG, "<%x,%x> -> <%x,%x>",
...@@ -1380,11 +1457,11 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups) ...@@ -1380,11 +1457,11 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
/* now update statistics in pg_class */ /* now update statistics in pg_class */
nipages = RelationGetNumberOfBlocks(indrel); nipages = RelationGetNumberOfBlocks(indrel);
_vc_updstats(indrel->rd_id, nipages, nitups, false); vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
getrusage(RUSAGE_SELF, &ru1); getrusage(RUSAGE_SELF, &ru1);
elog (MESSLEV, "Ind %.*s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.", elog (MESSAGE_LEVEL, "Ind %.*s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
NAMEDATALEN, indrel->rd_rel->relname.data, nipages, nitups, nvac, NAMEDATALEN, indrel->rd_rel->relname.data, nipages, nitups, nvac,
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec, ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec); ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
...@@ -1393,15 +1470,15 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups) ...@@ -1393,15 +1470,15 @@ _vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)", elog (NOTICE, "NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
nitups, nhtups); nitups, nhtups);
} /* _vc_vaconeind */ } /* vc_vaconeind */
/* /*
* _vc_tidreapped() -- is a particular tid reapped? * vc_tidreapped() -- is a particular tid reapped?
* *
* vpl->VPageDescr_array is sorted in right order. * vpl->VPageDescr_array is sorted in right order.
*/ */
static VPageDescr static VPageDescr
_vc_tidreapped(ItemPointer itemptr, VPageList vpl) vc_tidreapped(ItemPointer itemptr, VPageList vpl)
{ {
OffsetNumber ioffno; OffsetNumber ioffno;
OffsetNumber *voff; OffsetNumber *voff;
...@@ -1412,9 +1489,9 @@ _vc_tidreapped(ItemPointer itemptr, VPageList vpl) ...@@ -1412,9 +1489,9 @@ _vc_tidreapped(ItemPointer itemptr, VPageList vpl)
ioffno = ItemPointerGetOffsetNumber(itemptr); ioffno = ItemPointerGetOffsetNumber(itemptr);
vp = &vpd; vp = &vpd;
vpp = (VPageDescr*) _vc_find_eq ((char*)(vpl->vpl_pgdesc), vpp = (VPageDescr*) vc_find_eq ((char*)(vpl->vpl_pgdesc),
vpl->vpl_npages, sizeof (VPageDescr), (char*)&vp, vpl->vpl_npages, sizeof (VPageDescr), (char*)&vp,
_vc_cmp_blk); vc_cmp_blk);
if ( vpp == (VPageDescr*) NULL ) if ( vpp == (VPageDescr*) NULL )
return ((VPageDescr)NULL); return ((VPageDescr)NULL);
...@@ -1426,74 +1503,333 @@ _vc_tidreapped(ItemPointer itemptr, VPageList vpl) ...@@ -1426,74 +1503,333 @@ _vc_tidreapped(ItemPointer itemptr, VPageList vpl)
return (vp); return (vp);
} }
voff = (OffsetNumber*) _vc_find_eq ((char*)(vp->vpd_voff), voff = (OffsetNumber*) vc_find_eq ((char*)(vp->vpd_voff),
vp->vpd_noff, sizeof (OffsetNumber), (char*)&ioffno, vp->vpd_noff, sizeof (OffsetNumber), (char*)&ioffno,
_vc_cmp_offno); vc_cmp_offno);
if ( voff == (OffsetNumber*) NULL ) if ( voff == (OffsetNumber*) NULL )
return ((VPageDescr)NULL); return ((VPageDescr)NULL);
return (vp); return (vp);
} /* _vc_tidreapped */ } /* vc_tidreapped */
/*
* vc_attrstats() -- compute column statistics used by the optimzer
*
* We compute the column min, max, null and non-null counts.
* Plus we attempt to find the count of the value that occurs most
* frequently in each column
* These figures are used to compute the selectivity of the column
*
* We use a three-bucked cache to get the most frequent item
* The 'guess' buckets count hits. A cache miss causes guess1
* to get the most hit 'guess' item in the most recent cycle, and
* the new item goes into guess2. Whenever the total count of hits
* of a 'guess' entry is larger than 'best', 'guess' becomes 'best'.
*
* This method works perfectly for columns with unique values, and columns
* with only two unique values, plus nulls.
*
* It becomes less perfect as the number of unique values increases and
* their distribution in the table becomes more random.
*
*/
static void
vc_attrstats(Relation onerel, VacAttrStats *vacattrstats, HeapTuple htup)
{
int i, attr_cnt;
AttributeTupleForm *attr;
TupleDesc tupDesc;
Datum value;
bool isnull;
attr_cnt = onerel->rd_att->natts;
attr = onerel->rd_att->attrs;
tupDesc = onerel->rd_att;
for (i = 0; i < attr_cnt; i++) {
VacAttrStats *stats = &vacattrstats[i];
bool value_hit = true;
value = (Datum) heap_getattr(htup, InvalidBuffer, i+1, tupDesc, &isnull);
if (!VacAttrStatsEqValid(stats))
continue;
if (isnull)
stats->null_cnt++;
else {
stats->nonnull_cnt++;
if (stats->initialized == false) {
vc_bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
/* best_cnt gets incremented later */
vc_bucketcpy(stats->attr, value, &stats->guess1, &stats->guess1_len);
stats->guess1_cnt = stats->guess1_hits = 1;
vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
stats->guess2_hits = 1;
if (VacAttrStatsLtGtValid(stats)) {
vc_bucketcpy(stats->attr, value, &stats->max , &stats->max_len);
vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
}
stats->initialized = true;
}
if (VacAttrStatsLtGtValid(stats) && fmgr(stats->cmplt,value,stats->min)) {
vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
stats->min_cnt = 0;
}
if (VacAttrStatsLtGtValid(stats) && fmgr(stats->cmpgt,value,stats->max)) {
vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
stats->max_cnt = 0;
}
if (VacAttrStatsLtGtValid(stats) && fmgr(stats->cmpeq,value,stats->min))
stats->min_cnt++;
else if (VacAttrStatsLtGtValid(stats) && fmgr(stats->cmpeq,value,stats->max))
stats-> max_cnt++;
if (fmgr(stats->cmpeq,value,stats->best))
stats-> best_cnt++;
else if (fmgr(stats->cmpeq,value,stats->guess1)) {
stats->guess1_cnt++;
stats-> guess1_hits++;
}
else if (fmgr(stats->cmpeq,value,stats->guess2))
stats->guess2_hits++;
else value_hit = false;
if (stats->guess2_hits > stats->guess1_hits) {
swapDatum(stats->guess1,stats->guess2);
swapInt(stats->guess1_len,stats->guess2_len);
stats->guess1_cnt = stats->guess2_hits;
swapLong(stats->guess1_hits, stats->guess2_hits);
}
if (stats->guess1_cnt > stats->best_cnt) {
swapDatum(stats->best,stats->guess1);
swapLong(stats->best_cnt,stats->guess1_cnt);
stats->guess1_hits = 1;
stats-> guess2_hits = 1;
}
if (!value_hit) {
vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
stats->guess1_hits = 1;
stats-> guess2_hits = 1;
}
}
}
return;
}
/*
* vc_bucketcpy() -- update pg_class statistics for one relation
*
*/
static void
vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len)
{
if (attr->attbyval && attr->attlen != -1)
*bucket = value;
else {
int len = (attr->attlen != -1 ? attr->attlen : VARSIZE(value));
if (len > *bucket_len)
{
if (*bucket_len != 0)
pfree(DatumGetPointer(*bucket));
*bucket = PointerGetDatum(palloc(len));
*bucket_len = len;
}
memmove(DatumGetPointer(*bucket), DatumGetPointer(value), len);
}
}
/* /*
* _vc_updstats() -- update pg_class statistics for one relation * vc_updstats() -- update pg_class statistics for one relation
* *
* This routine works for both index and heap relation entries in * This routine works for both index and heap relation entries in
* pg_class. We violate no-overwrite semantics here by storing new * pg_class. We violate no-overwrite semantics here by storing new
* values for ntuples, npages, and hasindex directly in the pg_class * values for ntups, npages, and hasindex directly in the pg_class
* tuple that's already on the page. The reason for this is that if * tuple that's already on the page. The reason for this is that if
* we updated these tuples in the usual way, then every tuple in pg_class * we updated these tuples in the usual way, then every tuple in pg_class
* would be replaced every day. This would make planning and executing * would be replaced every day. This would make planning and executing
* historical queries very expensive. * historical queries very expensive.
*/ */
static void static void
_vc_updstats(Oid relid, int npages, int ntuples, bool hasindex) vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VacAttrStats *vacattrstats)
{ {
Relation rd; Relation rd, ad, sd;
HeapScanDesc sdesc; HeapScanDesc rsdesc, asdesc;
HeapTuple tup; TupleDesc sdesc;
Buffer buf; HeapTuple rtup, atup, stup;
Buffer rbuf, abuf;
Form_pg_class pgcform; Form_pg_class pgcform;
ScanKeyData skey; ScanKeyData rskey, askey;
AttributeTupleForm attp;
/* /*
* update number of tuples and number of pages in pg_class * update number of tuples and number of pages in pg_class
*/ */
ScanKeyEntryInitialize(&skey, 0x0, ObjectIdAttributeNumber, ScanKeyEntryInitialize(&rskey, 0x0, ObjectIdAttributeNumber,
ObjectIdEqualRegProcedure, ObjectIdEqualRegProcedure,
ObjectIdGetDatum(relid)); ObjectIdGetDatum(relid));
rd = heap_openr(RelationRelationName); rd = heap_openr(RelationRelationName);
sdesc = heap_beginscan(rd, false, NowTimeQual, 1, &skey); rsdesc = heap_beginscan(rd, false, NowTimeQual, 1, &rskey);
if (!HeapTupleIsValid(tup = heap_getnext(sdesc, 0, &buf))) if (!HeapTupleIsValid(rtup = heap_getnext(rsdesc, 0, &rbuf)))
elog(WARN, "pg_class entry for relid %d vanished during vacuuming", elog(WARN, "pg_class entry for relid %d vanished during vacuuming",
relid); relid);
/* overwrite the existing statistics in the tuple */ /* overwrite the existing statistics in the tuple */
_vc_setpagelock(rd, BufferGetBlockNumber(buf)); vc_setpagelock(rd, BufferGetBlockNumber(rbuf));
pgcform = (Form_pg_class) GETSTRUCT(tup); pgcform = (Form_pg_class) GETSTRUCT(rtup);
pgcform->reltuples = ntuples; pgcform->reltuples = ntups;
pgcform->relpages = npages; pgcform->relpages = npages;
pgcform->relhasindex = hasindex; pgcform->relhasindex = hasindex;
if (vacattrstats != NULL)
{
ad = heap_openr(AttributeRelationName);
sd = heap_openr(StatisticRelationName);
ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
F_INT4EQ, relid);
asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf))) {
int slot, i;
double selratio; /* average ratio of rows selected for a random constant */
VacAttrStats *stats;
Datum values[ Natts_pg_statistic ];
char nulls[ Natts_pg_statistic ];
attp = (AttributeTupleForm) GETSTRUCT(atup);
slot = attp->attnum - 1;
if (slot < 0) /* skip system attributes for now,
they are unique anyway */
continue;
stats = &vacattrstats[slot];
/* overwrite the existing statistics in the tuple */
if (VacAttrStatsEqValid(stats)) {
vc_setpagelock(ad, BufferGetBlockNumber(abuf));
if (stats->nonnull_cnt + stats->null_cnt == 0 ||
(stats->null_cnt <= 1 && stats->best_cnt == 1))
selratio = 0;
else if (VacAttrStatsLtGtValid(stats) && stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
{
double min_cnt_d = stats->min_cnt,
max_cnt_d = stats->max_cnt,
null_cnt_d = stats->null_cnt,
nonnullcnt_d = stats->nonnull_cnt; /* prevent overflow */
selratio = (min_cnt_d*min_cnt_d+max_cnt_d*max_cnt_d+null_cnt_d*null_cnt_d)/
(nonnullcnt_d+null_cnt_d)/(nonnullcnt_d+null_cnt_d);
}
else {
double most = (double)(stats->best_cnt > stats->null_cnt ? stats->best_cnt : stats->null_cnt);
double total = ((double)stats->nonnull_cnt)+((double)stats->null_cnt);
/* we assume count of other values are 20%
of best count in table */
selratio = (most*most + 0.20*most*(total-most))/total/total;
}
if (selratio > 1.0)
selratio = 1.0;
attp->attnvals = (selratio ? (selratio * ATTNVALS_SCALE) : 0);
WriteNoReleaseBuffer(abuf);
/* DO PG_STATISTIC INSERTS */
/* doing system relations, especially pg_statistic is a problem */
if (VacAttrStatsLtGtValid(stats) && stats->initialized /* &&
!IsSystemRelationName(pgcform->relname.data)*/) {
func_ptr out_function;
char *out_string;
int dummy;
for (i = 0; i < Natts_pg_statistic; ++i) nulls[i] = ' ';
/* ----------------
* initialize values[]
* ----------------
*/
i = 0;
values[i++] = (Datum) relid; /* 1 */
values[i++] = (Datum) attp->attnum; /* 2 */
values[i++] = (Datum) InvalidOid; /* 3 */
fmgr_info(stats->outfunc, &out_function, &dummy);
out_string = (*out_function)(stats->min, stats->attr->atttypid);
values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
pfree(out_string);
out_string = (char *)(*out_function)(stats->max, stats->attr->atttypid);
values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
pfree(out_string);
sdesc = sd->rd_att;
stup = heap_formtuple(sdesc, values, nulls);
/* ----------------
* insert the tuple in the relation and get the tuple's oid.
* ----------------
*/
heap_insert(sd, stup);
pfree(DatumGetPointer(values[3]));
pfree(DatumGetPointer(values[4]));
pfree(stup);
}
}
}
heap_endscan(asdesc);
heap_close(ad);
heap_close(sd);
}
/* XXX -- after write, should invalidate relcache in other backends */ /* XXX -- after write, should invalidate relcache in other backends */
WriteNoReleaseBuffer(buf); /* heap_endscan release scan' buffers ? */ WriteNoReleaseBuffer(rbuf); /* heap_endscan release scan' buffers ? */
/* invalidating system relations confuses the function cache /* invalidating system relations confuses the function cache
of pg_operator and pg_opclass */ of pg_operator and pg_opclass */
if ( !IsSystemRelationName(pgcform->relname.data)) if ( !IsSystemRelationName(pgcform->relname.data))
RelationInvalidateHeapTuple(rd, tup); RelationInvalidateHeapTuple(rd, rtup);
/* that's all, folks */ /* that's all, folks */
heap_endscan(sdesc); heap_endscan(rsdesc);
heap_close(rd); heap_close(rd);
} }
static void _vc_setpagelock(Relation rel, BlockNumber blkno) /*
* vc_delhilowstats() -- delete pg_statistics rows
*
*/
static void
vc_delhilowstats(Oid relid)
{
Relation pgstatistic;
HeapScanDesc pgsscan;
HeapTuple pgstup;
ScanKeyData pgskey;
pgstatistic = heap_openr(StatisticRelationName);
if (relid != InvalidOid ) {
ScanKeyEntryInitialize(&pgskey, 0x0, Anum_pg_statistic_starelid,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(relid));
pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 1, &pgskey);
}
else
pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL))) {
heap_delete(pgstatistic, &pgstup->t_ctid);
}
heap_endscan(pgsscan);
heap_close(pgstatistic);
}
static void vc_setpagelock(Relation rel, BlockNumber blkno)
{ {
ItemPointerData itm; ItemPointerData itm;
...@@ -1504,14 +1840,14 @@ static void _vc_setpagelock(Relation rel, BlockNumber blkno) ...@@ -1504,14 +1840,14 @@ static void _vc_setpagelock(Relation rel, BlockNumber blkno)
/* /*
* _vc_reappage() -- save a page on the array of reapped pages. * vc_reappage() -- save a page on the array of reapped pages.
* *
* As a side effect of the way that the vacuuming loop for a given * As a side effect of the way that the vacuuming loop for a given
* relation works, higher pages come after lower pages in the array * relation works, higher pages come after lower pages in the array
* (and highest tid on a page is last). * (and highest tid on a page is last).
*/ */
static void static void
_vc_reappage(VPageList vpl, VPageDescr vpc) vc_reappage(VPageList vpl, VPageDescr vpc)
{ {
VPageDescr newvpd; VPageDescr newvpd;
...@@ -1527,12 +1863,12 @@ _vc_reappage(VPageList vpl, VPageDescr vpc) ...@@ -1527,12 +1863,12 @@ _vc_reappage(VPageList vpl, VPageDescr vpc)
newvpd->vpd_noff = vpc->vpd_noff; newvpd->vpd_noff = vpc->vpd_noff;
/* insert this page into vpl list */ /* insert this page into vpl list */
_vc_vpinsert (vpl, newvpd); vc_vpinsert (vpl, newvpd);
} /* _vc_reappage */ } /* vc_reappage */
static void static void
_vc_vpinsert (VPageList vpl, VPageDescr vpnew) vc_vpinsert (VPageList vpl, VPageDescr vpnew)
{ {
/* allocate a VPageDescr entry if needed */ /* allocate a VPageDescr entry if needed */
...@@ -1546,10 +1882,9 @@ _vc_vpinsert (VPageList vpl, VPageDescr vpnew) ...@@ -1546,10 +1882,9 @@ _vc_vpinsert (VPageList vpl, VPageDescr vpnew)
} }
static void static void
_vc_free(Portal p, VRelList vrl) vc_free(Portal p, VRelList vrl)
{ {
VRelList p_vrl; VRelList p_vrl;
VAttList p_val, val;
MemoryContext old; MemoryContext old;
PortalVariableMemory pmem; PortalVariableMemory pmem;
...@@ -1558,14 +1893,6 @@ _vc_free(Portal p, VRelList vrl) ...@@ -1558,14 +1893,6 @@ _vc_free(Portal p, VRelList vrl)
while (vrl != (VRelList) NULL) { while (vrl != (VRelList) NULL) {
/* free attribute list */
val = vrl->vrl_attlist;
while (val != (VAttList) NULL) {
p_val = val;
val = val->val_next;
pfree(p_val);
}
/* free rel list entry */ /* free rel list entry */
p_vrl = vrl; p_vrl = vrl;
vrl = vrl->vrl_next; vrl = vrl->vrl_next;
...@@ -1576,7 +1903,7 @@ _vc_free(Portal p, VRelList vrl) ...@@ -1576,7 +1903,7 @@ _vc_free(Portal p, VRelList vrl)
} }
/* /*
* _vc_getarchrel() -- open the archive relation for a heap relation * vc_getarchrel() -- open the archive relation for a heap relation
* *
* The archive relation is named 'a,XXXXX' for the heap relation * The archive relation is named 'a,XXXXX' for the heap relation
* whose relid is XXXXX. * whose relid is XXXXX.
...@@ -1585,7 +1912,7 @@ _vc_free(Portal p, VRelList vrl) ...@@ -1585,7 +1912,7 @@ _vc_free(Portal p, VRelList vrl)
#define ARCHIVE_PREFIX "a," #define ARCHIVE_PREFIX "a,"
static Relation static Relation
_vc_getarchrel(Relation heaprel) vc_getarchrel(Relation heaprel)
{ {
Relation archrel; Relation archrel;
char *archrelname; char *archrelname;
...@@ -1600,19 +1927,19 @@ _vc_getarchrel(Relation heaprel) ...@@ -1600,19 +1927,19 @@ _vc_getarchrel(Relation heaprel)
} }
/* /*
* _vc_archive() -- write a tuple to an archive relation * vc_archive() -- write a tuple to an archive relation
* *
* In the future, this will invoke the archived accessd method. For * In the future, this will invoke the archived accessd method. For
* now, archive relations are on mag disk. * now, archive relations are on mag disk.
*/ */
static void static void
_vc_archive(Relation archrel, HeapTuple htup) vc_archive(Relation archrel, HeapTuple htup)
{ {
doinsert(archrel, htup); doinsert(archrel, htup);
} }
static bool static bool
_vc_isarchrel(char *rname) vc_isarchrel(char *rname)
{ {
if (strncmp(ARCHIVE_PREFIX, rname,strlen(ARCHIVE_PREFIX)) == 0) if (strncmp(ARCHIVE_PREFIX, rname,strlen(ARCHIVE_PREFIX)) == 0)
return (true); return (true);
...@@ -1621,7 +1948,7 @@ _vc_isarchrel(char *rname) ...@@ -1621,7 +1948,7 @@ _vc_isarchrel(char *rname)
} }
static char * static char *
_vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *)) vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *))
{ {
int res; int res;
int last = nelem - 1; int last = nelem - 1;
...@@ -1671,10 +1998,10 @@ _vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, ch ...@@ -1671,10 +1998,10 @@ _vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, ch
first_move = true; first_move = true;
} }
} /* _vc_find_eq */ } /* vc_find_eq */
static int static int
_vc_cmp_blk (char *left, char *right) vc_cmp_blk (char *left, char *right)
{ {
BlockNumber lblk, rblk; BlockNumber lblk, rblk;
...@@ -1687,10 +2014,10 @@ _vc_cmp_blk (char *left, char *right) ...@@ -1687,10 +2014,10 @@ _vc_cmp_blk (char *left, char *right)
return (0); return (0);
return (1); return (1);
} /* _vc_cmp_blk */ } /* vc_cmp_blk */
static int static int
_vc_cmp_offno (char *left, char *right) vc_cmp_offno (char *left, char *right)
{ {
if ( *(OffsetNumber*)left < *(OffsetNumber*)right ) if ( *(OffsetNumber*)left < *(OffsetNumber*)right )
...@@ -1699,11 +2026,11 @@ _vc_cmp_offno (char *left, char *right) ...@@ -1699,11 +2026,11 @@ _vc_cmp_offno (char *left, char *right)
return (0); return (0);
return (1); return (1);
} /* _vc_cmp_offno */ } /* vc_cmp_offno */
static void static void
_vc_getindices (Oid relid, int *nindices, Relation **Irel) vc_getindices (Oid relid, int *nindices, Relation **Irel)
{ {
Relation pgindex; Relation pgindex;
Relation irel; Relation irel;
...@@ -1773,11 +2100,11 @@ _vc_getindices (Oid relid, int *nindices, Relation **Irel) ...@@ -1773,11 +2100,11 @@ _vc_getindices (Oid relid, int *nindices, Relation **Irel)
*Irel = (Relation *) NULL; *Irel = (Relation *) NULL;
} }
} /* _vc_getindices */ } /* vc_getindices */
static void static void
_vc_clsindices (int nindices, Relation *Irel) vc_clsindices (int nindices, Relation *Irel)
{ {
if ( Irel == (Relation*) NULL ) if ( Irel == (Relation*) NULL )
...@@ -1788,11 +2115,11 @@ _vc_clsindices (int nindices, Relation *Irel) ...@@ -1788,11 +2115,11 @@ _vc_clsindices (int nindices, Relation *Irel)
} }
pfree (Irel); pfree (Irel);
} /* _vc_clsindices */ } /* vc_clsindices */
static void static void
_vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc) vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc)
{ {
IndDesc *idcur; IndDesc *idcur;
HeapTuple pgIndexTup; HeapTuple pgIndexTup;
...@@ -1824,11 +2151,11 @@ _vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc) ...@@ -1824,11 +2151,11 @@ _vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc)
idcur->natts = natts; idcur->natts = natts;
} }
} /* _vc_mkindesc */ } /* vc_mkindesc */
static bool static bool
_vc_enough_space (VPageDescr vpd, Size len) vc_enough_space (VPageDescr vpd, Size len)
{ {
len = DOUBLEALIGN(len); len = DOUBLEALIGN(len);
...@@ -1845,4 +2172,4 @@ _vc_enough_space (VPageDescr vpd, Size len) ...@@ -1845,4 +2172,4 @@ _vc_enough_space (VPageDescr vpd, Size len)
return (false); return (false);
} /* _vc_enough_space */ } /* vc_enough_space */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.20 1997/01/22 01:42:54 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.21 1997/02/07 16:22:50 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1486,7 +1486,7 @@ any_ordering_op(int restype) ...@@ -1486,7 +1486,7 @@ any_ordering_op(int restype)
Operator order_op; Operator order_op;
Oid order_opid; Oid order_opid;
order_op = oper("<",restype,restype); order_op = oper("<",restype,restype,false);
order_opid = oprid(order_op); order_opid = oprid(order_op);
return order_opid; return order_opid;
...@@ -1554,7 +1554,7 @@ transformSortClause(ParseState *pstate, ...@@ -1554,7 +1554,7 @@ transformSortClause(ParseState *pstate,
sortcl->resdom = resdom = restarget->resdom; sortcl->resdom = resdom = restarget->resdom;
sortcl->opoid = oprid(oper(sortby->useOp, sortcl->opoid = oprid(oper(sortby->useOp,
resdom->restype, resdom->restype,
resdom->restype)); resdom->restype,false));
if (sortlist == NIL) { if (sortlist == NIL) {
s = sortlist = lcons(sortcl, NIL); s = sortlist = lcons(sortcl, NIL);
}else { }else {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.15 1997/01/22 01:43:08 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.16 1997/02/07 16:23:08 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -473,7 +473,7 @@ binary_oper_select_candidate(Oid arg1, ...@@ -473,7 +473,7 @@ binary_oper_select_candidate(Oid arg1,
/* Given operator, types of arg1, and arg2, return oper struct */ /* Given operator, types of arg1, and arg2, return oper struct */
/* arg1, arg2 --typeids */ /* arg1, arg2 --typeids */
Operator Operator
oper(char *op, Oid arg1, Oid arg2) oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
{ {
HeapTuple tup; HeapTuple tup;
CandidateList candidates; CandidateList candidates;
...@@ -492,7 +492,8 @@ oper(char *op, Oid arg1, Oid arg2) ...@@ -492,7 +492,8 @@ oper(char *op, Oid arg1, Oid arg2)
/* /*
* no operators of the desired types found * no operators of the desired types found
*/ */
op_error(op, arg1, arg2); if (!noWarnings)
op_error(op, arg1, arg2);
return(NULL); return(NULL);
} else if (ncandidates == 1) { } else if (ncandidates == 1) {
/* /*
...@@ -523,11 +524,12 @@ oper(char *op, Oid arg1, Oid arg2) ...@@ -523,11 +524,12 @@ oper(char *op, Oid arg1, Oid arg2)
/* we chose none of them */ /* we chose none of them */
tp1 = get_id_type(arg1); tp1 = get_id_type(arg1);
tp2 = get_id_type(arg2); tp2 = get_id_type(arg2);
elog(NOTICE, "there is more than one operator %s for types", op); if (!noWarnings) {
elog(NOTICE, "%s and %s. You will have to retype this query", elog(NOTICE, "there is more than one operator %s for types", op);
tname(tp1), tname(tp2)); elog(NOTICE, "%s and %s. You will have to retype this query",
elog(WARN, "using an explicit cast"); tname(tp1), tname(tp2));
elog(WARN, "using an explicit cast");
}
return(NULL); return(NULL);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.12 1997/01/22 01:43:19 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.13 1997/02/07 16:23:21 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -352,7 +352,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -352,7 +352,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
/* right operator */ /* right operator */
ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree); ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree);
temp = right_oper(opname, ltypeId); temp = oper(opname, ltypeId, rtypeId, false);
opform = (OperatorTupleForm) GETSTRUCT(temp); opform = (OperatorTupleForm) GETSTRUCT(temp);
left = make_operand(opname, ltree, ltypeId, opform->oprleft); left = make_operand(opname, ltree, ltypeId, opform->oprleft);
right = NULL; right = NULL;
...@@ -411,7 +411,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -411,7 +411,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
((Const *)ltree)->constbyval = tbyval(newtype); ((Const *)ltree)->constbyval = tbyval(newtype);
} }
temp = oper(opname, ltypeId, rtypeId); temp = oper(opname, ltypeId, rtypeId, false);
opform = (OperatorTupleForm) GETSTRUCT(temp); opform = (OperatorTupleForm) GETSTRUCT(temp);
left = make_operand(opname, ltree, ltypeId, opform->oprleft); left = make_operand(opname, ltree, ltypeId, opform->oprleft);
right = make_operand(opname, rtree, rtypeId, opform->oprright); right = make_operand(opname, rtree, rtypeId, opform->oprright);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.4 1996/11/03 06:53:08 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.5 1997/02/07 16:23:39 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "utils/lsyscache.h" /* for get_oprrest() */ #include "utils/lsyscache.h" /* for get_oprrest() */
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
#include "commands/vacuum.h" /* for ATTNVALS_SCALE */
/* N is not a valid var/constant or relation id */ /* N is not a valid var/constant or relation id */
#define NONVALUE(N) ((N) == -1) #define NONVALUE(N) ((N) == -1)
...@@ -68,7 +69,7 @@ eqsel(Oid opid, ...@@ -68,7 +69,7 @@ eqsel(Oid opid,
if (nvals == 0) if (nvals == 0)
*result = 0.0; *result = 0.0;
else else
*result = 1.0 / nvals; *result = ((float64data)nvals) / ((float64data)ATTNVALS_SCALE);
} }
return(result); return(result);
} }
...@@ -125,7 +126,7 @@ intltsel(Oid opid, ...@@ -125,7 +126,7 @@ intltsel(Oid opid,
if (nvals == 0) if (nvals == 0)
*result = 1.0 / 3.0; *result = 1.0 / 3.0;
else else
*result = 3.0 / nvals; *result = 3.0 * ((float64data)nvals) / ((float64data)ATTNVALS_SCALE);
}else { }else {
bottom = high - low; bottom = high - low;
if (bottom == 0) if (bottom == 0)
...@@ -192,7 +193,7 @@ eqjoinsel(Oid opid, ...@@ -192,7 +193,7 @@ eqjoinsel(Oid opid,
if (max == 0) if (max == 0)
*result = 1.0; *result = 1.0;
else else
*result = 1.0 / max; *result = ((float64data)max) / ((float64data)ATTNVALS_SCALE);
} }
return(result); return(result);
} }
......
...@@ -6,13 +6,16 @@ ...@@ -6,13 +6,16 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: vacuum.h,v 1.5 1997/01/13 03:44:54 momjian Exp $ * $Id: vacuum.h,v 1.6 1997/02/07 16:23:57 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef VACUUM_H #ifndef VACUUM_H
#define VACUUM_H #define VACUUM_H
#include <access/funcindex.h>
#include <catalog/pg_index.h>
typedef struct VAttListData { typedef struct VAttListData {
int val_dummy; int val_dummy;
struct VAttListData *val_next; struct VAttListData *val_next;
...@@ -38,23 +41,46 @@ typedef struct VPageListData { ...@@ -38,23 +41,46 @@ typedef struct VPageListData {
typedef VPageListData *VPageList; typedef VPageListData *VPageList;
typedef struct {
FuncIndexInfo finfo;
FuncIndexInfo *finfoP;
IndexTupleForm tform;
int natts;
} IndDesc;
typedef struct {
AttributeTupleForm attr;
Datum best, guess1, guess2, max, min;
int16 best_len, guess1_len, guess2_len, max_len, min_len;
int32 best_cnt, guess1_cnt, guess1_hits, guess2_hits, null_cnt,nonnull_cnt;
int32 max_cnt, min_cnt;
regproc cmpeq, cmplt, cmpgt, outfunc;
bool initialized;
} VacAttrStats;
typedef struct VRelListData { typedef struct VRelListData {
Oid vrl_relid; Oid vrl_relid;
VAttList vrl_attlist;
int vrl_ntups;
int vrl_npages;
Size vrl_min_tlen;
Size vrl_max_tlen;
bool vrl_hasindex;
struct VRelListData *vrl_next; struct VRelListData *vrl_next;
} VRelListData; } VRelListData;
typedef VRelListData *VRelList; typedef VRelListData *VRelList;
typedef struct VRelStats {
Oid relid;
int ntups;
int npages;
Size min_tlen;
Size max_tlen;
bool hasindex;
int natts;
VacAttrStats *vacattrstats;
} VRelStats;
extern bool VacuumRunning; extern bool VacuumRunning;
extern void vc_abort(void); extern void vc_abort(void);
extern void vacuum(char *vacrel, bool verbose); extern void vacuum(char *vacrel, bool verbose);
#define ATTNVALS_SCALE 1000000000 /* XXX so it can act as a float4 */
#endif /* VACUUM_H */ #endif /* VACUUM_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: catalog_utils.h,v 1.7 1997/01/22 01:44:02 momjian Exp $ * $Id: catalog_utils.h,v 1.8 1997/02/07 16:24:12 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -31,7 +31,7 @@ extern bool tbyval(Type t); ...@@ -31,7 +31,7 @@ extern bool tbyval(Type t);
extern char *tname(Type t); extern char *tname(Type t);
extern int tbyvalue(Type t); extern int tbyvalue(Type t);
extern Oid oprid(Operator op); extern Oid oprid(Operator op);
extern Operator oper(char *op, Oid arg1, Oid arg2); extern Operator oper(char *op, Oid arg1, Oid arg2, bool noWarnings);
extern Operator right_oper(char *op, Oid arg); extern Operator right_oper(char *op, Oid arg);
extern Operator left_oper(char *op, Oid arg); extern Operator left_oper(char *op, Oid arg);
extern int varattno(Relation rd, char *a); extern int varattno(Relation rd, char *a);
......
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