diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index beff1b9..9f2ec1f 100644 *** a/contrib/pgstattuple/pgstatindex.c --- b/contrib/pgstattuple/pgstatindex.c *************** pgstatindex(PG_FUNCTION_ARGS) *** 95,100 **** --- 95,101 ---- BlockNumber nblocks; BlockNumber blkno; BTIndexStat indexStat; + BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD); if (!superuser()) ereport(ERROR, *************** pgstatindex(PG_FUNCTION_ARGS) *** 122,128 **** * Read metapage */ { ! Buffer buffer = ReadBuffer(rel, 0); Page page = BufferGetPage(buffer); BTMetaPageData *metad = BTPageGetMeta(page); --- 123,129 ---- * Read metapage */ { ! Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy); Page page = BufferGetPage(buffer); BTMetaPageData *metad = BTPageGetMeta(page); *************** pgstatindex(PG_FUNCTION_ARGS) *** 159,165 **** CHECK_FOR_INTERRUPTS(); /* Read and lock buffer */ ! buffer = ReadBuffer(rel, blkno); LockBuffer(buffer, BUFFER_LOCK_SHARE); page = BufferGetPage(buffer); --- 160,166 ---- CHECK_FOR_INTERRUPTS(); /* Read and lock buffer */ ! buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buffer, BUFFER_LOCK_SHARE); page = BufferGetPage(buffer); diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index e5ddd87..6bbc957 100644 *** a/contrib/pgstattuple/pgstattuple.c --- b/contrib/pgstattuple/pgstattuple.c *************** *** 24,33 **** --- 24,35 ---- #include "postgres.h" + #include "access/gin_private.h" #include "access/gist_private.h" #include "access/hash.h" #include "access/nbtree.h" #include "access/relscan.h" + #include "access/spgist_private.h" #include "catalog/namespace.h" #include "funcapi.h" #include "miscadmin.h" *************** static void pgstat_hash_page(pgstattuple *** 73,83 **** --- 75,96 ---- Relation rel, BlockNumber blkno); static void pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno); + static void pgstat_gin_page(pgstattuple_type *stat, + Relation rel, BlockNumber blkno); + static void pgstat_spgist_page(pgstattuple_type *stat, + Relation rel, BlockNumber blkno); static Datum pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn, FunctionCallInfo fcinfo); static void pgstat_index_page(pgstattuple_type *stat, Page page, OffsetNumber minoff, OffsetNumber maxoff); + /* + * Buffer access strategy for reading relations, it's simpler to keep it + * global because pgstat_*_page() functions read one buffer at a time. + * pgstat_heap() and pgstat_index() should initialize it before use. + */ + BufferAccessStrategy bstrategy; + /* * build_pgstattuple_type -- build a pgstattuple_type tuple */ *************** pgstat_relation(Relation rel, FunctionCa *** 229,235 **** return pgstat_index(rel, GIST_ROOT_BLKNO + 1, pgstat_gist_page, fcinfo); case GIN_AM_OID: ! err = "gin index"; break; default: err = "unknown index"; --- 242,253 ---- return pgstat_index(rel, GIST_ROOT_BLKNO + 1, pgstat_gist_page, fcinfo); case GIN_AM_OID: ! return pgstat_index(rel, GIN_METAPAGE_BLKNO + 1, ! pgstat_gin_page, fcinfo); ! break; ! case SPGIST_AM_OID: ! return pgstat_index(rel, SPGIST_METAPAGE_BLKNO + 1, ! pgstat_spgist_page, fcinfo); break; default: err = "unknown index"; *************** pgstat_heap(Relation rel, FunctionCallIn *** 276,281 **** --- 294,302 ---- nblocks = scan->rs_nblocks; /* # blocks to be scanned */ + /* prepare access strategy for this table */ + bstrategy = GetAccessStrategy(BAS_BULKREAD); + /* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { *************** pgstat_heap(Relation rel, FunctionCallIn *** 309,315 **** { CHECK_FOR_INTERRUPTS(); ! buffer = ReadBuffer(rel, block); LockBuffer(buffer, BUFFER_LOCK_SHARE); stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); --- 330,336 ---- { CHECK_FOR_INTERRUPTS(); ! buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block, RBM_NORMAL, bstrategy); LockBuffer(buffer, BUFFER_LOCK_SHARE); stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); *************** pgstat_heap(Relation rel, FunctionCallIn *** 322,328 **** { CHECK_FOR_INTERRUPTS(); ! buffer = ReadBuffer(rel, block); LockBuffer(buffer, BUFFER_LOCK_SHARE); stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); --- 343,349 ---- { CHECK_FOR_INTERRUPTS(); ! buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block, RBM_NORMAL, bstrategy); LockBuffer(buffer, BUFFER_LOCK_SHARE); stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer)); UnlockReleaseBuffer(buffer); *************** pgstat_btree_page(pgstattuple_type *stat *** 345,351 **** Buffer buf; Page page; ! buf = ReadBuffer(rel, blkno); LockBuffer(buf, BT_READ); page = BufferGetPage(buf); --- 366,372 ---- Buffer buf; Page page; ! buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buf, BT_READ); page = BufferGetPage(buf); *************** pgstat_hash_page(pgstattuple_type *stat, *** 389,395 **** Page page; _hash_getlock(rel, blkno, HASH_SHARE); ! buf = _hash_getbuf(rel, blkno, HASH_READ, 0); page = BufferGetPage(buf); if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) --- 410,416 ---- Page page; _hash_getlock(rel, blkno, HASH_SHARE); ! buf = _hash_getbuf_with_strategy(rel, blkno, HASH_READ, 0, bstrategy); page = BufferGetPage(buf); if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) *************** pgstat_gist_page(pgstattuple_type *stat, *** 431,437 **** Buffer buf; Page page; ! buf = ReadBuffer(rel, blkno); LockBuffer(buf, GIST_SHARE); gistcheckpage(rel, buf); page = BufferGetPage(buf); --- 452,458 ---- Buffer buf; Page page; ! buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buf, GIST_SHARE); gistcheckpage(rel, buf); page = BufferGetPage(buf); *************** pgstat_gist_page(pgstattuple_type *stat, *** 450,455 **** --- 471,538 ---- } /* + * pgstat_gin_page -- check tuples in a gin page + */ + static void + pgstat_gin_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno) + { + Buffer buf; + Page page; + + buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); + LockBuffer(buf, GIN_SHARE); + page = BufferGetPage(buf); + + if (GinPageIsDeleted(page)) + { + /* recyclable page */ + stat->free_space += BLCKSZ; + } + else if (GinPageIsLeaf(page) || GinPageIsData(page)) + { + pgstat_index_page(stat, page, FirstOffsetNumber, + PageGetMaxOffsetNumber(page)); + } + else + { + /* root or node */ + } + + UnlockReleaseBuffer(buf); + } + + /* + * pgstat_spgist_page -- check tuples in a spgist page + */ + static void + pgstat_spgist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno) + { + Buffer buf; + Page page; + + buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); + LockBuffer(buf, BUFFER_LOCK_SHARE); + page = BufferGetPage(buf); + + if (SpGistPageIsDeleted(page)) + { + /* recyclable page */ + stat->free_space += BLCKSZ; + } + else if (SpGistPageIsLeaf(page)) + { + pgstat_index_page(stat, page, FirstOffsetNumber, + PageGetMaxOffsetNumber(page)); + } + else + { + /* root or node */ + } + + UnlockReleaseBuffer(buf); + } + + /* * pgstat_index -- returns live/dead tuples info in a generic index */ static Datum *************** pgstat_index(Relation rel, BlockNumber s *** 460,465 **** --- 543,551 ---- BlockNumber blkno; pgstattuple_type stat = {0}; + /* prepare access strategy for this index */ + bstrategy = GetAccessStrategy(BAS_BULKREAD); + blkno = start; for (;;) {