Commit 357cbaae authored by Heikki Linnakangas's avatar Heikki Linnakangas

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

Fujii Masao, reviewed by Kyotaro Horiguchi.
parent cdf498c5
......@@ -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
......
......@@ -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)
......@@ -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);
}
/* 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;
/* 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;
# pgstattuple extension
comment = 'show tuple-level statistics'
default_version = '1.0'
default_version = '1.1'
module_pathname = '$libdir/pgstattuple'
relocatable = true
......@@ -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');
......@@ -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</>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment