From fef2bcdcba0888c95ddf2a7535179c3b9a6a2f0e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 17 Mar 2017 09:49:10 -0400 Subject: [PATCH] pageinspect: Add page_checksum function Author: Tomas Vondra Reviewed-by: Ashutosh Sharma --- contrib/pageinspect/expected/page.out | 6 +++ contrib/pageinspect/pageinspect--1.5--1.6.sql | 8 ++++ contrib/pageinspect/rawpage.c | 37 +++++++++++++++ contrib/pageinspect/sql/page.sql | 2 + doc/src/sgml/pageinspect.sgml | 47 ++++++++++++++++++- 5 files changed, 98 insertions(+), 2 deletions(-) diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out index 08599af774d..8e15947a818 100644 --- a/contrib/pageinspect/expected/page.out +++ b/contrib/pageinspect/expected/page.out @@ -49,6 +49,12 @@ SELECT pagesize, version FROM page_header(get_raw_page('test1', 0)); 8192 | 4 (1 row) +SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test; + silly_checksum_test +--------------------- + t +(1 row) + SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('test1', 0)); tuple_data_split diff --git a/contrib/pageinspect/pageinspect--1.5--1.6.sql b/contrib/pageinspect/pageinspect--1.5--1.6.sql index ac3956882c9..6ac2a8011d8 100644 --- a/contrib/pageinspect/pageinspect--1.5--1.6.sql +++ b/contrib/pageinspect/pageinspect--1.5--1.6.sql @@ -75,3 +75,11 @@ CREATE FUNCTION hash_metapage_info(IN page bytea, OUT mapp int8[]) AS 'MODULE_PATHNAME', 'hash_metapage_info' LANGUAGE C STRICT PARALLEL SAFE; + +-- +-- page_checksum() +-- +CREATE FUNCTION page_checksum(IN page bytea, IN blkno int4) +RETURNS smallint +AS 'MODULE_PATHNAME', 'page_checksum' +LANGUAGE C STRICT PARALLEL SAFE; diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index a5def917511..631e435a939 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -24,6 +24,7 @@ #include "funcapi.h" #include "miscadmin.h" #include "storage/bufmgr.h" +#include "storage/checksum.h" #include "utils/builtins.h" #include "utils/pg_lsn.h" #include "utils/rel.h" @@ -280,3 +281,39 @@ page_header(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } + +/* + * page_checksum + * + * Compute checksum of a raw page + */ + +PG_FUNCTION_INFO_V1(page_checksum); + +Datum +page_checksum(PG_FUNCTION_ARGS) +{ + bytea *raw_page = PG_GETARG_BYTEA_P(0); + uint32 blkno = PG_GETARG_INT32(1); + int raw_page_size; + PageHeader page; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to use raw page functions")))); + + raw_page_size = VARSIZE(raw_page) - VARHDRSZ; + + /* + * Check that the supplied page is of the right size. + */ + if (raw_page_size != BLCKSZ) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("incorrect size of input page (%d bytes)", raw_page_size))); + + page = (PageHeader) VARDATA(raw_page); + + PG_RETURN_INT16(pg_checksum_page((char *)page, blkno)); +} diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql index 53e9f8022d4..493ca9b211d 100644 --- a/contrib/pageinspect/sql/page.sql +++ b/contrib/pageinspect/sql/page.sql @@ -24,6 +24,8 @@ SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0); SELECT pagesize, version FROM page_header(get_raw_page('test1', 0)); +SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test; + SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('test1', 0)); diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml index 5e6712f9cde..9f41bb21eb9 100644 --- a/doc/src/sgml/pageinspect.sgml +++ b/doc/src/sgml/pageinspect.sgml @@ -73,12 +73,55 @@ test=# SELECT * FROM page_header(get_raw_page('pg_class', 0)); lsn | checksum | flags | lower | upper | special | pagesize | version | prune_xid -----------+----------+--------+-------+-------+---------+----------+---------+----------- - 0/24A1B50 | 1 | 1 | 232 | 368 | 8192 | 8192 | 4 | 0 + 0/24A1B50 | 0 | 1 | 232 | 368 | 8192 | 8192 | 4 | 0 The returned columns correspond to the fields in the PageHeaderData struct. See src/include/storage/bufpage.h for details. - + + + + The checksum field is the checksum stored in + the page, which might be incorrect if the page is somehow corrupted. If + data checksums are not enabled for this instance, then the value stored + is meaningless. + + + + + + + page_checksum(page bytea, blkno int4) returns smallint + + page_checksum + + + + + + page_checksum computes the checksum for the page, as if + it was located at the given block. + + + + A page image obtained with get_raw_page should be + passed as argument. For example: + +test=# SELECT page_checksum(get_raw_page('pg_class', 0), 0); + page_checksum +--------------- + 13443 + + Note that the checksum depends on the block number, so matching block + numbers should be passed (except when doing esoteric debugging). + + + + The checksum computed with this function can be compared with + the checksum result field of the + function page_header. If data checksums are + enabled for this instance, then the two values should be equal. +