Fix pgstattuple to acquire a read lock on the target table. This

prevents embarassments such as having the table dropped or truncated
partway through the scan.  Also, fix free space calculation to include
pages that currently contain no tuples.
This commit is contained in:
Tom Lane 2001-12-19 20:28:41 +00:00
parent 9aa2e7da51
commit 897083715b
2 changed files with 38 additions and 20 deletions

View File

@ -15,7 +15,7 @@ NOTICE: physical length: 0.08MB live tuples: 20 (0.00MB, 1.17%) dead tuples: 32
18.75
(1 row)
Above example shows tellers tables includes 18.75% dead tuples.
Above example shows tellers table includes 18.75% dead tuples.
physical length physical size of the table in MB
live tuples information on the live tuples
@ -40,7 +40,7 @@ NOTICE: physical length: 0.08MB live tuples: 20 (0.00MB, 1.17%) dead tuples: 32
4. Notes
pgstattuple does not lock the target table at all. So concurrent
pgstattuple acquires only a read lock on the table. So concurrent
update may affect the result.
pgstattuple judges a tuple is "dead" if HeapTupleSatisfiesNow()

View File

@ -1,5 +1,5 @@
/*
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.2 2001/10/25 05:49:20 momjian Exp $
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.3 2001/12/19 20:28:41 tgl Exp $
*
* Copyright (c) 2001 Tatsuo Ishii
*
@ -23,6 +23,7 @@
*/
#include "postgres.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "access/transam.h"
@ -48,20 +49,21 @@ pgstattuple(PG_FUNCTION_ARGS)
HeapScanDesc scan;
HeapTuple tuple;
BlockNumber nblocks;
BlockNumber block = InvalidBlockNumber;
BlockNumber block = 0; /* next block to count free space in */
BlockNumber tupblock;
Buffer buffer;
double table_len;
uint64 tuple_len = 0;
uint64 dead_tuple_len = 0;
uint32 tuple_count = 0;
uint32 dead_tuple_count = 0;
uint64 tuple_count = 0;
uint64 dead_tuple_count = 0;
double tuple_percent;
double dead_tuple_percent;
Buffer buffer = InvalidBuffer;
uint64 free_space = 0; /* free/reusable space in bytes */
double free_percent; /* free/reusable space in % */
rel = heap_openr(NameStr(*p), NoLock);
rel = heap_openr(NameStr(*p), AccessShareLock);
nblocks = RelationGetNumberOfBlocks(rel);
scan = heap_beginscan(rel, false, SnapshotAny, 0, NULL);
@ -78,17 +80,33 @@ pgstattuple(PG_FUNCTION_ARGS)
dead_tuple_count++;
}
if (!BlockNumberIsValid(block) ||
block != BlockIdGetBlockNumber(&tuple->t_self.ip_blkid))
/*
* To avoid physically reading the table twice, try to do the
* free-space scan in parallel with the heap scan. However,
* heap_getnext may find no tuples on a given page, so we cannot
* simply examine the pages returned by the heap scan.
*/
tupblock = BlockIdGetBlockNumber(&tuple->t_self.ip_blkid);
while (block <= tupblock)
{
block = BlockIdGetBlockNumber(&tuple->t_self.ip_blkid);
buffer = ReadBuffer(rel, block);
free_space += PageGetFreeSpace((Page) BufferGetPage(buffer));
ReleaseBuffer(buffer);
block++;
}
}
heap_endscan(scan);
heap_close(rel, NoLock);
while (block < nblocks)
{
buffer = ReadBuffer(rel, block);
free_space += PageGetFreeSpace((Page) BufferGetPage(buffer));
ReleaseBuffer(buffer);
block++;
}
heap_close(rel, AccessShareLock);
table_len = (double) nblocks *BLCKSZ;
@ -105,20 +123,20 @@ pgstattuple(PG_FUNCTION_ARGS)
free_percent = (double) free_space *100.0 / table_len;
}
elog(NOTICE, "physical length: %.2fMB live tuples: %u (%.2fMB, %.2f%%) dead tuples: %u (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%",
elog(NOTICE, "physical length: %.2fMB live tuples: %.0f (%.2fMB, %.2f%%) dead tuples: %.0f (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%",
table_len / 1024 / 1024, /* phsical length in MB */
table_len / (1024 * 1024), /* physical length in MB */
tuple_count, /* number of live tuples */
(double) tuple_len / 1024 / 1024, /* live tuples in MB */
(double) tuple_count, /* number of live tuples */
(double) tuple_len / (1024 * 1024), /* live tuples in MB */
tuple_percent, /* live tuples in % */
dead_tuple_count, /* number of dead tuples */
(double) dead_tuple_len / 1024 / 1024, /* dead tuples in MB */
(double) dead_tuple_count, /* number of dead tuples */
(double) dead_tuple_len / (1024 * 1024), /* dead tuples in MB */
dead_tuple_percent, /* dead tuples in % */
(double) free_space / 1024 / 1024, /* free/available space in
* MB */
(double) free_space / (1024 * 1024), /* free/available space in
* MB */
free_percent, /* free/available space in % */