1
1
/*
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 $
3
3
*
4
4
* Copyright (c) 2001 Tatsuo Ishii
5
5
*
23
23
*/
24
24
25
25
#include "postgres.h"
26
+
26
27
#include "fmgr.h"
27
28
#include "access/heapam.h"
28
29
#include "access/transam.h"
@@ -48,20 +49,21 @@ pgstattuple(PG_FUNCTION_ARGS)
48
49
HeapScanDesc scan ;
49
50
HeapTuple tuple ;
50
51
BlockNumber nblocks ;
51
- BlockNumber block = InvalidBlockNumber ;
52
+ BlockNumber block = 0 ; /* next block to count free space in */
53
+ BlockNumber tupblock ;
54
+ Buffer buffer ;
52
55
double table_len ;
53
56
uint64 tuple_len = 0 ;
54
57
uint64 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 ;
57
60
double tuple_percent ;
58
61
double dead_tuple_percent ;
59
62
60
- Buffer buffer = InvalidBuffer ;
61
63
uint64 free_space = 0 ; /* free/reusable space in bytes */
62
64
double free_percent ; /* free/reusable space in % */
63
65
64
- rel = heap_openr (NameStr (* p ), NoLock );
66
+ rel = heap_openr (NameStr (* p ), AccessShareLock );
65
67
nblocks = RelationGetNumberOfBlocks (rel );
66
68
scan = heap_beginscan (rel , false, SnapshotAny , 0 , NULL );
67
69
@@ -78,17 +80,33 @@ pgstattuple(PG_FUNCTION_ARGS)
78
80
dead_tuple_count ++ ;
79
81
}
80
82
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 )
83
92
{
84
- block = BlockIdGetBlockNumber (& tuple -> t_self .ip_blkid );
85
93
buffer = ReadBuffer (rel , block );
86
94
free_space += PageGetFreeSpace ((Page ) BufferGetPage (buffer ));
87
95
ReleaseBuffer (buffer );
96
+ block ++ ;
88
97
}
89
98
}
90
99
heap_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 );
92
110
93
111
table_len = (double ) nblocks * BLCKSZ ;
94
112
@@ -105,20 +123,20 @@ pgstattuple(PG_FUNCTION_ARGS)
105
123
free_percent = (double ) free_space * 100.0 / table_len ;
106
124
}
107
125
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%%" ,
109
127
110
- table_len / 1024 / 1024 , /* phsical length in MB */
128
+ table_len / ( 1024 * 1024 ) , /* physical length in MB */
111
129
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 */
114
132
tuple_percent , /* live tuples in % */
115
133
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 */
118
136
dead_tuple_percent , /* dead tuples in % */
119
137
120
- (double ) free_space / 1024 / 1024 , /* free/available space in
121
- * MB */
138
+ (double ) free_space / ( 1024 * 1024 ), /* free/available space in
139
+ * MB */
122
140
123
141
free_percent , /* free/available space in % */
124
142
0 commit comments