mdbx: add mdbx_is_readahead_reasonable().

Change-Id: Iac090a9050d6b046b62b2c79cefbc70cc62c9144
This commit is contained in:
Leonid Yuriev 2019-10-12 14:16:45 +03:00
parent 3ce4c3a0e4
commit bb922c208c
3 changed files with 140 additions and 0 deletions

18
mdbx.h
View File

@ -965,6 +965,10 @@ LIBMDBX_API char *mdbx_dump_val(const MDBX_val *key, char *const buf,
* may help random read performance when the DB is larger than RAM and system
* RAM is full.
*
* NOTE: The mdbx_is_readahead_reasonable() function allows to quickly find out
* whether to use readahead or not based on the size of the data and the
* amount of available memory.
*
* This flag affects only at environment opening and can't be changed after. */
#define MDBX_NORDAHEAD 0x800000u
@ -2014,6 +2018,20 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
intptr_t pagesize);
LIBMDBX_API int mdbx_env_set_mapsize(MDBX_env *env, size_t size);
/* Find out whether to use readahead or not, based on the given database size
* and the amount of available memory.
*
* [in] volume The expected database size in bytes.
* [in] redundancy Additional reserve or overload in case of negative value.
*
* Returns:
* - MDBX_RESULT_TRUE = readahead is reasonable.
* - MDBX_RESULT_FALSE = readahead is NOT reasonable, i.e. MDBX_NORDAHEAD
* is useful to open environment by mdbx_env_open().
* - Otherwise the error code. */
LIBMDBX_API int mdbx_is_readahead_reasonable(size_t volume,
intptr_t redundancy);
/* The minimal database page size in bytes. */
#define MDBX_MIN_PAGESIZE 512
__inline intptr_t mdbx_limits_pgsize_min(void) { return MDBX_MIN_PAGESIZE; }

View File

@ -7516,6 +7516,112 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
return lck_seize_rc;
}
__cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
if (volume <= 1024 * 1024 * 4ul)
return MDBX_RESULT_TRUE;
const size_t pagesize = mdbx_syspagesize();
if (unlikely(!mdbx_is_power2(pagesize) || pagesize < MIN_PAGESIZE))
return MDBX_INCOMPATIBLE;
#if defined(_WIN32) || defined(_WIN64)
MEMORYSTATUSEX info;
memset(&info, 0, sizeof(info));
info.dwLength = sizeof(info);
if (!GlobalMemoryStatusEx(&info))
return GetLastError();
#endif
const int log2page = mdbx_log2(pagesize);
#if defined(_WIN32) || defined(_WIN64)
const intptr_t total_ram_pages = (intptr_t)(info.ullTotalPhys >> log2page);
#elif defined(_SC_PHYS_PAGES)
const intptr_t total_ram_pages = sysconf(_SC_PHYS_PAGES);
if (total_ram_pages == -1)
return errno;
#elif defined(_SC_AIX_REALMEM)
const intptr_t total_ram_Kb = sysconf(_SC_AIX_REALMEM);
if (total_ram_Kb == -1)
return errno;
const intptr_t total_ram_pages = (total_ram_Kb << 10) >> log2page;
#elif defined(HW_USERMEM) || defined(HW_PHYSMEM64) || defined(HW_MEMSIZE) || \
defined(HW_PHYSMEM)
size_t ram;
size_t len = sizeof(ram);
static const int mib[2] = {
CTL_HW,
#if defined(HW_USERMEM)
HW_USERMEM
#elif defined(HW_PHYSMEM64)
HW_PHYSMEM64
#elif defined(HW_MEMSIZE)
HW_MEMSIZE
#else
HW_PHYSMEM
#endif
};
if (sysctl(mib, ARRAY_LENGTH(mib), &ram, &len, NULL, 0) != 0)
return errno;
if (len != sizeof(ram))
return MDBX_ENOSYS;
const intptr_t total_ram_pages = (intptr_t)(ram >> log2page);
#else
#error "FIXME: Get User-accessible or physical RAM"
#endif
if (total_ram_pages < 1)
return MDBX_ENOSYS;
const intptr_t volume_pages = (volume + pagesize - 1) >> log2page;
const intptr_t redundancy_pages =
(redundancy < 0) ? -(intptr_t)((-redundancy + pagesize - 1) >> log2page)
: (intptr_t)(redundancy + pagesize - 1) >> log2page;
if (volume_pages >= total_ram_pages ||
volume_pages + redundancy_pages >= total_ram_pages)
return MDBX_RESULT_FALSE;
#if defined(_WIN32) || defined(_WIN64)
const intptr_t avail_ram_pages = (intptr_t)(info.ullAvailPhys >> log2page);
#elif defined(_SC_AVPHYS_PAGES)
const intptr_t avail_ram_pages = sysconf(_SC_AVPHYS_PAGES);
if (avail_ram_pages == -1)
return errno;
#elif defined(__MACH__)
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
vm_statistics_data_t vmstat;
mach_port_t mport = mach_host_self();
kern_return_t kerr = host_statistics(mach_host_self(), HOST_VM_INFO,
(host_info_t)&vmstat, &count);
mach_port_deallocate(mach_task_self(), mport);
if (unlikely(kerr != KERN_SUCCESS))
return MDBX_ENOSYS;
const intptr_t avail_ram_pages = vmstat.free_count;
#elif defined(VM_TOTAL) || defined(VM_METER)
struct vmtotal info;
size_t len = sizeof(info);
static const int mib[2] = {
CTL_VM,
#if defined(VM_TOTAL)
VM_TOTAL
#elif defined(VM_METER)
VM_METER
#endif
};
if (sysctl(mib, ARRAY_LENGTH(mib), &info, &len, NULL, 0) != 0)
return errno;
if (len != sizeof(info))
return MDBX_ENOSYS;
const intptr_t avail_ram_pages = info.t_free;
#else
#error "FIXME: Get Available RAM"
#endif
if (avail_ram_pages < 1)
return MDBX_ENOSYS;
return (volume_pages + redundancy_pages >= avail_ram_pages)
? MDBX_RESULT_FALSE
: MDBX_RESULT_TRUE;
}
/* Only a subset of the mdbx_env flags can be changed
* at runtime. Changing other flags requires closing the
* environment and re-opening it with the new flags. */

View File

@ -74,6 +74,14 @@
defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \
defined(__DragonFly__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/cdefs.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <vm/vm_param.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__)
#include <uvm/uvm_param.h>
#endif
#include <sys/vmmeter.h>
#else
#include <malloc.h>
#ifndef _POSIX_C_SOURCE
@ -89,7 +97,15 @@
#include <malloc/malloc.h>
#endif /* MacOS */
#if defined(__MACH__)
#include <mach/host_info.h>
#include <mach/mach_host.h>
#include <mach/mach_port.h>
#undef P_DIRTY
#endif
#if defined(__linux__) || defined(__gnu_linux__)
#include <linux/sysctl.h>
#include <sys/sendfile.h>
#endif /* Linux */