From: Robert Haas Date: Mon, 5 May 2014 14:34:02 +0000 (+0000) Subject: Teach sb_free about large objects; avoid hysteresis therein. X-Git-Url: http://git.postgresql.org/gitweb/static/developers.postgresql.org?a=commitdiff_plain;h=5c2248ecf188c3890889612b5bf291ba3d94374e;p=users%2Frhaas%2Fpostgres.git Teach sb_free about large objects; avoid hysteresis therein. --- diff --git a/src/backend/utils/mmgr/sb_alloc.c b/src/backend/utils/mmgr/sb_alloc.c index b306fc3731..528ee2da92 100644 --- a/src/backend/utils/mmgr/sb_alloc.c +++ b/src/backend/utils/mmgr/sb_alloc.c @@ -306,12 +306,27 @@ sb_free(void *ptr) LWLockAcquire(lock, LW_EXCLUSIVE); } - /* XXX. What about large objects? */ - /* Compute the object size. */ size_class = span->size_class; obsize = sb_size_classes[size_class]; + /* If it's a large object, free the entire span. */ + if (size_class == SB_SCLASS_SPAN_LARGE) + { + sb_heap *heap = relptr_access(base, span->parent); + Size first_page; + + sb_unlink_span(base, heap, span); + first_page = fpm_pointer_to_page(fpm_base, + relptr_access(base, span->start)); + FreePageManagerPut(region->fpm, first_page, span->npages); + sb_free(span); + + /* We're done, but must release any lock first. */ + if (lock != NULL) + LWLockRelease(lock); + } + /* Put the object on the superblock's freelist. */ superblock = relptr_access(base, span->start); Assert(((char *) ptr) >= superblock); @@ -321,17 +336,17 @@ sb_free(void *ptr) span->firstfree = (((char *) ptr) - superblock) / obsize; span->nallocatable++; - /* - * If the superblock was previously completely full, we need to move it - * out of the highest-numbered fullness class so that it can potentially - * be used for new allocations. - */ if (span->nallocatable == 1 && span->fclass == SB_FULLNESS_CLASSES - 1) { sb_heap *heap = relptr_access(base, span->parent); sb_span *new_nextspan; - /* Move to next lower-numbered list. */ + /* + * The superblock is completely full and is located in the + * highest-numbered fullness class, which is never scanned for free + * chunks. We must move it to the next-lower fullness class. + */ + sb_unlink_span(base, heap, span); span->fclass = SB_FULLNESS_CLASSES - 2; relptr_copy(span->nextspan, heap->spans[SB_FULLNESS_CLASSES - 2]); @@ -342,11 +357,20 @@ sb_free(void *ptr) relptr_store(base, new_nextspan->prevspan, span); relptr_store(base, heap->spans[SB_FULLNESS_CLASSES - 2], span); } - else if (span->nallocatable == span->nmax) + else if (span->nallocatable == span->nmax && (span->fclass != 1 || + !relptr_is_null(span->prevspan))) { sb_heap *heap = relptr_access(base, span->parent); Size first_page; + /* + * This entire superblock is free, and it's not the active superblock + * for this size class. Return the memory to the free page manager. + * We don't do this for the active superblock to prevent hysteresis: + * if we repeatedly allocate and free the only chunk in the active + * superblock, it will be very inefficient if we deallocate and + * reallocate the superblock every time. + */ sb_unlink_span(base, heap, span); first_page = fpm_pointer_to_page(fpm_base, relptr_access(base, span->start));