Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fb0919f

Browse files
committed
Don't assume that max offset number stays fixed on a page when we're
not holding a pin on the page. Use double instead of long to count rows in relation, so that code still works for > LONG_MAX rows in rel.
1 parent 6497a7f commit fb0919f

File tree

1 file changed

+67
-66
lines changed

1 file changed

+67
-66
lines changed

src/backend/commands/analyze.c

Lines changed: 67 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.21 2001/06/22 19:16:21 wieck Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.22 2001/07/05 19:33:35 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -97,8 +97,8 @@ typedef struct
9797
} ScalarMCVItem;
9898

9999

100-
#define swapInt(a,b) {int _tmp; _tmp=a; a=b; b=_tmp;}
101-
#define swapDatum(a,b) {Datum _tmp; _tmp=a; a=b; b=_tmp;}
100+
#define swapInt(a,b) do {int _tmp; _tmp=a; a=b; b=_tmp;} while(0)
101+
#define swapDatum(a,b) do {Datum _tmp; _tmp=a; a=b; b=_tmp;} while(0)
102102

103103

104104
static int MESSAGE_LEVEL;
@@ -111,20 +111,18 @@ static int *datumCmpTupnoLink;
111111

112112
static VacAttrStats *examine_attribute(Relation onerel, int attnum);
113113
static int acquire_sample_rows(Relation onerel, HeapTuple *rows,
114-
int targrows, long *totalrows);
114+
int targrows, double *totalrows);
115115
static double random_fract(void);
116116
static double init_selection_state(int n);
117-
static long select_next_random_record(long t, int n, double *stateptr);
117+
static double select_next_random_record(double t, int n, double *stateptr);
118118
static int compare_rows(const void *a, const void *b);
119119
static int compare_scalars(const void *a, const void *b);
120120
static int compare_mcvs(const void *a, const void *b);
121-
static OffsetNumber get_page_max_offset(Relation relation,
122-
BlockNumber blocknumber);
123121
static void compute_minimal_stats(VacAttrStats *stats,
124-
TupleDesc tupDesc, long totalrows,
122+
TupleDesc tupDesc, double totalrows,
125123
HeapTuple *rows, int numrows);
126124
static void compute_scalar_stats(VacAttrStats *stats,
127-
TupleDesc tupDesc, long totalrows,
125+
TupleDesc tupDesc, double totalrows,
128126
HeapTuple *rows, int numrows);
129127
static void update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats);
130128

@@ -143,7 +141,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
143141
VacAttrStats **vacattrstats;
144142
int targrows,
145143
numrows;
146-
long totalrows;
144+
double totalrows;
147145
HeapTuple *rows;
148146
HeapTuple tuple;
149147

@@ -298,7 +296,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
298296
if (!vacstmt->vacuum)
299297
vac_update_relstats(RelationGetRelid(onerel),
300298
onerel->rd_nblocks,
301-
(double) totalrows,
299+
totalrows,
302300
RelationGetForm(onerel)->relhasindex);
303301

