11/*
2- * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.2 2001/10/25 05:49:20 momjian Exp $
2+ * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.3 2001/12/19 20:28:41 tgl Exp $
33 *
44 * Copyright (c) 2001 Tatsuo Ishii
55 *
2323 */
2424
2525#include "postgres.h"
26+
2627#include "fmgr.h"
2728#include "access/heapam.h"
2829#include "access/transam.h"
@@ -48,20 +49,21 @@ pgstattuple(PG_FUNCTION_ARGS)
4849HeapScanDesc scan ;
4950HeapTuple tuple ;
5051BlockNumber nblocks ;
51- BlockNumber block = InvalidBlockNumber ;
52+ BlockNumber block = 0 ;/* next block to count free space in */
53+ BlockNumber tupblock ;
54+ Buffer buffer ;
5255double table_len ;
5356uint64 tuple_len = 0 ;
5457uint64 dead_tuple_len = 0 ;
55- uint32 tuple_count = 0 ;
56- uint32 dead_tuple_count = 0 ;
58+ uint64 tuple_count = 0 ;
59+ uint64 dead_tuple_count = 0 ;
5760double tuple_percent ;
5861double dead_tuple_percent ;
5962
60- Buffer buffer = InvalidBuffer ;
6163uint64 free_space = 0 ;/* free/reusable space in bytes */
6264double free_percent ;/* free/reusable space in % */
6365
64- rel = heap_openr (NameStr (* p ),NoLock );
66+ rel = heap_openr (NameStr (* p ),AccessShareLock );
6567nblocks = RelationGetNumberOfBlocks (rel );
6668scan = heap_beginscan (rel , false,SnapshotAny ,0 ,NULL );
6769
@@ -78,17 +80,33 @@ pgstattuple(PG_FUNCTION_ARGS)
7880dead_tuple_count ++ ;
7981}
8082
81- if (!BlockNumberIsValid (block )||
82- block != BlockIdGetBlockNumber (& tuple -> t_self .ip_blkid ))
83+ /*
84+ * To avoid physically reading the table twice, try to do the
85+ * free-space scan in parallel with the heap scan. However,
86+ * heap_getnext may find no tuples on a given page, so we cannot
87+ * simply examine the pages returned by the heap scan.
88+ */
89+ tupblock = BlockIdGetBlockNumber (& tuple -> t_self .ip_blkid );
90+
91+ while (block <=tupblock )
8392{
84- block = BlockIdGetBlockNumber (& tuple -> t_self .ip_blkid );
8593buffer = ReadBuffer (rel ,block );
8694free_space += PageGetFreeSpace ((Page )BufferGetPage (buffer ));
8795ReleaseBuffer (buffer );
96+ block ++ ;
8897}
8998}
9099heap_endscan (scan );
91- heap_close (rel ,NoLock );
100+
101+ while (block < nblocks )
102+ {
103+ buffer = ReadBuffer (rel ,block );
104+ free_space += PageGetFreeSpace ((Page )BufferGetPage (buffer ));
105+ ReleaseBuffer (buffer );
106+ block ++ ;
107+ }
108+
109+ heap_close (rel ,AccessShareLock );
92110
93111table_len = (double )nblocks * BLCKSZ ;
94112
@@ -105,20 +123,20 @@ pgstattuple(PG_FUNCTION_ARGS)
105123free_percent = (double )free_space * 100.0 /table_len ;
106124}
107125
108- elog (NOTICE ,"physical length: %.2fMB live tuples: %u (%.2fMB, %.2f%%) dead tuples: %u (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%" ,
126+ elog (NOTICE ,"physical length: %.2fMB live tuples: %.0f (%.2fMB, %.2f%%) dead tuples: %.0f (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%" ,
109127
110- table_len /1024 / 1024 ,/*phsical length in MB */
128+ table_len /( 1024 * 1024 ) ,/*physical length in MB */
111129
112- tuple_count ,/* number of live tuples */
113- (double )tuple_len /1024 / 1024 ,/* live tuples in MB */
130+ ( double ) tuple_count ,/* number of live tuples */
131+ (double )tuple_len /( 1024 * 1024 ) ,/* live tuples in MB */
114132tuple_percent ,/* live tuples in % */
115133
116- dead_tuple_count ,/* number of dead tuples */
117- (double )dead_tuple_len /1024 / 1024 ,/* dead tuples in MB */
134+ ( double ) dead_tuple_count ,/* number of dead tuples */
135+ (double )dead_tuple_len /( 1024 * 1024 ) ,/* dead tuples in MB */
118136dead_tuple_percent ,/* dead tuples in % */
119137
120- (double )free_space /1024 / 1024 , /* free/available space in
121- * MB */
138+ (double )free_space /( 1024 * 1024 ), /* free/available space in
139+ * MB */
122140
123141free_percent ,/* free/available space in % */
124142