From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp56.i.mail.ru (smtp56.i.mail.ru [217.69.128.36]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id D9A464765E1 for ; Tue, 29 Dec 2020 14:03:43 +0300 (MSK) From: mechanik20051988 Date: Tue, 29 Dec 2020 14:03:32 +0300 Message-Id: <05164208e6bb872d94fc06314d1405a895f61e1d.1609239402.git.mechanik20051988@tarantool.org> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 4/4] Implement system allocator, based on malloc List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org, alyapunov@tarantool.org Cc: tarantool-patches@dev.tarantool.org --- src/box/CMakeLists.txt | 2 + src/box/lua/slab.cc | 44 ++++- src/box/memtx_engine.cc | 30 +++- src/box/memtx_space.cc | 6 +- src/box/sysalloc.c | 210 +++++++++++++++++++++++ src/box/sysalloc.h | 145 ++++++++++++++++ src/box/system_allocator.cc | 68 ++++++++ src/box/system_allocator.h | 54 ++++++ test/box/choose_memtx_allocator.lua | 9 + test/box/choose_memtx_allocator.result | 139 +++++++++++++++ test/box/choose_memtx_allocator.test.lua | 44 +++++ 11 files changed, 741 insertions(+), 10 deletions(-) create mode 100644 src/box/sysalloc.c create mode 100644 src/box/sysalloc.h create mode 100644 src/box/system_allocator.cc create mode 100644 src/box/system_allocator.h create mode 100644 test/box/choose_memtx_allocator.lua create mode 100644 test/box/choose_memtx_allocator.result create mode 100644 test/box/choose_memtx_allocator.test.lua diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index aebf76bd4..55fb14d0a 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -130,6 +130,8 @@ add_library(box STATIC memtx_engine.cc memtx_space.cc small_allocator.cc + system_allocator.cc + sysalloc.c sysview.c blackhole.c service_engine.c diff --git a/src/box/lua/slab.cc b/src/box/lua/slab.cc index 4b247885f..c4fdd35c4 100644 --- a/src/box/lua/slab.cc +++ b/src/box/lua/slab.cc @@ -44,14 +44,18 @@ #include "box/engine.h" #include "box/memtx_engine.h" #include "box/small_allocator.h" - -static int -small_stats_noop_cb(const struct mempool_stats *stats, void *cb_ctx) -{ - (void) stats; - (void) cb_ctx; - return 0; +#include "box/system_allocator.h" + +#define STATS_NOOP_CB(allocator, cb_stats) \ +static int \ +allocator##_stats_noop_cb(const struct cb_stats *stats, void *cb_ctx) \ +{ \ + (void) stats; \ + (void) cb_ctx; \ + return 0; \ } +STATS_NOOP_CB(small, mempool_stats) +STATS_NOOP_CB(system, system_stats) static int small_stats_lua_cb(const struct mempool_stats *stats, void *cb_ctx) @@ -103,6 +107,25 @@ small_stats_lua_cb(const struct mempool_stats *stats, void *cb_ctx) return 0; } +static int +system_stats_lua_cb(const struct system_stats *stats, void *cb_ctx) +{ + struct lua_State *L = (struct lua_State *) cb_ctx; + lua_pushnumber(L, lua_objlen(L, -1) + 1); + lua_newtable(L); + luaL_setmaphint(L, -1); + lua_pushstring(L, "mem_used"); + luaL_pushuint64(L, stats->used); + lua_settable(L, -3); + + lua_pushstring(L, "mem_free"); + luaL_pushuint64(L, stats->total - stats->used); + lua_settable(L, -3); + lua_settable(L, -3); + return 0; +} + + template static int @@ -120,7 +143,7 @@ lbox_slab_stats(struct lua_State *L) Allocator::stats(&totals, stats_cb, L); struct mempool_stats index_stats; mempool_stats(&memtx->index_extent_pool, &index_stats); - stats_cb(&index_stats, L); + small_stats_lua_cb(&index_stats, L); return 1; } @@ -282,6 +305,11 @@ box_lua_slab_init(struct lua_State *L) struct mempool_stats, SmallAllocator, small_stats_noop_cb, small_stats_lua_cb>(L); break; + case MEMTX_SYSTEM_ALLOCATOR: + box_lua_slab_init(L); + break; default: ; } diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc index 48c0f13d0..526187062 100644 --- a/src/box/memtx_engine.cc +++ b/src/box/memtx_engine.cc @@ -51,6 +51,7 @@ #include "gc.h" #include "raft.h" #include "small_allocator.h" +#include "system_allocator.h" /* sync snapshot every 16MB */ #define SNAP_SYNC_INTERVAL (1 << 24) @@ -155,6 +156,8 @@ memtx_engine_shutdown(struct engine *engine) case MEMTX_SMALL_ALLOCATOR: SmallAllocator::destroy(); break; + case MEMTX_SYSTEM_ALLOCATOR: + SystemAllocator::destroy(); default: ; } @@ -994,6 +997,14 @@ small_stats_noop_cb(const struct mempool_stats *stats, void *cb_ctx) return 0; } +static int +system_stats_noop_cb(const struct system_stats *stats, void *cb_ctx) +{ + (void)stats; + (void)cb_ctx; + return 0; +} + template static void @@ -1100,6 +1111,14 @@ memtx_engine_new(const char *snap_dirname, bool force_recovery, struct mempool_stats, SmallAllocator, small_stats_noop_cb>; + } else if (!strcmp(allocator, "system")) { + memtx->allocator_type = MEMTX_SYSTEM_ALLOCATOR; + MEMXT_TUPLE_FORMAT_VTAB(SystemAllocator) + memtx_engine_vtab.memory_stat = + memtx_engine_memory_stat; } else { diag_set(IllegalParams, "Invalid memory allocator name"); free(memtx); @@ -1171,6 +1190,9 @@ memtx_engine_new(const char *snap_dirname, bool force_recovery, say_info("Actual slab_alloc_factor calculated on the basis of desired " "slab_alloc_factor = %f", actual_alloc_factor); break; + case MEMTX_SYSTEM_ALLOCATOR: + SystemAllocator::create(&memtx->arena); + break; default: ; } @@ -1242,6 +1264,9 @@ memtx_enter_delayed_free_mode(struct memtx_engine *memtx) case MEMTX_SMALL_ALLOCATOR: SmallAllocator::enter_delayed_free_mode(); break; + case MEMTX_SYSTEM_ALLOCATOR: + SystemAllocator::enter_delayed_free_mode(); + break; default: ; } @@ -1255,7 +1280,10 @@ memtx_leave_delayed_free_mode(struct memtx_engine *memtx) if (--memtx->delayed_free_mode == 0) { switch (memtx->allocator_type) { case MEMTX_SMALL_ALLOCATOR: - SmallAllocator::enter_delayed_free_mode(); + SmallAllocator::leave_delayed_free_mode(); + break; + case MEMTX_SYSTEM_ALLOCATOR: + SystemAllocator::leave_delayed_free_mode(); break; default: ; diff --git a/src/box/memtx_space.cc b/src/box/memtx_space.cc index 932b3af16..df0a7021e 100644 --- a/src/box/memtx_space.cc +++ b/src/box/memtx_space.cc @@ -1170,8 +1170,8 @@ memtx_space_prepare_alter(struct space *old_space, struct space *new_space) /* }}} DDL */ -struct SmallAllocator; #define MEMTX_SPACE_VTAB(Allocator, allocator) \ +struct Allocator; \ static const struct space_vtab memtx_space_vtab_##allocator = { \ /* .destroy = */ memtx_space_destroy, \ /* .bsize = */ memtx_space_bsize, \ @@ -1195,6 +1195,7 @@ static const struct space_vtab memtx_space_vtab_##allocator = { \ /* .invalidate = */ generic_space_invalidate, \ }; MEMTX_SPACE_VTAB(SmallAllocator, small) +MEMTX_SPACE_VTAB(SystemAllocator, system) struct space * memtx_space_new(struct memtx_engine *memtx, @@ -1231,6 +1232,9 @@ memtx_space_new(struct memtx_engine *memtx, case MEMTX_SMALL_ALLOCATOR: vtab = &memtx_space_vtab_small; break; + case MEMTX_SYSTEM_ALLOCATOR: + vtab = &memtx_space_vtab_system; + break; default: tuple_format_unref(format); free(memtx_space); diff --git a/src/box/sysalloc.c b/src/box/sysalloc.c new file mode 100644 index 000000000..40dd067ad --- /dev/null +++ b/src/box/sysalloc.c @@ -0,0 +1,210 @@ +/* + * Copyright 2010-2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sysalloc.h" + +#include +#include + +#if TARGET_OS_DARWIN +#include +static inline size_t +portable_malloc_usable_size(void *p) +{ + return malloc_size(p); +} +#elif (TARGET_OS_FREEBSD || TARGET_OS_NETBSD || TARGET_OS_OPENBSD) +#include +static inline size_t +portable_malloc_usable_size(void *p) +{ + return malloc_usable_size(p); +} +#elif TARGET_OS_LINUX +#include +static inline size_t +portable_malloc_usable_size(void *p) +{ + return malloc_usable_size(p); +} +#else +#error "Undefined system type" +#endif + +static RLIST_HEAD(alloc_list); + +static inline void +system_collect_garbage(struct system_alloc *alloc) +{ + if (alloc->free_mode != SYSTEM_COLLECT_GARBAGE) + return; + + const int BATCH = 100; + if (!lifo_is_empty(&alloc->delayed)) { + for (int i = 0; i < BATCH; i++) { + void *item = lifo_pop(&alloc->delayed); + if (item == NULL) + break; + sysfree(alloc, item, 0 /* unused parameter */); + } + } else { + /* Finish garbage collection and switch to regular mode */ + alloc->free_mode = SYSTEM_FREE; + } +} + +void +system_alloc_setopt(struct system_alloc *alloc, enum system_opt opt, bool val) +{ + switch (opt) { + case SYSTEM_DELAYED_FREE_MODE: + alloc->free_mode = val ? SYSTEM_DELAYED_FREE : + SYSTEM_COLLECT_GARBAGE; + break; + default: + assert(false); + break; + } +} + +void +system_stats(struct system_alloc *alloc, struct system_stats *totals, + system_stats_cb cb, void *cb_ctx) +{ + totals->used = pm_atomic_load_explicit(&alloc->used_bytes, + pm_memory_order_relaxed); + totals->total = quota_total(alloc->quota); + cb(totals, cb_ctx); +} + +void +system_alloc_create(struct system_alloc *alloc, struct slab_arena *arena) +{ + alloc->used_bytes = 0; + alloc->arena_bytes = 0; + alloc->arena = arena; + alloc->quota = arena->quota; + lifo_init(&alloc->delayed); + alloc->allocator_thread = pthread_self(); +} + +void +system_alloc_destroy(struct system_alloc *alloc) +{ + assert(alloc->allocator_thread == pthread_self()); + struct rlist *item, *tmp; + for (item = alloc_list.next; (item != &alloc_list) && + (tmp = item->next); item = tmp) + sysfree(alloc, ((void *)item) + sizeof(struct rlist), (~0lu)); + assert(alloc->used_bytes == 0); + uint32_t units = alloc->arena_bytes / alloc->arena->slab_size; + pm_atomic_fetch_sub(&alloc->arena->used, + units * alloc->arena->slab_size); +} + +void +sysfree(struct system_alloc *alloc, void *ptr, size_t bytes) +{ + assert(alloc->allocator_thread == pthread_self()); + ptr -= sizeof(struct rlist); + size_t size = portable_malloc_usable_size(ptr); + uint32_t s = size % QUOTA_UNIT_SIZE, units = size / QUOTA_UNIT_SIZE; + size_t used_bytes = pm_atomic_fetch_sub(&alloc->used_bytes, size); + if (small_align(used_bytes, QUOTA_UNIT_SIZE) > + small_align(used_bytes - s, QUOTA_UNIT_SIZE)) + units++; + if (units > 0) + quota_release(alloc->quota, units * QUOTA_UNIT_SIZE); + pm_atomic_fetch_add(&alloc->arena_bytes, size); + if (bytes != (~0lu)) + rlist_del((struct rlist *)ptr); + free(ptr); +} + +void +sysfree_delayed(struct system_alloc *alloc, void *ptr, size_t bytes) +{ + assert(alloc->allocator_thread == pthread_self()); + if (alloc->free_mode == SYSTEM_DELAYED_FREE && ptr) { + lifo_push(&alloc->delayed, ptr); + } else { + sysfree(alloc, ptr, bytes); + } +} + +void * +sysalloc(struct system_alloc *alloc, size_t bytes) +{ + assert(alloc->allocator_thread == pthread_self()); + system_collect_garbage(alloc); + + void *ptr = malloc(sizeof(struct rlist) + bytes); + if (!ptr) + return NULL; + size_t size = portable_malloc_usable_size(ptr); + uint32_t s = size % QUOTA_UNIT_SIZE, units = size / QUOTA_UNIT_SIZE; + while (1) { + size_t used_bytes = pm_atomic_load(&alloc->used_bytes); + if (small_align(used_bytes, QUOTA_UNIT_SIZE) < + small_align(used_bytes + s, QUOTA_UNIT_SIZE)) + units++; + if (units > 0) { + if (quota_use(alloc->quota, + units * QUOTA_UNIT_SIZE) < 0) { + free(ptr); + return NULL; + } + } + if (pm_atomic_compare_exchange_strong(&alloc->used_bytes, + &used_bytes, used_bytes + size)) + break; + if (units > 0) + quota_release(alloc->quota, units * QUOTA_UNIT_SIZE); + } + + size_t arena_bytes; + do { + while (size > (arena_bytes = pm_atomic_load(&alloc->arena_bytes))) { + uint32_t units = (size - arena_bytes) / + alloc->arena->slab_size + 1; + if (!pm_atomic_compare_exchange_strong(&alloc->arena_bytes, + &arena_bytes, arena_bytes + + units * alloc->arena->slab_size)) + continue; + pm_atomic_fetch_add(&alloc->arena->used, + units * alloc->arena->slab_size); + } + } while (!pm_atomic_compare_exchange_strong(&alloc->arena_bytes, + &arena_bytes, arena_bytes - size)); + + rlist_add_tail(&alloc_list, (struct rlist *)ptr); + return ptr + sizeof(struct rlist); +} + diff --git a/src/box/sysalloc.h b/src/box/sysalloc.h new file mode 100644 index 000000000..bd906c8cf --- /dev/null +++ b/src/box/sysalloc.h @@ -0,0 +1,145 @@ +#pragma once +/* + * Copyright 2010-2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +enum system_opt { + SYSTEM_DELAYED_FREE_MODE +}; + +/** + * Free mode + */ +enum system_free_mode { + /** Free objects immediately. */ + SYSTEM_FREE, + /** Collect garbage after delayed free. */ + SYSTEM_COLLECT_GARBAGE, + /** Postpone deletion of objects. */ + SYSTEM_DELAYED_FREE, +}; + +struct system_alloc { + /** + * Bytes allocated by system allocator + */ + uint64_t used_bytes; + /** + * Arena free bytes + */ + uint64_t arena_bytes; + /** + * Allocator arena + */ + struct slab_arena *arena; + /** + * Allocator quota + */ + struct quota *quota; + /** + * Free mode. + */ + enum system_free_mode free_mode; + /** + * List of pointers for delayed free. + */ + struct lifo delayed; + /** + * Allocator thread + */ + pthread_t allocator_thread; +}; + +struct system_stats { + size_t used; + size_t total; +}; + +typedef int (*system_stats_cb)(const struct system_stats *stats, + void *cb_ctx); + +/** Initialize a system memory allocator. */ +void +system_alloc_create(struct system_alloc *alloc, struct slab_arena *arena); + +/** + * Enter or leave delayed mode - in delayed mode sysfree_delayed() + * doesn't free memory but puts them into a list, for futher deletion. + */ + void +system_alloc_setopt(struct system_alloc *alloc, enum system_opt opt, bool val); + +/** + * Destroy the allocator, the destruction of + * all allocated memory is on the user's conscience. + */ +void +system_alloc_destroy(struct system_alloc *alloc); + +/** + * Allocate memory in the system allocator, using malloc. + */ +void * +sysalloc(struct system_alloc *alloc, size_t bytes); + +/** + * Free memory in the system allocator, using feee. + */ +void +sysfree(struct system_alloc *alloc, void *ptr, MAYBE_UNUSED size_t bytes); + +/** + * Free memory allocated by the system allocator + * if not in snapshot mode, otherwise put to the delayed + * free list. + */ +void +sysfree_delayed(struct system_alloc *alloc, void *ptr, size_t bytes); + +/** + * Get system allocator statistic + */ +void +system_stats(struct system_alloc *alloc, struct system_stats *totals, + system_stats_cb cb, void *cb_ctx); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ diff --git a/src/box/system_allocator.cc b/src/box/system_allocator.cc new file mode 100644 index 000000000..8b9e3114b --- /dev/null +++ b/src/box/system_allocator.cc @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "system_allocator.h" + +void +SystemAllocator::create(struct slab_arena *arena) +{ + system_alloc_create(&system_alloc, arena); +} + +void +SystemAllocator::destroy(void) +{ + system_alloc_destroy(&system_alloc); +} + +void +SystemAllocator::enter_delayed_free_mode(void) +{ + system_alloc_setopt(&system_alloc, SYSTEM_DELAYED_FREE_MODE, true); +} + +void +SystemAllocator::leave_delayed_free_mode(void) +{ + system_alloc_setopt(&system_alloc, SYSTEM_DELAYED_FREE_MODE, false); +} + +void +SystemAllocator::stats(struct system_stats *stats, system_stats_cb cb, void *cb_ctx) +{ + system_stats(&system_alloc, stats, cb, cb_ctx); +} + +void +SystemAllocator::memory_check(void) +{ +} + +struct system_alloc SystemAllocator::system_alloc; diff --git a/src/box/system_allocator.h b/src/box/system_allocator.h new file mode 100644 index 000000000..aed4e0fc9 --- /dev/null +++ b/src/box/system_allocator.h @@ -0,0 +1,54 @@ +#pragma once +/* + * Copyright 2010-2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sysalloc.h" + +struct SystemAllocator +{ + static void create(struct slab_arena *arena); + static void destroy(void); + static void enter_delayed_free_mode(void); + static void leave_delayed_free_mode(void); + static void stats(struct system_stats *stats, system_stats_cb cb, void *cb_ctx); + static void memory_check(void); + static inline void *alloc(size_t size) { + return sysalloc(&system_alloc, size); + }; + static inline void free(void *ptr, size_t size) { + sysfree(&system_alloc, ptr, size); + } + static inline void free_delayed(void *ptr, size_t size) { + sysfree_delayed(&system_alloc, ptr, size); + } + + /** Tuple allocator. */ + static struct system_alloc system_alloc; +}; diff --git a/test/box/choose_memtx_allocator.lua b/test/box/choose_memtx_allocator.lua new file mode 100644 index 000000000..d56f985e1 --- /dev/null +++ b/test/box/choose_memtx_allocator.lua @@ -0,0 +1,9 @@ +#!/usr/bin/env tarantool + +require('console').listen(os.getenv('ADMIN')) + +box.cfg({ + listen = os.getenv("LISTEN"), + allocator=arg[1], + checkpoint_interval=5 +}) diff --git a/test/box/choose_memtx_allocator.result b/test/box/choose_memtx_allocator.result new file mode 100644 index 000000000..23660be6e --- /dev/null +++ b/test/box/choose_memtx_allocator.result @@ -0,0 +1,139 @@ +-- test-run result file version 2 + +-- write data recover from latest snapshot +env = require('test_run') + | --- + | ... +test_run = env.new() + | --- + | ... +test_run:cmd('create server test with script="box/choose_memtx_allocator.lua"') + | --- + | - true + | ... +--test small allocator +test_run:cmd('start server test with args="small"') + | --- + | - true + | ... +test_run:cmd('switch test') + | --- + | - true + | ... +space = box.schema.space.create('test') + | --- + | ... +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) + | --- + | ... +s = space:create_index('primary', { parts = {'id'} }) + | --- + | ... +for key = 1, 1000 do space:insert({key, key + 1000}) end + | --- + | ... +for key = 1, 1000 do space:replace({key, key + 5000}) end + | --- + | ... +box.snapshot() + | --- + | - ok + | ... +for key = 1, 1000 do space:delete(key) end + | --- + | ... +space:drop() + | --- + | ... +test_run:cmd('switch default') + | --- + | - true + | ... +test_run:cmd('stop server test') + | --- + | - true + | ... +--test system(malloc) allocator +test_run:cmd('start server test with args="system"') + | --- + | - true + | ... +test_run:cmd('switch test') + | --- + | - true + | ... +space = box.schema.space.create('test') + | --- + | ... +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) + | --- + | ... +s = space:create_index('primary', { parts = {'id'} }) + | --- + | ... +for key = 1, 200000 do space:insert({key, key + 1000}) end + | --- + | ... +for key = 1, 200000 do space:replace({key, key + 5000}) end + | --- + | ... +for key = 1, 200000 do space:delete(key) end + | --- + | ... +space:drop() + | --- + | ... +test_run:cmd('switch default') + | --- + | - true + | ... +test_run:cmd('stop server test') + | --- + | - true + | ... +--test default (small) allocator +test_run:cmd('start server test') + | --- + | - true + | ... +test_run:cmd('switch test') + | --- + | - true + | ... +space = box.schema.space.create('test') + | --- + | ... +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) + | --- + | ... +s = space:create_index('primary', { parts = {'id'} }) + | --- + | ... +for key = 1, 1000 do space:insert({key, key + 1000}) end + | --- + | ... +for key = 1, 1000 do space:replace({key, key + 5000}) end + | --- + | ... +for key = 1, 1000 do space:delete(key) end + | --- + | ... +space:drop() + | --- + | ... +test_run:cmd('switch default') + | --- + | - true + | ... +test_run:cmd('stop server test') + | --- + | - true + | ... +test_run:cmd('cleanup server test') + | --- + | - true + | ... +test_run:cmd('delete server test') + | --- + | - true + | ... diff --git a/test/box/choose_memtx_allocator.test.lua b/test/box/choose_memtx_allocator.test.lua new file mode 100644 index 000000000..25d43c781 --- /dev/null +++ b/test/box/choose_memtx_allocator.test.lua @@ -0,0 +1,44 @@ + +-- write data recover from latest snapshot +env = require('test_run') +test_run = env.new() +test_run:cmd('create server test with script="box/choose_memtx_allocator.lua"') +--test small allocator +test_run:cmd('start server test with args="small"') +test_run:cmd('switch test') +space = box.schema.space.create('test') +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) +s = space:create_index('primary', { parts = {'id'} }) +for key = 1, 1000 do space:insert({key, key + 1000}) end +for key = 1, 1000 do space:replace({key, key + 5000}) end +box.snapshot() +for key = 1, 1000 do space:delete(key) end +space:drop() +test_run:cmd('switch default') +test_run:cmd('stop server test') +--test system(malloc) allocator +test_run:cmd('start server test with args="system"') +test_run:cmd('switch test') +space = box.schema.space.create('test') +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) +s = space:create_index('primary', { parts = {'id'} }) +for key = 1, 200000 do space:insert({key, key + 1000}) end +for key = 1, 200000 do space:replace({key, key + 5000}) end +for key = 1, 200000 do space:delete(key) end +space:drop() +test_run:cmd('switch default') +test_run:cmd('stop server test') +--test default (small) allocator +test_run:cmd('start server test') +test_run:cmd('switch test') +space = box.schema.space.create('test') +space:format({ {name = 'id', type = 'unsigned'}, {name = 'year', type = 'unsigned'} }) +s = space:create_index('primary', { parts = {'id'} }) +for key = 1, 1000 do space:insert({key, key + 1000}) end +for key = 1, 1000 do space:replace({key, key + 5000}) end +for key = 1, 1000 do space:delete(key) end +space:drop() +test_run:cmd('switch default') +test_run:cmd('stop server test') +test_run:cmd('cleanup server test') +test_run:cmd('delete server test') -- 2.20.1