rough sketch of sb_alloc_from_heap
authorRobert Haas <rhaas@postgresql.org>
Sat, 22 Mar 2014 14:51:17 +0000 (10:51 -0400)
committerRobert Haas <rhaas@postgresql.org>
Sat, 22 Mar 2014 14:51:17 +0000 (10:51 -0400)
src/backend/utils/mmgr/sb_alloc.c

index a2f5b0139053e803cac50348e6933b7ba9ed3f0a..4da7016db3f158743f39ffd26136d50331150a0d 100644 (file)
@@ -111,7 +111,7 @@ static char sb_size_class_map[] = {
        (SB_SCLASS_FIRST_REGULAR + lengthof(sb_size_classes))
 
 /* Helper functions. */
-static char *sb_alloc_from_heap(char *base, sb_heap *heap);
+static char *sb_alloc_from_heap(char *base, sb_heap *heap, Size obsize);
 static char *sb_alloc_guts(char *base, sb_region *region,
                          sb_allocator *a, int size_class);
 static void sb_init_span(char *base, sb_span *span, sb_heap *heap,
@@ -269,12 +269,101 @@ sb_alloc(sb_allocator *a, Size size, int flags)
 /*
  * Allocate an object from the provided heap.  Caller is responsible for
  * any required locking.
+ *
+ * Fullness classes K of 0..N is loosely intended to represent superblocks
+ * whose utilization percentage is at least K/N, but we only enforce this
+ * rigorously for the highest-numbered fullness class, which always contains
+ * exactly those blocks that are completely full.  It's otherwise acceptable
+ * for a superblock to be in a higher-numbered fullness class than the one
+ * to which it logically belongs.  In addition, the active superblock, which
+ * is always the first block in fullness class 1, is permitted to have a
+ * higher allocation percentage than would normally be allowable for that
+ * fullness class; we don't move it until it's completely full, and then
+ * it goes to the highest-numbered fullness class.
+ *
+ * It might seem odd that the active superblock is the head of fullness class
+ * 1 rather than fullness class 0, but experience with other allocators has
+ * shown that it's usually better to allocate from a superblock that's
+ * moderately full rather than one that's nearly empty.  Insofar as is
+ * reasonably possible, we want to avoid performing new allocations in a
+ * superblock that would otherwise become empty soon.
  */
 static char *
-sb_alloc_from_heap(char *base, sb_heap *heap)
+sb_alloc_from_heap(char *base, sb_heap *heap, Size obsize)
 {
-       /* XXX */
-       return NULL;
+       sb_span *active_sb;
+       Size    fclass;
+       Size    nmax = (FPM_PAGE_SIZE * SB_PAGES_PER_SUPERBLOCK) / obsize;
+
+       /*
+        * If fullness class 1 is empty, try to find something to put in it by
+        * scanning higher-numbered fullness classes (excluding the last one,
+        * whose blocks are certain to all be completely full).
+        */
+       for (fclass = 2; fclass < SB_FULLNESS_CLASSES - 1; ++fclass)
+       {
+               sb_span *span;
+
+               if (relptr_is_null(heap->spans[1]))
+                       break;
+
+               span = relptr_access(base, heap->spans[fclass]);
+               while (span != NULL)
+               {
+                       /* XXX. Figure out what fullness class it should go in. */
+
+                       /* XXX. If the fullness class it should go is less than this one,
+                        * move it there. */
+
+                       /* XXX. Advance to next span on list. */
+               }
+       }
+
+       /*
+        * If there are no superblocks that properly belong in fullness class 1,
+        * pick one from some other fullness class and move it there anyway, so
+        * that we have an allocation target.
+        */
+       if (relptr_is_null(heap->spans[1]))
+       {
+               for (fclass = 2; fclass < SB_FULLNESS_CLASSES - 1; ++fclass)
+               {
+                       sb_span *span;
+
+                       span = relptr_access(base, heap->spans[fclass]);
+                       if (span != NULL)
+                               /* XXX. Move it to fullness class 1 and break. */;
+               }
+               if (relptr_is_null(heap->spans[1]))
+               {
+                       sb_span *span = relptr_access(base, heap->spans[0]);
+
+                       if (span != NULL)
+                       {
+                               /*
+                                * The only superblocks with freespace are almost empty, but
+                                * using one of those is still better than allocating a new
+                                * one.
+                                */
+                               /* XXX. Move it to fullness class 1. */
+                       }
+                       else
+                       {
+                               /* All superblocks are completely full. */
+                               return NULL;
+                       }
+               }
+       }
+
+       /* We have a superblock from which to allocate; do it. */
+       active_sb = relptr_access(base, heap->spans[1]);
+       Assert(active_sb != NULL);
+       /* XXX need to actually allocate something here! */
+
+       if (active_sb->nused == nmax)
+               /* XXX. Move it to the highest-numbered fullness class. */;
+
+       return NULL; /* XXX */
 }
 
 /*
@@ -289,13 +378,24 @@ sb_alloc_guts(char *base, sb_region *region, sb_allocator *a, int size_class)
        sb_heap *heap = &a->heaps[heapno];
        LWLock *lock = relptr_access(base, heap->lock);
        char *result = NULL;
+       Size    obsize;
+
+       /* Work out object size. */
+       if (size_class == 0)
+               obsize = sizeof(sb_span);
+       else
+       {
+               Assert(size_class >= SB_SCLASS_FIRST_REGULAR);
+               Assert(size_class < SB_NUM_SIZE_CLASSES);
+               obsize = sb_size_classes[size_class - SB_SCLASS_FIRST_REGULAR];
+       }
 
        /* If locking is in use, acquire the lock. */
        if (lock != NULL)
                LWLockAcquire(lock, LW_EXCLUSIVE);
 
        /* Attempt to allocate from the heap. */
-       result = sb_alloc_from_heap(base, heap);
+       result = sb_alloc_from_heap(base, heap, obsize);
 
        /*
         * If there's no space in the current heap, but there are multiple heaps
@@ -308,7 +408,7 @@ sb_alloc_guts(char *base, sb_region *region, sb_allocator *a, int size_class)
                        sb_try_to_steal_superblock(base, a, heapproc, size_class))
                {
                        /* The superblock we stole shouldn't full, so this should work. */
-                       result = sb_alloc_from_heap(base, heap);
+                       result = sb_alloc_from_heap(base, heap, obsize);
                        Assert(result != NULL);
                }
                else
@@ -366,7 +466,7 @@ sb_alloc_guts(char *base, sb_region *region, sb_allocator *a, int size_class)
                                span->ninitialized = span->nused = 1;
 
                        /* This should work now. */
-                       result = sb_alloc_from_heap(base, heap);
+                       result = sb_alloc_from_heap(base, heap, obsize);
                        Assert(result != NULL);
                }
        }