From: Ilya Kosarev <i.kosarev@tarantool.org> To: v.shpilevoy@tarantool.org, alyapunov@tarantool.org Cc: tarantool-patches@dev.tarantool.org Subject: [Tarantool-patches] [PATCH] quota: add is_enabled field Date: Fri, 11 Dec 2020 18:37:03 +0300 [thread overview] Message-ID: <20201211153703.7450-1-i.kosarev@tarantool.org> (raw) By default the quota is enabled. If it is set to false, quota_use will allow to overuse the total available memory limit. In case of disabled quota smalloc() allocates (and frees) large slabs using malloc so that the quota will be able to shrink back after those slabs are freed. Test introduced. Part of tarantool/tarantool#3807 --- Branch: https://github.com/tarantool/small/tree/i.kosarev/gh-3807-safe-alloc-on-truncation Issue: https://github.com/tarantool/tarantool/issues/3807 small/quota.h | 21 ++++++++++++++++++++- small/slab_cache.c | 6 ++++++ small/slab_cache.h | 3 +++ small/small.c | 10 ++++++---- test/small_alloc.c | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/small/quota.h b/small/quota.h index 3d3b4f0..c71ee5d 100644 --- a/small/quota.h +++ b/small/quota.h @@ -57,6 +57,12 @@ struct quota { * QUOTA_UNIT_SIZE. */ uint64_t value; + /** + * By default the quota is enabled. If it is set to + * false, quota_use will allow to overuse the total + * available memory limit. + */ + bool is_enabled; }; /** @@ -68,6 +74,7 @@ quota_init(struct quota *quota, size_t total) uint64_t new_total = (total + (QUOTA_UNIT_SIZE - 1)) / QUOTA_UNIT_SIZE; quota->value = new_total << 32; + quota->is_enabled = true; } /** @@ -122,6 +129,18 @@ quota_set(struct quota *quota, size_t new_total) return new_total_in_units * QUOTA_UNIT_SIZE; } +static inline void +quota_enable(struct quota *quota) +{ + quota->is_enabled = true; +} + +static inline void +quota_disable(struct quota *quota) +{ + quota->is_enabled = false; +} + /** * Use up a quota * @retval > 0 aligned value on success @@ -143,7 +162,7 @@ quota_use(struct quota *quota, size_t size) uint32_t new_used_in_units = used_in_units + size_in_units; assert(new_used_in_units > used_in_units); - if (new_used_in_units > total_in_units) + if (new_used_in_units > total_in_units && quota->is_enabled) return -1; uint64_t new_value = diff --git a/small/slab_cache.c b/small/slab_cache.c index 2ba56c5..b3b7004 100644 --- a/small/slab_cache.c +++ b/small/slab_cache.c @@ -462,3 +462,9 @@ slab_cache_check(struct slab_cache *cache) return; abort(); } + +bool +slab_cache_quota_enabled(struct slab_cache *cache) +{ + return cache->arena->quota->is_enabled; +} diff --git a/small/slab_cache.h b/small/slab_cache.h index d81c1c5..bbfdc74 100644 --- a/small/slab_cache.h +++ b/small/slab_cache.h @@ -271,6 +271,9 @@ slab_from_data(void *data) void slab_cache_check(struct slab_cache *cache); +bool +slab_cache_quota_enabled(struct slab_cache *cache); + /** * Find the nearest power of 2 size capable of containing * a chunk of the given size. Adjust for cache->order0_size diff --git a/small/small.c b/small/small.c index 48085fb..154a0e9 100644 --- a/small/small.c +++ b/small/small.c @@ -228,7 +228,7 @@ smalloc(struct small_alloc *alloc, size_t size) struct mempool *pool; int idx = (size - 1) >> STEP_SIZE_LB; idx = (idx > (int) alloc->step_pool0_step_count) ? idx - alloc->step_pool0_step_count : 0; - if (idx < STEP_POOL_MAX) { + if (idx < STEP_POOL_MAX && slab_cache_quota_enabled(alloc->cache)) { /* Allocate in a stepped pool. */ pool = &alloc->step_pools[idx]; assert(size <= pool->objsize && @@ -238,7 +238,8 @@ smalloc(struct small_alloc *alloc, size_t size) pattern.pool.objsize = size; struct factor_pool *upper_bound = factor_tree_nsearch(&alloc->factor_pools, &pattern); - if (upper_bound == NULL) { + if (upper_bound == NULL || + !slab_cache_quota_enabled(alloc->cache)) { /* Object is too large, fallback to slab_cache */ struct slab *slab = slab_get_large(alloc->cache, size); if (slab == NULL) @@ -276,7 +277,7 @@ mempool_find(struct small_alloc *alloc, size_t size) struct mempool *pool; int idx = (size - 1) >> STEP_SIZE_LB; idx = (idx > (int) alloc->step_pool0_step_count) ? idx - alloc->step_pool0_step_count : 0; - if (idx < STEP_POOL_MAX) { + if (idx < STEP_POOL_MAX && slab_cache_quota_enabled(alloc->cache)) { /* Allocated in a stepped pool. */ pool = &alloc->step_pools[idx]; assert((size + STEP_SIZE > pool->objsize) || (idx == 0)); @@ -286,7 +287,8 @@ mempool_find(struct small_alloc *alloc, size_t size) pattern.pool.objsize = size; struct factor_pool *upper_bound = factor_tree_nsearch(&alloc->factor_pools, &pattern); - if (upper_bound == NULL) + if (upper_bound == NULL || + !slab_cache_quota_enabled(alloc->cache)) return NULL; /* Allocated by slab_cache. */ assert(size >= upper_bound->objsize_min); pool = &upper_bound->pool; diff --git a/test/small_alloc.c b/test/small_alloc.c index 421442a..1563cc9 100644 --- a/test/small_alloc.c +++ b/test/small_alloc.c @@ -128,6 +128,37 @@ small_alloc_large(void) footer(); } +static void +small_quota_release(void) +{ + header(); + + size_t total, used; + size_t alloc_size = 1000; + quota_get_total_and_used("a, &total, &used); + size_t amount = (total - used) / alloc_size; + + int **a = calloc(amount, sizeof(int *)); + int i = 0; + while (quota_use("a, 1) >= 0) { + quota_disable("a); + a[i++] = smalloc(&alloc, alloc_size); + quota_enable("a); + } + + quota_get_total_and_used("a, &total, &used); + fail_unless((int)total - (int)used < 0); + + quota_disable("a); + smfree(&alloc, a[0], alloc_size); + quota_enable("a); + free(a); + + quota_get_total_and_used("a, &total, &used); + fail_unless((int)total - (int)used > 0); + footer(); +} + int main() { seed = time(0); @@ -142,6 +173,7 @@ int main() small_alloc_basic(); small_alloc_large(); + small_quota_release(); slab_cache_destroy(&cache); } -- 2.17.1
next reply other threads:[~2020-12-11 15:37 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-12-11 15:37 Ilya Kosarev [this message] 2020-12-14 23:41 ` Vladislav Shpilevoy -- strict thread matches above, loose matches on Subject: below -- 2020-02-14 19:31 Ilya Kosarev 2020-02-14 22:48 ` Vladislav Shpilevoy
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20201211153703.7450-1-i.kosarev@tarantool.org \ --to=i.kosarev@tarantool.org \ --cc=alyapunov@tarantool.org \ --cc=tarantool-patches@dev.tarantool.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [Tarantool-patches] [PATCH] quota: add is_enabled field' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox