From 357cbaaeae5bc1f385828be97345e7ea24235f92 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 5 Dec 2012 09:58:03 +0200 Subject: [PATCH] Add pgstatginindex() function to get the size of the GIN pending list. Fujii Masao, reviewed by Kyotaro Horiguchi. --- contrib/pgstattuple/Makefile | 2 +- contrib/pgstattuple/expected/pgstattuple.out | 9 +- contrib/pgstattuple/pgstatindex.c | 94 +++++++++++++++++++ contrib/pgstattuple/pgstattuple--1.0--1.1.sql | 11 +++ ...tattuple--1.0.sql => pgstattuple--1.1.sql} | 11 ++- contrib/pgstattuple/pgstattuple.control | 2 +- contrib/pgstattuple/sql/pgstattuple.sql | 6 +- doc/src/sgml/pgstattuple.sgml | 57 +++++++++++ 8 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 contrib/pgstattuple/pgstattuple--1.0--1.1.sql rename contrib/pgstattuple/{pgstattuple--1.0.sql => pgstattuple--1.1.sql} (87%) diff --git a/contrib/pgstattuple/Makefile b/contrib/pgstattuple/Makefile index 6ac277598c..fc893d8c85 100644 --- a/contrib/pgstattuple/Makefile +++ b/contrib/pgstattuple/Makefile @@ -4,7 +4,7 @@ MODULE_big = pgstattuple OBJS = pgstattuple.o pgstatindex.o EXTENSION = pgstattuple -DATA = pgstattuple--1.0.sql pgstattuple--unpackaged--1.0.sql +DATA = pgstattuple--1.1.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql REGRESS = pgstattuple diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out index 2d8dd5e19c..ab28f50cb0 100644 --- a/contrib/pgstattuple/expected/pgstattuple.out +++ b/contrib/pgstattuple/expected/pgstattuple.out @@ -4,7 +4,7 @@ CREATE EXTENSION pgstattuple; -- the pgstattuple functions, but the results for empty tables and -- indexes should be that. -- -create table test (a int primary key); +create table test (a int primary key, b int[]); select * from pgstattuple('test'::text); table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent -----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+-------------- @@ -35,3 +35,10 @@ select pg_relpages('test_pkey'); 1 (1 row) +create index test_ginidx on test using gin (b); +select * from pgstatginindex('test_ginidx'); + version | pending_pages | pending_tuples +---------+---------------+---------------- + 1 | 0 | 0 +(1 row) + diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index d4fc8a0fd6..984ff7c45a 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -27,7 +27,9 @@ #include "postgres.h" +#include "access/gin_private.h" #include "access/heapam.h" +#include "access/htup_details.h" #include "access/nbtree.h" #include "catalog/namespace.h" #include "funcapi.h" @@ -39,12 +41,15 @@ extern Datum pgstatindex(PG_FUNCTION_ARGS); extern Datum pg_relpages(PG_FUNCTION_ARGS); +extern Datum pgstatginindex(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pgstatindex); PG_FUNCTION_INFO_V1(pg_relpages); +PG_FUNCTION_INFO_V1(pgstatginindex); #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX) #define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID) +#define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID) #define CHECK_PAGE_OFFSET_RANGE(pg, offnum) { \ if ( !(FirstOffsetNumber <= (offnum) && \ @@ -79,6 +84,19 @@ typedef struct BTIndexStat uint64 fragments; } BTIndexStat; +/* ------------------------------------------------ + * A structure for a whole GIN index statistics + * used by pgstatginindex(). + * ------------------------------------------------ + */ +typedef struct GinIndexStat +{ + int32 version; + + BlockNumber pending_pages; + int64 pending_tuples; +} GinIndexStat; + /* ------------------------------------------------------ * pgstatindex() * @@ -292,3 +310,79 @@ pg_relpages(PG_FUNCTION_ARGS) PG_RETURN_INT64(relpages); } + +/* ------------------------------------------------------ + * pgstatginindex() + * + * Usage: SELECT * FROM pgstatginindex('ginindex'); + * ------------------------------------------------------ + */ +Datum +pgstatginindex(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Relation rel; + Buffer buffer; + Page page; + GinMetaPageData *metadata; + GinIndexStat stats; + HeapTuple tuple; + TupleDesc tupleDesc; + Datum values[3]; + bool nulls[3] = {false, false, false}; + Datum result; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to use pgstattuple functions")))); + + rel = relation_open(relid, AccessShareLock); + + if (!IS_INDEX(rel) || !IS_GIN(rel)) + elog(ERROR, "relation \"%s\" is not a GIN index", + RelationGetRelationName(rel)); + + /* + * Reject attempts to read non-local temporary relations; we would be + * likely to get wrong data since we have no visibility into the owning + * session's local buffers. + */ + if (RELATION_IS_OTHER_TEMP(rel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary indexes of other sessions"))); + + /* + * Read metapage + */ + buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO); + LockBuffer(buffer, GIN_SHARE); + page = BufferGetPage(buffer); + metadata = GinPageGetMeta(page); + + stats.version = metadata->ginVersion; + stats.pending_pages = metadata->nPendingPages; + stats.pending_tuples = metadata->nPendingHeapTuples; + + UnlockReleaseBuffer(buffer); + relation_close(rel, AccessShareLock); + + /* + * Build a tuple descriptor for our result type + */ + if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + values[0] = Int32GetDatum(stats.version); + values[1] = UInt32GetDatum(stats.pending_pages); + values[2] = Int64GetDatum(stats.pending_tuples); + + /* + * Build and return the tuple + */ + tuple = heap_form_tuple(tupleDesc, values, nulls); + result = HeapTupleGetDatum(tuple); + + PG_RETURN_DATUM(result); +} diff --git a/contrib/pgstattuple/pgstattuple--1.0--1.1.sql b/contrib/pgstattuple/pgstattuple--1.0--1.1.sql new file mode 100644 index 0000000000..cf582a0b81 --- /dev/null +++ b/contrib/pgstattuple/pgstattuple--1.0--1.1.sql @@ -0,0 +1,11 @@ +/* contrib/pgstattuple/pgstattuple--1.0--1.1.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.1'" to load this file. \quit + +CREATE FUNCTION pgstatginindex(IN relname regclass, + OUT version INT4, + OUT pending_pages INT4, + OUT pending_tuples BIGINT) +AS 'MODULE_PATHNAME', 'pgstatginindex' +LANGUAGE C STRICT; diff --git a/contrib/pgstattuple/pgstattuple--1.0.sql b/contrib/pgstattuple/pgstattuple--1.1.sql similarity index 87% rename from contrib/pgstattuple/pgstattuple--1.0.sql rename to contrib/pgstattuple/pgstattuple--1.1.sql index f7e03083ad..b21fbf83e4 100644 --- a/contrib/pgstattuple/pgstattuple--1.0.sql +++ b/contrib/pgstattuple/pgstattuple--1.1.sql @@ -1,4 +1,4 @@ -/* contrib/pgstattuple/pgstattuple--1.0.sql */ +/* contrib/pgstattuple/pgstattuple--1.1.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit @@ -47,3 +47,12 @@ CREATE FUNCTION pg_relpages(IN relname text) RETURNS BIGINT AS 'MODULE_PATHNAME', 'pg_relpages' LANGUAGE C STRICT; + +/* New stuff in 1.1 begins here */ + +CREATE FUNCTION pgstatginindex(IN relname regclass, + OUT version INT4, + OUT pending_pages INT4, + OUT pending_tuples BIGINT) +AS 'MODULE_PATHNAME', 'pgstatginindex' +LANGUAGE C STRICT; diff --git a/contrib/pgstattuple/pgstattuple.control b/contrib/pgstattuple/pgstattuple.control index 7b5129b2f2..fcfd36f1b1 100644 --- a/contrib/pgstattuple/pgstattuple.control +++ b/contrib/pgstattuple/pgstattuple.control @@ -1,5 +1,5 @@ # pgstattuple extension comment = 'show tuple-level statistics' -default_version = '1.0' +default_version = '1.1' module_pathname = '$libdir/pgstattuple' relocatable = true diff --git a/contrib/pgstattuple/sql/pgstattuple.sql b/contrib/pgstattuple/sql/pgstattuple.sql index 2fd1152e8c..8cb350d6ee 100644 --- a/contrib/pgstattuple/sql/pgstattuple.sql +++ b/contrib/pgstattuple/sql/pgstattuple.sql @@ -6,7 +6,7 @@ CREATE EXTENSION pgstattuple; -- indexes should be that. -- -create table test (a int primary key); +create table test (a int primary key, b int[]); select * from pgstattuple('test'::text); select * from pgstattuple('test'::regclass); @@ -15,3 +15,7 @@ select * from pgstatindex('test_pkey'); select pg_relpages('test'); select pg_relpages('test_pkey'); + +create index test_ginidx on test using gin (b); + +select * from pgstatginindex('test_ginidx'); diff --git a/doc/src/sgml/pgstattuple.sgml b/doc/src/sgml/pgstattuple.sgml index a55b35cb3f..9f98448d7b 100644 --- a/doc/src/sgml/pgstattuple.sgml +++ b/doc/src/sgml/pgstattuple.sgml @@ -244,6 +244,63 @@ leaf_fragmentation | 0 + + + pgstatginindex(regclass) returns record + + + + + pgstatginindex returns a record showing information + about a GIN index. For example: + +test=> SELECT * FROM pgstatginindex('test_gin_index'); +-[ RECORD 1 ]--+-- +version | 1 +pending_pages | 0 +pending_tuples | 0 + + + + + The output columns are: + + + + + + Column + Type + Description + + + + + + version + integer + GIN version number + + + + pending_pages + integer + Number of pages in the pending list + + + + pending_tuples + bigint + Number of tuples in the pending list + + + + + + + + + pg_relpages(text) returns bigint