sb_private_region_for_allocator, part one.
authorRobert Haas <rhaas@postgresql.org>
Wed, 19 Mar 2014 20:28:25 +0000 (16:28 -0400)
committerRobert Haas <rhaas@postgresql.org>
Wed, 19 Mar 2014 20:28:25 +0000 (16:28 -0400)
src/backend/utils/mmgr/sb_region.c

index 2e7609c985af5324567e9d9139ae14da0b54f2ce..8ae176320c6efd980602170855ae8400fe26ddfb 100644 (file)
@@ -153,16 +153,93 @@ sb_lookup_region(void *ptr)
        return NULL;
 }
 
+/*
+ * When a backend-private sb_allocator needs more memory, it calls this
+ * function.  We search the existing backend-private regions for one capable
+ * of satisfying the request; if none found, we must create a new region.
+ */
+sb_region *
+sb_private_region_for_allocator(Size npages)
+{
+       int freelist = Min(fls(npages), NUM_PRIVATE_FREELISTS);
+
+       Assert(npages > 0);
+
+       while (freelist < NUM_PRIVATE_FREELISTS)
+       {
+               dlist_mutable_iter      iter;
+               Size            threshold = 1 << (freelist - 1);
+
+               dlist_foreach_modify(iter, &private_freelist[freelist])
+               {
+                       sb_region  *region;
+                       Size    largest;
+
+                       region = dlist_container(sb_region, fl_node, iter.cur);
+
+                       /* Skip regions that are certain not to have space. */
+                       if (region->contiguous_pages < npages)
+                               continue;
+
+                       /*
+                        * The region we're examining was at one point reported to
+                        * have adequate space, but subsequent allocations might have
+                        * eroded that, so recheck.  If there's enough, we're done!
+                        *
+                        * NB: For larger allocations this might be suboptimal, because
+                        * we might carve space out of a chunk that's bigger than we
+                        * really need rather than locating the best fit across all
+                        * chunks.  It shouldn't be too far off, though, because
+                        * chunks with way more contiguous space available will be on
+                        * a higher-numbered freelist.  For really large allocations,
+                        * it's probably better to malloc() directly than go through
+                        * this machinery.
+                        */
+                       largest = FreePageManagerInquireLargest(region->fpm);
+                       region->contiguous_pages = largest;
+                       if (largest >= npages)
+                               return region;
+
+                       /*
+                        * The region we're examining not only doesn't have enough
+                        * contiguous freespace to satisfy this allocation, but it
+                        * doesn't even belong in this bucket.  Move it to the right place.
+                        */
+                       if (largest < threshold)
+                       {
+                               int     new_freelist = Min(fls(npages), NUM_PRIVATE_FREELISTS);
+
+                               dlist_delete(iter.cur);
+                               dlist_push_head(&private_freelist[new_freelist],
+                                                               &region->fl_node);
+                       }
+               }
+
+               /* Try next freelist. */
+               ++freelist;
+       }
+
+       /*
+        * There is no existing backend-private region with enough freespace
+        * to satisfy the allocation request.  Create a new one.
+        */
+
+       /* XXX. Not implemented yet. */
+
+       return NULL;
+}
+
 /*
  * When a free page manager detects that the maximum contiguous freespace in
  * a backend-private region has increased, it calls this function.  Our job
- * is to move the region to a higher-numbered freelist if necessary.
+ * is to free the region completely if there are no remaining allocatons,
+ * and otherwise to 
  */
 void
 sb_report_contiguous_freespace(sb_region *region, Size npages)
 {
-       Size    old_freelist;
-       Size    new_freelist;
+       int             old_freelist;
+       int             new_freelist;
 
        /* This should only be called for private regions. */
        Assert(region->seg == NULL);