More hacking.
authorRobert Haas <rhaas@postgresql.org>
Wed, 19 Feb 2014 22:54:35 +0000 (17:54 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 19 Feb 2014 22:54:35 +0000 (17:54 -0500)
src/backend/utils/mmgr/freepage.c

index cb6c8690f5d473c215eb243aece421104aa80f70..2e4dda83fcc284d1724017da8a389052d9890b17 100644 (file)
@@ -90,6 +90,8 @@ static bool FreePageManagerGetInternal(FreePageManager *fpm, Size npages,
 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,
@@ -365,14 +367,35 @@ FreePageManagerGetInternal(FreePageManager *fpm, Size npages, Size *first_page)
        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;
 }