[Tarantool-patches] [PATCH 4/4] Implement system allocator, based on malloc
mechanik20051988
mechanik20051988 at tarantool.org
Tue Dec 29 14:03:32 MSK 2020
---
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 <class allocator_stats, class cb_stats, class Allocator,
int (*stats_cb)(const cb_stats *stats, void *cb_ctx)>
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<struct system_stats,
+ struct system_stats, SystemAllocator,
+ system_stats_noop_cb, system_stats_lua_cb>(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 <class allocator_stats, class cb_stats, class Allocator,
int (*stats_cb)(const cb_stats *stats, void *cb_ctx)>
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<struct system_stats,
+ struct system_stats,
+ SystemAllocator,
+ system_stats_noop_cb>;
} 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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 <small/slab_arena.h>
+#include <small/rlist.h>
+
+#if TARGET_OS_DARWIN
+#include <malloc/malloc.h>
+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 <malloc_np.h>
+static inline size_t
+portable_malloc_usable_size(void *p)
+{
+ return malloc_usable_size(p);
+}
+#elif TARGET_OS_LINUX
+#include <malloc.h>
+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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 <pthread.h>
+#include <trivia/util.h>
+#include <trivia/config.h>
+#include <small/slab_arena.h>
+#include <small/quota.h>
+#include <small/lifo.h>
+
+#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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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
More information about the Tarantool-patches
mailing list