Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions

pgstatindex.c File Reference

#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"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/builtins.h"
#include "utils/rel.h"
Include dependency graph for pgstatindex.c:

Go to the source code of this file.

Data Structures

struct  BTIndexStat
struct  GinIndexStat

Defines

#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)
#define CHECK_RELATION_BLOCK_RANGE(rel, blkno)

Typedefs

typedef struct BTIndexStat BTIndexStat
typedef struct GinIndexStat GinIndexStat

Functions

Datum pgstatindex (PG_FUNCTION_ARGS)
Datum pg_relpages (PG_FUNCTION_ARGS)
Datum pgstatginindex (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (pgstatindex)
 PG_FUNCTION_INFO_V1 (pg_relpages)
 PG_FUNCTION_INFO_V1 (pgstatginindex)

Define Documentation

#define CHECK_PAGE_OFFSET_RANGE (   pg,
  offnum 
)
Value:
{ \
        if ( !(FirstOffsetNumber <= (offnum) && \
                        (offnum) <= PageGetMaxOffsetNumber(pg)) ) \
             elog(ERROR, "page offset number out of range"); }

Definition at line 54 of file pgstatindex.c.

#define CHECK_RELATION_BLOCK_RANGE (   rel,
  blkno 
)
Value:
{ \
        if ( RelationGetNumberOfBlocks(rel) <= (BlockNumber) (blkno) ) \
             elog(ERROR, "block number out of range"); }

Definition at line 60 of file pgstatindex.c.

#define IS_BTREE (   r  )     ((r)->rd_rel->relam == BTREE_AM_OID)

Definition at line 51 of file pgstatindex.c.

Referenced by pgstatindex().

#define IS_GIN (   r  )     ((r)->rd_rel->relam == GIN_AM_OID)

Definition at line 52 of file pgstatindex.c.

Referenced by pgstatginindex().

#define IS_INDEX (   r  )     ((r)->rd_rel->relkind == RELKIND_INDEX)

Definition at line 50 of file pgstatindex.c.

Referenced by pgstatginindex(), and pgstatindex().


Typedef Documentation

typedef struct BTIndexStat BTIndexStat
typedef struct GinIndexStat GinIndexStat

Function Documentation

PG_FUNCTION_INFO_V1 ( pgstatindex   ) 
PG_FUNCTION_INFO_V1 ( pg_relpages   ) 
PG_FUNCTION_INFO_V1 ( pgstatginindex   ) 
Datum pg_relpages ( PG_FUNCTION_ARGS   ) 

Definition at line 290 of file pgstatindex.c.

References AccessShareLock, ereport, errcode(), errmsg(), ERROR, makeRangeVarFromNameList(), PG_GETARG_TEXT_P, PG_RETURN_INT64, relation_close(), relation_openrv(), RelationGetNumberOfBlocks, superuser(), and textToQualifiedNameList().

{
    text       *relname = PG_GETARG_TEXT_P(0);
    int64       relpages;
    Relation    rel;
    RangeVar   *relrv;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use pgstattuple functions"))));

    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
    rel = relation_openrv(relrv, AccessShareLock);

    /* note: this will work OK on non-local temp tables */

    relpages = RelationGetNumberOfBlocks(rel);

    relation_close(rel, AccessShareLock);

    PG_RETURN_INT64(relpages);
}

Datum pgstatginindex ( PG_FUNCTION_ARGS   ) 

Definition at line 321 of file pgstatindex.c.

References AccessShareLock, BufferGetPage, elog, ereport, errcode(), errmsg(), ERROR, get_call_result_type(), GIN_METAPAGE_BLKNO, GIN_SHARE, GinPageGetMeta, GinMetaPageData::ginVersion, heap_form_tuple(), HeapTupleGetDatum, Int32GetDatum, Int64GetDatum(), IS_GIN, IS_INDEX, LockBuffer(), GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, NULL, GinIndexStat::pending_pages, GinIndexStat::pending_tuples, PG_GETARG_OID, PG_RETURN_DATUM, ReadBuffer(), relation_close(), RELATION_IS_OTHER_TEMP, relation_open(), RelationGetRelationName, superuser(), TYPEFUNC_COMPOSITE, UInt32GetDatum, UnlockReleaseBuffer(), values, and GinIndexStat::version.

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

Datum pgstatindex ( PG_FUNCTION_ARGS   ) 

Definition at line 107 of file pgstatindex.c.

References AccessShareLock, BAS_BULKREAD, BTMetaPageData::btm_level, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTPageOpaqueData::btpo_next, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, BuildTupleFromCStrings(), CHECK_FOR_INTERRUPTS, BTIndexStat::deleted_pages, elog, BTIndexStat::empty_pages, ereport, errcode(), errmsg(), ERROR, BTIndexStat::fragments, BTIndexStat::free_space, get_call_result_type(), GetAccessStrategy(), HeapTupleGetDatum, BTIndexStat::internal_pages, IS_BTREE, IS_INDEX, BTIndexStat::leaf_pages, BTIndexStat::level, LockBuffer(), MAIN_FORKNUM, makeRangeVarFromNameList(), BTIndexStat::max_avail, NULL, P_IGNORE, P_ISDELETED, P_ISLEAF, P_ISROOT, P_NONE, PageGetFreeSpace(), PageGetSpecialPointer, palloc(), PG_GETARG_TEXT_P, PG_RETURN_DATUM, RBM_NORMAL, ReadBufferExtended(), relation_close(), RELATION_IS_OTHER_TEMP, relation_openrv(), RelationGetNumberOfBlocks, RelationGetRelationName, ReleaseBuffer(), BTIndexStat::root_blkno, BTIndexStat::root_pages, snprintf(), superuser(), textToQualifiedNameList(), TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, values, and BTIndexStat::version.

