mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 02:14:13 +08:00
mdbx-posix: checking for file removal during LCK-seizing.
Change-Id: I7626ceda62fc4dac86323bec4194ae46bc19d9d3
This commit is contained in:
parent
ccb45730f2
commit
e3d328621e
@ -220,6 +220,65 @@ MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc) {
|
||||
}
|
||||
#endif /* MDBX_LOCKING > MDBX_LOCKING_SYSV */
|
||||
|
||||
static int check_fstat(MDBX_env *env) {
|
||||
struct stat st;
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
if (fstat(env->me_lazy_fd, &st)) {
|
||||
rc = errno;
|
||||
mdbx_error("fstat(%s), err %d", "DXB", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
|
||||
#ifdef EBADFD
|
||||
rc = EBADFD;
|
||||
#else
|
||||
rc = EPERM;
|
||||
#endif
|
||||
mdbx_error("%s %s, err %d", "DXB",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st.st_size < (off_t)(MDBX_MIN_PAGESIZE * NUM_METAS)) {
|
||||
mdbx_verbose("dxb-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
if (fstat(env->me_lfd, &st)) {
|
||||
rc = errno;
|
||||
mdbx_error("fstat(%s), err %d", "LCK", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode) || st.st_nlink < 1) {
|
||||
#ifdef EBADFD
|
||||
rc = EBADFD;
|
||||
#else
|
||||
rc = EPERM;
|
||||
#endif
|
||||
mdbx_error("%s %s, err %d", "LCK",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Checking file size for detect the situation when we got the shared lock
|
||||
* immediately after mdbx_lck_destroy(). */
|
||||
if (st.st_size < (off_t)(sizeof(MDBX_lockinfo) + sizeof(MDBX_reader))) {
|
||||
mdbx_verbose("lck-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int __cold mdbx_lck_seize(MDBX_env *env) {
|
||||
assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(mdbx_getpid() != env->me_pid))
|
||||
@ -229,7 +288,7 @@ MDBX_INTERNAL_FUNC int __cold mdbx_lck_seize(MDBX_env *env) {
|
||||
choice_fcntl();
|
||||
#endif /* MDBX_USE_OFDLOCKS */
|
||||
|
||||
int rc;
|
||||
int rc = MDBX_SUCCESS;
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE) {
|
||||
/* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
|
||||
rc =
|
||||
@ -242,11 +301,27 @@ MDBX_INTERNAL_FUNC int __cold mdbx_lck_seize(MDBX_env *env) {
|
||||
}
|
||||
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
||||
}
|
||||
#if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
|
||||
sched_yield();
|
||||
#endif
|
||||
|
||||
retry:
|
||||
if (rc == MDBX_RESULT_TRUE) {
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_UNLCK, 0, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "unlock-before-retry", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
retry_exclusive:
|
||||
/* Firstly try to get exclusive locking. */
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, 1);
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
rc = check_fstat(env);
|
||||
if (MDBX_IS_ERROR(rc))
|
||||
return rc;
|
||||
|
||||
continue_dxb_exclusive:
|
||||
rc =
|
||||
lck_op(env->me_lazy_fd, op_setlk,
|
||||
@ -254,6 +329,10 @@ retry_exclusive:
|
||||
if (rc == MDBX_SUCCESS)
|
||||
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
||||
|
||||
int err = check_fstat(env);
|
||||
if (MDBX_IS_ERROR(err))
|
||||
return err;
|
||||
|
||||
/* the cause may be a collision with POSIX's file-lock recovery. */
|
||||
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK ||
|
||||
rc == EDEADLK)) {
|
||||
@ -263,6 +342,11 @@ retry_exclusive:
|
||||
}
|
||||
|
||||
/* Fallback to lck-shared */
|
||||
} else if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY ||
|
||||
rc == EWOULDBLOCK || rc == EDEADLK)) {
|
||||
mdbx_error("%s, err %u", "try-exclusive", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Here could be one of two:
|
||||
@ -282,6 +366,14 @@ retry_exclusive:
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = check_fstat(env);
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
goto retry;
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "lck_fstat", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* got shared, retry exclusive */
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, 1);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
@ -294,27 +386,6 @@ retry_exclusive:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Checking file size for detect the situation when we got the shared lock
|
||||
* immediately after mdbx_lck_destroy(). */
|
||||
struct stat st;
|
||||
if (fstat(env->me_lfd, &st)) {
|
||||
rc = errno;
|
||||
mdbx_error("%s(%s) failed: errcode %u", __func__, "check-filesize", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
if (st.st_size < (unsigned)(sizeof(MDBX_lockinfo) + sizeof(MDBX_reader))) {
|
||||
mdbx_verbose("lck-file is too short (%u), retry exclusive-lock",
|
||||
(unsigned)st.st_size);
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_UNLCK, 0, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s(%s) failed: errcode %u", __func__, "retry-exclusive", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
goto retry_exclusive;
|
||||
}
|
||||
|
||||
/* Lock against another process operating in without-lck or exclusive mode. */
|
||||
rc =
|
||||
lck_op(env->me_lazy_fd, op_setlk,
|
||||
@ -357,10 +428,13 @@ MDBX_INTERNAL_FUNC int __cold mdbx_lck_destroy(MDBX_env *env,
|
||||
return MDBX_PANIC;
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
struct stat lck_info;
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE && !inprocess_neighbor &&
|
||||
env->me_lck &&
|
||||
/* try get exclusive access */
|
||||
lck_op(env->me_lfd, op_setlk, F_WRLCK, 0, OFF_T_MAX) == 0 &&
|
||||
/* if LCK was not removed */
|
||||
fstat(env->me_lfd, &lck_info) == 0 && lck_info.st_nlink > 0 &&
|
||||
lck_op(env->me_lazy_fd, op_setlk,
|
||||
(env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0,
|
||||
OFF_T_MAX) == 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user