(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,
/*
* 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 */
}
/*
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
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
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);
}
}