#include "postgres.h"
-#include "utils/sb_alloc.h"
+#include "miscadmin.h"
+#include "utils/sb_region.h"
/*
* Small allocations are handled by dividing a relatively large chunk of
5456, 6552, 7280, 8192 /* 4 classes separated by ~1024 bytes */
};
-#if 0
/*
* The following lookup table is used to map the size of small objects
* (less than 1kB) onto the corresponding size class. To use this table,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23
};
-#define MSPAN_SIZE_CLASS_MAP_QUANTUM 8
-#endif
+#define SB_SIZE_CLASS_MAP_QUANTUM 8
+
+/* Special size classes. */
+#define SB_SCLASS_SPAN_OF_SPANS 0
+#define SB_SCLASS_SPAN_LARGE 1
+#define SB_SCLASS_FIRST_REGULAR 2
+
+/* Helper functions. */
+static char *sb_alloc_guts(sb_region *region, sb_allocator *a, int size_class);
+static void sb_out_of_memory_error(sb_allocator *a);
/*
* Create a backend-private allocator.
return a;
}
+
+/*
+ * Allocate memory.
+ */
+void *
+sb_alloc(sb_allocator *a, Size size, int flags)
+{
+ sb_region *region = NULL;
+ char *base = NULL;
+ int size_class;
+ char *result;
+
+ /*
+ * For shared memory allocation, pointers are relative to the start of the
+ * region, so finding out that information is essential. For
+ * backend-private memory allocation, allocators aren't uniquely tied to
+ * a region; we'll only need to grab a region if we can't allocate out of
+ * an existing superblock.
+ */
+ if (!a->private)
+ {
+ region = sb_lookup_region(a);
+ if (region == NULL)
+ elog(ERROR, "sb_region not found");
+ base = region->region_start;
+ }
+
+ /* If it's too big for a superblock, just grab a raw run of pages. */
+ if (size > sb_size_classes[lengthof(sb_size_classes) - 1])
+ {
+ Size npages = fpm_size_to_pages(size);
+ Size first_page;
+ sb_span *span;
+
+ /* Obtain a span object. */
+ span = (sb_span *) sb_alloc_guts(region, a, SB_SCLASS_SPAN_OF_SPANS);
+ if (span == NULL)
+ {
+ if ((flags & SB_ALLOC_SOFT_FAIL) == 0)
+ sb_out_of_memory_error(a);
+ return NULL;
+ }
+
+ /* Find a region from which to allocate. */
+ if (region == NULL)
+ region = sb_private_region_for_allocator(npages);
+
+ /* Here's where we try to perform the actual allocation. */
+ if (region == NULL ||
+ !FreePageManagerGet(region->fpm, npages, &first_page))
+ {
+ /* XXX. Free the span. */
+ if ((flags & SB_ALLOC_SOFT_FAIL) == 0)
+ sb_out_of_memory_error(a);
+ return NULL;
+ }
+
+ /* XXX. Put the span on the large object heap! */
+
+ sb_map_set(region->pagemap, first_page, ((char *) span) - base);
+
+ return fpm_page_to_pointer(fpm_segment_base(region->fpm),
+ first_page);
+ }
+
+ /* Map allocation to a size class. */
+ if (size < lengthof(sb_size_class_map) * SB_SIZE_CLASS_MAP_QUANTUM)
+ {
+ int mapidx;
+
+ mapidx = (size + SB_SIZE_CLASS_MAP_QUANTUM - 1) /
+ SB_SIZE_CLASS_MAP_QUANTUM;
+ size_class = sb_size_class_map[mapidx];
+ }
+ else
+ {
+ uint16 min = sb_size_class_map[lengthof(sb_size_class_map) - 1];
+ uint16 max = lengthof(sb_size_classes) - 1;
+
+ while (min < max)
+ {
+ uint16 mid = (min + max) / 2;
+ uint16 class_size = sb_size_classes[mid];
+
+ if (class_size < size)
+ min = mid + 1;
+ else
+ max = mid;
+ }
+
+ size_class = min;
+ }
+ Assert(size <= sb_size_classes[size_class]);
+ size_class += SB_SCLASS_FIRST_REGULAR;
+
+ /* Attempt the actual allocation. */
+ result = sb_alloc_guts(region, a, size_class);
+ if (result == NULL && (flags & SB_ALLOC_SOFT_FAIL) == 0)
+ sb_out_of_memory_error(a);
+ return result;
+}
+
+/*
+ * Guts of the memory allocation routine.
+ */
+static char *
+sb_alloc_guts(sb_region *region, sb_allocator *a, int size_class)
+{
+ /* XXX */
+ return NULL;
+}
+
+/*
+ * Report an out-of-memory condition.
+ */
+static void
+sb_out_of_memory_error(sb_allocator *a)
+{
+ if (a->private)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of shared memory")));
+}