Skip to content

Commit 357cbaa

Browse files
committed
Add pgstatginindex() function to get the size of the GIN pending list.
Fujii Masao, reviewed by Kyotaro Horiguchi.
1 parent cdf498c commit 357cbaa

File tree

8 files changed

+187
-5
lines changed

8 files changed

+187
-5
lines changed

contrib/pgstattuple/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ MODULE_big = pgstattuple
44
OBJS = pgstattuple.o pgstatindex.o
55

66
EXTENSION = pgstattuple
7-
DATA = pgstattuple--1.0.sql pgstattuple--unpackaged--1.0.sql
7+
DATA = pgstattuple--1.1.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
88

99
REGRESS = pgstattuple
1010

contrib/pgstattuple/expected/pgstattuple.out

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CREATE EXTENSION pgstattuple;
44
-- the pgstattuple functions, but the results for empty tables and
55
-- indexes should be that.
66
--
7-
create table test (a int primary key);
7+
create table test (a int primary key, b int[]);
88
select * from pgstattuple('test'::text);
99
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
1010
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
@@ -35,3 +35,10 @@ select pg_relpages('test_pkey');
3535
1
3636
(1 row)
3737

38+
create index test_ginidx on test using gin (b);
39+
select * from pgstatginindex('test_ginidx');
40+
version | pending_pages | pending_tuples
41+
---------+---------------+----------------
42+
1 | 0 | 0
43+
(1 row)
44+

contrib/pgstattuple/pgstatindex.c

+94
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727

2828
#include "postgres.h"
2929

30+
#include "access/gin_private.h"
3031
#include "access/heapam.h"
32+
#include "access/htup_details.h"
3133
#include "access/nbtree.h"
3234
#include "catalog/namespace.h"
3335
#include "funcapi.h"
@@ -39,12 +41,15 @@
3941

4042
extern Datum pgstatindex(PG_FUNCTION_ARGS);
4143
extern Datum pg_relpages(PG_FUNCTION_ARGS);
44+
extern Datum pgstatginindex(PG_FUNCTION_ARGS);
4245

4346
PG_FUNCTION_INFO_V1(pgstatindex);
4447
PG_FUNCTION_INFO_V1(pg_relpages);
48+
PG_FUNCTION_INFO_V1(pgstatginindex);
4549

4650
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
4751
#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
52+
#define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID)
4853

4954
#define CHECK_PAGE_OFFSET_RANGE(pg, offnum) { \
5055
if ( !(FirstOffsetNumber <= (offnum) && \
@@ -79,6 +84,19 @@ typedef struct BTIndexStat
7984
uint64 fragments;
8085
} BTIndexStat;
8186

87+
/* ------------------------------------------------
88+
* A structure for a whole GIN index statistics
89+
* used by pgstatginindex().
90+
* ------------------------------------------------
91+
*/
92+
typedef struct GinIndexStat
93+
{
94+
int32 version;
95+
96+
BlockNumber pending_pages;
97+
int64 pending_tuples;
98+
} GinIndexStat;
99+
82100
/* ------------------------------------------------------
83101
* pgstatindex()
84102
*
@@ -292,3 +310,79 @@ pg_relpages(PG_FUNCTION_ARGS)
292310

293311
PG_RETURN_INT64(relpages);
294312
}
313+
314+
/* ------------------------------------------------------
315+
* pgstatginindex()
316+
*
317+
* Usage: SELECT * FROM pgstatginindex('ginindex');
318+
* ------------------------------------------------------
319+
*/
320+
Datum
321+
pgstatginindex(PG_FUNCTION_ARGS)
322+
{
323+
Oid relid = PG_GETARG_OID(0);
324+
Relation rel;
325+
Buffer buffer;
326+
Page page;
327+
GinMetaPageData *metadata;
328+
GinIndexStat stats;
329+
HeapTuple tuple;
330+
TupleDesc tupleDesc;
331+
Datum values[3];
332+
bool nulls[3] = {false, false, false};
333+
Datum result;
334+
335+
if (!superuser())
336+
ereport(ERROR,
337+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
338+
(errmsg("must be superuser to use pgstattuple functions"))));
339+
340+
rel = relation_open(relid, AccessShareLock);
341+
342+
if (!IS_INDEX(rel) || !IS_GIN(rel))
343+
elog(ERROR, "relation \"%s\" is not a GIN index",
344+
RelationGetRelationName(rel));
345+
346+
/*
347+
* Reject attempts to read non-local temporary relations; we would be
348+
* likely to get wrong data since we have no visibility into the owning
349+
* session's local buffers.
350+
*/
351+
if (RELATION_IS_OTHER_TEMP(rel))
352+
ereport(ERROR,
353+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
354+
errmsg("cannot access temporary indexes of other sessions")));
355+
356+
/*
357+
* Read metapage
358+
*/
359+
buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO);
360+
LockBuffer(buffer, GIN_SHARE);
361+
page = BufferGetPage(buffer);
362+
metadata = GinPageGetMeta(page);
363+
364+
stats.version = metadata->ginVersion;
365+
stats.pending_pages = metadata->nPendingPages;
366+
stats.pending_tuples = metadata->nPendingHeapTuples;
367+
368+
UnlockReleaseBuffer(buffer);
369+
relation_close(rel, AccessShareLock);
370+
371+
/*
372+
* Build a tuple descriptor for our result type
373+
*/
374+
if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
375+
elog(ERROR, "return type must be a row type");
376+
377+
values[0] = Int32GetDatum(stats.version);
378+
values[1] = UInt32GetDatum(stats.pending_pages);
379+
values[2] = Int64GetDatum(stats.pending_tuples);
380+
381+
/*
382+
* Build and return the tuple
383+
*/
384+
tuple = heap_form_tuple(tupleDesc, values, nulls);
385+
result = HeapTupleGetDatum(tuple);
386+
387+
PG_RETURN_DATUM(result);
388+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* contrib/pgstattuple/pgstattuple--1.0--1.1.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.1'" to load this file. \quit
5+
6+
CREATE FUNCTION pgstatginindex(IN relname regclass,
7+
OUT version INT4,
8+
OUT pending_pages INT4,
9+
OUT pending_tuples BIGINT)
10+
AS 'MODULE_PATHNAME', 'pgstatginindex'
11+
LANGUAGE C STRICT;

