if (lock != NULL)
LWLockRelease(lock);
- return true;
+ return result;
}
/*
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). */
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);
}
* 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]))
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
{
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. */
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;
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);
}
/* 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;
FreePageBtreeFirstKey(newsibling);
relptr_store(base, newroot->u.internal_key[1].child,
target);
+ fpm->btree_depth++;
break;
}
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;
}
}
if (index == 0)
FreePageBtreeAdjustAncestorKeys(fpm, result.page_next);
+ /* Put it on the free list. */
+ FreePagePushSpanLeader(fpm, first_page, npages);
+
return true;
}