Skip to content

Commit

Permalink
memcached: use own slab arena
Browse files Browse the repository at this point in the history
Historically memcached module uses slab cache created by Tarantool.
Fibers get access to it via call of function cord_slab_cache() that is a
part of Tarantool C API. The problem is happen when memcached and
Tarantool use different versions of Small library where ABI is broken.
Issues #59 and #96 are examples of such problems.

We decided use independent slab arena in memcached module to avoid such
problems in future and this patch implements it.

Below I'll describe what is important in switching to own arena.

memcached module uses different types of Small's allocators (ibuf and
obuf used for every network connection, one slab cache used per fiber).
There are two important things with used Small's allocators:

1. some allocators depends on other and sequence of allocations should
   be correct. README in small source code repository has a clear
   description of relationships between allocators [1].
2. some allocators are thread-safe and others not. slab arena is shared
   between all memcached instances, when slab cache allocated on top of
   slab arena is not thread-safe and must be used in scope of fiber.

memcached performs memory allocations and deallocations on different
stages and I would list all these stages explicitly:

- memcached module initialization
- memcached module deinitialization
- memcached instance gc
- memcached instance initialization
- memcached instance start
- memcached instance stop
- memcached instance deinitialization

Most part of these cases covered in tests
test/common/instance_api.test.lua and test/common/module_api.test.lua
that were added in previous commits. The exception here is gc that was
checked manually.

1. https://github.com/tarantool/small

Fixes #96
  • Loading branch information
ligurio committed Feb 11, 2022
1 parent 022a32b commit 2fdbaf0
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 9 deletions.
7 changes: 4 additions & 3 deletions memcached/internal/alloc.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#include <tarantool/module.h>
#include <small/slab_cache.h>

#include "memcached_persistent.h"

extern __thread struct slab_cache slabc;

void *
box_persistent_malloc(size_t len, size_t *total)
{
struct slab *slab = slab_get(cord_slab_cache(), len);
struct slab *slab = slab_get(&slabc, len);
char *ptr = NULL; size_t sz = 0;
if (slab != NULL) {
ptr = slab_data(slab);
Expand All @@ -28,7 +29,7 @@ box_persistent_malloc0(size_t len, size_t *total)

void
box_persistent_free(void *ptr) {
if (ptr) slab_put(cord_slab_cache(), slab_from_data(ptr));
if (ptr) slab_put(&slabc, slab_from_data(ptr));
}

void *
Expand Down
51 changes: 49 additions & 2 deletions memcached/internal/memcached.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
#include <unistd.h>
#include <inttypes.h>
#include <stdbool.h>
#include <limits.h>

#include <tarantool/module.h>
#include <small/ibuf.h>
#include <small/obuf.h>
#include <small/quota.h>

#include "memcached.h"
#include "memcached_layer.h"
Expand All @@ -46,6 +48,44 @@
#include "expiration.h"
#include "mc_sasl.h"

__thread struct slab_cache slabc;
struct quota quota;
struct slab_arena arena;

void
memcached_slab_arena_create()
{
static __thread bool inited = false;
if (inited) return;
quota_init(&quota, UINT_MAX);
/* Parameters are the same as in src/lib/core/fiber.c */
const size_t SLAB_SIZE = 4 * 1024 * 1024;
slab_arena_create(&arena, &quota, 0, SLAB_SIZE, SLAB_ARENA_PRIVATE);
inited = 1;
}

void
memcached_slab_arena_destroy()
{
slab_arena_destroy(&arena);
}

void
memcached_slab_cache_create()
{
static __thread bool inited = false;
if (inited) return;
slab_cache_set_thread(&slabc);
slab_cache_create(&slabc, &arena);
inited = 1;
}

void
memcached_slab_cache_destroy()
{
slab_cache_destroy(&slabc);
}

static inline int
memcached_skip_request(struct memcached_connection *con) {
struct ibuf *in = con->in;
Expand Down Expand Up @@ -219,6 +259,9 @@ memcached_loop(struct memcached_connection *con)
void
memcached_handler(struct memcached_service *p, int fd)
{
memcached_slab_cache_create();
iobuf_mempool_create();

struct memcached_connection con;
/* TODO: move to connection_init */
memset(&con, 0, sizeof(struct memcached_connection));
Expand Down Expand Up @@ -250,7 +293,7 @@ memcached_handler(struct memcached_service *p, int fd)
assert(0); /* unreacheable */
}

region_create(&con.gc, cord_slab_cache());
region_create(&con.gc, &slabc);

/* read-write cycle */
con.cfg->stat.curr_conns++;
Expand All @@ -265,12 +308,13 @@ memcached_handler(struct memcached_service *p, int fd)
const box_error_t *err = box_error_last();
if (err)
say_error("%s", box_error_message(err));

memcached_slab_cache_destroy();
}

struct memcached_service*
memcached_create(const char *name, uint32_t sid)
{
iobuf_mempool_create();
memcached_sasl_init();
struct memcached_service *srv = (struct memcached_service *)
calloc(1, sizeof(struct memcached_service));
Expand Down Expand Up @@ -306,6 +350,8 @@ memcached_free(struct memcached_service *srv)
int
memcached_start (struct memcached_service *srv)
{
memcached_slab_arena_create();

/* Run expiration fiber only if expire_enabled is true */
if (srv->expire_enabled == true && memcached_expire_start(srv) == -1)
return -1;
Expand All @@ -318,6 +364,7 @@ memcached_stop (struct memcached_service *srv)
memcached_expire_stop(srv);
while (srv->stat.curr_conns != 0)
fiber_sleep(0.001);
memcached_slab_arena_destroy();
}

void
Expand Down
9 changes: 5 additions & 4 deletions memcached/internal/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define IOV_MAX UIO_MAXIOV
#endif

extern __thread struct slab_cache slabc;
static __thread struct mempool ibuf_pool, obuf_pool;

static int iobuf_readahead = 16320;
Expand All @@ -31,8 +32,8 @@ iobuf_mempool_create()
{
static __thread bool inited = false;
if (inited) return;
mempool_create(&ibuf_pool, cord_slab_cache(), sizeof(struct ibuf));
mempool_create(&obuf_pool, cord_slab_cache(), sizeof(struct obuf));
mempool_create(&ibuf_pool, &slabc, sizeof(struct ibuf));
mempool_create(&obuf_pool, &slabc, sizeof(struct obuf));
inited = 1;
}

Expand All @@ -48,7 +49,7 @@ ibuf_new()
{
void *ibuf = mempool_alloc(&ibuf_pool);
if (ibuf == NULL) return NULL;
ibuf_create((struct ibuf *)ibuf, cord_slab_cache(), iobuf_readahead);
ibuf_create((struct ibuf *)ibuf, &slabc, iobuf_readahead);
return ibuf;
}

Expand All @@ -57,7 +58,7 @@ obuf_new()
{
void *obuf = mempool_alloc(&obuf_pool);
if (obuf == NULL) return NULL;
obuf_create((struct obuf *)obuf, cord_slab_cache(), iobuf_readahead);
obuf_create((struct obuf *)obuf, &slabc, iobuf_readahead);
return obuf;
}

Expand Down

0 comments on commit 2fdbaf0

Please sign in to comment.