PostgreSQL Source Code  git master
pgstatapprox.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/relation.h"
#include "access/transam.h"
#include "access/visibilitymap.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_am_d.h"
#include "commands/vacuum.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
Include dependency graph for pgstatapprox.c:

Go to the source code of this file.

Data Structures

struct  output_type
 

Macros

#define NUM_OUTPUT_COLUMNS   10
 

Typedefs

typedef struct output_type output_type
 

Functions

 PG_FUNCTION_INFO_V1 (pgstattuple_approx)
 
 PG_FUNCTION_INFO_V1 (pgstattuple_approx_v1_5)
 
Datum pgstattuple_approx_internal (Oid relid, FunctionCallInfo fcinfo)
 
static void statapprox_heap (Relation rel, output_type *stat)
 
Datum pgstattuple_approx (PG_FUNCTION_ARGS)
 
Datum pgstattuple_approx_v1_5 (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ NUM_OUTPUT_COLUMNS

#define NUM_OUTPUT_COLUMNS   10

Definition at line 52 of file pgstatapprox.c.

Referenced by pgstattuple_approx_internal().

Typedef Documentation

◆ output_type

typedef struct output_type output_type

Function Documentation

◆ PG_FUNCTION_INFO_V1() [1/2]

PG_FUNCTION_INFO_V1 ( pgstattuple_approx  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( pgstattuple_approx_v1_5  )

◆ pgstattuple_approx()

Datum pgstattuple_approx ( PG_FUNCTION_ARGS  )

Definition at line 227 of file pgstatapprox.c.

References ereport, errcode(), errmsg(), ERROR, PG_GETARG_OID, PG_RETURN_DATUM, pgstattuple_approx_internal(), and superuser().

228 {
229  Oid relid = PG_GETARG_OID(0);
230 
231  if (!superuser())
232  ereport(ERROR,
233  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
234  errmsg("must be superuser to use pgstattuple functions")));
235 
237 }
int errcode(int sqlerrcode)
Definition: elog.c:691
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
#define ERROR
Definition: elog.h:43
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define ereport(elevel,...)
Definition: elog.h:155
Datum pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
Definition: pgstatapprox.c:255
int errmsg(const char *fmt,...)
Definition: elog.c:902

◆ pgstattuple_approx_internal()

Datum pgstattuple_approx_internal ( Oid  relid,
FunctionCallInfo  fcinfo 
)

Definition at line 255 of file pgstatapprox.c.

References AccessShareLock, output_type::dead_tuple_count, output_type::dead_tuple_len, output_type::dead_tuple_percent, elog, ereport, errcode(), errmsg(), ERROR, Float8GetDatum(), output_type::free_percent, output_type::free_space, get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum, i, Int64GetDatum(), TupleDescData::natts, NUM_OUTPUT_COLUMNS, RelationData::rd_rel, relation_close(), RELATION_IS_OTHER_TEMP, relation_open(), RelationGetRelationName, output_type::scanned_percent, statapprox_heap(), output_type::table_len, output_type::tuple_count, output_type::tuple_len, output_type::tuple_percent, TYPEFUNC_COMPOSITE, and values.

Referenced by pgstattuple_approx(), and pgstattuple_approx_v1_5().

256 {
257  Relation rel;
258  output_type stat = {0};
259  TupleDesc tupdesc;
260  bool nulls[NUM_OUTPUT_COLUMNS];
262  HeapTuple ret;
263  int i = 0;
264 
265  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
266  elog(ERROR, "return type must be a row type");
267 
268  if (tupdesc->natts != NUM_OUTPUT_COLUMNS)
269  elog(ERROR, "incorrect number of output arguments");
270 
271  rel = relation_open(relid, AccessShareLock);
272 
273  /*
274  * Reject attempts to read non-local temporary relations; we would be
275  * likely to get wrong data since we have no visibility into the owning
276  * session's local buffers.
277  */
278  if (RELATION_IS_OTHER_TEMP(rel))
279  ereport(ERROR,
280  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
281  errmsg("cannot access temporary tables of other sessions")));
282 
283  /*
284  * We support only relation kinds with a visibility map and a free space
285  * map.
286  */
287  if (!(rel->rd_rel->relkind == RELKIND_RELATION ||
288  rel->rd_rel->relkind == RELKIND_MATVIEW ||
289  rel->rd_rel->relkind == RELKIND_TOASTVALUE))
290  ereport(ERROR,
291  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
292  errmsg("\"%s\" is not a table, materialized view, or TOAST table",
293  RelationGetRelationName(rel))));
294 
295  if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
296  ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
297  errmsg("only heap AM is supported")));
298 
299  statapprox_heap(rel, &stat);
300 
302 
303  memset(nulls, 0, sizeof(nulls));
304 
305  values[i++] = Int64GetDatum(stat.table_len);
306  values[i++] = Float8GetDatum(stat.scanned_percent);
307  values[i++] = Int64GetDatum(stat.tuple_count);
308  values[i++] = Int64GetDatum(stat.tuple_len);
309  values[i++] = Float8GetDatum(stat.tuple_percent);
310  values[i++] = Int64GetDatum(stat.dead_tuple_count);
311  values[i++] = Int64GetDatum(stat.dead_tuple_len);
312  values[i++] = Float8GetDatum(stat.dead_tuple_percent);
313  values[i++] = Int64GetDatum(stat.free_space);
314  values[i++] = Float8GetDatum(stat.free_percent);
315 
316  ret = heap_form_tuple(tupdesc, values, nulls);
317  return HeapTupleGetDatum(ret);
318 }
#define NUM_OUTPUT_COLUMNS
Definition: pgstatapprox.c:52
uint64 dead_tuple_count
Definition: pgstatapprox.c:45
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:691
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
double dead_tuple_percent
Definition: pgstatapprox.c:47
Form_pg_class rd_rel
Definition: rel.h:110
uint64 tuple_count
Definition: pgstatapprox.c:42
double free_percent
Definition: pgstatapprox.c:49
uint64 table_len
Definition: pgstatapprox.c:40
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1710
double tuple_percent
Definition: pgstatapprox.c:44
uint64 tuple_len
Definition: pgstatapprox.c:43
#define ERROR
Definition: elog.h:43
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define RelationGetRelationName(relation)
Definition: rel.h:491
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1701
uintptr_t Datum
Definition: postgres.h:367
#define ereport(elevel,...)
Definition: elog.h:155
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:594
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
static void statapprox_heap(Relation rel, output_type *stat)
Definition: pgstatapprox.c:65
static Datum values[MAXATTR]
Definition: bootstrap.c:165
uint64 free_space
Definition: pgstatapprox.c:48
uint64 dead_tuple_len
Definition: pgstatapprox.c:46
int errmsg(const char *fmt,...)
Definition: elog.c:902
uint64 scanned_percent
Definition: pgstatapprox.c:41
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ pgstattuple_approx_v1_5()

