mdbx: добавление MDBX_opt_gc_time_limit.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2023-11-29 00:35:25 +03:00
parent 508cf83c32
commit eeec44f56d
3 changed files with 87 additions and 7 deletions

28
mdbx.h
View File

@ -2133,6 +2133,7 @@ enum MDBX_option_t {
/** \brief Controls the in-process limit to grow a list of reclaimed/recycled
* page's numbers for finding a sequence of contiguous pages for large data
* items.
* \see MDBX_opt_gc_time_limit
*
* \details A long values requires allocation of contiguous database pages.
* To find such sequences, it may be necessary to accumulate very large lists,
@ -2293,6 +2294,33 @@ enum MDBX_option_t {
* in the \ref MDBX_WRITEMAP mode by clearing ones through file handle before
* touching. */
MDBX_opt_prefault_write_enable,
/** \brief Controls the in-process spending time limit of searching
* consecutive pages inside GC.
* \see MDBX_opt_rp_augment_limit
*
* \details Задаёт ограничение времени в 1/65536 долях секунды, которое может
* быть потрачено в ходе пишущей транзакции на поиск последовательностей
* страниц внутри GC/freelist после достижения ограничения задаваемого опцией
* \ref MDBX_opt_rp_augment_limit. Контроль по времени не выполняется при
* поиске/выделении одиночных страниц и выделении страниц под нужды GC (при
* обновлении GC в ходе фиксации транзакции).
*
* Задаваемый лимит времени исчисляется по "настенным часам" и контролируется
* в рамках транзакции, наследуется для вложенных транзакций и с
* аккумулированием в родительской при их фиксации. Контроль по времени
* производится только при достижении ограничения задаваемого опцией \ref
* MDBX_opt_rp_augment_limit. Это позволяет гибко управлять поведением
* используя обе опции.
*
* По умолчанию ограничение устанавливается в 0, что приводит к
* незамедлительной остановке поиска в GC при достижении \ref
* MDBX_opt_rp_augment_limit во внутреннем состоянии транзакции и
* соответствует поведению до появления опции `MDBX_opt_gc_time_limit`.
* С другой стороны, при минимальном значении (включая 0)
* `MDBX_opt_rp_augment_limit` переработка GC будет ограничиваться
* преимущественно затраченным временем. */
MDBX_opt_gc_time_limit
};
#ifndef __cplusplus
/** \ingroup c_settings */

View File

