From 35a3257fb875165e9bc466f5c74262f3ff85812d Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 20 Feb 2014 08:16:10 -0500 Subject: [PATCH] More hacking. --- src/backend/utils/mmgr/freepage.c | 144 ++++++++++++++++++++++++++++++ src/include/utils/freepage.h | 5 +- 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/mmgr/freepage.c b/src/backend/utils/mmgr/freepage.c index 0e06b4e06c..7ad319cc89 100644 --- a/src/backend/utils/mmgr/freepage.c +++ b/src/backend/utils/mmgr/freepage.c @@ -13,6 +13,8 @@ */ #include "postgres.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" #include "utils/freepage.h" /* Magic numbers to identify various page types */ @@ -100,6 +102,11 @@ static Size FreePageBtreeSearchInternal(FreePageBtree *btp, Size first_page); static Size FreePageBtreeSearchLeaf(FreePageBtree *btp, Size first_page); static FreePageBtree *FreePageBtreeSplitPage(FreePageManager *fpm, FreePageBtree *btp); +static void FreePageManagerDumpBtree(FreePageManager *fpm, FreePageBtree *btp, + int level, StringInfo buf); +static void FreePageManagerDumpSpans(FreePageManager *fpm, + FreePageSpanLeader *span, Size expected_pages, + StringInfo buf); static bool FreePageManagerGetInternal(FreePageManager *fpm, Size npages, Size *first_page); static void FreePagePopSpanLeader(FreePageManager *fpm, Size pageno); @@ -194,6 +201,81 @@ FreePageManagerPut(FreePageManager *fpm, Size first_page, Size npages) LWLockRelease(lock); } +/* + * Produce a debugging dump of the state of a free page manager. + */ +char * +FreePageManagerDump(FreePageManager *fpm) +{ + LWLock *lock = fpm_lock(fpm); + char *base = fpm_segment_base(fpm); + StringInfoData buf; + FreePageSpanLeader *recycle; + bool dumped_any_freelist = false; + Size f; + + /* Initialize output buffer. */ + initStringInfo(&buf); + + /* Acquire lock (if there is one). */ + if (lock != NULL) + LWLockAcquire(lock, LW_SHARED); + + /* Dump general stuff. */ + appendStringInfo(&buf, "metadata: self %zu lock %zu fixed %c\n", + fpm->self.relptr_off, fpm->lock.relptr_off, + fpm->lock_address_is_fixed ? 't' : 'f'); + + /* Dump btree. */ + if (fpm->btree_depth > 0) + { + FreePageBtree *root; + + appendStringInfo(&buf, "btree depth %u:\n", fpm->btree_depth); + root = relptr_access(base, fpm->btree_root); + FreePageManagerDumpBtree(fpm, root, 0, &buf); + } + else if (fpm->singleton_npages > 0) + { + appendStringInfo(&buf, "singleton: %zu(%zu)\n", + fpm->singleton_first_page, fpm->singleton_npages); + } + + /* Dump btree recycle list. */ + recycle = relptr_access(base, fpm->btree_recycle); + if (recycle != NULL) + { + appendStringInfo(&buf, "btree recycle: "); + FreePageManagerDumpSpans(fpm, recycle, 1, &buf); + } + + /* Dump free lists. */ + for (f = 0; f < FPM_NUM_FREELISTS; ++f) + { + FreePageSpanLeader *span; + + if (relptr_is_null(fpm->freelist[f])) + continue; + if (!dumped_any_freelist) + { + appendStringInfo(&buf, "freelists:\n"); + dumped_any_freelist = true; + } + appendStringInfo(&buf, " %zu:", f); + span = relptr_access(base, fpm->freelist[f]); + FreePageManagerDumpSpans(fpm, span, + f < FPM_NUM_FREELISTS - 1 ? f - 1 : 0, &buf); + } + + /* Release lock (if there is one). */ + if (lock != NULL) + LWLockRelease(lock); + + /* And return result to caller. */ + return buf.data; +} + + /* * The first_page value stored it index zero in any non-root page must match * the first_page value stored in its parent at the index which points to that @@ -678,6 +760,68 @@ FreePageBtreeSplitPage(FreePageManager *fpm, FreePageBtree *btp) return newsibling; } +/* + * Debugging dump of btree data. + */ +static void +FreePageManagerDumpBtree(FreePageManager *fpm, FreePageBtree *btp, int level, + StringInfo buf) +{ + char *base = fpm_segment_base(fpm); + Size pageno = fpm_pointer_to_page(base, btp); + Size index; + + check_stack_depth(); + appendStringInfo(buf, " %zu@%d %c:", pageno, level, + btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC ? 'i' : 'l'); + for (index = 0; index < btp->hdr.nused; ++index) + { + if (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + appendStringInfo(buf, " %zu->%zu", + btp->u.internal_key[index].first_page, + btp->u.internal_key[index].child.relptr_off / FPM_PAGE_SIZE); + else + appendStringInfo(buf, " %zu(%zu)", + btp->u.leaf_key[index].first_page, + btp->u.leaf_key[index].npages); + } + appendStringInfo(buf, "\n"); + + if (btp->hdr.magic == FREE_PAGE_INTERNAL_MAGIC) + { + for (index = 0; index < btp->hdr.nused; ++index) + { + FreePageBtree *child; + + child = relptr_access(base, btp->u.internal_key[index].child); + FreePageManagerDumpBtree(fpm, child, level + 1, buf); + } + } + appendStringInfo(buf, "\n"); +} + +/* + * Debugging dump of free-span data. + */ +static void +FreePageManagerDumpSpans(FreePageManager *fpm, FreePageSpanLeader *span, + Size expected_pages, StringInfo buf) +{ + char *base = fpm_segment_base(fpm); + + while (span != NULL) + { + if (expected_pages == 0 || span->npages != expected_pages) + appendStringInfo(buf, " %zu(%zu)", fpm_pointer_to_page(base, span), + span->npages); + else + appendStringInfo(buf, " %zu", span->npages); + span = relptr_access(base, span->next); + } + + appendStringInfo(buf, "\n"); +} + /* * Like FreePageManagerGet, this function allocates a run of pages of the * given length from the free page manager, but without taking and releasing diff --git a/src/include/utils/freepage.h b/src/include/utils/freepage.h index f14705669e..b19ccd7b5d 100644 --- a/src/include/utils/freepage.h +++ b/src/include/utils/freepage.h @@ -56,8 +56,8 @@ struct FreePageManager relptr(FreePageSpanLeader) btree_recycle; unsigned btree_depth; unsigned btree_recycle_count; - unsigned singleton_first_page; - unsigned singleton_npages; + Size singleton_first_page; + Size singleton_npages; relptr(FreePageSpanLeader) freelist[FPM_NUM_FREELISTS]; }; @@ -90,5 +90,6 @@ extern bool FreePageManagerGet(FreePageManager *fpm, Size npages, Size *first_page); extern void FreePageManagerPut(FreePageManager *fpm, Size first_page, Size npages); +extern char *FreePageManagerDump(FreePageManager *fpm); #endif /* FREEPAGE_H */ -- 2.39.5