More hacking.
authorRobert Haas <rhaas@postgresql.org>
Thu, 20 Feb 2014 13:16:10 +0000 (08:16 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 20 Feb 2014 13:16:10 +0000 (08:16 -0500)
src/backend/utils/mmgr/freepage.c
src/include/utils/freepage.h

index 0e06b4e06c1ddda6966525009bcd3dacbe99b2b6..7ad319cc89eb1e5dd205f3060a53503044a136b6 100644 (file)
@@ -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
index f14705669e0b4f31c60da33dccf22f2e854d89ec..b19ccd7b5d0a8c08b95c13296dca77df20555c9e 100644 (file)
@@ -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 */