Compare commits

...

14 Commits

Author SHA1 Message Date
Леонид Юрьев (Leonid Yuriev)
aaa9112c83 mdbx: release v0.11.10
The stable bugfix release.
It is planned that this will be the last release of the v0.11 branch.

New:
----

 - The C++ API has been refined to simplify support for `wchar_t` in path names.
 - Added explicit error message for Buildroot's Microblaze toolchain maintainers.

Fixes:
------

 - Never use modern `__cxa_thread_atexit()` on Apple's OSes.
 - Use `MultiByteToWideChar(CP_THREAD_ACP)` instead of `mbstowcs()`.
 - Don't check owner for finished transactions.
 - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG.

Minors:
-------

 - Fixed variable name typo.
 - Using `ldd` to check used dso.
 - Added `MDBX_WEAK_IMPORT_ATTRIBUTE` macro.
 - Use current transaction geometry for untouched parameters when `env_set_geometry()` called within a write transaction.
 - Minor clarified `iov_page()` failure case.

14 files changed, 263 insertions(+), 252 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2022-08-22 13:32:24 +03:00
Леонид Юрьев (Leonid Yuriev)
26f52a19c3 mdbx: add explicit error message for Buildroot's Microblaze toolchain maintainers. 2022-08-22 12:59:42 +03:00
Леонид Юрьев (Leonid Yuriev)
5368551081 mdbx: minor clarify iov_page() failure case. 2022-08-22 12:59:42 +03:00
Леонид Юрьев (Leonid Yuriev)
4f02199648 mdbx: update ChangeLog. 2022-08-17 23:56:53 +03:00
Леонид Юрьев (Leonid Yuriev)
316ddf9e01 mdbx: fix typo in MDBX_EINVAL which breaks MingGW builds with CLANG. 2022-08-16 11:09:52 +03:00
Леонид Юрьев (Leonid Yuriev)
3fbbe32adf mdbx: fix checking owner for finished write transactions inside txn_abort().
Fixed regression after 06734bf8ff.
2022-08-14 12:39:21 +03:00
Леонид Юрьев (Leonid Yuriev)
8467cc6d03 mdbx: use current txn geo for untouched parameters when env_set_geometry() called within a write transaction. 2022-08-13 16:56:29 +03:00
Леонид Юрьев (Leonid Yuriev)
9f0e2ecc67 mdbx: fix variable name typo. 2022-08-13 16:56:09 +03:00
Леонид Юрьев (Leonid Yuriev)
0287a00ee3 mdbx++: refine/simplify wchar_t support for pathnames. 2022-08-09 18:54:22 +03:00
Леонид Юрьев (Leonid Yuriev)
c8b1392cbe mdbx: use MultiByteToWideChar(CP_THREAD_ACP) instead of mbstowcs(). 2022-08-09 16:12:24 +03:00
Леонид Юрьев (Leonid Yuriev)
6d85e35876 mdbx: never use modern __cxa_thread_atexit() on Apple's OSes. 2022-08-08 15:23:39 +03:00
Леонид Юрьев (Leonid Yuriev)
dd01aabaeb mdbx: add MDBX_WEAK_IMPORT_ATTRIBUTE macro. 2022-08-08 15:18:16 +03:00
Леонид Юрьев (Leonid Yuriev)
f0a46da6a5 mdbx-make: using ldd to check used dso. 2022-08-06 19:42:38 +03:00
Леонид Юрьев (Leonid Yuriev)
06734bf8ff mdbx: don't check owner for finished transactions. 2022-08-06 13:19:49 +03:00
14 changed files with 266 additions and 255 deletions

View File

@@ -1,10 +1,38 @@
ChangeLog
---------
## v0.11.10 (the TriColor) at 2022-08-22
The stable bugfix release.
It is planned that this will be the last release of the v0.11 branch.
New:
- The C++ API has been refined to simplify support for `wchar_t` in path names.
- Added explicit error message for Buildroot's Microblaze toolchain maintainers.
Fixes:
- Never use modern `__cxa_thread_atexit()` on Apple's OSes.
- Use `MultiByteToWideChar(CP_THREAD_ACP)` instead of `mbstowcs()`.
- Don't check owner for finished transactions.
- Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG.
Minors:
- Fixed variable name typo.
- Using `ldd` to check used dso.
- Added `MDBX_WEAK_IMPORT_ATTRIBUTE` macro.
- Use current transaction geometry for untouched parameters when `env_set_geometry()` called within a write transaction.
- Minor clarified `iov_page()` failure case.
-------------------------------------------------------------------------------
## v0.11.9 (Чирчик-1992) at 2022-08-02
The stable bugfix release.
It is planned that this will be the last release of the v0.11 branch.
```
18 files changed, 318 insertions(+), 178 deletions(-)

View File

@@ -808,13 +808,13 @@ else
define bench-rule
bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST))
@echo ' RUNNING ioarena for $1/$2...'
$(QUIET)LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
$(QUIET)(export LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}"; \
ldd $(IOARENA) && \
$(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \
| tee $$@ | grep throughput && \
LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}" \
$(IOARENA) -D $(1) -B get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \
| tee -a $$@ | grep throughput \
|| mv -f $$@ $$@.error
| tee $$@ | grep throughput && \
$(IOARENA) -D $(1) -B iterate,get,iterate,get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \
| tee -a $$@ | grep throughput \
) || mv -f $$@ $$@.error
endef

View File

@@ -157,12 +157,12 @@
#define nullptr NULL
#endif
#ifdef __APPLE__
#if defined(__APPLE__) || defined(_DARWIN_C_SOURCE)
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#ifndef MAC_OS_X_VERSION_MIN_REQUIRED
#define MAC_OS_X_VERSION_MIN_REQUIRED 1070 /* Mac OS X 10.7, 2011 */
#endif
#include <TargetConditionals.h>
#endif /* Apple OSX & iOS */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
@@ -611,6 +611,19 @@ __extern_C key_t ftok(const char *, int);
#endif
#endif /* __anonymous_struct_extension__ */
#ifndef MDBX_WEAK_IMPORT_ATTRIBUTE
#ifdef WEAK_IMPORT_ATTRIBUTE
#define MDBX_WEAK_IMPORT_ATTRIBUTE WEAK_IMPORT_ATTRIBUTE
#elif __has_attribute(__weak__) && __has_attribute(__weak_import__)
#define MDBX_WEAK_IMPORT_ATTRIBUTE __attribute__((__weak__, __weak_import__))
#elif __has_attribute(__weak__) || \
(defined(__GNUC__) && __GNUC__ >= 4 && defined(__ELF__))
#define MDBX_WEAK_IMPORT_ATTRIBUTE __attribute__((__weak__))
#else
#define MDBX_WEAK_IMPORT_ATTRIBUTE
#endif
#endif /* MDBX_WEAK_IMPORT_ATTRIBUTE */
/*----------------------------------------------------------------------------*/
#if defined(MDBX_USE_VALGRIND)

View File

@@ -1269,55 +1269,50 @@ rthc_compare_and_clean(const void *rthc, const uint64_t signature) {
static __inline int rthc_atexit(void (*dtor)(void *), void *obj,
void *dso_symbol) {
int rc = MDBX_ENOSYS;
#ifndef MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL
#if defined(LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) || \
defined(HAVE___CXA_THREAD_ATEXIT_IMPL) || __GLIBC_PREREQ(2, 18) || \
defined(ANDROID)
#define MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL 1
#else
#define MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL 0
#endif
#endif /* MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL */
#if defined(__APPLE__) || defined(_DARWIN_C_SOURCE)
#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || !defined(MAC_OS_X_VERSION_10_7)
#error \
"The <AvailabilityMacros.h> should be included and MAC_OS_X_VERSION_MIN_REQUIRED must be defined"
#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
#ifndef MDBX_HAVE_CXA_THREAD_ATEXIT
#if defined(LIBCXXABI_HAS_CXA_THREAD_ATEXIT) || \
defined(HAVE___CXA_THREAD_ATEXIT)
#define MDBX_HAVE_CXA_THREAD_ATEXIT 1
#elif !MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL && \
(defined(__linux__) || defined(__gnu_linux__))
#define MDBX_HAVE_CXA_THREAD_ATEXIT 1
#else
#define MDBX_HAVE_CXA_THREAD_ATEXIT 0
#endif
#endif /* MDBX_HAVE_CXA_THREAD_ATEXIT */
int rc = MDBX_ENOSYS;
#if MDBX_HAVE_CXA_THREAD_ATEXIT_IMPL && !MDBX_HAVE_CXA_THREAD_ATEXIT
#define __cxa_thread_atexit __cxa_thread_atexit_impl
#endif
#if MDBX_HAVE_CXA_THREAD_ATEXIT || defined(__cxa_thread_atexit)
extern int __cxa_thread_atexit(void (*dtor)(void *), void *obj,
void *dso_symbol) MDBX_WEAK_IMPORT_ATTRIBUTE;
if (&__cxa_thread_atexit)
rc = __cxa_thread_atexit(dtor, obj, dso_symbol);
#elif defined(__APPLE__) || defined(_DARWIN_C_SOURCE)
extern void _tlv_atexit(void (*termfunc)(void *objAddr), void *objAddr)
__attribute__((__weak__, __weak_import__));
if (rc && &_tlv_atexit) {
MDBX_WEAK_IMPORT_ATTRIBUTE;
if (&_tlv_atexit) {
(void)dso_symbol;
_tlv_atexit(dtor, obj);
rc = 0;
}
#elif !defined(MDBX_HAVE_CXA_THREAD_ATEXIT)
#define MDBX_HAVE_CXA_THREAD_ATEXIT 1
#endif /* MAC_OS_X_VERSION_MIN_REQUIRED */
#endif /* Apple */
#if defined(MDBX_HAVE_CXA_THREAD_ATEXIT) && MDBX_HAVE_CXA_THREAD_ATEXIT
extern int __cxa_thread_atexit(void (*dtor)(void *), void *obj,
void *dso_symbol)
#ifdef WEAK_IMPORT_ATTRIBUTE
WEAK_IMPORT_ATTRIBUTE
#elif defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
MAC_OS_X_VERSION_MIN_REQUIRED >= 1020 && \
((__has_attribute(__weak__) && __has_attribute(__weak_import__)) || \
(defined(__GNUC__) && __GNUC__ >= 4))
__attribute__((__weak__, __weak_import__))
#elif (__has_attribute(__weak__) || (defined(__GNUC__) && __GNUC__ >= 4)) && \
!defined(MAC_OS_X_VERSION_MIN_REQUIRED)
__attribute__((__weak__))
#endif
;
if (rc && &__cxa_thread_atexit)
rc = __cxa_thread_atexit(dtor, obj, dso_symbol);
#elif __GLIBC_PREREQ(2, 18) || defined(ANDROID) || defined(__linux__) || \
defined(__gnu_linux__)
extern int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj,
void *dso_symbol)
__attribute__((__weak__));
if (rc && &__cxa_thread_atexit_impl)
rc = __cxa_thread_atexit_impl(dtor, obj, dso_symbol);
#else
(void)dtor;
(void)obj;
(void)dso_symbol;
#endif
return rc;
}
@@ -5616,8 +5611,11 @@ static int mdbx_txn_spill(MDBX_txn *const txn, MDBX_cursor *const m0,
txn->tw.dirtyroom += spilled;
mdbx_tassert(txn, mdbx_dirtylist_check(txn));
if (ctx.iov_items)
if (ctx.iov_items) {
/* iov_page() frees dirty-pages and reset iov_items in case of failure. */
mdbx_tassert(txn, rc == MDBX_SUCCESS);
rc = mdbx_iov_write(txn, &ctx);
}
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
@@ -8152,13 +8150,19 @@ static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) {
if (unlikely(txn->mt_flags & bad_bits))
return MDBX_BAD_TXN;
mdbx_tassert(txn, (txn->mt_flags & MDBX_NOTLS) ==
((txn->mt_flags & MDBX_TXN_RDONLY)
? txn->mt_env->me_flags & MDBX_NOTLS
: 0));
#if MDBX_TXN_CHECKOWNER
if ((txn->mt_flags & MDBX_NOTLS) == 0 &&
unlikely(txn->mt_owner != mdbx_thread_self()))
STATIC_ASSERT(MDBX_NOTLS > MDBX_TXN_FINISHED + MDBX_TXN_RDONLY);
if (unlikely(txn->mt_owner != mdbx_thread_self()) &&
(txn->mt_flags & (MDBX_NOTLS | MDBX_TXN_FINISHED | MDBX_TXN_RDONLY)) <
(MDBX_TXN_FINISHED | MDBX_TXN_RDONLY))
return txn->mt_owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
#endif /* MDBX_TXN_CHECKOWNER */
if (unlikely(!txn->mt_env->me_map))
if (bad_bits && unlikely(!txn->mt_env->me_map))
return MDBX_EPERM;
return MDBX_SUCCESS;
@@ -8959,6 +8963,9 @@ int mdbx_txn_abort(MDBX_txn *txn) {
return mdbx_txn_end(txn, MDBX_END_ABORT | MDBX_END_UPDATE | MDBX_END_SLOT |
MDBX_END_FREE);
if (unlikely(txn->mt_flags & MDBX_TXN_FINISHED))
return MDBX_BAD_TXN;
if (txn->mt_child)
mdbx_txn_abort(txn->mt_child);
@@ -9975,8 +9982,11 @@ static int mdbx_txn_write(MDBX_txn *txn, struct mdbx_iov_ctx *ctx) {
break;
}
if (ctx->iov_items)
if (ctx->iov_items) {
/* iov_page() frees dirty-pages and reset iov_items in case of failure. */
mdbx_tassert(txn, rc == MDBX_SUCCESS);
rc = mdbx_iov_write(txn, ctx);
}
while (r <= dl->length)
dl->items[++w] = dl->items[r++];
@@ -11672,38 +11682,40 @@ mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, intptr_t size_now,
if (unlikely(env->me_flags & MDBX_RDONLY))
return MDBX_EACCESS;
if (!inside_txn) {
const MDBX_geo *geo = nullptr;
if (inside_txn)
geo = &env->me_txn->mt_geo;
else {
int err = mdbx_txn_lock(env, false);
if (unlikely(err != MDBX_SUCCESS))
return err;
need_unlock = true;
}
const MDBX_meta *head = constmeta_prefer_last(env);
if (!inside_txn) {
const MDBX_meta *head = constmeta_prefer_last(env);
geo = &head->mm_geo;
env->me_txn0->mt_txnid = constmeta_txnid(env, head);
mdbx_find_oldest(env->me_txn0);
}
/* get untouched params from DB */
/* get untouched params from current write-txn or DB */
if (pagesize <= 0 || pagesize >= INT_MAX)
pagesize = env->me_psize;
if (size_lower < 0)
size_lower = pgno2bytes(env, head->mm_geo.lower);
size_lower = pgno2bytes(env, geo->lower);
if (size_now < 0)
size_now = pgno2bytes(env, head->mm_geo.now);
size_now = pgno2bytes(env, geo->now);
if (size_upper < 0)
size_upper = pgno2bytes(env, head->mm_geo.upper);
size_upper = pgno2bytes(env, geo->upper);
if (growth_step < 0)
growth_step = pgno2bytes(env, pv2pages(head->mm_geo.grow_pv));
growth_step = pgno2bytes(env, pv2pages(geo->grow_pv));
if (shrink_threshold < 0)
shrink_threshold = pgno2bytes(env, pv2pages(head->mm_geo.shrink_pv));
shrink_threshold = pgno2bytes(env, pv2pages(geo->shrink_pv));
if (pagesize != (intptr_t)env->me_psize) {
rc = MDBX_EINVAL;
goto bailout;
}
const size_t usedbytes =
pgno2bytes(env, mdbx_find_largest(env, head->mm_geo.next));
const size_t usedbytes = pgno2bytes(env, mdbx_find_largest(env, geo->next));
if ((size_t)size_upper < usedbytes) {
rc = MDBX_MAP_FULL;
goto bailout;
@@ -12439,7 +12451,7 @@ __cold static int mdbx_setup_dxb(MDBX_env *env, const int lck_rc,
} else {
const txnid_t txnid = constmeta_txnid(env, head);
const txnid_t next_txnid = safe64_txnid_next(txnid);
if (unlikely(txnid > MAX_TXNID)) {
if (unlikely(next_txnid > MAX_TXNID)) {
mdbx_error("txnid overflow, raise %d", MDBX_TXN_FULL);
return MDBX_TXN_FULL;
}
@@ -12972,12 +12984,8 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx,
return MDBX_EINVAL;
#if defined(_WIN32) || defined(_WIN64)
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
return ERROR_INVALID_NAME;
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
return ERROR_INVALID_NAME;
const wchar_t *pathnameW = nullptr;
MUSTDIE_MB2WIDE(pathname, pathnameW);
const DWORD dwAttrib = GetFileAttributesW(pathnameW);
if (dwAttrib == INVALID_FILE_ATTRIBUTES) {
@@ -15251,7 +15259,7 @@ int mdbx_cursor_get_batch(MDBX_cursor *mc, size_t *count, MDBX_val *pairs,
break;
default:
mdbx_debug("unhandled/unimplemented cursor operation %u", op);
rc = EINVAL;
rc = MDBX_EINVAL;
break;
}

View File

@@ -201,9 +201,12 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck,
((uint64_t)offset + (uint64_t)len));
for (;;) {
struct flock lock_op;
STATIC_ASSERT(sizeof(off_t) <= sizeof(lock_op.l_start) &&
sizeof(off_t) <= sizeof(lock_op.l_len) &&
OFF_T_MAX == (off_t)OFF_T_MAX);
STATIC_ASSERT_MSG(sizeof(off_t) <= sizeof(lock_op.l_start) &&
sizeof(off_t) <= sizeof(lock_op.l_len) &&
OFF_T_MAX == (off_t)OFF_T_MAX,
"Support for large/64-bit-sized files is misconfigured "
"for the target system and/or toolchain. "
"Please fix it or at least disable it completely.");
memset(&lock_op, 0, sizeof(lock_op));
lock_op.l_type = lck;
lock_op.l_whence = SEEK_SET;

View File

@@ -1,6 +1,6 @@
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_CHK 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_CHK 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_chk \- MDBX checking tool
.SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_COPY 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_COPY 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_copy \- MDBX environment copy tool
.SH SYNOPSIS

View File

@@ -1,7 +1,7 @@
.\" Copyright 2021-2022 Leonid Yuriev <leo@yuriev.ru>.
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_DROP 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_DROP 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_drop \- MDBX database delete tool
.SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_DUMP 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_DUMP 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_dump \- MDBX environment export tool
.SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_LOAD 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_LOAD 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_load \- MDBX environment import tool
.SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.TH MDBX_STAT 1 "2022-08-02" "MDBX 0.11.9"
.TH MDBX_STAT 1 "2022-08-22" "MDBX 0.11.10"
.SH NAME
mdbx_stat \- MDBX environment status tool
.SH SYNOPSIS

View File

@@ -203,58 +203,35 @@ __cold bug::~bug() noexcept {}
//------------------------------------------------------------------------------
template <typename PATH> struct path_to_pchar {
const std::string str;
path_to_pchar(const PATH &path) : str(path.generic_string()) {}
operator const char *() const { return str.c_str(); }
};
template <typename PATH>
MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) {
return PATH(c_str);
}
#if defined(_WIN32) || defined(_WIN64)
#ifndef WC_ERR_INVALID_CHARS
static const DWORD WC_ERR_INVALID_CHARS =
(6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion())))
? 0x00000080
: 0;
#endif /* WC_ERR_INVALID_CHARS */
template <> struct path_to_pchar<std::wstring> {
std::string str;
path_to_pchar(const std::wstring &path) {
if (!path.empty()) {
const int chars =
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
int(path.size()), nullptr, 0, nullptr, nullptr);
if (chars == 0)
mdbx::error::throw_exception(GetLastError());
str.append(chars, '\0');
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
int(path.size()), const_cast<char *>(str.data()),
chars, nullptr, nullptr);
}
}
operator const char *() const { return str.c_str(); }
};
template <>
MDBX_MAYBE_UNUSED std::wstring pchar_to_path<std::wstring>(const char *c_str) {
std::wstring wstr;
if (c_str && *c_str) {
const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
int(strlen(c_str)), nullptr, 0);
if (chars == 0)
std::string w2mb(const std::wstring &in) {
std::string out;
if (!in.empty()) {
const auto out_len = mdbx_w2mb(nullptr, 0, in.data(), in.size());
if (out_len < 1)
mdbx::error::throw_exception(GetLastError());
out.append(out_len, '\0');
if (out_len != mdbx_w2mb(const_cast<char *>(out.data()), out_len, in.data(),
in.size()))
mdbx::error::throw_exception(GetLastError());
wstr.append(chars, '\0');
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
int(strlen(c_str)), const_cast<wchar_t *>(wstr.data()),
chars);
}
return wstr;
return out;
}
std::wstring mb2w(const char *in) {
std::wstring out;
if (in && *in) {
const auto in_len = strlen(in);
const auto out_len = mdbx_mb2w(nullptr, 0, in, in_len);
if (out_len < 1)
mdbx::error::throw_exception(GetLastError());
out.append(out_len, '\0');
if (out_len !=
mdbx_mb2w(const_cast<wchar_t *>(out.data()), out_len, in, in_len))
mdbx::error::throw_exception(GetLastError());
}
return out;
}
#endif /* Windows */
@@ -1239,31 +1216,14 @@ bool env::is_pristine() const {
bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; }
#ifdef MDBX_STD_FILESYSTEM_PATH
env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
bool force_dynamic_size) {
const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(destination);
env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
error::success_or_throw(
::mdbx_env_copy(handle_, utf8,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
::mdbx_env_copy2fd(handle_, fd,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
return *this;
}
#endif /* MDBX_STD_FILESYSTEM_PATH */
#if defined(_WIN32) || defined(_WIN64)
env &env::copy(const ::std::wstring &destination, bool compactify,
bool force_dynamic_size) {
const path_to_pchar<::std::wstring> utf8(destination);
error::success_or_throw(
::mdbx_env_copy(handle_, utf8,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
return *this;
}
#endif /* Windows */
env &env::copy(const char *destination, bool compactify,
bool force_dynamic_size) {
@@ -1280,38 +1240,32 @@ env &env::copy(const ::std::string &destination, bool compactify,
return copy(destination.c_str(), compactify, force_dynamic_size);
}
env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
error::success_or_throw(
::mdbx_env_copy2fd(handle_, fd,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
return *this;
}
path env::get_path() const {
const char *c_str;
error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
return pchar_to_path<path>(c_str);
}
#ifdef MDBX_STD_FILESYSTEM_PATH
bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
const remove_mode mode) {
const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
return error::boolean_or_throw(
::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode)));
env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
bool force_dynamic_size) {
return copy(destination.native(), compactify, force_dynamic_size);
}
#endif /* MDBX_STD_FILESYSTEM_PATH */
#if defined(_WIN32) || defined(_WIN64)
bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
const path_to_pchar<::std::wstring> utf8(pathname);
return error::boolean_or_throw(
::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode)));
env &env::copy(const ::std::wstring &destination, bool compactify,
bool force_dynamic_size) {
return copy(w2mb(destination), compactify, force_dynamic_size);
}
#endif /* Windows */
path env::get_path() const {
const char *c_str;
error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
#if defined(_WIN32) || defined(_WIN64)
static_assert(sizeof(path::value_type) == sizeof(wchar_t), "Oops");
return path(mb2w(c_str));
#else
static_assert(sizeof(path::value_type) == sizeof(char), "Oops");
return path(c_str);
#endif
}
bool env::remove(const char *pathname, const remove_mode mode) {
return error::boolean_or_throw(
::mdbx_env_delete(pathname, MDBX_env_delete_mode_t(mode)));
@@ -1321,6 +1275,19 @@ bool env::remove(const ::std::string &pathname, const remove_mode mode) {
return remove(pathname.c_str(), mode);
}
#ifdef MDBX_STD_FILESYSTEM_PATH
bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
const remove_mode mode) {
return remove(pathname.native(), mode);
}
#endif /* MDBX_STD_FILESYSTEM_PATH */
#if defined(_WIN32) || defined(_WIN64)
bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
return remove(w2mb(pathname), mode);
}
#endif /* Windows */
//------------------------------------------------------------------------------
static inline MDBX_env *create_env() {
@@ -1357,68 +1324,6 @@ __cold void env_managed::setup(unsigned max_maps, unsigned max_readers) {
error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps));
}
#ifdef MDBX_STD_FILESYSTEM_PATH
__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
const operate_parameters &op, bool accede)
: env_managed(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
const env_managed::create_parameters &cp,
const env::operate_parameters &op, bool accede)
: env_managed(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<MDBX_STD_FILESYSTEM_PATH> utf8(pathname);
set_geometry(cp.geometry);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
cp.file_mode_bits));
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
#endif /* MDBX_STD_FILESYSTEM_PATH */
#if defined(_WIN32) || defined(_WIN64)
__cold env_managed::env_managed(const ::std::wstring &pathname,
const operate_parameters &op, bool accede)
: env_managed(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<::std::wstring> utf8(pathname);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env_managed::env_managed(const ::std::wstring &pathname,
const env_managed::create_parameters &cp,
const env::operate_parameters &op, bool accede)
: env_managed(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<::std::wstring> utf8(pathname);
set_geometry(cp.geometry);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
cp.file_mode_bits));
if (op.options.nested_write_transactions &&
!get_options().nested_write_transactions)
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
}
#endif /* Windows */
__cold env_managed::env_managed(const char *pathname,
const operate_parameters &op, bool accede)
: env_managed(create_env()) {
@@ -1455,6 +1360,28 @@ __cold env_managed::env_managed(const ::std::string &pathname,
const env::operate_parameters &op, bool accede)
: env_managed(pathname.c_str(), cp, op, accede) {}
#ifdef MDBX_STD_FILESYSTEM_PATH
__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
const operate_parameters &op, bool accede)
: env_managed(pathname.native(), op, accede) {}
__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
const env_managed::create_parameters &cp,
const env::operate_parameters &op, bool accede)
: env_managed(pathname.native(), cp, op, accede) {}
#endif /* MDBX_STD_FILESYSTEM_PATH */
#if defined(_WIN32) || defined(_WIN64)
__cold env_managed::env_managed(const ::std::wstring &pathname,
const operate_parameters &op, bool accede)
: env_managed(w2mb(pathname), op, accede) {}
__cold env_managed::env_managed(const ::std::wstring &pathname,
const env_managed::create_parameters &cp,
const env::operate_parameters &op, bool accede)
: env_managed(w2mb(pathname), cp, op, accede) {}
#endif /* Windows */
//------------------------------------------------------------------------------
txn_managed txn::start_nested() {

View File

@@ -518,14 +518,35 @@ MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) {
/*----------------------------------------------------------------------------*/
#if defined(_WIN32) || defined(_WIN64)
#ifndef WC_ERR_INVALID_CHARS
static const DWORD WC_ERR_INVALID_CHARS =
(6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion())))
? 0x00000080
: 0;
#endif /* WC_ERR_INVALID_CHARS */
MDBX_INTERNAL_FUNC size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src,
size_t src_n) {
return MultiByteToWideChar(CP_THREAD_ACP, MB_ERR_INVALID_CHARS, src,
(int)src_n, dst, (int)dst_n);
}
MDBX_INTERNAL_FUNC size_t mdbx_w2mb(char *dst, size_t dst_n, const wchar_t *src,
size_t src_n) {
return WideCharToMultiByte(CP_THREAD_ACP, WC_ERR_INVALID_CHARS, src,
(int)src_n, dst, (int)dst_n, nullptr, nullptr);
}
#endif /* Windows */
/*----------------------------------------------------------------------------*/
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
#if defined(_WIN32) || defined(_WIN64)
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
return ERROR_INVALID_NAME;
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
return ERROR_INVALID_NAME;
const wchar_t *pathnameW = nullptr;
MUSTDIE_MB2WIDE(pathname, pathnameW);
return DeleteFileW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError();
#else
return unlink(pathname) ? errno : MDBX_SUCCESS;
@@ -538,12 +559,8 @@ static bool is_valid_fd(int fd) { return !(isatty(fd) < 0 && errno == EBADF); }
MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) {
#if defined(_WIN32) || defined(_WIN64)
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
return ERROR_INVALID_NAME;
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
return ERROR_INVALID_NAME;
const wchar_t *pathnameW = nullptr;
MUSTDIE_MB2WIDE(pathname, pathnameW);
return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError();
#else
return rmdir(pathname) ? errno : MDBX_SUCCESS;
@@ -557,12 +574,8 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
*fd = INVALID_HANDLE_VALUE;
#if defined(_WIN32) || defined(_WIN64)
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
return ERROR_INVALID_NAME;
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
return ERROR_INVALID_NAME;
const wchar_t *pathnameW = nullptr;
MUSTDIE_MB2WIDE(pathname, pathnameW);
DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING;
DWORD FlagsAndAttributes =

View File

@@ -180,6 +180,11 @@ static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
#define vsnprintf _vsnprintf /* ntdll */
#endif
MDBX_INTERNAL_FUNC size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src,
size_t src_n);
MDBX_INTERNAL_FUNC size_t mdbx_w2mb(char *dst, size_t dst_n, const wchar_t *src,
size_t src_n);
#else /*----------------------------------------------------------------------*/
typedef pthread_t mdbx_thread_t;
@@ -549,6 +554,20 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
#if defined(_WIN32) || defined(_WIN64)
#define MUSTDIE_MB2WIDE(FROM, TO) \
do { \
const char *const from_tmp = (FROM); \
const size_t from_mblen = strlen(from_tmp); \
const size_t to_wlen = mdbx_mb2w(nullptr, 0, from_tmp, from_mblen); \
if (to_wlen < 1 || to_wlen > /* MAX_PATH */ INT16_MAX) \
return ERROR_INVALID_NAME; \
wchar_t *const to_tmp = _alloca((to_wlen + 1) * sizeof(wchar_t)); \
if (to_wlen + 1 != \
mdbx_mb2w(to_tmp, to_wlen + 1, from_tmp, from_mblen + 1)) \
return ERROR_INVALID_NAME; \
(TO) = to_tmp; \
} while (0)
typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,