mirror of
https://github.com/isar/libmdbx.git
synced 2025-08-01 22:34:44 +08:00
mdbx: переработка ошибок файловых блокировок в API копирования с устранением проблемы на OSX (backport).
На 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), если целевой файл на не-локальной файловой системе.
This commit is contained in:
parent
6318ca701a
commit
5c69cb322a
@ -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;
|
||||
}
|
||||
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)
|
||||
|
@ -383,6 +383,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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user