From 6f49e7dfeb1adf6af1a0716b5952b2e0428cc96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 20 Jul 2025 15:59:07 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D0=BE=D0=B2=D0=BE=D0=BA=20?= =?UTF-8?q?=D0=B2=20API=20=D0=BA=D0=BE=D0=BF=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=81=20=D1=83=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BF=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=BB=D0=B5=D0=BC=D1=8B=20=D0=BD=D0=B0=20OSX.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit На POSIX-платформах внутри API копирования используются файловый блокировки `fcntl(F_SETLK)` и `flock()`, так как только совместное использование обеспечивает блокировку на всех платформах и файловых системах, включая NFS и SMB. Однако, в зависимости от платформы, версии ядра ОС, типа файловой системы, а в случае NFS/SMB также от удаленной стороны, используемые системные файловые блокировки могут не работать или конфликтовать между собой (в частности на OSX). Поэтому в этом коммите реализуется более гибкий подход. Если кратко, то допускается отказ одной из блокировок при успехе другой: - При успехе fcntl(F_SETLK) допускается EAGAIN/EWOULDBLOCK и EREMOTEIO от flock(), если целевой файл на не-локальной файловой системе, а также на не-Linux платформах, где одновременная блокировка может быть не разрешена fcntl(F_SETLK) и flock(). - При успехе flock() допускается ENOTSUP и REMOTEIO от fcntl(F_SETLK), если целевой файл на не-локальной файловой системе. --- src/api-copy.c | 76 +++++++++++++++++++++++++++++++++++--------------- src/cogs.h | 5 ++++ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/api-copy.c b/src/api-copy.c index bb7cda78..a87c6ea7 100644 --- a/src/api-copy.c +++ b/src/api-copy.c @@ -756,35 +756,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; - } + 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; + 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); - rc = err_flock; - } else { - WARNING("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "ignore", 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; + 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) diff --git a/src/cogs.h b/src/cogs.h index 70836997..0b75702c 100644 --- a/src/cogs.h +++ b/src/cogs.h @@ -389,6 +389,11 @@ MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_eagain 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) {