Datum pgstattuple_approx_v1_5 ( PG_FUNCTION_ARGS  )

Definition at line 247 of file pgstatapprox.c.

References PG_GETARG_OID, PG_RETURN_DATUM, and pgstattuple_approx_internal().

248 {
249  Oid relid = PG_GETARG_OID(0);
250 
252 }
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
Definition: pgstatapprox.c:255

◆ statapprox_heap()

static void statapprox_heap ( Relation  rel,
output_type stat 
)
static

Definition at line 65 of file pgstatapprox.c.

References Assert, BAS_BULKREAD, buf, BUFFER_LOCK_SHARE, BufferGetPage, BufferIsValid, CHECK_FOR_INTERRUPTS, output_type::dead_tuple_count, output_type::dead_tuple_len, output_type::dead_tuple_percent, elog, ERROR, FirstOffsetNumber, output_type::free_percent, output_type::free_space, GetAccessStrategy(), GetOldestNonRemovableTransactionId(), GetRecordedFreeSpace(), HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleSatisfiesVacuum(), InvalidBuffer, ItemIdGetLength, ItemIdIsDead, ItemIdIsNormal, ItemIdIsRedirected, ItemIdIsUsed, ItemPointerSet, LockBuffer(), MAIN_FORKNUM, Max, OffsetNumberNext, OldestXmin, PageGetHeapFreeSpace(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageIsEmpty, PageIsNew, RBM_NORMAL, ReadBufferExtended(), RelationGetNumberOfBlocks, RelationGetRelid, ReleaseBuffer(), output_type::scanned_percent, SizeOfPageHeaderData, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, output_type::table_len, output_type::tuple_count, output_type::tuple_len, output_type::tuple_percent, UnlockReleaseBuffer(), vac_estimate_reltuples(), and VM_ALL_VISIBLE.

Referenced by pgstattuple_approx_internal().

66 {
67  BlockNumber scanned,
68  nblocks,
69  blkno;
70  Buffer vmbuffer = InvalidBuffer;
71  BufferAccessStrategy bstrategy;
73 
74  OldestXmin = GetOldestNonRemovableTransactionId(rel);
75  bstrategy = GetAccessStrategy(BAS_BULKREAD);
76 
77  nblocks = RelationGetNumberOfBlocks(rel);
78  scanned = 0;
79 
80  for (blkno = 0; blkno < nblocks; blkno++)
81  {
82  Buffer buf;
83  Page page;
84  OffsetNumber offnum,
85  maxoff;
86  Size freespace;
87 
89 
90  /*
91  * If the page has only visible tuples, then we can find out the free
92  * space from the FSM and move on.
93  */
94  if (VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
95  {
96  freespace = GetRecordedFreeSpace(rel, blkno);
97  stat->tuple_len += BLCKSZ - freespace;
98  stat->free_space += freespace;
99  continue;
100  }
101 
102  buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno,
103  RBM_NORMAL, bstrategy);
104 
106 
107  page = BufferGetPage(buf);
108 
109  /*
110  * It's not safe to call PageGetHeapFreeSpace() on new pages, so we
111  * treat them as being free space for our purposes.
112  */
113  if (!PageIsNew(page))
114  stat->free_space += PageGetHeapFreeSpace(page);
115  else
116  stat->free_space += BLCKSZ - SizeOfPageHeaderData;
117 
118  /* We may count the page as scanned even if it's new/empty */
119  scanned++;
120 
121  if (PageIsNew(page) || PageIsEmpty(page))
122  {
123  UnlockReleaseBuffer(buf);
124  continue;
125  }
126 
127  /*
128  * Look at each tuple on the page and decide whether it's live or
129  * dead, then count it and its size. Unlike lazy_scan_heap, we can
130  * afford to ignore problems and special cases.
131  */
132  maxoff = PageGetMaxOffsetNumber(page);
133 
134  for (offnum = FirstOffsetNumber;
135  offnum <= maxoff;
136  offnum = OffsetNumberNext(offnum))
137  {
138  ItemId itemid;
139  HeapTupleData tuple;
140 
141  itemid = PageGetItemId(page, offnum);
142 
143  if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid) ||
144  ItemIdIsDead(itemid))
145  {
146  continue;
147  }
148 
149  Assert(ItemIdIsNormal(itemid));
150 
151  ItemPointerSet(&(tuple.t_self), blkno, offnum);
152 
153  tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
154  tuple.t_len = ItemIdGetLength(itemid);
155  tuple.t_tableOid = RelationGetRelid(rel);
156 
157  /*
158  * We follow VACUUM's lead in counting INSERT_IN_PROGRESS tuples
159  * as "dead" while DELETE_IN_PROGRESS tuples are "live". We don't
160  * bother distinguishing tuples inserted/deleted by our own
161  * transaction.
162  */
163  switch (HeapTupleSatisfiesVacuum(&tuple, OldestXmin, buf))
164  {
165  case HEAPTUPLE_LIVE:
167  stat->tuple_len += tuple.t_len;
168  stat->tuple_count++;
169  break;
170  case HEAPTUPLE_DEAD:
173  stat->dead_tuple_len += tuple.t_len;
174  stat->dead_tuple_count++;
175  break;
176  default:
177  elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
178  break;
179  }
180  }
181 
182  UnlockReleaseBuffer(buf);
183  }
184 
185  stat->table_len = (uint64) nblocks * BLCKSZ;
186 
187  /*
188  * We don't know how many tuples are in the pages we didn't scan, so
189  * extrapolate the live-tuple count to the whole table in the same way
190  * that VACUUM does. (Like VACUUM, we're not taking a random sample, so
191  * just extrapolating linearly seems unsafe.) There should be no dead
192  * tuples in all-visible pages, so no correction is needed for that, and
193  * we already accounted for the space in those pages, too.
194  */
195  stat->tuple_count = vac_estimate_reltuples(rel, nblocks, scanned,
196  stat->tuple_count);
197 
198  /* It's not clear if we could get -1 here, but be safe. */
199  stat->tuple_count = Max(stat->tuple_count, 0);
200 
201  /*
202  * Calculate percentages if the relation has one or more pages.
203  */
204  if (nblocks != 0)
205  {
206  stat->scanned_percent = 100 * scanned / nblocks;
207  stat->tuple_percent = 100.0 * stat->tuple_len / stat->table_len;
208  stat->dead_tuple_percent = 100.0 * stat->dead_tuple_len / stat->table_len;
209  stat->free_percent = 100.0 * stat->free_space / stat->table_len;
210  }
211 
212  if (BufferIsValid(vmbuffer))
213  {
214  ReleaseBuffer(vmbuffer);
215  vmbuffer = InvalidBuffer;
216  }
217 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
uint64 dead_tuple_count
Definition: pgstatapprox.c:45
#define PageIsEmpty(page)
Definition: bufpage.h:222
double vac_estimate_reltuples(Relation relation, BlockNumber total_pages, BlockNumber scanned_pages, double scanned_tuples)
Definition: vacuum.c:1141
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
uint32 TransactionId
Definition: c.h:575
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:654
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3513
double dead_tuple_percent
Definition: pgstatapprox.c:47
#define SizeOfPageHeaderData
Definition: bufpage.h:216
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
uint64 tuple_count
Definition: pgstatapprox.c:42
double free_percent
Definition: pgstatapprox.c:49
uint64 table_len
Definition: pgstatapprox.c:40
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
double tuple_percent
Definition: pgstatapprox.c:44
uint64 tuple_len
Definition: pgstatapprox.c:43
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3536
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
Definition: procarray.c:1913
#define ERROR
Definition: elog.h:43
Size PageGetHeapFreeSpace(Page page)
Definition: bufpage.c:874
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
static char * buf
Definition: pg_test_fsync.c:68
#define FirstOffsetNumber
Definition: off.h:27
static TransactionId OldestXmin
Definition: vacuumlazy.c:335
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
Size GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk)
Definition: freespace.c:230
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3752
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:211
#define Max(x, y)
Definition: c.h:976
#define Assert(condition)
Definition: c.h:800
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define VM_ALL_VISIBLE(r, b, v)
Definition: visibilitymap.h:32
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
size_t Size
Definition: c.h:528
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
uint64 free_space
Definition: pgstatapprox.c:48
#define PageIsNew(page)
Definition: bufpage.h:229
uint64 dead_tuple_len
Definition: pgstatapprox.c:46
uint64 scanned_percent
Definition: pgstatapprox.c:41
#define elog(elevel,...)
Definition: elog.h:228
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:457
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127