From 0a64b45152b593c5eb95f2e88fbce7fbfe84ae7b Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Thu, 5 Apr 2018 17:56:00 +0300 Subject: [PATCH] Fix handling of non-upgraded B-tree metapages 857f9c36 bumps B-tree metapage version while upgrade is performed "on the fly" when needed. However, some asserts fired when old version metapage was cached to rel->rd_amcache. Despite new metadata fields are never used from rel->rd_amcache, that needs to be fixed. This patch introduces metadata upgrade during its caching, which fills unavailable fields with their default values. contrib/pageinspect is also patched to handle non-upgraded metapages in the same way. Author: Alexander Korotkov --- contrib/pageinspect/btreefuncs.c | 17 +++++++++-- src/backend/access/nbtree/nbtpage.c | 47 +++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index 5133653791..558a8c41f4 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -555,8 +555,21 @@ bt_metap(PG_FUNCTION_ARGS) values[j++] = psprintf("%d", metad->btm_level); values[j++] = psprintf("%d", metad->btm_fastroot); values[j++] = psprintf("%d", metad->btm_fastlevel); - values[j++] = psprintf("%u", metad->btm_oldest_btpo_xact); - values[j++] = psprintf("%lf", metad->btm_last_cleanup_num_heap_tuples); + + /* + * Get values of extended metadata if available, use default values + * otherwise. + */ + if (metad->btm_version == BTREE_VERSION) + { + values[j++] = psprintf("%u", metad->btm_oldest_btpo_xact); + values[j++] = psprintf("%lf", metad->btm_last_cleanup_num_heap_tuples); + } + else + { + values[j++] = "0"; + values[j++] = "-1"; + } tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index c98603bbf8..019fe48cb6 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -33,6 +33,7 @@ #include "storage/predicate.h" #include "utils/snapmgr.h" +static void _bt_cachemetadata(Relation rel, BTMetaPageData *metad); static bool _bt_mark_page_halfdead(Relation rel, Buffer buf, BTStack stack); static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty); @@ -105,6 +106,44 @@ _bt_upgrademetapage(Page page) ((char *) metad + sizeof(BTMetaPageData)) - (char *) page; } +/* + * Cache metadata from meta page to rel->rd_amcache. + */ +static void +_bt_cachemetadata(Relation rel, BTMetaPageData *metad) +{ + /* We assume rel->rd_amcache was already freed by caller */ + Assert(rel->rd_amcache == NULL); + rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt, + sizeof(BTMetaPageData)); + + /* + * Meta page should be of supported version (should be already checked by + * caller). + */ + Assert(metad->btm_version >= BTREE_MIN_VERSION && + metad->btm_version <= BTREE_VERSION); + + if (metad->btm_version == BTREE_VERSION) + { + /* Last version of meta-data, no need to upgrade */ + memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData)); + } + else + { + BTMetaPageData *cached_metad = (BTMetaPageData *) rel->rd_amcache; + + /* + * Upgrade meta-data: copy available information from meta-page and + * fill new fields with default values. + */ + memcpy(rel->rd_amcache, metad, offsetof(BTMetaPageData, btm_oldest_btpo_xact)); + cached_metad->btm_version = BTREE_VERSION; + cached_metad->btm_oldest_btpo_xact = InvalidTransactionId; + cached_metad->btm_last_cleanup_num_heap_tuples = -1.0; + } +} + /* * _bt_update_meta_cleanup_info() -- Update cleanup-related information in * the metapage. @@ -403,9 +442,7 @@ _bt_getroot(Relation rel, int access) /* * Cache the metapage data for next time */ - rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt, - sizeof(BTMetaPageData)); - memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData)); + _bt_cachemetadata(rel, metad); /* * We are done with the metapage; arrange to release it via first @@ -604,9 +641,7 @@ _bt_getrootheight(Relation rel) /* * Cache the metapage data for next time */ - rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt, - sizeof(BTMetaPageData)); - memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData)); + _bt_cachemetadata(rel, metad); _bt_relbuf(rel, metabuf); }