static void FreePageBtreeRecycle(FreePageManager *fpm, Size pageno);
static void FreePageBtreeRemove(FreePageManager *fpm, FreePageBtree *btp,
Size index);
+static void FreePagePushSpanLeader(FreePageManager *fpm, Size first_page,
+ Size npages);
static bool FreePageManagerPutInternal(FreePageManager *fpm, Size first_page,
Size npages, bool soft);
static void FreePageBtreeRemove(FreePageManager *fpm, FreePageBtree *btp,
if (next != NULL)
relptr_copy(next->prev, victim->prev);
- /* Remove span from btree. */
+ /*
+ * If the span we found is exactly the right size, remove it from the
+ * btree completely. Otherwise, adjust the btree entry to reflect the
+ * still-unallocated portion of the span, and put that portion on the
+ * appropriate free list.
+ */
FreePageBtreeSearch(fpm, victim_page, &result);
Assert(result.page_exact != NULL);
- FreePageBtreeRemove(fpm, result.page_exact, result.index_exact);
-
- /* XXX. But the span we found might have been oversized ... we
- * need to put the rest back! */
+ if (victim->npages == npages)
+ FreePageBtreeRemove(fpm, result.page_exact, result.index_exact);
+ else
+ {
+ FreePageBtreeLeafKey *key;
+
+ /* Adjust btree to reflect remaining pages. */
+ Assert(victim->npages > npages);
+ key = &result.page_exact->u.leaf_key[result.index_exact];
+ Assert(key->npages == victim->npages);
+ key->first_page += npages;
+ key->npages -= npages;
+ if (result.index_exact == 0)
+ FreePageBtreeAdjustAncestorKeys(fpm, result.page_exact);
+
+ /* Put the unallocated pages back on the appropriate free list. */
+ FreePagePushSpanLeader(fpm, victim_page + npages,
+ victim->npages - npages);
+ }
+ /* Return results to caller. */
*first_page = fpm_pointer_to_page(base, victim);
return true;
}