contrib/pgstattuple/pgstattuple--1.0.sql renamed to contrib/pgstattuple/pgstattuple--1.1.sql

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* contrib/pgstattuple/pgstattuple--1.0.sql */
1+
/* contrib/pgstattuple/pgstattuple--1.1.sql */
22

33
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
44
\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
@@ -47,3 +47,12 @@ CREATE FUNCTION pg_relpages(IN relname text)
4747
RETURNS BIGINT
4848
AS 'MODULE_PATHNAME', 'pg_relpages'
4949
LANGUAGE C STRICT;
50+
51+
/* New stuff in 1.1 begins here */
52+
53+
CREATE FUNCTION pgstatginindex(IN relname regclass,
54+
OUT version INT4,
55+
OUT pending_pages INT4,
56+
OUT pending_tuples BIGINT)
57+
AS 'MODULE_PATHNAME', 'pgstatginindex'
58+
LANGUAGE C STRICT;
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pgstattuple extension
22
comment = 'show tuple-level statistics'
3-
default_version = '1.0'
3+
default_version = '1.1'
44
module_pathname = '$libdir/pgstattuple'
55
relocatable = true

contrib/pgstattuple/sql/pgstattuple.sql

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CREATE EXTENSION pgstattuple;
66
-- indexes should be that.
77
--
88

9-
create table test (a int primary key);
9+
create table test (a int primary key, b int[]);
1010

1111
select * from pgstattuple('test'::text);
1212
select * from pgstattuple('test'::regclass);
@@ -15,3 +15,7 @@ select * from pgstatindex('test_pkey');
1515

1616
select pg_relpages('test');
1717
select pg_relpages('test_pkey');
18+
19+
create index test_ginidx on test using gin (b);
20+
21+
select * from pgstatginindex('test_ginidx');

doc/src/sgml/pgstattuple.sgml

+57
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,63 @@ leaf_fragmentation | 0
244244
</listitem>
245245
</varlistentry>
246246

247+
<varlistentry>
248+
<term>
249+
<function>pgstatginindex(regclass) returns record</>
250+
</term>
251+
252+
<listitem>
253+
<para>
254+
<function>pgstatginindex</function> returns a record showing information
255+
about a GIN index. For example:
256+
<programlisting>
257+
test=> SELECT * FROM pgstatginindex('test_gin_index');
258+
-[ RECORD 1 ]--+--
259+
version | 1
260+
pending_pages | 0
261+
pending_tuples | 0
262+
</programlisting>
263+
</para>
264+
265+
<para>
266+
The output columns are:
267+
268+
<informaltable>
269+
<tgroup cols="3">
270+
<thead>
271+
<row>
272+
<entry>Column</entry>
273+
<entry>Type</entry>
274+
<entry>Description</entry>
275+
</row>
276+
</thead>
277+
278+
<tbody>
279+
<row>
280+
<entry><structfield>version</structfield></entry>
281+
<entry><type>integer</type></entry>
282+
<entry>GIN version number</entry>
283+
</row>
284+
285+
<row>
286+
<entry><structfield>pending_pages</structfield></entry>
287+
<entry><type>integer</type></entry>
288+
<entry>Number of pages in the pending list</entry>
289+
</row>
290+
291+
<row>
292+
<entry><structfield>pending_tuples</structfield></entry>
293+
<entry><type>bigint</type></entry>
294+
<entry>Number of tuples in the pending list</entry>
295+
</row>
296+
297+
</tbody>
298+
</tgroup>
299+
</informaltable>
300+
</para>
301+
</listitem>
302+
</varlistentry>
303+
247304
<varlistentry>
248305
<term>
249306
<function>pg_relpages(text) returns bigint</>

0 commit comments

Comments
 (0)