Replace poorly-coded vac_find_eq routine with call to standard bsearch

library code.  Tweak progress messages to include elapsed real time,
not only CPU time.
This commit is contained in:
Tom Lane 2001-05-17 01:28:50 +00:00
parent 6c183005d3
commit 77f277575a

View File

@ -8,22 +8,23 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.190 2001/05/07 00:43:18 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.191 2001/05/17 01:28:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef HAVE_GETRUSAGE #ifndef HAVE_GETRUSAGE
#include "rusagestub.h" #include "rusagestub.h"
#else #else
#include <sys/time.h>
#include <sys/resource.h> #include <sys/resource.h>
#endif #endif
@ -113,6 +114,11 @@ typedef struct VRelStats
VTupleLink vtlinks; VTupleLink vtlinks;
} VRelStats; } VRelStats;
typedef struct VacRUsage
{
struct timeval tv;
struct rusage ru;
} VacRUsage;
static MemoryContext vac_context = NULL; static MemoryContext vac_context = NULL;
@ -144,13 +150,15 @@ static void get_indices(Relation relation, int *nindices, Relation **Irel);
static void close_indices(int nindices, Relation *Irel); static void close_indices(int nindices, Relation *Irel);
static IndexInfo **get_index_desc(Relation onerel, int nindices, static IndexInfo **get_index_desc(Relation onerel, int nindices,
Relation *Irel); Relation *Irel);
static void *vac_find_eq(void *bot, int nelem, int size, void *elm, static void *vac_bsearch(const void *key, const void *base,
int (*compar) (const void *, const void *)); size_t nelem, size_t size,
int (*compar) (const void *, const void *));
static int vac_cmp_blk(const void *left, const void *right); static int vac_cmp_blk(const void *left, const void *right);
static int vac_cmp_offno(const void *left, const void *right); 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(VacPage vacpage, Size len); static bool enough_space(VacPage vacpage, Size len);
static char *show_rusage(struct rusage * ru0); static void init_rusage(VacRUsage *ru0);
static char *show_rusage(VacRUsage *ru0);
/* /*
@ -635,9 +643,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
VTupleLink vtlinks = (VTupleLink) palloc(100 * sizeof(VTupleLinkData)); VTupleLink vtlinks = (VTupleLink) palloc(100 * sizeof(VTupleLinkData));
int num_vtlinks = 0; int num_vtlinks = 0;
int free_vtlinks = 100; int free_vtlinks = 100;
struct rusage ru0; VacRUsage ru0;
getrusage(RUSAGE_SELF, &ru0); init_rusage(&ru0);
relname = RelationGetRelationName(onerel); relname = RelationGetRelationName(onerel);
elog(MESSAGE_LEVEL, "--Relation %s--", relname); elog(MESSAGE_LEVEL, "--Relation %s--", relname);
@ -1062,9 +1070,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
bool isempty, bool isempty,
dowrite, dowrite,
chain_tuple_moved; chain_tuple_moved;
struct rusage ru0; VacRUsage ru0;
getrusage(RUSAGE_SELF, &ru0); init_rusage(&ru0);
myXID = GetCurrentTransactionId(); myXID = GetCurrentTransactionId();
myCID = GetCurrentCommandId(); myCID = GetCurrentCommandId();
@ -1360,10 +1368,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
vtld.new_tid = tp.t_self; vtld.new_tid = tp.t_self;
vtlp = (VTupleLink) vtlp = (VTupleLink)
vac_find_eq((void *) (vacrelstats->vtlinks), vac_bsearch((void *) &vtld,
(void *) (vacrelstats->vtlinks),
vacrelstats->num_vtlinks, vacrelstats->num_vtlinks,
sizeof(VTupleLinkData), sizeof(VTupleLinkData),
(void *) &vtld,
vac_cmp_vtlinks); vac_cmp_vtlinks);
if (vtlp == NULL) if (vtlp == NULL)
elog(ERROR, "Parent tuple was not found"); elog(ERROR, "Parent tuple was not found");
@ -2134,9 +2142,9 @@ scan_index(Relation indrel, long num_tuples)
IndexScanDesc iscan; IndexScanDesc iscan;
long nitups; long nitups;
int nipages; int nipages;
struct rusage ru0; VacRUsage ru0;
getrusage(RUSAGE_SELF, &ru0); init_rusage(&ru0);
/* walk through the entire index */ /* walk through the entire index */
iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL); iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
@ -2189,9 +2197,9 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
long num_index_tuples; long num_index_tuples;
int num_pages; int num_pages;
VacPage vp; VacPage vp;
struct rusage ru0; VacRUsage ru0;
getrusage(RUSAGE_SELF, &ru0); init_rusage(&ru0);
/* walk through the entire index */ /* walk through the entire index */
iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL); iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
@ -2264,30 +2272,35 @@ tid_reaped(ItemPointer itemptr, VacPageList vacpagelist)
ioffno = ItemPointerGetOffsetNumber(itemptr); ioffno = ItemPointerGetOffsetNumber(itemptr);
vp = &vacpage; vp = &vacpage;
vpp = (VacPage *) vac_find_eq((void *) (vacpagelist->pagedesc), vpp = (VacPage *) vac_bsearch((void *) &vp,
vacpagelist->num_pages, sizeof(VacPage), (void *) &vp, (void *) (vacpagelist->pagedesc),
vacpagelist->num_pages,
sizeof(VacPage),
vac_cmp_blk); vac_cmp_blk);
if (vpp == (VacPage *) NULL) if (vpp == (VacPage *) NULL)
return (VacPage) NULL; return (VacPage) NULL;
/* ok - we are on a partially or fully reaped page */
vp = *vpp; vp = *vpp;
/* ok - we are on true page */
if (vp->offsets_free == 0) if (vp->offsets_free == 0)
{ /* this is EmptyPage !!! */ {
/* this is EmptyPage, so claim all tuples on it are reaped!!! */
return vp; return vp;
} }
voff = (OffsetNumber *) vac_find_eq((void *) (vp->offsets), voff = (OffsetNumber *) vac_bsearch((void *) &ioffno,
vp->offsets_free, sizeof(OffsetNumber), (void *) &ioffno, (void *) (vp->offsets),
vp->offsets_free,
sizeof(OffsetNumber),
vac_cmp_offno); vac_cmp_offno);
if (voff == (OffsetNumber *) NULL) if (voff == (OffsetNumber *) NULL)
return (VacPage) NULL; return (VacPage) NULL;
/* tid is reaped */
return vp; return vp;
} }
/* /*
@ -2393,64 +2406,47 @@ vpage_insert(VacPageList vacpagelist, VacPage vpnew)
} }
vacpagelist->pagedesc[vacpagelist->num_pages] = vpnew; vacpagelist->pagedesc[vacpagelist->num_pages] = vpnew;
(vacpagelist->num_pages)++; (vacpagelist->num_pages)++;
} }
/*
* vac_bsearch: just like standard C library routine bsearch(),
* except that we first test to see whether the target key is outside
* the range of the table entries. This case is handled relatively slowly
* by the normal binary search algorithm (ie, no faster than any other key)
* but it occurs often enough in VACUUM to be worth optimizing.
*/
static void * static void *
vac_find_eq(void *bot, int nelem, int size, void *elm, vac_bsearch(const void *key, const void *base,
size_t nelem, size_t size,
int (*compar) (const void *, const void *)) int (*compar) (const void *, const void *))
{ {
int res; int res;
int last = nelem - 1; const void *last;
int celm = nelem / 2;
bool last_move,
first_move;
last_move = first_move = true; if (nelem == 0)
for (;;) return NULL;
res = compar(key, base);
if (res < 0)
return NULL;
if (res == 0)
return (void *) base;
if (nelem > 1)
{ {
if (first_move == true) last = (const void *) ((const char *) base + (nelem - 1) * size);
{ res = compar(key, last);
res = compar(bot, elm); if (res > 0)
if (res > 0)
return NULL;
if (res == 0)
return bot;
first_move = false;
}
if (last_move == true)
{
res = compar(elm, (void *) ((char *) bot + last * size));
if (res > 0)
return NULL;
if (res == 0)
return (void *) ((char *) bot + last * size);
last_move = false;
}
res = compar(elm, (void *) ((char *) bot + celm * size));
if (res == 0)
return (void *) ((char *) bot + celm * size);
if (res < 0)
{
if (celm == 0)
return NULL;
last = celm - 1;
celm = celm / 2;
last_move = true;
continue;
}
if (celm == last)
return NULL; return NULL;
if (res == 0)
last = last - celm - 1; return (void *) last;
bot = (void *) ((char *) bot + (celm + 1) * size);
celm = (last + 1) / 2;
first_move = true;
} }
if (nelem <= 2)
return NULL; /* already checked 'em all */
return bsearch(key, base, nelem, size, compar);
} }
/*
* Comparator routines for use with qsort() and bsearch().
*/
static int static int
vac_cmp_blk(const void *left, const void *right) vac_cmp_blk(const void *left, const void *right)
{ {
@ -2465,25 +2461,21 @@ vac_cmp_blk(const void *left, const void *right)
if (lblk == rblk) if (lblk == rblk)
return 0; return 0;
return 1; return 1;
} }
static int static int
vac_cmp_offno(const void *left, const void *right) vac_cmp_offno(const void *left, const void *right)
{ {
if (*(OffsetNumber *) left < *(OffsetNumber *) right) if (*(OffsetNumber *) left < *(OffsetNumber *) right)
return -1; return -1;
if (*(OffsetNumber *) left == *(OffsetNumber *) right) if (*(OffsetNumber *) left == *(OffsetNumber *) right)
return 0; return 0;
return 1; return 1;
} }
static int static int
vac_cmp_vtlinks(const void *left, const void *right) vac_cmp_vtlinks(const void *left, const void *right)
{ {
if (((VTupleLink) left)->new_tid.ip_blkid.bi_hi < if (((VTupleLink) left)->new_tid.ip_blkid.bi_hi <
((VTupleLink) right)->new_tid.ip_blkid.bi_hi) ((VTupleLink) right)->new_tid.ip_blkid.bi_hi)
return -1; return -1;
@ -2505,7 +2497,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
((VTupleLink) right)->new_tid.ip_posid) ((VTupleLink) right)->new_tid.ip_posid)
return 1; return 1;
return 0; return 0;
} }
@ -2602,6 +2593,18 @@ enough_space(VacPage vacpage, Size len)
} }
/*
* Initialize usage snapshot.
*/
static void
init_rusage(VacRUsage *ru0)
{
struct timezone tz;
getrusage(RUSAGE_SELF, &ru0->ru);
gettimeofday(&ru0->tv, &tz);
}
/* /*
* Compute elapsed time since ru0 usage snapshot, and format into * Compute elapsed time since ru0 usage snapshot, and format into
* a displayable string. Result is in a static string, which is * a displayable string. Result is in a static string, which is
@ -2609,30 +2612,37 @@ enough_space(VacPage vacpage, Size len)
* threadable... * threadable...
*/ */
static char * static char *
show_rusage(struct rusage * ru0) show_rusage(VacRUsage *ru0)
{ {
static char result[64]; static char result[100];
struct rusage ru1; VacRUsage ru1;
getrusage(RUSAGE_SELF, &ru1); init_rusage(&ru1);
if (ru1.ru_stime.tv_usec < ru0->ru_stime.tv_usec) if (ru1.tv.tv_usec < ru0->tv.tv_usec)
{ {
ru1.ru_stime.tv_sec--; ru1.tv.tv_sec--;
ru1.ru_stime.tv_usec += 1000000; ru1.tv.tv_usec += 1000000;
} }
if (ru1.ru_utime.tv_usec < ru0->ru_utime.tv_usec) if (ru1.ru.ru_stime.tv_usec < ru0->ru.ru_stime.tv_usec)
{ {
ru1.ru_utime.tv_sec--; ru1.ru.ru_stime.tv_sec--;
ru1.ru_utime.tv_usec += 1000000; ru1.ru.ru_stime.tv_usec += 1000000;
}
if (ru1.ru.ru_utime.tv_usec < ru0->ru.ru_utime.tv_usec)
{
ru1.ru.ru_utime.tv_sec--;
ru1.ru.ru_utime.tv_usec += 1000000;
} }
snprintf(result, sizeof(result), snprintf(result, sizeof(result),
"CPU %d.%02ds/%d.%02du sec.", "CPU %d.%02ds/%d.%02du sec elapsed %d.%02d sec.",
(int) (ru1.ru_stime.tv_sec - ru0->ru_stime.tv_sec), (int) (ru1.ru.ru_stime.tv_sec - ru0->ru.ru_stime.tv_sec),
(int) (ru1.ru_stime.tv_usec - ru0->ru_stime.tv_usec) / 10000, (int) (ru1.ru.ru_stime.tv_usec - ru0->ru.ru_stime.tv_usec) / 10000,
(int) (ru1.ru_utime.tv_sec - ru0->ru_utime.tv_sec), (int) (ru1.ru.ru_utime.tv_sec - ru0->ru.ru_utime.tv_sec),
(int) (ru1.ru_utime.tv_usec - ru0->ru_utime.tv_usec) / 10000); (int) (ru1.ru.ru_utime.tv_usec - ru0->ru.ru_utime.tv_usec) / 10000,
(int) (ru1.tv.tv_sec - ru0->tv.tv_sec),
(int) (ru1.tv.tv_usec - ru0->tv.tv_usec) / 10000);
return result; return result;
} }