mdbx-posix: checking for file removal during LCK-seizing.

Change-Id: I7626ceda62fc4dac86323bec4194ae46bc19d9d3
This commit is contained in:
Leonid Yuriev 2019-12-21 13:18:45 +03:00
parent ccb45730f2
commit e3d328621e

View File

@ -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) {