diff options
author | Robert Haas | 2014-02-06 16:39:09 +0000 |
---|---|---|
committer | Robert Haas | 2014-02-06 16:39:09 +0000 |
commit | 6eb7d118b2a419b1ef49a3d29abcf23ae5e53027 (patch) | |
tree | 06ab6535c8f78a9bb5e996745ef92d7144842170 | |
parent | 87f72ccb6a406cf0be5a67e754a8293a82261799 (diff) |
Hack, hack.memory
-rw-r--r-- | src/backend/utils/mmgr/mspan.c | 221 | ||||
-rw-r--r-- | src/include/utils/mspan.h | 3 |
2 files changed, 155 insertions, 69 deletions
diff --git a/src/backend/utils/mmgr/mspan.c b/src/backend/utils/mmgr/mspan.c index c84de1b92c..8f040b9483 100644 --- a/src/backend/utils/mmgr/mspan.c +++ b/src/backend/utils/mmgr/mspan.c @@ -35,6 +35,13 @@ #define MSPAN_MAX_32BIT_PAGES (1 << (32 - MSPAN_PAGE_BITS)) /* + * Amount of space to allocate from the operating system at one time, as + * a multiple of our page size. The first chunk will be of the first size + * in the array, and then we work up as we allocate more chunks. + */ +static Size mspan_sysalloc_pages[] = { 256, 512, 1024, 2048, 4096, 8192 }; + +/* * Small allocations are handled by dividing a relatively large chunk of * memory called a superblock into many small objects of equal size. The * chunk sizes are defined by the following array. Larger size classes are @@ -125,6 +132,8 @@ struct mspan uint16 ninitialized; /* Maximum number of objects ever allocated. */ uint16 nused; /* Number of objects currently allocated. */ uint16 firstfree; /* First object on free list. */ + void *syschunk; /* Pointer returned by OS malloc. */ + Size syspages; /* Original size of span, before splitting. */ }; #define MSPAN_FIRSTFREE_NONE ((uint16) -1) @@ -443,8 +452,8 @@ mspan_allocate_context_descriptor(char *base, mspan_manager *mgr) if (span != NULL) { /* - * If the span is just one page, deallocate it completely (see - * function header comments for why this is OK). Otherwise, remove + * If the span is just one page, deallocate it completely (context + * objects are never freed, so this is OK). Otherwise, remove * the first page from the span and put the rest back on the * appropriate free list. Also adjust the page map entries as * appropriate. @@ -535,56 +544,6 @@ mspan_allocate_from_superblock(char *base, mspan *superblock) } /* - * Allocate new space for a new span descriptor. - */ -static mspan * -mspan_allocate_span_descriptor(char *base, mspan_manager *mgr) -{ - mspan *span_of_spans; - - if (!relptr_is_null(mgr->span_of_spans)) - { - char *result; - - /* Try to allocate from the first span-of-spans. */ - span_of_spans = relptr_access(base, mgr->span_of_spans); - Assert(span_of_spans->span_type == MSPAN_TYPE_SPAN_OF_SPANS); - result = mspan_allocate_from_superblock(base, span_of_spans); - if (result != NULL) - return (mspan *) result; - - /* Walk the list looking for a span-of-spans that isn't full. */ - for (;;) - { - span_of_spans = relptr_access(base, span_of_spans->nextspan); - if (span_of_spans == NULL) - break; - Assert(span_of_spans->span_type == MSPAN_TYPE_SPAN_OF_SPANS); - result = mspan_allocate_from_superblock(base, span_of_spans); - if (result != NULL) - { - /* - * Move the span from which we allocate to head of list in - * the hope of speeding up future searches. - */ - mspan_unlink_span(base, span_of_spans); - mspan_link_span_to_manager(base, mgr, span_of_spans); - - /* Return a pointer to the space we allocated. */ - return (mspan *) result; - } - } - } - - /* Create a new span descriptor. */ - span_of_spans = - mspan_allocate_span(base, mgr, NULL, MSPAN_TYPE_SPAN_OF_SPANS, 0); - if (span_of_spans == NULL) - return NULL; - return (mspan *) mspan_allocate_from_superblock(base, span_of_spans); -} - -/* * Allocate a span. * * We can do this either by finding a free span which is already suitable @@ -603,6 +562,8 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt, uint16 span_type, Size pages) { mspan *span; + char *syschunk = NULL; + Size syspages = 0; Size first_page; /* @@ -665,6 +626,10 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt, * such a span, and the only other lookups we expect are for the pages * end pages to check whether this is a free span that can be * consolidated. + * + * XXX. So what happens if we go to do these page map updates and + * run out of memory? It's not safe to just bail out here; we'd + * leak the allocated span. */ Assert(span->npages == pages); if (span_type != MSPAN_TYPE_LARGE) @@ -688,6 +653,10 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt, * spans. Otherwise, we prefer to allocate the span descriptor here * rather than after finding storage, because it's easier to back this * out if storage allocation fails than the other way around. + * + * XXX. This is completely bogus in the non-DSM case, because we might + * recuse back into this routine, allocate more space from the OS, and yet + * not know it, and thus allocate more again. */ if (span_type != MSPAN_TYPE_SPAN_OF_SPANS) { @@ -703,34 +672,93 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt, if (mgr->boundary + pages >= mgr->npages) { /* Not enough pages remaining. */ - mspan_destroy_span(base, span); + if (span != NULL) + mspan_destroy_span(base, span); return NULL; } first_page = mgr->boundary; mgr->boundary += pages; + + /* + * If this is a span-of-spans, allocate a descriptor for the new span + * out of the span itself. If it's not, span should already be + * non-NULL; see above. + */ + if (span_type == MSPAN_TYPE_SPAN_OF_SPANS) + { + Assert(span == NULL); + span = (mspan *) (base + first_page * MSPAN_PAGE_SIZE); + } + Assert(span != NULL); + + /* Initialize the new span. */ + span->first_page = first_page; + span->npages = pages; + mspan_initialize_span(base, mgr, cxt, span, span_type); } else { + /* Allocate from the operating system. */ + if (pages > mspan_sysalloc_pages[0]) + { + /* + * This is a large allocation, so ask the operating system for + * exactly the amount of space we need. + */ + syspages = pages; + syschunk = malloc(syspages * MSPAN_PAGE_SIZE); + if (syschunk == NULL) + { + if (span != NULL) + mspan_destroy_span(base, span); + return NULL; + } + } + else + { + Size i; + + /* + * Try to allocate a chunk of the size appropriate to the number + * of system chunks already allocated. If that fails, ratchet the + * request back, but not below the minimum chunk size. + */ + i = Max(mgr->nsyschunks, lengthof(mspan_sysalloc_pages) - 1); + for (;;) + { + syspages = mspan_sysalloc_pages[i]; + syschunk = malloc(syspages * MSPAN_PAGE_SIZE); + if (syschunk != NULL) + break; + if (i == 0) + { + if (span != NULL) + mspan_destroy_span(base, span); + return NULL; + } + --i; + } + } + /* - * XXX. Allocate more core via malloc. We need a system here for - * this. Obviously we shouldn't just allocate the smallest amount - * needed for this span unless that's already pretty big. Instead, - * we should allocate enough for this span and then throw the remainder - * in a bucket for later use. But the mechanism for that is not - * designed yet. - * - * XXX. How exactly are we going to give the segments we malloc - * back to the OS? How are we even going to know where they are? - * We can add them to the freelists as a big old span, but that's - * not going to help much in terms of identifying them later. + * Work out the number of usable pages in the span, and the location + * of the first one. If the operating system returned a page-aligned + * address, as we hope, then the number of usable pages is exactly + * equal to the number of pages we allocated. If not, then both the + * first and last pages are partial and therefore unusable. */ - first_page = 0; /* XXX. Bogus. */ + first_page = ((Size) syschunk) << MSPAN_PAGE_BITS; + if (((Size) syschunk) % MSPAN_PAGE_BITS != 0) + { + ++first_page; + syspages -= 2; + } } /* * If this is a span-of-spans, allocate a descriptor for the new span - * out of the span itself. If it's not, span shuold already be non-NULL; - * see above. + * out of the span itself. If it's not, span should already be + * non-NULL; see above. */ if (span_type == MSPAN_TYPE_SPAN_OF_SPANS) { @@ -742,12 +770,71 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt, /* Initialize the new span. */ span->first_page = first_page; span->npages = pages; + span->syschunk = syschunk; + span->syspages = syspages; mspan_initialize_span(base, mgr, cxt, span, span_type); + /* + * XXX. If we just allocated a new system chunk, it's probably larger + * than the number of pages we actually used for the span. We need to + * turn the rest into another span, put it on the free list, and make + * page map entries for it. + */ + return span; } /* + * Allocate new space for a new span descriptor. + */ +static mspan * +mspan_allocate_span_descriptor(char *base, mspan_manager *mgr) +{ + mspan *span_of_spans; + + if (!relptr_is_null(mgr->span_of_spans)) + { + char *result; + + /* Try to allocate from the first span-of-spans. */ + span_of_spans = relptr_access(base, mgr->span_of_spans); + Assert(span_of_spans->span_type == MSPAN_TYPE_SPAN_OF_SPANS); + result = mspan_allocate_from_superblock(base, span_of_spans); + if (result != NULL) + return (mspan *) result; + + /* Walk the list looking for a span-of-spans that isn't full. */ + for (;;) + { + span_of_spans = relptr_access(base, span_of_spans->nextspan); + if (span_of_spans == NULL) + break; + Assert(span_of_spans->span_type == MSPAN_TYPE_SPAN_OF_SPANS); + result = mspan_allocate_from_superblock(base, span_of_spans); + if (result != NULL) + { + /* + * Move the span from which we allocate to head of list in + * the hope of speeding up future searches. + */ + mspan_unlink_span(base, span_of_spans); + mspan_link_span_to_manager(base, mgr, span_of_spans); + + /* Return a pointer to the space we allocated. */ + return (mspan *) result; + } + } + } + + /* Create a new span descriptor. */ + span_of_spans = + mspan_allocate_span(base, mgr, NULL, MSPAN_TYPE_SPAN_OF_SPANS, 0); + if (span_of_spans == NULL) + return NULL; + return (mspan *) mspan_allocate_from_superblock(base, span_of_spans); +} + +/* * Deallocate a span descriptor. */ static void diff --git a/src/include/utils/mspan.h b/src/include/utils/mspan.h index 67a8e51911..6c33dcf387 100644 --- a/src/include/utils/mspan.h +++ b/src/include/utils/mspan.h @@ -76,8 +76,7 @@ struct mspan_manager Size base; /* offset of page 0 within dsm; 0 for private */ Size boundary; /* first unallocated page in dsm; 0 for private */ Size ncontexts; /* # of outstanding contexts */ - Size nspans; /* # of outstanding spans */ - Size nspansuperblocks; /* # of superblocks for span objects */ + Size nsyschunks; /* # of chunks allocated from OS */ relptr(mspan) span_of_spans; /* superblock for span descriptors */ relptr(mspan_context) freecontext; /* allocatable context object */ aspace_map page_map; /* map pages to mspans */ |