BlockNumber scanned_pages; /* number of pages we examined */
BlockNumber pinskipped_pages; /* # of pages we skipped due to a pin */
BlockNumber frozenskipped_pages; /* # of frozen pages we skipped */
- double scanned_tuples; /* counts only tuples on scanned pages */
+ BlockNumber tupcount_pages; /* pages whose tuples we counted */
+ double scanned_tuples; /* counts only tuples on tupcount_pages */
double old_rel_tuples; /* previous value of pg_class.reltuples */
double new_rel_tuples; /* new estimated total # of tuples */
double new_dead_tuples; /* new estimated total # of dead tuples */
* density") with nonzero relpages and reltuples=0 (which means "zero
* tuple density") unless there's some actual evidence for the latter.
*
+ * It's important that we use tupcount_pages and not scanned_pages for the
+ * check described above; scanned_pages counts pages where we could not
+ * get cleanup lock, and which were processed only for frozenxid purposes.
+ *
* We do update relallvisible even in the corner case, since if the table
* is all-visible we'd definitely like to know that. But clamp the value
* to be not more than what we're setting relpages to.
*/
new_rel_pages = vacrelstats->rel_pages;
new_rel_tuples = vacrelstats->new_rel_tuples;
- if (vacrelstats->scanned_pages == 0 && new_rel_pages > 0)
+ if (vacrelstats->tupcount_pages == 0 && new_rel_pages > 0)
{
new_rel_pages = vacrelstats->old_rel_pages;
new_rel_tuples = vacrelstats->old_rel_tuples;
nblocks = RelationGetNumberOfBlocks(onerel);
vacrelstats->rel_pages = nblocks;
vacrelstats->scanned_pages = 0;
+ vacrelstats->tupcount_pages = 0;
vacrelstats->nonempty_pages = 0;
vacrelstats->latestRemovedXid = InvalidTransactionId;
}
vacrelstats->scanned_pages++;
+ vacrelstats->tupcount_pages++;
page = BufferGetPage(buf);
/* now we can compute the new value for pg_class.reltuples */
vacrelstats->new_rel_tuples = vac_estimate_reltuples(onerel, false,
nblocks,
- vacrelstats->scanned_pages,
+ vacrelstats->tupcount_pages,
num_tuples);
/*
ivinfo.index = indrel;
ivinfo.analyze_only = false;
- ivinfo.estimated_count = (vacrelstats->scanned_pages < vacrelstats->rel_pages);
+ ivinfo.estimated_count = (vacrelstats->tupcount_pages < vacrelstats->rel_pages);
ivinfo.message_level = elevel;
ivinfo.num_heap_tuples = vacrelstats->new_rel_tuples;
ivinfo.strategy = vac_strategy;
--- /dev/null
+Parsed test spec with 2 sessions
+
+starting permutation: modify vac stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step vac:
+ vacuum smalltbl;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
+
+starting permutation: modify open fetch1 vac close stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step open:
+ begin;
+ declare c1 cursor for select * from smalltbl;
+
+step fetch1:
+ fetch next from c1;
+
+id
+
+2
+step vac:
+ vacuum smalltbl;
+
+step close:
+ commit;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
+
+starting permutation: modify vac stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step vac:
+ vacuum smalltbl;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
--- /dev/null
+# Test for vacuum's handling of reltuples when pages are skipped due
+# to page pins. We absolutely need to avoid setting reltuples=0 in
+# such cases, since that interferes badly with planning.
+
+setup {
+ create table smalltbl
+ as select i as id from generate_series(1,20) i;
+ alter table smalltbl set (autovacuum_enabled = off);
+}
+setup {
+ vacuum analyze smalltbl;
+}
+
+teardown {
+ drop table smalltbl;
+}
+
+session "worker"
+step "open" {
+ begin;
+ declare c1 cursor for select * from smalltbl;
+}
+step "fetch1" {
+ fetch next from c1;
+}
+step "close" {
+ commit;
+}
+step "stats" {
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+}
+
+session "vacuumer"
+step "vac" {
+ vacuum smalltbl;
+}
+step "modify" {
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+}
+
+permutation "modify" "vac" "stats"
+permutation "modify" "open" "fetch1" "vac" "close" "stats"
+permutation "modify" "vac" "stats"