Hi Amit, >>> + >>> + /* Check if it is an unused hash page. */ >>> + if (pageopaque->hasho_flag == LH_UNUSED_PAGE) >>> + return page; >>> >>> >>> I don't see we need to have a separate check for unused page, why >>> can't it be checked with other page types in below check. >>> >>> if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE && >>> pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE) >> >> That is because UNUSED page is as good as an empty page except that >> empty page doesn't have any pagetype. If we add condition for checking >> UNUSED page in above if check it will never show unused page as an >> unsed page rather it will always show it as an empty page. >> > > Oh, okay, but my main objection was that we should not check hash page > type (hasho_flag) without ensuring whether it is a hash page. Can you > try to adjust the above code so that this check can be moved after > hasho_page_id check?
Yes, I got your point. I have done that but then i had to remove the check for PageIsEmpty(). Anyways, I think PageIsEmpty() condition will only be true for one page in entire hash index table and can be ignored. If you wish, I could mention about it in the documentation. > >> To avoid >> this, at the start of verify_hash_page function itself if we recognise >> page as UNUSED page we return immediately. >> >>> >>> 2. >>> + /* Check if it is an empty hash page. */ >>> + if (PageIsEmpty(page)) >>> + ereport(ERROR, >>> + (errcode(ERRCODE_INDEX_CORRUPTED), >>> + errmsg("index table contains empty page"))); >>> >>> >>> Do we want to give a separate message for EMPTY and NEW pages? Isn't >>> it better that the same error message can be given for both of them as >>> from user perspective there is not much difference between both the >>> messages? >> >> I think we should show separate message because they are two different >> type of pages. In the sense like, one is initialised whereas other is >> completely zero. >> > > I understand your point, but not sure if it makes any difference to user. > okay, I have now anyways removed the check for PageIsEmpty. Please refer to the attached '0002 allow_pageinspect_handle_UNUSED_hash_pages.patch' Also, I have attached '0001-Mark-freed-overflow-page-as-UNUSED-pagetype-v2.patch' that handles your comment mentioned in [1]. [1] - https://www.postgresql.org/message-id/CAA4eK1%2BVE_TDRLWpyeOf%2B7%2B6if68kgPNwO4guKo060rm_t3O5w%40mail.gmail.com -- With Regards, Ashutosh Sharma EnterpriseDB:http://www.enterprisedb.com
From 86eb711ea80b495c9d2f5228558682d0e95c41eb Mon Sep 17 00:00:00 2001 From: ashu <ashu@localhost.localdomain> Date: Thu, 23 Mar 2017 16:47:17 +0530 Subject: [PATCH] Mark freed overflow page as UNUSED pagetype v2 --- src/backend/access/hash/hash_xlog.c | 9 +++++++++ src/backend/access/hash/hashovfl.c | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c index d9ac42c..2ccaf46 100644 --- a/src/backend/access/hash/hash_xlog.c +++ b/src/backend/access/hash/hash_xlog.c @@ -697,11 +697,20 @@ hash_xlog_squeeze_page(XLogReaderState *record) if (XLogReadBufferForRedo(record, 2, &ovflbuf) == BLK_NEEDS_REDO) { Page ovflpage; + HashPageOpaque ovflopaque; ovflpage = BufferGetPage(ovflbuf); _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf)); + ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage); + + ovflopaque->hasho_prevblkno = InvalidBlockNumber; + ovflopaque->hasho_nextblkno = InvalidBlockNumber; + ovflopaque->hasho_bucket = -1; + ovflopaque->hasho_flag = LH_UNUSED_PAGE; + ovflopaque->hasho_page_id = HASHO_PAGE_ID; + PageSetLSN(ovflpage, lsn); MarkBufferDirty(ovflbuf); } diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c index a3cae21..d3eaee0 100644 --- a/src/backend/access/hash/hashovfl.c +++ b/src/backend/access/hash/hashovfl.c @@ -591,9 +591,20 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf, /* * Initialize the freed overflow page. Just zeroing the page won't work, * because WAL replay routines expect pages to be initialized. See - * explanation of RBM_NORMAL mode atop XLogReadBufferExtended. + * explanation of RBM_NORMAL mode atop XLogReadBufferExtended. Also, mark + * the page as UNUSED type and retain it's page id. This allows the tools + * like pageinspect to consider it as a hash page. */ _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf)); + + ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage); + + ovflopaque->hasho_prevblkno = InvalidBlockNumber; + ovflopaque->hasho_nextblkno = InvalidBlockNumber; + ovflopaque->hasho_bucket = -1; + ovflopaque->hasho_flag = LH_UNUSED_PAGE; + ovflopaque->hasho_page_id = HASHO_PAGE_ID; + MarkBufferDirty(ovflbuf); if (BufferIsValid(prevbuf)) -- 1.8.3.1
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 812a03f..6ba8847 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -70,6 +70,7 @@ verify_hash_page(bytea *raw_page, int flags) errmsg("index table contains corrupted page"))); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); + if (pageopaque->hasho_page_id != HASHO_PAGE_ID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -77,6 +78,10 @@ verify_hash_page(bytea *raw_page, int flags) errdetail("Expected %08x, got %08x.", HASHO_PAGE_ID, pageopaque->hasho_page_id))); + /* Check if it is an unused hash page. */ + if (pageopaque->hasho_flag == LH_UNUSED_PAGE) + return page; + /* Check that page type is sane. */ pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE; if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers