mirror of
https://github.com/isar/libmdbx.git
synced 2025-04-06 04:37:45 +08:00
mdbx: добавление опций для subpage: limit, room_threshold, reserve_prereq, reserve_limit.
This commit is contained in:
parent
0e831f42cc
commit
5792eb31eb
44
mdbx.h
44
mdbx.h
@ -2344,7 +2344,49 @@ typedef enum MDBX_option {
|
|||||||
* будет УМЕНЬШАТЬ неравномерность заполнения страниц.
|
* будет УМЕНЬШАТЬ неравномерность заполнения страниц.
|
||||||
*
|
*
|
||||||
* \see MDBX_opt_merge_threshold_16dot16_percent */
|
* \see MDBX_opt_merge_threshold_16dot16_percent */
|
||||||
MDBX_opt_prefer_waf_insteadof_balance
|
MDBX_opt_prefer_waf_insteadof_balance,
|
||||||
|
|
||||||
|
/** \brief Задаёт в % максимальный размер вложенных страниц, используемых для
|
||||||
|
* размещения небольшого количества мульти-значений связанных с одном ключем.
|
||||||
|
*
|
||||||
|
* Использование вложенных страниц, вместо выноса значений на отдельные
|
||||||
|
* страницы вложенного дерева, позволяет уменьшить объем неиспользуемого места
|
||||||
|
* и этим увеличить плотность размещения данных.
|
||||||
|
*
|
||||||
|
* Но с увеличением размера вложенных страниц требуется больше листовых
|
||||||
|
* страниц основного дерева, что также увеличивает высоту основного дерева.
|
||||||
|
* Кроме этого, изменение данных на вложенных страницах требует дополнительных
|
||||||
|
* копирований, поэтому стоимость может быть больше во многих сценариях.
|
||||||
|
*
|
||||||
|
* min 12.5% (8192), max 100% (65535), default = 100% */
|
||||||
|
MDBX_opt_subpage_limit,
|
||||||
|
|
||||||
|
/** \brief Задаёт в % минимальный объём свободного места на основной странице,
|
||||||
|
* при отсутствии которого вложенные страницы выносятся в отдельное дерево.
|
||||||
|
*
|
||||||
|
* min 0, max 100% (65535), default = 0 */
|
||||||
|
MDBX_opt_subpage_room_threshold,
|
||||||
|
|
||||||
|
/** \brief Задаёт в % минимальный объём свободного места на основной странице,
|
||||||
|
* при наличии которого, производится резервирование места во вложенной.
|
||||||
|
*
|
||||||
|
* Если на основной странице свободного места недостаточно, то вложенная
|
||||||
|
* страница будет минимального размера. В свою очередь, при отсутствии резерва
|
||||||
|
* во вложенной странице, каждое добавлении в неё элементов будет требовать
|
||||||
|
* переформирования основной страниц с переносом всех узлов данных.
|
||||||
|
*
|
||||||
|
* Поэтому резервирование места, как правило, выгодно в сценариях с
|
||||||
|
* интенсивным добавлением коротких мульти-значений, например при
|
||||||
|
* индексировании. Но уменьшает плотность размещения данных, соответственно
|
||||||
|
* увеличивает объем БД и операций ввода-вывода.
|
||||||
|
*
|
||||||
|
* min 0, max 100% (65535), default = 42% (27525) */
|
||||||
|
MDBX_opt_subpage_reserve_prereq,
|
||||||
|
|
||||||
|
/** \brief Задаёт в % ограничение резервирования места на вложенных страницах.
|
||||||
|
*
|
||||||
|
* min 0, max 100% (65535), default = 4.2% (2753) */
|
||||||
|
MDBX_opt_subpage_reserve_limit
|
||||||
} MDBX_option_t;
|
} MDBX_option_t;
|
||||||
|
|
||||||
/** \brief Sets the value of a extra runtime options for an environment.
|
/** \brief Sets the value of a extra runtime options for an environment.
|
||||||
|
@ -31,6 +31,26 @@ static bool default_prefer_waf_insteadof_balance(const MDBX_env *env) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t default_subpage_limit(const MDBX_env *env) {
|
||||||
|
(void)env;
|
||||||
|
return 65535 /* 100% */;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t default_subpage_room_threshold(const MDBX_env *env) {
|
||||||
|
(void)env;
|
||||||
|
return 0 /* 0% */;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t default_subpage_reserve_prereq(const MDBX_env *env) {
|
||||||
|
(void)env;
|
||||||
|
return 27525 /* 42% */;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t default_subpage_reserve_limit(const MDBX_env *env) {
|
||||||
|
(void)env;
|
||||||
|
return 2753 /* 4.2% */;
|
||||||
|
}
|
||||||
|
|
||||||
void env_options_init(MDBX_env *env) {
|
void env_options_init(MDBX_env *env) {
|
||||||
env->options.rp_augment_limit = MDBX_PNL_INITIAL;
|
env->options.rp_augment_limit = MDBX_PNL_INITIAL;
|
||||||
env->options.dp_reserve_limit = MDBX_PNL_INITIAL;
|
env->options.dp_reserve_limit = MDBX_PNL_INITIAL;
|
||||||
@ -50,6 +70,11 @@ void env_options_init(MDBX_env *env) {
|
|||||||
#endif /* Linux */
|
#endif /* Linux */
|
||||||
MDBX_WRITETHROUGH_THRESHOLD_DEFAULT;
|
MDBX_WRITETHROUGH_THRESHOLD_DEFAULT;
|
||||||
#endif /* Windows */
|
#endif /* Windows */
|
||||||
|
|
||||||
|
env->options.subpage.limit = default_subpage_limit(env);
|
||||||
|
env->options.subpage.room_threshold = default_subpage_room_threshold(env);
|
||||||
|
env->options.subpage.reserve_prereq = default_subpage_reserve_prereq(env);
|
||||||
|
env->options.subpage.reserve_limit = default_subpage_reserve_limit(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_options_adjust_defaults(MDBX_env *env) {
|
void env_options_adjust_defaults(MDBX_env *env) {
|
||||||
@ -318,6 +343,54 @@ __cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option,
|
|||||||
env->options.prefer_waf_insteadof_balance = value != 0;
|
env->options.prefer_waf_insteadof_balance = value != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_limit:
|
||||||
|
if (value == /* default */ UINT64_MAX) {
|
||||||
|
env->options.subpage.limit = default_subpage_limit(env);
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
} else if (value > 65535)
|
||||||
|
err = MDBX_EINVAL;
|
||||||
|
else {
|
||||||
|
env->options.subpage.limit = (uint16_t)value;
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_room_threshold:
|
||||||
|
if (value == /* default */ UINT64_MAX) {
|
||||||
|
env->options.subpage.room_threshold = default_subpage_room_threshold(env);
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
} else if (value > 65535)
|
||||||
|
err = MDBX_EINVAL;
|
||||||
|
else {
|
||||||
|
env->options.subpage.room_threshold = (uint16_t)value;
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_reserve_prereq:
|
||||||
|
if (value == /* default */ UINT64_MAX) {
|
||||||
|
env->options.subpage.reserve_prereq = default_subpage_reserve_prereq(env);
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
} else if (value > 65535)
|
||||||
|
err = MDBX_EINVAL;
|
||||||
|
else {
|
||||||
|
env->options.subpage.reserve_prereq = (uint16_t)value;
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_reserve_limit:
|
||||||
|
if (value == /* default */ UINT64_MAX) {
|
||||||
|
env->options.subpage.reserve_limit = default_subpage_reserve_limit(env);
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
} else if (value > 65535)
|
||||||
|
err = MDBX_EINVAL;
|
||||||
|
else {
|
||||||
|
env->options.subpage.reserve_limit = (uint16_t)value;
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
}
|
}
|
||||||
@ -411,6 +484,22 @@ __cold int mdbx_env_get_option(const MDBX_env *env, const MDBX_option_t option,
|
|||||||
*pvalue = env->options.prefer_waf_insteadof_balance;
|
*pvalue = env->options.prefer_waf_insteadof_balance;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_limit:
|
||||||
|
*pvalue = env->options.subpage.limit;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_room_threshold:
|
||||||
|
*pvalue = env->options.subpage.room_threshold;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_reserve_prereq:
|
||||||
|
*pvalue = env->options.subpage.reserve_prereq;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MDBX_opt_subpage_reserve_limit:
|
||||||
|
*pvalue = env->options.subpage.reserve_limit;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
}
|
}
|
||||||
|
10
src/env.c
10
src/env.c
@ -58,15 +58,7 @@ __cold unsigned env_setup_pagesize(MDBX_env *env, const size_t pagesize) {
|
|||||||
eASSERT(env, pgno2bytes(env, 1) == pagesize);
|
eASSERT(env, pgno2bytes(env, 1) == pagesize);
|
||||||
eASSERT(env, bytes2pgno(env, pagesize + pagesize) == 2);
|
eASSERT(env, bytes2pgno(env, pagesize + pagesize) == 2);
|
||||||
recalculate_merge_thresholds(env);
|
recalculate_merge_thresholds(env);
|
||||||
|
recalculate_subpage_thresholds(env);
|
||||||
/* TODO: recalculate me_subpage_xyz values from MDBX_opt_subpage_xyz. */
|
|
||||||
env->subpage_limit = env->leaf_nodemax - NODESIZE;
|
|
||||||
env->subpage_room_threshold = 0;
|
|
||||||
env->subpage_reserve_prereq = env->leaf_nodemax;
|
|
||||||
env->subpage_reserve_limit = env->subpage_limit / 42;
|
|
||||||
eASSERT(env, env->subpage_reserve_prereq >
|
|
||||||
env->subpage_room_threshold + env->subpage_reserve_limit);
|
|
||||||
eASSERT(env, env->leaf_nodemax >= env->subpage_limit + NODESIZE);
|
|
||||||
|
|
||||||
const pgno_t max_pgno = bytes2pgno(env, MAX_MAPSIZE);
|
const pgno_t max_pgno = bytes2pgno(env, MAX_MAPSIZE);
|
||||||
if (!env->options.flags.non_auto.dp_limit) {
|
if (!env->options.flags.non_auto.dp_limit) {
|
||||||
|
@ -408,6 +408,13 @@ struct MDBX_env {
|
|||||||
bool prefault_write;
|
bool prefault_write;
|
||||||
bool prefer_waf_insteadof_balance; /* Strive to minimize WAF instead of
|
bool prefer_waf_insteadof_balance; /* Strive to minimize WAF instead of
|
||||||
balancing pages fullment */
|
balancing pages fullment */
|
||||||
|
struct {
|
||||||
|
uint16_t limit;
|
||||||
|
uint16_t room_threshold;
|
||||||
|
uint16_t reserve_prereq;
|
||||||
|
uint16_t reserve_limit;
|
||||||
|
} subpage;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
unsigned all;
|
unsigned all;
|
||||||
/* tracks options with non-auto values but tuned by user */
|
/* tracks options with non-auto values but tuned by user */
|
||||||
|
@ -752,12 +752,35 @@ __hot int __must_check_result page_dirty(MDBX_txn *txn, page_t *mp,
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t page_subleaf2_reserve(const MDBX_env *const env, size_t host_page_room,
|
void recalculate_subpage_thresholds(MDBX_env *env) {
|
||||||
|
size_t whole = env->leaf_nodemax - NODESIZE;
|
||||||
|
env->subpage_limit = (whole * env->options.subpage.limit + 32767) >> 16;
|
||||||
|
whole = env->subpage_limit;
|
||||||
|
env->subpage_reserve_limit =
|
||||||
|
(whole * env->options.subpage.reserve_limit + 32767) >> 16;
|
||||||
|
eASSERT(env, env->leaf_nodemax >= env->subpage_limit + NODESIZE);
|
||||||
|
eASSERT(env, env->subpage_limit >= env->subpage_reserve_limit);
|
||||||
|
|
||||||
|
whole = env->leaf_nodemax;
|
||||||
|
env->subpage_room_threshold =
|
||||||
|
(whole * env->options.subpage.room_threshold + 32767) >> 16;
|
||||||
|
env->subpage_reserve_prereq =
|
||||||
|
(whole * env->options.subpage.reserve_prereq + 32767) >> 16;
|
||||||
|
if (env->subpage_room_threshold + env->subpage_reserve_limit >
|
||||||
|
(intptr_t)page_space(env))
|
||||||
|
env->subpage_reserve_prereq = page_space(env);
|
||||||
|
else if (env->subpage_reserve_prereq <
|
||||||
|
env->subpage_room_threshold + env->subpage_reserve_limit)
|
||||||
|
env->subpage_reserve_prereq =
|
||||||
|
env->subpage_room_threshold + env->subpage_reserve_limit;
|
||||||
|
eASSERT(env, env->subpage_reserve_prereq >
|
||||||
|
env->subpage_room_threshold + env->subpage_reserve_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t page_subleaf2_reserve(const MDBX_env *env, size_t host_page_room,
|
||||||
size_t subpage_len, size_t item_len) {
|
size_t subpage_len, size_t item_len) {
|
||||||
eASSERT(env, (subpage_len & 1) == 0);
|
eASSERT(env, (subpage_len & 1) == 0);
|
||||||
eASSERT(env, env->subpage_reserve_prereq > env->subpage_room_threshold +
|
eASSERT(env, env->leaf_nodemax >= env->subpage_limit + NODESIZE);
|
||||||
env->subpage_reserve_limit &&
|
|
||||||
env->leaf_nodemax >= env->subpage_limit + NODESIZE);
|
|
||||||
size_t reserve = 0;
|
size_t reserve = 0;
|
||||||
for (size_t n = 0;
|
for (size_t n = 0;
|
||||||
n < 5 && reserve + item_len <= env->subpage_reserve_limit &&
|
n < 5 && reserve + item_len <= env->subpage_reserve_limit &&
|
||||||
|
@ -171,7 +171,7 @@ static inline void page_wash(MDBX_txn *txn, size_t di, page_t *const mp,
|
|||||||
pgno2bytes(txn->env, npages) - PAGEHDRSZ);
|
pgno2bytes(txn->env, npages) - PAGEHDRSZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDBX_INTERNAL size_t page_subleaf2_reserve(const MDBX_env *const env,
|
MDBX_INTERNAL size_t page_subleaf2_reserve(const MDBX_env *env,
|
||||||
size_t host_page_room,
|
size_t host_page_room,
|
||||||
size_t subpage_len, size_t item_len);
|
size_t subpage_len, size_t item_len);
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ MDBX_INTERNAL int __must_check_result tree_rebalance(MDBX_cursor *mc);
|
|||||||
MDBX_INTERNAL int __must_check_result tree_propagate_key(MDBX_cursor *mc,
|
MDBX_INTERNAL int __must_check_result tree_propagate_key(MDBX_cursor *mc,
|
||||||
const MDBX_val *key);
|
const MDBX_val *key);
|
||||||
MDBX_INTERNAL void recalculate_merge_thresholds(MDBX_env *env);
|
MDBX_INTERNAL void recalculate_merge_thresholds(MDBX_env *env);
|
||||||
|
MDBX_INTERNAL void recalculate_subpage_thresholds(MDBX_env *env);
|
||||||
|
|
||||||
/* subdb.c */
|
/* subdb.c */
|
||||||
MDBX_INTERNAL int __must_check_result sdb_fetch(MDBX_txn *txn, size_t dbi);
|
MDBX_INTERNAL int __must_check_result sdb_fetch(MDBX_txn *txn, size_t dbi);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user