Fix bugs.
authorRobert Haas <rhaas@postgresql.org>
Thu, 20 Feb 2014 17:25:17 +0000 (12:25 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 20 Feb 2014 17:25:17 +0000 (12:25 -0500)
src/backend/utils/mmgr/freepage.c

index 7ad319cc89eb1e5dd205f3060a53503044a136b6..9aa7cce6df308a6d8d9c4ea3661d194bdb023406 100644 (file)
@@ -176,7 +176,7 @@ FreePageManagerGet(FreePageManager *fpm, Size npages, Size *first_page)
        if (lock != NULL)
                LWLockRelease(lock);
 
-       return true;
+       return result;
 }
 
 /*
@@ -261,10 +261,9 @@ FreePageManagerDump(FreePageManager *fpm)
                        appendStringInfo(&buf, "freelists:\n");
                        dumped_any_freelist = true;
                }
-               appendStringInfo(&buf, "  %zu:", f);
+               appendStringInfo(&buf, "  %zu:", f + 1);
                span = relptr_access(base, fpm->freelist[f]);
-               FreePageManagerDumpSpans(fpm, span,
-                                                                f < FPM_NUM_FREELISTS - 1 ? f - 1 : 0, &buf);
+               FreePageManagerDumpSpans(fpm, span, f + 1, &buf);
        }
 
        /* Release lock (if there is one). */
