mdbx: guess a reasonable maximum DB size for the default upper limit of geometry.

Fixes https://github.com/erthink/libmdbx/issues/183

Change-Id: Ic7b616e229d3008fda49e5a04121e22997ac53ea
This commit is contained in:
Leonid Yuriev 2021-04-07 04:40:17 +03:00
parent 8ff44026c3
commit c14e4235ee

View File

@ -10517,6 +10517,41 @@ bailout:
return rc;
}
__cold static intptr_t get_reasonable_db_maxsize(intptr_t *cached_result) {
if (*cached_result == 0) {
intptr_t pagesize, total_ram_pages;
if (unlikely(mdbx_get_sysraminfo(&pagesize, &total_ram_pages, nullptr) !=
MDBX_SUCCESS))
return MAX_MAPSIZE32 /* the 32-bit limit is good enough for fallback */;
if (unlikely((size_t)total_ram_pages * 2 > MAX_MAPSIZE / (size_t)pagesize))
return MAX_MAPSIZE;
assert(MAX_MAPSIZE >= (size_t)(total_ram_pages * pagesize * 2));
/* Suggesting should not be more than golden ratio of the size of RAM. */
*cached_result =
(intptr_t)(total_ram_pages * pagesize * 1.6180339887498948482);
/* Round to the nearest human-readable granulation. */
for (int i = 10; i < MDBX_WORDBITS - 1; i += 10) {
const size_t unit = (size_t)1 << i;
const size_t floor = floor_powerof2(*cached_result, unit);
const size_t ceil = ceil_powerof2(*cached_result, unit);
if (*cached_result - floor < ceil - *cached_result ||
ceil > MAX_MAPSIZE) {
if (*cached_result - floor > (size_t)*cached_result / 16)
break;
*cached_result = floor;
} else {
if (ceil - *cached_result > (size_t)*cached_result / 16)
break;
*cached_result = ceil;
}
}
}
return *cached_result;
}
__cold LIBMDBX_API int
mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
intptr_t size_upper, intptr_t growth_step,
@ -10535,6 +10570,7 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
shrink_threshold = 1;
#endif
intptr_t reasonable_maxsize = 0;
bool need_unlock = false;
if (env->me_map) {
/* env already mapped */
@ -10604,7 +10640,7 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
else if (max_size == 0 /* minimal */)
max_size = MIN_MAPSIZE;
else if (max_size >= (intptr_t)MAX_MAPSIZE /* maximal */)
max_size = MAX_MAPSIZE;
max_size = get_reasonable_db_maxsize(&reasonable_maxsize);
while (max_size > pagesize * (int64_t)MAX_PAGENO &&
pagesize < MAX_PAGESIZE)
@ -10624,7 +10660,7 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
size_lower = MIN_PAGENO * pagesize;
}
if (size_lower >= INTPTR_MAX) {
size_lower = MAX_MAPSIZE;
size_lower = get_reasonable_db_maxsize(&reasonable_maxsize);
if ((size_t)size_lower / pagesize > MAX_PAGENO)
size_lower = pagesize * MAX_PAGENO;
}
@ -10635,14 +10671,14 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
size_now = size_upper;
}
if (size_now >= INTPTR_MAX) {
size_now = MAX_MAPSIZE;
size_now = get_reasonable_db_maxsize(&reasonable_maxsize);
if ((size_t)size_now / pagesize > MAX_PAGENO)
size_now = pagesize * MAX_PAGENO;
}
if (size_upper <= 0) {
if ((size_t)size_now >= MAX_MAPSIZE / 2)
size_upper = MAX_MAPSIZE;
if (size_now >= get_reasonable_db_maxsize(&reasonable_maxsize) / 2)
size_upper = get_reasonable_db_maxsize(&reasonable_maxsize);
else if (MAX_MAPSIZE != MAX_MAPSIZE32 &&
(size_t)size_now >= MAX_MAPSIZE32 / 2 &&
(size_t)size_now <= MAX_MAPSIZE32 / 4 * 3)
@ -10655,7 +10691,7 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
if ((size_t)size_upper / pagesize > MAX_PAGENO)
size_upper = pagesize * MAX_PAGENO;
} else if (size_upper >= INTPTR_MAX) {
size_upper = MAX_MAPSIZE;
size_upper = get_reasonable_db_maxsize(&reasonable_maxsize);
if ((size_t)size_upper / pagesize > MAX_PAGENO)
size_upper = pagesize * MAX_PAGENO;
}