From cb644f2894f2fdd66a2fd9d4603e017eeffcd9b5 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Fri, 15 Aug 2014 19:31:45 +0400 Subject: [PATCH] Fixes gh-378 "assertion failed" Do not align maxalloc (the limit on the amount of memory used by the allocator), it's not necessary. Make an effort to correctly align large (for 32 bit) prealloc values (like, a few gigs). --- src/lib/small/slab_arena.c | 25 +++++++++++-------------- src/lib/small/slab_arena.h | 14 +++++++++++--- test/unit/slab_arena.result | 12 ++++++------ test/wal/oom.result | 12 ++++++------ 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/lib/small/slab_arena.c b/src/lib/small/slab_arena.c index 6d30c355d0..0d3a6e301e 100644 --- a/src/lib/small/slab_arena.c +++ b/src/lib/small/slab_arena.c @@ -54,9 +54,10 @@ munmap_checked(void *addr, size_t size) static void * mmap_checked(size_t size, size_t align, int flags) { - /* The size must be a power of two. */ - assert((size & (size - 1)) == 0); + /* The alignment must be a power of two. */ assert((align & (align - 1)) == 0); + /* The size must be a multiple of alignment */ + assert((size & (align - 1)) == 0); /* * mmap twice the requested amount to be able to align * the mapped address. @@ -101,6 +102,7 @@ pow2round(size_t size) #endif #define MAX(a, b) (a) > (b) ? (a) : (b) +#define MIN(a, b) (a) < (b) ? (a) : (b) int slab_arena_create(struct slab_arena *arena, @@ -116,18 +118,13 @@ slab_arena_create(struct slab_arena *arena, */ arena->slab_size = small_round(MAX(slab_size, SLAB_MIN_SIZE)); - if (maxalloc) { - arena->maxalloc = small_round(MAX(maxalloc, - arena->slab_size)); - } else { - arena->maxalloc = 0; - } - - /* Align arena around a fixed number of slabs. */ - arena->prealloc = small_align(small_round(prealloc), - arena->slab_size); - if (arena->maxalloc < arena->prealloc) - arena->prealloc = arena->maxalloc; + arena->maxalloc = maxalloc; + /** Prealloc can not be greater than maxalloc */ + prealloc = MIN(prealloc, maxalloc); + /** Extremely large sizes can not be aligned properly */ + prealloc = MIN(prealloc, SIZE_MAX - arena->slab_size); + /* Align prealloc around a fixed number of slabs. */ + arena->prealloc = small_align(prealloc, arena->slab_size); arena->used = 0; diff --git a/src/lib/small/slab_arena.h b/src/lib/small/slab_arena.h index 1531b816d7..322fb80a08 100644 --- a/src/lib/small/slab_arena.h +++ b/src/lib/small/slab_arena.h @@ -36,8 +36,12 @@ extern "C" { #endif /* defined(__cplusplus) */ -enum { SLAB_MIN_SIZE = USHRT_MAX, - SMALL_UNLIMITED = SIZE_MAX/2 + 1}; +enum { + /* Smallest possible slab size. */ + SLAB_MIN_SIZE = USHRT_MAX, + /** The largest allowed amount of memory of a single arena. */ + SMALL_UNLIMITED = SIZE_MAX/2 + 1 +}; /** * slab_arena -- a source of large aligned blocks of memory. @@ -121,7 +125,11 @@ slab_arena_mprotect(struct slab_arena *arena); static inline size_t small_align(size_t size, size_t alignment) { - return (size + alignment - 1) & ~(alignment - 1); + /* Must be a power of two */ + assert((alignment & (alignment - 1)) == 0); + /* Bit arithmetics won't work for a large size */ + assert(size <= SIZE_MAX - alignment); + return (size - 1 + alignment) & ~(alignment - 1); } /** Round a number to the nearest power of two. */ diff --git a/test/unit/slab_arena.result b/test/unit/slab_arena.result index b8ec4d8b0b..5af7304e74 100644 --- a/test/unit/slab_arena.result +++ b/test/unit/slab_arena.result @@ -3,23 +3,23 @@ arena->maxalloc = 0 arena->used = 0 arena->slab_size = 65536 arena->prealloc = 65536 -arena->maxalloc = 65536 +arena->maxalloc = 1 arena->used = 0 arena->slab_size = 65536 arena->prealloc = 65536 -arena->maxalloc = 65536 +arena->maxalloc = 1 arena->used = 65536 arena->slab_size = 65536 going beyond the limit: (nil) arena->prealloc = 65536 -arena->maxalloc = 65536 +arena->maxalloc = 1 arena->used = 65536 arena->slab_size = 65536 arena->prealloc = 65536 -arena->maxalloc = 65536 +arena->maxalloc = 1 arena->used = 65536 arena->slab_size = 65536 -arena->prealloc = 2097152 -arena->maxalloc = 4194304 +arena->prealloc = 2031616 +arena->maxalloc = 3000000 arena->used = 0 arena->slab_size = 65536 diff --git a/test/wal/oom.result b/test/wal/oom.result index 9c14e32bfa..089a7c863c 100644 --- a/test/wal/oom.result +++ b/test/wal/oom.result @@ -15,11 +15,11 @@ while true do i = i + 1 end; --- -- error: Failed to allocate 313 bytes in slab allocator for tuple +- error: Failed to allocate 268 bytes in slab allocator for tuple ... space:len(); --- -- 73 +- 62 ... i = 1; --- @@ -29,11 +29,11 @@ while true do i = i + 1 end; --- -- error: Failed to allocate 314 bytes in slab allocator for tuple +- error: Failed to allocate 268 bytes in slab allocator for tuple ... space:len(); --- -- 146 +- 124 ... i = 1; --- @@ -43,12 +43,12 @@ while true do i = i + 1 end; --- -- error: Failed to allocate 314 bytes in slab allocator for tuple +- error: Failed to allocate 265 bytes in slab allocator for tuple ... --# setopt delimiter '' space:len() --- -- 219 +- 185 ... space.index['primary']:get{0} --- -- GitLab