mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08:00
Add pgstatginindex() function to get the size of the GIN pending list.
Fujii Masao, reviewed by Kyotaro Horiguchi.
This commit is contained in:
parent
cdf498c5d7
commit
357cbaaeae
@ -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);
|
||||
}
|
||||
|
11
contrib/pgstattuple/pgstattuple--1.0--1.1.sql
Normal file
11
contrib/pgstattuple/pgstattuple--1.0--1.1.sql
Normal 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;
|
@ -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;
|
@ -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
|
||||
|
@ -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</>
|
||||
|
Loading…
Reference in New Issue
Block a user