mdbx: purpose-oriented openfile().

Change-Id: I657689dab538af9a27c27f58eeb4e5ca43bdbc38
This commit is contained in:
Leonid Yuriev 2019-12-15 00:13:43 +03:00
parent 116d14bb76
commit 2db5736554
3 changed files with 169 additions and 129 deletions

View File

@ -8597,8 +8597,7 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
mdbx_assert(env, env->me_fd != INVALID_HANDLE_VALUE);
mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE);
int err = mdbx_openfile(lck_pathname, O_RDWR | O_CREAT, mode, &env->me_lfd,
(env->me_flags & MDBX_EXCLUSIVE) ? true : false);
int err = mdbx_openfile(MDBX_OPEN_LCK, env, lck_pathname, &env->me_lfd, mode);
if (err != MDBX_SUCCESS) {
if (!(err == MDBX_ENOFILE && (env->me_flags & MDBX_EXCLUSIVE)) &&
!((err == MDBX_EROFS || err == MDBX_EACCESS || err == MDBX_EPERM) &&
@ -8908,9 +8907,9 @@ __cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
#error "Persistent DB flags & env flags overlap, but both go in mm_flags"
#endif
int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
int __cold mdbx_env_open(MDBX_env *env, const char *pathname, unsigned flags,
mode_t mode) {
if (unlikely(!env || !path))
if (unlikely(!env || !pathname))
return MDBX_EINVAL;
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
@ -8923,7 +8922,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
(env->me_flags & MDBX_ENV_ACTIVE) != 0)
return MDBX_EPERM;
size_t len_full, len = strlen(path);
size_t len_full, len = strlen(pathname);
if (flags & MDBX_NOSUBDIR) {
len_full = len + sizeof(MDBX_LOCK_SUFFIX) + len + 1;
} else {
@ -8936,12 +8935,12 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
char *dxb_pathname;
if (flags & MDBX_NOSUBDIR) {
dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCK_SUFFIX);
sprintf(lck_pathname, "%s" MDBX_LOCK_SUFFIX, path);
strcpy(dxb_pathname, path);
sprintf(lck_pathname, "%s" MDBX_LOCK_SUFFIX, pathname);
strcpy(dxb_pathname, pathname);
} else {
dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCKNAME);
sprintf(lck_pathname, "%s" MDBX_LOCKNAME, path);
sprintf(dxb_pathname, "%s" MDBX_DATANAME, path);
sprintf(lck_pathname, "%s" MDBX_LOCKNAME, pathname);
sprintf(dxb_pathname, "%s" MDBX_DATANAME, pathname);
}
int rc = MDBX_SUCCESS;
@ -8978,7 +8977,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
if (rc)
goto bailout;
env->me_path = mdbx_strdup(path);
env->me_path = mdbx_strdup(pathname);
env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx));
env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0]));
env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0]));
@ -8989,37 +8988,39 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
env->me_dbxs[FREE_DBI].md_cmp =
mdbx_cmp_int_align4; /* aligned MDBX_INTEGERKEY */
int oflags;
if (F_ISSET(flags, MDBX_RDONLY))
oflags = O_RDONLY;
else if (mode != 0) {
if ((flags & MDBX_NOSUBDIR) == 0) {
if ((flags & (MDBX_RDONLY | MDBX_NOSUBDIR)) == 0 && mode != 0) {
#if defined(_WIN32) || defined(_WIN64)
if (!CreateDirectoryA(path, nullptr)) {
rc = GetLastError();
if (rc != ERROR_ALREADY_EXISTS)
goto bailout;
}
#else
const mode_t dir_mode =
(/* inherit read/write permissions for group and others */ mode &
(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
/* always add read/write/search for owner */ S_IRWXU |
((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) |
((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0);
if (mkdir(path, dir_mode)) {
rc = errno;
if (rc != EEXIST)
goto bailout;
}
#endif
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)) {
rc = ERROR_INVALID_NAME;
goto bailout;
}
oflags = O_RDWR | O_CREAT;
} else
oflags = O_RDWR;
if (!CreateDirectoryW(pathnameW, nullptr)) {
rc = GetLastError();
if (rc != ERROR_ALREADY_EXISTS)
goto bailout;
}
#else
const mode_t dir_mode =
(/* inherit read/write permissions for group and others */ mode &
(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
/* always add read/write/search for owner */ S_IRWXU |
((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) |
((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0);
if (mkdir(pathname, dir_mode)) {
rc = errno;
if (rc != EEXIST)
goto bailout;
}
#endif
}
rc = mdbx_openfile(dxb_pathname, oflags, mode, &env->me_fd,
(env->me_flags & MDBX_EXCLUSIVE) ? true : false);
rc = mdbx_openfile(F_ISSET(flags, MDBX_RDONLY) ? MDBX_OPEN_DXB_READ
: MDBX_OPEN_DXB_LAZY,
env, dxb_pathname, &env->me_fd, mode);
if (rc != MDBX_SUCCESS)
goto bailout;
@ -14443,49 +14444,28 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, unsigned flags) {
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
return MDBX_EBADSIGN;
char *dxb_pathname;
mdbx_filehandle_t newfd = INVALID_HANDLE_VALUE;
if (env->me_flags & MDBX_NOSUBDIR) {
dxb_pathname = (char *)dest_path;
} else {
size_t len = strlen(dest_path);
len += sizeof(MDBX_DATANAME);
dxb_pathname = mdbx_malloc(len);
if (!dxb_pathname)
return MDBX_ENOMEM;
sprintf(dxb_pathname, "%s" MDBX_DATANAME, dest_path);
}
/* The destination path must exist, but the destination file must not.
* We don't want the OS to cache the writes, since the source data is
* already in the OS cache. */
int rc = mdbx_openfile(dxb_pathname, O_WRONLY | O_CREAT | O_EXCL, 0640,
&newfd, true);
if (rc == MDBX_SUCCESS) {
if (env->me_psize >= env->me_os_psize) {
#ifdef F_NOCACHE /* __APPLE__ */
(void)fcntl(newfd, F_NOCACHE, 1);
#elif defined(O_DIRECT) && defined(F_GETFL)
/* Set O_DIRECT if the file system supports it */
if ((rc = fcntl(newfd, F_GETFL)) != -1)
(void)fcntl(newfd, F_SETFL, rc | O_DIRECT);
mdbx_filehandle_t newfd;
int rc = mdbx_openfile(MDBX_OPEN_COPY, env, dest_path, &newfd,
#if defined(_WIN32) || defined(_WIN64)
(mode_t)-1
#else
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
#endif
}
);
if (rc == MDBX_SUCCESS)
rc = mdbx_env_copy2fd(env, newfd, flags);
}
if (newfd != INVALID_HANDLE_VALUE) {
int err = mdbx_closefile(newfd);
if (rc == MDBX_SUCCESS && err != rc)
rc = err;
if (rc != MDBX_SUCCESS)
(void)mdbx_removefile(dxb_pathname);
(void)mdbx_removefile(dest_path);
}
if (dxb_pathname != dest_path)
mdbx_free(dxb_pathname);
return rc;
}

View File

@ -512,106 +512,156 @@ MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) {
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
#if defined(_WIN32) || defined(_WIN64)
return DeleteFileA(pathname) ? MDBX_SUCCESS : GetLastError();
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 DeleteFileW(pathnameW) ? MDBX_SUCCESS : GetLastError();
#else
return unlink(pathname) ? errno : MDBX_SUCCESS;
#endif
}
MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
mode_t mode, mdbx_filehandle_t *fd,
bool exclusive) {
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
const MDBX_env *env, const char *pathname,
mdbx_filehandle_t *fd,
mode_t unix_mode_bits) {
*fd = INVALID_HANDLE_VALUE;
#if defined(_WIN32) || defined(_WIN64)
(void)mode;
size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
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;
DWORD DesiredAccess, ShareMode;
DWORD FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING;
DWORD FlagsAndAttributes =
FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
DWORD DesiredAccess = FILE_READ_ATTRIBUTES;
DWORD ShareMode = (env->me_flags & MDBX_EXCLUSIVE)
? 0
: (FILE_SHARE_READ | FILE_SHARE_WRITE);
switch (purpose) {
default:
return ERROR_INVALID_PARAMETER;
case O_RDONLY:
DesiredAccess = GENERIC_READ;
ShareMode =
exclusive ? FILE_SHARE_READ : (FILE_SHARE_READ | FILE_SHARE_WRITE);
case MDBX_OPEN_LCK:
CreationDisposition = OPEN_ALWAYS;
DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
FlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY;
break;
case O_WRONLY: /* assume for MDBX_env_copy() and friends output */
DesiredAccess = GENERIC_WRITE;
ShareMode = 0;
case MDBX_OPEN_DXB_READ:
CreationDisposition = OPEN_EXISTING;
DesiredAccess |= GENERIC_READ;
ShareMode |= FILE_SHARE_READ;
break;
case MDBX_OPEN_DXB_LAZY:
DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
break;
case MDBX_OPEN_DXB_DSYNC:
CreationDisposition = OPEN_EXISTING;
DesiredAccess |= GENERIC_WRITE;
FlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
break;
case O_RDWR:
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
ShareMode = exclusive ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
break;
}
DWORD CreationDisposition;
switch (flags & (O_EXCL | O_CREAT)) {
default:
return ERROR_INVALID_PARAMETER;
case 0:
CreationDisposition = OPEN_EXISTING;
break;
case O_EXCL | O_CREAT:
case MDBX_OPEN_COPY:
CreationDisposition = CREATE_NEW;
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
break;
case O_CREAT:
CreationDisposition = OPEN_ALWAYS;
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
ShareMode = 0;
DesiredAccess |= GENERIC_WRITE;
FlagsAndAttributes |=
(env->me_psize < env->me_os_psize) ? 0 : FILE_FLAG_NO_BUFFERING;
break;
}
*fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL,
CreationDisposition, FlagsAndAttributes, NULL);
if (*fd == INVALID_HANDLE_VALUE)
return GetLastError();
if ((flags & O_CREAT) && GetLastError() != ERROR_ALREADY_EXISTS) {
/* set FILE_ATTRIBUTE_NOT_CONTENT_INDEXED for new file */
DWORD FileAttributes = GetFileAttributesA(pathname);
if (FileAttributes == INVALID_FILE_ATTRIBUTES ||
!SetFileAttributesA(pathname, FileAttributes |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {
int rc = GetLastError();
CloseHandle(*fd);
*fd = INVALID_HANDLE_VALUE;
return rc;
}
BY_HANDLE_FILE_INFORMATION info;
if (!GetFileInformationByHandle(*fd, &info)) {
int err = GetLastError();
CloseHandle(*fd);
*fd = INVALID_HANDLE_VALUE;
return err;
}
const DWORD AttributesDiff =
(info.dwFileAttributes ^ FlagsAndAttributes) &
(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_COMPRESSED);
if (AttributesDiff)
(void)SetFileAttributesW(pathnameW, info.dwFileAttributes ^ AttributesDiff);
#else
(void)exclusive;
int flags = unix_mode_bits ? O_CREAT : 0;
switch (purpose) {
default:
return EINVAL;
case MDBX_OPEN_LCK:
flags |= O_RDWR;
break;
case MDBX_OPEN_DXB_READ:
flags = O_RDONLY;
break;
case MDBX_OPEN_DXB_LAZY:
flags |= O_RDWR;
break;
case MDBX_OPEN_COPY:
flags = O_CREAT | O_WRONLY | O_EXCL;
break;
case MDBX_OPEN_DXB_DSYNC:
flags |= O_WRONLY;
#if defined(O_DSYNC)
flags |= O_DSYNC;
#elif defined(O_SYNC)
flags |= O_SYNC;
#elif defined(O_FSYNC)
flags |= O_FSYNC;
#endif
break;
}
const bool direct_nocache_for_copy =
env->me_psize >= env->me_os_psize && purpose == MDBX_OPEN_COPY;
if (direct_nocache_for_copy) {
#if defined(O_DIRECT)
flags |= O_DIRECT;
#endif /* O_DIRECT */
#if defined(O_NOCACHE)
flags |= O_NOCACHE;
#endif /* O_NOCACHE */
}
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif /* O_CLOEXEC */
*fd = open(pathname, flags, mode);
*fd = open(pathname, flags, unix_mode_bits);
#if defined(O_DIRECT)
if (*fd < 0 && (flags & O_DIRECT) &&
(errno == EINVAL || errno == EAFNOSUPPORT)) {
flags &= ~(O_DIRECT | O_EXCL);
*fd = open(pathname, flags, unix_mode_bits);
}
#endif /* O_DIRECT */
if (*fd < 0)
return errno;
#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
int fd_flags = fcntl(*fd, F_GETFD);
const int fd_flags = fcntl(*fd, F_GETFD);
if (fd_flags != -1)
(void)fcntl(*fd, F_SETFD, fd_flags | FD_CLOEXEC);
#endif /* FD_CLOEXEC && !O_CLOEXEC */
if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY) {
/* assume for MDBX_env_copy() and friends output */
#if defined(O_DIRECT)
int fd_flags = fcntl(*fd, F_GETFD);
if (fd_flags != -1)
(void)fcntl(*fd, F_SETFL, fd_flags | O_DIRECT);
#endif /* O_DIRECT */
#if defined(F_NOCACHE)
if (direct_nocache_for_copy) {
#if defined(F_NOCACHE) && !defined(O_NOCACHE)
(void)fcntl(*fd, F_NOCACHE, 1);
#endif /* F_NOCACHE */
}
#endif
return MDBX_SUCCESS;

View File

@ -566,9 +566,19 @@ MDBX_INTERNAL_FUNC int mdbx_filesync(mdbx_filehandle_t fd,
MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
mode_t mode, mdbx_filehandle_t *fd,
bool exclusive);
enum mdbx_openfile_purpose {
MDBX_OPEN_DXB_READ = 0,
MDBX_OPEN_DXB_LAZY = 1,
MDBX_OPEN_DXB_DSYNC = 2,
MDBX_OPEN_LCK = 3,
MDBX_OPEN_COPY = 4
};
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
const MDBX_env *env, const char *pathname,
mdbx_filehandle_t *fd,
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_is_pipe(mdbx_filehandle_t fd);