304302
/*
@@ -488,7 +486,7 @@ examine_attribute(Relation onerel, int attnum)
488486
*/
489487
static int
490488
acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
491-
long *totalrows)
489+
double *totalrows)
492490
{
493491
int numrows = 0;
494492
HeapScanDesc scan;
@@ -499,7 +497,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
499497
OffsetNumber lastoffset;
500498
int numest;
501499
double tuplesperpage;
502-
long t;
500+
double t;
503501
double rstate;
504502

505503
Assert(targrows > 1);
@@ -520,7 +518,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
520518
*/
521519
if (!HeapTupleIsValid(tuple))
522520
{
523-
*totalrows = numrows;
521+
*totalrows = (double) numrows;
524522
return numrows;
525523
}
526524
/*
@@ -565,20 +563,22 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
565563
}
566564
tuplesperpage = (double) numest / (double) estblock;
567565

568-
t = numrows; /* t is the # of records processed so far */
566+
t = (double) numrows; /* t is the # of records processed so far */
569567
rstate = init_selection_state(targrows);
570568
for (;;)
571569
{
572570
double targpos;
573571
BlockNumber targblock;
572+
Buffer targbuffer;
573+
Page targpage;
574574
OffsetNumber targoffset,
575575
maxoffset;
576576

577577
t = select_next_random_record(t, targrows, &rstate);
578578
/* Try to read the t'th record in the table */
579-
targpos = (double) t / tuplesperpage;
579+
targpos = t / tuplesperpage;
580580
targblock = (BlockNumber) targpos;
581-
targoffset = ((int) (targpos - targblock) * tuplesperpage) +
581+
targoffset = ((int) ((targpos - targblock) * tuplesperpage)) +
582582
FirstOffsetNumber;
583583
/* Make sure we are past the last selected record */
584584
if (targblock <= lastblock)
@@ -595,21 +595,37 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
595595
*/
596596
if (targblock >= onerel->rd_nblocks)
597597
break;
598-
maxoffset = get_page_max_offset(onerel, targblock);
598+
/*
599+
* We must maintain a pin on the target page's buffer to ensure that
600+
* the maxoffset value stays good (else concurrent VACUUM might
601+
* delete tuples out from under us). Hence, pin the page until we
602+
* are done looking at it. We don't maintain a lock on the page,
603+
* so tuples could get added to it, but we ignore such tuples.
604+
*/
605+
targbuffer = ReadBuffer(onerel, targblock);
606+
if (!BufferIsValid(targbuffer))
607+
elog(ERROR, "acquire_sample_rows: ReadBuffer(%s,%u) failed",
608+
RelationGetRelationName(onerel), targblock);
609+
LockBuffer(targbuffer, BUFFER_LOCK_SHARE);
610+
targpage = BufferGetPage(targbuffer);
611+
maxoffset = PageGetMaxOffsetNumber(targpage);
612+
LockBuffer(targbuffer, BUFFER_LOCK_UNLOCK);
613+
599614
for (;;)
600615
{
601616
HeapTupleData targtuple;
602-
Buffer targbuffer;
617+
Buffer tupbuffer;
603618

604619
if (targoffset > maxoffset)
605620
{
606621
/* Fell off end of this page, try next */
622+
ReleaseBuffer(targbuffer);
607623
targblock++;
608624
targoffset = FirstOffsetNumber;
609625
goto pageloop;
610626
}
611627
ItemPointerSet(&targtuple.t_self, targblock, targoffset);
612-
heap_fetch(onerel, SnapshotNow, &targtuple, &targbuffer, NULL);
628+
heap_fetch(onerel, SnapshotNow, &targtuple, &tupbuffer, NULL);
613629
if (targtuple.t_data != NULL)
614630
{
615631
/*
@@ -621,6 +637,9 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
621637
Assert(k >= 0 && k < targrows);
622638
heap_freetuple(rows[k]);
623639
rows[k] = heap_copytuple(&targtuple);
640+
/* this releases the second pin acquired by heap_fetch: */
641+
ReleaseBuffer(tupbuffer);
642+
/* this releases the initial pin: */
624643
ReleaseBuffer(targbuffer);
625644
lastblock = targblock;
626645
lastoffset = targoffset;
@@ -639,7 +658,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
639658
/*
640659
* Estimate total number of valid rows in relation.
641660
*/
642-
*totalrows = (long) (onerel->rd_nblocks * tuplesperpage + 0.5);
661+
*totalrows = floor((double) onerel->rd_nblocks * tuplesperpage + 0.5);
643662

644663
return numrows;
645664
}
@@ -667,6 +686,12 @@ random_fract(void)
667686
* of the last record processed and next record to process. The only extra
668687
* state needed between calls is W, a random state variable.
669688
*
689+
* Note: the original algorithm defines t, S, numer, and denom as integers.
690+
* Here we express them as doubles to avoid overflow if the number of rows
691+
* in the table exceeds INT_MAX. The algorithm should work as long as the
692+
* row count does not become so large that it is not represented accurately
693+
* in a double (on IEEE-math machines this would be around 2^52 rows).
694+
*
670695
* init_selection_state computes the initial W value.
671696
*
672697
* Given that we've already processed t records (t >= n),
@@ -680,36 +705,36 @@ init_selection_state(int n)
680705
return exp(- log(random_fract())/n);
681706
}
682707

683-
static long
684-
select_next_random_record(long t, int n, double *stateptr)
708+
static double
709+
select_next_random_record(double t, int n, double *stateptr)
685710
{
686711
/* The magic constant here is T from Vitter's paper */
687-
if (t <= (22 * n))
712+
if (t <= (22.0 * n))
688713
{
689714
/* Process records using Algorithm X until t is large enough */
690715
double V,
691716
quot;
692717

693718
V = random_fract(); /* Generate V */
694-
t++;
695-
quot = (double) (t - n) / (double) t;
719+
t += 1;
720+
quot = (t - (double) n) / t;
696721
/* Find min S satisfying (4.1) */
697722
while (quot > V)
698723
{
699-
t++;
700-
quot *= (double) (t - n) / (double) t;
724+
t += 1;
725+
quot *= (t - (double) n) / t;
701726
}
702727
}
703728
else
704729
{
705730
/* Now apply Algorithm Z */
706731
double W = *stateptr;
707-
long term = t - n + 1;
708-
int S;
732+
double term = t - (double) n + 1;
733+
double S;
709734

710735
for (;;)
711736
{
712-
long numer,
737+
double numer,
713738
numer_lim,
714739
denom;
715740
double U,
@@ -722,9 +747,9 @@ select_next_random_record(long t, int n, double *stateptr)
722747
/* Generate U and X */
723748
U = random_fract();
724749
X = t * (W - 1.0);
725-
S = X; /* S is tentatively set to floor(X) */
750+
S = floor(X); /* S is tentatively set to floor(X) */
726751
/* Test if U <= h(S)/cg(X) in the manner of (6.3) */
727-
tmp = (double) (t + 1) / (double) term;
752+
tmp = (t + 1) / term;
728753
lhs = exp(log(((U * tmp * tmp) * (term + S))/(t + X))/n);
729754
rhs = (((t + X)/(term + S)) * term)/t;
730755
if (lhs <= rhs)
@@ -734,20 +759,20 @@ select_next_random_record(long t, int n, double *stateptr)
734759
}
735760
/* Test if U <= f(S)/cg(X) */
736761
y = (((U * (t + 1))/term) * (t + S + 1))/(t + X);
737-
if (n < S)
762+
if ((double) n < S)
738763
{
739764
denom = t;
740765
numer_lim = term + S;
741766
}
742767
else
743768
{
744-
denom = t - n + S;
769+
denom = t - (double) n + S;
745770
numer_lim = t + 1;
746771
}
747-
for (numer = t + S; numer >= numer_lim; numer--)
772+
for (numer = t + S; numer >= numer_lim; numer -= 1)
748773
{
749-
y *= (double) numer / (double) denom;
750-
denom--;
774+
y *= numer / denom;
775+
denom -= 1;
751776
}
752777
W = exp(- log(random_fract())/n); /* Generate W in advance */
753778
if (exp(log(y)/n) <= (t + X)/t)
@@ -783,30 +808,6 @@ compare_rows(const void *a, const void *b)
783808
return 0;
784809
}
785810

786-
/*
787-
* Discover the largest valid tuple offset number on the given page
788-
*
789-
* This code probably ought to live in some other module.
790-
*/
791-
static OffsetNumber
792-
get_page_max_offset(Relation relation, BlockNumber blocknumber)
793-
{
794-
Buffer buffer;
795-
Page p;
796-
OffsetNumber offnum;
797-
798-
buffer = ReadBuffer(relation, blocknumber);
799-
if (!BufferIsValid(buffer))
800-
elog(ERROR, "get_page_max_offset: %s relation: ReadBuffer(%ld) failed",
801-
RelationGetRelationName(relation), (long) blocknumber);
802-
LockBuffer(buffer, BUFFER_LOCK_SHARE);
803-
p = BufferGetPage(buffer);
804-
offnum = PageGetMaxOffsetNumber(p);
805-
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
806-
ReleaseBuffer(buffer);
807-
return offnum;
808-
}
809-
810811

811812
/*
812813
* compute_minimal_stats() -- compute minimal column statistics
@@ -825,7 +826,7 @@ get_page_max_offset(Relation relation, BlockNumber blocknumber)
825826
*/
826827
static void
827828
compute_minimal_stats(VacAttrStats *stats,
828-
TupleDesc tupDesc, long totalrows,
829+
TupleDesc tupDesc, double totalrows,
829830
HeapTuple *rows, int numrows)
830831
{
831832
int i;
@@ -1002,7 +1003,7 @@ compute_minimal_stats(VacAttrStats *stats,
10021003

10031004
if (f1 < 1)
10041005
f1 = 1;
1005-
term1 = sqrt((double) totalrows / (double) numrows) * f1;
1006+
term1 = sqrt(totalrows / (double) numrows) * f1;
10061007
stats->stadistinct = floor(term1 + nmultiple + 0.5);
10071008
}
10081009

@@ -1104,7 +1105,7 @@ compute_minimal_stats(VacAttrStats *stats,
11041105
*/
11051106
static void
11061107
compute_scalar_stats(VacAttrStats *stats,
1107-
TupleDesc tupDesc, long totalrows,
1108+
TupleDesc tupDesc, double totalrows,
11081109
HeapTuple *rows, int numrows)
11091110
{
11101111
int i;
@@ -1298,7 +1299,7 @@ compute_scalar_stats(VacAttrStats *stats,
12981299

12991300
if (f1 < 1)
13001301
f1 = 1;
1301-
term1 = sqrt((double) totalrows / (double) numrows) * f1;
1302+
term1 = sqrt(totalrows / (double) numrows) * f1;
13021303
stats->stadistinct = floor(term1 + nmultiple + 0.5);
13031304
}
13041305

0 commit comments

Comments
 (0)