From f20103dfd0d4aa308fd41305ff63d4b8d2d9cd76 Mon Sep 17 00:00:00 2001 From: Magomed Date: Mon, 6 Jan 2025 18:17:07 +0300 Subject: [PATCH] matras: introduce the matras_alloc_reserve function The function is meant to be used in order to reserve the amount of extents possibly required to allocate the specified amount of blocks. Needed for tarantool/tarantool#10831 --- include/small/matras.h | 7 +++++++ include/small/util.h | 2 ++ small/matras.c | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/include/small/matras.h b/include/small/matras.h index 85d436c..5ef16b1 100644 --- a/include/small/matras.h +++ b/include/small/matras.h @@ -310,6 +310,13 @@ matras_dealloc_range(struct matras *m, matras_id_t range_count); int matras_touch_reserve(struct matras *m, int count); +/** + * Reserve the max amount of extents required to successfully allocate @p count + * blocks. The extents are reserved in the allocator given on construction. + */ +int +matras_alloc_reserve(struct matras *m, int count); + /** * Convert block id into block address. */ diff --git a/include/small/util.h b/include/small/util.h index c53fb16..951ec07 100644 --- a/include/small/util.h +++ b/include/small/util.h @@ -88,6 +88,8 @@ # define lengthof(array) (sizeof (array) / sizeof ((array)[0])) #endif +#define SMALL_DIV_ROUND_UP(a, b) ((a) + (b) - 1) / (b) + #define small_xmalloc(size) \ ({ \ void *ret = malloc(size); \ diff --git a/small/matras.c b/small/matras.c index 991eeac..46da9a2 100644 --- a/small/matras.c +++ b/small/matras.c @@ -12,6 +12,8 @@ #pragma intrinsic (_BitScanReverse) #endif +#include "util.h" + /** * Dummy thread-local matras_stats struct used if matras_stats wasn't * passed to matras_create(). @@ -364,6 +366,30 @@ matras_touch_reserve(struct matras *m, int count) return matras_allocator_reserve(m->allocator, max_extents_required); } +/** + * Reserve the max amount of extents required to successfully allocate @p count + * blocks. The extents are reserved in the allocator given on construction. + */ +int +matras_alloc_reserve(struct matras *m, int count) +{ + assert(count >= 0); + + /* No allocations planned. */ + if (count == 0) + return 0; + + /* + * This reserves up to 3 extents more than required, but it should be OK + * since the reserved memory is generic for all matras_allocator users. + */ + int l3_count = SMALL_DIV_ROUND_UP(m->block_size * count, + m->allocator->extent_size); + int l2_count = SMALL_DIV_ROUND_UP(l3_count * sizeof(void *), + m->allocator->extent_size); + return matras_allocator_reserve(m->allocator, l3_count + l2_count + 1); +} + /** * Return the number of allocated extents (of size m->extent_size each) */