Commit 08bf6e52 authored by Robert Haas's avatar Robert Haas

pageinspect: Support hash indexes.

Patch by Jesper Pedersen and Ashutosh Sharma, with some error handling
improvements by me.  Tests from Peter Eisentraut.  Reviewed by Álvaro
Herrera, Michael Paquier, Jesper Pedersen, Jeff Janes, Peter
Eisentraut, Amit Kapila, Mithun Cy, and me.

Discussion: http://postgr.es/m/e2ac6c58-b93f-9dd9-f4e6-d6d30add7fdf@redhat.com
parent acd73ad1
......@@ -2,16 +2,16 @@
MODULE_big = pageinspect
OBJS = rawpage.o heapfuncs.o btreefuncs.o fsmfuncs.o \
brinfuncs.o ginfuncs.o $(WIN32RES)
brinfuncs.o ginfuncs.o hashfuncs.o $(WIN32RES)
EXTENSION = pageinspect
DATA = pageinspect--1.5.sql pageinspect--1.4--1.5.sql \
pageinspect--1.3--1.4.sql pageinspect--1.2--1.3.sql \
pageinspect--1.1--1.2.sql pageinspect--1.0--1.1.sql \
pageinspect--unpackaged--1.0.sql
DATA = pageinspect--1.5.sql pageinspect--1.5--1.6.sql \
pageinspect--1.4--1.5.sql pageinspect--1.3--1.4.sql \
pageinspect--1.2--1.3.sql pageinspect--1.1--1.2.sql \
pageinspect--1.0--1.1.sql pageinspect--unpackaged--1.0.sql
PGFILEDESC = "pageinspect - functions to inspect contents of database pages"
REGRESS = page btree brin gin
REGRESS = page btree brin gin hash
ifdef USE_PGXS
PG_CONFIG = pg_config
......
CREATE TABLE test_hash (a int, b text);
INSERT INTO test_hash VALUES (1, 'one');
CREATE INDEX test_hash_a_idx ON test_hash USING hash (a);
WARNING: hash indexes are not WAL-logged and their use is discouraged
\x
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 0));
-[ RECORD 1 ]--+---------
hash_page_type | metapage
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 1));
-[ RECORD 1 ]--+-------
hash_page_type | bucket
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 2));
-[ RECORD 1 ]--+-------
hash_page_type | bucket
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 3));
-[ RECORD 1 ]--+-------
hash_page_type | bucket
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 4));
-[ RECORD 1 ]--+-------
hash_page_type | bucket
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 5));
-[ RECORD 1 ]--+-------
hash_page_type | bitmap
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6));
ERROR: block number 6 is out of range for relation "test_hash_a_idx"
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000008.
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000002.
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000002.
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000002.
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000002.
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5);
ERROR: page is not an overflow page
DETAIL: Expected 00000001, got 00000004.
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0));
-[ RECORD 1 ]----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
magic | 105121344
version | 2
ntuples | 1
ffactor | 307
bsize | 8152
bmsize | 4096
bmshift | 15
maxbucket | 3
highmask | 7
lowmask | 3
ovflpoint | 2
firstfree | 0
nmaps | 1
procid | 450
spares | {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
mapp | {5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 1));
ERROR: page is not a hash meta page
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 2));
ERROR: page is not a hash meta page
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 3));
ERROR: page is not a hash meta page
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 4));
ERROR: page is not a hash meta page
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 5));
ERROR: page is not a hash meta page
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 0));
ERROR: page is not a hash bucket or overflow page
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 1));
-[ RECORD 1 ]---+-----------
live_items | 0
dead_items | 0
page_size | 8192
free_size | 8148
hasho_prevblkno | 4294967295
hasho_nextblkno | 4294967295
hasho_bucket | 0
hasho_flag | 2
hasho_page_id | 65408
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 2));
-[ RECORD 1 ]---+-----------
live_items | 0
dead_items | 0
page_size | 8192
free_size | 8148
hasho_prevblkno | 4294967295
hasho_nextblkno | 4294967295
hasho_bucket | 1
hasho_flag | 2
hasho_page_id | 65408
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 3));
-[ RECORD 1 ]---+-----------
live_items | 1
dead_items | 0
page_size | 8192
free_size | 8128
hasho_prevblkno | 4294967295
hasho_nextblkno | 4294967295
hasho_bucket | 2
hasho_flag | 2
hasho_page_id | 65408
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 4));
-[ RECORD 1 ]---+-----------
live_items | 0
dead_items | 0
page_size | 8192
free_size | 8148
hasho_prevblkno | 4294967295
hasho_nextblkno | 4294967295
hasho_bucket | 3
hasho_flag | 2
hasho_page_id | 65408
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 5));
ERROR: page is not a hash bucket or overflow page
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 0));
ERROR: page is not a hash bucket or overflow page
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 1));
(0 rows)
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 2));
(0 rows)
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 3));
-[ RECORD 1 ]----------
itemoffset | 1
ctid | (0,1)
data | 2389907270
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 4));
(0 rows)
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 5));
ERROR: page is not a hash bucket or overflow page
DROP TABLE test_hash;
This diff is collapsed.
/* contrib/pageinspect/pageinspect--1.5--1.6.sql */
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION pageinspect UPDATE TO '1.6'" to load this file. \quit
--
-- HASH functions
--
--
-- hash_page_type()
--
CREATE FUNCTION hash_page_type(IN page bytea)
RETURNS text
AS 'MODULE_PATHNAME', 'hash_page_type'
LANGUAGE C STRICT PARALLEL SAFE;
--
-- hash_page_stats()
--
CREATE FUNCTION hash_page_stats(IN page bytea,
OUT live_items smallint,
OUT dead_items smallint,
OUT page_size smallint,
OUT free_size smallint,
OUT hasho_prevblkno int8,
OUT hasho_nextblkno int8,
OUT hasho_bucket int8,
OUT hasho_flag smallint,
OUT hasho_page_id int4)
AS 'MODULE_PATHNAME', 'hash_page_stats'
LANGUAGE C STRICT PARALLEL SAFE;
--
-- hash_page_items()
--
CREATE FUNCTION hash_page_items(IN page bytea,
OUT itemoffset smallint,
OUT ctid tid,
OUT data int8)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'hash_page_items'
LANGUAGE C STRICT PARALLEL SAFE;
--
-- hash_bitmap_info()
--
CREATE FUNCTION hash_bitmap_info(IN index_oid regclass, IN blkno int8,
OUT bitmapblkno int8,
OUT bitmapbit int4,
OUT bitstatus bool)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'hash_bitmap_info'
LANGUAGE C STRICT PARALLEL SAFE;
--
-- hash_metapage_info()
--
CREATE FUNCTION hash_metapage_info(IN page bytea,
OUT magic int8,
OUT version int8,
OUT ntuples double precision,
OUT ffactor int4,
OUT bsize int4,
OUT bmsize int4,
OUT bmshift int4,
OUT maxbucket int8,
OUT highmask int8,
OUT lowmask int8,
OUT ovflpoint int8,
OUT firstfree int8,
OUT nmaps int8,
OUT procid int4,
OUT spares int8[],
OUT mapp int8[])
AS 'MODULE_PATHNAME', 'hash_metapage_info'
LANGUAGE C STRICT PARALLEL SAFE;
# pageinspect extension
comment = 'inspect the contents of database pages at a low level'
default_version = '1.5'
default_version = '1.6'
module_pathname = '$libdir/pageinspect'
relocatable = true
CREATE TABLE test_hash (a int, b text);
INSERT INTO test_hash VALUES (1, 'one');
CREATE INDEX test_hash_a_idx ON test_hash USING hash (a);
\x
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 0));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 1));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 2));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 3));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 4));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 5));
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6));
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0);
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1);
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2);
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3);
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4);
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5);
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0));
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 1));
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 2));
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 3));
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 4));
SELECT * FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 5));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 0));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 1));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 2));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 3));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 4));
SELECT * FROM hash_page_stats(get_raw_page('test_hash_a_idx', 5));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 0));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 1));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 2));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 3));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 4));
SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 5));
DROP TABLE test_hash;
......@@ -486,6 +486,150 @@ test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids
(170,30) | 376 | {"(170,30)","(170,31)","(170,32)","(170,33)","(170,34)"}
(173,44) | 197 | {"(173,44)","(173,45)","(173,46)","(173,47)","(173,48)"}
(7 rows)
</screen>
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2>
<title>Hash Functions</title>
<variablelist>
<varlistentry>
<term>
<function>hash_page_type(page bytea) returns text</function>
<indexterm>
<primary>hash_page_type</primary>
</indexterm>
</term>
<listitem>
<para>
<function>hash_page_type</function> returns page type of
the given <acronym>HASH</acronym> index page. For example:
<screen>
test=# SELECT hash_page_type(get_raw_page('con_hash_index', 0));
hash_page_type
----------------
metapage
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>hash_page_stats(page bytea) returns setof record</function>
<indexterm>
<primary>hash_page_stats</primary>
</indexterm>
</term>
<listitem>
<para>
<function>hash_page_stats</function> returns information about
a bucket or overflow page of a <acronym>HASH</acronym> index.
For example:
<screen>
test=# SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
-[ RECORD 1 ]---+-----------
live_items | 407
dead_items | 0
page_size | 8192
free_size | 8
hasho_prevblkno | 4294967295
hasho_nextblkno | 8474
hasho_bucket | 0
hasho_flag | 66
hasho_page_id | 65408
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>hash_page_items(page bytea) returns setof record</function>
<indexterm>
<primary>hash_page_items</primary>
</indexterm>
</term>
<listitem>
<para>
<function>hash_page_items</function> returns information about
the data stored in a bucket or overflow page of a <acronym>HASH</acronym>
index page. For example:
<screen>
test=# SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1)) LIMIT 5;
itemoffset | ctid | data
------------+-----------+------------
1 | (899,77) | 1053474816
2 | (897,29) | 1053474816
3 | (894,207) | 1053474816
4 | (892,159) | 1053474816
5 | (890,111) | 1053474816
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>hash_bitmap_info(index oid, blkno int) returns record</function>
<indexterm>
<primary>hash_bitmap_info</primary>
</indexterm>
</term>
<listitem>
<para>
<function>hash_bitmap_info</function> shows the status of a bit
in the bitmap page for a particular overflow page of <acronym>HASH</acronym>
index. For example:
<screen>
test=# SELECT * FROM hash_bitmap_info('con_hash_index', 2052);
bitmapblkno | bitmapbit | bitstatus
-------------+-----------+-----------
65 | 3 | t
</screen>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<function>hash_metapage_info(page bytea) returns record</function>
<indexterm>
<primary>hash_metapage_info</primary>
</indexterm>
</term>
<listitem>
<para>
<function>hash_metapage_info</function> returns information stored
in meta page of a <acronym>HASH</acronym> index. For example:
<screen>
test=# SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0));
-[ RECORD 1 ]-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
magic | 105121344
version | 2
ntuples | 500500
ffactor | 40
bsize | 8152
bmsize | 4096
bmshift | 15
maxbucket | 12512
highmask | 16383
lowmask | 8191
ovflpoint | 14
firstfree | 1204
nmaps | 1
procid | 450
spares | {0,0,0,0,0,0,1,1,1,1,1,4,59,704,1204,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
mapp | {65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
</screen>
</para>
</listitem>
......
......@@ -52,10 +52,12 @@ bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum)
}
/*
* _hash_ovflblkno_to_bitno
*
* Convert overflow page block number to bit number for free-page bitmap.
*/
static uint32
blkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
uint32
_hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
{
uint32 splitnum = metap->hashm_ovflpoint;
uint32 i;
......@@ -485,7 +487,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, Buffer wbuf,
metap = HashPageGetMeta(BufferGetPage(metabuf));
/* Identify which bit to set */
ovflbitno = blkno_to_bitno(metap, ovflblkno);
ovflbitno = _hash_ovflblkno_to_bitno(metap, ovflblkno);
bitmappage = ovflbitno >> BMPG_SHIFT(metap);
bitmapbit = ovflbitno & BMPG_MASK(metap);
......
......@@ -58,6 +58,9 @@ typedef uint32 Bucket;
#define LH_BUCKET_BEING_SPLIT (1 << 5)
#define LH_BUCKET_NEEDS_SPLIT_CLEANUP (1 << 6)
#define LH_PAGE_TYPE \
(LH_OVERFLOW_PAGE|LH_BUCKET_PAGE|LH_BITMAP_PAGE|LH_META_PAGE)
typedef struct HashPageOpaqueData
{
BlockNumber hasho_prevblkno; /* previous ovfl (or bucket) blkno */
......@@ -299,6 +302,7 @@ extern void _hash_squeezebucket(Relation rel,
Bucket bucket, BlockNumber bucket_blkno,
Buffer bucket_buf,
BufferAccessStrategy bstrategy);
extern uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno);
/* hashpage.c */
extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno,
......
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