mirror of
https://github.com/isar/libmdbx.git
synced 2024-12-30 01:14:12 +08:00
mdbx: add mdbx_env_delete()
.
Resolves https://github.com/erthink/libmdbx/issues/119 Related to https://github.com/Kerollmops/heed/issues/58 Change-Id: Iec5bf5978e45bb6843f3ed8dd06ea4d34f2895cb
This commit is contained in:
parent
cd0c727880
commit
0627d902dd
@ -11,6 +11,7 @@ TODO:
|
||||
|
||||
Added features:
|
||||
- Provided package for [buildroot](https://buildroot.org/).
|
||||
- Added `mdbx_env_delete()` for deletion an environment files in a proper and multiprocess-safe way.
|
||||
|
||||
Fixes:
|
||||
|
||||
|
42
mdbx.h
42
mdbx.h
@ -1801,6 +1801,48 @@ LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
|
||||
LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode);
|
||||
|
||||
/** \brief Deletion modes for \ref mdbx_env_delete()
|
||||
* \ingroup c_extra
|
||||
* \see mdbx_env_delete() */
|
||||
enum MDBX_env_delete_mode_t {
|
||||
/** \brief Just delete the environment's files and directory if any.
|
||||
* \note On POSIX systems, processes already working with the database will
|
||||
* continue to work without interference until it close the environment.
|
||||
* \note On Windows, the behavior of `MDB_ENV_JUST_DELETE` is different
|
||||
* because the system does not support deleting files that are currently
|
||||
* memory mapped. */
|
||||
MDBX_ENV_JUST_DELETE = 0,
|
||||
/** Make sure that the environment is not being used by other processes,
|
||||
* or return an error otherwise. */
|
||||
MDBX_ENV_ENSURE_UNUSED = 1,
|
||||
/** Wait until other processes closes the environment before deletion. */
|
||||
MDBX_ENV_WAIT_FOR_UNUSED = 2,
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
/** \c_extra c_statinfo */
|
||||
typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t;
|
||||
#endif
|
||||
|
||||
/** \brief Delete the environment files in a proper and multiprocess-safe way.
|
||||
* \ingroup c_extra
|
||||
*
|
||||
* \param [in] pathname The pathname for the database or the directory in which
|
||||
* the database files reside.
|
||||
*
|
||||
* \param [in] mode Special deletion mode for the environment. This
|
||||
* parameter must be set to one of the values described
|
||||
* above in the \ref MDBX_env_delete_mode_t section.
|
||||
*
|
||||
* \note The \ref MDBX_ENV_JUST_DELETE don't supported on Windows since system
|
||||
* unable to delete a memory-mapped files.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_RESULT_TRUE No corresponding files or directories were found,
|
||||
* so no deletion was performed. */
|
||||
LIBMDBX_API int mdbx_env_delete(const char *pathname,
|
||||
MDBX_env_delete_mode_t mode);
|
||||
|
||||
/** \brief Copy an MDBX environment to the specified path, with options.
|
||||
* \ingroup c_extra
|
||||
*
|
||||
|
75
src/core.c
75
src/core.c
@ -10467,6 +10467,81 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *result,
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
__cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) {
|
||||
switch (mode) {
|
||||
default:
|
||||
return MDBX_EINVAL;
|
||||
case MDBX_ENV_JUST_DELETE:
|
||||
case MDBX_ENV_ENSURE_UNUSED:
|
||||
case MDBX_ENV_WAIT_FOR_UNUSED:
|
||||
break;
|
||||
}
|
||||
|
||||
MDBX_env dummy_env;
|
||||
memset(&dummy_env, 0, sizeof(dummy_env));
|
||||
dummy_env.me_flags =
|
||||
(mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS;
|
||||
dummy_env.me_psize = dummy_env.me_os_psize = (unsigned)mdbx_syspagesize();
|
||||
dummy_env.me_path = (char *)pathname;
|
||||
|
||||
MDBX_handle_env_pathname env_pathname;
|
||||
STATIC_ASSERT(sizeof(dummy_env.me_flags) == sizeof(MDBX_env_flags_t));
|
||||
int rc = MDBX_RESULT_TRUE,
|
||||
err = mdbx_handle_env_pathname(
|
||||
&env_pathname, pathname, (MDBX_env_flags_t *)&dummy_env.me_flags, 0);
|
||||
if (likely(err == MDBX_SUCCESS)) {
|
||||
mdbx_filehandle_t clk_handle = INVALID_HANDLE_VALUE,
|
||||
dxb_handle = INVALID_HANDLE_VALUE;
|
||||
if (mode > MDBX_ENV_JUST_DELETE) {
|
||||
err = mdbx_openfile(MDBX_OPEN_DELETE, &dummy_env, env_pathname.dxb,
|
||||
&dxb_handle, 0);
|
||||
err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err;
|
||||
if (err == MDBX_SUCCESS) {
|
||||
err = mdbx_openfile(MDBX_OPEN_DELETE, &dummy_env, env_pathname.lck,
|
||||
&clk_handle, 0);
|
||||
err = (err == MDBX_ENOFILE) ? MDBX_SUCCESS : err;
|
||||
}
|
||||
if (err == MDBX_SUCCESS && clk_handle != INVALID_HANDLE_VALUE)
|
||||
err = mdbx_lockfile(clk_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED);
|
||||
if (err == MDBX_SUCCESS && dxb_handle != INVALID_HANDLE_VALUE)
|
||||
err = mdbx_lockfile(dxb_handle, mode == MDBX_ENV_WAIT_FOR_UNUSED);
|
||||
}
|
||||
|
||||
if (err == MDBX_SUCCESS) {
|
||||
err = mdbx_removefile(env_pathname.dxb);
|
||||
if (err == MDBX_SUCCESS)
|
||||
rc = MDBX_SUCCESS;
|
||||
else if (err == MDBX_ENOFILE)
|
||||
err = MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
if (err == MDBX_SUCCESS) {
|
||||
err = mdbx_removefile(env_pathname.lck);
|
||||
if (err == MDBX_SUCCESS)
|
||||
rc = MDBX_SUCCESS;
|
||||
else if (err == MDBX_ENOFILE)
|
||||
err = MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
if (err == MDBX_SUCCESS && !(dummy_env.me_flags & MDBX_NOSUBDIR)) {
|
||||
err = mdbx_removedirectory(pathname);
|
||||
if (err == MDBX_SUCCESS)
|
||||
rc = MDBX_SUCCESS;
|
||||
else if (err == MDBX_ENOFILE)
|
||||
err = MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
if (dxb_handle != INVALID_HANDLE_VALUE)
|
||||
mdbx_closefile(dxb_handle);
|
||||
if (clk_handle != INVALID_HANDLE_VALUE)
|
||||
mdbx_closefile(clk_handle);
|
||||
} else if (err == MDBX_ENOFILE)
|
||||
err = MDBX_SUCCESS;
|
||||
|
||||
mdbx_free(env_pathname.buffer_for_free);
|
||||
return (err == MDBX_SUCCESS) ? rc : err;
|
||||
}
|
||||
|
||||
__cold int mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode) {
|
||||
int rc = check_env(env);
|
||||
|
@ -190,6 +190,14 @@ static int lck_op(mdbx_filehandle_t fd, int cmd, int lck, off_t offset,
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (unlikely(op_setlk == 0))
|
||||
choice_fcntl();
|
||||
#endif /* MDBX_USE_OFDLOCKS */
|
||||
return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) {
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_pid > 0);
|
||||
|
@ -204,6 +204,15 @@ MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
|
||||
mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return flock(fd,
|
||||
wait ? LCK_EXCLUSIVE | LCK_WAITFOR
|
||||
: LCK_EXCLUSIVE | LCK_DONTWAIT,
|
||||
0, LCK_MAXLEN)
|
||||
? MDBX_SUCCESS
|
||||
: GetLastError();
|
||||
}
|
||||
|
||||
static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
const DWORD ThreadId) {
|
||||
const unsigned limit = (*array)->limit;
|
||||
|
23
src/osal.c
23
src/osal.c
@ -521,6 +521,20 @@ MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
|
||||
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
|
||||
return ERROR_INVALID_NAME;
|
||||
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
|
||||
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
|
||||
return ERROR_INVALID_NAME;
|
||||
return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : GetLastError();
|
||||
#else
|
||||
return rmdir(pathname) ? errno : MDBX_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
mdbx_filehandle_t *fd,
|
||||
@ -571,6 +585,12 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
FlagsAndAttributes |=
|
||||
(env->me_psize < env->me_os_psize) ? 0 : FILE_FLAG_NO_BUFFERING;
|
||||
break;
|
||||
case MDBX_OPEN_DELETE:
|
||||
CreationDisposition = OPEN_EXISTING;
|
||||
ShareMode |= FILE_SHARE_DELETE;
|
||||
DesiredAccess =
|
||||
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
*fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL,
|
||||
@ -619,6 +639,9 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
flags |= O_FSYNC;
|
||||
#endif
|
||||
break;
|
||||
case MDBX_OPEN_DELETE:
|
||||
flags = O_RDWR;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool direct_nocache_for_copy =
|
||||
|
@ -626,7 +626,8 @@ enum mdbx_openfile_purpose {
|
||||
MDBX_OPEN_DXB_LAZY = 1,
|
||||
MDBX_OPEN_DXB_DSYNC = 2,
|
||||
MDBX_OPEN_LCK = 3,
|
||||
MDBX_OPEN_COPY = 4
|
||||
MDBX_OPEN_COPY = 4,
|
||||
MDBX_OPEN_DELETE = 5
|
||||
};
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
@ -635,7 +636,9 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
mdbx_mode_t unix_mode_bits);
|
||||
MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
|
||||
|
||||
#define MMAP_OPTION_TRUNCATE 1
|
||||
#define MMAP_OPTION_SEMAPHORE 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user