@@ -811,11 +810,11 @@ FreePageManagerDumpSpans(FreePageManager *fpm, FreePageSpanLeader *span,
 
        while (span != NULL)
        {
-               if (expected_pages == 0 || span->npages != expected_pages)
+               if (span->npages != expected_pages)
                        appendStringInfo(buf, " %zu(%zu)", fpm_pointer_to_page(base, span),
                                                         span->npages);
                else
-                       appendStringInfo(buf, " %zu", span->npages);
+                       appendStringInfo(buf, " %zu", fpm_pointer_to_page(base, span));
                span = relptr_access(base, span->next);
        }
 
@@ -851,7 +850,7 @@ FreePageManagerGetInternal(FreePageManager *fpm, Size npages, Size *first_page)
         * but no policy can be optimal under all circumstances unless it has
         * knowledge of future allocation patterns.
         */
-       for (f = Max(npages, FPM_NUM_FREELISTS) - 1; f < FPM_NUM_FREELISTS; ++f)
+       for (f = Min(npages, FPM_NUM_FREELISTS) - 1; f < FPM_NUM_FREELISTS; ++f)
        {
                /* Skip empty freelists. */
                if (relptr_is_null(fpm->freelist[f]))
@@ -911,6 +910,9 @@ FreePageManagerGetInternal(FreePageManager *fpm, Size npages, Size *first_page)
                Assert(victim->npages >= npages);
                fpm->singleton_first_page += npages;
                fpm->singleton_npages -= npages;
+               if (fpm->singleton_npages > 0)
+                       FreePagePushSpanLeader(fpm, fpm->singleton_first_page,
+                                                                  fpm->singleton_npages);
        }
        else
        {
@@ -1015,47 +1017,66 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
        FreePageBtreeLeafKey *nextkey = NULL;
        Size    index;
 
-       /*
-        * As a special case, we store the very first range in the FreePageManager
-        * itself, so that a request for the entire number of pages will succeed.
-        * Otherwise, we must build or update a btree.
-        */
-       if (fpm->btree_depth == 0 && fpm->singleton_npages == 0)
-       {
-               fpm->singleton_first_page = first_page;
-               fpm->singleton_npages = npages;
-               return true;
-       }
-
-       /*
-        * When we see the second range, we need to initialize the btree for
-        * real.
-        */
+       /* We can store a single free span without initializing the btree. */
        if (fpm->btree_depth == 0)
        {
-               Size    root_page;
-               FreePageBtree *root;
-
-               if (!relptr_is_null(fpm->btree_recycle))
-                       root = FreePageBtreeGetRecycled(fpm);
-               else if (FreePageManagerGetInternal(fpm, 1, &root_page))
-                       root = (FreePageBtree *) fpm_page_to_pointer(base, root_page);
-               else
+               if (fpm->singleton_npages == 0)
                {
-                       /* We'd better be able to get a page from the existing range. */
-                       elog(FATAL, "free page manager btree is corrupt");
+                       /* Don't have a span yet; store this one. */
+                       fpm->singleton_first_page = first_page;
+                       fpm->singleton_npages = npages;
+                       FreePagePushSpanLeader(fpm, first_page, npages);
+                       return true;
                }
+               else if (fpm->singleton_first_page + fpm->singleton_npages ==
+                                       first_page)
+               {
+                       /* New span immediately follows sole existing span. */
+                       fpm->singleton_npages += npages;
+                       FreePagePopSpanLeader(fpm, fpm->singleton_first_page);
+                       FreePagePushSpanLeader(fpm, fpm->singleton_first_page,
+                                                                  fpm->singleton_npages);
+                       return true;
+               }
+               else if (first_page + npages == fpm->singleton_first_page)
+               {
+                       /* New span immediately precedes sole existing span. */
+                       FreePagePopSpanLeader(fpm, fpm->singleton_first_page);
+                       fpm->singleton_first_page = first_page;
+                       fpm->singleton_npages += npages;
+                       FreePagePushSpanLeader(fpm, fpm->singleton_first_page,
+                                                                  fpm->singleton_npages);
+                       return true;
+               }
+               else
+               {
+                       /* Not contiguous; we need to initialize the btree. */
+                       Size    root_page;
+                       FreePageBtree *root;
+
+                       if (!relptr_is_null(fpm->btree_recycle))
+                               root = FreePageBtreeGetRecycled(fpm);
+                       else if (FreePageManagerGetInternal(fpm, 1, &root_page))
+                               root = (FreePageBtree *) fpm_page_to_pointer(base, root_page);
+                       else
+                       {
+                               /* We'd better be able to get a page from the existing range. */
+                               elog(FATAL, "free page manager btree is corrupt");
+                       }
 
-               /* Create the btree and move the preexisting range into it. */
-               root->hdr.magic = FREE_PAGE_LEAF_MAGIC;
-               root->hdr.nused = 1;
-               relptr_store(base, root->hdr.parent, (FreePageBtree *) NULL);
-               root->u.leaf_key[0].first_page = fpm->singleton_first_page;
-               root->u.leaf_key[0].npages = fpm->singleton_npages;
-               fpm->singleton_first_page = 0;
-               fpm->singleton_npages = 0;
-
-               /* Fall through to insert the new key. */
+                       /* Create the btree and move the preexisting range into it. */
+                       root->hdr.magic = FREE_PAGE_LEAF_MAGIC;
+                       root->hdr.nused = 1;
+                       relptr_store(base, root->hdr.parent, (FreePageBtree *) NULL);
+                       root->u.leaf_key[0].first_page = fpm->singleton_first_page;
+                       root->u.leaf_key[0].npages = fpm->singleton_npages;
+                       relptr_store(base, fpm->btree_root, root);
+                       fpm->singleton_first_page = 0;
+                       fpm->singleton_npages = 0;
+                       fpm->btree_depth = 1;
+
+                       /* Fall through to insert the new key. */
+               }
        }
 
        /* Search the btree. */
@@ -1067,7 +1088,7 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
                nextkey = &result.page_next->u.leaf_key[result.index_next];
 
        /* Consolidate with the previous entry if possible. */
-       if (prevkey->first_page + prevkey->npages >= first_page)
+       if (prevkey != NULL && prevkey->first_page + prevkey->npages >= first_page)
        {
                bool    remove_next = false;
 
@@ -1075,7 +1096,8 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
                prevkey->npages = (first_page - prevkey->first_page) + npages;
 
                /* Check whether we can *also* consolidate with the following entry. */
-               if (prevkey->first_page + prevkey->npages >= nextkey->first_page)
+               if (nextkey != NULL &&
+                       prevkey->first_page + prevkey->npages >= nextkey->first_page)
                {
                        Assert(prevkey->first_page + prevkey->npages ==
                                        nextkey->first_page);
@@ -1105,7 +1127,7 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
        }
 
        /* Consolidate with the next entry if possible. */
-       if (first_page + npages >= nextkey->first_page)
+       if (nextkey != NULL && first_page + npages >= nextkey->first_page)
        {
                Size    newpages;
 
@@ -1258,6 +1280,7 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
                                                FreePageBtreeFirstKey(newsibling);
                                        relptr_store(base, newroot->u.internal_key[1].child,
                                                target);
+                                       fpm->btree_depth++;
 
                                        break;
                                }
@@ -1281,7 +1304,11 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
                                target = parent;
                        }
 
-                       /* The loop above did the insert, so we're done! */                     
+                       /*
+                        * The loop above did the insert, so just need to update the
+                        * free list, and we're done.
+                        */
+                       FreePagePushSpanLeader(fpm, first_page, npages);
                        return true;
                }
        }
@@ -1294,5 +1321,8 @@ FreePageManagerPutInternal(FreePageManager *fpm, Size first_page, Size npages,
        if (index == 0)
                FreePageBtreeAdjustAncestorKeys(fpm, result.page_next);
 
+       /* Put it on the free list. */
+       FreePagePushSpanLeader(fpm, first_page, npages);
+
        return true;
 }