From: Robert Haas Date: Thu, 20 Feb 2014 17:25:17 +0000 (-0500) Subject: Fix bugs. X-Git-Url: http://git.postgresql.org/gitweb/static/developers.postgresql.org?a=commitdiff_plain;h=86232c50836f82d25975ee181de62a8e0b699867;p=users%2Frhaas%2Fpostgres.git Fix bugs. --- diff --git a/src/backend/utils/mmgr/freepage.c b/src/backend/utils/mmgr/freepage.c index 7ad319cc89..9aa7cce6df 100644 --- a/src/backend/utils/mmgr/freepage.c +++ b/src/backend/utils/mmgr/freepage.c @@ -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; }