Add pgstatginindex() function to get the size of the GIN pending list.

Fujii Masao, reviewed by Kyotaro Horiguchi.
This commit is contained in:
Heikki Linnakangas 2012-12-05 09:58:03 +02:00
parent cdf498c5d7
commit 357cbaaeae
8 changed files with 187 additions and 5 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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');

View File

@ -244,6 +244,63 @@ leaf_fragmentation | 0
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>pgstatginindex(regclass) returns record</>
</term>
<listitem>
<para>
<function>pgstatginindex</function> returns a record showing information
about a GIN index. For example:
<programlisting>
test=> SELECT * FROM pgstatginindex('test_gin_index');
-[ RECORD 1 ]--+--
version | 1
pending_pages | 0
pending_tuples | 0
</programlisting>
</para>
<para>
The output columns are:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Column</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>version</structfield></entry>
<entry><type>integer</type></entry>
<entry>GIN version number</entry>
</row>
<row>
<entry><structfield>pending_pages</structfield></entry>
<entry><type>integer</type></entry>
<entry>Number of pages in the pending list</entry>
</row>
<row>
<entry><structfield>pending_tuples</structfield></entry>
<entry><type>bigint</type></entry>
<entry>Number of tuples in the pending list</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>pg_relpages(text) returns bigint</>