v15-0007-DEBUG-Add-pageinspect-instrumentation.patch
application/octet-stream
Filename: v15-0007-DEBUG-Add-pageinspect-instrumentation.patch
Type: application/octet-stream
Part: 6
Patch
Format: format-patch
Series: patch v15-0007
Subject: DEBUG: Add pageinspect instrumentation.
| File | + | − |
|---|---|---|
| contrib/pageinspect/btreefuncs.c | 55 | 13 |
| contrib/pageinspect/expected/btree.out | 2 | 1 |
| contrib/pageinspect/pageinspect--1.6--1.7.sql | 22 | 0 |
From 9d5dc36128e0bff6cc2fd758dcec7c2d249b1dc2 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Mon, 10 Sep 2018 19:53:51 -0700
Subject: [PATCH v15 7/7] DEBUG: Add pageinspect instrumentation.
Have pageinspect display user-visible attribute values.
This patch is not proposed for inclusion in PostgreSQL; it's included
for the convenience of reviewers.
The following query can be used with this hacked pageinspect, which
visualizes the internal pages:
"""
with recursive index_details as (
select
'my_test_index'::text idx
),
size_in_pages_index as (
select
(pg_relation_size(idx::regclass) / (2^13))::int4 size_pages
from
index_details
),
page_stats as (
select
index_details.*,
stats.*
from
index_details,
size_in_pages_index,
lateral (select i from generate_series(1, size_pages - 1) i) series,
lateral (select * from bt_page_stats(idx, i)) stats),
internal_page_stats as (
select
*
from
page_stats
where
type != 'l'),
meta_stats as (
select
*
from
index_details s,
lateral (select * from bt_metap(s.idx)) meta),
internal_items as (
select
*
from
internal_page_stats
order by
btpo desc),
-- XXX: Note ordering dependency within this CTE, on internal_items
ordered_internal_items(item, blk, level) as (
select
1,
blkno,
btpo
from
internal_items
where
btpo_prev = 0
and btpo = (select level from meta_stats)
union
select
case when level = btpo then o.item + 1 else 1 end,
blkno,
btpo
from
internal_items i,
ordered_internal_items o
where
i.btpo_prev = o.blk or (btpo_prev = 0 and btpo = o.level - 1)
)
select
--idx,
btpo as level,
item as l_item,
blkno,
--btpo_prev,
--btpo_next,
btpo_flags,
type,
live_items,
dead_items,
avg_item_size,
page_size,
free_size,
-- Only non-rightmost pages have high key. Show heap TID for both pivot and non-pivot tuples here.
case when btpo_next != 0 then (select data || coalesce(', (htid)=(''' || htid || ''')', '')
from bt_page_items(idx, blkno) where itemoffset = 1) end as highkey
from
ordered_internal_items o
join internal_items i on o.blk = i.blkno
order by btpo desc, item;
"""
---
contrib/pageinspect/btreefuncs.c | 68 +++++++++++++++----
contrib/pageinspect/expected/btree.out | 3 +-
contrib/pageinspect/pageinspect--1.6--1.7.sql | 22 ++++++
3 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index 8d27c9b0f6..95c81c0808 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -29,6 +29,7 @@
#include "pageinspect.h"
+#include "access/genam.h"
#include "access/nbtree.h"
#include "access/relation.h"
#include "catalog/namespace.h"
@@ -243,6 +244,7 @@ bt_page_stats(PG_FUNCTION_ARGS)
*/
struct user_args
{
+ Relation rel;
Page page;
OffsetNumber offset;
};
@@ -254,9 +256,9 @@ struct user_args
* ------------------------------------------------------
*/
static Datum
-bt_page_print_tuples(FuncCallContext *fctx, Page page, OffsetNumber offset)
+bt_page_print_tuples(FuncCallContext *fctx, Page page, OffsetNumber offset, Relation rel)
{
- char *values[6];
+ char *values[7];
HeapTuple tuple;
ItemId id;
IndexTuple itup;
@@ -265,6 +267,8 @@ bt_page_print_tuples(FuncCallContext *fctx, Page page, OffsetNumber offset)
int dlen;
char *dump;
char *ptr;
+ ItemPointer htid;
+ BTPageOpaque opaque;
id = PageGetItemId(page, offset);
@@ -283,16 +287,53 @@ bt_page_print_tuples(FuncCallContext *fctx, Page page, OffsetNumber offset)
values[j++] = psprintf("%c", IndexTupleHasVarwidths(itup) ? 't' : 'f');
ptr = (char *) itup + IndexInfoFindDataOffset(itup->t_info);
- dlen = IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info);
- dump = palloc0(dlen * 3 + 1);
- values[j] = dump;
- for (off = 0; off < dlen; off++)
+ if (rel)
{
- if (off > 0)
- *dump++ = ' ';
- sprintf(dump, "%02x", *(ptr + off) & 0xff);
- dump += 2;
+ TupleDesc itupdesc = RelationGetDescr(rel);
+ Datum datvalues[INDEX_MAX_KEYS];
+ bool isnull[INDEX_MAX_KEYS];
+ int natts;
+ int indnkeyatts;
+
+ natts = BTreeTupleGetNAtts(itup, rel);
+
+ itupdesc->natts = natts;
+ memset(&isnull, 0xFF, sizeof(isnull));
+ index_deform_tuple(itup, itupdesc, datvalues, isnull);
+ indnkeyatts = rel->rd_index->indnkeyatts;
+ rel->rd_index->indnkeyatts = natts;
+ values[j++] = BuildIndexValueDescription(rel, datvalues, isnull);
+ itupdesc->natts = IndexRelationGetNumberOfAttributes(rel);
+ rel->rd_index->indnkeyatts = indnkeyatts;
}
+ else
+ {
+ dlen = IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info);
+ dump = palloc0(dlen * 3 + 1);
+ values[j++] = dump;
+ for (off = 0; off < dlen; off++)
+ {
+ if (off > 0)
+ *dump++ = ' ';
+ sprintf(dump, "%02x", *(ptr + off) & 0xff);
+ dump += 2;
+ }
+ }
+
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ if (P_ISLEAF(opaque) && offset >= P_FIRSTDATAKEY(opaque))
+ htid = &itup->t_tid;
+ else if (_bt_heapkeyspace(rel))
+ htid = BTreeTupleGetHeapTID(itup);
+ else
+ htid = NULL;
+
+ if (htid)
+ values[j] = psprintf("(%u,%u)",
+ ItemPointerGetBlockNumberNoCheck(htid),
+ ItemPointerGetOffsetNumberNoCheck(htid));
+ else
+ values[j] = NULL;
tuple = BuildTupleFromCStrings(fctx->attinmeta, values);
@@ -366,11 +407,11 @@ bt_page_items(PG_FUNCTION_ARGS)
uargs = palloc(sizeof(struct user_args));
+ uargs->rel = rel;
uargs->page = palloc(BLCKSZ);
memcpy(uargs->page, BufferGetPage(buffer), BLCKSZ);
UnlockReleaseBuffer(buffer);
- relation_close(rel, AccessShareLock);
uargs->offset = FirstOffsetNumber;
@@ -397,12 +438,13 @@ bt_page_items(PG_FUNCTION_ARGS)
if (fctx->call_cntr < fctx->max_calls)
{
- result = bt_page_print_tuples(fctx, uargs->page, uargs->offset);
+ result = bt_page_print_tuples(fctx, uargs->page, uargs->offset, uargs->rel);
uargs->offset++;
SRF_RETURN_NEXT(fctx, result);
}
else
{
+ relation_close(uargs->rel, AccessShareLock);
pfree(uargs->page);
pfree(uargs);
SRF_RETURN_DONE(fctx);
@@ -482,7 +524,7 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
if (fctx->call_cntr < fctx->max_calls)
{
- result = bt_page_print_tuples(fctx, uargs->page, uargs->offset);
+ result = bt_page_print_tuples(fctx, uargs->page, uargs->offset, NULL);
uargs->offset++;
SRF_RETURN_NEXT(fctx, result);
}
diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out
index 07c2dcd771..067e73f21a 100644
--- a/contrib/pageinspect/expected/btree.out
+++ b/contrib/pageinspect/expected/btree.out
@@ -40,7 +40,8 @@ ctid | (0,1)
itemlen | 16
nulls | f
vars | f
-data | 01 00 00 00 00 00 00 01
+data | (a)=(72057594037927937)
+htid | (0,1)
SELECT * FROM bt_page_items('test1_a_idx', 2);
ERROR: block number out of range
diff --git a/contrib/pageinspect/pageinspect--1.6--1.7.sql b/contrib/pageinspect/pageinspect--1.6--1.7.sql
index 2433a21af2..9acbad1589 100644
--- a/contrib/pageinspect/pageinspect--1.6--1.7.sql
+++ b/contrib/pageinspect/pageinspect--1.6--1.7.sql
@@ -24,3 +24,25 @@ CREATE FUNCTION bt_metap(IN relname text,
OUT last_cleanup_num_tuples real)
AS 'MODULE_PATHNAME', 'bt_metap'
LANGUAGE C STRICT PARALLEL SAFE;
+
+--
+-- bt_page_items()
+--
+DROP FUNCTION bt_page_items(IN relname text, IN blkno int4,
+ OUT itemoffset smallint,
+ OUT ctid tid,
+ OUT itemlen smallint,
+ OUT nulls bool,
+ OUT vars bool,
+ OUT data text);
+CREATE FUNCTION bt_page_items(IN relname text, IN blkno int4,
+ OUT itemoffset smallint,
+ OUT ctid tid,
+ OUT itemlen smallint,
+ OUT nulls bool,
+ OUT vars bool,
+ OUT data text,
+ OUT htid tid)
+RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'bt_page_items'
+LANGUAGE C STRICT PARALLEL SAFE;
--
2.17.1