{
    text       *relname = PG_GETARG_TEXT_P(0);
    Relation    rel;
    RangeVar   *relrv;
    Datum       result;
    BlockNumber nblocks;
    BlockNumber blkno;
    BTIndexStat indexStat;
    BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to use pgstattuple functions"))));

    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
    rel = relation_openrv(relrv, AccessShareLock);

    if (!IS_INDEX(rel) || !IS_BTREE(rel))
        elog(ERROR, "relation \"%s\" is not a btree 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 tables of other sessions")));

    /*
     * Read metapage
     */
    {
        Buffer      buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy);
        Page        page = BufferGetPage(buffer);
        BTMetaPageData *metad = BTPageGetMeta(page);

        indexStat.version = metad->btm_version;
        indexStat.level = metad->btm_level;
        indexStat.root_blkno = metad->btm_root;

        ReleaseBuffer(buffer);
    }

    /* -- init counters -- */
    indexStat.root_pages = 0;
    indexStat.internal_pages = 0;
    indexStat.leaf_pages = 0;
    indexStat.empty_pages = 0;
    indexStat.deleted_pages = 0;

    indexStat.max_avail = 0;
    indexStat.free_space = 0;

    indexStat.fragments = 0;

    /*
     * Scan all blocks except the metapage
     */
    nblocks = RelationGetNumberOfBlocks(rel);

    for (blkno = 1; blkno < nblocks; blkno++)
    {
        Buffer      buffer;
        Page        page;
        BTPageOpaque opaque;

        CHECK_FOR_INTERRUPTS();

        /* Read and lock buffer */
        buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
        LockBuffer(buffer, BUFFER_LOCK_SHARE);

        page = BufferGetPage(buffer);
        opaque = (BTPageOpaque) PageGetSpecialPointer(page);

        /* Determine page type, and update totals */

        if (P_ISLEAF(opaque))
        {
            int         max_avail;

            max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData);
            indexStat.max_avail += max_avail;
            indexStat.free_space += PageGetFreeSpace(page);

            indexStat.leaf_pages++;

            /*
             * If the next leaf is on an earlier block, it means a
             * fragmentation.
             */
            if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno)
                indexStat.fragments++;
        }
        else if (P_ISDELETED(opaque))
            indexStat.deleted_pages++;
        else if (P_IGNORE(opaque))
            indexStat.empty_pages++;
        else if (P_ISROOT(opaque))
            indexStat.root_pages++;
        else
            indexStat.internal_pages++;

        /* Unlock and release buffer */
        LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
        ReleaseBuffer(buffer);
    }

    relation_close(rel, AccessShareLock);

    /*----------------------------
     * Build a result tuple
     *----------------------------
     */
    {
        TupleDesc   tupleDesc;
        int         j;
        char       *values[10];
        HeapTuple   tuple;

        /* 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");

        j = 0;
        values[j] = palloc(32);
        snprintf(values[j++], 32, "%d", indexStat.version);
        values[j] = palloc(32);
        snprintf(values[j++], 32, "%d", indexStat.level);
        values[j] = palloc(32);
        snprintf(values[j++], 32, INT64_FORMAT,
                 (indexStat.root_pages +
                  indexStat.leaf_pages +
                  indexStat.internal_pages +
                  indexStat.deleted_pages +
                  indexStat.empty_pages) * BLCKSZ);
        values[j] = palloc(32);
        snprintf(values[j++], 32, "%u", indexStat.root_blkno);
        values[j] = palloc(32);
        snprintf(values[j++], 32, INT64_FORMAT, indexStat.internal_pages);
        values[j] = palloc(32);
        snprintf(values[j++], 32, INT64_FORMAT, indexStat.leaf_pages);
        values[j] = palloc(32);
        snprintf(values[j++], 32, INT64_FORMAT, indexStat.empty_pages);
        values[j] = palloc(32);
        snprintf(values[j++], 32, INT64_FORMAT, indexStat.deleted_pages);
        values[j] = palloc(32);
        if (indexStat.max_avail > 0)
            snprintf(values[j++], 32, "%.2f",
                     100.0 - (double) indexStat.free_space / (double) indexStat.max_avail * 100.0);
        else
            snprintf(values[j++], 32, "NaN");
        values[j] = palloc(32);
        if (indexStat.leaf_pages > 0)
            snprintf(values[j++], 32, "%.2f",
                     (double) indexStat.fragments / (double) indexStat.leaf_pages * 100.0);
        else
            snprintf(values[j++], 32, "NaN");

        tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
                                       values);

        result = HeapTupleGetDatum(tuple);
    }

    PG_RETURN_DATUM(result);
}