Skip to content
Snippets Groups Projects
Commit bc88b325 authored by mechanik20051988's avatar mechanik20051988 Committed by Nikita Pettik
Browse files

memtx: implement system allocator, based on malloc

Slab allocator, which is used for tuples allocation,
has a certain disadvantage - it tends to unresolvable
fragmentation on certain workloads (size migration).
In this case user should be able to choose other allocator.
System allocator based on malloc function, but restricted
by the same qouta as slab allocator. System allocator
does not alloc all memory at start, istead, it allocate
memory as needed, checking that quota is not exceeded.
Part of #5419
parent 94e137bc
No related branches found
No related tags found
No related merge requests found
......@@ -132,6 +132,7 @@ add_library(box STATIC
memtx_engine.cc
memtx_space.c
sysview.c
sysalloc.c
blackhole.c
service_engine.c
session_settings.c
......
......@@ -30,6 +30,7 @@
* SUCH DAMAGE.
*/
#include <small/small.h>
#include "sysalloc.h"
struct alloc_stats {
size_t used;
......@@ -88,3 +89,37 @@ class SmallAlloc
private:
static struct small_alloc small_alloc;
};
class SysAlloc
{
public:
static inline void
create(struct quota *quota)
{
sys_alloc_create(&sys_alloc, quota);
}
static inline void
destroy(void)
{
sys_alloc_destroy(&sys_alloc);
}
static inline void *
alloc(size_t size)
{
return sysalloc(&sys_alloc, size);
};
static inline void
free(void *ptr, size_t size)
{
return sysfree(&sys_alloc, ptr, size);
}
static inline void
stats(struct alloc_stats *alloc_stats)
{
struct sys_stats data_stats;
sys_stats(&sys_alloc, &data_stats);
alloc_stats->used = data_stats.used;
}
private:
static struct sys_alloc sys_alloc;
};
/*
* 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/quota.h>
struct container {
struct rlist rlist;
size_t bytes;
};
void
sys_alloc_create(struct sys_alloc *alloc, struct quota *quota)
{
alloc->used_bytes = 0;
alloc->quota = quota;
rlist_create(&alloc->allocations);
#ifndef _NDEBUG
alloc->thread_id = pthread_self();
#endif
}
void
sys_alloc_destroy(struct sys_alloc *alloc)
{
assert(pthread_equal(alloc->thread_id, pthread_self()));
struct container *item, *tmp;
rlist_foreach_entry_safe(item, &alloc->allocations, rlist, tmp)
sysfree(alloc, ((void *)item) + sizeof(struct container), item->bytes);
assert(alloc->used_bytes == 0);
}
void *
sysalloc(struct sys_alloc *alloc, size_t bytes)
{
assert(pthread_equal(alloc->thread_id, pthread_self()));
void *ptr = malloc(sizeof(struct container) + bytes);
if (ptr == NULL)
return NULL;
/*
* The limit on the amount of memory available to allocator
* is stored in struct quota. We request from the quota at least
* QUOTA_UNIT_SIZE bytes. Divide the requested bytes into two parts:
* integer number of blocks by QUOTA_UNIT_SIZE bytes and remaining
* bytes count.
*/
size_t remaining = bytes % QUOTA_UNIT_SIZE;
size_t units = bytes / QUOTA_UNIT_SIZE;
/*
* Check that we need one more quota block for remaining bytes
*/
if (small_align(alloc->used_bytes, QUOTA_UNIT_SIZE) <
small_align(alloc->used_bytes + remaining, QUOTA_UNIT_SIZE))
units++;
if (units > 0 &&
quota_use(alloc->quota, units * QUOTA_UNIT_SIZE) < 0) {
free(ptr);
return NULL;
}
alloc->used_bytes += bytes;
((struct container *)ptr)->bytes = bytes;
rlist_add_entry(&alloc->allocations, (struct container *)ptr, rlist);
return ptr + sizeof(struct container);
}
void
sysfree(struct sys_alloc *alloc, void *ptr, size_t bytes)
{
assert(alloc->thread_id == pthread_self());
ptr -= sizeof(struct container);
size_t remaining = bytes % QUOTA_UNIT_SIZE;
size_t units = bytes / QUOTA_UNIT_SIZE;
/*
* Check that we can free one more quota block when we
* released remaining bytes
*/
if (small_align(alloc->used_bytes, QUOTA_UNIT_SIZE) >
small_align(alloc->used_bytes - remaining, QUOTA_UNIT_SIZE))
units++;
alloc->used_bytes -= bytes;
if (units > 0)
quota_release(alloc->quota, units * QUOTA_UNIT_SIZE);
rlist_del_entry((struct container *)ptr, rlist);
free(ptr);
}
#pragma once
/*
* Copyright 2010-2021, 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 <small/small.h>
#include <pthread.h>
#if defined(__cplusplus)
extern "C" {
#endif /* defined(__cplusplus) */
struct sys_stats {
size_t used;
};
struct sys_alloc {
/** Allocated bytes */
uint64_t used_bytes;
/** The source of allocations */
struct quota *quota;
/**
* List of allocations, used to free up
* memory, when allocator is destroyed
*/
struct rlist allocations;
#ifndef _NDEBUG
/**
* Debug only: track that all allocations
* are made from a single thread.
*/
pthread_t thread_id;
#endif
};
static inline void
sys_stats(struct sys_alloc *alloc, struct sys_stats *totals)
{
totals->used = alloc->used_bytes;
}
void
sys_alloc_create(struct sys_alloc *alloc, struct quota *quota);
void
sys_alloc_destroy(struct sys_alloc *alloc);
void *
sysalloc(struct sys_alloc *alloc, size_t size);
void
sysfree(struct sys_alloc *alloc, void *ptr, size_t size);
#if defined(__cplusplus)
} /* extern "C" */
#endif /* defined(__cplusplus) */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment