mirror of
https://github.com/isar/libmdbx.git
synced 2025-08-04 11:44:43 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
566b0f93c7 | ||
|
df3a18d0cf | ||
|
675b462601 | ||
|
7c990542e3 | ||
|
9093435ce6 | ||
|
7ef7a1f983 | ||
|
ac275d246b | ||
|
d2f4697df3 | ||
|
b107842c3d | ||
|
cb428e613f | ||
|
5c69cb322a | ||
|
6318ca701a | ||
|
9c1f3aa4b5 | ||
|
759d0442d4 | ||
|
6cb9305b31 | ||
|
68f9dc18be | ||
|
f5aa804a2d | ||
|
7468ce6ada | ||
|
decf34fd2b | ||
|
f1b933c541 | ||
|
230fbd64f5 | ||
|
e8bfffc9f6 | ||
|
6abaa67eb8 | ||
|
266937e72d |
57
ChangeLog.md
57
ChangeLog.md
@ -4,9 +4,62 @@ ChangeLog
|
||||
English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__change_log.html?_x_tr_sl=ru&_x_tr_tl=en)
|
||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html).
|
||||
|
||||
## v0.13.7 в процессе накопления изменений, выпуск запланирован на конец мая.
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx) and mirrors on [abf.io](https://abf.io/erthink/libmdbx), [hub.mos.ru](https://hub.mos.ru/leo/libmdbx) and [Github](https://github.com/erthink/libmdbx).
|
||||
Please use the `stable` branch or the latest release for production environment through stagging, but the `master` branch for development a derivative projects.
|
||||
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||
Всё будет хорошо!
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
||||
|
||||
## v0.13.7 "Дружба" (Friendship) от 2025-07-30.
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов,
|
||||
в [международный день дружбы](https://www.un.org/ru/observances/friendship-day).
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Erigon](https://erigon.tech/) за спонсорство.
|
||||
- [Артёму Воротникову](https://github.com/vorot93) за сообщение об ошибках и тестировании [призязок для Rust](https://github.com/vorot93/libmdbx-rs).
|
||||
|
||||
Исправления:
|
||||
|
||||
- Устранена критическая ошибка в функционале `mdbx_env_resurrect_after_fork()` при использовании SysV-семафоров.
|
||||
|
||||
Проявлялась ошибка только после порождения дочернего процесса посредством `fork()` на фоне выполняющейся пишущей транзакции, что
|
||||
приводило к неверной работе семафоров и далее к самым различным ошибкам, вплоть до повреждения БД. Проблема существовала начиная с появления
|
||||
`mdbx_env_resurrect_after_fork()` и затрагивала OSX, а также POSIX-платформы при сборке с опцией `MDBX_LOCKING=5`.
|
||||
|
||||
- Устранена проблема в API копирования БД на отличных от Linux системах POSIX,
|
||||
а также в некоторых случаях при расположении целевого файла на не-локальной файловой системе.
|
||||
Проблема проявлялась в основном на OSX, возвратом ошибки `EWOULDBLOCK`/`EAGAIN` (35),
|
||||
что обусловлено недочетом/конфликтом блокировок `fcntl(F_SETLK)` и `flock()` в ядре ОС.
|
||||
Переработана обработка ошибок захвата файловых блокировок в API копирования на системах POSIX.
|
||||
|
||||
- Устранена ошибка приводившая к неожиданному возврату `MDBX_BAD_DBI` при одновременном старте нескольких транзакций внутри одного процесса после открытия БД.
|
||||
|
||||
- Устранена ошибка приводившая к неожиданному возврату `MDBX_DBS_FULL` при повторном открытии уже открытых таблиц и уже достигнутом лимите открытых DBI-дескрипторов.
|
||||
|
||||
- Исправлена ошибка сборки для платформы Android при явном определении `_FILE_OFFSET_BITS`.
|
||||
|
||||
- Исправлена ошибка использования `ENOMEM` вместо `MDBX_ENOMEM`.
|
||||
Что могло ломать сборку на не-POSIX/Windows платформах, в зависимости от конфигурации и/или версии SDK.
|
||||
|
||||
- Поправлено либо удалено несколько неверных assert-проверок, из-за которых происходили падения отладочных сборок в специфических ситуациях.
|
||||
Главным образом, в коде функций `txn_end()`, `txn_lock()` и `txn_unlock()` как на Windows, так и на POSIX.
|
||||
|
||||
- Устранены несущественные предупреждения MSVC. Отключены предупреждения `C5286` и `C5287`.
|
||||
|
||||
Прочие доработки:
|
||||
|
||||
- Доработана логика отказа от использования OFD-блокировок на POSIX-платформах.
|
||||
Теперь кроме `EINVAL` учитываются дополнительные коды ошибок (`ENOSYS`, `ENOIMPL`, `ENOTSUP`, `ENOSUPP`, `EOPNOTSUPP`),
|
||||
что позволит работать собранной библиотеке в некоторых случаях,
|
||||
когда актуальное ядро/контейнер/эмулятор не поддерживает требуемых системных вызовов.
|
||||
|
||||
- В тестовый фреймворк добавлена поддержка опции --numa # для привязки стохастического теста к NUMA-узлу,
|
||||
а в battery/tmux-скрипте добавлено явное распределение по NUMA-узлам, что существенно увеличило КПД
|
||||
при тестировании на NUMA-машинах.
|
||||
|
||||
- В стохастическом скрипте реализован случайный порядок запуска отдельных тестов.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
29
GNUmakefile
29
GNUmakefile
@ -384,8 +384,9 @@ endef
|
||||
|
||||
define uname2titer
|
||||
case "$(UNAME)" in
|
||||
CYGWIN*|MINGW*|MSYS*|Windows*) echo 2;;
|
||||
Darwin*|Mach*) echo 2;;
|
||||
*) echo 12;;
|
||||
*) if [ -z "${CI}" ]; then echo 7; else echo 3; fi;;
|
||||
esac
|
||||
endef
|
||||
|
||||
@ -809,17 +810,21 @@ endif
|
||||
# Cross-compilation simple test
|
||||
|
||||
CROSS_LIST = \
|
||||
mips64-linux-gnuabi64-gcc mips-linux-gnu-gcc \
|
||||
hppa-linux-gnu-gcc s390x-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc powerpc-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc
|
||||
aarch64-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc \
|
||||
hppa-linux-gnu-gcc \
|
||||
mips64-linux-gnuabi64-gcc \
|
||||
mips-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc\
|
||||
riscv64-linux-gnu-gcc \
|
||||
s390x-linux-gnu-gcc \
|
||||
sh4-linux-gnu-gcc
|
||||
|
||||
## On Ubuntu Focal (22.04) with QEMU 6.2 (1:6.2+dfsg-2ubuntu6.6) & GCC 11.3 (11.3.0-1ubuntu1~22.04)
|
||||
# sh4-linux-gnu-gcc - coredump (qemu mmap-troubles)
|
||||
# sparc64-linux-gnu-gcc - coredump (qemu mmap-troubles, previously: qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
# alpha-linux-gnu-gcc - coredump (qemu mmap-troubles)
|
||||
# risc64-linux-gnu-gcc - coredump (qemu qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
CROSS_LIST_NOQEMU = sh4-linux-gnu-gcc sparc64-linux-gnu-gcc alpha-linux-gnu-gcc riscv64-linux-gnu-gcc
|
||||
## On Ubuntu Noble (24.04.2) with QEMU 8.2 (8.2.2+ds-0ubuntu1.7) & GCC 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
|
||||
# sparc64-linux-gnu-gcc - fails mmap/BAD_ADDRESS (previously: qemu-coredump sice mmap-troubles, qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
# alpha-linux-gnu-gcc - qemu-coredump (qemu mmap-troubles)
|
||||
# powerpc-linux-gnu-gcc - fails mmap/BAD_ADDRESS (previously: qemu-coredump sice mmap-troubles, qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
CROSS_LIST_NOQEMU = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc powerpc-linux-gnu-gcc
|
||||
|
||||
cross-gcc:
|
||||
@echo ' Re-building by cross-compiler for: $(CROSS_LIST_NOQEMU) $(CROSS_LIST)'
|
||||
@ -841,7 +846,7 @@ cross-qemu:
|
||||
$(QUIET)for CC in $(CROSS_LIST); do \
|
||||
echo "===================== $$CC + qemu"; \
|
||||
$(MAKE) IOARENA=false CXXSTD= clean && \
|
||||
CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \
|
||||
CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_LOCKING=5 -DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \
|
||||
$(MAKE) IOARENA=false smoke-singleprocess test-singleprocess || exit $$?; \
|
||||
done
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
||||
|
||||
> Please refer to the online [documentation](https://libmdbx.dqdkfa.ru)
|
||||
> Please refer to the online [official libmdbx documentation site](https://libmdbx.dqdkfa.ru)
|
||||
> with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html)
|
||||
> and pay attention to the [`C++` API](https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1).
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx).
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx) and mirrors on [abf.io](https://abf.io/erthink/libmdbx), [hub.mos.ru](https://hub.mos.ru/leo/libmdbx) and [Github](https://github.com/erthink/libmdbx).
|
||||
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||
Всё будет хорошо!
|
||||
|
||||
|
@ -603,7 +603,7 @@ retry_snap_meta:
|
||||
continue;
|
||||
}
|
||||
rc = MDBX_ENODATA;
|
||||
if (written == 0 || ignore_enosys(rc = errno) != MDBX_RESULT_TRUE)
|
||||
if (written == 0 || ignore_enosys_and_eagain(rc = errno) != MDBX_RESULT_TRUE)
|
||||
break;
|
||||
sendfile_unavailable = true;
|
||||
}
|
||||
@ -627,7 +627,7 @@ retry_snap_meta:
|
||||
maybe useful for others FS */
|
||||
EINVAL)
|
||||
not_the_same_filesystem = true;
|
||||
else if (ignore_enosys(rc) == MDBX_RESULT_TRUE)
|
||||
else if (ignore_enosys_and_eagain(rc) == MDBX_RESULT_TRUE)
|
||||
copyfilerange_unavailable = true;
|
||||
else
|
||||
break;
|
||||
@ -755,35 +755,67 @@ __cold static int copy2pathname(MDBX_txn *txn, const pathchar_t *dest_path, MDBX
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
|
||||
#endif
|
||||
);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* no locking required since the file opened with ShareMode == 0 */
|
||||
#else
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
MDBX_STRUCT_FLOCK lock_op;
|
||||
memset(&lock_op, 0, sizeof(lock_op));
|
||||
lock_op.l_type = F_WRLCK;
|
||||
lock_op.l_whence = SEEK_SET;
|
||||
lock_op.l_start = 0;
|
||||
lock_op.l_len = OFF_T_MAX;
|
||||
if (MDBX_FCNTL(newfd, MDBX_F_SETLK, &lock_op))
|
||||
rc = errno;
|
||||
}
|
||||
const int err_fcntl = MDBX_FCNTL(newfd, MDBX_F_SETLK, &lock_op) ? errno : MDBX_SUCCESS;
|
||||
|
||||
#if defined(LOCK_EX) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 24)
|
||||
if (rc == MDBX_SUCCESS && flock(newfd, LOCK_EX | LOCK_NB)) {
|
||||
const int err_flock = errno, err_fs = osal_check_fs_local(newfd, 0);
|
||||
if (err_flock != EAGAIN || err_fs != MDBX_EREMOTE) {
|
||||
ERROR("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "unexpected", dest_path, err_flock,
|
||||
err_fs);
|
||||
const int err_flock =
|
||||
#ifdef LOCK_EX
|
||||
flock(newfd, LOCK_EX | LOCK_NB) ? errno : MDBX_SUCCESS;
|
||||
#else
|
||||
MDBX_ENOSYS;
|
||||
#endif /* LOCK_EX */
|
||||
|
||||
const int err_check_fs_local =
|
||||
/* avoid call osal_check_fs_local() on success */
|
||||
(!err_fcntl && !err_flock && !MDBX_DEBUG) ? MDBX_SUCCESS :
|
||||
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 24
|
||||
osal_check_fs_local(newfd, 0);
|
||||
#else
|
||||
MDBX_ENOSYS;
|
||||
#endif
|
||||
|
||||
const bool flock_may_fail =
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
err_check_fs_local != 0;
|
||||
#else
|
||||
true;
|
||||
#endif /* Linux */
|
||||
|
||||
if (!err_fcntl &&
|
||||
(err_flock == EWOULDBLOCK || err_flock == EAGAIN || ignore_enosys_and_eremote(err_flock) == MDBX_RESULT_TRUE)) {
|
||||
rc = err_flock;
|
||||
} else {
|
||||
WARNING("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "ignore", dest_path, err_flock,
|
||||
err_fs);
|
||||
if (flock_may_fail) {
|
||||
WARNING("ignore %s(%" MDBX_PRIsPATH ") error %d: since %s done, local/remote-fs check %d", "flock", dest_path,
|
||||
err_flock, "fcntl-lock", err_check_fs_local);
|
||||
rc = MDBX_SUCCESS;
|
||||
}
|
||||
} else if (!err_flock && err_check_fs_local == MDBX_RESULT_TRUE &&
|
||||
ignore_enosys_and_eremote(err_fcntl) == MDBX_RESULT_TRUE) {
|
||||
WARNING("ignore %s(%" MDBX_PRIsPATH ") error %d: since %s done, local/remote-fs check %d", "fcntl-lock", dest_path,
|
||||
err_fcntl, "flock", err_check_fs_local);
|
||||
} else if (err_fcntl || err_flock) {
|
||||
ERROR("file-lock(%" MDBX_PRIsPATH ") failed: fcntl-lock %d, flock %d, local/remote-fs check %d", dest_path,
|
||||
err_fcntl, err_flock, err_check_fs_local);
|
||||
if (err_fcntl == ENOLCK || err_flock == ENOLCK)
|
||||
rc = ENOLCK;
|
||||
else if (err_fcntl == EWOULDBLOCK || err_flock == EWOULDBLOCK)
|
||||
rc = EWOULDBLOCK;
|
||||
else if (EWOULDBLOCK != EAGAIN && (err_fcntl == EAGAIN || err_flock == EAGAIN))
|
||||
rc = EAGAIN;
|
||||
else
|
||||
rc = (err_fcntl && ignore_enosys_and_eremote(err_fcntl) != MDBX_RESULT_TRUE) ? err_fcntl : err_flock;
|
||||
}
|
||||
#endif /* LOCK_EX && ANDROID_API >= 24 */
|
||||
|
||||
#endif /* Windows / POSIX */
|
||||
|
||||
if (rc == MDBX_SUCCESS)
|
||||
|
@ -213,7 +213,7 @@ __cold static void MDBX_PRINTF_ARGS(5, 6)
|
||||
issue->next = chk->usr->scope->issues;
|
||||
chk->usr->scope->issues = issue;
|
||||
} else
|
||||
chk_error_rc(scope, ENOMEM, "adding issue");
|
||||
chk_error_rc(scope, MDBX_ENOMEM, "adding issue");
|
||||
}
|
||||
|
||||
va_list args;
|
||||
|
17
src/cogs.h
17
src/cogs.h
@ -352,7 +352,7 @@ MDBX_CONST_FUNCTION static inline lck_t *lckless_stub(const MDBX_env *env) {
|
||||
}
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
MDBX_MAYBE_UNUSED static inline int ignore_enosys(int err) {
|
||||
MDBX_CONST_FUNCTION static inline int ignore_enosys(int err) {
|
||||
#ifdef ENOSYS
|
||||
if (err == ENOSYS)
|
||||
return MDBX_RESULT_TRUE;
|
||||
@ -373,10 +373,21 @@ MDBX_MAYBE_UNUSED static inline int ignore_enosys(int err) {
|
||||
if (err == EOPNOTSUPP)
|
||||
return MDBX_RESULT_TRUE;
|
||||
#endif /* EOPNOTSUPP */
|
||||
if (err == EAGAIN)
|
||||
return MDBX_RESULT_TRUE;
|
||||
return err;
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_eagain(int err) {
|
||||
return (err == EAGAIN) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_einval(int err) {
|
||||
return (err == EINVAL) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_eremote(int err) {
|
||||
return (err == MDBX_EREMOTE) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
static inline int check_env(const MDBX_env *env, const bool wanna_active) {
|
||||
|
73
src/dbi.c
73
src/dbi.c
@ -84,7 +84,7 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) {
|
||||
/* dbi-слот еще не инициализирован в транзакции, а хендл не использовался */
|
||||
txn->cursors[dbi] = nullptr;
|
||||
MDBX_txn *const parent = txn->parent;
|
||||
if (parent) {
|
||||
if (unlikely(parent)) {
|
||||
/* вложенная пишущая транзакция */
|
||||
int rc = dbi_check(parent, dbi);
|
||||
/* копируем состояние table очищая new-флаги. */
|
||||
@ -107,26 +107,31 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) {
|
||||
txn->dbi_state[dbi] = DBI_LINDO;
|
||||
} else {
|
||||
eASSERT(env, txn->dbi_seqs[dbi] != env->dbi_seqs[dbi].weak);
|
||||
if (unlikely((txn->dbi_state[dbi] & (DBI_VALID | DBI_OLDEN)) || txn->cursors[dbi])) {
|
||||
/* хендл уже использовался в транзакции, но был закрыт или переоткрыт,
|
||||
* либо при явном пере-открытии хендла есть висячие курсоры */
|
||||
eASSERT(env, (txn->dbi_state[dbi] & DBI_STALE) == 0);
|
||||
if (unlikely(txn->cursors[dbi])) {
|
||||
/* хендл уже использовался в транзакции и остались висячие курсоры */
|
||||
txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak;
|
||||
txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO;
|
||||
return txn->cursors[dbi] ? MDBX_DANGLING_DBI : MDBX_BAD_DBI;
|
||||
return MDBX_DANGLING_DBI;
|
||||
}
|
||||
if (unlikely(txn->dbi_state[dbi] & (DBI_OLDEN | DBI_VALID))) {
|
||||
/* хендл уже использовался в транзакции, но был закрыт или переоткрыт,
|
||||
* висячих курсоров нет */
|
||||
txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak;
|
||||
txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO;
|
||||
return MDBX_BAD_DBI;
|
||||
}
|
||||
}
|
||||
|
||||
/* хендл не использовался в транзакции, либо явно пере-отрывается при
|
||||
* отсутствии висячих курсоров */
|
||||
eASSERT(env, (txn->dbi_state[dbi] & DBI_LINDO) && !txn->cursors[dbi]);
|
||||
eASSERT(env, (txn->dbi_state[dbi] & (DBI_LINDO | DBI_VALID)) == DBI_LINDO && !txn->cursors[dbi]);
|
||||
|
||||
/* читаем актуальные флаги и sequence */
|
||||
struct dbi_snap_result snap = dbi_snap(env, dbi);
|
||||
txn->dbi_seqs[dbi] = snap.sequence;
|
||||
if (snap.flags & DB_VALID) {
|
||||
txn->dbs[dbi].flags = snap.flags & DB_PERSISTENT_FLAGS;
|
||||
txn->dbi_state[dbi] = DBI_LINDO | DBI_VALID | DBI_STALE;
|
||||
txn->dbi_state[dbi] = (dbi >= CORE_DBS) ? DBI_LINDO | DBI_VALID | DBI_STALE : DBI_LINDO | DBI_VALID;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
return MDBX_BAD_DBI;
|
||||
@ -380,7 +385,7 @@ static int dbi_open_locked(MDBX_txn *txn, unsigned user_flags, MDBX_dbi *dbi, MD
|
||||
slot = (slot < scan) ? slot : scan;
|
||||
continue;
|
||||
}
|
||||
if (!env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[scan].name)) {
|
||||
if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[scan].name) == 0) {
|
||||
slot = scan;
|
||||
int err = dbi_check(txn, slot);
|
||||
if (err == MDBX_BAD_DBI && txn->dbi_state[slot] == (DBI_OLDEN | DBI_LINDO)) {
|
||||
@ -536,34 +541,40 @@ int dbi_open(MDBX_txn *txn, const MDBX_val *const name, unsigned user_flags, MDB
|
||||
#if MDBX_ENABLE_DBI_LOCKFREE
|
||||
/* Is the DB already open? */
|
||||
const MDBX_env *const env = txn->env;
|
||||
size_t free_slot = env->n_dbi;
|
||||
bool have_free_slot = env->n_dbi < env->max_dbi;
|
||||
for (size_t i = CORE_DBS; i < env->n_dbi; ++i) {
|
||||
retry:
|
||||
if ((env->dbs_flags[i] & DB_VALID) == 0) {
|
||||
free_slot = i;
|
||||
have_free_slot = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t snap_seq = atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease);
|
||||
const uint16_t snap_flags = env->dbs_flags[i];
|
||||
struct dbi_snap_result snap = dbi_snap(env, i);
|
||||
const MDBX_val snap_name = env->kvs[i].name;
|
||||
if (user_flags != MDBX_ACCEDE &&
|
||||
(((user_flags ^ snap_flags) & DB_PERSISTENT_FLAGS) || (keycmp && keycmp != env->kvs[i].clc.k.cmp) ||
|
||||
(datacmp && datacmp != env->kvs[i].clc.v.cmp)))
|
||||
continue;
|
||||
const uint32_t main_seq = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
MDBX_cmp_func *const snap_cmp = env->kvs[MAIN_DBI].clc.k.cmp;
|
||||
if (unlikely(!(snap_flags & DB_VALID) || !snap_name.iov_base || !snap_name.iov_len || !snap_cmp))
|
||||
continue;
|
||||
if (unlikely(!(snap.flags & DB_VALID) || !snap_name.iov_base || !snap_name.iov_len || !snap_cmp))
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
|
||||
const bool name_match = snap_cmp(&snap_name, name) == 0;
|
||||
osal_flush_incoherent_cpu_writeback();
|
||||
if (unlikely(snap_seq != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
if (unlikely(snap.sequence != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
main_seq != atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease) ||
|
||||
snap_flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap.flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap_name.iov_len != env->kvs[i].name.iov_len))
|
||||
goto retry;
|
||||
if (name_match) {
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
|
||||
if (!name_match)
|
||||
continue;
|
||||
|
||||
osal_flush_incoherent_cpu_writeback();
|
||||
if (user_flags != MDBX_ACCEDE &&
|
||||
(((user_flags ^ snap.flags) & DB_PERSISTENT_FLAGS) || (keycmp && keycmp != env->kvs[i].clc.k.cmp) ||
|
||||
(datacmp && datacmp != env->kvs[i].clc.v.cmp)))
|
||||
/* есть подозрение что пользователь открывает таблицу с другими флагами/атрибутами
|
||||
* или другими компараторами, поэтому уходим в безопасный режим */
|
||||
goto slowpath_locking;
|
||||
|
||||
rc = dbi_check(txn, i);
|
||||
if (rc == MDBX_BAD_DBI && txn->dbi_state[i] == (DBI_OLDEN | DBI_LINDO)) {
|
||||
/* хендл использовался, стал невалидным,
|
||||
@ -573,17 +584,25 @@ int dbi_open(MDBX_txn *txn, const MDBX_val *const name, unsigned user_flags, MDB
|
||||
rc = dbi_check(txn, i);
|
||||
}
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
if (unlikely(snap.sequence != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
main_seq != atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease) ||
|
||||
snap.flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap_name.iov_len != env->kvs[i].name.iov_len))
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
rc = dbi_bind(txn, i, user_flags, keycmp, datacmp);
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
*dbi = (MDBX_dbi)i;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fail, if no free slot and max hit */
|
||||
if (unlikely(free_slot >= env->max_dbi))
|
||||
if (unlikely(!have_free_slot))
|
||||
return MDBX_DBS_FULL;
|
||||
|
||||
slowpath_locking:
|
||||
|
||||
#endif /* MDBX_ENABLE_DBI_LOCKFREE */
|
||||
|
||||
rc = osal_fastmutex_acquire(&txn->env->dbi_lock);
|
||||
|
23
src/dxb.c
23
src/dxb.c
@ -234,13 +234,14 @@ __cold int dxb_resize(MDBX_env *const env, const pgno_t used_pgno, const pgno_t
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
#if defined(MADV_REMOVE)
|
||||
if (env->flags & MDBX_WRITEMAP)
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_REMOVE) ? ignore_enosys(errno)
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_REMOVE)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#endif /* MADV_REMOVE */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_DONTNEED)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
@ -426,7 +427,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
void *const ptr = ptr_disp(env->dxb_mmap.base, offset);
|
||||
if (enable) {
|
||||
#if defined(MADV_NORMAL)
|
||||
err = madvise(ptr, length, MADV_NORMAL) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_NORMAL) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_NORMAL)
|
||||
@ -454,7 +455,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
hint.ra_count = unlikely(length > INT_MAX && sizeof(length) > sizeof(hint.ra_count)) ? INT_MAX : (int)length;
|
||||
(void)/* Ignore ENOTTY for DB on the ram-disk and so on */ fcntl(env->lazy_fd, F_RDADVISE, &hint);
|
||||
#elif defined(MADV_WILLNEED)
|
||||
err = madvise(ptr, length, MADV_WILLNEED) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_WILLNEED) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_WILLNEED)
|
||||
@ -479,7 +480,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
} else {
|
||||
mincore_clean_cache(env);
|
||||
#if defined(MADV_RANDOM)
|
||||
err = madvise(ptr, length, MADV_RANDOM) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_RANDOM) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_RANDOM)
|
||||
@ -686,14 +687,16 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
return err;
|
||||
|
||||
#if defined(MADV_DONTDUMP)
|
||||
err = madvise(env->dxb_mmap.base, env->dxb_mmap.limit, MADV_DONTDUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err =
|
||||
madvise(env->dxb_mmap.base, env->dxb_mmap.limit, MADV_DONTDUMP) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#endif /* MADV_DONTDUMP */
|
||||
#if defined(MADV_DODUMP)
|
||||
if (globals.runtime_flags & MDBX_DBG_DUMP) {
|
||||
const size_t meta_length_aligned2os = pgno_align2os_bytes(env, NUM_METAS);
|
||||
err = madvise(env->dxb_mmap.base, meta_length_aligned2os, MADV_DODUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->dxb_mmap.base, meta_length_aligned2os, MADV_DODUMP) ? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
}
|
||||
@ -932,7 +935,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
bytes2pgno(env, env->dxb_mmap.current));
|
||||
err = madvise(ptr_disp(env->dxb_mmap.base, used_aligned2os_bytes), env->dxb_mmap.current - used_aligned2os_bytes,
|
||||
MADV_REMOVE)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
@ -942,7 +945,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
NOTICE("open-MADV_%s %u..%u", "DONTNEED", env->lck->discarded_tail.weak, bytes2pgno(env, env->dxb_mmap.current));
|
||||
err = madvise(ptr_disp(env->dxb_mmap.base, used_aligned2os_bytes), env->dxb_mmap.current - used_aligned2os_bytes,
|
||||
MADV_DONTNEED)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
@ -1034,7 +1037,7 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika
|
||||
#endif /* MADV_FREE */
|
||||
int err = madvise(ptr_disp(env->dxb_mmap.base, discard_edge_bytes), prev_discarded_bytes - discard_edge_bytes,
|
||||
advise)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#else
|
||||
int err = ignore_enosys(posix_madvise(ptr_disp(env->dxb_mmap.base, discard_edge_bytes),
|
||||
|
@ -28,12 +28,6 @@
|
||||
typedef struct iov_ctx iov_ctx_t;
|
||||
#include "osal.h"
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64)
|
||||
#define MDBX_WORDBITS 64
|
||||
#else
|
||||
#define MDBX_WORDBITS 32
|
||||
#endif /* MDBX_WORDBITS */
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include "atomics-types.h"
|
||||
|
@ -872,10 +872,8 @@ pgr_t gc_alloc_ex(const MDBX_cursor *const mc, const size_t num, uint8_t flags)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
if (unlikely(!is_gc_usable(txn, mc, flags))) {
|
||||
eASSERT(env, (txn->flags & txn_gc_drained) || num > 1);
|
||||
if (unlikely(!is_gc_usable(txn, mc, flags)))
|
||||
goto no_gc;
|
||||
}
|
||||
|
||||
eASSERT(env, (flags & (ALLOC_COALESCE | ALLOC_LIFO | ALLOC_SHOULD_SCAN)) == 0);
|
||||
flags += (env->flags & MDBX_LIFORECLAIM) ? ALLOC_LIFO : 0;
|
||||
|
@ -93,10 +93,11 @@ __cold static void choice_fcntl(void) {
|
||||
|
||||
static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_t offset, off_t len) {
|
||||
STATIC_ASSERT(sizeof(off_t) >= sizeof(void *) && sizeof(off_t) >= sizeof(size_t));
|
||||
#ifdef __ANDROID_API__
|
||||
STATIC_ASSERT_MSG((sizeof(off_t) * 8 == MDBX_WORDBITS), "The bitness of system `off_t` type is mismatch. Please "
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
||||
STATIC_ASSERT_MSG((sizeof(off_t) * CHAR_BIT == MDBX_WORDBITS),
|
||||
"The bitness of system `off_t` type is mismatch. Please "
|
||||
"fix build and/or NDK configuration.");
|
||||
#endif /* Android */
|
||||
#endif /* Android && API < 24 */
|
||||
assert(offset >= 0 && len > 0);
|
||||
assert((uint64_t)offset < (uint64_t)INT64_MAX && (uint64_t)len < (uint64_t)INT64_MAX &&
|
||||
(uint64_t)(offset + len) > (uint64_t)offset);
|
||||
@ -132,7 +133,8 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_
|
||||
}
|
||||
rc = errno;
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (rc == EINVAL && (cmd == MDBX_F_OFD_SETLK || cmd == MDBX_F_OFD_SETLKW || cmd == MDBX_F_OFD_GETLK)) {
|
||||
if (ignore_enosys_and_einval(rc) == MDBX_RESULT_TRUE &&
|
||||
(cmd == MDBX_F_OFD_SETLK || cmd == MDBX_F_OFD_SETLKW || cmd == MDBX_F_OFD_GETLK)) {
|
||||
/* fallback to non-OFD locks */
|
||||
if (cmd == MDBX_F_OFD_SETLK)
|
||||
cmd = MDBX_F_SETLK;
|
||||
@ -460,6 +462,10 @@ __cold MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor
|
||||
jitter4testing(false);
|
||||
}
|
||||
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
env->me_sysv_ipc.semid = -1;
|
||||
#endif /* MDBX_LOCKING */
|
||||
|
||||
if (current_pid != env->pid) {
|
||||
eASSERT(env, !inprocess_neighbor);
|
||||
NOTICE("drown env %p after-fork pid %d -> %d", __Wpedantic_format_voidptr(env), env->pid, current_pid);
|
||||
@ -776,14 +782,14 @@ static int osal_ipclock_lock(MDBX_env *env, osal_ipclock_t *ipc, const bool dont
|
||||
return rc;
|
||||
}
|
||||
|
||||
int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
static int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
int err = MDBX_ENOSYS;
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
err = pthread_mutex_unlock(ipc);
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
err = sem_post(ipc) ? errno : MDBX_SUCCESS;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
if (unlikely(*ipc != (pid_t)env->pid))
|
||||
if (unlikely(*ipc != (pid_t)env->pid || env->me_sysv_ipc.key == -1))
|
||||
err = EPERM;
|
||||
else {
|
||||
*ipc = 0;
|
||||
@ -823,7 +829,6 @@ MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
|
||||
int lck_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
TRACE("%swait %s", dont_wait ? "dont-" : "", ">>");
|
||||
eASSERT(env, env->basal_txn || (env->lck == lckless_stub(env) && (env->flags & MDBX_RDONLY)));
|
||||
jitter4testing(true);
|
||||
const int err = osal_ipclock_lock(env, &env->lck->wrt_lock, dont_wait);
|
||||
int rc = err;
|
||||
@ -841,10 +846,8 @@ int lck_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
void lck_txn_unlock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
if (env->basal_txn) {
|
||||
eASSERT(env, !env->basal_txn || env->basal_txn->owner == osal_thread_self());
|
||||
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
||||
env->basal_txn->owner = 0;
|
||||
} else {
|
||||
eASSERT(env, env->lck == lckless_stub(env) && (env->flags & MDBX_RDONLY));
|
||||
}
|
||||
int err = osal_ipclock_unlock(env, &env->lck->wrt_lock);
|
||||
TRACE("<< err %d", err);
|
||||
|
@ -87,7 +87,7 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
}
|
||||
|
||||
eASSERT(env, !env->basal_txn->owner);
|
||||
eASSERT(env, !env->basal_txn || !env->basal_txn->owner);
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
goto done;
|
||||
|
||||
@ -104,10 +104,11 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
done:
|
||||
if (env->basal_txn)
|
||||
env->basal_txn->owner = osal_thread_self();
|
||||
/* Zap: Failing to release lock 'env->windowsbug_lock'
|
||||
* in function 'mdbx_txn_lock' */
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(26115);
|
||||
env->basal_txn->owner = osal_thread_self();
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
@ -116,13 +117,14 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
|
||||
void lck_txn_unlock(MDBX_env *env) {
|
||||
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
||||
eASSERT(env, !env->basal_txn || env->basal_txn->owner == osal_thread_self());
|
||||
if ((env->flags & MDBX_EXCLUSIVE) == 0) {
|
||||
const HANDLE fd4data = env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
int err = funlock(fd4data, DXB_BODY);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
if (env->basal_txn)
|
||||
env->basal_txn->owner = 0;
|
||||
LeaveCriticalSection(&env->windowsbug_lock);
|
||||
}
|
||||
|
@ -69,13 +69,13 @@ __cold static int lck_setup_locked(MDBX_env *env) {
|
||||
return err;
|
||||
|
||||
#ifdef MADV_DODUMP
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#endif /* MADV_DODUMP */
|
||||
|
||||
#ifdef MADV_WILLNEED
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_WILLNEED) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_WILLNEED) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_WILLNEED)
|
||||
|
@ -193,7 +193,14 @@ typedef struct osal_mmap {
|
||||
#elif defined(__ANDROID_API__)
|
||||
|
||||
#if __ANDROID_API__ < 24
|
||||
/* https://android-developers.googleblog.com/2017/09/introducing-android-native-development.html
|
||||
* https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "_FILE_OFFSET_BITS != MDBX_WORDBITS and __ANDROID_API__ < 24" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "__FILE_OFFSET_BITS != MDBX_WORDBITS and __ANDROID_API__ < 24" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_HAVE_PWRITEV 1
|
||||
#endif
|
||||
|
@ -122,6 +122,8 @@
|
||||
#pragma warning(disable : 6235) /* <expression> is always a constant */
|
||||
#pragma warning(disable : 6237) /* <expression> is never evaluated and might \
|
||||
have side effects */
|
||||
#pragma warning(disable : 5286) /* implicit conversion from enum type 'type 1' to enum type 'type 2' */
|
||||
#pragma warning(disable : 5287) /* operands are different enum types 'type 1' and 'type 2' */
|
||||
#endif
|
||||
#pragma warning(disable : 4710) /* 'xyz': function not inlined */
|
||||
#pragma warning(disable : 4711) /* function 'xyz' selected for automatic \
|
||||
@ -433,11 +435,6 @@ __extern_C key_t ftok(const char *, int);
|
||||
#if __ANDROID_API__ >= 21
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#endif
|
||||
#endif /* Android */
|
||||
|
||||
#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
|
||||
@ -522,6 +519,12 @@ __extern_C key_t ftok(const char *, int);
|
||||
#endif
|
||||
#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64)
|
||||
#define MDBX_WORDBITS 64
|
||||
#else
|
||||
#define MDBX_WORDBITS 32
|
||||
#endif /* MDBX_WORDBITS */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Availability of CMOV or equivalent */
|
||||
|
||||
|
17
src/txn.c
17
src/txn.c
@ -676,7 +676,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
txn->dbi_seqs[FREE_DBI] = 0;
|
||||
txn->dbi_seqs[MAIN_DBI] = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
|
||||
if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags))) {
|
||||
if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags) || !txn->dbi_seqs[MAIN_DBI])) {
|
||||
const bool need_txn_lock = env->basal_txn && env->basal_txn->owner != osal_thread_self();
|
||||
bool should_unlock = false;
|
||||
if (need_txn_lock) {
|
||||
@ -688,24 +688,24 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
}
|
||||
rc = osal_fastmutex_acquire(&env->dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
uint32_t seq = dbi_seq_next(env, MAIN_DBI);
|
||||
/* проверяем повторно после захвата блокировки */
|
||||
uint32_t seq = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
if (env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags)) {
|
||||
if (!need_txn_lock || should_unlock ||
|
||||
/* если нет активной пишущей транзакции,
|
||||
* то следующая будет ждать на dbi_lock */
|
||||
!env->txn) {
|
||||
if (env->dbs_flags[MAIN_DBI] != 0 || MDBX_DEBUG)
|
||||
if (!(env->dbs_flags[MAIN_DBI] & DB_VALID) || !need_txn_lock || should_unlock ||
|
||||
/* если нет активной пишущей транзакции, * то следующая будет ждать на dbi_lock */ !env->txn) {
|
||||
if (env->dbs_flags[MAIN_DBI] & DB_VALID) {
|
||||
NOTICE("renew MainDB for %s-txn %" PRIaTXN " since db-flags changes 0x%x -> 0x%x",
|
||||
(txn->flags & MDBX_TXN_RDONLY) ? "ro" : "rw", txn->txnid, env->dbs_flags[MAIN_DBI] & ~DB_VALID,
|
||||
txn->dbs[MAIN_DBI].flags);
|
||||
seq = dbi_seq_next(env, MAIN_DBI);
|
||||
env->dbs_flags[MAIN_DBI] = DB_POISON;
|
||||
atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
}
|
||||
rc = tbl_setup(env, &env->kvs[MAIN_DBI], &txn->dbs[MAIN_DBI]);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
seq = dbi_seq_next(env, MAIN_DBI);
|
||||
env->dbs_flags[MAIN_DBI] = DB_VALID | txn->dbs[MAIN_DBI].flags;
|
||||
txn->dbi_seqs[MAIN_DBI] = atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
}
|
||||
} else {
|
||||
ERROR("MainDB db-flags changes 0x%x -> 0x%x ahead of read-txn "
|
||||
@ -714,6 +714,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
rc = MDBX_INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
txn->dbi_seqs[MAIN_DBI] = seq;
|
||||
ENSURE(env, osal_fastmutex_release(&env->dbi_lock) == MDBX_SUCCESS);
|
||||
} else {
|
||||
DEBUG("dbi_lock failed, err %d", rc);
|
||||
|
@ -3,36 +3,62 @@
|
||||
# Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
TEST="./test/stochastic.sh --skip-make --db-upto-gb 32"
|
||||
TMUX=tmux
|
||||
DIR="$(dirname ${BASH_SOURCE[0]})"
|
||||
TEST="${DIR}/stochastic.sh --skip-make --db-upto-gb 32"
|
||||
PREFIX="/dev/shm/mdbxtest-"
|
||||
|
||||
tmux kill-session -t mdbx
|
||||
NUMACTL="$(which numactl 2>-)"
|
||||
NUMALIST=()
|
||||
NUMAIDX=0
|
||||
if [ -n "${NUMACTL}" -a $(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | wc -l) -gt 1 ]; then
|
||||
NUMALIST=($(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | cut -d ' ' -f 2))
|
||||
fi
|
||||
|
||||
function test_numacycle {
|
||||
NUMAIDX=$((NUMAIDX + 1))
|
||||
if [ ${NUMAIDX} -ge ${#NUMALIST[@]} ]; then
|
||||
NUMAIDX=0
|
||||
fi
|
||||
}
|
||||
|
||||
function test_numanode {
|
||||
if [[ ${#NUMALIST[@]} > 1 ]]; then
|
||||
echo "${TEST} --numa ${NUMALIST[$NUMAIDX]}"
|
||||
else
|
||||
echo "${TEST}"
|
||||
fi
|
||||
}
|
||||
|
||||
${TMUX} kill-session -t mdbx
|
||||
rm -rf ${PREFIX}*
|
||||
# git clean -x -f -d && make test-assertions
|
||||
tmux -f ./test/tmux.conf new-session -d -s mdbx htop
|
||||
${TMUX} -f "${DIR}/tmux.conf" new-session -d -s mdbx htop
|
||||
|
||||
W=0
|
||||
for ps in min 4k max; do
|
||||
for from in 1 30000; do
|
||||
for n in 0 1 2 3; do
|
||||
CMD="${TEST} --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
|
||||
CMD="$(test_numanode) --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
|
||||
if [ $n -eq 0 ]; then
|
||||
tmux new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
|
||||
tmux select-layout -E tiled
|
||||
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
|
||||
${TMUX} select-layout -E tiled
|
||||
else
|
||||
tmux split-window -t mdbx:$W -l 20% -d $CMD
|
||||
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
||||
fi
|
||||
test_numacycle
|
||||
done
|
||||
for n in 0 1 2 3; do
|
||||
CMD="${TEST} --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
|
||||
CMD="$(test_numanode) --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
|
||||
if [ $n -eq 0 ]; then
|
||||
tmux new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
|
||||
tmux select-layout -E tiled
|
||||
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
|
||||
${TMUX} select-layout -E tiled
|
||||
else
|
||||
tmux split-window -t mdbx:$W -l 20% -d $CMD
|
||||
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
||||
fi
|
||||
test_numacycle
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
tmux attach -t mdbx
|
||||
${TMUX} attach -t mdbx
|
||||
|
@ -2,17 +2,9 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static char log_buffer[1024];
|
||||
mdbx::path db_filename = "test-dbi";
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int doit() {
|
||||
mdbx::path db_filename = "test-dbi";
|
||||
bool case1() {
|
||||
mdbx::env::remove(db_filename);
|
||||
|
||||
mdbx::env::operate_parameters operateParameters(100, 10, mdbx::env::nested_transactions);
|
||||
@ -45,15 +37,15 @@ int doit() {
|
||||
MDBX_stat stat;
|
||||
int err = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat));
|
||||
if (err != MDBX_BAD_DBI) {
|
||||
std::cerr << "unexpected result err-code " << err;
|
||||
return EXIT_FAILURE;
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_BAD_DBI/-30780)\n";
|
||||
return false;
|
||||
}
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
{
|
||||
// снова проверяем что таблица открывается и хендл доступень в родительской транзакции после коммита открывшей его
|
||||
// дочерней
|
||||
// снова проверяем что таблица открывается и хендл доступень в родительской транзакции,
|
||||
// после коммита открывшей его дочерней
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::txn_managed nested = txn.start_nested();
|
||||
mdbx::map_handle dbi = nested.open_map_accede("fap1");
|
||||
@ -63,8 +55,165 @@ int doit() {
|
||||
env.close_map(dbi);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool case2() {
|
||||
bool ok = true;
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
mdbx::env::remove(db_filename);
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_CREATE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_CREATE | MDBX_DUPSORT | MDBX_DUPFIXED, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::map_handle dbi = txn.create_map("dup", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal);
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::map_handle dbi = txn.create_map("uni", mdbx::key_mode::reverse, mdbx::value_mode::single);
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
std::cerr << "Unexpected err " << err << "\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
std::cerr << "Unexpected err " << err << "\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool case3() {
|
||||
bool ok = true;
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
mdbx::env::remove(db_filename);
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi notexists_dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_DB_DEFAULTS, ¬exists_dbi);
|
||||
if (err != MDBX_NOTFOUND) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_NOTFOUND/-30798)\n";
|
||||
ok = false;
|
||||
}
|
||||
mdbx::map_handle dbi = txn.create_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
|
||||
dbi = txn.open_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
|
||||
err = mdbx_dbi_close(env, dbi);
|
||||
if (err != MDBX_DANGLING_DBI) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DANGLING_DBI/-30412)\n";
|
||||
ok = false;
|
||||
}
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
int doit() {
|
||||
|
||||
bool ok = true;
|
||||
ok = case1() && ok;
|
||||
ok = case2() && ok;
|
||||
ok = case3() && ok;
|
||||
|
||||
if (ok) {
|
||||
std::cout << "OK\n";
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
std::cerr << "FAIL\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -31,15 +31,6 @@ int main(int argc, const char *argv[]) {
|
||||
#include <latch>
|
||||
#include <thread>
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
bool case0(const mdbx::path &path) {
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB);
|
||||
@ -322,19 +313,85 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool case3(const mdbx::path &path, bool no_sticky_threads) {
|
||||
mdbx::env::remove(path);
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB);
|
||||
mdbx::env::operate_parameters operateParameters(100, 10);
|
||||
operateParameters.options.no_sticky_threads = no_sticky_threads;
|
||||
mdbx::env_managed env(path, createParameters, operateParameters);
|
||||
|
||||
mdbx::pair pair = {"key", "val"};
|
||||
const auto N = std::thread::hardware_concurrency() * 2;
|
||||
std::latch s0(N + 1), s1(N + 1), s2(N + 1);
|
||||
std::vector<std::thread> l;
|
||||
|
||||
volatile bool ok = true;
|
||||
for (size_t n = 0; n < N; ++n)
|
||||
l.push_back(std::thread([&]() {
|
||||
try {
|
||||
s0.arrive_and_wait();
|
||||
{
|
||||
auto txn = env.start_read();
|
||||
mdbx::slice value;
|
||||
int err = mdbx_get(txn, 1, pair.key, &value);
|
||||
if (err != MDBX_NOTFOUND) {
|
||||
ok = false;
|
||||
std::cerr << "Unexpected error " << err << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
s1.arrive_and_wait();
|
||||
s2.arrive_and_wait();
|
||||
{
|
||||
auto txn = env.start_read();
|
||||
if (txn.get(1, pair.key) != pair.value)
|
||||
ok = false;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cerr << "Exception: " << ex.what() << "\n";
|
||||
ok = false;
|
||||
}
|
||||
}));
|
||||
|
||||
s0.arrive_and_wait();
|
||||
auto txn = env.start_write();
|
||||
s1.arrive_and_wait();
|
||||
txn.insert(1, pair);
|
||||
txn.commit();
|
||||
s2.arrive_and_wait();
|
||||
|
||||
for (auto &t : l)
|
||||
t.join();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int doit() {
|
||||
mdbx::path path = "test-txn";
|
||||
mdbx::env::remove(path);
|
||||
|
||||
bool ok = case0(path);
|
||||
bool ok = true;
|
||||
ok = case0(path) && ok;
|
||||
ok = case1(path) && ok;
|
||||
ok = case2(path, false) && ok;
|
||||
ok = case2(path, true) && ok;
|
||||
ok = case3(path, false) && ok;
|
||||
ok = case3(path, true) && ok;
|
||||
|
||||
std::cout << (ok ? "OK\n" : "FAIL\n");
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
@ -28,6 +28,7 @@ REPORT_DEPTH=no
|
||||
REPEAT=11
|
||||
ROUNDS=1
|
||||
SMALL=no
|
||||
NUMABIND=
|
||||
|
||||
while [ -n "$1" ]
|
||||
do
|
||||
@ -51,6 +52,7 @@ do
|
||||
echo "--db-upto-gb NN --''--''--''--''--''--''--''--''-- NN gigabytes"
|
||||
echo "--no-geometry-jitter Disable jitter for geometry upper-size"
|
||||
echo "--pagesize NN Use specified page size (256 is minimal and used by default)"
|
||||
echo "--numa NODE Bind to the specified NUMA node"
|
||||
echo "--dont-check-ram-size Don't check available RAM"
|
||||
echo "--extra Iterate extra modes/flags"
|
||||
echo "--taillog Dump tail of test log on failure"
|
||||
@ -209,6 +211,15 @@ do
|
||||
--small)
|
||||
SMALL=yes
|
||||
;;
|
||||
--numa)
|
||||
NUMANODE=$2
|
||||
if [[ ! $NUMANODE =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid value '$NUMANODE' for --numa option, expect an integer of NUMA-node"
|
||||
exit -2
|
||||
fi
|
||||
NUMABIND="numactl --membind ${NUMANODE} --cpunodebind ${NUMANODE}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option '$1'"
|
||||
exit -2
|
||||
@ -393,7 +404,7 @@ if [ "$SKIP_MAKE" != "yes" ]; then
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# 5. run stochastic iterations
|
||||
# 5. internal preparations
|
||||
|
||||
if which setsid >/dev/null 2>/dev/null; then
|
||||
SETSID=$(which setsid)
|
||||
@ -504,9 +515,9 @@ function probe {
|
||||
else
|
||||
exec {LFD}> >(logger)
|
||||
fi
|
||||
${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=${REPEAT} --pathname=${TESTDB_DIR}/long.db --cleanup-after=no --geometry-jitter=${GEOMETRY_JITTER} "$@" $case >&${LFD} \
|
||||
&& ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
|
||||
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|
||||
${NUMABIND} ${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=${REPEAT} --pathname=${TESTDB_DIR}/long.db --cleanup-after=no --geometry-jitter=${GEOMETRY_JITTER} "$@" $case >&${LFD} \
|
||||
&& ${NUMABIND} ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
|
||||
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${NUMABIND} ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|
||||
|| failed
|
||||
if [ ${LFD} -ne 0 ]; then
|
||||
echo "@@@ END-OF-LOG/ITERATION" >&${LFD}
|
||||
@ -516,6 +527,115 @@ function probe {
|
||||
done
|
||||
}
|
||||
|
||||
# generate caseset
|
||||
declare -A caseset_id2caption
|
||||
declare -A caseset_id2args
|
||||
cases=0
|
||||
for ((bits=2**${#options[@]}; --bits >= 0; )); do
|
||||
|
||||
split=30
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
split=24
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
split=16
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
fi
|
||||
|
||||
split=4
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
done
|
||||
|
||||
###############################################################################
|
||||
# 6. run stochastic iterations
|
||||
|
||||
function pass {
|
||||
for ((round=1; round <= ROUNDS; ++round)); do
|
||||
echo "======================================================================="
|
||||
@ -524,122 +644,22 @@ function pass {
|
||||
else
|
||||
${BANNER} "$nops / $wbatch"
|
||||
fi
|
||||
subcase=0
|
||||
for ((bits=2**${#options[@]}; --bits >= 0; )); do
|
||||
|
||||
seed=$(($(date +%s) + RANDOM))
|
||||
|
||||
split=30
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=24
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=16
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
fi
|
||||
|
||||
split=4
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
done # options
|
||||
cases="${subcase}"
|
||||
subcase=0
|
||||
for id in $(seq 1 ${cases} | shuf); do
|
||||
caption="$((++count)) ${caseset_id2caption[${id}]}, case $((++subcase))/${id} of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M ${caseset_id2args[${id}]} --nops=$nops --batch.write=$wbatch
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
if [ "$DELAY" != "0" ]; then
|
||||
sleep $DELAY
|
||||
fi
|
||||
|
||||
count=0
|
||||
loop=0
|
||||
cases='?'
|
||||
if [[ $SMALL != "yes" ]]; then
|
||||
for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10000000 33333333 100000000 333333333 1000000000; do
|
||||
if [ $nops -lt $FROM ]; then continue; fi
|
||||
|
Loading…
x
Reference in New Issue
Block a user