@ -7674,12 +7674,24 @@ bailout:
return ret;
}
struct monotime_cache {
uint64_t value;
int expire_countdown;
};
static __inline uint64_t monotime_since_cached(uint64_t begin_timestamp,
struct monotime_cache *cache) {
if (cache->expire_countdown)
cache->expire_countdown -= 1;
else {
cache->value = osal_monotime();
cache->expire_countdown = 42 / 3;
}
return cache->value - begin_timestamp;
}
static pgr_t page_alloc_slowpath(const MDBX_cursor *const mc, const size_t num,
uint8_t flags) {
#if MDBX_ENABLE_PROFGC
const uint64_t monotime_before = osal_monotime();
#endif /* MDBX_ENABLE_PROFGC */
pgr_t ret;
MDBX_txn *const txn = mc->mc_txn;
MDBX_env *const env = txn->mt_env;
@ -7694,8 +7706,19 @@ static pgr_t page_alloc_slowpath(const MDBX_cursor *const mc, const size_t num,
eASSERT(env, pnl_check_allocated(txn->tw.relist,
txn->mt_next_pgno - MDBX_ENABLE_REFUND));
pgno_t pgno = 0;
size_t newnext;
const uint64_t monotime_begin =
(MDBX_ENABLE_PROFGC || (num > 1 && env->me_options.gc_time_limit))
? osal_monotime()
: 0;
struct monotime_cache now_cache;
now_cache.expire_countdown =
1 /* старт с 1 позволяет избавиться как от лишних системных вызовов когда
лимит времени задан нулевой или уже исчерпан, так и от подсчета
времени при не-достижении rp_augment_limit */
;
now_cache.value = monotime_begin;
pgno_t pgno = 0;
if (num > 1) {
#if MDBX_ENABLE_PROFGC
prof->xpages += 1;
@ -7871,7 +7894,10 @@ next_gc:;
txn->tw.relist) >= env->me_options.rp_augment_limit) &&
((/* not a slot-request from gc-update */ num &&
/* have enough unallocated space */ txn->mt_geo.upper >=
txn->mt_next_pgno + num) ||
txn->mt_next_pgno + num &&
monotime_since_cached(monotime_begin, &now_cache) +
txn->tw.gc_time_acc >=
env->me_options.gc_time_limit) ||
gc_len + MDBX_PNL_GETSIZE(txn->tw.relist) >= MDBX_PGL_LIMIT)) {
/* Stop reclaiming to avoid large/overflow the page list. This is a rare
* case while search for a continuously multi-page region in a
@ -8173,6 +8199,8 @@ done:
(size_t)txn->mt_dbs[FREE_DBI].md_entries);
ret.page = NULL;
}
if (num > 1)
txn->tw.gc_time_acc += monotime_since_cached(monotime_begin, &now_cache);
} else {
early_exit:
DEBUG("return NULL for %zu pages for ALLOC_%s, rc %d", num,
@ -8181,7 +8209,7 @@ done:
}
#if MDBX_ENABLE_PROFGC
prof->rtime_monotonic += osal_monotime() - monotime_before;
prof->rtime_monotonic += osal_monotime() - monotime_begin;
#endif /* MDBX_ENABLE_PROFGC */
return ret;
}
@ -9352,6 +9380,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) {
MDBX_PNL_SETSIZE(txn->tw.retired_pages, 0);
txn->tw.spilled.list = NULL;
txn->tw.spilled.least_removed = 0;
txn->tw.gc_time_acc = 0;
txn->tw.last_reclaimed = 0;
if (txn->tw.lifo_reclaimed)
MDBX_PNL_SETSIZE(txn->tw.lifo_reclaimed, 0);
@ -9800,6 +9829,7 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags,
= parent->mt_next_pgno) -
MDBX_ENABLE_REFUND));
txn->tw.gc_time_acc = parent->tw.gc_time_acc;
txn->tw.last_reclaimed = parent->tw.last_reclaimed;
if (parent->tw.lifo_reclaimed) {
txn->tw.lifo_reclaimed = parent->tw.lifo_reclaimed;
@ -12037,6 +12067,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
pnl_free(parent->tw.relist);
parent->tw.relist = txn->tw.relist;
txn->tw.relist = NULL;
parent->tw.gc_time_acc = txn->tw.gc_time_acc;
parent->tw.last_reclaimed = txn->tw.last_reclaimed;
parent->mt_geo = txn->mt_geo;
@ -25875,6 +25906,21 @@ __cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option,
}
break;
case MDBX_opt_gc_time_limit:
if (value == /* default */ UINT64_MAX)
value = 0;
if (unlikely(value > UINT32_MAX))
return MDBX_EINVAL;
if (unlikely(env->me_flags & MDBX_RDONLY))
return MDBX_EACCESS;
value = osal_16dot16_to_monotime((uint32_t)value);
if (value != env->me_options.gc_time_limit) {
if (env->me_txn && env->me_txn0->mt_owner != osal_thread_self())
return MDBX_EPERM;
env->me_options.gc_time_limit = value;
}
break;
case MDBX_opt_txn_dp_limit:
case MDBX_opt_txn_dp_initial:
if (value == /* default */ UINT64_MAX)
@ -26027,6 +26073,10 @@ __cold int mdbx_env_get_option(const MDBX_env *env, const MDBX_option_t option,
*pvalue = env->me_options.rp_augment_limit;
break;
case MDBX_opt_gc_time_limit:
*pvalue = osal_monotime_to_16dot16(env->me_options.gc_time_limit);
break;
case MDBX_opt_txn_dp_limit:
*pvalue = env->me_options.dp_limit;
break;

View File

@ -1260,6 +1260,7 @@ struct MDBX_txn {
size_t writemap_dirty_npages;
size_t writemap_spilled_npages;
};
uint64_t gc_time_acc;
} tw;
};
};
@ -1422,6 +1423,7 @@ struct MDBX_env {
unsigned rp_augment_limit;
unsigned dp_limit;
unsigned dp_initial;
uint64_t gc_time_limit;
uint8_t dp_loose_limit;
uint8_t spill_max_denominator;
uint8_t spill_min_denominator;